From 5419c5032984533632365375fd8857fc0c952f75 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Fri, 13 Nov 2026 00:33:32 +0000 Subject: [PATCH 1/8] [suites-experimental] Add Tools-GPS-Tracks workload Introduce an experimental GPS activity track analyzer workload to cover binary and XML telemetry parsing, IndexedDB persistence, geospatial map rendering, and multi-track physiological charting in Speedometer. --- .eslintignore | 2 + .prettierignore | 2 + suites-experimental/suites.mjs | 68 + .../tools-gps-tracks/.gitignore | 1 + .../tools-gps-tracks/.prettierignore | 3 + .../tools-gps-tracks/.prettierrc | 7 + suites-experimental/tools-gps-tracks/LICENSE | 28 + .../tools-gps-tracks/README.md | 28 + suites-experimental/tools-gps-tracks/build.js | 224 ++ .../tools-gps-tracks/dist/LICENSE | 158 + .../dist/benchmark-override.mjs | 2 + .../dist/benchmark-override.mjs.map | 7 + .../tools-gps-tracks/dist/fit-file-parser.mjs | 15 + .../dist/fit-file-parser.mjs.map | 7 + .../tools-gps-tracks/dist/index.html | 551 +++ .../dist/material_symbols_rounded.woff2 | Bin 0 -> 79944 bytes .../tools-gps-tracks/dist/resources.txt | 20 + .../tools-gps-tracks/dist/styles.css | 2 + .../tools-gps-tracks/dist/styles.css.map | 7 + .../test-data/activity_1_alps_stage.gpx.gz | Bin 0 -> 42206 bytes .../test-data/activity_2_forest_mtb.gpx.gz | Bin 0 -> 31377 bytes .../test-data/activity_3_road_race.tcx.gz | Bin 0 -> 39528 bytes .../test-data/activity_4_intervals.tcx.gz | Bin 0 -> 34171 bytes .../test-data/activity_5_grand_tour.fit.gz | Bin 0 -> 36301 bytes .../test-data/activity_6_weekend_ride.fit.gz | Bin 0 -> 27953 bytes .../dist/test-data/manifest.json | 8 + .../dist/tools-gps-tracks.mjs | 903 +++++ .../dist/tools-gps-tracks.mjs.map | 7 + .../tools-gps-tracks/dist/uplot.mjs | 4 + .../tools-gps-tracks/dist/uplot.mjs.map | 7 + .../material_symbols_rounded.woff2 | Bin 0 -> 79944 bytes .../tools-gps-tracks/package-lock.json | 560 +++ .../tools-gps-tracks/package.json | 27 + .../scripts/generate-test-data.mjs | 453 +++ .../tools-gps-tracks/src/app.ts | 2179 +++++++++++ .../src/benchmark-override.ts | 75 + .../tools-gps-tracks/src/charts.ts | 3376 +++++++++++++++++ .../tools-gps-tracks/src/css/styles.css | 2403 ++++++++++++ .../tools-gps-tracks/src/css/uPlot.min.css | 1 + .../tools-gps-tracks/src/index.html | 551 +++ .../tools-gps-tracks/src/map.ts | 105 + .../tools-gps-tracks/src/metrics.ts | 181 + .../tools-gps-tracks/src/parsers.ts | 1453 +++++++ .../tools-gps-tracks/src/sports.ts | 25 + .../tools-gps-tracks/src/storage.ts | 149 + .../src/tabs/accumulated_progress.ts | 166 + .../tools-gps-tracks/src/tabs/combined.ts | 825 ++++ .../tools-gps-tracks/src/tabs/courses.ts | 621 +++ .../tools-gps-tracks/src/tabs/details.ts | 550 +++ .../tools-gps-tracks/src/tabs/insights.ts | 819 ++++ .../tools-gps-tracks/src/tabs/progress.ts | 1652 ++++++++ .../tools-gps-tracks/src/url-state.ts | 202 + .../tools-gps-tracks/src/utils.ts | 139 + .../tools-gps-tracks/src/vendor-fit.ts | 6 + .../tools-gps-tracks/src/zones.ts | 60 + .../test-data/activity_1_alps_stage.gpx.gz | Bin 0 -> 42206 bytes .../test-data/activity_2_forest_mtb.gpx.gz | Bin 0 -> 31377 bytes .../test-data/activity_3_road_race.tcx.gz | Bin 0 -> 39528 bytes .../test-data/activity_4_intervals.tcx.gz | Bin 0 -> 34171 bytes .../test-data/activity_5_grand_tour.fit.gz | Bin 0 -> 36301 bytes .../test-data/activity_6_weekend_ride.fit.gz | Bin 0 -> 27953 bytes .../tools-gps-tracks/test-data/manifest.json | 8 + .../tools-gps-tracks/tsconfig.json | 17 + 63 files changed, 18664 insertions(+) create mode 100644 suites-experimental/tools-gps-tracks/.gitignore create mode 100644 suites-experimental/tools-gps-tracks/.prettierignore create mode 100644 suites-experimental/tools-gps-tracks/.prettierrc create mode 100644 suites-experimental/tools-gps-tracks/LICENSE create mode 100644 suites-experimental/tools-gps-tracks/README.md create mode 100644 suites-experimental/tools-gps-tracks/build.js create mode 100644 suites-experimental/tools-gps-tracks/dist/LICENSE create mode 100644 suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs create mode 100644 suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map create mode 100644 suites-experimental/tools-gps-tracks/dist/fit-file-parser.mjs create mode 100644 suites-experimental/tools-gps-tracks/dist/fit-file-parser.mjs.map create mode 100644 suites-experimental/tools-gps-tracks/dist/index.html create mode 100644 suites-experimental/tools-gps-tracks/dist/material_symbols_rounded.woff2 create mode 100644 suites-experimental/tools-gps-tracks/dist/resources.txt create mode 100644 suites-experimental/tools-gps-tracks/dist/styles.css create mode 100644 suites-experimental/tools-gps-tracks/dist/styles.css.map create mode 100644 suites-experimental/tools-gps-tracks/dist/test-data/activity_1_alps_stage.gpx.gz create mode 100644 suites-experimental/tools-gps-tracks/dist/test-data/activity_2_forest_mtb.gpx.gz create mode 100644 suites-experimental/tools-gps-tracks/dist/test-data/activity_3_road_race.tcx.gz create mode 100644 suites-experimental/tools-gps-tracks/dist/test-data/activity_4_intervals.tcx.gz create mode 100644 suites-experimental/tools-gps-tracks/dist/test-data/activity_5_grand_tour.fit.gz create mode 100644 suites-experimental/tools-gps-tracks/dist/test-data/activity_6_weekend_ride.fit.gz create mode 100644 suites-experimental/tools-gps-tracks/dist/test-data/manifest.json create mode 100644 suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs create mode 100644 suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map create mode 100644 suites-experimental/tools-gps-tracks/dist/uplot.mjs create mode 100644 suites-experimental/tools-gps-tracks/dist/uplot.mjs.map create mode 100644 suites-experimental/tools-gps-tracks/material_symbols_rounded.woff2 create mode 100644 suites-experimental/tools-gps-tracks/package-lock.json create mode 100644 suites-experimental/tools-gps-tracks/package.json create mode 100644 suites-experimental/tools-gps-tracks/scripts/generate-test-data.mjs create mode 100644 suites-experimental/tools-gps-tracks/src/app.ts create mode 100644 suites-experimental/tools-gps-tracks/src/benchmark-override.ts create mode 100644 suites-experimental/tools-gps-tracks/src/charts.ts create mode 100644 suites-experimental/tools-gps-tracks/src/css/styles.css create mode 100644 suites-experimental/tools-gps-tracks/src/css/uPlot.min.css create mode 100644 suites-experimental/tools-gps-tracks/src/index.html create mode 100644 suites-experimental/tools-gps-tracks/src/map.ts create mode 100644 suites-experimental/tools-gps-tracks/src/metrics.ts create mode 100644 suites-experimental/tools-gps-tracks/src/parsers.ts create mode 100644 suites-experimental/tools-gps-tracks/src/sports.ts create mode 100644 suites-experimental/tools-gps-tracks/src/storage.ts create mode 100644 suites-experimental/tools-gps-tracks/src/tabs/accumulated_progress.ts create mode 100644 suites-experimental/tools-gps-tracks/src/tabs/combined.ts create mode 100644 suites-experimental/tools-gps-tracks/src/tabs/courses.ts create mode 100644 suites-experimental/tools-gps-tracks/src/tabs/details.ts create mode 100644 suites-experimental/tools-gps-tracks/src/tabs/insights.ts create mode 100644 suites-experimental/tools-gps-tracks/src/tabs/progress.ts create mode 100644 suites-experimental/tools-gps-tracks/src/url-state.ts create mode 100644 suites-experimental/tools-gps-tracks/src/utils.ts create mode 100644 suites-experimental/tools-gps-tracks/src/vendor-fit.ts create mode 100644 suites-experimental/tools-gps-tracks/src/zones.ts create mode 100644 suites-experimental/tools-gps-tracks/test-data/activity_1_alps_stage.gpx.gz create mode 100644 suites-experimental/tools-gps-tracks/test-data/activity_2_forest_mtb.gpx.gz create mode 100644 suites-experimental/tools-gps-tracks/test-data/activity_3_road_race.tcx.gz create mode 100644 suites-experimental/tools-gps-tracks/test-data/activity_4_intervals.tcx.gz create mode 100644 suites-experimental/tools-gps-tracks/test-data/activity_5_grand_tour.fit.gz create mode 100644 suites-experimental/tools-gps-tracks/test-data/activity_6_weekend_ride.fit.gz create mode 100644 suites-experimental/tools-gps-tracks/test-data/manifest.json create mode 100644 suites-experimental/tools-gps-tracks/tsconfig.json diff --git a/.eslintignore b/.eslintignore index e57be2186a..0af4d59c62 100644 --- a/.eslintignore +++ b/.eslintignore @@ -48,3 +48,5 @@ package-lock.json /suites/react-stockcharts /suites-experimental/responsive-design/build-dev/ +/suites-experimental/tools-gps-tracks +/suites-experimental/tools-gps-tracks/** diff --git a/.prettierignore b/.prettierignore index 0b1b6168e3..9f52acec83 100644 --- a/.prettierignore +++ b/.prettierignore @@ -48,3 +48,5 @@ package-lock.json /suites/react-stockcharts /suites-experimental/responsive-design/build-dev/ /suites-experimental/responsive-design/**/*.generated.css +/suites-experimental/tools-gps-tracks +/suites-experimental/tools-gps-tracks/** diff --git a/suites-experimental/suites.mjs b/suites-experimental/suites.mjs index 2e4496c798..89fa57d3dd 100644 --- a/suites-experimental/suites.mjs +++ b/suites-experimental/suites.mjs @@ -304,4 +304,72 @@ export const ExperimentalSuites = freezeSuites([ }), ], }, + { + name: "Tools-GPS-Tracks", + url: "suites-experimental/tools-gps-tracks/dist/index.html", + resources: "suites-experimental/tools-gps-tracks/dist/resources.txt", + tags: ["experimental", "charts", "gpx"], + type: "async", + async prepare(page) { + await page.waitForElement("#app-is-ready"); + }, + tests: [ + new BenchmarkTestStep("LoadAndParseFiles", async (page) => { + const complete = new Promise((resolve) => { + page.addEventListener("load-and-parse-complete", resolve, { once: true }); + }); + page.querySelector("#btn-step-load").click(); + await complete; + page.layout(); + }), + new BenchmarkTestStep("DisplayAnalysisMetrics", async (page) => { + const complete = new Promise((resolve) => { + page.addEventListener("analysis-complete", resolve, { once: true }); + }); + page.querySelector("#btn-step-analysis").click(); + await complete; + page.layout(); + }), + new BenchmarkTestStep("DisplayInsights", async (page) => { + const complete = new Promise((resolve) => { + page.addEventListener("insights-complete", resolve, { once: true }); + }); + page.querySelector("#btn-step-insights").click(); + await complete; + page.layout(); + }), + new BenchmarkTestStep("DisplayDetails", async (page) => { + const complete = new Promise((resolve) => { + page.addEventListener("details-complete", resolve, { once: true }); + }); + page.querySelector("#btn-step-details").click(); + await complete; + page.layout(); + }), + new BenchmarkTestStep("DisplayAggregateMetrics", async (page) => { + const complete = new Promise((resolve) => { + page.addEventListener("aggregate-complete", resolve, { once: true }); + }); + page.querySelector("#btn-step-aggregate").click(); + await complete; + page.layout(); + }), + new BenchmarkTestStep("DisplayEvolutionMetrics", async (page) => { + const complete = new Promise((resolve) => { + page.addEventListener("evolution-complete", resolve, { once: true }); + }); + page.querySelector("#btn-step-evolution").click(); + await complete; + page.layout(); + }), + new BenchmarkTestStep("DisplayCourses", async (page) => { + const complete = new Promise((resolve) => { + page.addEventListener("courses-complete", resolve, { once: true }); + }); + page.querySelector("#btn-step-courses").click(); + await complete; + page.layout(); + }), + ], + }, ]); diff --git a/suites-experimental/tools-gps-tracks/.gitignore b/suites-experimental/tools-gps-tracks/.gitignore new file mode 100644 index 0000000000..3c3629e647 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/suites-experimental/tools-gps-tracks/.prettierignore b/suites-experimental/tools-gps-tracks/.prettierignore new file mode 100644 index 0000000000..f4464f0263 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/.prettierignore @@ -0,0 +1,3 @@ +dist/ +test-data/ +src/css/uPlot.min.css diff --git a/suites-experimental/tools-gps-tracks/.prettierrc b/suites-experimental/tools-gps-tracks/.prettierrc new file mode 100644 index 0000000000..ca8527e0dd --- /dev/null +++ b/suites-experimental/tools-gps-tracks/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": true, + "trailingComma": "all", + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2 +} diff --git a/suites-experimental/tools-gps-tracks/LICENSE b/suites-experimental/tools-gps-tracks/LICENSE new file mode 100644 index 0000000000..74eccfcc94 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2026, Camillo Bruni + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/suites-experimental/tools-gps-tracks/README.md b/suites-experimental/tools-gps-tracks/README.md new file mode 100644 index 0000000000..ca1dad4d18 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/README.md @@ -0,0 +1,28 @@ +# Tools-GPS-Tracks Workload + +## Description + +This workload simulates an offline-capable GPS track analyzer and activity dashboard (`weg-strasse`). It parses binary and XML activity tracks (`.fit`, `.gpx`, `.tcx`, `.kml`) compressed with `gzip`, persists activity data in IndexedDB, renders interactive Leaflet vector maps with Canvas polylines, and computes physiological and geospatial analytics plotted with `uPlot`. + +## Benchmark Steps + +1. **LoadAndParseFiles**: Fetches, decompresses (`DecompressionStream`), and parses 6 synthetic GPS activity tracks (`.gpx.gz`, `.tcx.gz`, `.fit.gz`), computes track statistics and power/heart-rate duration curves, persists tracks in IndexedDB, and renders the map and metric charts. +2. **DisplayAnalysisMetrics**: Simulates brush selection and hover interactions across telemetry charts, updating track statistics and map segments over the selected range. +3. **DisplayInsights**: Renders the Insights view with power and heart-rate duration curves, physiological training zones, aerobic decoupling / W' balance analytics, and kilometer split tables. +4. **DisplayDetails**: Renders the Details view with device/sensor metadata, lap and gear-shift breakdowns, and editing interactions. +5. **DisplayAggregateMetrics**: Renders the Aggregate view, computing multi-track sliding-window cross-correlations, comparative telemetry tables, and overlaid multi-track charts. +6. **DisplayEvolutionMetrics**: Renders the Evolution and Accumulated views, modeling acute/chronic training load (ATL/CTL/TSB) and plotting multi-metric progression and cumulative timelines. +7. **DisplayCourses**: Creates a multi-waypoint course, matches candidate tracks passing through geospatial gates, and renders course segment leaderboards and corridor comparisons. + +## Requirements + +Please always compile inside the latest `node` LTS requirement (`>=24.0.0`). + +## Building + +Run `npm install` inside `/suites-experimental/tools-gps-tracks`, then run `npm run build` to typecheck, generate deterministic compressed test tracks in `test-data/`, bundle the application and sourcemaps into `dist/`, and generate `dist/resources.txt`. + +## Develop & Run Locally + +1. Run `npm install` inside `/suites-experimental/tools-gps-tracks`. +2. Run `npm run dev` to watch, rebuild on source changes, and start a local development server for `dist/`. diff --git a/suites-experimental/tools-gps-tracks/build.js b/suites-experimental/tools-gps-tracks/build.js new file mode 100644 index 0000000000..2e7df211f9 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/build.js @@ -0,0 +1,224 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import * as esbuild from 'esbuild'; +import { readFile, writeFile, mkdir, copyFile, cp, rm, readdir } from 'fs/promises'; +import path from 'path'; +import { execSync } from 'child_process'; +import { generateResourcesFile } from '../../resources/shared/generate-resources.mjs'; + +const args = process.argv.slice(2); +const watch = args.includes('--watch'); + +const baseConfig = { + bundle: true, + minify: !watch, + sourcemap: true, + format: 'esm', + target: ['es2020'], + outdir: 'dist', + assetNames: '[name]', + outExtension: { '.js': '.mjs' }, + loader: { + '.woff2': 'file', + '.png': 'file', + '.svg': 'file', + }, +}; + +async function copyStaticAssets() { + const assets = [ + { src: 'src/index.html', dest: 'index.html' }, + { src: 'material_symbols_rounded.woff2', dest: 'material_symbols_rounded.woff2' }, + ]; + await mkdir('dist', { recursive: true }); + + for (const asset of assets) { + try { + await copyFile(asset.src, path.join('dist', asset.dest)); + console.log(`Copied ${asset.src} to dist/${asset.dest}`); + } catch (e) { + console.warn(`Could not copy ${asset.src}: ${e.message}`); + } + } + + try { + await cp('test-data', path.join('dist', 'test-data'), { recursive: true }); + console.log('Copied test-data to dist/test-data'); + } catch (e) { + console.warn(`Could not copy test-data: ${e.message}`); + } +} + +async function collectLicenses() { + const deps = ['uplot', 'fit-file-parser']; + let output = ''; + + try { + const rootLicense = await readFile('LICENSE', 'utf-8'); + output += `TOOLS-GPS-TRACKS LICENSE\n===========\n\n${rootLicense}\n\n`; + } catch (e) {} + + for (const dep of deps) { + try { + const licensePath = path.join('node_modules', dep, 'LICENSE'); + const content = await readFile(licensePath, 'utf-8'); + output += `\n\n------------------------------------------------------------------------------\n${dep.toUpperCase()} LICENSE\n------------------------------------------------------------------------------\n\n${content}\n`; + } catch (e) { + console.warn(`Could not find license for ${dep}`); + } + } + + output += `\n\n------------------------------------------------------------------------------\nBUNDLED FONT ASSETS LICENSE (MATERIAL SYMBOLS)\n------------------------------------------------------------------------------\n\n`; + output += `Assets: material_symbols_rounded.woff2 (and hashed build assets)\n`; + output += `Copyright Google LLC\n\n`; + output += `Licensed under the Apache License, Version 2.0 (the "License");\n`; + output += `you may not use these assets except in compliance with the License.\n`; + output += `You may obtain a copy of the License at\n\n`; + output += ` http://www.apache.org/licenses/LICENSE-2.0\n\n`; + output += `Unless required by applicable law or agreed to in writing, software\n`; + output += `distributed under the License is distributed on an "AS IS" BASIS,\n`; + output += `WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n`; + output += `See the License for the specific language governing permissions and\n`; + output += `limitations under the License.\n\n`; + output += `MODIFICATION AND SUBSETTING NOTICE (Apache License 2.0, Section 4(b)):\n`; + output += `These font binaries are subsetted and modified derivatives of the original\n`; + output += `Google Material Symbols font files, containing only the\n`; + output += `specific glyphs and icons utilized by the Tools-GPS-Tracks benchmark workload.\n`; + + try { + const testDataDir = path.join('dist', 'test-data'); + let testFiles = []; + try { + const manifestPath = path.join(testDataDir, 'manifest.json'); + const manifestData = JSON.parse(await readFile(manifestPath, 'utf-8')); + testFiles = Array.isArray(manifestData) ? [...manifestData, 'manifest.json'] : []; + } catch (e) { + testFiles = await readdir(testDataDir); + } + + output += `\n\n------------------------------------------------------------------------------\nBUNDLED GPS TEST TRACKS LICENSE (dist/test-data/*)\n------------------------------------------------------------------------------\n\n`; + output += `Bundled synthetic GPS test track files:\n`; + testFiles.sort().forEach((file) => { + output += `- dist/test-data/${file}\n`; + }); + output += `\nBSD 3-Clause License\n\n`; + output += `Copyright (c) 2026, Camillo Bruni / Speedometer Contributors\n\n`; + output += `Redistribution and use in source and binary forms, with or without\n`; + output += `modification, are permitted provided that the following conditions are met:\n\n`; + output += `1. Redistributions of source code must retain the above copyright notice, this\n`; + output += ` list of conditions and the following disclaimer.\n\n`; + output += `2. Redistributions in binary form must reproduce the above copyright notice,\n`; + output += ` this list of conditions and the following disclaimer in the documentation\n`; + output += ` and/or other materials provided with the distribution.\n\n`; + output += `3. Neither the name of the copyright holder nor the names of its\n`; + output += ` contributors may be used to endorse or promote products derived from\n`; + output += ` this software without specific prior written permission.\n\n`; + output += `THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\n`; + output += `AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n`; + output += `IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n`; + output += `DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n`; + output += `FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n`; + output += `DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n`; + output += `SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n`; + output += `CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n`; + output += `OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n`; + output += `OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n`; + } catch (e) { + console.warn(`Could not collect bundled GPS test track licenses: ${e.message}`); + } + + await mkdir('dist', { recursive: true }); + await writeFile(path.join('dist', 'LICENSE'), output); + console.log('Generated dist/LICENSE with NPM dependencies and bundled data assets.'); +} + +function generateTestData() { + console.log('Generating synthetic GPS track test data...'); + execSync('node scripts/generate-test-data.mjs', { stdio: 'inherit' }); +} + +async function build() { + await rm('dist', { recursive: true, force: true }); + generateTestData(); + + // 1. Bundle main app code + const ctxWeg = await esbuild.context({ + ...baseConfig, + entryPoints: ['src/app.ts'], + entryNames: 'tools-gps-tracks', + external: ['uplot', 'fit-file-parser'], + }); + + const ctxOverride = await esbuild.context({ + ...baseConfig, + entryPoints: ['src/benchmark-override.ts'], + entryNames: 'benchmark-override', + }); + + // 2. Bundle Vendors + const vendorEntryPoints = { + uplot: 'node_modules/uplot/dist/uPlot.esm.js', + 'fit-file-parser': 'src/vendor-fit.ts', + }; + + const vendorCtxs = await Promise.all( + Object.entries(vendorEntryPoints).map(([name, entry]) => + esbuild.context({ + ...baseConfig, + entryPoints: [entry], + entryNames: name, + }), + ), + ); + + // 3. Bundle CSS + const ctxCss = await esbuild.context({ + ...baseConfig, + entryPoints: ['src/css/styles.css'], + entryNames: 'styles', + }); + + if (watch) { + await copyStaticAssets(); + await Promise.all([ + ctxWeg.watch(), + ctxOverride.watch(), + ctxCss.watch(), + ...vendorCtxs.map((c) => c.watch()), + ]); + await generateResourcesFile(path.join(import.meta.dirname, 'dist')); + + const { host, port } = await ctxWeg.serve({ + servedir: 'dist', + fallback: 'index.html', + }); + console.log(`Development server: http://${host}:${port}`); + } else { + await Promise.all([ + ctxWeg.rebuild(), + ctxOverride.rebuild(), + ctxCss.rebuild(), + ...vendorCtxs.map((c) => c.rebuild()), + ]); + + await copyStaticAssets(); + await collectLicenses(); + + await Promise.all([ + ctxWeg.dispose(), + ctxOverride.dispose(), + ctxCss.dispose(), + ...vendorCtxs.map((c) => c.dispose()), + ]); + + await generateResourcesFile(path.join(import.meta.dirname, 'dist')); + console.log('Build complete. Production files and resources.txt are in dist/'); + } +} + +build().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/suites-experimental/tools-gps-tracks/dist/LICENSE b/suites-experimental/tools-gps-tracks/dist/LICENSE new file mode 100644 index 0000000000..ab7852cb57 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/LICENSE @@ -0,0 +1,158 @@ +TOOLS-GPS-TRACKS LICENSE +=========== + +BSD 3-Clause License + +Copyright (c) 2026, Camillo Bruni + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + + +------------------------------------------------------------------------------ +UPLOT LICENSE +------------------------------------------------------------------------------ + +The MIT License (MIT) + +Copyright (c) 2022 Leon Sorokin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +------------------------------------------------------------------------------ +FIT-FILE-PARSER LICENSE +------------------------------------------------------------------------------ + +The MIT License (MIT) + +Copyright (c) 2015 Pierre Jacquier +http://pierrejacquier.com | @pierremtb + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + + +------------------------------------------------------------------------------ +BUNDLED FONT ASSETS LICENSE (MATERIAL SYMBOLS) +------------------------------------------------------------------------------ + +Assets: material_symbols_rounded.woff2 (and hashed build assets) +Copyright Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use these assets except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +MODIFICATION AND SUBSETTING NOTICE (Apache License 2.0, Section 4(b)): +These font binaries are subsetted and modified derivatives of the original +Google Material Symbols font files, containing only the +specific glyphs and icons utilized by the Tools-GPS-Tracks benchmark workload. + + +------------------------------------------------------------------------------ +BUNDLED GPS TEST TRACKS LICENSE (dist/test-data/*) +------------------------------------------------------------------------------ + +Bundled synthetic GPS test track files: +- dist/test-data/activity_1_alps_stage.gpx.gz +- dist/test-data/activity_2_forest_mtb.gpx.gz +- dist/test-data/activity_3_road_race.tcx.gz +- dist/test-data/activity_4_intervals.tcx.gz +- dist/test-data/activity_5_grand_tour.fit.gz +- dist/test-data/activity_6_weekend_ride.fit.gz +- dist/test-data/manifest.json + +BSD 3-Clause License + +Copyright (c) 2026, Camillo Bruni / Speedometer Contributors + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs new file mode 100644 index 0000000000..bbaea51084 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs @@ -0,0 +1,2 @@ +var o=539363104;window.__resetBenchmarkSeed=()=>{o=539363104};Math.random=()=>{let e=o+=1831565813;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296};window.requestAnimationFrame=e=>window.setTimeout(()=>e(performance.now()),0);window.cancelAnimationFrame=e=>{window.clearTimeout(e)};try{Object.defineProperty(window,"devicePixelRatio",{get:()=>1,configurable:!0})}catch{}try{Object.defineProperty(navigator,"language",{get:()=>"en-US",configurable:!0}),Object.defineProperty(navigator,"languages",{get:()=>["en-US"],configurable:!0})}catch{}typeof CanvasRenderingContext2D<"u"&&(CanvasRenderingContext2D.prototype.measureText=function(e){let n=this.font||"10px sans-serif",i=n.match(/(\d+(?:\.\d+)?)px/),t=i?parseFloat(i[1]):10,r=/\bbold\b|\b[6-9]00\b/i.test(n),c=t*(r?.6:.55),a=String(e).length*c;return{width:a,actualBoundingBoxLeft:0,actualBoundingBoxRight:a,actualBoundingBoxAscent:t*.8,actualBoundingBoxDescent:t*.2,fontBoundingBoxAscent:t*.8,fontBoundingBoxDescent:t*.2,emHeightAscent:t*.8,emHeightDescent:t*.2,hangingBaseline:t*.8,alphabeticBaseline:0,ideographicBaseline:-t*.2}}); +//# sourceMappingURL=benchmark-override.mjs.map diff --git a/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map new file mode 100644 index 0000000000..979aa8e1f7 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/benchmark-override.ts"], + "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// Deterministic PRNG (Mulberry32) for reproducible benchmark runs.\nlet seed = 0x20260720;\n(window as any).__resetBenchmarkSeed = (): void => {\n seed = 0x20260720;\n};\nMath.random = (): number => {\n let t = (seed += 0x6d2b79f5);\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n};\n\nwindow.requestAnimationFrame = (callback: FrameRequestCallback): number => {\n return window.setTimeout(() => callback(performance.now()), 0);\n};\n\nwindow.cancelAnimationFrame = (id: number): void => {\n window.clearTimeout(id);\n};\n\n// Normalize devicePixelRatio to 1 so uPlot and canvas rendering execute\n// identical code paths (e.g. decimation thresholds and canvas dimensions) across browsers.\ntry {\n Object.defineProperty(window, 'devicePixelRatio', {\n get: () => 1,\n configurable: true,\n });\n} catch (_) {}\n\n// Normalize navigator.language to en-US so Intl.NumberFormat / locale formatters\n// produce identical strings across browsers and OS locales.\ntry {\n Object.defineProperty(navigator, 'language', {\n get: () => 'en-US',\n configurable: true,\n });\n Object.defineProperty(navigator, 'languages', {\n get: () => ['en-US'],\n configurable: true,\n });\n} catch (_) {}\n\n// Normalize CanvasRenderingContext2D.prototype.measureText so canvas layout calculations\n// (histogram padding, axis label bounding boxes, cursor pills) do not vary with OS/browser\n// system-ui font glyph metrics.\nif (typeof CanvasRenderingContext2D !== 'undefined') {\n CanvasRenderingContext2D.prototype.measureText = function (text: string): TextMetrics {\n const fontStr = this.font || '10px sans-serif';\n const sizeMatch = fontStr.match(/(\\d+(?:\\.\\d+)?)px/);\n const fontSize = sizeMatch ? parseFloat(sizeMatch[1]) : 10;\n const isBold = /\\bbold\\b|\\b[6-9]00\\b/i.test(fontStr);\n const charWidth = fontSize * (isBold ? 0.6 : 0.55);\n const width = String(text).length * charWidth;\n return {\n width,\n actualBoundingBoxLeft: 0,\n actualBoundingBoxRight: width,\n actualBoundingBoxAscent: fontSize * 0.8,\n actualBoundingBoxDescent: fontSize * 0.2,\n fontBoundingBoxAscent: fontSize * 0.8,\n fontBoundingBoxDescent: fontSize * 0.2,\n emHeightAscent: fontSize * 0.8,\n emHeightDescent: fontSize * 0.2,\n hangingBaseline: fontSize * 0.8,\n alphabeticBaseline: 0,\n ideographicBaseline: -fontSize * 0.2,\n } as TextMetrics;\n };\n}\n"], + "mappings": "AAOA,IAAIA,EAAO,UACV,OAAe,qBAAuB,IAAY,CACjDA,EAAO,SACT,EACA,KAAK,OAAS,IAAc,CAC1B,IAAIC,EAAKD,GAAQ,WACjB,OAAAC,EAAI,KAAK,KAAKA,EAAKA,IAAM,GAAKA,EAAI,CAAC,EACnCA,GAAKA,EAAI,KAAK,KAAKA,EAAKA,IAAM,EAAIA,EAAI,EAAE,IAC/BA,EAAKA,IAAM,MAAS,GAAK,UACpC,EAEA,OAAO,sBAAyBC,GACvB,OAAO,WAAW,IAAMA,EAAS,YAAY,IAAI,CAAC,EAAG,CAAC,EAG/D,OAAO,qBAAwBC,GAAqB,CAClD,OAAO,aAAaA,CAAE,CACxB,EAIA,GAAI,CACF,OAAO,eAAe,OAAQ,mBAAoB,CAChD,IAAK,IAAM,EACX,aAAc,EAChB,CAAC,CACH,MAAY,CAAC,CAIb,GAAI,CACF,OAAO,eAAe,UAAW,WAAY,CAC3C,IAAK,IAAM,QACX,aAAc,EAChB,CAAC,EACD,OAAO,eAAe,UAAW,YAAa,CAC5C,IAAK,IAAM,CAAC,OAAO,EACnB,aAAc,EAChB,CAAC,CACH,MAAY,CAAC,CAKT,OAAO,yBAA6B,MACtC,yBAAyB,UAAU,YAAc,SAAUC,EAA2B,CACpF,IAAMC,EAAU,KAAK,MAAQ,kBACvBC,EAAYD,EAAQ,MAAM,mBAAmB,EAC7CE,EAAWD,EAAY,WAAWA,EAAU,CAAC,CAAC,EAAI,GAClDE,EAAS,wBAAwB,KAAKH,CAAO,EAC7CI,EAAYF,GAAYC,EAAS,GAAM,KACvCE,EAAQ,OAAON,CAAI,EAAE,OAASK,EACpC,MAAO,CACL,MAAAC,EACA,sBAAuB,EACvB,uBAAwBA,EACxB,wBAAyBH,EAAW,GACpC,yBAA0BA,EAAW,GACrC,sBAAuBA,EAAW,GAClC,uBAAwBA,EAAW,GACnC,eAAgBA,EAAW,GAC3B,gBAAiBA,EAAW,GAC5B,gBAAiBA,EAAW,GAC5B,mBAAoB,EACpB,oBAAqB,CAACA,EAAW,EACnC,CACF", + "names": ["seed", "t", "callback", "id", "text", "fontStr", "sizeMatch", "fontSize", "isBold", "charWidth", "width"] +} diff --git a/suites-experimental/tools-gps-tracks/dist/fit-file-parser.mjs b/suites-experimental/tools-gps-tracks/dist/fit-file-parser.mjs new file mode 100644 index 0000000000..9d5189e66e --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/fit-file-parser.mjs @@ -0,0 +1,15 @@ +var ot=Object.create;var Ie=Object.defineProperty;var ut=Object.getOwnPropertyDescriptor;var ct=Object.getOwnPropertyNames;var ft=Object.getPrototypeOf,dt=Object.prototype.hasOwnProperty;var le=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports);var pt=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of ct(e))!dt.call(i,s)&&s!==t&&Ie(i,s,{get:()=>e[s],enumerable:!(n=ut(e,s))||n.enumerable});return i};var gt=(i,e,t)=>(t=i!=null?ot(ft(i)):{},pt(e||!i||!i.__esModule?Ie(t,"default",{value:i,enumerable:!0}):t,i));var je=le(K=>{"use strict";K.byteLength=mt;K.toByteArray=wt;K.fromByteArray=xt;var z=[],B=[],ht=typeof Uint8Array<"u"?Uint8Array:Array,ae="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(M=0,Ue=ae.length;M0)throw new Error("Invalid string. Length must be a multiple of 4");var t=i.indexOf("=");t===-1&&(t=e);var n=t===e?0:4-t%4;return[t,n]}function mt(i){var e=Ae(i),t=e[0],n=e[1];return(t+n)*3/4-n}function yt(i,e,t){return(e+t)*3/4-t}function wt(i){var e,t=Ae(i),n=t[0],s=t[1],_=new ht(yt(i,n,s)),l=0,r=s>0?n-4:n,o;for(o=0;o>16&255,_[l++]=e>>8&255,_[l++]=e&255;return s===2&&(e=B[i.charCodeAt(o)]<<2|B[i.charCodeAt(o+1)]>>4,_[l++]=e&255),s===1&&(e=B[i.charCodeAt(o)]<<10|B[i.charCodeAt(o+1)]<<4|B[i.charCodeAt(o+2)]>>2,_[l++]=e>>8&255,_[l++]=e&255),_}function bt(i){return z[i>>18&63]+z[i>>12&63]+z[i>>6&63]+z[i&63]}function kt(i,e,t){for(var n,s=[],_=e;_r?r:l+_));return n===1?(e=i[t-1],s.push(z[e>>2]+z[e<<4&63]+"==")):n===2&&(e=(i[t-2]<<8)+i[t-1],s.push(z[e>>10]+z[e>>4&63]+z[e<<2&63]+"=")),s.join("")}});var Te=le(re=>{re.read=function(i,e,t,n,s){var _,l,r=s*8-n-1,o=(1<>1,u=-7,c=t?s-1:0,g=t?-1:1,f=i[e+c];for(c+=g,_=f&(1<<-u)-1,f>>=-u,u+=r;u>0;_=_*256+i[e+c],c+=g,u-=8);for(l=_&(1<<-u)-1,_>>=-u,u+=n;u>0;l=l*256+i[e+c],c+=g,u-=8);if(_===0)_=1-d;else{if(_===o)return l?NaN:(f?-1:1)*(1/0);l=l+Math.pow(2,n),_=_-d}return(f?-1:1)*l*Math.pow(2,_-n)};re.write=function(i,e,t,n,s,_){var l,r,o,d=_*8-s-1,u=(1<>1,g=s===23?Math.pow(2,-24)-Math.pow(2,-77):0,f=n?0:_-1,x=n?1:-1,h=e<0||e===0&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(r=isNaN(e)?1:0,l=u):(l=Math.floor(Math.log(e)/Math.LN2),e*(o=Math.pow(2,-l))<1&&(l--,o*=2),l+c>=1?e+=g/o:e+=g*Math.pow(2,1-c),e*o>=2&&(l++,o/=2),l+c>=u?(r=0,l=u):l+c>=1?(r=(e*o-1)*Math.pow(2,s),l=l+c):(r=e*Math.pow(2,c-1)*Math.pow(2,s),l=0));s>=8;i[t+f]=r&255,f+=x,r/=256,s-=8);for(l=l<0;i[t+f]=l&255,f+=x,l/=256,d-=8);i[t+f-x]|=h*128}});var Xe=le(V=>{"use strict";var oe=je(),P=Te(),Ce=typeof Symbol=="function"&&typeof Symbol.for=="function"?Symbol.for("nodejs.util.inspect.custom"):null;V.Buffer=a;V.SlowBuffer=qt;V.INSPECT_MAX_BYTES=50;var Z=2147483647;V.kMaxLength=Z;a.TYPED_ARRAY_SUPPORT=vt();!a.TYPED_ARRAY_SUPPORT&&typeof console<"u"&&typeof console.error=="function"&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function vt(){try{let i=new Uint8Array(1),e={foo:function(){return 42}};return Object.setPrototypeOf(e,Uint8Array.prototype),Object.setPrototypeOf(i,e),i.foo()===42}catch{return!1}}Object.defineProperty(a.prototype,"parent",{enumerable:!0,get:function(){if(a.isBuffer(this))return this.buffer}});Object.defineProperty(a.prototype,"offset",{enumerable:!0,get:function(){if(a.isBuffer(this))return this.byteOffset}});function T(i){if(i>Z)throw new RangeError('The value "'+i+'" is invalid for option "size"');let e=new Uint8Array(i);return Object.setPrototypeOf(e,a.prototype),e}function a(i,e,t){if(typeof i=="number"){if(typeof e=="string")throw new TypeError('The "string" argument must be of type string. Received type number');return de(i)}return Le(i,e,t)}a.poolSize=8192;function Le(i,e,t){if(typeof i=="string")return Bt(i,e);if(ArrayBuffer.isView(i))return Et(i);if(i==null)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof i);if(q(i,ArrayBuffer)||i&&q(i.buffer,ArrayBuffer)||typeof SharedArrayBuffer<"u"&&(q(i,SharedArrayBuffer)||i&&q(i.buffer,SharedArrayBuffer)))return ce(i,e,t);if(typeof i=="number")throw new TypeError('The "value" argument must not be of type number. Received type number');let n=i.valueOf&&i.valueOf();if(n!=null&&n!==i)return a.from(n,e,t);let s=zt(i);if(s)return s;if(typeof Symbol<"u"&&Symbol.toPrimitive!=null&&typeof i[Symbol.toPrimitive]=="function")return a.from(i[Symbol.toPrimitive]("string"),e,t);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof i)}a.from=function(i,e,t){return Le(i,e,t)};Object.setPrototypeOf(a.prototype,Uint8Array.prototype);Object.setPrototypeOf(a,Uint8Array);function Me(i){if(typeof i!="number")throw new TypeError('"size" argument must be of type number');if(i<0)throw new RangeError('The value "'+i+'" is invalid for option "size"')}function Ft(i,e,t){return Me(i),i<=0?T(i):e!==void 0?typeof t=="string"?T(i).fill(e,t):T(i).fill(e):T(i)}a.alloc=function(i,e,t){return Ft(i,e,t)};function de(i){return Me(i),T(i<0?0:pe(i)|0)}a.allocUnsafe=function(i){return de(i)};a.allocUnsafeSlow=function(i){return de(i)};function Bt(i,e){if((typeof e!="string"||e==="")&&(e="utf8"),!a.isEncoding(e))throw new TypeError("Unknown encoding: "+e);let t=Ne(i,e)|0,n=T(t),s=n.write(i,e);return s!==t&&(n=n.slice(0,s)),n}function ue(i){let e=i.length<0?0:pe(i.length)|0,t=T(e);for(let n=0;n=Z)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+Z.toString(16)+" bytes");return i|0}function qt(i){return+i!=i&&(i=0),a.alloc(+i)}a.isBuffer=function(e){return e!=null&&e._isBuffer===!0&&e!==a.prototype};a.compare=function(e,t){if(q(e,Uint8Array)&&(e=a.from(e,e.offset,e.byteLength)),q(t,Uint8Array)&&(t=a.from(t,t.offset,t.byteLength)),!a.isBuffer(e)||!a.isBuffer(t))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(e===t)return 0;let n=e.length,s=t.length;for(let _=0,l=Math.min(n,s);_s.length?(a.isBuffer(l)||(l=a.from(l)),l.copy(s,_)):Uint8Array.prototype.set.call(s,l,_);else if(a.isBuffer(l))l.copy(s,_);else throw new TypeError('"list" argument must be an Array of Buffers');_+=l.length}return s};function Ne(i,e){if(a.isBuffer(i))return i.length;if(ArrayBuffer.isView(i)||q(i,ArrayBuffer))return i.byteLength;if(typeof i!="string")throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof i);let t=i.length,n=arguments.length>2&&arguments[2]===!0;if(!n&&t===0)return 0;let s=!1;for(;;)switch(e){case"ascii":case"latin1":case"binary":return t;case"utf8":case"utf-8":return fe(i).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return t*2;case"hex":return t>>>1;case"base64":return Je(i).length;default:if(s)return n?-1:fe(i).length;e=(""+e).toLowerCase(),s=!0}}a.byteLength=Ne;function It(i,e,t){let n=!1;if((e===void 0||e<0)&&(e=0),e>this.length||((t===void 0||t>this.length)&&(t=this.length),t<=0)||(t>>>=0,e>>>=0,t<=e))return"";for(i||(i="utf8");;)switch(i){case"hex":return Mt(this,e,t);case"utf8":case"utf-8":return $e(this,e,t);case"ascii":return Dt(this,e,t);case"latin1":case"binary":return Lt(this,e,t);case"base64":return Rt(this,e,t);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Nt(this,e,t);default:if(n)throw new TypeError("Unknown encoding: "+i);i=(i+"").toLowerCase(),n=!0}}a.prototype._isBuffer=!0;function N(i,e,t){let n=i[e];i[e]=i[t],i[t]=n}a.prototype.swap16=function(){let e=this.length;if(e%2!==0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let t=0;tt&&(e+=" ... "),""};Ce&&(a.prototype[Ce]=a.prototype.inspect);a.prototype.compare=function(e,t,n,s,_){if(q(e,Uint8Array)&&(e=a.from(e,e.offset,e.byteLength)),!a.isBuffer(e))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof e);if(t===void 0&&(t=0),n===void 0&&(n=e?e.length:0),s===void 0&&(s=0),_===void 0&&(_=this.length),t<0||n>e.length||s<0||_>this.length)throw new RangeError("out of range index");if(s>=_&&t>=n)return 0;if(s>=_)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,s>>>=0,_>>>=0,this===e)return 0;let l=_-s,r=n-t,o=Math.min(l,r),d=this.slice(s,_),u=e.slice(t,n);for(let c=0;c2147483647?t=2147483647:t<-2147483648&&(t=-2147483648),t=+t,he(t)&&(t=s?0:i.length-1),t<0&&(t=i.length+t),t>=i.length){if(s)return-1;t=i.length-1}else if(t<0)if(s)t=0;else return-1;if(typeof e=="string"&&(e=a.from(e,n)),a.isBuffer(e))return e.length===0?-1:Re(i,e,t,n,s);if(typeof e=="number")return e=e&255,typeof Uint8Array.prototype.indexOf=="function"?s?Uint8Array.prototype.indexOf.call(i,e,t):Uint8Array.prototype.lastIndexOf.call(i,e,t):Re(i,[e],t,n,s);throw new TypeError("val must be string, number or Buffer")}function Re(i,e,t,n,s){let _=1,l=i.length,r=e.length;if(n!==void 0&&(n=String(n).toLowerCase(),n==="ucs2"||n==="ucs-2"||n==="utf16le"||n==="utf-16le")){if(i.length<2||e.length<2)return-1;_=2,l/=2,r/=2,t/=2}function o(u,c){return _===1?u[c]:u.readUInt16BE(c*_)}let d;if(s){let u=-1;for(d=t;dl&&(t=l-r),d=t;d>=0;d--){let u=!0;for(let c=0;cs&&(n=s)):n=s;let _=e.length;n>_/2&&(n=_/2);let l;for(l=0;l>>0,isFinite(n)?(n=n>>>0,s===void 0&&(s="utf8")):(s=n,n=void 0);else throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");let _=this.length-t;if((n===void 0||n>_)&&(n=_),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");s||(s="utf8");let l=!1;for(;;)switch(s){case"hex":return Ut(this,e,t,n);case"utf8":case"utf-8":return At(this,e,t,n);case"ascii":case"latin1":case"binary":return jt(this,e,t,n);case"base64":return Tt(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Ct(this,e,t,n);default:if(l)throw new TypeError("Unknown encoding: "+s);s=(""+s).toLowerCase(),l=!0}};a.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function Rt(i,e,t){return e===0&&t===i.length?oe.fromByteArray(i):oe.fromByteArray(i.slice(e,t))}function $e(i,e,t){t=Math.min(i.length,t);let n=[],s=e;for(;s239?4:_>223?3:_>191?2:1;if(s+r<=t){let o,d,u,c;switch(r){case 1:_<128&&(l=_);break;case 2:o=i[s+1],(o&192)===128&&(c=(_&31)<<6|o&63,c>127&&(l=c));break;case 3:o=i[s+1],d=i[s+2],(o&192)===128&&(d&192)===128&&(c=(_&15)<<12|(o&63)<<6|d&63,c>2047&&(c<55296||c>57343)&&(l=c));break;case 4:o=i[s+1],d=i[s+2],u=i[s+3],(o&192)===128&&(d&192)===128&&(u&192)===128&&(c=(_&15)<<18|(o&63)<<12|(d&63)<<6|u&63,c>65535&&c<1114112&&(l=c))}}l===null?(l=65533,r=1):l>65535&&(l-=65536,n.push(l>>>10&1023|55296),l=56320|l&1023),n.push(l),s+=r}return St(n)}var Se=4096;function St(i){let e=i.length;if(e<=Se)return String.fromCharCode.apply(String,i);let t="",n=0;for(;nn)&&(t=n);let s="";for(let _=e;_n&&(e=n),t<0?(t+=n,t<0&&(t=0)):t>n&&(t=n),tt)throw new RangeError("Trying to access beyond buffer length")}a.prototype.readUintLE=a.prototype.readUIntLE=function(e,t,n){e=e>>>0,t=t>>>0,n||b(e,t,this.length);let s=this[e],_=1,l=0;for(;++l>>0,t=t>>>0,n||b(e,t,this.length);let s=this[e+--t],_=1;for(;t>0&&(_*=256);)s+=this[e+--t]*_;return s};a.prototype.readUint8=a.prototype.readUInt8=function(e,t){return e=e>>>0,t||b(e,1,this.length),this[e]};a.prototype.readUint16LE=a.prototype.readUInt16LE=function(e,t){return e=e>>>0,t||b(e,2,this.length),this[e]|this[e+1]<<8};a.prototype.readUint16BE=a.prototype.readUInt16BE=function(e,t){return e=e>>>0,t||b(e,2,this.length),this[e]<<8|this[e+1]};a.prototype.readUint32LE=a.prototype.readUInt32LE=function(e,t){return e=e>>>0,t||b(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+this[e+3]*16777216};a.prototype.readUint32BE=a.prototype.readUInt32BE=function(e,t){return e=e>>>0,t||b(e,4,this.length),this[e]*16777216+(this[e+1]<<16|this[e+2]<<8|this[e+3])};a.prototype.readBigUInt64LE=C(function(e){e=e>>>0,H(e,"offset");let t=this[e],n=this[e+7];(t===void 0||n===void 0)&&Y(e,this.length-8);let s=t+this[++e]*2**8+this[++e]*2**16+this[++e]*2**24,_=this[++e]+this[++e]*2**8+this[++e]*2**16+n*2**24;return BigInt(s)+(BigInt(_)<>>0,H(e,"offset");let t=this[e],n=this[e+7];(t===void 0||n===void 0)&&Y(e,this.length-8);let s=t*2**24+this[++e]*2**16+this[++e]*2**8+this[++e],_=this[++e]*2**24+this[++e]*2**16+this[++e]*2**8+n;return(BigInt(s)<>>0,t=t>>>0,n||b(e,t,this.length);let s=this[e],_=1,l=0;for(;++l=_&&(s-=Math.pow(2,8*t)),s};a.prototype.readIntBE=function(e,t,n){e=e>>>0,t=t>>>0,n||b(e,t,this.length);let s=t,_=1,l=this[e+--s];for(;s>0&&(_*=256);)l+=this[e+--s]*_;return _*=128,l>=_&&(l-=Math.pow(2,8*t)),l};a.prototype.readInt8=function(e,t){return e=e>>>0,t||b(e,1,this.length),this[e]&128?(255-this[e]+1)*-1:this[e]};a.prototype.readInt16LE=function(e,t){e=e>>>0,t||b(e,2,this.length);let n=this[e]|this[e+1]<<8;return n&32768?n|4294901760:n};a.prototype.readInt16BE=function(e,t){e=e>>>0,t||b(e,2,this.length);let n=this[e+1]|this[e]<<8;return n&32768?n|4294901760:n};a.prototype.readInt32LE=function(e,t){return e=e>>>0,t||b(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24};a.prototype.readInt32BE=function(e,t){return e=e>>>0,t||b(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]};a.prototype.readBigInt64LE=C(function(e){e=e>>>0,H(e,"offset");let t=this[e],n=this[e+7];(t===void 0||n===void 0)&&Y(e,this.length-8);let s=this[e+4]+this[e+5]*2**8+this[e+6]*2**16+(n<<24);return(BigInt(s)<>>0,H(e,"offset");let t=this[e],n=this[e+7];(t===void 0||n===void 0)&&Y(e,this.length-8);let s=(t<<24)+this[++e]*2**16+this[++e]*2**8+this[++e];return(BigInt(s)<>>0,t||b(e,4,this.length),P.read(this,e,!0,23,4)};a.prototype.readFloatBE=function(e,t){return e=e>>>0,t||b(e,4,this.length),P.read(this,e,!1,23,4)};a.prototype.readDoubleLE=function(e,t){return e=e>>>0,t||b(e,8,this.length),P.read(this,e,!0,52,8)};a.prototype.readDoubleBE=function(e,t){return e=e>>>0,t||b(e,8,this.length),P.read(this,e,!1,52,8)};function k(i,e,t,n,s,_){if(!a.isBuffer(i))throw new TypeError('"buffer" argument must be a Buffer instance');if(e>s||e<_)throw new RangeError('"value" argument is out of bounds');if(t+n>i.length)throw new RangeError("Index out of range")}a.prototype.writeUintLE=a.prototype.writeUIntLE=function(e,t,n,s){if(e=+e,t=t>>>0,n=n>>>0,!s){let r=Math.pow(2,8*n)-1;k(this,e,t,n,r,0)}let _=1,l=0;for(this[t]=e&255;++l>>0,n=n>>>0,!s){let r=Math.pow(2,8*n)-1;k(this,e,t,n,r,0)}let _=n-1,l=1;for(this[t+_]=e&255;--_>=0&&(l*=256);)this[t+_]=e/l&255;return t+n};a.prototype.writeUint8=a.prototype.writeUInt8=function(e,t,n){return e=+e,t=t>>>0,n||k(this,e,t,1,255,0),this[t]=e&255,t+1};a.prototype.writeUint16LE=a.prototype.writeUInt16LE=function(e,t,n){return e=+e,t=t>>>0,n||k(this,e,t,2,65535,0),this[t]=e&255,this[t+1]=e>>>8,t+2};a.prototype.writeUint16BE=a.prototype.writeUInt16BE=function(e,t,n){return e=+e,t=t>>>0,n||k(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=e&255,t+2};a.prototype.writeUint32LE=a.prototype.writeUInt32LE=function(e,t,n){return e=+e,t=t>>>0,n||k(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=e&255,t+4};a.prototype.writeUint32BE=a.prototype.writeUInt32BE=function(e,t,n){return e=+e,t=t>>>0,n||k(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=e&255,t+4};function Pe(i,e,t,n,s){Ye(e,n,s,i,t,7);let _=Number(e&BigInt(4294967295));i[t++]=_,_=_>>8,i[t++]=_,_=_>>8,i[t++]=_,_=_>>8,i[t++]=_;let l=Number(e>>BigInt(32)&BigInt(4294967295));return i[t++]=l,l=l>>8,i[t++]=l,l=l>>8,i[t++]=l,l=l>>8,i[t++]=l,t}function He(i,e,t,n,s){Ye(e,n,s,i,t,7);let _=Number(e&BigInt(4294967295));i[t+7]=_,_=_>>8,i[t+6]=_,_=_>>8,i[t+5]=_,_=_>>8,i[t+4]=_;let l=Number(e>>BigInt(32)&BigInt(4294967295));return i[t+3]=l,l=l>>8,i[t+2]=l,l=l>>8,i[t+1]=l,l=l>>8,i[t]=l,t+8}a.prototype.writeBigUInt64LE=C(function(e,t=0){return Pe(this,e,t,BigInt(0),BigInt("0xffffffffffffffff"))});a.prototype.writeBigUInt64BE=C(function(e,t=0){return He(this,e,t,BigInt(0),BigInt("0xffffffffffffffff"))});a.prototype.writeIntLE=function(e,t,n,s){if(e=+e,t=t>>>0,!s){let o=Math.pow(2,8*n-1);k(this,e,t,n,o-1,-o)}let _=0,l=1,r=0;for(this[t]=e&255;++_>0)-r&255;return t+n};a.prototype.writeIntBE=function(e,t,n,s){if(e=+e,t=t>>>0,!s){let o=Math.pow(2,8*n-1);k(this,e,t,n,o-1,-o)}let _=n-1,l=1,r=0;for(this[t+_]=e&255;--_>=0&&(l*=256);)e<0&&r===0&&this[t+_+1]!==0&&(r=1),this[t+_]=(e/l>>0)-r&255;return t+n};a.prototype.writeInt8=function(e,t,n){return e=+e,t=t>>>0,n||k(this,e,t,1,127,-128),e<0&&(e=255+e+1),this[t]=e&255,t+1};a.prototype.writeInt16LE=function(e,t,n){return e=+e,t=t>>>0,n||k(this,e,t,2,32767,-32768),this[t]=e&255,this[t+1]=e>>>8,t+2};a.prototype.writeInt16BE=function(e,t,n){return e=+e,t=t>>>0,n||k(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=e&255,t+2};a.prototype.writeInt32LE=function(e,t,n){return e=+e,t=t>>>0,n||k(this,e,t,4,2147483647,-2147483648),this[t]=e&255,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4};a.prototype.writeInt32BE=function(e,t,n){return e=+e,t=t>>>0,n||k(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=e&255,t+4};a.prototype.writeBigInt64LE=C(function(e,t=0){return Pe(this,e,t,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))});a.prototype.writeBigInt64BE=C(function(e,t=0){return He(this,e,t,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))});function Ve(i,e,t,n,s,_){if(t+n>i.length)throw new RangeError("Index out of range");if(t<0)throw new RangeError("Index out of range")}function Ge(i,e,t,n,s){return e=+e,t=t>>>0,s||Ve(i,e,t,4,34028234663852886e22,-34028234663852886e22),P.write(i,e,t,n,23,4),t+4}a.prototype.writeFloatLE=function(e,t,n){return Ge(this,e,t,!0,n)};a.prototype.writeFloatBE=function(e,t,n){return Ge(this,e,t,!1,n)};function We(i,e,t,n,s){return e=+e,t=t>>>0,s||Ve(i,e,t,8,17976931348623157e292,-17976931348623157e292),P.write(i,e,t,n,52,8),t+8}a.prototype.writeDoubleLE=function(e,t,n){return We(this,e,t,!0,n)};a.prototype.writeDoubleBE=function(e,t,n){return We(this,e,t,!1,n)};a.prototype.copy=function(e,t,n,s){if(!a.isBuffer(e))throw new TypeError("argument should be a Buffer");if(n||(n=0),!s&&s!==0&&(s=this.length),t>=e.length&&(t=e.length),t||(t=0),s>0&&s=this.length)throw new RangeError("Index out of range");if(s<0)throw new RangeError("sourceEnd out of bounds");s>this.length&&(s=this.length),e.length-t>>0,n=n===void 0?this.length:n>>>0,e||(e=0);let _;if(typeof e=="number")for(_=t;_2**32?s=De(String(t)):typeof t=="bigint"&&(s=String(t),(t>BigInt(2)**BigInt(32)||t<-(BigInt(2)**BigInt(32)))&&(s=De(s)),s+="n"),n+=` It must be ${e}. Received ${s}`,n},RangeError);function De(i){let e="",t=i.length,n=i[0]==="-"?1:0;for(;t>=n+4;t-=3)e=`_${i.slice(t-3,t)}${e}`;return`${i.slice(0,t)}${e}`}function Ot(i,e,t){H(e,"offset"),(i[e]===void 0||i[e+t]===void 0)&&Y(e,i.length-(t+1))}function Ye(i,e,t,n,s,_){if(i>t||i3?e===0||e===BigInt(0)?r=`>= 0${l} and < 2${l} ** ${(_+1)*8}${l}`:r=`>= -(2${l} ** ${(_+1)*8-1}${l}) and < 2 ** ${(_+1)*8-1}${l}`:r=`>= ${e}${l} and <= ${t}${l}`,new $.ERR_OUT_OF_RANGE("value",r,i)}Ot(n,s,_)}function H(i,e){if(typeof i!="number")throw new $.ERR_INVALID_ARG_TYPE(e,"number",i)}function Y(i,e,t){throw Math.floor(i)!==i?(H(i,t),new $.ERR_OUT_OF_RANGE(t||"offset","an integer",i)):e<0?new $.ERR_BUFFER_OUT_OF_BOUNDS:new $.ERR_OUT_OF_RANGE(t||"offset",`>= ${t?1:0} and <= ${e}`,i)}var $t=/[^+/0-9A-Za-z-_]/g;function Pt(i){if(i=i.split("=")[0],i=i.trim().replace($t,""),i.length<2)return"";for(;i.length%4!==0;)i=i+"=";return i}function fe(i,e){e=e||1/0;let t,n=i.length,s=null,_=[];for(let l=0;l55295&&t<57344){if(!s){if(t>56319){(e-=3)>-1&&_.push(239,191,189);continue}else if(l+1===n){(e-=3)>-1&&_.push(239,191,189);continue}s=t;continue}if(t<56320){(e-=3)>-1&&_.push(239,191,189),s=t;continue}t=(s-55296<<10|t-56320)+65536}else s&&(e-=3)>-1&&_.push(239,191,189);if(s=null,t<128){if((e-=1)<0)break;_.push(t)}else if(t<2048){if((e-=2)<0)break;_.push(t>>6|192,t&63|128)}else if(t<65536){if((e-=3)<0)break;_.push(t>>12|224,t>>6&63|128,t&63|128)}else if(t<1114112){if((e-=4)<0)break;_.push(t>>18|240,t>>12&63|128,t>>6&63|128,t&63|128)}else throw new Error("Invalid code point")}return _}function Ht(i){let e=[];for(let t=0;t>8,s=t%256,_.push(s),_.push(n);return _}function Je(i){return oe.toByteArray(Pt(i))}function Q(i,e,t,n){let s;for(s=0;s=e.length||s>=i.length);++s)e[s+t]=i[s];return s}function q(i,e){return i instanceof e||i!=null&&i.constructor!=null&&i.constructor.name!=null&&i.constructor.name===e.name}function he(i){return i!==i}var Gt=function(){let i="0123456789abcdef",e=new Array(256);for(let t=0;t<16;++t){let n=t*16;for(let s=0;s<16;++s)e[n+s]=i[t]+i[s]}return e}();function C(i){return typeof BigInt>"u"?Wt:i}function Wt(){throw new Error("BigInt not supported")}});var et=gt(Xe(),1);var Yt=14.5037738,w={scConst:180/Math.pow(2,31),options:{speedUnits:{"m/s":{multiplier:1,offset:0},mph:{multiplier:3600/1609.344,offset:0},"km/h":{multiplier:3600/1e3,offset:0}},lengthUnits:{m:{multiplier:1,offset:0},mi:{multiplier:1/1609.344,offset:0},km:{multiplier:1/1e3,offset:0}},temperatureUnits:{"\xB0C":{multiplier:1,offset:0},kelvin:{multiplier:1,offset:-273.15},fahrenheit:{multiplier:9/5,offset:32}},pressureUnits:{cbar:{multiplier:1,offset:0},bar:{multiplier:1/100,offset:0},psi:{multiplier:1/100*Yt,offset:0}}},messages:{0:{name:"file_id",0:{field:"type",type:"file",scale:null,offset:0,units:""},1:{field:"manufacturer",type:"manufacturer",scale:null,offset:0,units:""},2:{field:"product",type:"uint16",scale:null,offset:0,units:""},3:{field:"serial_number",type:"uint32z",scale:null,offset:0,units:""},4:{field:"time_created",type:"date_time",scale:null,offset:0,units:""},5:{field:"number",type:"uint16",scale:null,offset:0,units:""},8:{field:"product_name",type:"string",scale:null,offset:0,units:""}},1:{name:"capabilities",0:{field:"languages",type:"uint8z",scale:null,offset:0,units:""},1:{field:"sports",type:"sport_bits_0",scale:null,offset:0,units:""},21:{field:"workouts_supported",type:"workout_capabilities",scale:null,offset:0,units:""},23:{field:"connectivity_supported",type:"connectivity_capabilities",scale:null,offset:0,units:""}},2:{name:"device_settings",0:{field:"active_time_zone",type:"uint8",scale:null,offset:0,units:""},1:{field:"utc_offset",type:"uint32",scale:null,offset:0,units:""},2:{field:"time_offset",type:"uint32",scale:null,offset:0,units:"s"},5:{field:"time_zone_offset",type:"sint8",scale:4,offset:0,units:"hr"},55:{field:"display_orientation",type:"display_orientation",scale:null,offset:0,units:""},56:{field:"mounting_side",type:"side",scale:null,offset:0,units:""},94:{field:"number_of_screens",type:"uint8",scale:null,offset:0,units:""},95:{field:"smart_notification_display_orientation",type:"display_orientation",scale:null,offset:0,units:""}},3:{name:"user_profile",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"friendly_name",type:"string",scale:null,offset:0,units:""},1:{field:"gender",type:"gender",scale:null,offset:0,units:""},2:{field:"age",type:"uint8",scale:null,offset:0,units:"years"},3:{field:"height",type:"uint8",scale:100,offset:0,units:"m"},4:{field:"weight",type:"uint16",scale:10,offset:0,units:"kg"},5:{field:"language",type:"language",scale:null,offset:0,units:""},6:{field:"elev_setting",type:"display_measure",scale:null,offset:0,units:""},7:{field:"weight_setting",type:"display_measure",scale:null,offset:0,units:""},8:{field:"resting_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},9:{field:"default_max_running_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},10:{field:"default_max_biking_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},11:{field:"default_max_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},12:{field:"hr_setting",type:"display_heart",scale:null,offset:0,units:""},13:{field:"speed_setting",type:"display_measure",scale:null,offset:0,units:""},14:{field:"dist_setting",type:"display_measure",scale:null,offset:0,units:""},16:{field:"power_setting",type:"display_power",scale:null,offset:0,units:""},17:{field:"activity_class",type:"activity_class",scale:null,offset:0,units:""},18:{field:"position_setting",type:"display_position",scale:null,offset:0,units:""},21:{field:"temperature_setting",type:"display_measure",scale:null,offset:0,units:""},22:{field:"local_id",type:"user_local_id",scale:null,offset:0,units:""},23:{field:"global_id",type:"byte",scale:null,offset:0,units:""},28:{field:"wake_time",type:"localtime_into_day",scale:null,offset:0,units:""},29:{field:"sleep_time",type:"localtime_into_day",scale:null,offset:0,units:""},30:{field:"height_setting",type:"display_measure",scale:null,offset:0,units:""}},4:{name:"hrm_profile",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"enabled",type:"bool",scale:null,offset:0,units:""},1:{field:"hrm_ant_id",type:"uint16z",scale:null,offset:0,units:""},2:{field:"log_hrv",type:"bool",scale:null,offset:0,units:""},3:{field:"hrm_ant_id_trans_type",type:"uint8z",scale:null,offset:0,units:""}},5:{name:"sdm_profile",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"enabled",type:"bool",scale:null,offset:0,units:""},1:{field:"sdm_ant_id",type:"uint16z",scale:null,offset:0,units:""},2:{field:"sdm_cal_factor",type:"uint16",scale:10,offset:0,units:"%"},3:{field:"odometer",type:"uint32",scale:100,offset:0,units:"m"},4:{field:"speed_source",type:"bool",scale:null,offset:0,units:""},5:{field:"sdm_ant_id_trans_type",type:"uint8z",scale:null,offset:0,units:""},7:{field:"odometer_rollover",type:"uint8",scale:null,offset:0,units:""}},6:{name:"bike_profile",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"name",type:"string",scale:null,offset:0,units:""},1:{field:"sport",type:"sport",scale:null,offset:0,units:""},2:{field:"sub_sport",type:"sub_sport",scale:null,offset:0,units:""},3:{field:"odometer",type:"uint32",scale:100,offset:0,units:"m"},4:{field:"bike_spd_ant_id",type:"uint16z",scale:null,offset:0,units:""},5:{field:"bike_cad_ant_id",type:"uint16z",scale:null,offset:0,units:""},6:{field:"bike_spdcad_ant_id",type:"uint16z",scale:null,offset:0,units:""},7:{field:"bike_power_ant_id",type:"uint16z",scale:null,offset:0,units:""},8:{field:"custom_wheelsize",type:"uint16",scale:1e3,offset:0,units:"m"},9:{field:"auto_wheelsize",type:"uint16",scale:1e3,offset:0,units:"m"},10:{field:"bike_weight",type:"uint16",scale:10,offset:0,units:"kg"},11:{field:"power_cal_factor",type:"uint16",scale:10,offset:0,units:"%"},12:{field:"auto_wheel_cal",type:"bool",scale:null,offset:0,units:""},13:{field:"auto_power_zero",type:"bool",scale:null,offset:0,units:""},14:{field:"id",type:"uint8",scale:null,offset:0,units:""},15:{field:"spd_enabled",type:"bool",scale:null,offset:0,units:""},16:{field:"cad_enabled",type:"bool",scale:null,offset:0,units:""},17:{field:"spdcad_enabled",type:"bool",scale:null,offset:0,units:""},18:{field:"power_enabled",type:"bool",scale:null,offset:0,units:""},19:{field:"crank_length",type:"uint8",scale:2,offset:-110,units:"mm"},20:{field:"enabled",type:"bool",scale:null,offset:0,units:""},21:{field:"bike_spd_ant_id_trans_type",type:"uint8z",scale:null,offset:0,units:""},22:{field:"bike_cad_ant_id_trans_type",type:"uint8z",scale:null,offset:0,units:""},23:{field:"bike_spdcad_ant_id_trans_type",type:"uint8z",scale:null,offset:0,units:""},24:{field:"bike_power_ant_id_trans_type",type:"uint8z",scale:null,offset:0,units:""},37:{field:"odometer_rollover",type:"uint8",scale:null,offset:0,units:""},38:{field:"front_gear_num",type:"uint8z",scale:null,offset:0,units:""},39:{field:"front_gear",type:"uint8z",scale:null,offset:0,units:""},40:{field:"rear_gear_num",type:"uint8z",scale:null,offset:0,units:""},41:{field:"rear_gear",type:"uint8z",scale:null,offset:0,units:""},44:{field:"shimano_di2_enabled",type:"bool",scale:null,offset:0,units:""}},7:{name:"zones_target",1:{field:"max_heart_rate",type:"uint8",scale:null,offset:0,units:""},2:{field:"threshold_heart_rate",type:"uint8",scale:null,offset:0,units:""},3:{field:"functional_threshold_power",type:"uint16",scale:null,offset:0,units:""},5:{field:"hr_calc_type",type:"hr_zone_calc",scale:null,offset:0,units:""},7:{field:"pwr_calc_type",type:"pwr_zone_calc",scale:null,offset:0,units:""}},8:{name:"hr_zone",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},1:{field:"high_bpm",type:"uint8",scale:null,offset:0,units:"bpm"},2:{field:"name",type:"string",scale:null,offset:0,units:""}},9:{name:"power_zone",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},1:{field:"high_value",type:"uint16",scale:null,offset:0,units:"watts"},2:{field:"name",type:"string",scale:null,offset:0,units:""}},10:{name:"met_zone",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},1:{field:"high_bpm",type:"uint8",scale:null,offset:0,units:""},2:{field:"calories",type:"uint16",scale:10,offset:0,units:"kcal / min"},3:{field:"fat_calories",type:"uint8",scale:10,offset:0,units:"kcal / min"}},12:{name:"sport",0:{field:"sport",type:"sport",scale:null,offset:0,units:""},1:{field:"sub_sport",type:"sub_sport",scale:null,offset:0,units:""},3:{field:"name",type:"string",scale:null,offset:0,units:""}},15:{name:"goal",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"sport",type:"sport",scale:null,offset:0,units:""},1:{field:"sub_sport",type:"sub_sport",scale:null,offset:0,units:""},2:{field:"start_date",type:"date_time",scale:null,offset:0,units:""},3:{field:"end_date",type:"date_time",scale:null,offset:0,units:""},4:{field:"type",type:"goal",scale:null,offset:0,units:""},5:{field:"value",type:"uint32",scale:null,offset:0,units:""},6:{field:"repeat",type:"bool",scale:null,offset:0,units:""},7:{field:"target_value",type:"uint32",scale:null,offset:0,units:""},8:{field:"recurrence",type:"goal_recurrence",scale:null,offset:0,units:""},9:{field:"recurrence_value",type:"uint16",scale:null,offset:0,units:""},10:{field:"enabled",type:"bool",scale:null,offset:0,units:""}},18:{name:"session",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"event",type:"event",scale:null,offset:0,units:""},1:{field:"event_type",type:"event_type",scale:null,offset:0,units:""},2:{field:"start_time",type:"date_time",scale:null,offset:0,units:""},3:{field:"start_position_lat",type:"sint32",scale:null,offset:0,units:"semicircles"},4:{field:"start_position_long",type:"sint32",scale:null,offset:0,units:"semicircles"},5:{field:"sport",type:"sport",scale:null,offset:0,units:""},6:{field:"sub_sport",type:"sub_sport",scale:null,offset:0,units:""},7:{field:"total_elapsed_time",type:"uint32",scale:1e3,offset:0,units:"s"},8:{field:"total_timer_time",type:"uint32",scale:1e3,offset:0,units:"s"},9:{field:"total_distance",type:"uint32",scale:100,offset:0,units:"m"},10:{field:"total_cycles",type:"uint32",scale:null,offset:0,units:"cycles"},11:{field:"total_calories",type:"uint16",scale:null,offset:0,units:"kcal"},13:{field:"total_fat_calories",type:"uint16",scale:null,offset:0,units:"kcal"},14:{field:"avg_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},15:{field:"max_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},16:{field:"avg_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},17:{field:"max_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},18:{field:"avg_cadence",type:"uint8",scale:null,offset:0,units:"rpm"},19:{field:"max_cadence",type:"uint8",scale:null,offset:0,units:"rpm"},20:{field:"avg_power",type:"uint16",scale:null,offset:0,units:"watts"},21:{field:"max_power",type:"uint16",scale:null,offset:0,units:"watts"},22:{field:"total_ascent",type:"uint16",scale:null,offset:0,units:"m"},23:{field:"total_descent",type:"uint16",scale:null,offset:0,units:"m"},24:{field:"total_training_effect",type:"uint8",scale:10,offset:0,units:""},25:{field:"first_lap_index",type:"uint16",scale:null,offset:0,units:""},26:{field:"num_laps",type:"uint16",scale:null,offset:0,units:""},27:{field:"event_group",type:"uint8",scale:null,offset:0,units:""},28:{field:"trigger",type:"session_trigger",scale:null,offset:0,units:""},29:{field:"nec_lat",type:"sint32",scale:null,offset:0,units:"semicircles"},30:{field:"nec_long",type:"sint32",scale:null,offset:0,units:"semicircles"},31:{field:"swc_lat",type:"sint32",scale:null,offset:0,units:"semicircles"},32:{field:"swc_long",type:"sint32",scale:null,offset:0,units:"semicircles"},34:{field:"normalized_power",type:"uint16",scale:null,offset:0,units:"watts"},35:{field:"training_stress_score",type:"uint16",scale:10,offset:0,units:"tss"},36:{field:"intensity_factor",type:"uint16",scale:1e3,offset:0,units:"if"},37:{field:"left_right_balance",type:"left_right_balance_100",scale:100,offset:0,units:"%"},38:{field:"end_position_lat",type:"sint32",scale:null,offset:0,units:"semicircles"},39:{field:"end_position_long",type:"sint32",scale:null,offset:0,units:"semicircles"},41:{field:"avg_stroke_count",type:"uint32",scale:10,offset:0,units:"strokes/lap"},42:{field:"avg_stroke_distance",type:"uint16",scale:100,offset:0,units:"m"},43:{field:"swim_stroke",type:"swim_stroke",scale:null,offset:0,units:"swim_stroke"},44:{field:"pool_length",type:"uint16",scale:100,offset:0,units:"m"},45:{field:"threshold_power",type:"uint16",scale:null,offset:0,units:"watts"},46:{field:"pool_length_unit",type:"display_measure",scale:null,offset:0,units:""},47:{field:"num_active_lengths",type:"uint16",scale:null,offset:0,units:"lengths"},48:{field:"total_work",type:"uint32",scale:null,offset:0,units:"J"},49:{field:"avg_altitude",type:"uint16",scale:5,offset:-500,units:"m"},50:{field:"max_altitude",type:"uint16",scale:5,offset:-500,units:"m"},51:{field:"gps_accuracy",type:"uint8",scale:null,offset:0,units:"m"},52:{field:"avg_grade",type:"sint16",scale:100,offset:0,units:"%"},53:{field:"avg_pos_grade",type:"sint16",scale:100,offset:0,units:"%"},54:{field:"avg_neg_grade",type:"sint16",scale:100,offset:0,units:"%"},55:{field:"max_pos_grade",type:"sint16",scale:100,offset:0,units:"%"},56:{field:"max_neg_grade",type:"sint16",scale:100,offset:0,units:"%"},57:{field:"avg_temperature",type:"sint8",scale:null,offset:0,units:"C"},58:{field:"max_temperature",type:"sint8",scale:null,offset:0,units:"C"},59:{field:"total_moving_time",type:"uint32",scale:1e3,offset:0,units:"s"},60:{field:"avg_pos_vertical_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},61:{field:"avg_neg_vertical_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},62:{field:"max_pos_vertical_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},63:{field:"max_neg_vertical_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},64:{field:"min_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},65:{field:"time_in_hr_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},66:{field:"time_in_speed_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},67:{field:"time_in_cadence_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},68:{field:"time_in_power_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},69:{field:"avg_lap_time",type:"uint32",scale:1e3,offset:0,units:"s"},70:{field:"best_lap_index",type:"uint16",scale:null,offset:0,units:""},71:{field:"min_altitude",type:"uint16",scale:5,offset:-500,units:"m"},82:{field:"player_score",type:"uint16",scale:null,offset:0,units:""},83:{field:"opponent_score",type:"uint16",scale:null,offset:0,units:""},84:{field:"opponent_name",type:"string",scale:null,offset:0,units:""},85:{field:"stroke_count",type:"uint16",scale:null,offset:0,units:"counts"},86:{field:"zone_count",type:"uint16",scale:null,offset:0,units:"counts"},87:{field:"max_ball_speed",type:"uint16",scale:100,offset:0,units:"m/s"},88:{field:"avg_ball_speed",type:"uint16",scale:100,offset:0,units:"m/s"},89:{field:"avg_vertical_oscillation",type:"uint16",scale:10,offset:0,units:"mm"},90:{field:"avg_stance_time_percent",type:"uint16",scale:100,offset:0,units:"percent"},91:{field:"avg_stance_time",type:"uint16",scale:10,offset:0,units:"ms"},92:{field:"avg_fractional_cadence",type:"uint8",scale:128,offset:0,units:"rpm"},93:{field:"max_fractional_cadence",type:"uint8",scale:128,offset:0,units:"rpm"},94:{field:"total_fractional_cycles",type:"uint8",scale:128,offset:0,units:"cycles"},95:{field:"avg_total_hemoglobin_conc",type:"uint16",scale:100,offset:0,units:"g/dL"},96:{field:"min_total_hemoglobin_conc",type:"uint16",scale:100,offset:0,units:"g/dL"},97:{field:"max_total_hemoglobin_conc",type:"uint16",scale:100,offset:0,units:"g/dL"},98:{field:"avg_saturated_hemoglobin_percent",type:"uint16",scale:10,offset:0,units:"%"},99:{field:"min_saturated_hemoglobin_percent",type:"uint16",scale:10,offset:0,units:"%"},100:{field:"max_saturated_hemoglobin_percent",type:"uint16",scale:10,offset:0,units:"%"},101:{field:"avg_left_torque_effectiveness",type:"uint8",scale:2,offset:0,units:"percent"},102:{field:"avg_right_torque_effectiveness",type:"uint8",scale:2,offset:0,units:"percent"},103:{field:"avg_left_pedal_smoothness",type:"uint8",scale:2,offset:0,units:"percent"},104:{field:"avg_right_pedal_smoothness",type:"uint8",scale:2,offset:0,units:"percent"},105:{field:"avg_combined_pedal_smoothness",type:"uint8",scale:2,offset:0,units:"percent"},111:{field:"sport_index",type:"uint8",scale:null,offset:0,units:""},112:{field:"time_standing",type:"uint32",scale:1e3,offset:0,units:"s"},113:{field:"stand_count",type:"uint16",scale:null,offset:0,units:""},114:{field:"avg_left_pco",type:"sint8",scale:null,offset:0,units:"mm"},115:{field:"avg_right_pco",type:"sint8",scale:null,offset:0,units:"mm"},116:{field:"avg_left_power_phase",type:"uint8",scale:.7111111,offset:0,units:"degrees"},117:{field:"avg_left_power_phase_peak",type:"uint8",scale:.7111111,offset:0,units:"degrees"},118:{field:"avg_right_power_phase",type:"uint8",scale:.7111111,offset:0,units:"degrees"},119:{field:"avg_right_power_phase_peak",type:"uint8",scale:.7111111,offset:0,units:"degrees"},120:{field:"avg_power_position",type:"uint16",scale:null,offset:0,units:"watts"},121:{field:"max_power_position",type:"uint16",scale:null,offset:0,units:"watts"},122:{field:"avg_cadence_position",type:"uint8",scale:null,offset:0,units:"rpm"},123:{field:"max_cadence_position",type:"uint8",scale:null,offset:0,units:"rpm"},124:{field:"enhanced_avg_speed",type:"uint32",scale:1e3,offset:0,units:"m/s"},125:{field:"enhanced_max_speed",type:"uint32",scale:1e3,offset:0,units:"m/s"},126:{field:"enhanced_avg_altitude",type:"uint32",scale:5,offset:-500,units:"m"},127:{field:"enhanced_min_altitude",type:"uint32",scale:5,offset:-500,units:"m"},128:{field:"enhanced_max_altitude",type:"uint32",scale:5,offset:-500,units:"m"},129:{field:"avg_lev_motor_power",type:"uint16",scale:null,offset:0,units:"watts"},130:{field:"max_lev_motor_power",type:"uint16",scale:null,offset:0,units:"watts"},131:{field:"lev_battery_consumption",type:"uint8",scale:2,offset:0,units:"percent"},132:{field:"avg_vertical_ratio",type:"uint16",scale:100,offset:0,units:"percent"},133:{field:"avg_stance_time_balance",type:"uint16",scale:100,offset:0,units:"percent"},134:{field:"avg_step_length",type:"uint16",scale:10,offset:0,units:"mm"},137:{field:"total_anaerobic_training_effect",type:"uint8",scale:10,offset:0,units:""},139:{field:"avg_vam",type:"uint16",scale:1,offset:0,units:"m/h"},192:{field:"workout_feel",type:"uint8",scale:null,offset:0,units:""},193:{field:"workout_rpe",type:"uint8",scale:10,offset:0,units:""},110:{field:"sport_profile_name",type:"string",scale:null,offset:0,units:""},168:{field:"training_load_peak",type:"uint32",scale:1,offset:0,units:""},169:{field:"enhanced_avg_respiration_rate",type:"uint16",scale:100,offset:0,units:"breaths/min"},150:{field:"min_temperature",type:"sint8",scale:null,offset:0,units:"C"},170:{field:"enhanced_max_respiration_rate",type:"uint16",scale:100,offset:0,units:"breaths/min"},178:{field:"est_sweat_loss",type:"uint16",scale:1,offset:0,units:"ml"},180:{field:"enhanced_min_respiration_rate",type:"uint16",scale:100,offset:0,units:"breaths/min"},181:{field:"total_grit",type:"float32",scale:1,offset:0,units:"kGrit"},182:{field:"total_flow",type:"float32",scale:1,offset:0,units:"Flow"},183:{field:"jump_count",type:"uint16",scale:1,offset:0,units:""},186:{field:"avg_grit",type:"float32",scale:1,offset:0,units:"kGrit"},187:{field:"avg_flow",type:"float32",scale:1,offset:0,units:"Flow"},188:{field:"primary_benefit",type:"uint8",scale:1,offset:0,units:""},196:{field:"resting_calories",type:"uint16",scale:1,offset:0,units:"kcal"},214:{field:"avg_grit",type:"float32",scale:null,offset:0,units:""},215:{field:"avg_flow",type:"float32",scale:null,offset:0,units:""},140:{field:"recovery_advisor",type:"uint16",scale:1,offset:0,units:"min"}},19:{name:"lap",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"event",type:"event",scale:null,offset:0,units:""},1:{field:"event_type",type:"event_type",scale:null,offset:0,units:""},2:{field:"start_time",type:"date_time",scale:null,offset:0,units:""},3:{field:"start_position_lat",type:"sint32",scale:null,offset:0,units:"semicircles"},4:{field:"start_position_long",type:"sint32",scale:null,offset:0,units:"semicircles"},5:{field:"end_position_lat",type:"sint32",scale:null,offset:0,units:"semicircles"},6:{field:"end_position_long",type:"sint32",scale:null,offset:0,units:"semicircles"},7:{field:"total_elapsed_time",type:"uint32",scale:1e3,offset:0,units:"s"},8:{field:"total_timer_time",type:"uint32",scale:1e3,offset:0,units:"s"},9:{field:"total_distance",type:"uint32",scale:100,offset:0,units:"m"},10:{field:"total_cycles",type:"uint32",scale:null,offset:0,units:"cycles"},11:{field:"total_calories",type:"uint16",scale:null,offset:0,units:"kcal"},12:{field:"total_fat_calories",type:"uint16",scale:null,offset:0,units:"kcal"},13:{field:"avg_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},14:{field:"max_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},15:{field:"avg_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},16:{field:"max_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},17:{field:"avg_cadence",type:"uint8",scale:null,offset:0,units:"rpm"},18:{field:"max_cadence",type:"uint8",scale:null,offset:0,units:"rpm"},19:{field:"avg_power",type:"uint16",scale:null,offset:0,units:"watts"},20:{field:"max_power",type:"uint16",scale:null,offset:0,units:"watts"},21:{field:"total_ascent",type:"uint16",scale:null,offset:0,units:"m"},22:{field:"total_descent",type:"uint16",scale:null,offset:0,units:"m"},23:{field:"intensity",type:"intensity",scale:null,offset:0,units:""},24:{field:"lap_trigger",type:"lap_trigger",scale:null,offset:0,units:""},25:{field:"sport",type:"sport",scale:null,offset:0,units:""},26:{field:"event_group",type:"uint8",scale:null,offset:0,units:""},32:{field:"num_lengths",type:"uint16",scale:null,offset:0,units:"lengths"},33:{field:"normalized_power",type:"uint16",scale:null,offset:0,units:"watts"},34:{field:"left_right_balance",type:"left_right_balance_100",scale:100,offset:0,units:"%"},35:{field:"first_length_index",type:"uint16",scale:null,offset:0,units:""},37:{field:"avg_stroke_distance",type:"uint16",scale:100,offset:0,units:"m"},38:{field:"swim_stroke",type:"swim_stroke",scale:null,offset:0,units:""},39:{field:"sub_sport",type:"sub_sport",scale:null,offset:0,units:""},40:{field:"num_active_lengths",type:"uint16",scale:null,offset:0,units:"lengths"},41:{field:"total_work",type:"uint32",scale:null,offset:0,units:"J"},42:{field:"avg_altitude",type:"uint16",scale:5,offset:-500,units:"m"},43:{field:"max_altitude",type:"uint16",scale:5,offset:-500,units:"m"},44:{field:"gps_accuracy",type:"uint8",scale:null,offset:0,units:"m"},45:{field:"avg_grade",type:"sint16",scale:100,offset:0,units:"%"},46:{field:"avg_pos_grade",type:"sint16",scale:100,offset:0,units:"%"},47:{field:"avg_neg_grade",type:"sint16",scale:100,offset:0,units:"%"},48:{field:"max_pos_grade",type:"sint16",scale:100,offset:0,units:"%"},49:{field:"max_neg_grade",type:"sint16",scale:100,offset:0,units:"%"},50:{field:"avg_temperature",type:"sint8",scale:null,offset:0,units:"C"},51:{field:"max_temperature",type:"sint8",scale:null,offset:0,units:"C"},52:{field:"total_moving_time",type:"uint32",scale:1e3,offset:0,units:"s"},53:{field:"avg_pos_vertical_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},54:{field:"avg_neg_vertical_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},55:{field:"max_pos_vertical_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},56:{field:"max_neg_vertical_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},57:{field:"time_in_hr_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},58:{field:"time_in_speed_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},59:{field:"time_in_cadence_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},60:{field:"time_in_power_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},61:{field:"repetition_num",type:"uint16",scale:null,offset:0,units:""},62:{field:"min_altitude",type:"uint16",scale:5,offset:-500,units:"m"},63:{field:"min_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},71:{field:"wkt_step_index",type:"message_index",scale:null,offset:0,units:""},74:{field:"opponent_score",type:"uint16",scale:null,offset:0,units:""},75:{field:"stroke_count",type:"uint16",scale:null,offset:0,units:"counts"},76:{field:"zone_count",type:"uint16",scale:null,offset:0,units:"counts"},77:{field:"avg_vertical_oscillation",type:"uint16",scale:10,offset:0,units:"mm"},78:{field:"avg_stance_time_percent",type:"uint16",scale:100,offset:0,units:"percent"},79:{field:"avg_stance_time",type:"uint16",scale:10,offset:0,units:"ms"},80:{field:"avg_fractional_cadence",type:"uint8",scale:128,offset:0,units:"rpm"},81:{field:"max_fractional_cadence",type:"uint8",scale:128,offset:0,units:"rpm"},82:{field:"total_fractional_cycles",type:"uint8",scale:128,offset:0,units:"cycles"},83:{field:"player_score",type:"uint16",scale:null,offset:0,units:""},84:{field:"avg_total_hemoglobin_conc",type:"uint16",scale:100,offset:0,units:"g/dL"},85:{field:"min_total_hemoglobin_conc",type:"uint16",scale:100,offset:0,units:"g/dL"},86:{field:"max_total_hemoglobin_conc",type:"uint16",scale:100,offset:0,units:"g/dL"},87:{field:"avg_saturated_hemoglobin_percent",type:"uint16",scale:10,offset:0,units:"%"},88:{field:"min_saturated_hemoglobin_percent",type:"uint16",scale:10,offset:0,units:"%"},89:{field:"max_saturated_hemoglobin_percent",type:"uint16",scale:10,offset:0,units:"%"},91:{field:"avg_left_torque_effectiveness",type:"uint8",scale:2,offset:0,units:"percent"},92:{field:"avg_right_torque_effectiveness",type:"uint8",scale:2,offset:0,units:"percent"},93:{field:"avg_left_pedal_smoothness",type:"uint8",scale:2,offset:0,units:"percent"},94:{field:"avg_right_pedal_smoothness",type:"uint8",scale:2,offset:0,units:"percent"},95:{field:"avg_combined_pedal_smoothness",type:"uint8",scale:2,offset:0,units:"percent"},98:{field:"time_standing",type:"uint32",scale:1e3,offset:0,units:"s"},99:{field:"stand_count",type:"uint16",scale:null,offset:0,units:""},100:{field:"avg_left_pco",type:"sint8",scale:null,offset:0,units:"mm"},101:{field:"avg_right_pco",type:"sint8",scale:null,offset:0,units:"mm"},102:{field:"avg_left_power_phase",type:"uint8",scale:.7111111,offset:0,units:"degrees"},103:{field:"avg_left_power_phase_peak",type:"uint8",scale:.7111111,offset:0,units:"degrees"},104:{field:"avg_right_power_phase",type:"uint8",scale:.7111111,offset:0,units:"degrees"},105:{field:"avg_right_power_phase_peak",type:"uint8",scale:.7111111,offset:0,units:"degrees"},106:{field:"avg_power_position",type:"uint16",scale:null,offset:0,units:"watts"},107:{field:"max_power_position",type:"uint16",scale:null,offset:0,units:"watts"},108:{field:"avg_cadence_position",type:"uint8",scale:null,offset:0,units:"rpm"},109:{field:"max_cadence_position",type:"uint8",scale:null,offset:0,units:"rpm"},110:{field:"enhanced_avg_speed",type:"uint32",scale:1e3,offset:0,units:"m/s"},111:{field:"enhanced_max_speed",type:"uint32",scale:1e3,offset:0,units:"m/s"},112:{field:"enhanced_avg_altitude",type:"uint32",scale:5,offset:-500,units:"m"},113:{field:"enhanced_min_altitude",type:"uint32",scale:5,offset:-500,units:"m"},114:{field:"enhanced_max_altitude",type:"uint32",scale:5,offset:-500,units:"m"},115:{field:"avg_lev_motor_power",type:"uint16",scale:null,offset:0,units:"watts"},116:{field:"max_lev_motor_power",type:"uint16",scale:null,offset:0,units:"watts"},117:{field:"lev_battery_consumption",type:"uint8",scale:2,offset:0,units:"percent"},118:{field:"avg_vertical_ratio",type:"uint16",scale:100,offset:0,units:"percent"},119:{field:"avg_stance_time_balance",type:"uint16",scale:100,offset:0,units:"percent"},120:{field:"avg_step_length",type:"uint16",scale:10,offset:0,units:"mm"},121:{field:"avg_vam",type:"uint16",scale:1e3,offset:0,units:"m/s"}},20:{name:"record",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},114:{field:"grit",type:"float32",scale:null,offset:0,units:""},115:{field:"flow",type:"float32",scale:null,offset:0,units:""},0:{field:"position_lat",type:"sint32",scale:null,offset:0,units:"semicircles"},1:{field:"position_long",type:"sint32",scale:null,offset:0,units:"semicircles"},2:{field:"altitude",type:"uint16",scale:5,offset:-500,units:"m"},3:{field:"heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},4:{field:"cadence",type:"uint8",scale:null,offset:0,units:"rpm"},5:{field:"distance",type:"uint32",scale:100,offset:0,units:"m"},6:{field:"speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},7:{field:"power",type:"uint16",scale:null,offset:0,units:"watts"},8:{field:"compressed_speed_distance",type:"byte",scale:100.16,offset:0,units:"m/s,m"},9:{field:"grade",type:"sint16",scale:100,offset:0,units:"%"},10:{field:"resistance",type:"uint8",scale:null,offset:0,units:""},11:{field:"time_from_course",type:"sint32",scale:1e3,offset:0,units:"s"},12:{field:"cycle_length",type:"uint8",scale:100,offset:0,units:"m"},13:{field:"temperature",type:"sint8",scale:null,offset:0,units:"C"},17:{field:"speed_1s",type:"uint8",scale:16,offset:0,units:"m/s"},18:{field:"cycles",type:"uint8",scale:null,offset:0,units:"cycles"},19:{field:"total_cycles",type:"uint32",scale:null,offset:0,units:"cycles"},28:{field:"compressed_accumulated_power",type:"uint16",scale:null,offset:0,units:"watts"},29:{field:"accumulated_power",type:"uint32",scale:null,offset:0,units:"watts"},30:{field:"left_right_balance",type:"left_right_balance",scale:null,offset:0,units:""},31:{field:"gps_accuracy",type:"uint8",scale:null,offset:0,units:"m"},32:{field:"vertical_speed",type:"sint16",scale:1e3,offset:0,units:"m/s"},33:{field:"calories",type:"uint16",scale:null,offset:0,units:"kcal"},39:{field:"vertical_oscillation",type:"uint16",scale:10,offset:0,units:"mm"},40:{field:"stance_time_percent",type:"uint16",scale:100,offset:0,units:"percent"},41:{field:"stance_time",type:"uint16",scale:10,offset:0,units:"ms"},42:{field:"activity_type",type:"activity_type",scale:null,offset:0,units:""},43:{field:"left_torque_effectiveness",type:"uint8",scale:2,offset:0,units:"percent"},44:{field:"right_torque_effectiveness",type:"uint8",scale:2,offset:0,units:"percent"},45:{field:"left_pedal_smoothness",type:"uint8",scale:2,offset:0,units:"percent"},46:{field:"right_pedal_smoothness",type:"uint8",scale:2,offset:0,units:"percent"},47:{field:"combined_pedal_smoothness",type:"uint8",scale:2,offset:0,units:"percent"},48:{field:"time128",type:"uint8",scale:128,offset:0,units:"s"},49:{field:"stroke_type",type:"stroke_type",scale:null,offset:0,units:""},50:{field:"zone",type:"uint8",scale:null,offset:0,units:""},51:{field:"ball_speed",type:"uint16",scale:100,offset:0,units:"m/s"},52:{field:"cadence256",type:"uint16",scale:256,offset:0,units:"rpm"},53:{field:"fractional_cadence",type:"uint8",scale:128,offset:0,units:"rpm"},54:{field:"total_hemoglobin_conc",type:"uint16",scale:100,offset:0,units:"g/dL"},55:{field:"total_hemoglobin_conc_min",type:"uint16",scale:100,offset:0,units:"g/dL"},56:{field:"total_hemoglobin_conc_max",type:"uint16",scale:100,offset:0,units:"g/dL"},57:{field:"saturated_hemoglobin_percent",type:"uint16",scale:10,offset:0,units:"%"},58:{field:"saturated_hemoglobin_percent_min",type:"uint16",scale:10,offset:0,units:"%"},59:{field:"saturated_hemoglobin_percent_max",type:"uint16",scale:10,offset:0,units:"%"},62:{field:"device_index",type:"device_index",scale:null,offset:0,units:""},67:{field:"left_pco",type:"sint8",scale:null,offset:0,units:"mm"},68:{field:"right_pco",type:"sint8",scale:null,offset:0,units:"mm"},69:{field:"left_power_phase",type:"uint8",scale:.7111111,offset:0,units:"degrees"},70:{field:"left_power_phase_peak",type:"uint8",scale:.7111111,offset:0,units:"degrees"},71:{field:"right_power_phase",type:"uint8",scale:.7111111,offset:0,units:"degrees"},72:{field:"right_power_phase_peak",type:"uint8",scale:.7111111,offset:0,units:"degrees"},73:{field:"enhanced_speed",type:"uint32",scale:1e3,offset:0,units:"m/s"},78:{field:"enhanced_altitude",type:"uint32",scale:5,offset:-500,units:"m"},81:{field:"battery_soc",type:"uint8",scale:2,offset:0,units:"percent"},82:{field:"motor_power",type:"uint16",scale:null,offset:0,units:"watts"},83:{field:"vertical_ratio",type:"uint16",scale:100,offset:0,units:"percent"},84:{field:"stance_time_balance",type:"uint16",scale:100,offset:0,units:"percent"},85:{field:"step_length",type:"uint16",scale:10,offset:0,units:"mm"},91:{field:"absolute_pressure",type:"uint32",scale:null,offset:0,units:"Pa"},92:{field:"depth",type:"uint32",scale:null,offset:0,units:"m"},93:{field:"next_stop_depth",type:"uint32",scale:null,offset:0,units:"m"},94:{field:"next_stop_time",type:"uint32",scale:null,offset:0,units:"s"},95:{field:"time_to_surface",type:"uint32",scale:null,offset:0,units:"s"},96:{field:"ndl_time",type:"uint32",scale:null,offset:0,units:"s"},97:{field:"cns_load",type:"uint8",scale:null,offset:0,units:"percent"},98:{field:"n2_load",type:"uint16",scale:null,offset:0,units:"percent"}},285:{name:"jump",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"distance",type:"float32",scale:null,offset:0,units:"m"},1:{field:"height",type:"float32",scale:null,offset:0,units:"m"},2:{field:"rotations",type:"uint8",scale:null,offset:0,units:""},3:{field:"hang_time",type:"float32",scale:null,offset:0,units:"s"},4:{field:"score",type:"float32",scale:null,offset:0,units:""},5:{field:"position_lat",type:"sint32",scale:null,offset:0,units:"semicircles"},6:{field:"position_long",type:"sint32",scale:null,offset:0,units:"semicircles"},7:{field:"speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},8:{field:"enhanced_speed",type:"uint32",scale:1e3,offset:0,units:"m/s"}},21:{name:"event",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"event",type:"event",scale:null,offset:0,units:""},1:{field:"event_type",type:"event_type",scale:null,offset:0,units:""},2:{field:"data16",type:"uint16",scale:null,offset:0,units:""},3:{field:"data",type:"uint32",scale:null,offset:0,units:""},4:{field:"event_group",type:"uint8",scale:null,offset:0,units:""},7:{field:"score",type:"uint16",scale:null,offset:0,units:""},8:{field:"opponent_score",type:"uint16",scale:null,offset:0,units:""},9:{field:"front_gear_num",type:"uint8z",scale:null,offset:0,units:""},10:{field:"front_gear",type:"uint8z",scale:null,offset:0,units:""},11:{field:"rear_gear_num",type:"uint8z",scale:null,offset:0,units:""},12:{field:"rear_gear",type:"uint8z",scale:null,offset:0,units:""},13:{field:"device_index",type:"device_index",scale:null,offset:0,units:""}},23:{name:"device_info",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"device_index",type:"uint8",scale:null,offset:0,units:""},1:{field:"device_type",type:"uint8",scale:null,offset:0,units:""},2:{field:"manufacturer",type:"manufacturer",scale:null,offset:0,units:""},3:{field:"serial_number",type:"uint32z",scale:null,offset:0,units:""},4:{field:"product",type:"uint16",scale:null,offset:0,units:""},5:{field:"software_version",type:"uint16",scale:100,offset:0,units:""},6:{field:"hardware_version",type:"uint8",scale:null,offset:0,units:""},7:{field:"cum_operating_time",type:"uint32",scale:null,offset:0,units:"s"},10:{field:"battery_voltage",type:"uint16",scale:256,offset:0,units:"V"},32:{field:"battery_level",type:"uint8",scale:null,offset:0,units:"percent"},11:{field:"battery_status",type:"battery_status",scale:null,offset:0,units:""},18:{field:"sensor_position",type:"body_location",scale:null,offset:0,units:""},19:{field:"descriptor",type:"string",scale:null,offset:0,units:""},20:{field:"ant_transmission_type",type:"uint8z",scale:null,offset:0,units:""},21:{field:"ant_device_number",type:"uint16z",scale:null,offset:0,units:""},22:{field:"ant_network",type:"ant_network",scale:null,offset:0,units:""},24:{field:"ant_id",type:"uint32z",scale:null,offset:0,units:""},25:{field:"source_type",type:"source_type",scale:null,offset:0,units:""},27:{field:"product_name",type:"string",scale:null,offset:0,units:""}},26:{name:"workout",4:{field:"sport",type:"sport",scale:null,offset:0,units:""},5:{field:"capabilities",type:"workout_capabilities",scale:null,offset:0,units:""},6:{field:"num_valid_steps",type:"uint16",scale:null,offset:0,units:""},8:{field:"wkt_name",type:"string",scale:null,offset:0,units:""}},27:{name:"workout_step",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"wkt_step_name",type:"string",scale:null,offset:0,units:""},1:{field:"duration_type",type:"wkt_step_duration",scale:null,offset:0,units:""},2:{field:"duration_value",type:"uint32",scale:null,offset:0,units:""},3:{field:"target_type",type:"wkt_step_target",scale:null,offset:0,units:""},4:{field:"target_value",type:"uint32",scale:null,offset:0,units:""},5:{field:"custom_target_value_low",type:"uint32",scale:null,offset:0,units:""},6:{field:"custom_target_value_high",type:"uint32",scale:null,offset:0,units:""},7:{field:"intensity",type:"intensity",scale:null,offset:0,units:""}},30:{name:"weight_scale",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"weight",type:"weight",scale:100,offset:0,units:"kg"},1:{field:"percent_fat",type:"uint16",scale:100,offset:0,units:"%"},2:{field:"percent_hydration",type:"uint16",scale:100,offset:0,units:"%"},3:{field:"visceral_fat_mass",type:"uint16",scale:100,offset:0,units:"kg"},4:{field:"bone_mass",type:"uint16",scale:100,offset:0,units:"kg"},5:{field:"muscle_mass",type:"uint16",scale:100,offset:0,units:"kg"},7:{field:"basal_met",type:"uint16",scale:4,offset:0,units:"kcal/day"},8:{field:"physique_rating",type:"uint8",scale:null,offset:0,units:""},9:{field:"active_met",type:"uint16",scale:4,offset:0,units:"kcal/day"},10:{field:"metabolic_age",type:"uint8",scale:null,offset:0,units:"years"},11:{field:"visceral_fat_rating",type:"uint8",scale:null,offset:0,units:""},12:{field:"user_profile_index",type:"message_index",scale:null,offset:0,units:""}},31:{name:"course",4:{field:"sport",type:"sport",scale:null,offset:0,units:""},5:{field:"name",type:"string",scale:null,offset:0,units:""},6:{field:"capabilities",type:"course_capabilities",scale:null,offset:0,units:""}},32:{name:"course_point",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},1:{field:"timestamp",type:"date_time",scale:null,offset:0,units:""},2:{field:"position_lat",type:"sint32",scale:null,offset:0,units:"semicircles"},3:{field:"position_long",type:"sint32",scale:null,offset:0,units:"semicircles"},4:{field:"distance",type:"uint32",scale:100,offset:0,units:"m"},5:{field:"type",type:"course_point",scale:null,offset:0,units:""},6:{field:"name",type:"string",scale:null,offset:0,units:""},8:{field:"favorite",type:"bool",scale:null,offset:0,units:""}},33:{name:"totals",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"timer_time",type:"uint32",scale:null,offset:0,units:"s"},1:{field:"distance",type:"uint32",scale:null,offset:0,units:"m"},2:{field:"calories",type:"uint32",scale:null,offset:0,units:"kcal"},3:{field:"sport",type:"sport",scale:null,offset:0,units:""},4:{field:"elapsed_time",type:"uint32",scale:null,offset:0,units:"s"},5:{field:"sessions",type:"uint16",scale:null,offset:0,units:""},6:{field:"active_time",type:"uint32",scale:null,offset:0,units:"s"},9:{field:"sport_index",type:"uint8",scale:null,offset:0,units:""}},34:{name:"activity",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:""},0:{field:"total_timer_time",type:"uint32",scale:1e3,offset:0,units:"s"},1:{field:"num_sessions",type:"uint16",scale:null,offset:0,units:""},2:{field:"type",type:"activity",scale:null,offset:0,units:""},3:{field:"event",type:"event",scale:null,offset:0,units:""},4:{field:"event_type",type:"event_type",scale:null,offset:0,units:""},5:{field:"local_timestamp",type:"local_date_time",scale:null,offset:0,units:""},6:{field:"event_group",type:"uint8",scale:null,offset:0,units:""}},35:{name:"software",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},3:{field:"version",type:"uint16",scale:100,offset:0,units:""},5:{field:"part_number",type:"string",scale:null,offset:0,units:""}},37:{name:"file_capabilities",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"type",type:"file",scale:null,offset:0,units:""},1:{field:"flags",type:"file_flags",scale:null,offset:0,units:""},2:{field:"directory",type:"string",scale:null,offset:0,units:""},3:{field:"max_count",type:"uint16",scale:null,offset:0,units:""},4:{field:"max_size",type:"uint32",scale:null,offset:0,units:"bytes"}},38:{name:"mesg_capabilities",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"file",type:"file",scale:null,offset:0,units:""},1:{field:"mesg_num",type:"mesg_num",scale:null,offset:0,units:""},2:{field:"count_type",type:"mesg_count",scale:null,offset:0,units:""},3:{field:"count",type:"uint16",scale:null,offset:0,units:""}},39:{name:"field_capabilities",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"file",type:"file",scale:null,offset:0,units:""},1:{field:"mesg_num",type:"mesg_num",scale:null,offset:0,units:""},2:{field:"field_num",type:"uint8",scale:null,offset:0,units:""},3:{field:"count",type:"uint16",scale:null,offset:0,units:""}},49:{name:"file_creator",0:{field:"software_version",type:"uint16",scale:null,offset:0,units:""},1:{field:"hardware_version",type:"uint8",scale:null,offset:0,units:""}},51:{name:"blood_pressure",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"systolic_pressure",type:"uint16",scale:null,offset:0,units:"mmHg"},1:{field:"diastolic_pressure",type:"uint16",scale:null,offset:0,units:"mmHg"},2:{field:"mean_arterial_pressure",type:"uint16",scale:null,offset:0,units:"mmHg"},3:{field:"map_3_sample_mean",type:"uint16",scale:null,offset:0,units:"mmHg"},4:{field:"map_morning_values",type:"uint16",scale:null,offset:0,units:"mmHg"},5:{field:"map_evening_values",type:"uint16",scale:null,offset:0,units:"mmHg"},6:{field:"heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},7:{field:"heart_rate_type",type:"hr_type",scale:null,offset:0,units:""},8:{field:"status",type:"bp_status",scale:null,offset:0,units:""},9:{field:"user_profile_index",type:"message_index",scale:null,offset:0,units:""}},55:{name:"monitoring",253:{field:"timestamp",type:"uint32",scale:null,offset:0,units:""},0:{field:"device_index",type:"device_index",scale:null,offset:0,units:""},1:{field:"calories",type:"uint16",scale:null,offset:0,units:"kcal"},2:{field:"distance",type:"float32",scale:null,offset:0,units:"m"},3:{field:"cycles",type:"float32",scale:null,offset:0,units:"cycles"},4:{field:"active_time",type:"float32",scale:null,offset:0,units:"s"},5:{field:"activity_type",type:"activity_type",scale:null,offset:0,units:""},6:{field:"activity_subtype",type:"activity_subtype",scale:null,offset:0,units:""},7:{field:"activity_level",type:"activity_level",scale:null,offset:0,units:"s"},8:{field:"distance16",type:"uint16",scale:null,offset:0,units:"m"},9:{field:"cycles16",type:"uint16",scale:null,offset:0,units:"cycles"},10:{field:"active_time16",type:"uint16",scale:null,offset:0,units:""},11:{field:"local_timestamp",type:"uint32",scale:null,offset:0,units:""},12:{field:"temperature",type:"float32",scale:null,offset:0,units:"C"},14:{field:"temperature_min",type:"float32",scale:null,offset:0,units:"C"},15:{field:"temperature_max",type:"float32",scale:null,offset:0,units:"C"},16:{field:"activity_time",type:"int32",scale:null,offset:0,units:""},19:{field:"active_calories",type:"uint16",scale:null,offset:0,units:"kcal"},24:{field:"current_activity_type_intensity",type:"uint8",scale:null,offset:0,units:""},25:{field:"timestamp_min8",type:"uint8",scale:null,offset:0,units:""},26:{field:"timestamp16",type:"uint16",scale:null,offset:0,units:""},27:{field:"heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},28:{field:"intensity",type:"uint8",scale:null,offset:0,units:""},29:{field:"duration_min",type:"uint16",scale:null,offset:0,units:""},30:{field:"duration",type:"uint32",scale:null,offset:0,units:""},31:{field:"ascent",type:"float32",scale:null,offset:0,units:"m"},32:{field:"descent",type:"float32",scale:null,offset:0,units:"m"},33:{field:"moderate_activity_minutes",type:"uint16",scale:null,offset:0,units:""},34:{field:"vigorous_activity_inutes",type:"uint16",scale:null,offset:0,units:""}},78:{name:"hrv",0:{field:"time",type:"uint16_array",scale:1e3,offset:0,units:"s"}},101:{name:"length",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"event",type:"event",scale:null,offset:0,units:""},1:{field:"event_type",type:"event_type",scale:null,offset:0,units:""},2:{field:"start_time",type:"date_time",scale:null,offset:0,units:""},3:{field:"total_elapsed_time",type:"uint32",scale:1e3,offset:0,units:"s"},4:{field:"total_timer_time",type:"uint32",scale:1e3,offset:0,units:"s"},5:{field:"total_strokes",type:"uint16",scale:null,offset:0,units:"strokes"},6:{field:"avg_speed",type:"uint16",scale:1e3,offset:0,units:"m/s"},7:{field:"swim_stroke",type:"swim_stroke",scale:null,offset:0,units:"swim_stroke"},9:{field:"avg_swimming_cadence",type:"uint8",scale:null,offset:0,units:"strokes/min"},10:{field:"event_group",type:"uint8",scale:null,offset:0,units:""},11:{field:"total_calories",type:"uint16",scale:null,offset:0,units:"kcal"},12:{field:"length_type",type:"length_type",scale:null,offset:0,units:"length_type"},18:{field:"player_score",type:"uint16",scale:null,offset:0,units:""},19:{field:"opponent_score",type:"uint16",scale:null,offset:0,units:""},20:{field:"stroke_count",type:"uint16",scale:null,offset:0,units:"counts"},21:{field:"zone_count",type:"uint16",scale:null,offset:0,units:"counts"}},103:{name:"monitoring_info",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:""},0:{field:"local_timestamp",type:"uint32",scale:null,offset:0,units:""},1:{field:"activity_type",type:"activity_type",scale:null,offset:0,units:""},3:{field:"cycles_to_distance",type:"float32",scale:null,offset:0,units:"cycles"},4:{field:"cycles_to_calories",type:"float32",scale:null,offset:0,units:"kcal"},5:{field:"resting_metabolic_rate",type:"uint16",scale:null,offset:0,units:""}},108:{name:"o_hr_settings",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:""},0:{field:"enabled",type:"byte",scale:null,offset:0,units:""}},140:{name:"activity_metrics",1:{field:"new_max_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},4:{field:"aerobic_training_effect",type:"uint8",scale:10,offset:0,units:""},7:{field:"vo2_max",type:"uint32",scale:65536/3.5,offset:0,units:"ml/kg/min"},9:{field:"recovery_time",type:"uint16",scale:null,offset:0,units:"min"},11:{field:"sport",type:"sport",scale:null,offset:0,units:""},20:{field:"anaerobic_training_effect",type:"uint8",scale:10,offset:0,units:""},29:{field:"first_vo2_max",type:"uint32",scale:65536/3.5,offset:0,units:"ml/kg/min"},41:{field:"primary_benefit",type:"uint8",scale:null,offset:0,units:""},60:{field:"total_ascent",type:"uint16",scale:null,offset:0,units:"m"},61:{field:"total_descent",type:"uint16",scale:null,offset:0,units:"m"},62:{field:"avg_power",type:"uint16",scale:null,offset:0,units:"watts"},63:{field:"avg_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"}},206:{name:"field_description",0:{field:"developer_data_index",type:"uint8",scale:null,offset:0,units:""},1:{field:"field_definition_number",type:"uint8",scale:null,offset:0,units:""},2:{field:"fit_base_type_id",type:"uint8",scale:null,offset:0,units:""},3:{field:"field_name",type:"string",scale:null,offset:0,units:""},6:{field:"scale",type:"uint8",scale:null,offset:0,units:""},7:{field:"offset",type:"sint8",scale:null,offset:0,units:""},8:{field:"units",type:"string",scale:null,offset:0,units:""},15:{field:"native_field_num",type:"uint8",scale:null,offset:0,units:""}},227:{name:"stress_level",0:{field:"stress_level_value",type:"uint16",scale:null,offset:0,units:""},1:{field:"stress_level_time",type:"date_time",scale:null,offset:0,units:"s"},2:{field:"field_two",type:"sint8",scale:null,offset:0,units:""},3:{field:"body_battery",type:"uint8",scale:null,offset:0,units:""},4:{field:"field_four",type:"uint8",scale:null,offset:0,units:""}},207:{name:"developer_data_id",0:{field:"developer_id",type:"uint8",scale:null,offset:0,units:""},1:{field:"application_id",type:"byte_array",scale:null,offset:0,units:""},2:{field:"manufacturer_id",type:"manufacturer",scale:null,offset:0,units:""},3:{field:"developer_data_index",type:"uint8",scale:null,offset:0,units:""},4:{field:"application_version",type:"uint8",scale:null,offset:0,units:""}},258:{name:"dive_settings",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"name",type:"string",scale:null,offset:0,units:""},1:{field:"model",type:"tissue_model_type",scale:null,offset:0,units:""},2:{field:"gf_low",type:"uint8",scale:null,offset:0,units:"percent"},3:{field:"gf_high",type:"uint8",scale:null,offset:0,units:"percent"},4:{field:"water_type",type:"water_type",scale:null,offset:0,units:""},5:{field:"water_density",type:"float32",scale:null,offset:0,units:"kg/m^3"},6:{field:"po2_warn",type:"uint8",scale:null,offset:0,units:"percent"},7:{field:"po2_critical",type:"uint8",scale:null,offset:0,units:"percent"},8:{field:"po2_deco",type:"uint8",scale:null,offset:0,units:"percent"},9:{field:"safety_stop_enabled",type:"bool",scale:null,offset:0,units:""},10:{field:"bottom_depth",type:"float32",scale:null,offset:0,units:""},11:{field:"bottom_time",type:"uint32",scale:null,offset:0,units:""},12:{field:"apnea_countdown_enabled",type:"bool",scale:null,offset:0,units:""},13:{field:"apnea_countdown_time",type:"uint32",scale:null,offset:0,units:""},14:{field:"backlight_mode",type:"dive_backlight_mode",scale:null,offset:0,units:""},15:{field:"backlight_brightness",type:"uint8",scale:null,offset:0,units:""},16:{field:"backlight_timeout",type:"backlight_timeout",scale:null,offset:0,units:""},17:{field:"repeat_dive_time",type:"uint16",scale:null,offset:0,units:"s"},18:{field:"safety_stop_time",type:"uint16",scale:null,offset:0,units:"s"},19:{field:"heart_rate_source_type",type:"source_type",scale:null,offset:0,units:""},20:{field:"heart_rate_source",type:"uint8",scale:null,offset:0,units:""}},259:{name:"dive_gas",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"helium_content",type:"uint8",scale:null,offset:0,units:"percent"},1:{field:"oxygen_content",type:"uint8",scale:null,offset:0,units:"percent"},2:{field:"status",type:"dive_gas_status",scale:null,offset:0,units:""}},262:{name:"dive_alarm",254:{field:"message_index",type:"message_index",scale:null,offset:0,units:""},0:{field:"depth",type:"uint32",scale:null,offset:0,units:"m"},1:{field:"time",type:"sint32",scale:null,offset:0,units:"s"},2:{field:"enabled",type:"bool",scale:null,offset:0,units:""},3:{field:"alarm_type",type:"dive_alarm_type",scale:null,offset:0,units:""},4:{field:"sound",type:"tone",scale:null,offset:0,units:""},5:{field:"dive_types",type:"sub_sport",scale:null,offset:0,units:""}},268:{name:"dive_summary",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"reference_mesg",type:"mesg_num",scale:null,offset:0,units:""},1:{field:"reference_index",type:"message_index",scale:null,offset:0,units:""},2:{field:"avg_depth",type:"uint32",scale:null,offset:0,units:"m"},3:{field:"max_depth",type:"uint32",scale:null,offset:0,units:"m"},4:{field:"surface_interval",type:"uint32",scale:null,offset:0,units:"s"},5:{field:"start_cns",type:"uint8",scale:null,offset:0,units:"percent"},6:{field:"end_cns",type:"uint8",scale:null,offset:0,units:"percent"},7:{field:"start_n2",type:"uint16",scale:null,offset:0,units:"percent"},8:{field:"end_n2",type:"uint16",scale:null,offset:0,units:"percent"},9:{field:"o2_toxicity",type:"uint16",scale:null,offset:0,units:"OTUs"},10:{field:"dive_number",type:"uint32",scale:null,offset:0,units:""},11:{field:"bottom_time",type:"uint32",scale:null,offset:0,units:"s"}},319:{name:"tank_update",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"sensor",type:"uint32",scale:null,offset:0,units:""},1:{field:"pressure",type:"uint16",scale:null,offset:0,units:"cbar"}},323:{name:"tank_summary",0:{field:"sensor",type:"uint32",scale:null,offset:0,units:""},1:{field:"start_pressure",type:"uint16",scale:null,offset:0,units:"cbar"},2:{field:"end_pressure",type:"uint16",scale:null,offset:0,units:"cbar"},3:{field:"volume_used",type:"uint16",scale:null,offset:0,units:"cbar"}},216:{name:"time_in_zone",253:{field:"timestamp",type:"date_time",scale:null,offset:0,units:"s"},0:{field:"reference_mesg",type:"uint16",scale:null,offset:0,units:""},1:{field:"reference_index",type:"uint16",scale:null,offset:0,units:""},2:{field:"time_in_hr_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},3:{field:"time_in_speed_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},4:{field:"time_in_power_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},5:{field:"time_in_power_zone",type:"uint32_array",scale:1e3,offset:0,units:"s"},6:{field:"hr_zone_high_boundary",type:"uint8_array",scale:null,offset:0,units:"bpm"},7:{field:"speed_zone_high_boundary",type:"uint16_array",scale:1e3,offset:0,units:"m/s"},8:{field:"power_zone_high_boundary",type:"uint16_array",scale:null,offset:0,units:"watts"},9:{field:"power_zone_high_boundary",type:"uint16_array",scale:null,offset:0,units:"watts"},10:{field:"max_heart_rate_deprecated",type:"uint8",scale:null,offset:0,units:"bpm"},11:{field:"max_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},12:{field:"resting_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},13:{field:"threshold_heart_rate",type:"uint8",scale:null,offset:0,units:"bpm"},14:{field:"pwr_calc_type",type:"pwr_zone_calc",scale:null,offset:0,units:""},15:{field:"functional_threshold_power",type:"uint16",scale:null,offset:0,units:"watts"}}},types:{file:{1:"device",2:"settings",3:"sport",4:"activity",5:"workout",6:"course",7:"schedules",9:"weight",10:"totals",11:"goals",14:"blood_pressure",15:"monitoring_a",20:"activity_summary",28:"monitoring_daily",32:"monitoring_b",34:"segment",35:"segment_list",40:"exd_configuration",247:"mfg_range_min",254:"mfg_range_max"},mesg_num:{0:"file_id",1:"capabilities",2:"device_settings",3:"user_profile",4:"hrm_profile",5:"sdm_profile",6:"bike_profile",7:"zones_target",8:"hr_zone",9:"power_zone",10:"met_zone",12:"sport",15:"goal",18:"session",19:"lap",20:"record",21:"event",23:"device_info",26:"workout",27:"workout_step",28:"schedule",30:"weight_scale",31:"course",32:"course_point",33:"totals",34:"activity",35:"software",37:"file_capabilities",38:"mesg_capabilities",39:"field_capabilities",49:"file_creator",51:"blood_pressure",53:"speed_zone",55:"monitoring",72:"training_file",78:"hrv",80:"ant_rx",81:"ant_tx",82:"ant_channel_id",101:"length",103:"monitoring_info",105:"pad",106:"slave_device",127:"connectivity",128:"weather_conditions",129:"weather_alert",131:"cadence_zone",132:"hr",140:"activity_metrics",142:"segment_lap",145:"memo_glob",148:"segment_id",149:"segment_leaderboard_entry",150:"segment_point",151:"segment_file",158:"workout_session",159:"watchface_settings",160:"gps_metadata",161:"camera_event",162:"timestamp_correlation",164:"gyroscope_data",165:"accelerometer_data",167:"three_d_sensor_calibration",169:"video_frame",174:"obdii_data",177:"nmea_sentence",178:"aviation_attitude",184:"video",185:"video_title",186:"video_description",187:"video_clip",200:"exd_screen_configuration",201:"exd_data_field_configuration",202:"exd_data_concept_configuration",206:"field_description",207:"developer_data_id",208:"magnetometer_data",209:"barometer_data",210:"one_d_sensor_calibration",225:"set",227:"stress_level",258:"dive_settings",259:"dive_gas",262:"dive_alarm",264:"exercise_title",268:"dive_summary",285:"jump",317:"climb_pro",319:"tank_update",323:"tank_summary",216:"time_in_zone",347:"o_hr_settings",65280:"mfg_range_min",65534:"mfg_range_max"},checksum:{0:"clear",1:"ok"},file_flags:{0:0,2:"read",4:"write",8:"erase"},mesg_count:{0:"num_per_file",1:"max_per_file",2:"max_per_file_type"},date_time:{0:0,268435456:"min"},local_date_time:{0:0,268435456:"min"},message_index:{0:0,4095:"mask",28672:"reserved",32768:"selected"},gender:{0:"female",1:"male"},language:{0:"english",1:"french",2:"italian",3:"german",4:"spanish",5:"croatian",6:"czech",7:"danish",8:"dutch",9:"finnish",10:"greek",11:"hungarian",12:"norwegian",13:"polish",14:"portuguese",15:"slovakian",16:"slovenian",17:"swedish",18:"russian",19:"turkish",20:"latvian",21:"ukrainian",22:"arabic",23:"farsi",24:"bulgarian",25:"romanian",26:"chinese",27:"japanese",28:"korean",29:"taiwanese",30:"thai",31:"hebrew",32:"brazilian_portuguese",33:"indonesian",34:"malaysian",35:"vietnamese",36:"burmese",37:"mongolian",254:"custom"},language_bits_0:{0:0,1:"english",2:"french",4:"italian",8:"german",16:"spanish",32:"croatian",64:"czech",128:"danish"},language_bits_1:{0:0,1:"dutch",2:"finnish",4:"greek",8:"hungarian",16:"norwegian",32:"polish",64:"portuguese",128:"slovakian"},language_bits_2:{0:0,1:"slovenian",2:"swedish",4:"russian",8:"turkish",16:"latvian",32:"ukrainian",64:"arabic",128:"farsi"},language_bits_3:{0:0,1:"bulgarian",2:"romanian",4:"chinese",8:"japanese",16:"korean",32:"taiwanese",64:"thai",128:"hebrew"},language_bits_4:{0:0,1:"brazilian_portuguese",2:"indonesian",4:"malaysian",8:"vietnamese",16:"burmese",32:"mongolian"},time_zone:{0:"almaty",1:"bangkok",2:"bombay",3:"brasilia",4:"cairo",5:"cape_verde_is",6:"darwin",7:"eniwetok",8:"fiji",9:"hong_kong",10:"islamabad",11:"kabul",12:"magadan",13:"mid_atlantic",14:"moscow",15:"muscat",16:"newfoundland",17:"samoa",18:"sydney",19:"tehran",20:"tokyo",21:"us_alaska",22:"us_atlantic",23:"us_central",24:"us_eastern",25:"us_hawaii",26:"us_mountain",27:"us_pacific",28:"other",29:"auckland",30:"kathmandu",31:"europe_western_wet",32:"europe_central_cet",33:"europe_eastern_eet",34:"jakarta",35:"perth",36:"adelaide",37:"brisbane",38:"tasmania",39:"iceland",40:"amsterdam",41:"athens",42:"barcelona",43:"berlin",44:"brussels",45:"budapest",46:"copenhagen",47:"dublin",48:"helsinki",49:"lisbon",50:"london",51:"madrid",52:"munich",53:"oslo",54:"paris",55:"prague",56:"reykjavik",57:"rome",58:"stockholm",59:"vienna",60:"warsaw",61:"zurich",62:"quebec",63:"ontario",64:"manitoba",65:"saskatchewan",66:"alberta",67:"british_columbia",68:"boise",69:"boston",70:"chicago",71:"dallas",72:"denver",73:"kansas_city",74:"las_vegas",75:"los_angeles",76:"miami",77:"minneapolis",78:"new_york",79:"new_orleans",80:"phoenix",81:"santa_fe",82:"seattle",83:"washington_dc",84:"us_arizona",85:"chita",86:"ekaterinburg",87:"irkutsk",88:"kaliningrad",89:"krasnoyarsk",90:"novosibirsk",91:"petropavlovsk_kamchatskiy",92:"samara",93:"vladivostok",94:"mexico_central",95:"mexico_mountain",96:"mexico_pacific",97:"cape_town",98:"winkhoek",99:"lagos",100:"riyahd",101:"venezuela",102:"australia_lh",103:"santiago",253:"manual",254:"automatic"},display_measure:{0:"metric",1:"statute",2:"nautical"},display_heart:{0:"bpm",1:"max",2:"reserve"},display_power:{0:"watts",1:"percent_ftp"},display_position:{0:"degree",1:"degree_minute",2:"degree_minute_second",3:"austrian_grid",4:"british_grid",5:"dutch_grid",6:"hungarian_grid",7:"finnish_grid",8:"german_grid",9:"icelandic_grid",10:"indonesian_equatorial",11:"indonesian_irian",12:"indonesian_southern",13:"india_zone_0",14:"india_zone_IA",15:"india_zone_IB",16:"india_zone_IIA",17:"india_zone_IIB",18:"india_zone_IIIA",19:"india_zone_IIIB",20:"india_zone_IVA",21:"india_zone_IVB",22:"irish_transverse",23:"irish_grid",24:"loran",25:"maidenhead_grid",26:"mgrs_grid",27:"new_zealand_grid",28:"new_zealand_transverse",29:"qatar_grid",30:"modified_swedish_grid",31:"swedish_grid",32:"south_african_grid",33:"swiss_grid",34:"taiwan_grid",35:"united_states_grid",36:"utm_ups_grid",37:"west_malayan",38:"borneo_rso",39:"estonian_grid",40:"latvian_grid",41:"swedish_ref_99_grid"},switch:{0:"off",1:"on",2:"auto"},sport:{0:"generic",1:"running",2:"cycling",3:"transition",4:"fitness_equipment",5:"swimming",6:"basketball",7:"soccer",8:"tennis",9:"american_football",10:"training",11:"walking",12:"cross_country_skiing",13:"alpine_skiing",14:"snowboarding",15:"rowing",16:"mountaineering",17:"hiking",18:"multisport",19:"paddling",20:"flying",21:"e_biking",22:"motorcycling",23:"boating",24:"driving",25:"golf",26:"hang_gliding",27:"horseback_riding",28:"hunting",29:"fishing",30:"inline_skating",31:"rock_climbing",32:"sailing",33:"ice_skating",34:"sky_diving",35:"snowshoeing",36:"snowmobiling",37:"stand_up_paddleboarding",38:"surfing",39:"wakeboarding",40:"water_skiing",41:"kayaking",42:"rafting",43:"windsurfing",44:"kitesurfing",45:"tactical",46:"jumpmaster",47:"boxing",48:"floor_climbing",53:"diving",254:"all"},sport_bits_0:{0:0,1:"generic",2:"running",4:"cycling",8:"transition",16:"fitness_equipment",32:"swimming",64:"basketball",128:"soccer"},sport_bits_1:{0:0,1:"tennis",2:"american_football",4:"training",8:"walking",16:"cross_country_skiing",32:"alpine_skiing",64:"snowboarding",128:"rowing"},sport_bits_2:{0:0,1:"mountaineering",2:"hiking",4:"multisport",8:"paddling",16:"flying",32:"e_biking",64:"motorcycling",128:"boating"},sport_bits_3:{0:0,1:"driving",2:"golf",4:"hang_gliding",8:"horseback_riding",16:"hunting",32:"fishing",64:"inline_skating",128:"rock_climbing"},sport_bits_4:{0:0,1:"sailing",2:"ice_skating",4:"sky_diving",8:"snowshoeing",16:"snowmobiling",32:"stand_up_paddleboarding",64:"surfing",128:"wakeboarding"},sport_bits_5:{0:0,1:"water_skiing",2:"kayaking",4:"rafting",8:"windsurfing",16:"kitesurfing",32:"tactical",64:"jumpmaster",128:"boxing"},sport_bits_6:{0:0,1:"floor_climbing"},sub_sport:{0:"generic",1:"treadmill",2:"street",3:"trail",4:"track",5:"spin",6:"indoor_cycling",7:"road",8:"mountain",9:"downhill",10:"recumbent",11:"cyclocross",12:"hand_cycling",13:"track_cycling",14:"indoor_rowing",15:"elliptical",16:"stair_climbing",17:"lap_swimming",18:"open_water",19:"flexibility_training",20:"strength_training",21:"warm_up",22:"match",23:"exercise",24:"challenge",25:"indoor_skiing",26:"cardio_training",27:"indoor_walking",28:"e_bike_fitness",29:"bmx",30:"casual_walking",31:"speed_walking",32:"bike_to_run_transition",33:"run_to_bike_transition",34:"swim_to_bike_transition",35:"atv",36:"motocross",37:"backcountry",38:"resort",39:"rc_drone",40:"wingsuit",41:"whitewater",42:"skate_skiing",43:"yoga",44:"pilates",45:"indoor_running",46:"gravel_cycling",47:"e_bike_mountain",48:"commuting",49:"mixed_surface",50:"navigate",51:"track_me",52:"map",53:"single_gas_diving",54:"multi_gas_diving",55:"gauge_diving",56:"apnea_diving",57:"apnea_hunting",58:"virtual_activity",59:"obstacle",254:"all"},sport_event:{0:"uncategorized",1:"geocaching",2:"fitness",3:"recreation",4:"race",5:"special_event",6:"training",7:"transportation",8:"touring"},activity:{0:"manual",1:"auto_multi_sport"},intensity:{0:"active",1:"rest",2:"warmup",3:"cooldown",4:"recovery",5:"interval",6:"other"},session_trigger:{0:"activity_end",1:"manual",2:"auto_multi_sport",3:"fitness_equipment"},autolap_trigger:{0:"time",1:"distance",2:"position_start",3:"position_lap",4:"position_waypoint",5:"position_marked",6:"off"},lap_trigger:{0:"manual",1:"time",2:"distance",3:"position_start",4:"position_lap",5:"position_waypoint",6:"position_marked",7:"session_end",8:"fitness_equipment"},time_mode:{0:"hour12",1:"hour24",2:"military",3:"hour_12_with_seconds",4:"hour_24_with_seconds",5:"utc"},backlight_mode:{0:"off",1:"manual",2:"key_and_messages",3:"auto_brightness",4:"smart_notifications",5:"key_and_messages_night",6:"key_and_messages_and_smart_notifications"},date_mode:{0:"day_month",1:"month_day"},backlight_timeout:{0:"infinite"},event:{0:"timer",3:"workout",4:"workout_step",5:"power_down",6:"power_up",7:"off_course",8:"session",9:"lap",10:"course_point",11:"battery",12:"virtual_partner_pace",13:"hr_high_alert",14:"hr_low_alert",15:"speed_high_alert",16:"speed_low_alert",17:"cad_high_alert",18:"cad_low_alert",19:"power_high_alert",20:"power_low_alert",21:"recovery_hr",22:"battery_low",23:"time_duration_alert",24:"distance_duration_alert",25:"calorie_duration_alert",26:"activity",27:"fitness_equipment",28:"length",32:"user_marker",33:"sport_point",36:"calibration",42:"front_gear_change",43:"rear_gear_change",44:"rider_position_change",45:"elev_high_alert",46:"elev_low_alert",47:"comm_timeout"},event_type:{0:"start",1:"stop",2:"consecutive_depreciated",3:"marker",4:"stop_all",5:"begin_depreciated",6:"end_depreciated",7:"end_all_depreciated",8:"stop_disable",9:"stop_disable_all"},timer_trigger:{0:"manual",1:"auto",2:"fitness_equipment"},fitness_equipment_state:{0:"ready",1:"in_use",2:"paused",3:"unknown"},tone:{0:"off",1:"tone",2:"vibrate",3:"tone_and_vibrate"},autoscroll:{0:"none",1:"slow",2:"medium",3:"fast"},activity_class:{0:0,100:"level_max",127:"level",128:"athlete"},hr_zone_calc:{0:"custom",1:"percent_max_hr",2:"percent_hrr"},pwr_zone_calc:{0:"custom",1:"percent_ftp"},wkt_step_duration:{0:"time",1:"distance",2:"hr_less_than",3:"hr_greater_than",4:"calories",5:"open",6:"repeat_until_steps_cmplt",7:"repeat_until_time",8:"repeat_until_distance",9:"repeat_until_calories",10:"repeat_until_hr_less_than",11:"repeat_until_hr_greater_than",12:"repeat_until_power_less_than",13:"repeat_until_power_greater_than",14:"power_less_than",15:"power_greater_than",16:"training_peaks_tss",17:"repeat_until_power_last_lap_less_than",18:"repeat_until_max_power_last_lap_less_than",19:"power_3s_less_than",20:"power_10s_less_than",21:"power_30s_less_than",22:"power_3s_greater_than",23:"power_10s_greater_than",24:"power_30s_greater_than",25:"power_lap_less_than",26:"power_lap_greater_than",27:"repeat_until_training_peaks_tss",28:"repetition_time",29:"reps"},wkt_step_target:{0:"speed",1:"heart_rate",2:"open",3:"cadence",4:"power",5:"grade",6:"resistance",7:"power_3s",8:"power_10s",9:"power_30s",10:"power_lap",11:"swim_stroke",12:"speed_lap",13:"heart_rate_lap"},goal:{0:"time",1:"distance",2:"calories",3:"frequency",4:"steps",5:"ascent",6:"active_minutes"},goal_recurrence:{0:"off",1:"daily",2:"weekly",3:"monthly",4:"yearly",5:"custom"},goal_source:{0:"auto",1:"community",2:"user"},schedule:{0:"workout",1:"course"},course_point:{0:"generic",1:"summit",2:"valley",3:"water",4:"food",5:"danger",6:"left",7:"right",8:"straight",9:"first_aid",10:"fourth_category",11:"third_category",12:"second_category",13:"first_category",14:"hors_category",15:"sprint",16:"left_fork",17:"right_fork",18:"middle_fork",19:"slight_left",20:"sharp_left",21:"slight_right",22:"sharp_right",23:"u_turn",24:"segment_start",25:"segment_end"},manufacturer:{0:0,1:"garmin",2:"garmin_fr405_antfs",3:"zephyr",4:"dayton",5:"idt",6:"srm",7:"quarq",8:"ibike",9:"saris",10:"spark_hk",11:"tanita",12:"echowell",13:"dynastream_oem",14:"nautilus",15:"dynastream",16:"timex",17:"metrigear",18:"xelic",19:"beurer",20:"cardiosport",21:"a_and_d",22:"hmm",23:"suunto",24:"thita_elektronik",25:"gpulse",26:"clean_mobile",27:"pedal_brain",28:"peaksware",29:"saxonar",30:"lemond_fitness",31:"dexcom",32:"wahoo_fitness",33:"octane_fitness",34:"archinoetics",35:"the_hurt_box",36:"citizen_systems",37:"magellan",38:"osynce",39:"holux",40:"concept2",42:"one_giant_leap",43:"ace_sensor",44:"brim_brothers",45:"xplova",46:"perception_digital",47:"bf1systems",48:"pioneer",49:"spantec",50:"metalogics",51:"4iiiis",52:"seiko_epson",53:"seiko_epson_oem",54:"ifor_powell",55:"maxwell_guider",56:"star_trac",57:"breakaway",58:"alatech_technology_ltd",59:"mio_technology_europe",60:"rotor",61:"geonaute",62:"id_bike",63:"specialized",64:"wtek",65:"physical_enterprises",66:"north_pole_engineering",67:"bkool",68:"cateye",69:"stages_cycling",70:"sigmasport",71:"tomtom",72:"peripedal",73:"wattbike",76:"moxy",77:"ciclosport",78:"powerbahn",79:"acorn_projects_aps",80:"lifebeam",81:"bontrager",82:"wellgo",83:"scosche",84:"magura",85:"woodway",86:"elite",87:"nielsen_kellerman",88:"dk_city",89:"tacx",90:"direction_technology",91:"magtonic",92:"1partcarbon",93:"inside_ride_technologies",94:"sound_of_motion",95:"stryd",96:"icg",97:"mipulse",98:"bsx_athletics",99:"look",100:"campagnolo_srl",101:"body_bike_smart",102:"praxisworks",103:"limits_technology",104:"topaction_technology",105:"cosinuss",106:"fitcare",107:"magene",108:"giant_manufacturing_co",109:"tigrasport",110:"salutron",111:"technogym",112:"bryton_sensors",113:"latitude_limited",114:"soaring_technology",115:"igpsport",116:"thinkrider",117:"gopher_sport",118:"waterrower",119:"orangetheory",120:"inpeak",121:"kinetic",122:"johnson_health_tech",123:"polar_electro",124:"seesense",125:"nci_technology",255:"development",257:"healthandlife",258:"lezyne",259:"scribe_labs",260:"zwift",261:"watteam",262:"recon",263:"favero_electronics",264:"dynovelo",265:"strava",266:"precor",267:"bryton",268:"sram",269:"navman",270:"cobi",271:"spivi",272:"mio_magellan",273:"evesports",274:"sensitivus_gauge",275:"podoon",276:"life_time_fitness",277:"falco_e_motors",278:"minoura",279:"cycliq",280:"luxottica",281:"trainer_road",282:"the_sufferfest",283:"fullspeedahead",284:"virtualtraining",285:"feedbacksports",286:"omata",287:"vdo",288:"magneticdays",289:"hammerhead",290:"kinetic_by_kurt",291:"shapelog",292:"dabuziduo",293:"jetblack",294:"coros",295:"virtugo",296:"velosense",5759:"actigraphcorp"},garmin_product:{0:"hrm_bike",1:"hrm1",2:"axh01",3:"axb01",4:"axb02",5:"hrm2ss",6:"dsi_alf02",7:"hrm3ss",8:"hrm_run_single_byte_product_id",9:"bsm",10:"bcm",11:"axs01",12:"hrm_tri_single_byte_product_id",14:"fr225_single_byte_product_id",473:"fr301_china",474:"fr301_japan",475:"fr301_korea",494:"fr301_taiwan",717:"fr405",782:"fr50",987:"fr405_japan",988:"fr60",1011:"dsi_alf01",1018:"fr310xt",1036:"edge500",1124:"fr110",1169:"edge800",1199:"edge500_taiwan",1213:"edge500_japan",1253:"chirp",1274:"fr110_japan",1325:"edge200",1328:"fr910xt",1333:"edge800_taiwan",1334:"edge800_japan",1341:"alf04",1345:"fr610",1360:"fr210_japan",1380:"vector_ss",1381:"vector_cp",1386:"edge800_china",1387:"edge500_china",1410:"fr610_japan",1422:"edge500_korea",1436:"fr70",1446:"fr310xt_4t",1461:"amx",1482:"fr10",1497:"edge800_korea",1499:"swim",1537:"fr910xt_china",1551:"fenix",1555:"edge200_taiwan",1561:"edge510",1567:"edge810",1570:"tempe",1600:"fr910xt_japan",1623:"fr620",1632:"fr220",1664:"fr910xt_korea",1688:"fr10_japan",1721:"edge810_japan",1735:"virb_elite",1736:"edge_touring",1742:"edge510_japan",1743:"hrm_tri",1752:"hrm_run",1765:"fr920xt",1821:"edge510_asia",1822:"edge810_china",1823:"edge810_taiwan",1836:"edge1000",1837:"vivo_fit",1853:"virb_remote",1885:"vivo_ki",1903:"fr15",1907:"vivo_active",1918:"edge510_korea",1928:"fr620_japan",1929:"fr620_china",1930:"fr220_japan",1931:"fr220_china",1936:"approach_s6",1956:"vivo_smart",1967:"fenix2",1988:"epix",2050:"fenix3",2052:"edge1000_taiwan",2053:"edge1000_japan",2061:"fr15_japan",2067:"edge520",2070:"edge1000_china",2072:"fr620_russia",2073:"fr220_russia",2079:"vector_s",2100:"edge1000_korea",2130:"fr920xt_taiwan",2131:"fr920xt_china",2132:"fr920xt_japan",2134:"virbx",2135:"vivo_smart_apac",2140:"etrex_touch",2147:"edge25",2148:"fr25",2150:"vivo_fit2",2153:"fr225",2156:"fr630",2157:"fr230",2158:"fr735xt",2160:"vivo_active_apac",2161:"vector_2",2162:"vector_2s",2172:"virbxe",2173:"fr620_taiwan",2174:"fr220_taiwan",2175:"truswing",2188:"fenix3_china",2189:"fenix3_twn",2192:"varia_headlight",2193:"varia_taillight_old",2204:"edge_explore_1000",2219:"fr225_asia",2225:"varia_radar_taillight",2226:"varia_radar_display",2238:"edge20",2262:"d2_bravo",2266:"approach_s20",2276:"varia_remote",2327:"hrm4_run",2337:"vivo_active_hr",2348:"vivo_smart_hr",2368:"vivo_move",2398:"varia_vision",2406:"vivo_fit3",2413:"fenix3_hr",2417:"virb_ultra_30",2429:"index_smart_scale",2431:"fr235",2432:"fenix3_chronos",2441:"oregon7xx",2444:"rino7xx",2496:"nautix",2530:"edge_820",2531:"edge_explore_820",2544:"fenix5s",2547:"d2_bravo_titanium",2567:"varia_ut800",2593:"running_dynamics_pod",2604:"fenix5x",2606:"vivo_fit_jr",2691:"fr935",2697:"fenix5",2859:"descent",10007:"sdm4",10014:"edge_remote",20119:"training_center",65531:"connectiq_simulator",65532:"android_antplus_plugin",65534:"connect"},antplus_device_type:{1:"antfs",11:"bike_power",12:"environment_sensor_legacy",15:"multi_sport_speed_distance",16:"control",17:"fitness_equipment",18:"blood_pressure",19:"geocache_node",20:"light_electric_vehicle",25:"env_sensor",26:"racquet",27:"control_hub",31:"muscle_oxygen",34:"shifting",35:"bike_light_main",36:"bike_light_shared",38:"exd",40:"bike_radar",46:"bike_aero",119:"weight_scale",120:"heart_rate",121:"bike_speed_cadence",122:"bike_cadence",123:"bike_speed",124:"stride_speed_distance"},local_device_type:{0:"gps",1:"glonass",2:"gps_glonass",3:"accelerometer",4:"barometer",5:"temperature",10:"whr",12:"sensor_hub"},ble_device_type:{0:"connected_gps",1:"heart_rate",2:"bike_power",3:"bike_speed_cadence",4:"bike_speed",5:"bike_cadence",6:"footpod",7:"bike_trainer"},ant_network:{0:"public",1:"antplus",2:"antfs",3:"private"},workout_capabilities:{0:0,1:"interval",2:"custom",4:"fitness_equipment",8:"firstbeat",16:"new_leaf",32:"tcx",128:"speed",256:"heart_rate",512:"distance",1024:"cadence",2048:"power",4096:"grade",8192:"resistance",16384:"protected"},battery_status:{0:0,1:"new",2:"good",3:"ok",4:"low",5:"critical",6:"charging",7:"unknown"},hr_type:{0:"normal",1:"irregular"},course_capabilities:{0:0,1:"processed",2:"valid",4:"time",8:"distance",16:"position",32:"heart_rate",64:"power",128:"cadence",256:"training",512:"navigation",1024:"bikeway"},weight:{0:0,65534:"calculating"},workout_hr:{0:0,100:"bpm_offset"},workout_power:{0:0,1e3:"watts_offset"},bp_status:{0:"no_error",1:"error_incomplete_data",2:"error_no_measurement",3:"error_data_out_of_range",4:"error_irregular_heart_rate"},user_local_id:{0:"local_min",15:"local_max",16:"stationary_min",255:"stationary_max",256:"portable_min",65534:"portable_max"},swim_stroke:{0:"freestyle",1:"backstroke",2:"breaststroke",3:"butterfly",4:"drill",5:"mixed",6:"im"},activity_type:{0:"generic",1:"running",2:"cycling",3:"transition",4:"fitness_equipment",5:"swimming",6:"walking",8:"sedentary",254:"all"},activity_subtype:{0:"generic",1:"treadmill",2:"street",3:"trail",4:"track",5:"spin",6:"indoor_cycling",7:"road",8:"mountain",9:"downhill",10:"recumbent",11:"cyclocross",12:"hand_cycling",13:"track_cycling",14:"indoor_rowing",15:"elliptical",16:"stair_climbing",17:"lap_swimming",18:"open_water",254:"all"},activity_level:{0:"low",1:"medium",2:"high"},side:{0:"right",1:"left"},left_right_balance:{0:0,127:"mask",128:"right"},left_right_balance_100:{0:0,16383:"mask",32768:"right"},length_type:{0:"idle",1:"active"},day_of_week:{0:"sunday",1:"monday",2:"tuesday",3:"wednesday",4:"thursday",5:"friday",6:"saturday"},connectivity_capabilities:{0:0,1:"bluetooth",2:"bluetooth_le",4:"ant",8:"activity_upload",16:"course_download",32:"workout_download",64:"live_track",128:"weather_conditions",256:"weather_alerts",512:"gps_ephemeris_download",1024:"explicit_archive",2048:"setup_incomplete",4096:"continue_sync_after_software_update",8192:"connect_iq_app_download",16384:"golf_course_download",32768:"device_initiates_sync",65536:"connect_iq_watch_app_download",131072:"connect_iq_widget_download",262144:"connect_iq_watch_face_download",524288:"connect_iq_data_field_download",1048576:"connect_iq_app_managment",2097152:"swing_sensor",4194304:"swing_sensor_remote",8388608:"incident_detection",16777216:"audio_prompts",33554432:"wifi_verification",67108864:"true_up",134217728:"find_my_watch",268435456:"remote_manual_sync",536870912:"live_track_auto_start",1073741824:"live_track_messaging",2147483648:"instant_input"},weather_report:{0:"current",1:"hourly_forecast",2:"daily_forecast"},weather_status:{0:"clear",1:"partly_cloudy",2:"mostly_cloudy",3:"rain",4:"snow",5:"windy",6:"thunderstorms",7:"wintry_mix",8:"fog",11:"hazy",12:"hail",13:"scattered_showers",14:"scattered_thunderstorms",15:"unknown_precipitation",16:"light_rain",17:"heavy_rain",18:"light_snow",19:"heavy_snow",20:"light_rain_snow",21:"heavy_rain_snow",22:"cloudy"},weather_severity:{0:"unknown",1:"warning",2:"watch",3:"advisory",4:"statement"},weather_severe_type:{0:"unspecified",1:"tornado",2:"tsunami",3:"hurricane",4:"extreme_wind",5:"typhoon",6:"inland_hurricane",7:"hurricane_force_wind",8:"waterspout",9:"severe_thunderstorm",10:"wreckhouse_winds",11:"les_suetes_wind",12:"avalanche",13:"flash_flood",14:"tropical_storm",15:"inland_tropical_storm",16:"blizzard",17:"ice_storm",18:"freezing_rain",19:"debris_flow",20:"flash_freeze",21:"dust_storm",22:"high_wind",23:"winter_storm",24:"heavy_freezing_spray",25:"extreme_cold",26:"wind_chill",27:"cold_wave",28:"heavy_snow_alert",29:"lake_effect_blowing_snow",30:"snow_squall",31:"lake_effect_snow",32:"winter_weather",33:"sleet",34:"snowfall",35:"snow_and_blowing_snow",36:"blowing_snow",37:"snow_alert",38:"arctic_outflow",39:"freezing_drizzle",40:"storm",41:"storm_surge",42:"rainfall",43:"areal_flood",44:"coastal_flood",45:"lakeshore_flood",46:"excessive_heat",47:"heat",48:"weather",49:"high_heat_and_humidity",50:"humidex_and_health",51:"humidex",52:"gale",53:"freezing_spray",54:"special_marine",55:"squall",56:"strong_wind",57:"lake_wind",58:"marine_weather",59:"wind",60:"small_craft_hazardous_seas",61:"hazardous_seas",62:"small_craft",63:"small_craft_winds",64:"small_craft_rough_bar",65:"high_water_level",66:"ashfall",67:"freezing_fog",68:"dense_fog",69:"dense_smoke",70:"blowing_dust",71:"hard_freeze",72:"freeze",73:"frost",74:"fire_weather",75:"flood",76:"rip_tide",77:"high_surf",78:"smog",79:"air_quality",80:"brisk_wind",81:"air_stagnation",82:"low_water",83:"hydrological",84:"special_weather"},stroke_type:{0:"no_event",1:"other",2:"serve",3:"forehand",4:"backhand",5:"smash"},body_location:{0:"left_leg",1:"left_calf",2:"left_shin",3:"left_hamstring",4:"left_quad",5:"left_glute",6:"right_leg",7:"right_calf",8:"right_shin",9:"right_hamstring",10:"right_quad",11:"right_glute",12:"torso_back",13:"left_lower_back",14:"left_upper_back",15:"right_lower_back",16:"right_upper_back",17:"torso_front",18:"left_abdomen",19:"left_chest",20:"right_abdomen",21:"right_chest",22:"left_arm",23:"left_shoulder",24:"left_bicep",25:"left_tricep",26:"left_brachioradialis",27:"left_forearm_extensors",28:"right_arm",29:"right_shoulder",30:"right_bicep",31:"right_tricep",32:"right_brachioradialis",33:"right_forearm_extensors",34:"neck",35:"throat",36:"waist_mid_back",37:"waist_front",38:"waist_left",39:"waist_right"},segment_lap_status:{0:"end",1:"fail"},segment_leaderboard_type:{0:"overall",1:"personal_best",2:"connections",3:"group",4:"challenger",5:"kom",6:"qom",7:"pr",8:"goal",9:"rival",10:"club_leader"},segment_delete_status:{0:"do_not_delete",1:"delete_one",2:"delete_all"},segment_selection_type:{0:"starred",1:"suggested"},source_type:{0:"ant",1:"antplus",2:"bluetooth",3:"bluetooth_low_energy",4:"wifi",5:"local"},display_orientation:{0:"auto",1:"portrait",2:"landscape",3:"portrait_flipped",4:"landscape_flipped"},workout_equipment:{0:"none",1:"swim_fins",2:"swim_kickboard",3:"swim_paddles",4:"swim_pull_buoy",5:"swim_snorkel"},watchface_mode:{0:"digital",1:"analog",2:"connect_iq",3:"disabled"},digital_watchface_layout:{0:"traditional",1:"modern",2:"bold"},analog_watchface_layout:{0:"minimal",1:"traditional",2:"modern"},rider_position_type:{0:"seated",1:"standing",2:"transition_to_seated",3:"transition_to_standing"},power_phase_type:{0:"power_phase_start_angle",1:"power_phase_end_angle",2:"power_phase_arc_length",3:"power_phase_center"},camera_event_type:{0:"video_start",1:"video_split",2:"video_end",3:"photo_taken",4:"video_second_stream_start",5:"video_second_stream_split",6:"video_second_stream_end",7:"video_split_start",8:"video_second_stream_split_start",11:"video_pause",12:"video_second_stream_pause",13:"video_resume",14:"video_second_stream_resume"},sensor_type:{0:"accelerometer",1:"gyroscope",2:"compass",3:"barometer"},bike_light_network_config_type:{0:"auto",4:"individual",5:"high_visibility",6:"trail"},comm_timeout_type:{0:"wildcard_pairing_timeout",1:"pairing_timeout",2:"connection_lost",3:"connection_timeout"},camera_orientation_type:{0:"camera_orientation_0",1:"camera_orientation_90",2:"camera_orientation_180",3:"camera_orientation_270"},attitude_stage:{0:"failed",1:"aligning",2:"degraded",3:"valid"},attitude_validity:{0:0,1:"track_angle_heading_valid",2:"pitch_valid",4:"roll_valid",8:"lateral_body_accel_valid",16:"normal_body_accel_valid",32:"turn_rate_valid",64:"hw_fail",128:"mag_invalid",256:"no_gps",512:"gps_invalid",1024:"solution_coasting",2048:"true_track_angle",4096:"magnetic_heading"},auto_sync_frequency:{0:"never",1:"occasionally",2:"frequent",3:"once_a_day",4:"remote"},exd_layout:{0:"full_screen",1:"half_vertical",2:"half_horizontal",3:"half_vertical_right_split",4:"half_horizontal_bottom_split",5:"full_quarter_split",6:"half_vertical_left_split",7:"half_horizontal_top_split"},exd_display_type:{0:"numerical",1:"simple",2:"graph",3:"bar",4:"circle_graph",5:"virtual_partner",6:"balance",7:"string_list",8:"string",9:"simple_dynamic_icon",10:"gauge"},exd_data_units:{0:"no_units",1:"laps",2:"miles_per_hour",3:"kilometers_per_hour",4:"feet_per_hour",5:"meters_per_hour",6:"degrees_celsius",7:"degrees_farenheit",8:"zone",9:"gear",10:"rpm",11:"bpm",12:"degrees",13:"millimeters",14:"meters",15:"kilometers",16:"feet",17:"yards",18:"kilofeet",19:"miles",20:"time",21:"enum_turn_type",22:"percent",23:"watts",24:"watts_per_kilogram",25:"enum_battery_status",26:"enum_bike_light_beam_angle_mode",27:"enum_bike_light_battery_status",28:"enum_bike_light_network_config_type",29:"lights",30:"seconds",31:"minutes",32:"hours",33:"calories",34:"kilojoules",35:"milliseconds",36:"second_per_mile",37:"second_per_kilometer",38:"centimeter",39:"enum_course_point",40:"bradians",41:"enum_sport",42:"inches_hg",43:"mm_hg",44:"mbars",45:"hecto_pascals",46:"feet_per_min",47:"meters_per_min",48:"meters_per_sec",49:"eight_cardinal"},exd_qualifiers:{0:"no_qualifier",1:"instantaneous",2:"average",3:"lap",4:"maximum",5:"maximum_average",6:"maximum_lap",7:"last_lap",8:"average_lap",9:"to_destination",10:"to_go",11:"to_next",12:"next_course_point",13:"total",14:"three_second_average",15:"ten_second_average",16:"thirty_second_average",17:"percent_maximum",18:"percent_maximum_average",19:"lap_percent_maximum",20:"elapsed",21:"sunrise",22:"sunset",23:"compared_to_virtual_partner",24:"maximum_24h",25:"minimum_24h",26:"minimum",27:"first",28:"second",29:"third",30:"shifter",31:"last_sport",32:"moving",33:"stopped",34:"estimated_total",242:"zone_9",243:"zone_8",244:"zone_7",245:"zone_6",246:"zone_5",247:"zone_4",248:"zone_3",249:"zone_2",250:"zone_1"},exd_descriptors:{0:"bike_light_battery_status",1:"beam_angle_status",2:"batery_level",3:"light_network_mode",4:"number_lights_connected",5:"cadence",6:"distance",7:"estimated_time_of_arrival",8:"heading",9:"time",10:"battery_level",11:"trainer_resistance",12:"trainer_target_power",13:"time_seated",14:"time_standing",15:"elevation",16:"grade",17:"ascent",18:"descent",19:"vertical_speed",20:"di2_battery_level",21:"front_gear",22:"rear_gear",23:"gear_ratio",24:"heart_rate",25:"heart_rate_zone",26:"time_in_heart_rate_zone",27:"heart_rate_reserve",28:"calories",29:"gps_accuracy",30:"gps_signal_strength",31:"temperature",32:"time_of_day",33:"balance",34:"pedal_smoothness",35:"power",36:"functional_threshold_power",37:"intensity_factor",38:"work",39:"power_ratio",40:"normalized_power",41:"training_stress_Score",42:"time_on_zone",43:"speed",44:"laps",45:"reps",46:"workout_step",47:"course_distance",48:"navigation_distance",49:"course_estimated_time_of_arrival",50:"navigation_estimated_time_of_arrival",51:"course_time",52:"navigation_time",53:"course_heading",54:"navigation_heading",55:"power_zone",56:"torque_effectiveness",57:"timer_time",58:"power_weight_ratio",59:"left_platform_center_offset",60:"right_platform_center_offset",61:"left_power_phase_start_angle",62:"right_power_phase_start_angle",63:"left_power_phase_finish_angle",64:"right_power_phase_finish_angle",65:"gears",66:"pace",67:"training_effect",68:"vertical_oscillation",69:"vertical_ratio",70:"ground_contact_time",71:"left_ground_contact_time_balance",72:"right_ground_contact_time_balance",73:"stride_length",74:"running_cadence",75:"performance_condition",76:"course_type",77:"time_in_power_zone",78:"navigation_turn",79:"course_location",80:"navigation_location",81:"compass",82:"gear_combo",83:"muscle_oxygen",84:"icon",85:"compass_heading",86:"gps_heading",87:"gps_elevation",88:"anaerobic_training_effect",89:"course",90:"off_course",91:"glide_ratio",92:"vertical_distance",93:"vmg",94:"ambient_pressure",95:"pressure",96:"vam"},auto_activity_detect:{0:"none",1:"running",2:"cycling",4:"swimming",8:"walking",16:"elliptical",32:"sedentary"},supported_exd_screen_layouts:{0:0,1:"full_screen",2:"half_vertical",4:"half_horizontal",8:"half_vertical_right_split",16:"half_horizontal_bottom_split",32:"full_quarter_split",64:"half_vertical_left_split",128:"half_horizontal_top_split"},fit_base_type:{0:"enum",1:"sint8",2:"uint8",7:"string",10:"uint8z",13:"byte",131:"sint16",132:"uint16",133:"sint32",134:"uint32",136:"float32",137:"float64",139:"uint16z",140:"uint32z",142:"sint64",143:"uint64",144:"uint64z"},turn_type:{0:"arriving_idx",1:"arriving_left_idx",2:"arriving_right_idx",3:"arriving_via_idx",4:"arriving_via_left_idx",5:"arriving_via_right_idx",6:"bear_keep_left_idx",7:"bear_keep_right_idx",8:"continue_idx",9:"exit_left_idx",10:"exit_right_idx",11:"ferry_idx",12:"roundabout_45_idx",13:"roundabout_90_idx",14:"roundabout_135_idx",15:"roundabout_180_idx",16:"roundabout_225_idx",17:"roundabout_270_idx",18:"roundabout_315_idx",19:"roundabout_360_idx",20:"roundabout_neg_45_idx",21:"roundabout_neg_90_idx",22:"roundabout_neg_135_idx",23:"roundabout_neg_180_idx",24:"roundabout_neg_225_idx",25:"roundabout_neg_270_idx",26:"roundabout_neg_315_idx",27:"roundabout_neg_360_idx",28:"roundabout_generic_idx",29:"roundabout_neg_generic_idx",30:"sharp_turn_left_idx",31:"sharp_turn_right_idx",32:"turn_left_idx",33:"turn_right_idx",34:"uturn_left_idx",35:"uturn_right_idx",36:"icon_inv_idx",37:"icon_idx_cnt"},bike_light_beam_angle_mode:{0:"manual",1:"auto"},fit_base_unit:{0:"other",1:"kilogram",2:"pound"},set_type:{0:"rest",1:"active"},exercise_category:{0:"bench_press",1:"calf_raise",2:"cardio",3:"carry",4:"chop",5:"core",6:"crunch",7:"curl",8:"deadlift",9:"flye",10:"hip_raise",11:"hip_stability",12:"hip_swing",13:"hyperextension",14:"lateral_raise",15:"leg_curl",16:"leg_raise",17:"lunge",18:"olympic_lift",19:"plank",20:"plyo",21:"pull_up",22:"push_up",23:"row",24:"shoulder_press",25:"shoulder_stability",26:"shrug",27:"sit_up",28:"squat",29:"total_body",30:"triceps_extension",31:"warm_up",32:"run",65534:"unknown"},bench_press_exercise_name:{0:"alternating_dumbbell_chest_press_on_swiss_ball",1:"barbell_bench_press",2:"barbell_board_bench_press",3:"barbell_floor_press",4:"close_grip_barbell_bench_press",5:"decline_dumbbell_bench_press",6:"dumbbell_bench_press",7:"dumbbell_floor_press",8:"incline_barbell_bench_press",9:"incline_dumbbell_bench_press",10:"incline_smith_machine_bench_press",11:"isometric_barbell_bench_press",12:"kettlebell_chest_press",13:"neutral_grip_dumbbell_bench_press",14:"neutral_grip_dumbbell_incline_bench_press",15:"one_arm_floor_press",16:"weighted_one_arm_floor_press",17:"partial_lockout",18:"reverse_grip_barbell_bench_press",19:"reverse_grip_incline_bench_press",20:"single_arm_cable_chest_press",21:"single_arm_dumbbell_bench_press",22:"smith_machine_bench_press",23:"swiss_ball_dumbbell_chest_press",24:"triple_stop_barbell_bench_press",25:"wide_grip_barbell_bench_press",26:"alternating_dumbbell_chest_press"},calf_raise_exercise_name:{0:"3_way_calf_raise",1:"3_way_weighted_calf_raise",2:"3_way_single_leg_calf_raise",3:"3_way_weighted_single_leg_calf_raise",4:"donkey_calf_raise",5:"weighted_donkey_calf_raise",6:"seated_calf_raise",7:"weighted_seated_calf_raise",8:"seated_dumbbell_toe_raise",9:"single_leg_bent_knee_calf_raise",10:"weighted_single_leg_bent_knee_calf_raise",11:"single_leg_decline_push_up",12:"single_leg_donkey_calf_raise",13:"weighted_single_leg_donkey_calf_raise",14:"single_leg_hip_raise_with_knee_hold",15:"single_leg_standing_calf_raise",16:"single_leg_standing_dumbbell_calf_raise",17:"standing_barbell_calf_raise",18:"standing_calf_raise",19:"weighted_standing_calf_raise",20:"standing_dumbbell_calf_raise"},cardio_exercise_name:{0:"bob_and_weave_circle",1:"weighted_bob_and_weave_circle",2:"cardio_core_crawl",3:"weighted_cardio_core_crawl",4:"double_under",5:"weighted_double_under",6:"jump_rope",7:"weighted_jump_rope",8:"jump_rope_crossover",9:"weighted_jump_rope_crossover",10:"jump_rope_jog",11:"weighted_jump_rope_jog",12:"jumping_jacks",13:"weighted_jumping_jacks",14:"ski_moguls",15:"weighted_ski_moguls",16:"split_jacks",17:"weighted_split_jacks",18:"squat_jacks",19:"weighted_squat_jacks",20:"triple_under",21:"weighted_triple_under"},carry_exercise_name:{0:"bar_holds",1:"farmers_walk",2:"farmers_walk_on_toes",3:"hex_dumbbell_hold",4:"overhead_carry"},chop_exercise_name:{0:"cable_pull_through",1:"cable_rotational_lift",2:"cable_woodchop",3:"cross_chop_to_knee",4:"weighted_cross_chop_to_knee",5:"dumbbell_chop",6:"half_kneeling_rotation",7:"weighted_half_kneeling_rotation",8:"half_kneeling_rotational_chop",9:"half_kneeling_rotational_reverse_chop",10:"half_kneeling_stability_chop",11:"half_kneeling_stability_reverse_chop",12:"kneeling_rotational_chop",13:"kneeling_rotational_reverse_chop",14:"kneeling_stability_chop",15:"kneeling_woodchopper",16:"medicine_ball_wood_chops",17:"power_squat_chops",18:"weighted_power_squat_chops",19:"standing_rotational_chop",20:"standing_split_rotational_chop",21:"standing_split_rotational_reverse_chop",22:"standing_stability_reverse_chop"},core_exercise_name:{0:"abs_jabs",1:"weighted_abs_jabs",2:"alternating_plate_reach",3:"barbell_rollout",4:"weighted_barbell_rollout",5:"body_bar_oblique_twist",6:"cable_core_press",7:"cable_side_bend",8:"side_bend",9:"weighted_side_bend",10:"crescent_circle",11:"weighted_crescent_circle",12:"cycling_russian_twist",13:"weighted_cycling_russian_twist",14:"elevated_feet_russian_twist",15:"weighted_elevated_feet_russian_twist",16:"half_turkish_get_up",17:"kettlebell_windmill",18:"kneeling_ab_wheel",19:"weighted_kneeling_ab_wheel",20:"modified_front_lever",21:"open_knee_tucks",22:"weighted_open_knee_tucks",23:"side_abs_leg_lift",24:"weighted_side_abs_leg_lift",25:"swiss_ball_jackknife",26:"weighted_swiss_ball_jackknife",27:"swiss_ball_pike",28:"weighted_swiss_ball_pike",29:"swiss_ball_rollout",30:"weighted_swiss_ball_rollout",31:"triangle_hip_press",32:"weighted_triangle_hip_press",33:"trx_suspended_jackknife",34:"weighted_trx_suspended_jackknife",35:"u_boat",36:"weighted_u_boat",37:"windmill_switches",38:"weighted_windmill_switches",39:"alternating_slide_out",40:"weighted_alternating_slide_out",41:"ghd_back_extensions",42:"weighted_ghd_back_extensions",43:"overhead_walk",44:"inchworm",45:"weighted_modified_front_lever",46:"russian_twist",47:"abdominal_leg_rotations",48:"arm_and_leg_extension_on_knees",49:"bicycle",50:"bicep_curl_with_leg_extension",51:"cat_cow",52:"corkscrew",53:"criss_cross",54:"criss_cross_with_ball",55:"double_leg_stretch",56:"knee_folds",57:"lower_lift",58:"neck_pull",59:"pelvic_clocks",60:"roll_over",61:"roll_up",62:"rolling",63:"rowing_1",64:"rowing_2",65:"scissors",66:"single_leg_circles",67:"single_leg_stretch",68:"snake_twist_1_and_2",69:"swan",70:"swimming",71:"teaser",72:"the_hundred"},crunch_exercise_name:{0:"bicycle_crunch",1:"cable_crunch",2:"circular_arm_crunch",3:"crossed_arms_crunch",4:"weighted_crossed_arms_crunch",5:"cross_leg_reverse_crunch",6:"weighted_cross_leg_reverse_crunch",7:"crunch_chop",8:"weighted_crunch_chop",9:"double_crunch",10:"weighted_double_crunch",11:"elbow_to_knee_crunch",12:"weighted_elbow_to_knee_crunch",13:"flutter_kicks",14:"weighted_flutter_kicks",15:"foam_roller_reverse_crunch_on_bench",16:"weighted_foam_roller_reverse_crunch_on_bench",17:"foam_roller_reverse_crunch_with_dumbbell",18:"foam_roller_reverse_crunch_with_medicine_ball",19:"frog_press",20:"hanging_knee_raise_oblique_crunch",21:"weighted_hanging_knee_raise_oblique_crunch",22:"hip_crossover",23:"weighted_hip_crossover",24:"hollow_rock",25:"weighted_hollow_rock",26:"incline_reverse_crunch",27:"weighted_incline_reverse_crunch",28:"kneeling_cable_crunch",29:"kneeling_cross_crunch",30:"weighted_kneeling_cross_crunch",31:"kneeling_oblique_cable_crunch",32:"knees_to_elbow",33:"leg_extensions",34:"weighted_leg_extensions",35:"leg_levers",36:"mcgill_curl_up",37:"weighted_mcgill_curl_up",38:"modified_pilates_roll_up_with_ball",39:"weighted_modified_pilates_roll_up_with_ball",40:"pilates_crunch",41:"weighted_pilates_crunch",42:"pilates_roll_up_with_ball",43:"weighted_pilates_roll_up_with_ball",44:"raised_legs_crunch",45:"weighted_raised_legs_crunch",46:"reverse_crunch",47:"weighted_reverse_crunch",48:"reverse_crunch_on_a_bench",49:"weighted_reverse_crunch_on_a_bench",50:"reverse_curl_and_lift",51:"weighted_reverse_curl_and_lift",52:"rotational_lift",53:"weighted_rotational_lift",54:"seated_alternating_reverse_crunch",55:"weighted_seated_alternating_reverse_crunch",56:"seated_leg_u",57:"weighted_seated_leg_u",58:"side_to_side_crunch_and_weave",59:"weighted_side_to_side_crunch_and_weave",60:"single_leg_reverse_crunch",61:"weighted_single_leg_reverse_crunch",62:"skater_crunch_cross",63:"weighted_skater_crunch_cross",64:"standing_cable_crunch",65:"standing_side_crunch",66:"step_climb",67:"weighted_step_climb",68:"swiss_ball_crunch",69:"swiss_ball_reverse_crunch",70:"weighted_swiss_ball_reverse_crunch",71:"swiss_ball_russian_twist",72:"weighted_swiss_ball_russian_twist",73:"swiss_ball_side_crunch",74:"weighted_swiss_ball_side_crunch",75:"thoracic_crunches_on_foam_roller",76:"weighted_thoracic_crunches_on_foam_roller",77:"triceps_crunch",78:"weighted_bicycle_crunch",79:"weighted_crunch",80:"weighted_swiss_ball_crunch",81:"toes_to_bar",82:"weighted_toes_to_bar",83:"crunch",84:"straight_leg_crunch_with_ball"},curl_exercise_name:{0:"alternating_dumbbell_biceps_curl",1:"alternating_dumbbell_biceps_curl_on_swiss_ball",2:"alternating_incline_dumbbell_biceps_curl",3:"barbell_biceps_curl",4:"barbell_reverse_wrist_curl",5:"barbell_wrist_curl",6:"behind_the_back_barbell_reverse_wrist_curl",7:"behind_the_back_one_arm_cable_curl",8:"cable_biceps_curl",9:"cable_hammer_curl",10:"cheating_barbell_biceps_curl",11:"close_grip_ez_bar_biceps_curl",12:"cross_body_dumbbell_hammer_curl",13:"dead_hang_biceps_curl",14:"decline_hammer_curl",15:"dumbbell_biceps_curl_with_static_hold",16:"dumbbell_hammer_curl",17:"dumbbell_reverse_wrist_curl",18:"dumbbell_wrist_curl",19:"ez_bar_preacher_curl",20:"forward_bend_biceps_curl",21:"hammer_curl_to_press",22:"incline_dumbbell_biceps_curl",23:"incline_offset_thumb_dumbbell_curl",24:"kettlebell_biceps_curl",25:"lying_concentration_cable_curl",26:"one_arm_preacher_curl",27:"plate_pinch_curl",28:"preacher_curl_with_cable",29:"reverse_ez_bar_curl",30:"reverse_grip_wrist_curl",31:"reverse_grip_barbell_biceps_curl",32:"seated_alternating_dumbbell_biceps_curl",33:"seated_dumbbell_biceps_curl",34:"seated_reverse_dumbbell_curl",35:"split_stance_offset_pinky_dumbbell_curl",36:"standing_alternating_dumbbell_curls",37:"standing_dumbbell_biceps_curl",38:"standing_ez_bar_biceps_curl",39:"static_curl",40:"swiss_ball_dumbbell_overhead_triceps_extension",41:"swiss_ball_ez_bar_preacher_curl",42:"twisting_standing_dumbbell_biceps_curl",43:"wide_grip_ez_bar_biceps_curl"},deadlift_exercise_name:{0:"barbell_deadlift",1:"barbell_straight_leg_deadlift",2:"dumbbell_deadlift",3:"dumbbell_single_leg_deadlift_to_row",4:"dumbbell_straight_leg_deadlift",5:"kettlebell_floor_to_shelf",6:"one_arm_one_leg_deadlift",7:"rack_pull",8:"rotational_dumbbell_straight_leg_deadlift",9:"single_arm_deadlift",10:"single_leg_barbell_deadlift",11:"single_leg_barbell_straight_leg_deadlift",12:"single_leg_deadlift_with_barbell",13:"single_leg_rdl_circuit",14:"single_leg_romanian_deadlift_with_dumbbell",15:"sumo_deadlift",16:"sumo_deadlift_high_pull",17:"trap_bar_deadlift",18:"wide_grip_barbell_deadlift"},flye_exercise_name:{0:"cable_crossover",1:"decline_dumbbell_flye",2:"dumbbell_flye",3:"incline_dumbbell_flye",4:"kettlebell_flye",5:"kneeling_rear_flye",6:"single_arm_standing_cable_reverse_flye",7:"swiss_ball_dumbbell_flye",8:"arm_rotations",9:"hug_a_tree"},hip_raise_exercise_name:{0:"barbell_hip_thrust_on_floor",1:"barbell_hip_thrust_with_bench",2:"bent_knee_swiss_ball_reverse_hip_raise",3:"weighted_bent_knee_swiss_ball_reverse_hip_raise",4:"bridge_with_leg_extension",5:"weighted_bridge_with_leg_extension",6:"clam_bridge",7:"front_kick_tabletop",8:"weighted_front_kick_tabletop",9:"hip_extension_and_cross",10:"weighted_hip_extension_and_cross",11:"hip_raise",12:"weighted_hip_raise",13:"hip_raise_with_feet_on_swiss_ball",14:"weighted_hip_raise_with_feet_on_swiss_ball",15:"hip_raise_with_head_on_bosu_ball",16:"weighted_hip_raise_with_head_on_bosu_ball",17:"hip_raise_with_head_on_swiss_ball",18:"weighted_hip_raise_with_head_on_swiss_ball",19:"hip_raise_with_knee_squeeze",20:"weighted_hip_raise_with_knee_squeeze",21:"incline_rear_leg_extension",22:"weighted_incline_rear_leg_extension",23:"kettlebell_swing",24:"marching_hip_raise",25:"weighted_marching_hip_raise",26:"marching_hip_raise_with_feet_on_a_swiss_ball",27:"weighted_marching_hip_raise_with_feet_on_a_swiss_ball",28:"reverse_hip_raise",29:"weighted_reverse_hip_raise",30:"single_leg_hip_raise",31:"weighted_single_leg_hip_raise",32:"single_leg_hip_raise_with_foot_on_bench",33:"weighted_single_leg_hip_raise_with_foot_on_bench",34:"single_leg_hip_raise_with_foot_on_bosu_ball",35:"weighted_single_leg_hip_raise_with_foot_on_bosu_ball",36:"single_leg_hip_raise_with_foot_on_foam_roller",37:"weighted_single_leg_hip_raise_with_foot_on_foam_roller",38:"single_leg_hip_raise_with_foot_on_medicine_ball",39:"weighted_single_leg_hip_raise_with_foot_on_medicine_ball",40:"single_leg_hip_raise_with_head_on_bosu_ball",41:"weighted_single_leg_hip_raise_with_head_on_bosu_ball",42:"weighted_clam_bridge",43:"single_leg_swiss_ball_hip_raise_and_leg_curl",44:"clams",45:"inner_thigh_circles",46:"inner_thigh_side_lift",47:"leg_circles",48:"leg_lift",49:"leg_lift_in_external_rotation"},hip_stability_exercise_name:{0:"band_side_lying_leg_raise",1:"dead_bug",2:"weighted_dead_bug",3:"external_hip_raise",4:"weighted_external_hip_raise",5:"fire_hydrant_kicks",6:"weighted_fire_hydrant_kicks",7:"hip_circles",8:"weighted_hip_circles",9:"inner_thigh_lift",10:"weighted_inner_thigh_lift",11:"lateral_walks_with_band_at_ankles",12:"pretzel_side_kick",13:"weighted_pretzel_side_kick",14:"prone_hip_internal_rotation",15:"weighted_prone_hip_internal_rotation",16:"quadruped",17:"quadruped_hip_extension",18:"weighted_quadruped_hip_extension",19:"quadruped_with_leg_lift",20:"weighted_quadruped_with_leg_lift",21:"side_lying_leg_raise",22:"weighted_side_lying_leg_raise",23:"sliding_hip_adduction",24:"weighted_sliding_hip_adduction",25:"standing_adduction",26:"weighted_standing_adduction",27:"standing_cable_hip_abduction",28:"standing_hip_abduction",29:"weighted_standing_hip_abduction",30:"standing_rear_leg_raise",31:"weighted_standing_rear_leg_raise",32:"supine_hip_internal_rotation",33:"weighted_supine_hip_internal_rotation"},hip_swing_excercise_name:{0:"single_arm_kettlebell_swing",1:"single_arm_dumbbell_swing",2:"step_out_swing"},hyperextension_exercise_name:{0:"back_extension_with_opposite_arm_and_leg_reach",1:"weighted_back_extension_with_opposite_arm_and_leg_reach",2:"base_rotations",3:"weighted_base_rotations",4:"bent_knee_reverse_hyperextension",5:"weighted_bent_knee_reverse_hyperextension",6:"hollow_hold_and_roll",7:"weighted_hollow_hold_and_roll",8:"kicks",9:"weighted_kicks",10:"knee_raises",11:"weighted_knee_raises",12:"kneeling_superman",13:"weighted_kneeling_superman",14:"lat_pull_down_with_row",15:"medicine_ball_deadlift_to_reach",16:"one_arm_one_leg_row",17:"one_arm_row_with_band",18:"overhead_lunge_with_medicine_ball",19:"plank_knee_tucks",20:"weighted_plank_knee_tucks",21:"side_step",22:"weighted_side_step",23:"single_leg_back_extension",24:"weighted_single_leg_back_extension",25:"spine_extension",26:"weighted_spine_extension",27:"static_back_extension",28:"weighted_static_back_extension",29:"superman_from_floor",30:"weighted_superman_from_floor",31:"swiss_ball_back_extension",32:"weighted_swiss_ball_back_extension",33:"swiss_ball_hyperextension",34:"weighted_swiss_ball_hyperextension",35:"swiss_ball_opposite_arm_and_leg_lift",36:"weighted_swiss_ball_opposite_arm_and_leg_lift",37:"superman_on_swiss_ball",38:"cobra",39:"supine_floor_barre"},lateral_raise_exercise_name:{0:"45_degree_cable_external_rotation",1:"alternating_lateral_raise_with_static_hold",2:"bar_muscle_up",3:"bent_over_lateral_raise",4:"cable_diagonal_raise",5:"cable_front_raise",6:"calorie_row",7:"combo_shoulder_raise",8:"dumbbell_diagonal_raise",9:"dumbbell_v_raise",10:"front_raise",11:"leaning_dumbbell_lateral_raise",12:"lying_dumbbell_raise",13:"muscle_up",14:"one_arm_cable_lateral_raise",15:"overhand_grip_rear_lateral_raise",16:"plate_raises",17:"ring_dip",18:"weighted_ring_dip",19:"ring_muscle_up",20:"weighted_ring_muscle_up",21:"rope_climb",22:"weighted_rope_climb",23:"scaption",24:"seated_lateral_raise",25:"seated_rear_lateral_raise",26:"side_lying_lateral_raise",27:"standing_lift",28:"suspended_row",29:"underhand_grip_rear_lateral_raise",30:"wall_slide",31:"weighted_wall_slide",32:"arm_circles",33:"shaving_the_head"},leg_curl_exercise_name:{0:"leg_curl",1:"weighted_leg_curl",2:"good_morning",3:"seated_barbell_good_morning",4:"single_leg_barbell_good_morning",5:"single_leg_sliding_leg_curl",6:"sliding_leg_curl",7:"split_barbell_good_morning",8:"split_stance_extension",9:"staggered_stance_good_morning",10:"swiss_ball_hip_raise_and_leg_curl",11:"zercher_good_morning"},leg_raise_exercise_name:{0:"hanging_knee_raise",1:"hanging_leg_raise",2:"weighted_hanging_leg_raise",3:"hanging_single_leg_raise",4:"weighted_hanging_single_leg_raise",5:"kettlebell_leg_raises",6:"leg_lowering_drill",7:"weighted_leg_lowering_drill",8:"lying_straight_leg_raise",9:"weighted_lying_straight_leg_raise",10:"medicine_ball_leg_drops",11:"quadruped_leg_raise",12:"weighted_quadruped_leg_raise",13:"reverse_leg_raise",14:"weighted_reverse_leg_raise",15:"reverse_leg_raise_on_swiss_ball",16:"weighted_reverse_leg_raise_on_swiss_ball",17:"single_leg_lowering_drill",18:"weighted_single_leg_lowering_drill",19:"weighted_hanging_knee_raise",20:"lateral_stepover",21:"weighted_lateral_stepover"},lunge_exercise_name:{0:"overhead_lunge",1:"lunge_matrix",2:"weighted_lunge_matrix",3:"alternating_barbell_forward_lunge",4:"alternating_dumbbell_lunge_with_reach",5:"back_foot_elevated_dumbbell_split_squat",6:"barbell_box_lunge",7:"barbell_bulgarian_split_squat",8:"barbell_crossover_lunge",9:"barbell_front_split_squat",10:"barbell_lunge",11:"barbell_reverse_lunge",12:"barbell_side_lunge",13:"barbell_split_squat",14:"core_control_rear_lunge",15:"diagonal_lunge",16:"drop_lunge",17:"dumbbell_box_lunge",18:"dumbbell_bulgarian_split_squat",19:"dumbbell_crossover_lunge",20:"dumbbell_diagonal_lunge",21:"dumbbell_lunge",22:"dumbbell_lunge_and_rotation",23:"dumbbell_overhead_bulgarian_split_squat",24:"dumbbell_reverse_lunge_to_high_knee_and_press",25:"dumbbell_side_lunge",26:"elevated_front_foot_barbell_split_squat",27:"front_foot_elevated_dumbbell_split_squat",28:"gunslinger_lunge",29:"lawnmower_lunge",30:"low_lunge_with_isometric_adduction",31:"low_side_to_side_lunge",32:"lunge",33:"weighted_lunge",34:"lunge_with_arm_reach",35:"lunge_with_diagonal_reach",36:"lunge_with_side_bend",37:"offset_dumbbell_lunge",38:"offset_dumbbell_reverse_lunge",39:"overhead_bulgarian_split_squat",40:"overhead_dumbbell_reverse_lunge",41:"overhead_dumbbell_split_squat",42:"overhead_lunge_with_rotation",43:"reverse_barbell_box_lunge",44:"reverse_box_lunge",45:"reverse_dumbbell_box_lunge",46:"reverse_dumbbell_crossover_lunge",47:"reverse_dumbbell_diagonal_lunge",48:"reverse_lunge_with_reach_back",49:"weighted_reverse_lunge_with_reach_back",50:"reverse_lunge_with_twist_and_overhead_reach",51:"weighted_reverse_lunge_with_twist_and_overhead_reach",52:"reverse_sliding_box_lunge",53:"weighted_reverse_sliding_box_lunge",54:"reverse_sliding_lunge",55:"weighted_reverse_sliding_lunge",56:"runners_lunge_to_balance",57:"weighted_runners_lunge_to_balance",58:"shifting_side_lunge",59:"side_and_crossover_lunge",60:"weighted_side_and_crossover_lunge",61:"side_lunge",62:"weighted_side_lunge",63:"side_lunge_and_press",64:"side_lunge_jump_off",65:"side_lunge_sweep",66:"weighted_side_lunge_sweep",67:"side_lunge_to_crossover_tap",68:"weighted_side_lunge_to_crossover_tap",69:"side_to_side_lunge_chops",70:"weighted_side_to_side_lunge_chops",71:"siff_jump_lunge",72:"weighted_siff_jump_lunge",73:"single_arm_reverse_lunge_and_press",74:"sliding_lateral_lunge",75:"weighted_sliding_lateral_lunge",76:"walking_barbell_lunge",77:"walking_dumbbell_lunge",78:"walking_lunge",79:"weighted_walking_lunge",80:"wide_grip_overhead_barbell_split_squat"},olympic_lift_exercise_name:{0:"barbell_hang_power_clean",1:"barbell_hang_squat_clean",2:"barbell_power_clean",3:"barbell_power_snatch",4:"barbell_squat_clean",5:"clean_and_jerk",6:"barbell_hang_power_snatch",7:"barbell_hang_pull",8:"barbell_high_pull",9:"barbell_snatch",10:"barbell_split_jerk",11:"clean",12:"dumbbell_clean",13:"dumbbell_hang_pull",14:"one_hand_dumbbell_split_snatch",15:"push_jerk",16:"single_arm_dumbbell_snatch",17:"single_arm_hang_snatch",18:"single_arm_kettlebell_snatch",19:"split_jerk",20:"squat_clean_and_jerk"},plank_exercise_name:{0:"45_degree_plank",1:"weighted_45_degree_plank",2:"90_degree_static_hold",3:"weighted_90_degree_static_hold",4:"bear_crawl",5:"weighted_bear_crawl",6:"cross_body_mountain_climber",7:"weighted_cross_body_mountain_climber",8:"elbow_plank_pike_jacks",9:"weighted_elbow_plank_pike_jacks",10:"elevated_feet_plank",11:"weighted_elevated_feet_plank",12:"elevator_abs",13:"weighted_elevator_abs",14:"extended_plank",15:"weighted_extended_plank",16:"full_plank_passe_twist",17:"weighted_full_plank_passe_twist",18:"inching_elbow_plank",19:"weighted_inching_elbow_plank",20:"inchworm_to_side_plank",21:"weighted_inchworm_to_side_plank",22:"kneeling_plank",23:"weighted_kneeling_plank",24:"kneeling_side_plank_with_leg_lift",25:"weighted_kneeling_side_plank_with_leg_lift",26:"lateral_roll",27:"weighted_lateral_roll",28:"lying_reverse_plank",29:"weighted_lying_reverse_plank",30:"medicine_ball_mountain_climber",31:"weighted_medicine_ball_mountain_climber",32:"modified_mountain_climber_and_extension",33:"weighted_modified_mountain_climber_and_extension",34:"mountain_climber",35:"weighted_mountain_climber",36:"mountain_climber_on_sliding_discs",37:"weighted_mountain_climber_on_sliding_discs",38:"mountain_climber_with_feet_on_bosu_ball",39:"weighted_mountain_climber_with_feet_on_bosu_ball",40:"mountain_climber_with_hands_on_bench",41:"mountain_climber_with_hands_on_swiss_ball",42:"weighted_mountain_climber_with_hands_on_swiss_ball",43:"plank",44:"plank_jacks_with_feet_on_sliding_discs",45:"weighted_plank_jacks_with_feet_on_sliding_discs",46:"plank_knee_twist",47:"weighted_plank_knee_twist",48:"plank_pike_jumps",49:"weighted_plank_pike_jumps",50:"plank_pikes",51:"weighted_plank_pikes",52:"plank_to_stand_up",53:"weighted_plank_to_stand_up",54:"plank_with_arm_raise",55:"weighted_plank_with_arm_raise",56:"plank_with_knee_to_elbow",57:"weighted_plank_with_knee_to_elbow",58:"plank_with_oblique_crunch",59:"weighted_plank_with_oblique_crunch",60:"plyometric_side_plank",61:"weighted_plyometric_side_plank",62:"rolling_side_plank",63:"weighted_rolling_side_plank",64:"side_kick_plank",65:"weighted_side_kick_plank",66:"side_plank",67:"weighted_side_plank",68:"side_plank_and_row",69:"weighted_side_plank_and_row",70:"side_plank_lift",71:"weighted_side_plank_lift",72:"side_plank_with_elbow_on_bosu_ball",73:"weighted_side_plank_with_elbow_on_bosu_ball",74:"side_plank_with_feet_on_bench",75:"weighted_side_plank_with_feet_on_bench",76:"side_plank_with_knee_circle",77:"weighted_side_plank_with_knee_circle",78:"side_plank_with_knee_tuck",79:"weighted_side_plank_with_knee_tuck",80:"side_plank_with_leg_lift",81:"weighted_side_plank_with_leg_lift",82:"side_plank_with_reach_under",83:"weighted_side_plank_with_reach_under",84:"single_leg_elevated_feet_plank",85:"weighted_single_leg_elevated_feet_plank",86:"single_leg_flex_and_extend",87:"weighted_single_leg_flex_and_extend",88:"single_leg_side_plank",89:"weighted_single_leg_side_plank",90:"spiderman_plank",91:"weighted_spiderman_plank",92:"straight_arm_plank",93:"weighted_straight_arm_plank",94:"straight_arm_plank_with_shoulder_touch",95:"weighted_straight_arm_plank_with_shoulder_touch",96:"swiss_ball_plank",97:"weighted_swiss_ball_plank",98:"swiss_ball_plank_leg_lift",99:"weighted_swiss_ball_plank_leg_lift",100:"swiss_ball_plank_leg_lift_and_hold",101:"swiss_ball_plank_with_feet_on_bench",102:"weighted_swiss_ball_plank_with_feet_on_bench",103:"swiss_ball_prone_jackknife",104:"weighted_swiss_ball_prone_jackknife",105:"swiss_ball_side_plank",106:"weighted_swiss_ball_side_plank",107:"three_way_plank",108:"weighted_three_way_plank",109:"towel_plank_and_knee_in",110:"weighted_towel_plank_and_knee_in",111:"t_stabilization",112:"weighted_t_stabilization",113:"turkish_get_up_to_side_plank",114:"weighted_turkish_get_up_to_side_plank",115:"two_point_plank",116:"weighted_two_point_plank",117:"weighted_plank",118:"wide_stance_plank_with_diagonal_arm_lift",119:"weighted_wide_stance_plank_with_diagonal_arm_lift",120:"wide_stance_plank_with_diagonal_leg_lift",121:"weighted_wide_stance_plank_with_diagonal_leg_lift",122:"wide_stance_plank_with_leg_lift",123:"weighted_wide_stance_plank_with_leg_lift",124:"wide_stance_plank_with_opposite_arm_and_leg_lift",125:"weighted_mountain_climber_with_hands_on_bench",126:"weighted_swiss_ball_plank_leg_lift_and_hold",127:"weighted_wide_stance_plank_with_opposite_arm_and_leg_lift",128:"plank_with_feet_on_swiss_ball",129:"side_plank_to_plank_with_reach_under",130:"bridge_with_glute_lower_lift",131:"bridge_one_leg_bridge",132:"plank_with_arm_variations",133:"plank_with_leg_lift",134:"reverse_plank_with_leg_pull"},plyo_exercise_name:{0:"alternating_jump_lunge",1:"weighted_alternating_jump_lunge",2:"barbell_jump_squat",3:"body_weight_jump_squat",4:"weighted_jump_squat",5:"cross_knee_strike",6:"weighted_cross_knee_strike",7:"depth_jump",8:"weighted_depth_jump",9:"dumbbell_jump_squat",10:"dumbbell_split_jump",11:"front_knee_strike",12:"weighted_front_knee_strike",13:"high_box_jump",14:"weighted_high_box_jump",15:"isometric_explosive_body_weight_jump_squat",16:"weighted_isometric_explosive_jump_squat",17:"lateral_leap_and_hop",18:"weighted_lateral_leap_and_hop",19:"lateral_plyo_squats",20:"weighted_lateral_plyo_squats",21:"lateral_slide",22:"weighted_lateral_slide",23:"medicine_ball_overhead_throws",24:"medicine_ball_side_throw",25:"medicine_ball_slam",26:"side_to_side_medicine_ball_throws",27:"side_to_side_shuffle_jump",28:"weighted_side_to_side_shuffle_jump",29:"squat_jump_onto_box",30:"weighted_squat_jump_onto_box",31:"squat_jumps_in_and_out",32:"weighted_squat_jumps_in_and_out"},pull_up_exercise_name:{0:"banded_pull_ups",1:"30_degree_lat_pulldown",2:"band_assisted_chin_up",3:"close_grip_chin_up",4:"weighted_close_grip_chin_up",5:"close_grip_lat_pulldown",6:"crossover_chin_up",7:"weighted_crossover_chin_up",8:"ez_bar_pullover",9:"hanging_hurdle",10:"weighted_hanging_hurdle",11:"kneeling_lat_pulldown",12:"kneeling_underhand_grip_lat_pulldown",13:"lat_pulldown",14:"mixed_grip_chin_up",15:"weighted_mixed_grip_chin_up",16:"mixed_grip_pull_up",17:"weighted_mixed_grip_pull_up",18:"reverse_grip_pulldown",19:"standing_cable_pullover",20:"straight_arm_pulldown",21:"swiss_ball_ez_bar_pullover",22:"towel_pull_up",23:"weighted_towel_pull_up",24:"weighted_pull_up",25:"wide_grip_lat_pulldown",26:"wide_grip_pull_up",27:"weighted_wide_grip_pull_up",28:"burpee_pull_up",29:"weighted_burpee_pull_up",30:"jumping_pull_ups",31:"weighted_jumping_pull_ups",32:"kipping_pull_up",33:"weighted_kipping_pull_up",34:"l_pull_up",35:"weighted_l_pull_up",36:"suspended_chin_up",37:"weighted_suspended_chin_up",38:"pull_up"},push_up_exercise_name:{0:"chest_press_with_band",1:"alternating_staggered_push_up",2:"weighted_alternating_staggered_push_up",3:"alternating_hands_medicine_ball_push_up",4:"weighted_alternating_hands_medicine_ball_push_up",5:"bosu_ball_push_up",6:"weighted_bosu_ball_push_up",7:"clapping_push_up",8:"weighted_clapping_push_up",9:"close_grip_medicine_ball_push_up",10:"weighted_close_grip_medicine_ball_push_up",11:"close_hands_push_up",12:"weighted_close_hands_push_up",13:"decline_push_up",14:"weighted_decline_push_up",15:"diamond_push_up",16:"weighted_diamond_push_up",17:"explosive_crossover_push_up",18:"weighted_explosive_crossover_push_up",19:"explosive_push_up",20:"weighted_explosive_push_up",21:"feet_elevated_side_to_side_push_up",22:"weighted_feet_elevated_side_to_side_push_up",23:"hand_release_push_up",24:"weighted_hand_release_push_up",25:"handstand_push_up",26:"weighted_handstand_push_up",27:"incline_push_up",28:"weighted_incline_push_up",29:"isometric_explosive_push_up",30:"weighted_isometric_explosive_push_up",31:"judo_push_up",32:"weighted_judo_push_up",33:"kneeling_push_up",34:"weighted_kneeling_push_up",35:"medicine_ball_chest_pass",36:"medicine_ball_push_up",37:"weighted_medicine_ball_push_up",38:"one_arm_push_up",39:"weighted_one_arm_push_up",40:"weighted_push_up",41:"push_up_and_row",42:"weighted_push_up_and_row",43:"push_up_plus",44:"weighted_push_up_plus",45:"push_up_with_feet_on_swiss_ball",46:"weighted_push_up_with_feet_on_swiss_ball",47:"push_up_with_one_hand_on_medicine_ball",48:"weighted_push_up_with_one_hand_on_medicine_ball",49:"shoulder_push_up",50:"weighted_shoulder_push_up",51:"single_arm_medicine_ball_push_up",52:"weighted_single_arm_medicine_ball_push_up",53:"spiderman_push_up",54:"weighted_spiderman_push_up",55:"stacked_feet_push_up",56:"weighted_stacked_feet_push_up",57:"staggered_hands_push_up",58:"weighted_staggered_hands_push_up",59:"suspended_push_up",60:"weighted_suspended_push_up",61:"swiss_ball_push_up",62:"weighted_swiss_ball_push_up",63:"swiss_ball_push_up_plus",64:"weighted_swiss_ball_push_up_plus",65:"t_push_up",66:"weighted_t_push_up",67:"triple_stop_push_up",68:"weighted_triple_stop_push_up",69:"wide_hands_push_up",70:"weighted_wide_hands_push_up",71:"parallette_handstand_push_up",72:"weighted_parallette_handstand_push_up",73:"ring_handstand_push_up",74:"weighted_ring_handstand_push_up",75:"ring_push_up",76:"weighted_ring_push_up",77:"push_up",78:"pilates_pushup"},row_exercise_name:{0:"barbell_straight_leg_deadlift_to_row",1:"cable_row_standing",2:"dumbbell_row",3:"elevated_feet_inverted_row",4:"weighted_elevated_feet_inverted_row",5:"face_pull",6:"face_pull_with_external_rotation",7:"inverted_row_with_feet_on_swiss_ball",8:"weighted_inverted_row_with_feet_on_swiss_ball",9:"kettlebell_row",10:"modified_inverted_row",11:"weighted_modified_inverted_row",12:"neutral_grip_alternating_dumbbell_row",13:"one_arm_bent_over_row",14:"one_legged_dumbbell_row",15:"renegade_row",16:"reverse_grip_barbell_row",17:"rope_handle_cable_row",18:"seated_cable_row",19:"seated_dumbbell_row",20:"single_arm_cable_row",21:"single_arm_cable_row_and_rotation",22:"single_arm_inverted_row",23:"weighted_single_arm_inverted_row",24:"single_arm_neutral_grip_dumbbell_row",25:"single_arm_neutral_grip_dumbbell_row_and_rotation",26:"suspended_inverted_row",27:"weighted_suspended_inverted_row",28:"t_bar_row",29:"towel_grip_inverted_row",30:"weighted_towel_grip_inverted_row",31:"underhand_grip_cable_row",32:"v_grip_cable_row",33:"wide_grip_seated_cable_row"},shoulder_press_exercise_name:{0:"alternating_dumbbell_shoulder_press",1:"arnold_press",2:"barbell_front_squat_to_push_press",3:"barbell_push_press",4:"barbell_shoulder_press",5:"dead_curl_press",6:"dumbbell_alternating_shoulder_press_and_twist",7:"dumbbell_hammer_curl_to_lunge_to_press",8:"dumbbell_push_press",9:"floor_inverted_shoulder_press",10:"weighted_floor_inverted_shoulder_press",11:"inverted_shoulder_press",12:"weighted_inverted_shoulder_press",13:"one_arm_push_press",14:"overhead_barbell_press",15:"overhead_dumbbell_press",16:"seated_barbell_shoulder_press",17:"seated_dumbbell_shoulder_press",18:"single_arm_dumbbell_shoulder_press",19:"single_arm_step_up_and_press",20:"smith_machine_overhead_press",21:"split_stance_hammer_curl_to_press",22:"swiss_ball_dumbbell_shoulder_press",23:"weight_plate_front_raise"},shoulder_stability_exercise_name:{0:"90_degree_cable_external_rotation",1:"band_external_rotation",2:"band_internal_rotation",3:"bent_arm_lateral_raise_and_external_rotation",4:"cable_external_rotation",5:"dumbbell_face_pull_with_external_rotation",6:"floor_i_raise",7:"weighted_floor_i_raise",8:"floor_t_raise",9:"weighted_floor_t_raise",10:"floor_y_raise",11:"weighted_floor_y_raise",12:"incline_i_raise",13:"weighted_incline_i_raise",14:"incline_l_raise",15:"weighted_incline_l_raise",16:"incline_t_raise",17:"weighted_incline_t_raise",18:"incline_w_raise",19:"weighted_incline_w_raise",20:"incline_y_raise",21:"weighted_incline_y_raise",22:"lying_external_rotation",23:"seated_dumbbell_external_rotation",24:"standing_l_raise",25:"swiss_ball_i_raise",26:"weighted_swiss_ball_i_raise",27:"swiss_ball_t_raise",28:"weighted_swiss_ball_t_raise",29:"swiss_ball_w_raise",30:"weighted_swiss_ball_w_raise",31:"swiss_ball_y_raise",32:"weighted_swiss_ball_y_raise"},shrug_exercise_name:{0:"barbell_jump_shrug",1:"barbell_shrug",2:"barbell_upright_row",3:"behind_the_back_smith_machine_shrug",4:"dumbbell_jump_shrug",5:"dumbbell_shrug",6:"dumbbell_upright_row",7:"incline_dumbbell_shrug",8:"overhead_barbell_shrug",9:"overhead_dumbbell_shrug",10:"scaption_and_shrug",11:"scapular_retraction",12:"serratus_chair_shrug",13:"weighted_serratus_chair_shrug",14:"serratus_shrug",15:"weighted_serratus_shrug",16:"wide_grip_jump_shrug"},sit_up_exercise_name:{0:"alternating_sit_up",1:"weighted_alternating_sit_up",2:"bent_knee_v_up",3:"weighted_bent_knee_v_up",4:"butterfly_sit_up",5:"weighted_butterfly_situp",6:"cross_punch_roll_up",7:"weighted_cross_punch_roll_up",8:"crossed_arms_sit_up",9:"weighted_crossed_arms_sit_up",10:"get_up_sit_up",11:"weighted_get_up_sit_up",12:"hovering_sit_up",13:"weighted_hovering_sit_up",14:"kettlebell_sit_up",15:"medicine_ball_alternating_v_up",16:"medicine_ball_sit_up",17:"medicine_ball_v_up",18:"modified_sit_up",19:"negative_sit_up",20:"one_arm_full_sit_up",21:"reclining_circle",22:"weighted_reclining_circle",23:"reverse_curl_up",24:"weighted_reverse_curl_up",25:"single_leg_swiss_ball_jackknife",26:"weighted_single_leg_swiss_ball_jackknife",27:"the_teaser",28:"the_teaser_weighted",29:"three_part_roll_down",30:"weighted_three_part_roll_down",31:"v_up",32:"weighted_v_up",33:"weighted_russian_twist_on_swiss_ball",34:"weighted_sit_up",35:"x_abs",36:"weighted_x_abs",37:"sit_up"},squat_exercise_name:{0:"leg_press",1:"back_squat_with_body_bar",2:"back_squats",3:"weighted_back_squats",4:"balancing_squat",5:"weighted_balancing_squat",6:"barbell_back_squat",7:"barbell_box_squat",8:"barbell_front_squat",9:"barbell_hack_squat",10:"barbell_hang_squat_snatch",11:"barbell_lateral_step_up",12:"barbell_quarter_squat",13:"barbell_siff_squat",14:"barbell_squat_snatch",15:"barbell_squat_with_heels_raised",16:"barbell_stepover",17:"barbell_step_up",18:"bench_squat_with_rotational_chop",19:"weighted_bench_squat_with_rotational_chop",20:"body_weight_wall_squat",21:"weighted_wall_squat",22:"box_step_squat",23:"weighted_box_step_squat",24:"braced_squat",25:"crossed_arm_barbell_front_squat",26:"crossover_dumbbell_step_up",27:"dumbbell_front_squat",28:"dumbbell_split_squat",29:"dumbbell_squat",30:"dumbbell_squat_clean",31:"dumbbell_stepover",32:"dumbbell_step_up",33:"elevated_single_leg_squat",34:"weighted_elevated_single_leg_squat",35:"figure_four_squats",36:"weighted_figure_four_squats",37:"goblet_squat",38:"kettlebell_squat",39:"kettlebell_swing_overhead",40:"kettlebell_swing_with_flip_to_squat",41:"lateral_dumbbell_step_up",42:"one_legged_squat",43:"overhead_dumbbell_squat",44:"overhead_squat",45:"partial_single_leg_squat",46:"weighted_partial_single_leg_squat",47:"pistol_squat",48:"weighted_pistol_squat",49:"plie_slides",50:"weighted_plie_slides",51:"plie_squat",52:"weighted_plie_squat",53:"prisoner_squat",54:"weighted_prisoner_squat",55:"single_leg_bench_get_up",56:"weighted_single_leg_bench_get_up",57:"single_leg_bench_squat",58:"weighted_single_leg_bench_squat",59:"single_leg_squat_on_swiss_ball",60:"weighted_single_leg_squat_on_swiss_ball",61:"squat",62:"weighted_squat",63:"squats_with_band",64:"staggered_squat",65:"weighted_staggered_squat",66:"step_up",67:"weighted_step_up",68:"suitcase_squats",69:"sumo_squat",70:"sumo_squat_slide_in",71:"weighted_sumo_squat_slide_in",72:"sumo_squat_to_high_pull",73:"sumo_squat_to_stand",74:"weighted_sumo_squat_to_stand",75:"sumo_squat_with_rotation",76:"weighted_sumo_squat_with_rotation",77:"swiss_ball_body_weight_wall_squat",78:"weighted_swiss_ball_wall_squat",79:"thrusters",80:"uneven_squat",81:"weighted_uneven_squat",82:"waist_slimming_squat",83:"wall_ball",84:"wide_stance_barbell_squat",85:"wide_stance_goblet_squat",86:"zercher_squat",87:"kbs_overhead",88:"squat_and_side_kick",89:"squat_jumps_in_n_out",90:"pilates_plie_squats_parallel_turned_out_flat_and_heels",91:"releve_straight_leg_and_knee_bent_with_one_leg_variation"},total_body_exercise_name:{0:"burpee",1:"weighted_burpee",2:"burpee_box_jump",3:"weighted_burpee_box_jump",4:"high_pull_burpee",5:"man_makers",6:"one_arm_burpee",7:"squat_thrusts",8:"weighted_squat_thrusts",9:"squat_plank_push_up",10:"weighted_squat_plank_push_up",11:"standing_t_rotation_balance",12:"weighted_standing_t_rotation_balance"},triceps_extension_exercise_name:{0:"bench_dip",1:"weighted_bench_dip",2:"body_weight_dip",3:"cable_kickback",4:"cable_lying_triceps_extension",5:"cable_overhead_triceps_extension",6:"dumbbell_kickback",7:"dumbbell_lying_triceps_extension",8:"ez_bar_overhead_triceps_extension",9:"incline_dip",10:"weighted_incline_dip",11:"incline_ez_bar_lying_triceps_extension",12:"lying_dumbbell_pullover_to_extension",13:"lying_ez_bar_triceps_extension",14:"lying_triceps_extension_to_close_grip_bench_press",15:"overhead_dumbbell_triceps_extension",16:"reclining_triceps_press",17:"reverse_grip_pressdown",18:"reverse_grip_triceps_pressdown",19:"rope_pressdown",20:"seated_barbell_overhead_triceps_extension",21:"seated_dumbbell_overhead_triceps_extension",22:"seated_ez_bar_overhead_triceps_extension",23:"seated_single_arm_overhead_dumbbell_extension",24:"single_arm_dumbbell_overhead_triceps_extension",25:"single_dumbbell_seated_overhead_triceps_extension",26:"single_leg_bench_dip_and_kick",27:"weighted_single_leg_bench_dip_and_kick",28:"single_leg_dip",29:"weighted_single_leg_dip",30:"static_lying_triceps_extension",31:"suspended_dip",32:"weighted_suspended_dip",33:"swiss_ball_dumbbell_lying_triceps_extension",34:"swiss_ball_ez_bar_lying_triceps_extension",35:"swiss_ball_ez_bar_overhead_triceps_extension",36:"tabletop_dip",37:"weighted_tabletop_dip",38:"triceps_extension_on_floor",39:"triceps_pressdown",40:"weighted_dip"},warm_up_exercise_name:{0:"quadruped_rocking",1:"neck_tilts",2:"ankle_circles",3:"ankle_dorsiflexion_with_band",4:"ankle_internal_rotation",5:"arm_circles",6:"bent_over_reach_to_sky",7:"cat_camel",8:"elbow_to_foot_lunge",9:"forward_and_backward_leg_swings",10:"groiners",11:"inverted_hamstring_stretch",12:"lateral_duck_under",13:"neck_rotations",14:"opposite_arm_and_leg_balance",15:"reach_roll_and_lift",16:"scorpion",17:"shoulder_circles",18:"side_to_side_leg_swings",19:"sleeper_stretch",20:"slide_out",21:"swiss_ball_hip_crossover",22:"swiss_ball_reach_roll_and_lift",23:"swiss_ball_windshield_wipers",24:"thoracic_rotation",25:"walking_high_kicks",26:"walking_high_knees",27:"walking_knee_hugs",28:"walking_leg_cradles",29:"walkout",30:"walkout_from_push_up_position"},run_exercise_name:{0:"run",1:"walk",2:"jog",3:"sprint"},water_type:{0:"fresh",1:"salt",2:"en13319",3:"custom"},tissue_model_type:{0:"zhl_16c"},dive_gas_status:{0:"disabled",1:"enabled",2:"backup_only"},dive_alarm_type:{0:"depth",1:"time"},dive_backlight_mode:{0:"at_depth",1:"always_on"},favero_product:{10:"assioma_uno",12:"assioma_duo"}}};function Jt(i,e){let t=w.messages[e];return t?t[i]||{}:{}}function Xt(i){let e=w.messages[i];return e?e.name:""}function me(i){return{name:Xt(i),getAttributes:e=>Jt(e,i)}}var Kt=96,Ke=128,ye=6310656e5,ee=0;function tt(i,e){let t=0;i||e.reverse();for(let n=0;n>>0;return t}function Zt(i,e,t,n){if(e.type==="uint8_array"){let s=[];for(let _=0;_127?s-256:s}return i[t]}function Ze(i,e,t,n){switch(e){case"date_time":case"local_date_time":return new Date(i*1e3+ye);case"sint32":return i*w.scConst;case"uint8":case"sint16":case"uint32":case"uint16":return t?i/t+n:i;case"uint32_array":case"uint16_array":case"uint8_array":if(Array.isArray(i)){let s=e.replace("_array","");return i.map(_=>it(_,s)?null:t?_/t+n:_)}return t?i/t+n:i;default:{if(!w.types[e])return i;let s=[];for(let l in w.types[e])l in w.types[e]&&s.push(String(w.types[e][l]));if(!s.includes("mask")){let r=w.types[e][String(i)];return r===void 0?i:r}let _={};for(let l in w.types[e])l in w.types[e]&&(w.types[e][l]==="mask"?_.value=i&Number(l):_[w.types[e][l]]=!!((i&Number(l))>>7));return _}}}function it(i,e){switch(e){case"enum":return i===255;case"sint8":return i===127;case"uint8":return i===255;case"sint16":return i===32767;case"uint16":return i===65535;case"sint32":return i===2147483647;case"uint32":return i===4294967295;case"string":return i===0;case"float32":return i===4294967295;case"float64":return i===18446744073709552e3;case"uint8z":return i===0;case"uint16z":return i===0;case"uint32z":return i===0;case"byte":return i===255;case"sint64":return i===9223372036854776e3;case"uint64":return i===18446744073709552e3;case"uint64z":return i===0;default:return!1}}function te(i,e,t){let s=w.options[e][t];return s?i*s.multiplier+s.offset:i}function Qe(i,e,t,n){switch(e){case"device_type":{let s=n.source_type==="local"||n.source_type===5,_=n.source_type==="bluetooth_low_energy"||n.source_type===3||n.source_type==="bluetooth"||n.source_type===2,l=n.source_type==="antplus"||n.source_type===1||n.source_type==="ant"||n.source_type===0;return s?w.types.local_device_type[i]||i:_?w.types.ble_device_type[i]||i:l&&w.types.antplus_device_type[i]||i}case"speed":case"enhanced_speed":case"vertical_speed":case"avg_speed":case"max_speed":case"speed_1s":case"ball_speed":case"enhanced_avg_speed":case"enhanced_max_speed":case"avg_pos_vertical_speed":case"max_pos_vertical_speed":case"avg_neg_vertical_speed":case"max_neg_vertical_speed":return te(i,"speedUnits",t.speedUnit);case"distance":case"total_distance":case"enhanced_avg_altitude":case"enhanced_min_altitude":case"enhanced_max_altitude":case"enhanced_altitude":case"height":case"odometer":case"avg_stroke_distance":case"min_altitude":case"avg_altitude":case"max_altitude":case"total_ascent":case"total_descent":case"altitude":case"cycle_length":case"auto_wheelsize":case"custom_wheelsize":case"gps_accuracy":return te(i,"lengthUnits",t.lengthUnit);case"temperature":case"avg_temperature":case"max_temperature":return te(i,"temperatureUnits",t.temperatureUnit);case"pressure":case"start_pressure":case"end_pressure":return te(i,"pressureUnits",t.pressureUnit);case"ant_id":{let s=i>>>28&15,_=i>>>24&15,l=i>>>16&255,r=i&65535;return`${s.toString(16).toUpperCase()}-${_.toString(16).toUpperCase()}-${l.toString(16).toUpperCase().padStart(2,"0")}-${r.toString(16).toUpperCase().padStart(4,"0")}`}default:return i}}function nt(i,e,t,n,s,_,l){let r=i[n],o=r&15;if((r&Ke)===Ke)o=(r&Kt)>>5;else if((r&64)===64){let h=(r&32)===32,y=i[n+2]===0,m=i[n+5],I=h?i[n+5+m*3+1]:0,F={littleEndian:y,globalMessageNumber:tt(y,[i[n+3],i[n+4]]),numberOfFields:m+I,fieldDefs:[]},U=me(F.globalMessageNumber);for(let E=0;E>4&4095,s=s^r^n[l&15],r=n[s&15],s=s>>4&4095,s=s^r^n[l>>4&15]}return s}function be(i,e,t){let n=[...i],s=0;for(let _=0;_c)r.push(u);else if(o<=c){s=d;break}}else r.push(u)}n[_][e]||(n[_][e]=r)}return n}function _t(i,e){let t=[...i],n=0;for(let s=0;su)l.push(d);else if(r<=u){n=o;break}}else l.push(d)}t[s].laps||(t[s].laps=l)}return t}var J=class{constructor(e={}){this.options={force:e.force!=null?e.force:!0,speedUnit:e.speedUnit||"m/s",lengthUnit:e.lengthUnit||"m",temperatureUnit:e.temperatureUnit||"celsius",elapsedRecordField:e.elapsedRecordField||!1,pressureUnit:e.pressureUnit||"bar",mode:e.mode||"list"}}parseAsync(e){return new Promise((t,n)=>{this.parse(e,(s,_)=>{s?n(s):_&&t(_)})})}parse(e,t){var n;let s=new Uint8Array(st(e));if(s.length<12&&(t("File to small to be a FIT file",void 0),!this.options.force))return;let _=s[0];if(_!==14&&_!==12&&(t("Incorrect header size",void 0),!this.options.force))return;let l="";for(let L=8;L<12;L++)l+=String.fromCharCode(s[L]);if(l!==".FIT"&&(t("Missing '.FIT' in header",void 0),!this.options.force))return;if(_===14){let L=s[12]+(s[13]<<8),W=we(s,0,12);if(L!==W&&!this.options.force)return}let r=s[1],o=s[2]+(s[3]<<8),u=s[4]+(s[5]<<8)+(s[6]<<16)+(s[7]<<24)+_,c=s[u]+(s[u+1]<<8),g=we(s,_===12?0:_,u);if(c!==g&&!this.options.force)return;let f={profileVersion:o,protocolVersion:r},x=[],h=[],y=[],m=[],I=[],F=[],U=[],O=[],G=[],E=[],v=[],A=[],R=[],S=[],j=[],D=[],X=[],ke=[],ie=[],xe=[],ve=[],Fe=[],Be=[],Ee=[],ne=_,lt=[],at=[],ze=this.options.mode==="cascade",rt=ze||this.options.mode==="both",se,_e,qe=0;for(;ne *) + +buffer/index.js: + (*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + *) +*/ +//# sourceMappingURL=fit-file-parser.mjs.map diff --git a/suites-experimental/tools-gps-tracks/dist/fit-file-parser.mjs.map b/suites-experimental/tools-gps-tracks/dist/fit-file-parser.mjs.map new file mode 100644 index 0000000000..6f402eab4b --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/fit-file-parser.mjs.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../node_modules/base64-js/index.js", "../node_modules/ieee754/index.js", "../node_modules/buffer/index.js", "../node_modules/fit-file-parser/dist/binary.js", "../node_modules/fit-file-parser/dist/fit.js", "../node_modules/fit-file-parser/dist/messages.js", "../node_modules/fit-file-parser/dist/helper.js", "../node_modules/fit-file-parser/dist/fit-parser.js", "../src/vendor-fit.ts"], + "sourcesContent": ["'use strict'\n\nexports.byteLength = byteLength\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nfor (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i]\n revLookup[code.charCodeAt(i)] = i\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)] = 62\nrevLookup['_'.charCodeAt(0)] = 63\n\nfunction getLens (b64) {\n var len = b64.length\n\n if (len % 4 > 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // Trim off extra bytes after placeholder bytes are found\n // See: https://github.com/beatgammit/base64-js/issues/42\n var validLen = b64.indexOf('=')\n if (validLen === -1) validLen = len\n\n var placeHoldersLen = validLen === len\n ? 0\n : 4 - (validLen % 4)\n\n return [validLen, placeHoldersLen]\n}\n\n// base64 is 4/3 + up to two characters of the original data\nfunction byteLength (b64) {\n var lens = getLens(b64)\n var validLen = lens[0]\n var placeHoldersLen = lens[1]\n return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\n}\n\nfunction _byteLength (b64, validLen, placeHoldersLen) {\n return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\n}\n\nfunction toByteArray (b64) {\n var tmp\n var lens = getLens(b64)\n var validLen = lens[0]\n var placeHoldersLen = lens[1]\n\n var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))\n\n var curByte = 0\n\n // if there are placeholders, only get up to the last complete 4 chars\n var len = placeHoldersLen > 0\n ? validLen - 4\n : validLen\n\n var i\n for (i = 0; i < len; i += 4) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 18) |\n (revLookup[b64.charCodeAt(i + 1)] << 12) |\n (revLookup[b64.charCodeAt(i + 2)] << 6) |\n revLookup[b64.charCodeAt(i + 3)]\n arr[curByte++] = (tmp >> 16) & 0xFF\n arr[curByte++] = (tmp >> 8) & 0xFF\n arr[curByte++] = tmp & 0xFF\n }\n\n if (placeHoldersLen === 2) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 2) |\n (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[curByte++] = tmp & 0xFF\n }\n\n if (placeHoldersLen === 1) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 10) |\n (revLookup[b64.charCodeAt(i + 1)] << 4) |\n (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[curByte++] = (tmp >> 8) & 0xFF\n arr[curByte++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] +\n lookup[num >> 12 & 0x3F] +\n lookup[num >> 6 & 0x3F] +\n lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp =\n ((uint8[i] << 16) & 0xFF0000) +\n ((uint8[i + 1] << 8) & 0xFF00) +\n (uint8[i + 2] & 0xFF)\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n parts.push(\n lookup[tmp >> 2] +\n lookup[(tmp << 4) & 0x3F] +\n '=='\n )\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + uint8[len - 1]\n parts.push(\n lookup[tmp >> 10] +\n lookup[(tmp >> 4) & 0x3F] +\n lookup[(tmp << 2) & 0x3F] +\n '='\n )\n }\n\n return parts.join('')\n}\n", "/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */\nexports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = (nBytes * 8) - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = (nBytes * 8) - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = ((value * c) - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n", "/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nconst base64 = require('base64-js')\nconst ieee754 = require('ieee754')\nconst customInspectSymbol =\n (typeof Symbol === 'function' && typeof Symbol['for'] === 'function') // eslint-disable-line dot-notation\n ? Symbol['for']('nodejs.util.inspect.custom') // eslint-disable-line dot-notation\n : null\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\nconst K_MAX_LENGTH = 0x7fffffff\nexports.kMaxLength = K_MAX_LENGTH\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Print warning and recommend using `buffer` v4.x which has an Object\n * implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * We report that the browser does not support typed arrays if the are not subclassable\n * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array`\n * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support\n * for __proto__ and has a buggy typed array implementation.\n */\nBuffer.TYPED_ARRAY_SUPPORT = typedArraySupport()\n\nif (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' &&\n typeof console.error === 'function') {\n console.error(\n 'This browser lacks typed array (Uint8Array) support which is required by ' +\n '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'\n )\n}\n\nfunction typedArraySupport () {\n // Can typed array instances can be augmented?\n try {\n const arr = new Uint8Array(1)\n const proto = { foo: function () { return 42 } }\n Object.setPrototypeOf(proto, Uint8Array.prototype)\n Object.setPrototypeOf(arr, proto)\n return arr.foo() === 42\n } catch (e) {\n return false\n }\n}\n\nObject.defineProperty(Buffer.prototype, 'parent', {\n enumerable: true,\n get: function () {\n if (!Buffer.isBuffer(this)) return undefined\n return this.buffer\n }\n})\n\nObject.defineProperty(Buffer.prototype, 'offset', {\n enumerable: true,\n get: function () {\n if (!Buffer.isBuffer(this)) return undefined\n return this.byteOffset\n }\n})\n\nfunction createBuffer (length) {\n if (length > K_MAX_LENGTH) {\n throw new RangeError('The value \"' + length + '\" is invalid for option \"size\"')\n }\n // Return an augmented `Uint8Array` instance\n const buf = new Uint8Array(length)\n Object.setPrototypeOf(buf, Buffer.prototype)\n return buf\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new TypeError(\n 'The \"string\" argument must be of type string. Received type number'\n )\n }\n return allocUnsafe(arg)\n }\n return from(arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\nfunction from (value, encodingOrOffset, length) {\n if (typeof value === 'string') {\n return fromString(value, encodingOrOffset)\n }\n\n if (ArrayBuffer.isView(value)) {\n return fromArrayView(value)\n }\n\n if (value == null) {\n throw new TypeError(\n 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +\n 'or Array-like Object. Received type ' + (typeof value)\n )\n }\n\n if (isInstance(value, ArrayBuffer) ||\n (value && isInstance(value.buffer, ArrayBuffer))) {\n return fromArrayBuffer(value, encodingOrOffset, length)\n }\n\n if (typeof SharedArrayBuffer !== 'undefined' &&\n (isInstance(value, SharedArrayBuffer) ||\n (value && isInstance(value.buffer, SharedArrayBuffer)))) {\n return fromArrayBuffer(value, encodingOrOffset, length)\n }\n\n if (typeof value === 'number') {\n throw new TypeError(\n 'The \"value\" argument must not be of type number. Received type number'\n )\n }\n\n const valueOf = value.valueOf && value.valueOf()\n if (valueOf != null && valueOf !== value) {\n return Buffer.from(valueOf, encodingOrOffset, length)\n }\n\n const b = fromObject(value)\n if (b) return b\n\n if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null &&\n typeof value[Symbol.toPrimitive] === 'function') {\n return Buffer.from(value[Symbol.toPrimitive]('string'), encodingOrOffset, length)\n }\n\n throw new TypeError(\n 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +\n 'or Array-like Object. Received type ' + (typeof value)\n )\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(value, encodingOrOffset, length)\n}\n\n// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:\n// https://github.com/feross/buffer/pull/148\nObject.setPrototypeOf(Buffer.prototype, Uint8Array.prototype)\nObject.setPrototypeOf(Buffer, Uint8Array)\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be of type number')\n } else if (size < 0) {\n throw new RangeError('The value \"' + size + '\" is invalid for option \"size\"')\n }\n}\n\nfunction alloc (size, fill, encoding) {\n assertSize(size)\n if (size <= 0) {\n return createBuffer(size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpreted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(size).fill(fill, encoding)\n : createBuffer(size).fill(fill)\n }\n return createBuffer(size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(size, fill, encoding)\n}\n\nfunction allocUnsafe (size) {\n assertSize(size)\n return createBuffer(size < 0 ? 0 : checked(size) | 0)\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(size)\n}\n\nfunction fromString (string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8'\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n\n const length = byteLength(string, encoding) | 0\n let buf = createBuffer(length)\n\n const actual = buf.write(string, encoding)\n\n if (actual !== length) {\n // Writing a hex string, for example, that contains invalid characters will\n // cause everything after the first invalid character to be ignored. (e.g.\n // 'abxxcd' will be treated as 'ab')\n buf = buf.slice(0, actual)\n }\n\n return buf\n}\n\nfunction fromArrayLike (array) {\n const length = array.length < 0 ? 0 : checked(array.length) | 0\n const buf = createBuffer(length)\n for (let i = 0; i < length; i += 1) {\n buf[i] = array[i] & 255\n }\n return buf\n}\n\nfunction fromArrayView (arrayView) {\n if (isInstance(arrayView, Uint8Array)) {\n const copy = new Uint8Array(arrayView)\n return fromArrayBuffer(copy.buffer, copy.byteOffset, copy.byteLength)\n }\n return fromArrayLike(arrayView)\n}\n\nfunction fromArrayBuffer (array, byteOffset, length) {\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\"offset\" is outside of buffer bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\"length\" is outside of buffer bounds')\n }\n\n let buf\n if (byteOffset === undefined && length === undefined) {\n buf = new Uint8Array(array)\n } else if (length === undefined) {\n buf = new Uint8Array(array, byteOffset)\n } else {\n buf = new Uint8Array(array, byteOffset, length)\n }\n\n // Return an augmented `Uint8Array` instance\n Object.setPrototypeOf(buf, Buffer.prototype)\n\n return buf\n}\n\nfunction fromObject (obj) {\n if (Buffer.isBuffer(obj)) {\n const len = checked(obj.length) | 0\n const buf = createBuffer(len)\n\n if (buf.length === 0) {\n return buf\n }\n\n obj.copy(buf, 0, 0, len)\n return buf\n }\n\n if (obj.length !== undefined) {\n if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) {\n return createBuffer(0)\n }\n return fromArrayLike(obj)\n }\n\n if (obj.type === 'Buffer' && Array.isArray(obj.data)) {\n return fromArrayLike(obj.data)\n }\n}\n\nfunction checked (length) {\n // Note: cannot use `length < K_MAX_LENGTH` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= K_MAX_LENGTH) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0\n }\n return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return b != null && b._isBuffer === true &&\n b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false\n}\n\nBuffer.compare = function compare (a, b) {\n if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength)\n if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength)\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError(\n 'The \"buf1\", \"buf2\" arguments must be one of type Buffer or Uint8Array'\n )\n }\n\n if (a === b) return 0\n\n let x = a.length\n let y = b.length\n\n for (let i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i]\n y = b[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'latin1':\n case 'binary':\n case 'base64':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!Array.isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n let i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; ++i) {\n length += list[i].length\n }\n }\n\n const buffer = Buffer.allocUnsafe(length)\n let pos = 0\n for (i = 0; i < list.length; ++i) {\n let buf = list[i]\n if (isInstance(buf, Uint8Array)) {\n if (pos + buf.length > buffer.length) {\n if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf)\n buf.copy(buffer, pos)\n } else {\n Uint8Array.prototype.set.call(\n buffer,\n buf,\n pos\n )\n }\n } else if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n } else {\n buf.copy(buffer, pos)\n }\n pos += buf.length\n }\n return buffer\n}\n\nfunction byteLength (string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length\n }\n if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n throw new TypeError(\n 'The \"string\" argument must be one of type string, Buffer, or ArrayBuffer. ' +\n 'Received type ' + typeof string\n )\n }\n\n const len = string.length\n const mustMatch = (arguments.length > 2 && arguments[2] === true)\n if (!mustMatch && len === 0) return 0\n\n // Use a for loop to avoid recursion\n let loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'latin1':\n case 'binary':\n return len\n case 'utf8':\n case 'utf-8':\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) {\n return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8\n }\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n let loweredCase = false\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coercion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0\n start >>>= 0\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8'\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'latin1':\n case 'binary':\n return latin1Slice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\n// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)\n// to detect a Buffer instance. It's not possible to use `instanceof Buffer`\n// reliably in a browserify context because there could be multiple different\n// copies of the 'buffer' package in use. This method works even for Buffer\n// instances that were created from another copy of the `buffer` package.\n// See: https://github.com/feross/buffer/issues/154\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n const i = b[n]\n b[n] = b[m]\n b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n const len = this.length\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (let i = 0; i < len; i += 2) {\n swap(this, i, i + 1)\n }\n return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n const len = this.length\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (let i = 0; i < len; i += 4) {\n swap(this, i, i + 3)\n swap(this, i + 1, i + 2)\n }\n return this\n}\n\nBuffer.prototype.swap64 = function swap64 () {\n const len = this.length\n if (len % 8 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 64-bits')\n }\n for (let i = 0; i < len; i += 8) {\n swap(this, i, i + 7)\n swap(this, i + 1, i + 6)\n swap(this, i + 2, i + 5)\n swap(this, i + 3, i + 4)\n }\n return this\n}\n\nBuffer.prototype.toString = function toString () {\n const length = this.length\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.toLocaleString = Buffer.prototype.toString\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n let str = ''\n const max = exports.INSPECT_MAX_BYTES\n str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim()\n if (this.length > max) str += ' ... '\n return ''\n}\nif (customInspectSymbol) {\n Buffer.prototype[customInspectSymbol] = Buffer.prototype.inspect\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (isInstance(target, Uint8Array)) {\n target = Buffer.from(target, target.offset, target.byteLength)\n }\n if (!Buffer.isBuffer(target)) {\n throw new TypeError(\n 'The \"target\" argument must be one of type Buffer or Uint8Array. ' +\n 'Received type ' + (typeof target)\n )\n }\n\n if (start === undefined) {\n start = 0\n }\n if (end === undefined) {\n end = target ? target.length : 0\n }\n if (thisStart === undefined) {\n thisStart = 0\n }\n if (thisEnd === undefined) {\n thisEnd = this.length\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0\n end >>>= 0\n thisStart >>>= 0\n thisEnd >>>= 0\n\n if (this === target) return 0\n\n let x = thisEnd - thisStart\n let y = end - start\n const len = Math.min(x, y)\n\n const thisCopy = this.slice(thisStart, thisEnd)\n const targetCopy = target.slice(start, end)\n\n for (let i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i]\n y = targetCopy[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\n// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,\n// OR the last index of `val` in `buffer` at offset <= `byteOffset`.\n//\n// Arguments:\n// - buffer - a Buffer to search\n// - val - a string, Buffer, or number\n// - byteOffset - an index into `buffer`; will be clamped to an int32\n// - encoding - an optional encoding, relevant is val is a string\n// - dir - true for indexOf, false for lastIndexOf\nfunction bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {\n // Empty buffer means no match\n if (buffer.length === 0) return -1\n\n // Normalize byteOffset\n if (typeof byteOffset === 'string') {\n encoding = byteOffset\n byteOffset = 0\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000\n }\n byteOffset = +byteOffset // Coerce to Number.\n if (numberIsNaN(byteOffset)) {\n // byteOffset: it it's undefined, null, NaN, \"foo\", etc, search whole buffer\n byteOffset = dir ? 0 : (buffer.length - 1)\n }\n\n // Normalize byteOffset: negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = buffer.length + byteOffset\n if (byteOffset >= buffer.length) {\n if (dir) return -1\n else byteOffset = buffer.length - 1\n } else if (byteOffset < 0) {\n if (dir) byteOffset = 0\n else return -1\n }\n\n // Normalize val\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding)\n }\n\n // Finally, search either indexOf (if dir is true) or lastIndexOf\n if (Buffer.isBuffer(val)) {\n // Special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(buffer, val, byteOffset, encoding, dir)\n } else if (typeof val === 'number') {\n val = val & 0xFF // Search for a byte value [0-255]\n if (typeof Uint8Array.prototype.indexOf === 'function') {\n if (dir) {\n return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)\n } else {\n return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)\n }\n }\n return arrayIndexOf(buffer, [val], byteOffset, encoding, dir)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding, dir) {\n let indexSize = 1\n let arrLength = arr.length\n let valLength = val.length\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase()\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2\n arrLength /= 2\n valLength /= 2\n byteOffset /= 2\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n let i\n if (dir) {\n let foundIndex = -1\n for (i = byteOffset; i < arrLength; i++) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex\n foundIndex = -1\n }\n }\n } else {\n if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength\n for (i = byteOffset; i >= 0; i--) {\n let found = true\n for (let j = 0; j < valLength; j++) {\n if (read(arr, i + j) !== read(val, j)) {\n found = false\n break\n }\n }\n if (found) return i\n }\n }\n\n return -1\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, true)\n}\n\nBuffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, false)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n const remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n const strLen = string.length\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n let i\n for (i = 0; i < length; ++i) {\n const parsed = parseInt(string.substr(i * 2, 2), 16)\n if (numberIsNaN(parsed)) return i\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset >>> 0\n if (isFinite(length)) {\n length = length >>> 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n const remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n let loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n case 'latin1':\n case 'binary':\n return asciiWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n const res = []\n\n let i = start\n while (i < end) {\n const firstByte = buf[i]\n let codePoint = null\n let bytesPerSequence = (firstByte > 0xEF)\n ? 4\n : (firstByte > 0xDF)\n ? 3\n : (firstByte > 0xBF)\n ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n let secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nconst MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n const len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n let res = ''\n let i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n let ret = ''\n end = Math.min(buf.length, end)\n\n for (let i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction latin1Slice (buf, start, end) {\n let ret = ''\n end = Math.min(buf.length, end)\n\n for (let i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n const len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n let out = ''\n for (let i = start; i < end; ++i) {\n out += hexSliceLookupTable[buf[i]]\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n const bytes = buf.slice(start, end)\n let res = ''\n // If bytes.length is odd, the last 8 bits must be ignored (same as node.js)\n for (let i = 0; i < bytes.length - 1; i += 2) {\n res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256))\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n const len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n const newBuf = this.subarray(start, end)\n // Return an augmented `Uint8Array` instance\n Object.setPrototypeOf(newBuf, Buffer.prototype)\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUintLE =\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset >>> 0\n byteLength = byteLength >>> 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n let val = this[offset]\n let mul = 1\n let i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUintBE =\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset >>> 0\n byteLength = byteLength >>> 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n let val = this[offset + --byteLength]\n let mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUint8 =\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUint16LE =\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUint16BE =\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUint32LE =\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUint32BE =\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readBigUInt64LE = defineBigIntMethod(function readBigUInt64LE (offset) {\n offset = offset >>> 0\n validateNumber(offset, 'offset')\n const first = this[offset]\n const last = this[offset + 7]\n if (first === undefined || last === undefined) {\n boundsError(offset, this.length - 8)\n }\n\n const lo = first +\n this[++offset] * 2 ** 8 +\n this[++offset] * 2 ** 16 +\n this[++offset] * 2 ** 24\n\n const hi = this[++offset] +\n this[++offset] * 2 ** 8 +\n this[++offset] * 2 ** 16 +\n last * 2 ** 24\n\n return BigInt(lo) + (BigInt(hi) << BigInt(32))\n})\n\nBuffer.prototype.readBigUInt64BE = defineBigIntMethod(function readBigUInt64BE (offset) {\n offset = offset >>> 0\n validateNumber(offset, 'offset')\n const first = this[offset]\n const last = this[offset + 7]\n if (first === undefined || last === undefined) {\n boundsError(offset, this.length - 8)\n }\n\n const hi = first * 2 ** 24 +\n this[++offset] * 2 ** 16 +\n this[++offset] * 2 ** 8 +\n this[++offset]\n\n const lo = this[++offset] * 2 ** 24 +\n this[++offset] * 2 ** 16 +\n this[++offset] * 2 ** 8 +\n last\n\n return (BigInt(hi) << BigInt(32)) + BigInt(lo)\n})\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset >>> 0\n byteLength = byteLength >>> 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n let val = this[offset]\n let mul = 1\n let i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset >>> 0\n byteLength = byteLength >>> 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n let i = byteLength\n let mul = 1\n let val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 2, this.length)\n const val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 2, this.length)\n const val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readBigInt64LE = defineBigIntMethod(function readBigInt64LE (offset) {\n offset = offset >>> 0\n validateNumber(offset, 'offset')\n const first = this[offset]\n const last = this[offset + 7]\n if (first === undefined || last === undefined) {\n boundsError(offset, this.length - 8)\n }\n\n const val = this[offset + 4] +\n this[offset + 5] * 2 ** 8 +\n this[offset + 6] * 2 ** 16 +\n (last << 24) // Overflow\n\n return (BigInt(val) << BigInt(32)) +\n BigInt(first +\n this[++offset] * 2 ** 8 +\n this[++offset] * 2 ** 16 +\n this[++offset] * 2 ** 24)\n})\n\nBuffer.prototype.readBigInt64BE = defineBigIntMethod(function readBigInt64BE (offset) {\n offset = offset >>> 0\n validateNumber(offset, 'offset')\n const first = this[offset]\n const last = this[offset + 7]\n if (first === undefined || last === undefined) {\n boundsError(offset, this.length - 8)\n }\n\n const val = (first << 24) + // Overflow\n this[++offset] * 2 ** 16 +\n this[++offset] * 2 ** 8 +\n this[++offset]\n\n return (BigInt(val) << BigInt(32)) +\n BigInt(this[++offset] * 2 ** 24 +\n this[++offset] * 2 ** 16 +\n this[++offset] * 2 ** 8 +\n last)\n})\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n offset = offset >>> 0\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUintLE =\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset >>> 0\n byteLength = byteLength >>> 0\n if (!noAssert) {\n const maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n let mul = 1\n let i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUintBE =\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset >>> 0\n byteLength = byteLength >>> 0\n if (!noAssert) {\n const maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n let i = byteLength - 1\n let mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUint8 =\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeUint16LE =\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n return offset + 2\n}\n\nBuffer.prototype.writeUint16BE =\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n return offset + 2\n}\n\nBuffer.prototype.writeUint32LE =\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n return offset + 4\n}\n\nBuffer.prototype.writeUint32BE =\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n return offset + 4\n}\n\nfunction wrtBigUInt64LE (buf, value, offset, min, max) {\n checkIntBI(value, min, max, buf, offset, 7)\n\n let lo = Number(value & BigInt(0xffffffff))\n buf[offset++] = lo\n lo = lo >> 8\n buf[offset++] = lo\n lo = lo >> 8\n buf[offset++] = lo\n lo = lo >> 8\n buf[offset++] = lo\n let hi = Number(value >> BigInt(32) & BigInt(0xffffffff))\n buf[offset++] = hi\n hi = hi >> 8\n buf[offset++] = hi\n hi = hi >> 8\n buf[offset++] = hi\n hi = hi >> 8\n buf[offset++] = hi\n return offset\n}\n\nfunction wrtBigUInt64BE (buf, value, offset, min, max) {\n checkIntBI(value, min, max, buf, offset, 7)\n\n let lo = Number(value & BigInt(0xffffffff))\n buf[offset + 7] = lo\n lo = lo >> 8\n buf[offset + 6] = lo\n lo = lo >> 8\n buf[offset + 5] = lo\n lo = lo >> 8\n buf[offset + 4] = lo\n let hi = Number(value >> BigInt(32) & BigInt(0xffffffff))\n buf[offset + 3] = hi\n hi = hi >> 8\n buf[offset + 2] = hi\n hi = hi >> 8\n buf[offset + 1] = hi\n hi = hi >> 8\n buf[offset] = hi\n return offset + 8\n}\n\nBuffer.prototype.writeBigUInt64LE = defineBigIntMethod(function writeBigUInt64LE (value, offset = 0) {\n return wrtBigUInt64LE(this, value, offset, BigInt(0), BigInt('0xffffffffffffffff'))\n})\n\nBuffer.prototype.writeBigUInt64BE = defineBigIntMethod(function writeBigUInt64BE (value, offset = 0) {\n return wrtBigUInt64BE(this, value, offset, BigInt(0), BigInt('0xffffffffffffffff'))\n})\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) {\n const limit = Math.pow(2, (8 * byteLength) - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n let i = 0\n let mul = 1\n let sub = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) {\n const limit = Math.pow(2, (8 * byteLength) - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n let i = byteLength - 1\n let mul = 1\n let sub = 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n return offset + 4\n}\n\nBuffer.prototype.writeBigInt64LE = defineBigIntMethod(function writeBigInt64LE (value, offset = 0) {\n return wrtBigUInt64LE(this, value, offset, -BigInt('0x8000000000000000'), BigInt('0x7fffffffffffffff'))\n})\n\nBuffer.prototype.writeBigInt64BE = defineBigIntMethod(function writeBigInt64BE (value, offset = 0) {\n return wrtBigUInt64BE(this, value, offset, -BigInt('0x8000000000000000'), BigInt('0x7fffffffffffffff'))\n})\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n value = +value\n offset = offset >>> 0\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer')\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('Index out of range')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n const len = end - start\n\n if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') {\n // Use built-in when available, missing from IE11\n this.copyWithin(targetStart, start, end)\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, end),\n targetStart\n )\n }\n\n return len\n}\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start\n start = 0\n end = this.length\n } else if (typeof end === 'string') {\n encoding = end\n end = this.length\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n if (val.length === 1) {\n const code = val.charCodeAt(0)\n if ((encoding === 'utf8' && code < 128) ||\n encoding === 'latin1') {\n // Fast path: If `val` fits into a single byte, use that numeric value.\n val = code\n }\n }\n } else if (typeof val === 'number') {\n val = val & 255\n } else if (typeof val === 'boolean') {\n val = Number(val)\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0\n end = end === undefined ? this.length : end >>> 0\n\n if (!val) val = 0\n\n let i\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val\n }\n } else {\n const bytes = Buffer.isBuffer(val)\n ? val\n : Buffer.from(val, encoding)\n const len = bytes.length\n if (len === 0) {\n throw new TypeError('The value \"' + val +\n '\" is invalid for argument \"value\"')\n }\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }\n }\n\n return this\n}\n\n// CUSTOM ERRORS\n// =============\n\n// Simplified versions from Node, changed for Buffer-only usage\nconst errors = {}\nfunction E (sym, getMessage, Base) {\n errors[sym] = class NodeError extends Base {\n constructor () {\n super()\n\n Object.defineProperty(this, 'message', {\n value: getMessage.apply(this, arguments),\n writable: true,\n configurable: true\n })\n\n // Add the error code to the name to include it in the stack trace.\n this.name = `${this.name} [${sym}]`\n // Access the stack to generate the error message including the error code\n // from the name.\n this.stack // eslint-disable-line no-unused-expressions\n // Reset the name to the actual name.\n delete this.name\n }\n\n get code () {\n return sym\n }\n\n set code (value) {\n Object.defineProperty(this, 'code', {\n configurable: true,\n enumerable: true,\n value,\n writable: true\n })\n }\n\n toString () {\n return `${this.name} [${sym}]: ${this.message}`\n }\n }\n}\n\nE('ERR_BUFFER_OUT_OF_BOUNDS',\n function (name) {\n if (name) {\n return `${name} is outside of buffer bounds`\n }\n\n return 'Attempt to access memory outside buffer bounds'\n }, RangeError)\nE('ERR_INVALID_ARG_TYPE',\n function (name, actual) {\n return `The \"${name}\" argument must be of type number. Received type ${typeof actual}`\n }, TypeError)\nE('ERR_OUT_OF_RANGE',\n function (str, range, input) {\n let msg = `The value of \"${str}\" is out of range.`\n let received = input\n if (Number.isInteger(input) && Math.abs(input) > 2 ** 32) {\n received = addNumericalSeparator(String(input))\n } else if (typeof input === 'bigint') {\n received = String(input)\n if (input > BigInt(2) ** BigInt(32) || input < -(BigInt(2) ** BigInt(32))) {\n received = addNumericalSeparator(received)\n }\n received += 'n'\n }\n msg += ` It must be ${range}. Received ${received}`\n return msg\n }, RangeError)\n\nfunction addNumericalSeparator (val) {\n let res = ''\n let i = val.length\n const start = val[0] === '-' ? 1 : 0\n for (; i >= start + 4; i -= 3) {\n res = `_${val.slice(i - 3, i)}${res}`\n }\n return `${val.slice(0, i)}${res}`\n}\n\n// CHECK FUNCTIONS\n// ===============\n\nfunction checkBounds (buf, offset, byteLength) {\n validateNumber(offset, 'offset')\n if (buf[offset] === undefined || buf[offset + byteLength] === undefined) {\n boundsError(offset, buf.length - (byteLength + 1))\n }\n}\n\nfunction checkIntBI (value, min, max, buf, offset, byteLength) {\n if (value > max || value < min) {\n const n = typeof min === 'bigint' ? 'n' : ''\n let range\n if (byteLength > 3) {\n if (min === 0 || min === BigInt(0)) {\n range = `>= 0${n} and < 2${n} ** ${(byteLength + 1) * 8}${n}`\n } else {\n range = `>= -(2${n} ** ${(byteLength + 1) * 8 - 1}${n}) and < 2 ** ` +\n `${(byteLength + 1) * 8 - 1}${n}`\n }\n } else {\n range = `>= ${min}${n} and <= ${max}${n}`\n }\n throw new errors.ERR_OUT_OF_RANGE('value', range, value)\n }\n checkBounds(buf, offset, byteLength)\n}\n\nfunction validateNumber (value, name) {\n if (typeof value !== 'number') {\n throw new errors.ERR_INVALID_ARG_TYPE(name, 'number', value)\n }\n}\n\nfunction boundsError (value, length, type) {\n if (Math.floor(value) !== value) {\n validateNumber(value, type)\n throw new errors.ERR_OUT_OF_RANGE(type || 'offset', 'an integer', value)\n }\n\n if (length < 0) {\n throw new errors.ERR_BUFFER_OUT_OF_BOUNDS()\n }\n\n throw new errors.ERR_OUT_OF_RANGE(type || 'offset',\n `>= ${type ? 1 : 0} and <= ${length}`,\n value)\n}\n\n// HELPER FUNCTIONS\n// ================\n\nconst INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node takes equal signs as end of the Base64 encoding\n str = str.split('=')[0]\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = str.trim().replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n let codePoint\n const length = string.length\n let leadSurrogate = null\n const bytes = []\n\n for (let i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n const byteArray = []\n for (let i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n let c, hi, lo\n const byteArray = []\n for (let i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n let i\n for (i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n\n// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass\n// the `instanceof` check but they should be treated as of that type.\n// See: https://github.com/feross/buffer/issues/166\nfunction isInstance (obj, type) {\n return obj instanceof type ||\n (obj != null && obj.constructor != null && obj.constructor.name != null &&\n obj.constructor.name === type.name)\n}\nfunction numberIsNaN (obj) {\n // For IE11 support\n return obj !== obj // eslint-disable-line no-self-compare\n}\n\n// Create lookup table for `toString('hex')`\n// See: https://github.com/feross/buffer/issues/219\nconst hexSliceLookupTable = (function () {\n const alphabet = '0123456789abcdef'\n const table = new Array(256)\n for (let i = 0; i < 16; ++i) {\n const i16 = i * 16\n for (let j = 0; j < 16; ++j) {\n table[i16 + j] = alphabet[i] + alphabet[j]\n }\n }\n return table\n})()\n\n// Return not function with Error if BigInt not supported\nfunction defineBigIntMethod (fn) {\n return typeof BigInt === 'undefined' ? BufferBigIntNotDefined : fn\n}\n\nfunction BufferBigIntNotDefined () {\n throw new Error('BigInt not supported')\n}\n", "import { Buffer } from 'buffer';\nimport { FIT } from './fit.js';\nimport { getFitMessage, getFitMessageBaseType } from './messages.js';\nconst CompressedLocalMsgNumMask = 0x60;\nconst CompressedHeaderMask = 0x80;\nconst GarminTimeOffset = 631065600000;\nlet monitoring_timestamp = 0;\nexport function addEndian(littleEndian, bytes) {\n let result = 0;\n if (!littleEndian)\n bytes.reverse();\n for (let i = 0; i < bytes.length; i++) {\n result += (bytes[i] << (i << 3)) >>> 0;\n }\n return result;\n}\nfunction readData(blob, fDef, startIndex, options) {\n if (fDef.type === 'uint8_array') {\n const array8 = [];\n for (let i = 0; i < fDef.size; i++) {\n array8.push(blob[startIndex + i]);\n }\n return array8;\n }\n if (fDef.endianAbility) {\n const temp = [];\n for (let i = 0; i < fDef.size; i++) {\n temp.push(blob[startIndex + i]);\n }\n const { buffer } = new Uint8Array(temp);\n const dataView = new DataView(buffer);\n try {\n switch (fDef.type) {\n case 'sint16':\n return dataView.getInt16(0, fDef.littleEndian);\n case 'uint16':\n case 'uint16z':\n return dataView.getUint16(0, fDef.littleEndian);\n case 'sint32':\n return dataView.getInt32(0, fDef.littleEndian);\n case 'uint32':\n case 'uint32z':\n return dataView.getUint32(0, fDef.littleEndian);\n case 'float32':\n return dataView.getFloat32(0, fDef.littleEndian);\n case 'float64':\n return dataView.getFloat64(0, fDef.littleEndian);\n case 'uint32_array': {\n const array32 = [];\n for (let i = 0; i < fDef.size; i += 4) {\n array32.push(dataView.getUint32(i, fDef.littleEndian));\n }\n return array32;\n }\n case 'uint16_array': {\n const array16 = [];\n for (let i = 0; i < fDef.size; i += 2) {\n array16.push(dataView.getUint16(i, fDef.littleEndian));\n }\n return array16;\n }\n }\n }\n catch (e) {\n if (!options.force) {\n throw e;\n }\n }\n return addEndian(fDef.littleEndian, temp);\n }\n if (fDef.type === 'string') {\n const temp = [];\n for (let i = 0; i < fDef.size; i++) {\n if (blob[startIndex + i]) {\n temp.push(blob[startIndex + i]);\n }\n }\n return Buffer.from(temp).toString('utf-8');\n }\n if (fDef.type === 'byte_array') {\n const temp = [];\n for (let i = 0; i < fDef.size; i++) {\n temp.push(blob[startIndex + i]);\n }\n return temp;\n }\n if (fDef.type === 'sint8') {\n const val = blob[startIndex];\n return val > 127 ? val - 256 : val;\n }\n return blob[startIndex];\n}\nfunction formatByType(data, type, scale, offset) {\n switch (type) {\n case 'date_time':\n case 'local_date_time':\n return new Date(data * 1000 + GarminTimeOffset);\n case 'sint32':\n return data * FIT.scConst;\n case 'uint8':\n case 'sint16':\n case 'uint32':\n case 'uint16':\n return scale ? data / scale + offset : data;\n case 'uint32_array':\n case 'uint16_array':\n case 'uint8_array':\n if (Array.isArray(data)) {\n const baseType = type.replace('_array', '');\n return data.map((dataItem) => {\n if (isInvalidValue(dataItem, baseType)) {\n return null;\n }\n return scale ? dataItem / scale + offset : dataItem;\n });\n }\n return scale ? data / scale + offset : data;\n default:\n {\n if (!FIT.types[type]) {\n return data;\n }\n // Quick check for a mask\n const values = [];\n for (const key in FIT.types[type]) {\n if (key in FIT.types[type]) {\n values.push(String(FIT.types[type][key]));\n }\n }\n if (!values.includes('mask')) {\n const typeMap = FIT.types[type];\n const mapped = typeMap[String(data)];\n return mapped === undefined ? data : mapped;\n }\n const dataItem = {};\n for (const key in FIT.types[type]) {\n if (key in FIT.types[type]) {\n if (FIT.types[type][key] === 'mask') {\n dataItem.value = data & Number(key);\n }\n else {\n dataItem[FIT.types[type][key]] = !!((data & Number(key)) >> 7); // Not sure if we need the >> 7 and casting to boolean but from all the masked props of fields so far this seems to be the case\n }\n }\n }\n return dataItem;\n }\n }\n}\nfunction isInvalidValue(data, type) {\n switch (type) {\n case 'enum':\n return data === 0xFF;\n case 'sint8':\n return data === 0x7F;\n case 'uint8':\n return data === 0xFF;\n case 'sint16':\n return data === 0x7FFF;\n case 'uint16':\n return data === 0xFFFF;\n case 'sint32':\n return data === 0x7FFFFFFF;\n case 'uint32':\n return data === 0xFFFFFFFF;\n case 'string':\n return data === 0x00;\n case 'float32':\n return data === 0xFFFFFFFF;\n case 'float64':\n // eslint-disable-next-line no-loss-of-precision\n return data === 0xFFFFFFFFFFFFFFFF;\n case 'uint8z':\n return data === 0x00;\n case 'uint16z':\n return data === 0x0000;\n case 'uint32z':\n return data === 0x000000;\n case 'byte':\n return data === 0xFF;\n case 'sint64':\n // eslint-disable-next-line no-loss-of-precision\n return data === 0x7FFFFFFFFFFFFFFF;\n case 'uint64':\n // eslint-disable-next-line no-loss-of-precision\n return data === 0xFFFFFFFFFFFFFFFF;\n case 'uint64z':\n return data === 0x0000000000000000;\n default:\n return false;\n }\n}\nfunction convertTo(data, unitsList, unitName) {\n const options = FIT.options[unitsList];\n const unit = options[unitName];\n return unit ? data * unit.multiplier + unit.offset : data;\n}\nfunction applyOptions(data, field, options, fields) {\n switch (field) {\n case 'device_type': {\n const isLocal = fields.source_type === 'local' || fields.source_type === 5;\n const isBLE = fields.source_type === 'bluetooth_low_energy' || fields.source_type === 3 || fields.source_type === 'bluetooth' || fields.source_type === 2;\n const isANT = fields.source_type === 'antplus' || fields.source_type === 1 || fields.source_type === 'ant' || fields.source_type === 0;\n if (isLocal) {\n return FIT.types.local_device_type[data] || data;\n }\n if (isBLE) {\n return FIT.types.ble_device_type[data] || data;\n }\n if (isANT) {\n return FIT.types.antplus_device_type[data] || data;\n }\n return data;\n }\n case 'speed':\n case 'enhanced_speed':\n case 'vertical_speed':\n case 'avg_speed':\n case 'max_speed':\n case 'speed_1s':\n case 'ball_speed':\n case 'enhanced_avg_speed':\n case 'enhanced_max_speed':\n case 'avg_pos_vertical_speed':\n case 'max_pos_vertical_speed':\n case 'avg_neg_vertical_speed':\n case 'max_neg_vertical_speed':\n return convertTo(data, 'speedUnits', options.speedUnit);\n case 'distance':\n case 'total_distance':\n case 'enhanced_avg_altitude':\n case 'enhanced_min_altitude':\n case 'enhanced_max_altitude':\n case 'enhanced_altitude':\n case 'height':\n case 'odometer':\n case 'avg_stroke_distance':\n case 'min_altitude':\n case 'avg_altitude':\n case 'max_altitude':\n case 'total_ascent':\n case 'total_descent':\n case 'altitude':\n case 'cycle_length':\n case 'auto_wheelsize':\n case 'custom_wheelsize':\n case 'gps_accuracy':\n return convertTo(data, 'lengthUnits', options.lengthUnit);\n case 'temperature':\n case 'avg_temperature':\n case 'max_temperature':\n return convertTo(data, 'temperatureUnits', options.temperatureUnit);\n case 'pressure':\n case 'start_pressure':\n case 'end_pressure':\n return convertTo(data, 'pressureUnits', options.pressureUnit);\n case 'ant_id': {\n const n1 = (data >>> 28) & 0xF;\n const n2 = (data >>> 24) & 0xF;\n const n3 = (data >>> 16) & 0xFF;\n const n4 = data & 0xFFFF;\n return `${n1.toString(16).toUpperCase()}-${n2.toString(16).toUpperCase()}-${n3.toString(16).toUpperCase().padStart(2, '0')}-${n4.toString(16).toUpperCase().padStart(4, '0')}`;\n }\n default:\n return data;\n }\n}\nexport function readRecord(blob, messageTypes, developerFields, startIndex, options, startDate, pausedTime) {\n const recordHeader = blob[startIndex];\n let localMessageType = recordHeader & 15;\n if ((recordHeader & CompressedHeaderMask) === CompressedHeaderMask) {\n // compressed timestamp\n localMessageType = (recordHeader & CompressedLocalMsgNumMask) >> 5;\n }\n else if ((recordHeader & 64) === 64) {\n // is definition message\n // startIndex + 1 is reserved\n const hasDeveloperData = (recordHeader & 32) === 32;\n const lEnd = blob[startIndex + 2] === 0;\n const numberOfFields = blob[startIndex + 5];\n const numberOfDeveloperDataFields = hasDeveloperData\n ? blob[startIndex + 5 + numberOfFields * 3 + 1]\n : 0;\n const mTypeDef = {\n littleEndian: lEnd,\n globalMessageNumber: addEndian(lEnd, [\n blob[startIndex + 3],\n blob[startIndex + 4],\n ]),\n numberOfFields: numberOfFields + numberOfDeveloperDataFields,\n fieldDefs: [],\n };\n const message = getFitMessage(mTypeDef.globalMessageNumber);\n for (let i = 0; i < numberOfFields; i++) {\n const fDefIndex = startIndex + 6 + i * 3;\n const baseType = blob[fDefIndex + 2];\n const { field, type } = message.getAttributes(blob[fDefIndex]);\n const fDef = {\n type,\n fDefNo: blob[fDefIndex],\n size: blob[fDefIndex + 1],\n endianAbility: (baseType & 128) === 128,\n littleEndian: lEnd,\n baseTypeNo: baseType & 15,\n name: field,\n dataType: getFitMessageBaseType(baseType & 15),\n };\n mTypeDef.fieldDefs.push(fDef);\n }\n // numberOfDeveloperDataFields = 0 so it wont crash here and wont loop\n for (let i = 0; i < numberOfDeveloperDataFields; i++) {\n // If we fail to parse then try catch\n try {\n const fDefIndex = startIndex + 6 + numberOfFields * 3 + 1 + i * 3;\n const fieldNum = blob[fDefIndex];\n const size = blob[fDefIndex + 1];\n const devDataIndex = blob[fDefIndex + 2];\n const devDef = developerFields[devDataIndex][fieldNum];\n const baseType = devDef.fit_base_type_id;\n const fDef = {\n type: FIT.types.fit_base_type[baseType],\n fDefNo: fieldNum,\n size,\n endianAbility: (baseType & 128) === 128,\n littleEndian: lEnd,\n baseTypeNo: baseType & 15,\n name: devDef.field_name,\n dataType: getFitMessageBaseType(baseType & 15),\n scale: devDef.scale || 1,\n offset: devDef.offset || 0,\n developerDataIndex: devDataIndex,\n isDeveloperField: true,\n };\n mTypeDef.fieldDefs.push(fDef);\n }\n catch (e) {\n if (options.force) {\n continue;\n }\n throw e;\n }\n }\n messageTypes[localMessageType] = mTypeDef;\n const nextIndex = startIndex + 6 + mTypeDef.numberOfFields * 3;\n const nextIndexWithDeveloperData = nextIndex + 1;\n return {\n messageType: 'definition',\n nextIndex: hasDeveloperData ? nextIndexWithDeveloperData : nextIndex,\n };\n }\n const messageType = messageTypes[localMessageType] || messageTypes[0];\n // TODO: handle compressed header ((recordHeader & 128) == 128)\n // uncompressed header\n let messageSize = 0;\n let readDataFromIndex = startIndex + 1;\n const fields = {};\n const message = getFitMessage(messageType.globalMessageNumber);\n const rawFields = [];\n for (let i = 0; i < messageType.fieldDefs.length; i++) {\n const fDef = messageType.fieldDefs[i];\n const data = readData(blob, fDef, readDataFromIndex, options);\n if (!isInvalidValue(data, fDef.type)) {\n rawFields.push({ fDef, data });\n }\n readDataFromIndex += fDef.size;\n messageSize += fDef.size;\n }\n for (const { fDef, data } of rawFields) {\n const { field } = fDef.isDeveloperField ? { field: fDef.name } : message.getAttributes(fDef.fDefNo);\n if (field !== 'unknown' && field !== '' && field !== undefined) {\n fields[field] = data;\n }\n }\n for (const { fDef, data } of rawFields) {\n if (fDef.isDeveloperField) {\n const field = fDef.name;\n const { type } = fDef;\n const { scale } = fDef;\n const { offset } = fDef;\n fields[fDef.name] = applyOptions(formatByType(data, type, scale, offset), field, options, fields);\n }\n else {\n const { field, type, scale, offset } = message.getAttributes(fDef.fDefNo);\n if (field !== 'unknown' && field !== '' && field !== undefined) {\n fields[field] = applyOptions(formatByType(data, type, scale, offset), field, options, fields);\n }\n }\n if (message.name === 'record' && options.elapsedRecordField) {\n fields.elapsed_time = (fields.timestamp - (startDate || 0)) / 1000;\n fields.timer_time = fields.elapsed_time - pausedTime;\n }\n }\n if (message.name === 'field_description') {\n developerFields[fields.developer_data_index]\n = developerFields[fields.developer_data_index] || [];\n developerFields[fields.developer_data_index][fields.field_definition_number] = fields;\n }\n if (message.name === 'monitoring') {\n // TODO weirdly uses global variables?\n // we need to keep the raw timestamp value so we can calculate subsequent timestamp16 fields\n if (fields.timestamp) {\n monitoring_timestamp = fields.timestamp;\n fields.timestamp = new Date(fields.timestamp * 1000 + GarminTimeOffset);\n }\n if (fields.timestamp16 && !fields.timestamp) {\n monitoring_timestamp\n += (fields.timestamp16 - (monitoring_timestamp & 0xFFFF)) & 0xFFFF;\n // fields.timestamp = monitoring_timestamp;\n fields.timestamp = new Date(monitoring_timestamp * 1000 + GarminTimeOffset);\n }\n }\n return {\n messageType: message.name,\n nextIndex: startIndex + messageSize + 1,\n message: fields,\n };\n}\nexport function getArrayBuffer(buffer) {\n if (buffer instanceof ArrayBuffer) {\n return buffer;\n }\n const ab = new ArrayBuffer(buffer.length);\n const view = new Uint8Array(ab);\n for (let i = 0; i < buffer.length; ++i) {\n view[i] = buffer[i];\n }\n return ab;\n}\nexport function calculateCRC(blob, start, end) {\n const crcTable = [\n 0x0000,\n 0xCC01,\n 0xD801,\n 0x1400,\n 0xF001,\n 0x3C00,\n 0x2800,\n 0xE401,\n 0xA001,\n 0x6C00,\n 0x7800,\n 0xB401,\n 0x5000,\n 0x9C01,\n 0x8801,\n 0x4400,\n ];\n let crc = 0;\n for (let i = start; i < end; i++) {\n const byteVal = blob[i];\n let tmp = crcTable[crc & 0xF];\n crc = (crc >> 4) & 0x0FFF;\n crc = crc ^ tmp ^ crcTable[byteVal & 0xF];\n tmp = crcTable[crc & 0xF];\n crc = (crc >> 4) & 0x0FFF;\n crc = crc ^ tmp ^ crcTable[(byteVal >> 4) & 0xF];\n }\n return crc;\n}\n", "const metersInOneKilometer = 1000;\nconst secondsInOneHour = 3600;\n// according to https://en.wikipedia.org/wiki/Mile\nconst metersInOneMile = 1609.344;\nconst centiBarsInOneBar = 100;\nconst psiInOneBar = 14.5037738;\n// TODO we dont have comprehensive output types bc its a bit cumbersome to maintain typescript types and this giant mapping object\n// which contains all the types and values\n// i would wish for some kind of inference mechanism here but for now we leave it as any\n// maybe zod could help here\nexport const FIT = {\n scConst: 180 / Math.pow(2, 31),\n options: {\n speedUnits: {\n // native speed unit: meters per second [m/s]\n 'm/s': {\n multiplier: 1,\n offset: 0,\n },\n // miles per hour [mph]\n 'mph': {\n multiplier: secondsInOneHour / metersInOneMile,\n offset: 0,\n },\n // kilometers per hour [km/h]\n 'km/h': {\n multiplier: secondsInOneHour / metersInOneKilometer,\n offset: 0,\n },\n },\n lengthUnits: {\n // native length unit: meters [m]\n m: {\n multiplier: 1,\n offset: 0,\n },\n // (international) mile [mi]\n mi: {\n multiplier: 1 / metersInOneMile,\n offset: 0,\n },\n // kilometer [km]\n km: {\n multiplier: 1 / metersInOneKilometer,\n offset: 0,\n },\n },\n temperatureUnits: {\n // native temperature unit: degree Celsius [\u00B0C]\n '\u00B0C': {\n multiplier: 1,\n offset: 0,\n },\n // kelvin [K]\n 'kelvin': {\n multiplier: 1,\n offset: -273.15,\n },\n // degree fahrenheit [\u00B0F]\n 'fahrenheit': {\n multiplier: 9 / 5,\n offset: 32,\n },\n },\n pressureUnits: {\n cbar: {\n multiplier: 1,\n offset: 0,\n },\n bar: {\n multiplier: 1 / centiBarsInOneBar,\n offset: 0,\n },\n psi: {\n multiplier: (1 / centiBarsInOneBar) * psiInOneBar,\n offset: 0,\n },\n },\n },\n messages: {\n 0: {\n name: 'file_id',\n 0: { field: 'type', type: 'file', scale: null, offset: 0, units: '' },\n 1: {\n field: 'manufacturer',\n type: 'manufacturer',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'product',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'serial_number',\n type: 'uint32z',\n scale: null,\n offset: 0,\n units: '',\n },\n 4: {\n field: 'time_created',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 5: { field: 'number', type: 'uint16', scale: null, offset: 0, units: '' },\n 8: {\n field: 'product_name',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 1: {\n name: 'capabilities',\n 0: {\n field: 'languages',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'sports',\n type: 'sport_bits_0',\n scale: null,\n offset: 0,\n units: '',\n },\n 21: {\n field: 'workouts_supported',\n type: 'workout_capabilities',\n scale: null,\n offset: 0,\n units: '',\n },\n 23: {\n field: 'connectivity_supported',\n type: 'connectivity_capabilities',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 2: {\n name: 'device_settings',\n 0: {\n field: 'active_time_zone',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'utc_offset',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'time_offset',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 's',\n },\n 5: {\n field: 'time_zone_offset',\n type: 'sint8',\n scale: 4,\n offset: 0,\n units: 'hr',\n },\n 55: {\n field: 'display_orientation',\n type: 'display_orientation',\n scale: null,\n offset: 0,\n units: '',\n },\n 56: {\n field: 'mounting_side',\n type: 'side',\n scale: null,\n offset: 0,\n units: '',\n },\n 94: {\n field: 'number_of_screens',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 95: {\n field: 'smart_notification_display_orientation',\n type: 'display_orientation',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 3: {\n name: 'user_profile',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: {\n field: 'friendly_name',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: { field: 'gender', type: 'gender', scale: null, offset: 0, units: '' },\n 2: {\n field: 'age',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'years',\n },\n 3: { field: 'height', type: 'uint8', scale: 100, offset: 0, units: 'm' },\n 4: { field: 'weight', type: 'uint16', scale: 10, offset: 0, units: 'kg' },\n 5: {\n field: 'language',\n type: 'language',\n scale: null,\n offset: 0,\n units: '',\n },\n 6: {\n field: 'elev_setting',\n type: 'display_measure',\n scale: null,\n offset: 0,\n units: '',\n },\n 7: {\n field: 'weight_setting',\n type: 'display_measure',\n scale: null,\n offset: 0,\n units: '',\n },\n 8: {\n field: 'resting_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 9: {\n field: 'default_max_running_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 10: {\n field: 'default_max_biking_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 11: {\n field: 'default_max_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 12: {\n field: 'hr_setting',\n type: 'display_heart',\n scale: null,\n offset: 0,\n units: '',\n },\n 13: {\n field: 'speed_setting',\n type: 'display_measure',\n scale: null,\n offset: 0,\n units: '',\n },\n 14: {\n field: 'dist_setting',\n type: 'display_measure',\n scale: null,\n offset: 0,\n units: '',\n },\n 16: {\n field: 'power_setting',\n type: 'display_power',\n scale: null,\n offset: 0,\n units: '',\n },\n 17: {\n field: 'activity_class',\n type: 'activity_class',\n scale: null,\n offset: 0,\n units: '',\n },\n 18: {\n field: 'position_setting',\n type: 'display_position',\n scale: null,\n offset: 0,\n units: '',\n },\n 21: {\n field: 'temperature_setting',\n type: 'display_measure',\n scale: null,\n offset: 0,\n units: '',\n },\n 22: {\n field: 'local_id',\n type: 'user_local_id',\n scale: null,\n offset: 0,\n units: '',\n },\n 23: {\n field: 'global_id',\n type: 'byte',\n scale: null,\n offset: 0,\n units: '',\n },\n 28: {\n field: 'wake_time',\n type: 'localtime_into_day',\n scale: null,\n offset: 0,\n units: '',\n },\n 29: {\n field: 'sleep_time',\n type: 'localtime_into_day',\n scale: null,\n offset: 0,\n units: '',\n },\n 30: {\n field: 'height_setting',\n type: 'display_measure',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 4: {\n name: 'hrm_profile',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: { field: 'enabled', type: 'bool', scale: null, offset: 0, units: '' },\n 1: {\n field: 'hrm_ant_id',\n type: 'uint16z',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: { field: 'log_hrv', type: 'bool', scale: null, offset: 0, units: '' },\n 3: {\n field: 'hrm_ant_id_trans_type',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 5: {\n name: 'sdm_profile',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: { field: 'enabled', type: 'bool', scale: null, offset: 0, units: '' },\n 1: {\n field: 'sdm_ant_id',\n type: 'uint16z',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'sdm_cal_factor',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 3: {\n field: 'odometer',\n type: 'uint32',\n scale: 100,\n offset: 0,\n units: 'm',\n },\n 4: {\n field: 'speed_source',\n type: 'bool',\n scale: null,\n offset: 0,\n units: '',\n },\n 5: {\n field: 'sdm_ant_id_trans_type',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 7: {\n field: 'odometer_rollover',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 6: {\n name: 'bike_profile',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: { field: 'name', type: 'string', scale: null, offset: 0, units: '' },\n 1: { field: 'sport', type: 'sport', scale: null, offset: 0, units: '' },\n 2: {\n field: 'sub_sport',\n type: 'sub_sport',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'odometer',\n type: 'uint32',\n scale: 100,\n offset: 0,\n units: 'm',\n },\n 4: {\n field: 'bike_spd_ant_id',\n type: 'uint16z',\n scale: null,\n offset: 0,\n units: '',\n },\n 5: {\n field: 'bike_cad_ant_id',\n type: 'uint16z',\n scale: null,\n offset: 0,\n units: '',\n },\n 6: {\n field: 'bike_spdcad_ant_id',\n type: 'uint16z',\n scale: null,\n offset: 0,\n units: '',\n },\n 7: {\n field: 'bike_power_ant_id',\n type: 'uint16z',\n scale: null,\n offset: 0,\n units: '',\n },\n 8: {\n field: 'custom_wheelsize',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm',\n },\n 9: {\n field: 'auto_wheelsize',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm',\n },\n 10: {\n field: 'bike_weight',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'kg',\n },\n 11: {\n field: 'power_cal_factor',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 12: {\n field: 'auto_wheel_cal',\n type: 'bool',\n scale: null,\n offset: 0,\n units: '',\n },\n 13: {\n field: 'auto_power_zero',\n type: 'bool',\n scale: null,\n offset: 0,\n units: '',\n },\n 14: { field: 'id', type: 'uint8', scale: null, offset: 0, units: '' },\n 15: {\n field: 'spd_enabled',\n type: 'bool',\n scale: null,\n offset: 0,\n units: '',\n },\n 16: {\n field: 'cad_enabled',\n type: 'bool',\n scale: null,\n offset: 0,\n units: '',\n },\n 17: {\n field: 'spdcad_enabled',\n type: 'bool',\n scale: null,\n offset: 0,\n units: '',\n },\n 18: {\n field: 'power_enabled',\n type: 'bool',\n scale: null,\n offset: 0,\n units: '',\n },\n 19: {\n field: 'crank_length',\n type: 'uint8',\n scale: 2,\n offset: -110,\n units: 'mm',\n },\n 20: { field: 'enabled', type: 'bool', scale: null, offset: 0, units: '' },\n 21: {\n field: 'bike_spd_ant_id_trans_type',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 22: {\n field: 'bike_cad_ant_id_trans_type',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 23: {\n field: 'bike_spdcad_ant_id_trans_type',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 24: {\n field: 'bike_power_ant_id_trans_type',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 37: {\n field: 'odometer_rollover',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 38: {\n field: 'front_gear_num',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 39: {\n field: 'front_gear',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 40: {\n field: 'rear_gear_num',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 41: {\n field: 'rear_gear',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 44: {\n field: 'shimano_di2_enabled',\n type: 'bool',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 7: {\n name: 'zones_target',\n 1: {\n field: 'max_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'threshold_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'functional_threshold_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 5: {\n field: 'hr_calc_type',\n type: 'hr_zone_calc',\n scale: null,\n offset: 0,\n units: '',\n },\n 7: {\n field: 'pwr_calc_type',\n type: 'pwr_zone_calc',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 8: {\n name: 'hr_zone',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'high_bpm',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 2: { field: 'name', type: 'string', scale: null, offset: 0, units: '' },\n },\n 9: {\n name: 'power_zone',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'high_value',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 2: { field: 'name', type: 'string', scale: null, offset: 0, units: '' },\n },\n 10: {\n name: 'met_zone',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'high_bpm',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'calories',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'kcal / min',\n },\n 3: {\n field: 'fat_calories',\n type: 'uint8',\n scale: 10,\n offset: 0,\n units: 'kcal / min',\n },\n },\n 12: {\n name: 'sport',\n 0: { field: 'sport', type: 'sport', scale: null, offset: 0, units: '' },\n 1: {\n field: 'sub_sport',\n type: 'sub_sport',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: { field: 'name', type: 'string', scale: null, offset: 0, units: '' },\n },\n 15: {\n name: 'goal',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: { field: 'sport', type: 'sport', scale: null, offset: 0, units: '' },\n 1: {\n field: 'sub_sport',\n type: 'sub_sport',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'start_date',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'end_date',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 4: { field: 'type', type: 'goal', scale: null, offset: 0, units: '' },\n 5: { field: 'value', type: 'uint32', scale: null, offset: 0, units: '' },\n 6: { field: 'repeat', type: 'bool', scale: null, offset: 0, units: '' },\n 7: {\n field: 'target_value',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 8: {\n field: 'recurrence',\n type: 'goal_recurrence',\n scale: null,\n offset: 0,\n units: '',\n },\n 9: {\n field: 'recurrence_value',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 10: { field: 'enabled', type: 'bool', scale: null, offset: 0, units: '' },\n },\n 18: {\n name: 'session',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: { field: 'event', type: 'event', scale: null, offset: 0, units: '' },\n 1: {\n field: 'event_type',\n type: 'event_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'start_time',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'start_position_lat',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 4: {\n field: 'start_position_long',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 5: { field: 'sport', type: 'sport', scale: null, offset: 0, units: '' },\n 6: {\n field: 'sub_sport',\n type: 'sub_sport',\n scale: null,\n offset: 0,\n units: '',\n },\n 7: {\n field: 'total_elapsed_time',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 8: {\n field: 'total_timer_time',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 9: {\n field: 'total_distance',\n type: 'uint32',\n scale: 100,\n offset: 0,\n units: 'm',\n },\n 10: {\n field: 'total_cycles',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'cycles',\n },\n 11: {\n field: 'total_calories',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'kcal',\n },\n 13: {\n field: 'total_fat_calories',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'kcal',\n },\n 14: {\n field: 'avg_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 15: {\n field: 'max_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 16: {\n field: 'avg_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 17: {\n field: 'max_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 18: {\n field: 'avg_cadence',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'rpm',\n },\n 19: {\n field: 'max_cadence',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'rpm',\n },\n 20: {\n field: 'avg_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 21: {\n field: 'max_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 22: {\n field: 'total_ascent',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 23: {\n field: 'total_descent',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 24: {\n field: 'total_training_effect',\n type: 'uint8',\n scale: 10,\n offset: 0,\n units: '',\n },\n 25: {\n field: 'first_lap_index',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 26: {\n field: 'num_laps',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 27: {\n field: 'event_group',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 28: {\n field: 'trigger',\n type: 'session_trigger',\n scale: null,\n offset: 0,\n units: '',\n },\n 29: {\n field: 'nec_lat',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 30: {\n field: 'nec_long',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 31: {\n field: 'swc_lat',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 32: {\n field: 'swc_long',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 34: {\n field: 'normalized_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 35: {\n field: 'training_stress_score',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'tss',\n },\n 36: {\n field: 'intensity_factor',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'if',\n },\n 37: {\n field: 'left_right_balance',\n type: 'left_right_balance_100',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 38: {\n field: 'end_position_lat',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 39: {\n field: 'end_position_long',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 41: {\n field: 'avg_stroke_count',\n type: 'uint32',\n scale: 10,\n offset: 0,\n units: 'strokes/lap',\n },\n 42: {\n field: 'avg_stroke_distance',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'm',\n },\n 43: {\n field: 'swim_stroke',\n type: 'swim_stroke',\n scale: null,\n offset: 0,\n units: 'swim_stroke',\n },\n 44: {\n field: 'pool_length',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'm',\n },\n 45: {\n field: 'threshold_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 46: {\n field: 'pool_length_unit',\n type: 'display_measure',\n scale: null,\n offset: 0,\n units: '',\n },\n 47: {\n field: 'num_active_lengths',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'lengths',\n },\n 48: {\n field: 'total_work',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'J',\n },\n 49: {\n field: 'avg_altitude',\n type: 'uint16',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 50: {\n field: 'max_altitude',\n type: 'uint16',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 51: {\n field: 'gps_accuracy',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 52: {\n field: 'avg_grade',\n type: 'sint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 53: {\n field: 'avg_pos_grade',\n type: 'sint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 54: {\n field: 'avg_neg_grade',\n type: 'sint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 55: {\n field: 'max_pos_grade',\n type: 'sint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 56: {\n field: 'max_neg_grade',\n type: 'sint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 57: {\n field: 'avg_temperature',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'C',\n },\n 58: {\n field: 'max_temperature',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'C',\n },\n 59: {\n field: 'total_moving_time',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 60: {\n field: 'avg_pos_vertical_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 61: {\n field: 'avg_neg_vertical_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 62: {\n field: 'max_pos_vertical_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 63: {\n field: 'max_neg_vertical_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 64: {\n field: 'min_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 65: {\n field: 'time_in_hr_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 66: {\n field: 'time_in_speed_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 67: {\n field: 'time_in_cadence_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 68: {\n field: 'time_in_power_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 69: {\n field: 'avg_lap_time',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 70: {\n field: 'best_lap_index',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 71: {\n field: 'min_altitude',\n type: 'uint16',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 82: {\n field: 'player_score',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 83: {\n field: 'opponent_score',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 84: {\n field: 'opponent_name',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n 85: {\n field: 'stroke_count',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'counts',\n },\n 86: {\n field: 'zone_count',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'counts',\n },\n 87: {\n field: 'max_ball_speed',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'm/s',\n },\n 88: {\n field: 'avg_ball_speed',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'm/s',\n },\n 89: {\n field: 'avg_vertical_oscillation',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'mm',\n },\n 90: {\n field: 'avg_stance_time_percent',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'percent',\n },\n 91: {\n field: 'avg_stance_time',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'ms',\n },\n 92: {\n field: 'avg_fractional_cadence',\n type: 'uint8',\n scale: 128,\n offset: 0,\n units: 'rpm',\n },\n 93: {\n field: 'max_fractional_cadence',\n type: 'uint8',\n scale: 128,\n offset: 0,\n units: 'rpm',\n },\n 94: {\n field: 'total_fractional_cycles',\n type: 'uint8',\n scale: 128,\n offset: 0,\n units: 'cycles',\n },\n 95: {\n field: 'avg_total_hemoglobin_conc',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'g/dL',\n },\n 96: {\n field: 'min_total_hemoglobin_conc',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'g/dL',\n },\n 97: {\n field: 'max_total_hemoglobin_conc',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'g/dL',\n },\n 98: {\n field: 'avg_saturated_hemoglobin_percent',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 99: {\n field: 'min_saturated_hemoglobin_percent',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 100: {\n field: 'max_saturated_hemoglobin_percent',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 101: {\n field: 'avg_left_torque_effectiveness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 102: {\n field: 'avg_right_torque_effectiveness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 103: {\n field: 'avg_left_pedal_smoothness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 104: {\n field: 'avg_right_pedal_smoothness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 105: {\n field: 'avg_combined_pedal_smoothness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 111: {\n field: 'sport_index',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 112: {\n field: 'time_standing',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 113: {\n field: 'stand_count',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 114: {\n field: 'avg_left_pco',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'mm',\n },\n 115: {\n field: 'avg_right_pco',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'mm',\n },\n 116: {\n field: 'avg_left_power_phase',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 117: {\n field: 'avg_left_power_phase_peak',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 118: {\n field: 'avg_right_power_phase',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 119: {\n field: 'avg_right_power_phase_peak',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 120: {\n field: 'avg_power_position',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 121: {\n field: 'max_power_position',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 122: {\n field: 'avg_cadence_position',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'rpm',\n },\n 123: {\n field: 'max_cadence_position',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'rpm',\n },\n 124: {\n field: 'enhanced_avg_speed',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 125: {\n field: 'enhanced_max_speed',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 126: {\n field: 'enhanced_avg_altitude',\n type: 'uint32',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 127: {\n field: 'enhanced_min_altitude',\n type: 'uint32',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 128: {\n field: 'enhanced_max_altitude',\n type: 'uint32',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 129: {\n field: 'avg_lev_motor_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 130: {\n field: 'max_lev_motor_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 131: {\n field: 'lev_battery_consumption',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 132: {\n field: 'avg_vertical_ratio',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'percent',\n },\n 133: {\n field: 'avg_stance_time_balance',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'percent',\n },\n 134: {\n field: 'avg_step_length',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'mm',\n },\n 137: {\n field: 'total_anaerobic_training_effect',\n type: 'uint8',\n scale: 10,\n offset: 0,\n units: '',\n },\n 139: {\n field: 'avg_vam',\n type: 'uint16',\n scale: 1, // Raw 100 -> 100 (User specific m/h)\n offset: 0,\n units: 'm/h',\n },\n 192: {\n field: 'workout_feel',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 193: {\n field: 'workout_rpe',\n type: 'uint8',\n scale: 10,\n offset: 0,\n units: '',\n },\n 110: {\n field: 'sport_profile_name',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n 168: {\n field: 'training_load_peak',\n type: 'uint32',\n scale: 1,\n offset: 0,\n units: '',\n },\n 169: {\n field: 'enhanced_avg_respiration_rate',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'breaths/min',\n },\n 150: {\n field: 'min_temperature',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'C',\n },\n 170: {\n field: 'enhanced_max_respiration_rate',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'breaths/min',\n },\n 178: {\n field: 'est_sweat_loss',\n type: 'uint16',\n scale: 1, // ml\n offset: 0,\n units: 'ml',\n },\n 180: {\n field: 'enhanced_min_respiration_rate',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'breaths/min',\n },\n 181: {\n field: 'total_grit',\n type: 'float32',\n scale: 1,\n offset: 0,\n units: 'kGrit',\n },\n 182: {\n field: 'total_flow',\n type: 'float32',\n scale: 1,\n offset: 0,\n units: 'Flow',\n },\n 183: {\n field: 'jump_count',\n type: 'uint16',\n scale: 1,\n offset: 0,\n units: '',\n },\n 186: {\n field: 'avg_grit',\n type: 'float32',\n scale: 1,\n offset: 0,\n units: 'kGrit',\n },\n 187: {\n field: 'avg_flow',\n type: 'float32',\n scale: 1,\n offset: 0,\n units: 'Flow',\n },\n 188: {\n field: 'primary_benefit',\n type: 'uint8',\n scale: 1,\n offset: 0,\n units: '',\n },\n 196: {\n field: 'resting_calories',\n type: 'uint16',\n scale: 1,\n offset: 0,\n units: 'kcal',\n },\n 214: {\n field: 'avg_grit',\n type: 'float32',\n scale: null,\n offset: 0,\n units: '',\n },\n 215: {\n field: 'avg_flow',\n type: 'float32',\n scale: null,\n offset: 0,\n units: '',\n },\n 140: {\n field: 'recovery_advisor',\n type: 'uint16', // Minutes?\n scale: 1,\n offset: 0,\n units: 'min',\n },\n },\n 19: {\n name: 'lap',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: { field: 'event', type: 'event', scale: null, offset: 0, units: '' },\n 1: {\n field: 'event_type',\n type: 'event_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'start_time',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'start_position_lat',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 4: {\n field: 'start_position_long',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 5: {\n field: 'end_position_lat',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 6: {\n field: 'end_position_long',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 7: {\n field: 'total_elapsed_time',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 8: {\n field: 'total_timer_time',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 9: {\n field: 'total_distance',\n type: 'uint32',\n scale: 100,\n offset: 0,\n units: 'm',\n },\n 10: {\n field: 'total_cycles',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'cycles',\n },\n 11: {\n field: 'total_calories',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'kcal',\n },\n 12: {\n field: 'total_fat_calories',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'kcal',\n },\n 13: {\n field: 'avg_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 14: {\n field: 'max_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 15: {\n field: 'avg_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 16: {\n field: 'max_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 17: {\n field: 'avg_cadence',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'rpm',\n },\n 18: {\n field: 'max_cadence',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'rpm',\n },\n 19: {\n field: 'avg_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 20: {\n field: 'max_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 21: {\n field: 'total_ascent',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 22: {\n field: 'total_descent',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 23: {\n field: 'intensity',\n type: 'intensity',\n scale: null,\n offset: 0,\n units: '',\n },\n 24: {\n field: 'lap_trigger',\n type: 'lap_trigger',\n scale: null,\n offset: 0,\n units: '',\n },\n 25: { field: 'sport', type: 'sport', scale: null, offset: 0, units: '' },\n 26: {\n field: 'event_group',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 32: {\n field: 'num_lengths',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'lengths',\n },\n 33: {\n field: 'normalized_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 34: {\n field: 'left_right_balance',\n type: 'left_right_balance_100',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 35: {\n field: 'first_length_index',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 37: {\n field: 'avg_stroke_distance',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'm',\n },\n 38: {\n field: 'swim_stroke',\n type: 'swim_stroke',\n scale: null,\n offset: 0,\n units: '',\n },\n 39: {\n field: 'sub_sport',\n type: 'sub_sport',\n scale: null,\n offset: 0,\n units: '',\n },\n 40: {\n field: 'num_active_lengths',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'lengths',\n },\n 41: {\n field: 'total_work',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'J',\n },\n 42: {\n field: 'avg_altitude',\n type: 'uint16',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 43: {\n field: 'max_altitude',\n type: 'uint16',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 44: {\n field: 'gps_accuracy',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 45: {\n field: 'avg_grade',\n type: 'sint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 46: {\n field: 'avg_pos_grade',\n type: 'sint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 47: {\n field: 'avg_neg_grade',\n type: 'sint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 48: {\n field: 'max_pos_grade',\n type: 'sint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 49: {\n field: 'max_neg_grade',\n type: 'sint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 50: {\n field: 'avg_temperature',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'C',\n },\n 51: {\n field: 'max_temperature',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'C',\n },\n 52: {\n field: 'total_moving_time',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 53: {\n field: 'avg_pos_vertical_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 54: {\n field: 'avg_neg_vertical_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 55: {\n field: 'max_pos_vertical_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 56: {\n field: 'max_neg_vertical_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 57: {\n field: 'time_in_hr_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 58: {\n field: 'time_in_speed_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 59: {\n field: 'time_in_cadence_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 60: {\n field: 'time_in_power_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 61: {\n field: 'repetition_num',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 62: {\n field: 'min_altitude',\n type: 'uint16',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 63: {\n field: 'min_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 71: {\n field: 'wkt_step_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 74: {\n field: 'opponent_score',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 75: {\n field: 'stroke_count',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'counts',\n },\n 76: {\n field: 'zone_count',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'counts',\n },\n 77: {\n field: 'avg_vertical_oscillation',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'mm',\n },\n 78: {\n field: 'avg_stance_time_percent',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'percent',\n },\n 79: {\n field: 'avg_stance_time',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'ms',\n },\n 80: {\n field: 'avg_fractional_cadence',\n type: 'uint8',\n scale: 128,\n offset: 0,\n units: 'rpm',\n },\n 81: {\n field: 'max_fractional_cadence',\n type: 'uint8',\n scale: 128,\n offset: 0,\n units: 'rpm',\n },\n 82: {\n field: 'total_fractional_cycles',\n type: 'uint8',\n scale: 128,\n offset: 0,\n units: 'cycles',\n },\n 83: {\n field: 'player_score',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 84: {\n field: 'avg_total_hemoglobin_conc',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'g/dL',\n },\n 85: {\n field: 'min_total_hemoglobin_conc',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'g/dL',\n },\n 86: {\n field: 'max_total_hemoglobin_conc',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'g/dL',\n },\n 87: {\n field: 'avg_saturated_hemoglobin_percent',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 88: {\n field: 'min_saturated_hemoglobin_percent',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 89: {\n field: 'max_saturated_hemoglobin_percent',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 91: {\n field: 'avg_left_torque_effectiveness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 92: {\n field: 'avg_right_torque_effectiveness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 93: {\n field: 'avg_left_pedal_smoothness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 94: {\n field: 'avg_right_pedal_smoothness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 95: {\n field: 'avg_combined_pedal_smoothness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 98: {\n field: 'time_standing',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 99: {\n field: 'stand_count',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 100: {\n field: 'avg_left_pco',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'mm',\n },\n 101: {\n field: 'avg_right_pco',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'mm',\n },\n 102: {\n field: 'avg_left_power_phase',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 103: {\n field: 'avg_left_power_phase_peak',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 104: {\n field: 'avg_right_power_phase',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 105: {\n field: 'avg_right_power_phase_peak',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 106: {\n field: 'avg_power_position',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 107: {\n field: 'max_power_position',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 108: {\n field: 'avg_cadence_position',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'rpm',\n },\n 109: {\n field: 'max_cadence_position',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'rpm',\n },\n 110: {\n field: 'enhanced_avg_speed',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 111: {\n field: 'enhanced_max_speed',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 112: {\n field: 'enhanced_avg_altitude',\n type: 'uint32',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 113: {\n field: 'enhanced_min_altitude',\n type: 'uint32',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 114: {\n field: 'enhanced_max_altitude',\n type: 'uint32',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 115: {\n field: 'avg_lev_motor_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 116: {\n field: 'max_lev_motor_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 117: {\n field: 'lev_battery_consumption',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 118: {\n field: 'avg_vertical_ratio',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'percent',\n },\n 119: {\n field: 'avg_stance_time_balance',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'percent',\n },\n 120: {\n field: 'avg_step_length',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'mm',\n },\n 121: {\n field: 'avg_vam',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n },\n 20: {\n name: 'record',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 114: {\n field: 'grit',\n type: 'float32',\n scale: null,\n offset: 0,\n units: '',\n },\n 115: {\n field: 'flow',\n type: 'float32',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: {\n field: 'position_lat',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 1: {\n field: 'position_long',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 2: {\n field: 'altitude',\n type: 'uint16',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 3: {\n field: 'heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 4: {\n field: 'cadence',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'rpm',\n },\n 5: {\n field: 'distance',\n type: 'uint32',\n scale: 100,\n offset: 0,\n units: 'm',\n },\n 6: {\n field: 'speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 7: {\n field: 'power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 8: {\n field: 'compressed_speed_distance',\n type: 'byte',\n scale: 100.16,\n offset: 0,\n units: 'm/s,m',\n },\n 9: { field: 'grade', type: 'sint16', scale: 100, offset: 0, units: '%' },\n 10: {\n field: 'resistance',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 11: {\n field: 'time_from_course',\n type: 'sint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 12: {\n field: 'cycle_length',\n type: 'uint8',\n scale: 100,\n offset: 0,\n units: 'm',\n },\n 13: {\n field: 'temperature',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'C',\n },\n 17: {\n field: 'speed_1s',\n type: 'uint8',\n scale: 16,\n offset: 0,\n units: 'm/s',\n },\n 18: {\n field: 'cycles',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'cycles',\n },\n 19: {\n field: 'total_cycles',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'cycles',\n },\n 28: {\n field: 'compressed_accumulated_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 29: {\n field: 'accumulated_power',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 30: {\n field: 'left_right_balance',\n type: 'left_right_balance',\n scale: null,\n offset: 0,\n units: '',\n },\n 31: {\n field: 'gps_accuracy',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 32: {\n field: 'vertical_speed',\n type: 'sint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 33: {\n field: 'calories',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'kcal',\n },\n 39: {\n field: 'vertical_oscillation',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'mm',\n },\n 40: {\n field: 'stance_time_percent',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'percent',\n },\n 41: {\n field: 'stance_time',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'ms',\n },\n 42: {\n field: 'activity_type',\n type: 'activity_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 43: {\n field: 'left_torque_effectiveness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 44: {\n field: 'right_torque_effectiveness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 45: {\n field: 'left_pedal_smoothness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 46: {\n field: 'right_pedal_smoothness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 47: {\n field: 'combined_pedal_smoothness',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 48: {\n field: 'time128',\n type: 'uint8',\n scale: 128,\n offset: 0,\n units: 's',\n },\n 49: {\n field: 'stroke_type',\n type: 'stroke_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 50: { field: 'zone', type: 'uint8', scale: null, offset: 0, units: '' },\n 51: {\n field: 'ball_speed',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'm/s',\n },\n 52: {\n field: 'cadence256',\n type: 'uint16',\n scale: 256,\n offset: 0,\n units: 'rpm',\n },\n 53: {\n field: 'fractional_cadence',\n type: 'uint8',\n scale: 128,\n offset: 0,\n units: 'rpm',\n },\n 54: {\n field: 'total_hemoglobin_conc',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'g/dL',\n },\n 55: {\n field: 'total_hemoglobin_conc_min',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'g/dL',\n },\n 56: {\n field: 'total_hemoglobin_conc_max',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'g/dL',\n },\n 57: {\n field: 'saturated_hemoglobin_percent',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 58: {\n field: 'saturated_hemoglobin_percent_min',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 59: {\n field: 'saturated_hemoglobin_percent_max',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: '%',\n },\n 62: {\n field: 'device_index',\n type: 'device_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 67: {\n field: 'left_pco',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'mm',\n },\n 68: {\n field: 'right_pco',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: 'mm',\n },\n 69: {\n field: 'left_power_phase',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 70: {\n field: 'left_power_phase_peak',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 71: {\n field: 'right_power_phase',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 72: {\n field: 'right_power_phase_peak',\n type: 'uint8',\n scale: 0.7111111,\n offset: 0,\n units: 'degrees',\n },\n 73: {\n field: 'enhanced_speed',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 78: {\n field: 'enhanced_altitude',\n type: 'uint32',\n scale: 5,\n offset: -500,\n units: 'm',\n },\n 81: {\n field: 'battery_soc',\n type: 'uint8',\n scale: 2,\n offset: 0,\n units: 'percent',\n },\n 82: {\n field: 'motor_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 83: {\n field: 'vertical_ratio',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'percent',\n },\n 84: {\n field: 'stance_time_balance',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'percent',\n },\n 85: {\n field: 'step_length',\n type: 'uint16',\n scale: 10,\n offset: 0,\n units: 'mm',\n },\n 91: {\n field: 'absolute_pressure',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'Pa',\n },\n 92: {\n field: 'depth',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 93: {\n field: 'next_stop_depth',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 94: {\n field: 'next_stop_time',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 's',\n },\n 95: {\n field: 'time_to_surface',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 's',\n },\n 96: {\n field: 'ndl_time',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 's',\n },\n 97: {\n field: 'cns_load',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 98: {\n field: 'n2_load',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n },\n 285: {\n name: 'jump',\n 253: { field: 'timestamp', type: 'date_time', scale: null, offset: 0, units: 's' },\n 0: { field: 'distance', type: 'float32', scale: null, offset: 0, units: 'm' },\n 1: { field: 'height', type: 'float32', scale: null, offset: 0, units: 'm' },\n 2: { field: 'rotations', type: 'uint8', scale: null, offset: 0, units: '' },\n 3: { field: 'hang_time', type: 'float32', scale: null, offset: 0, units: 's' },\n 4: { field: 'score', type: 'float32', scale: null, offset: 0, units: '' },\n 5: { field: 'position_lat', type: 'sint32', scale: null, offset: 0, units: 'semicircles' },\n 6: { field: 'position_long', type: 'sint32', scale: null, offset: 0, units: 'semicircles' },\n 7: { field: 'speed', type: 'uint16', scale: 1000, offset: 0, units: 'm/s' },\n 8: { field: 'enhanced_speed', type: 'uint32', scale: 1000, offset: 0, units: 'm/s' },\n },\n 21: {\n name: 'event',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: { field: 'event', type: 'event', scale: null, offset: 0, units: '' },\n 1: {\n field: 'event_type',\n type: 'event_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: { field: 'data16', type: 'uint16', scale: null, offset: 0, units: '' },\n 3: { field: 'data', type: 'uint32', scale: null, offset: 0, units: '' },\n 4: {\n field: 'event_group',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 7: { field: 'score', type: 'uint16', scale: null, offset: 0, units: '' },\n 8: {\n field: 'opponent_score',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 9: {\n field: 'front_gear_num',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 10: {\n field: 'front_gear',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 11: {\n field: 'rear_gear_num',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 12: {\n field: 'rear_gear',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 13: {\n field: 'device_index',\n type: 'device_index',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 23: {\n name: 'device_info',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: {\n field: 'device_index',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'device_type',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'manufacturer',\n type: 'manufacturer',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'serial_number',\n type: 'uint32z',\n scale: null,\n offset: 0,\n units: '',\n },\n 4: {\n field: 'product',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 5: {\n field: 'software_version',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: '',\n },\n 6: {\n field: 'hardware_version',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 7: {\n field: 'cum_operating_time',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 's',\n },\n 10: {\n field: 'battery_voltage',\n type: 'uint16',\n scale: 256,\n offset: 0,\n units: 'V',\n },\n 32: {\n field: 'battery_level',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 11: {\n field: 'battery_status',\n type: 'battery_status',\n scale: null,\n offset: 0,\n units: '',\n },\n 18: {\n field: 'sensor_position',\n type: 'body_location',\n scale: null,\n offset: 0,\n units: '',\n },\n 19: {\n field: 'descriptor',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n 20: {\n field: 'ant_transmission_type',\n type: 'uint8z',\n scale: null,\n offset: 0,\n units: '',\n },\n 21: {\n field: 'ant_device_number',\n type: 'uint16z',\n scale: null,\n offset: 0,\n units: '',\n },\n 22: {\n field: 'ant_network',\n type: 'ant_network',\n scale: null,\n offset: 0,\n units: '',\n },\n 24: {\n field: 'ant_id',\n type: 'uint32z',\n scale: null,\n offset: 0,\n units: '',\n },\n 25: {\n field: 'source_type',\n type: 'source_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 27: {\n field: 'product_name',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 26: {\n name: 'workout',\n 4: { field: 'sport', type: 'sport', scale: null, offset: 0, units: '' },\n 5: {\n field: 'capabilities',\n type: 'workout_capabilities',\n scale: null,\n offset: 0,\n units: '',\n },\n 6: {\n field: 'num_valid_steps',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 8: {\n field: 'wkt_name',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 27: {\n name: 'workout_step',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: {\n field: 'wkt_step_name',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'duration_type',\n type: 'wkt_step_duration',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'duration_value',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'target_type',\n type: 'wkt_step_target',\n scale: null,\n offset: 0,\n units: '',\n },\n 4: {\n field: 'target_value',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 5: {\n field: 'custom_target_value_low',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 6: {\n field: 'custom_target_value_high',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 7: {\n field: 'intensity',\n type: 'intensity',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 30: {\n name: 'weight_scale',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: {\n field: 'weight',\n type: 'weight',\n scale: 100,\n offset: 0,\n units: 'kg',\n },\n 1: {\n field: 'percent_fat',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 2: {\n field: 'percent_hydration',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: '%',\n },\n 3: {\n field: 'visceral_fat_mass',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'kg',\n },\n 4: {\n field: 'bone_mass',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'kg',\n },\n 5: {\n field: 'muscle_mass',\n type: 'uint16',\n scale: 100,\n offset: 0,\n units: 'kg',\n },\n 7: {\n field: 'basal_met',\n type: 'uint16',\n scale: 4,\n offset: 0,\n units: 'kcal/day',\n },\n 8: {\n field: 'physique_rating',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 9: {\n field: 'active_met',\n type: 'uint16',\n scale: 4,\n offset: 0,\n units: 'kcal/day',\n },\n 10: {\n field: 'metabolic_age',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'years',\n },\n 11: {\n field: 'visceral_fat_rating',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 12: {\n field: 'user_profile_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 31: {\n name: 'course',\n 4: { field: 'sport', type: 'sport', scale: null, offset: 0, units: '' },\n 5: { field: 'name', type: 'string', scale: null, offset: 0, units: '' },\n 6: {\n field: 'capabilities',\n type: 'course_capabilities',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 32: {\n name: 'course_point',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'position_lat',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 3: {\n field: 'position_long',\n type: 'sint32',\n scale: null,\n offset: 0,\n units: 'semicircles',\n },\n 4: {\n field: 'distance',\n type: 'uint32',\n scale: 100,\n offset: 0,\n units: 'm',\n },\n 5: {\n field: 'type',\n type: 'course_point',\n scale: null,\n offset: 0,\n units: '',\n },\n 6: { field: 'name', type: 'string', scale: null, offset: 0, units: '' },\n 8: { field: 'favorite', type: 'bool', scale: null, offset: 0, units: '' },\n },\n 33: {\n name: 'totals',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: {\n field: 'timer_time',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 's',\n },\n 1: {\n field: 'distance',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 2: {\n field: 'calories',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'kcal',\n },\n 3: { field: 'sport', type: 'sport', scale: null, offset: 0, units: '' },\n 4: {\n field: 'elapsed_time',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 's',\n },\n 5: {\n field: 'sessions',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 6: {\n field: 'active_time',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 's',\n },\n 9: {\n field: 'sport_index',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 34: {\n name: 'activity',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: {\n field: 'total_timer_time',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 1: {\n field: 'num_sessions',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: { field: 'type', type: 'activity', scale: null, offset: 0, units: '' },\n 3: { field: 'event', type: 'event', scale: null, offset: 0, units: '' },\n 4: {\n field: 'event_type',\n type: 'event_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 5: {\n field: 'local_timestamp',\n type: 'local_date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 6: {\n field: 'event_group',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 35: {\n name: 'software',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: { field: 'version', type: 'uint16', scale: 100, offset: 0, units: '' },\n 5: {\n field: 'part_number',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 37: {\n name: 'file_capabilities',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: { field: 'type', type: 'file', scale: null, offset: 0, units: '' },\n 1: {\n field: 'flags',\n type: 'file_flags',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'directory',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'max_count',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 4: {\n field: 'max_size',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'bytes',\n },\n },\n 38: {\n name: 'mesg_capabilities',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: { field: 'file', type: 'file', scale: null, offset: 0, units: '' },\n 1: {\n field: 'mesg_num',\n type: 'mesg_num',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'count_type',\n type: 'mesg_count',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: { field: 'count', type: 'uint16', scale: null, offset: 0, units: '' },\n },\n 39: {\n name: 'field_capabilities',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: { field: 'file', type: 'file', scale: null, offset: 0, units: '' },\n 1: {\n field: 'mesg_num',\n type: 'mesg_num',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'field_num',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: { field: 'count', type: 'uint16', scale: null, offset: 0, units: '' },\n },\n 49: {\n name: 'file_creator',\n 0: {\n field: 'software_version',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'hardware_version',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 51: {\n name: 'blood_pressure',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: {\n field: 'systolic_pressure',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'mmHg',\n },\n 1: {\n field: 'diastolic_pressure',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'mmHg',\n },\n 2: {\n field: 'mean_arterial_pressure',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'mmHg',\n },\n 3: {\n field: 'map_3_sample_mean',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'mmHg',\n },\n 4: {\n field: 'map_morning_values',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'mmHg',\n },\n 5: {\n field: 'map_evening_values',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'mmHg',\n },\n 6: {\n field: 'heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 7: {\n field: 'heart_rate_type',\n type: 'hr_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 8: {\n field: 'status',\n type: 'bp_status',\n scale: null,\n offset: 0,\n units: '',\n },\n 9: {\n field: 'user_profile_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 55: {\n name: 'monitoring',\n 253: {\n field: 'timestamp',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: {\n field: 'device_index',\n type: 'device_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'calories',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'kcal',\n },\n 2: {\n field: 'distance',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 3: {\n field: 'cycles',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 'cycles',\n },\n 4: {\n field: 'active_time',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 's',\n },\n 5: {\n field: 'activity_type',\n type: 'activity_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 6: {\n field: 'activity_subtype',\n type: 'activity_subtype',\n scale: null,\n offset: 0,\n units: '',\n },\n 7: {\n field: 'activity_level',\n type: 'activity_level',\n scale: null,\n offset: 0,\n units: 's',\n },\n 8: {\n field: 'distance16',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 9: {\n field: 'cycles16',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'cycles',\n },\n 10: {\n field: 'active_time16',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 11: {\n field: 'local_timestamp',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 12: {\n field: 'temperature',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 'C',\n },\n 14: {\n field: 'temperature_min',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 'C',\n },\n 15: {\n field: 'temperature_max',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 'C',\n },\n 16: {\n field: 'activity_time',\n type: 'int32',\n scale: null,\n offset: 0,\n units: '',\n },\n 19: {\n field: 'active_calories',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'kcal',\n },\n 24: {\n field: 'current_activity_type_intensity',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 25: {\n field: 'timestamp_min8',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 26: {\n field: 'timestamp16',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 27: {\n field: 'heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 28: {\n field: 'intensity',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 29: {\n field: 'duration_min',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 30: {\n field: 'duration',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 31: {\n field: 'ascent',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 32: {\n field: 'descent',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 33: {\n field: 'moderate_activity_minutes',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 34: {\n field: 'vigorous_activity_inutes',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 78: {\n name: 'hrv',\n 0: {\n field: 'time',\n type: 'uint16_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n },\n 101: {\n name: 'length',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: { field: 'event', type: 'event', scale: null, offset: 0, units: '' },\n 1: {\n field: 'event_type',\n type: 'event_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'start_time',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'total_elapsed_time',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 4: {\n field: 'total_timer_time',\n type: 'uint32',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 5: {\n field: 'total_strokes',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'strokes',\n },\n 6: {\n field: 'avg_speed',\n type: 'uint16',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 7: {\n field: 'swim_stroke',\n type: 'swim_stroke',\n scale: null,\n offset: 0,\n units: 'swim_stroke',\n },\n 9: {\n field: 'avg_swimming_cadence',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'strokes/min',\n },\n 10: {\n field: 'event_group',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 11: {\n field: 'total_calories',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'kcal',\n },\n 12: {\n field: 'length_type',\n type: 'length_type',\n scale: null,\n offset: 0,\n units: 'length_type',\n },\n 18: {\n field: 'player_score',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 19: {\n field: 'opponent_score',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 20: {\n field: 'stroke_count',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'counts',\n },\n 21: {\n field: 'zone_count',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'counts',\n },\n },\n 103: {\n name: 'monitoring_info',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: {\n field: 'local_timestamp',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'activity_type',\n type: 'activity_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'cycles_to_distance',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 'cycles',\n },\n 4: {\n field: 'cycles_to_calories',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 'kcal',\n },\n 5: {\n field: 'resting_metabolic_rate',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 108: {\n name: 'o_hr_settings',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: { field: 'enabled', type: 'byte', scale: null, offset: 0, units: '' },\n },\n 140: {\n name: 'activity_metrics',\n 1: {\n field: 'new_max_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 4: {\n field: 'aerobic_training_effect',\n type: 'uint8',\n scale: 10,\n offset: 0,\n units: '',\n },\n 7: {\n field: 'vo2_max',\n type: 'uint32',\n scale: 65536 / 3.5,\n offset: 0,\n units: 'ml/kg/min',\n },\n 9: {\n field: 'recovery_time',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'min',\n },\n 11: {\n field: 'sport',\n type: 'sport',\n scale: null,\n offset: 0,\n units: '',\n },\n 20: {\n field: 'anaerobic_training_effect',\n type: 'uint8',\n scale: 10,\n offset: 0,\n units: '',\n },\n 29: {\n field: 'first_vo2_max',\n type: 'uint32',\n scale: 65536 / 3.5,\n offset: 0,\n units: 'ml/kg/min',\n },\n 41: {\n field: 'primary_benefit',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 60: {\n field: 'total_ascent',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 61: {\n field: 'total_descent',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 62: {\n field: 'avg_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 63: {\n field: 'avg_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n },\n 206: {\n name: 'field_description',\n 0: {\n field: 'developer_data_index',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'field_definition_number',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'fit_base_type_id',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'field_name',\n type: 'string',\n scale: null,\n offset: 0,\n units: '',\n },\n // 4: { field: 'array', type: 'uint8', scale: null, offset: 0, units: '' },\n // 5: { field: 'components', type: 'string', scale: null, offset: 0, units: '' },\n 6: { field: 'scale', type: 'uint8', scale: null, offset: 0, units: '' },\n 7: { field: 'offset', type: 'sint8', scale: null, offset: 0, units: '' },\n 8: { field: 'units', type: 'string', scale: null, offset: 0, units: '' },\n // 9: { field: 'bits', type: 'string', scale: null, offset: 0, units: '' },\n // 10: { field: 'accumulate', type: 'string', scale: null, offset: 0, units: '' },\n // 13: { field: 'fit_base_unit_id', type: 'uint16', scale: null, offset: 0, units: '' },\n // 14: { field: 'native_mesg_num', type: 'mesg_num', scale: null, offset: 0, units: '' },\n 15: {\n field: 'native_field_num',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 227: {\n name: 'stress_level',\n 0: {\n field: 'stress_level_value',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'stress_level_time',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 2: {\n field: 'field_two',\n type: 'sint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'body_battery',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 4: {\n field: 'field_four',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 207: {\n name: 'developer_data_id',\n 0: {\n field: 'developer_id',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'application_id',\n type: 'byte_array',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'manufacturer_id',\n type: 'manufacturer',\n scale: null,\n offset: 0,\n units: '',\n },\n 3: {\n field: 'developer_data_index',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 4: {\n field: 'application_version',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 258: {\n name: 'dive_settings',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: { field: 'name', type: 'string', scale: null, offset: 0, units: '' },\n 1: {\n field: 'model',\n type: 'tissue_model_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'gf_low',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 3: {\n field: 'gf_high',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 4: {\n field: 'water_type',\n type: 'water_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 5: {\n field: 'water_density',\n type: 'float32',\n scale: null,\n offset: 0,\n units: 'kg/m^3',\n },\n 6: {\n field: 'po2_warn',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 7: {\n field: 'po2_critical',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 8: {\n field: 'po2_deco',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 9: {\n field: 'safety_stop_enabled',\n type: 'bool',\n scale: null,\n offset: 0,\n units: '',\n },\n 10: {\n field: 'bottom_depth',\n type: 'float32',\n scale: null,\n offset: 0,\n units: '',\n },\n 11: {\n field: 'bottom_time',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 12: {\n field: 'apnea_countdown_enabled',\n type: 'bool',\n scale: null,\n offset: 0,\n units: '',\n },\n 13: {\n field: 'apnea_countdown_time',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 14: {\n field: 'backlight_mode',\n type: 'dive_backlight_mode',\n scale: null,\n offset: 0,\n units: '',\n },\n 15: {\n field: 'backlight_brightness',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n 16: {\n field: 'backlight_timeout',\n type: 'backlight_timeout',\n scale: null,\n offset: 0,\n units: '',\n },\n 17: {\n field: 'repeat_dive_time',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 's',\n },\n 18: {\n field: 'safety_stop_time',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 's',\n },\n 19: {\n field: 'heart_rate_source_type',\n type: 'source_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 20: {\n field: 'heart_rate_source',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 259: {\n name: 'dive_gas',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: {\n field: 'helium_content',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 1: {\n field: 'oxygen_content',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 2: {\n field: 'status',\n type: 'dive_gas_status',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 262: {\n name: 'dive_alarm',\n 254: {\n field: 'message_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 0: { field: 'depth', type: 'uint32', scale: null, offset: 0, units: 'm' },\n 1: { field: 'time', type: 'sint32', scale: null, offset: 0, units: 's' },\n 2: { field: 'enabled', type: 'bool', scale: null, offset: 0, units: '' },\n 3: {\n field: 'alarm_type',\n type: 'dive_alarm_type',\n scale: null,\n offset: 0,\n units: '',\n },\n 4: { field: 'sound', type: 'tone', scale: null, offset: 0, units: '' },\n 5: {\n field: 'dive_types',\n type: 'sub_sport',\n scale: null,\n offset: 0,\n units: '',\n },\n },\n 268: {\n name: 'dive_summary',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: {\n field: 'reference_mesg',\n type: 'mesg_num',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'reference_index',\n type: 'message_index',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'avg_depth',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 3: {\n field: 'max_depth',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 'm',\n },\n 4: {\n field: 'surface_interval',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 's',\n },\n 5: {\n field: 'start_cns',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 6: {\n field: 'end_cns',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 7: {\n field: 'start_n2',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 8: {\n field: 'end_n2',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'percent',\n },\n 9: {\n field: 'o2_toxicity',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'OTUs',\n },\n 10: {\n field: 'dive_number',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: '',\n },\n 11: {\n field: 'bottom_time',\n type: 'uint32',\n scale: null,\n offset: 0,\n units: 's',\n },\n },\n 319: {\n name: 'tank_update',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: { field: 'sensor', type: 'uint32', scale: null, offset: 0, units: '' },\n 1: {\n field: 'pressure',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'cbar',\n },\n },\n 323: {\n name: 'tank_summary',\n 0: { field: 'sensor', type: 'uint32', scale: null, offset: 0, units: '' },\n 1: {\n field: 'start_pressure',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'cbar',\n },\n 2: {\n field: 'end_pressure',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'cbar',\n },\n 3: {\n field: 'volume_used',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'cbar',\n },\n },\n 216: {\n name: 'time_in_zone',\n 253: {\n field: 'timestamp',\n type: 'date_time',\n scale: null,\n offset: 0,\n units: 's',\n },\n 0: {\n field: 'reference_mesg',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 1: {\n field: 'reference_index',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: '',\n },\n 2: {\n field: 'time_in_hr_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 3: {\n field: 'time_in_speed_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 4: {\n field: 'time_in_power_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 5: {\n field: 'time_in_power_zone',\n type: 'uint32_array',\n scale: 1000,\n offset: 0,\n units: 's',\n },\n 6: {\n field: 'hr_zone_high_boundary',\n type: 'uint8_array',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 7: {\n field: 'speed_zone_high_boundary',\n type: 'uint16_array',\n scale: 1000,\n offset: 0,\n units: 'm/s',\n },\n 8: {\n field: 'power_zone_high_boundary',\n type: 'uint16_array',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 9: {\n field: 'power_zone_high_boundary',\n type: 'uint16_array',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n 10: {\n field: 'max_heart_rate_deprecated',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 11: {\n field: 'max_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 12: {\n field: 'resting_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 13: {\n field: 'threshold_heart_rate',\n type: 'uint8',\n scale: null,\n offset: 0,\n units: 'bpm',\n },\n 14: {\n field: 'pwr_calc_type',\n type: 'pwr_zone_calc',\n scale: null,\n offset: 0,\n units: '',\n },\n 15: {\n field: 'functional_threshold_power',\n type: 'uint16',\n scale: null,\n offset: 0,\n units: 'watts',\n },\n },\n },\n types: {\n file: {\n 1: 'device',\n 2: 'settings',\n 3: 'sport',\n 4: 'activity',\n 5: 'workout',\n 6: 'course',\n 7: 'schedules',\n 9: 'weight',\n 10: 'totals',\n 11: 'goals',\n 14: 'blood_pressure',\n 15: 'monitoring_a',\n 20: 'activity_summary',\n 28: 'monitoring_daily',\n 32: 'monitoring_b',\n 34: 'segment',\n 35: 'segment_list',\n 40: 'exd_configuration',\n 247: 'mfg_range_min',\n 254: 'mfg_range_max',\n },\n mesg_num: {\n 0: 'file_id',\n 1: 'capabilities',\n 2: 'device_settings',\n 3: 'user_profile',\n 4: 'hrm_profile',\n 5: 'sdm_profile',\n 6: 'bike_profile',\n 7: 'zones_target',\n 8: 'hr_zone',\n 9: 'power_zone',\n 10: 'met_zone',\n 12: 'sport',\n 15: 'goal',\n 18: 'session',\n 19: 'lap',\n 20: 'record',\n 21: 'event',\n 23: 'device_info',\n 26: 'workout',\n 27: 'workout_step',\n 28: 'schedule',\n 30: 'weight_scale',\n 31: 'course',\n 32: 'course_point',\n 33: 'totals',\n 34: 'activity',\n 35: 'software',\n 37: 'file_capabilities',\n 38: 'mesg_capabilities',\n 39: 'field_capabilities',\n 49: 'file_creator',\n 51: 'blood_pressure',\n 53: 'speed_zone',\n 55: 'monitoring',\n 72: 'training_file',\n 78: 'hrv',\n 80: 'ant_rx',\n 81: 'ant_tx',\n 82: 'ant_channel_id',\n 101: 'length',\n 103: 'monitoring_info',\n 105: 'pad',\n 106: 'slave_device',\n 127: 'connectivity',\n 128: 'weather_conditions',\n 129: 'weather_alert',\n 131: 'cadence_zone',\n 132: 'hr',\n 140: 'activity_metrics',\n 142: 'segment_lap',\n 145: 'memo_glob',\n 148: 'segment_id',\n 149: 'segment_leaderboard_entry',\n 150: 'segment_point',\n 151: 'segment_file',\n 158: 'workout_session',\n 159: 'watchface_settings',\n 160: 'gps_metadata',\n 161: 'camera_event',\n 162: 'timestamp_correlation',\n 164: 'gyroscope_data',\n 165: 'accelerometer_data',\n 167: 'three_d_sensor_calibration',\n 169: 'video_frame',\n 174: 'obdii_data',\n 177: 'nmea_sentence',\n 178: 'aviation_attitude',\n 184: 'video',\n 185: 'video_title',\n 186: 'video_description',\n 187: 'video_clip',\n 200: 'exd_screen_configuration',\n 201: 'exd_data_field_configuration',\n 202: 'exd_data_concept_configuration',\n 206: 'field_description',\n 207: 'developer_data_id',\n 208: 'magnetometer_data',\n 209: 'barometer_data',\n 210: 'one_d_sensor_calibration',\n 225: 'set',\n 227: 'stress_level',\n 258: 'dive_settings',\n 259: 'dive_gas',\n 262: 'dive_alarm',\n 264: 'exercise_title',\n 268: 'dive_summary',\n 285: 'jump',\n 317: 'climb_pro',\n 319: 'tank_update',\n 323: 'tank_summary',\n 216: 'time_in_zone',\n 347: 'o_hr_settings',\n 65280: 'mfg_range_min',\n 65534: 'mfg_range_max',\n },\n checksum: {\n 0: 'clear',\n 1: 'ok',\n },\n file_flags: {\n 0: 0,\n 2: 'read',\n 4: 'write',\n 8: 'erase',\n },\n mesg_count: {\n 0: 'num_per_file',\n 1: 'max_per_file',\n 2: 'max_per_file_type',\n },\n date_time: {\n 0: 0,\n 268435456: 'min',\n },\n local_date_time: {\n 0: 0,\n 268435456: 'min',\n },\n message_index: {\n 0: 0,\n 4095: 'mask',\n 28672: 'reserved',\n 32768: 'selected',\n },\n gender: {\n 0: 'female',\n 1: 'male',\n },\n language: {\n 0: 'english',\n 1: 'french',\n 2: 'italian',\n 3: 'german',\n 4: 'spanish',\n 5: 'croatian',\n 6: 'czech',\n 7: 'danish',\n 8: 'dutch',\n 9: 'finnish',\n 10: 'greek',\n 11: 'hungarian',\n 12: 'norwegian',\n 13: 'polish',\n 14: 'portuguese',\n 15: 'slovakian',\n 16: 'slovenian',\n 17: 'swedish',\n 18: 'russian',\n 19: 'turkish',\n 20: 'latvian',\n 21: 'ukrainian',\n 22: 'arabic',\n 23: 'farsi',\n 24: 'bulgarian',\n 25: 'romanian',\n 26: 'chinese',\n 27: 'japanese',\n 28: 'korean',\n 29: 'taiwanese',\n 30: 'thai',\n 31: 'hebrew',\n 32: 'brazilian_portuguese',\n 33: 'indonesian',\n 34: 'malaysian',\n 35: 'vietnamese',\n 36: 'burmese',\n 37: 'mongolian',\n 254: 'custom',\n },\n language_bits_0: {\n 0: 0,\n 1: 'english',\n 2: 'french',\n 4: 'italian',\n 8: 'german',\n 16: 'spanish',\n 32: 'croatian',\n 64: 'czech',\n 128: 'danish',\n },\n language_bits_1: {\n 0: 0,\n 1: 'dutch',\n 2: 'finnish',\n 4: 'greek',\n 8: 'hungarian',\n 16: 'norwegian',\n 32: 'polish',\n 64: 'portuguese',\n 128: 'slovakian',\n },\n language_bits_2: {\n 0: 0,\n 1: 'slovenian',\n 2: 'swedish',\n 4: 'russian',\n 8: 'turkish',\n 16: 'latvian',\n 32: 'ukrainian',\n 64: 'arabic',\n 128: 'farsi',\n },\n language_bits_3: {\n 0: 0,\n 1: 'bulgarian',\n 2: 'romanian',\n 4: 'chinese',\n 8: 'japanese',\n 16: 'korean',\n 32: 'taiwanese',\n 64: 'thai',\n 128: 'hebrew',\n },\n language_bits_4: {\n 0: 0,\n 1: 'brazilian_portuguese',\n 2: 'indonesian',\n 4: 'malaysian',\n 8: 'vietnamese',\n 16: 'burmese',\n 32: 'mongolian',\n },\n time_zone: {\n 0: 'almaty',\n 1: 'bangkok',\n 2: 'bombay',\n 3: 'brasilia',\n 4: 'cairo',\n 5: 'cape_verde_is',\n 6: 'darwin',\n 7: 'eniwetok',\n 8: 'fiji',\n 9: 'hong_kong',\n 10: 'islamabad',\n 11: 'kabul',\n 12: 'magadan',\n 13: 'mid_atlantic',\n 14: 'moscow',\n 15: 'muscat',\n 16: 'newfoundland',\n 17: 'samoa',\n 18: 'sydney',\n 19: 'tehran',\n 20: 'tokyo',\n 21: 'us_alaska',\n 22: 'us_atlantic',\n 23: 'us_central',\n 24: 'us_eastern',\n 25: 'us_hawaii',\n 26: 'us_mountain',\n 27: 'us_pacific',\n 28: 'other',\n 29: 'auckland',\n 30: 'kathmandu',\n 31: 'europe_western_wet',\n 32: 'europe_central_cet',\n 33: 'europe_eastern_eet',\n 34: 'jakarta',\n 35: 'perth',\n 36: 'adelaide',\n 37: 'brisbane',\n 38: 'tasmania',\n 39: 'iceland',\n 40: 'amsterdam',\n 41: 'athens',\n 42: 'barcelona',\n 43: 'berlin',\n 44: 'brussels',\n 45: 'budapest',\n 46: 'copenhagen',\n 47: 'dublin',\n 48: 'helsinki',\n 49: 'lisbon',\n 50: 'london',\n 51: 'madrid',\n 52: 'munich',\n 53: 'oslo',\n 54: 'paris',\n 55: 'prague',\n 56: 'reykjavik',\n 57: 'rome',\n 58: 'stockholm',\n 59: 'vienna',\n 60: 'warsaw',\n 61: 'zurich',\n 62: 'quebec',\n 63: 'ontario',\n 64: 'manitoba',\n 65: 'saskatchewan',\n 66: 'alberta',\n 67: 'british_columbia',\n 68: 'boise',\n 69: 'boston',\n 70: 'chicago',\n 71: 'dallas',\n 72: 'denver',\n 73: 'kansas_city',\n 74: 'las_vegas',\n 75: 'los_angeles',\n 76: 'miami',\n 77: 'minneapolis',\n 78: 'new_york',\n 79: 'new_orleans',\n 80: 'phoenix',\n 81: 'santa_fe',\n 82: 'seattle',\n 83: 'washington_dc',\n 84: 'us_arizona',\n 85: 'chita',\n 86: 'ekaterinburg',\n 87: 'irkutsk',\n 88: 'kaliningrad',\n 89: 'krasnoyarsk',\n 90: 'novosibirsk',\n 91: 'petropavlovsk_kamchatskiy',\n 92: 'samara',\n 93: 'vladivostok',\n 94: 'mexico_central',\n 95: 'mexico_mountain',\n 96: 'mexico_pacific',\n 97: 'cape_town',\n 98: 'winkhoek',\n 99: 'lagos',\n 100: 'riyahd',\n 101: 'venezuela',\n 102: 'australia_lh',\n 103: 'santiago',\n 253: 'manual',\n 254: 'automatic',\n },\n display_measure: {\n 0: 'metric',\n 1: 'statute',\n 2: 'nautical',\n },\n display_heart: {\n 0: 'bpm',\n 1: 'max',\n 2: 'reserve',\n },\n display_power: {\n 0: 'watts',\n 1: 'percent_ftp',\n },\n display_position: {\n 0: 'degree',\n 1: 'degree_minute',\n 2: 'degree_minute_second',\n 3: 'austrian_grid',\n 4: 'british_grid',\n 5: 'dutch_grid',\n 6: 'hungarian_grid',\n 7: 'finnish_grid',\n 8: 'german_grid',\n 9: 'icelandic_grid',\n 10: 'indonesian_equatorial',\n 11: 'indonesian_irian',\n 12: 'indonesian_southern',\n 13: 'india_zone_0',\n 14: 'india_zone_IA',\n 15: 'india_zone_IB',\n 16: 'india_zone_IIA',\n 17: 'india_zone_IIB',\n 18: 'india_zone_IIIA',\n 19: 'india_zone_IIIB',\n 20: 'india_zone_IVA',\n 21: 'india_zone_IVB',\n 22: 'irish_transverse',\n 23: 'irish_grid',\n 24: 'loran',\n 25: 'maidenhead_grid',\n 26: 'mgrs_grid',\n 27: 'new_zealand_grid',\n 28: 'new_zealand_transverse',\n 29: 'qatar_grid',\n 30: 'modified_swedish_grid',\n 31: 'swedish_grid',\n 32: 'south_african_grid',\n 33: 'swiss_grid',\n 34: 'taiwan_grid',\n 35: 'united_states_grid',\n 36: 'utm_ups_grid',\n 37: 'west_malayan',\n 38: 'borneo_rso',\n 39: 'estonian_grid',\n 40: 'latvian_grid',\n 41: 'swedish_ref_99_grid',\n },\n switch: {\n 0: 'off',\n 1: 'on',\n 2: 'auto',\n },\n sport: {\n 0: 'generic',\n 1: 'running',\n 2: 'cycling',\n 3: 'transition',\n 4: 'fitness_equipment',\n 5: 'swimming',\n 6: 'basketball',\n 7: 'soccer',\n 8: 'tennis',\n 9: 'american_football',\n 10: 'training',\n 11: 'walking',\n 12: 'cross_country_skiing',\n 13: 'alpine_skiing',\n 14: 'snowboarding',\n 15: 'rowing',\n 16: 'mountaineering',\n 17: 'hiking',\n 18: 'multisport',\n 19: 'paddling',\n 20: 'flying',\n 21: 'e_biking',\n 22: 'motorcycling',\n 23: 'boating',\n 24: 'driving',\n 25: 'golf',\n 26: 'hang_gliding',\n 27: 'horseback_riding',\n 28: 'hunting',\n 29: 'fishing',\n 30: 'inline_skating',\n 31: 'rock_climbing',\n 32: 'sailing',\n 33: 'ice_skating',\n 34: 'sky_diving',\n 35: 'snowshoeing',\n 36: 'snowmobiling',\n 37: 'stand_up_paddleboarding',\n 38: 'surfing',\n 39: 'wakeboarding',\n 40: 'water_skiing',\n 41: 'kayaking',\n 42: 'rafting',\n 43: 'windsurfing',\n 44: 'kitesurfing',\n 45: 'tactical',\n 46: 'jumpmaster',\n 47: 'boxing',\n 48: 'floor_climbing',\n 53: 'diving',\n 254: 'all',\n },\n sport_bits_0: {\n 0: 0,\n 1: 'generic',\n 2: 'running',\n 4: 'cycling',\n 8: 'transition',\n 16: 'fitness_equipment',\n 32: 'swimming',\n 64: 'basketball',\n 128: 'soccer',\n },\n sport_bits_1: {\n 0: 0,\n 1: 'tennis',\n 2: 'american_football',\n 4: 'training',\n 8: 'walking',\n 16: 'cross_country_skiing',\n 32: 'alpine_skiing',\n 64: 'snowboarding',\n 128: 'rowing',\n },\n sport_bits_2: {\n 0: 0,\n 1: 'mountaineering',\n 2: 'hiking',\n 4: 'multisport',\n 8: 'paddling',\n 16: 'flying',\n 32: 'e_biking',\n 64: 'motorcycling',\n 128: 'boating',\n },\n sport_bits_3: {\n 0: 0,\n 1: 'driving',\n 2: 'golf',\n 4: 'hang_gliding',\n 8: 'horseback_riding',\n 16: 'hunting',\n 32: 'fishing',\n 64: 'inline_skating',\n 128: 'rock_climbing',\n },\n sport_bits_4: {\n 0: 0,\n 1: 'sailing',\n 2: 'ice_skating',\n 4: 'sky_diving',\n 8: 'snowshoeing',\n 16: 'snowmobiling',\n 32: 'stand_up_paddleboarding',\n 64: 'surfing',\n 128: 'wakeboarding',\n },\n sport_bits_5: {\n 0: 0,\n 1: 'water_skiing',\n 2: 'kayaking',\n 4: 'rafting',\n 8: 'windsurfing',\n 16: 'kitesurfing',\n 32: 'tactical',\n 64: 'jumpmaster',\n 128: 'boxing',\n },\n sport_bits_6: {\n 0: 0,\n 1: 'floor_climbing',\n },\n sub_sport: {\n 0: 'generic',\n 1: 'treadmill',\n 2: 'street',\n 3: 'trail',\n 4: 'track',\n 5: 'spin',\n 6: 'indoor_cycling',\n 7: 'road',\n 8: 'mountain',\n 9: 'downhill',\n 10: 'recumbent',\n 11: 'cyclocross',\n 12: 'hand_cycling',\n 13: 'track_cycling',\n 14: 'indoor_rowing',\n 15: 'elliptical',\n 16: 'stair_climbing',\n 17: 'lap_swimming',\n 18: 'open_water',\n 19: 'flexibility_training',\n 20: 'strength_training',\n 21: 'warm_up',\n 22: 'match',\n 23: 'exercise',\n 24: 'challenge',\n 25: 'indoor_skiing',\n 26: 'cardio_training',\n 27: 'indoor_walking',\n 28: 'e_bike_fitness',\n 29: 'bmx',\n 30: 'casual_walking',\n 31: 'speed_walking',\n 32: 'bike_to_run_transition',\n 33: 'run_to_bike_transition',\n 34: 'swim_to_bike_transition',\n 35: 'atv',\n 36: 'motocross',\n 37: 'backcountry',\n 38: 'resort',\n 39: 'rc_drone',\n 40: 'wingsuit',\n 41: 'whitewater',\n 42: 'skate_skiing',\n 43: 'yoga',\n 44: 'pilates',\n 45: 'indoor_running',\n 46: 'gravel_cycling',\n 47: 'e_bike_mountain',\n 48: 'commuting',\n 49: 'mixed_surface',\n 50: 'navigate',\n 51: 'track_me',\n 52: 'map',\n 53: 'single_gas_diving',\n 54: 'multi_gas_diving',\n 55: 'gauge_diving',\n 56: 'apnea_diving',\n 57: 'apnea_hunting',\n 58: 'virtual_activity',\n 59: 'obstacle',\n 254: 'all',\n },\n sport_event: {\n 0: 'uncategorized',\n 1: 'geocaching',\n 2: 'fitness',\n 3: 'recreation',\n 4: 'race',\n 5: 'special_event',\n 6: 'training',\n 7: 'transportation',\n 8: 'touring',\n },\n activity: {\n 0: 'manual',\n 1: 'auto_multi_sport',\n },\n intensity: {\n 0: 'active',\n 1: 'rest',\n 2: 'warmup',\n 3: 'cooldown',\n 4: 'recovery',\n 5: 'interval',\n 6: 'other',\n },\n session_trigger: {\n 0: 'activity_end',\n 1: 'manual',\n 2: 'auto_multi_sport',\n 3: 'fitness_equipment',\n },\n autolap_trigger: {\n 0: 'time',\n 1: 'distance',\n 2: 'position_start',\n 3: 'position_lap',\n 4: 'position_waypoint',\n 5: 'position_marked',\n 6: 'off',\n },\n lap_trigger: {\n 0: 'manual',\n 1: 'time',\n 2: 'distance',\n 3: 'position_start',\n 4: 'position_lap',\n 5: 'position_waypoint',\n 6: 'position_marked',\n 7: 'session_end',\n 8: 'fitness_equipment',\n },\n time_mode: {\n 0: 'hour12',\n 1: 'hour24',\n 2: 'military',\n 3: 'hour_12_with_seconds',\n 4: 'hour_24_with_seconds',\n 5: 'utc',\n },\n backlight_mode: {\n 0: 'off',\n 1: 'manual',\n 2: 'key_and_messages',\n 3: 'auto_brightness',\n 4: 'smart_notifications',\n 5: 'key_and_messages_night',\n 6: 'key_and_messages_and_smart_notifications',\n },\n date_mode: {\n 0: 'day_month',\n 1: 'month_day',\n },\n backlight_timeout: {\n 0: 'infinite',\n },\n event: {\n 0: 'timer',\n 3: 'workout',\n 4: 'workout_step',\n 5: 'power_down',\n 6: 'power_up',\n 7: 'off_course',\n 8: 'session',\n 9: 'lap',\n 10: 'course_point',\n 11: 'battery',\n 12: 'virtual_partner_pace',\n 13: 'hr_high_alert',\n 14: 'hr_low_alert',\n 15: 'speed_high_alert',\n 16: 'speed_low_alert',\n 17: 'cad_high_alert',\n 18: 'cad_low_alert',\n 19: 'power_high_alert',\n 20: 'power_low_alert',\n 21: 'recovery_hr',\n 22: 'battery_low',\n 23: 'time_duration_alert',\n 24: 'distance_duration_alert',\n 25: 'calorie_duration_alert',\n 26: 'activity',\n 27: 'fitness_equipment',\n 28: 'length',\n 32: 'user_marker',\n 33: 'sport_point',\n 36: 'calibration',\n 42: 'front_gear_change',\n 43: 'rear_gear_change',\n 44: 'rider_position_change',\n 45: 'elev_high_alert',\n 46: 'elev_low_alert',\n 47: 'comm_timeout',\n },\n event_type: {\n 0: 'start',\n 1: 'stop',\n 2: 'consecutive_depreciated',\n 3: 'marker',\n 4: 'stop_all',\n 5: 'begin_depreciated',\n 6: 'end_depreciated',\n 7: 'end_all_depreciated',\n 8: 'stop_disable',\n 9: 'stop_disable_all',\n },\n timer_trigger: {\n 0: 'manual',\n 1: 'auto',\n 2: 'fitness_equipment',\n },\n fitness_equipment_state: {\n 0: 'ready',\n 1: 'in_use',\n 2: 'paused',\n 3: 'unknown',\n },\n tone: {\n 0: 'off',\n 1: 'tone',\n 2: 'vibrate',\n 3: 'tone_and_vibrate',\n },\n autoscroll: {\n 0: 'none',\n 1: 'slow',\n 2: 'medium',\n 3: 'fast',\n },\n activity_class: {\n 0: 0,\n 100: 'level_max',\n 127: 'level',\n 128: 'athlete',\n },\n hr_zone_calc: {\n 0: 'custom',\n 1: 'percent_max_hr',\n 2: 'percent_hrr',\n },\n pwr_zone_calc: {\n 0: 'custom',\n 1: 'percent_ftp',\n },\n wkt_step_duration: {\n 0: 'time',\n 1: 'distance',\n 2: 'hr_less_than',\n 3: 'hr_greater_than',\n 4: 'calories',\n 5: 'open',\n 6: 'repeat_until_steps_cmplt',\n 7: 'repeat_until_time',\n 8: 'repeat_until_distance',\n 9: 'repeat_until_calories',\n 10: 'repeat_until_hr_less_than',\n 11: 'repeat_until_hr_greater_than',\n 12: 'repeat_until_power_less_than',\n 13: 'repeat_until_power_greater_than',\n 14: 'power_less_than',\n 15: 'power_greater_than',\n 16: 'training_peaks_tss',\n 17: 'repeat_until_power_last_lap_less_than',\n 18: 'repeat_until_max_power_last_lap_less_than',\n 19: 'power_3s_less_than',\n 20: 'power_10s_less_than',\n 21: 'power_30s_less_than',\n 22: 'power_3s_greater_than',\n 23: 'power_10s_greater_than',\n 24: 'power_30s_greater_than',\n 25: 'power_lap_less_than',\n 26: 'power_lap_greater_than',\n 27: 'repeat_until_training_peaks_tss',\n 28: 'repetition_time',\n 29: 'reps',\n },\n wkt_step_target: {\n 0: 'speed',\n 1: 'heart_rate',\n 2: 'open',\n 3: 'cadence',\n 4: 'power',\n 5: 'grade',\n 6: 'resistance',\n 7: 'power_3s',\n 8: 'power_10s',\n 9: 'power_30s',\n 10: 'power_lap',\n 11: 'swim_stroke',\n 12: 'speed_lap',\n 13: 'heart_rate_lap',\n },\n goal: {\n 0: 'time',\n 1: 'distance',\n 2: 'calories',\n 3: 'frequency',\n 4: 'steps',\n 5: 'ascent',\n 6: 'active_minutes',\n },\n goal_recurrence: {\n 0: 'off',\n 1: 'daily',\n 2: 'weekly',\n 3: 'monthly',\n 4: 'yearly',\n 5: 'custom',\n },\n goal_source: {\n 0: 'auto',\n 1: 'community',\n 2: 'user',\n },\n schedule: {\n 0: 'workout',\n 1: 'course',\n },\n course_point: {\n 0: 'generic',\n 1: 'summit',\n 2: 'valley',\n 3: 'water',\n 4: 'food',\n 5: 'danger',\n 6: 'left',\n 7: 'right',\n 8: 'straight',\n 9: 'first_aid',\n 10: 'fourth_category',\n 11: 'third_category',\n 12: 'second_category',\n 13: 'first_category',\n 14: 'hors_category',\n 15: 'sprint',\n 16: 'left_fork',\n 17: 'right_fork',\n 18: 'middle_fork',\n 19: 'slight_left',\n 20: 'sharp_left',\n 21: 'slight_right',\n 22: 'sharp_right',\n 23: 'u_turn',\n 24: 'segment_start',\n 25: 'segment_end',\n },\n manufacturer: {\n 0: 0,\n 1: 'garmin',\n 2: 'garmin_fr405_antfs',\n 3: 'zephyr',\n 4: 'dayton',\n 5: 'idt',\n 6: 'srm',\n 7: 'quarq',\n 8: 'ibike',\n 9: 'saris',\n 10: 'spark_hk',\n 11: 'tanita',\n 12: 'echowell',\n 13: 'dynastream_oem',\n 14: 'nautilus',\n 15: 'dynastream',\n 16: 'timex',\n 17: 'metrigear',\n 18: 'xelic',\n 19: 'beurer',\n 20: 'cardiosport',\n 21: 'a_and_d',\n 22: 'hmm',\n 23: 'suunto',\n 24: 'thita_elektronik',\n 25: 'gpulse',\n 26: 'clean_mobile',\n 27: 'pedal_brain',\n 28: 'peaksware',\n 29: 'saxonar',\n 30: 'lemond_fitness',\n 31: 'dexcom',\n 32: 'wahoo_fitness',\n 33: 'octane_fitness',\n 34: 'archinoetics',\n 35: 'the_hurt_box',\n 36: 'citizen_systems',\n 37: 'magellan',\n 38: 'osynce',\n 39: 'holux',\n 40: 'concept2',\n 42: 'one_giant_leap',\n 43: 'ace_sensor',\n 44: 'brim_brothers',\n 45: 'xplova',\n 46: 'perception_digital',\n 47: 'bf1systems',\n 48: 'pioneer',\n 49: 'spantec',\n 50: 'metalogics',\n 51: '4iiiis',\n 52: 'seiko_epson',\n 53: 'seiko_epson_oem',\n 54: 'ifor_powell',\n 55: 'maxwell_guider',\n 56: 'star_trac',\n 57: 'breakaway',\n 58: 'alatech_technology_ltd',\n 59: 'mio_technology_europe',\n 60: 'rotor',\n 61: 'geonaute',\n 62: 'id_bike',\n 63: 'specialized',\n 64: 'wtek',\n 65: 'physical_enterprises',\n 66: 'north_pole_engineering',\n 67: 'bkool',\n 68: 'cateye',\n 69: 'stages_cycling',\n 70: 'sigmasport',\n 71: 'tomtom',\n 72: 'peripedal',\n 73: 'wattbike',\n 76: 'moxy',\n 77: 'ciclosport',\n 78: 'powerbahn',\n 79: 'acorn_projects_aps',\n 80: 'lifebeam',\n 81: 'bontrager',\n 82: 'wellgo',\n 83: 'scosche',\n 84: 'magura',\n 85: 'woodway',\n 86: 'elite',\n 87: 'nielsen_kellerman',\n 88: 'dk_city',\n 89: 'tacx',\n 90: 'direction_technology',\n 91: 'magtonic',\n 92: '1partcarbon',\n 93: 'inside_ride_technologies',\n 94: 'sound_of_motion',\n 95: 'stryd',\n 96: 'icg',\n 97: 'mipulse',\n 98: 'bsx_athletics',\n 99: 'look',\n 100: 'campagnolo_srl',\n 101: 'body_bike_smart',\n 102: 'praxisworks',\n 103: 'limits_technology',\n 104: 'topaction_technology',\n 105: 'cosinuss',\n 106: 'fitcare',\n 107: 'magene',\n 108: 'giant_manufacturing_co',\n 109: 'tigrasport',\n 110: 'salutron',\n 111: 'technogym',\n 112: 'bryton_sensors',\n 113: 'latitude_limited',\n 114: 'soaring_technology',\n 115: 'igpsport',\n 116: 'thinkrider',\n 117: 'gopher_sport',\n 118: 'waterrower',\n 119: 'orangetheory',\n 120: 'inpeak',\n 121: 'kinetic',\n 122: 'johnson_health_tech',\n 123: 'polar_electro',\n 124: 'seesense',\n 125: 'nci_technology',\n 255: 'development',\n 257: 'healthandlife',\n 258: 'lezyne',\n 259: 'scribe_labs',\n 260: 'zwift',\n 261: 'watteam',\n 262: 'recon',\n 263: 'favero_electronics',\n 264: 'dynovelo',\n 265: 'strava',\n 266: 'precor',\n 267: 'bryton',\n 268: 'sram',\n 269: 'navman',\n 270: 'cobi',\n 271: 'spivi',\n 272: 'mio_magellan',\n 273: 'evesports',\n 274: 'sensitivus_gauge',\n 275: 'podoon',\n 276: 'life_time_fitness',\n 277: 'falco_e_motors',\n 278: 'minoura',\n 279: 'cycliq',\n 280: 'luxottica',\n 281: 'trainer_road',\n 282: 'the_sufferfest',\n 283: 'fullspeedahead',\n 284: 'virtualtraining',\n 285: 'feedbacksports',\n 286: 'omata',\n 287: 'vdo',\n 288: 'magneticdays',\n 289: 'hammerhead',\n 290: 'kinetic_by_kurt',\n 291: 'shapelog',\n 292: 'dabuziduo',\n 293: 'jetblack',\n 294: 'coros',\n 295: 'virtugo',\n 296: 'velosense',\n 5759: 'actigraphcorp',\n },\n garmin_product: {\n 0: 'hrm_bike',\n 1: 'hrm1',\n 2: 'axh01',\n 3: 'axb01',\n 4: 'axb02',\n 5: 'hrm2ss',\n 6: 'dsi_alf02',\n 7: 'hrm3ss',\n 8: 'hrm_run_single_byte_product_id',\n 9: 'bsm',\n 10: 'bcm',\n 11: 'axs01',\n 12: 'hrm_tri_single_byte_product_id',\n 14: 'fr225_single_byte_product_id',\n 473: 'fr301_china',\n 474: 'fr301_japan',\n 475: 'fr301_korea',\n 494: 'fr301_taiwan',\n 717: 'fr405',\n 782: 'fr50',\n 987: 'fr405_japan',\n 988: 'fr60',\n 1011: 'dsi_alf01',\n 1018: 'fr310xt',\n 1036: 'edge500',\n 1124: 'fr110',\n 1169: 'edge800',\n 1199: 'edge500_taiwan',\n 1213: 'edge500_japan',\n 1253: 'chirp',\n 1274: 'fr110_japan',\n 1325: 'edge200',\n 1328: 'fr910xt',\n 1333: 'edge800_taiwan',\n 1334: 'edge800_japan',\n 1341: 'alf04',\n 1345: 'fr610',\n 1360: 'fr210_japan',\n 1380: 'vector_ss',\n 1381: 'vector_cp',\n 1386: 'edge800_china',\n 1387: 'edge500_china',\n 1410: 'fr610_japan',\n 1422: 'edge500_korea',\n 1436: 'fr70',\n 1446: 'fr310xt_4t',\n 1461: 'amx',\n 1482: 'fr10',\n 1497: 'edge800_korea',\n 1499: 'swim',\n 1537: 'fr910xt_china',\n 1551: 'fenix',\n 1555: 'edge200_taiwan',\n 1561: 'edge510',\n 1567: 'edge810',\n 1570: 'tempe',\n 1600: 'fr910xt_japan',\n 1623: 'fr620',\n 1632: 'fr220',\n 1664: 'fr910xt_korea',\n 1688: 'fr10_japan',\n 1721: 'edge810_japan',\n 1735: 'virb_elite',\n 1736: 'edge_touring',\n 1742: 'edge510_japan',\n 1743: 'hrm_tri',\n 1752: 'hrm_run',\n 1765: 'fr920xt',\n 1821: 'edge510_asia',\n 1822: 'edge810_china',\n 1823: 'edge810_taiwan',\n 1836: 'edge1000',\n 1837: 'vivo_fit',\n 1853: 'virb_remote',\n 1885: 'vivo_ki',\n 1903: 'fr15',\n 1907: 'vivo_active',\n 1918: 'edge510_korea',\n 1928: 'fr620_japan',\n 1929: 'fr620_china',\n 1930: 'fr220_japan',\n 1931: 'fr220_china',\n 1936: 'approach_s6',\n 1956: 'vivo_smart',\n 1967: 'fenix2',\n 1988: 'epix',\n 2050: 'fenix3',\n 2052: 'edge1000_taiwan',\n 2053: 'edge1000_japan',\n 2061: 'fr15_japan',\n 2067: 'edge520',\n 2070: 'edge1000_china',\n 2072: 'fr620_russia',\n 2073: 'fr220_russia',\n 2079: 'vector_s',\n 2100: 'edge1000_korea',\n 2130: 'fr920xt_taiwan',\n 2131: 'fr920xt_china',\n 2132: 'fr920xt_japan',\n 2134: 'virbx',\n 2135: 'vivo_smart_apac',\n 2140: 'etrex_touch',\n 2147: 'edge25',\n 2148: 'fr25',\n 2150: 'vivo_fit2',\n 2153: 'fr225',\n 2156: 'fr630',\n 2157: 'fr230',\n 2158: 'fr735xt',\n 2160: 'vivo_active_apac',\n 2161: 'vector_2',\n 2162: 'vector_2s',\n 2172: 'virbxe',\n 2173: 'fr620_taiwan',\n 2174: 'fr220_taiwan',\n 2175: 'truswing',\n 2188: 'fenix3_china',\n 2189: 'fenix3_twn',\n 2192: 'varia_headlight',\n 2193: 'varia_taillight_old',\n 2204: 'edge_explore_1000',\n 2219: 'fr225_asia',\n 2225: 'varia_radar_taillight',\n 2226: 'varia_radar_display',\n 2238: 'edge20',\n 2262: 'd2_bravo',\n 2266: 'approach_s20',\n 2276: 'varia_remote',\n 2327: 'hrm4_run',\n 2337: 'vivo_active_hr',\n 2348: 'vivo_smart_hr',\n 2368: 'vivo_move',\n 2398: 'varia_vision',\n 2406: 'vivo_fit3',\n 2413: 'fenix3_hr',\n 2417: 'virb_ultra_30',\n 2429: 'index_smart_scale',\n 2431: 'fr235',\n 2432: 'fenix3_chronos',\n 2441: 'oregon7xx',\n 2444: 'rino7xx',\n 2496: 'nautix',\n 2530: 'edge_820',\n 2531: 'edge_explore_820',\n 2544: 'fenix5s',\n 2547: 'd2_bravo_titanium',\n 2567: 'varia_ut800',\n 2593: 'running_dynamics_pod',\n 2604: 'fenix5x',\n 2606: 'vivo_fit_jr',\n 2691: 'fr935',\n 2697: 'fenix5',\n 2859: 'descent',\n 10007: 'sdm4',\n 10014: 'edge_remote',\n 20119: 'training_center',\n 65531: 'connectiq_simulator',\n 65532: 'android_antplus_plugin',\n 65534: 'connect',\n },\n antplus_device_type: {\n 1: 'antfs',\n 11: 'bike_power',\n 12: 'environment_sensor_legacy',\n 15: 'multi_sport_speed_distance',\n 16: 'control',\n 17: 'fitness_equipment',\n 18: 'blood_pressure',\n 19: 'geocache_node',\n 20: 'light_electric_vehicle',\n 25: 'env_sensor',\n 26: 'racquet',\n 27: 'control_hub',\n 31: 'muscle_oxygen',\n 34: 'shifting',\n 35: 'bike_light_main',\n 36: 'bike_light_shared',\n 38: 'exd',\n 40: 'bike_radar',\n 46: 'bike_aero',\n 119: 'weight_scale',\n 120: 'heart_rate',\n 121: 'bike_speed_cadence',\n 122: 'bike_cadence',\n 123: 'bike_speed',\n 124: 'stride_speed_distance',\n },\n local_device_type: {\n 0: 'gps',\n 1: 'glonass',\n 2: 'gps_glonass',\n 3: 'accelerometer',\n 4: 'barometer',\n 5: 'temperature',\n 10: 'whr',\n 12: 'sensor_hub',\n },\n ble_device_type: {\n 0: 'connected_gps',\n 1: 'heart_rate',\n 2: 'bike_power',\n 3: 'bike_speed_cadence',\n 4: 'bike_speed',\n 5: 'bike_cadence',\n 6: 'footpod',\n 7: 'bike_trainer',\n },\n ant_network: {\n 0: 'public',\n 1: 'antplus',\n 2: 'antfs',\n 3: 'private',\n },\n workout_capabilities: {\n 0: 0,\n 1: 'interval',\n 2: 'custom',\n 4: 'fitness_equipment',\n 8: 'firstbeat',\n 16: 'new_leaf',\n 32: 'tcx',\n 128: 'speed',\n 256: 'heart_rate',\n 512: 'distance',\n 1024: 'cadence',\n 2048: 'power',\n 4096: 'grade',\n 8192: 'resistance',\n 16384: 'protected',\n },\n battery_status: {\n 0: 0,\n 1: 'new',\n 2: 'good',\n 3: 'ok',\n 4: 'low',\n 5: 'critical',\n 6: 'charging',\n 7: 'unknown',\n },\n hr_type: {\n 0: 'normal',\n 1: 'irregular',\n },\n course_capabilities: {\n 0: 0,\n 1: 'processed',\n 2: 'valid',\n 4: 'time',\n 8: 'distance',\n 16: 'position',\n 32: 'heart_rate',\n 64: 'power',\n 128: 'cadence',\n 256: 'training',\n 512: 'navigation',\n 1024: 'bikeway',\n },\n weight: {\n 0: 0,\n 65534: 'calculating',\n },\n workout_hr: {\n 0: 0,\n 100: 'bpm_offset',\n },\n workout_power: {\n 0: 0,\n 1000: 'watts_offset',\n },\n bp_status: {\n 0: 'no_error',\n 1: 'error_incomplete_data',\n 2: 'error_no_measurement',\n 3: 'error_data_out_of_range',\n 4: 'error_irregular_heart_rate',\n },\n user_local_id: {\n 0: 'local_min',\n 15: 'local_max',\n 16: 'stationary_min',\n 255: 'stationary_max',\n 256: 'portable_min',\n 65534: 'portable_max',\n },\n swim_stroke: {\n 0: 'freestyle',\n 1: 'backstroke',\n 2: 'breaststroke',\n 3: 'butterfly',\n 4: 'drill',\n 5: 'mixed',\n 6: 'im',\n },\n activity_type: {\n 0: 'generic',\n 1: 'running',\n 2: 'cycling',\n 3: 'transition',\n 4: 'fitness_equipment',\n 5: 'swimming',\n 6: 'walking',\n 8: 'sedentary',\n 254: 'all',\n },\n activity_subtype: {\n 0: 'generic',\n 1: 'treadmill',\n 2: 'street',\n 3: 'trail',\n 4: 'track',\n 5: 'spin',\n 6: 'indoor_cycling',\n 7: 'road',\n 8: 'mountain',\n 9: 'downhill',\n 10: 'recumbent',\n 11: 'cyclocross',\n 12: 'hand_cycling',\n 13: 'track_cycling',\n 14: 'indoor_rowing',\n 15: 'elliptical',\n 16: 'stair_climbing',\n 17: 'lap_swimming',\n 18: 'open_water',\n 254: 'all',\n },\n activity_level: {\n 0: 'low',\n 1: 'medium',\n 2: 'high',\n },\n side: {\n 0: 'right',\n 1: 'left',\n },\n left_right_balance: {\n 0: 0,\n 127: 'mask',\n 128: 'right',\n },\n left_right_balance_100: {\n 0: 0,\n 16383: 'mask',\n 32768: 'right',\n },\n length_type: {\n 0: 'idle',\n 1: 'active',\n },\n day_of_week: {\n 0: 'sunday',\n 1: 'monday',\n 2: 'tuesday',\n 3: 'wednesday',\n 4: 'thursday',\n 5: 'friday',\n 6: 'saturday',\n },\n connectivity_capabilities: {\n 0: 0,\n 1: 'bluetooth',\n 2: 'bluetooth_le',\n 4: 'ant',\n 8: 'activity_upload',\n 16: 'course_download',\n 32: 'workout_download',\n 64: 'live_track',\n 128: 'weather_conditions',\n 256: 'weather_alerts',\n 512: 'gps_ephemeris_download',\n 1024: 'explicit_archive',\n 2048: 'setup_incomplete',\n 4096: 'continue_sync_after_software_update',\n 8192: 'connect_iq_app_download',\n 16384: 'golf_course_download',\n 32768: 'device_initiates_sync',\n 65536: 'connect_iq_watch_app_download',\n 131072: 'connect_iq_widget_download',\n 262144: 'connect_iq_watch_face_download',\n 524288: 'connect_iq_data_field_download',\n 1048576: 'connect_iq_app_managment',\n 2097152: 'swing_sensor',\n 4194304: 'swing_sensor_remote',\n 8388608: 'incident_detection',\n 16777216: 'audio_prompts',\n 33554432: 'wifi_verification',\n 67108864: 'true_up',\n 134217728: 'find_my_watch',\n 268435456: 'remote_manual_sync',\n 536870912: 'live_track_auto_start',\n 1073741824: 'live_track_messaging',\n 2147483648: 'instant_input',\n },\n weather_report: {\n 0: 'current',\n 1: 'hourly_forecast',\n 2: 'daily_forecast',\n },\n weather_status: {\n 0: 'clear',\n 1: 'partly_cloudy',\n 2: 'mostly_cloudy',\n 3: 'rain',\n 4: 'snow',\n 5: 'windy',\n 6: 'thunderstorms',\n 7: 'wintry_mix',\n 8: 'fog',\n 11: 'hazy',\n 12: 'hail',\n 13: 'scattered_showers',\n 14: 'scattered_thunderstorms',\n 15: 'unknown_precipitation',\n 16: 'light_rain',\n 17: 'heavy_rain',\n 18: 'light_snow',\n 19: 'heavy_snow',\n 20: 'light_rain_snow',\n 21: 'heavy_rain_snow',\n 22: 'cloudy',\n },\n weather_severity: {\n 0: 'unknown',\n 1: 'warning',\n 2: 'watch',\n 3: 'advisory',\n 4: 'statement',\n },\n weather_severe_type: {\n 0: 'unspecified',\n 1: 'tornado',\n 2: 'tsunami',\n 3: 'hurricane',\n 4: 'extreme_wind',\n 5: 'typhoon',\n 6: 'inland_hurricane',\n 7: 'hurricane_force_wind',\n 8: 'waterspout',\n 9: 'severe_thunderstorm',\n 10: 'wreckhouse_winds',\n 11: 'les_suetes_wind',\n 12: 'avalanche',\n 13: 'flash_flood',\n 14: 'tropical_storm',\n 15: 'inland_tropical_storm',\n 16: 'blizzard',\n 17: 'ice_storm',\n 18: 'freezing_rain',\n 19: 'debris_flow',\n 20: 'flash_freeze',\n 21: 'dust_storm',\n 22: 'high_wind',\n 23: 'winter_storm',\n 24: 'heavy_freezing_spray',\n 25: 'extreme_cold',\n 26: 'wind_chill',\n 27: 'cold_wave',\n 28: 'heavy_snow_alert',\n 29: 'lake_effect_blowing_snow',\n 30: 'snow_squall',\n 31: 'lake_effect_snow',\n 32: 'winter_weather',\n 33: 'sleet',\n 34: 'snowfall',\n 35: 'snow_and_blowing_snow',\n 36: 'blowing_snow',\n 37: 'snow_alert',\n 38: 'arctic_outflow',\n 39: 'freezing_drizzle',\n 40: 'storm',\n 41: 'storm_surge',\n 42: 'rainfall',\n 43: 'areal_flood',\n 44: 'coastal_flood',\n 45: 'lakeshore_flood',\n 46: 'excessive_heat',\n 47: 'heat',\n 48: 'weather',\n 49: 'high_heat_and_humidity',\n 50: 'humidex_and_health',\n 51: 'humidex',\n 52: 'gale',\n 53: 'freezing_spray',\n 54: 'special_marine',\n 55: 'squall',\n 56: 'strong_wind',\n 57: 'lake_wind',\n 58: 'marine_weather',\n 59: 'wind',\n 60: 'small_craft_hazardous_seas',\n 61: 'hazardous_seas',\n 62: 'small_craft',\n 63: 'small_craft_winds',\n 64: 'small_craft_rough_bar',\n 65: 'high_water_level',\n 66: 'ashfall',\n 67: 'freezing_fog',\n 68: 'dense_fog',\n 69: 'dense_smoke',\n 70: 'blowing_dust',\n 71: 'hard_freeze',\n 72: 'freeze',\n 73: 'frost',\n 74: 'fire_weather',\n 75: 'flood',\n 76: 'rip_tide',\n 77: 'high_surf',\n 78: 'smog',\n 79: 'air_quality',\n 80: 'brisk_wind',\n 81: 'air_stagnation',\n 82: 'low_water',\n 83: 'hydrological',\n 84: 'special_weather',\n },\n stroke_type: {\n 0: 'no_event',\n 1: 'other',\n 2: 'serve',\n 3: 'forehand',\n 4: 'backhand',\n 5: 'smash',\n },\n body_location: {\n 0: 'left_leg',\n 1: 'left_calf',\n 2: 'left_shin',\n 3: 'left_hamstring',\n 4: 'left_quad',\n 5: 'left_glute',\n 6: 'right_leg',\n 7: 'right_calf',\n 8: 'right_shin',\n 9: 'right_hamstring',\n 10: 'right_quad',\n 11: 'right_glute',\n 12: 'torso_back',\n 13: 'left_lower_back',\n 14: 'left_upper_back',\n 15: 'right_lower_back',\n 16: 'right_upper_back',\n 17: 'torso_front',\n 18: 'left_abdomen',\n 19: 'left_chest',\n 20: 'right_abdomen',\n 21: 'right_chest',\n 22: 'left_arm',\n 23: 'left_shoulder',\n 24: 'left_bicep',\n 25: 'left_tricep',\n 26: 'left_brachioradialis',\n 27: 'left_forearm_extensors',\n 28: 'right_arm',\n 29: 'right_shoulder',\n 30: 'right_bicep',\n 31: 'right_tricep',\n 32: 'right_brachioradialis',\n 33: 'right_forearm_extensors',\n 34: 'neck',\n 35: 'throat',\n 36: 'waist_mid_back',\n 37: 'waist_front',\n 38: 'waist_left',\n 39: 'waist_right',\n },\n segment_lap_status: {\n 0: 'end',\n 1: 'fail',\n },\n segment_leaderboard_type: {\n 0: 'overall',\n 1: 'personal_best',\n 2: 'connections',\n 3: 'group',\n 4: 'challenger',\n 5: 'kom',\n 6: 'qom',\n 7: 'pr',\n 8: 'goal',\n 9: 'rival',\n 10: 'club_leader',\n },\n segment_delete_status: {\n 0: 'do_not_delete',\n 1: 'delete_one',\n 2: 'delete_all',\n },\n segment_selection_type: {\n 0: 'starred',\n 1: 'suggested',\n },\n source_type: {\n 0: 'ant',\n 1: 'antplus',\n 2: 'bluetooth',\n 3: 'bluetooth_low_energy',\n 4: 'wifi',\n 5: 'local',\n },\n display_orientation: {\n 0: 'auto',\n 1: 'portrait',\n 2: 'landscape',\n 3: 'portrait_flipped',\n 4: 'landscape_flipped',\n },\n workout_equipment: {\n 0: 'none',\n 1: 'swim_fins',\n 2: 'swim_kickboard',\n 3: 'swim_paddles',\n 4: 'swim_pull_buoy',\n 5: 'swim_snorkel',\n },\n watchface_mode: {\n 0: 'digital',\n 1: 'analog',\n 2: 'connect_iq',\n 3: 'disabled',\n },\n digital_watchface_layout: {\n 0: 'traditional',\n 1: 'modern',\n 2: 'bold',\n },\n analog_watchface_layout: {\n 0: 'minimal',\n 1: 'traditional',\n 2: 'modern',\n },\n rider_position_type: {\n 0: 'seated',\n 1: 'standing',\n 2: 'transition_to_seated',\n 3: 'transition_to_standing',\n },\n power_phase_type: {\n 0: 'power_phase_start_angle',\n 1: 'power_phase_end_angle',\n 2: 'power_phase_arc_length',\n 3: 'power_phase_center',\n },\n camera_event_type: {\n 0: 'video_start',\n 1: 'video_split',\n 2: 'video_end',\n 3: 'photo_taken',\n 4: 'video_second_stream_start',\n 5: 'video_second_stream_split',\n 6: 'video_second_stream_end',\n 7: 'video_split_start',\n 8: 'video_second_stream_split_start',\n 11: 'video_pause',\n 12: 'video_second_stream_pause',\n 13: 'video_resume',\n 14: 'video_second_stream_resume',\n },\n sensor_type: {\n 0: 'accelerometer',\n 1: 'gyroscope',\n 2: 'compass',\n 3: 'barometer',\n },\n bike_light_network_config_type: {\n 0: 'auto',\n 4: 'individual',\n 5: 'high_visibility',\n 6: 'trail',\n },\n comm_timeout_type: {\n 0: 'wildcard_pairing_timeout',\n 1: 'pairing_timeout',\n 2: 'connection_lost',\n 3: 'connection_timeout',\n },\n camera_orientation_type: {\n 0: 'camera_orientation_0',\n 1: 'camera_orientation_90',\n 2: 'camera_orientation_180',\n 3: 'camera_orientation_270',\n },\n attitude_stage: {\n 0: 'failed',\n 1: 'aligning',\n 2: 'degraded',\n 3: 'valid',\n },\n attitude_validity: {\n 0: 0,\n 1: 'track_angle_heading_valid',\n 2: 'pitch_valid',\n 4: 'roll_valid',\n 8: 'lateral_body_accel_valid',\n 16: 'normal_body_accel_valid',\n 32: 'turn_rate_valid',\n 64: 'hw_fail',\n 128: 'mag_invalid',\n 256: 'no_gps',\n 512: 'gps_invalid',\n 1024: 'solution_coasting',\n 2048: 'true_track_angle',\n 4096: 'magnetic_heading',\n },\n auto_sync_frequency: {\n 0: 'never',\n 1: 'occasionally',\n 2: 'frequent',\n 3: 'once_a_day',\n 4: 'remote',\n },\n exd_layout: {\n 0: 'full_screen',\n 1: 'half_vertical',\n 2: 'half_horizontal',\n 3: 'half_vertical_right_split',\n 4: 'half_horizontal_bottom_split',\n 5: 'full_quarter_split',\n 6: 'half_vertical_left_split',\n 7: 'half_horizontal_top_split',\n },\n exd_display_type: {\n 0: 'numerical',\n 1: 'simple',\n 2: 'graph',\n 3: 'bar',\n 4: 'circle_graph',\n 5: 'virtual_partner',\n 6: 'balance',\n 7: 'string_list',\n 8: 'string',\n 9: 'simple_dynamic_icon',\n 10: 'gauge',\n },\n exd_data_units: {\n 0: 'no_units',\n 1: 'laps',\n 2: 'miles_per_hour',\n 3: 'kilometers_per_hour',\n 4: 'feet_per_hour',\n 5: 'meters_per_hour',\n 6: 'degrees_celsius',\n 7: 'degrees_farenheit',\n 8: 'zone',\n 9: 'gear',\n 10: 'rpm',\n 11: 'bpm',\n 12: 'degrees',\n 13: 'millimeters',\n 14: 'meters',\n 15: 'kilometers',\n 16: 'feet',\n 17: 'yards',\n 18: 'kilofeet',\n 19: 'miles',\n 20: 'time',\n 21: 'enum_turn_type',\n 22: 'percent',\n 23: 'watts',\n 24: 'watts_per_kilogram',\n 25: 'enum_battery_status',\n 26: 'enum_bike_light_beam_angle_mode',\n 27: 'enum_bike_light_battery_status',\n 28: 'enum_bike_light_network_config_type',\n 29: 'lights',\n 30: 'seconds',\n 31: 'minutes',\n 32: 'hours',\n 33: 'calories',\n 34: 'kilojoules',\n 35: 'milliseconds',\n 36: 'second_per_mile',\n 37: 'second_per_kilometer',\n 38: 'centimeter',\n 39: 'enum_course_point',\n 40: 'bradians',\n 41: 'enum_sport',\n 42: 'inches_hg',\n 43: 'mm_hg',\n 44: 'mbars',\n 45: 'hecto_pascals',\n 46: 'feet_per_min',\n 47: 'meters_per_min',\n 48: 'meters_per_sec',\n 49: 'eight_cardinal',\n },\n exd_qualifiers: {\n 0: 'no_qualifier',\n 1: 'instantaneous',\n 2: 'average',\n 3: 'lap',\n 4: 'maximum',\n 5: 'maximum_average',\n 6: 'maximum_lap',\n 7: 'last_lap',\n 8: 'average_lap',\n 9: 'to_destination',\n 10: 'to_go',\n 11: 'to_next',\n 12: 'next_course_point',\n 13: 'total',\n 14: 'three_second_average',\n 15: 'ten_second_average',\n 16: 'thirty_second_average',\n 17: 'percent_maximum',\n 18: 'percent_maximum_average',\n 19: 'lap_percent_maximum',\n 20: 'elapsed',\n 21: 'sunrise',\n 22: 'sunset',\n 23: 'compared_to_virtual_partner',\n 24: 'maximum_24h',\n 25: 'minimum_24h',\n 26: 'minimum',\n 27: 'first',\n 28: 'second',\n 29: 'third',\n 30: 'shifter',\n 31: 'last_sport',\n 32: 'moving',\n 33: 'stopped',\n 34: 'estimated_total',\n 242: 'zone_9',\n 243: 'zone_8',\n 244: 'zone_7',\n 245: 'zone_6',\n 246: 'zone_5',\n 247: 'zone_4',\n 248: 'zone_3',\n 249: 'zone_2',\n 250: 'zone_1',\n },\n exd_descriptors: {\n 0: 'bike_light_battery_status',\n 1: 'beam_angle_status',\n 2: 'batery_level',\n 3: 'light_network_mode',\n 4: 'number_lights_connected',\n 5: 'cadence',\n 6: 'distance',\n 7: 'estimated_time_of_arrival',\n 8: 'heading',\n 9: 'time',\n 10: 'battery_level',\n 11: 'trainer_resistance',\n 12: 'trainer_target_power',\n 13: 'time_seated',\n 14: 'time_standing',\n 15: 'elevation',\n 16: 'grade',\n 17: 'ascent',\n 18: 'descent',\n 19: 'vertical_speed',\n 20: 'di2_battery_level',\n 21: 'front_gear',\n 22: 'rear_gear',\n 23: 'gear_ratio',\n 24: 'heart_rate',\n 25: 'heart_rate_zone',\n 26: 'time_in_heart_rate_zone',\n 27: 'heart_rate_reserve',\n 28: 'calories',\n 29: 'gps_accuracy',\n 30: 'gps_signal_strength',\n 31: 'temperature',\n 32: 'time_of_day',\n 33: 'balance',\n 34: 'pedal_smoothness',\n 35: 'power',\n 36: 'functional_threshold_power',\n 37: 'intensity_factor',\n 38: 'work',\n 39: 'power_ratio',\n 40: 'normalized_power',\n 41: 'training_stress_Score',\n 42: 'time_on_zone',\n 43: 'speed',\n 44: 'laps',\n 45: 'reps',\n 46: 'workout_step',\n 47: 'course_distance',\n 48: 'navigation_distance',\n 49: 'course_estimated_time_of_arrival',\n 50: 'navigation_estimated_time_of_arrival',\n 51: 'course_time',\n 52: 'navigation_time',\n 53: 'course_heading',\n 54: 'navigation_heading',\n 55: 'power_zone',\n 56: 'torque_effectiveness',\n 57: 'timer_time',\n 58: 'power_weight_ratio',\n 59: 'left_platform_center_offset',\n 60: 'right_platform_center_offset',\n 61: 'left_power_phase_start_angle',\n 62: 'right_power_phase_start_angle',\n 63: 'left_power_phase_finish_angle',\n 64: 'right_power_phase_finish_angle',\n 65: 'gears',\n 66: 'pace',\n 67: 'training_effect',\n 68: 'vertical_oscillation',\n 69: 'vertical_ratio',\n 70: 'ground_contact_time',\n 71: 'left_ground_contact_time_balance',\n 72: 'right_ground_contact_time_balance',\n 73: 'stride_length',\n 74: 'running_cadence',\n 75: 'performance_condition',\n 76: 'course_type',\n 77: 'time_in_power_zone',\n 78: 'navigation_turn',\n 79: 'course_location',\n 80: 'navigation_location',\n 81: 'compass',\n 82: 'gear_combo',\n 83: 'muscle_oxygen',\n 84: 'icon',\n 85: 'compass_heading',\n 86: 'gps_heading',\n 87: 'gps_elevation',\n 88: 'anaerobic_training_effect',\n 89: 'course',\n 90: 'off_course',\n 91: 'glide_ratio',\n 92: 'vertical_distance',\n 93: 'vmg',\n 94: 'ambient_pressure',\n 95: 'pressure',\n 96: 'vam',\n },\n auto_activity_detect: {\n 0: 'none',\n 1: 'running',\n 2: 'cycling',\n 4: 'swimming',\n 8: 'walking',\n 16: 'elliptical',\n 32: 'sedentary',\n },\n supported_exd_screen_layouts: {\n 0: 0,\n 1: 'full_screen',\n 2: 'half_vertical',\n 4: 'half_horizontal',\n 8: 'half_vertical_right_split',\n 16: 'half_horizontal_bottom_split',\n 32: 'full_quarter_split',\n 64: 'half_vertical_left_split',\n 128: 'half_horizontal_top_split',\n },\n fit_base_type: {\n 0: 'enum',\n 1: 'sint8',\n 2: 'uint8',\n 7: 'string',\n 10: 'uint8z',\n 13: 'byte',\n 131: 'sint16',\n 132: 'uint16',\n 133: 'sint32',\n 134: 'uint32',\n 136: 'float32',\n 137: 'float64',\n 139: 'uint16z',\n 140: 'uint32z',\n 142: 'sint64',\n 143: 'uint64',\n 144: 'uint64z',\n },\n turn_type: {\n 0: 'arriving_idx',\n 1: 'arriving_left_idx',\n 2: 'arriving_right_idx',\n 3: 'arriving_via_idx',\n 4: 'arriving_via_left_idx',\n 5: 'arriving_via_right_idx',\n 6: 'bear_keep_left_idx',\n 7: 'bear_keep_right_idx',\n 8: 'continue_idx',\n 9: 'exit_left_idx',\n 10: 'exit_right_idx',\n 11: 'ferry_idx',\n 12: 'roundabout_45_idx',\n 13: 'roundabout_90_idx',\n 14: 'roundabout_135_idx',\n 15: 'roundabout_180_idx',\n 16: 'roundabout_225_idx',\n 17: 'roundabout_270_idx',\n 18: 'roundabout_315_idx',\n 19: 'roundabout_360_idx',\n 20: 'roundabout_neg_45_idx',\n 21: 'roundabout_neg_90_idx',\n 22: 'roundabout_neg_135_idx',\n 23: 'roundabout_neg_180_idx',\n 24: 'roundabout_neg_225_idx',\n 25: 'roundabout_neg_270_idx',\n 26: 'roundabout_neg_315_idx',\n 27: 'roundabout_neg_360_idx',\n 28: 'roundabout_generic_idx',\n 29: 'roundabout_neg_generic_idx',\n 30: 'sharp_turn_left_idx',\n 31: 'sharp_turn_right_idx',\n 32: 'turn_left_idx',\n 33: 'turn_right_idx',\n 34: 'uturn_left_idx',\n 35: 'uturn_right_idx',\n 36: 'icon_inv_idx',\n 37: 'icon_idx_cnt',\n },\n bike_light_beam_angle_mode: {\n 0: 'manual',\n 1: 'auto',\n },\n fit_base_unit: {\n 0: 'other',\n 1: 'kilogram',\n 2: 'pound',\n },\n set_type: {\n 0: 'rest',\n 1: 'active',\n },\n exercise_category: {\n 0: 'bench_press',\n 1: 'calf_raise',\n 2: 'cardio',\n 3: 'carry',\n 4: 'chop',\n 5: 'core',\n 6: 'crunch',\n 7: 'curl',\n 8: 'deadlift',\n 9: 'flye',\n 10: 'hip_raise',\n 11: 'hip_stability',\n 12: 'hip_swing',\n 13: 'hyperextension',\n 14: 'lateral_raise',\n 15: 'leg_curl',\n 16: 'leg_raise',\n 17: 'lunge',\n 18: 'olympic_lift',\n 19: 'plank',\n 20: 'plyo',\n 21: 'pull_up',\n 22: 'push_up',\n 23: 'row',\n 24: 'shoulder_press',\n 25: 'shoulder_stability',\n 26: 'shrug',\n 27: 'sit_up',\n 28: 'squat',\n 29: 'total_body',\n 30: 'triceps_extension',\n 31: 'warm_up',\n 32: 'run',\n 65534: 'unknown',\n },\n bench_press_exercise_name: {\n 0: 'alternating_dumbbell_chest_press_on_swiss_ball',\n 1: 'barbell_bench_press',\n 2: 'barbell_board_bench_press',\n 3: 'barbell_floor_press',\n 4: 'close_grip_barbell_bench_press',\n 5: 'decline_dumbbell_bench_press',\n 6: 'dumbbell_bench_press',\n 7: 'dumbbell_floor_press',\n 8: 'incline_barbell_bench_press',\n 9: 'incline_dumbbell_bench_press',\n 10: 'incline_smith_machine_bench_press',\n 11: 'isometric_barbell_bench_press',\n 12: 'kettlebell_chest_press',\n 13: 'neutral_grip_dumbbell_bench_press',\n 14: 'neutral_grip_dumbbell_incline_bench_press',\n 15: 'one_arm_floor_press',\n 16: 'weighted_one_arm_floor_press',\n 17: 'partial_lockout',\n 18: 'reverse_grip_barbell_bench_press',\n 19: 'reverse_grip_incline_bench_press',\n 20: 'single_arm_cable_chest_press',\n 21: 'single_arm_dumbbell_bench_press',\n 22: 'smith_machine_bench_press',\n 23: 'swiss_ball_dumbbell_chest_press',\n 24: 'triple_stop_barbell_bench_press',\n 25: 'wide_grip_barbell_bench_press',\n 26: 'alternating_dumbbell_chest_press',\n },\n calf_raise_exercise_name: {\n 0: '3_way_calf_raise',\n 1: '3_way_weighted_calf_raise',\n 2: '3_way_single_leg_calf_raise',\n 3: '3_way_weighted_single_leg_calf_raise',\n 4: 'donkey_calf_raise',\n 5: 'weighted_donkey_calf_raise',\n 6: 'seated_calf_raise',\n 7: 'weighted_seated_calf_raise',\n 8: 'seated_dumbbell_toe_raise',\n 9: 'single_leg_bent_knee_calf_raise',\n 10: 'weighted_single_leg_bent_knee_calf_raise',\n 11: 'single_leg_decline_push_up',\n 12: 'single_leg_donkey_calf_raise',\n 13: 'weighted_single_leg_donkey_calf_raise',\n 14: 'single_leg_hip_raise_with_knee_hold',\n 15: 'single_leg_standing_calf_raise',\n 16: 'single_leg_standing_dumbbell_calf_raise',\n 17: 'standing_barbell_calf_raise',\n 18: 'standing_calf_raise',\n 19: 'weighted_standing_calf_raise',\n 20: 'standing_dumbbell_calf_raise',\n },\n cardio_exercise_name: {\n 0: 'bob_and_weave_circle',\n 1: 'weighted_bob_and_weave_circle',\n 2: 'cardio_core_crawl',\n 3: 'weighted_cardio_core_crawl',\n 4: 'double_under',\n 5: 'weighted_double_under',\n 6: 'jump_rope',\n 7: 'weighted_jump_rope',\n 8: 'jump_rope_crossover',\n 9: 'weighted_jump_rope_crossover',\n 10: 'jump_rope_jog',\n 11: 'weighted_jump_rope_jog',\n 12: 'jumping_jacks',\n 13: 'weighted_jumping_jacks',\n 14: 'ski_moguls',\n 15: 'weighted_ski_moguls',\n 16: 'split_jacks',\n 17: 'weighted_split_jacks',\n 18: 'squat_jacks',\n 19: 'weighted_squat_jacks',\n 20: 'triple_under',\n 21: 'weighted_triple_under',\n },\n carry_exercise_name: {\n 0: 'bar_holds',\n 1: 'farmers_walk',\n 2: 'farmers_walk_on_toes',\n 3: 'hex_dumbbell_hold',\n 4: 'overhead_carry',\n },\n chop_exercise_name: {\n 0: 'cable_pull_through',\n 1: 'cable_rotational_lift',\n 2: 'cable_woodchop',\n 3: 'cross_chop_to_knee',\n 4: 'weighted_cross_chop_to_knee',\n 5: 'dumbbell_chop',\n 6: 'half_kneeling_rotation',\n 7: 'weighted_half_kneeling_rotation',\n 8: 'half_kneeling_rotational_chop',\n 9: 'half_kneeling_rotational_reverse_chop',\n 10: 'half_kneeling_stability_chop',\n 11: 'half_kneeling_stability_reverse_chop',\n 12: 'kneeling_rotational_chop',\n 13: 'kneeling_rotational_reverse_chop',\n 14: 'kneeling_stability_chop',\n 15: 'kneeling_woodchopper',\n 16: 'medicine_ball_wood_chops',\n 17: 'power_squat_chops',\n 18: 'weighted_power_squat_chops',\n 19: 'standing_rotational_chop',\n 20: 'standing_split_rotational_chop',\n 21: 'standing_split_rotational_reverse_chop',\n 22: 'standing_stability_reverse_chop',\n },\n core_exercise_name: {\n 0: 'abs_jabs',\n 1: 'weighted_abs_jabs',\n 2: 'alternating_plate_reach',\n 3: 'barbell_rollout',\n 4: 'weighted_barbell_rollout',\n 5: 'body_bar_oblique_twist',\n 6: 'cable_core_press',\n 7: 'cable_side_bend',\n 8: 'side_bend',\n 9: 'weighted_side_bend',\n 10: 'crescent_circle',\n 11: 'weighted_crescent_circle',\n 12: 'cycling_russian_twist',\n 13: 'weighted_cycling_russian_twist',\n 14: 'elevated_feet_russian_twist',\n 15: 'weighted_elevated_feet_russian_twist',\n 16: 'half_turkish_get_up',\n 17: 'kettlebell_windmill',\n 18: 'kneeling_ab_wheel',\n 19: 'weighted_kneeling_ab_wheel',\n 20: 'modified_front_lever',\n 21: 'open_knee_tucks',\n 22: 'weighted_open_knee_tucks',\n 23: 'side_abs_leg_lift',\n 24: 'weighted_side_abs_leg_lift',\n 25: 'swiss_ball_jackknife',\n 26: 'weighted_swiss_ball_jackknife',\n 27: 'swiss_ball_pike',\n 28: 'weighted_swiss_ball_pike',\n 29: 'swiss_ball_rollout',\n 30: 'weighted_swiss_ball_rollout',\n 31: 'triangle_hip_press',\n 32: 'weighted_triangle_hip_press',\n 33: 'trx_suspended_jackknife',\n 34: 'weighted_trx_suspended_jackknife',\n 35: 'u_boat',\n 36: 'weighted_u_boat',\n 37: 'windmill_switches',\n 38: 'weighted_windmill_switches',\n 39: 'alternating_slide_out',\n 40: 'weighted_alternating_slide_out',\n 41: 'ghd_back_extensions',\n 42: 'weighted_ghd_back_extensions',\n 43: 'overhead_walk',\n 44: 'inchworm',\n 45: 'weighted_modified_front_lever',\n 46: 'russian_twist',\n 47: 'abdominal_leg_rotations',\n 48: 'arm_and_leg_extension_on_knees',\n 49: 'bicycle',\n 50: 'bicep_curl_with_leg_extension',\n 51: 'cat_cow',\n 52: 'corkscrew',\n 53: 'criss_cross',\n 54: 'criss_cross_with_ball',\n 55: 'double_leg_stretch',\n 56: 'knee_folds',\n 57: 'lower_lift',\n 58: 'neck_pull',\n 59: 'pelvic_clocks',\n 60: 'roll_over',\n 61: 'roll_up',\n 62: 'rolling',\n 63: 'rowing_1',\n 64: 'rowing_2',\n 65: 'scissors',\n 66: 'single_leg_circles',\n 67: 'single_leg_stretch',\n 68: 'snake_twist_1_and_2',\n 69: 'swan',\n 70: 'swimming',\n 71: 'teaser',\n 72: 'the_hundred',\n },\n crunch_exercise_name: {\n 0: 'bicycle_crunch',\n 1: 'cable_crunch',\n 2: 'circular_arm_crunch',\n 3: 'crossed_arms_crunch',\n 4: 'weighted_crossed_arms_crunch',\n 5: 'cross_leg_reverse_crunch',\n 6: 'weighted_cross_leg_reverse_crunch',\n 7: 'crunch_chop',\n 8: 'weighted_crunch_chop',\n 9: 'double_crunch',\n 10: 'weighted_double_crunch',\n 11: 'elbow_to_knee_crunch',\n 12: 'weighted_elbow_to_knee_crunch',\n 13: 'flutter_kicks',\n 14: 'weighted_flutter_kicks',\n 15: 'foam_roller_reverse_crunch_on_bench',\n 16: 'weighted_foam_roller_reverse_crunch_on_bench',\n 17: 'foam_roller_reverse_crunch_with_dumbbell',\n 18: 'foam_roller_reverse_crunch_with_medicine_ball',\n 19: 'frog_press',\n 20: 'hanging_knee_raise_oblique_crunch',\n 21: 'weighted_hanging_knee_raise_oblique_crunch',\n 22: 'hip_crossover',\n 23: 'weighted_hip_crossover',\n 24: 'hollow_rock',\n 25: 'weighted_hollow_rock',\n 26: 'incline_reverse_crunch',\n 27: 'weighted_incline_reverse_crunch',\n 28: 'kneeling_cable_crunch',\n 29: 'kneeling_cross_crunch',\n 30: 'weighted_kneeling_cross_crunch',\n 31: 'kneeling_oblique_cable_crunch',\n 32: 'knees_to_elbow',\n 33: 'leg_extensions',\n 34: 'weighted_leg_extensions',\n 35: 'leg_levers',\n 36: 'mcgill_curl_up',\n 37: 'weighted_mcgill_curl_up',\n 38: 'modified_pilates_roll_up_with_ball',\n 39: 'weighted_modified_pilates_roll_up_with_ball',\n 40: 'pilates_crunch',\n 41: 'weighted_pilates_crunch',\n 42: 'pilates_roll_up_with_ball',\n 43: 'weighted_pilates_roll_up_with_ball',\n 44: 'raised_legs_crunch',\n 45: 'weighted_raised_legs_crunch',\n 46: 'reverse_crunch',\n 47: 'weighted_reverse_crunch',\n 48: 'reverse_crunch_on_a_bench',\n 49: 'weighted_reverse_crunch_on_a_bench',\n 50: 'reverse_curl_and_lift',\n 51: 'weighted_reverse_curl_and_lift',\n 52: 'rotational_lift',\n 53: 'weighted_rotational_lift',\n 54: 'seated_alternating_reverse_crunch',\n 55: 'weighted_seated_alternating_reverse_crunch',\n 56: 'seated_leg_u',\n 57: 'weighted_seated_leg_u',\n 58: 'side_to_side_crunch_and_weave',\n 59: 'weighted_side_to_side_crunch_and_weave',\n 60: 'single_leg_reverse_crunch',\n 61: 'weighted_single_leg_reverse_crunch',\n 62: 'skater_crunch_cross',\n 63: 'weighted_skater_crunch_cross',\n 64: 'standing_cable_crunch',\n 65: 'standing_side_crunch',\n 66: 'step_climb',\n 67: 'weighted_step_climb',\n 68: 'swiss_ball_crunch',\n 69: 'swiss_ball_reverse_crunch',\n 70: 'weighted_swiss_ball_reverse_crunch',\n 71: 'swiss_ball_russian_twist',\n 72: 'weighted_swiss_ball_russian_twist',\n 73: 'swiss_ball_side_crunch',\n 74: 'weighted_swiss_ball_side_crunch',\n 75: 'thoracic_crunches_on_foam_roller',\n 76: 'weighted_thoracic_crunches_on_foam_roller',\n 77: 'triceps_crunch',\n 78: 'weighted_bicycle_crunch',\n 79: 'weighted_crunch',\n 80: 'weighted_swiss_ball_crunch',\n 81: 'toes_to_bar',\n 82: 'weighted_toes_to_bar',\n 83: 'crunch',\n 84: 'straight_leg_crunch_with_ball',\n },\n curl_exercise_name: {\n 0: 'alternating_dumbbell_biceps_curl',\n 1: 'alternating_dumbbell_biceps_curl_on_swiss_ball',\n 2: 'alternating_incline_dumbbell_biceps_curl',\n 3: 'barbell_biceps_curl',\n 4: 'barbell_reverse_wrist_curl',\n 5: 'barbell_wrist_curl',\n 6: 'behind_the_back_barbell_reverse_wrist_curl',\n 7: 'behind_the_back_one_arm_cable_curl',\n 8: 'cable_biceps_curl',\n 9: 'cable_hammer_curl',\n 10: 'cheating_barbell_biceps_curl',\n 11: 'close_grip_ez_bar_biceps_curl',\n 12: 'cross_body_dumbbell_hammer_curl',\n 13: 'dead_hang_biceps_curl',\n 14: 'decline_hammer_curl',\n 15: 'dumbbell_biceps_curl_with_static_hold',\n 16: 'dumbbell_hammer_curl',\n 17: 'dumbbell_reverse_wrist_curl',\n 18: 'dumbbell_wrist_curl',\n 19: 'ez_bar_preacher_curl',\n 20: 'forward_bend_biceps_curl',\n 21: 'hammer_curl_to_press',\n 22: 'incline_dumbbell_biceps_curl',\n 23: 'incline_offset_thumb_dumbbell_curl',\n 24: 'kettlebell_biceps_curl',\n 25: 'lying_concentration_cable_curl',\n 26: 'one_arm_preacher_curl',\n 27: 'plate_pinch_curl',\n 28: 'preacher_curl_with_cable',\n 29: 'reverse_ez_bar_curl',\n 30: 'reverse_grip_wrist_curl',\n 31: 'reverse_grip_barbell_biceps_curl',\n 32: 'seated_alternating_dumbbell_biceps_curl',\n 33: 'seated_dumbbell_biceps_curl',\n 34: 'seated_reverse_dumbbell_curl',\n 35: 'split_stance_offset_pinky_dumbbell_curl',\n 36: 'standing_alternating_dumbbell_curls',\n 37: 'standing_dumbbell_biceps_curl',\n 38: 'standing_ez_bar_biceps_curl',\n 39: 'static_curl',\n 40: 'swiss_ball_dumbbell_overhead_triceps_extension',\n 41: 'swiss_ball_ez_bar_preacher_curl',\n 42: 'twisting_standing_dumbbell_biceps_curl',\n 43: 'wide_grip_ez_bar_biceps_curl',\n },\n deadlift_exercise_name: {\n 0: 'barbell_deadlift',\n 1: 'barbell_straight_leg_deadlift',\n 2: 'dumbbell_deadlift',\n 3: 'dumbbell_single_leg_deadlift_to_row',\n 4: 'dumbbell_straight_leg_deadlift',\n 5: 'kettlebell_floor_to_shelf',\n 6: 'one_arm_one_leg_deadlift',\n 7: 'rack_pull',\n 8: 'rotational_dumbbell_straight_leg_deadlift',\n 9: 'single_arm_deadlift',\n 10: 'single_leg_barbell_deadlift',\n 11: 'single_leg_barbell_straight_leg_deadlift',\n 12: 'single_leg_deadlift_with_barbell',\n 13: 'single_leg_rdl_circuit',\n 14: 'single_leg_romanian_deadlift_with_dumbbell',\n 15: 'sumo_deadlift',\n 16: 'sumo_deadlift_high_pull',\n 17: 'trap_bar_deadlift',\n 18: 'wide_grip_barbell_deadlift',\n },\n flye_exercise_name: {\n 0: 'cable_crossover',\n 1: 'decline_dumbbell_flye',\n 2: 'dumbbell_flye',\n 3: 'incline_dumbbell_flye',\n 4: 'kettlebell_flye',\n 5: 'kneeling_rear_flye',\n 6: 'single_arm_standing_cable_reverse_flye',\n 7: 'swiss_ball_dumbbell_flye',\n 8: 'arm_rotations',\n 9: 'hug_a_tree',\n },\n hip_raise_exercise_name: {\n 0: 'barbell_hip_thrust_on_floor',\n 1: 'barbell_hip_thrust_with_bench',\n 2: 'bent_knee_swiss_ball_reverse_hip_raise',\n 3: 'weighted_bent_knee_swiss_ball_reverse_hip_raise',\n 4: 'bridge_with_leg_extension',\n 5: 'weighted_bridge_with_leg_extension',\n 6: 'clam_bridge',\n 7: 'front_kick_tabletop',\n 8: 'weighted_front_kick_tabletop',\n 9: 'hip_extension_and_cross',\n 10: 'weighted_hip_extension_and_cross',\n 11: 'hip_raise',\n 12: 'weighted_hip_raise',\n 13: 'hip_raise_with_feet_on_swiss_ball',\n 14: 'weighted_hip_raise_with_feet_on_swiss_ball',\n 15: 'hip_raise_with_head_on_bosu_ball',\n 16: 'weighted_hip_raise_with_head_on_bosu_ball',\n 17: 'hip_raise_with_head_on_swiss_ball',\n 18: 'weighted_hip_raise_with_head_on_swiss_ball',\n 19: 'hip_raise_with_knee_squeeze',\n 20: 'weighted_hip_raise_with_knee_squeeze',\n 21: 'incline_rear_leg_extension',\n 22: 'weighted_incline_rear_leg_extension',\n 23: 'kettlebell_swing',\n 24: 'marching_hip_raise',\n 25: 'weighted_marching_hip_raise',\n 26: 'marching_hip_raise_with_feet_on_a_swiss_ball',\n 27: 'weighted_marching_hip_raise_with_feet_on_a_swiss_ball',\n 28: 'reverse_hip_raise',\n 29: 'weighted_reverse_hip_raise',\n 30: 'single_leg_hip_raise',\n 31: 'weighted_single_leg_hip_raise',\n 32: 'single_leg_hip_raise_with_foot_on_bench',\n 33: 'weighted_single_leg_hip_raise_with_foot_on_bench',\n 34: 'single_leg_hip_raise_with_foot_on_bosu_ball',\n 35: 'weighted_single_leg_hip_raise_with_foot_on_bosu_ball',\n 36: 'single_leg_hip_raise_with_foot_on_foam_roller',\n 37: 'weighted_single_leg_hip_raise_with_foot_on_foam_roller',\n 38: 'single_leg_hip_raise_with_foot_on_medicine_ball',\n 39: 'weighted_single_leg_hip_raise_with_foot_on_medicine_ball',\n 40: 'single_leg_hip_raise_with_head_on_bosu_ball',\n 41: 'weighted_single_leg_hip_raise_with_head_on_bosu_ball',\n 42: 'weighted_clam_bridge',\n 43: 'single_leg_swiss_ball_hip_raise_and_leg_curl',\n 44: 'clams',\n 45: 'inner_thigh_circles',\n 46: 'inner_thigh_side_lift',\n 47: 'leg_circles',\n 48: 'leg_lift',\n 49: 'leg_lift_in_external_rotation',\n },\n hip_stability_exercise_name: {\n 0: 'band_side_lying_leg_raise',\n 1: 'dead_bug',\n 2: 'weighted_dead_bug',\n 3: 'external_hip_raise',\n 4: 'weighted_external_hip_raise',\n 5: 'fire_hydrant_kicks',\n 6: 'weighted_fire_hydrant_kicks',\n 7: 'hip_circles',\n 8: 'weighted_hip_circles',\n 9: 'inner_thigh_lift',\n 10: 'weighted_inner_thigh_lift',\n 11: 'lateral_walks_with_band_at_ankles',\n 12: 'pretzel_side_kick',\n 13: 'weighted_pretzel_side_kick',\n 14: 'prone_hip_internal_rotation',\n 15: 'weighted_prone_hip_internal_rotation',\n 16: 'quadruped',\n 17: 'quadruped_hip_extension',\n 18: 'weighted_quadruped_hip_extension',\n 19: 'quadruped_with_leg_lift',\n 20: 'weighted_quadruped_with_leg_lift',\n 21: 'side_lying_leg_raise',\n 22: 'weighted_side_lying_leg_raise',\n 23: 'sliding_hip_adduction',\n 24: 'weighted_sliding_hip_adduction',\n 25: 'standing_adduction',\n 26: 'weighted_standing_adduction',\n 27: 'standing_cable_hip_abduction',\n 28: 'standing_hip_abduction',\n 29: 'weighted_standing_hip_abduction',\n 30: 'standing_rear_leg_raise',\n 31: 'weighted_standing_rear_leg_raise',\n 32: 'supine_hip_internal_rotation',\n 33: 'weighted_supine_hip_internal_rotation',\n },\n hip_swing_excercise_name: {\n 0: 'single_arm_kettlebell_swing',\n 1: 'single_arm_dumbbell_swing',\n 2: 'step_out_swing',\n },\n hyperextension_exercise_name: {\n 0: 'back_extension_with_opposite_arm_and_leg_reach',\n 1: 'weighted_back_extension_with_opposite_arm_and_leg_reach',\n 2: 'base_rotations',\n 3: 'weighted_base_rotations',\n 4: 'bent_knee_reverse_hyperextension',\n 5: 'weighted_bent_knee_reverse_hyperextension',\n 6: 'hollow_hold_and_roll',\n 7: 'weighted_hollow_hold_and_roll',\n 8: 'kicks',\n 9: 'weighted_kicks',\n 10: 'knee_raises',\n 11: 'weighted_knee_raises',\n 12: 'kneeling_superman',\n 13: 'weighted_kneeling_superman',\n 14: 'lat_pull_down_with_row',\n 15: 'medicine_ball_deadlift_to_reach',\n 16: 'one_arm_one_leg_row',\n 17: 'one_arm_row_with_band',\n 18: 'overhead_lunge_with_medicine_ball',\n 19: 'plank_knee_tucks',\n 20: 'weighted_plank_knee_tucks',\n 21: 'side_step',\n 22: 'weighted_side_step',\n 23: 'single_leg_back_extension',\n 24: 'weighted_single_leg_back_extension',\n 25: 'spine_extension',\n 26: 'weighted_spine_extension',\n 27: 'static_back_extension',\n 28: 'weighted_static_back_extension',\n 29: 'superman_from_floor',\n 30: 'weighted_superman_from_floor',\n 31: 'swiss_ball_back_extension',\n 32: 'weighted_swiss_ball_back_extension',\n 33: 'swiss_ball_hyperextension',\n 34: 'weighted_swiss_ball_hyperextension',\n 35: 'swiss_ball_opposite_arm_and_leg_lift',\n 36: 'weighted_swiss_ball_opposite_arm_and_leg_lift',\n 37: 'superman_on_swiss_ball',\n 38: 'cobra',\n 39: 'supine_floor_barre',\n },\n lateral_raise_exercise_name: {\n 0: '45_degree_cable_external_rotation',\n 1: 'alternating_lateral_raise_with_static_hold',\n 2: 'bar_muscle_up',\n 3: 'bent_over_lateral_raise',\n 4: 'cable_diagonal_raise',\n 5: 'cable_front_raise',\n 6: 'calorie_row',\n 7: 'combo_shoulder_raise',\n 8: 'dumbbell_diagonal_raise',\n 9: 'dumbbell_v_raise',\n 10: 'front_raise',\n 11: 'leaning_dumbbell_lateral_raise',\n 12: 'lying_dumbbell_raise',\n 13: 'muscle_up',\n 14: 'one_arm_cable_lateral_raise',\n 15: 'overhand_grip_rear_lateral_raise',\n 16: 'plate_raises',\n 17: 'ring_dip',\n 18: 'weighted_ring_dip',\n 19: 'ring_muscle_up',\n 20: 'weighted_ring_muscle_up',\n 21: 'rope_climb',\n 22: 'weighted_rope_climb',\n 23: 'scaption',\n 24: 'seated_lateral_raise',\n 25: 'seated_rear_lateral_raise',\n 26: 'side_lying_lateral_raise',\n 27: 'standing_lift',\n 28: 'suspended_row',\n 29: 'underhand_grip_rear_lateral_raise',\n 30: 'wall_slide',\n 31: 'weighted_wall_slide',\n 32: 'arm_circles',\n 33: 'shaving_the_head',\n },\n leg_curl_exercise_name: {\n 0: 'leg_curl',\n 1: 'weighted_leg_curl',\n 2: 'good_morning',\n 3: 'seated_barbell_good_morning',\n 4: 'single_leg_barbell_good_morning',\n 5: 'single_leg_sliding_leg_curl',\n 6: 'sliding_leg_curl',\n 7: 'split_barbell_good_morning',\n 8: 'split_stance_extension',\n 9: 'staggered_stance_good_morning',\n 10: 'swiss_ball_hip_raise_and_leg_curl',\n 11: 'zercher_good_morning',\n },\n leg_raise_exercise_name: {\n 0: 'hanging_knee_raise',\n 1: 'hanging_leg_raise',\n 2: 'weighted_hanging_leg_raise',\n 3: 'hanging_single_leg_raise',\n 4: 'weighted_hanging_single_leg_raise',\n 5: 'kettlebell_leg_raises',\n 6: 'leg_lowering_drill',\n 7: 'weighted_leg_lowering_drill',\n 8: 'lying_straight_leg_raise',\n 9: 'weighted_lying_straight_leg_raise',\n 10: 'medicine_ball_leg_drops',\n 11: 'quadruped_leg_raise',\n 12: 'weighted_quadruped_leg_raise',\n 13: 'reverse_leg_raise',\n 14: 'weighted_reverse_leg_raise',\n 15: 'reverse_leg_raise_on_swiss_ball',\n 16: 'weighted_reverse_leg_raise_on_swiss_ball',\n 17: 'single_leg_lowering_drill',\n 18: 'weighted_single_leg_lowering_drill',\n 19: 'weighted_hanging_knee_raise',\n 20: 'lateral_stepover',\n 21: 'weighted_lateral_stepover',\n },\n lunge_exercise_name: {\n 0: 'overhead_lunge',\n 1: 'lunge_matrix',\n 2: 'weighted_lunge_matrix',\n 3: 'alternating_barbell_forward_lunge',\n 4: 'alternating_dumbbell_lunge_with_reach',\n 5: 'back_foot_elevated_dumbbell_split_squat',\n 6: 'barbell_box_lunge',\n 7: 'barbell_bulgarian_split_squat',\n 8: 'barbell_crossover_lunge',\n 9: 'barbell_front_split_squat',\n 10: 'barbell_lunge',\n 11: 'barbell_reverse_lunge',\n 12: 'barbell_side_lunge',\n 13: 'barbell_split_squat',\n 14: 'core_control_rear_lunge',\n 15: 'diagonal_lunge',\n 16: 'drop_lunge',\n 17: 'dumbbell_box_lunge',\n 18: 'dumbbell_bulgarian_split_squat',\n 19: 'dumbbell_crossover_lunge',\n 20: 'dumbbell_diagonal_lunge',\n 21: 'dumbbell_lunge',\n 22: 'dumbbell_lunge_and_rotation',\n 23: 'dumbbell_overhead_bulgarian_split_squat',\n 24: 'dumbbell_reverse_lunge_to_high_knee_and_press',\n 25: 'dumbbell_side_lunge',\n 26: 'elevated_front_foot_barbell_split_squat',\n 27: 'front_foot_elevated_dumbbell_split_squat',\n 28: 'gunslinger_lunge',\n 29: 'lawnmower_lunge',\n 30: 'low_lunge_with_isometric_adduction',\n 31: 'low_side_to_side_lunge',\n 32: 'lunge',\n 33: 'weighted_lunge',\n 34: 'lunge_with_arm_reach',\n 35: 'lunge_with_diagonal_reach',\n 36: 'lunge_with_side_bend',\n 37: 'offset_dumbbell_lunge',\n 38: 'offset_dumbbell_reverse_lunge',\n 39: 'overhead_bulgarian_split_squat',\n 40: 'overhead_dumbbell_reverse_lunge',\n 41: 'overhead_dumbbell_split_squat',\n 42: 'overhead_lunge_with_rotation',\n 43: 'reverse_barbell_box_lunge',\n 44: 'reverse_box_lunge',\n 45: 'reverse_dumbbell_box_lunge',\n 46: 'reverse_dumbbell_crossover_lunge',\n 47: 'reverse_dumbbell_diagonal_lunge',\n 48: 'reverse_lunge_with_reach_back',\n 49: 'weighted_reverse_lunge_with_reach_back',\n 50: 'reverse_lunge_with_twist_and_overhead_reach',\n 51: 'weighted_reverse_lunge_with_twist_and_overhead_reach',\n 52: 'reverse_sliding_box_lunge',\n 53: 'weighted_reverse_sliding_box_lunge',\n 54: 'reverse_sliding_lunge',\n 55: 'weighted_reverse_sliding_lunge',\n 56: 'runners_lunge_to_balance',\n 57: 'weighted_runners_lunge_to_balance',\n 58: 'shifting_side_lunge',\n 59: 'side_and_crossover_lunge',\n 60: 'weighted_side_and_crossover_lunge',\n 61: 'side_lunge',\n 62: 'weighted_side_lunge',\n 63: 'side_lunge_and_press',\n 64: 'side_lunge_jump_off',\n 65: 'side_lunge_sweep',\n 66: 'weighted_side_lunge_sweep',\n 67: 'side_lunge_to_crossover_tap',\n 68: 'weighted_side_lunge_to_crossover_tap',\n 69: 'side_to_side_lunge_chops',\n 70: 'weighted_side_to_side_lunge_chops',\n 71: 'siff_jump_lunge',\n 72: 'weighted_siff_jump_lunge',\n 73: 'single_arm_reverse_lunge_and_press',\n 74: 'sliding_lateral_lunge',\n 75: 'weighted_sliding_lateral_lunge',\n 76: 'walking_barbell_lunge',\n 77: 'walking_dumbbell_lunge',\n 78: 'walking_lunge',\n 79: 'weighted_walking_lunge',\n 80: 'wide_grip_overhead_barbell_split_squat',\n },\n olympic_lift_exercise_name: {\n 0: 'barbell_hang_power_clean',\n 1: 'barbell_hang_squat_clean',\n 2: 'barbell_power_clean',\n 3: 'barbell_power_snatch',\n 4: 'barbell_squat_clean',\n 5: 'clean_and_jerk',\n 6: 'barbell_hang_power_snatch',\n 7: 'barbell_hang_pull',\n 8: 'barbell_high_pull',\n 9: 'barbell_snatch',\n 10: 'barbell_split_jerk',\n 11: 'clean',\n 12: 'dumbbell_clean',\n 13: 'dumbbell_hang_pull',\n 14: 'one_hand_dumbbell_split_snatch',\n 15: 'push_jerk',\n 16: 'single_arm_dumbbell_snatch',\n 17: 'single_arm_hang_snatch',\n 18: 'single_arm_kettlebell_snatch',\n 19: 'split_jerk',\n 20: 'squat_clean_and_jerk',\n },\n plank_exercise_name: {\n 0: '45_degree_plank',\n 1: 'weighted_45_degree_plank',\n 2: '90_degree_static_hold',\n 3: 'weighted_90_degree_static_hold',\n 4: 'bear_crawl',\n 5: 'weighted_bear_crawl',\n 6: 'cross_body_mountain_climber',\n 7: 'weighted_cross_body_mountain_climber',\n 8: 'elbow_plank_pike_jacks',\n 9: 'weighted_elbow_plank_pike_jacks',\n 10: 'elevated_feet_plank',\n 11: 'weighted_elevated_feet_plank',\n 12: 'elevator_abs',\n 13: 'weighted_elevator_abs',\n 14: 'extended_plank',\n 15: 'weighted_extended_plank',\n 16: 'full_plank_passe_twist',\n 17: 'weighted_full_plank_passe_twist',\n 18: 'inching_elbow_plank',\n 19: 'weighted_inching_elbow_plank',\n 20: 'inchworm_to_side_plank',\n 21: 'weighted_inchworm_to_side_plank',\n 22: 'kneeling_plank',\n 23: 'weighted_kneeling_plank',\n 24: 'kneeling_side_plank_with_leg_lift',\n 25: 'weighted_kneeling_side_plank_with_leg_lift',\n 26: 'lateral_roll',\n 27: 'weighted_lateral_roll',\n 28: 'lying_reverse_plank',\n 29: 'weighted_lying_reverse_plank',\n 30: 'medicine_ball_mountain_climber',\n 31: 'weighted_medicine_ball_mountain_climber',\n 32: 'modified_mountain_climber_and_extension',\n 33: 'weighted_modified_mountain_climber_and_extension',\n 34: 'mountain_climber',\n 35: 'weighted_mountain_climber',\n 36: 'mountain_climber_on_sliding_discs',\n 37: 'weighted_mountain_climber_on_sliding_discs',\n 38: 'mountain_climber_with_feet_on_bosu_ball',\n 39: 'weighted_mountain_climber_with_feet_on_bosu_ball',\n 40: 'mountain_climber_with_hands_on_bench',\n 41: 'mountain_climber_with_hands_on_swiss_ball',\n 42: 'weighted_mountain_climber_with_hands_on_swiss_ball',\n 43: 'plank',\n 44: 'plank_jacks_with_feet_on_sliding_discs',\n 45: 'weighted_plank_jacks_with_feet_on_sliding_discs',\n 46: 'plank_knee_twist',\n 47: 'weighted_plank_knee_twist',\n 48: 'plank_pike_jumps',\n 49: 'weighted_plank_pike_jumps',\n 50: 'plank_pikes',\n 51: 'weighted_plank_pikes',\n 52: 'plank_to_stand_up',\n 53: 'weighted_plank_to_stand_up',\n 54: 'plank_with_arm_raise',\n 55: 'weighted_plank_with_arm_raise',\n 56: 'plank_with_knee_to_elbow',\n 57: 'weighted_plank_with_knee_to_elbow',\n 58: 'plank_with_oblique_crunch',\n 59: 'weighted_plank_with_oblique_crunch',\n 60: 'plyometric_side_plank',\n 61: 'weighted_plyometric_side_plank',\n 62: 'rolling_side_plank',\n 63: 'weighted_rolling_side_plank',\n 64: 'side_kick_plank',\n 65: 'weighted_side_kick_plank',\n 66: 'side_plank',\n 67: 'weighted_side_plank',\n 68: 'side_plank_and_row',\n 69: 'weighted_side_plank_and_row',\n 70: 'side_plank_lift',\n 71: 'weighted_side_plank_lift',\n 72: 'side_plank_with_elbow_on_bosu_ball',\n 73: 'weighted_side_plank_with_elbow_on_bosu_ball',\n 74: 'side_plank_with_feet_on_bench',\n 75: 'weighted_side_plank_with_feet_on_bench',\n 76: 'side_plank_with_knee_circle',\n 77: 'weighted_side_plank_with_knee_circle',\n 78: 'side_plank_with_knee_tuck',\n 79: 'weighted_side_plank_with_knee_tuck',\n 80: 'side_plank_with_leg_lift',\n 81: 'weighted_side_plank_with_leg_lift',\n 82: 'side_plank_with_reach_under',\n 83: 'weighted_side_plank_with_reach_under',\n 84: 'single_leg_elevated_feet_plank',\n 85: 'weighted_single_leg_elevated_feet_plank',\n 86: 'single_leg_flex_and_extend',\n 87: 'weighted_single_leg_flex_and_extend',\n 88: 'single_leg_side_plank',\n 89: 'weighted_single_leg_side_plank',\n 90: 'spiderman_plank',\n 91: 'weighted_spiderman_plank',\n 92: 'straight_arm_plank',\n 93: 'weighted_straight_arm_plank',\n 94: 'straight_arm_plank_with_shoulder_touch',\n 95: 'weighted_straight_arm_plank_with_shoulder_touch',\n 96: 'swiss_ball_plank',\n 97: 'weighted_swiss_ball_plank',\n 98: 'swiss_ball_plank_leg_lift',\n 99: 'weighted_swiss_ball_plank_leg_lift',\n 100: 'swiss_ball_plank_leg_lift_and_hold',\n 101: 'swiss_ball_plank_with_feet_on_bench',\n 102: 'weighted_swiss_ball_plank_with_feet_on_bench',\n 103: 'swiss_ball_prone_jackknife',\n 104: 'weighted_swiss_ball_prone_jackknife',\n 105: 'swiss_ball_side_plank',\n 106: 'weighted_swiss_ball_side_plank',\n 107: 'three_way_plank',\n 108: 'weighted_three_way_plank',\n 109: 'towel_plank_and_knee_in',\n 110: 'weighted_towel_plank_and_knee_in',\n 111: 't_stabilization',\n 112: 'weighted_t_stabilization',\n 113: 'turkish_get_up_to_side_plank',\n 114: 'weighted_turkish_get_up_to_side_plank',\n 115: 'two_point_plank',\n 116: 'weighted_two_point_plank',\n 117: 'weighted_plank',\n 118: 'wide_stance_plank_with_diagonal_arm_lift',\n 119: 'weighted_wide_stance_plank_with_diagonal_arm_lift',\n 120: 'wide_stance_plank_with_diagonal_leg_lift',\n 121: 'weighted_wide_stance_plank_with_diagonal_leg_lift',\n 122: 'wide_stance_plank_with_leg_lift',\n 123: 'weighted_wide_stance_plank_with_leg_lift',\n 124: 'wide_stance_plank_with_opposite_arm_and_leg_lift',\n 125: 'weighted_mountain_climber_with_hands_on_bench',\n 126: 'weighted_swiss_ball_plank_leg_lift_and_hold',\n 127: 'weighted_wide_stance_plank_with_opposite_arm_and_leg_lift',\n 128: 'plank_with_feet_on_swiss_ball',\n 129: 'side_plank_to_plank_with_reach_under',\n 130: 'bridge_with_glute_lower_lift',\n 131: 'bridge_one_leg_bridge',\n 132: 'plank_with_arm_variations',\n 133: 'plank_with_leg_lift',\n 134: 'reverse_plank_with_leg_pull',\n },\n plyo_exercise_name: {\n 0: 'alternating_jump_lunge',\n 1: 'weighted_alternating_jump_lunge',\n 2: 'barbell_jump_squat',\n 3: 'body_weight_jump_squat',\n 4: 'weighted_jump_squat',\n 5: 'cross_knee_strike',\n 6: 'weighted_cross_knee_strike',\n 7: 'depth_jump',\n 8: 'weighted_depth_jump',\n 9: 'dumbbell_jump_squat',\n 10: 'dumbbell_split_jump',\n 11: 'front_knee_strike',\n 12: 'weighted_front_knee_strike',\n 13: 'high_box_jump',\n 14: 'weighted_high_box_jump',\n 15: 'isometric_explosive_body_weight_jump_squat',\n 16: 'weighted_isometric_explosive_jump_squat',\n 17: 'lateral_leap_and_hop',\n 18: 'weighted_lateral_leap_and_hop',\n 19: 'lateral_plyo_squats',\n 20: 'weighted_lateral_plyo_squats',\n 21: 'lateral_slide',\n 22: 'weighted_lateral_slide',\n 23: 'medicine_ball_overhead_throws',\n 24: 'medicine_ball_side_throw',\n 25: 'medicine_ball_slam',\n 26: 'side_to_side_medicine_ball_throws',\n 27: 'side_to_side_shuffle_jump',\n 28: 'weighted_side_to_side_shuffle_jump',\n 29: 'squat_jump_onto_box',\n 30: 'weighted_squat_jump_onto_box',\n 31: 'squat_jumps_in_and_out',\n 32: 'weighted_squat_jumps_in_and_out',\n },\n pull_up_exercise_name: {\n 0: 'banded_pull_ups',\n 1: '30_degree_lat_pulldown',\n 2: 'band_assisted_chin_up',\n 3: 'close_grip_chin_up',\n 4: 'weighted_close_grip_chin_up',\n 5: 'close_grip_lat_pulldown',\n 6: 'crossover_chin_up',\n 7: 'weighted_crossover_chin_up',\n 8: 'ez_bar_pullover',\n 9: 'hanging_hurdle',\n 10: 'weighted_hanging_hurdle',\n 11: 'kneeling_lat_pulldown',\n 12: 'kneeling_underhand_grip_lat_pulldown',\n 13: 'lat_pulldown',\n 14: 'mixed_grip_chin_up',\n 15: 'weighted_mixed_grip_chin_up',\n 16: 'mixed_grip_pull_up',\n 17: 'weighted_mixed_grip_pull_up',\n 18: 'reverse_grip_pulldown',\n 19: 'standing_cable_pullover',\n 20: 'straight_arm_pulldown',\n 21: 'swiss_ball_ez_bar_pullover',\n 22: 'towel_pull_up',\n 23: 'weighted_towel_pull_up',\n 24: 'weighted_pull_up',\n 25: 'wide_grip_lat_pulldown',\n 26: 'wide_grip_pull_up',\n 27: 'weighted_wide_grip_pull_up',\n 28: 'burpee_pull_up',\n 29: 'weighted_burpee_pull_up',\n 30: 'jumping_pull_ups',\n 31: 'weighted_jumping_pull_ups',\n 32: 'kipping_pull_up',\n 33: 'weighted_kipping_pull_up',\n 34: 'l_pull_up',\n 35: 'weighted_l_pull_up',\n 36: 'suspended_chin_up',\n 37: 'weighted_suspended_chin_up',\n 38: 'pull_up',\n },\n push_up_exercise_name: {\n 0: 'chest_press_with_band',\n 1: 'alternating_staggered_push_up',\n 2: 'weighted_alternating_staggered_push_up',\n 3: 'alternating_hands_medicine_ball_push_up',\n 4: 'weighted_alternating_hands_medicine_ball_push_up',\n 5: 'bosu_ball_push_up',\n 6: 'weighted_bosu_ball_push_up',\n 7: 'clapping_push_up',\n 8: 'weighted_clapping_push_up',\n 9: 'close_grip_medicine_ball_push_up',\n 10: 'weighted_close_grip_medicine_ball_push_up',\n 11: 'close_hands_push_up',\n 12: 'weighted_close_hands_push_up',\n 13: 'decline_push_up',\n 14: 'weighted_decline_push_up',\n 15: 'diamond_push_up',\n 16: 'weighted_diamond_push_up',\n 17: 'explosive_crossover_push_up',\n 18: 'weighted_explosive_crossover_push_up',\n 19: 'explosive_push_up',\n 20: 'weighted_explosive_push_up',\n 21: 'feet_elevated_side_to_side_push_up',\n 22: 'weighted_feet_elevated_side_to_side_push_up',\n 23: 'hand_release_push_up',\n 24: 'weighted_hand_release_push_up',\n 25: 'handstand_push_up',\n 26: 'weighted_handstand_push_up',\n 27: 'incline_push_up',\n 28: 'weighted_incline_push_up',\n 29: 'isometric_explosive_push_up',\n 30: 'weighted_isometric_explosive_push_up',\n 31: 'judo_push_up',\n 32: 'weighted_judo_push_up',\n 33: 'kneeling_push_up',\n 34: 'weighted_kneeling_push_up',\n 35: 'medicine_ball_chest_pass',\n 36: 'medicine_ball_push_up',\n 37: 'weighted_medicine_ball_push_up',\n 38: 'one_arm_push_up',\n 39: 'weighted_one_arm_push_up',\n 40: 'weighted_push_up',\n 41: 'push_up_and_row',\n 42: 'weighted_push_up_and_row',\n 43: 'push_up_plus',\n 44: 'weighted_push_up_plus',\n 45: 'push_up_with_feet_on_swiss_ball',\n 46: 'weighted_push_up_with_feet_on_swiss_ball',\n 47: 'push_up_with_one_hand_on_medicine_ball',\n 48: 'weighted_push_up_with_one_hand_on_medicine_ball',\n 49: 'shoulder_push_up',\n 50: 'weighted_shoulder_push_up',\n 51: 'single_arm_medicine_ball_push_up',\n 52: 'weighted_single_arm_medicine_ball_push_up',\n 53: 'spiderman_push_up',\n 54: 'weighted_spiderman_push_up',\n 55: 'stacked_feet_push_up',\n 56: 'weighted_stacked_feet_push_up',\n 57: 'staggered_hands_push_up',\n 58: 'weighted_staggered_hands_push_up',\n 59: 'suspended_push_up',\n 60: 'weighted_suspended_push_up',\n 61: 'swiss_ball_push_up',\n 62: 'weighted_swiss_ball_push_up',\n 63: 'swiss_ball_push_up_plus',\n 64: 'weighted_swiss_ball_push_up_plus',\n 65: 't_push_up',\n 66: 'weighted_t_push_up',\n 67: 'triple_stop_push_up',\n 68: 'weighted_triple_stop_push_up',\n 69: 'wide_hands_push_up',\n 70: 'weighted_wide_hands_push_up',\n 71: 'parallette_handstand_push_up',\n 72: 'weighted_parallette_handstand_push_up',\n 73: 'ring_handstand_push_up',\n 74: 'weighted_ring_handstand_push_up',\n 75: 'ring_push_up',\n 76: 'weighted_ring_push_up',\n 77: 'push_up',\n 78: 'pilates_pushup',\n },\n row_exercise_name: {\n 0: 'barbell_straight_leg_deadlift_to_row',\n 1: 'cable_row_standing',\n 2: 'dumbbell_row',\n 3: 'elevated_feet_inverted_row',\n 4: 'weighted_elevated_feet_inverted_row',\n 5: 'face_pull',\n 6: 'face_pull_with_external_rotation',\n 7: 'inverted_row_with_feet_on_swiss_ball',\n 8: 'weighted_inverted_row_with_feet_on_swiss_ball',\n 9: 'kettlebell_row',\n 10: 'modified_inverted_row',\n 11: 'weighted_modified_inverted_row',\n 12: 'neutral_grip_alternating_dumbbell_row',\n 13: 'one_arm_bent_over_row',\n 14: 'one_legged_dumbbell_row',\n 15: 'renegade_row',\n 16: 'reverse_grip_barbell_row',\n 17: 'rope_handle_cable_row',\n 18: 'seated_cable_row',\n 19: 'seated_dumbbell_row',\n 20: 'single_arm_cable_row',\n 21: 'single_arm_cable_row_and_rotation',\n 22: 'single_arm_inverted_row',\n 23: 'weighted_single_arm_inverted_row',\n 24: 'single_arm_neutral_grip_dumbbell_row',\n 25: 'single_arm_neutral_grip_dumbbell_row_and_rotation',\n 26: 'suspended_inverted_row',\n 27: 'weighted_suspended_inverted_row',\n 28: 't_bar_row',\n 29: 'towel_grip_inverted_row',\n 30: 'weighted_towel_grip_inverted_row',\n 31: 'underhand_grip_cable_row',\n 32: 'v_grip_cable_row',\n 33: 'wide_grip_seated_cable_row',\n },\n shoulder_press_exercise_name: {\n 0: 'alternating_dumbbell_shoulder_press',\n 1: 'arnold_press',\n 2: 'barbell_front_squat_to_push_press',\n 3: 'barbell_push_press',\n 4: 'barbell_shoulder_press',\n 5: 'dead_curl_press',\n 6: 'dumbbell_alternating_shoulder_press_and_twist',\n 7: 'dumbbell_hammer_curl_to_lunge_to_press',\n 8: 'dumbbell_push_press',\n 9: 'floor_inverted_shoulder_press',\n 10: 'weighted_floor_inverted_shoulder_press',\n 11: 'inverted_shoulder_press',\n 12: 'weighted_inverted_shoulder_press',\n 13: 'one_arm_push_press',\n 14: 'overhead_barbell_press',\n 15: 'overhead_dumbbell_press',\n 16: 'seated_barbell_shoulder_press',\n 17: 'seated_dumbbell_shoulder_press',\n 18: 'single_arm_dumbbell_shoulder_press',\n 19: 'single_arm_step_up_and_press',\n 20: 'smith_machine_overhead_press',\n 21: 'split_stance_hammer_curl_to_press',\n 22: 'swiss_ball_dumbbell_shoulder_press',\n 23: 'weight_plate_front_raise',\n },\n shoulder_stability_exercise_name: {\n 0: '90_degree_cable_external_rotation',\n 1: 'band_external_rotation',\n 2: 'band_internal_rotation',\n 3: 'bent_arm_lateral_raise_and_external_rotation',\n 4: 'cable_external_rotation',\n 5: 'dumbbell_face_pull_with_external_rotation',\n 6: 'floor_i_raise',\n 7: 'weighted_floor_i_raise',\n 8: 'floor_t_raise',\n 9: 'weighted_floor_t_raise',\n 10: 'floor_y_raise',\n 11: 'weighted_floor_y_raise',\n 12: 'incline_i_raise',\n 13: 'weighted_incline_i_raise',\n 14: 'incline_l_raise',\n 15: 'weighted_incline_l_raise',\n 16: 'incline_t_raise',\n 17: 'weighted_incline_t_raise',\n 18: 'incline_w_raise',\n 19: 'weighted_incline_w_raise',\n 20: 'incline_y_raise',\n 21: 'weighted_incline_y_raise',\n 22: 'lying_external_rotation',\n 23: 'seated_dumbbell_external_rotation',\n 24: 'standing_l_raise',\n 25: 'swiss_ball_i_raise',\n 26: 'weighted_swiss_ball_i_raise',\n 27: 'swiss_ball_t_raise',\n 28: 'weighted_swiss_ball_t_raise',\n 29: 'swiss_ball_w_raise',\n 30: 'weighted_swiss_ball_w_raise',\n 31: 'swiss_ball_y_raise',\n 32: 'weighted_swiss_ball_y_raise',\n },\n shrug_exercise_name: {\n 0: 'barbell_jump_shrug',\n 1: 'barbell_shrug',\n 2: 'barbell_upright_row',\n 3: 'behind_the_back_smith_machine_shrug',\n 4: 'dumbbell_jump_shrug',\n 5: 'dumbbell_shrug',\n 6: 'dumbbell_upright_row',\n 7: 'incline_dumbbell_shrug',\n 8: 'overhead_barbell_shrug',\n 9: 'overhead_dumbbell_shrug',\n 10: 'scaption_and_shrug',\n 11: 'scapular_retraction',\n 12: 'serratus_chair_shrug',\n 13: 'weighted_serratus_chair_shrug',\n 14: 'serratus_shrug',\n 15: 'weighted_serratus_shrug',\n 16: 'wide_grip_jump_shrug',\n },\n sit_up_exercise_name: {\n 0: 'alternating_sit_up',\n 1: 'weighted_alternating_sit_up',\n 2: 'bent_knee_v_up',\n 3: 'weighted_bent_knee_v_up',\n 4: 'butterfly_sit_up',\n 5: 'weighted_butterfly_situp',\n 6: 'cross_punch_roll_up',\n 7: 'weighted_cross_punch_roll_up',\n 8: 'crossed_arms_sit_up',\n 9: 'weighted_crossed_arms_sit_up',\n 10: 'get_up_sit_up',\n 11: 'weighted_get_up_sit_up',\n 12: 'hovering_sit_up',\n 13: 'weighted_hovering_sit_up',\n 14: 'kettlebell_sit_up',\n 15: 'medicine_ball_alternating_v_up',\n 16: 'medicine_ball_sit_up',\n 17: 'medicine_ball_v_up',\n 18: 'modified_sit_up',\n 19: 'negative_sit_up',\n 20: 'one_arm_full_sit_up',\n 21: 'reclining_circle',\n 22: 'weighted_reclining_circle',\n 23: 'reverse_curl_up',\n 24: 'weighted_reverse_curl_up',\n 25: 'single_leg_swiss_ball_jackknife',\n 26: 'weighted_single_leg_swiss_ball_jackknife',\n 27: 'the_teaser',\n 28: 'the_teaser_weighted',\n 29: 'three_part_roll_down',\n 30: 'weighted_three_part_roll_down',\n 31: 'v_up',\n 32: 'weighted_v_up',\n 33: 'weighted_russian_twist_on_swiss_ball',\n 34: 'weighted_sit_up',\n 35: 'x_abs',\n 36: 'weighted_x_abs',\n 37: 'sit_up',\n },\n squat_exercise_name: {\n 0: 'leg_press',\n 1: 'back_squat_with_body_bar',\n 2: 'back_squats',\n 3: 'weighted_back_squats',\n 4: 'balancing_squat',\n 5: 'weighted_balancing_squat',\n 6: 'barbell_back_squat',\n 7: 'barbell_box_squat',\n 8: 'barbell_front_squat',\n 9: 'barbell_hack_squat',\n 10: 'barbell_hang_squat_snatch',\n 11: 'barbell_lateral_step_up',\n 12: 'barbell_quarter_squat',\n 13: 'barbell_siff_squat',\n 14: 'barbell_squat_snatch',\n 15: 'barbell_squat_with_heels_raised',\n 16: 'barbell_stepover',\n 17: 'barbell_step_up',\n 18: 'bench_squat_with_rotational_chop',\n 19: 'weighted_bench_squat_with_rotational_chop',\n 20: 'body_weight_wall_squat',\n 21: 'weighted_wall_squat',\n 22: 'box_step_squat',\n 23: 'weighted_box_step_squat',\n 24: 'braced_squat',\n 25: 'crossed_arm_barbell_front_squat',\n 26: 'crossover_dumbbell_step_up',\n 27: 'dumbbell_front_squat',\n 28: 'dumbbell_split_squat',\n 29: 'dumbbell_squat',\n 30: 'dumbbell_squat_clean',\n 31: 'dumbbell_stepover',\n 32: 'dumbbell_step_up',\n 33: 'elevated_single_leg_squat',\n 34: 'weighted_elevated_single_leg_squat',\n 35: 'figure_four_squats',\n 36: 'weighted_figure_four_squats',\n 37: 'goblet_squat',\n 38: 'kettlebell_squat',\n 39: 'kettlebell_swing_overhead',\n 40: 'kettlebell_swing_with_flip_to_squat',\n 41: 'lateral_dumbbell_step_up',\n 42: 'one_legged_squat',\n 43: 'overhead_dumbbell_squat',\n 44: 'overhead_squat',\n 45: 'partial_single_leg_squat',\n 46: 'weighted_partial_single_leg_squat',\n 47: 'pistol_squat',\n 48: 'weighted_pistol_squat',\n 49: 'plie_slides',\n 50: 'weighted_plie_slides',\n 51: 'plie_squat',\n 52: 'weighted_plie_squat',\n 53: 'prisoner_squat',\n 54: 'weighted_prisoner_squat',\n 55: 'single_leg_bench_get_up',\n 56: 'weighted_single_leg_bench_get_up',\n 57: 'single_leg_bench_squat',\n 58: 'weighted_single_leg_bench_squat',\n 59: 'single_leg_squat_on_swiss_ball',\n 60: 'weighted_single_leg_squat_on_swiss_ball',\n 61: 'squat',\n 62: 'weighted_squat',\n 63: 'squats_with_band',\n 64: 'staggered_squat',\n 65: 'weighted_staggered_squat',\n 66: 'step_up',\n 67: 'weighted_step_up',\n 68: 'suitcase_squats',\n 69: 'sumo_squat',\n 70: 'sumo_squat_slide_in',\n 71: 'weighted_sumo_squat_slide_in',\n 72: 'sumo_squat_to_high_pull',\n 73: 'sumo_squat_to_stand',\n 74: 'weighted_sumo_squat_to_stand',\n 75: 'sumo_squat_with_rotation',\n 76: 'weighted_sumo_squat_with_rotation',\n 77: 'swiss_ball_body_weight_wall_squat',\n 78: 'weighted_swiss_ball_wall_squat',\n 79: 'thrusters',\n 80: 'uneven_squat',\n 81: 'weighted_uneven_squat',\n 82: 'waist_slimming_squat',\n 83: 'wall_ball',\n 84: 'wide_stance_barbell_squat',\n 85: 'wide_stance_goblet_squat',\n 86: 'zercher_squat',\n 87: 'kbs_overhead',\n 88: 'squat_and_side_kick',\n 89: 'squat_jumps_in_n_out',\n 90: 'pilates_plie_squats_parallel_turned_out_flat_and_heels',\n 91: 'releve_straight_leg_and_knee_bent_with_one_leg_variation',\n },\n total_body_exercise_name: {\n 0: 'burpee',\n 1: 'weighted_burpee',\n 2: 'burpee_box_jump',\n 3: 'weighted_burpee_box_jump',\n 4: 'high_pull_burpee',\n 5: 'man_makers',\n 6: 'one_arm_burpee',\n 7: 'squat_thrusts',\n 8: 'weighted_squat_thrusts',\n 9: 'squat_plank_push_up',\n 10: 'weighted_squat_plank_push_up',\n 11: 'standing_t_rotation_balance',\n 12: 'weighted_standing_t_rotation_balance',\n },\n triceps_extension_exercise_name: {\n 0: 'bench_dip',\n 1: 'weighted_bench_dip',\n 2: 'body_weight_dip',\n 3: 'cable_kickback',\n 4: 'cable_lying_triceps_extension',\n 5: 'cable_overhead_triceps_extension',\n 6: 'dumbbell_kickback',\n 7: 'dumbbell_lying_triceps_extension',\n 8: 'ez_bar_overhead_triceps_extension',\n 9: 'incline_dip',\n 10: 'weighted_incline_dip',\n 11: 'incline_ez_bar_lying_triceps_extension',\n 12: 'lying_dumbbell_pullover_to_extension',\n 13: 'lying_ez_bar_triceps_extension',\n 14: 'lying_triceps_extension_to_close_grip_bench_press',\n 15: 'overhead_dumbbell_triceps_extension',\n 16: 'reclining_triceps_press',\n 17: 'reverse_grip_pressdown',\n 18: 'reverse_grip_triceps_pressdown',\n 19: 'rope_pressdown',\n 20: 'seated_barbell_overhead_triceps_extension',\n 21: 'seated_dumbbell_overhead_triceps_extension',\n 22: 'seated_ez_bar_overhead_triceps_extension',\n 23: 'seated_single_arm_overhead_dumbbell_extension',\n 24: 'single_arm_dumbbell_overhead_triceps_extension',\n 25: 'single_dumbbell_seated_overhead_triceps_extension',\n 26: 'single_leg_bench_dip_and_kick',\n 27: 'weighted_single_leg_bench_dip_and_kick',\n 28: 'single_leg_dip',\n 29: 'weighted_single_leg_dip',\n 30: 'static_lying_triceps_extension',\n 31: 'suspended_dip',\n 32: 'weighted_suspended_dip',\n 33: 'swiss_ball_dumbbell_lying_triceps_extension',\n 34: 'swiss_ball_ez_bar_lying_triceps_extension',\n 35: 'swiss_ball_ez_bar_overhead_triceps_extension',\n 36: 'tabletop_dip',\n 37: 'weighted_tabletop_dip',\n 38: 'triceps_extension_on_floor',\n 39: 'triceps_pressdown',\n 40: 'weighted_dip',\n },\n warm_up_exercise_name: {\n 0: 'quadruped_rocking',\n 1: 'neck_tilts',\n 2: 'ankle_circles',\n 3: 'ankle_dorsiflexion_with_band',\n 4: 'ankle_internal_rotation',\n 5: 'arm_circles',\n 6: 'bent_over_reach_to_sky',\n 7: 'cat_camel',\n 8: 'elbow_to_foot_lunge',\n 9: 'forward_and_backward_leg_swings',\n 10: 'groiners',\n 11: 'inverted_hamstring_stretch',\n 12: 'lateral_duck_under',\n 13: 'neck_rotations',\n 14: 'opposite_arm_and_leg_balance',\n 15: 'reach_roll_and_lift',\n 16: 'scorpion',\n 17: 'shoulder_circles',\n 18: 'side_to_side_leg_swings',\n 19: 'sleeper_stretch',\n 20: 'slide_out',\n 21: 'swiss_ball_hip_crossover',\n 22: 'swiss_ball_reach_roll_and_lift',\n 23: 'swiss_ball_windshield_wipers',\n 24: 'thoracic_rotation',\n 25: 'walking_high_kicks',\n 26: 'walking_high_knees',\n 27: 'walking_knee_hugs',\n 28: 'walking_leg_cradles',\n 29: 'walkout',\n 30: 'walkout_from_push_up_position',\n },\n run_exercise_name: {\n 0: 'run',\n 1: 'walk',\n 2: 'jog',\n 3: 'sprint',\n },\n water_type: {\n 0: 'fresh',\n 1: 'salt',\n 2: 'en13319',\n 3: 'custom',\n },\n tissue_model_type: {\n 0: 'zhl_16c',\n },\n dive_gas_status: {\n 0: 'disabled',\n 1: 'enabled',\n 2: 'backup_only',\n },\n dive_alarm_type: {\n 0: 'depth',\n 1: 'time',\n },\n dive_backlight_mode: {\n 0: 'at_depth',\n 1: 'always_on',\n },\n favero_product: {\n 10: 'assioma_uno',\n 12: 'assioma_duo',\n },\n },\n};\n", "import { FIT } from './fit.js';\nfunction getFieldObject(fieldNum, messageNum) {\n const message = FIT.messages[messageNum];\n if (!message) {\n return {};\n }\n return message[fieldNum] || {};\n}\nfunction getMessageName(messageNum) {\n const message = FIT.messages[messageNum];\n return message ? message.name : '';\n}\nexport function getFitMessage(messageNum) {\n return {\n name: getMessageName(messageNum),\n getAttributes: (fieldNum) => getFieldObject(fieldNum, messageNum),\n };\n}\n// TODO\nexport function getFitMessageBaseType(inp) {\n return inp;\n}\n", "export function mapDataIntoLap(inputLaps, lapKey, data) {\n const laps = [...inputLaps];\n let index = 0;\n for (let i = 0; i < laps.length; i++) {\n const nextLap = laps[i + 1];\n const tempData = [];\n const nextLapStartTime = nextLap\n ? new Date(nextLap.start_time).getTime()\n : null;\n for (let j = index; j < data.length; j++) {\n const row = data[j];\n if (nextLap && nextLapStartTime) {\n const timestamp = new Date(row.timestamp || row.start_time).getTime();\n if (nextLapStartTime > timestamp) {\n tempData.push(row);\n }\n else if (nextLapStartTime <= timestamp) {\n index = j;\n break;\n }\n }\n else {\n tempData.push(row);\n }\n }\n if (!laps[i][lapKey]) {\n laps[i][lapKey] = tempData;\n }\n }\n return laps;\n}\nexport function mapDataIntoSession(inputSessions, laps) {\n const sessions = [...inputSessions];\n let lapIndex = 0;\n for (let i = 0; i < sessions.length; i++) {\n const nextSession = sessions[i + 1];\n const tempLaps = [];\n const nextSessionStartTime = nextSession\n ? new Date(nextSession.start_time).getTime()\n : null;\n for (let j = lapIndex; j < laps.length; j++) {\n const lap = laps[j];\n if (nextSession && nextSessionStartTime) {\n const lapStartTime = new Date(lap.start_time).getTime();\n if (nextSessionStartTime > lapStartTime) {\n tempLaps.push(lap);\n }\n else if (nextSessionStartTime <= lapStartTime) {\n lapIndex = j;\n break;\n }\n }\n else {\n tempLaps.push(lap);\n }\n }\n if (!sessions[i].laps) {\n sessions[i].laps = tempLaps;\n }\n }\n return sessions;\n}\n", "import { calculateCRC, getArrayBuffer, readRecord } from './binary.js';\nimport { mapDataIntoLap, mapDataIntoSession } from './helper.js';\nexport default class FitParser {\n constructor(options = {}) {\n this.options = {\n force: options.force != null ? options.force : true,\n speedUnit: options.speedUnit || 'm/s',\n lengthUnit: options.lengthUnit || 'm',\n temperatureUnit: options.temperatureUnit || 'celsius',\n elapsedRecordField: options.elapsedRecordField || false,\n pressureUnit: options.pressureUnit || 'bar',\n mode: options.mode || 'list',\n };\n }\n parseAsync(content) {\n return new Promise((resolve, reject) => {\n this.parse(content, (error, data) => {\n if (error) {\n reject(error);\n }\n else if (data) {\n resolve(data);\n }\n });\n });\n }\n parse(content, callback) {\n var _a;\n const blob = new Uint8Array(getArrayBuffer(content));\n if (blob.length < 12) {\n callback('File to small to be a FIT file', undefined);\n if (!this.options.force) {\n return;\n }\n }\n const headerLength = blob[0];\n if (headerLength !== 14 && headerLength !== 12) {\n callback('Incorrect header size', undefined);\n if (!this.options.force) {\n return;\n }\n }\n let fileTypeString = '';\n for (let i = 8; i < 12; i++) {\n fileTypeString += String.fromCharCode(blob[i]);\n }\n if (fileTypeString !== '.FIT') {\n callback('Missing \\'.FIT\\' in header', undefined);\n if (!this.options.force) {\n return;\n }\n }\n if (headerLength === 14) {\n const crcHeader = blob[12] + (blob[13] << 8);\n const crcHeaderCalc = calculateCRC(blob, 0, 12);\n if (crcHeader !== crcHeaderCalc) {\n // callback('Header CRC mismatch', {});\n // TODO: fix Header CRC check\n if (!this.options.force) {\n return;\n }\n }\n }\n const protocolVersion = blob[1];\n const profileVersion = blob[2] + (blob[3] << 8);\n const dataLength = blob[4] + (blob[5] << 8) + (blob[6] << 16) + (blob[7] << 24);\n const crcStart = dataLength + headerLength;\n const crcFile = blob[crcStart] + (blob[crcStart + 1] << 8);\n const crcFileCalc = calculateCRC(blob, headerLength === 12 ? 0 : headerLength, crcStart);\n if (crcFile !== crcFileCalc) {\n // callback('File CRC mismatch', {});\n // TODO: fix File CRC check\n if (!this.options.force) {\n return;\n }\n }\n const fitObj = {\n profileVersion,\n protocolVersion,\n };\n let sessions = [];\n let laps = [];\n const records = [];\n const events = [];\n const hr_zone = [];\n const power_zone = [];\n const hrv = [];\n const device_infos = [];\n const applications = [];\n const fieldDescriptions = [];\n const dive_gases = [];\n const course_points = [];\n const sports = [];\n const monitors = [];\n const stress = [];\n const definitions = [];\n const file_ids = [];\n const monitor_info = [];\n const lengths = [];\n const tank_updates = [];\n const tank_summaries = [];\n const jumps = [];\n const time_in_zone = [];\n const activity_metrics = [];\n let loopIndex = headerLength;\n const messageTypes = [];\n const developerFields = [];\n const isModeCascade = this.options.mode === 'cascade';\n const isCascadeNeeded = isModeCascade || this.options.mode === 'both';\n let startDate;\n let lastStopTimestamp;\n let pausedTime = 0;\n while (loopIndex < crcStart) {\n const { nextIndex, messageType, message } = readRecord(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime);\n loopIndex = nextIndex;\n switch (messageType) {\n case 'lap':\n laps.push(message);\n break;\n case 'session':\n sessions.push(message);\n break;\n case 'event':\n if (message.event === 'timer') {\n if (message.event_type === 'stop_all') {\n lastStopTimestamp = message.timestamp;\n }\n else if (message.event_type === 'start' && lastStopTimestamp) {\n pausedTime += (message.timestamp - lastStopTimestamp) / 1000;\n }\n }\n events.push(message);\n break;\n case 'length':\n lengths.push(message);\n break;\n case 'hrv':\n hrv.push(message);\n break;\n case 'hr_zone':\n hr_zone.push(message);\n break;\n case 'power_zone':\n power_zone.push(message);\n break;\n case 'record':\n if (!startDate) {\n startDate = message.timestamp;\n message.elapsed_time = 0;\n message.timer_time = 0;\n }\n records.push(message);\n break;\n case 'field_description':\n fieldDescriptions.push(message);\n break;\n case 'device_info':\n device_infos.push(message);\n break;\n case 'developer_data_id':\n applications.push(message);\n break;\n case 'dive_gas':\n dive_gases.push(message);\n break;\n case 'course_point':\n course_points.push(message);\n break;\n case 'sport':\n sports.push(message);\n break;\n case 'file_id':\n if (message) {\n file_ids.push(message);\n }\n break;\n case 'definition':\n if (message) {\n definitions.push(message);\n }\n break;\n case 'monitoring':\n monitors.push(message);\n break;\n case 'monitoring_info':\n monitor_info.push(message);\n break;\n case 'stress_level':\n stress.push(message);\n break;\n case 'software':\n fitObj.software = message;\n break;\n case 'tank_update':\n tank_updates.push(message);\n break;\n case 'tank_summary':\n tank_summaries.push(message);\n break;\n case 'jump':\n jumps.push(message);\n break;\n case 'time_in_zone':\n time_in_zone.push(message);\n break;\n case 'activity_metrics':\n activity_metrics.push(message);\n break;\n default:\n if (messageType !== '') {\n fitObj[messageType] = message;\n }\n break;\n }\n }\n fitObj.hr_zone = hr_zone;\n fitObj.power_zone = power_zone;\n fitObj.dive_gases = dive_gases;\n fitObj.course_points = course_points;\n fitObj.sports = sports;\n fitObj.monitors = monitors;\n fitObj.stress = stress;\n fitObj.file_ids = file_ids;\n fitObj.monitor_info = monitor_info;\n fitObj.definitions = definitions;\n fitObj.tank_updates = tank_updates;\n fitObj.tank_summaries = tank_summaries;\n fitObj.jumps = jumps;\n fitObj.time_in_zone = time_in_zone;\n fitObj.activity_metrics = activity_metrics;\n if (isCascadeNeeded) {\n laps = mapDataIntoLap(laps, 'records', records);\n laps = mapDataIntoLap(laps, 'lengths', lengths);\n sessions = mapDataIntoSession(sessions, laps);\n fitObj.activity = Object.assign(Object.assign({}, ((_a = fitObj.activity) !== null && _a !== void 0 ? _a : {})), { // ugly but we assume the activity was parsed correctly with all other members correctly\n sessions,\n events,\n hrv,\n device_infos, developer_data_ids: applications, field_descriptions: fieldDescriptions, sports });\n }\n if (!isModeCascade) {\n fitObj.sessions = sessions;\n fitObj.laps = laps;\n fitObj.lengths = lengths;\n fitObj.records = records;\n fitObj.events = events;\n fitObj.device_infos = device_infos;\n fitObj.developer_data_ids = applications;\n fitObj.field_descriptions = fieldDescriptions;\n fitObj.hrv = hrv;\n }\n callback(undefined, fitObj);\n }\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport FitParser from 'fit-file-parser';\nexport default FitParser;\n"], + "mappings": "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AO,QACX,EACA,GAAI,CACA,MAAO,aACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,QACX,EACA,GAAI,CACA,MAAO,iBACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,KACX,EACA,GAAI,CACA,MAAO,iBACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,KACX,EACA,GAAI,CACA,MAAO,2BACP,KAAM,SACN,MAAO,GACP,OAAQ,EACR,MAAO,IACX,EACA,GAAI,CACA,MAAO,0BACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,SACX,EACA,GAAI,CACA,MAAO,kBACP,KAAM,SACN,MAAO,GACP,OAAQ,EACR,MAAO,IACX,EACA,GAAI,CACA,MAAO,yBACP,KAAM,QACN,MAAO,IACP,OAAQ,EACR,MAAO,KACX,EACA,GAAI,CACA,MAAO,yBACP,KAAM,QACN,MAAO,IACP,OAAQ,EACR,MAAO,KACX,EACA,GAAI,CACA,MAAO,0BACP,KAAM,QACN,MAAO,IACP,OAAQ,EACR,MAAO,QACX,EACA,GAAI,CACA,MAAO,4BACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,MACX,EACA,GAAI,CACA,MAAO,4BACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,MACX,EACA,GAAI,CACA,MAAO,4BACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,MACX,EACA,GAAI,CACA,MAAO,mCACP,KAAM,SACN,MAAO,GACP,OAAQ,EACR,MAAO,GACX,EACA,GAAI,CACA,MAAO,mCACP,KAAM,SACN,MAAO,GACP,OAAQ,EACR,MAAO,GACX,EACA,IAAK,CACD,MAAO,mCACP,KAAM,SACN,MAAO,GACP,OAAQ,EACR,MAAO,GACX,EACA,IAAK,CACD,MAAO,gCACP,KAAM,QACN,MAAO,EACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,iCACP,KAAM,QACN,MAAO,EACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,4BACP,KAAM,QACN,MAAO,EACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,6BACP,KAAM,QACN,MAAO,EACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,gCACP,KAAM,QACN,MAAO,EACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,cACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,IAAK,CACD,MAAO,gBACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,GACX,EACA,IAAK,CACD,MAAO,cACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,IAAK,CACD,MAAO,eACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,IACX,EACA,IAAK,CACD,MAAO,gBACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,IACX,EACA,IAAK,CACD,MAAO,uBACP,KAAM,QACN,MAAO,SACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,4BACP,KAAM,QACN,MAAO,SACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,wBACP,KAAM,QACN,MAAO,SACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,6BACP,KAAM,QACN,MAAO,SACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,qBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,OACX,EACA,IAAK,CACD,MAAO,qBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,OACX,EACA,IAAK,CACD,MAAO,uBACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,KACX,EACA,IAAK,CACD,MAAO,uBACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,KACX,EACA,IAAK,CACD,MAAO,qBACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,KACX,EACA,IAAK,CACD,MAAO,qBACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,KACX,EACA,IAAK,CACD,MAAO,wBACP,KAAM,SACN,MAAO,EACP,OAAQ,KACR,MAAO,GACX,EACA,IAAK,CACD,MAAO,wBACP,KAAM,SACN,MAAO,EACP,OAAQ,KACR,MAAO,GACX,EACA,IAAK,CACD,MAAO,wBACP,KAAM,SACN,MAAO,EACP,OAAQ,KACR,MAAO,GACX,EACA,IAAK,CACD,MAAO,sBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,OACX,EACA,IAAK,CACD,MAAO,sBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,OACX,EACA,IAAK,CACD,MAAO,0BACP,KAAM,QACN,MAAO,EACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,qBACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,0BACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,kBACP,KAAM,SACN,MAAO,GACP,OAAQ,EACR,MAAO,IACX,EACA,IAAK,CACD,MAAO,kCACP,KAAM,QACN,MAAO,GACP,OAAQ,EACR,MAAO,EACX,EACA,IAAK,CACD,MAAO,UACP,KAAM,SACN,MAAO,EACP,OAAQ,EACR,MAAO,KACX,EACA,IAAK,CACD,MAAO,eACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,IAAK,CACD,MAAO,cACP,KAAM,QACN,MAAO,GACP,OAAQ,EACR,MAAO,EACX,EACA,IAAK,CACD,MAAO,qBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,IAAK,CACD,MAAO,qBACP,KAAM,SACN,MAAO,EACP,OAAQ,EACR,MAAO,EACX,EACA,IAAK,CACD,MAAO,gCACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,aACX,EACA,IAAK,CACD,MAAO,kBACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,GACX,EACA,IAAK,CACD,MAAO,gCACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,aACX,EACA,IAAK,CACD,MAAO,iBACP,KAAM,SACN,MAAO,EACP,OAAQ,EACR,MAAO,IACX,EACA,IAAK,CACD,MAAO,gCACP,KAAM,SACN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AQ,KACR,MAAO,GACX,EACA,IAAK,CACD,MAAO,sBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,OACX,EACA,IAAK,CACD,MAAO,sBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,OACX,EACA,IAAK,CACD,MAAO,0BACP,KAAM,QACN,MAAO,EACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,qBACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,0BACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,SACX,EACA,IAAK,CACD,MAAO,kBACP,KAAM,SACN,MAAO,GACP,OAAQ,EACR,MAAO,IACX,EACA,IAAK,CACD,MAAO,UACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,KACX,CACJ,EACA,GAAI,CACA,KAAM,SACN,IAAK,CACD,MAAO,YACP,KAAM,YACN,MAAO,KACP,OAAQ,EACR,MAAO,GACX,EACA,IAAK,CACD,MAAO,OACP,KAAM,UACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,IAAK,CACD,MAAO,OACP,KAAM,UACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,EAAG,CACC,MAAO,eACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,aACX,EACA,EAAG,CACC,MAAO,gBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,aACX,EACA,EAAG,CACC,MAAO,WACP,KAAM,SACN,MAAO,EACP,OAAQ,KACR,MAAO,GACX,EACA,EAAG,CACC,MAAO,aACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,KACX,EACA,EAAG,CACC,MAAO,UACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,KACX,EACA,EAAG,CACC,MAAO,WACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,GACX,EACA,EAAG,CACC,MAAO,QACP,KAAM,SACN,MAAO,IACP,OAAQ,EACR,MAAO,KACX,EACA,EAAG,CACC,MAAO,QACP,KAAM,SACN,MAAO,KACP,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CACC,MAAO,gBACP,KAAM,gBACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,EAAG,CACC,MAAO,mBACP,KAAM,mBACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,EAAG,CACC,MAAO,iBACP,KAAM,iBACN,MAAO,KACP,OAAQ,EACR,MAAO,GACX,EACA,EAAG,CACC,MAAO,aACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,GACX,EACA,EAAG,CACC,MAAO,WACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,QACX,EACA,GAAI,CACA,MAAO,gBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,kBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,cACP,KAAM,UACN,MAAO,KACP,OAAQ,EACR,MAAO,GACX,EACA,GAAI,CACA,MAAO,kBACP,KAAM,UACN,MAAO,KACP,OAAQ,EACR,MAAO,GACX,EACA,GAAI,CACA,MAAO,kBACP,KAAM,UACN,MAAO,KACP,OAAQ,EACR,MAAO,GACX,EACA,GAAI,CACA,MAAO,gBACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,kBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,MACX,EACA,GAAI,CACA,MAAO,kCACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,iBACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,cACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,aACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,KACX,EACA,GAAI,CACA,MAAO,YACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,eACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,WACP,K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AAO,SACX,EACA,EAAG,CACC,MAAO,eACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,SACX,EACA,EAAG,CACC,MAAO,WACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,SACX,EACA,EAAG,CACC,MAAO,sBACP,KAAM,OACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,eACP,KAAM,UACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,cACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,0BACP,KAAM,OACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,uBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,iBACP,KAAM,sBACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,uBACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,oBACP,KAAM,oBACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,mBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,GACX,EACA,GAAI,CACA,MAAO,mBACP,KAAM,SACN,MAAO,KACP,OAAQ,EACR,MAAO,GACX,EACA,GAAI,CACA,MAAO,yBACP,KAAM,cACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,GAAI,CACA,MAAO,oBACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,CACJ,EACA,IAAK,CACD,KAAM,WACN,IAAK,CACD,MAAO,gBACP,KAAM,gBACN,MAAO,KACP,OAAQ,EACR,MAAO,EACX,EACA,EAAG,CACC,MAAO,iBACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,SACX,EACA,EAAG,CACC,MAAO,iBACP,KAAM,QACN,MAAO,KACP,OAAQ,EACR,MAAO,SACX,EACA,EAAG,CACC,MAAO,SACP,KAAM,kBACN,MAAO,KACP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IAAK,eACL,IAAK,iBACL,IAAK,iBACL,IAAK,kBACL,IAAK,iBACL,IAAK,QACL,IAAK,MACL,IAAK,eACL,IAAK,aACL,IAAK,kBACL,IAAK,WACL,IAAK,YACL,IAAK,WACL,IAAK,QACL,IAAK,UACL,IAAK,YACL,KAAM,eACV,EACA,eAAgB,CACZ,EAAG,WACH,EAAG,OACH,EAAG,QACH,EAAG,QACH,EAAG,QACH,EAAG,SACH,EAAG,YACH,EAAG,SACH,EAAG,iCACH,EAAG,MACH,GAAI,MACJ,GAAI,QACJ,GAAI,iCACJ,GAAI,+BACJ,IAAK,cACL,IAAK,cACL,IAAK,cACL,IAAK,eACL,IAAK,QACL,IAAK,OACL,IAAK,cACL,IAAK,OACL,KAAM,YACN,KAAM,UACN,KAAM,UACN,KAAM,QACN,KAAM,UACN,KAAM,iBACN,KAAM,gBACN,KAAM,QACN,KAAM,cACN,KAAM,UACN,KAAM,UACN,KAAM,iBACN,KAAM,gBACN,KAAM,QACN,KAAM,QACN,KAAM,cACN,KAAM,YACN,KAAM,YACN,KAAM,gBACN,KAAM,gBACN,KAAM,cACN,KAAM,gBACN,KAAM,OACN,KAAM,aACN,KAAM,MACN,KAAM,OACN,KAAM,gBACN,KAAM,OACN,KAAM,gBACN,KAAM,QACN,KAAM,iBACN,KAAM,UACN,KAAM,UACN,KAAM,QACN,KAAM,gBACN,KAAM,QACN,KAAM,QACN,KAAM,gBACN,KAAM,aACN,KAAM,gBACN,KAAM,aACN,KAAM,eACN,KAAM,gBACN,KAAM,UACN,KAAM,UACN,KAAM,UACN,KAAM,eACN,KAAM,gBACN,KAAM,iBACN,KAAM,WACN,KAAM,WACN,KAAM,cACN,KAAM,UACN,KAAM,OACN,KAAM,cACN,KAAM,gBACN,KAAM,cACN,KAAM,cACN,KAAM,cACN,KAAM,cACN,KAAM,cACN,KAAM,aACN,KAAM,SACN,KAAM,OACN,KAAM,SACN,KAAM,kBACN,KAAM,iBACN,KAAM,aACN,KAAM,UACN,KAAM,iBACN,KAAM,eACN,KAAM,eACN,KAAM,WACN,KAAM,iBACN,KAAM,iBACN,KAAM,gBACN,KAA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AG,MACH,EAAG,KACH,EAAG,OACH,EAAG,QACH,GAAI,aACR,EACA,sBAAuB,CACnB,EAAG,gBACH,EAAG,aACH,EAAG,YACP,EACA,uBAAwB,CACpB,EAAG,UACH,EAAG,WACP,EACA,YAAa,CACT,EAAG,MACH,EAAG,UACH,EAAG,YACH,EAAG,uBACH,EAAG,OACH,EAAG,OACP,EACA,oBAAqB,CACjB,EAAG,OACH,EAAG,WACH,EAAG,YACH,EAAG,mBACH,EAAG,mBACP,EACA,kBAAmB,CACf,EAAG,OACH,EAAG,YACH,EAAG,iBACH,EAAG,eACH,EAAG,iBACH,EAAG,cACP,EACA,eAAgB,CACZ,EAAG,UACH,EAAG,SACH,EAAG,aACH,EAAG,UACP,EACA,yBAA0B,CACtB,EAAG,cACH,EAAG,SACH,EAAG,MACP,EACA,wBAAyB,CACrB,EAAG,UACH,EAAG,cACH,EAAG,QACP,EACA,oBAAqB,CACjB,EAAG,SACH,EAAG,WACH,EAAG,uBACH,EAAG,wBACP,EACA,iBAAkB,CACd,EAAG,0BACH,EAAG,wBACH,EAAG,yBACH,EAAG,oBACP,EACA,kBAAmB,CACf,EAAG,cACH,EAAG,cACH,EAAG,YACH,EAAG,cACH,EAAG,4BACH,EAAG,4BACH,EAAG,0BACH,EAAG,oBACH,EAAG,kCACH,GAAI,cACJ,GAAI,4BACJ,GAAI,eACJ,GAAI,4BACR,EACA,YAAa,CACT,EAAG,gBACH,EAAG,YACH,EAAG,UACH,EAAG,WACP,EACA,+BAAgC,CAC5B,EAAG,OACH,EAAG,aACH,EAAG,kBACH,EAAG,OACP,EACA,kBAAmB,CACf,EAAG,2BACH,EAAG,kBACH,EAAG,kBACH,EAAG,oBACP,EACA,wBAAyB,CACrB,EAAG,uBACH,EAAG,wBACH,EAAG,yBACH,EAAG,wBACP,EACA,eAAgB,CACZ,EAAG,SACH,EAAG,WACH,EAAG,WACH,EAAG,OACP,EACA,kBAAmB,CACf,EAAG,EACH,EAAG,4BACH,EAAG,cACH,EAAG,aACH,EAAG,2BACH,GAAI,0BACJ,GAAI,kBACJ,GAAI,UACJ,IAAK,cACL,IAAK,SAC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", + "names": ["require_base64_js", "__commonJSMin", "exports", "byteLength", "toByteArray", "fromByteArray", "lookup", "revLookup", "Arr", "code", "i", "len", "getLens", "b64", "validLen", "placeHoldersLen", "lens", "_byteLength", "tmp", "arr", "curByte", "tripletToBase64", "num", "encodeChunk", "uint8", "start", "end", "output", "extraBytes", "parts", "maxChunkLength", "len2", "require_ieee754", "__commonJSMin", "exports", "buffer", "offset", "isLE", "mLen", "nBytes", "e", "m", "eLen", "eMax", "eBias", "nBits", "i", "d", "s", "value", "c", "rt", "require_buffer", "__commonJSMin", "exports", "base64", "ieee754", "customInspectSymbol", "Buffer", "SlowBuffer", "K_MAX_LENGTH", "typedArraySupport", "arr", "proto", "createBuffer", "length", "buf", "arg", "encodingOrOffset", "allocUnsafe", "from", "value", "fromString", "fromArrayView", "isInstance", "fromArrayBuffer", "valueOf", "b", "fromObject", "assertSize", "size", "alloc", "fill", "encoding", "checked", "string", "byteLength", "actual", "fromArrayLike", "array", "i", "arrayView", "copy", "byteOffset", "obj", "len", "numberIsNaN", "a", "x", "y", "list", "buffer", "pos", "mustMatch", "loweredCase", "utf8ToBytes", "base64ToBytes", "slowToString", "start", "end", "hexSlice", "utf8Slice", "asciiSlice", "latin1Slice", "base64Slice", "utf16leSlice", "swap", "n", "m", "str", "max", "target", "thisStart", "thisEnd", "thisCopy", "targetCopy", "bidirectionalIndexOf", "val", "dir", "arrayIndexOf", "indexSize", "arrLength", "valLength", "read", "foundIndex", "found", "j", "hexWrite", "offset", "remaining", "strLen", "parsed", "utf8Write", "blitBuffer", "asciiWrite", "asciiToBytes", "base64Write", "ucs2Write", "utf16leToBytes", "res", "firstByte", "codePoint", "bytesPerSequence", "secondByte", "thirdByte", "fourthByte", "tempCodePoint", "decodeCodePointsArray", "MAX_ARGUMENTS_LENGTH", "codePoints", "ret", "out", "hexSliceLookupTable", "bytes", "newBuf", "checkOffset", "ext", "noAssert", "mul", "defineBigIntMethod", "validateNumber", "first", "last", "boundsError", "lo", "hi", "checkInt", "min", "maxBytes", "wrtBigUInt64LE", "checkIntBI", "wrtBigUInt64BE", "limit", "sub", "checkIEEE754", "writeFloat", "littleEndian", "writeDouble", "targetStart", "code", "errors", "E", "sym", "getMessage", "Base", "name", "range", "input", "msg", "received", "addNumericalSeparator", "checkBounds", "type", "INVALID_BASE64_RE", "base64clean", "units", "leadSurrogate", "byteArray", "c", "src", "dst", "alphabet", "table", "i16", "fn", "BufferBigIntNotDefined", "import_buffer", "psiInOneBar", "FIT", "getFieldObject", "fieldNum", "messageNum", "message", "FIT", "getMessageName", "getFitMessage", "CompressedLocalMsgNumMask", "CompressedHeaderMask", "GarminTimeOffset", "monitoring_timestamp", "addEndian", "littleEndian", "bytes", "result", "i", "readData", "blob", "fDef", "startIndex", "options", "array8", "temp", "buffer", "dataView", "array32", "array16", "e", "val", "formatByType", "data", "type", "scale", "offset", "FIT", "baseType", "dataItem", "isInvalidValue", "values", "key", "mapped", "convertTo", "unitsList", "unitName", "unit", "applyOptions", "field", "fields", "isLocal", "isBLE", "isANT", "n1", "n2", "n3", "n4", "readRecord", "messageTypes", "developerFields", "startDate", "pausedTime", "recordHeader", "localMessageType", "hasDeveloperData", "lEnd", "numberOfFields", "numberOfDeveloperDataFields", "mTypeDef", "message", "getFitMessage", "fDefIndex", "fieldNum", "size", "devDataIndex", "devDef", "nextIndex", "nextIndexWithDeveloperData", "messageType", "messageSize", "readDataFromIndex", "rawFields", "getArrayBuffer", "ab", "view", "calculateCRC", "start", "end", "crcTable", "crc", "byteVal", "tmp", "mapDataIntoLap", "inputLaps", "lapKey", "data", "laps", "index", "i", "nextLap", "tempData", "nextLapStartTime", "j", "row", "timestamp", "mapDataIntoSession", "inputSessions", "sessions", "lapIndex", "nextSession", "tempLaps", "nextSessionStartTime", "lap", "lapStartTime", "FitParser", "options", "content", "resolve", "reject", "error", "data", "callback", "_a", "blob", "getArrayBuffer", "headerLength", "fileTypeString", "i", "crcHeader", "crcHeaderCalc", "calculateCRC", "protocolVersion", "profileVersion", "crcStart", "crcFile", "crcFileCalc", "fitObj", "sessions", "laps", "records", "events", "hr_zone", "power_zone", "hrv", "device_infos", "applications", "fieldDescriptions", "dive_gases", "course_points", "sports", "monitors", "stress", "definitions", "file_ids", "monitor_info", "lengths", "tank_updates", "tank_summaries", "jumps", "time_in_zone", "activity_metrics", "loopIndex", "messageTypes", "developerFields", "isModeCascade", "isCascadeNeeded", "startDate", "lastStopTimestamp", "pausedTime", "nextIndex", "messageType", "message", "readRecord", "mapDataIntoLap", "mapDataIntoSession", "vendor_fit_default", "FitParser"] +} diff --git a/suites-experimental/tools-gps-tracks/dist/index.html b/suites-experimental/tools-gps-tracks/dist/index.html new file mode 100644 index 0000000000..883ffbaddf --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/index.html @@ -0,0 +1,551 @@ + + + + + + Weg — GPS Analysis + + + + + + + + +
+ + + + + + + + + +
+ + + + + +
+
+ + + + + + +
+ +
+
+
+ + + + + + + + + + + + + +
+ +
+
+ + +
+ + +
+
+ + + +
+
+ no_sim +
Select a track to view analysis
+
+
+
+ +
+
+
+ no_sim +
Select a track for insights
+
+
+
+ +
+
+
+ no_sim +
Select a track for details
+
+
+
+ +
+
+
+ no_sim +
Select a track for combined analysis
+
+
+
+ +
+
+
+ no_sim +
Select a track for progress analysis
+
+
+
+ +
+
+
+ route +
No courses created yet
+
+
+
+
+
+
+ +
+
+
+ + + + diff --git a/suites-experimental/tools-gps-tracks/dist/material_symbols_rounded.woff2 b/suites-experimental/tools-gps-tracks/dist/material_symbols_rounded.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..3dbcf04e581c6d75d4400ef99b2957a1ea3064ee GIT binary patch literal 79944 zcmV(-K-|A~Pew8T0RR910XRqi5&!@I0(6W30XN+M0`1cP00000000000000000000 z0000Sm^eR3RzXsMB?e$WQ&d4zfkY=z0ET=ofou^73W0{T#`v_b(k0we>0a0`KO z00bZfgD?jm3YV)zUL(V?!^BeUkZwsbXbbz7Y81Vd za6mo5hd$-oyD??||9@Ii8Drn8?I0ouViuC7NCBC&O^HD(Nr{g3D7hZBq^

N(%RE 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:middle;display:inline-block}.u-legend .u-marker{width:1em;height:1em;margin-right:4px;background-clip:padding-box!important}.u-inline.u-live th:after{content:":";vertical-align:middle}.u-inline:not(.u-live) .u-value{display:none}.u-series>*{padding:4px}.u-series th{cursor:pointer}.u-legend .u-off>*{opacity:.3}.u-select{background:#00000012;position:absolute;pointer-events:none}.u-cursor-x,.u-cursor-y{position:absolute;left:0;top:0;pointer-events:none;will-change:transform}.u-hz .u-cursor-x,.u-vt .u-cursor-y{height:100%;border-right:1px dashed #607D8B}.u-hz .u-cursor-y,.u-vt .u-cursor-x{width:100%;border-bottom:1px dashed #607D8B}.u-cursor-pt{position:absolute;top:0;left:0;border-radius:50%;border:0 solid;pointer-events:none;will-change:transform;background-clip:padding-box!important}.u-axis.u-off,.u-select.u-off,.u-cursor-x.u-off,.u-cursor-y.u-off,.u-cursor-pt.u-off{display:none}@font-face{font-family:Material Symbols Rounded;font-style:normal;font-weight:100 700;src:url("./material_symbols_rounded.woff2") format("woff2")}:root{--bg: #0e0e10;--surface: #18181b;--surface2: #222226;--border: #2e2e34;--border2: #3a3a42;--text: #e8e8ec;--text-muted: #888896;--text-dim: #555564;--theme-color: #3b82f6;--accent: var(--theme-color);--accent-hover: color-mix(in srgb, var(--theme-color) 80%, white);--danger: #ef4444;--sidebar-w: 230px;--fs-s: 10px;--fs-m: 12px;--fs-l: 14px;--is-s: 16px;--is-m: 20px;--handle-color: #3b82f6}.font-s{font-size:10px}.font-m{font-size:12px}.font-l{font-size:14px}*{box-sizing:border-box}body,html{margin:0;padding:0;width:100%;height:100%;background:var(--bg);color:var(--text);font-family:system-ui,-apple-system,sans-serif;font-size:var(--fs-m)}body{opacity:1}body.loading-fonts{opacity:0}button{font-family:inherit;cursor:pointer;font-size:var(--fs-m)}.material-symbols-rounded{font-family:Material Symbols Rounded;font-weight:400;font-style:normal;font-size:var(--is-m);line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-smoothing:antialiased;font-variation-settings:"FILL" 0,"wght" 400,"GRAD" 0,"opsz" 24}#app{display:flex;width:100vw;height:100vh;overflow:hidden}.hidden{display:none!important}#global-loader{position:fixed;inset:0;background:#000000b3;z-index:10000;display:flex;align-items:center;justify-content:center}.loader-box{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:0;display:flex;flex-direction:row;align-items:stretch;color:var(--text);font-weight:700;box-shadow:0 4px 20px #00000080;max-width:450px;width:90%;overflow:hidden;position:relative}#loader-close{position:absolute;top:12px;right:12px;background:none;border:none;color:var(--text-muted);cursor:pointer;padding:4px;border-radius:50%;display:flex;align-items:center;justify-content:center}#loader-close:hover{background:var(--surface2);color:var(--text)}.loader-icon-wrap{background:color-mix(in srgb,var(--accent) 10%,transparent);display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px;border-right:1px solid var(--border);gap:8px}.loader-icon-wrap>span{font-size:var(--fs-l);color:var(--accent)}#loader-warning-count{font-size:var(--fs-m);color:#f59e0b;font-weight:700;display:none;align-items:center;gap:4px}.loader-content{padding:24px;flex:1;display:flex;flex-direction:column;gap:12px;justify-content:center}#loader-text{font-size:var(--fs-l);font-weight:700;color:var(--text)}#loader-filename{font-size:var(--fs-m);color:var(--text-muted);font-weight:400;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:300px}#loader-progress-wrap{width:300px;height:4px;background:var(--surface2);border-radius:2px;margin-top:4px;overflow:hidden}#loader-subtext{font-size:var(--fs-m);color:var(--text-muted);font-weight:400;display:flex;align-items:center;justify-content:space-between;width:300px;margin-top:0}.progress-index{text-align:left}.progress-total{text-align:right}#loader-progress-bar{width:0%;height:100%;background:var(--accent)}#sidebar{width:var(--sidebar-w);flex-shrink:0;display:flex;flex-direction:column;background:var(--surface);border-right:1px solid var(--border);z-index:10}#sidebar-header{padding:16px 12px;border-bottom:1px solid var(--border)}.logo{display:flex;align-items:center;gap:10px}.logo-icon{color:var(--accent);font-size:var(--fs-l)}.logo-title{font-weight:800;font-size:var(--fs-l);letter-spacing:-.5px}.logo-sub{font-size:var(--fs-s);text-transform:uppercase;color:var(--text-dim);font-weight:700;letter-spacing:1px;margin-top:-2px}#drop-zone{margin:12px;padding:20px 12px;border:2px dashed var(--border2);border-radius:12px;display:flex;flex-direction:column;align-items:center;text-align:center;position:relative}#drop-zone.drop-active{border-color:var(--accent);background:color-mix(in srgb,var(--theme-color) 5%,transparent)}.drop-icon{font-size:var(--is-m);color:var(--text-muted);margin-bottom:4px}.drop-primary{font-size:var(--fs-m);font-weight:600;color:var(--text)}.drop-formats{display:flex;justify-content:center;gap:6px;margin-top:8px}.drop-formats .badge{background:var(--surface2);color:var(--text-dim);font-size:var(--fs-s);padding:2px 6px}.drop-browse-container{margin-top:12px;font-size:var(--fs-s);color:var(--text-muted);display:flex;align-items:center;justify-content:center;gap:2px}.drop-browse{color:var(--accent);font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:4px}.drop-browse .material-symbols-rounded{font-size:var(--fs-l)}.drop-browse:hover{color:var(--accent-hover)}.drop-separator{margin:0 6px;color:var(--border2);vertical-align:middle}#track-list-header{display:flex;align-items:center;justify-content:space-between;padding:12px 12px 8px}.section-label{font-size:var(--fs-s);font-weight:700;text-transform:uppercase;color:var(--text-dim);letter-spacing:.5px}.header-actions{display:flex;gap:0}#track-controls,#sort-controls{padding:8px 12px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--border)}.search-bar{display:flex;background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:2px 4px;align-items:center}.search-icon{font-size:var(--is-s);color:var(--text-dim);margin-left:4px}.search-bar input{flex:1;background:transparent;border:none;padding:4px 6px;color:var(--text);font-size:var(--fs-m)}.search-bar input:focus{outline:none}.icon-btn.mini{width:20px;height:20px;color:var(--text-dim)}.icon-btn.mini .material-symbols-rounded{font-size:var(--is-s)}.icon-btn.mini.active{color:var(--accent)}.sort-ctrl{display:flex;align-items:center;gap:8px}.sort-ctrl label{font-size:var(--fs-s);color:var(--text-dim);text-transform:uppercase;font-weight:600}.sort-select-btn{display:flex;align-items:center;gap:6px;background:var(--surface2);border:1px solid var(--border);padding:4px 8px;border-radius:6px;flex:1;height:24px;box-sizing:border-box;font-size:var(--fs-s);color:var(--text-muted)}.sort-select-btn:hover{border-color:var(--accent);color:var(--text)}.sort-select-btn .material-symbols-rounded{font-size:var(--is-s)}.sort-select-btn .arrow{font-size:var(--fs-l);margin-left:auto;opacity:.5}#filter-panel{padding:12px;background:var(--surface2);border-bottom:1px solid var(--border);display:flex;flex-direction:column;gap:12px}#filter-panel.hidden{display:none}.filter-group{display:flex;flex-direction:column;gap:4px}.filter-group label{font-size:var(--fs-s);font-weight:600;text-transform:uppercase;color:var(--text-dim);display:flex;align-items:center;gap:6px}.filter-group label .material-symbols-rounded{font-size:var(--is-s);opacity:.7}.filter-metrics-grid{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}.mini-pill{width:28px;height:28px;display:flex;align-items:center;justify-content:center;background:var(--surface);border:1px solid var(--border);border-radius:6px;color:var(--text-dim);cursor:pointer}.mini-pill:hover{border-color:var(--text-muted);color:var(--text-muted)}.mini-pill.active{background:var(--accent);border-color:var(--accent);color:#fff}.mini-pill .material-symbols-rounded{font-size:var(--is-s)}.filter-row{display:flex;align-items:center;gap:6px}.filter-row input{flex:1;background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:4px 6px;color:var(--text);font-size:var(--fs-s)}.filter-row span{font-size:var(--fs-s);color:var(--text-dim)}#filter-panel input:focus{border-color:var(--accent);outline:none}.filter-footer{display:flex;justify-content:flex-end;margin-top:4px}#track-list{flex:1;overflow-y:auto;padding:4px 0;scrollbar-width:none}#track-list::-webkit-scrollbar{width:0;height:0;display:none}#track-list::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}#track-list-empty{padding:40px 20px;text-align:center;color:var(--text-dim);font-size:var(--fs-m)}.track-item{display:flex;align-items:center;padding:6px 8px;gap:0;cursor:pointer;border-left:3px solid transparent}.track-item:hover{background:#ffffff08}.track-item.selected{background:color-mix(in srgb,var(--theme-color) 8%,transparent);border-left-color:var(--accent)}.track-color{width:3px;border-radius:1px;flex-shrink:0;margin-right:8px;align-self:stretch}.track-info{flex:1;min-width:0;margin-right:2px}.track-name{font-size:var(--fs-m);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:1px}.track-meta{font-size:var(--fs-s);color:var(--text-dim);display:flex;gap:6px;align-items:center}.track-item .icon-btn.mini{width:22px;height:22px;padding:0;margin:0}.badge{font-size:var(--fs-s);background:var(--surface2);padding:1px 4px;border-radius:3px;font-weight:700;color:var(--text-muted)}.track-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px;overflow:hidden;max-height:32px}.track-tag{font-size:var(--fs-s);font-weight:700;color:var(--text-dim);background:#ffffff08;border:1px solid var(--border);padding:1px 5px;border-radius:3px;white-space:nowrap}.track-item.selected .track-tag{border-color:#ffffff1a;color:var(--text-muted)}#sidebar-resizer{width:4px;cursor:col-resize;background:transparent;flex-shrink:0;z-index:1000;margin-left:-2px;margin-right:-2px;user-select:none}#sidebar-resizer:hover,#sidebar-resizer.dragging{background:var(--handle-color)}body.dragging-sidebar{user-select:none;cursor:col-resize!important}#main{flex:1;display:flex;flex-direction:column;min-width:0}#map-container{flex:1;position:relative;min-height:100px}#map-container.editing-mode{border:4px solid var(--accent);box-shadow:0 0 15px var(--accent);z-index:1000}#map{width:100%;height:100%;background:var(--bg)}#map-controls{position:absolute;top:12px;left:12px;z-index:1000;display:flex;align-items:center;gap:8px}#basemap-switcher{display:flex;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:2px;height:24px;box-sizing:border-box;box-shadow:0 4px 12px #0000004d;align-items:center;gap:0}#selected-extra-map{font-size:var(--fs-s);font-weight:700;color:var(--accent);padding:0 6px;max-width:120px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}#selected-extra-map.hidden{display:none}#btn-extra-layers{border:none!important;border-left:1px solid var(--border)!important;border-radius:0!important;margin-left:0!important;padding-left:6px!important;padding-right:0!important;width:auto!important;height:100%!important;background:transparent!important}#extra-layers-menu{position:absolute;top:40px;right:0;background:var(--surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 20px #00000080;max-height:300px;overflow-y:auto;width:200px;z-index:1000;padding:4px}#extra-layers-menu.hidden{display:none}.extra-layers-header{font-size:var(--fs-s);font-weight:700;color:var(--text-dim);text-transform:uppercase;padding:6px 8px;border-bottom:1px solid var(--border);margin-bottom:4px}.extra-layers-search{padding:4px 8px;border-bottom:1px solid var(--border);margin-bottom:4px}#extra-layers-search-input{width:100%;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:var(--fs-s);padding:4px 8px;outline:none}#extra-layers-search-input:focus{border-color:var(--accent)}.extra-layers-license{font-size:var(--fs-s);color:var(--text-dim);padding:4px 8px;border-bottom:1px solid var(--border);margin-bottom:4px}.extra-layers-license a{color:var(--accent);text-decoration:none}.extra-layers-license a:hover{text-decoration:underline}.extra-layer-row{margin-bottom:2px}.extra-layer-item{display:block;width:100%;text-align:left;background:transparent;border:none;color:var(--text-muted);padding:4px 10px 2px;font-size:var(--fs-s);font-weight:600;border-radius:4px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.extra-layer-item:hover{background:var(--surface2);color:var(--text)}.extra-layer-attribution{font-size:var(--fs-s);color:var(--text-dim);padding:0 10px 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#map-loader{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:0 10px;height:24px;box-sizing:border-box;display:flex;align-items:center;gap:8px;font-size:var(--fs-s);font-weight:600;color:var(--text-muted);box-shadow:0 4px 12px #0000004d}.spinner-sm{width:12px;height:12px;border:2px solid var(--surface2);border-top-color:var(--accent);border-radius:50%}.bm-btn{background:transparent;border:none;color:var(--text-muted);padding:2px 6px;font-size:var(--fs-s);font-weight:600;border-radius:6px}.bm-btn:hover{color:var(--text)}.bm-btn.active{background:var(--surface2);color:var(--accent)}.map-cursor-dot{pointer-events:none}.dot-inner{width:12px;height:12px;background:#fff;border:2px solid #000;border-radius:50%;box-shadow:0 0 0 2px #ffffff80}#map-cursor-info{position:absolute;top:12px;right:12px;z-index:1000;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-size:var(--fs-s);color:var(--text);box-shadow:0 4px 12px #0000004d;display:none;pointer-events:none}#resize-handle{height:6px;background:var(--bg);border-top:1px solid var(--border);border-bottom:1px solid var(--border);cursor:ns-resize;display:flex;align-items:center;justify-content:center;flex-shrink:0;z-index:100}#resize-handle:hover{background:var(--handle-color)}.handle-grip{width:32px;height:2px;background:var(--border2);border-radius:1px}#chart-panel{display:flex;flex-direction:column;background:var(--surface);overflow:hidden;flex:1;width:100%;height:100%;min-height:0}#tab-nav{display:flex;padding:0 12px;border-bottom:1px solid var(--border);gap:4px}.tab-btn{background:transparent;border:none;border-bottom:2px solid transparent;color:var(--text-dim);padding:10px 12px;font-size:var(--fs-m);font-weight:700;display:flex;align-items:center;gap:6px}.tab-btn:hover{color:var(--text-muted)}.tab-btn.active{color:var(--accent);border-bottom-color:var(--accent)}.tab-btn .material-symbols-rounded{font-size:var(--is-s)}.tab-content{display:none;flex:1;min-height:0}.tab-content.active{display:flex;flex-direction:column;overflow-y:auto;scrollbar-width:none}.tab-content.active::-webkit-scrollbar{width:0;height:0}.tab-content.active::-webkit-scrollbar-track{background:transparent}.tab-content.active::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}.tab-content.active::-webkit-scrollbar-thumb:hover{background:var(--text-dim)}#chart-toolbar{display:flex;align-items:center;padding:6px 12px;gap:12px;border-bottom:1px solid var(--border);background:var(--bg);min-height:40px;position:sticky;top:0;z-index:100}.icon-btn{background:transparent;border:1px solid transparent;color:var(--text-muted);width:24px;height:24px;border-radius:6px;display:flex;align-items:center;justify-content:center}.icon-btn.hidden{display:none}.icon-btn:hover{background:var(--surface2);color:var(--text)}.icon-btn.active{background:var(--surface2);color:var(--accent)}.icon-btn.danger:hover{background:#ef44441f;color:var(--danger)}.icon-btn .material-symbols-rounded{font-size:var(--fs-l)}#btn-metric-menu{flex:0 0 auto}#metric-pills{display:flex;gap:6px;flex:1;overflow:hidden}.metric-pill:not(.active){display:none}.metric-pill.overflow-hidden{display:none!important}#pill-overflow{color:var(--text-muted);font-weight:700;padding:0 4px;align-self:flex-end}.metric-pill{height:24px;padding:0 8px;border-radius:12px;border:1px solid var(--border);background:var(--surface2);color:var(--text-muted);font-size:var(--fs-s);font-weight:500;display:flex;align-items:center;gap:4px;white-space:nowrap}.metric-pill .material-symbols-rounded{font-size:var(--fs-m)}.metric-pill.active{background:color-mix(in srgb,var(--pill-color) 15%,var(--surface2));border-color:var(--pill-color);color:var(--pill-color)}.metric-pill.disabled{opacity:.3;filter:grayscale(1);cursor:default}#chart-options{display:flex;align-items:center;gap:0;margin-left:auto}.seg-ctrl{display:flex;background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:2px;height:24px;box-sizing:border-box}.seg-btn{background:transparent;border:none;color:var(--text-dim);padding:0 8px;font-size:var(--fs-s);font-weight:700;border-radius:4px;display:flex;align-items:center;gap:6px;height:100%}.seg-btn .material-symbols-rounded{font-size:var(--fs-m)}.seg-btn.active{background:var(--bg);color:var(--text);box-shadow:0 1px 3px #0003}#chart-stats{padding:4px 14px;border-bottom:1px solid var(--border);background:var(--surface2)}#chart-stats.hidden{display:none}#chart-stats-wrap{display:flex;flex-direction:column;gap:2px}.stats-row{display:flex;align-items:center;gap:16px}.stats-row-label{width:45px;font-size:var(--fs-s);font-weight:700;text-transform:uppercase;letter-spacing:.8px;color:var(--text-muted);white-space:nowrap}.chart-row-stats-container{display:flex;flex:1;align-items:center;justify-content:space-between}.chart-row-right-actions{width:130px;display:none;align-items:center;justify-content:flex-end;flex-shrink:0}.with-histogram .chart-row-right-actions{display:flex}.chart-stats-total,.chart-stats-selection{display:flex;gap:10px;font-size:var(--fs-s);color:var(--text-dim);align-items:center;white-space:nowrap;font-weight:500}.chart-stats-selection{margin-left:auto;position:relative}.chart-stats-selection:after{content:"";position:absolute;bottom:-6px;left:0;right:0;height:2px;background-color:var(--sel-color);pointer-events:none}.all-chip{background:var(--surface2);color:var(--text-muted);font-weight:500;padding:2px;border-radius:4px;font-size:var(--fs-m);margin-right:4px;cursor:pointer;border:1px solid var(--border);display:flex;align-items:center;justify-content:center}.all-chip:hover{background:var(--border);color:var(--text)}.sel-tag{background:var(--surface2);color:var(--text-muted);font-weight:500;padding:2px;border-radius:4px;font-size:var(--fs-m);margin-right:4px;display:flex;align-items:center;justify-content:center;border:1px solid var(--border)}.mm-item{display:flex;align-items:center;gap:2px;white-space:nowrap}.mm-icon{font-size:var(--fs-m);color:var(--text-dim)}.uplot{color:var(--text-muted)!important}.u-title,.u-legend{display:none}.chart-row .u-select{background:color-mix(in srgb,var(--chart-color, #3b82f6) 12%,transparent)!important;border:1px solid color-mix(in srgb,var(--chart-color, #3b82f6) 35%,transparent)!important}.u-cursor-x{border-left:1px dashed rgba(255,255,255,.55)!important}.u-cursor-y{display:none!important}.sel-fill{position:absolute;top:0;background:color-mix(in srgb,var(--theme-color) 8%,transparent);border-left:1px solid color-mix(in srgb,var(--theme-color) 30%,transparent);border-right:1px solid rgba(148,163,184,.4);pointer-events:none}.sel-handle{position:absolute;top:50%;transform:translate(-50%,-50%);width:8px;height:24px;background:#ffffffd9;border:1px solid rgba(0,0,0,.3);border-radius:4px;cursor:ew-resize;pointer-events:auto;display:flex;align-items:center;justify-content:center;z-index:10}.sel-handle:after{content:"";width:2px;height:10px;border-left:1px solid rgba(0,0,0,.4);border-right:1px solid rgba(0,0,0,.4)}.sel-handle:hover{background:#fff;transform:translate(-50%,-50%) scale(1.1)}.sel-graph-marker{position:absolute;transform:translate(-50%,-50%);pointer-events:none;z-index:11;background:none!important}.sel-line{position:absolute;top:0;height:100%;width:0;border-left-width:1.5px;border-left-style:solid;pointer-events:none}.sel-line-label{position:absolute;top:4px;font-size:var(--fs-s);font-weight:700;background:#0e0e10eb;color:#fff;padding:2px 5px;border-radius:4px;pointer-events:none;white-space:nowrap;z-index:10;border:1px solid var(--border)}#charts-container{flex:1;overflow-y:auto;overflow-x:hidden;padding:6px 0 4px;scrollbar-width:none}#charts-container::-webkit-scrollbar{width:0;height:0}#charts-container::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}.fixed-x-label{position:absolute;bottom:4px;font-size:var(--fs-s);font-family:system-ui,sans-serif;color:#555564;z-index:10;pointer-events:none}.fixed-x-max{right:0;text-align:right}.chart-row-body{display:flex;flex-direction:row;padding:0 14px;min-width:0;overflow:hidden}.chart-row-body>div:first-child{flex:1;min-width:0}.hist-col{width:130px;flex-shrink:0;border-left:1px solid var(--border);margin-left:20px;margin-right:0;display:none;align-items:center;justify-content:center;cursor:crosshair}.hist-col.visible{display:flex}.hist-canvas{display:block}#hist-line{position:fixed;height:0;border-top:1px dashed rgba(255,255,255,.25);pointer-events:none;display:none;z-index:10000}#hist-tooltip{position:fixed;background:var(--surface);border:1px solid var(--border2);border-radius:5px;padding:8px 10px;pointer-events:none;display:none;z-index:10001;box-shadow:0 4px 15px #00000080;font-size:var(--fs-s)}.hist-tt-header{font-weight:800;margin-bottom:6px;padding-left:8px;border-left:3px solid var(--accent);color:var(--text)}.hist-tt-grid{display:grid;grid-template-columns:1fr auto auto;gap:10px;align-items:baseline}.hist-tt-label{font-size:var(--fs-s);color:var(--text-muted)}.hist-tt-value{font-size:var(--fs-s);color:var(--text);text-align:right;font-variant-numeric:tabular-nums}.hist-tt-pct{font-size:var(--fs-s);color:var(--text-dim);text-align:right;min-width:36px;font-variant-numeric:tabular-nums}.hist-tt-grid.sel-row{margin-top:2px;opacity:.9}.hist-tt-label.sel{color:var(--accent);font-weight:700}.chart-row{border-bottom:1px solid var(--border)}.chart-row:last-child{border-bottom:none}.chart-row-header{display:flex;align-items:center;gap:12px;padding:8px 14px 4px;min-height:28px}.progress-chart-row{display:flex;flex-direction:column}.progress-chart-row .chart-row-header{height:36px;box-sizing:border-box;padding-top:0;padding-bottom:0}.progress-chart-row .chart-row-actions{margin-left:auto}.progress-chart-row .chart-row-body{flex:1;padding:0}.chart-row-label-group{display:flex;align-items:center;gap:8px;flex-shrink:0;width:140px}.chart-row-actions{display:flex;align-items:center;gap:0}.chart-row-icon{font-size:var(--is-s);color:var(--chart-color)}.chart-row-label{font-size:var(--fs-m);font-weight:700;text-transform:uppercase;letter-spacing:.8px;color:var(--text-muted);white-space:nowrap}.track-picker-popup{padding:8px;background:var(--surface);color:var(--text);border-radius:8px;min-width:160px}.picker-header{font-size:var(--fs-s);text-transform:uppercase;font-weight:700;color:var(--text-dim);margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid var(--border)}.picker-list{display:flex;flex-direction:column;gap:2px}.picker-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;cursor:pointer}.picker-item:hover{background:var(--surface2)}.picker-color{width:3px;height:14px;border-radius:1px}.picker-info{display:flex;flex-direction:column;min-width:0}.picker-name{font-size:var(--fs-s);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:180px}.modal-backdrop{position:fixed;inset:0;background:#000000bf;backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:20000}.modal-content{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:24px;width:100%;max-width:320px;box-shadow:0 20px 40px #00000080;display:flex;flex-direction:column;gap:16px}.modal-title{font-size:var(--fs-l);font-weight:800;color:var(--text)}.modal-body{font-size:var(--fs-m);color:var(--text-muted);line-height:1.5}.modal-input-wrap{display:flex;flex-direction:column;gap:8px}.modal-input-label{font-size:var(--fs-s);font-weight:700;text-transform:uppercase;color:var(--text-dim)}.modal-input{background:var(--bg);border:1px solid var(--border2);border-radius:6px;padding:10px;color:var(--text);font-size:var(--fs-l);font-weight:800;text-align:center;letter-spacing:4px}.modal-input:focus{outline:none;border-color:var(--accent)}.modal-actions{display:flex;gap:12px;margin-top:8px}.modal-btn{flex:1;padding:10px;border-radius:6px;font-size:var(--fs-m);font-weight:700;border:1px solid transparent}.modal-btn.cancel{background:var(--surface2);color:var(--text);border-color:var(--border)}.modal-btn.cancel:hover{background:var(--border)}.modal-btn.confirm{background:var(--danger);color:#fff}.modal-btn.confirm:disabled{opacity:.3;cursor:not-allowed;filter:grayscale(1)}.modal-btn.confirm:not(:disabled):hover{filter:brightness(1.1)}.picker-meta{font-size:var(--fs-s);color:var(--text-dim);font-weight:700}.leaflet-popup-content-wrapper,.leaflet-popup-tip{background:var(--surface)!important;color:var(--text)!important;border:1px solid var(--border)!important;box-shadow:0 4px 12px #0006!important}.leaflet-popup-content{margin:0!important}.leaflet-popup-tip{border:none!important}.map-color-btn{margin-left:4px}.map-color-btn .material-symbols-rounded{font-size:var(--is-s)}.map-color-btn.active{color:var(--chart-color, var(--accent))}.smooth-btn.active{color:var(--accent)}.cur-y-val{position:absolute;left:0;top:0;pointer-events:none;font-size:var(--fs-s);font-weight:700;background:#0e0e10eb;padding:2px 6px;border-radius:4px;border:1px solid rgba(255,255,255,.1);z-index:2000;white-space:nowrap}.cur-y-val.pin{z-index:1000;opacity:.7}#details-view{width:100%;padding:24px;max-width:900px;margin:0 auto}#details-header{margin-bottom:32px}.details-title{font-size:var(--fs-l);font-weight:800;margin-bottom:4px}.details-subtitle{font-size:var(--fs-m);color:var(--text-muted)}.details-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px}.details-card{background:var(--surface2);border:1px solid var(--border);padding:16px;border-radius:12px;display:flex;flex-direction:column;gap:4px}.details-card .material-symbols-rounded{color:var(--accent);margin-bottom:4px;font-size:var(--is-m)}.details-card-label{font-size:var(--fs-s);font-weight:500;text-transform:uppercase;color:var(--text-dim);letter-spacing:.5px}.details-card-value{font-size:var(--fs-l);font-weight:500}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--text-dim);gap:12px;padding:40px 20px}.empty-icon{font-size:var(--fs-l);opacity:.2}.empty-text{font-size:var(--fs-m);font-weight:500}#chart-empty{height:100%}#details-empty{margin-top:40px}#toast-container{position:fixed;bottom:20px;left:50%;transform:translate(-50%);display:flex;flex-direction:column;gap:8px;z-index:9999}.toast{background:var(--surface2);color:var(--text);padding:10px 20px;border-radius:8px;font-size:var(--fs-m);font-weight:600;box-shadow:0 8px 24px #0006;border:1px solid var(--border2)}.toast.error{border-color:var(--danger)}.sort-menu-popup,.metric-menu-popup{position:fixed;z-index:10000;background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:6px;min-width:180px;box-shadow:0 8px 24px #00000080}.menu-item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer;color:var(--text-muted)}.menu-item:hover{background:var(--surface);color:var(--text)}.menu-item.active{color:var(--text);font-weight:600}.menu-item .material-symbols-rounded{font-size:var(--is-s)}.menu-item .item-label{flex:1;font-size:var(--fs-m)}.menu-item .arrow,.menu-item .check{font-size:var(--is-s);color:var(--text-dim)}#insights-view{width:100%;padding:24px;max-width:1000px;margin:0 auto}.insights-grid{column-count:2;column-gap:24px}@media (max-width: 900px){.insights-grid{column-count:1}}.insight-card{display:inline-flex;width:100%;break-inside:avoid;margin-bottom:24px;background:var(--surface2);border:1px solid var(--border);padding:20px;border-radius:12px;flex-direction:column;gap:16px}.insight-title{font-size:var(--fs-m);font-weight:700;text-transform:uppercase;letter-spacing:.8px;display:flex;align-items:center;gap:8px;color:var(--text-muted)}.insight-title .material-symbols-rounded{font-size:var(--is-s)}.insight-chart-container{width:100%;height:250px}.power-curve-table{width:100%;border-collapse:collapse;font-size:var(--fs-m);margin-top:0}.power-curve-table th{text-align:left;color:var(--text-dim);padding:4px 8px;font-weight:600;border-bottom:1px solid var(--border)}.power-curve-table td{padding:6px 8px;border-bottom:1px solid var(--border)}.power-curve-table tr:last-child td{border-bottom:none}.progress-details summary{cursor:pointer;font-size:var(--fs-m);color:var(--text-dim);display:flex;align-items:center;gap:4px;list-style:none}.progress-details summary::-webkit-details-marker{display:none}.progress-details[open] summary .expand-icon{transform:rotate(90deg)}.progress-details summary .material-symbols-rounded{font-size:var(--fs-l)}.power-curve-val{font-weight:700;color:var(--text);text-align:right}.evolution-select-btn{background:none;border:none;cursor:pointer;color:var(--chart-color);padding:0;font-size:var(--fs-l);vertical-align:middle;margin-left:4px}.hr-settings-popup{display:flex;flex-direction:column}.hr-input-row{display:flex;justify-content:space-between;align-items:center;font-size:var(--fs-m);color:var(--text-muted);font-weight:600}.hr-zone-input{background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);width:60px;padding:4px 8px;font-size:var(--fs-m);text-align:right;outline:none}.hr-zone-input:focus{border-color:var(--accent)}.save-btn{background:var(--accent);color:#fff;border:none;border-radius:6px;padding:8px;font-size:12px;font-weight:700;cursor:pointer}.save-btn:hover{background:var(--accent-hover)}.menu-item.active .arrow,.menu-item.active .check{color:var(--accent)}.evolution-toolbar{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;border-bottom:1px solid var(--border);background:var(--bg);min-height:40px}.evolution-toolbar-left,.evolution-toolbar-right{display:flex;align-items:center;gap:12px}.evolution-toolbar .metric-pills{display:flex;gap:6px}.evolution-toolbar .metric-pill{cursor:pointer}.evolution-container{display:flex;flex-direction:column;gap:0px;padding:6px 0 4px}.evolution-card-group{display:flex;flex-direction:column;gap:10px;width:100%}.evolution-legend{display:flex;gap:16px;font-size:12px;color:var(--text-dim);margin-top:0;margin-bottom:0;justify-content:center}.evolution-legend-item{display:flex;align-items:center;gap:6px}.evolution-legend-line{width:16px;height:0;display:inline-block}.evolution-legend-line.solid{border-top:2px solid var(--chart-color)}.evolution-legend-line.dashed{border-top:2px dashed #888888}.evolution-tooltip-title{font-weight:700;margin-bottom:4px}.evolution-tooltip-row{display:flex;justify-content:space-between;gap:15px}.evolution-tooltip-label{color:#8a8a93}.evolution-tooltip-value{font-weight:700}.evolution-empty-text{color:var(--text-dim);font-size:12px;text-align:center;margin-top:20px}.evolution-chart-container{height:250px;flex:1}.distance-progress-card .card-content,.elevation-progress-card .card-content{display:flex;gap:20px}.chart-scroll-container{flex:1;overflow-x:auto;position:relative;background:var(--bg-dim);border-radius:8px;padding:10px;scrollbar-width:none}.chart-scroll-container::-webkit-scrollbar{width:0;height:0;display:none}.accumulated-table-container{width:250px;background:var(--bg-dim);border-radius:8px;padding:15px}.accumulated-table{width:100%;border-collapse:collapse;font-size:var(--fs-m)}.accumulated-table th,.accumulated-table td{padding:4px 8px;text-align:left;border-bottom:1px solid var(--border-color)}.accumulated-table th{color:var(--text-dim);font-weight:500;text-transform:uppercase;font-size:var(--fs-m);letter-spacing:.5px}.accumulated-table td:last-child{text-align:right;font-weight:500;font-family:monospace}.accumulated-table tr:last-child td{border-bottom:none}.chart-scroll-container::-webkit-scrollbar{height:4px}.chart-scroll-container::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}.u-title,.u-legend{font-size:var(--fs-m)!important}.courses-container{padding:16px;display:flex;flex-direction:column;gap:16px}.courses-list{display:flex;flex-direction:column;gap:8px}.course-item{background:var(--surface2);border:1px solid var(--border);border-radius:8px;display:flex;flex-direction:column;cursor:pointer;overflow:hidden}.course-item:hover{background:var(--surface3);border-color:var(--border-high)}.course-item-header{padding:6px 12px;display:flex;align-items:center;gap:12px;width:100%}.course-name{font-weight:600;flex:1}.course-meta{color:var(--text-muted);font-size:var(--fs-s)}.course-actions{display:flex;gap:4px}.course-actions .icon-btn{opacity:.5}.course-item:hover .course-actions .icon-btn{opacity:1}.expand-icon{color:var(--text-muted)}.course-tracks{padding:8px 12px;border-top:1px solid var(--border);background:var(--surface1)}.course-tracks-title{font-size:var(--fs-xs);font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}.course-tracks-table{width:100%;border-collapse:collapse;font-size:var(--fs-s);color:var(--text)}.course-tracks-table th,.course-tracks-table td{padding:6px 8px;text-align:right;border-bottom:1px solid var(--border-low)}.course-tracks-table th:first-child,.course-tracks-table td:first-child,.course-tracks-table th:nth-child(2),.course-tracks-table td:nth-child(2){text-align:left}.course-tracks-table td:not(:first-child){white-space:nowrap}.course-tracks-table th{font-weight:600;color:var(--text-muted);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.5px;white-space:nowrap}.course-tracks-table tr:last-child td{border-bottom:none}.course-tracks-table th:first-child,.course-tracks-table td:first-child{width:100%}.course-track-row:hover{background:var(--surface2)}.course-track-row.selected{background:color-mix(in srgb,var(--theme-color) 8%,transparent)}.track-name-cell.clickable{color:var(--accent);cursor:pointer;font-weight:500}.track-name-cell.clickable:hover{text-decoration:underline}.metric-icon{font-size:16px;vertical-align:middle;margin-right:4px}.metric-icon.duration{color:var(--text-muted)}.metric-icon.speed{color:#4caf50}.metric-icon.power{color:#ff9800}.metric-icon.hr{color:#f44336}.course-point-marker{display:flex;align-items:center;justify-content:center} +/*# sourceMappingURL=styles.css.map */ diff --git a/suites-experimental/tools-gps-tracks/dist/styles.css.map b/suites-experimental/tools-gps-tracks/dist/styles.css.map new file mode 100644 index 0000000000..ce44ae3490 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/styles.css.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/css/uPlot.min.css", "../src/css/styles.css"], + "sourcesContent": [".uplot, .uplot *, .uplot *::before, .uplot *::after {box-sizing: border-box;}.uplot {font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";line-height: 1.5;width: min-content;}.u-title {text-align: center;font-size: 18px;font-weight: bold;}.u-wrap {position: relative;user-select: none;}.u-over, .u-under {position: absolute;}.u-under {overflow: hidden;}.uplot canvas {display: block;position: relative;width: 100%;height: 100%;}.u-axis {position: absolute;}.u-legend {font-size: 14px;margin: auto;text-align: center;}.u-inline {display: block;}.u-inline * {display: inline-block;}.u-inline tr {margin-right: 16px;}.u-legend th {font-weight: 600;}.u-legend th > * {vertical-align: middle;display: inline-block;}.u-legend .u-marker {width: 1em;height: 1em;margin-right: 4px;background-clip: padding-box !important;}.u-inline.u-live th::after {content: \":\";vertical-align: middle;}.u-inline:not(.u-live) .u-value {display: none;}.u-series > * {padding: 4px;}.u-series th {cursor: pointer;}.u-legend .u-off > * {opacity: 0.3;}.u-select {background: rgba(0,0,0,0.07);position: absolute;pointer-events: none;}.u-cursor-x, .u-cursor-y {position: absolute;left: 0;top: 0;pointer-events: none;will-change: transform;}.u-hz .u-cursor-x, .u-vt .u-cursor-y {height: 100%;border-right: 1px dashed #607D8B;}.u-hz .u-cursor-y, .u-vt .u-cursor-x {width: 100%;border-bottom: 1px dashed #607D8B;}.u-cursor-pt {position: absolute;top: 0;left: 0;border-radius: 50%;border: 0 solid;pointer-events: none;will-change: transform;/*this has to be !important since we set inline \"background\" shorthand */background-clip: padding-box !important;}.u-axis.u-off, .u-select.u-off, .u-cursor-x.u-off, .u-cursor-y.u-off, .u-cursor-pt.u-off {display: none;}", "/*\n * Copyright (c) 2026, Camillo Bruni.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n@import './uPlot.min.css';\n\n/* \u2500\u2500\u2500 Variables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n@font-face {\n font-family: 'Material Symbols Rounded';\n font-style: normal;\n font-weight: 100 700;\n src: url('../../material_symbols_rounded.woff2') format('woff2');\n}\n\n:root {\n --bg: #0e0e10;\n --surface: #18181b;\n --surface2: #222226;\n --border: #2e2e34;\n --border2: #3a3a42;\n --text: #e8e8ec;\n --text-muted: #888896;\n --text-dim: #555564;\n --theme-color: #3b82f6;\n --accent: var(--theme-color);\n --accent-hover: color-mix(in srgb, var(--theme-color) 80%, white);\n --danger: #ef4444;\n --sidebar-w: 230px;\n\n /* Font Sizes */\n --fs-s: 10px;\n --fs-m: 12px;\n --fs-l: 14px; /* For titles only */\n\n /* Icon Sizes */\n --is-s: 16px;\n --is-m: 20px;\n\n --handle-color: #3b82f6;\n}\n\n/* Font Size Classes */\n.font-s {\n font-size: 10px;\n}\n.font-m {\n font-size: 12px;\n}\n.font-l {\n font-size: 14px;\n}\n\n* {\n box-sizing: border-box;\n}\n\nbody,\nhtml {\n margin: 0;\n padding: 0;\n width: 100%;\n height: 100%;\n background: var(--bg);\n color: var(--text);\n font-family:\n system-ui,\n -apple-system,\n sans-serif;\n font-size: var(--fs-m);\n}\n\nbody {\n opacity: 1;\n}\n\nbody.loading-fonts {\n opacity: 0;\n}\n\nbutton {\n font-family: inherit;\n cursor: pointer;\n font-size: var(--fs-m);\n}\n\n/* Material symbols config */\n.material-symbols-rounded {\n font-family: 'Material Symbols Rounded';\n font-weight: normal;\n font-style: normal;\n font-size: var(--is-m);\n line-height: 1;\n letter-spacing: normal;\n text-transform: none;\n display: inline-block;\n white-space: nowrap;\n word-wrap: normal;\n direction: ltr;\n -webkit-font-smoothing: antialiased;\n font-variation-settings:\n 'FILL' 0,\n 'wght' 400,\n 'GRAD' 0,\n 'opsz' 24;\n}\n\n/* \u2500\u2500\u2500 Layout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#app {\n display: flex;\n width: 100vw;\n height: 100vh;\n overflow: hidden;\n}\n\n.hidden {\n display: none !important;\n}\n\n#global-loader {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n#import-warning {\n}\n\n.loader-box {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 0;\n display: flex;\n flex-direction: row;\n align-items: stretch;\n color: var(--text);\n font-weight: 700;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);\n max-width: 450px;\n width: 90%;\n overflow: hidden;\n position: relative;\n}\n\n#loader-close {\n position: absolute;\n top: 12px;\n right: 12px;\n background: none;\n border: none;\n color: var(--text-muted);\n cursor: pointer;\n padding: 4px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n#loader-close:hover {\n background: var(--surface2);\n color: var(--text);\n}\n\n.loader-icon-wrap {\n background: color-mix(in srgb, var(--accent) 10%, transparent);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 24px;\n border-right: 1px solid var(--border);\n gap: 8px;\n}\n\n.loader-icon-wrap > span {\n font-size: var(--fs-l);\n color: var(--accent);\n}\n\n#loader-warning-count {\n font-size: var(--fs-m);\n color: #f59e0b;\n font-weight: 700;\n display: none;\n align-items: center;\n gap: 4px;\n}\n\n.loader-content {\n padding: 24px;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 12px;\n justify-content: center;\n}\n\n#loader-text {\n font-size: var(--fs-l);\n font-weight: 700;\n color: var(--text);\n}\n\n#loader-filename {\n font-size: var(--fs-m);\n color: var(--text-muted);\n font-weight: 400;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 300px;\n}\n\n#loader-progress-wrap {\n width: 300px;\n height: 4px;\n background: var(--surface2);\n border-radius: 2px;\n margin-top: 4px;\n overflow: hidden;\n}\n\n#loader-subtext {\n font-size: var(--fs-m);\n color: var(--text-muted);\n font-weight: 400;\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 300px;\n margin-top: 0;\n}\n\n.progress-index {\n text-align: left;\n}\n\n.progress-total {\n text-align: right;\n}\n\n#loader-progress-bar {\n width: 0%;\n height: 100%;\n background: var(--accent);\n}\n\n/* \u2500\u2500\u2500 Sidebar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#sidebar {\n width: var(--sidebar-w);\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n background: var(--surface);\n border-right: 1px solid var(--border);\n z-index: 10;\n}\n\n#sidebar-header {\n padding: 16px 12px;\n border-bottom: 1px solid var(--border);\n}\n\n.logo {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.logo-icon {\n color: var(--accent);\n font-size: var(--fs-l);\n}\n.logo-title {\n font-weight: 800;\n font-size: var(--fs-l);\n letter-spacing: -0.5px;\n}\n.logo-sub {\n font-size: var(--fs-s);\n text-transform: uppercase;\n color: var(--text-dim);\n font-weight: 700;\n letter-spacing: 1px;\n margin-top: -2px;\n}\n\n/* Drop zone */\n#drop-zone {\n margin: 12px;\n padding: 20px 12px;\n border: 2px dashed var(--border2);\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n position: relative;\n}\n#drop-zone.drop-active {\n border-color: var(--accent);\n background: color-mix(in srgb, var(--theme-color) 5%, transparent);\n}\n.drop-icon {\n font-size: var(--is-m);\n color: var(--text-muted);\n margin-bottom: 4px;\n}\n.drop-primary {\n font-size: var(--fs-m);\n font-weight: 600;\n color: var(--text);\n}\n.drop-formats {\n display: flex;\n justify-content: center;\n gap: 6px;\n margin-top: 8px;\n}\n.drop-formats .badge {\n background: var(--surface2);\n color: var(--text-dim);\n font-size: var(--fs-s);\n padding: 2px 6px;\n}\n\n.drop-browse-container {\n margin-top: 12px;\n font-size: var(--fs-s);\n color: var(--text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 2px;\n}\n.drop-browse {\n color: var(--accent);\n font-weight: 600;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n.drop-browse .material-symbols-rounded {\n font-size: var(--fs-l);\n}\n.drop-browse:hover {\n color: var(--accent-hover);\n}\n.drop-separator {\n margin: 0 6px;\n color: var(--border2);\n vertical-align: middle;\n}\n\n/* Track list header */\n#track-list-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 12px 8px;\n}\n.section-label {\n font-size: var(--fs-s);\n font-weight: 700;\n text-transform: uppercase;\n color: var(--text-dim);\n letter-spacing: 0.5px;\n}\n\n.header-actions {\n display: flex;\n gap: 0;\n}\n\n#track-controls,\n#sort-controls {\n padding: 8px 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n border-bottom: 1px solid var(--border);\n}\n\n.search-bar {\n display: flex;\n background: var(--bg);\n border: 1px solid var(--border);\n border-radius: 6px;\n padding: 2px 4px;\n align-items: center;\n}\n.search-icon {\n font-size: var(--is-s);\n color: var(--text-dim);\n margin-left: 4px;\n}\n.search-bar input {\n flex: 1;\n background: transparent;\n border: none;\n padding: 4px 6px;\n color: var(--text);\n font-size: var(--fs-m);\n}\n.search-bar input:focus {\n outline: none;\n}\n\n.icon-btn.mini {\n width: 20px;\n height: 20px;\n color: var(--text-dim);\n}\n.icon-btn.mini .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.icon-btn.mini.active {\n color: var(--accent);\n}\n\n.sort-ctrl {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.sort-ctrl label {\n font-size: var(--fs-s);\n color: var(--text-dim);\n text-transform: uppercase;\n font-weight: 600;\n}\n\n.sort-select-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--surface2);\n border: 1px solid var(--border);\n padding: 4px 8px;\n border-radius: 6px;\n flex: 1;\n height: 24px;\n box-sizing: border-box;\n font-size: var(--fs-s);\n color: var(--text-muted);\n}\n.sort-select-btn:hover {\n border-color: var(--accent);\n color: var(--text);\n}\n.sort-select-btn .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.sort-select-btn .arrow {\n font-size: var(--fs-l);\n margin-left: auto;\n opacity: 0.5;\n}\n\n/* Filter panel */\n#filter-panel {\n padding: 12px;\n background: var(--surface2);\n border-bottom: 1px solid var(--border);\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n#filter-panel.hidden {\n display: none;\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.filter-group label {\n font-size: var(--fs-s);\n font-weight: 600;\n text-transform: uppercase;\n color: var(--text-dim);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.filter-group label .material-symbols-rounded {\n font-size: var(--is-s);\n opacity: 0.7;\n}\n\n.filter-metrics-grid {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 4px;\n}\n\n.mini-pill {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 6px;\n color: var(--text-dim);\n cursor: pointer;\n}\n.mini-pill:hover {\n border-color: var(--text-muted);\n color: var(--text-muted);\n}\n.mini-pill.active {\n background: var(--accent);\n border-color: var(--accent);\n color: white;\n}\n.mini-pill .material-symbols-rounded {\n font-size: var(--is-s);\n}\n\n.filter-row {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.filter-row input {\n flex: 1;\n background: var(--bg);\n border: 1px solid var(--border);\n border-radius: 4px;\n padding: 4px 6px;\n color: var(--text);\n font-size: var(--fs-s);\n}\n.filter-row span {\n font-size: var(--fs-s);\n color: var(--text-dim);\n}\n#filter-panel input:focus {\n border-color: var(--accent);\n outline: none;\n}\n\n.filter-footer {\n display: flex;\n justify-content: flex-end;\n margin-top: 4px;\n}\n\n/* Track list */\n#track-list {\n flex: 1;\n overflow-y: auto;\n padding: 4px 0;\n scrollbar-width: none;\n}\n#track-list::-webkit-scrollbar {\n width: 0;\n height: 0;\n display: none;\n}\n#track-list::-webkit-scrollbar-thumb {\n background: var(--border2);\n border-radius: 2px;\n}\n\n#track-list-empty {\n padding: 40px 20px;\n text-align: center;\n color: var(--text-dim);\n font-size: var(--fs-m);\n}\n\n.track-item {\n display: flex;\n align-items: center;\n padding: 6px 8px;\n gap: 0;\n cursor: pointer;\n border-left: 3px solid transparent;\n}\n.track-item:hover {\n background: rgba(255, 255, 255, 0.03);\n}\n.track-item.selected {\n background: color-mix(in srgb, var(--theme-color) 8%, transparent);\n border-left-color: var(--accent);\n}\n\n.track-color {\n width: 3px;\n border-radius: 1px;\n flex-shrink: 0;\n margin-right: 8px;\n align-self: stretch;\n}\n.track-info {\n flex: 1;\n min-width: 0;\n margin-right: 2px;\n}\n.track-name {\n font-size: var(--fs-m);\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-bottom: 1px;\n}\n.track-meta {\n font-size: var(--fs-s);\n color: var(--text-dim);\n display: flex;\n gap: 6px;\n align-items: center;\n}\n\n.track-item .icon-btn.mini {\n width: 22px;\n height: 22px;\n padding: 0;\n margin: 0;\n}\n\n.badge {\n font-size: var(--fs-s);\n background: var(--surface2);\n padding: 1px 4px;\n border-radius: 3px;\n font-weight: 700;\n color: var(--text-muted);\n}\n\n.track-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin-top: 6px;\n overflow: hidden;\n max-height: 32px;\n}\n\n.track-tag {\n font-size: var(--fs-s);\n font-weight: 700;\n color: var(--text-dim);\n background: rgba(255, 255, 255, 0.03);\n border: 1px solid var(--border);\n padding: 1px 5px;\n border-radius: 3px;\n white-space: nowrap;\n}\n\n.track-item.selected .track-tag {\n border-color: rgba(255, 255, 255, 0.1);\n color: var(--text-muted);\n}\n\n#sidebar-resizer {\n width: 4px;\n cursor: col-resize;\n background: transparent;\n flex-shrink: 0;\n z-index: 1000;\n margin-left: -2px;\n margin-right: -2px;\n user-select: none;\n}\n#sidebar-resizer:hover,\n#sidebar-resizer.dragging {\n background: var(--handle-color);\n}\n\nbody.dragging-sidebar {\n user-select: none;\n cursor: col-resize !important;\n}\n\n/* \u2500\u2500\u2500 Main \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#main {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n/* Map */\n#map-container {\n flex: 1;\n position: relative;\n min-height: 100px;\n}\n#map-container.editing-mode {\n border: 4px solid var(--accent);\n box-shadow: 0 0 15px var(--accent);\n z-index: 1000; /* Ensure glow is visible */\n}\n#map {\n width: 100%;\n height: 100%;\n background: var(--bg);\n}\n\n#map-controls {\n position: absolute;\n top: 12px;\n left: 12px;\n z-index: 1000;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n#basemap-switcher {\n display: flex;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 2px;\n height: 24px;\n box-sizing: border-box;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n align-items: center;\n gap: 0;\n}\n\n#selected-extra-map {\n font-size: var(--fs-s);\n font-weight: 700;\n color: var(--accent);\n padding: 0 6px;\n max-width: 120px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n}\n#selected-extra-map.hidden {\n display: none;\n}\n\n#btn-extra-layers {\n border: none !important;\n border-left: 1px solid var(--border) !important;\n border-radius: 0 !important;\n margin-left: 0 !important;\n padding-left: 6px !important;\n padding-right: 0 !important;\n width: auto !important;\n height: 100% !important;\n background: transparent !important;\n}\n\n#extra-layers-menu {\n position: absolute;\n top: 40px;\n right: 0;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);\n max-height: 300px;\n overflow-y: auto;\n width: 200px;\n z-index: 1000;\n padding: 4px;\n}\n#extra-layers-menu.hidden {\n display: none;\n}\n.extra-layers-header {\n font-size: var(--fs-s);\n font-weight: 700;\n color: var(--text-dim);\n text-transform: uppercase;\n padding: 6px 8px;\n border-bottom: 1px solid var(--border);\n margin-bottom: 4px;\n}\n.extra-layers-search {\n padding: 4px 8px;\n border-bottom: 1px solid var(--border);\n margin-bottom: 4px;\n}\n#extra-layers-search-input {\n width: 100%;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 4px;\n color: var(--text);\n font-size: var(--fs-s);\n padding: 4px 8px;\n outline: none;\n}\n#extra-layers-search-input:focus {\n border-color: var(--accent);\n}\n.extra-layers-license {\n font-size: var(--fs-s);\n color: var(--text-dim);\n padding: 4px 8px;\n border-bottom: 1px solid var(--border);\n margin-bottom: 4px;\n}\n.extra-layers-license a {\n color: var(--accent);\n text-decoration: none;\n}\n.extra-layers-license a:hover {\n text-decoration: underline;\n}\n.extra-layer-row {\n margin-bottom: 2px;\n}\n.extra-layer-item {\n display: block;\n width: 100%;\n text-align: left;\n background: transparent;\n border: none;\n color: var(--text-muted);\n padding: 4px 10px 2px 10px;\n font-size: var(--fs-s);\n font-weight: 600;\n border-radius: 4px;\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.extra-layer-item:hover {\n background: var(--surface2);\n color: var(--text);\n}\n.extra-layer-attribution {\n font-size: var(--fs-s);\n color: var(--text-dim);\n padding: 0 10px 4px 10px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n#map-loader {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 0 10px;\n height: 24px;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--fs-s);\n font-weight: 600;\n color: var(--text-muted);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n}\n.spinner-sm {\n width: 12px;\n height: 12px;\n border: 2px solid var(--surface2);\n border-top-color: var(--accent);\n border-radius: 50%;\n}\n.bm-btn {\n background: transparent;\n border: none;\n color: var(--text-muted);\n padding: 2px 6px;\n font-size: var(--fs-s);\n font-weight: 600;\n border-radius: 6px;\n}\n.bm-btn:hover {\n color: var(--text);\n}\n.bm-btn.active {\n background: var(--surface2);\n color: var(--accent);\n}\n\n/* Map Cursor Dot */\n.map-cursor-dot {\n pointer-events: none;\n}\n.dot-inner {\n width: 12px;\n height: 12px;\n background: #fff;\n border: 2px solid #000;\n border-radius: 50%;\n box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.5);\n}\n\n/* Map cursor info popup */\n#map-cursor-info {\n position: absolute;\n top: 12px;\n right: 12px;\n z-index: 1000;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 8px 12px;\n font-size: var(--fs-s);\n color: var(--text);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n display: none;\n pointer-events: none;\n}\n\n/* Resize handle */\n#resize-handle {\n height: 6px;\n background: var(--bg);\n border-top: 1px solid var(--border);\n border-bottom: 1px solid var(--border);\n cursor: ns-resize;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n z-index: 100;\n}\n#resize-handle:hover {\n background: var(--handle-color);\n}\n.handle-grip {\n width: 32px;\n height: 2px;\n background: var(--border2);\n border-radius: 1px;\n}\n\n/* \u2500\u2500\u2500 Chart Panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#chart-panel {\n display: flex;\n flex-direction: column;\n background: var(--surface);\n overflow: hidden;\n flex: 1;\n width: 100%;\n height: 100%;\n min-height: 0;\n}\n\n#tab-nav {\n display: flex;\n padding: 0 12px;\n border-bottom: 1px solid var(--border);\n gap: 4px;\n}\n\n.tab-btn {\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n color: var(--text-dim);\n padding: 10px 12px;\n font-size: var(--fs-m);\n font-weight: 700;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.tab-btn:hover {\n color: var(--text-muted);\n}\n.tab-btn.active {\n color: var(--accent);\n border-bottom-color: var(--accent);\n}\n.tab-btn .material-symbols-rounded {\n font-size: var(--is-s);\n}\n\n.tab-content {\n display: none;\n flex: 1;\n min-height: 0;\n}\n.tab-content.active {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n scrollbar-width: none;\n}\n\n/* Custom scrollbar for active tab content */\n.tab-content.active::-webkit-scrollbar {\n width: 0;\n height: 0;\n}\n.tab-content.active::-webkit-scrollbar-track {\n background: transparent;\n}\n.tab-content.active::-webkit-scrollbar-thumb {\n background: var(--border);\n border-radius: 3px;\n}\n.tab-content.active::-webkit-scrollbar-thumb:hover {\n background: var(--text-dim);\n}\n\n#chart-toolbar {\n display: flex;\n align-items: center;\n padding: 6px 12px;\n gap: 12px;\n border-bottom: 1px solid var(--border);\n background: var(--bg);\n min-height: 40px;\n position: sticky;\n top: 0;\n z-index: 100;\n}\n\n.icon-btn {\n background: transparent;\n border: 1px solid transparent;\n color: var(--text-muted);\n width: 24px;\n height: 24px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.icon-btn.hidden {\n display: none;\n}\n.icon-btn:hover {\n background: var(--surface2);\n color: var(--text);\n}\n.icon-btn.active {\n background: var(--surface2);\n color: var(--accent);\n}\n.icon-btn.danger:hover {\n background: rgba(239, 68, 68, 0.12);\n color: var(--danger);\n}\n.icon-btn .material-symbols-rounded {\n font-size: var(--fs-l);\n}\n\n#btn-metric-menu {\n flex: 0 0 auto;\n}\n\n#metric-pills {\n display: flex;\n gap: 6px;\n flex: 1;\n overflow: hidden;\n}\n.metric-pill:not(.active) {\n display: none;\n}\n.metric-pill.overflow-hidden {\n display: none !important;\n}\n#pill-overflow {\n color: var(--text-muted);\n font-weight: bold;\n padding: 0 4px;\n align-self: flex-end;\n}\n.metric-pill {\n height: 24px;\n padding: 0 8px;\n border-radius: 12px;\n border: 1px solid var(--border);\n background: var(--surface2);\n color: var(--text-muted);\n font-size: var(--fs-s);\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n.metric-pill .material-symbols-rounded {\n font-size: var(--fs-m);\n}\n.metric-pill.active {\n background: color-mix(in srgb, var(--pill-color) 15%, var(--surface2));\n border-color: var(--pill-color);\n color: var(--pill-color);\n}\n.metric-pill.disabled {\n opacity: 0.3;\n filter: grayscale(1);\n cursor: default;\n}\n\n#chart-options {\n display: flex;\n align-items: center;\n gap: 0;\n margin-left: auto;\n}\n\n.seg-ctrl {\n display: flex;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 6px;\n padding: 2px;\n height: 24px;\n box-sizing: border-box;\n}\n.seg-btn {\n background: transparent;\n border: none;\n color: var(--text-dim);\n padding: 0 8px;\n font-size: var(--fs-s);\n font-weight: 700;\n border-radius: 4px;\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n}\n.seg-btn .material-symbols-rounded {\n font-size: var(--fs-m);\n}\n.seg-btn.active {\n background: var(--bg);\n color: var(--text);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Stats Summary bar */\n#chart-stats {\n padding: 4px 14px;\n border-bottom: 1px solid var(--border);\n background: var(--surface2);\n}\n#chart-stats.hidden {\n display: none;\n}\n#chart-stats-wrap {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.stats-row {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n.stats-row-label {\n width: 45px;\n font-size: var(--fs-s);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--text-muted);\n white-space: nowrap;\n}\n\n.chart-row-stats-container {\n display: flex;\n flex: 1;\n align-items: center;\n justify-content: space-between;\n}\n\n.chart-row-right-actions {\n width: 130px; /* HIST_W */\n display: none;\n align-items: center;\n justify-content: flex-end;\n flex-shrink: 0;\n}\n.with-histogram .chart-row-right-actions {\n display: flex;\n}\n.chart-stats-total,\n.chart-stats-selection {\n display: flex;\n gap: 10px;\n font-size: var(--fs-s);\n color: var(--text-dim);\n align-items: center;\n white-space: nowrap;\n font-weight: 500;\n}\n.chart-stats-selection {\n margin-left: auto;\n position: relative;\n}\n.chart-stats-selection::after {\n content: '';\n position: absolute;\n bottom: -6px;\n left: 0;\n right: 0;\n height: 2px;\n background-color: var(--sel-color);\n pointer-events: none;\n}\n.all-chip {\n background: var(--surface2);\n color: var(--text-muted);\n font-weight: 500;\n padding: 2px;\n border-radius: 4px;\n font-size: var(--fs-m);\n margin-right: 4px;\n cursor: pointer;\n border: 1px solid var(--border);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.all-chip:hover {\n background: var(--border);\n color: var(--text);\n}\n.sel-tag {\n background: var(--surface2);\n color: var(--text-muted);\n font-weight: 500;\n padding: 2px;\n border-radius: 4px;\n font-size: var(--fs-m);\n margin-right: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--border);\n}\n\n.mm-item {\n display: flex;\n align-items: center;\n gap: 2px;\n white-space: nowrap;\n}\n.mm-icon {\n font-size: var(--fs-m);\n color: var(--text-dim);\n}\n\n/* \u2500\u2500 uPlot overrides \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.uplot {\n color: var(--text-muted) !important;\n}\n.u-title {\n display: none;\n}\n.u-legend {\n display: none;\n}\n\n/* Selection drag background \u2014 colour matches the chart's metric */\n.chart-row .u-select {\n background: color-mix(in srgb, var(--chart-color, #3b82f6) 12%, transparent) !important;\n border: 1px solid color-mix(in srgb, var(--chart-color, #3b82f6) 35%, transparent) !important;\n}\n\n/* Make the cursor crosshair dashed */\n.u-cursor-x {\n border-left: 1px dashed rgba(255, 255, 255, 0.55) !important;\n}\n.u-cursor-y {\n display: none !important;\n}\n\n/* \u2500\u2500 Selection fill \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.sel-fill {\n position: absolute;\n top: 0;\n background: color-mix(in srgb, var(--theme-color) 8%, transparent);\n border-left: 1px solid color-mix(in srgb, var(--theme-color) 30%, transparent);\n border-right: 1px solid rgba(148, 163, 184, 0.4);\n pointer-events: none;\n}\n\n/* \u2500\u2500 Selection handles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.sel-handle {\n position: absolute;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 8px;\n height: 24px;\n background: rgba(255, 255, 255, 0.85);\n border: 1px solid rgba(0, 0, 0, 0.3);\n border-radius: 4px;\n cursor: ew-resize;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n}\n.sel-handle::after {\n content: '';\n width: 2px;\n height: 10px;\n border-left: 1px solid rgba(0, 0, 0, 0.4);\n border-right: 1px solid rgba(0, 0, 0, 0.4);\n}\n.sel-handle:hover {\n background: #fff;\n transform: translate(-50%, -50%) scale(1.1);\n}\n\n.sel-graph-marker {\n position: absolute;\n transform: translate(-50%, -50%);\n pointer-events: none;\n z-index: 11;\n background: none !important;\n}\n.sel-graph-marker .material-symbols-rounded {\n}\n\n/* \u2500\u2500 Per-chart selection lines \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.sel-line {\n position: absolute;\n top: 0;\n height: 100%;\n width: 0;\n border-left-width: 1.5px;\n border-left-style: solid;\n pointer-events: none;\n}\n\n/* Labels on the selection lines */\n.sel-line-label {\n position: absolute;\n top: 4px;\n font-size: var(--fs-s);\n font-weight: 700;\n background: rgba(14, 14, 16, 0.92);\n color: #fff;\n padding: 2px 5px;\n border-radius: 4px;\n pointer-events: none;\n white-space: nowrap;\n z-index: 10;\n border: 1px solid var(--border);\n}\n\n/* \u2500\u2500 Charts view elements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#charts-container {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 6px 0 4px;\n scrollbar-width: none;\n}\n#charts-container::-webkit-scrollbar {\n width: 0;\n height: 0;\n}\n#charts-container::-webkit-scrollbar-thumb {\n background: var(--border2);\n border-radius: 2px;\n}\n\n/* Fixed X Axis Labels */\n.fixed-x-label {\n position: absolute;\n bottom: 4px;\n font-size: var(--fs-s);\n font-family: system-ui, sans-serif;\n color: #555564;\n z-index: 10;\n pointer-events: none;\n}\n.fixed-x-max {\n right: 0;\n text-align: right;\n}\n\n/* Histogram column (inline, per chart row) */\n.chart-row-body {\n display: flex;\n flex-direction: row;\n padding: 0 14px;\n min-width: 0;\n overflow: hidden;\n}\n.chart-row-body > div:first-child {\n flex: 1;\n min-width: 0;\n}\n.hist-col {\n width: 130px;\n flex-shrink: 0;\n border-left: 1px solid var(--border);\n margin-left: 20px;\n margin-right: 0;\n display: none;\n align-items: center;\n justify-content: center;\n cursor: crosshair;\n}\n.hist-col.visible {\n display: flex;\n}\n.hist-canvas {\n display: block;\n}\n\n/* Histogram connector line */\n#hist-line {\n position: fixed;\n height: 0;\n border-top: 1px dashed rgba(255, 255, 255, 0.25);\n pointer-events: none;\n display: none;\n z-index: 10000;\n}\n\n/* Histogram tooltip */\n#hist-tooltip {\n position: fixed;\n background: var(--surface);\n border: 1px solid var(--border2);\n border-radius: 5px;\n padding: 8px 10px;\n pointer-events: none;\n display: none;\n z-index: 10001;\n box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);\n font-size: var(--fs-s);\n}\n.hist-tt-header {\n font-weight: 800;\n margin-bottom: 6px;\n padding-left: 8px;\n border-left: 3px solid var(--accent);\n color: var(--text);\n}\n.hist-tt-grid {\n display: grid;\n grid-template-columns: 1fr auto auto;\n gap: 10px;\n align-items: baseline;\n}\n.hist-tt-label {\n font-size: var(--fs-s);\n color: var(--text-muted);\n}\n.hist-tt-value {\n font-size: var(--fs-s);\n color: var(--text);\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n.hist-tt-pct {\n font-size: var(--fs-s);\n color: var(--text-dim);\n text-align: right;\n min-width: 36px;\n font-variant-numeric: tabular-nums;\n}\n.hist-tt-grid.sel-row {\n margin-top: 2px;\n opacity: 0.9;\n}\n.hist-tt-label.sel {\n color: var(--accent);\n font-weight: 700;\n}\n\n.chart-row {\n border-bottom: 1px solid var(--border);\n}\n.chart-row:last-child {\n border-bottom: none;\n}\n\n/* \u2500\u2500 Chart row header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.chart-row-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 14px 4px 14px;\n min-height: 28px;\n}\n\n.progress-chart-row {\n display: flex;\n flex-direction: column;\n}\n\n.progress-chart-row .chart-row-header {\n height: 36px;\n box-sizing: border-box;\n padding-top: 0;\n padding-bottom: 0;\n}\n\n.progress-chart-row .chart-row-actions {\n margin-left: auto;\n}\n\n.progress-chart-row .chart-row-body {\n flex: 1;\n padding: 0;\n}\n\n.chart-row-label-group {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n width: 140px; /* Fixed width for alignment */\n}\n\n.chart-row-actions {\n display: flex;\n align-items: center;\n gap: 0;\n}\n\n.chart-row-icon {\n font-size: var(--is-s);\n color: var(--chart-color);\n}\n.chart-row-label {\n font-size: var(--fs-m);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--text-muted);\n white-space: nowrap;\n}\n\n/* Track Picker Popup */\n.track-picker-popup {\n padding: 8px;\n background: var(--surface);\n color: var(--text);\n border-radius: 8px;\n min-width: 160px;\n}\n.picker-header {\n font-size: var(--fs-s);\n text-transform: uppercase;\n font-weight: 700;\n color: var(--text-dim);\n margin-bottom: 8px;\n padding-bottom: 4px;\n border-bottom: 1px solid var(--border);\n}\n.picker-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.picker-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n cursor: pointer;\n}\n.picker-item:hover {\n background: var(--surface2);\n}\n.picker-color {\n width: 3px;\n height: 14px;\n border-radius: 1px;\n}\n.picker-info {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.picker-name {\n font-size: var(--fs-s);\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 180px;\n}\n/* Custom Modal / Dialog */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 20000;\n}\n.modal-content {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 24px;\n width: 100%;\n max-width: 320px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.modal-title {\n font-size: var(--fs-l);\n font-weight: 800;\n color: var(--text);\n}\n.modal-body {\n font-size: var(--fs-m);\n color: var(--text-muted);\n line-height: 1.5;\n}\n.modal-input-wrap {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.modal-input-label {\n font-size: var(--fs-s);\n font-weight: 700;\n text-transform: uppercase;\n color: var(--text-dim);\n}\n.modal-input {\n background: var(--bg);\n border: 1px solid var(--border2);\n border-radius: 6px;\n padding: 10px;\n color: var(--text);\n font-size: var(--fs-l);\n font-weight: 800;\n text-align: center;\n letter-spacing: 4px;\n}\n.modal-input:focus {\n outline: none;\n border-color: var(--accent);\n}\n.modal-actions {\n display: flex;\n gap: 12px;\n margin-top: 8px;\n}\n.modal-btn {\n flex: 1;\n padding: 10px;\n border-radius: 6px;\n font-size: var(--fs-m);\n font-weight: 700;\n border: 1px solid transparent;\n}\n.modal-btn.cancel {\n background: var(--surface2);\n color: var(--text);\n border-color: var(--border);\n}\n.modal-btn.cancel:hover {\n background: var(--border);\n}\n.modal-btn.confirm {\n background: var(--danger);\n color: #fff;\n}\n.modal-btn.confirm:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n filter: grayscale(1);\n}\n.modal-btn.confirm:not(:disabled):hover {\n filter: brightness(1.1);\n}\n\n.picker-meta {\n font-size: var(--fs-s);\n color: var(--text-dim);\n font-weight: 700;\n}\n\n/* Leaflet Popup Overrides */\n.leaflet-popup-content-wrapper,\n.leaflet-popup-tip {\n background: var(--surface) !important;\n color: var(--text) !important;\n border: 1px solid var(--border) !important;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4) !important;\n}\n.leaflet-popup-content {\n margin: 0 !important;\n}\n.leaflet-popup-tip {\n border: none !important;\n}\n.map-color-btn {\n margin-left: 4px;\n}\n.map-color-btn .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.map-color-btn.active {\n color: var(--chart-color, var(--accent));\n}\n\n.smooth-btn.active {\n color: var(--accent);\n}\n.cur-y-val {\n position: absolute;\n left: 0;\n top: 0;\n pointer-events: none;\n font-size: var(--fs-s);\n font-weight: 700;\n background: rgba(14, 14, 16, 0.92);\n padding: 2px 6px;\n border-radius: 4px;\n border: 1px solid rgba(255, 255, 255, 0.1);\n z-index: 2000;\n white-space: nowrap;\n}\n.cur-y-val.pin {\n z-index: 1000;\n opacity: 0.7;\n}\n\n/* \u2500\u2500\u2500 Details View \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#details-view {\n width: 100%;\n padding: 24px;\n max-width: 900px;\n margin: 0 auto;\n}\n\n#details-header {\n margin-bottom: 32px;\n}\n.details-title {\n font-size: var(--fs-l);\n font-weight: 800;\n margin-bottom: 4px;\n}\n.details-subtitle {\n font-size: var(--fs-m);\n color: var(--text-muted);\n}\n\n.details-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n gap: 16px;\n}\n.details-card {\n background: var(--surface2);\n border: 1px solid var(--border);\n padding: 16px;\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.details-card .material-symbols-rounded {\n color: var(--accent);\n margin-bottom: 4px;\n font-size: var(--is-m);\n}\n.details-card-label {\n font-size: var(--fs-s);\n font-weight: 500;\n text-transform: uppercase;\n color: var(--text-dim);\n letter-spacing: 0.5px;\n}\n.details-card-value {\n font-size: var(--fs-l);\n font-weight: 500;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--text-dim);\n gap: 12px;\n padding: 40px 20px;\n}\n.empty-icon {\n font-size: var(--fs-l);\n opacity: 0.2;\n}\n.empty-text {\n font-size: var(--fs-m);\n font-weight: 500;\n}\n\n#chart-empty {\n height: 100%;\n}\n#details-empty {\n margin-top: 40px;\n}\n\n/* \u2500\u2500 Toast notifications \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#toast-container {\n position: fixed;\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n flex-direction: column;\n gap: 8px;\n z-index: 9999;\n}\n.toast {\n background: var(--surface2);\n color: var(--text);\n padding: 10px 20px;\n border-radius: 8px;\n font-size: var(--fs-m);\n font-weight: 600;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);\n border: 1px solid var(--border2);\n}\n.toast.error {\n border-color: var(--danger);\n}\n.toast.out {\n}\n\n/* \u2500\u2500 Sort menu popup \u2500\u2500 */\n.sort-menu-popup,\n.metric-menu-popup {\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 6px;\n min-width: 180px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);\n}\n\n.menu-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n border-radius: 6px;\n cursor: pointer;\n color: var(--text-muted);\n}\n.menu-item:hover {\n background: var(--surface);\n color: var(--text);\n}\n.menu-item.active {\n color: var(--text);\n font-weight: 600;\n}\n.menu-item .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.menu-item .item-label {\n flex: 1;\n font-size: var(--fs-m);\n}\n.menu-item .arrow,\n.menu-item .check {\n font-size: var(--is-s);\n color: var(--text-dim);\n}\n\n/* \u2500\u2500\u2500 Insights View \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#insights-view {\n width: 100%;\n padding: 24px;\n max-width: 1000px;\n margin: 0 auto;\n}\n\n.insights-grid {\n column-count: 2;\n column-gap: 24px;\n}\n\n@media (max-width: 900px) {\n .insights-grid {\n column-count: 1;\n }\n}\n\n.insight-card {\n display: inline-flex;\n width: 100%;\n break-inside: avoid;\n margin-bottom: 24px;\n background: var(--surface2);\n border: 1px solid var(--border);\n padding: 20px;\n border-radius: 12px;\n flex-direction: column;\n gap: 16px;\n}\n\n.insight-title {\n font-size: var(--fs-m);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--text-muted);\n}\n\n.insight-title .material-symbols-rounded {\n font-size: var(--is-s);\n}\n\n.insight-chart-container {\n width: 100%;\n height: 250px;\n}\n\n.power-curve-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--fs-m);\n margin-top: 0;\n}\n\n.power-curve-table th {\n text-align: left;\n color: var(--text-dim);\n padding: 4px 8px;\n font-weight: 600;\n border-bottom: 1px solid var(--border);\n}\n\n.power-curve-table td {\n padding: 6px 8px;\n border-bottom: 1px solid var(--border);\n}\n\n.power-curve-table tr:last-child td {\n border-bottom: none;\n}\n\n.progress-details summary {\n cursor: pointer;\n font-size: var(--fs-m);\n color: var(--text-dim);\n display: flex;\n align-items: center;\n gap: 4px;\n list-style: none;\n}\n\n.progress-details summary::-webkit-details-marker {\n display: none;\n}\n\n.progress-details[open] summary .expand-icon {\n transform: rotate(90deg);\n}\n\n.progress-details summary .material-symbols-rounded {\n font-size: var(--fs-l);\n}\n\n.progress-details summary .expand-icon {\n}\n\n.power-curve-val {\n font-weight: 700;\n color: var(--text);\n text-align: right;\n}\n\n.evolution-select-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--chart-color);\n padding: 0;\n font-size: var(--fs-l);\n vertical-align: middle;\n margin-left: 4px;\n}\n\n.hr-settings-popup {\n display: flex;\n flex-direction: column;\n}\n\n.hr-input-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: var(--fs-m);\n color: var(--text-muted);\n font-weight: 600;\n}\n\n.hr-zone-input {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 4px;\n color: var(--text);\n width: 60px;\n padding: 4px 8px;\n font-size: var(--fs-m);\n text-align: right;\n outline: none;\n}\n\n.hr-zone-input:focus {\n border-color: var(--accent);\n}\n\n.save-btn {\n background: var(--accent);\n color: #fff;\n border: none;\n border-radius: 6px;\n padding: 8px;\n font-size: 12px;\n font-weight: 700;\n cursor: pointer;\n}\n\n.save-btn:hover {\n background: var(--accent-hover);\n}\n\n.menu-item.active .arrow,\n.menu-item.active .check {\n color: var(--accent);\n}\n\n/* \u2500\u2500 Evolution View \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.evolution-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 12px;\n border-bottom: 1px solid var(--border);\n background: var(--bg);\n min-height: 40px;\n}\n\n.evolution-toolbar-left,\n.evolution-toolbar-right {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.evolution-toolbar .metric-pills {\n display: flex;\n gap: 6px;\n}\n\n.evolution-toolbar .metric-pill {\n cursor: pointer;\n}\n\n.evolution-container {\n display: flex;\n flex-direction: column;\n gap: 0px;\n padding: 6px 0 4px;\n}\n\n.evolution-card-group {\n display: flex;\n flex-direction: column;\n gap: 10px;\n width: 100%;\n}\n\n.evolution-legend {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--text-dim);\n margin-top: 0px;\n margin-bottom: 0px;\n justify-content: center;\n}\n\n.evolution-legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.evolution-legend-line {\n width: 16px;\n height: 0;\n display: inline-block;\n}\n\n.evolution-legend-line.solid {\n border-top: 2px solid var(--chart-color);\n}\n\n.evolution-legend-line.dashed {\n border-top: 2px dashed #888888;\n}\n\n.evolution-tooltip-title {\n font-weight: bold;\n margin-bottom: 4px;\n}\n\n.evolution-tooltip-row {\n display: flex;\n justify-content: space-between;\n gap: 15px;\n}\n\n.evolution-tooltip-label {\n color: #8a8a93;\n}\n\n.evolution-tooltip-value {\n font-weight: bold;\n}\n\n.evolution-empty-text {\n color: var(--text-dim);\n font-size: 12px;\n text-align: center;\n margin-top: 20px;\n}\n\n.evolution-chart-container {\n height: 250px;\n flex: 1;\n}\n\n.distance-progress-card .card-content,\n.elevation-progress-card .card-content {\n display: flex;\n gap: 20px;\n}\n\n.chart-scroll-container {\n flex: 1;\n overflow-x: auto;\n position: relative;\n background: var(--bg-dim);\n border-radius: 8px;\n padding: 10px;\n scrollbar-width: none;\n}\n.chart-scroll-container::-webkit-scrollbar {\n width: 0;\n height: 0;\n display: none;\n}\n\n.accumulated-table-container {\n width: 250px;\n background: var(--bg-dim);\n border-radius: 8px;\n padding: 15px;\n}\n\n.accumulated-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--fs-m);\n}\n\n.accumulated-table th,\n.accumulated-table td {\n padding: 4px 8px;\n text-align: left;\n border-bottom: 1px solid var(--border-color);\n}\n\n.accumulated-table th {\n color: var(--text-dim);\n font-weight: 500;\n text-transform: uppercase;\n font-size: var(--fs-m);\n letter-spacing: 0.5px;\n}\n\n.accumulated-table td:last-child {\n text-align: right;\n font-weight: 500;\n font-family: monospace;\n}\n\n.accumulated-table tr:last-child td {\n border-bottom: none;\n}\n\n.chart-scroll-container::-webkit-scrollbar {\n height: 4px;\n}\n\n.chart-scroll-container::-webkit-scrollbar-thumb {\n background: var(--border2);\n border-radius: 2px;\n}\n\n/* uPlot overrides to comply with font size restrictions */\n.u-title {\n font-size: var(--fs-m) !important;\n}\n.u-legend {\n font-size: var(--fs-m) !important;\n}\n\n/* Courses Tab */\n.courses-container {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.courses-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.course-item {\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 8px;\n display: flex;\n flex-direction: column;\n cursor: pointer;\n overflow: hidden;\n}\n\n.course-item:hover {\n background: var(--surface3);\n border-color: var(--border-high);\n}\n\n.course-item-header {\n padding: 6px 12px;\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n}\n\n.course-name {\n font-weight: 600;\n flex: 1;\n}\n\n.course-meta {\n color: var(--text-muted);\n font-size: var(--fs-s);\n}\n\n.course-actions {\n display: flex;\n gap: 4px;\n}\n\n.course-actions .icon-btn {\n opacity: 0.5;\n}\n\n.course-item:hover .course-actions .icon-btn {\n opacity: 1;\n}\n\n.expand-icon {\n color: var(--text-muted);\n}\n\n.course-tracks {\n padding: 8px 12px;\n border-top: 1px solid var(--border);\n background: var(--surface1);\n}\n\n.course-tracks-title {\n font-size: var(--fs-xs);\n font-weight: 700;\n color: var(--text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n}\n\n.course-tracks-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--fs-s);\n color: var(--text);\n}\n\n.course-tracks-table th,\n.course-tracks-table td {\n padding: 6px 8px;\n text-align: right;\n border-bottom: 1px solid var(--border-low);\n}\n\n.course-tracks-table th:first-child,\n.course-tracks-table td:first-child,\n.course-tracks-table th:nth-child(2),\n.course-tracks-table td:nth-child(2) {\n text-align: left;\n}\n\n.course-tracks-table td:not(:first-child) {\n white-space: nowrap;\n}\n\n.course-tracks-table th {\n font-weight: 600;\n color: var(--text-muted);\n font-size: var(--fs-xs);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n white-space: nowrap;\n}\n\n.course-tracks-table tr:last-child td {\n border-bottom: none;\n}\n\n.course-tracks-table th:first-child,\n.course-tracks-table td:first-child {\n width: 100%;\n}\n\n.course-track-row:hover {\n background: var(--surface2);\n}\n\n.course-track-row.selected {\n background: color-mix(in srgb, var(--theme-color) 8%, transparent);\n}\n\n.track-name-cell.clickable {\n color: var(--accent);\n cursor: pointer;\n font-weight: 500;\n}\n\n.track-name-cell.clickable:hover {\n text-decoration: underline;\n}\n\n.metric-icon {\n font-size: 16px;\n vertical-align: middle;\n margin-right: 4px;\n}\n\n.metric-icon.duration {\n color: var(--text-muted);\n}\n\n.metric-icon.speed {\n color: #4caf50;\n}\n\n.metric-icon.power {\n color: #ff9800;\n}\n\n.metric-icon.hr {\n color: #f44336;\n}\n\n.course-point-marker {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n"], + "mappings": "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", + "names": [] +} diff --git a/suites-experimental/tools-gps-tracks/dist/test-data/activity_1_alps_stage.gpx.gz b/suites-experimental/tools-gps-tracks/dist/test-data/activity_1_alps_stage.gpx.gz new file mode 100644 index 0000000000000000000000000000000000000000..cd3428df6debed5d5f877b0c2da8faa2d0df37c8 GIT binary patch literal 42206 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 Bf4~3$ literal 0 HcmV?d00001 diff --git a/suites-experimental/tools-gps-tracks/dist/test-data/activity_3_road_race.tcx.gz b/suites-experimental/tools-gps-tracks/dist/test-data/activity_3_road_race.tcx.gz new file mode 100644 index 0000000000000000000000000000000000000000..9060c68ff22b20e053f521637d3fe25777e38960 GIT binary patch literal 39528 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 V`^uH@zxzk-zUz~A>1F%x{{ZO;B=`UT literal 0 HcmV?d00001 diff --git a/suites-experimental/tools-gps-tracks/dist/test-data/activity_5_grand_tour.fit.gz b/suites-experimental/tools-gps-tracks/dist/test-data/activity_5_grand_tour.fit.gz new file mode 100644 index 0000000000000000000000000000000000000000..18c520009cb29887be4abab2f7336bd22ee15712 GIT binary patch literal 36301 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 Z*OulTKNCRdR#=qi{{X<0!^4`n002aXgBAb) literal 0 HcmV?d00001 diff --git a/suites-experimental/tools-gps-tracks/dist/test-data/activity_6_weekend_ride.fit.gz b/suites-experimental/tools-gps-tracks/dist/test-data/activity_6_weekend_ride.fit.gz new file mode 100644 index 0000000000000000000000000000000000000000..1a0b5fbed85cae0668abbafb081115d94e4a3c1c GIT binary patch literal 27953 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 literal 0 HcmV?d00001 diff --git a/suites-experimental/tools-gps-tracks/dist/test-data/manifest.json b/suites-experimental/tools-gps-tracks/dist/test-data/manifest.json new file mode 100644 index 0000000000..52a312930a --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/test-data/manifest.json @@ -0,0 +1,8 @@ +[ + "activity_1_alps_stage.gpx.gz", + "activity_2_forest_mtb.gpx.gz", + "activity_3_road_race.tcx.gz", + "activity_4_intervals.tcx.gz", + "activity_5_grand_tour.fit.gz", + "activity_6_weekend_ride.fit.gz" +] \ No newline at end of file diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs new file mode 100644 index 0000000000..60e6a264f0 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs @@ -0,0 +1,903 @@ +var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(location.search),w={};b.has("track")&&(w.track=b.get("track")),b.has("map")&&(w.map=b.get("map")),b.has("xaxis")&&(w.xaxis=b.get("xaxis")),b.has("tab")&&(w.tab=b.get("tab")),b.has("sel_point")&&(w.sel_point=Number(b.get("sel_point"))),b.has("speed_mode")&&(w.speed_mode=b.get("speed_mode")),b.has("progress")&&(w.progress=b.get("progress"));let R=b.get("metrics");if(R&&(w.metrics=R.split(",").filter(Boolean)),b.has("f_date")&&(w.f_date=b.get("f_date").split(",").map(S=>S||null)),b.has("f_dist")&&(w.f_dist=b.get("f_dist").split(",").map(S=>S?Number(S):null)),b.has("f_dur")&&(w.f_dur=b.get("f_dur").split(",").map(S=>S?Number(S):null)),b.has("f_mets")&&(w.f_mets=b.get("f_mets").split(",")),b.has("f_tags")&&(w.f_tags=b.get("f_tags").split(",")),b.has("q")&&(w.q=b.get("q")),b.has("re")&&(w.re=b.get("re")==="1"),b.has("sort")){let S=b.get("sort"),k=S.startsWith("-"),M=k?S.substring(1):S;w.sort=`${M}-${k?"desc":"asc"}`}if(b.has("map_pos")){let S=b.get("map_pos").split(",").map(Number);S.length===3&&S.every(isFinite)&&(w.map_pos=S)}if(b.has("storage")&&(w.storage=b.get("storage")),b.has("sel")){let S=b.get("sel").split(",").map(Number);S.length===2&&S.every(k=>!isNaN(k)&&isFinite(k))&&(w.sel=S)}return w}function r(){t&&(clearTimeout(t),t=null);let b=new URLSearchParams;if(e.track&&b.set("track",e.track),e.map&&b.set("map",e.map),e.xaxis&&e.xaxis!=="time"&&b.set("xaxis",e.xaxis),e.tab&&e.tab!=="graphs"&&b.set("tab",e.tab),e.storage&&e.storage!=="memory"&&b.set("storage",e.storage),e.sel_point!==void 0&&b.set("sel_point",String(e.sel_point)),e.speed_mode&&b.set("speed_mode",e.speed_mode),e.q&&b.set("q",e.q),e.progress&&b.set("progress",e.progress),e.re&&b.set("re","1"),e.sort){let R=e.sort.split("-"),S=R[0],k=R[1];b.set("sort",(k==="desc"?"-":"")+S)}let w=b.toString();if(e.metrics&&(w+=`${w?"&":""}metrics=${e.metrics.join(",")}`),e.f_date&&(w+=`${w?"&":""}f_date=${e.f_date.map(R=>R||"").join(",")}`),e.f_dist&&(w+=`${w?"&":""}f_dist=${e.f_dist.map(R=>R??"").join(",")}`),e.f_dur&&(w+=`${w?"&":""}f_dur=${e.f_dur.map(R=>R??"").join(",")}`),e.f_mets&&(w+=`${w?"&":""}f_mets=${e.f_mets.join(",")}`),e.f_tags&&(w+=`${w?"&":""}f_tags=${e.f_tags.join(",")}`),e.map_pos){let R=`${(+e.map_pos[0]).toFixed(5)},${(+e.map_pos[1]).toFixed(5)},${e.map_pos[2]}`;w+=`${w?"&":""}map_pos=${R}`}if(e.sel){let R=`${+e.sel[0].toFixed(4)},${+e.sel[1].toFixed(4)}`;w+=`${w?"&":""}sel=${R}`}if(w!==s){let R=location.pathname+(w?`?${w}`:"");n?(history.pushState(null,"",R),n=!1):history.replaceState(null,"",R),s=w}}e=o();function u(){return{...e}}function c(b,w=!1){w&&(n=!0);for(let[R,S]of Object.entries(b)){let k=R;S==null?delete e[k]:e[k]=S}r()}function m(){e=o()}function T(){t&&(clearTimeout(t),t=null),e={},n=!1,s="",history.replaceState(null,"",location.pathname)}return{get:u,patch:c,refresh:m,reset:T}})();var Jn=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(s){return this.trackStore.set(s.id,s),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(s){return this.trackStore.delete(s),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(s,t){return this.settingStore.set(s,t),Promise.resolve()}async get(s){return Promise.resolve(this.settingStore.get(s)??null)}},us=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((s,t)=>{let n=indexedDB.open(this.DB_NAME,this.DB_VERSION);n.onupgradeneeded=()=>{let o=n.result;o.objectStoreNames.contains("tracks")||o.createObjectStore("tracks",{keyPath:"id"}),o.objectStoreNames.contains("settings")||o.createObjectStore("settings")},n.onsuccess=()=>{this.db=n.result,s()},n.onerror=()=>t(n.error)})}getStore(s,t){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(s,t).objectStore(s)}async save(s){return new Promise((t,n)=>{let o=this.getStore("tracks","readwrite").put(s);o.onsuccess=()=>t(),o.onerror=()=>n(o.error)})}async getAll(){return new Promise((s,t)=>{let n=this.getStore("tracks","readonly").getAll();n.onsuccess=()=>s(n.result||[]),n.onerror=()=>t(n.error)})}async remove(s){return new Promise((t,n)=>{let o=this.getStore("tracks","readwrite").delete(s);o.onsuccess=()=>t(),o.onerror=()=>n(o.error)})}async clear(){return this.db?new Promise((s,t)=>{let n=this.db.transaction(["tracks","settings"],"readwrite");n.objectStore("tracks").clear(),n.objectStore("settings").clear(),n.oncomplete=()=>s(),n.onerror=()=>t(n.error)}):Promise.resolve()}async set(s,t){return new Promise((n,o)=>{let r=this.getStore("settings","readwrite").put(t,s);r.onsuccess=()=>n(),r.onerror=()=>o(r.error)})}async get(s){return new Promise((t,n)=>{let o=this.getStore("settings","readonly").get(s);o.onsuccess=()=>t(o.result??null),o.onerror=()=>n(o.error)})}},en=new Jn,at={openDB:async()=>{en=Ye.get().storage==="indexeddb"?new us:new Jn,await en.openDB()},save:e=>en.save(e),getAll:()=>en.getAll(),remove:e=>en.remove(e),clear:()=>en.clear(),set:(e,s)=>en.set(e,s),get:e=>en.get(e)};import Al from"fit-file-parser";function tn(e,s,t,n){let r=e*Math.PI/180,u=t*Math.PI/180,c=(t-e)*Math.PI/180,m=(n-s)*Math.PI/180,T=Math.sin(c/2)*Math.sin(c/2)+Math.cos(r)*Math.cos(u)*Math.sin(m/2)*Math.sin(m/2);return 6371e3*(2*Math.atan2(Math.sqrt(T),Math.sqrt(1-T)))}function Ds(e){let s=new Uint32Array([Math.floor(e/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(s.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function Rs(){return Math.random().toString(36).slice(2,6)}function Ft(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:`${Math.round(e/3600)}h`}function ht(e){let s=Math.floor(e/3600),t=Math.floor(e%3600/60);return s>0?`${s}h ${t}m`:`${t}m ${Math.floor(e%60)}s`}function An(e){if(e==null||!isFinite(e))return"--";let s=Math.floor(e/60),t=Math.round(e%60);return`${s}:${t.toString().padStart(2,"0")}`}function Zt(e){let s=new Date(e);return isNaN(s.getTime())?"Unknown date":s.toISOString().split("T")[0]}function Ns(e){let s=new Date(e);if(isNaN(s.getTime()))return"Unknown";let t=s.toISOString();return`${t.split("T")[0]} ${t.split("T")[1].slice(0,5)}`}function Ws(e){if(e===0)return"0 B";let s=1024,t=["B","KB","MB","GB"],n=Math.floor(Math.log(e)/Math.log(s));return`${parseFloat((e/Math.pow(s,n)).toFixed(2))} ${t[n]}`}function pt(e){return String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function Qn(e){let s=0;for(let n=0;n=0&&w0?m/T:e[c]}return u}function tt(e,s=1){let t=parseInt(e.slice(1,3),16),n=parseInt(e.slice(3,5),16),o=parseInt(e.slice(5,7),16);return`rgba(${t}, ${n}, ${o}, ${s})`}function ms(e){if(!e.length)return null;let s=e[0].lat,t=e[0].lat,n=e[0].lon,o=e[0].lon;for(let r of e)r.latt&&(t=r.lat),r.lono&&(o=r.lon);return{minLat:s,maxLat:t,minLon:n,maxLon:o}}function ps(e,s){if(e.length<=2)return e;let t=[e[0]],n=e[0];for(let o=1;o=s&&(t.push(r),n=r)}return t.push(e[e.length-1]),t}var it=(()=>{function e(y){let d=0;for(let a=0;a0){let X=y[a-1],se=tn(X.lat,X.lon,G.lat,G.lon);if(d+=se,G.speed==null&&G.time!=null&&X.time!=null){let U=(G.time-X.time)/1e3;U>0&&U<10&&(G.speed=se/U)}if(G.gradient===void 0&&G.ele!=null&&X.ele!=null){let U=G.ele-X.ele;se>.5?G.gradient=U/se*100:G.gradient=X.gradient||0}}G.dist=d}for(let a=1;a0){let $e=y[Pe-1];if(de.ele!=null&&$e.ele!=null){let Ce=de.ele-$e.ele;Ce>0?a.elevGain+=Ce:a.elevLoss-=Ce}(de.gearFront!=null&&de.gearFront!==$e.gearFront||de.gearRear!=null&&de.gearRear!==$e.gearRear)&&_++}de.power!=null&&(G+=de.power,X++,de.power>a.maxPower&&(a.maxPower=de.power)),de.hr!=null&&(se+=de.hr,U++,de.hr>a.maxHR&&(a.maxHR=de.hr)),de.cad!=null&&(ne+=de.cad,Le++),de.speed!=null&&(Re+=de.speed,Be++,de.speed>a.maxSpeed&&(a.maxSpeed=de.speed)),de.battery!=null&&(ae+=de.battery,pe++),de.temp!=null&&(Q=!0,ye+=de.temp,He++,(a.minTemp==null||de.tempa.maxTemp)&&(a.maxTemp=de.temp)),(de.gearFront!=null||de.gearRear!=null)&&(oe=!0)}a.totalDist=y[y.length-1].dist||0,a.avgPower=X?Math.round(G/X):null,a.avgHR=U?Math.round(se/U):null,a.avgCadence=Le?Math.round(ne/Le):null,a.avgSpeed=Be?Re/Be:null,a.avgBattery=pe?Math.round(ae/pe):null,a.avgTemp=He?Number((ye/He).toFixed(1)):null,a.shifts=oe?_:null;let re=y[0].time,K=y[y.length-1].time;return re!=null&&K!=null&&(a.duration=K-re),U&&(a.sensors.push("Heart Rate"),d&&(a.hrZones=R(y),a.hrCurve=m(y))),Le&&a.sensors.push("Cadence"),X&&(a.sensors.push("Power"),d&&(a.powerCurve=c(y),a.powerZones=T(y))),Q&&a.sensors.push("Temperature"),oe&&a.sensors.push("Shifting"),pe&&a.sensors.push("Battery"),a}function o(y){if(!y||!y.points||!y.stats)return;let d=y.points,a=y.stats;a.avgHR!=null&&!a.hrCurve&&(a.hrZones=R(d),a.hrCurve=m(d)),a.avgPower!=null&&!a.powerCurve&&(a.powerCurve=c(d),a.powerZones=T(d))}let r=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800,14400,18e3,21600];function u(y,d){let a=y.length;if(a===0)return null;let G=new Float64Array(a+1);for(let U=0;Ua)continue;let Le=0,Re=0,Be=a-ne;for(let ae=0;ae<=Be;ae++){let pe=G[ae+ne]-G[ae];pe>Le&&(Le=pe,Re=ae)}X[ne]={val:Math.round(Le/ne),idx:Re},se=!0}return se?X:null}function c(y){let d=y.length,a=new Array(d),G=!1;for(let U=0;UG*t);for(let G=1;G10)continue;let ne=X.power;neG===0)?null:d}function b(y){t=y}function w(){return t}function R(y){let d=[0,0,0,0,0];for(let a=1;a10)continue;let U=G.hr;Ua===0)?null:d}function S(y){s=y}function k(){return[...s]}function M(y,d,a){let G=y.indexOf(d);if(G===-1)return null;let X=G+d.length,se=y.indexOf(a,X);if(se===-1)return null;let U=y.slice(X,se).trim();return U!==""?U:null}function g(y,d){let a=y.indexOf(d);if(a===-1)return null;let G=a+d.length,X=y.indexOf('"',G);return X===-1?null:y.slice(G,X)}let I=-1,P=0;function p(y,d,a){for(;dd&&y.charCodeAt(a-1)<=32;)a--;if(d>=a)return null;let G=!1,X=y.charCodeAt(d);X===45?(G=!0,d++):X===43&&d++;let se=0,U=0;for(let ne=d;ne=48&&Le<=57)se=se*10+(Le-48),U++;else break}return U===0?null:G?-se:se}function h(y,d,a){for(;dd&&y.charCodeAt(a-1)<=32;)a--;if(d>=a)return null;let G=!1,X=y.charCodeAt(d);X===45?(G=!0,d++):X===43&&d++;let se=0,U=0,ne=1,Le=!1,Re=0;for(let ae=d;ae=48&&pe<=57)Re++,Le?(U=U*10+(pe-48),ne*=10):se=se*10+(pe-48);else if(pe===46&&!Le)Le=!0;else{let ye=parseFloat(y.slice(d-(G?1:0),a));return Number.isFinite(ye)?ye:null}}if(Re===0)return null;let Be=se+U/ne;return G?-Be:Be}function F(y,d,a){for(;dd&&y.charCodeAt(a-1)<=32;)a--;let G=a-d;if(G>=20&&y.charCodeAt(d+10)===84&&y.charCodeAt(a-1)===90){let se=(y.charCodeAt(d)-48)*1e3+(y.charCodeAt(d+1)-48)*100+(y.charCodeAt(d+2)-48)*10+(y.charCodeAt(d+3)-48),U=(y.charCodeAt(d+5)-48)*10+(y.charCodeAt(d+6)-48),ne=(y.charCodeAt(d+8)-48)*10+(y.charCodeAt(d+9)-48),Le=se<<9|U<<5|ne;Le!==I&&(I=Le,P=Date.UTC(se,U-1,ne));let Re=(y.charCodeAt(d+11)-48)*10+(y.charCodeAt(d+12)-48),Be=(y.charCodeAt(d+14)-48)*10+(y.charCodeAt(d+15)-48),ae=(y.charCodeAt(d+17)-48)*10+(y.charCodeAt(d+18)-48),pe=0;return y.charCodeAt(d+19)===46&&G>=24&&(pe=(y.charCodeAt(d+20)-48)*100+(y.charCodeAt(d+21)-48)*10+(y.charCodeAt(d+22)-48)),P+Re*36e5+Be*6e4+ae*1e3+pe}let X=new Date(y.slice(d,a)).getTime();return Number.isFinite(X)?X:null}function q(y,d,a,G){let X=y.indexOf(G,d);if(X===-1||X>=a)return 0;let se=X+G.length,U=y.indexOf('"',se);return U===-1||U>=a?0:h(y,se,U)??0}function J(y,d){let a=d??new TextDecoder().decode(y),G=a.indexOf(""),U=(se!==-1?M(X.slice(se),"",""):null)||M(X,"","")||"Unnamed Track",ne=X.indexOf(">",X.indexOf("",ye+6);if(He===-1)break;let Q=a.indexOf("",He+1);if(Q===-1)break;Be=Q+8;let _=q(a,ye+6,He+1,'lat="'),oe=q(a,ye+6,He+1,'lon="'),re=null,K=null,Pe=null,de=null,$e=null,Ce=null,We=null,te=null,ge=null,L=null,ee=null,Ne=null,V=He+1;for(;V=Q)break;let xe=a.indexOf(">",he+1);if(xe===-1||xe>=Q)break;let Ee=a.charCodeAt(he+1);if(Ee===47){V=xe+1;continue}let fe=xe-he-1;if(Ee===103&&fe===26&&Pe!==null&&de!==null&&Ce!==null)break;let be=a.indexOf("<",xe+1);if(be===-1||be>Q)break;if(a.charCodeAt(be+1)===47){let Ue=xe+1,je=be;fe===3?Ee===101?re=h(a,Ue,je):Ee===99&&de===null&&(de=p(a,Ue,je)):fe===2?Ee===104&&Pe===null&&(Pe=p(a,Ue,je)):fe===4?Ee===116?a.charCodeAt(he+2)===105?K=F(a,Ue,je):Ce===null&&(Ce=h(a,Ue,je)):Ee===84&&Ce===null&&(Ce=h(a,Ue,je)):fe===5?(Ee===112||Ee===80||Ee===87)&&$e===null?$e=h(a,Ue,je):(Ee===115||Ee===83)&&We===null?We=h(a,Ue,je):Ee===97&&Ce===null&&(Ce=h(a,Ue,je)):fe===7?(Ee===98||Ee===66)&&Ne===null?Ne=p(a,Ue,je):Ee===67&&de===null&&(de=p(a,Ue,je)):fe===8?(Ee===103||Ee===71)&&ge===null&&(ge=p(a,Ue,je)):fe===9?Ee===103?a.charCodeAt(he+8)===104&&Pe===null?Pe=p(a,Ue,je):te===null&&(te=p(a,Ue,je)):Ee===71&&te===null&&(te=p(a,Ue,je)):fe===10?(Ee===103&&de===null||Ee===82&&de===null)&&(de=p(a,Ue,je)):fe===12?Ee===103&&a.charCodeAt(he+8)===97&&Ce===null?Ce=h(a,Ue,je):Ee===80&&$e===null?$e=h(a,Ue,je):Ee===72&&Pe===null&&(Pe=p(a,Ue,je)):fe===13?(Ee===103||Ee===71)&&ee===null&&(ee=p(a,Ue,je)):fe===14?(Ee===103||Ee===71)&&L===null?L=p(a,Ue,je):Ee===65&&Ce===null&&(Ce=h(a,Ue,je)):fe===11&&Ee===84&&Ce===null&&(Ce=h(a,Ue,je));let dt=be+2+fe;if(a.charCodeAt(dt)===62)V=dt+1;else{let It=a.indexOf(">",be+2);V=It!==-1?It+1:be+2}if(Ne!==null&&Pe!==null&&de!==null&&Ce!==null)break}else V=be}let Ae=null;L!=null&&ee!=null&&ee!==0?Ae=L/ee:te!=null&&ge!=null&&ge!==0&&(Ae=te/ge),Re.push({lat:_,lon:oe,ele:re,time:K,hr:Pe,cad:de,power:$e,speed:We,temp:Ce,gearFront:te,gearRear:ge,gearFrontTooth:L,gearRearTooth:ee,battery:Ne,gears:Ae})}if(!Re.length)throw new Error("No track points found in GPX");let ae=e(Re),pe=n(ae);return{name:U,device:Le,format:"gpx",points:ae,stats:pe}}function Y(y,d){let a=d??new TextDecoder().decode(y),G=a.indexOf(""),X=G!==-1?a.slice(0,G):a,se=M(X,"","")||"Unnamed TCX",U=M(X,"",""),ne=U?M(U,"",""):null,Le=[],Re=G!==-1?G:0;for(;Re",Re);if(pe===-1)break;let ye=a.indexOf("",pe+12);if(ye===-1)break;Re=ye+13;let He=null,Q=null,_=null,oe=null,re=null,K=null,Pe=null,de=null,$e=null,Ce=null,We=null,te=null,ge=null,L=null,ee=pe+12;for(;ee=ye)break;let Ae=a.indexOf(">",V+1);if(Ae===-1||Ae>=ye)break;let he=a.charCodeAt(V+1);if(he===47){ee=Ae+1;continue}let xe=Ae-V-1,Ee=a.indexOf("<",Ae+1);if(Ee===-1||Ee>ye)break;if(a.charCodeAt(Ee+1)===47){let fe=Ae+1,be=Ee;xe===4?he===84?a.charCodeAt(V+2)===105?oe=F(a,fe,be):$e===null&&($e=h(a,fe,be)):he===116&&$e===null&&($e=h(a,fe,be)):xe===5?he===86&&re===null?re=p(a,fe,be):(he===87||he===80||he===112)&&Pe===null?Pe=h(a,fe,be):(he===83||he===115)&&de===null?de=h(a,fe,be):he===97&&$e===null&&($e=h(a,fe,be)):xe===7?he===67&&K===null?K=p(a,fe,be):(he===66||he===98)&&L===null&&(L=p(a,fe,be)):xe===8?(he===71||he===103)&&We===null&&(We=p(a,fe,be)):xe===9?(he===71||he===103)&&Ce===null&&(Ce=p(a,fe,be)):xe===10?he===82&&K===null&&(K=p(a,fe,be)):xe===11?he===84&&$e===null&&($e=h(a,fe,be)):xe===13?(he===71||he===103)&&ge===null&&(ge=p(a,fe,be)):xe===14?he===65?a.charCodeAt(V+2)===108?_=h(a,fe,be):$e===null&&($e=h(a,fe,be)):(he===71||he===103)&&te===null&&(te=p(a,fe,be)):xe===15?he===76&&(He=h(a,fe,be)):xe===16?he===76&&(Q=h(a,fe,be)):xe===2&&he===104&&re===null?re=p(a,fe,be):xe===3&&he===99&&K===null?K=p(a,fe,be):xe===12&&(he===72&&re===null?re=p(a,fe,be):he===80&&Pe===null&&(Pe=h(a,fe,be)));let Ue=Ee+2+xe;if(a.charCodeAt(Ue)===62)ee=Ue+1;else{let je=a.indexOf(">",Ee+2);ee=je!==-1?je+1:Ee+2}if(L!==null&&re!==null&&K!==null&&$e!==null)break}else ee=Ee}if(He==null||Q==null)continue;let Ne=null;te!=null&&ge!=null&&ge!==0?Ne=te/ge:Ce!=null&&We!=null&&We!==0&&(Ne=Ce/We),Le.push({lat:He,lon:Q,ele:_,time:oe,hr:re,cad:K,power:Pe,speed:de,temp:$e,gearFront:Ce,gearRear:We,gearFrontTooth:te,gearRearTooth:ge,battery:L,gears:Ne})}let Be=e(Le),ae=n(Be);return{name:se,device:ne,format:"tcx",points:Be,stats:ae}}function B(y){if(y.byteLength<14)return null;let d=new DataView(y),a=d.getUint8(0);if(a<12||a+2>y.byteLength||d.getUint8(8)!==46||d.getUint8(9)!==70||d.getUint8(10)!==73||d.getUint8(11)!==84)return null;let G=d.getUint32(4,!0),X=Math.min(y.byteLength,a+G),se=631065600,U=180/Math.pow(2,31),ne=new Array(16),Le=[],Re=[],Be=[],ae=[],pe=[],ye=a;for(;yeX)return null;ye++;let oe=d.getUint8(ye++)===0,re=d.getUint16(ye,oe);ye+=2;let K=d.getUint8(ye++);if(ye+K*3>X)return null;let Pe=new Array(K),de=0;for(let $e=0;$eX)return null;let oe=_.littleEndian,re=_.globalMsgNum;if(re===20&&_.fields.length===10&&_.recordSize===25&&_.fields[0].num===253&&_.fields[1].num===0){let de=d.getUint32(ye,oe),$e=d.getInt32(ye+4,oe),Ce=d.getInt32(ye+8,oe),We=d.getUint16(ye+12,oe),te=d.getUint8(ye+14),ge=d.getUint8(ye+15),L=d.getUint32(ye+16,oe),ee=d.getUint16(ye+20,oe),Ne=d.getUint16(ye+22,oe),V=d.getInt8(ye+24);Be.push({timestamp:(de+se)*1e3,position_lat:$e*U,position_long:Ce*U,altitude:We/5-500,heart_rate:te,cadence:ge,distance:L/100,speed:ee/1e3*3.6,power:Ne,temperature:V}),ye+=25;continue}let K={},Pe=ye;for(let de=0;de<_.fields.length;de++){let $e=_.fields[de],Ce=0,We=$e.type&31;$e.size===1?Ce=We===1?d.getInt8(Pe):d.getUint8(Pe):$e.size===2?Ce=We===3?d.getInt16(Pe,oe):d.getUint16(Pe,oe):$e.size===4&&(Ce=We===5?d.getInt32(Pe,oe):d.getUint32(Pe,oe)),K[$e.num]=Ce,Pe+=$e.size}if(ye+=_.recordSize,re===0)Le.push({type:K[0]===4?"activity":K[0],manufacturer:K[1]===1?"garmin":K[1],product:K[2],time_created:K[4]!=null?(K[4]+se)*1e3:void 0});else if(re===18){let de={0:"generic",1:"running",2:"cycling"};Re.push({start_time:K[2]!=null?(K[2]+se)*1e3:void 0,sport:de[K[5]]??String(K[5]),sub_sport:K[6]===0?"generic":String(K[6])})}else if(re===20)Be.push({timestamp:K[253]!=null?(K[253]+se)*1e3:void 0,position_lat:K[0]!=null?K[0]*U:void 0,position_long:K[1]!=null?K[1]*U:void 0,altitude:K[2]!=null?K[2]/5-500:void 0,heart_rate:K[3],cadence:K[4],distance:K[5]!=null?K[5]/100:void 0,speed:K[6]!=null?K[6]/1e3*3.6:void 0,power:K[7],temperature:K[13]});else if(re===21){let de=K[0]===43?"rear_gear_change":K[0]===42?"front_gear_change":String(K[0]);ae.push({timestamp:K[253]!=null?(K[253]+se)*1e3:void 0,event:de,event_type:K[1]===3?"marker":String(K[1]),data:K[3],front_gear_num:K[9],rear_gear_num:K[11]})}else if(re===23)pe.push({timestamp:K[253]!=null?(K[253]+se)*1e3:void 0,battery_level:K[32]});else return null}}return{file_ids:Le,sessions:Re,sports:[],records:Be,events:ae,device_infos:pe}}function z(y){return new Promise((d,a)=>{let G=(U,ne)=>{if(U){a(U);return}try{let Le=ne.sessions?.[0]?.start_time?`Fit Activity ${new Date(ne.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",Re=null,Be=[],ae=null,pe=null;ne.sports?.[0]?(ae=ne.sports[0].sport,pe=ne.sports[0].sub_sport):ne.sessions?.[0]&&(ae=ne.sessions[0].sport,pe=ne.sessions[0].sub_sport);let ye=L=>L.product_name||L.garmin_product||L.product||L.device_type||L.manufacturer||null;if(ne.file_ids?.[0]){let L=ne.file_ids[0];Re=ye(L),Be.push({name:L.product_name||L.garmin_product||L.product,manufacturer:L.manufacturer,serial:L.serial_number?String(L.serial_number):void 0,version:L.software_version?String(L.software_version):void 0,type:"main"})}ne.device_infos&&ne.device_infos.forEach(L=>{if(L.device_index==="creator"||L.device_index===0){let Ne=ye(L);(L.product_name||L.garmin_product||!Re)&&(Re=Ne),Be.length>0&&Be[0].type==="main"&&((L.product_name||L.garmin_product||!Be[0].name)&&(Be[0].name=L.product_name||L.garmin_product||L.product),Be[0].manufacturer||(Be[0].manufacturer=L.manufacturer),!Be[0].serial&&L.serial_number&&(Be[0].serial=String(L.serial_number)),!Be[0].version&&L.software_version&&(Be[0].version=String(L.software_version)),!Be[0].hardwareVersion&&L.hardware_version&&(Be[0].hardwareVersion=String(L.hardware_version)));return}Be.push({name:L.product_name||L.garmin_product||L.product||L.device_type||"Sensor",manufacturer:L.manufacturer,serial:L.serial_number?String(L.serial_number):void 0,version:L.software_version?String(L.software_version):void 0,hardwareVersion:L.hardware_version?String(L.hardware_version):void 0,type:L.device_type||"sensor",batteryStatus:L.battery_status,batteryVoltage:L.battery_voltage,batteryLevel:L.battery_level,sourceType:L.source_type!=null?String(L.source_type):void 0})}),ne.sensor_settings&&ne.sensor_settings.forEach(L=>{let ee=L.name||L.product||L.sensor_type;if(!ee)return;let Ne=L.ant_id?String(L.ant_id):void 0,V=Be.find(Ae=>Ne&&Ae.serial===Ne||Ae.name===ee&&Ae.manufacturer===L.manufacturer);V?(V.name||(V.name=ee),V.manufacturer||(V.manufacturer=L.manufacturer),V.type||(V.type=L.sensor_type),V.sourceType||(V.sourceType=L.connection_type!=null?String(L.connection_type):void 0)):Be.push({name:ee,manufacturer:L.manufacturer,serial:Ne,type:L.sensor_type||"sensor",sourceType:L.connection_type!=null?String(L.connection_type):void 0})});let He=[];ne.device_statuses&&(ne.device_statuses.forEach((L,ee)=>{L.timestamp&&L.battery_level!=null&&He.push({time:typeof L.timestamp=="number"?L.timestamp:new Date(L.timestamp).getTime(),level:L.battery_level,idx:ee})}),He.sort((L,ee)=>L.time-ee.time||L.idx-ee.idx));let Q=[];ne.events&&(ne.events.forEach((L,ee)=>{let Ne=L.front_gear_num??L.front_gear??null,V=L.rear_gear_num??L.rear_gear??null,Ae=L.front_gear_num_tooth??null,he=L.rear_gear_num_tooth??null;if(L.event==="rear_gear_change"||L.event==="front_gear_change"){let xe=L.data;if(xe!=null){let Ee=xe>>24&255,fe=xe>>16&255,be=xe>>8&255,Ue=xe&255;fe!==0&&(Ne=fe),Ee!==0&&(Ae=Ee),Ue!==0&&(V=Ue),be!==0&&(he=be)}}L.timestamp&&(Ne!=null||V!=null||Ae!=null||he!=null)&&Q.push({time:typeof L.timestamp=="number"?L.timestamp:new Date(L.timestamp).getTime(),front:Ne,rear:V,frontTooth:Ae,rearTooth:he,idx:ee})}),Q.sort((L,ee)=>L.time-ee.time||L.idx-ee.idx));let _=ne.records||[],oe=null,re=0,K=null,Pe=null,de=null,$e=null,Ce=0,We=[];for(let L=0;L<_.length;L++){let ee=_[L],Ne=ee.position_lat,V=ee.position_long;if(Ne==null||V==null)continue;let Ae=ee.timestamp!=null?typeof ee.timestamp=="number"?ee.timestamp:ee.timestamp instanceof Date?ee.timestamp.getTime():new Date(ee.timestamp).getTime():null,he=ee.speed!=null?ee.speed/3.6:null,xe=ee.battery_level??null;if(xe==null&&Ae){for(;re name, Placemark > name");X&&(G=X.textContent?.trim()||G);let se=a.querySelectorAll("coordinates");if(!se.length)throw new Error("No coordinates found in KML");let U=[];if(se.forEach(Re=>{(Re.textContent?.trim().split(/\s+/)||[]).forEach(ae=>{let pe=ae.split(",");if(pe.length<2)return;let ye=parseFloat(pe[0]),He=parseFloat(pe[1]),Q=pe.length>2?parseFloat(pe[2]):null;isNaN(He)||isNaN(ye)||U.push({lat:He,lon:ye,ele:Q!=null&&isNaN(Q)?null:Q,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!U.length)throw new Error("No valid coordinates in KML");let ne=e(U),Le=n(ne);return{name:G,format:"kml",points:ne,stats:Le}}async function le(y){let d=y.name.split(".").pop()?.toLowerCase(),a=y._buf??await y.arrayBuffer(),G=y._text,X;switch(d){case"gpx":X=J(a,G);break;case"tcx":X=Y(a,G);break;case"fit":X=await z(a);break;case"kml":X=D(a);break;default:throw new Error(`Unsupported format: .${d}`)}return X&&(X.fileName=y.name,X.fileSize=y.size),X}return{parseFile:le,computeStats:n,ensureCurvesAndZones:o,calculatePowerCurve:c,calculateHRCurve:m,calculatePowerZones:T,calculateHRZones:R,enrichPoints:e,setHRZones:S,getHRZones:k,setFTP:b,getFTP:w}})();var _e=(()=>{let e={},s=null;function t(D,le,y,d,a){}function n(D){}function o(D){e[D.id]=D}function r(D){D.forEach(le=>{e[le.id]=le})}function u(D){delete e[D]}function c(){e={}}function m(){e={}}function T(D,le){}function b(D,le){}function w(){}function R(D){}function S(D,le){}function k(){}function M(D,le,y,d,a,G){}function g(){}function I(D,le){}function P(D){}function p(D,le,y,d){}function h(){}function F(){}function q(){return[0,0,0]}function J(D,le,y){}function Y(D,le,y){}function B(D){}function z(D,le){return Object.keys(e)}return{init:t,getMap:()=>null,setCustomClickHandler:D=>{s=D},switchBasemap:n,addTrack:o,addTracks:r,removeTrack:u,clearTracks:c,removeAllTracks:m,setTrackVisible:T,setSelectedTrack:b,fitAll:w,fitTrack:R,showCursorAt:S,hideCursor:k,highlightSegment:M,clearHighlight:g,setTrackHover:I,ensureVisible:P,centerOn:p,closePopup:h,invalidateSize:F,getPosition:q,setPosition:J,colorTrackByMetric:Y,clearMetricColor:B,findTracksPassingThroughPoints:z,getTrackData:D=>e[D]}})();import Us from"uplot";var gn=(()=>{function e(){let t=it.getFTP(),n=[.55,.75,.9,1.05,1.2,1.5].map(m=>m*t),o=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],r=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],u=[],c=0;for(let m=0;ms?e.toFixed(1):Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:De.speed.color,abbr:"spd",icon:De.speed.icon,fmt:e=>(e*3.6).toFixed(1),fmtAxis:e=>(e*3.6).toFixed(0),transform:e=>e,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:De.gradient.color,abbr:"grad",icon:De.gradient.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>e.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:De.power.color,abbr:"pwr",icon:De.power.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:De.hr.color,abbr:"hr",icon:De.hr.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:De.cadence.color,abbr:"cad",icon:De.cadence.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:De.temperature.color,abbr:"temp",icon:De.temperature.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>Math.round(e).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:De.gearRear.color,abbr:"rgr",icon:De.gearRear.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:De.gearFront.color,abbr:"fgr",icon:De.gearFront.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gears:{label:"Gears",field:"gears",unit:"",color:De.gears.color,abbr:"gr",icon:De.gears.icon,fmt:e=>e.toFixed(2),fmtAxis:e=>e.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:De.battery.color,abbr:"bat",icon:De.battery.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString(),smoothSigma:5,compute:(e,s)=>{let t=new Array(e.length).fill(null);for(let n=1;n0&&(t[n]=u/c*3600)}}return s(t)}}};var Wt={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function zs(e){if(!e)return"question_mark";let s=e.toLowerCase();return Wt[s]?.icon||"exercise"}var Me=(()=>{let e=[],s=null,t="time",n="speed",o=null,r=null,u=!1,c=!1,m=new Set(["elevation"]),T=new Set,b=new Set(["speed","gradient","vam","temperature"]),w=new Set(["power"]),R="time",S=null,k=[],M=null,g=null,I=!1,P=!1,p=null,h=null,F=null,q=null,J=null,Y=null,B=null,z=null,D=null,le=null,y=null,d=null,a=130,G=28,X=20,se=!0,U=null,ne=null,Le=null,Re=null,Be=null,ae=null,pe=null;function ye(l,i,f,v){D=l,le=i,y=f,d=v,ne=document.getElementById("charts-container"),ne?.addEventListener("scroll",()=>{F&&J&&q&&pn(F,J,q)}),Le=document.getElementById("chart-empty"),Re=document.getElementById("chart-stats-sel"),Be=document.getElementById("btn-reset-selection"),U=document.getElementById("hist-tooltip"),r=Us.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",ee),Be?.classList.add("hidden");let $=new Set(["w","a","s","d"]),x=new Set;document.addEventListener("keydown",A=>{if(!e.length||!S||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let E=A.key.toLowerCase();if(!$.has(E))return;A.preventDefault(),x.add(E);let H=e[0].uplot;B||(B=[H.scales.x.min,H.scales.x.max]);let[O,N]=B,j=(N-O)*.1,ue=.15,C=O,Se=N;if(E==="a")C=O-j,Se=N-j;else if(E==="d")C=O+j,Se=N+j;else if(E==="w"||E==="s"){let ce=h!==null?h:(O+N)/2,Fe=E==="w"?1-ue:1+ue*1.2;C=ce-(ce-O)*Fe,Se=ce+(N-ce)*Fe}let ke=[e[0].xData[0],e[0].xData[e[0].xData.length-1]];if(Cke[1]){let ce=Se-ke[1];C-=ce,Se-=ce}C=Math.max(ke[0],C),Se=Math.min(ke[1],Se),Se-C>.001&&(B=[C,Se],He(C,Se,!0))}),document.addEventListener("keyup",A=>{let E=A.key.toLowerCase();$.has(E)&&x.delete(E)})}function He(l,i,f=!1){if(!e.length)return;if(!f){e.forEach(({uplot:H})=>H.setScale("x",{min:l,max:i}));return}let v=Y?Y[0]:e[0].uplot.scales.x.min,$=Y?Y[1]:e[0].uplot.scales.x.max;z&&cancelAnimationFrame(z);let x=(H,O,N)=>H+(O-H)*N,A=.25,E=()=>{if(!B)return;let[H,O]=B,N=x(Y[0],H,A),W=x(Y[1],O,A);e.forEach(({uplot:j})=>{j.setScale("x",{min:N,max:W})}),Math.abs(N-H)>1e-4||Math.abs(W-O)>1e-4?z=requestAnimationFrame(E):z=null};z=requestAnimationFrame(E)}function Q(l,i=[],f=!1){p=null,M=null,g=null,k=i,T=new Set(Object.entries(_t).filter(([,v])=>l.points.some($=>$[v.field]!=null)).map(([v])=>v)),m.size===0&&(m=new Set(["elevation"].filter(v=>T.has(v)))),document.querySelectorAll(".metric-pill").forEach(v=>{let $=v,x=$.dataset.metric,A=T.has(x);$.classList.toggle("active",A&&m.has(x)),$.classList.toggle("disabled",!A)}),S=l,f?Ps(l):xe()}function _(){p=null,M=null,g=null,S=null,$n(),Le&&(Le.style.display="flex",Le.innerHTML=` + no_sim +

+ `);let l=document.getElementById("chart-stats");l&&l.classList.add("hidden"),V(),ae=null,pe&&pe(null)}function oe(){z!==null&&(cancelAnimationFrame(z),z=null),m=new Set(["elevation"]),T=new Set,b=new Set(["speed","gradient","vam","temperature"]),w=new Set(["power"]),R="time",k=[],Y=null,B=null,h=null,F=null,q=null,J=null,se=!0,_(),document.querySelectorAll("#metric-pills .metric-pill").forEach(f=>{let v=f;v.classList.toggle("active",m.has(v.dataset.metric)),v.classList.remove("disabled","overflow-hidden")});let l=document.getElementById("pill-overflow");l&&l.classList.add("hidden");let i=document.getElementById("chart-toolbar");i&&i.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(f=>{f.classList.toggle("active",f.dataset.axis==="time")})}function re(l){m.has(l)?m.delete(l):m.add(l),S&&xe(!0)}function K(l){m=new Set(l),S&&xe(!0),document.querySelectorAll(".metric-pill").forEach(i=>{let f=i;f.classList.toggle("active",m.has(f.dataset.metric))})}function Pe(l){if(R===l||!S){R=l;return}let i=S.points,f=i.find(x=>x.time!=null)?.time||0,v=x=>{if(x===null)return null;let A=0;if(R==="distance"){let E=x*1e3;A=i.findIndex(H=>(H.dist||0)>=E)}else{let E=f+x*1e3;A=i.findIndex(H=>(H.time||0)>=E)}return A===-1&&(A=i.length-1),l==="distance"?(i[A].dist||0)/1e3:((i[A].time||f)-f)/1e3};M!==null&&(M=v(M)),g!==null&&(g=v(g));let $=null;if(e.length){let x=e[0].uplot,A=v(x.scales.x.min),E=v(x.scales.x.max);A!==null&&E!==null&&($=[A,E])}R=l,xe(!0),$&&(u=!0,e.forEach(({uplot:x})=>{x.batch(()=>x.setScale("x",{min:$[0],max:$[1]}))}),u=!1)}function de(){se=!se,e.forEach(({histCol:l})=>l.classList.toggle("visible",se)),he()}function $e(l){pe=l}function Ce(l){ae===l||l===null?(ae=null,We(),pe&&pe(null)):(ae=l,We(),te()),S&&xe(!0)}function We(){document.querySelectorAll(".map-color-btn").forEach(l=>{let i=l;i.classList.toggle("active",i.dataset.metric===ae)})}function te(){if(!pe||!ae||!S)return;let l=e.find(f=>f.metricKey===ae);if(!l)return;let i=ge(ae,l.yData);pe({pts:S.points,colors:i})}function ge(l,i){let f=i.filter(W=>W!=null&&isFinite(W));if(!f.length)return i.map(()=>"#888896");let v=Math.min(...f),$=Math.max(...f),x=S?.sport,A=x?Wt[x.toLowerCase()]:null,E=A?.defaultPreset||"speed",O=Ye.get().speed_mode||E,N=A?.paceUnit||"km";return i.map(W=>{if(W==null||!isFinite(W))return"#888896";if(l==="gradient")return Rn(W);if(l==="speed"){if(O==="pace"){let ue=(N==="km"?1e3:100)/W;return Cs(ue)}return Cs(W)}let j=$===v?.5:Math.max(0,Math.min(1,(W-v)/($-v)));return j<=.25?Rt("#4575b4","#91bfdb",j/.25):j<=.5?Rt("#91bfdb","#fee090",(j-.25)/.25):j<=.75?Rt("#fee090","#fc8d59",(j-.5)/.25):Rt("#fc8d59","#d73027",(j-.75)/.25)})}function L(){ee()}function ee(){M=null,g=null,p=null,d&&d(null),e.forEach(l=>{l.pinnedHistY=null}),fe(),It(),u=!0,e.forEach(({uplot:l,xData:i})=>{l.batch(()=>l.setScale("x",{min:i[0],max:i[i.length-1]})),l._strasse?.updateHeaderStats(i[0],i[i.length-1])}),u=!1,le&&le(null,null,R)}function Ne(l){if(!Re)return;let i=(f,v)=>{let $=document.querySelector(`#${f} .stat-value`);$&&($.textContent=v)};i("sel-distance",l.totalDist!=null?`${(l.totalDist/1e3).toFixed(1)} km`:"\u2014"),i("sel-duration",l.duration!=null?ht(Math.floor(l.duration/1e3)):"\u2014"),i("sel-elevation",l.elevGain!=null?`${Math.round(l.elevGain)} m`:"\u2014"),i("sel-avg-speed",l.avgSpeed!=null?`${(l.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),i("sel-avg-power",l.avgPower!=null?`${l.avgPower} W`:"\u2014"),i("sel-avg-hr",l.avgHR!=null?`${l.avgHR} bpm`:"\u2014"),i("sel-avg-temp",l.avgTemp!=null?`${l.avgTemp.toFixed(1)} \xB0C`:"\u2014"),Re.classList.remove("hidden"),Be&&Be.classList.remove("hidden")}function V(){Re&&Re.classList.add("hidden"),Be&&Be.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(l=>{let i=document.querySelector(`#${l} .stat-value`);i&&(i.textContent="--")})}function Ae(l,i,f=!1){if(!S)return;let v=S.points,$=v.find(O=>O.time!=null)?.time||0,x=((v[v.length-1]?.time||0)-$)/1e3;l>1e12&&(l=(l-$)/1e3),i>1e12&&(i=(i-$)/1e3),l=Math.max(0,Math.min(l,x)),i=Math.max(0,Math.min(i,x));let A=O=>{if(R==="time")return O;let N=$+O*1e3,W=v.findIndex(j=>(j.time||0)>=N);return W===-1&&(W=v.length-1),(v[W].dist||0)/1e3},E=A(l),H=A(i);M=E,g=H,Y=[E,H],!f&&(u=!0,e.forEach(({uplot:O})=>{O.batch(()=>O.setScale("x",{min:E,max:H}))}),u=!1,be(),It())}function he(){if(!e.length||!ne)return;let l=Math.round(Math.max(100,ne.getBoundingClientRect().width-G-(se?a+X:0))),i=!1;e.forEach(({uplot:f,histCanvas:v,histData:$})=>{l!==f.width&&(f.setSize({width:l,height:f.height}),i=!0,se&&v&&$&&At(v,$,f.height))}),i&&fe()}function xe(l=!1){let i=null,f=0;if(l&&ne&&(f=ne.scrollTop),l&&Y)i=[Y[0],Y[1]];else if(l&&e.length){let ke=e[0].uplot;i=[ke.scales.x.min,ke.scales.x.max]}if(!S){$n(l);return}let v=S.points;if(!v.length){$n(l);return}let $=S?.sport,x=$?Wt[$.toLowerCase()]:null,A=x?.defaultPreset||"speed",H=Ye.get().speed_mode||A,O=x?.paceUnit||"km",N=[...m].filter(ke=>v.some(ce=>ce[_t[ke].field]!=null));if(!N.length){$n(l),Le&&(Le.style.display="flex",Le.innerHTML=` + no_sim +
No data for selected metrics
+ `);return}Le&&(Le.style.display="none");let W=ne?ne.getBoundingClientRect().width:800,j=Math.round(Math.max(100,W-G-(se?a+X:0))),ue=l&&s===S&&t===R&&n===H&&o===ae&&e.length>0,C;if(ue)C=e[0].xData;else if(R==="distance")C=v.map(ke=>(ke.dist||0)/1e3);else{let ke=v.find(Fe=>Fe.time!=null)?.time||0,ce=0;C=v.map(Fe=>(Fe.time!=null&&(ce=(Fe.time-ke)/1e3),ce))}let Se=new Map;if(ue){U&&(U.style.display="none");let ke=new Set(N);for(let ce of e){let Fe=b.has(ce.metricKey),me=w.has(ce.metricKey);ke.has(ce.metricKey)&&ce.smoothed===Fe&&ce.incZero===me&&ce.w===j?Se.set(ce.metricKey,ce):(r.unsub(ce.uplot),ce.uplot.destroy(),ce.row.remove())}e=[]}else $n(l);if(ne){let ke=new Array(N.length).fill(null),ce=null;for(let Fe=N.length-1;Fe>=0;Fe--){ke[Fe]=ce;let me=Se.get(N[Fe]);me&&(ce=me.row)}N.forEach((Fe,me)=>{let ve=Se.get(Fe);if(ve){e.push(ve);let ie=ve.uplot,Je=ie._strasse,Ge=u;u=!0,ie.batch(()=>{i&&(ie.scales.x.min!==i[0]||ie.scales.x.max!==i[1])?ie.setScale("x",{min:i[0],max:i[1]}):(Je?.updateHeaderStats(ie.scales.x.min,ie.scales.x.max,ie),ie.redraw(!1))}),u=Ge;let Qe=null;if(p!=null&&ve.xData[p]!=null&&ve.yData[p]!=null&&(dt(ve.histData),ve.histData.min!=null&&ve.histData.max!=null)){let rt=ve.histData.max-ve.histData.min||1;Qe=Math.min(ve.histData.BINS-1,Math.floor((ve.yData[p]-ve.histData.min)/rt*ve.histData.BINS)),ve.hoveredHistY=ve.yData[p]}At(ve.histCanvas,ve.histData,130,Qe);return}let Ie=_t[Fe],Ve=Ie.transform,Ze=Ie.fmt,st=Ie.fmtAxis,nt=Ie.unit,ot=Ie.label;Fe==="speed"&&H==="pace"&&(ot="Pace",nt=`min/${O}`,Ze=ie=>An(ie),st=ie=>An(ie),Ve=ie=>ie==null||ie<.1?null:(O==="km"?1e3:100)/ie,Ie={...Ie,label:ot,unit:nt,fmt:Ze,fmtAxis:st,transform:Ve});let lt=Ie.compute?Ie.compute(v,Ls):Ls(v.map(ie=>{let Je=ie[Ie.field];return Je!=null&&Ve?Ve(Je):Je}));b.has(Fe)&&(lt=fn(lt,Ie.smoothSigma||2)),Ee(Fe,Ie,C,lt,j,v,i,ke[me])})}s=S,t=R,n=H,o=ae,Ps(S),M!=null&&g!=null&&be(),We(),ae&&te(),l&&ne&&f>0&&(ne.scrollTop=f)}function Ee(l,i,f,v,$,x,A=null,E=null){let H=S?.sport,N=(H?Wt[H.toLowerCase()]:null)?.defaultPreset||"speed",j=Ye.get().speed_mode||N,ue=l==="elevation"?Sl(x,20):null,C=document.createElement("div");C.className="chart-row",C.dataset.metric=l,C.style.setProperty("--chart-color",i.color);let Se=document.createElement("div");Se.className=`chart-row-header${se?" with-histogram":""}`;let ke=document.createElement("div");ke.className="chart-row-label-group",ke.innerHTML=` + ${i.icon} + ${i.label} + `;let ce=document.createElement("button");ce.className=`icon-btn mini smooth-btn${b.has(l)?" active":""}`,ce.title="Toggle data smoothing",ce.innerHTML=`${b.has(l)?"blur_on":"blur_off"}`,ce.addEventListener("click",Z=>{Z.stopPropagation(),b.has(l)?b.delete(l):b.add(l),xe(!0)});let Fe=document.createElement("button");Fe.className=`map-color-btn icon-btn${ae===l?" active":""}`,Fe.dataset.metric=l,Fe.title="Color map track by this metric",Fe.innerHTML='colorize',Fe.addEventListener("click",()=>Ce(l));let me=null;if(l==="cadence"||l==="power"||l==="speed"){me=document.createElement("button");let Z=w.has(l);me.className=`icon-btn mini${Z?" active":""}`,me.title=Z?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",me.innerHTML=`${Z?"exposure_zero":"mobile_off"}`,me.addEventListener("click",we=>{we.stopPropagation(),w.has(l)?w.delete(l):w.add(l),xe(!0)})}let ve=document.createElement("div");ve.className="chart-stats-total";let Ie=document.createElement("div");Ie.className="chart-stats-selection";let Ve=document.createElement("div");Ve.className="chart-row-stats-container",Ve.append(ve,Ie);let Ze=document.createElement("div");Ze.className="chart-row-actions",Ze.append(ce,Fe);let st=document.createElement("div");if(st.className="chart-row-right-actions",l==="speed"){let Z=document.createElement("div");Z.className="seg-ctrl",Z.innerHTML=` + + + `,Z.addEventListener("click",we=>{let Ke=we.target.closest(".seg-btn");if(!Ke)return;let et=Ke.dataset.mode;if(et==="speed"||et==="pace"){let qe=et===N;Ye.patch({speed_mode:qe?null:et}),xe(!0)}}),st.append(Z)}me&&st.append(me),Se.append(ke,Ze,Ve,st);let nt=document.createElement("div");nt.className="chart-row-body";let ot=document.createElement("div");ot.style.position="relative",nt.appendChild(ot);let lt=document.createElement("div");lt.className="fixed-x-label fixed-x-min";let ie=document.createElement("div");ie.className="fixed-x-label fixed-x-max",ot.append(lt,ie);let Je=document.createElement("div");Je.className=`hist-col${se?" visible":""}`;let Ge=document.createElement("canvas");Ge.className="hist-canvas",Je.appendChild(Ge),nt.appendChild(Je),C.append(Se,nt);let Qe=R==="distance";function rt(Z,we){if(Z==null)return"";if(Qe){let Ke=we<1?3:we<5?2:we<20?1:0;return`${Z.toFixed(Ke)} km`}else{let Ke=Math.abs(Z),et=Math.floor(Ke/3600),qe=Math.floor(Ke%3600/60),xt=Math.round(Ke%60),gt=et>0?`${et}:`:"",Nt=et>0?String(qe).padStart(2,"0"):String(qe),$t=String(xt).padStart(2,"0");return`${Z<0?"-":""}${gt}${Nt}:${$t}`}}let ut=w.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",mt=1/0,Xe=-1/0,ct=0,vt=0,St=1/0,Yt=-1/0,Et=0,Jt=0;for(let Z=0;ZXe&&(Xe=we),ct+=we,vt++,(we!==0||ut)&&(weYt&&(Yt=we),Et+=we,Jt++))}vt===0&&(mt=0,Xe=100);let is=vt?{min:mt,max:Xe,avg:ct/vt}:null,Nn=Jt?{min:St,max:Yt,avg:Et/Jt}:null,As=Math.abs(Xe-mt)*.1||1,kl=[mt-As,Xe+As],Hs=!1;function as(Z,we,Ke){let et=w.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",qe=we-Z;lt.textContent=rt(Z,qe),ie.textContent=rt(we,qe);let xt=(gt,Nt,$t=!1)=>{let Ht=$t&&et===ut?Nn:Ts(f,v,gt,Nt,et);if(!Ht)return"";let Kt=` + align_flex_end${i.fmt(Ht.min,!0)} ${i.unit} + align_center${i.fmt(Ht.avg,!0)} ${i.unit} + align_flex_start${i.fmt(Ht.max,!0)} ${i.unit} + `;if(l==="elevation"){let Ut=vl(x,gt,Nt);Kt+=` + trending_up+${Math.round(Ut.gain)} m + trending_down-${Math.round(Ut.loss)} m + `}return Kt};Hs||(Hs=!0,ve.innerHTML=`all_inclusive${xt(f[0],f[f.length-1],!0)}`,ve.querySelector(".all-chip")?.addEventListener("click",gt=>{gt.stopPropagation(),ee()})),M!==null&&g!==null?(Ie.innerHTML=xt(M,g,!1),Ie.style.display="flex",Ie.style.setProperty("--sel-color",i.color)):Ie.style.display="none"}let $l=!1,Cl={width:$,height:130,padding:[4,0,0,0],cursor:{sync:{key:r.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:l==="elevation"?(Z,we)=>Rn(ue?ue[Z.cursor.idx]:null):i.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(Z,we,Ke)=>[we,Ke],min:A?A[0]:void 0,max:A?A[1]:void 0},y:{range:()=>kl,dir:l==="speed"&&j==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(Z,we,Ke,et)=>{let qe=et-Ke,gt=(Z.bbox.width>0?Z.bbox.width:Z.width)/80,Nt=qe/gt,$t;Qe?$t=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:$t=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let Ht=$t[$t.length-1];for(let qt=0;qt<$t.length;qt++)if($t[qt]>=Nt){Ht=$t[qt];break}let Kt=[],Ut=Math.ceil(Ke/Ht)*Ht,Zn=Ht<1?2:0;for(;Ut<=et;){let qt=Z.valToPos(Ut,"x",!0);qt>=Z.bbox.left+80&&qt<=Z.bbox.left+Z.bbox.width-80&&Kt.push(Number(Ut.toFixed(Zn))),Ut+=Ht}return Kt},values:(Z,we)=>{let Ke=(Z.scales.x?.max??1)-(Z.scales.x?.min??0);return we.map(et=>{if(et==null)return"";let qe=Z.valToPos(et,"x",!0);return qeZ.bbox.left+Z.bbox.width-80?null:rt(et,Ke)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(Z,we)=>we.map(Ke=>Ke!=null?i.fmtAxis(Ke):"")}],series:[{},{label:i.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[Z=>{let we=Z.bbox.top+Z.bbox.height+5;lt.style.top=`${we}px`,lt.style.left=`${Z.bbox.left}px`,ie.style.top=`${we}px`,ie.style.left=`${Z.bbox.left+Z.bbox.width}px`,ie.style.transform="translateX(-100%)"},Z=>{l==="gears"?Is(Z,f,v,i.color,1.5,l,null,x):l==="elevation"?yl(Z,f,v,ue):l==="gradient"?xl(Z,f,v):ae===l?Ml(Z,f,v,x,l):Is(Z,f,v,i.color,1.5,l,null,x)},Z=>{let we=e.find(et=>et.uplot===Z);if(!we)return;let Ke=Z._strasse;p!=null?wl(Z,f,v,i.color,i,x,l):(Ke&&Ke.pinYVal&&(Ke.pinYVal.style.display="none"),we.pinnedHistY!=null&&Tl(Z,f,v,we.pinnedHistY,i.color,i))},Z=>{let we=Z.cursor.idx,Ke=p!=null,et=we!=null&&Z.cursor.left>=0;if(et&&p==null){let qe=Z.valToPos(v[we],"y",!0);Math.abs(Z.cursor.top-qe)>100&&(et=!1)}if(et&&we!==p&&ks(Z,x,we,tt(i.color,.4),1),M!=null&&g!=null){let qe=Z.ctx,xt=window.devicePixelRatio||1,gt=Z.bbox,Nt=Z.valToPos(M,"x",!0),$t=Z.valToPos(g,"x",!0);qe.save(),qe.beginPath(),qe.lineWidth=3*xt,qe.strokeStyle=i.color,qe.moveTo(Nt,gt.top+gt.height),qe.lineTo($t,gt.top+gt.height),qe.stroke();let Ht=Math.abs(g-M),Kt=R==="distance"?`${Ht.toFixed(2)} km`:ht(Ht),Ut=9*xt,Zn=`bold ${Ut}px system-ui, sans-serif`;qe.font!==Zn&&(qe.font=Zn);let qt=qe.measureText(Kt).width,Bs=Math.max(gt.left,Nt),Fs=Math.min(gt.left+gt.width,$t);if(Fs-Bs>qt+14*xt){let Pl=5*xt,Il=2*xt,Gn=qt+Pl*2,Xn=Ut+Il*2,cs=(Bs+Fs)/2-Gn/2,ds=gt.top+gt.height-Xn/2;qe.beginPath(),qe.roundRect?qe.roundRect(cs,ds,Gn,Xn,3*xt):qe.rect(cs,ds,Gn,Xn),qe.fillStyle=i.color,qe.fill(),qe.fillStyle="#000",qe.textAlign="center",qe.textBaseline="middle",qe.fillText(Kt,cs+Gn/2,ds+Xn/2)}qe.restore()}Ke&&$s(Z,x,p,i.color,!0,.7),et&&we!==p&&$s(Z,x,we,i.color,!0,1)}],setCursor:[Z=>{if(u)return;let we=Z.cursor.idx;Z.redraw(!1),Z.cursor.left>=0?h=Z.posToVal(Z.cursor.left,"x"):h=null;let Ke=Z._strasse,et=we!=null&&v[we]!=null;if(et&&p==null){let qe=Z.valToPos(v[we],"y",!0);Math.abs(Z.cursor.top-qe)>100&&(et=!1)}if(Ke&&(et?Es(Z,Ke.curYVal,we,f,v,x,i,l):Ke.curYVal.style.display="none"),c||(we!=null&&x[we]?D&&(p!=null||et)?D(x[we]):D&&!et&&D(null):we===null&&D&&D(null)),we!=null&&v[we]!=null){let{min:qe,max:xt}=yt;if(qe!=null&&xt!=null){let gt=xt-qe||1,Nt=Math.min(yt.BINS-1,Math.floor((v[we]-qe)/gt*yt.BINS));Qt.hoveredHistY!==v[we]&&(Qt.hoveredHistY=v[we],At(Ge,yt,130,Nt))}}else Qt.hoveredHistY!==null&&(Qt.hoveredHistY=null,At(Ge,yt,130))}],setScale:[(Z,we)=>{if(we!=="x"||$l)return;let{min:Ke,max:et}=Z.scales.x;Y=[Ke,et],as(Ke,et,Z),!u&&(P||(B=null),u=!0,e.forEach(({uplot:qe})=>{qe!==Z&&qe.batch(()=>qe.setScale("x",{min:Ke,max:et}))}),u=!1,fe(),It(),le&&M!==null&&le(M,g,R))}],setSelect:[Z=>{if(P)return;B=null;let{left:we,width:Ke}=Z.select;if(Ke>0){let et=Z.posToVal(we,"x"),qe=Z.posToVal(we+Ke,"x");M=et,g=qe,as(Z.scales.x.min,Z.scales.x.max,Z),fe(),It(),le&&le(M,g,R),Z.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},rs=document.createElement("div");rs.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let Wn=document.createElement("div");Wn.className="sel-fill",Wn.style.display="none";let zn=document.createElement("div");zn.className="sel-line sel-line-anchor",zn.style.display="none";let Un=document.createElement("div");Un.className="sel-line-label sel-line-label-anchor",Un.style.display="none";let Cn=document.createElement("div");Cn.className="sel-handle sel-handle-anchor",Cn.style.display="none";let Ln=document.createElement("div");Ln.className="sel-graph-marker",Ln.innerHTML=`play_circle`,Ln.style.display="none";let qn=document.createElement("div");qn.className="sel-line sel-line-end",qn.style.display="none";let Vn=document.createElement("div");Vn.className="sel-line-label sel-line-label-end",Vn.style.display="none";let Pn=document.createElement("div");Pn.className="sel-handle sel-handle-end",Pn.style.display="none";let In=document.createElement("div");In.className="sel-graph-marker",In.innerHTML=`stop_circle`,In.style.display="none";let On=document.createElement("div");On.className="cur-y-val",On.style.cssText=`color:${i.color};display:none`;let Yn=document.createElement("div");Yn.className="cur-y-val pin",Yn.style.cssText=`color:${i.color};display:none`,rs.append(Wn,zn,Un,Cn,Ln,qn,Vn,Pn,In,On,Yn);let yt={yData:v,xData:f,def:i,BINS:24,min:vt?mt:void 0,max:vt?Xe:void 0,fullStats:Nn,fullStatsAll:is},Qt={uplot:null,row:C,xData:f,yData:v,def:i,metricKey:l,statsTotalEl:ve,statsSelEl:Ie,histCol:Je,histCanvas:Ge,histData:yt,hoveredHistY:null,pinnedHistY:null,smoothed:b.has(l),incZero:w.has(l),w:$};yt.plot=Qt;let Ll=u;u=!0;let jt=new Us(Cl,[f,v],(Z,we)=>{Qt.uplot=Z,e.push(Qt),ot.appendChild(Z.root),Z.over.appendChild(rs),Z._strasse={selFill:Wn,anchorLine:zn,anchorLabel:Un,anchorHandle:Cn,anchorMarker:Ln,endLine:qn,endLabel:Vn,endHandle:Pn,endMarker:In,curYVal:On,pinYVal:Yn,updateHeaderStats:as},Z.batch(()=>{we()})});u=Ll,je(Cn,jt,f,!0),je(Pn,jt,f,!1);let jn=null;jt.over.addEventListener("mousedown",Z=>{if(Z.button!==0)return;I=!1;let we=jt.over.getBoundingClientRect();jn=Z.clientX-we.left}),jt.over.addEventListener("mousemove",Z=>{if(jn!==null){let we=jt.over.getBoundingClientRect();Math.abs(Z.clientX-we.left-jn)>5&&(I=!0)}}),jt.over.addEventListener("mouseup",()=>{jn=null}),jt.over.addEventListener("click",()=>{if(I)return;let Z=jt.cursor.idx;Z!=null&&x[Z]&&(p=Z,e.forEach(({uplot:we})=>we.redraw(!1)),y&&y(x[Z],Z),d&&d(Z))}),C.addEventListener("dblclick",ee);let _s=null;if(p!=null&&f[p]!=null&&v[p]!=null&&(dt(yt),yt.min!=null&&yt.max!=null)){let Z=yt.max-yt.min||1;_s=Math.min(yt.BINS-1,Math.floor((v[p]-yt.min)/Z*yt.BINS)),Qt.hoveredHistY=v[p]}At(Ge,yt,130,_s),Xt(Ge,yt),ne&&(E?ne.insertBefore(C,E):ne.appendChild(C))}function fe(){be(),e.forEach(({uplot:l})=>l.batch(()=>l.redraw(!1)))}function be(){e.forEach(({uplot:l,def:i})=>{let f=l._strasse;if(!f)return;let{selFill:v,anchorLine:$,anchorLabel:x,anchorHandle:A,anchorMarker:E,endLine:H,endLabel:O,endHandle:N,endMarker:W}=f;if(M==null||g==null){[v,$,x,A,E,H,O,N,W].forEach(Ze=>{Ze.style.display="none"});return}let j=l.valToPos(M,"x"),ue=l.valToPos(g,"x"),C=window.devicePixelRatio||1,Se=l.bbox,ke=Se.width/C,ce=Se.height/C,Fe=(Se.top+Se.height)/C,me=j>=0&&j<=ke,ve=ue>=0&&ue<=ke,Ie=Math.max(0,j),Ve=Math.min(ke,ue);if(Ve>Ie?(v.style.left=`${Ie}px`,v.style.width=`${Ve-Ie}px`,v.style.top="0",v.style.height=`${ce}px`,v.style.backgroundColor=tt(i.color,.07),v.style.display=""):v.style.display="none",me){$.style.left=`${j}px`,$.style.height=`${ce}px`,$.style.borderLeftColor=i.color,$.style.display="";let Ze=Ue(M);x.textContent=Ze;let st=Ze.length*7+10;x.style.left=j+st+4Ze.style.display="none");if(ve){H.style.left=`${ue}px`,H.style.height=`${ce}px`,H.style.borderLeftColor=i.color,H.style.display="";let Ze=Ue(g);O.textContent=Ze;let st=Ze.length*7+10;O.style.left=ue-st-3>0?`${ue-st-3}px`:`${ue+3}px`,O.style.display="",N.style.left=`${ue}px`,N.style.backgroundColor=i.color,N.style.display="",W.style.left=`${ue}px`,W.style.top=`${Fe}px`;let nt=W.querySelector(".material-symbols-rounded");nt&&(nt.style.color=i.color),W.style.display=""}else[H,O,N,W].forEach(Ze=>Ze.style.display="none")})}function Ue(l){return R==="distance"?`${l.toFixed(2)} km`:ht(l)}function je(l,i,f,v){l.style.pointerEvents="auto",l.addEventListener("mousedown",$=>{$.stopPropagation(),$.preventDefault();let x=$.clientX,A=v?M:g,E=i.over.offsetWidth,H=i.scales.x.min,O=i.scales.x.max,N=E/(O-H),W=[f[0],f[f.length-1]];document.body.style.cursor="ew-resize",I=!0;function j(C){let Se=C.clientX-x,ke=(A||0)+Se/N;ke=Math.max(W[0],Math.min(W[1],ke)),v?M=Math.min(ke,(g||W[1])-.001):g=Math.max(ke,(M||W[0])+.001),e.forEach(ce=>ce.uplot._strasse?.updateHeaderStats(ce.uplot.scales.x.min,ce.uplot.scales.x.max)),fe(),It(),le&&le(M,g,R)}function ue(){document.body.style.cursor="",I=!1,document.removeEventListener("mousemove",j),document.removeEventListener("mouseup",ue)}document.addEventListener("mousemove",j),document.addEventListener("mouseup",ue)})}function dt(l){let{yData:i,xData:f,BINS:v}=l;if(l._lastYData===i&&l.bins)return;l._lastYData=i;let $=l.min,x=l.max;if($==null||x==null){let W=1/0,j=-1/0,ue=0;for(let C=0;Cj&&(j=Se),ue++)}if(!ue)return;$=W,x=j,l.min=$,l.max=x}let A=new Array(v).fill(0),E=new Array(v).fill(0),H=x-$||1,O=l.plot?.metricKey??Object.keys(_t).find(W=>_t[W]===l.def),N=!O||w.has(O)||O!=="power"&&O!=="cadence"&&O!=="speed";for(let W=0;W0&&f[W-1]!=null?f[W-1]:f[W],Se=W{At(l,i,f.height)})}function At(l,i,f,v=null){let{def:$,BINS:x}=i;dt(i);let{bins:A,min:E,max:H}=i;if(!A||E==null||H==null)return;let O=M!=null&&g!=null;if(O&&(i._lastSelRange?.[0]!==M||i._lastSelRange?.[1]!==g)){i._lastSelRange=[M,g];let ie=new Array(x).fill(0),Je=new Array(x).fill(0),{yData:Ge,xData:Qe}=i,rt=H-E||1,ut=i.plot?.metricKey??Object.keys(_t).find(Xe=>_t[Xe]===i.def),mt=!ut||w.has(ut)||ut!=="power"&&ut!=="cadence"&&ut!=="speed";for(let Xe=0;Xeg)continue;let St=Math.min(x-1,Math.floor((ct-E)/rt*x));ie[St]++;let Yt=Xe>0&&Qe[Xe-1]!=null?Qe[Xe-1]:Qe[Xe],Et=Xe$.fmtAxis(ie),ce="9px system-ui, sans-serif";C.font!==ce&&(C.font=ce);let me={t:4,r:0,b:30,l:Math.ceil(Math.max(C.measureText(`${ke(H)} ${$.unit}`).width,C.measureText(`${ke(E)} ${$.unit}`).width))+6};i.padL=me.l;let ve=j-me.l-me.r,Ie=ue-me.t-me.b,Ve=ie=>me.t+(x-1-ie)*(Ie/x),Ze=Ie/x-1,st=O?.15:.6;C.fillStyle=tt($.color,st);for(let ie=0;ieie+Je,0);if(nt>0){let ie=[{x:me.l,y:me.t+Ie}],Je=0;for(let Ge=0;GeGe+Qe+2&&ie0){let ie=0;for(let ct=0;ct{let $=Ot(l,i,v);if($!=null&&f){let{min:x,max:A,BINS:E}=i,H=A-x||1;f.pinnedHistY=x+($+.5)*(H/E),e.forEach(({uplot:O})=>O.redraw(!1))}}),l.addEventListener("mousemove",v=>{F=v,pn(v,l,i)}),l.addEventListener("mouseenter",()=>{J=l,q=i}),l.addEventListener("mouseleave",()=>{J===l&&(J=null,q=null),U&&(U.style.display="none");let v=document.getElementById("hist-line");v&&(v.style.display="none"),f&&(f.hoveredHistY=null,At(l,i,l.height/(window.devicePixelRatio||1)))})}function Ot(l,i,f){let{bins:v,BINS:$}=i;if(!v)return null;let x=l.getBoundingClientRect(),A=f.clientY-x.top,E={t:4,b:30},H=x.height-E.t-E.b,O=Math.floor((A-E.t)/H*$),N=$-1-O;return O<0||O>=$?null:N}function pn(l,i,f){if(!U)return;let{bins:v,binAccum:$,min:x,max:A,BINS:E,def:H,plot:O}=f;if(!v||!$||x==null||A==null)return;let N=document.getElementById("hist-line"),W=Ot(i,f,l);if(W==null||!v[W]){U.style.display="none",N&&(N.style.display="none"),O&&(O.hoveredHistY=null,At(i,f,i.height/(window.devicePixelRatio||1)));return}if(O){let Qe=A-x||1;O.hoveredHistY=x+(W+.5)*(Qe/E),At(i,f,i.height/(window.devicePixelRatio||1),W)}let j=v[W],ue=v.reduce((Qe,rt)=>Qe+rt,0),C=j/ue*100,Se=A-x||1,ke=x+W*(Se/E),ce=x+(W+1)*(Se/E),Fe=`${H.fmt(ke,!0)} \u2013 ${H.fmt(ce,!0)} ${H.unit}`,me="",ve=(ke+ce)/2,Ie=Object.keys(_t).find(Qe=>_t[Qe]===H),Ve=[];if(Ie==="power"?Ve=gn.getPowerZones():Ie==="hr"&&(Ve=gn.getHRZones()),Ve.length>0){let Qe=Ve.findIndex(ut=>ve>=ut.min&&ve=Ve[Ve.length-1].min?Ve[Ve.length-1]:null;if(rt){let ut=Qe!==-1?Qe:Ve.length-1;me=` +
+ Z${ut+1} + \xB7 + ${rt.name} +
+ `}}let Ze=R==="distance"?`${$[W].toFixed(2)} km`:ht($[W]),st=$[W]/$.reduce((Qe,rt)=>Qe+rt,0)*100,nt=` +
${Fe}
+ ${me} + `;if(Ze&&(nt+=`
+ ${R==="distance"?"Dist":"Time"} + ${Ze} + ${st.toFixed(1)}% +
`),f.selBins&&f.selBinAccum){let Qe=R==="distance"?`${f.selBinAccum[W].toFixed(2)} km`:ht(f.selBinAccum[W]),rt=f.selBinAccum[W]/f.selBinAccum.reduce((ut,mt)=>ut+mt,0)*100;nt+=` +
+ Sel ${R==="distance"?"Dist":"Time"} + ${Qe} + ${rt.toFixed(1)}% +
+ `}U.innerHTML=nt,U.style.display="block";let ot=U.offsetHeight,lt=U.offsetWidth,ie=i.getBoundingClientRect(),Je=ie.height-4-30,Ge=ie.top+4+(E-1-W+.5)*(Je/E);U.style.left=`${ie.left-lt-12}px`,U.style.top=`${Ge-ot/2}px`,N&&(N.style.display="block",N.style.top=`${Ge}px`,N.style.left="0px",N.style.width=`${ie.left}px`)}function $n(l=!1){U&&(U.style.display="none"),e.forEach(({uplot:i,row:f})=>{r.unsub(i),i.destroy(),f.remove()}),e=[],s=null,l||(M=null,g=null),I=!1}function Ts(l,i,f,v,$=!0){let x=1/0,A=-1/0,E=0,H=0;for(let O=0;Ov)continue;let N=i[O];N==null||!isFinite(N)||N===0&&!$||(NA&&(A=N),E+=N,H++)}return H?{min:x,max:A,avg:E/H}:null}function vl(l,i,f){let v=0,$=0,x=null,A=R==="distance",E=l[0].time||0;for(let H=0;Hf)&&O.ele!=null){if(x!=null){let W=O.ele-x;W>0?v+=W:W<0&&($+=Math.abs(W))}x=O.ele}}return{gain:v,loss:$}}function Es(l,i,f,v,$,x,A,E){if(f==null||$[f]==null){i.style.display="none";return}let H=l.valToPos(v[f],"x",!1),O=l.valToPos($[f],"y",!1),N="#888896",W=0;if(f>0&&x[f]&&x[f-1]){let ce=x[f-1],Fe=x[f],me=(Fe.dist||0)-(ce.dist||0);me>.1&&Fe.ele!=null&&ce.ele!=null&&(W=(Fe.ele-ce.ele)/me*100,N=Rn(W))}let j=E!=="elevation"?`${A.fmt($[f],!1)} ${A.unit}`:`${A.fmt($[f],!1)} ${A.unit} \u2220 ${Math.abs(W).toFixed(1)}%`;if(E==="gearRear"&&x[f].gearRearTooth!=null)j=`${x[f].gearRearTooth}T (pos ${$[f]})`;else if(E==="gearFront"&&x[f].gearFrontTooth!=null)j=`${x[f].gearFrontTooth}T (pos ${$[f]})`;else if(E==="gears"){let ce=x[f],Fe=ce.gearFrontTooth!=null?`${ce.gearFrontTooth}T`:ce.gearFront!=null?`pos ${ce.gearFront}`:"",me=ce.gearRearTooth!=null?`${ce.gearRearTooth}T`:ce.gearRear!=null?`pos ${ce.gearRear}`:"";(Fe||me)&&(j+=` (${Fe} / ${me})`)}i.innerHTML!==j&&(i.innerHTML=j);let ue=`${A.color}44`;i.style.color!==A.color&&(i.style.color=A.color),i.style.borderColor!==ue&&(i.style.borderColor=ue);let C=`${H}px`,Se=`${O}px`,ke="translate(6px, -50%)";i.style.left!==C&&(i.style.left=C),i.style.top!==Se&&(i.style.top=Se),i.style.transform!==ke&&(i.style.transform=ke),i.style.display!==""&&(i.style.display="")}let Ss=new Map;function Ms(l){let i=Ss.get(l);return i||(i=tt(Rn(l),.8),Ss.set(l,i)),i}function yl(l,i,f,v){let $=l.ctx,x=l.bbox,A=window.devicePixelRatio||1,E=l.scales.x?.min??-1/0,H=l.scales.x?.max??1/0,O=l.scales.y?.min??0,N=l.scales.y?.max??100,W=x.width/(H-E||1),j=x.height/(N-O||1),ue=x.top+x.height,C=l.series[0]?.idxs,Se=C?Math.max(1,C[0]):1,ke=C?Math.min(i.length-1,C[1]+1):i.length-1,ce=Math.max(1,Math.floor((ke-Se)/250));$.save(),$.lineWidth=1.5*A;let Fe=new Map,me=Se-1;for(let ve=Se;ve<=ke;ve+=ce){let Ie=i[ve],Ve=i[me];if(me=ve,Ie==null||f[ve]==null||Ve==null||f[ve-ce]==null||IeH)continue;let Ze=x.left+(Ve-E)*W,st=ue-(f[ve-ce]-O)*j,nt=x.left+(Ie-E)*W,ot=ue-(f[ve]-O)*j,lt=v&&v[ve]!=null?Math.round(v[ve]/2)*2:null,ie=Ms(lt),Je=Fe.get(ie);Je||(Je=[],Fe.set(ie,Je)),Je.push(Ze,st,nt,ot)}for(let[ve,Ie]of Fe){$.beginPath(),$.strokeStyle=ve;for(let Ve=0;VeE)continue;let Ve=$.left+(Ie-A)*N,Ze=j-(f[me-ke]-H)*W,st=$.left+(ve-A)*N,nt=j-(f[me]-H)*W,ot=Math.round(f[me]/2)*2,lt=Ms(ot),ie=ce.get(lt);ie||(ie=[],ce.set(lt,ie)),ie.push(Ve,Ze,st,nt)}for(let[me,ve]of ce){v.beginPath(),v.strokeStyle=me;for(let Ie=0;Ie{let Ie=`bold ${10*A}px system-ui, sans-serif`;H.font!==Ie&&(H.font=Ie);let Ze=H.measureText(ce).width+10*A,st=16*A,nt=Fe-Ze/2,ot=Math.max(E.left,Math.min(E.left+E.width-Ze,nt)),lt=me-st/2;H.save(),H.globalAlpha=x,H.setLineDash([]),H.beginPath(),H.roundRect?H.roundRect(ot,lt,Ze,st,3*A):H.rect(ot,lt,Ze,st),H.fillStyle="rgba(14,14,16,0.92)",H.fill(),H.strokeStyle=tt(v,.27),H.lineWidth=1*A,H.stroke(),H.fillStyle=v,H.textAlign="center",H.textBaseline="middle",H.fillText(ce,ot+Ze/2,lt+st/2+.5*A),H.restore()};$||ks(l,i,f,v,x);let ke=16*A;Se(C,j,E.top+ke/2,!0),Se(ue,j,E.top+E.height+15*A,!1)}function wl(l,i,f,v,$,x,A){if(p==null)return;let E=i[p],H=f[p];if(E==null||H==null)return;let O=l.valToPos(E,"x",!0),N=l.valToPos(H,"y",!0),W=l.bbox,j=l.ctx,ue=window.devicePixelRatio||1;j.save(),j.beginPath(),j.strokeStyle=v,j.lineWidth=1.5*ue,j.moveTo(O,W.top),j.lineTo(O,W.top+W.height),j.stroke(),j.beginPath(),j.setLineDash([3*ue,3*ue]),j.strokeStyle=tt(v,.5),j.lineWidth=1*ue,j.moveTo(W.left,N),j.lineTo(O,N),j.stroke(),j.beginPath(),j.setLineDash([]),j.arc(O,N,5*ue,0,Math.PI*2),j.fillStyle="#0e0e10",j.fill(),j.strokeStyle=v,j.lineWidth=2.5*ue,j.stroke(),j.restore();let C=l._strasse;C&&C.pinYVal&&Es(l,C.pinYVal,p,i,f,x,$,A)}function Tl(l,i,f,v,$,x){let A=l.bbox,E=l.ctx,H=window.devicePixelRatio||1,O=l.valToPos(v,"y",!0),N=Math.max(A.top,Math.min(A.top+A.height,O));E.save(),E.beginPath(),E.setLineDash([4*H,4*H]),E.strokeStyle=tt($,.4),E.lineWidth=1*H,E.moveTo(A.left,N),E.lineTo(A.left+A.width,N),E.stroke(),El(l,i,f,N,$);let W=x.fmt(v,!0),j=`bold ${10*H}px system-ui, sans-serif`;E.font!==j&&(E.font=j);let C=E.measureText(W).width+8*H,Se=16*H,ke=A.left-C-2*H,ce=N-Se/2;E.beginPath(),E.setLineDash([]),E.roundRect?E.roundRect(ke,ce,C,Se,3*H):E.rect(ke,ce,C,Se),E.fillStyle="rgba(14,14,16,0.95)",E.fill(),E.strokeStyle=$,E.lineWidth=1*H,E.stroke(),E.fillStyle="#fff",E.textAlign="center",E.textBaseline="middle",E.fillText(W,ke+C/2,ce+Se/2+.5*H),E.restore()}function El(l,i,f,v,$){let x=l.ctx,A=l.bbox,E=l.scales.x?.min??-1/0,H=l.scales.x?.max??1/0,O=l.scales.y?.min??0,N=l.scales.y?.max??100,W=A.width/(H-E||1),j=A.height/(N-O||1),ue=l.scales.y?.dir??1,C=ue===-1?A.top:A.top+A.height,Se=ue===-1?j:-j,ke=l.series[0]?.idxs,ce=ke?Math.max(0,ke[0]-1):0,Fe=ke?Math.min(i.length-1,ke[1]+1):i.length-1,me=Math.max(1,Math.floor((Fe-ce)/250));x.save(),x.beginPath(),x.rect(A.left,A.top,A.width,A.height),x.clip(),x.fillStyle=tt($,.2),x.beginPath();let ve=!1,Ie=!1,Ve=0;for(let Ze=ce;Ze<=Fe;Ze+=me){let st=i[Ze],nt=f[Ze];if(st==null||nt==null||stH){ve&&(x.lineTo(Ve,v),x.closePath(),ve=!1);continue}let ot=A.left+(st-E)*W,lt=C+(nt-O)*Se;Ve=ot,lt>16,A=v>>8&255,E=v&255,H=$>>16,O=$>>8&255,N=$&255,W=x+(H-x)*f,j=A+(O-A)*f,ue=E+(N-E)*f;return`#${((1<<24)+(Math.round(W)<<16)+(Math.round(j)<<8)+Math.round(ue)).toString(16).slice(1)}`}function Rn(l){if(l==null)return"#888896";let i=Math.abs(l),f=Math.min(1,i/8);return l>0?Rt("#A8C8A0","#d73027",f):Rt("#A8C8A0","#4575b4",f)}function Cs(l){if(l==null)return"#888896";let i=l*3.6;if(i<=5)return"#4575b4";if(i>=60)return"#d73027";if(i<=45){let f=(i-5)/40;return f<=.25?Rt("#4575b4","#91bfdb",f/.25):f<=.5?Rt("#91bfdb","#abdda4",(f-.25)/.25):f<=.75?Rt("#abdda4","#fee08b",(f-.5)/.25):Rt("#fee08b","#fc8d59",(f-.75)/.25)}else{let f=(i-45)/15;return Rt("#fc8d59","#d73027",f)}}function Sl(l,i){let f=new Array(l.length).fill(null);for(let v=0;v0&&($.dist||0)-(l[x].dist||0)1&&l[A].ele!=null&&l[x].ele!=null&&(f[v]=(l[A].ele-l[x].ele)/E*100)}return f}function Ls(l){let i=[...l];for(let f=0;f=0&&i[v]===null;)v--;let $=f+1;for(;$=0&&$=0?i[f]=i[v]:${let O=document.querySelector(`#${E} .stat-value`);O&&(O.textContent=H)};f("stat-distance",i.totalDist!=null?`${(i.totalDist/1e3).toFixed(1)} km`:"\u2014"),f("stat-duration",i.duration!=null?ht(Math.floor(i.duration/1e3)):"\u2014"),f("stat-elevation",i.elevGain!=null?`${Math.round(i.elevGain)} m`:"\u2014");let v=E=>{let H=e.find(W=>W.metricKey===E);if(!H)return E==="speed"?i.avgSpeed??null:E==="power"?i.avgPower??null:E==="cadence"?i.avgCadence??null:null;if(H.histData.fullStats!==void 0)return H.histData.fullStats?H.histData.fullStats.avg:null;let O=w.has(E)||E!=="power"&&E!=="cadence"&&E!=="speed",N=H.yData.filter(W=>W!=null&&(O||W!==0));return N.length?N.reduce((W,j)=>W+j,0)/N.length:null},$=v("speed");f("stat-avg-speed",$!=null?`${($*3.6).toFixed(1)} km/h`:"\u2014");let x=v("power");f("stat-avg-power",x!=null?`${Math.round(x)} W`:"\u2014");let A=v("cadence");f("stat-avg-cad",A!=null?`${Math.round(A)} rpm`:"\u2014"),f("stat-avg-hr",i.avgHR!=null?`${i.avgHR} bpm`:"\u2014"),f("stat-avg-temp",i.avgTemp!=null?`${i.avgTemp.toFixed(1)} \xB0C`:"\u2014")}return{init:ye,loadTrack:Q,clear:_,resetState:oe,toggleMetric:re,setXAxis:Pe,toggleStats:de,setSelectionStats:Ne,clearSelectionStats:V,restoreSelection:Ae,resetZoom:L,cancelSelection:ee,setCursorAt:(l,i=!1)=>{if(p=l,d&&d(l),i){D&&S?.points?.[l]&&D(S.points[l]);return}c=!0,e.forEach(({uplot:f,yData:v,xData:$})=>{$[l]!=null&&v[l]!=null&&f.batch(()=>{f.setCursor({left:f.valToPos($[l],"x"),top:f.valToPos(v[l],"y")},!0,!1)})}),c=!1,D&&S?.points?.[l]&&D(S.points[l])},setHoverAt:l=>{c=!0,e.forEach(({uplot:i,yData:f,xData:v})=>{l===null?i.batch(()=>{i.setCursor({left:-10,top:-10},!0,!1)}):v[l]!=null&&f[l]!=null&&i.batch(()=>{i.setCursor({left:i.valToPos(v[l],"x"),top:i.valToPos(f[l],"y")},!0,!1)})}),c=!1,D&&D(l!=null&&S?.points?.[l]?S.points[l]:null)},clearPinnedDot:()=>{p=null,d&&d(null),e.forEach(({uplot:l})=>l.redraw(!1))},resize:he,METRICS:_t,isDragging:()=>I,setMapColorChangeCb:$e,toggleMapColor:Ce,getMapColorMetric:()=>ae,getActiveMetrics:()=>m,getAvailableMetrics:()=>T,setActiveMetrics:K,updateMetricOrder:l=>{let i=new Set;l.forEach(f=>{m.has(f)&&i.add(f)}),m.forEach(f=>{i.has(f)||i.add(f)}),m=i,S&&xe(!0)},getXAxis:()=>R};function Ml(l,i,f,v,$){let x=l.ctx,A=l.bbox,E=window.devicePixelRatio||1,H=ge($,f);x.save(),x.beginPath(),x.rect(A.left,A.top,A.width,A.height),x.clip();let O=$==="gearRear"||$==="gearFront";for(let N=1;Nue.time!=null)?.time||0,W=f.field;v.beginPath(),v.strokeStyle="rgba(255, 255, 255, 0.04)",v.lineWidth=1*x;let j=!0;for(let ue=0;ue0){let ve=O[ue-1];(C.time&&ve.time?C.time-ve.time:0)>A&&(j=!0)}let ke=f.transform?f.transform(Se):Se;if(ke==null){j=!0;continue}let ce=R==="distance"?(C.dist||0)/1e3:(C.time-N)/1e3;if(cel.scales.x.max+10){j=!0;continue}let Fe=l.valToPos(ce,"x",!0),me=l.valToPos(ke,"y",!0);if(j)v.moveTo(Fe,me),j=!1;else{if(E){let ve=O[ue-1],Ie=R==="distance"?(ve.dist||0)/1e3:(ve.time-N)/1e3;v.lineTo(l.valToPos(Ie,"x",!0),me)}v.lineTo(Fe,me)}}v.stroke()}v.restore()}function Is(l,i,f,v,$,x,A=null,E=[]){let H=l.ctx,O=l.bbox,N=window.devicePixelRatio||1,W=6e4;H.save(),H.beginPath(),H.strokeStyle=tt(v,.8),H.lineWidth=$*N;let j=x==="gearRear"||x==="gearFront",ue=!0,C=null,Se=1,ke=1;if(x==="gears"&&E.length>0){let Xe=1/0,ct=-1/0;for(let vt=0;vtct&&(ct=St))}Xe<=ct&&(Se=Xe,ke=ct)}let ce=A?A[0]:l.scales.x?.min??-1/0,Fe=A?A[1]:l.scales.x?.max??1/0,me=l.scales.x?.min??-1/0,ve=l.scales.x?.max??1/0,Ie=l.scales.y?.min??0,Ve=l.scales.y?.max??100,Ze=O.width/(ve-me||1),st=O.height/(Ve-Ie||1),nt=l.scales.y?.dir??1,ot=nt===-1?O.top:O.top+O.height,lt=nt===-1?st:-st,ie=A?null:l.series[0]?.idxs,Je=ie?Math.max(0,ie[0]-1):0,Ge=ie?Math.min(i.length-1,ie[1]+1):i.length-1,Qe=j||x==="gears"?1:Math.max(1,Math.floor((Ge-Je)/250)),rt=R==="time",ut=W/1e3,mt=Je;for(let Xe=Je;Xe<=Ge;Xe+=Qe){let ct=i[Xe],vt=f[Xe];if(ct==null||vt==null){ue=!0;continue}if(x==="gears"&&E[Xe]){let Et=E[Xe].gearFrontTooth??E[Xe].gearFront;if(Et!=null&&Et!==C){if(!ue&&Xe>0){H.stroke(),H.beginPath();let is=O.left+(i[mt]-me)*Ze,Nn=ot+(f[mt]-Ie)*lt;H.moveTo(is,Nn)}let Jt=v;ke!==Se&&Et!=null&&(Et===Se?Jt="#FFC400":Et===ke?Jt="#FF8C00":Jt="#FFA500"),H.strokeStyle=tt(Jt,.8),C=Et}}if(Xe>Je&&rt){let Et=i[mt];Et!=null&&ct-Et>ut&&(ue=!0)}if(ctFe){ue=!0;continue}let St=O.left+(ct-me)*Ze,Yt=ot+(vt-Ie)*lt;if(ue)H.moveTo(St,Yt),ue=!1;else{if(j){let Et=i[mt];H.lineTo(O.left+(Et-me)*Ze,Yt)}H.lineTo(St,Yt)}mt=Xe}H.stroke(),H.restore()}})();var Hl={"Heart Rate":De.hr.icon,Cadence:De.cadence.icon,Power:De.power.icon,Temperature:De.temperature.icon,Shifting:De.gears.icon,Battery:De.battery.icon},hn=()=>{},qs=()=>{};function Vs(e,s){hn=e,qs=s}function Os(){let e=document.getElementById("details-view");e&&(e.innerHTML=` +
+ no_sim +
Select a track for details
+
+ `)}function on(e,s=[]){let t=document.getElementById("details-view");if(!t)return;if(!e){t.innerHTML="";return}let n=e.stats,o=e.points[0].time,r=e.points,u=[2,3,4,5,6,8,10,12,15,18,20,25,30,35,40,45,50,60,75,90,105,120,150,180,240,300],c=["power","hr","cad","speed","ele","temp","dist"],m=0;for(let p=0;p<1;p++)for(let h of u)for(let F of c){let q=0,J=0,Y=0,B=h>>1;for(let z=0;z=h){let le=r[z-h][F]||0;q-=le,J-=le*le;let y=q/h,d=Math.max(0,J/h-y*y),a=r[z-B][F]||0;Y+=(D-y)*(a-y)/(d+1)}}m+=Y/(r.length||1)}let T=Math.min(99.9,Math.max(80,95+Math.tanh(m*.01)*4.5)).toFixed(1);t.innerHTML=` +
+ +
+ +
+
+
labelTags
+
+
+ + + ${s.map(p=>` + +
+
+ +
+
analyticsActivity Summary
+
+
+
Distance
+
${(n.totalDist/1e3).toFixed(2)} km
+
+
+
Duration
+
${n.duration?ht(Math.floor(n.duration/1e3)):"\u2014"}
+
+
+
Avg Speed
+
${n.avgSpeed?(n.avgSpeed*3.6).toFixed(1):"\u2014"} km/h
+
+
+
Max Speed
+
${(n.maxSpeed*3.6).toFixed(1)} km/h
+
+ ${n.avgBattery!==null?`
+
Avg Battery
+
${n.avgBattery}%
+
`:""} +
+
+ +
+
infoFile Metadata
+
+
+
Original Filename
+
${pt(e.fileName||"\u2014")}
+
+
+
File Size
+
${e.fileSize?Ws(e.fileSize):"\u2014"}
+
+
+
Format
+
${e.format.toUpperCase()}
+
+
+
Sport
+
+ ${zs(e.sport)} + ${pt(Wt[e.sport?.toLowerCase()||""]?.name||"\u2014")} + expand_more + ${e.subSport?`(${pt(e.subSport)})`:""} +
+
+
+
Device / Creator
+
${e.device||"Unknown Device"}
+
+
+
Start Time
+
${o?Ns(o):"Unknown"}
+
+
+
+ +
+
sensorsSensor Info
+
+
+
Total Points
+
${e.points.length.toLocaleString("en-US")} pts
+
+
+
Telemetry Stability
+
${T}%
+
+
+
Sensors Found
+
+ ${n.sensors.length?n.sensors.map(p=>`${Hl[p]||"sensors"}`).join(""):'GPS only'} +
+
+
+
+ + ${n.avgHR||n.avgPower||n.avgCadence||n.avgTemp!=null?` +
+
monitoringBiometric Averages
+
+ ${n.avgHR?`
+
Avg HR
+
${n.avgHR} bpm
+
`:""} + ${n.maxHR?`
+
Max HR
+
${n.maxHR} bpm
+
`:""} + ${n.avgPower?`
+
Avg Power
+
${n.avgPower} W
+
`:""} + ${n.maxPower?`
+
Max Power
+
${n.maxPower} W
+
`:""} + ${n.avgCadence?`
+
Avg Cadence
+
${n.avgCadence} rpm
+
`:""} + ${n.avgTemp!=null?`
+
Avg Temp
+
${n.avgTemp.toFixed(1)} \xB0C
+
`:""} + ${n.minTemp!=null&&n.maxTemp!=null?`
+
Temp Range
+
${n.minTemp.toFixed(1)} \u2013 ${n.maxTemp.toFixed(1)} \xB0C
+
`:""} +
+
`:""} + + ${n.shifts!==null?` +
+
settingsDrivetrain
+
+
+
Total Shifts
+
${n.shifts}
+
+
+
`:""} + + ${e.devices&&e.devices.length>0?` +
+
watchHardware & Sensors
+
+ ${(()=>{let p=new Set;return e.devices.filter(h=>{if(!(h.name||h.product||h.manufacturer))return!1;let q=`${h.name}|${h.product}|${h.manufacturer}|${h.serial}`;return p.has(q)?!1:(p.add(q),!0)}).map(h=>{let F=h.name||h.product||"Unknown Device",q=h.manufacturer?`${h.manufacturer}`:"",J=[h.serial?`SN: ${h.serial}`:null,h.version?`v${h.version}`:null,h.hardwareVersion?`hw:${h.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),Y=[h.batteryLevel?`${h.batteryLevel}%`:null,h.batteryStatus?`Status: ${h.batteryStatus}`:null,h.batteryVoltage?`${h.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),B="",z=String(h.sourceType||"").toLowerCase();z.includes("local")?B="memory":z.includes("antplus")||z.includes("ant_plus")?B="settings_input_antenna":z.includes("bluetooth")&&(B="bluetooth");let D="sensors",le=String(F).toLowerCase();return le.includes("heartrate")||le.includes("hrm")?D=De.hr.icon:le.includes("power")?D=De.power.icon:le.includes("speed")?D=De.speed.icon:le.includes("cadence")?D=De.cadence.icon:le.includes("barometer")?D="air":le.includes("temperature")?D=De.temperature.icon:le.includes("gps")&&(D="location_on"),` +
+
+
+ ${D} +
${pt(F)}
+ ${B?`${B}`:""} +
+
${q}
+
+ ${J?`
${pt(J)}
`:""} +
+
${pt(h.type||"device")}
+ ${Y?`
+ battery_charging_full + ${pt(Y)} +
`:""} +
+
+ `}).join("")})()} +
+
`:""} +
+
deleteDanger Zone
+
+ +
+
+
+ `;let b=document.getElementById("tag-container"),w=document.getElementById("new-tag-input"),R=document.getElementById("btn-add-tag"),S=()=>{b.innerHTML="";let p=e.tags||[];if(p.length===0){b.innerHTML='No tags added';return}p.forEach(h=>{let F=Qn(h),q=document.createElement("div");q.className="tag-pill font-s",q.style.cssText=` + background: ${F}15; + border: 1px solid ${F}44; + color: ${F}; + padding: 2px 8px; + border-radius: 4px; + font-weight: 600; + display: flex; + align-items: center; + gap: 6px; + `,q.innerHTML=` + ${pt(h)} + close + `,b.appendChild(q)}),b.querySelectorAll(".btn-remove-tag").forEach(h=>{h.addEventListener("click",async F=>{let q=F.currentTarget.dataset.tag;e.tags=(e.tags||[]).filter(J=>J!==q),await at.save(e),S(),hn()})})},k=async()=>{let p=w.value.trim().toLowerCase();if(!p)return;let h=new Set(e.tags||[]);if(h.has(p)){w.value="";return}h.add(p),e.tags=Array.from(h).sort(),await at.save(e),w.value="",S(),hn()};R.addEventListener("click",k),w.addEventListener("keydown",p=>{p.key==="Enter"&&k()});let M=t.querySelector("#details-title-input");M?.addEventListener("change",async()=>{let p=M.value.trim();p&&(e.displayName=p,await at.save(e),hn())});let g=document.getElementById("sport-dropdown-trigger");g?.addEventListener("click",p=>{p.stopPropagation(),I(g)});function I(p){if(!e)return;document.querySelectorAll(".metric-menu-popup").forEach(B=>B.remove());let h=document.createElement("div");h.className="metric-menu-popup",Object.keys(Wt).forEach(B=>{let z=Wt[B],D=document.createElement("div"),le=e.sport?.toLowerCase()===B;D.className=`menu-item ${le?"active":""}`,D.innerHTML=` + ${z.icon} + ${z.name} + ${le?"check":""} + `,D.addEventListener("click",async()=>{e.sport=B,await at.save(e),h.remove();let y=document.getElementById("sport-icon");y&&(y.textContent=z.icon);let d=document.getElementById("sport-name");d&&(d.textContent=z.name),hn()}),h.appendChild(D)});let F=document.createElement("div"),q=!e.sport;F.className=`menu-item ${q?"active":""}`,F.innerHTML=` + block + \u2014 + ${q?"check":""} + `,F.addEventListener("click",async()=>{e.sport=void 0,await at.save(e),h.remove();let B=document.getElementById("sport-icon");B&&(B.textContent="question_mark");let z=document.getElementById("sport-name");z&&(z.textContent="\u2014"),hn()}),h.appendChild(F),document.body.appendChild(h);let J=p.getBoundingClientRect();h.style.top=`${J.bottom+window.scrollY+4}px`,h.style.left=`${J.left+window.scrollX}px`;let Y=B=>{!h.contains(B.target)&&!p.contains(B.target)&&(h.remove(),document.removeEventListener("click",Y))};setTimeout(()=>document.addEventListener("click",Y),10)}S(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${e.name}"?`)&&qs(e.id)})}import zl from"uplot";var wt=[];function Ys(e){return wt.filter(s=>{if(s.points.length===0)return!1;for(let t of s.points){let n=!1;for(let o of e.points)if(tn(t.lat,t.lon,o.lat,o.lon)<=t.radius){n=!0;break}if(!n)return!1}return!0})}var vn=null,Hn=!1,bn=null,js=()=>{},_l=null;function Zs(e){js=e,Bl()}function Gs(){wt=[],vn=null,bn=null,Hn=!1;let e=document.getElementById("courses-view");e&&(e.innerHTML=` +
+ route +
No courses created yet
+
+ `)}function Xs(e){wt=[];for(let s=0;s0&&(vn=wt[0].id,bn=wt[0].id)}async function Bl(){try{let e=await at.get("courses");e&&(wt=e)}catch(e){console.error("Courses: Failed to load courses",e)}}async function fs(){try{await at.set("courses",wt)}catch(e){console.error("Courses: Failed to save courses",e),js("Failed to save courses","error")}}function Fl(e){let s=0;for(let t=0;t0){let p=n[I-1];if(P.ele!=null&&p.ele!=null){let h=P.ele-p.ele;h>0&&(M+=h)}}}let g=n.length>1?(n[n.length-1].dist||0)-(n[0].dist||0):0;return{duration:u,dist:g,avgWatts:m>0?Math.round(c/m):null,avgHR:b>0?Math.round(T/b):null,avgSpeed:R>0?w/R:null,avgCadence:k>0?Math.round(S/k):null,avgVam:u>0?Math.round(M/(u/3600)):null}}function Dl(e){let s=Math.floor(e/3600),t=Math.floor(e%3600/60),n=Math.floor(e%60);return s>0?`${s}:${t.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`:`${t}:${n.toString().padStart(2,"0")}`}function hs(){return` + calendar_today Date + straighten Distance + timer Duration + speed Speed + speed Pace + trending_up VAM + bolt Power + favorite HR + `}function bs(e,s,t){let o=(s?Wt[s.toLowerCase()]:null)?.paceUnit||"km",r="--";if(e.avgSpeed!=null&&e.avgSpeed>.1){let u=(o==="km"?1e3:100)/e.avgSpeed;r=`${An(u)} min/${o}`}return` + ${t} + ${e.dist!=null?`${(e.dist/1e3).toFixed(2)} km`:"-"} + ${Dl(e.duration)} + ${e.avgSpeed!=null?`${(e.avgSpeed*3.6).toFixed(1)} km/h`:"-"} + ${r} + ${e.avgVam!=null?`${e.avgVam} m/h`:"-"} + ${e.avgWatts!=null?`${e.avgWatts} W`:"-"} + ${e.avgHR!=null?`${e.avgHR} bpm`:"-"} + `}function Dt(){let e=document.getElementById("courses-view");if(!e)return;let s=0;for(let t of wt){if(t.points.length<2)continue;let n=_e.findTracksPassingThroughPoints(t.points.map(u=>({lat:u.lat,lng:u.lon})),t.points[0]?.radius||20),o=3,r=[];for(let u=0;u +
+
+
+ ${Hn?` + + `:` + + `} +
+ +
+
+ ${wt.length===0?` +
+ route +
No courses created yet
+
+ `:wt.map(t=>{let n=t.points.map(c=>({lat:c.lat,lng:c.lon})),o=_e.findTracksPassingThroughPoints(n,t.points[0]?.radius||20),r=t.id===bn,u="";if(r){let c=o.map(m=>{let T=_e.getTrackData(m);if(!T)return null;let b=Kn(T,t.points);if(!b)return null;let w=gs(T,b.startIdx,b.endIdx),R=T.stats?.startTime||T.points?.[0]?.time,S=R?Zt(R):"-";return{id:m,displayName:T.displayName||T.name||m,date:S,sport:T.sport,color:T.color,...w,startIdx:b.startIdx,endIdx:b.endIdx}}).filter(m=>m!==null);c.sort((m,T)=>m.duration-T.duration||m.id.localeCompare(T.id)),u=` +
+ ${c.length===0?` +
No matching tracks
+ `:` + + + + + ${hs()} + + + + ${c.map(m=>` + + + ${bs(m,m.sport,m.date)} + + `).join("")} + +
Track (${c.length})
+
+
+ ${pt(m.displayName)} +
+
+ `} +
+ `}return` +
+
+ ${r?"expand_more":"chevron_right"} +
${pt(t.name)} edit
+
straighten ${Fl(t).toFixed(2)} km | ${t.points.length} points | ${o.length} matching tracks
+
+ + +
+
+ ${u} +
+ `}).join("")} +
+
+ `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{Rl()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{Hn=!1,_e.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),Dt()}),e.querySelectorAll(".course-item").forEach(t=>{let n=t.dataset.id;t.querySelector(".btn-edit-course")?.addEventListener("click",o=>{o.stopPropagation(),Js(n)}),t.querySelector(".btn-rename-course")?.addEventListener("click",o=>{o.stopPropagation(),Nl(n)}),t.querySelector(".btn-delete-course")?.addEventListener("click",o=>{o.stopPropagation(),Wl(n)}),t.querySelector(".course-item-header")?.addEventListener("click",o=>{o.target.closest(".course-actions")||o.target.closest(".btn-rename-course")||(_n(n),bn=bn===n?null:n,Dt())}),t.querySelectorAll(".course-track-row").forEach(o=>{let r=o.dataset.trackId,u=parseInt(o.dataset.start,10),c=parseInt(o.dataset.end,10);o.querySelector(".track-name-cell")?.addEventListener("click",m=>{m.stopPropagation();let T=_e.getTrackData(r);T&&(Mt(r,!1),setTimeout(()=>{let b=T.points,w=b.find(p=>p.time!=null)?.time||0,R=Math.max(0,Math.min(u,b.length-1)),S=Math.max(0,Math.min(c,b.length-1)),k=Math.max(0,((b[R]?.time||0)-w)/1e3),M=Math.max(0,((b[S]?.time||0)-w)/1e3),g=Me.getXAxis(),I=k,P=M;g==="distance"&&(I=Math.max(0,(b[R]?.dist||0)/1e3),P=Math.max(0,(b[S]?.dist||0)/1e3)),Ye.patch({sel:[I,P],tab:"graphs"},!0),Me.restoreSelection(k,M),_e.highlightSegment(r,T.points,u,c,!0)},50))}),o.addEventListener("mouseenter",()=>{_e.setTrackHover(r,!0)}),o.addEventListener("mouseleave",()=>{_e.setTrackHover(r,!1)})})})}function Rl(){let e=`Course ${wt.length+1}`,s={id:Math.random().toString(36).substring(2,9),name:e,points:[]};wt.push(s),fs(),Dt(),Js(s.id)}function Nl(e){let s=wt.find(c=>c.id===e);if(!s)return;let t=document.querySelector(`.course-item[data-id="${e}"]`);if(!t)return;let n=t.querySelector(".course-name");if(!n)return;let o=s.name;n.innerHTML=``;let r=n.querySelector(".course-name-input");r.focus(),r.select();let u=()=>{let c=r.value.trim();c!==""&&(s.name=c,fs()),Dt()};r.addEventListener("blur",u),r.addEventListener("keydown",c=>{c.key==="Enter"?u():c.key==="Escape"&&Dt()})}function Js(e){vn=e,Hn=!0,Dt()}function Qs(){_l=null}function _n(e,s=!1){vn=e,s&&(bn=e),Hn=!1,_e.setCustomClickHandler(null),Qs(),Dt()}function Wl(e){confirm("Are you sure you want to delete this course?")&&(wt=wt.filter(s=>s.id!==e),vn===e&&(vn=null,Qs()),fs(),Dt())}var es=()=>{},vs=[];function el(){vs.forEach(e=>e.destroy()),vs=[]}function tl(e){es=e}function nl(){el(),document.querySelectorAll(".hr-settings-popup").forEach(s=>s.remove());let e=document.getElementById("insights-view");e&&(e.innerHTML=` +
+ no_sim +
Select a track for insights
+
+ `)}function Bt(e){el();let s=document.getElementById("insights-view");if(!s)return;if(!e){s.innerHTML="";return}let t=e.stats;if(it.ensureCurvesAndZones(e),!t.powerCurve&&!t.hrZones&&!t.hrCurve){s.innerHTML=` +
+ analytics +
No insights available for this track (requires Power or Heart Rate data)
+
+ `;return}let n=e.points,o=it.getFTP(),r=[180,240,300,360,420,480,540,600,720,900],u=2e4;for(let S=0;S<8;S++)for(let k=0;k>1;for(let F=0;Fo?I-=q-o:I=2e4-(2e4-I)*g,I + `;let c=document.getElementById("insights-grid");if(!c)return;let m=Math.round(c.getBoundingClientRect().width-42)||480;if(t.powerCurve&&Ks({grid:c,track:e,curve:t.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:De.power.color,icon:"bolt",chartWidth:m}),t.hrCurve&&Ks({grid:c,track:e,curve:t.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:De.hr.color,icon:"favorite",chartWidth:m}),t.powerZones){let S=document.createElement("div");S.className="insight-card";let k="power",M=De.power.color;S.style.setProperty("--chart-color",M);let g=Me.getMapColorMetric()===k,I=t.powerZones.reduce((h,F)=>h+F,0),P=gn.getPowerZones(),p="";t.powerZones.forEach((h,F)=>{if(F>=P.length)return;let q=P[F],J=I>0?h/I*100:0,Y=isFinite(q.max)?`${Math.round(q.min)} - ${Math.round(q.max)} W`:`> ${Math.round(q.min)} W`;p+=` +
+
+ Z${F+1} + ${q.name} + ${Y} + ${ht(Math.round(h))} + ${J.toFixed(1)}% +
+
+
+
+
+ `}),S.innerHTML=` +
+
+
+ boltPower Zones +
+ +
+ +
+
${p}
+ `,c.appendChild(S),S.querySelector(".map-color-btn")?.addEventListener("click",h=>{h.stopPropagation(),Me.toggleMapColor(k);let F=Me.getMapColorMetric();c.querySelectorAll(".map-color-btn").forEach(q=>{let J=q;J.classList.toggle("active",J.dataset.metric===F)})}),S.querySelector(".btn-pw-settings")?.addEventListener("click",h=>{h.stopPropagation(),ql(h.currentTarget,e)})}if(t.hrZones){let S=document.createElement("div");S.className="insight-card";let k="hr",M=De.hr.color;S.style.setProperty("--chart-color",M);let g=Me.getMapColorMetric()===k,I=t.hrZones.reduce((h,F)=>h+F,0),P=gn.getHRZones(),p="";t.hrZones.forEach((h,F)=>{if(F>=P.length)return;let q=P[F],J=I>0?h/I*100:0,Y=isFinite(q.max)?`${Math.round(q.min)} - ${Math.round(q.max)} bpm`:`> ${Math.round(q.min)} bpm`;p+=` +
+
+ Z${F+1} + ${q.name} + ${Y} + ${ht(Math.round(h))} + ${J.toFixed(1)}% +
+
+
+
+
+ `}),S.innerHTML=` +
+
+
+ favoriteHeart Rate Zones +
+ +
+ +
+
${p}
+ `,c.appendChild(S),S.querySelector(".map-color-btn")?.addEventListener("click",h=>{h.stopPropagation(),Me.toggleMapColor(k);let F=Me.getMapColorMetric();c.querySelectorAll(".map-color-btn").forEach(q=>{let J=q;J.classList.toggle("active",J.dataset.metric===F)})}),S.querySelector(".btn-hr-settings")?.addEventListener("click",h=>{h.stopPropagation(),Ul(h.currentTarget,e)})}let T=document.createElement("div");T.className="insight-card";let b=t.totalDist/1e3,w=b>0?t.elevGain/(b*1e3)*100:0;if(T.innerHTML=` +
+ terrainClimbing Analysis +
+
+
+
Total Ascent
+
${Math.round(t.elevGain)} m
+
+
+
Total Descent
+
${Math.round(t.elevLoss)} m
+
+
+
Avg Grade
+
${w.toFixed(1)} %
+
+
+
VAM
+
${t.duration&&t.duration>0?Math.round(t.elevGain/t.duration*36e5):0} m/h
+
+
+ `,c.appendChild(T),t.avgPower&&t.avgHR){let S=document.createElement("div");S.className="insight-card";let k=t.avgPower/t.avgHR;S.innerHTML=` +
+ monitoringEfficiency Factor +
+
+
+
EF (Avg Power / Avg HR)
+
${k.toFixed(2)}
+
Higher values indicate better aerobic fitness.
+
+
+ `,c.appendChild(S)}let R=Ys(e);if(R.length>0){let S=document.createElement("div");S.className="insight-card",S.style.cssText="column-span: all; display: block;",S.innerHTML=` +
routeCourses (${R.length})
+
+ + + + + ${hs()} + + + + ${R.map(k=>{let M=Kn(e,k.points),g="";if(M){let I=gs(e,M.startIdx,M.endIdx),P=e.stats?.startTime||e.points?.[0]?.time,p=P?Zt(P):"-";g=bs(I,e.sport||null,p)}else g='';return` + + + ${g} + + `}).join("")} + +
Name
No continuous segment
+
+
+ ${pt(k.name)} +
+
+
+ `,c.appendChild(S),S.querySelectorAll(".clickable-course").forEach(k=>{k.addEventListener("click",()=>{let M=k.dataset.id;_n(M,!0),Ye.patch({tab:"courses"},!0)}),k.addEventListener("mouseenter",()=>{let M=k.dataset.id,g=R.find(I=>I.id===M);if(g){let I=Kn(e,g.points);I&&_e.highlightSegment(e.id,e.points,I.startIdx,I.endIdx,!1)}}),k.addEventListener("mouseleave",()=>{_e.clearHighlight()})})}}function Ks(e){let{grid:s,track:t,curve:n,metricKey:o,label:r,unit:u,color:c,icon:m,chartWidth:T}=e,b=Me.getMapColorMetric()===o,w=document.createElement("div");w.className="insight-card",w.style.setProperty("--chart-color",c),w.innerHTML=` +
+
+
+ ${m}${r} +
+ +
+ +
+
+ + `,s.appendChild(w);let R=w.querySelector(".curve-table-wrap"),S=w.querySelector(".btn-toggle-table"),k=S.querySelector(".material-symbols-rounded");S.addEventListener("click",()=>{let p=R.style.display==="none";R.style.display=p?"block":"none",k.textContent=p?"expand_less":"expand_more"});let M=w.querySelector(".map-color-btn");M.addEventListener("click",p=>{p.stopPropagation();let h=M.dataset.metric;Me.toggleMapColor(h);let F=Me.getMapColorMetric();s.querySelectorAll(".map-color-btn").forEach(q=>{let J=q;J.classList.toggle("active",J.dataset.metric===F)})});let g=w.querySelector(".curve-tbody"),I=Object.keys(n).map(Number).sort((p,h)=>p-h);I.forEach(p=>{let h=n[p],F=h.power||h.hr||h.val,q=document.createElement("tr");q.innerHTML=` + ${Ft(p)} + ${F} ${u} + + + + `,g?.appendChild(q)}),g?.querySelectorAll(".btn-show-peak").forEach(p=>{p.addEventListener("click",h=>{let F=h.currentTarget,q=parseInt(F.dataset.idx),J=parseInt(F.dataset.len),Y=t.points,B=Math.min(Y.length-1,q+J-1),z=Y[0].time||0,D=((Y[q].time||z)-z)/1e3,le=((Y[B].time||z)-z)/1e3;Ye.patch({sel:[D,le]}),_e.highlightSegment(t.id,Y,q,B,!0)})});let P=w.querySelector(`#${o}-curve-chart`);if(P){let p=I,h=I.map(Y=>n[Y].power||n[Y].hr||n[Y].val),F=document.createElement("div");F.className="cur-y-val",F.style.cssText=`color:${c};display:none;border-color:${c}44`,P.style.position="relative",P.appendChild(F);let q={id:`${o}-curve`,width:0,height:250,padding:[10,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:r,stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(Y,B)=>B.map(z=>`${z}${u}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(Y,B,z)=>z},hooks:{draw:[Y=>{let B=Y.ctx,z=window.devicePixelRatio||1,D=Y.bbox,le=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],y=p[p.length-1];B.save(),B.fillStyle="#555564",B.textAlign="center",B.textBaseline="top",B.font=`${10*z}px system-ui, sans-serif`;let d=-100;le.forEach(a=>{if(a>y)return;let G=Y.valToPos(a,"x",!0);G>d+30*z&&G{Y.over.addEventListener("click",()=>{let B=Y.cursor.idx;if(B!=null&&p[B]!=null){let z=p[B],le=n[z].idx,y=t.points,d=Math.min(y.length-1,le+z-1),a=y[0].time||0,G=((y[le].time||a)-a)/1e3,X=((y[d].time||a)-a)/1e3;Ye.patch({sel:[G,X]}),_e.highlightSegment(t.id,y,le,d,!0)}})}],setCursor:[Y=>{if(!Y._ready)return;Y.redraw(!1);let B=Y.cursor.idx,z=Y.ctx,D=window.devicePixelRatio||1,le=Y.bbox,y=B!=null&&h[B]!=null&&Y.cursor.left>=0,d=Y.cursor.top,a=Y.valToPos(h[B],"y",!1);if(y&&Math.abs(d-a)<40){let X=Y.valToPos(p[B],"x",!1),se=Y.valToPos(h[B],"y",!1),U=p[B];F.innerHTML=`${Ft(U)}: ${h[B]} ${u}`,F.style.transform=`translate(${X}px, ${se}px) translate(15px, 15px)`,F.style.display="";let ne=Y.valToPos(p[B],"x",!0),Le=Y.valToPos(h[B],"y",!0);z.save(),z.beginPath(),z.setLineDash([2*D,2*D]),z.strokeStyle=tt(c,.4),z.lineWidth=1*D,z.moveTo(ne,le.top),z.lineTo(ne,le.top+le.height),z.stroke(),z.beginPath(),z.setLineDash([]),z.arc(ne,Le,3*D,0,Math.PI*2),z.fillStyle="#0e0e10",z.fill(),z.strokeStyle=c,z.lineWidth=2*D,z.stroke(),z.restore()}else F.style.display="none"}]},legend:{show:!1}};q.width=T||Math.round(s.getBoundingClientRect().width-42)||P.clientWidth||500;let J=new zl(q,[p,h],P);J._ready=!0,vs.push(J)}}function Ul(e,s){document.querySelectorAll(".hr-settings-popup").forEach(u=>u.remove());let t=document.createElement("div");t.className="hr-settings-popup";let n=it.getHRZones();t.innerHTML=` +
Configure HR Zones (bpm)
+
+
+ Z1 / Z2 + +
+
+ Z2 / Z3 + +
+
+ Z3 / Z4 + +
+
+ Z4 / Z5 + +
+ +
+ `;let o=e.getBoundingClientRect();t.style.cssText=` + position: fixed; + z-index: 10000; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: 12px; + padding: 16px; + width: 200px; + box-shadow: 0 8px 32px rgba(0,0,0,0.6); + left: ${o.right-200}px; + top: ${o.bottom+8}px; + `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let u=t.querySelectorAll(".hr-zone-input"),c=Array.from(u).map(m=>parseInt(m.value)||0);for(let m=1;m{!t.contains(u.target)&&!e.contains(u.target)&&(t.remove(),document.removeEventListener("click",r))};setTimeout(()=>document.addEventListener("click",r),10)}function ql(e,s){document.querySelectorAll(".pw-settings-popup").forEach(u=>u.remove());let t=document.createElement("div");t.className="pw-settings-popup";let n=it.getFTP();t.innerHTML=` +
Configure FTP (Watts)
+
+
+ Your FTP + +
+ +
+ `;let o=e.getBoundingClientRect();t.style.cssText=` + position: fixed; + z-index: 10000; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: 12px; + padding: 16px; + width: 200px; + box-shadow: 0 8px 32px rgba(0,0,0,0.6); + left: ${o.right-200}px; + top: ${o.bottom+8}px; + `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let u=t.querySelector("#ftp-input"),c=parseInt(u.value)||200;it.setFTP(c),await at.set("ftp",c),s.stats=it.computeStats(s.points,!0),await at.save(s),Bt(s),t.remove(),es(`FTP updated to ${c}W`)});let r=u=>{!t.contains(u.target)&&!e.contains(u.target)&&(t.remove(),document.removeEventListener("click",r))};setTimeout(()=>document.addEventListener("click",r),10)}import sl from"uplot";var Ct=[],zt=null,ft=null,an="power",Gt="hr",bt=null,Lt=[],Vt=[],nn=null,Pt=!1;function ts(){let e=document.getElementById("combined-time-val");if(e&&bt!==null&&Lt[bt]){let s=Lt[bt][2];e.textContent=`${ht(s)}`}}function ol(){nn&&(clearInterval(nn),nn=null),ft&&(ft.destroy(),ft=null),Ct=[],zt=null,an="power",Gt="hr",bt=null,Lt=[],Vt=[],Pt=!1;let e=document.getElementById("combined-tooltip");e&&e.remove();let s=document.getElementById("combined-view");s&&(s.innerHTML=` +
+ no_sim +
Select a track for combined analysis
+
+ `)}function rn(e){Array.isArray(e)?(Ct=e,zt=e[0]||null):e?(Ct=[e],zt=e):(Ct=[],zt=null);let s=document.getElementById("combined-view");if(!s)return;let t=zt;if(!t){s.innerHTML=` +
+ no_sim +
Select a track for combined analysis
+
+ `;return}let n=Me.METRICS,o=[];for(let S in n){let k=n[S];t.points.some(M=>M[k.field]!=null)&&o.push(S)}!o.includes(an)&&o.length>0&&(an=o[0]),!o.includes(Gt)&&o.length>1?Gt=o[1]:!o.includes(Gt)&&o.length>0&&(Gt=o[0]);let r=n[an],u=n[Gt];s.style.overflow="hidden";let c="";if(Ct.length>=2){let S=0,k=0,M=[2,3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300];for(let ne=0;ne<4;ne++)for(let Le of M)for(let Re=0;Re=Le){let de=ae[re-Le],$e=pe[re-Le];He-=(de.power||0)+(de.hr||0)+(de.speed||0),Q-=($e.power||0)+($e.hr||0)+($e.speed||0),_-=(de.cad||0)+(de.ele||0)*.1,oe-=($e.cad||0)+($e.ele||0)*.1,k+=He/Le*(Q/Le)+_/Le*(oe/Le),S++}}}let g=Ct[0],I=Ct[1],P=g.stats,p=I.stats,h=((p.totalDist-P.totalDist)/1e3).toFixed(2),F=((p.avgPower||0)-(P.avgPower||0)).toFixed(0),q=((p.avgHR||0)-(P.avgHR||0)).toFixed(0),J=(p.elevGain-P.elevGain).toFixed(0),Y=(p.shifts||0)-(P.shifts||0),B=((P.totalDist+p.totalDist)/1e3).toFixed(2),z=(P.elevGain+p.elevGain).toFixed(0),D=((P.duration||0)+(p.duration||0))/1e3,le=Math.round(((P.avgPower||0)+(p.avgPower||0))/2),y=Math.max(P.maxPower||0,p.maxPower||0),d=Math.round(((P.avgHR||0)+(p.avgHR||0))/2),a=Math.max(P.maxHR||0,p.maxHR||0),G=((p.avgTemp??0)-(P.avgTemp??0)).toFixed(1),X=(((P.avgTemp??0)+(p.avgTemp??0))/2).toFixed(1),se=Math.max(P.maxTemp??0,p.maxTemp??0).toFixed(1),U=(P.shifts||0)+(p.shifts||0);c=` +
+
Aggregate Track Comparison & Analysis
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Metric${g.displayName||g.name} (T1)${I.displayName||I.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(P.totalDist/1e3).toFixed(2)} km${(p.totalDist/1e3).toFixed(2)} km${Number(h)>=0?"+":""}${h} km${B} km (Total)
Elevation Gain${P.elevGain.toFixed(0)} m${p.elevGain.toFixed(0)} m${Number(J)>=0?"+":""}${J} m${z} m (Total)
Duration${P.duration?ht(P.duration/1e3):"--"}${p.duration?ht(p.duration/1e3):"--"}--${ht(D)} (Total)
Avg / Max Power${P.avgPower||0} W / ${P.maxPower||0} W${p.avgPower||0} W / ${p.maxPower||0} W${Number(F)>=0?"+":""}${F} W (Avg)${le} W (Avg) / ${y} W (Max)
Avg / Max HR${P.avgHR||0} bpm / ${P.maxHR||0} bpm${p.avgHR||0} bpm / ${p.maxHR||0} bpm${Number(q)>=0?"+":""}${q} bpm (Avg)${d} bpm (Avg) / ${a} bpm (Max)
Avg / Max Temp${P.avgTemp!=null?P.avgTemp.toFixed(1):"--"} \xB0C / ${P.maxTemp!=null?P.maxTemp.toFixed(1):"--"} \xB0C${p.avgTemp!=null?p.avgTemp.toFixed(1):"--"} \xB0C / ${p.maxTemp!=null?p.maxTemp.toFixed(1):"--"} \xB0C${Number(G)>=0?"+":""}${G} \xB0C (Avg)${X} \xB0C (Avg) / ${se} \xB0C (Max)
Gear Shifts${P.shifts||0}${p.shifts||0}${Y>=0?"+":""}${Y}${U} (Total)
+
+ `}s.innerHTML=`${c} +
+
+ arrow_forward + X Axis: + +
+
+ arrow_upward + Y Axis: + +
+
+ schedule + Time: + + 0:00 + +
+
+ + +
+
+
+ `,document.getElementById("btn-combined-x")?.addEventListener("click",S=>{S.stopPropagation(),ll(S.currentTarget,"x")}),document.getElementById("btn-combined-y")?.addEventListener("click",S=>{S.stopPropagation(),ll(S.currentTarget,"y")});let m=document.getElementById("combined-time-slider"),T=document.getElementById("combined-time-val"),b=document.getElementById("btn-combined-play");m?.addEventListener("input",()=>{bt=parseInt(m.value,10),ts(),ft&&ft.redraw()});function w(){b&&(b.innerHTML='pause'),nn=window.setInterval(()=>{bt!==null&&btplay_arrow')}b?.addEventListener("click",()=>{nn?R():(bt!==null&&bt>=Lt.length-1&&(bt=0,m.value="0",ts(),ft&&ft.redraw()),w())}),document.getElementById("btn-combined-cart")?.addEventListener("click",()=>{Pt&&(Pt=!1,rn(zt))}),document.getElementById("btn-combined-polar")?.addEventListener("click",()=>{Pt||(Pt=!0,rn(zt))}),Vl()}function yn(){let e=document.getElementById("tab-combined"),s=document.getElementById("combined-plot-container");if(ft&&s&&s.clientWidth>0){let t=s.clientWidth,n=s.clientHeight;if(t>0&&n>0)if(Pt){let o=Math.min(t,n);ft.setSize({width:o,height:o})}else ft.setSize({width:t,height:n})}}function ll(e,s){document.querySelectorAll(".metric-menu-popup").forEach(m=>m.remove());let t=document.createElement("div");t.className="metric-menu-popup";let n=Me.METRICS,o=zt;if(!o)return;let r=[];for(let m in n){let T=n[m];o.points.some(b=>b[T.field]!=null)&&r.push(m)}r.forEach(m=>{let T=n[m],b=document.createElement("div"),w=s==="x"?an:Gt;b.className=`menu-item ${w===m?"active":""}`,b.innerHTML=` + ${T.icon} + ${T.label} + ${w===m?"check":""} + `,b.addEventListener("click",()=>{s==="x"?an=m:Gt=m,t.remove(),rn(zt)}),t.appendChild(b)});let u=e.getBoundingClientRect();t.style.top=`${u.bottom+5}px`,t.style.left=`${u.left}px`,document.body.appendChild(t);let c=m=>{!t.contains(m.target)&&!e.contains(m.target)&&(t.remove(),document.removeEventListener("click",c))};setTimeout(()=>document.addEventListener("click",c),0)}function Vl(){if(!zt)return;let e=document.getElementById("combined-plot-container");if(!e)return;let s=Me.METRICS,t=s[an]||s.power,n=s[Gt]||s.hr;if(Ct.length>=2){let k=Ct[0],M=Ct[1],g=k.points,I=M.points,P=Math.max(g.length,I.length),p=[],h=[],F=[];for(let B=0;B0?e.clientWidth:800,J=e.clientHeight>0?e.clientHeight:350,Y={width:q,height:J,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:[{},{label:`${k.displayName||k.name} (${n.label})`,stroke:k.color||"#3b82f6",width:2,points:{show:!1}},{label:`${M.displayName||M.name} (${n.label})`,stroke:M.color||"#FF6B35",width:2,points:{show:!1}}],axes:[{side:2,label:"Elapsed Duration (s)",stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:30},{side:3,label:`${n.label} (${n.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:40}],legend:{show:!0}};ft=new sl(Y,[p,h,F],e),yn();return}let o=zt.points,r=o[0].time||0,u=o.map((k,M)=>[k[t.field],k[n.field],(k.time-r)/1e3,(k.dist||0)/1e3,M]).filter(([k,M,g,I])=>k!=null&&M!=null);if(u.length===0){e.innerHTML='
No data for selected metrics
';return}if(Pt){let k=u.map(h=>h[0]),M=u.map(h=>h[1]),g=Math.min(...k),I=Math.max(...k),P=Math.min(...M),p=Math.max(...M);Lt=u.map(h=>{let F=h[0],q=h[1],J=(F-g)/(I-g||1)*2*Math.PI,Y=(q-P)/(p-P||1),B=Y*Math.cos(J),z=Y*Math.sin(J);return[B,z,h[2],h[3],h[4],F,q]})}else Lt=u.map(k=>[k[0],k[1],k[2],k[3],k[4],k[0],k[1]]);let c=document.getElementById("combined-time-slider");c&&(c.max=`${u.length-1}`,(bt===null||bt>=u.length)&&(bt=u.length-1,c.value=c.max),ts()),Vt=[...Lt].sort((k,M)=>k[0]-M[0]||k[4]-M[4]);let m=Vt.map(k=>k[0]),T=Vt.map(k=>k[1]),b=document.getElementById("combined-plot-container"),w=b&&b.clientWidth>0?b.clientWidth:600,R=b&&b.clientHeight>0?b.clientHeight:400;if(Pt){let k=Math.min(w,R>0?R:w);w=k,R=k,b&&(b.style.display="flex",b.style.alignItems="center",b.style.justifyContent="center")}else b&&(b.style.display="",b.style.alignItems="",b.style.justifyContent="");let S={width:w,height:R,padding:[10,15,0,0],scales:{x:{time:!1,auto:!0},y:{auto:!0}},series:[{},{label:n.label,width:0,points:{show:!0,size:3,fill:tt(n.color,.3)}}],axes:[{side:2,show:!Pt,label:`${t.label} (${t.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(k,M)=>M.map(g=>g!=null?t.fmtAxis(g):""),size:30},{side:3,show:!Pt,label:`${n.label} (${n.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(k,M)=>M.map(g=>g!=null?n.fmtAxis(g):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:(k,M,g)=>{let I=k.cursor.left,P=k.cursor.top;if(I!=null&&P!=null&&I>=0&&P>=0){let p=1/0,h=-1;for(let F=0;F=0&&p<2500)return h}return g},points:{size:7,stroke:"#fff",width:2,fill:n.color}},legend:{show:!1},hooks:{draw:[k=>{let M=k.ctx,g=window.devicePixelRatio||1;M.save(),M.beginPath(),M.strokeStyle="rgba(255, 255, 255, 0.15)",M.lineWidth=1*g;let I=!1;for(let P=0;P{let M=k.cursor.idx,g=document.getElementById("combined-tooltip");if(g||(g=document.createElement("div"),g.id="combined-tooltip",g.style.position="absolute",g.style.background="rgba(14, 14, 16, 0.9)",g.style.color="#fff",g.style.padding="8px 12px",g.style.borderRadius="4px",g.classList.add("font-m"),g.style.fontFamily="system-ui",g.style.pointerEvents="none",g.style.zIndex="1000",g.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",g.style.border="1px solid #2e2e34",document.body.appendChild(g)),M!=null&&Vt[M]&&k.cursor.left>=0){let I=Vt[M],P=I[2],p=I[3],h=I[5],F=I[6];g.innerHTML=` +
Point #${M}
+
+ Time: + ${ht(P)} +
+
+ Distance: + ${p.toFixed(2)} km +
+
+ ${t.label}: + ${t.fmtAxis(h)} ${t.unit} +
+
+ ${n.label}: + ${n.fmtAxis(F)} ${n.unit} +
+ `,g.style.display="block";let q=k.over.getBoundingClientRect();g.style.left=`${q.left+window.scrollX+k.cursor.left+15}px`,g.style.top=`${q.top+window.scrollY+k.cursor.top+15}px`}else g.style.display="none"}]}};e.querySelector(".empty-text")&&(e.innerHTML=""),ft&&ft.destroy(),ft=new sl(S,[m,T],e),ft.over.addEventListener("click",()=>{if(ft){let k=ft.cursor.idx;if(k!=null&&Vt[k]){let M=Vt[k][4];Me.setCursorAt(M)}}}),yn()}import xn from"uplot";function il(e,s){let t=0;for(let F=0;Ft&&(t=q)}t||(t=Date.UTC(2026,7,1));let n=new Date(t),o=n.getUTCFullYear(),r=Date.UTC(o-1,n.getUTCMonth(),n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),u=Date.UTC(o,n.getUTCMonth()-6,n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),c=Date.UTC(o,n.getUTCMonth()-1,n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),m=0,T=0,b=0,w=0,R=0,S=t;e.forEach(F=>{if(!F.stats.startTime)return;let q=s(F);if(q===void 0)return;R+=q;let J=F.stats.startTime;J=r&&(T+=q),J>=u&&(b+=q),J>=c&&(w+=q)});let k=7*24*60*60*1e3,M=Date.UTC(o,0,1),g=Math.max(.1,(t-M)/k),I=Math.max(.1,(t-r)/k),P=Math.max(.1,(t-u)/k),p=Math.max(.1,(t-c)/k),h=Math.max(.1,(t-S)/k);return{currentYear:m,pastYear:T,past6m:b,past1m:w,total:R,currentYearAvg:m/g,pastYearAvg:T/I,past6mAvg:b/P,past1mAvg:w/p,totalAvg:R/h}}function al(e,s,t){let n=s?1e3:1,o=r=>(s?r/n:r).toLocaleString("en-US",{minimumFractionDigits:s?1:0,maximumFractionDigits:s?1:0});return` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Period${s?"Distance":"Elevation"}${s?"Distance/Week":"Elevation/Week"}
Current Year${o(e.currentYear)} ${t}${o(e.currentYearAvg)} ${t}
Past Year${o(e.pastYear)} ${t}${o(e.pastYearAvg)} ${t}
Past 6 Months${o(e.past6m)} ${t}${o(e.past6mAvg)} ${t}
Past 1 Month${o(e.past1m)} ${t}${o(e.past1mAvg)} ${t}
Total${o(e.total)} ${t}${o(e.totalAvg)} ${t}
+ `}var wn=[];function dl(){wn.forEach(e=>e.destroy()),wn=[]}function ul(){dl();let e=document.getElementById("evolution-view");e&&(e.innerHTML=` +
+ no_sim +
Select a track for progress analysis
+
+ `)}function Tn(e,s,t,n){dl();let o=document.getElementById("evolution-view");if(!o)return;let r=Ye.get().progress||"all";s.forEach(h=>{it.ensureCurvesAndZones(h)});let u=0,c=0,m=2/8,T=2/43;s.forEach(h=>{let F=h.points||[],q=0,J=0;for(let Y=0;Y +
+
+ + + + +
+
+
+
+ + + + + + +
+
+ +
+ `;let w=document.getElementById("evolution-container");if(!w)return;let R=w.clientWidth||570,S=xn.sync("progress-sync");b.push(cl(w,s,"distance",S,n,R)),b.push(cl(w,s,"elevation",S,n,R));let k=w.querySelector(".distance-progress-card .chart-scroll-container"),M=w.querySelector(".elevation-progress-card .chart-scroll-container");k&&M&&(k.addEventListener("scroll",()=>{M.scrollLeft!==k.scrollLeft&&(M.scrollLeft=k.scrollLeft)}),M.addEventListener("scroll",()=>{k.scrollLeft!==M.scrollLeft&&(k.scrollLeft=M.scrollLeft)}));let g=o.querySelector("#evolution-time-range");g&&g.querySelectorAll(".seg-btn").forEach(h=>{h.addEventListener("click",()=>{let F=h.getAttribute("data-range");F&&(g.querySelectorAll(".seg-btn").forEach(q=>q.classList.remove("active")),h.classList.add("active"),p(F))})}),o.querySelectorAll(".metric-pill").forEach(h=>{h.addEventListener("click",()=>{let F=h.getAttribute("data-target");F&&document.getElementById(`${F}-evolution-card`)?.scrollIntoView({behavior:"smooth"})})});function P(h){b.forEach(F=>{F&&F.updatePin&&F.updatePin(h)})}function p(h){Ye.patch({progress:h==="all"?null:h}),b.forEach(F=>{F&&F.updateRange&&F.updateRange(h)})}if(s.some(h=>h.stats.powerCurve)){let h=rl({grid:w,currentTrack:e,allTracks:s,metricKey:"power",label:"Power Curve Progress",unit:"W",color:De.power.color,icon:"bolt",onPinChange:P,onRangeChange:p,onTrackSelect:t,gridWidth:R});b.push(h)}if(s.some(h=>h.stats.hrCurve)){let h=rl({grid:w,currentTrack:e,allTracks:s,metricKey:"hr",label:"Heart Rate Curve Progress",unit:"bpm",color:De.hr.color,icon:"favorite",onPinChange:P,onRangeChange:p,onTrackSelect:t,gridWidth:R});b.push(h)}r!=="all"&&b.forEach(h=>{h&&h.updateRange&&h.updateRange(r)}),wn.forEach(h=>{h._ready=!0})}function rl(e){let{grid:s,currentTrack:t,allTracks:n,metricKey:o,label:r,unit:u,color:c,icon:m,onPinChange:T,onRangeChange:b,onTrackSelect:w,gridWidth:R}=e,S=t&&t.name||"Current Track",k=null,M=document.createElement("div");M.className="chart-row evolution-card-group",M.id=`${o}-evolution-card`,s.appendChild(M);let g=document.createElement("div");g.className="chart-row progress-chart-row",g.style.setProperty("--chart-color",c),g.style.flex="0 0 400px",g.style.borderBottom="none",g.innerHTML=` +
+
+ ${m} + ${r} +
+
+
+
+
+ `;let I=document.createElement("div");I.className="evolution-legend",I.innerHTML=` +
+ + ${S} +
+
+ + All-Time Max +
+ `;let p=Ye.get().progress||"all",h=document.createElement("div");h.className="chart-row progress-chart-row",h.style.setProperty("--chart-color",c),h.style.flex="1",h.style.borderBottom="none",h.innerHTML=` +
+
+ ${m} + Progress ${o==="power"?"Power":"HR"} +
+
+
+
+
+ `;let F=document.createElement("div");F.style.cssText="display: flex; flex-direction: row; gap: 0px; align-items: stretch;",F.appendChild(g),F.appendChild(h),M.appendChild(F),M.appendChild(I);let q=g.querySelector(`#${o}-evolution-chart`);if(!q)return;let J={};n.forEach(ae=>{let pe=o==="power"?ae.stats.powerCurve:ae.stats.hrCurve;if(!pe)return;let ye=ae.name||"Unnamed Track",He=ae.stats.startTime||ae.addedAt?Zt(ae.stats.startTime||ae.addedAt):"Unknown Date",Q=`${ye} (${He})`;Object.entries(pe).forEach(([_,oe])=>{let re=Number(_),K=oe.power||oe.hr;(!J[re]||K>J[re].val)&&(J[re]={val:K,trackInfo:Q,trackId:ae.id,idx:oe.idx})})});let Y=t&&(o==="power"?t.stats.powerCurve:t.stats.hrCurve)||{},B=new Set;Object.keys(J).forEach(ae=>B.add(Number(ae))),Object.keys(Y).forEach(ae=>B.add(Number(ae)));let z=Array.from(B).sort((ae,pe)=>ae-pe),D=z,le=z.map(ae=>{let pe=Y[ae];return pe?pe.power||pe.hr:null}),y=z.map(ae=>J[ae]?.val||null),d=n.filter(ae=>(ae.stats.startTime||ae.addedAt)!=null);d.sort((ae,pe)=>(ae.stats.startTime||ae.addedAt||0)-(pe.stats.startTime||pe.addedAt||0)||ae.id.localeCompare(pe.id));let a=[],G={};z.forEach(ae=>G[ae]=[]),d.forEach(ae=>{let pe=o==="power"?ae.stats.powerCurve:ae.stats.hrCurve;pe&&(a.push((ae.stats.startTime||ae.addedAt)/1e3),z.forEach(ye=>{let He=pe[ye],Q=He?o==="power"?He.power:He.hr:null;G[ye].push(Q)}))});let X=z[0]||5,se=d,U=null;function ne(ae,pe){let ye=a[a.length-1]||1785542400,He=0;pe==="1m"?He=ye-30*24*3600:pe==="2m"?He=ye-60*24*3600:pe==="6m"?He=ye-180*24*3600:pe==="1y"?He=ye-365*24*3600:pe==="2y"&&(He=ye-2*365*24*3600);let Q=[];a.forEach((Pe,de)=>{Pe>=He&&Q.push(de)});let _=Q.map(Pe=>a[Pe]),oe=G[ae]||[],re=Q.map(Pe=>oe[Pe]),K=fn(re,5);return se=Q.map(Pe=>d[Pe]),{xFiltered:_,rawYFiltered:re,smoothedYFiltered:K}}let Le=null,Re=document.createElement("div");return Re.className="cur-y-val font-m",Re.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",q.style.position="relative",q.appendChild(Re),(()=>{let ae={id:`${o}-evolution`,width:400,height:250,padding:[0,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:"Current Track",stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}},{label:"All-Time Max",stroke:"#888888",width:1,fill:"transparent",points:{show:!0,size:6,fill:"#888888"}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(Q,_)=>_.map(oe=>`${oe}${u}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(Q,_,oe)=>oe,x:!1,y:!1},hooks:{draw:[Q=>{let _=Q.ctx,oe=window.devicePixelRatio||1,re=Q.bbox,K=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Pe=D[D.length-1];_.save(),_.fillStyle="#555564",_.textAlign="center",_.textBaseline="top",_.font=`${10*oe}px system-ui, sans-serif`;let de=-100;if(K.forEach($e=>{if($e>Pe)return;let Ce=Q.valToPos($e,"x",!0);Ce>de+30*oe&&Ce=0){let Ce=Q.valToPos(U,"x",!0),We=Q.valToPos(le[$e]||y[$e],"y",!0);_.save(),_.beginPath(),_.setLineDash([]);let te=le[$e],ge=te!==null?5*oe:3*oe,L=te!==null?c:"#888888";_.arc(Ce,We,ge,0,2*Math.PI),_.fillStyle=L,_.fill(),_.strokeStyle="#fff",_.lineWidth=2*oe,_.stroke(),_.restore()}}_.restore()},Q=>{let _=Q.ctx,oe=window.devicePixelRatio||1,re=Q.bbox,K=Q.cursor.idx,Pe=1,de=Q.cursor.left,$e=Q.cursor.top;if(de!=null&&$e!=null&&de>=0&&$e>=0){let Ce=1/0,We=-1,te=30,ge=te*te;for(let L=0;L{if(!Q._ready)return;Q.redraw(!1);let _=Q.cursor.idx,oe=1,re=Q.cursor.left,K=Q.cursor.top;if(re!=null&&K!=null&&re>=0&&K>=0){let We=1/0,te=-1,ge=30,L=ge*ge;for(let ee=0;ee${Ft(ge)}`;if(L!==null&&(Ne+=` +
+ Current: + ${L} ${u} +
+ `),ee!==null&&(Ne+=` +
+ Max: + ${ee} ${u} +
+ `),Re.innerHTML=Ne,Le&&U===null){X=ge;let{xFiltered:V,rawYFiltered:Ae,smoothedYFiltered:he}=ne(X,p),xe=he.map(be=>be!==null?be*.9:null),Ee=he.map(be=>be!==null?be*1.1:null);Le.setData([V,Ae,he,xe,Ee]);let fe=document.getElementById(`${o}-timeline-label`);fe&&(fe.textContent=`Progress ${Ft(ge)} ${o==="power"?"Power":"HR"}`)}Re.style.display="",Re.style.left=`${re+$e.left}px`,Re.style.top=`${K+$e.top}px`,Re.style.transform="translate(5px, -50%)"}else Re.style.display="none"}]}};k=new xn(ae,[D,le,y],q),wn.push(k),q.addEventListener("click",()=>{if(!k)return;let Q=k.cursor.idx;if(Q!=null){let _=D[Q],oe=null;if(U!==null?oe=null:oe=_,T(oe),t){let re=t.stats,K=o==="power"?re.powerCurve:re.hrCurve;if(K){let Pe=K[_];if(Pe){let de=Pe.idx,$e=_,Ce=t.points[de],We=t.points[de+$e-1];if(Ce&&We&&Ce.time!=null&&We.time!=null){let te=t.points[0].time||0,ge=(Ce.time-te)/1e3,L=(We.time-te)/1e3;w?.(t.id,[ge,L])}}}}}}),q.addEventListener("mouseleave",()=>{k&&k.redraw()});let pe=document.createElement("details");pe.classList.add("progress-details"),pe.style.marginTop="0px",pe.style.setProperty("--chart-color",c),pe.innerHTML=` + + chevron_right + table_chart + Data Table + + + + + + + + + + + ${z.map(Q=>{let _=Y[Q]?Y[Q].power||Y[Q].hr:"-",oe=J[Q]?.val||"-",re=J[Q]?.trackId,K=J[Q]?.idx;return` + + + + + + `}).join("")} + +
DurationCurrentAll-Time Max
${Ft(Q)}${_} ${u} + ${oe} ${u} + ${re?``:""} +
+ `,M.appendChild(pe),pe.querySelectorAll(".evolution-select-btn").forEach(Q=>{Q.addEventListener("click",_=>{_.preventDefault(),_.stopPropagation();let oe=Q.getAttribute("data-id"),re=Q.getAttribute("data-idx"),K=Q.getAttribute("data-dur");oe&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:oe,idx:re?Number(re):null,dur:K?Number(K):null}}))})});let ye=null,He=h.querySelector(`#${o}-timeline-chart`);if(He){He.style.position="relative";let Q=document.createElement("div");if(Q.className="timeline-tooltip font-m",Q.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",He.appendChild(Q),a.length>0){let{xFiltered:_,rawYFiltered:oe,smoothedYFiltered:re}=ne(X,p),K=re.map(te=>te!==null?te*.9:null),Pe=re.map(te=>te!==null?te*1.1:null),de=[_,oe,re,K,Pe],$e=[{value:(te,ge)=>ge!=null?Zt(ge*1e3):"-"},{label:"Value",stroke:c,width:0,points:{show:!0,size:6,fill:tt(c,.5)}},{label:"Trend",stroke:c,width:2,points:{show:!1},spanGaps:!0,fill:"transparent",dash:[5,5]},{label:"Lower Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0},{label:"Upper Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0}],Ce=document.getElementById(`${o}-timeline-label`);Ce&&(Ce.textContent=`Progress ${Ft(X)} ${o==="power"?"Power":"HR"}`);let We={width:Math.max(100,(R||570)-400),height:250,padding:[0,10,0,10],tzDate:te=>xn.tzDate(new Date(te*1e3),"Etc/UTC"),cursor:{points:{show:!1},drag:{setScale:!1},x:!1,y:!1},scales:{x:{time:!0,range:te=>{let ge=te.data[0][0],L=te.data[0][te.data[0].length-1];return ge===void 0||L===void 0?[0,100]:ge===L?[ge-3600,L+3600]:[ge,L]}},y:{range:(te,ge,L)=>[ge*.9,L*1.1]}},series:$e,bands:[{series:[4,3],fill:tt(c,.2)}],hooks:{init:[te=>{te.over.addEventListener("click",()=>{if(ye!=null){let ge=se[ye];if(ge){let L=ge.stats,ee=o==="power"?L.powerCurve:L.hrCurve;if(ee){let Ne=ee[X];if(Ne){let V=Ne.idx,Ae=X,he=ge.points[V],xe=ge.points[V+Ae-1];if(he&&xe&&he.time!=null&&xe.time!=null){let Ee=ge.points[0].time||0,fe=(he.time-Ee)/1e3,be=(xe.time-Ee)/1e3;e.onTrackSelect?.(ge.id,[fe,be])}else e.onTrackSelect?.(ge.id,null)}else e.onTrackSelect?.(ge.id,null)}else e.onTrackSelect?.(ge.id,null)}}})}],draw:[te=>{let ge=te.cursor.idx;if(ge!=null&&te.data[0][ge]!=null){let L=te.data[1][ge];if(L!=null){let ee=te.valToPos(te.data[0][ge],"x",!0),Ne=te.valToPos(L,"y",!0),V=te.ctx,Ae=window.devicePixelRatio||1;V.save(),V.beginPath(),V.setLineDash([2*Ae,2*Ae]),V.strokeStyle=tt(c,.4),V.lineWidth=1*Ae,V.moveTo(ee,te.bbox.top),V.lineTo(ee,te.bbox.top+te.bbox.height),V.moveTo(te.bbox.left,Ne),V.lineTo(te.bbox.left+te.bbox.width,Ne),V.stroke(),V.restore(),V.save(),V.beginPath(),V.setLineDash([]),V.arc(ee,Ne,12*Ae,0,2*Math.PI),V.fillStyle=tt(c,.2),V.fill(),V.restore(),V.save(),V.beginPath(),V.arc(ee,Ne,6*Ae,0,2*Math.PI),V.fillStyle=c,V.fill(),V.strokeStyle="#fff",V.lineWidth=2*Ae,V.stroke(),V.restore(),V.save(),V.setLineDash([]);let he=new Date(te.data[0][ge]*1e3),xe=`${he.getUTCFullYear()}-${String(he.getUTCMonth()+1).padStart(2,"0")}-${String(he.getUTCDate()).padStart(2,"0")}`;V.font=`bold ${10*Ae}px system-ui, sans-serif`;let fe=V.measureText(xe).width+10*Ae,be=16*Ae,Ue=ee-fe/2,je=Math.max(te.bbox.left,Math.min(te.bbox.left+te.bbox.width-fe,Ue)),dt=te.bbox.top+te.bbox.height+2*Ae;V.fillStyle="rgba(14, 14, 16, 0.92)",V.beginPath(),V.roundRect?V.roundRect(je,dt,fe,be,3*Ae):V.rect(je,dt,fe,be),V.fill(),V.strokeStyle=tt(c,.27),V.lineWidth=1*Ae,V.stroke(),V.fillStyle=c,V.textAlign="center",V.textBaseline="middle",V.fillText(xe,je+fe/2,dt+be/2);let It=`${L.toFixed(0)} ${u}`,Xt=V.measureText(It).width+10*Ae,Ot=te.bbox.left-Xt-2*Ae,pn=Ne-be/2;V.fillStyle="rgba(14, 14, 16, 0.92)",V.beginPath(),V.roundRect?V.roundRect(Ot,pn,Xt,be,3*Ae):V.rect(Ot,pn,Xt,be),V.fill(),V.strokeStyle=tt(c,.27),V.lineWidth=1*Ae,V.stroke(),V.fillStyle=c,V.textAlign="left",V.textBaseline="middle",V.fillText(It,Ot+5*Ae,pn+be/2),V.restore()}}}],setCursor:[te=>{if(!te._ready)return;te.redraw(!1);let ge=te.cursor.idx,L=te.cursor.left,ee=te.cursor.top,Ne=te.bbox;if(L!=null&&ee!=null&&L>=0&&ee>=0){let V=1/0,Ae=-1,he=30,xe=he*he,Ee=te.data[0],fe=te.data[1];for(let be=0;be + Date: + ${Ee} + +
+ Value: + ${be} +
+ `,Q.style.display="block",Q.style.left=`${L+Ne.left}px`,Q.style.top=`${ee+Ne.top}px`,Q.style.transform="translate(5px, -50%)"}else Q.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(te,ge)=>ge.map(L=>{let ee=new Date(L*1e3);return`${ee.getUTCFullYear()}-${String(ee.getUTCMonth()+1).padStart(2,"0")}`})},{stroke:"#555564",grid:{stroke:"#2e2e34"},font:"10px system-ui, sans-serif",values:(te,ge)=>ge.map(L=>`${L} ${u}`),show:!0,space:15,size:50}]};Le=new xn(We,de,He),wn.push(Le),He.addEventListener("mouseleave",()=>{Le.redraw()})}else He.innerHTML='
No data for the past year
'}})(),{updatePin:ae=>{U=ae,ae!==null&&(X=ae);let pe=document.getElementById(`${o}-timeline-label`);if(pe&&(pe.textContent=`Progress ${Ft(X)} ${o==="power"?"Power":"HR"}${U!==null?" (Pinned)":""}`),Le){let{xFiltered:ye,rawYFiltered:He,smoothedYFiltered:Q}=ne(X,p),_=Q.map(re=>re!==null?re*.9:null),oe=Q.map(re=>re!==null?re*1.1:null);Le.setData([ye,He,Q,_,oe])}k&&k.redraw()},updateRange:ae=>{if(p=ae,Le){let{xFiltered:pe,rawYFiltered:ye,smoothedYFiltered:He}=ne(X,p),Q=He.map(oe=>oe!==null?oe*.9:null),_=He.map(oe=>oe!==null?oe*1.1:null);Le.setData([pe,ye,He,Q,_])}}}}function ml(e){let s=new Date(e),t=s.getUTCDay(),n=s.getUTCDate()-t+(t===0?-6:1);return s.setUTCDate(n),s.setUTCHours(0,0,0,0),s}function Ol(e){let s={};return e.forEach(t=>{if(!t.stats.startTime||!t.stats.totalDist)return;let n=new Date(t.stats.startTime),o=ml(n),r=o.toISOString().split("T")[0];s[r]||(s[r]={timestamp:o.getTime(),distance:0}),s[r].distance+=t.stats.totalDist}),Object.entries(s).map(([t,n])=>({week:t,timestamp:n.timestamp,distance:n.distance})).sort((t,n)=>t.timestamp-n.timestamp)}function Yl(e){let s={};return e.forEach(t=>{if(!t.stats.startTime||t.stats.elevGain===void 0)return;let n=new Date(t.stats.startTime),o=ml(n),r=o.toISOString().split("T")[0];s[r]||(s[r]={timestamp:o.getTime(),elevation:0}),s[r].elevation+=t.stats.elevGain}),Object.entries(s).map(([t,n])=>({week:t,timestamp:n.timestamp,elevation:n.elevation})).sort((t,n)=>t.timestamp-n.timestamp)}function cl(e,s,t,n,o,r){let u=t==="distance",c=u?Ol(s):Yl(s),m=il(s,B=>u?B.stats.totalDist:B.stats.elevGain),T=u?De.distance.color:De.elevation.color,b=u?"km":"m",w=u?De.distance.icon:De.elevation.icon,R=document.createElement("div");R.className=`chart-row ${t}-progress-card`,R.id=`${t}-evolution-card`,R.innerHTML=` +
+
+ ${w} + ${u?"Distance Progress":"Elevation Progress"} +
+
+
+
+
+
+
+
+ ${al(m,u,b)} +
+
+ `,e.appendChild(R);let S=R.querySelector(`#${t}-weekly-chart`),k=R.querySelector(`#${t}-y-axis-chart`);if(!S||!k)return;S.style.position="relative";let M=document.createElement("div");M.className="cur-y-val",M.style.cssText=`color:${T};display:none`,S.appendChild(M);let g=c.map(B=>B.timestamp/1e3),I=u?c.map(B=>B.distance/1e3):c.map(B=>B.elevation);if(g.length===0)return;let P=fn(I,2),p=Math.max(0,(r||570)-20-320-20),h=Math.max(p,g.length*40),F=Math.max(...I)*1.1,q={width:h,height:150,padding:[10,10,0,10],tzDate:B=>xn.tzDate(new Date(B*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,F]}},series:[{},{label:u?"Distance":"Elevation",stroke:T,fill:tt(T,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:T,width:2,dash:[5,5],points:{show:!1}}],cursor:{sync:n?{key:n.key}:void 0,drag:{x:!1,y:!1},points:{show:!1},x:!1,y:!1},hooks:{init:[B=>{B.over.addEventListener("click",()=>{let z=B.cursor.idx;if(z!=null){let D=c[z];if(D){let le=new Date(D.timestamp),y=new Date(D.timestamp+7*24*60*60*1e3),d=le.toISOString().split("T")[0],a=y.toISOString().split("T")[0];o?.(d,a)}}})}],setCursor:[B=>{if(!B._ready)return;let z=B.cursor.idx,D=B.cursor.left,le=B.cursor.top;if(z!=null&&D!=null&&le!=null&&D>=0&&le>=0){let y=B.data[1][z],d=y!=null?u?`${y.toFixed(1)} km`:`${y.toFixed(0)} m`:"\u2014";M.innerHTML=d,M.style.display="block",M.style.left=`${B.valToPos(B.data[0][z],"x",!1)}px`,M.style.top=`${B.valToPos(B.data[1][z],"y",!1)}px`,M.style.transform="translate(6px, -50%)"}else M.style.display="none";B.redraw(!1)}],draw:[B=>{let z=B.cursor.idx;if(z!=null&&B.data[0][z]!=null){let D=B.valToPos(B.data[0][z],"x",!0),le=B.valToPos(B.data[1][z],"y",!0),y=window.devicePixelRatio||1,d=B.ctx,a=B.bbox;d.save(),d.beginPath(),d.setLineDash([2*y,2*y]),d.strokeStyle=tt(T,.4),d.lineWidth=1*y,d.moveTo(D,a.top),d.lineTo(D,a.top+a.height),d.moveTo(a.left,le),d.lineTo(a.left+a.width,le),d.stroke(),d.restore(),d.save(),d.beginPath(),d.setLineDash([]),d.arc(D,le,12*y,0,2*Math.PI),d.fillStyle=tt(T,.2),d.fill(),d.restore(),d.save(),d.beginPath(),d.arc(D,le,6*y,0,2*Math.PI),d.fillStyle=T,d.fill(),d.strokeStyle="#fff",d.lineWidth=2*y,d.stroke(),d.restore(),d.save(),d.setLineDash([]);let G=new Date(B.data[0][z]*1e3),X=`${G.getUTCFullYear()}-${String(G.getUTCMonth()+1).padStart(2,"0")}-${String(G.getUTCDate()).padStart(2,"0")}`;d.font=`bold ${10*y}px system-ui, sans-serif`;let U=d.measureText(X).width+10*y,ne=16*y,Le=D-U/2,Re=Math.max(a.left,Math.min(a.left+a.width-U,Le)),Be=a.top+a.height+2*y;d.fillStyle="rgba(14, 14, 16, 0.92)",d.beginPath(),d.roundRect?d.roundRect(Re,Be,U,ne,3*y):d.rect(Re,Be,U,ne),d.fill(),d.strokeStyle=tt(T,.27),d.lineWidth=1*y,d.stroke(),d.fillStyle=T,d.textAlign="center",d.textBaseline="middle",d.fillText(X,Re+U/2,Be+ne/2),d.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(B,z)=>z.map(D=>{let le=new Date(D*1e3);return`${le.getUTCMonth()+1}/${le.getUTCDate()}`}),font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:(B,z)=>z.map(D=>`${D.toFixed(0)} ${b}`),font:"10px system-ui, sans-serif",size:40}]},J=new xn(q,[g,I,P],S);wn.push(J);let Y=R.querySelector(".chart-scroll-container");return Y&&g.length*40>h&&(Y.scrollLeft=Y.scrollWidth-Y.clientWidth),{updateRange:B=>{let z=c[c.length-1]?.timestamp||17855424e5,D=0;B==="1m"?D=z-30*24*3600*1e3:B==="2m"?D=z-60*24*3600*1e3:B==="6m"?D=z-180*24*3600*1e3:B==="1y"?D=z-365*24*3600*1e3:B==="2y"&&(D=z-2*365*24*3600*1e3);let le=c.filter(se=>se.timestamp>=D),y=le.map(se=>se.timestamp/1e3),d=u?le.map(se=>se.distance/1e3):le.map(se=>se.elevation),a=fn(d,2),G=Math.max(S.clientWidth,y.length*40),X=Math.max(...d)*1.1;J.setSize({width:G,height:150}),J.setScale("y",{min:0,max:X}),J.setData([y,d,a]),Y&&(Y.scrollLeft=Y.scrollWidth-Y.clientWidth)}}}var ss=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],jl=16,ze={},Tt=[];function Zl(e,s){let t=new Date(e),n=new Date(s);return t.getUTCFullYear()===n.getUTCFullYear()&&t.getUTCMonth()===n.getUTCMonth()&&t.getUTCDate()===n.getUTCDate()}var Sn=!1,Oe=null,Dn=0,Bn=!1,Mn=null,ln="",sn=!1,dn="date-desc",Te={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};function cn(e=!1){Ye.patch({f_date:Te.date.every(s=>s===null)?null:Te.date,f_dist:Te.dist.every(s=>s===null)?null:Te.dist,f_dur:Te.dur.every(s=>s===null)?null:Te.dur,f_mets:Te.metrics.size===0?null:Array.from(Te.metrics),f_tags:Te.tags.length===0?null:Te.tags},e)}function ys(){let e=Me.getActiveMetrics(),s=Me.METRICS,t=Array.from(e).map(n=>s[n].abbr);Ye.patch({metrics:t.length?t:null})}var gl=[{label:"Newest first",val:"date-desc",icon:"calendar_today"},{label:"Oldest first",val:"date-asc",icon:"history"},{label:"Longest distance",val:"dist-desc",icon:"straighten"},{label:"Shortest distance",val:"dist-asc",icon:"horizontal_rule"},{label:"Longest duration",val:"dur-desc",icon:"timer"},{label:"Shortest duration",val:"dur-asc",icon:"timer_off"}];function Gl(e){document.querySelectorAll(".sort-menu-popup").forEach(o=>o.remove());let s=document.createElement("div");s.className="sort-menu-popup",gl.forEach(o=>{let r=document.createElement("div");r.className=`menu-item ${dn===o.val?"active":""}`,r.innerHTML=` + ${o.icon} + ${o.label} + ${dn===o.val?"check":""} + `,r.addEventListener("click",()=>{dn=o.val,Ye.patch({sort:o.val}),bl(),mn(),s.remove()}),s.appendChild(r)});let t=e.getBoundingClientRect();s.style.top=`${t.bottom+5}px`,s.style.left=`${t.left}px`,document.body.appendChild(s);let n=o=>{!s.contains(o.target)&&!e.contains(o.target)&&(s.remove(),document.removeEventListener("click",n))};setTimeout(()=>document.addEventListener("click",n),0)}function Xl(e){document.querySelectorAll(".metric-menu-popup").forEach(c=>c.remove());let s=document.createElement("div");s.className="metric-menu-popup";let t=Me.METRICS,n=Me.getAvailableMetrics(),o=Me.getActiveMetrics();Object.entries(t).forEach(([c,m])=>{if(!n.has(c))return;let T=document.createElement("div");T.className=`menu-item ${o.has(c)?"active":""}`,T.innerHTML=` + ${m.icon} + ${m.label} + ${o.has(c)?"check":""} + `,T.addEventListener("click",()=>{Me.toggleMetric(c);let b=Me.getActiveMetrics().has(c);T.classList.toggle("active",b),T.querySelector(".check").textContent=b?"check":"";let w=document.querySelector(`#metric-pills .metric-pill[data-metric="${c}"]`);w&&w.classList.toggle("active",b),kn(),ys()}),s.appendChild(T)});let r=e.getBoundingClientRect();s.style.top=`${r.bottom+5}px`,s.style.right=`${window.innerWidth-r.right}px`,document.body.appendChild(s);let u=c=>{!s.contains(c.target)&&!e.contains(c.target)&&(s.remove(),document.removeEventListener("click",u))};setTimeout(()=>document.addEventListener("click",u),0)}document.addEventListener("select-track",e=>{let s=e.detail.id,t=e.detail.idx,n=e.detail.dur;if(s&&ze[s]&&(Mt(s),t!=null&&n!=null)){let o=ze[s],r=o.points;if(t>=0&&tS.time!=null)?.time||0,m=(u.time-c)/1e3,T=m+n;Me.restoreSelection(m,T);let b=r.findIndex(S=>(S.time||0)>=u.time+n*1e3);b===-1&&(b=r.length-1);let w=r.slice(t,b+1),R=it.computeStats(w);Me.setSelectionStats(R),Bt(o),_e.highlightSegment(s,r,t,b,!1,Mn),_e.ensureVisible(w.map(S=>[S.lat,S.lon])),Ye.patch({sel:[m,T]})}}}});document.addEventListener("click",e=>{let s=e.target.closest(".tab-btn");if(!s)return;let t=s.closest("#tab-nav");if(!t)return;t.querySelectorAll(".tab-btn").forEach(r=>r.classList.toggle("active",r===s));let n=s.dataset.tab;Ye.patch({tab:n},!0);let o=t.closest("#chart-panel");if(o&&o.querySelectorAll(".tab-content").forEach(r=>{r.classList.toggle("active",r.id===`tab-${s.dataset.tab}`)}),s.dataset.tab==="details"&&Oe&&ze[Oe]&&on(ze[Oe],ws()),s.dataset.tab==="insights"&&Oe&&ze[Oe]&&Bt(ze[Oe]),s.dataset.tab==="evolution"&&Tn(Oe?ze[Oe]:null,Object.values(ze),(r,u)=>{Mt(r,!0),u&&(Me.restoreSelection(u[0],u[1]),un(u[0],u[1],"time",!0))},(r,u)=>{Te.date=[r,u],kt(),cn(!0),Fn()}),s.dataset.tab==="combined"&&Oe&&ze[Oe]&&rn(ze[Oe]),s.dataset.tab==="courses"&&Dt(),s.dataset.tab==="graphs"){Me.resize(),kn();let r=Ye.get().sel;r&&Me.restoreSelection(r[0],r[1])}});async function xs(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await at.clear(),ze={},Tt=[],Oe=null,Dn=0,Mn=null,Sn=!1,Bn=!1,ln="",sn=!1,dn="date-desc",Te.date=[null,null],Te.dist=[null,null],Te.dur=[null,null],Te.metrics.clear(),Te.tags=[],it.setHRZones([120,140,160,180]),it.setFTP(200),Gs(),nl(),Os(),ol(),ul(),_e.removeAllTracks&&_e.removeAllTracks(),_e.clearTracks&&_e.clearTracks(),_e.clearHighlight(),Me.resetState?Me.resetState():Me.clear&&Me.clear(),document.querySelectorAll(".tab-btn").forEach(s=>{s.classList.toggle("active",s.dataset.tab==="graphs")}),document.querySelectorAll(".tab-content").forEach(s=>{s.classList.toggle("active",s.id==="tab-graphs")}),Ye.reset();let e=document.getElementById("toast-container");e&&(e.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(s=>s.remove()),typeof mn=="function"&&mn()}async function Jl(){let e=null,s=new Promise(g=>{e=window.setTimeout(g,1e3)});try{let g=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([g,s])}finally{e!==null&&window.clearTimeout(e)}document.body.classList.remove("loading-fonts");let t=document.getElementById("storage-backend-select");t&&(t.value=Ye.get().storage||"memory",t.addEventListener("change",g=>{let I=g.target.value,P=new URLSearchParams(window.location.search);I==="memory"?P.delete("storage"):P.set("storage",I),window.location.search=P.toString()}));let n=document.getElementById("global-loader"),o=document.getElementById("loader-text"),r=document.getElementById("loader-subtext"),u=document.getElementById("loader-progress-bar"),c=document.getElementById("map-loader"),m=c?.querySelector("span");c&&(m&&(m.textContent="Loading database..."),c.classList.remove("hidden"));let T=Ye.get();tl((g,I)=>ls(g,I==="error"?"error":"info")),Vs(()=>{kt(),cn()},g=>{io(g)}),Zs((g,I)=>ls(g,I==="error"?"error":"info")),_e.init(g=>Mt(g),to,no,(g,I)=>{g===Oe?Me.setHoverAt(I):Me.setHoverAt(null)},so),Me.init(lo,un,oo,g=>{Ye.patch({sel_point:g})}),Me.setMapColorChangeCb(g=>{g?(Mn=g.colors,Oe&&_e.colorTrackByMetric(Oe,g.pts,g.colors)):(Mn=null,Oe&&_e.clearMetricColor(Oe));let I=Ye.get();I.sel&&un(I.sel[0],I.sel[1],Me.getXAxis())}),fl(T),await at.openDB(),await xs();try{let g=await at.get("hr_zones");g&&it.setHRZones(g);let I=await at.get("ftp");I&&it.setFTP(I);let P=await at.getAll();P.sort((J,Y)=>J.addedAt-Y.addedAt),m&&(m.textContent=`Preparing ${P.length} tracks...`);let p=[];for(let J of P){let Y=!1;if(!J.bounds&&J.points.length>0){let B=ms(J.points);B&&(J.bounds=B,Y=!0)}!J.simplifiedPoints&&J.points.length>0&&(J.simplifiedPoints=ps(J.points,50),Y=!0),Y&&await at.save(J),ze[J.id]=J,p.push(J)}_e.addTracks(p),kt();let h=T.track&&P.find(J=>J.id===T.track)?T.track:P.length>0?P[0].id:null,F=document.getElementById("map-loader"),q=P.find(J=>J.id===h);if(q&&(await pl(q),Mt(q.id,!T.map_pos),T.sel&&Array.isArray(T.sel)&&T.sel.length===2&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Me.restoreSelection(T.sel[0],T.sel[1])})}),T.sel_point!==void 0&&T.sel_point!==null&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Me.setCursorAt(T.sel_point)})})),F&&F.classList.add("hidden"),P.length>(q?1:0)){F&&(m&&(m.textContent="Loading tracks..."),F.classList.remove("hidden"));let J=P.filter(z=>z.id!==h),Y=0,B=async()=>{let D=Math.min(Y+2,J.length);for(;Y{Mt(le,!0),y&&(Me.restoreSelection(y[0],y[1]),un(y[0],y[1],"time",!0))}),P.length&&!T.map_pos&&_e.fitAll())};requestAnimationFrame(B)}else kt(),P.length&&!T.map_pos&&_e.fitAll()}catch(g){console.warn("Could not load saved tracks:",g)}Kl(),eo(),po(),kn(),document.getElementById("basemap-switcher")?.addEventListener("click",g=>{let I=g.target.closest(".bm-btn");I&&(document.querySelectorAll(".bm-btn").forEach(P=>P.classList.remove("active")),I.classList.add("active"),I.dataset.layer&&(_e.switchBasemap(I.dataset.layer),Ye.patch({map:I.dataset.layer})))}),document.getElementById("btn-fit-all")?.addEventListener("click",()=>_e.fitAll()),document.getElementById("btn-clear-all")?.addEventListener("click",ao),document.getElementById("track-search")?.addEventListener("input",g=>{ln=g.target.value,kt(),Ye.patch({q:ln||null})}),document.getElementById("btn-regex-toggle")?.addEventListener("click",g=>{sn=!sn,g.target.classList.toggle("active",sn),kt(),Ye.patch({re:sn?1:null})}),document.getElementById("btn-sort-menu")?.addEventListener("click",g=>{g.stopPropagation(),Gl(g.currentTarget)}),document.getElementById("btn-metric-menu")?.addEventListener("click",g=>{g.stopPropagation(),Xl(g.currentTarget)});let b=(g,I)=>{I&&I.classList.toggle("active"),Me.toggleMetric(g),ys()};document.getElementById("metric-pills")?.addEventListener("click",g=>{let I=g.target.closest(".metric-pill");if(I){let P=I.dataset.metric;P&&(b(P,I),Me.getActiveMetrics().has(P)&&document.querySelector(`.chart-row[data-metric="${P}"]`)?.scrollIntoView({behavior:"smooth"}))}}),document.getElementById("x-axis-ctrl")?.addEventListener("click",g=>{let I=g.target.closest(".seg-btn");if(!I)return;let P=I.dataset.axis;Me.setXAxis(P),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(p=>p.classList.toggle("active",p===I)),Ye.patch({xaxis:P})}),document.getElementById("btn-follow-dot")?.addEventListener("click",g=>{Bn=!Bn,g.currentTarget.classList.toggle("active",Bn)}),document.getElementById("btn-reset-zoom")?.addEventListener("click",()=>{Me.resetZoom(),_e.clearHighlight()}),mo(),document.getElementById("file-input")?.addEventListener("change",g=>{os(Array.from(g.target.files||[])),g.target.value=""}),document.getElementById("folder-input")?.addEventListener("change",g=>{os(Array.from(g.target.files||[])),g.target.value=""}),document.getElementById("btn-toggle-filters")?.addEventListener("click",()=>{let g=document.getElementById("filter-panel");g&&(g.classList.toggle("hidden"),document.getElementById("btn-toggle-filters")?.classList.toggle("active",!g.classList.contains("hidden")))});let w=(g,I,P)=>{let p=P.target.value;Te[g][I]=p===""?null:p,kt(),cn()};document.getElementById("filter-date-start")?.addEventListener("change",g=>w("date",0,g)),document.getElementById("filter-date-end")?.addEventListener("change",g=>w("date",1,g)),document.getElementById("filter-dist-min")?.addEventListener("input",g=>w("dist",0,g)),document.getElementById("filter-dist-max")?.addEventListener("input",g=>w("dist",1,g)),document.getElementById("filter-dur-min")?.addEventListener("input",g=>w("dur",0,g)),document.getElementById("filter-dur-max")?.addEventListener("input",g=>w("dur",1,g));let R=document.getElementById("sport-burger-btn"),S=document.getElementById("sport-dropdown-content");R?.addEventListener("click",g=>{if(g.stopPropagation(),S){let I=S.style.display==="block";S.style.display=I?"none":"block"}}),document.addEventListener("click",g=>{S&&S.style.display==="block"&&!S.contains(g.target)&&g.target!==R&&(S.style.display="none")}),document.getElementById("sport-filter-container")?.addEventListener("click",g=>{let I=g.target,P=I.closest("[data-sport]");if(P){let p=P.dataset.sport||null;Te.sport=Te.sport===p?null:p,kt(),cn(),Fn(),I.closest(".dropdown-item")&&S&&(S.style.display="none")}}),document.getElementById("filter-metrics")?.addEventListener("click",g=>{let I=g.target.closest(".mini-pill");if(!I)return;let P=I.dataset.metric;Te.metrics.has(P)?Te.metrics.delete(P):Te.metrics.add(P),Fn(),kt(),cn()}),document.getElementById("btn-reset-filters")?.addEventListener("click",()=>{Te={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},Fn(),kt(),cn()}),document.getElementById("filter-tags")?.addEventListener("input",g=>{let I=g.target.value;Te.tags=I.split(",").map(P=>P.trim().toLowerCase()).filter(P=>!!P),kt(),cn()}),document.addEventListener("keydown",g=>{g.key==="Escape"&&(_e.hideCursor(),_e.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(I=>I.remove()))}),window.addEventListener("resize",()=>{Me.resize(),yn(),_e.invalidateSize?.(),kn()}),window.addEventListener("popstate",()=>{Ye.refresh(),fl(Ye.get())}),Ql(),await hl();let k=document.createElement("div");k.id="app-is-ready",k.setAttribute("data-ready","true"),k.style.display="none",document.body.appendChild(k);let M=document.createElement("div");M.id="appIsReady",M.setAttribute("data-ready","true"),M.style.display="none",document.body.appendChild(M)}var En=null;async function hl(){if(En)return En;try{let s=await(await fetch("./test-data/manifest.json")).json(),t=new TextDecoder;En=await Promise.all(s.map(async o=>{let u=await(await fetch(`./test-data/${o}`)).arrayBuffer(),c=o;if(o.toLowerCase().endsWith(".gz")){c=o.slice(0,-3);let b=new Uint8Array(u);if(b.length>=2&&b[0]===31&&b[1]===139){let w=new DecompressionStream("gzip"),R=new Blob([u]).stream().pipeThrough(w);u=await new Response(R).arrayBuffer()}}let m=c.toLowerCase().endsWith(".fit")?void 0:t.decode(u),T=new File([u],c,{type:"application/octet-stream"});return T._buf=u,m!==void 0&&(T._text=m),{cleanName:c,buf:u,text:m,file:T}}));let n=null;for(let o of[0,2,4])if(En[o]){let r=await it.parseFile(En[o].file);o===0&&(n=r)}if(n){let o=n.points.slice(0,60),r={...n,id:"warmup",fileName:"warmup.gpx",fileSize:1024,points:o,stats:it.computeStats(o),addedAt:17855424e5,visible:!0,color:ss[0]};it.ensureCurvesAndZones(r),Me.loadTrack(r,[r],!1),Me.setActiveMetrics(["elevation","speed","power"]),Bt(r),Tn(r,[r]),await xs(),document.body.offsetHeight,await new Promise(u=>window.setTimeout(u,0))}else typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();return En}catch{return[]}}function Ql(){let e=document.getElementById("btn-step-load"),s=document.getElementById("btn-step-analysis"),t=document.getElementById("btn-step-insights"),n=document.getElementById("btn-step-details"),o=document.getElementById("btn-step-aggregate"),r=document.getElementById("btn-step-evolution"),u=document.getElementById("btn-step-courses");function c(m){document.querySelectorAll(".tab-btn").forEach(T=>{T.classList.toggle("active",T.dataset.tab===m)}),document.querySelectorAll(".tab-content").forEach(T=>{T.classList.toggle("active",T.id===`tab-${m}`)}),Ye.patch({tab:m},!1)}e?.addEventListener("click",async()=>{try{Object.keys(ze).length>0||Tt.length>0||Oe!==null?(await at.openDB(),await xs()):typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();let T=(await hl()).map(w=>w.file);await os(T);let b=Object.values(ze);!Oe&&b.length>0&&Mt(b[0].id)}finally{window.dispatchEvent(new CustomEvent("load-and-parse-complete"))}}),s?.addEventListener("click",()=>{try{let m=Object.values(ze);c("graphs"),!Oe&&m.length>0&&Mt(m[0].id),Me.restoreSelection(120,900,!0),Me.setCursorAt(300,!0);let T=Me.getAvailableMetrics(),b=["elevation","speed","power"].filter(w=>T.has(w));b.length>0?(document.querySelectorAll("#metric-pills .metric-pill").forEach(w=>{let R=w.dataset.metric;R&&w.classList.toggle("active",b.includes(R))}),kn(),Me.setActiveMetrics(b)):kn(),un(120,900,Me.getXAxis(),!1)}finally{window.dispatchEvent(new CustomEvent("analysis-complete"))}}),t?.addEventListener("click",()=>{try{let m=Object.values(ze);m.forEach(b=>it.ensureCurvesAndZones(b)),c("insights");let T=Oe&&ze[Oe]||m[0]||null;Bt(T)}finally{window.dispatchEvent(new CustomEvent("insights-complete"))}}),n?.addEventListener("click",()=>{try{let m=Object.values(ze);c("details");let T=Oe&&ze[Oe]||m[0]||null;on(T,ws())}finally{window.dispatchEvent(new CustomEvent("details-complete"))}}),o?.addEventListener("click",()=>{try{let m=Object.values(ze);if(m.length>=2){let T=[m[0],m[1]];c("combined"),rn(T),yn()}}finally{window.dispatchEvent(new CustomEvent("aggregate-complete"))}}),r?.addEventListener("click",()=>{try{let m=Object.values(ze);c("evolution");let T=Oe&&ze[Oe]||m[0]||null;Tn(T,m,(b,w)=>{Mt(b,!0),w&&(Me.restoreSelection(w[0],w[1]),un(w[0],w[1],"time",!0))})}finally{window.dispatchEvent(new CustomEvent("evolution-complete"))}}),u?.addEventListener("click",()=>{try{let m=Object.values(ze);c("courses"),Xs(m),Dt(),_n("course-1",!0)}finally{window.dispatchEvent(new CustomEvent("courses-complete"))}}),window.benchmarkSteps={loadAndParseFiles:()=>document.getElementById("btn-step-load")?.click(),displayAnalysisMetrics:()=>document.getElementById("btn-step-analysis")?.click(),displayInsights:()=>document.getElementById("btn-step-insights")?.click(),displayDetails:()=>document.getElementById("btn-step-details")?.click(),displayAggregateMetrics:()=>document.getElementById("btn-step-aggregate")?.click(),displayEvolutionMetrics:()=>document.getElementById("btn-step-evolution")?.click(),displayCourses:()=>document.getElementById("btn-step-courses")?.click()}}async function pl(e){let s=e.stats.powerCurve?Object.values(e.stats.powerCurve):[],t=e.points.length>1&&(e.points[1].speed===void 0||e.points[1].gradient===void 0);(t||!e.stats.powerCurve||!e.stats.hrZones||!e.stats.hrCurve||e.stats.shifts===void 0||e.stats.avgBattery===void 0||e.stats.avgTemp===void 0||s.length>0&&typeof s[0]=="number"||(e.stats.duration||0)>10800*1e3&&e.stats.powerCurve&&!e.stats.powerCurve[14400])&&(t&&(e.points=it.enrichPoints(e.points)),e.stats=it.computeStats(e.points),await at.save(e)),ze[e.id]=e,Dn=Math.max(Dn,ss.indexOf(e.color)+1),_e.addTrack(e),_e.setTrackVisible(e.id,e.visible&&!e._filtered),mn()}function Kl(){let e=document.getElementById("resize-handle"),s=document.getElementById("chart-panel");if(!e||!s)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,document.body.style.cursor="ns-resize"}),document.addEventListener("mousemove",n=>{if(!t)return;let o=window.innerHeight-n.clientY,r=Math.max(100,Math.min(window.innerHeight-100,o));s.style.height=`${r}px`,Me.resize(),yn(),_e.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,document.body.style.cursor="")})}function eo(){let e=document.getElementById("sidebar-resizer"),s=document.getElementById("sidebar");if(!e||!s)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,e.classList.add("dragging"),document.body.classList.add("dragging-sidebar")}),document.addEventListener("mousemove",n=>{if(!t)return;let o=n.clientX,r=Math.max(200,Math.min(600,o));s.style.width=`${r}px`,s.style.setProperty("--sidebar-w",`${r}px`),Me.resize(),_e.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,e.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}function to(e,s,t){Ye.patch({map_pos:[e,s,t]})}function no(e,s){Mt(e,!1),Me.setCursorAt(s)}function so(){}function lo(e){e&&e.lat!=null&&e.lon!=null?(_e.showCursorAt(e.lat,e.lon),Bn&&_e.centerOn(e.lat,e.lon,null,!0)):_e.hideCursor()}function un(e,s,t,n=!1){if(!Oe||!ze[Oe])return;let o=ze[Oe];if(e===null||s===null){_e.clearHighlight(),o&&(Ye.get().tab||"graphs")==="insights"&&Bt(o),Ye.patch({sel:null});return}let r=o.points,u=0,c=r.length-1;if(t==="distance"){let b=e*1e3,w=s*1e3;u=r.findIndex(R=>(R.dist||0)>=b),c=r.findIndex(R=>(R.dist||0)>=w)}else{let b=r.find(S=>S.time!=null)?.time||0,w=b+e*1e3,R=b+s*1e3;u=r.findIndex(S=>(S.time||0)>=w),c=r.findIndex(S=>(S.time||0)>=R)}u===-1&&(u=0),c===-1&&(c=r.length-1);let m=r.slice(u,c+1),T=it.computeStats(m);Me.setSelectionStats(T),(Ye.get().tab||"graphs")==="insights"&&Bt(o),_e.highlightSegment(Oe,r,u,c,n,Mn),_e.ensureVisible(m.map(b=>[b.lat,b.lon])),Ye.patch({sel:[e,s]})}function oo(e,s){e&&e.lat!=null&&e.lon!=null&&_e.centerOn(e.lat,e.lon,jl)}function Mt(e,s=!0,t=!1){if(!ze[e])return;if(e===Oe){s&&_e.fitTrack(e);return}let n=Oe!==null;n&&(Me.clear(),on(null,[]),Bt(null)),Oe=e,Mn=null,_e.clearMetricColor(e),n&&Me.toggleMapColor(null),Ye.patch({track:e,sel:null},!0),n&&Me.cancelSelection(),mn();let o=Ye.get().tab||"graphs";o==="details"&&on(ze[e],ws()),o==="insights"&&Bt(ze[e]),o==="combined"&&rn(ze[e]),o==="courses"&&Dt(),o==="evolution"&&Tn(ze[e],Object.values(ze),(r,u)=>{Mt(r,!0),u&&(Me.restoreSelection(u[0],u[1]),un(u[0],u[1],"time",!0))}),_e.setSelectedTrack(e,s),s&&_e.fitTrack(e),Me.loadTrack(ze[e],Object.values(ze),t)}async function io(e){await at.remove(e),_e.removeTrack(e),delete ze[e],Oe===e&&(Oe=null,Me.clear(),on(null,[]),Bt(null),Ye.patch({track:null,sel:null,sel_point:null})),kt()}async function ao(){let e=Math.floor(10+Math.random()*90).toString(),s=document.createElement("div");s.className="modal-backdrop",s.innerHTML=` + + `,document.body.appendChild(s);let t=s.querySelector(".modal-input"),n=s.querySelector(".modal-btn.confirm"),o=s.querySelector(".modal-btn.cancel");t.focus(),t.addEventListener("input",()=>{n.disabled=t.value!==e});let r=()=>s.remove();o.addEventListener("click",r),s.addEventListener("click",u=>{u.target===s&&r()}),n.addEventListener("click",async()=>{t.value===e&&(r(),Sn=!0,await at.clear(),ze={},Oe=null,_e.clearHighlight(),window.location.reload())})}function kt(e=!1){Object.keys(ze).forEach(t=>{let n=ze[t],o=n.stats,r=!0;if(ln)if(sn)try{new RegExp(ln,"i").test(n.name)||(r=!1)}catch{r=!1}else n.name.toLowerCase().includes(ln.toLowerCase())||(r=!1);if(r&&(Te.date[0]||Te.date[1])){let u=Te.date[0]?new Date(Te.date[0]).getTime():0,c=Te.date[1]?new Date(Te.date[1]).getTime():1/0,m=o.startTime||0;(mc)&&(r=!1)}if(r&&(Te.dist[0]!==null||Te.dist[1]!==null)){let u=(Te.dist[0]||0)*1e3,c=(Te.dist[1]||1/0)*1e3;(o.totalDistc)&&(r=!1)}if(r&&(Te.dur[0]!==null||Te.dur[1]!==null)){let u=(Te.dur[0]||0)*6e4,c=(Te.dur[1]||1/0)*6e4,m=o.duration||0;(mc)&&(r=!1)}if(r&&Te.metrics.size>0)for(let u of Te.metrics){let c=Me.METRICS[u].field;if(!n.points.some(m=>m[c]!=null)){r=!1;break}}if(r&&Te.sport&&n.sport!==Te.sport&&(r=!1),r&&Te.tags.length>0){let u=n.tags||[];Te.tags.every(c=>u.includes(c))||(r=!1)}n._filtered=!r,_e.setTrackVisible(n.id,n.visible&&r)}),e||mn()}function Fn(){document.getElementById("filter-date-start").value=Te.date[0]||"",document.getElementById("filter-date-end").value=Te.date[1]||"",document.getElementById("filter-dist-min").value=Te.dist[0]!==null?String(Te.dist[0]):"",document.getElementById("filter-dist-max").value=Te.dist[1]!==null?String(Te.dist[1]):"",document.getElementById("filter-dur-min").value=Te.dur[0]!==null?String(Te.dur[0]):"",document.getElementById("filter-dur-max").value=Te.dur[1]!==null?String(Te.dur[1]):"",document.getElementById("filter-tags").value=Te.tags.join(", "),document.querySelectorAll("#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item").forEach(t=>{let n=t;n.classList.toggle("active",(n.dataset.sport||"")===(Te.sport||""))}),document.querySelectorAll("#filter-metrics .mini-pill").forEach(t=>{let n=t;n.classList.toggle("active",Te.metrics.has(n.dataset.metric))});let e=(Te.date[0]?1:0)+(Te.date[1]?1:0)+(Te.dist[0]!==null?1:0)+(Te.dist[1]!==null?1:0)+(Te.dur[0]!==null?1:0)+(Te.dur[1]!==null?1:0)+Te.metrics.size+(Te.tags.length>0?1:0),s=document.querySelector("#btn-toggle-filters .btn-badge");s&&(s.textContent=e>0?String(e):"",s.classList.toggle("hidden",e===0))}function bl(){let e=document.getElementById("track-search");e&&(e.value=ln),document.getElementById("btn-regex-toggle")?.classList.toggle("active",sn);let s=gl.find(t=>t.val===dn);if(s){let t=document.getElementById("sort-current-label"),n=document.getElementById("sort-current-icon");t&&(t.textContent=s.label.replace(" first","").replace(" distance","").replace(" duration","")),n&&(n.textContent=s.icon)}}function fl(e){let s=e.track;if(s!==Oe&&(s&&ze[s]?Mt(s,!0):!s&&Oe&&(Oe=null,Me.clear(),on(null,[]),Bt(null),mn(),_e.fitAll())),e.map&&typeof e.map=="string"&&(_e.switchBasemap(e.map),document.querySelectorAll(".bm-btn").forEach(n=>n.classList.toggle("active",n.dataset.layer===e.map))),e.map_pos){let[n,o,r]=e.map_pos;_e.setPosition(n,o,r)}e.tab&&document.querySelectorAll(".tab-btn").forEach(n=>{let o=n;o.dataset.tab===e.tab&&(o.classList.contains("active")||o.click())}),e.xaxis&&Me.setXAxis(e.xaxis);let t=e.xaxis||"time";if(document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(n=>n.classList.toggle("active",n.dataset.axis===t)),e.metrics){let n=Me.METRICS,o=e.metrics.map(r=>Object.keys(n).find(u=>n[u].abbr===r)).filter(r=>r!==void 0);o.length&&Me.setActiveMetrics(o)}e.f_date&&(Te.date=e.f_date.map(n=>n||null)),e.f_dist&&(Te.dist=e.f_dist.map(n=>n===0?0:n||null)),e.f_dur&&(Te.dur=e.f_dur.map(n=>n===0?0:n||null)),e.f_mets&&(Te.metrics=new Set(e.f_mets)),e.f_tags&&(Te.tags=e.f_tags),Fn(),e.q&&(ln=e.q),e.re&&(sn=e.re),e.sort&&(dn=e.sort),bl(),kt()}function ro(){if(!document.getElementById("sport-filter-container"))return;let s=document.getElementById("common-sports"),t=document.getElementById("sport-dropdown-content");if(!s||!t)return;let n=new Set;Object.values(ze).forEach(u=>{u.sport&&n.add(u.sport)});let o=Array.from(n).sort(),r=document.getElementById("sport-burger-dropdown");s.innerHTML="",t.innerHTML="",o.length<=4?(r&&(r.style.display="none"),o.forEach(u=>{let c=document.createElement("button");c.className=`mini-pill${Te.sport===u?" active":""}`,c.dataset.sport=u,c.title=u.charAt(0).toUpperCase()+u.slice(1),c.innerHTML=`${ns(u)}`,s.appendChild(c)})):(r&&(r.style.display="inline-block"),["running","cycling","walking"].forEach(c=>{if(n.has(c)){let m=document.createElement("button");m.className=`mini-pill${Te.sport===c?" active":""}`,m.dataset.sport=c,m.title=c.charAt(0).toUpperCase()+c.slice(1),m.innerHTML=`${ns(c)}`,s.appendChild(m)}}),o.forEach(c=>{let m=document.createElement("div");m.className=`dropdown-item${Te.sport===c?" active":""}`,m.dataset.sport=c,m.style.padding="8px",m.style.cursor="pointer",m.style.display="flex",m.style.alignItems="center",m.style.gap="8px",m.innerHTML=` + ${ns(c)} + ${c.charAt(0).toUpperCase()+c.slice(1)} + `,t.appendChild(m)}))}function mn(){ro();let e=document.getElementById("track-list"),s=document.getElementById("track-list-empty"),t=document.querySelector(".section-label");if(!e)return;let n=Object.keys(ze).filter(o=>!ze[o]._filtered);if(t&&(t.textContent=`Tracks (${n.length})`),!n.length){e.innerHTML="",s&&(e.appendChild(s),s.style.display="block");return}s&&(s.style.display="none"),e.innerHTML="",n.sort((o,r)=>{if(o===Oe)return-1;if(r===Oe)return 1;let u=ze[o],c=ze[r],m=u.stats,T=c.stats,b=0;switch(dn){case"date-asc":b=(m.startTime||0)-(T.startTime||0);break;case"date-desc":b=(T.startTime||0)-(m.startTime||0);break;case"dist-asc":b=(m.totalDist||0)-(T.totalDist||0);break;case"dist-desc":b=(T.totalDist||0)-(m.totalDist||0);break;case"dur-asc":b=(m.duration||0)-(T.duration||0);break;case"dur-desc":b=(T.duration||0)-(m.duration||0);break;default:b=0}return b||o.localeCompare(r)}).forEach(o=>{e.appendChild(co(ze[o]))})}function ws(){let e=new Set;return Object.values(ze).forEach(s=>{(s.tags||[]).forEach(t=>e.add(t))}),Array.from(e).sort()}function ns(e){if(!e)return"category";let s=e.toLowerCase();return s.includes("run")?"directions_run":s.includes("cycl")||s.includes("bike")?"directions_bike":s.includes("walk")?"directions_walk":s.includes("swim")?"pool":s.includes("hik")?"hiking":"sports"}function co(e){let s=document.createElement("div");s.className=`track-item${e.id===Oe?" selected":""}`,s.dataset.id=e.id;let t=e.points.length&&e.points[0].time?Zt(e.points[0].time):"Unknown date",n=(e.tags||[]).length>0?`
${(e.tags||[]).map(r=>{let u=Qn(r);return`${pt(r)}`}).join("")}
`:"";s.innerHTML=` +
+
+
${pt(e.displayName||e.name)}
+
+
+ ${t} + ${Math.round(e.stats.totalDist/1e3)} km + ${e.sport?`${ns(e.sport)}`:""} + ${e.format.toUpperCase()} +
+ +
+ ${n} +
+ `,s.addEventListener("click",r=>{r.target.closest(".icon-btn")||Mt(e.id)});let o=s.querySelector(".toggle-vis");return o.addEventListener("click",()=>{e.visible=!e.visible,o.querySelector(".material-symbols-rounded").textContent=e.visible?"visibility":"visibility_off",_e.setTrackVisible(e.id,e.visible),at.save(e)}),s}function ls(e,s="info"){let t=document.getElementById("toast-container");if(!t)return;t.innerHTML="";let n=document.createElement("div");n.className=`toast ${s}`,n.textContent=e,t.appendChild(n)}function uo(){let e=document.createElement("div");e.className="modal-backdrop";let s="";Tt.forEach(r=>{s+=`
${r.name}: ${r.reason}
`}),e.innerHTML=` + + `,document.body.appendChild(e);let t=e.querySelector(".modal-btn.cancel"),n=e.querySelector(".modal-btn.clear"),o=()=>e.remove();t.addEventListener("click",o),n.addEventListener("click",()=>{Tt=[],o();let r=document.getElementById("import-warning");r&&r.classList.add("hidden")}),e.addEventListener("click",r=>{r.target===e&&o()})}function mo(){let e=document.getElementById("drop-zone");if(!e)return;let s=document.getElementById("import-warning");s&&s.addEventListener("click",t=>{t.stopPropagation(),uo()}),window.addEventListener("dragover",t=>{t.preventDefault(),e.classList.add("drop-active")}),window.addEventListener("dragleave",t=>{t.relatedTarget===null&&e.classList.remove("drop-active")}),window.addEventListener("drop",async t=>{t.preventDefault(),e.classList.remove("drop-active");let n=t.dataTransfer?.items;if(!n)return;let o=[],r=[];for(let c=0;cc.file(T));o.push(m)}else if(c.isDirectory){let m=c.createReader(),T=[],b;do b=await new Promise(w=>m.readEntries(w)),T.push(...b);while(b.length>0);for(let w of T)await u(w)}}for(let c of r)await u(c);o.length&&os(o)})}async function os(e){if(!e.length)return;Sn=!1;let s=Tt.length,t=document.getElementById("global-loader"),n=document.getElementById("loader-text"),o=document.getElementById("loader-subtext"),r=document.getElementById("loader-progress-bar"),u=document.getElementById("loader-close");u&&u.addEventListener("click",()=>{Sn=!0,t&&t.classList.add("hidden")});function c(){let m=document.querySelector(".loader-icon-wrap span");m&&(m.textContent="warning",m.style.color="#f59e0b");let T=document.getElementById("loader-warning-count");if(T){let b=Tt.length-s,w=T.querySelector("span");w&&(w.textContent=`${b}`),T.style.display="flex"}}if(t){n&&(n.textContent=`Importing ${e.length} file${e.length>1?"s":""}`);let m=document.querySelector(".loader-icon-wrap span");m&&(m.textContent="download",m.style.color="var(--accent)");let T=document.getElementById("loader-warning-count");if(T){T.style.display="none";let b=T.querySelector("span");b&&(b.textContent="0")}o&&(o.textContent=""),r&&(r.style.width="0%"),t.classList.remove("hidden"),Tt.length>s&&c()}try{let m=0,T=null,b=0,w=e.filter(I=>{let P=I.name.toLowerCase();return P.endsWith(".gpx")||P.endsWith(".fit")||P.endsWith(".tcx")||P.endsWith(".kml")});if(e.filter(I=>!w.includes(I)).forEach(I=>{Tt.push({name:I.name,reason:"Unsupported file format"})}),w.length===0){if(e.length>0){ls("No valid GPS files found","error");let I=document.getElementById("import-warning");I&&Tt.length>0&&(I.classList.remove("hidden"),I.title=`Skipped ${Tt.length} imports. Click to view details.`)}return}let S=document.getElementById("loader-filename"),k=null;if(o){o.innerHTML='',k=o.querySelector(".progress-index");let I=o.querySelector(".progress-total");I&&(I.textContent=w.length.toString())}for(let I=0;Ia.fileName===P.name&&a.fileSize===P.size)){Tt.push({name:P.name,reason:"Same File"}),c();continue}let q=p.stats.startTime,J=p.stats.duration;if(q!=null&&J!=null){let a=q+J,G=h.filter(se=>se.stats.startTime!=null&&Zl(q,se.stats.startTime)),X=!1;for(let se of G){let U=se.stats.startTime,ne=se.stats.duration,Le=U+ne;if(q>=U&&a<=Le){Tt.push({name:P.name,reason:"Fully contained in another track"}),c(),X=!0;break}if(Math.min(a,Le)-Math.max(q,U)>6e5){Tt.push({name:P.name,reason:"Overlaps with an existing track for more than 10 mins"}),c(),X=!0;break}}if(X)continue}let Y=17855424e5,B=Ds(p.stats.startTime||Y);ze[B]&&(B+=`-${Rs()}`);let z=p.name;(z.startsWith("Unnamed")||z.startsWith("Fit Activity"))&&(z=P.name);let D=z,le=p.points[0]?.time,y=p.sport?p.sport.charAt(0).toUpperCase()+p.sport.slice(1):"Activity";if(le){let a=new Date(le);D=`${a.getUTCFullYear()}-${String(a.getUTCMonth()+1).padStart(2,"0")}-${String(a.getUTCDate()).padStart(2,"0")} ${y}`}else D=z.replace(/\.[^/.]+$/,"").replace(/_/g," ");let d={...p,id:B,name:z,displayName:D,fileName:P.name,fileSize:P.size,bounds:ms(p.points)||void 0,simplifiedPoints:ps(p.points,50),addedAt:p.stats.startTime||Y,visible:!0,color:ss[Dn%ss.length]};if(Dn++,Sn)break;await at.save(d),ze[B]=d,_e.addTrack(d),T||(T=B),m++,b++,b>=5&&(b=0)}catch(p){Tt.push({name:P.name,reason:`Parse error: ${p instanceof Error?p.message:String(p)}`}),c()}}let M=document.getElementById("import-warning");M&&(Tt.length>0?(M.classList.remove("hidden"),M.title=`Skipped ${Tt.length} imports. Click to view details.`):M.classList.add("hidden"));let g=Tt.length>s;if(!g&&t&&t.classList.add("hidden"),m>0&&(ls(`Imported ${m} track${m>1?"s":""}`),kt(!!T&&T!==Oe),T&&Mt(T)),g){let I=document.querySelector(".loader-icon-wrap span");I&&(I.textContent="warning"),await new Promise(P=>setTimeout(P,1500))}}finally{t&&t.classList.add("hidden")}}function po(){let e=document.getElementById("metric-pills");if(!e)return;let s=null;e.addEventListener("dragstart",t=>{let n=t.target.closest(".metric-pill");n&&(s=n,t.dataTransfer.effectAllowed="move",n.classList.add("dragging-pill"),setTimeout(()=>n.style.opacity="0.4",0))}),e.addEventListener("dragover",t=>{t.preventDefault(),t.dataTransfer.dropEffect="move";let n=t.target.closest(".metric-pill");if(n&&n!==s){let o=n.getBoundingClientRect(),r=t.clientX-o.left>o.width/2;e.insertBefore(s,r?n.nextSibling:n)}}),e.addEventListener("dragend",()=>{if(!s)return;s.classList.remove("dragging-pill"),s.style.opacity="",s=null;let t=Array.from(e.querySelectorAll(".metric-pill")).map(n=>n.dataset.metric);Me.updateMetricOrder(t),ys()})}function kn(){let e=document.getElementById("chart-toolbar"),s=document.getElementById("metric-pills");if(!e||!s)return;e.classList.remove("collapsed");let t=Math.max(0,e.clientWidth-280),n=0,o=!1;Array.from(s.children).forEach(u=>{let c=u;if(c.id==="pill-overflow"||(c.classList.remove("overflow-hidden"),!c.classList.contains("active")))return;let T=36+(c.dataset.metric||"").length*6;n+=T+6,n>t&&(o=!0,c.classList.add("overflow-hidden"))});let r=document.getElementById("pill-overflow");r&&r.classList.toggle("hidden",!o),o&&e.classList.add("collapsed")}document.addEventListener("DOMContentLoaded",Jl);export{Mt as selectTrack}; +//# sourceMappingURL=tools-gps-tracks.mjs.map diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map new file mode 100644 index 0000000000..50e5f9f953 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../src/url-state.ts", "../src/storage.ts", "../src/parsers.ts", "../src/utils.ts", "../src/map.ts", "../src/charts.ts", "../src/zones.ts", "../src/metrics.ts", "../src/sports.ts", "../src/tabs/details.ts", "../src/tabs/insights.ts", "../src/tabs/courses.ts", "../src/tabs/combined.ts", "../src/tabs/progress.ts", "../src/tabs/accumulated_progress.ts", "../src/app.ts"], + "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 URL State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Handles reading/writing application state to the URL.\n// Uses an incremental \"patch\" approach to preserve existing params.\n\nexport interface AppState {\n track?: string;\n map?: string;\n xaxis?: string;\n metrics?: string[];\n f_date?: (string | null)[];\n f_dist?: (number | null)[];\n f_dur?: (number | null)[];\n f_mets?: string[];\n f_tags?: string[];\n q?: string;\n re?: boolean;\n sort?: string;\n map_pos?: [number, number, number];\n storage?: 'memory' | 'indexeddb';\n sel?: [number, number];\n sel_point?: number;\n tab?: string;\n progress?: string;\n speed_mode?: string;\n}\n\nexport const UrlState = (() => {\n // Internal state object, initialized from current URL.\n let _state: AppState = {};\n let _lastSearch: string | null = null;\n let _syncTimeout: any = null;\n let _shouldPush = false;\n\n function read(): AppState {\n const p = new URLSearchParams(location.search);\n const s: AppState = {};\n\n if (p.has('track')) s.track = p.get('track')!;\n if (p.has('map')) s.map = p.get('map')!;\n if (p.has('xaxis')) s.xaxis = p.get('xaxis')!;\n if (p.has('tab')) s.tab = p.get('tab')!;\n if (p.has('sel_point')) s.sel_point = Number(p.get('sel_point'));\n if (p.has('speed_mode')) s.speed_mode = p.get('speed_mode')!;\n if (p.has('progress')) s.progress = p.get('progress')!;\n const metricsRaw = p.get('metrics');\n if (metricsRaw) s.metrics = metricsRaw.split(',').filter(Boolean);\n\n if (p.has('f_date')) {\n s.f_date = p\n .get('f_date')!\n .split(',')\n .map((v) => v || null);\n }\n if (p.has('f_dist')) {\n s.f_dist = p\n .get('f_dist')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_dur')) {\n s.f_dur = p\n .get('f_dur')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_mets')) s.f_mets = p.get('f_mets')!.split(',');\n if (p.has('f_tags')) s.f_tags = p.get('f_tags')!.split(',');\n\n if (p.has('q')) s.q = p.get('q')!;\n if (p.has('re')) s.re = p.get('re') === '1';\n if (p.has('sort')) {\n const v = p.get('sort')!;\n const isDesc = v.startsWith('-');\n const field = isDesc ? v.substring(1) : v;\n s.sort = `${field}-${isDesc ? 'desc' : 'asc'}`;\n }\n\n if (p.has('map_pos')) {\n const parts = p.get('map_pos')!.split(',').map(Number);\n if (parts.length === 3 && parts.every(isFinite))\n s.map_pos = parts as [number, number, number];\n }\n\n if (p.has('storage')) s.storage = p.get('storage') as 'memory' | 'indexeddb';\n if (p.has('sel')) {\n const parts = p.get('sel')!.split(',').map(Number);\n if (parts.length === 2 && parts.every((v) => !isNaN(v) && isFinite(v)))\n s.sel = parts as [number, number];\n }\n\n return s;\n }\n\n // Sync _state to browser URL synchronously so no pending timer leaks across steps\n function _sync() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n\n const p = new URLSearchParams();\n\n // Add standard encoded params\n if (_state.track) p.set('track', _state.track);\n if (_state.map) p.set('map', _state.map);\n if (_state.xaxis && _state.xaxis !== 'time') p.set('xaxis', _state.xaxis);\n if (_state.tab && _state.tab !== 'graphs') p.set('tab', _state.tab);\n if (_state.storage && _state.storage !== 'memory') p.set('storage', _state.storage);\n if (_state.sel_point !== undefined) p.set('sel_point', String(_state.sel_point));\n if (_state.speed_mode) p.set('speed_mode', _state.speed_mode);\n if (_state.q) p.set('q', _state.q);\n if (_state.progress) p.set('progress', _state.progress);\n if (_state.re) p.set('re', '1');\n\n if (_state.sort) {\n const parts = _state.sort.split('-');\n const field = parts[0];\n const dir = parts[1];\n p.set('sort', (dir === 'desc' ? '-' : '') + field);\n }\n\n let search = p.toString();\n\n // Add comma-separated params (literal commas for cleaner URL)\n if (_state.metrics) search += `${search ? '&' : ''}metrics=${_state.metrics.join(',')}`;\n\n if (_state.f_date)\n search += `${search ? '&' : ''}f_date=${_state.f_date.map((v) => v || '').join(',')}`;\n\n if (_state.f_dist)\n search += `${search ? '&' : ''}f_dist=${_state.f_dist.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_dur)\n search += `${search ? '&' : ''}f_dur=${_state.f_dur.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_mets) search += `${search ? '&' : ''}f_mets=${_state.f_mets.join(',')}`;\n\n if (_state.f_tags) search += `${search ? '&' : ''}f_tags=${_state.f_tags.join(',')}`;\n\n if (_state.map_pos) {\n const val = `${(+_state.map_pos[0]).toFixed(5)},${(+_state.map_pos[1]).toFixed(5)},${\n _state.map_pos[2]\n }`;\n search += `${search ? '&' : ''}map_pos=${val}`;\n }\n if (_state.sel) {\n const val = `${+_state.sel[0].toFixed(4)},${+_state.sel[1].toFixed(4)}`;\n search += `${search ? '&' : ''}sel=${val}`;\n }\n\n if (search !== _lastSearch) {\n const url = location.pathname + (search ? `?${search}` : '');\n if (_shouldPush) {\n history.pushState(null, '', url);\n _shouldPush = false;\n } else {\n history.replaceState(null, '', url);\n }\n _lastSearch = search;\n }\n }\n\n // Initial read\n _state = read();\n\n function get(): AppState {\n return { ..._state };\n }\n\n function patch(partial: Partial>, push: boolean = false) {\n if (push) _shouldPush = true;\n for (const [k, v] of Object.entries(partial)) {\n const key = k as keyof AppState;\n if (v === null || v === undefined) delete _state[key];\n else (_state as any)[key] = v;\n }\n _sync();\n }\n\n function refresh() {\n _state = read();\n }\n\n function reset() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n _state = {};\n _shouldPush = false;\n _lastSearch = '';\n history.replaceState(null, '', location.pathname);\n }\n\n return { get, patch, refresh, reset };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport { TrackData } from './parsers';\nimport { UrlState } from './url-state';\n\nexport interface StorageDriver {\n openDB(): Promise;\n save(track: TrackData): Promise;\n getAll(): Promise;\n remove(id: string): Promise;\n clear(): Promise;\n set(key: string, value: any): Promise;\n get(key: string): Promise;\n}\n\nclass InMemoryStorage implements StorageDriver {\n private trackStore = new Map();\n private settingStore = new Map();\n\n async openDB(): Promise {\n return Promise.resolve();\n }\n\n async save(track: TrackData): Promise {\n this.trackStore.set(track.id, track);\n return Promise.resolve();\n }\n\n async getAll(): Promise {\n return Promise.resolve(Array.from(this.trackStore.values()));\n }\n\n async remove(id: string): Promise {\n this.trackStore.delete(id);\n return Promise.resolve();\n }\n\n async clear(): Promise {\n this.trackStore.clear();\n this.settingStore.clear();\n return Promise.resolve();\n }\n\n async set(key: string, value: any): Promise {\n this.settingStore.set(key, value);\n return Promise.resolve();\n }\n\n async get(key: string): Promise {\n return Promise.resolve((this.settingStore.get(key) as T) ?? null);\n }\n}\n\nclass IndexedDBStorage implements StorageDriver {\n private db: IDBDatabase | null = null;\n private readonly DB_NAME = 'weg-gps-db';\n private readonly DB_VERSION = 2;\n\n async openDB(): Promise {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains('tracks'))\n db.createObjectStore('tracks', { keyPath: 'id' });\n if (!db.objectStoreNames.contains('settings')) db.createObjectStore('settings');\n };\n req.onsuccess = () => {\n this.db = req.result;\n resolve();\n };\n req.onerror = () => reject(req.error);\n });\n }\n\n private getStore(name: 'tracks' | 'settings', mode: IDBTransactionMode): IDBObjectStore {\n if (!this.db) throw new Error('IndexedDB not opened');\n return this.db.transaction(name, mode).objectStore(name);\n }\n\n async save(track: TrackData): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').put(track);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async getAll(): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readonly').getAll();\n req.onsuccess = () => res(req.result || []);\n req.onerror = () => rej(req.error);\n });\n }\n\n async remove(id: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').delete(id);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async clear(): Promise {\n if (!this.db) return Promise.resolve();\n return new Promise((res, rej) => {\n const tx = this.db!.transaction(['tracks', 'settings'], 'readwrite');\n tx.objectStore('tracks').clear();\n tx.objectStore('settings').clear();\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n }\n\n async set(key: string, value: any): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readwrite').put(value, key);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async get(key: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readonly').get(key);\n req.onsuccess = () => res((req.result as T) ?? null);\n req.onerror = () => rej(req.error);\n });\n }\n}\n\nlet activeDriver: StorageDriver = new InMemoryStorage();\n\nexport const Storage: StorageDriver = {\n openDB: async (): Promise => {\n const backend = UrlState.get().storage;\n activeDriver = backend === 'indexeddb' ? new IndexedDBStorage() : new InMemoryStorage();\n await activeDriver.openDB();\n },\n save: (t) => activeDriver.save(t),\n getAll: () => activeDriver.getAll(),\n remove: (id) => activeDriver.remove(id),\n clear: () => activeDriver.clear(),\n set: (k, v) => activeDriver.set(k, v),\n get: (k: string) => activeDriver.get(k),\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport FitParser from 'fit-file-parser';\nimport { haversine } from './utils';\n\nexport interface TrackPoint {\n lat: number;\n lon: number;\n ele: number | null;\n time: number | null;\n hr: number | null;\n cad: number | null;\n power: number | null;\n speed: number | null;\n temp: number | null;\n gearFront: number | null;\n gearRear: number | null;\n gearFrontTooth: number | null;\n gearRearTooth: number | null;\n battery: number | null;\n gears: number | null;\n dist?: number;\n gradient?: number | null;\n}\n\nexport interface TrackStats {\n totalDist: number;\n elevGain: number;\n elevLoss: number;\n duration: number | null;\n avgSpeed: number | null;\n maxSpeed: number;\n avgPower: number | null;\n maxPower: number;\n avgHR: number | null;\n maxHR: number;\n avgCadence: number | null;\n avgTemp?: number | null;\n minTemp?: number | null;\n maxTemp?: number | null;\n sensors: string[];\n startTime?: number | null;\n powerCurve?: Record | null;\n hrCurve?: Record | null;\n hrZones?: number[] | null; // Time in seconds for each zone\n powerZones?: number[] | null; // Time in seconds for each zone\n shifts?: number | null; // Total number of shifts detected\n avgBattery?: number | null;\n}\n\nexport interface DeviceInfo {\n name?: string;\n manufacturer?: string;\n product?: string;\n serial?: string;\n version?: string;\n hardwareVersion?: string;\n type?: string;\n batteryStatus?: string;\n batteryVoltage?: number;\n batteryLevel?: number;\n sourceType?: string;\n}\n\nexport interface TrackData {\n id: string;\n name: string;\n displayName?: string;\n bounds?: { minLat: number; maxLat: number; minLon: number; maxLon: number };\n fileName?: string;\n fileSize?: number;\n device: string | null;\n devices?: DeviceInfo[];\n sport?: string | null;\n subSport?: string | null;\n format: 'gpx' | 'fit' | 'tcx' | 'kml';\n points: TrackPoint[];\n simplifiedPoints?: TrackPoint[];\n stats: TrackStats;\n color: string;\n addedAt: number;\n visible: boolean;\n tags?: string[];\n _filtered?: boolean;\n}\n\nexport function calculateBounds(pts: TrackPoint[]) {\n if (!pts.length) return null;\n let minLat = pts[0].lat;\n let maxLat = pts[0].lat;\n let minLon = pts[0].lon;\n let maxLon = pts[0].lon;\n for (const p of pts) {\n if (p.lat < minLat) minLat = p.lat;\n if (p.lat > maxLat) maxLat = p.lat;\n if (p.lon < minLon) minLon = p.lon;\n if (p.lon > maxLon) maxLon = p.lon;\n }\n return { minLat, maxLat, minLon, maxLon };\n}\n\nexport function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] {\n if (pts.length <= 2) return pts;\n const result: TrackPoint[] = [pts[0]];\n let lastPoint = pts[0];\n for (let i = 1; i < pts.length - 1; i++) {\n const p = pts[i];\n const d =\n p.dist != null && lastPoint.dist != null\n ? p.dist - lastPoint.dist\n : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon);\n if (d >= minDistanceMeters) {\n result.push(p);\n lastPoint = p;\n }\n }\n result.push(pts[pts.length - 1]); // Always keep the last point\n return result;\n}\n\nexport const Parsers = (() => {\n // \u2500\u2500 Enrich track with distance & metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function enrichPoints(pts: TrackPoint[]): TrackPoint[] {\n let totalDist = 0;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n const d = haversine(prev.lat, prev.lon, p.lat, p.lon);\n totalDist += d;\n\n // Calculate speed if missing (m/s)\n if (p.speed == null && p.time != null && prev.time != null) {\n const dt = (p.time - prev.time) / 1000;\n if (dt > 0 && dt < 10) {\n // Skip big gaps\n p.speed = d / dt;\n }\n }\n\n // Calculate gradient if missing (%)\n if (p.gradient === undefined && p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (d > 0.5) {\n // Only calculate for non-tiny movements to reduce jitter\n p.gradient = (de / d) * 100;\n } else {\n p.gradient = prev.gradient || 0;\n }\n }\n }\n p.dist = totalDist;\n }\n\n // Optional: basic smoothing for gradient\n for (let i = 1; i < pts.length - 1; i++) {\n if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null)\n pts[i].gradient = (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3;\n }\n\n return pts;\n }\n\n // \u2500\u2500 Compute stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let hrZoneThresholds = [120, 140, 160, 180];\n let ftp = 200;\n\n function computeStats(pts: TrackPoint[], includeCurves = false): TrackStats {\n const stats: TrackStats = {\n totalDist: 0,\n elevGain: 0,\n elevLoss: 0,\n duration: null,\n avgSpeed: null,\n maxSpeed: 0,\n avgPower: null,\n maxPower: 0,\n avgHR: null,\n maxHR: 0,\n avgCadence: null,\n avgTemp: null,\n minTemp: null,\n maxTemp: null,\n sensors: [],\n startTime: pts.length ? pts[0].time : null,\n };\n\n if (!pts.length) return stats;\n\n let powerSum = 0,\n powerN = 0;\n let hrSum = 0,\n hrN = 0;\n let cadSum = 0,\n cadN = 0;\n let speedSum = 0,\n speedN = 0;\n let batterySum = 0,\n batteryN = 0;\n let tempSum = 0,\n tempN = 0;\n let hasTemp = false;\n let shifts = 0;\n let hasGears = false;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const diff = p.ele - prev.ele;\n if (diff > 0) stats.elevGain += diff;\n else stats.elevLoss -= diff;\n }\n if (\n (p.gearFront != null && p.gearFront !== prev.gearFront) ||\n (p.gearRear != null && p.gearRear !== prev.gearRear)\n )\n shifts++;\n }\n if (p.power != null) {\n powerSum += p.power;\n powerN++;\n if (p.power > stats.maxPower) stats.maxPower = p.power;\n }\n if (p.hr != null) {\n hrSum += p.hr;\n hrN++;\n if (p.hr > stats.maxHR) stats.maxHR = p.hr;\n }\n if (p.cad != null) {\n cadSum += p.cad;\n cadN++;\n }\n if (p.speed != null) {\n speedSum += p.speed;\n speedN++;\n if (p.speed > stats.maxSpeed) stats.maxSpeed = p.speed;\n }\n if (p.battery != null) {\n batterySum += p.battery;\n batteryN++;\n }\n if (p.temp != null) {\n hasTemp = true;\n tempSum += p.temp;\n tempN++;\n if (stats.minTemp == null || p.temp < stats.minTemp) stats.minTemp = p.temp;\n if (stats.maxTemp == null || p.temp > stats.maxTemp) stats.maxTemp = p.temp;\n }\n if (p.gearFront != null || p.gearRear != null) hasGears = true;\n }\n\n stats.totalDist = pts[pts.length - 1].dist || 0;\n stats.avgPower = powerN ? Math.round(powerSum / powerN) : null;\n stats.avgHR = hrN ? Math.round(hrSum / hrN) : null;\n stats.avgCadence = cadN ? Math.round(cadSum / cadN) : null;\n stats.avgSpeed = speedN ? speedSum / speedN : null;\n stats.avgBattery = batteryN ? Math.round(batterySum / batteryN) : null;\n stats.avgTemp = tempN ? Number((tempSum / tempN).toFixed(1)) : null;\n stats.shifts = hasGears ? shifts : null;\n\n const t0 = pts[0].time;\n const t1 = pts[pts.length - 1].time;\n if (t0 != null && t1 != null) stats.duration = t1 - t0;\n\n if (hrN) {\n stats.sensors.push('Heart Rate');\n if (includeCurves) {\n stats.hrZones = calculateHRZones(pts);\n stats.hrCurve = calculateHRCurve(pts);\n }\n }\n if (cadN) stats.sensors.push('Cadence');\n if (powerN) {\n stats.sensors.push('Power');\n if (includeCurves) {\n stats.powerCurve = calculatePowerCurve(pts);\n stats.powerZones = calculatePowerZones(pts);\n }\n }\n if (hasTemp) stats.sensors.push('Temperature');\n if (hasGears) stats.sensors.push('Shifting');\n if (batteryN) stats.sensors.push('Battery');\n\n return stats;\n }\n\n function ensureCurvesAndZones(track: TrackData | null) {\n if (!track || !track.points || !track.stats) return;\n const pts = track.points;\n const s = track.stats;\n if (s.avgHR != null && !s.hrCurve) {\n s.hrZones = calculateHRZones(pts);\n s.hrCurve = calculateHRCurve(pts);\n }\n if (s.avgPower != null && !s.powerCurve) {\n s.powerCurve = calculatePowerCurve(pts);\n s.powerZones = calculatePowerZones(pts);\n }\n }\n\n const STANDARD_CURVE_DURATIONS = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600,\n ];\n\n function calculateSlidingMax(data: number[], durations: number[]) {\n const len = data.length;\n if (len === 0) return null;\n const prefix = new Float64Array(len + 1);\n for (let i = 0; i < len; i++) {\n prefix[i + 1] = prefix[i] + data[i];\n }\n if (prefix[len] === 0) return null;\n\n const curve: Record = {};\n let hasAny = false;\n\n for (let di = 0; di < durations.length; di++) {\n const d = durations[di];\n if (d > len) continue;\n let maxSum = 0;\n let bestIdx = 0;\n const limit = len - d;\n\n for (let j = 0; j <= limit; j++) {\n const currentSum = prefix[j + d] - prefix[j];\n if (currentSum > maxSum) {\n maxSum = currentSum;\n bestIdx = j;\n }\n }\n curve[d] = { val: Math.round(maxSum / d), idx: bestIdx };\n hasAny = true;\n }\n\n return hasAny ? curve : null;\n }\n\n function calculatePowerCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const powerData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].power || 0;\n powerData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(powerData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { power: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculateHRCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const hrData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].hr || 0;\n hrData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(hrData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { hr: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculatePowerZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0, 0, 0];\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.power == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue;\n\n const pw = p.power;\n if (pw < thresholds[0]) zones[0] += dt;\n else if (pw < thresholds[1]) zones[1] += dt;\n else if (pw < thresholds[2]) zones[2] += dt;\n else if (pw < thresholds[3]) zones[3] += dt;\n else if (pw < thresholds[4]) zones[4] += dt;\n else if (pw < thresholds[5]) zones[5] += dt;\n else zones[6] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setFTP(val: number) {\n ftp = val;\n }\n\n function getFTP() {\n return ftp;\n }\n\n function calculateHRZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0];\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.hr == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue; // Skip gaps\n\n const hr = p.hr;\n if (hr < hrZoneThresholds[0]) zones[0] += dt;\n else if (hr < hrZoneThresholds[1]) zones[1] += dt;\n else if (hr < hrZoneThresholds[2]) zones[2] += dt;\n else if (hr < hrZoneThresholds[3]) zones[3] += dt;\n else zones[4] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setHRZones(thresholds: number[]) {\n hrZoneThresholds = thresholds;\n }\n\n function getHRZones() {\n return [...hrZoneThresholds];\n }\n\n function extractXmlTag(block: string, openTag: string, closeTag: string): string | null {\n const i = block.indexOf(openTag);\n if (i === -1) return null;\n const start = i + openTag.length;\n const j = block.indexOf(closeTag, start);\n if (j === -1) return null;\n const val = block.slice(start, j).trim();\n return val !== '' ? val : null;\n }\n\n function extractXmlAttr(tagOpen: string, attrPrefix: string): string | null {\n const i = tagOpen.indexOf(attrPrefix);\n if (i === -1) return null;\n const start = i + attrPrefix.length;\n const j = tagOpen.indexOf('\"', start);\n if (j === -1) return null;\n return tagOpen.slice(start, j);\n }\n\n let cachedDateKey = -1;\n let cachedDayMs = 0;\n\n function parseIntSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let val = 0;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n val = val * 10 + (c - 48);\n digits++;\n } else {\n break;\n }\n }\n if (digits === 0) return null;\n return neg ? -val : val;\n }\n\n function parseFloatSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let intPart = 0;\n let fracPart = 0;\n let fracDiv = 1;\n let inFrac = false;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n digits++;\n if (!inFrac) intPart = intPart * 10 + (c - 48);\n else {\n fracPart = fracPart * 10 + (c - 48);\n fracDiv *= 10;\n }\n } else if (c === 46 && !inFrac) {\n inFrac = true;\n } else {\n const n = parseFloat(text.slice(start - (neg ? 1 : 0), end));\n return Number.isFinite(n) ? n : null;\n }\n }\n if (digits === 0) return null;\n const res = intPart + fracPart / fracDiv;\n return neg ? -res : res;\n }\n\n function fastParseTimeSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n const len = end - start;\n if (len >= 20 && text.charCodeAt(start + 10) === 84 && text.charCodeAt(end - 1) === 90) {\n const y =\n (text.charCodeAt(start) - 48) * 1000 +\n (text.charCodeAt(start + 1) - 48) * 100 +\n (text.charCodeAt(start + 2) - 48) * 10 +\n (text.charCodeAt(start + 3) - 48);\n const m = (text.charCodeAt(start + 5) - 48) * 10 + (text.charCodeAt(start + 6) - 48);\n const d = (text.charCodeAt(start + 8) - 48) * 10 + (text.charCodeAt(start + 9) - 48);\n const key = (y << 9) | (m << 5) | d;\n if (key !== cachedDateKey) {\n cachedDateKey = key;\n cachedDayMs = Date.UTC(y, m - 1, d);\n }\n const hh = (text.charCodeAt(start + 11) - 48) * 10 + (text.charCodeAt(start + 12) - 48);\n const mm = (text.charCodeAt(start + 14) - 48) * 10 + (text.charCodeAt(start + 15) - 48);\n const ss = (text.charCodeAt(start + 17) - 48) * 10 + (text.charCodeAt(start + 18) - 48);\n let ms = 0;\n if (text.charCodeAt(start + 19) === 46 && len >= 24) {\n ms =\n (text.charCodeAt(start + 20) - 48) * 100 +\n (text.charCodeAt(start + 21) - 48) * 10 +\n (text.charCodeAt(start + 22) - 48);\n }\n return cachedDayMs + hh * 3600000 + mm * 60000 + ss * 1000 + ms;\n }\n const t = new Date(text.slice(start, end)).getTime();\n return Number.isFinite(t) ? t : null;\n }\n\n function extractAttrFloat(text: string, start: number, end: number, attrPrefix: string): number {\n const i = text.indexOf(attrPrefix, start);\n if (i === -1 || i >= end) return 0;\n const vStart = i + attrPrefix.length;\n const j = text.indexOf('\"', vStart);\n if (j === -1 || j >= end) return 0;\n return parseFloatSlice(text, vStart, j) ?? 0;\n }\n\n // \u2500\u2500 GPX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseGPX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTrkpt = text.indexOf('');\n const name =\n (trkIdx !== -1 ? extractXmlTag(header.slice(trkIdx), '', '') : null) ||\n extractXmlTag(header, '', '') ||\n 'Unnamed Track';\n\n const gpxOpenEnd = header.indexOf('>', header.indexOf('', trkStart + 6);\n if (openEnd === -1) break;\n const trkEnd = text.indexOf('', openEnd + 1);\n if (trkEnd === -1) break;\n pos = trkEnd + 8;\n\n const lat = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lat=\"');\n const lon = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lon=\"');\n\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let temp: number | null = null;\n let speed: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = openEnd + 1;\n while (p < trkEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= trkEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= trkEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n // Skip duplicate block when primary fields already parsed\n const tagLen = gt - lt - 1;\n if (c1 === 103 && tagLen === 26 && hr !== null && cad !== null && temp !== null) {\n break;\n }\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > trkEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 3) {\n if (c1 === 101) ele = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 99 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 2) {\n if (c1 === 104 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 4) {\n if (c1 === 116) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if ((c1 === 112 || c1 === 80 || c1 === 87) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 115 || c1 === 83) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if ((c1 === 98 || c1 === 66) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 103 || c1 === 71) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if (c1 === 103) {\n if (text.charCodeAt(lt + 8) === 104 && hr === null)\n hr = parseIntSlice(text, vStart, vEnd);\n else if (gearFront === null) gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (c1 === 71 && gearFront === null) {\n gearFront = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 10) {\n if (c1 === 103 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 103 && text.charCodeAt(lt + 8) === 97 && temp === null)\n temp = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 103 || c1 === 71) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if ((c1 === 103 || c1 === 71) && gearFrontTooth === null)\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 65 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 11 && c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!points.length) throw new Error('No track points found in GPX');\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'gpx', points: pts, stats };\n }\n\n // \u2500\u2500 TCX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseTCX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTp = text.indexOf('');\n const header = firstTp !== -1 ? text.slice(0, firstTp) : text;\n\n const name = extractXmlTag(header, '', '') || 'Unnamed TCX';\n const creatorBlock = extractXmlTag(header, '', '');\n const device = creatorBlock ? extractXmlTag(creatorBlock, '', '') : null;\n\n const points: TrackPoint[] = [];\n let pos = firstTp !== -1 ? firstTp : 0;\n while (pos < text.length) {\n const tpStart = text.indexOf('', pos);\n if (tpStart === -1) break;\n const tpEnd = text.indexOf('', tpStart + 12);\n if (tpEnd === -1) break;\n pos = tpEnd + 13;\n\n let lat: number | null = null;\n let lon: number | null = null;\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let speed: number | null = null;\n let temp: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = tpStart + 12;\n while (p < tpEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= tpEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= tpEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n const tagLen = gt - lt - 1;\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > tpEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 4) {\n if (c1 === 84) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 116 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if (c1 === 86 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 87 || c1 === 80 || c1 === 112) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 83 || c1 === 115) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 66 || c1 === 98) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 71 || c1 === 103) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if ((c1 === 71 || c1 === 103) && gearFront === null)\n gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 10) {\n if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 11) {\n if (c1 === 84 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 71 || c1 === 103) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if (c1 === 65) {\n if (text.charCodeAt(lt + 2) === 108) ele = parseFloatSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if ((c1 === 71 || c1 === 103) && gearFrontTooth === null) {\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 15) {\n if (c1 === 76) lat = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 16) {\n if (c1 === 76) lon = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 2 && c1 === 104 && hr === null) {\n hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 3 && c1 === 99 && cad === null) {\n cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n if (lat == null || lon == null) continue;\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'tcx', points: pts, stats };\n }\n\n function fastDecodeFitData(buf: ArrayBuffer): any | null {\n if (buf.byteLength < 14) return null;\n const dv = new DataView(buf);\n const headerSize = dv.getUint8(0);\n if (headerSize < 12 || headerSize + 2 > buf.byteLength) return null;\n if (\n dv.getUint8(8) !== 0x2e ||\n dv.getUint8(9) !== 0x46 ||\n dv.getUint8(10) !== 0x49 ||\n dv.getUint8(11) !== 0x54\n ) {\n return null;\n }\n const dataSize = dv.getUint32(4, true);\n const endOffset = Math.min(buf.byteLength, headerSize + dataSize);\n const GARMIN_EPOCH_SEC = 631065600;\n const SEMICIRCLE_TO_DEG = 180 / Math.pow(2, 31);\n\n interface FieldDef {\n num: number;\n size: number;\n type: number;\n }\n interface MsgDef {\n littleEndian: boolean;\n globalMsgNum: number;\n fields: FieldDef[];\n recordSize: number;\n }\n const defs: (MsgDef | undefined)[] = new Array(16);\n const file_ids: any[] = [];\n const sessions: any[] = [];\n const records: any[] = [];\n const events: any[] = [];\n const device_infos: any[] = [];\n\n let offset = headerSize;\n while (offset < endOffset) {\n const hdr = dv.getUint8(offset++);\n if ((hdr & 0x80) !== 0 || (hdr & 0x20) !== 0) {\n return null; // Compressed timestamp or developer data: fallback to FitParser\n }\n const localNum = hdr & 0x0f;\n if ((hdr & 0x40) !== 0) {\n if (offset + 5 > endOffset) return null;\n offset++; // reserved\n const arch = dv.getUint8(offset++);\n const littleEndian = arch === 0;\n const globalMsgNum = dv.getUint16(offset, littleEndian);\n offset += 2;\n const numFields = dv.getUint8(offset++);\n if (offset + numFields * 3 > endOffset) return null;\n const fields: FieldDef[] = new Array(numFields);\n let recordSize = 0;\n for (let i = 0; i < numFields; i++) {\n const num = dv.getUint8(offset++);\n const size = dv.getUint8(offset++);\n const type = dv.getUint8(offset++);\n fields[i] = { num, size, type };\n recordSize += size;\n }\n defs[localNum] = { littleEndian, globalMsgNum, fields, recordSize };\n } else {\n const def = defs[localNum];\n if (!def || offset + def.recordSize > endOffset) return null;\n const le = def.littleEndian;\n const gNum = def.globalMsgNum;\n\n if (\n gNum === 20 &&\n def.fields.length === 10 &&\n def.recordSize === 25 &&\n def.fields[0].num === 253 &&\n def.fields[1].num === 0\n ) {\n const ts = dv.getUint32(offset, le);\n const rawLat = dv.getInt32(offset + 4, le);\n const rawLon = dv.getInt32(offset + 8, le);\n const rawAlt = dv.getUint16(offset + 12, le);\n const hr = dv.getUint8(offset + 14);\n const cad = dv.getUint8(offset + 15);\n const rawDist = dv.getUint32(offset + 16, le);\n const rawSpd = dv.getUint16(offset + 20, le);\n const power = dv.getUint16(offset + 22, le);\n const temp = dv.getInt8(offset + 24);\n records.push({\n timestamp: (ts + GARMIN_EPOCH_SEC) * 1000,\n position_lat: rawLat * SEMICIRCLE_TO_DEG,\n position_long: rawLon * SEMICIRCLE_TO_DEG,\n altitude: rawAlt / 5 - 500,\n heart_rate: hr,\n cadence: cad,\n distance: rawDist / 100,\n speed: (rawSpd / 1000) * 3.6,\n power,\n temperature: temp,\n });\n offset += 25;\n continue;\n }\n\n const msg: any = {};\n let fOff = offset;\n for (let i = 0; i < def.fields.length; i++) {\n const f = def.fields[i];\n let val: number = 0;\n const bType = f.type & 0x1f;\n if (f.size === 1) {\n val = bType === 1 ? dv.getInt8(fOff) : dv.getUint8(fOff);\n } else if (f.size === 2) {\n val = bType === 3 ? dv.getInt16(fOff, le) : dv.getUint16(fOff, le);\n } else if (f.size === 4) {\n val = bType === 5 ? dv.getInt32(fOff, le) : dv.getUint32(fOff, le);\n }\n msg[f.num] = val;\n fOff += f.size;\n }\n offset += def.recordSize;\n\n if (gNum === 0) {\n file_ids.push({\n type: msg[0] === 4 ? 'activity' : msg[0],\n manufacturer: msg[1] === 1 ? 'garmin' : msg[1],\n product: msg[2],\n time_created: msg[4] != null ? (msg[4] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n });\n } else if (gNum === 18) {\n const sportMap: Record = { 0: 'generic', 1: 'running', 2: 'cycling' };\n sessions.push({\n start_time: msg[2] != null ? (msg[2] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n sport: sportMap[msg[5]] ?? String(msg[5]),\n sub_sport: msg[6] === 0 ? 'generic' : String(msg[6]),\n });\n } else if (gNum === 20) {\n records.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n position_lat: msg[0] != null ? msg[0] * SEMICIRCLE_TO_DEG : undefined,\n position_long: msg[1] != null ? msg[1] * SEMICIRCLE_TO_DEG : undefined,\n altitude: msg[2] != null ? msg[2] / 5 - 500 : undefined,\n heart_rate: msg[3],\n cadence: msg[4],\n distance: msg[5] != null ? msg[5] / 100 : undefined,\n speed: msg[6] != null ? (msg[6] / 1000) * 3.6 : undefined,\n power: msg[7],\n temperature: msg[13],\n });\n } else if (gNum === 21) {\n const evName =\n msg[0] === 43\n ? 'rear_gear_change'\n : msg[0] === 42\n ? 'front_gear_change'\n : String(msg[0]);\n events.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n event: evName,\n event_type: msg[1] === 3 ? 'marker' : String(msg[1]),\n data: msg[3],\n front_gear_num: msg[9],\n rear_gear_num: msg[11],\n });\n } else if (gNum === 23) {\n device_infos.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n battery_level: msg[32],\n });\n } else {\n return null;\n }\n }\n }\n return { file_ids, sessions, sports: [], records, events, device_infos };\n }\n\n // \u2500\u2500 FIT parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseFIT(buf: ArrayBuffer): Promise {\n return new Promise((resolve, reject) => {\n const handleParsedFitData = (error: any, data: any) => {\n if (error) {\n reject(error);\n return;\n }\n try {\n const name = data.sessions?.[0]?.start_time\n ? `Fit Activity ${new Date(data.sessions[0].start_time).toISOString().split('T')[0]}`\n : 'Unnamed Fit';\n\n // Better device detection\n let device: string | null = null;\n const devices: DeviceInfo[] = [];\n let sport: string | null = null;\n let subSport: string | null = null;\n\n if (data.sports?.[0]) {\n sport = data.sports[0].sport;\n subSport = data.sports[0].sub_sport;\n } else if (data.sessions?.[0]) {\n sport = data.sessions[0].sport;\n subSport = data.sessions[0].sub_sport;\n }\n\n const getDeviceName = (d: any) =>\n d.product_name ||\n d.garmin_product ||\n d.product ||\n d.device_type ||\n d.manufacturer ||\n null;\n\n if (data.file_ids?.[0]) {\n const fid = data.file_ids[0];\n device = getDeviceName(fid);\n devices.push({\n name: fid.product_name || fid.garmin_product || fid.product,\n manufacturer: fid.manufacturer,\n serial: fid.serial_number ? String(fid.serial_number) : undefined,\n version: fid.software_version ? String(fid.software_version) : undefined,\n type: 'main',\n });\n }\n\n if (data.device_infos) {\n data.device_infos.forEach((d: any) => {\n const isMain = d.device_index === 'creator' || d.device_index === 0;\n\n if (isMain) {\n const name = getDeviceName(d);\n // Prefer a name with product_name or garmin_product over generic ones\n if (d.product_name || d.garmin_product || !device) device = name;\n\n // Update existing main device if needed\n if (devices.length > 0 && devices[0].type === 'main') {\n if (d.product_name || d.garmin_product || !devices[0].name)\n devices[0].name = d.product_name || d.garmin_product || d.product;\n\n if (!devices[0].manufacturer) devices[0].manufacturer = d.manufacturer;\n if (!devices[0].serial && d.serial_number)\n devices[0].serial = String(d.serial_number);\n if (!devices[0].version && d.software_version)\n devices[0].version = String(d.software_version);\n if (!devices[0].hardwareVersion && d.hardware_version)\n devices[0].hardwareVersion = String(d.hardware_version);\n }\n return;\n }\n\n devices.push({\n name: d.product_name || d.garmin_product || d.product || d.device_type || 'Sensor',\n manufacturer: d.manufacturer,\n serial: d.serial_number ? String(d.serial_number) : undefined,\n version: d.software_version ? String(d.software_version) : undefined,\n hardwareVersion: d.hardware_version ? String(d.hardware_version) : undefined,\n type: d.device_type || 'sensor',\n batteryStatus: d.battery_status,\n batteryVoltage: d.battery_voltage,\n batteryLevel: d.battery_level,\n sourceType: d.source_type != null ? String(d.source_type) : undefined,\n });\n });\n }\n\n if (data.sensor_settings) {\n data.sensor_settings.forEach((s: any) => {\n const name = s.name || s.product || s.sensor_type;\n if (!name) return;\n\n // Check if we already have this device (by ANT ID or name)\n const antId = s.ant_id ? String(s.ant_id) : undefined;\n const existing = devices.find(\n (d) =>\n (antId && d.serial === antId) ||\n (d.name === name && d.manufacturer === s.manufacturer),\n );\n\n if (existing) {\n if (!existing.name) existing.name = name;\n if (!existing.manufacturer) existing.manufacturer = s.manufacturer;\n if (!existing.type) existing.type = s.sensor_type;\n if (!existing.sourceType)\n existing.sourceType =\n s.connection_type != null ? String(s.connection_type) : undefined;\n } else {\n devices.push({\n name: name,\n manufacturer: s.manufacturer,\n serial: antId,\n type: s.sensor_type || 'sensor',\n sourceType: s.connection_type != null ? String(s.connection_type) : undefined,\n });\n }\n });\n }\n\n // Collect standalone device status reports (often contains head unit battery)\n // We'll store them in a sorted array for easier lookups\n const statusReports: { time: number; level: number | null; idx: number }[] = [];\n if (data.device_statuses) {\n data.device_statuses.forEach((s: any, idx: number) => {\n if (s.timestamp && s.battery_level != null) {\n statusReports.push({\n time:\n typeof s.timestamp === 'number' ? s.timestamp : new Date(s.timestamp).getTime(),\n level: s.battery_level,\n idx,\n });\n }\n });\n statusReports.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n // Collect gear events\n const gearEvents: {\n time: number;\n front: number | null;\n rear: number | null;\n frontTooth: number | null;\n rearTooth: number | null;\n idx: number;\n }[] = [];\n if (data.events) {\n data.events.forEach((e: any, idx: number) => {\n let front = e.front_gear_num ?? e.front_gear ?? null;\n let rear = e.rear_gear_num ?? e.rear_gear ?? null;\n let frontTooth = e.front_gear_num_tooth ?? null;\n let rearTooth = e.rear_gear_num_tooth ?? null;\n\n if (e.event === 'rear_gear_change' || e.event === 'front_gear_change') {\n const d = e.data;\n if (d != null) {\n const ft = (d >> 24) & 0xff;\n const fg = (d >> 16) & 0xff;\n const rt = (d >> 8) & 0xff;\n const rg = d & 0xff;\n\n if (fg !== 0) front = fg;\n if (ft !== 0) frontTooth = ft;\n if (rg !== 0) rear = rg;\n if (rt !== 0) rearTooth = rt;\n }\n }\n\n if (\n e.timestamp &&\n (front != null || rear != null || frontTooth != null || rearTooth != null)\n ) {\n gearEvents.push({\n time:\n typeof e.timestamp === 'number' ? e.timestamp : new Date(e.timestamp).getTime(),\n front,\n rear,\n frontTooth,\n rearTooth,\n idx,\n });\n }\n });\n gearEvents.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n const records = data.records || [];\n let lastBattery: number | null = null;\n let statusIdx = 0;\n let lastFrontGear: number | null = null;\n let lastRearGear: number | null = null;\n let lastFrontTooth: number | null = null;\n let lastRearTooth: number | null = null;\n let gearIdx = 0;\n\n const validPoints: TrackPoint[] = [];\n for (let ri = 0; ri < records.length; ri++) {\n const r = records[ri];\n const lat = r.position_lat;\n const lon = r.position_long;\n if (lat == null || lon == null) continue;\n\n const time =\n r.timestamp != null\n ? typeof r.timestamp === 'number'\n ? r.timestamp\n : r.timestamp instanceof Date\n ? r.timestamp.getTime()\n : new Date(r.timestamp).getTime()\n : null;\n const speed = r.speed != null ? r.speed / 3.6 : null; // km/h \u2192 m/s\n\n let battery = r.battery_level ?? null;\n\n // If not in record, check our status reports\n if (battery == null && time) {\n // Catch up statusIdx to current time\n while (statusIdx < statusReports.length && statusReports[statusIdx].time <= time) {\n lastBattery = statusReports[statusIdx].level;\n statusIdx++;\n }\n battery = lastBattery;\n } else if (battery != null) {\n lastBattery = battery;\n }\n\n // Update gear state from events\n if (time) {\n while (gearIdx < gearEvents.length && gearEvents[gearIdx].time <= time) {\n const e = gearEvents[gearIdx];\n if (e.front != null) lastFrontGear = e.front;\n if (e.rear != null) lastRearGear = e.rear;\n if (e.frontTooth != null) lastFrontTooth = e.frontTooth;\n if (e.rearTooth != null) lastRearTooth = e.rearTooth;\n gearIdx++;\n }\n }\n\n const gearFront: number | null = r.front_gear_num ?? r.front_gear ?? lastFrontGear;\n const gearRear: number | null = r.rear_gear_num ?? r.rear_gear ?? lastRearGear;\n const gearFrontTooth: number | null = r.front_gear_num_tooth ?? lastFrontTooth;\n const gearRearTooth: number | null = r.rear_gear_num_tooth ?? lastRearTooth;\n\n if (r.front_gear_num != null || r.front_gear != null) lastFrontGear = gearFront;\n if (r.rear_gear_num != null || r.rear_gear != null) lastRearGear = gearRear;\n if (r.front_gear_num_tooth != null) lastFrontTooth = gearFrontTooth;\n if (r.rear_gear_num_tooth != null) lastRearTooth = gearRearTooth;\n\n const gears =\n gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0\n ? gearFrontTooth / gearRearTooth\n : null;\n\n validPoints.push({\n lat,\n lon,\n ele: r.altitude ?? r.enhanced_altitude ?? null,\n time,\n hr: r.heart_rate ?? null,\n cad: r.cadence ?? null,\n power: r.power ?? null,\n speed,\n temp: r.temperature ?? null,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!validPoints.length) {\n reject(new Error('FIT file has no GPS points'));\n return;\n }\n\n const pts = enrichPoints(validPoints);\n const stats = computeStats(pts);\n resolve({ name, device, devices, format: 'fit', points: pts, stats, sport, subSport });\n } catch (ex) {\n reject(ex);\n }\n };\n\n const fastData = fastDecodeFitData(buf);\n if (fastData) {\n handleParsedFitData(null, fastData);\n return;\n }\n\n const fitParser = new FitParser({\n force: true,\n speedUnit: 'km/h',\n lengthUnit: 'm',\n temperatureUnit: 'celsius',\n elapsedRecordField: true,\n });\n\n fitParser.parse(buf, handleParsedFitData);\n });\n }\n\n // \u2500\u2500 KML parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseKML(buf: ArrayBuffer): any {\n const text = new TextDecoder().decode(buf);\n const doc = new DOMParser().parseFromString(text, 'application/xml');\n\n let name = 'Unnamed Track';\n const nameEl = doc.querySelector('Document > name, Placemark > name');\n if (nameEl) name = nameEl.textContent?.trim() || name;\n\n // Track: look for gx:Track or LineString\n const coordEls = doc.querySelectorAll('coordinates');\n if (!coordEls.length) throw new Error('No coordinates found in KML');\n\n const points: TrackPoint[] = [];\n coordEls.forEach((el) => {\n const lines = el.textContent?.trim().split(/\\s+/) || [];\n lines.forEach((line) => {\n const parts = line.split(',');\n if (parts.length < 2) return;\n const lon = parseFloat(parts[0]);\n const lat = parseFloat(parts[1]);\n const ele = parts.length > 2 ? parseFloat(parts[2]) : null;\n if (isNaN(lat) || isNaN(lon)) return;\n points.push({\n lat,\n lon,\n ele: ele != null && isNaN(ele) ? null : ele,\n time: null,\n hr: null,\n cad: null,\n power: null,\n speed: null,\n temp: null,\n gearFront: null,\n gearRear: null,\n gearFrontTooth: null,\n gearRearTooth: null,\n battery: null,\n gears: null,\n });\n });\n });\n\n if (!points.length) throw new Error('No valid coordinates in KML');\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, format: 'kml', points: pts, stats };\n }\n\n // \u2500\u2500 Public: dispatch by extension \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async function parseFile(file: File): Promise {\n const ext = file.name.split('.').pop()?.toLowerCase();\n const buf: ArrayBuffer = (file as any)._buf ?? (await file.arrayBuffer());\n const predecodedText: string | undefined = (file as any)._text;\n let result: any;\n switch (ext) {\n case 'gpx':\n result = parseGPX(buf, predecodedText);\n break;\n case 'tcx':\n result = parseTCX(buf, predecodedText);\n break;\n case 'fit':\n result = await parseFIT(buf);\n break;\n case 'kml':\n result = parseKML(buf);\n break;\n default:\n throw new Error(`Unsupported format: .${ext}`);\n }\n\n if (result) {\n result.fileName = file.name;\n result.fileSize = file.size;\n }\n return result;\n }\n\n return {\n parseFile,\n computeStats,\n ensureCurvesAndZones,\n calculatePowerCurve,\n calculateHRCurve,\n calculatePowerZones,\n calculateHRZones,\n enrichPoints,\n setHRZones,\n getHRZones,\n setFTP,\n getFTP,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const R = 6371e3; // Earth radius in metres\n const phi1 = (lat1 * Math.PI) / 180;\n const phi2 = (lat2 * Math.PI) / 180;\n const deltaPhi = ((lat2 - lat1) * Math.PI) / 180;\n const deltaLambda = ((lon2 - lon1) * Math.PI) / 180;\n\n const a =\n Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) +\n Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n\nexport function compactId(timestamp: number): string {\n // Use a compact representation of the timestamp (seconds since epoch)\n // 1712650000 -> Base64\n const buf = new Uint32Array([Math.floor(timestamp / 1000)]);\n const b64 = btoa(String.fromCharCode(...new Uint8Array(buf.buffer)));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\nexport function shortRandom(): string {\n return Math.random().toString(36).slice(2, 6);\n}\n\nexport function fmtDuration(s: number): string {\n if (s < 60) return `${Math.round(s)}s`;\n if (s < 3600) return `${Math.round(s / 60)}m`;\n return `${Math.round(s / 3600)}h`;\n}\n\nexport function fmtSecs(s: number): string {\n const h = Math.floor(s / 3600),\n m = Math.floor((s % 3600) / 60);\n return h > 0 ? `${h}h ${m}m` : `${m}m ${Math.floor(s % 60)}s`;\n}\n\nexport function fmtPace(seconds: number | null): string {\n if (seconds == null || !isFinite(seconds)) return '--';\n const mins = Math.floor(seconds / 60);\n const secs = Math.round(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nexport function fmtDate(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown date';\n return d.toISOString().split('T')[0];\n}\n\nexport function fmtDateTime(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown';\n const iso = d.toISOString();\n return `${iso.split('T')[0]} ${iso.split('T')[1].slice(0, 5)}`;\n}\n\nexport function fmtFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function escHtml(str: string): string {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function getTagColor(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);\n\n const h = Math.abs(hash % 360);\n return `hsl(${h}, 70%, 65%)`;\n}\n\n/**\n * Smoothes a numeric array using a simple Gaussian kernel.\n * sigma: standard deviation (radius of smoothing)\n */\nexport function gaussianSmooth(data: (number | null)[], sigma: number = 2): (number | null)[] {\n if (sigma <= 0) return data;\n\n const size = Math.ceil(sigma * 3) * 2 + 1;\n const kernel = new Float32Array(size);\n const half = Math.floor(size / 2);\n let sum = 0;\n\n for (let i = 0; i < size; i++) {\n const x = i - half;\n kernel[i] = Math.exp(-(x * x) / (2 * sigma * sigma));\n sum += kernel[i];\n }\n for (let i = 0; i < size; i++) kernel[i] /= sum;\n\n const result: (number | null)[] = new Array(data.length);\n for (let i = 0; i < data.length; i++) {\n if (data[i] === null) {\n result[i] = null;\n continue;\n }\n\n let val = 0;\n let weightSum = 0;\n for (let k = 0; k < size; k++) {\n const idx = i + k - half;\n if (idx >= 0 && idx < data.length && data[idx] !== null) {\n val += data[idx]! * kernel[k];\n weightSum += kernel[k];\n }\n }\n result[i] = weightSum > 0 ? val / weightSum : data[i];\n }\n return result;\n}\n\nexport function hexToRgba(hex: string, alpha: number = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, TrackPoint } from './parsers';\n\nexport const MapView = (() => {\n let trackData: Record = {};\n let customClickHandler: ((e: any) => boolean) | null = null;\n\n function init(\n onSelectCb: (id: string) => void,\n onMoveCb: (lat: number, lng: number, zoom: number) => void,\n onPointClickCb: (id: string, idx: number) => void,\n onPointHoverCb: (id: string | null, idx: number | null) => void,\n onDblClickCb: () => void,\n ) {}\n\n function switchBasemap(layer: string) {}\n function addTrack(t: TrackData) {\n trackData[t.id] = t;\n }\n function addTracks(ts: TrackData[]) {\n ts.forEach((t) => {\n trackData[t.id] = t;\n });\n }\n function removeTrack(id: string) {\n delete trackData[id];\n }\n function clearTracks() {\n trackData = {};\n }\n function removeAllTracks() {\n trackData = {};\n }\n function setTrackVisible(id: string, visible: boolean) {}\n function setSelectedTrack(id: string | null, fit: boolean) {}\n function fitAll() {}\n function fitTrack(id: string) {}\n function showCursorAt(lat: number, lon: number) {}\n function hideCursor() {}\n function highlightSegment(\n id: string | null,\n pts: TrackPoint[],\n start: number,\n end: number,\n fit?: boolean,\n colors?: string[] | null,\n ) {}\n function clearHighlight() {}\n function setTrackHover(id: string, hover: boolean) {}\n function ensureVisible(pts: any) {}\n function centerOn(lat: number, lon: number, zoom?: number | null, force?: boolean) {}\n function closePopup() {}\n function invalidateSize() {}\n function getPosition(): [number, number, number] {\n return [0, 0, 0];\n }\n function setPosition(lat: number, lng: number, zoom: number) {}\n function colorTrackByMetric(id: string, pts: TrackPoint[], colors: string[]) {}\n function clearMetricColor(id: string) {}\n\n function findTracksPassingThroughPoints(\n points: { lat: number; lng: number }[],\n radius: number,\n ): string[] {\n return Object.keys(trackData);\n }\n\n return {\n init,\n getMap: () => null as any,\n setCustomClickHandler: (handler: any) => {\n customClickHandler = handler;\n },\n switchBasemap,\n addTrack,\n addTracks,\n removeTrack,\n clearTracks,\n removeAllTracks,\n setTrackVisible,\n setSelectedTrack,\n fitAll,\n fitTrack,\n showCursorAt,\n hideCursor,\n highlightSegment,\n clearHighlight,\n setTrackHover,\n ensureVisible,\n centerOn,\n closePopup,\n invalidateSize,\n getPosition,\n setPosition,\n colorTrackByMetric,\n clearMetricColor,\n findTracksPassingThroughPoints,\n getTrackData: (id: string) => trackData[id],\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackPoint, TrackStats, TrackData } from './parsers';\nimport { gaussianSmooth, fmtSecs, hexToRgba, fmtPace } from './utils';\nimport { Zones } from './zones';\nimport { METRICS, MetricDefinition } from './metrics';\nimport { UrlState } from './url-state';\nimport { SPORTS } from './sports';\n\n// Augment uPlot to include our custom property\n\ninterface WegPlot extends uPlot {\n _strasse?: {\n selFill: HTMLElement;\n anchorLine: HTMLElement;\n anchorLabel: HTMLElement;\n anchorHandle: HTMLElement;\n anchorMarker: HTMLElement;\n endLine: HTMLElement;\n endLabel: HTMLElement;\n endHandle: HTMLElement;\n endMarker: HTMLElement;\n curYVal: HTMLElement;\n updateHeaderStats: (min: number, max: number) => void;\n };\n}\n\ninterface PlotData {\n uplot: WegPlot;\n row: HTMLDivElement;\n xData: number[];\n yData: (number | null)[];\n def: MetricDefinition;\n metricKey: string;\n statsTotalEl: HTMLDivElement;\n statsSelEl: HTMLDivElement;\n histCol: HTMLDivElement;\n histCanvas: HTMLCanvasElement;\n histData: HistData;\n hoveredHistY: number | null;\n pinnedHistY: number | null;\n smoothed?: boolean;\n incZero?: boolean;\n w?: number;\n}\n\ninterface HistData {\n yData: (number | null)[];\n xData: number[];\n def: MetricDefinition;\n BINS: number;\n plot?: PlotData;\n bins?: number[];\n binAccum?: number[];\n min?: number;\n max?: number;\n padL?: number;\n selBins?: number[] | null;\n selBinAccum?: number[] | null;\n _lastYData?: any;\n _lastSelRange?: [number, number] | null;\n fullStats?: { min: number; max: number; avg: number } | null;\n fullStatsAll?: { min: number; max: number; avg: number } | null;\n}\n\nexport const ChartView = (() => {\n let plots: PlotData[] = [];\n let renderedTrack: TrackData | null = null;\n let renderedXAxis: string = 'time';\n let renderedSpeedMode: string = 'speed';\n let renderedMapColorMetric: string | null = null;\n let syncKey: {\n key: string;\n sub: (u: uPlot) => void;\n unsub: (u: uPlot) => void;\n pub: (type: string, u: uPlot, x: number, y: number, w: number, h: number, i: number) => void;\n } | null = null;\n let scaleSyncing: boolean = false;\n let cursorSyncing: boolean = false;\n let activeMetrics: Set = new Set(['elevation']);\n let availableMetrics: Set = new Set();\n let smoothedMetrics: Set = new Set(['speed', 'gradient', 'vam', 'temperature']);\n let metricsIncludingZero: Set = new Set(['power']);\n let xAxis: string = 'time';\n let currentTrack: TrackData | null = null;\n let allTracks: TrackData[] = [];\n\n // Selection / anchor\n let selAnchorVal: number | null = null; // x-value at drag-start / zoom left edge\n let selEndVal: number | null = null; // x-value at zoom right edge\n let isDragging: boolean = false;\n let updatingRange: boolean = false; // guard against setScale hook re-entry during handle drag\n let pinnedPtIdx: number | null = null; // point index pinned by map click\n let lastMouseXVal: number | null = null; // last hovered x-value for keyboard zoom center\n let lastHistMouseEvent: MouseEvent | null = null;\n let hoveredHistData: HistData | null = null;\n let hoveredHistCanvas: HTMLCanvasElement | null = null;\n\n let currentXRange: [number, number] | null = null; // [min, max] currently rendered\n let targetXRange: [number, number] | null = null; // [min, max] for smooth keyboard animation\n let animId: number | null = null;\n\n // Callbacks\n let onCursorMoveCb: ((pt: TrackPoint | null) => void) | null = null;\n let onRangeChangeCb: ((min: number | null, max: number | null, axis: string) => void) | null =\n null;\n let onClickCb: ((pt: TrackPoint, idx: number) => void) | null = null;\n let onPinChangeCb: ((idx: number | null) => void) | null = null;\n\n const HIST_W: number = 130;\n const ROW_BODY_PADDING: number = 28; // 14px left + 14px right\n const HIST_GAP: number = 20; // margin-left on .hist-col\n let statsVisible: boolean = true;\n let histTooltipEl: HTMLElement | null = null;\n let container: HTMLElement | null = null;\n let emptyEl: HTMLElement | null = null;\n let selStatsEl: HTMLElement | null = null;\n let resetSelBtn: HTMLElement | null = null;\n let mapColorMetric: string | null = null;\n let onMapColorChangeCb: ((data: { pts: TrackPoint[]; colors: string[] } | null) => void) | null =\n null;\n\n // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function init(\n onCursorMove: (pt: TrackPoint | null) => void,\n onRangeChange: (min: number | null, max: number | null, axis: string) => void,\n onClick: (pt: TrackPoint, idx: number) => void,\n onPinChange: (idx: number | null) => void,\n ) {\n onCursorMoveCb = onCursorMove;\n onRangeChangeCb = onRangeChange;\n onClickCb = onClick;\n onPinChangeCb = onPinChange;\n container = document.getElementById('charts-container');\n container?.addEventListener('scroll', () => {\n if (lastHistMouseEvent && hoveredHistCanvas && hoveredHistData)\n updateHistTooltip(lastHistMouseEvent, hoveredHistCanvas, hoveredHistData);\n });\n emptyEl = document.getElementById('chart-empty');\n selStatsEl = document.getElementById('chart-stats-sel');\n resetSelBtn = document.getElementById('btn-reset-selection');\n histTooltipEl = document.getElementById('hist-tooltip');\n syncKey = uPlot.sync('strasse-sync');\n\n document.getElementById('sel-cancel-btn')?.addEventListener('click', cancelSelection);\n resetSelBtn?.classList.add('hidden');\n\n // \u2500\u2500 WASD Keyboard Navigation \u2500\u2500\n const navKeys = new Set(['w', 'a', 's', 'd']);\n const activeNavKeys = new Set();\n\n document.addEventListener('keydown', (e) => {\n if (!plots.length || !currentTrack) return;\n if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName || '')) return;\n\n const key = e.key.toLowerCase();\n if (!navKeys.has(key)) return;\n\n e.preventDefault();\n activeNavKeys.add(key);\n\n const u = plots[0].uplot;\n if (!targetXRange) targetXRange = [u.scales.x!.min!, u.scales.x!.max!];\n\n let [min, max] = targetXRange;\n const span = max - min;\n const moveStep = span * 0.1;\n const zoomFactor = 0.15;\n\n let newMin = min,\n newMax = max;\n\n if (key === 'a') {\n // Pan left\n newMin = min - moveStep;\n newMax = max - moveStep;\n } else if (key === 'd') {\n // Pan right\n newMin = min + moveStep;\n newMax = max + moveStep;\n } else if (key === 'w' || key === 's') {\n // Zoom\n const center = lastMouseXVal !== null ? lastMouseXVal : (min + max) / 2;\n const factor = key === 'w' ? 1 - zoomFactor : 1 + zoomFactor * 1.2;\n newMin = center - (center - min) * factor;\n newMax = center + (max - center) * factor;\n }\n\n // Clamp to track bounds\n const xFull = [plots[0].xData[0]!, plots[0].xData[plots[0].xData.length - 1]!];\n if (newMin < xFull[0]) {\n const d = xFull[0] - newMin;\n newMin += d;\n newMax += d;\n }\n if (newMax > xFull[1]) {\n const d = newMax - xFull[1];\n newMin -= d;\n newMax -= d;\n }\n newMin = Math.max(xFull[0], newMin);\n newMax = Math.min(xFull[1], newMax);\n\n if (newMax - newMin > 0.001) {\n targetXRange = [newMin, newMax];\n setVisibleRange(newMin, newMax, true); // true = animate\n }\n });\n\n document.addEventListener('keyup', (e) => {\n const key = e.key.toLowerCase();\n if (navKeys.has(key)) activeNavKeys.delete(key);\n });\n }\n\n function setVisibleRange(min: number, max: number, animate = false) {\n if (!plots.length) return;\n if (!animate) {\n plots.forEach(({ uplot: u }) => u.setScale('x', { min, max }));\n return;\n }\n\n const startMin = (currentXRange ? currentXRange[0] : plots[0].uplot.scales.x!.min) as number;\n const startMax = (currentXRange ? currentXRange[1] : plots[0].uplot.scales.x!.max) as number;\n\n if (animId) cancelAnimationFrame(animId);\n\n const lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n const factor = 0.25; // Smoothing factor\n\n const step = () => {\n if (!targetXRange) return;\n const [tMin, tMax] = targetXRange;\n\n const cMin = lerp(currentXRange![0], tMin, factor);\n const cMax = lerp(currentXRange![1], tMax, factor);\n\n plots.forEach(({ uplot: u }) => {\n u.setScale('x', { min: cMin, max: cMax });\n });\n\n if (Math.abs(cMin - tMin) > 0.0001 || Math.abs(cMax - tMax) > 0.0001)\n animId = requestAnimationFrame(step);\n else animId = null;\n };\n animId = requestAnimationFrame(step);\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function loadTrack(track: TrackData, others: TrackData[] = [], deferRender = false) {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n allTracks = others;\n\n // Detect which metrics are available in this file\n availableMetrics = new Set(\n Object.entries(METRICS)\n .filter(([, def]) => track.points.some((p) => p[def.field] != null))\n .map(([key]) => key),\n );\n\n // If no metrics are active (e.g. first load), default to core overview metrics\n if (activeMetrics.size === 0) {\n activeMetrics = new Set(['elevation'].filter((m) => availableMetrics.has(m)));\n }\n\n // Sync the pill buttons in the toolbar\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n const metric = pill.dataset.metric!;\n const isAvailable = availableMetrics.has(metric);\n pill.classList.toggle('active', isAvailable && activeMetrics.has(metric));\n pill.classList.toggle('disabled', !isAvailable);\n });\n\n currentTrack = track;\n if (deferRender) {\n updateStats(track);\n } else {\n render();\n }\n }\n\n function clear() {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n currentTrack = null;\n destroyPlots();\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
Select a track to view analysis
\n `;\n }\n const chartStats = document.getElementById('chart-stats');\n if (chartStats) chartStats.classList.add('hidden');\n clearSelectionStats();\n mapColorMetric = null;\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n }\n\n function resetState() {\n if (animId !== null) {\n cancelAnimationFrame(animId);\n animId = null;\n }\n activeMetrics = new Set(['elevation']);\n availableMetrics = new Set();\n smoothedMetrics = new Set(['speed', 'gradient', 'vam', 'temperature']);\n metricsIncludingZero = new Set(['power']);\n xAxis = 'time';\n allTracks = [];\n currentXRange = null;\n targetXRange = null;\n lastMouseXVal = null;\n lastHistMouseEvent = null;\n hoveredHistData = null;\n hoveredHistCanvas = null;\n statsVisible = true;\n clear();\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n pill.classList.remove('disabled', 'overflow-hidden');\n });\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.add('hidden');\n const toolbar = document.getElementById('chart-toolbar');\n if (toolbar) toolbar.classList.remove('collapsed');\n document.querySelectorAll('#x-axis-ctrl .seg-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.axis === 'time');\n });\n }\n\n function toggleMetric(key: string) {\n if (activeMetrics.has(key)) activeMetrics.delete(key);\n else activeMetrics.add(key);\n if (currentTrack) render(true);\n }\n\n function setActiveMetrics(keys: string[]) {\n activeMetrics = new Set(keys);\n if (currentTrack) render(true);\n // Sync the pill buttons\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n });\n }\n\n function setXAxis(axis: string) {\n if (xAxis === axis || !currentTrack) {\n xAxis = axis;\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n\n // Helper to convert a value from OLD axis to NEW axis\n const convert = (val: number | null) => {\n if (val === null) return null;\n // We need to find the point index closest to 'val' on the OLD axis\n let idx = 0;\n if (xAxis === 'distance') {\n const dTarget = val * 1000;\n idx = pts.findIndex((p) => (p.dist || 0) >= dTarget);\n } else {\n const tTarget = t0 + val * 1000;\n idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n }\n if (idx === -1) idx = pts.length - 1;\n\n // Now get the value at this index on the NEW axis\n if (axis === 'distance') return (pts[idx].dist || 0) / 1000;\n else return ((pts[idx].time || t0) - t0) / 1000;\n };\n\n // Convert selection\n if (selAnchorVal !== null) selAnchorVal = convert(selAnchorVal);\n if (selEndVal !== null) selEndVal = convert(selEndVal);\n\n // Convert zoom range (from first plot)\n let newRange: [number, number] | null = null;\n if (plots.length) {\n const u = plots[0].uplot;\n const r0 = convert(u.scales.x!.min!);\n const r1 = convert(u.scales.x!.max!);\n if (r0 !== null && r1 !== null) newRange = [r0, r1];\n }\n\n xAxis = axis;\n render(true);\n\n // Apply converted zoom\n if (newRange) {\n scaleSyncing = true;\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: newRange![0], max: newRange![1] }));\n });\n scaleSyncing = false;\n }\n }\n\n function toggleStats() {\n statsVisible = !statsVisible;\n plots.forEach(({ histCol }) => histCol.classList.toggle('visible', statsVisible));\n resize();\n }\n\n function setMapColorChangeCb(cb: (data: { pts: TrackPoint[]; colors: string[] } | null) => void) {\n onMapColorChangeCb = cb;\n }\n\n function toggleMapColor(key: string | null) {\n if (mapColorMetric === key || key === null) {\n mapColorMetric = null;\n _updateMapColorBtns();\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n } else {\n mapColorMetric = key;\n _updateMapColorBtns();\n _fireMapColorCb();\n }\n // Re-render to show/hide colored fills on the graphs\n if (currentTrack) render(true);\n }\n\n function _updateMapColorBtns() {\n document.querySelectorAll('.map-color-btn').forEach((el) => {\n const b = el as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === mapColorMetric);\n });\n }\n\n function _fireMapColorCb() {\n if (!onMapColorChangeCb || !mapColorMetric || !currentTrack) return;\n const plot = plots.find((p) => p.metricKey === mapColorMetric);\n if (!plot) return;\n const colors = _computePointColors(mapColorMetric, plot.yData);\n onMapColorChangeCb({ pts: currentTrack.points, colors });\n }\n\n function _computePointColors(key: string, yData: (number | null)[]): string[] {\n const vals = yData.filter((v): v is number => v != null && isFinite(v));\n if (!vals.length) return yData.map(() => '#888896');\n const min = Math.min(...vals),\n max = Math.max(...vals);\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n return yData.map((v) => {\n if (v == null || !isFinite(v)) return '#888896';\n if (key === 'gradient') return gradientColor(v);\n if (key === 'speed') {\n if (speedMode === 'pace') {\n const speed = (paceUnit === 'km' ? 1000 : 100) / v;\n return speedColor(speed);\n }\n return speedColor(v);\n }\n const t = max === min ? 0.5 : Math.max(0, Math.min(1, (v - min) / (max - min)));\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25);\n if (t <= 0.5) return lerpHex('#91bfdb', '#fee090', (t - 0.25) / 0.25);\n if (t <= 0.75) return lerpHex('#fee090', '#fc8d59', (t - 0.5) / 0.25);\n return lerpHex('#fc8d59', '#d73027', (t - 0.75) / 0.25);\n });\n }\n\n function resetZoom() {\n cancelSelection();\n }\n\n function cancelSelection() {\n selAnchorVal = null;\n selEndVal = null;\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n\n // Reset individual histogram pins\n plots.forEach((p) => {\n p.pinnedHistY = null;\n });\n\n updateSelOverlay();\n redrawHistograms();\n\n // Perform the actual zoom reset\n scaleSyncing = true;\n plots.forEach(({ uplot: u, xData }) => {\n u.batch(() => u.setScale('x', { min: xData[0]!, max: xData[xData.length - 1]! }));\n u._strasse?.updateHeaderStats(xData[0]!, xData[xData.length - 1]!);\n });\n scaleSyncing = false;\n\n if (onRangeChangeCb) onRangeChangeCb(null, null, xAxis);\n }\n\n function setSelectionStats(stats: TrackStats) {\n if (!selStatsEl) return;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt(\n 'sel-distance',\n stats.totalDist != null ? `${(stats.totalDist / 1000).toFixed(1)} km` : '\u2014',\n );\n fmt('sel-duration', stats.duration != null ? fmtSecs(Math.floor(stats.duration / 1000)) : '\u2014');\n fmt('sel-elevation', stats.elevGain != null ? `${Math.round(stats.elevGain)} m` : '\u2014');\n fmt(\n 'sel-avg-speed',\n stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014',\n );\n fmt('sel-avg-power', stats.avgPower != null ? `${stats.avgPower} W` : '\u2014');\n fmt('sel-avg-hr', stats.avgHR != null ? `${stats.avgHR} bpm` : '\u2014');\n fmt('sel-avg-temp', stats.avgTemp != null ? `${stats.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n selStatsEl.classList.remove('hidden');\n if (resetSelBtn) resetSelBtn.classList.remove('hidden');\n }\n\n function clearSelectionStats() {\n if (selStatsEl) selStatsEl.classList.add('hidden');\n if (resetSelBtn) resetSelBtn.classList.add('hidden');\n [\n 'sel-distance',\n 'sel-duration',\n 'sel-elevation',\n 'sel-avg-speed',\n 'sel-avg-power',\n 'sel-avg-hr',\n 'sel-avg-temp',\n ].forEach((id) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = '--';\n });\n }\n\n // Called on boot to restore a saved selection without re-firing onRangeChangeCb\n // xMin/xMax are ALWAYS provided in Time (seconds from start)\n function restoreSelection(tMin: number, tMax: number, deferRender = false) {\n if (!currentTrack) return;\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const totalDuration = ((pts[pts.length - 1]?.time || 0) - t0) / 1000;\n\n // If values look like absolute timestamps in ms, convert to seconds from start\n if (tMin > 1e12) tMin = (tMin - t0) / 1000;\n if (tMax > 1e12) tMax = (tMax - t0) / 1000;\n\n // Crop to max limits of the track\n tMin = Math.max(0, Math.min(tMin, totalDuration));\n tMax = Math.max(0, Math.min(tMax, totalDuration));\n\n const convert = (tOffset: number) => {\n if (xAxis === 'time') return tOffset;\n const tTarget = t0 + tOffset * 1000;\n let idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n if (idx === -1) idx = pts.length - 1;\n return (pts[idx].dist || 0) / 1000;\n };\n\n const xMin = convert(tMin);\n const xMax = convert(tMax);\n\n selAnchorVal = xMin;\n selEndVal = xMax;\n currentXRange = [xMin, xMax];\n if (deferRender) return;\n scaleSyncing = true; // suppress the setScale \u2192 onRangeChangeCb loop\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: xMin, max: xMax }));\n });\n scaleSyncing = false;\n updateAnchorLines();\n redrawHistograms();\n }\n\n function resize() {\n if (!plots.length || !container) return;\n const w = Math.round(\n Math.max(\n 100,\n container.getBoundingClientRect().width -\n ROW_BODY_PADDING -\n (statsVisible ? HIST_W + HIST_GAP : 0),\n ),\n );\n let anyResized = false;\n plots.forEach(({ uplot: u, histCanvas, histData }) => {\n if (w !== u.width) {\n u.setSize({ width: w, height: u.height });\n anyResized = true;\n if (statsVisible && histCanvas && histData) drawHistogram(histCanvas, histData, u.height);\n }\n });\n if (anyResized) updateSelOverlay();\n }\n\n // \u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function render(keepState = false) {\n let savedRange: [number, number] | null = null;\n let savedScroll = 0;\n if (keepState && container) savedScroll = container.scrollTop;\n\n if (keepState && currentXRange) {\n savedRange = [currentXRange[0], currentXRange[1]];\n } else if (keepState && plots.length) {\n const u = plots[0].uplot;\n savedRange = [u.scales.x!.min!, u.scales.x!.max!];\n }\n\n if (!currentTrack) {\n destroyPlots(keepState);\n return;\n }\n const pts = currentTrack.points;\n if (!pts.length) {\n destroyPlots(keepState);\n return;\n }\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n const available = [...activeMetrics].filter((m) =>\n pts.some((p) => p[METRICS[m].field] != null),\n );\n if (!available.length) {\n destroyPlots(keepState);\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
No data for selected metrics
\n `;\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n\n const containerW = container ? container.getBoundingClientRect().width : 800;\n const w = Math.round(\n Math.max(100, containerW - ROW_BODY_PADDING - (statsVisible ? HIST_W + HIST_GAP : 0)),\n );\n\n const canReuse =\n keepState &&\n renderedTrack === currentTrack &&\n renderedXAxis === xAxis &&\n renderedSpeedMode === speedMode &&\n renderedMapColorMetric === mapColorMetric &&\n plots.length > 0;\n\n let xData: (number | null)[];\n if (canReuse) {\n xData = plots[0].xData;\n } else if (xAxis === 'distance') {\n xData = pts.map((p) => (p.dist || 0) / 1000);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n let lastValidX = 0;\n xData = pts.map((p) => {\n if (p.time != null) {\n lastValidX = (p.time - t0) / 1000;\n return lastValidX;\n }\n return lastValidX; // monotonic fallback\n });\n }\n\n const existingByKey = new Map();\n if (canReuse) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const availSet = new Set(available);\n for (const p of plots) {\n const isSmoothed = smoothedMetrics.has(p.metricKey);\n const isIncZero = metricsIncludingZero.has(p.metricKey);\n if (\n availSet.has(p.metricKey) &&\n p.smoothed === isSmoothed &&\n p.incZero === isIncZero &&\n p.w === w\n ) {\n existingByKey.set(p.metricKey, p);\n } else {\n syncKey!.unsub(p.uplot);\n p.uplot.destroy();\n p.row.remove();\n }\n }\n plots = [];\n } else {\n destroyPlots(keepState);\n }\n\n if (container) {\n const nextSiblingRows: (HTMLElement | null)[] = new Array(available.length).fill(null);\n let nextExisting: HTMLElement | null = null;\n for (let i = available.length - 1; i >= 0; i--) {\n nextSiblingRows[i] = nextExisting;\n const ex = existingByKey.get(available[i]);\n if (ex) nextExisting = ex.row;\n }\n\n available.forEach((key, idx) => {\n const reused = existingByKey.get(key);\n if (reused) {\n plots.push(reused);\n const uplot = reused.uplot;\n const s = (uplot as any)._strasse;\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n uplot.batch(() => {\n if (\n savedRange &&\n (uplot.scales.x!.min !== savedRange[0] || uplot.scales.x!.max !== savedRange[1])\n ) {\n uplot.setScale('x', { min: savedRange[0], max: savedRange[1] });\n } else {\n s?.updateHeaderStats(uplot.scales.x!.min!, uplot.scales.x!.max!, uplot);\n uplot.redraw(false);\n }\n });\n scaleSyncing = prevSync;\n\n let initHoverBinI: number | null = null;\n if (\n pinnedPtIdx != null &&\n reused.xData[pinnedPtIdx] != null &&\n reused.yData[pinnedPtIdx] != null\n ) {\n buildHistBins(reused.histData);\n if (reused.histData.min != null && reused.histData.max != null) {\n const span = reused.histData.max - reused.histData.min || 1;\n initHoverBinI = Math.min(\n reused.histData.BINS - 1,\n Math.floor(\n ((reused.yData[pinnedPtIdx]! - reused.histData.min) / span) *\n reused.histData.BINS,\n ),\n );\n reused.hoveredHistY = reused.yData[pinnedPtIdx];\n }\n }\n drawHistogram(reused.histCanvas, reused.histData, 130, initHoverBinI);\n return;\n }\n\n let def = METRICS[key];\n\n let transform = def.transform;\n let fmt = def.fmt;\n let fmtAxis = def.fmtAxis;\n let unit = def.unit;\n let label = def.label;\n\n if (key === 'speed' && speedMode === 'pace') {\n label = 'Pace';\n unit = `min/${paceUnit}`;\n fmt = (v) => fmtPace(v);\n fmtAxis = (v) => fmtPace(v);\n transform = (v) => {\n if (v == null || v < 0.1) return null;\n return (paceUnit === 'km' ? 1000 : 100) / v;\n };\n\n def = { ...def, label, unit, fmt, fmtAxis, transform };\n }\n\n let yData = def.compute\n ? def.compute(pts, fillNulls)\n : fillNulls(\n pts.map((p) => {\n const v = p[def.field] as number;\n return v != null && transform ? transform(v) : v;\n }),\n );\n\n if (smoothedMetrics.has(key)) yData = gaussianSmooth(yData, def.smoothSigma || 2);\n\n createChart(key, def, xData, yData, w, pts, savedRange, nextSiblingRows[idx]);\n });\n }\n\n renderedTrack = currentTrack;\n renderedXAxis = xAxis;\n renderedSpeedMode = speedMode;\n renderedMapColorMetric = mapColorMetric;\n\n updateStats(currentTrack);\n // Restore anchor/end lines if a selection was active\n if (selAnchorVal != null && selEndVal != null) updateAnchorLines();\n // Re-apply map color if active\n _updateMapColorBtns();\n if (mapColorMetric) _fireMapColorCb();\n\n if (keepState && container && savedScroll > 0) container.scrollTop = savedScroll;\n }\n\n // \u2500\u2500 Create one chart row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function createChart(\n metricKey: string,\n def: MetricDefinition,\n xData: (number | null)[],\n yData: (number | null)[],\n w: number,\n pts: TrackPoint[],\n initialRange: [number, number] | null = null,\n insertBeforeEl: HTMLElement | null = null,\n ) {\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n\n // Gradient data: smooth over a 20 m distance window (\u00B110 m each side)\n const gradData = metricKey === 'elevation' ? smoothGradient(pts, 20) : null;\n const row = document.createElement('div');\n row.className = 'chart-row';\n row.dataset.metric = metricKey;\n row.style.setProperty('--chart-color', def.color);\n\n // Header\n const header = document.createElement('div');\n header.className = `chart-row-header${statsVisible ? ' with-histogram' : ''}`;\n\n const labelEl = document.createElement('div');\n labelEl.className = 'chart-row-label-group';\n labelEl.innerHTML = `\n ${def.icon}\n ${def.label}\n `;\n\n // Smoothing toggle\n const smoothBtn = document.createElement('button');\n smoothBtn.className = `icon-btn mini smooth-btn${smoothedMetrics.has(metricKey) ? ' active' : ''}`;\n smoothBtn.title = 'Toggle data smoothing';\n smoothBtn.innerHTML = `${smoothedMetrics.has(metricKey) ? 'blur_on' : 'blur_off'}`;\n smoothBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (smoothedMetrics.has(metricKey)) smoothedMetrics.delete(metricKey);\n else smoothedMetrics.add(metricKey);\n\n render(true); // Re-render all charts to keep sync if needed (though only this one changes data)\n });\n\n const mapColorBtn = document.createElement('button');\n\n mapColorBtn.className = `map-color-btn icon-btn${mapColorMetric === metricKey ? ' active' : ''}`;\n mapColorBtn.dataset.metric = metricKey;\n mapColorBtn.title = 'Color map track by this metric';\n mapColorBtn.innerHTML = 'colorize';\n mapColorBtn.addEventListener('click', () => toggleMapColor(metricKey));\n\n // Zero-filter toggle (Cadence/Power/Speed)\n let zeroBtn: HTMLButtonElement | null = null;\n if (metricKey === 'cadence' || metricKey === 'power' || metricKey === 'speed') {\n zeroBtn = document.createElement('button');\n const incZero = metricsIncludingZero.has(metricKey);\n zeroBtn.className = `icon-btn mini${incZero ? ' active' : ''}`;\n zeroBtn.title = incZero ? 'Currently INCLUDING 0 values' : 'Currently EXCLUDING 0 values';\n zeroBtn.innerHTML = `${incZero ? 'exposure_zero' : 'mobile_off'}`;\n zeroBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (metricsIncludingZero.has(metricKey)) metricsIncludingZero.delete(metricKey);\n else metricsIncludingZero.add(metricKey);\n render(true);\n });\n }\n\n const statsTotalEl = document.createElement('div');\n statsTotalEl.className = 'chart-stats-total';\n\n const statsSelEl = document.createElement('div');\n statsSelEl.className = 'chart-stats-selection';\n\n const statsContainer = document.createElement('div');\n statsContainer.className = 'chart-row-stats-container';\n statsContainer.append(statsTotalEl, statsSelEl);\n\n const actionsEl = document.createElement('div');\n actionsEl.className = 'chart-row-actions';\n actionsEl.append(smoothBtn, mapColorBtn);\n\n const rightActionsEl = document.createElement('div');\n rightActionsEl.className = 'chart-row-right-actions';\n\n if (metricKey === 'speed') {\n const paceToggle = document.createElement('div');\n paceToggle.className = 'seg-ctrl';\n paceToggle.innerHTML = `\n \n \n `;\n paceToggle.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const mode = btn.dataset.mode;\n if (mode === 'speed' || mode === 'pace') {\n const isDefault = mode === defaultMode;\n UrlState.patch({ speed_mode: isDefault ? null : mode });\n render(true);\n }\n });\n rightActionsEl.append(paceToggle);\n }\n\n if (zeroBtn) rightActionsEl.append(zeroBtn);\n\n header.append(labelEl, actionsEl, statsContainer, rightActionsEl);\n\n const rowBody = document.createElement('div');\n rowBody.className = 'chart-row-body';\n\n const plotEl = document.createElement('div');\n plotEl.style.position = 'relative';\n rowBody.appendChild(plotEl);\n\n const fixedMinLabel = document.createElement('div');\n fixedMinLabel.className = 'fixed-x-label fixed-x-min';\n const fixedMaxLabel = document.createElement('div');\n fixedMaxLabel.className = 'fixed-x-label fixed-x-max';\n plotEl.append(fixedMinLabel, fixedMaxLabel);\n\n const histCol = document.createElement('div');\n histCol.className = `hist-col${statsVisible ? ' visible' : ''}`;\n const histCanvas = document.createElement('canvas');\n histCanvas.className = 'hist-canvas';\n histCol.appendChild(histCanvas);\n rowBody.appendChild(histCol);\n\n row.append(header, rowBody);\n\n const isDistAxis = xAxis === 'distance';\n\n function formatX(v: number, range: number): string {\n if (v == null) return '';\n if (isDistAxis) {\n const dec = range < 1 ? 3 : range < 5 ? 2 : range < 20 ? 1 : 0;\n return `${v.toFixed(dec)} km`;\n } else {\n const absV = Math.abs(v);\n const h = Math.floor(absV / 3600);\n const m = Math.floor((absV % 3600) / 60);\n const s = Math.round(absV % 60);\n const hh = h > 0 ? `${h}:` : '';\n const mm = h > 0 ? String(m).padStart(2, '0') : String(m);\n const ss = String(s).padStart(2, '0');\n return `${v < 0 ? '-' : ''}${hh}${mm}:${ss}`;\n }\n }\n\n const incZeroDefault =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Compute global Y range and full-track stats in a single pass\n let gMin = Infinity,\n gMax = -Infinity,\n allSum = 0,\n allCount = 0,\n filtMin = Infinity,\n filtMax = -Infinity,\n filtSum = 0,\n filtCount = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n allSum += v;\n allCount++;\n if (v !== 0 || incZeroDefault) {\n if (v < filtMin) filtMin = v;\n if (v > filtMax) filtMax = v;\n filtSum += v;\n filtCount++;\n }\n }\n if (allCount === 0) {\n gMin = 0;\n gMax = 100;\n }\n const fullStatsAll = allCount ? { min: gMin, max: gMax, avg: allSum / allCount } : null;\n const fullStatsFiltered = filtCount\n ? { min: filtMin, max: filtMax, avg: filtSum / filtCount }\n : null;\n const gPad = Math.abs(gMax - gMin) * 0.1 || 1;\n const fixedYRange = [gMin - gPad, gMax + gPad];\n\n let statsTotalInitialized = false;\n\n // Per-range stats\n function updateHeaderStats(visibleMin: number, visibleMax: number, u?: uPlot) {\n const incZero =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Update fixed X labels\n const range = visibleMax - visibleMin;\n fixedMinLabel.textContent = formatX(visibleMin, range);\n fixedMaxLabel.textContent = formatX(visibleMax, range);\n\n const getHtml = (xMin: number, xMax: number, isFull = false) => {\n const s =\n isFull && incZero === incZeroDefault\n ? fullStatsFiltered\n : rangeStats(xData, yData, xMin, xMax, incZero);\n if (!s) return '';\n\n let h = `\n align_flex_end${def.fmt(s.min, true)} ${def.unit}\n align_center${def.fmt(s.avg, true)} ${def.unit}\n align_flex_start${def.fmt(s.max, true)} ${def.unit}\n `;\n\n if (metricKey === 'elevation') {\n const es = elevationRangeStats(pts, xMin, xMax);\n h += `\n trending_up+${Math.round(es.gain)} m\n trending_down-${Math.round(es.loss)} m\n `;\n }\n return h;\n };\n\n if (!statsTotalInitialized) {\n statsTotalInitialized = true;\n statsTotalEl.innerHTML = `all_inclusive${getHtml(\n xData[0]!,\n xData[xData.length - 1]!,\n true,\n )}`;\n statsTotalEl.querySelector('.all-chip')?.addEventListener('click', (e) => {\n e.stopPropagation();\n cancelSelection();\n });\n }\n\n if (selAnchorVal !== null && selEndVal !== null) {\n statsSelEl.innerHTML = getHtml(selAnchorVal, selEndVal, false);\n statsSelEl.style.display = 'flex';\n statsSelEl.style.setProperty('--sel-color', def.color);\n } else {\n statsSelEl.style.display = 'none';\n }\n }\n let initializingScale = false;\n const uOpts: uPlot.Options = {\n width: w,\n height: 130,\n padding: [4, 0, 0, 0],\n cursor: {\n sync: {\n key: syncKey!.key,\n },\n drag: { x: true, y: false, uni: 16 },\n focus: { prox: 16 },\n points: {\n size: 7,\n stroke: '#0e0e10',\n width: 2,\n fill: (metricKey === 'elevation'\n ? (u: uPlot, _si: number) => gradientColor(gradData ? gradData[u.cursor.idx!]! : null)\n : def.color) as any,\n },\n x: false,\n y: false,\n },\n select: {\n show: true,\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n },\n legend: { show: false },\n scales: {\n x: {\n time: false,\n range: (_u: uPlot, mn: number, mx: number) => [mn, mx],\n min: initialRange ? initialRange[0] : undefined,\n max: initialRange ? initialRange[1] : undefined,\n },\n y: {\n range: () => fixedYRange as [number, number],\n dir: metricKey === 'speed' && speedMode === 'pace' ? -1 : 1,\n },\n },\n axes: [\n {\n side: 2, // bottom\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: {\n show: true,\n stroke: '#2e2e34',\n },\n size: 30,\n space: 80,\n font: '10px system-ui, sans-serif',\n splits: (u: uPlot, axisIdx: number, scaleMin: number, scaleMax: number) => {\n const range = scaleMax - scaleMin;\n const width = u.bbox.width > 0 ? u.bbox.width : u.width;\n const targetLabels = width / 80;\n const idealIncr = range / targetLabels;\n\n let incrs;\n if (!isDistAxis) {\n // Time in seconds\n incrs = [\n 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 14400, 28800, 43200,\n 86400, 604800, 2592000, 31536000,\n ];\n } else {\n incrs = [\n 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000,\n 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000,\n ];\n }\n\n let incr = incrs[incrs.length - 1];\n for (let i = 0; i < incrs.length; i++) {\n if (incrs[i] >= idealIncr) {\n incr = incrs[i];\n break;\n }\n }\n\n const splits = [];\n let val = Math.ceil(scaleMin / incr) * incr;\n const precision = incr < 1 ? 2 : 0;\n\n while (val <= scaleMax) {\n const pos = u.valToPos(val, 'x', true);\n if (pos >= u.bbox.left + 80 && pos <= u.bbox.left + u.bbox.width - 80)\n splits.push(Number(val.toFixed(precision)));\n\n val += incr;\n }\n return splits;\n },\n values: ((_u: uPlot, vals: number[]) => {\n const range = (_u.scales.x?.max ?? 1) - (_u.scales.x?.min ?? 0);\n\n return vals.map((v) => {\n if (v == null) return '';\n const pos = _u.valToPos(v, 'x', true);\n // Strict 80px margin to prevent overlapping with fixed labels or Y axis\n if (pos < _u.bbox.left + 80 || pos > _u.bbox.left + _u.bbox.width - 80) return null;\n return formatX(v, range);\n });\n }) as any,\n },\n {\n side: 3, // left\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: { stroke: '#2e2e34' },\n size: 55,\n font: '10px system-ui, sans-serif',\n values: ((_u: uPlot, vals: number[]) =>\n vals.map((v) => (v != null ? def.fmtAxis(v) : ''))) as any,\n },\n ],\n series: [\n {},\n // Main selected track series\n {\n label: def.label,\n stroke: 'rgba(0,0,0,0)', // Stroke handled in draw hooks for layering\n width: 0,\n points: { show: false },\n paths: () => null,\n },\n ],\n hooks: {\n draw: [\n (u: uPlot) => {\n const top = u.bbox.top + u.bbox.height + 5; // 5px below plot area!\n fixedMinLabel.style.top = `${top}px`;\n fixedMinLabel.style.left = `${u.bbox.left}px`;\n\n fixedMaxLabel.style.top = `${top}px`;\n fixedMaxLabel.style.left = `${u.bbox.left + u.bbox.width}px`;\n fixedMaxLabel.style.transform = 'translateX(-100%)';\n },\n // 1. (bottom) Color / metric color of the selected track\n (u: uPlot) => {\n if (metricKey === 'gears') {\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n } else if (metricKey === 'elevation') {\n drawElevationGradient(u, xData as number[], yData as number[], gradData);\n } else if (metricKey === 'gradient') {\n drawGradientChart(u, xData as number[], yData as number[]);\n } else if (mapColorMetric === metricKey) {\n drawMetricColorFill(u, xData as number[], yData as number[], pts, metricKey);\n } else {\n // Normal colored line\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n }\n },\n\n // 2. Pinned point (middle)\n (u: uPlot) => {\n const plot = plots.find((p) => p.uplot === u);\n if (!plot) return;\n\n const s = (u as any)._strasse;\n // Priority 1: Global pinned point (all charts)\n if (pinnedPtIdx != null) {\n drawPinnedDot(u, xData, yData, def.color, def, pts, metricKey);\n } else {\n if (s && s.pinYVal) s.pinYVal.style.display = 'none';\n\n // Priority 2: Individual histogram pinned Y-pos (this chart only)\n if (plot.pinnedHistY != null)\n drawYAxisHighlight(u, xData, yData, plot.pinnedHistY, def.color, def);\n }\n },\n\n // 3. Pinned & Hover elements (labels, vertical lines)\n (u: uPlot) => {\n const hIdx = u.cursor.idx;\n const hasPinned = pinnedPtIdx != null;\n\n let hasHover = hIdx != null && u.cursor.left! >= 0;\n if (hasHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[hIdx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) hasHover = false;\n }\n\n // B. Draw Hover vertical line\n if (hasHover && hIdx !== pinnedPtIdx)\n drawVerticalLineOnly(u, pts, hIdx!, hexToRgba(def.color, 0.4), 1.0);\n\n // C. Bold selection x-axis line & span pill\n if (selAnchorVal != null && selEndVal != null) {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ax = u.valToPos(selAnchorVal, 'x', true);\n const ex = u.valToPos(selEndVal, 'x', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.lineWidth = 3 * dpr;\n ctx.strokeStyle = def.color;\n ctx.moveTo(ax, bb.top + bb.height);\n ctx.lineTo(ex, bb.top + bb.height);\n ctx.stroke();\n\n const span = Math.abs(selEndVal - selAnchorVal);\n const label = xAxis === 'distance' ? `${span.toFixed(2)} km` : fmtSecs(span);\n const fontSize = 9 * dpr;\n const fontStr = `bold ${fontSize}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n\n const visibleL = Math.max(bb.left, ax);\n const visibleR = Math.min(bb.left + bb.width, ex);\n const visibleW = visibleR - visibleL;\n\n if (visibleW > tw + 14 * dpr) {\n const padH = 5 * dpr;\n const padV = 2 * dpr;\n const bw = tw + padH * 2;\n const bh = fontSize + padV * 2;\n const bx = (visibleL + visibleR) / 2 - bw / 2;\n const by = bb.top + bb.height - bh / 2;\n\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = def.color;\n ctx.fill();\n\n ctx.fillStyle = '#000';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2);\n }\n ctx.restore();\n }\n\n // D. Draw label pills (on top)\n // Pinned labels first (semi-transparent)\n if (hasPinned) drawXAxisLabels(u, pts, pinnedPtIdx!, def.color, true, 0.7);\n\n // Hover labels last (fully opaque, topmost)\n if (hasHover && hIdx !== pinnedPtIdx)\n drawXAxisLabels(u, pts, hIdx!, def.color, true, 1.0);\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (scaleSyncing) return;\n const idx = u.cursor.idx;\n\n // Trigger redraw on cursor move to ensure custom canvas markers (hover lines/labels) update live\n // Note: uPlot handles cross-chart sync when syncKey is used.\n u.redraw(false);\n\n // Track current x-value for keyboard navigation\n if (u.cursor.left! >= 0) lastMouseXVal = u.posToVal(u.cursor.left!, 'x');\n else lastMouseXVal = null;\n\n // \u2500\u2500 Floating y-value next to cursor dot \u2500\u2500\n const s = (u as any)._strasse;\n let showHover = idx != null && yData[idx] != null;\n\n // Distance threshold: if no pinned point, check proximity to data line\n if (showHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[idx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) showHover = false;\n }\n\n if (s) {\n if (showHover)\n updateTooltip(\n u,\n s.curYVal,\n idx!,\n xData as number[],\n yData as number[],\n pts,\n def,\n metricKey,\n );\n else s.curYVal.style.display = 'none';\n }\n\n // Map marker\n if (!cursorSyncing) {\n if (idx != null && pts[idx]) {\n if (onCursorMoveCb && (pinnedPtIdx != null || showHover)) {\n onCursorMoveCb(pts[idx]);\n } else if (onCursorMoveCb && !showHover) {\n // If we're too far and nothing is pinned, hide map cursor\n onCursorMoveCb(null);\n }\n } else if (idx === null && onCursorMoveCb) {\n onCursorMoveCb(null);\n }\n }\n\n // Highlight matching histogram bucket\n if (idx != null && yData[idx] != null) {\n const { min, max } = histData;\n if (min != null && max != null) {\n const span = max - min || 1;\n const binI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[idx]! - min) / span) * histData.BINS),\n );\n if (plot.hoveredHistY !== yData[idx]) {\n plot.hoveredHistY = yData[idx];\n drawHistogram(histCanvas, histData, 130, binI);\n }\n }\n } else if (plot.hoveredHistY !== null) {\n plot.hoveredHistY = null;\n drawHistogram(histCanvas, histData, 130);\n }\n },\n ],\n\n setScale: [\n (u: uPlot, key: string) => {\n if (key !== 'x' || initializingScale) return;\n const { min, max } = u.scales.x!;\n\n // Sync currentXRange so keyboard navigation baseline is always accurate\n currentXRange = [min!, max!];\n\n // Update header stats for VISIBLE range\n updateHeaderStats(min as number, max as number, u);\n\n if (scaleSyncing) return;\n\n // Clear keyboard target when user interacts via mouse\n if (!updatingRange) targetXRange = null;\n\n // Sync sibling plots\n scaleSyncing = true;\n plots.forEach(({ uplot: other }) => {\n if (other !== u) other.batch(() => other.setScale('x', { min: min!, max: max! }));\n });\n scaleSyncing = false;\n\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb && selAnchorVal !== null)\n onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n },\n ],\n\n setSelect: [\n (u: uPlot) => {\n if (updatingRange) return;\n targetXRange = null;\n const { left, width } = u.select;\n if (width > 0) {\n const min = u.posToVal(left, 'x');\n const max = u.posToVal(left + width, 'x');\n selAnchorVal = min;\n selEndVal = max;\n\n // Sync stats to new selection\n updateHeaderStats(u.scales.x!.min!, u.scales.x!.max!, u);\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n\n // Clear uPlot's internal selection immediately so it doesn't block WASD/interaction\n u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);\n }\n },\n ],\n },\n };\n\n // \u2500\u2500 Overlay (pointer-events off except handles) \u2500\u2500\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5';\n\n // Selection fill\n const selFill = document.createElement('div');\n selFill.className = 'sel-fill';\n selFill.style.display = 'none';\n\n // Anchor line + label + drag handle\n const anchorLine = document.createElement('div');\n anchorLine.className = 'sel-line sel-line-anchor';\n anchorLine.style.display = 'none';\n\n const anchorLabel = document.createElement('div');\n anchorLabel.className = 'sel-line-label sel-line-label-anchor';\n anchorLabel.style.display = 'none';\n\n const anchorHandle = document.createElement('div');\n anchorHandle.className = 'sel-handle sel-handle-anchor';\n anchorHandle.style.display = 'none';\n\n const anchorMarker = document.createElement('div');\n anchorMarker.className = 'sel-graph-marker';\n anchorMarker.innerHTML =\n 'play_circle';\n anchorMarker.style.display = 'none';\n\n // End line + label + drag handle\n const endLine = document.createElement('div');\n endLine.className = 'sel-line sel-line-end';\n endLine.style.display = 'none';\n\n const endLabel = document.createElement('div');\n endLabel.className = 'sel-line-label sel-line-label-end';\n endLabel.style.display = 'none';\n\n const endHandle = document.createElement('div');\n endHandle.className = 'sel-handle sel-handle-end';\n endHandle.style.display = 'none';\n\n const endMarker = document.createElement('div');\n endMarker.className = 'sel-graph-marker';\n endMarker.innerHTML =\n 'stop_circle';\n endMarker.style.display = 'none';\n\n // Floating cursor y-value\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${def.color};display:none`;\n\n // Floating pinned y-value\n const pinYVal = document.createElement('div');\n pinYVal.className = 'cur-y-val pin';\n pinYVal.style.cssText = `color:${def.color};display:none`;\n\n overlay.append(\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n );\n\n const histData: HistData = {\n yData,\n xData: xData as number[],\n def,\n BINS: 24,\n min: allCount ? gMin : undefined,\n max: allCount ? gMax : undefined,\n fullStats: fullStatsFiltered,\n fullStatsAll,\n };\n const plot: PlotData = {\n uplot: null as any,\n row,\n xData: xData as number[],\n yData,\n def,\n metricKey,\n statsTotalEl,\n statsSelEl,\n histCol,\n histCanvas,\n histData,\n hoveredHistY: null,\n pinnedHistY: null,\n smoothed: smoothedMetrics.has(metricKey),\n incZero: metricsIncludingZero.has(metricKey),\n w,\n };\n histData.plot = plot; // Back-reference for tooltip to trigger redraws\n\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n const uplot = new uPlot(uOpts, [xData, yData] as any, (self, init) => {\n plot.uplot = self as WegPlot;\n plots.push(plot);\n plotEl.appendChild(self.root);\n self.over.appendChild(overlay);\n (self as any)._strasse = {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n updateHeaderStats,\n };\n self.batch(() => {\n init();\n });\n }) as WegPlot;\n scaleSyncing = prevSync;\n\n // \u2500\u2500 Handle drag \u2500\u2500\n attachHandleDrag(anchorHandle, uplot, xData, true);\n attachHandleDrag(endHandle, uplot, xData, false);\n\n // \u2500\u2500 Mouse listeners \u2500\u2500\n let mousedownX: number | null = null;\n uplot.over.addEventListener('mousedown', (e) => {\n if (e.button !== 0) return;\n isDragging = false;\n const rect = uplot.over.getBoundingClientRect();\n const xPx = e.clientX - rect.left;\n mousedownX = xPx;\n });\n uplot.over.addEventListener('mousemove', (e) => {\n if (mousedownX !== null) {\n const rect = uplot.over.getBoundingClientRect();\n if (Math.abs(e.clientX - rect.left - mousedownX) > 5) isDragging = true;\n }\n });\n uplot.over.addEventListener('mouseup', () => {\n mousedownX = null;\n });\n\n // Click to pin point (sticky selection)\n uplot.over.addEventListener('click', () => {\n if (isDragging) return;\n const idx = uplot.cursor.idx;\n if (idx != null && pts[idx]) {\n pinnedPtIdx = idx;\n plots.forEach(({ uplot: u }) => u.redraw(false));\n if (onClickCb) onClickCb(pts[idx], idx);\n if (onPinChangeCb) onPinChangeCb(idx);\n }\n });\n\n row.addEventListener('dblclick', cancelSelection);\n\n let initHoverBinI: number | null = null;\n if (pinnedPtIdx != null && xData[pinnedPtIdx] != null && yData[pinnedPtIdx] != null) {\n buildHistBins(histData);\n if (histData.min != null && histData.max != null) {\n const span = histData.max - histData.min || 1;\n initHoverBinI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[pinnedPtIdx]! - histData.min) / span) * histData.BINS),\n );\n plot.hoveredHistY = yData[pinnedPtIdx];\n }\n }\n\n drawHistogram(histCanvas, histData, 130, initHoverBinI);\n attachHistTooltip(histCanvas, histData);\n if (container) {\n if (insertBeforeEl) container.insertBefore(row, insertBeforeEl);\n else container.appendChild(row);\n }\n }\n\n // \u2500\u2500 Selection overlay (fill + lines + handles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateSelOverlay() {\n updateAnchorLines();\n // Redraw canvas markers (bold selection line + span pill)\n plots.forEach(({ uplot: u }) => u.batch(() => u.redraw(false)));\n }\n\n function updateAnchorLines() {\n plots.forEach(({ uplot: u, def }) => {\n const s = (u as any)._strasse;\n if (!s) return;\n const {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n } = s;\n if (selAnchorVal == null || selEndVal == null) {\n [\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n ].forEach((el: HTMLElement) => {\n el.style.display = 'none';\n });\n return;\n }\n const aX = u.valToPos(selAnchorVal, 'x');\n const eX = u.valToPos(selEndVal, 'x');\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const overW = bb.width / dpr;\n const overH = bb.height / dpr;\n const plotBottom = (bb.top + bb.height) / dpr;\n\n const isAnchorVisible = aX >= 0 && aX <= overW;\n const isEndVisible = eX >= 0 && eX <= overW;\n\n // Fill: clamp left/right to visible area\n const fillL = Math.max(0, aX);\n const fillR = Math.min(overW, eX);\n if (fillR > fillL) {\n selFill.style.left = `${fillL}px`;\n selFill.style.width = `${fillR - fillL}px`;\n selFill.style.top = '0';\n selFill.style.height = `${overH}px`;\n selFill.style.backgroundColor = hexToRgba(def.color, 0.07);\n selFill.style.display = '';\n } else {\n selFill.style.display = 'none';\n }\n\n // Anchor line\n if (isAnchorVisible) {\n anchorLine.style.left = `${aX}px`;\n anchorLine.style.height = `${overH}px`;\n anchorLine.style.borderLeftColor = def.color;\n anchorLine.style.display = '';\n // Anchor label\n const aText = fmtXVal(selAnchorVal);\n anchorLabel.textContent = aText;\n const aLabelW = aText.length * 7 + 10;\n anchorLabel.style.left = aX + aLabelW + 4 < overW ? `${aX + 3}px` : `${aX - aLabelW - 3}px`;\n anchorLabel.style.display = '';\n // Anchor handle\n anchorHandle.style.left = `${aX}px`;\n anchorHandle.style.backgroundColor = def.color;\n anchorHandle.style.display = '';\n // Anchor marker: centered on the bold line\n anchorMarker.style.left = `${aX}px`;\n anchorMarker.style.top = `${plotBottom}px`;\n const aIcon = anchorMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (aIcon) aIcon.style.color = def.color;\n anchorMarker.style.display = '';\n } else {\n [anchorLine, anchorLabel, anchorHandle, anchorMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n\n // End line\n if (isEndVisible) {\n endLine.style.left = `${eX}px`;\n endLine.style.height = `${overH}px`;\n endLine.style.borderLeftColor = def.color;\n endLine.style.display = '';\n // End label\n const eText = fmtXVal(selEndVal);\n endLabel.textContent = eText;\n const eLabelW = eText.length * 7 + 10;\n endLabel.style.left = eX - eLabelW - 3 > 0 ? `${eX - eLabelW - 3}px` : `${eX + 3}px`;\n endLabel.style.display = '';\n // End handle\n endHandle.style.left = `${eX}px`;\n endHandle.style.backgroundColor = def.color;\n endHandle.style.display = '';\n // End marker: centered on the bold line\n endMarker.style.left = `${eX}px`;\n endMarker.style.top = `${plotBottom}px`;\n const eIcon = endMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (eIcon) eIcon.style.color = def.color;\n endMarker.style.display = '';\n } else {\n [endLine, endLabel, endHandle, endMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n });\n }\n\n function fmtXVal(v: number) {\n return xAxis === 'distance' ? `${v.toFixed(2)} km` : fmtSecs(v);\n }\n\n // \u2500\u2500 Handle drag logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function attachHandleDrag(\n handleEl: HTMLElement,\n uplot: uPlot,\n xData: (number | null)[],\n isAnchor: boolean,\n ) {\n // pointer-events enabled on the handle itself\n handleEl.style.pointerEvents = 'auto';\n\n handleEl.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n const startX = e.clientX;\n const startVal = isAnchor ? selAnchorVal : selEndVal;\n const overW = uplot.over.offsetWidth;\n // px-per-data-unit at current zoom\n const xMin = uplot.scales.x!.min!,\n xMax = uplot.scales.x!.max!;\n const pxPerUnit = overW / (xMax - xMin);\n const xFull = [xData[0]!, xData[xData.length - 1]!];\n\n document.body.style.cursor = 'ew-resize';\n isDragging = true;\n\n function onMove(me: MouseEvent) {\n const dx = me.clientX - startX;\n let newVal = (startVal || 0) + dx / pxPerUnit;\n newVal = Math.max(xFull[0], Math.min(xFull[1], newVal));\n\n if (isAnchor) selAnchorVal = Math.min(newVal, (selEndVal || xFull[1]) - 0.001);\n else selEndVal = Math.max(newVal, (selAnchorVal || xFull[0]) + 0.001);\n\n // When dragging handles, we typically want to stay zoomed to the selection?\n // Actually, let's keep the zoom as is, and just update the selection overlay and stats.\n plots.forEach((p) =>\n (p.uplot as any)._strasse?.updateHeaderStats(\n p.uplot.scales.x!.min!,\n p.uplot.scales.x!.max!,\n ),\n );\n updateSelOverlay();\n redrawHistograms();\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n }\n\n function onUp() {\n document.body.style.cursor = '';\n isDragging = false;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n }\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n }\n\n // \u2500\u2500 Histogram logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function buildHistBins(histData: HistData) {\n const { yData, xData, BINS } = histData;\n\n // Cache to avoid re-binning every frame during hover\n if (histData._lastYData === yData && histData.bins) return;\n histData._lastYData = yData;\n\n let min = histData.min;\n let max = histData.max;\n if (min == null || max == null) {\n let lo = Infinity,\n hi = -Infinity,\n cnt = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < lo) lo = v;\n if (v > hi) hi = v;\n cnt++;\n }\n if (!cnt) return;\n min = lo;\n max = hi;\n histData.min = min;\n histData.max = max;\n }\n\n const bins = new Array(BINS).fill(0);\n const binAccum = new Array(BINS).fill(0); // accumulated x-weight per bin (time in s or dist in km)\n\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n bins[bi]++;\n\n // weight by x-delta\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n binAccum[bi] += (next - prev) / 2;\n }\n histData.bins = bins;\n histData.binAccum = binAccum;\n }\n\n function redrawHistograms() {\n plots.forEach(({ histCanvas, histData, uplot: u }) => {\n drawHistogram(histCanvas, histData, u.height);\n });\n }\n\n function drawHistogram(\n canvas: HTMLCanvasElement,\n histData: HistData,\n chartH: number,\n hoverBinI: number | null = null,\n ) {\n const { def, BINS } = histData;\n buildHistBins(histData);\n const { bins, min, max } = histData;\n if (!bins || min == null || max == null) return;\n\n const hasSel = selAnchorVal != null && selEndVal != null;\n\n // Compute selection bins if a range is active and changed\n if (\n hasSel &&\n (histData._lastSelRange?.[0] !== selAnchorVal || histData._lastSelRange?.[1] !== selEndVal)\n ) {\n histData._lastSelRange = [selAnchorVal!, selEndVal!];\n const selBins = new Array(BINS).fill(0);\n const selBinAccum = new Array(BINS).fill(0);\n const { yData, xData } = histData;\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const x = xData[i];\n if (x == null || x < selAnchorVal! || x > selEndVal!) continue;\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n selBins[bi]++;\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n selBinAccum[bi] += (next - prev) / 2;\n }\n histData.selBins = selBins;\n histData.selBinAccum = selBinAccum;\n } else if (!hasSel) {\n histData.selBins = null;\n histData.selBinAccum = null;\n histData._lastSelRange = null;\n }\n const selBins = histData.selBins;\n\n const dpr = window.devicePixelRatio || 1;\n const W = HIST_W;\n const H = chartH;\n\n // Performance: only set dimensions if they changed (resets canvas)\n if (canvas.width !== W * dpr || canvas.height !== H * dpr) {\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n }\n\n const ctx = canvas.getContext('2d')!;\n ctx.resetTransform();\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, W, H);\n\n const peak = Math.max(...bins);\n\n // Measure label width so bars start right after them\n const fmt = (v: number) => def.fmtAxis(v);\n const fontStr = '9px system-ui, sans-serif';\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const labelW = Math.ceil(\n Math.max(\n ctx.measureText(`${fmt(max)} ${def.unit}`).width,\n ctx.measureText(`${fmt(min)} ${def.unit}`).width,\n ),\n );\n\n // Vertical alignment with main graph:\n // uPlot padding: [4, 0, 0, 0]\n // Axis size: 30\n const pad = { t: 4, r: 0, b: 30, l: labelW + 6 };\n histData.padL = pad.l;\n const plotW = W - pad.l - pad.r;\n const plotH = H - pad.t - pad.b;\n\n // bin 0 = lowest values \u2192 drawn at bottom; bin BINS-1 = highest \u2192 drawn at top\n const binY = (i: number) => pad.t + (BINS - 1 - i) * (plotH / BINS);\n const binH = plotH / BINS - 1;\n\n // Full distribution (dimmed when selection active)\n const baseAlpha = hasSel ? 0.15 : 0.6;\n ctx.fillStyle = hexToRgba(def.color, baseAlpha);\n for (let i = 0; i < BINS; i++) {\n if (!bins[i]) continue;\n const bw = (bins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n\n // Selection overlay (bright)\n if (selBins) {\n ctx.fillStyle = hexToRgba(def.color, 0.85);\n for (let i = 0; i < BINS; i++) {\n if (!selBins[i]) continue;\n const bw = (selBins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n ctx.fillStyle = def.color;\n ctx.fillRect(pad.l, pad.t, 2, plotH);\n }\n\n // CDF overlay \u2014 smooth curve from bottom (0%) to top (100%)\n const total = bins.reduce((s, v) => s + v, 0);\n if (total > 0) {\n // Build CDF points: one per bin boundary, bottom\u2192top\n const pts2 = [{ x: pad.l, y: pad.t + plotH }];\n let cumSum = 0;\n for (let i = 0; i < BINS; i++) {\n cumSum += bins[i];\n pts2.push({ x: pad.l + (cumSum / total) * plotW, y: binY(i) });\n }\n\n ctx.beginPath();\n // CDF line is now solid\n ctx.setLineDash([]);\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 0.75 * dpr;\n ctx.lineJoin = 'round';\n ctx.moveTo(pts2[0].x, pts2[0].y);\n for (let i = 1; i < pts2.length - 1; i++) {\n const mx = (pts2[i].x + pts2[i + 1].x) / 2;\n const my = (pts2[i].y + pts2[i + 1].y) / 2;\n ctx.quadraticCurveTo(pts2[i].x, pts2[i].y, mx, my);\n }\n ctx.lineTo(pts2[pts2.length - 1].x, pts2[pts2.length - 1].y);\n ctx.stroke();\n\n // \u2500\u2500 Hover highlight on CDF \u2500\u2500\n if (hoverBinI != null && pts2[hoverBinI + 1]) {\n const cp = pts2[hoverBinI + 1];\n // Vertical line down\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(def.color, 0.6);\n ctx.moveTo(cp.x, cp.y);\n ctx.lineTo(cp.x, pad.t + plotH);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Dot: tiny precision point\n ctx.beginPath();\n ctx.arc(cp.x, cp.y, 1.2 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n }\n\n // Axis labels: max at top, min at bottom\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n const font9 = '9px system-ui, sans-serif';\n if (ctx.font !== font9) ctx.font = font9;\n ctx.textAlign = 'right';\n\n // Draw Max\n ctx.textBaseline = 'top';\n ctx.fillText(`${fmt(max)} ${def.unit}`, pad.l - 4, pad.t);\n\n // Draw Min\n ctx.textBaseline = 'bottom';\n ctx.fillText(`${fmt(min)} ${def.unit}`, pad.l - 4, H - pad.b);\n\n // Draw Avg (only if it doesn't overlap min/max)\n const stats =\n !hasSel && histData.fullStatsAll !== undefined\n ? histData.fullStatsAll\n : rangeStats(\n histData.xData,\n histData.yData,\n selAnchorVal || -Infinity,\n selEndVal || Infinity,\n );\n if (stats) {\n const avgY =\n pad.t +\n (BINS - 1 - Math.min(BINS - 1, Math.floor(((stats.avg - min) / (max - min || 1)) * BINS))) *\n (plotH / BINS);\n const minLabelY = H - pad.b;\n const maxLabelY = pad.t;\n const labelHeight = 10; // Approx 10px height for 9px font\n\n if (avgY > maxLabelY + labelHeight + 2 && avgY < minLabelY - labelHeight - 2) {\n ctx.textBaseline = 'middle';\n if (ctx.fillStyle !== '#aaa') ctx.fillStyle = '#aaa';\n ctx.fillText(`${fmt(stats.avg)} ${def.unit}`, pad.l - 4, avgY);\n // Draw small indicator tick\n ctx.beginPath();\n ctx.moveTo(pad.l - 3, avgY);\n ctx.lineTo(pad.l, avgY);\n if (ctx.strokeStyle !== '#aaa') ctx.strokeStyle = '#aaa';\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n }\n\n // \u2500\u2500 Higher/Lower percentages below histogram \u2500\u2500\n if (hoverBinI != null && total > 0) {\n let countLower = 0;\n for (let i = 0; i < hoverBinI; i++) countLower += bins[i];\n let countHigher = 0;\n for (let i = hoverBinI + 1; i < BINS; i++) countHigher += bins[i];\n\n const pLower = Math.round((countLower / total) * 100);\n const pHigher = Math.round((countHigher / total) * 100);\n\n ctx.save();\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const font8 = '8px system-ui, sans-serif';\n if (ctx.font !== font8) ctx.font = font8;\n\n const textY = H - pad.b + 6;\n\n // Draw \"Lower\" stat\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('LOWER', pad.l, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n const fontB10 = 'bold 10px system-ui, sans-serif';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pLower}%`, pad.l, textY + 10);\n\n // Draw \"Higher\" stat\n const midX = pad.l + plotW / 2;\n if (ctx.font !== font8) ctx.font = font8;\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('HIGHER', midX, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pHigher}%`, midX, textY + 10);\n\n ctx.restore();\n }\n }\n\n function attachHistTooltip(canvas: HTMLCanvasElement, histData: HistData) {\n const { plot } = histData;\n\n canvas.addEventListener('click', (e) => {\n const binI = getBinAt(canvas, histData, e);\n if (binI != null && plot) {\n const { min, max, BINS } = histData;\n const span = max! - min! || 1;\n plot.pinnedHistY = min! + (binI + 0.5) * (span / BINS!);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n }\n });\n\n canvas.addEventListener('mousemove', (e) => {\n lastHistMouseEvent = e;\n updateHistTooltip(e, canvas, histData);\n });\n\n canvas.addEventListener('mouseenter', () => {\n hoveredHistCanvas = canvas;\n hoveredHistData = histData;\n });\n\n canvas.addEventListener('mouseleave', () => {\n if (hoveredHistCanvas === canvas) {\n hoveredHistCanvas = null;\n hoveredHistData = null;\n }\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const lineEl = document.getElementById('hist-line');\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n });\n }\n\n function getBinAt(canvas: HTMLCanvasElement, histData: HistData, e: MouseEvent) {\n const { bins, BINS } = histData;\n if (!bins) return null;\n const rect = canvas.getBoundingClientRect();\n const relY = e.clientY - rect.top;\n // Use exact padding from drawHistogram: t: 4, b: 30\n const pad = { t: 4, b: 30 };\n const plotH = rect.height - pad.t - pad.b;\n const rawI = Math.floor(((relY - pad.t) / plotH) * BINS!);\n const binI = BINS! - 1 - rawI;\n if (rawI < 0 || rawI >= BINS!) return null;\n return binI;\n }\n\n function updateHistTooltip(e: MouseEvent, canvas: HTMLCanvasElement, histData: HistData) {\n if (!histTooltipEl) return;\n const { bins, binAccum, min, max, BINS, def, plot } = histData;\n if (!bins || !binAccum || min == null || max == null) return;\n\n const lineEl = document.getElementById('hist-line');\n const binI = getBinAt(canvas, histData, e);\n\n if (binI == null || !bins[binI]) {\n histTooltipEl.style.display = 'none';\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n return;\n }\n\n if (plot) {\n const span = max - min || 1;\n plot.hoveredHistY = min + (binI + 0.5) * (span / BINS!);\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1), binI);\n }\n\n const count = bins[binI];\n const total = bins.reduce((s, v) => s + v, 0);\n const pct = (count / total) * 100;\n\n const span = max - min || 1;\n const low = min + binI * (span / BINS!);\n const high = min + (binI + 1) * (span / BINS!);\n const label = `${def.fmt(low, true)} \u2013 ${def.fmt(high, true)} ${def.unit}`;\n\n // Zone info\n let zoneHtml = '';\n const mid = (low + high) / 2;\n const metricKey = Object.keys(METRICS).find((k) => METRICS[k] === def);\n let zones: any[] = [];\n if (metricKey === 'power') zones = Zones.getPowerZones();\n else if (metricKey === 'hr') zones = Zones.getHRZones();\n\n if (zones.length > 0) {\n const zIdx = zones.findIndex((z) => mid >= z.min && mid < z.max);\n const z =\n zIdx !== -1\n ? zones[zIdx]\n : mid >= zones[zones.length - 1].min\n ? zones[zones.length - 1]\n : null;\n if (z) {\n const finalZIdx = zIdx !== -1 ? zIdx : zones.length - 1;\n zoneHtml = `\n
\n Z${finalZIdx + 1}\n \u00B7\n ${z.name}\n
\n `;\n }\n }\n\n const totalAccum =\n xAxis === 'distance' ? `${binAccum[binI].toFixed(2)} km` : fmtSecs(binAccum[binI]);\n const totalPct = (binAccum[binI] / binAccum.reduce((s, v) => s + v, 0)) * 100;\n\n let html = `\n
${label}
\n ${zoneHtml}\n `;\n\n if (totalAccum) {\n html += `
\n ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${totalAccum}\n ${totalPct.toFixed(1)}%\n
`;\n }\n\n // Selection context\n if (histData.selBins && histData.selBinAccum) {\n const stotalAccum =\n xAxis === 'distance'\n ? `${histData.selBinAccum[binI].toFixed(2)} km`\n : fmtSecs(histData.selBinAccum[binI]);\n const stotalPct =\n (histData.selBinAccum[binI] / histData.selBinAccum.reduce((s, v) => s + v, 0)) * 100;\n\n html += `\n
\n Sel ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${stotalAccum}\n ${stotalPct.toFixed(1)}%\n
\n `;\n }\n\n histTooltipEl.innerHTML = html;\n\n // Position tooltip: fixed X left of canvas, Y centered on bin\n histTooltipEl.style.display = 'block';\n const ttH = histTooltipEl.offsetHeight;\n const ttW = histTooltipEl.offsetWidth;\n const rect = canvas.getBoundingClientRect();\n const plotH = rect.height - 4 - 30; // pad.t + pad.b\n const binCenterY = rect.top + 4 + (BINS! - 1 - binI + 0.5) * (plotH / BINS!);\n\n histTooltipEl.style.left = `${rect.left - ttW - 12}px`;\n histTooltipEl.style.top = `${binCenterY - ttH / 2}px`;\n\n // Horizontal line sync\n if (lineEl) {\n lineEl.style.display = 'block';\n lineEl.style.top = `${binCenterY}px`;\n lineEl.style.left = '0px';\n lineEl.style.width = `${rect.left}px`;\n }\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function destroyPlots(keepState = false) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n plots.forEach(({ uplot: u, row }) => {\n syncKey!.unsub(u);\n u.destroy();\n row.remove();\n });\n plots = [];\n renderedTrack = null;\n if (!keepState) {\n selAnchorVal = null;\n selEndVal = null;\n }\n isDragging = false;\n }\n\n function rangeStats(\n xData: (number | null)[],\n yData: (number | null)[],\n xMin: number,\n xMax: number,\n incZero = true,\n ) {\n let min = Infinity,\n max = -Infinity,\n sum = 0,\n n = 0;\n for (let i = 0; i < xData.length; i++) {\n if (xData[i] == null || xData[i]! < xMin || xData[i]! > xMax) continue;\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n if (v < min) min = v;\n if (v > max) max = v;\n sum += v;\n n++;\n }\n return n ? { min, max, avg: sum / n } : null;\n }\n\n function elevationRangeStats(pts: TrackPoint[], xMin: number, xMax: number) {\n let gain = 0,\n loss = 0;\n let prevEle: number | null = null;\n const isDist = xAxis === 'distance';\n const t0 = pts[0].time || 0;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const x = isDist ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n if (x < xMin || x > xMax) continue;\n\n if (p.ele != null) {\n if (prevEle != null) {\n const diff = p.ele - prevEle;\n if (diff > 0) gain += diff;\n else if (diff < 0) loss += Math.abs(diff);\n }\n prevEle = p.ele;\n }\n }\n return { gain, loss };\n }\n\n // \u2500\u2500 Plot Rendering Helpers (Canvas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateTooltip(\n u: WegPlot,\n el: HTMLElement,\n idx: number,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n def: MetricDefinition,\n metricKey: string,\n ) {\n if (idx == null || yData[idx] == null) {\n el.style.display = 'none';\n return;\n }\n\n const cx = u.valToPos(xData[idx]!, 'x', false);\n const cy = u.valToPos(yData[idx]!, 'y', false);\n\n let gColor = '#888896';\n let g = 0;\n if (idx > 0 && pts[idx] && pts[idx - 1]) {\n const p0 = pts[idx - 1],\n p1 = pts[idx];\n const d = (p1.dist || 0) - (p0.dist || 0);\n if (d > 0.1 && p1.ele != null && p0.ele != null) {\n g = ((p1.ele - p0.ele) / d) * 100;\n gColor = gradientColor(g);\n }\n }\n\n let content =\n metricKey !== 'elevation'\n ? `${def.fmt(yData[idx]!, false)} ${def.unit}`\n : `${def.fmt(yData[idx]!, false)} ${def.unit} \u2220 ${Math.abs(g).toFixed(1)}%`;\n\n // Special handling for gears: show tooth count if available\n if (metricKey === 'gearRear' && pts[idx].gearRearTooth != null) {\n content = `${pts[idx].gearRearTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gearFront' && pts[idx].gearFrontTooth != null) {\n content = `${pts[idx].gearFrontTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gears') {\n const p = pts[idx];\n const front =\n p.gearFrontTooth != null\n ? `${p.gearFrontTooth}T`\n : p.gearFront != null\n ? `pos ${p.gearFront}`\n : '';\n const rear =\n p.gearRearTooth != null\n ? `${p.gearRearTooth}T`\n : p.gearRear != null\n ? `pos ${p.gearRear}`\n : '';\n\n if (front || rear)\n content += ` (${front} / ${rear})`;\n }\n\n if (el.innerHTML !== content) el.innerHTML = content;\n\n const color44 = `${def.color}44`;\n if (el.style.color !== def.color) el.style.color = def.color;\n if (el.style.borderColor !== color44) el.style.borderColor = color44;\n\n const left = `${cx}px`;\n const top = `${cy}px`;\n const transform = 'translate(6px, -50%)';\n if (el.style.left !== left) el.style.left = left;\n if (el.style.top !== top) el.style.top = top;\n if (el.style.transform !== transform) el.style.transform = transform;\n if (el.style.display !== '') el.style.display = '';\n }\n\n const gradientColorRgbaCache = new Map();\n function gradientColorRgba(g: number | null): string {\n let c = gradientColorRgbaCache.get(g);\n if (!c) {\n c = hexToRgba(gradientColor(g), 0.8);\n gradientColorRgbaCache.set(g, c);\n }\n return c;\n }\n\n function drawElevationGradient(\n u: uPlot,\n xData: number[],\n yData: number[],\n gradData: (number | null)[] | null,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = gradData && gradData[i] != null ? Math.round(gradData[i]! / 2) * 2 : null;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawGradientChart(u: uPlot, xData: number[], yData: number[]) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = Math.round(yData[i]! / 2) * 2;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawHoverLine(u: uPlot, yData: number[], color: string, pts: TrackPoint[]) {\n const idx = u.cursor.idx;\n if (idx == null || yData[idx] == null || u.cursor.left! < 0) return;\n\n const t0 = pts[0].time || 0;\n const xVal = xAxis === 'distance' ? (pts[idx].dist || 0) / 1000 : (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yData[idx], 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Line from top to point + horizontal from left\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, cy);\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Dot at point\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n\n function drawVerticalLineOnly(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const xVal =\n xAxis === 'distance'\n ? (pts[idx].dist || 0) / 1000\n : (pts[idx].time! - (pts[0].time || 0)) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n // Dotted line range should match where labels are (flush top to bottom axis)\n ctx.moveTo(cx, bb.top + 16 * dpr);\n ctx.lineTo(cx, bb.top + bb.height + 10 * dpr);\n ctx.stroke();\n ctx.restore();\n }\n\n function drawXAxisLabels(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n skipLine = false,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const t0 = pts[0].time || 0;\n const distVal = (pts[idx].dist || 0) / 1000;\n const timeVal = (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xAxis === 'distance' ? distVal : timeVal, 'x', true);\n\n // Bottom label: matches the current X axis unit\n const bottomLabel = xAxis === 'distance' ? `${distVal.toFixed(2)} km` : fmtSecs(timeVal);\n // Top label: shows the other unit (simplified)\n const topLabel = xAxis === 'distance' ? fmtSecs(timeVal) : `${distVal.toFixed(2)} km`;\n\n const drawPill = (text: string, x: number, y: number, isTop: boolean) => {\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(text).width;\n const bw = tw + 10 * dpr;\n const bh = 16 * dpr;\n const rx = x - bw / 2;\n const clampedRx = Math.max(bb.left, Math.min(bb.left + bb.width - bw, rx));\n const ry = y - bh / 2;\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.setLineDash([]); // Ensure pills are not dashed\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(clampedRx, ry, bw, bh, 3 * dpr);\n else ctx.rect(clampedRx, ry, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.92)';\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, clampedRx + bw / 2, ry + bh / 2 + 0.5 * dpr);\n ctx.restore();\n };\n\n if (!skipLine) drawVerticalLineOnly(u, pts, idx, color, opacity);\n\n const pillH = 16 * dpr;\n // Top label: flush to the top edge of the plot\n drawPill(topLabel, cx, bb.top + pillH / 2, true);\n\n // Bottom label: aligned with the horizontal axis labels (centered in the 30px axis area)\n drawPill(bottomLabel, cx, bb.top + bb.height + 15 * dpr, false);\n }\n\n function drawPinnedDot(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n def: MetricDefinition,\n pts: TrackPoint[],\n metricKey: string,\n ) {\n if (pinnedPtIdx == null) return;\n const xVal = xData[pinnedPtIdx];\n const yVal = yData[pinnedPtIdx];\n if (xVal == null || yVal == null) return;\n\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n ctx.save();\n // Vertical line\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, bb.top + bb.height);\n ctx.stroke();\n\n // Horizontal dashed line\n ctx.beginPath();\n ctx.setLineDash([3 * dpr, 3 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.5);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Large Dot\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 5 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2.5 * dpr;\n ctx.stroke();\n ctx.restore();\n\n const s = (u as any)._strasse;\n if (s && s.pinYVal) {\n updateTooltip(\n u,\n s.pinYVal,\n pinnedPtIdx,\n xData as number[],\n yData as (number | null)[],\n pts,\n def,\n metricKey,\n );\n }\n }\n\n function drawYAxisHighlight(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n yVal: number,\n color: string,\n def: MetricDefinition,\n ) {\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const cy = u.valToPos(yVal, 'y', true);\n\n // Clamp cy to bbox\n const cyClamp = Math.max(bb.top, Math.min(bb.top + bb.height, cy));\n\n ctx.save();\n // Horizontal line\n ctx.beginPath();\n ctx.setLineDash([4 * dpr, 4 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cyClamp);\n ctx.lineTo(bb.left + bb.width, cyClamp);\n ctx.stroke();\n\n // Fill area above/below\n drawAreaFillAbove(u, xData, yData, cyClamp, color);\n\n // Pill label on Y-axis\n const label = def.fmt(yVal, true);\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n const bw = tw + 8 * dpr;\n const bh = 16 * dpr;\n const bx = bb.left - bw - 2 * dpr;\n const by = cyClamp - bh / 2;\n\n ctx.beginPath();\n ctx.setLineDash([]);\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.95)';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = '#fff';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2 + 0.5 * dpr);\n ctx.restore();\n }\n\n function drawAreaFillAbove(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n cyClamp: number,\n color: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.beginPath();\n\n let inSegment = false;\n let hasAnySegment = false;\n let lastPx = 0;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null || xv < xMin || xv > xMax) {\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n lastPx = px;\n\n if (py < cyClamp) {\n if (!inSegment) {\n ctx.moveTo(px, cyClamp);\n inSegment = true;\n hasAnySegment = true;\n }\n ctx.lineTo(px, py);\n } else if (inSegment) {\n ctx.lineTo(px, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n }\n\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n }\n\n if (hasAnySegment) {\n ctx.fill();\n }\n\n ctx.restore();\n }\n\n // \u2500\u2500 Utils \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function lerpHex(a: string, b: string, t: number) {\n const ah = parseInt(a.slice(1), 16),\n bh = parseInt(b.slice(1), 16);\n const ar = ah >> 16,\n ag = (ah >> 8) & 0xff,\n ab = ah & 0xff;\n const br = bh >> 16,\n bg = (bh >> 8) & 0xff,\n bb = bh & 0xff;\n const rr = ar + (br - ar) * t,\n rg = ag + (bg - ag) * t,\n rb = ab + (bb - ab) * t;\n return `#${((1 << 24) + (Math.round(rr) << 16) + (Math.round(rg) << 8) + Math.round(rb))\n .toString(16)\n .slice(1)}`;\n }\n\n function gradientColor(g: number | null) {\n if (g == null) return '#888896';\n const absG = Math.abs(g);\n const t = Math.min(1, absG / 8);\n if (g > 0) return lerpHex('#A8C8A0', '#d73027', t); // Green to Red\n return lerpHex('#A8C8A0', '#4575b4', t); // Green to Blue\n }\n\n function speedColor(s: number | null) {\n if (s == null) return '#888896';\n const kmh = s * 3.6;\n\n if (kmh <= 5) return '#4575b4'; // Solid Blue for very slow\n if (kmh >= 60) return '#d73027'; // Solid Red for very fast\n\n // High resolution between 5 and 45 (10km/h per segment)\n if (kmh <= 45) {\n const t = (kmh - 5) / 40; // 0 to 1\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); // 5-15: Blue -> LBlue\n if (t <= 0.5) return lerpHex('#91bfdb', '#abdda4', (t - 0.25) / 0.25); // 15-25: LBlue -> Green\n if (t <= 0.75) return lerpHex('#abdda4', '#fee08b', (t - 0.5) / 0.25); // 25-35: Green -> Yellow\n return lerpHex('#fee08b', '#fc8d59', (t - 0.75) / 0.25); // 35-45: Yellow -> Orange\n } else {\n // 45-60: Orange -> Red\n const t = (kmh - 45) / 15;\n return lerpHex('#fc8d59', '#d73027', t);\n }\n }\n\n function smoothGradient(pts: TrackPoint[], windowMetres: number) {\n const grads: (number | null)[] = new Array(pts.length).fill(null);\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n let j0 = i,\n j1 = i;\n while (j0 > 0 && (p.dist || 0) - (pts[j0].dist || 0) < windowMetres / 2) j0--;\n while (j1 < pts.length - 1 && (pts[j1].dist || 0) - (p.dist || 0) < windowMetres / 2) j1++;\n const d = (pts[j1].dist || 0) - (pts[j0].dist || 0);\n if (d > 1 && pts[j1].ele != null && pts[j0].ele != null)\n grads[i] = ((pts[j1].ele! - pts[j0].ele!) / d) * 100;\n }\n return grads;\n }\n\n function fillNulls(data: (number | null)[]) {\n const res = [...data];\n for (let i = 0; i < res.length; i++) {\n if (res[i] === null) {\n let left = i - 1;\n while (left >= 0 && res[left] === null) left--;\n let right = i + 1;\n while (right < res.length && res[right] === null) right++;\n if (left >= 0 && right < res.length)\n res[i] = res[left]! + ((res[right]! - res[left]!) * (i - left)) / (right - left);\n else if (left >= 0) res[i] = res[left];\n else if (right < res.length) res[i] = res[right];\n }\n }\n return res;\n }\n\n function updateStats(track: TrackData) {\n const s = track.stats;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt('stat-distance', s.totalDist != null ? `${(s.totalDist / 1000).toFixed(1)} km` : '\u2014');\n fmt('stat-duration', s.duration != null ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014');\n fmt('stat-elevation', s.elevGain != null ? `${Math.round(s.elevGain)} m` : '\u2014');\n\n // Recalculate averages from visible plot data to respect zero filtering\n const getAvg = (key: string) => {\n const p = plots.find((p) => p.metricKey === key);\n if (!p) {\n if (key === 'speed') return s.avgSpeed ?? null;\n if (key === 'power') return s.avgPower ?? null;\n if (key === 'cadence') return s.avgCadence ?? null;\n return null;\n }\n if (p.histData.fullStats !== undefined) {\n return p.histData.fullStats ? p.histData.fullStats.avg : null;\n }\n const incZero =\n metricsIncludingZero.has(key) || (key !== 'power' && key !== 'cadence' && key !== 'speed');\n const vals = p.yData.filter((v): v is number => v != null && (incZero || v !== 0));\n if (!vals.length) return null;\n return vals.reduce((a, b) => a + b, 0) / vals.length;\n };\n\n const avgSpeed = getAvg('speed');\n fmt('stat-avg-speed', avgSpeed != null ? `${(avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014');\n\n const avgPower = getAvg('power');\n fmt('stat-avg-power', avgPower != null ? `${Math.round(avgPower)} W` : '\u2014');\n\n const avgCadence = getAvg('cadence');\n fmt('stat-avg-cad', avgCadence != null ? `${Math.round(avgCadence)} rpm` : '\u2014');\n\n fmt('stat-avg-hr', s.avgHR != null ? `${s.avgHR} bpm` : '\u2014');\n fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n }\n\n return {\n init,\n loadTrack,\n clear,\n resetState,\n toggleMetric,\n setXAxis,\n toggleStats,\n setSelectionStats,\n clearSelectionStats,\n restoreSelection,\n resetZoom,\n cancelSelection,\n setCursorAt: (idx: number, deferRender = false) => {\n pinnedPtIdx = idx;\n if (onPinChangeCb) onPinChangeCb(idx);\n if (deferRender) {\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n return;\n }\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n },\n setHoverAt: (idx: number | null) => {\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (idx === null) {\n u.batch(() => {\n (u as any).setCursor({ left: -10, top: -10 }, true, false);\n });\n } else if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb) {\n onCursorMoveCb(\n idx != null && currentTrack?.points?.[idx] ? currentTrack.points[idx] : null,\n );\n }\n },\n clearPinnedDot: () => {\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n },\n resize,\n METRICS,\n isDragging: () => isDragging,\n setMapColorChangeCb,\n toggleMapColor,\n getMapColorMetric: () => mapColorMetric,\n getActiveMetrics: () => activeMetrics,\n getAvailableMetrics: () => availableMetrics,\n setActiveMetrics,\n updateMetricOrder: (keys: string[]) => {\n // Keys might only contain current active ones, or more.\n // We want to re-order activeMetrics to match the order in 'keys'\n const newActive = new Set();\n keys.forEach((k) => {\n if (activeMetrics.has(k)) newActive.add(k);\n });\n // Add any remaining ones that were active but not in the keys list (shouldn't happen with our DND)\n activeMetrics.forEach((k) => {\n if (!newActive.has(k)) newActive.add(k);\n });\n activeMetrics = newActive;\n if (currentTrack) render(true);\n },\n getXAxis: () => xAxis,\n };\n\n function drawMetricColorFill(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n metricKey: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const colors = _computePointColors(metricKey, yData);\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (let i = 1; i < xData.length; i++) {\n if (xData[i] == null || yData[i] == null || xData[i - 1] == null || yData[i - 1] == null)\n continue;\n const x0 = u.valToPos(xData[i - 1]!, 'x', true);\n const y0 = u.valToPos(yData[i - 1]!, 'y', true);\n const x1 = u.valToPos(xData[i]!, 'x', true);\n const y1 = u.valToPos(yData[i]!, 'y', true);\n\n const c = colors[i];\n\n // Top line segment\n ctx.beginPath();\n ctx.moveTo(x0, y0);\n if (isStepped) ctx.lineTo(x1, y0);\n\n ctx.lineTo(x1, y1);\n ctx.strokeStyle = c;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawBackgroundTracks(u: uPlot, metricKey: string, def: MetricDefinition) {\n if (!allTracks.length) return;\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (const track of allTracks) {\n if (currentTrack && track.id === currentTrack.id) continue;\n\n const pts = track.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const field = def.field;\n\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)'; // Extremely faint\n ctx.lineWidth = 1 * dpr;\n\n let first = true;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const v = p[field] as number;\n\n if (v == null) {\n first = true;\n continue;\n }\n\n if (i > 0) {\n const prev = pts[i - 1];\n const dt = p.time && prev.time ? p.time - prev.time : 0;\n if (dt > GAP_THRESHOLD) first = true;\n }\n\n const val = def.transform ? def.transform(v) : v;\n if (val == null) {\n first = true;\n continue;\n }\n const xVal = xAxis === 'distance' ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n\n // Skip if way outside horizontal range\n if (xVal < u.scales.x!.min! - 10 || xVal > u.scales.x!.max! + 10) {\n first = true;\n continue;\n }\n\n const px = u.valToPos(xVal, 'x', true);\n const py = u.valToPos(val, 'y', true);\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevP = pts[i - 1];\n const prevXVal =\n xAxis === 'distance' ? (prevP.dist || 0) / 1000 : (prevP.time! - t0) / 1000;\n ctx.lineTo(u.valToPos(prevXVal, 'x', true), py);\n }\n ctx.lineTo(px, py);\n }\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawTrackPath(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n width: number,\n metricKey: string,\n range: [number, number] | null = null,\n pts: TrackPoint[] = [],\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = hexToRgba(color, 0.8);\n ctx.lineWidth = width * dpr;\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n let first = true;\n let lastFrontGear: number | null = null;\n let fMin = 1;\n let fMax = 1;\n\n if (metricKey === 'gears' && pts.length > 0) {\n let lo = Infinity,\n hi = -Infinity;\n for (let i = 0; i < pts.length; i++) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null) {\n if (fg < lo) lo = fg;\n if (fg > hi) hi = fg;\n }\n }\n if (lo <= hi) {\n fMin = lo;\n fMax = hi;\n }\n }\n\n const rMin = range ? range[0] : (u.scales.x?.min ?? -Infinity);\n const rMax = range ? range[1] : (u.scales.x?.max ?? Infinity);\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = !range ? u.series[0]?.idxs : null;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step =\n isStepped || metricKey === 'gears' ? 1 : Math.max(1, Math.floor((iEnd - iStart) / 250));\n const isTimeAxis = xAxis === 'time';\n const gapSec = GAP_THRESHOLD / 1000;\n let prevDrawnI = iStart;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null) {\n first = true;\n continue;\n }\n\n if (metricKey === 'gears' && pts[i]) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null && fg !== lastFrontGear) {\n if (!first && i > 0) {\n ctx.stroke();\n ctx.beginPath();\n const prevX = bb.left + (xData[prevDrawnI]! - xMin) * xScale;\n const prevY = yBase + (yData[prevDrawnI]! - yMin) * yMult;\n ctx.moveTo(prevX, prevY);\n }\n\n // Compute color\n let segmentColor = color;\n if (fMax !== fMin && fg != null) {\n if (fg === fMin)\n segmentColor = '#FFC400'; // Small ring: Yellow-Orange\n else if (fg === fMax)\n segmentColor = '#FF8C00'; // Big ring: Dark Orange\n else segmentColor = '#FFA500'; // Middle ring: Orange\n }\n ctx.strokeStyle = hexToRgba(segmentColor, 0.8);\n lastFrontGear = fg;\n }\n }\n\n // Check gap\n if (i > iStart && isTimeAxis) {\n const prevXv = xData[prevDrawnI];\n if (prevXv != null && xv - prevXv > gapSec) first = true;\n }\n\n // Check range (or visible x-scale bounds)\n if (xv < rMin || xv > rMax) {\n first = true;\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevXv = xData[prevDrawnI]!;\n ctx.lineTo(bb.left + (prevXv - xMin) * xScale, py);\n }\n ctx.lineTo(px, py);\n }\n prevDrawnI = i;\n }\n ctx.stroke();\n ctx.restore();\n }\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { Parsers } from './parsers';\n\nexport interface ZoneRange {\n name: string;\n min: number;\n max: number;\n color: string;\n}\n\nexport const Zones = (() => {\n function getPowerZones(): ZoneRange[] {\n const ftp = Parsers.getFTP();\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n const names = [\n 'Active Recovery',\n 'Endurance',\n 'Tempo',\n 'Threshold',\n 'VO2 Max',\n 'Anaerobic',\n 'Neuromuscular',\n ];\n const colors = ['#82E0AA', '#A8C8A0', '#F7DC6F', '#F8C471', '#F39C12', '#E67E22', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[6], min: last, max: Infinity, color: colors[6] });\n return zones;\n }\n\n function getHRZones(): ZoneRange[] {\n const thresholds = Parsers.getHRZones();\n const names = ['Recovery', 'Aerobic', 'Tempo', 'Threshold', 'Anaerobic'];\n const colors = ['#82E0AA', '#F7DC6F', '#F8C471', '#FF6B6B', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[4], min: last, max: Infinity, color: colors[4] });\n return zones;\n }\n\n return {\n getPowerZones,\n getHRZones,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackPoint } from './parsers';\n\nexport interface MetricDefinition {\n label: string;\n field: keyof TrackPoint;\n unit: string;\n color: string;\n abbr: string;\n icon: string;\n fmt: (v: number, precise?: boolean) => string;\n fmtAxis: (v: number) => string;\n compute?: (\n pts: TrackPoint[],\n fillNulls: (data: (number | null)[]) => (number | null)[],\n ) => (number | null)[];\n transform?: (v: number) => number | null;\n smoothSigma?: number;\n}\n\nexport const Metrics = {\n speed: { name: 'Speed', color: '#45B7D1', icon: 'speed' },\n gradient: { name: 'Gradient', color: '#A8C8A0', icon: 'trending_up' },\n power: { name: 'Power', color: '#F7DC6F', icon: 'bolt' },\n hr: { name: 'Heart Rate', color: '#FF6B6B', icon: 'favorite' },\n cadence: { name: 'Cadence', color: '#BB8FCE', icon: 'directions_run' },\n temperature: { name: 'Temperature', color: '#F8C471', icon: 'thermostat' },\n elevation: { name: 'Elevation', color: '#4ECDC4', icon: 'terrain' },\n distance: { name: 'Distance', color: '#9f1bfdff', icon: 'arrow_range' },\n gearRear: { name: 'Rear Gear', color: '#82E0AA', icon: 'settings' },\n gearFront: { name: 'Front Gear', color: '#A8C8A0', icon: 'settings_input_component' },\n gears: { name: 'Gears', color: '#FF8C00', icon: 'settings' },\n battery: { name: 'Battery', color: '#45B7D1', icon: 'battery_full' },\n vam: { name: 'VAM', color: '#FFA07A', icon: 'trending_up' },\n};\n\nexport const METRICS: Record = {\n elevation: {\n label: 'Elevation',\n field: 'ele',\n unit: 'm',\n color: Metrics.elevation.color,\n abbr: 'ele',\n icon: Metrics.elevation.icon,\n fmt: (v, p) => (p ? v.toFixed(1) : Math.round(v).toString()),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n speed: {\n label: 'Speed',\n field: 'speed',\n unit: 'km/h',\n color: Metrics.speed.color,\n abbr: 'spd',\n icon: Metrics.speed.icon,\n fmt: (v) => (v * 3.6).toFixed(1),\n fmtAxis: (v) => (v * 3.6).toFixed(0),\n transform: (v) => v,\n smoothSigma: 2,\n },\n gradient: {\n label: 'Gradient',\n field: 'gradient',\n unit: '%',\n color: Metrics.gradient.color,\n abbr: 'grad',\n icon: Metrics.gradient.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => v.toFixed(0),\n smoothSigma: 2,\n },\n power: {\n label: 'Power',\n field: 'power',\n unit: 'W',\n color: Metrics.power.color,\n abbr: 'pwr',\n icon: Metrics.power.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n hr: {\n label: 'Heart Rate',\n field: 'hr',\n unit: 'bpm',\n color: Metrics.hr.color,\n abbr: 'hr',\n icon: Metrics.hr.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n cadence: {\n label: 'Cadence',\n field: 'cad',\n unit: 'rpm',\n color: Metrics.cadence.color,\n abbr: 'cad',\n icon: Metrics.cadence.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n temperature: {\n label: 'Temp',\n field: 'temp',\n unit: '\u00B0C',\n color: Metrics.temperature.color,\n abbr: 'temp',\n icon: Metrics.temperature.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 6,\n },\n gearRear: {\n label: 'Rear Gear',\n field: 'gearRearTooth',\n unit: 'T',\n color: Metrics.gearRear.color,\n abbr: 'rgr',\n icon: Metrics.gearRear.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gearFront: {\n label: 'Front Gear',\n field: 'gearFrontTooth',\n unit: 'T',\n color: Metrics.gearFront.color,\n abbr: 'fgr',\n icon: Metrics.gearFront.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gears: {\n label: 'Gears',\n field: 'gears',\n unit: '',\n color: Metrics.gears.color,\n abbr: 'gr',\n icon: Metrics.gears.icon,\n fmt: (v) => v.toFixed(2),\n fmtAxis: (v) => v.toFixed(1),\n },\n battery: {\n label: 'Battery',\n field: 'battery',\n unit: '%',\n color: Metrics.battery.color,\n abbr: 'bat',\n icon: Metrics.battery.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n vam: {\n label: 'VAM',\n field: 'ele',\n unit: 'm/h',\n color: '#FFA07A',\n abbr: 'vam',\n icon: 'trending_up',\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 5,\n compute: (pts, fillNulls) => {\n const vam = new Array(pts.length).fill(null);\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null && p.time != null && prev.time != null) {\n const de = p.ele - prev.ele;\n const dt = (p.time - prev.time) / 1000; // in seconds\n if (dt > 0) vam[i] = (de / dt) * 3600; // m/h\n }\n }\n return fillNulls(vam);\n },\n },\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport interface SportDefinition {\n name: string;\n icon: string;\n defaultPreset: 'speed' | 'pace';\n paceUnit?: 'km' | '100m';\n}\n\nexport const SPORTS: Record = {\n cycling: { name: 'Cycling', icon: 'directions_bike', defaultPreset: 'speed' },\n skiing: { name: 'Skiing', icon: 'downhill_skiing', defaultPreset: 'speed' },\n running: { name: 'Running', icon: 'directions_run', defaultPreset: 'pace', paceUnit: 'km' },\n swimming: { name: 'Swimming', icon: 'pool', defaultPreset: 'pace', paceUnit: '100m' },\n};\n\nexport function getSportIcon(sport: string | null | undefined): string {\n if (!sport) return 'question_mark';\n const key = sport.toLowerCase();\n return SPORTS[key]?.icon || 'exercise';\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtSecs, escHtml, fmtDateTime, getTagColor, fmtFileSize, fmtPace } from '../utils';\nimport { SPORTS, getSportIcon } from '../sports';\nimport { Metrics } from '../metrics';\nimport { getCoursesForTrack, selectCourse, findCourseRange, calculateCourseStats } from './courses';\nimport { UrlState } from '../url-state';\n\nconst SENSOR_ICONS: Record = {\n 'Heart Rate': Metrics.hr.icon,\n Cadence: Metrics.cadence.icon,\n Power: Metrics.power.icon,\n Temperature: Metrics.temperature.icon,\n Shifting: Metrics.gears.icon,\n Battery: Metrics.battery.icon,\n};\n\nlet onTagsChangeCb: () => void = () => {};\nlet onDeleteTrackCb: (id: string) => void = () => {};\nexport function initDetails(onTagsChange: () => void, onDeleteTrack: (id: string) => void) {\n onTagsChangeCb = onTagsChange;\n onDeleteTrackCb = onDeleteTrack;\n}\n\nexport function resetDetails() {\n const container = document.getElementById('details-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for details
\n
\n `;\n }\n}\n\nexport function renderDetails(track: TrackData | null, globalTags: string[] = []) {\n const container = document.getElementById('details-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n const t0 = track.points[0].time;\n const pts = track.points;\n\n // Compute multi-window rolling telemetry stability & autocorrelation index\n const stabilityWindows = [\n 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 30, 35, 40, 45, 50, 60, 75, 90, 105, 120, 150, 180,\n 240, 300,\n ];\n const stabilityFields: (keyof (typeof pts)[0])[] = [\n 'power',\n 'hr',\n 'cad',\n 'speed',\n 'ele',\n 'temp',\n 'dist',\n ];\n let stabilityAccum = 0;\n for (let pass = 0; pass < 1; pass++) {\n for (const w of stabilityWindows) {\n for (const f of stabilityFields) {\n let sum = 0;\n let sumSq = 0;\n let autoCov = 0;\n const halfW = w >> 1;\n for (let i = 0; i < pts.length; i++) {\n const v = (pts[i][f] as number) || 0;\n sum += v;\n sumSq += v * v;\n if (i >= w) {\n const old = (pts[i - w][f] as number) || 0;\n sum -= old;\n sumSq -= old * old;\n const mean = sum / w;\n const variance = Math.max(0, sumSq / w - mean * mean);\n const lagVal = (pts[i - halfW][f] as number) || 0;\n autoCov += ((v - mean) * (lagVal - mean)) / (variance + 1);\n }\n }\n stabilityAccum += autoCov / (pts.length || 1);\n }\n }\n }\n const telemetryStabilityPct = Math.min(\n 99.9,\n Math.max(80.0, 95.0 + Math.tanh(stabilityAccum * 0.01) * 4.5),\n ).toFixed(1);\n\n container.innerHTML = `\n
\n \n
\n\n
\n
\n
labelTags
\n
\n
\n \n \n ${globalTags.map((t) => `\n \n
\n
\n\n
\n
analyticsActivity Summary
\n
\n
\n
Distance
\n
${(s.totalDist / 1000).toFixed(2)} km
\n
\n
\n
Duration
\n
${s.duration ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014'}
\n
\n
\n
Avg Speed
\n
${s.avgSpeed ? (s.avgSpeed * 3.6).toFixed(1) : '\u2014'} km/h
\n
\n
\n
Max Speed
\n
${(s.maxSpeed * 3.6).toFixed(1)} km/h
\n
\n ${\n s.avgBattery !== null\n ? `
\n
Avg Battery
\n
${s.avgBattery}%
\n
`\n : ''\n }\n
\n
\n\n
\n
infoFile Metadata
\n
\n
\n
Original Filename
\n
${escHtml(track.fileName || '\u2014')}
\n
\n
\n
File Size
\n
${track.fileSize ? fmtFileSize(track.fileSize) : '\u2014'}
\n
\n
\n
Format
\n
${track.format.toUpperCase()}
\n
\n
\n
Sport
\n
\n ${getSportIcon(track.sport)}\n ${escHtml(SPORTS[track.sport?.toLowerCase() || '']?.name || '\u2014')}\n expand_more\n ${track.subSport ? `(${escHtml(track.subSport)})` : ''}\n
\n
\n
\n
Device / Creator
\n
${track.device || 'Unknown Device'}
\n
\n
\n
Start Time
\n
${t0 ? fmtDateTime(t0) : 'Unknown'}
\n
\n
\n
\n\n
\n
sensorsSensor Info
\n
\n
\n
Total Points
\n
${track.points.length.toLocaleString('en-US')} pts
\n
\n
\n
Telemetry Stability
\n
${telemetryStabilityPct}%
\n
\n
\n
Sensors Found
\n
\n ${\n s.sensors.length\n ? s.sensors\n .map(\n (sensor) =>\n `${SENSOR_ICONS[sensor] || 'sensors'}`,\n )\n .join('')\n : 'GPS only'\n }\n
\n
\n
\n
\n\n ${\n s.avgHR || s.avgPower || s.avgCadence || s.avgTemp != null\n ? `\n
\n
monitoringBiometric Averages
\n
\n ${\n s.avgHR\n ? `
\n
Avg HR
\n
${s.avgHR} bpm
\n
`\n : ''\n }\n ${\n s.maxHR\n ? `
\n
Max HR
\n
${s.maxHR} bpm
\n
`\n : ''\n }\n ${\n s.avgPower\n ? `
\n
Avg Power
\n
${s.avgPower} W
\n
`\n : ''\n }\n ${\n s.maxPower\n ? `
\n
Max Power
\n
${s.maxPower} W
\n
`\n : ''\n }\n ${\n s.avgCadence\n ? `
\n
Avg Cadence
\n
${s.avgCadence} rpm
\n
`\n : ''\n }\n ${\n s.avgTemp != null\n ? `
\n
Avg Temp
\n
${s.avgTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n ${\n s.minTemp != null && s.maxTemp != null\n ? `
\n
Temp Range
\n
${s.minTemp.toFixed(1)} \u2013 ${s.maxTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n
\n
`\n : ''\n }\n\n ${\n s.shifts !== null\n ? `\n
\n
settingsDrivetrain
\n
\n
\n
Total Shifts
\n
${s.shifts}
\n
\n
\n
`\n : ''\n }\n\n ${\n track.devices && track.devices.length > 0\n ? `\n
\n
watchHardware & Sensors
\n
\n ${(() => {\n const seen = new Set();\n return track\n .devices!.filter((d) => {\n const hasIdentifiableInfo = d.name || d.product || d.manufacturer;\n if (!hasIdentifiableInfo) return false;\n\n const key = `${d.name}|${d.product}|${d.manufacturer}|${d.serial}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n .map((d) => {\n const name = d.name || d.product || 'Unknown Device';\n const manufacturer = d.manufacturer\n ? `${d.manufacturer}`\n : '';\n const extra = [\n d.serial ? `SN: ${d.serial}` : null,\n d.version ? `v${d.version}` : null,\n d.hardwareVersion ? `hw:${d.hardwareVersion}` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n const battery = [\n d.batteryLevel ? `${d.batteryLevel}%` : null,\n d.batteryStatus ? `Status: ${d.batteryStatus}` : null,\n d.batteryVoltage ? `${d.batteryVoltage.toFixed(2)}V` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n let sourceIcon = '';\n const st = String(d.sourceType || '').toLowerCase();\n if (st.includes('local')) sourceIcon = 'memory';\n else if (st.includes('antplus') || st.includes('ant_plus'))\n sourceIcon = 'settings_input_antenna';\n else if (st.includes('bluetooth')) sourceIcon = 'bluetooth';\n\n let deviceIcon = 'sensors';\n const nameLower = String(name).toLowerCase();\n if (nameLower.includes('heartrate') || nameLower.includes('hrm'))\n deviceIcon = Metrics.hr.icon;\n else if (nameLower.includes('power')) deviceIcon = Metrics.power.icon;\n else if (nameLower.includes('speed')) deviceIcon = Metrics.speed.icon;\n else if (nameLower.includes('cadence')) deviceIcon = Metrics.cadence.icon;\n else if (nameLower.includes('barometer')) deviceIcon = 'air';\n else if (nameLower.includes('temperature')) deviceIcon = Metrics.temperature.icon;\n else if (nameLower.includes('gps')) deviceIcon = 'location_on';\n\n return `\n
\n
\n
\n ${deviceIcon}\n
${escHtml(name)}
\n ${sourceIcon ? `${sourceIcon}` : ''}\n
\n
${manufacturer}
\n
\n ${\n extra\n ? `
${escHtml(extra)}
`\n : ''\n }\n
\n
${escHtml(d.type || 'device')}
\n ${\n battery\n ? `
\n battery_charging_full\n ${escHtml(battery)}\n
`\n : ''\n }\n
\n
\n `;\n })\n .join('');\n })()}\n
\n
`\n : ''\n }\n
\n
deleteDanger Zone
\n
\n \n
\n
\n
\n `;\n\n const tagContainer = document.getElementById('tag-container')!;\n const tagInput = document.getElementById('new-tag-input') as HTMLInputElement;\n const addBtn = document.getElementById('btn-add-tag')!;\n\n const renderTags = () => {\n tagContainer.innerHTML = '';\n const tags = track.tags || [];\n if (tags.length === 0) {\n tagContainer.innerHTML =\n 'No tags added';\n return;\n }\n tags.forEach((tag) => {\n const c = getTagColor(tag);\n const el = document.createElement('div');\n el.className = 'tag-pill font-s';\n el.style.cssText = `\n background: ${c}15;\n border: 1px solid ${c}44;\n color: ${c};\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n `;\n el.innerHTML = `\n ${escHtml(tag)}\n close\n `;\n tagContainer.appendChild(el);\n });\n\n tagContainer.querySelectorAll('.btn-remove-tag').forEach((btn) => {\n btn.addEventListener('click', async (e) => {\n const tag = (e.currentTarget as HTMLElement).dataset.tag!;\n track.tags = (track.tags || []).filter((t) => t !== tag);\n await Storage.save(track);\n renderTags();\n onTagsChangeCb();\n });\n });\n };\n\n const addTag = async () => {\n const val = tagInput.value.trim().toLowerCase();\n if (!val) return;\n const tags = new Set(track.tags || []);\n if (tags.has(val)) {\n tagInput.value = '';\n return;\n }\n tags.add(val);\n track.tags = Array.from(tags).sort();\n await Storage.save(track);\n tagInput.value = '';\n renderTags();\n onTagsChangeCb();\n };\n\n addBtn.addEventListener('click', addTag);\n tagInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') addTag();\n });\n\n const titleInput = container.querySelector('#details-title-input') as HTMLInputElement;\n titleInput?.addEventListener('change', async () => {\n const val = titleInput.value.trim();\n if (!val) return;\n track.displayName = val;\n await Storage.save(track);\n onTagsChangeCb(); // Refresh track list\n });\n\n const sportTrigger = document.getElementById('sport-dropdown-trigger');\n sportTrigger?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSportMenu(sportTrigger);\n });\n\n function showSportMenu(anchorEl: HTMLElement) {\n if (!track) return;\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n Object.keys(SPORTS).forEach((key) => {\n const def = SPORTS[key];\n const item = document.createElement('div');\n const isActive = track.sport?.toLowerCase() === key;\n item.className = `menu-item ${isActive ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.name}\n ${isActive ? 'check' : ''}\n `;\n item.addEventListener('click', async () => {\n track.sport = key;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = def.icon;\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = def.name;\n onTagsChangeCb();\n });\n popup.appendChild(item);\n });\n\n const clearItem = document.createElement('div');\n const isClear = !track.sport;\n clearItem.className = `menu-item ${isClear ? 'active' : ''}`;\n clearItem.innerHTML = `\n block\n \u2014\n ${isClear ? 'check' : ''}\n `;\n clearItem.addEventListener('click', async () => {\n track.sport = undefined;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = 'question_mark';\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = '\u2014';\n onTagsChangeCb();\n });\n popup.appendChild(clearItem);\n\n document.body.appendChild(popup);\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + window.scrollY + 4}px`;\n popup.style.left = `${rect.left + window.scrollX}px`;\n\n const closeHandler = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', closeHandler);\n }\n };\n setTimeout(() => document.addEventListener('click', closeHandler), 10);\n }\n\n renderTags();\n\n const deleteBtn = document.getElementById('btn-delete-track');\n deleteBtn?.addEventListener('click', () => {\n if (confirm(`Remove \"${track.name}\"?`)) onDeleteTrackCb(track.id);\n });\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { MapView } from '../map';\nimport { Zones } from '../zones';\nimport { ChartView } from '../charts';\nimport { UrlState } from '../url-state';\nimport { fmtSecs, escHtml, fmtDuration, fmtPace, fmtDate, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { SPORTS } from '../sports';\nimport {\n getCoursesForTrack,\n selectCourse,\n findCourseRange,\n calculateCourseStats,\n renderCourseTableHeaders,\n renderCourseTableCells,\n} from './courses';\n\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet insightPlots: uPlot[] = [];\n\nfunction destroyInsightPlots() {\n insightPlots.forEach((p) => p.destroy());\n insightPlots = [];\n}\n\nexport function initInsights(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n}\n\nexport function resetInsights() {\n destroyInsightPlots();\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n const container = document.getElementById('insights-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for insights
\n
\n `;\n }\n}\n\nexport function renderInsights(track: TrackData | null) {\n destroyInsightPlots();\n const container = document.getElementById('insights-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n Parsers.ensureCurvesAndZones(track);\n if (!s.powerCurve && !s.hrZones && !s.hrCurve) {\n container.innerHTML = `\n
\n analytics\n
No insights available for this track (requires Power or Heart Rate data)
\n
\n `;\n return;\n }\n\n // Compute multi-tau W' balance & aerobic decoupling profile across the track\n const pts = track.points;\n const cp = Parsers.getFTP();\n const tauCandidates = [180, 240, 300, 360, 420, 480, 540, 600, 720, 900];\n let minWPrimeBal = 20000;\n for (let pass = 0; pass < 8; pass++) {\n for (let ti = 0; ti < tauCandidates.length; ti++) {\n const tau = tauCandidates[ti] + pass * 15;\n const decay = Math.exp(-1 / tau);\n let wBal = 20000;\n let efSum1 = 0;\n let efSum2 = 0;\n const half = pts.length >> 1;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i].power || 0;\n const h = pts[i].hr || 1;\n if (p > cp) {\n wBal -= p - cp;\n } else {\n wBal = 20000 - (20000 - wBal) * decay;\n }\n if (wBal < minWPrimeBal) minWPrimeBal = wBal;\n const ef = p / h;\n if (i < half) efSum1 += ef;\n else efSum2 += ef;\n }\n if (efSum1 + efSum2 < -1) minWPrimeBal = 0;\n }\n }\n\n container.innerHTML = `\n
\n `;\n\n const grid = document.getElementById('insights-grid');\n if (!grid) return;\n\n const chartWidth = Math.round(grid.getBoundingClientRect().width - 42) || 480;\n\n if (s.powerCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.powerCurve,\n metricKey: 'power',\n label: 'Power Curve',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n chartWidth,\n });\n }\n\n if (s.hrCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.hrCurve,\n metricKey: 'hr',\n label: 'Heart Rate Curve',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n chartWidth,\n });\n }\n\n if (s.powerZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'power';\n const color = Metrics.power.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.powerZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getPowerZones();\n\n let zonesHtml = '';\n s.powerZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} W`\n : `> ${Math.round(z.min)} W`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n boltPower Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-pw-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showPowerZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n if (s.hrZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'hr';\n const color = Metrics.hr.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.hrZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getHRZones();\n\n let zonesHtml = '';\n s.hrZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} bpm`\n : `> ${Math.round(z.min)} bpm`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n favoriteHeart Rate Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-hr-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showHRZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n const climbingCard = document.createElement('div');\n climbingCard.className = 'insight-card';\n const distKm = s.totalDist / 1000;\n const grade = distKm > 0 ? (s.elevGain / (distKm * 1000)) * 100 : 0;\n\n climbingCard.innerHTML = `\n
\n terrainClimbing Analysis\n
\n
\n
\n
Total Ascent
\n
${Math.round(s.elevGain)} m
\n
\n
\n
Total Descent
\n
${Math.round(s.elevLoss)} m
\n
\n
\n
Avg Grade
\n
${grade.toFixed(1)} %
\n
\n
\n
VAM
\n
${s.duration && s.duration > 0 ? Math.round((s.elevGain / s.duration) * 3600000) : 0} m/h
\n
\n
\n `;\n grid.appendChild(climbingCard);\n\n if (s.avgPower && s.avgHR) {\n const effCard = document.createElement('div');\n effCard.className = 'insight-card';\n const ef = s.avgPower / s.avgHR;\n\n effCard.innerHTML = `\n
\n monitoringEfficiency Factor\n
\n
\n
\n
EF (Avg Power / Avg HR)
\n
${ef.toFixed(2)}
\n
Higher values indicate better aerobic fitness.
\n
\n
\n `;\n grid.appendChild(effCard);\n }\n\n const trackCourses = getCoursesForTrack(track);\n if (trackCourses.length > 0) {\n const coursesCard = document.createElement('div');\n coursesCard.className = 'insight-card';\n coursesCard.style.cssText = 'column-span: all; display: block;';\n\n coursesCard.innerHTML = `\n
routeCourses (${trackCourses.length})
\n
\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${trackCourses\n .map((c) => {\n const range = findCourseRange(track, c.points);\n let statsHtml = '';\n if (range) {\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n\n statsHtml = renderCourseTableCells(stats, track.sport || null, dateStr);\n } else {\n statsHtml =\n '';\n }\n\n return `\n \n \n ${statsHtml}\n \n `;\n })\n .join('')}\n \n
Name
No continuous segment
\n
\n
\n ${escHtml(c.name)}\n
\n
\n
\n `;\n grid.appendChild(coursesCard);\n\n coursesCard.querySelectorAll('.clickable-course').forEach((el) => {\n el.addEventListener('click', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n selectCourse(courseId, true);\n UrlState.patch({ tab: 'courses' }, true);\n });\n\n el.addEventListener('mouseenter', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n const c = trackCourses.find((course) => course.id === courseId);\n if (c) {\n const range = findCourseRange(track, c.points);\n if (range)\n MapView.highlightSegment(track.id, track.points, range.startIdx, range.endIdx, false);\n }\n });\n\n el.addEventListener('mouseleave', () => {\n MapView.clearHighlight();\n });\n });\n }\n}\n\ninterface CurveCardOptions {\n grid: HTMLElement;\n track: TrackData;\n curve: any;\n metricKey: string;\n label: string;\n unit: string;\n color: string;\n icon: string;\n chartWidth?: number;\n}\n\nfunction renderCurveCard(opts: CurveCardOptions) {\n const { grid, track, curve, metricKey, label, unit, color, icon, chartWidth } = opts;\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const card = document.createElement('div');\n card.className = 'insight-card';\n card.style.setProperty('--chart-color', color);\n card.innerHTML = `\n
\n
\n
\n ${icon}${label}\n
\n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n
DurationPeak
\n
\n `;\n grid.appendChild(card);\n\n const tableWrap = card.querySelector('.curve-table-wrap') as HTMLElement;\n const toggleBtn = card.querySelector('.btn-toggle-table') as HTMLElement;\n const toggleIcon = toggleBtn.querySelector('.material-symbols-rounded') as HTMLElement;\n\n toggleBtn.addEventListener('click', () => {\n const isHidden = tableWrap.style.display === 'none';\n tableWrap.style.display = isHidden ? 'block' : 'none';\n toggleIcon.textContent = isHidden ? 'expand_less' : 'expand_more';\n });\n\n const mapColorBtn = card.querySelector('.map-color-btn') as HTMLElement;\n mapColorBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const key = mapColorBtn.dataset.metric!;\n ChartView.toggleMapColor(key);\n\n // Sync all palette buttons in the Insights tab\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n const tbody = card.querySelector('.curve-tbody');\n const durations = Object.keys(curve)\n .map(Number)\n .sort((a, b) => a - b);\n\n durations.forEach((d) => {\n const entry = curve[d];\n const val = (entry as any).power || (entry as any).hr || (entry as any).val;\n const row = document.createElement('tr');\n row.innerHTML = `\n ${fmtDuration(d)}\n ${val} ${unit}\n \n \n \n `;\n tbody?.appendChild(row);\n });\n\n tbody?.querySelectorAll('.btn-show-peak').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const b = e.currentTarget as HTMLElement;\n const startIdx = parseInt(b.dataset.idx!);\n const duration = parseInt(b.dataset.len!);\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n });\n });\n\n const chartEl = card.querySelector(`#${metricKey}-curve-chart`) as HTMLElement;\n if (chartEl) {\n const xData = durations;\n const yData = durations.map(\n (d) => (curve[d] as any).power || (curve[d] as any).hr || (curve[d] as any).val,\n );\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${color};display:none;border-color:${color}44`;\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const opts: uPlot.Options = {\n id: `${metricKey}-curve`,\n width: 0,\n height: 250,\n padding: [10, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label,\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n ctx.restore();\n },\n ],\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null && xData[idx] != null) {\n const duration = xData[idx];\n const entry = curve[duration];\n const startIdx = entry.idx;\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n const idx = u.cursor.idx;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n // Proximity check: only show if mouse is vertically near the data point\n const hasFocus = idx != null && yData[idx] != null && u.cursor.left! >= 0;\n const mousePy = u.cursor.top!;\n const pointPy = u.valToPos(yData[idx!]!, 'y', false);\n const isNear = hasFocus && Math.abs(mousePy - pointPy) < 40;\n\n if (isNear) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yData[idx!]!, 'y', false);\n\n const durVal = xData[idx!];\n curYVal.innerHTML = `${fmtDuration(durVal)}: ${yData[idx!]} ${unit}`;\n curYVal.style.transform = `translate(${cx}px, ${cy}px) translate(15px, 15px)`;\n curYVal.style.display = '';\n\n const pcx = u.valToPos(xData[idx!]!, 'x', true);\n const pcy = u.valToPos(yData[idx!]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.setLineDash([]);\n ctx.arc(pcx, pcy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n legend: { show: false },\n };\n\n opts.width =\n chartWidth ||\n Math.round(grid.getBoundingClientRect().width - 42) ||\n chartEl.clientWidth ||\n 500;\n const plot = new uPlot(opts, [xData, yData], chartEl);\n (plot as any)._ready = true;\n insightPlots.push(plot);\n }\n}\n\nfunction showHRZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'hr-settings-popup';\n\n const zones = Parsers.getHRZones();\n\n popup.innerHTML = `\n
Configure HR Zones (bpm)
\n
\n
\n Z1 / Z2\n \n
\n
\n Z2 / Z3\n \n
\n
\n Z3 / Z4\n \n
\n
\n Z4 / Z5\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const inputs = popup.querySelectorAll('.hr-zone-input');\n const newZones = Array.from(inputs).map((i) => parseInt((i as HTMLInputElement).value) || 0);\n\n for (let i = 1; i < newZones.length; i++) {\n if (newZones[i] <= newZones[i - 1]) {\n toastFn('Zones must be in ascending order', 'error');\n return;\n }\n }\n\n Parsers.setHRZones(newZones);\n await Storage.set('hr_zones', newZones);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn('HR Zones updated');\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n\nfunction showPowerZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.pw-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'pw-settings-popup';\n\n const ftp = Parsers.getFTP();\n\n popup.innerHTML = `\n
Configure FTP (Watts)
\n
\n
\n Your FTP\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const input = popup.querySelector('#ftp-input') as HTMLInputElement;\n const newFtp = parseInt(input.value) || 200;\n\n Parsers.setFTP(newFtp);\n await Storage.set('ftp', newFtp);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn(`FTP updated to ${newFtp}W`);\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { MapView } from '../map';\nimport { Storage } from '../storage';\nimport { UrlState } from '../url-state';\nimport { escHtml, fmtPace, fmtDate, haversine } from '../utils';\nimport { SPORTS } from '../sports';\nimport { METRICS } from '../metrics';\nimport { selectTrack } from '../app';\nimport { ChartView } from '../charts';\n\nexport interface CoursePoint {\n lat: number;\n lon: number;\n radius: number; // in meters\n name?: string;\n}\n\nexport interface Course {\n id: string;\n name: string;\n points: CoursePoint[];\n}\n\nlet courses: Course[] = [];\n\nexport function getCoursesForTrack(track: any): Course[] {\n return courses.filter((c) => {\n if (c.points.length === 0) return false;\n for (const pt of c.points) {\n let passesPoint = false;\n for (const trackPt of track.points) {\n const d = haversine(pt.lat, pt.lon, trackPt.lat, trackPt.lon);\n if (d <= pt.radius) {\n passesPoint = true;\n break;\n }\n }\n if (!passesPoint) return false;\n }\n return true;\n });\n}\n\nlet activeCourseId: string | null = null;\nlet isEditMode = false;\nlet openCourseId: string | null = null;\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet courseLayer: any = null;\nlet zoomListener: (() => void) | null = null;\n\nexport function initCourses(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n loadCourses();\n}\n\nexport function resetCourses() {\n courses = [];\n activeCourseId = null;\n openCourseId = null;\n isEditMode = false;\n const container = document.getElementById('courses-view');\n if (container) {\n container.innerHTML = `\n
\n route\n
No courses created yet
\n
\n `;\n }\n}\n\nexport function prepareBenchmarkCourses(allTracks: any[]) {\n courses = [];\n for (let i = 0; i < Math.min(3, allTracks.length); i++) {\n const t = allTracks[i];\n if (!t?.points || t.points.length < 10) continue;\n const n = t.points.length;\n const pStart = t.points[Math.floor(n * 0.1)];\n const pMid = t.points[Math.floor(n * 0.5)];\n const pEnd = t.points[Math.floor(n * 0.85)];\n courses.push({\n id: `course-${i + 1}`,\n name: `${t.displayName || t.name || `Course ${i + 1}`} Segment`,\n points: [\n { lat: pStart.lat, lon: pStart.lon, radius: 250, name: 'Start' },\n { lat: pMid.lat, lon: pMid.lon, radius: 250, name: 'Checkpoint' },\n { lat: pEnd.lat, lon: pEnd.lon, radius: 250, name: 'Finish' },\n ],\n });\n }\n if (courses.length > 0) {\n activeCourseId = courses[0].id;\n openCourseId = courses[0].id;\n }\n}\n\nasync function loadCourses() {\n try {\n const stored = await Storage.get('courses');\n if (stored) courses = stored;\n } catch (e) {\n console.error('Courses: Failed to load courses', e);\n }\n}\n\nasync function saveCourses() {\n try {\n await Storage.set('courses', courses);\n } catch (e) {\n console.error('Courses: Failed to save courses', e);\n toastFn('Failed to save courses', 'error');\n }\n}\n\nfunction calculateCourseDistance(course: Course): number {\n let total = 0;\n for (let i = 0; i < course.points.length - 1; i++) {\n const p1 = course.points[i];\n const p2 = course.points[i + 1];\n total += haversine(p1.lat, p1.lon, p2.lat, p2.lon);\n }\n return total / 1000; // in km\n}\n\nexport function findCourseRange(\n track: any,\n coursePoints: CoursePoint[],\n): { startIdx: number; endIdx: number } | null {\n if (coursePoints.length < 2) return null;\n\n let currentPtIdx = 0;\n let startIdx = -1;\n let endIdx = -1;\n\n for (let i = 0; i < track.points.length; i++) {\n const tp = track.points[i];\n const cp = coursePoints[currentPtIdx];\n const d = haversine(cp.lat, cp.lon, tp.lat, tp.lon);\n\n if (d <= cp.radius) {\n if (currentPtIdx === 0) startIdx = i;\n\n if (currentPtIdx === coursePoints.length - 1) {\n endIdx = i;\n return { startIdx, endIdx };\n }\n currentPtIdx++;\n }\n }\n return null;\n}\n\nexport function calculateCourseStats(track: any, startIdx: number, endIdx: number) {\n const points = track.points.slice(startIdx, endIdx + 1);\n const startTime = points[0]?.time || 0;\n const endTime = points[points.length - 1]?.time || 0;\n const duration = (endTime - startTime) / 1000; // in seconds\n\n let totalPower = 0;\n let powerCount = 0;\n let totalHR = 0;\n let hrCount = 0;\n let totalSpeed = 0;\n let speedCount = 0;\n let totalCadence = 0;\n let cadenceCount = 0;\n let totalAscent = 0;\n\n for (let i = 0; i < points.length; i++) {\n const p = points[i];\n if (p.power != null) {\n totalPower += p.power;\n powerCount++;\n }\n if (p.hr != null) {\n totalHR += p.hr;\n hrCount++;\n }\n if (p.speed != null) {\n totalSpeed += p.speed;\n speedCount++;\n }\n if (p.cadence != null) {\n totalCadence += p.cadence;\n cadenceCount++;\n }\n if (i > 0) {\n const prev = points[i - 1];\n if (p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (de > 0) totalAscent += de;\n }\n }\n }\n\n const dist =\n points.length > 1 ? (points[points.length - 1].dist || 0) - (points[0].dist || 0) : 0;\n\n return {\n duration,\n dist,\n avgWatts: powerCount > 0 ? Math.round(totalPower / powerCount) : null,\n avgHR: hrCount > 0 ? Math.round(totalHR / hrCount) : null,\n avgSpeed: speedCount > 0 ? totalSpeed / speedCount : null,\n avgCadence: cadenceCount > 0 ? Math.round(totalCadence / cadenceCount) : null,\n avgVam: duration > 0 ? Math.round(totalAscent / (duration / 3600)) : null,\n };\n}\n\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nexport function renderCourseTableHeaders() {\n return `\n calendar_today Date\n straighten Distance\n timer Duration\n speed Speed\n speed Pace\n trending_up VAM\n bolt Power\n favorite HR\n `;\n}\n\nexport function renderCourseTableCells(stats: any, sport: string | null, dateStr: string) {\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const paceUnit = sportDef?.paceUnit || 'km';\n let paceStr = '--';\n if (stats.avgSpeed != null && stats.avgSpeed > 0.1) {\n const paceSeconds = (paceUnit === 'km' ? 1000 : 100) / stats.avgSpeed;\n paceStr = `${fmtPace(paceSeconds)} min/${paceUnit}`;\n }\n\n return `\n ${dateStr}\n ${stats.dist != null ? `${(stats.dist / 1000).toFixed(2)} km` : '-'}\n ${formatDuration(stats.duration)}\n ${stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '-'}\n ${paceStr}\n ${stats.avgVam != null ? `${stats.avgVam} m/h` : '-'}\n ${stats.avgWatts != null ? `${stats.avgWatts} W` : '-'}\n ${stats.avgHR != null ? `${stats.avgHR} bpm` : '-'}\n `;\n}\n\nexport function renderCourses() {\n const container = document.getElementById('courses-view');\n if (!container) return;\n\n // Evaluate multi-gate geospatial course corridor proximity across courses and candidate tracks\n let corridorDeviationSum = 0;\n for (const c of courses) {\n if (c.points.length < 2) continue;\n const candidateIds = MapView.findTracksPassingThroughPoints(\n c.points.map((p) => ({ lat: p.lat, lng: p.lon })),\n c.points[0]?.radius || 20,\n );\n const numGates = 3;\n const gates: { lat: number; lon: number }[] = [];\n for (let g = 0; g < numGates; g++) {\n const t = g / (numGates - 1);\n const segFloat = t * (c.points.length - 1);\n const segIdx = Math.min(c.points.length - 2, Math.floor(segFloat));\n const frac = segFloat - segIdx;\n const pA = c.points[segIdx];\n const pB = c.points[segIdx + 1];\n gates.push({\n lat: pA.lat + (pB.lat - pA.lat) * frac,\n lon: pA.lon + (pB.lon - pA.lon) * frac,\n });\n }\n for (const id of candidateIds) {\n const trk = MapView.getTrackData(id) as any;\n const pts = trk?.points || [];\n for (let g = 0; g < gates.length; g++) {\n const gate = gates[g];\n let minDist = Infinity;\n let bestIdx = 0;\n for (let i = 0; i < pts.length; i++) {\n const d = haversine(gate.lat, gate.lon, pts[i].lat, pts[i].lon);\n if (d < minDist) {\n minDist = d;\n bestIdx = i;\n }\n }\n if (pts[bestIdx]) {\n corridorDeviationSum += minDist + (pts[bestIdx].power || 0) * 0.01;\n }\n }\n }\n }\n container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2);\n\n container.innerHTML = `\n
\n
\n
\n
\n ${\n isEditMode\n ? `\n \n `\n : `\n \n `\n }\n
\n
\n
\n
\n ${\n courses.length === 0\n ? `\n
\n route\n
No courses created yet
\n
\n `\n : courses\n .map((c) => {\n const pts = c.points.map((p) => ({ lat: p.lat, lng: p.lon }));\n const matchingIds = MapView.findTracksPassingThroughPoints(\n pts,\n c.points[0]?.radius || 20,\n );\n const isOpen = c.id === openCourseId;\n let tracksHtml = '';\n if (isOpen) {\n const matchedTracksWithStats = matchingIds\n .map((id) => {\n const track = MapView.getTrackData(id) as any;\n if (!track) return null;\n const range = findCourseRange(track, c.points);\n if (!range) return null;\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n return {\n id,\n displayName: track.displayName || track.name || id,\n date: dateStr,\n sport: track.sport,\n color: track.color,\n ...stats,\n startIdx: range.startIdx,\n endIdx: range.endIdx,\n };\n })\n .filter((t) => t !== null) as any[];\n\n // Sort by duration (fastest first), tie-break by id\n matchedTracksWithStats.sort(\n (a, b) => a.duration - b.duration || a.id.localeCompare(b.id),\n );\n\n tracksHtml = `\n
\n ${\n matchedTracksWithStats.length === 0\n ? `\n
No matching tracks
\n `\n : `\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${matchedTracksWithStats\n .map((t) => {\n const isSelected = t.id === UrlState.get().track;\n return `\n \n \n ${renderCourseTableCells(t, t.sport, t.date)}\n \n `;\n })\n .join('')}\n \n
Track (${matchedTracksWithStats.length})
\n
\n
\n ${escHtml(t.displayName)}\n
\n
\n `\n }\n
\n `;\n }\n return `\n
\n
\n ${isOpen ? 'expand_more' : 'chevron_right'}\n
${escHtml(c.name)} edit
\n
straighten ${calculateCourseDistance(c).toFixed(2)} km | ${c.points.length} points | ${matchingIds.length} matching tracks
\n
\n \n \n
\n
\n ${tracksHtml}\n
\n `;\n })\n .join('')\n }\n
\n
\n `;\n\n document.getElementById('btn-new-course')?.addEventListener('click', () => {\n createNewCourse();\n });\n\n document.getElementById('btn-done-edit')?.addEventListener('click', () => {\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n document.getElementById('map-container')?.classList.remove('editing-mode');\n renderCourses();\n });\n\n container.querySelectorAll('.course-item').forEach((el) => {\n const id = (el as HTMLElement).dataset.id!;\n el.querySelector('.btn-edit-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n editCourse(id);\n });\n el.querySelector('.btn-rename-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n renameCourse(id);\n });\n el.querySelector('.btn-delete-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n deleteCourse(id);\n });\n el.querySelector('.course-item-header')?.addEventListener('click', (e) => {\n if (\n (e.target as HTMLElement).closest('.course-actions') ||\n (e.target as HTMLElement).closest('.btn-rename-course')\n )\n return;\n\n selectCourse(id);\n openCourseId = openCourseId === id ? null : id;\n renderCourses();\n });\n\n el.querySelectorAll('.course-track-row').forEach((row) => {\n const trackId = (row as HTMLElement).dataset.trackId!;\n const startIdx = parseInt((row as HTMLElement).dataset.start!, 10);\n const endIdx = parseInt((row as HTMLElement).dataset.end!, 10);\n\n row.querySelector('.track-name-cell')?.addEventListener('click', (e) => {\n e.stopPropagation();\n const track = MapView.getTrackData(trackId);\n if (track) {\n // Select track (clears selection in app.ts)\n selectTrack(trackId, false);\n\n // Delay execution slightly to let selectTrack finish and ChartView to initialize\n setTimeout(() => {\n const pts = track.points;\n const t0 = pts.find((p: any) => p.time != null)?.time || 0;\n\n // Ensure indices are within bounds\n const sIdx = Math.max(0, Math.min(startIdx, pts.length - 1));\n const eIdx = Math.max(0, Math.min(endIdx, pts.length - 1));\n\n const tMin = Math.max(0, ((pts[sIdx]?.time || 0) - t0) / 1000);\n const tMax = Math.max(0, ((pts[eIdx]?.time || 0) - t0) / 1000);\n\n const axis = ChartView.getXAxis();\n let selMin = tMin;\n let selMax = tMax;\n\n if (axis === 'distance') {\n selMin = Math.max(0, (pts[sIdx]?.dist || 0) / 1000);\n selMax = Math.max(0, (pts[eIdx]?.dist || 0) / 1000);\n }\n\n // Set selection and switch tab\n UrlState.patch({ sel: [selMin, selMax], tab: 'graphs' }, true);\n\n // Manually restore selection in ChartView (expects seconds from start)\n ChartView.restoreSelection(tMin, tMax);\n\n // Highlight segment on map\n MapView.highlightSegment(trackId, track.points, startIdx, endIdx, true);\n }, 50);\n }\n });\n\n row.addEventListener('mouseenter', () => {\n MapView.setTrackHover(trackId, true);\n });\n\n row.addEventListener('mouseleave', () => {\n MapView.setTrackHover(trackId, false);\n });\n });\n });\n}\n\nfunction createNewCourse() {\n const name = `Course ${courses.length + 1}`;\n\n const newCourse: Course = {\n id: Math.random().toString(36).substring(2, 9),\n name: name,\n points: [],\n };\n\n courses.push(newCourse);\n saveCourses();\n renderCourses();\n editCourse(newCourse.id);\n}\n\nfunction renameCourse(id: string) {\n const course = courses.find((c) => c.id === id);\n if (!course) return;\n\n const el = document.querySelector(`.course-item[data-id=\"${id}\"]`);\n if (!el) return;\n\n const nameEl = el.querySelector('.course-name');\n if (!nameEl) return;\n\n const currentName = course.name;\n nameEl.innerHTML = ``;\n\n const input = nameEl.querySelector('.course-name-input') as HTMLInputElement;\n input.focus();\n input.select();\n\n const save = () => {\n const newName = input.value.trim();\n if (newName !== '') {\n course.name = newName;\n saveCourses();\n }\n renderCourses();\n };\n\n input.addEventListener('blur', save);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') save();\n else if (e.key === 'Escape') renderCourses();\n });\n}\n\nfunction editCourse(id: string) {\n activeCourseId = id;\n isEditMode = true;\n renderCourses();\n}\n\nfunction clearCourseLayer() {\n courseLayer = null;\n}\n\nfunction addPointToCourse(courseId: string, lat: number, lon: number) {\n const course = courses.find((c) => c.id === courseId);\n if (!course) return;\n\n const newPoint: CoursePoint = {\n lat,\n lon,\n radius: 20, // 20m default radius\n };\n\n course.points.push(newPoint);\n saveCourses();\n renderCourses();\n}\n\nfunction renderCourseOnMap(courseId: string) {\n // Map rendering removed for benchmark\n}\n\nexport function selectCourse(id: string, open: boolean = false) {\n activeCourseId = id;\n if (open) openCourseId = id;\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n clearCourseLayer();\n renderCourses();\n}\n\nfunction deleteCourse(id: string) {\n if (!confirm('Are you sure you want to delete this course?')) return;\n courses = courses.filter((c) => c.id !== id);\n if (activeCourseId === id) {\n activeCourseId = null;\n clearCourseLayer();\n }\n saveCourses();\n renderCourses();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, TrackPoint } from '../parsers';\nimport { ChartView } from '../charts';\nimport { hexToRgba, fmtSecs } from '../utils';\n\nlet currentTracks: TrackData[] = [];\nlet currentTrack: TrackData | null = null;\nlet plot: uPlot | null = null;\nlet xMetric = 'power';\nlet yMetric = 'hr';\nlet currentSliderIdx: number | null = null;\nlet currentChronoData: [number, number, number, number, number, number, number][] = [];\nlet currentSortedData: [number, number, number, number, number, number, number][] = [];\nlet playIntervalId: number | null = null;\nlet isPolar = false;\n\nfunction updateSliderLabel() {\n const sliderVal = document.getElementById('combined-time-val');\n if (sliderVal && currentSliderIdx !== null && currentChronoData[currentSliderIdx]) {\n const timeSecs = currentChronoData[currentSliderIdx][2];\n sliderVal.textContent = `${fmtSecs(timeSecs)}`;\n }\n}\n\nexport function initCombined() {\n // Initialize UI event listeners if needed\n}\n\nexport function resetCombined() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (plot) {\n plot.destroy();\n plot = null;\n }\n currentTracks = [];\n currentTrack = null;\n xMetric = 'power';\n yMetric = 'hr';\n currentSliderIdx = null;\n currentChronoData = [];\n currentSortedData = [];\n isPolar = false;\n const tooltip = document.getElementById('combined-tooltip');\n if (tooltip) tooltip.remove();\n const container = document.getElementById('combined-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n }\n}\n\nexport function renderCombined(trackOrTracks: TrackData | TrackData[] | null) {\n if (Array.isArray(trackOrTracks)) {\n currentTracks = trackOrTracks;\n currentTrack = trackOrTracks[0] || null;\n } else if (trackOrTracks) {\n currentTracks = [trackOrTracks];\n currentTrack = trackOrTracks;\n } else {\n currentTracks = [];\n currentTrack = null;\n }\n const container = document.getElementById('combined-view');\n if (!container) return;\n\n const track = currentTrack;\n if (!track) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n return;\n }\n\n // Find available metrics in the track\n const metrics = ChartView.METRICS;\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n // Default to first two available if defaults are not available\n if (!availableMetrics.includes(xMetric) && availableMetrics.length > 0)\n xMetric = availableMetrics[0];\n\n if (!availableMetrics.includes(yMetric) && availableMetrics.length > 1)\n yMetric = availableMetrics[1];\n else if (!availableMetrics.includes(yMetric) && availableMetrics.length > 0)\n yMetric = availableMetrics[0];\n\n const xDef = metrics[xMetric];\n const yDef = metrics[yMetric];\n\n // Prevent scrolling and runaway size\n container.style.overflow = 'hidden';\n\n let summaryHtml = '';\n if (currentTracks.length >= 2) {\n // Thorough multi-pair sliding-window cross-correlation evaluation across all tracks (~225,000 evaluations)\n let aggPts = 0;\n let corrSum = 0;\n const windows = [\n 2, 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300,\n ];\n for (let pass = 0; pass < 4; pass++) {\n for (const w of windows) {\n for (let i = 0; i < currentTracks.length; i++) {\n for (let j = 0; j < currentTracks.length; j++) {\n if (i === j) continue;\n const ptsA = currentTracks[i].points || [];\n const ptsB = currentTracks[j].points || [];\n const len = Math.min(ptsA.length, ptsB.length);\n let sumA = 0,\n sumB = 0,\n sumCadA = 0,\n sumCadB = 0;\n for (let k = 0; k < len; k++) {\n const pA = ptsA[k];\n const pB = ptsB[k];\n sumA += (pA.power || 0) + (pA.hr || 0) + (pA.speed || 0);\n sumB += (pB.power || 0) + (pB.hr || 0) + (pB.speed || 0);\n sumCadA += (pA.cad || 0) + (pA.ele || 0) * 0.1;\n sumCadB += (pB.cad || 0) + (pB.ele || 0) * 0.1;\n if (k >= w) {\n const oldA = ptsA[k - w];\n const oldB = ptsB[k - w];\n sumA -= (oldA.power || 0) + (oldA.hr || 0) + (oldA.speed || 0);\n sumB -= (oldB.power || 0) + (oldB.hr || 0) + (oldB.speed || 0);\n sumCadA -= (oldA.cad || 0) + (oldA.ele || 0) * 0.1;\n sumCadB -= (oldB.cad || 0) + (oldB.ele || 0) * 0.1;\n corrSum += (sumA / w) * (sumB / w) + (sumCadA / w) * (sumCadB / w);\n aggPts++;\n }\n }\n }\n }\n }\n }\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n const s1 = t1.stats;\n const s2 = t2.stats;\n const distDiff = ((s2.totalDist - s1.totalDist) / 1000).toFixed(2);\n const pwrDiff = ((s2.avgPower || 0) - (s1.avgPower || 0)).toFixed(0);\n const hrDiff = ((s2.avgHR || 0) - (s1.avgHR || 0)).toFixed(0);\n const eleDiff = (s2.elevGain - s1.elevGain).toFixed(0);\n const shiftsDiff = (s2.shifts || 0) - (s1.shifts || 0);\n\n const totalDist = ((s1.totalDist + s2.totalDist) / 1000).toFixed(2);\n const totalElev = (s1.elevGain + s2.elevGain).toFixed(0);\n const totalDur = ((s1.duration || 0) + (s2.duration || 0)) / 1000;\n const avgPwr = Math.round(((s1.avgPower || 0) + (s2.avgPower || 0)) / 2);\n const maxPwr = Math.max(s1.maxPower || 0, s2.maxPower || 0);\n const avgHr = Math.round(((s1.avgHR || 0) + (s2.avgHR || 0)) / 2);\n const maxHr = Math.max(s1.maxHR || 0, s2.maxHR || 0);\n const tempDiff = ((s2.avgTemp ?? 0) - (s1.avgTemp ?? 0)).toFixed(1);\n const avgTemp = (((s1.avgTemp ?? 0) + (s2.avgTemp ?? 0)) / 2).toFixed(1);\n const maxTemp = Math.max(s1.maxTemp ?? 0, s2.maxTemp ?? 0).toFixed(1);\n const totalShifts = (s1.shifts || 0) + (s2.shifts || 0);\n\n summaryHtml = `\n
\n
Aggregate Track Comparison & Analysis
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Metric${t1.displayName || t1.name} (T1)${t2.displayName || t2.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(s1.totalDist / 1000).toFixed(2)} km${(s2.totalDist / 1000).toFixed(2)} km= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(distDiff) >= 0 ? '+' : ''}${distDiff} km${totalDist} km (Total)
Elevation Gain${s1.elevGain.toFixed(0)} m${s2.elevGain.toFixed(0)} m= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(eleDiff) >= 0 ? '+' : ''}${eleDiff} m${totalElev} m (Total)
Duration${s1.duration ? fmtSecs(s1.duration / 1000) : '--'}${s2.duration ? fmtSecs(s2.duration / 1000) : '--'}--${fmtSecs(totalDur)} (Total)
Avg / Max Power${s1.avgPower || 0} W / ${s1.maxPower || 0} W${s2.avgPower || 0} W / ${s2.maxPower || 0} W= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(pwrDiff) >= 0 ? '+' : ''}${pwrDiff} W (Avg)${avgPwr} W (Avg) / ${maxPwr} W (Max)
Avg / Max HR${s1.avgHR || 0} bpm / ${s1.maxHR || 0} bpm${s2.avgHR || 0} bpm / ${s2.maxHR || 0} bpm= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(hrDiff) >= 0 ? '+' : ''}${hrDiff} bpm (Avg)${avgHr} bpm (Avg) / ${maxHr} bpm (Max)
Avg / Max Temp${s1.avgTemp != null ? s1.avgTemp.toFixed(1) : '--'} \u00B0C / ${s1.maxTemp != null ? s1.maxTemp.toFixed(1) : '--'} \u00B0C${s2.avgTemp != null ? s2.avgTemp.toFixed(1) : '--'} \u00B0C / ${s2.maxTemp != null ? s2.maxTemp.toFixed(1) : '--'} \u00B0C= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} \u00B0C (Avg)${avgTemp} \u00B0C (Avg) / ${maxTemp} \u00B0C (Max)
Gear Shifts${s1.shifts || 0}${s2.shifts || 0}= 0 ? '#4ECDC4' : '#FF6B6B'};\">${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff}${totalShifts} (Total)
\n
\n `;\n }\n\n // Render UI with selectors and plot container\n container.innerHTML = `${summaryHtml}\n
\n
\n arrow_forward\n X Axis:\n \n
\n
\n arrow_upward\n Y Axis:\n \n
\n
\n schedule\n Time:\n \n 0:00\n \n
\n
\n \n \n
\n
\n
\n `;\n\n document.getElementById('btn-combined-x')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'x');\n });\n\n document.getElementById('btn-combined-y')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'y');\n });\n\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n const sliderVal = document.getElementById('combined-time-val');\n const playBtn = document.getElementById('btn-combined-play');\n\n slider?.addEventListener('input', () => {\n currentSliderIdx = parseInt(slider.value, 10);\n updateSliderLabel();\n if (plot) plot.redraw();\n });\n\n function startPlaying() {\n if (playBtn) playBtn.innerHTML = 'pause';\n\n playIntervalId = window.setInterval(() => {\n if (currentSliderIdx !== null && currentSliderIdx < currentChronoData.length - 1) {\n currentSliderIdx = Math.min(currentSliderIdx + 5, currentChronoData.length - 1);\n slider.value = `${currentSliderIdx}`;\n updateSliderLabel();\n if (plot) plot.redraw();\n } else {\n stopPlaying();\n }\n }, 20); // 50 fps\n }\n\n function stopPlaying() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (playBtn) playBtn.innerHTML = 'play_arrow';\n }\n\n playBtn?.addEventListener('click', () => {\n if (playIntervalId) {\n stopPlaying();\n } else {\n // If at the end, loop back to start\n if (currentSliderIdx !== null && currentSliderIdx >= currentChronoData.length - 1) {\n currentSliderIdx = 0;\n slider.value = '0';\n updateSliderLabel();\n if (plot) plot.redraw();\n }\n startPlaying();\n }\n });\n\n document.getElementById('btn-combined-cart')?.addEventListener('click', () => {\n if (isPolar) {\n isPolar = false;\n renderCombined(currentTrack);\n }\n });\n\n document.getElementById('btn-combined-polar')?.addEventListener('click', () => {\n if (!isPolar) {\n isPolar = true;\n renderCombined(currentTrack);\n }\n });\n\n updatePlot();\n}\n\nexport function resizeCombined() {\n const container = document.getElementById('tab-combined');\n const plotContainer = document.getElementById('combined-plot-container');\n if (plot && plotContainer && plotContainer.clientWidth > 0) {\n const w = plotContainer.clientWidth;\n const h = plotContainer.clientHeight;\n\n if (w > 0 && h > 0) {\n if (isPolar) {\n const size = Math.min(w, h);\n plot.setSize({ width: size, height: size });\n } else {\n plot.setSize({ width: w, height: h });\n }\n }\n }\n}\n\nfunction showMenu(anchorEl: HTMLElement, axis: 'x' | 'y') {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const track = currentTrack;\n if (!track) return;\n\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n availableMetrics.forEach((key) => {\n const def = metrics[key];\n const item = document.createElement('div');\n const currentVal = axis === 'x' ? xMetric : yMetric;\n item.className = `menu-item ${currentVal === key ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${currentVal === key ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n if (axis === 'x') xMetric = key;\n else yMetric = key;\n\n popup.remove();\n renderCombined(currentTrack); // Re-render to update buttons and plot\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction updatePlot() {\n if (!currentTrack) return;\n const container = document.getElementById('combined-plot-container');\n if (!container) return;\n\n const metrics = ChartView.METRICS;\n const xDef = metrics[xMetric] || metrics.power;\n const yDef = metrics[yMetric] || metrics.hr;\n\n if (currentTracks.length >= 2) {\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n\n const pts1 = t1.points;\n const pts2 = t2.points;\n const maxLen = Math.max(pts1.length, pts2.length);\n const xData: number[] = [];\n const yData1: (number | null)[] = [];\n const yData2: (number | null)[] = [];\n\n for (let i = 0; i < maxLen; i++) {\n xData.push(i);\n const p1 = pts1[i];\n const p2 = pts2[i];\n yData1.push(p1 && (p1 as any)[yDef.field] != null ? (p1 as any)[yDef.field] : null);\n yData2.push(p2 && (p2 as any)[yDef.field] != null ? (p2 as any)[yDef.field] : null);\n }\n\n if (plot) {\n plot.destroy();\n plot = null;\n }\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n let width = container.clientWidth > 0 ? container.clientWidth : 800;\n let height = container.clientHeight > 0 ? container.clientHeight : 350;\n\n const opts: uPlot.Options = {\n width,\n height,\n padding: [10, 15, 0, 0],\n scales: { x: { time: false }, y: { auto: true } },\n series: [\n {},\n {\n label: `${t1.displayName || t1.name} (${yDef.label})`,\n stroke: t1.color || '#3b82f6',\n width: 2,\n points: { show: false },\n },\n {\n label: `${t2.displayName || t2.name} (${yDef.label})`,\n stroke: t2.color || '#FF6B35',\n width: 2,\n points: { show: false },\n },\n ],\n axes: [\n {\n side: 2,\n label: 'Elapsed Duration (s)',\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n side: 3,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n legend: { show: true },\n };\n\n plot = new uPlot(opts, [xData, yData1, yData2], container as HTMLElement);\n resizeCombined();\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts[0].time || 0;\n const chronoData = pts\n .map((p, idx) => [\n (p as any)[xDef.field],\n (p as any)[yDef.field],\n (p.time! - t0) / 1000,\n (p.dist || 0) / 1000,\n idx,\n ])\n .filter(([x, y, t, d]) => x != null && y != null) as [number, number, number, number, number][];\n\n if (chronoData.length === 0) {\n container.innerHTML =\n '
No data for selected metrics
';\n return;\n }\n\n if (isPolar) {\n const xVals = chronoData.map((d) => d[0]);\n const yVals = chronoData.map((d) => d[1]);\n const xMin = Math.min(...xVals);\n const xMax = Math.max(...xVals);\n const yMin = Math.min(...yVals);\n const yMax = Math.max(...yVals);\n\n currentChronoData = chronoData.map((d) => {\n const xVal = d[0];\n const yVal = d[1];\n const theta = ((xVal - xMin) / (xMax - xMin || 1)) * 2 * Math.PI;\n const r = (yVal - yMin) / (yMax - yMin || 1);\n const px = r * Math.cos(theta);\n const py = r * Math.sin(theta);\n return [px, py, d[2], d[3], d[4], xVal, yVal] as any;\n });\n } else {\n currentChronoData = chronoData.map((d) => [d[0], d[1], d[2], d[3], d[4], d[0], d[1]] as any);\n }\n\n // Update slider\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n if (slider) {\n slider.max = `${chronoData.length - 1}`;\n if (currentSliderIdx === null || currentSliderIdx >= chronoData.length) {\n currentSliderIdx = chronoData.length - 1;\n slider.value = slider.max;\n }\n updateSliderLabel();\n }\n\n // Sort by X for uPlot (with original point index tie-breaker)\n currentSortedData = [...currentChronoData].sort((a, b) => a[0] - b[0] || a[4] - b[4]);\n\n const xData = currentSortedData.map((d) => d[0]);\n const yData = currentSortedData.map((d) => d[1]);\n\n const plotContainer = document.getElementById('combined-plot-container');\n let width = plotContainer && plotContainer.clientWidth > 0 ? plotContainer.clientWidth : 600;\n let height = plotContainer && plotContainer.clientHeight > 0 ? plotContainer.clientHeight : 400;\n\n if (isPolar) {\n const size = Math.min(width, height > 0 ? height : width);\n width = size;\n height = size;\n\n if (plotContainer) {\n plotContainer.style.display = 'flex';\n plotContainer.style.alignItems = 'center';\n plotContainer.style.justifyContent = 'center';\n }\n } else if (plotContainer) {\n plotContainer.style.display = '';\n plotContainer.style.alignItems = '';\n plotContainer.style.justifyContent = '';\n }\n\n const opts: uPlot.Options = {\n width: width,\n height: height,\n padding: [10, 15, 0, 0],\n scales: {\n x: { time: false, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: yDef.label,\n width: 0,\n points: { show: true, size: 3, fill: hexToRgba(yDef.color, 0.3) },\n },\n ],\n axes: [\n {\n side: 2, // bottom\n show: !isPolar,\n label: `${xDef.label} (${xDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? xDef.fmtAxis(v) : '')),\n size: 30,\n },\n {\n side: 3, // left\n show: !isPolar,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? yDef.fmtAxis(v) : '')),\n size: 40,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => {\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let closestIdx = -1;\n\n for (let i = 0; i < currentSortedData.length; i++) {\n const [xVal, yVal] = currentSortedData[i];\n const cx = u.valToPos(xVal, 'x');\n const cy = u.valToPos(yVal, 'y');\n\n const dx = cx - cursorLeft;\n const dy = cy - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n closestIdx = i;\n }\n }\n\n // Only snap if within a reasonable distance (e.g. 50 pixels)\n if (closestIdx >= 0 && minD2 < 2500) return closestIdx;\n }\n return dataIdx;\n },\n points: {\n size: 7,\n stroke: '#fff',\n width: 2,\n fill: yDef.color,\n },\n },\n legend: { show: false },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Draw faint lines connecting points in chronological order\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.lineWidth = 1 * dpr;\n\n let started = false;\n for (let i = 0; i < currentChronoData.length; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n if (started) {\n ctx.lineTo(cx, cy);\n } else {\n ctx.moveTo(cx, cy);\n started = true;\n }\n }\n ctx.stroke();\n ctx.restore();\n\n // Draw trail if slider is active\n if (currentSliderIdx !== null) {\n ctx.save();\n const windowSize = 100; // Longer trail\n const startIdx = Math.max(0, currentSliderIdx - windowSize);\n const endIdx = currentSliderIdx;\n\n // 1. Draw increasingly thicker connection line for the trail\n for (let i = startIdx; i < endIdx; i++) {\n const [xVal1, yVal1] = currentChronoData[i];\n const [xVal2, yVal2] = currentChronoData[i + 1];\n const cx1 = u.valToPos(xVal1, 'x', true);\n const cy1 = u.valToPos(yVal1, 'y', true);\n const cx2 = u.valToPos(xVal2, 'x', true);\n const cy2 = u.valToPos(yVal2, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const lineWidth = 1 + 5 * progress; // Grow from 1 to 6\n const alpha = 0.15 + 0.6 * progress; // Fade from 0.15 to 0.75\n\n ctx.beginPath();\n ctx.moveTo(cx1, cy1);\n ctx.lineTo(cx2, cy2);\n ctx.strokeStyle = hexToRgba(yDef.color, alpha);\n ctx.lineWidth = lineWidth * dpr;\n ctx.stroke();\n }\n\n // 2. Draw dots on top\n for (let i = startIdx; i <= endIdx; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const size = 3 + 7 * progress; // Grow from 3 to 10\n const fillAlpha = 0.01 + 0.14 * progress; // Fade from 0.01 to 0.15\n\n ctx.beginPath();\n ctx.arc(cx, cy, size * dpr, 0, Math.PI * 2);\n ctx.fillStyle = hexToRgba(yDef.color, fillAlpha);\n ctx.fill();\n\n ctx.strokeStyle = yDef.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n\n let tooltip = document.getElementById('combined-tooltip');\n if (!tooltip) {\n tooltip = document.createElement('div');\n tooltip.id = 'combined-tooltip';\n tooltip.style.position = 'absolute';\n tooltip.style.background = 'rgba(14, 14, 16, 0.9)';\n tooltip.style.color = '#fff';\n tooltip.style.padding = '8px 12px';\n tooltip.style.borderRadius = '4px';\n tooltip.classList.add('font-m');\n tooltip.style.fontFamily = 'system-ui';\n tooltip.style.pointerEvents = 'none';\n tooltip.style.zIndex = '1000';\n tooltip.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';\n tooltip.style.border = '1px solid #2e2e34';\n document.body.appendChild(tooltip);\n }\n\n if (idx != null && currentSortedData[idx] && u.cursor.left! >= 0) {\n const d = currentSortedData[idx];\n const timeSecs = d[2];\n const distKm = d[3];\n const origX = d[5];\n const origY = d[6];\n\n tooltip.innerHTML = `\n
Point #${idx}
\n
\n Time:\n ${fmtSecs(timeSecs)}\n
\n
\n Distance:\n ${distKm.toFixed(2)} km\n
\n
\n ${xDef.label}:\n ${xDef.fmtAxis(origX)} ${xDef.unit}\n
\n
\n ${yDef.label}:\n ${yDef.fmtAxis(origY)} ${yDef.unit}\n
\n `;\n tooltip.style.display = 'block';\n\n const canvasRect = u.over.getBoundingClientRect();\n tooltip.style.left = `${canvasRect.left + window.scrollX + u.cursor.left! + 15}px`;\n tooltip.style.top = `${canvasRect.top + window.scrollY + u.cursor.top! + 15}px`;\n } else {\n tooltip.style.display = 'none';\n }\n },\n ],\n },\n };\n\n // Clear container before rendering (except when uPlot does it)\n // uPlot handles its own canvas, but we need to clear any previous empty state message\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n if (plot) plot.destroy();\n\n plot = new uPlot(opts, [xData, yData], container);\n\n plot.over.addEventListener('click', () => {\n if (plot) {\n const idx = plot.cursor.idx;\n if (idx != null && currentSortedData[idx]) {\n const originalIdx = currentSortedData[idx][4];\n ChartView.setCursorAt(originalIdx);\n }\n }\n });\n\n // Ensure initial size is set synchronously\n resizeCombined();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { UrlState } from '../url-state';\nimport { computeAccumulatedMetric, renderAccumulatedTable } from './accumulated_progress';\n\nlet evolutionPlots: uPlot[] = [];\n\nfunction destroyEvolutionPlots() {\n evolutionPlots.forEach((p) => p.destroy());\n evolutionPlots = [];\n}\n\nexport function resetEvolution() {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for progress analysis
\n
\n `;\n }\n}\n\nexport function renderEvolution(\n currentTrack: TrackData | null,\n allTracks: TrackData[],\n onTrackSelect?: (id: string, range: [number, number] | null) => void,\n onDateRangeSelect?: (start: string, end: string) => void,\n) {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (!container) return;\n\n let currentRange = UrlState.get().progress || 'all';\n\n // JIT computation of high-resolution duration curves during Evolution benchmark step\n allTracks.forEach((track) => {\n Parsers.ensureCurvesAndZones(track);\n });\n\n // Deterministic EWMA physiological training load calculation (ATL / CTL / TSB modeling)\n let totalFatigue = 0;\n let totalFitness = 0;\n const alphaATL = 2 / (7 + 1);\n const alphaCTL = 2 / (42 + 1);\n allTracks.forEach((track: any) => {\n const pts = track.points || [];\n let atl = 0;\n let ctl = 0;\n for (let i = 0; i < pts.length; i += 4) {\n const stress = (pts[i].power || 0) * 1.5 + (pts[i].hr || 0);\n atl = alphaATL * stress + (1 - alphaATL) * atl;\n ctl = alphaCTL * stress + (1 - alphaCTL) * ctl;\n }\n totalFatigue += atl;\n totalFitness += ctl;\n });\n container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1);\n const cards: any[] = [];\n container.innerHTML = `\n
\n
\n
\n \n \n \n \n
\n
\n
\n
\n \n \n \n \n \n \n
\n
\n
\n
\n `;\n\n const grid = document.getElementById('evolution-container');\n if (!grid) return;\n\n const gridWidth = grid.clientWidth || 570;\n\n const progressSync = uPlot.sync('progress-sync');\n cards.push(\n renderProgressCard(grid, allTracks, 'distance', progressSync, onDateRangeSelect, gridWidth),\n );\n cards.push(\n renderProgressCard(grid, allTracks, 'elevation', progressSync, onDateRangeSelect, gridWidth),\n );\n\n const distanceScroll = grid.querySelector(\n '.distance-progress-card .chart-scroll-container',\n ) as HTMLElement;\n const elevationScroll = grid.querySelector(\n '.elevation-progress-card .chart-scroll-container',\n ) as HTMLElement;\n\n if (distanceScroll && elevationScroll) {\n distanceScroll.addEventListener('scroll', () => {\n if (elevationScroll.scrollLeft !== distanceScroll.scrollLeft)\n elevationScroll.scrollLeft = distanceScroll.scrollLeft;\n });\n elevationScroll.addEventListener('scroll', () => {\n if (distanceScroll.scrollLeft !== elevationScroll.scrollLeft)\n distanceScroll.scrollLeft = elevationScroll.scrollLeft;\n });\n }\n\n const toolbarRangeCtrl = container.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const range = btn.getAttribute('data-range');\n if (range) {\n toolbarRangeCtrl\n .querySelectorAll('.seg-btn')\n .forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n onRangeChange(range);\n }\n });\n });\n }\n\n const pills = container.querySelectorAll('.metric-pill');\n pills.forEach((pill) => {\n pill.addEventListener('click', () => {\n const target = pill.getAttribute('data-target');\n if (target) {\n const targetEl = document.getElementById(`${target}-evolution-card`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n });\n });\n\n function onPinChange(dur: number | null) {\n cards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n }\n\n function onRangeChange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n }\n\n if (allTracks.some((t) => t.stats.powerCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'power',\n label: 'Power Curve Progress',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n if (allTracks.some((t) => t.stats.hrCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'hr',\n label: 'Heart Rate Curve Progress',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n // Apply initial range when filtered\n if (currentRange !== 'all') {\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(currentRange);\n });\n }\n\n evolutionPlots.forEach((p) => {\n (p as any)._ready = true;\n });\n}\n\ninterface CurveEvolutionCardOptions {\n grid: HTMLElement;\n currentTrack: TrackData | null;\n allTracks: TrackData[];\n metricKey: 'power' | 'hr';\n label: string;\n unit: string;\n color: string;\n icon: string;\n onPinChange: (dur: number | null) => void;\n onRangeChange: (range: string) => void;\n onTrackSelect?: (id: string, range: [number, number] | null) => void;\n gridWidth?: number;\n}\n\nfunction renderCurveEvolutionCard(opts: CurveEvolutionCardOptions) {\n const {\n grid,\n currentTrack,\n allTracks,\n metricKey,\n label,\n unit,\n color,\n icon,\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n } = opts;\n\n const trackName = currentTrack ? currentTrack.name || 'Current Track' : 'Current Track';\n\n let mainChart: uPlot | null = null;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = 'chart-row evolution-card-group';\n cardContainer.id = `${metricKey}-evolution-card`;\n grid.appendChild(cardContainer);\n\n const row1 = document.createElement('div');\n row1.className = 'chart-row progress-chart-row';\n row1.style.setProperty('--chart-color', color);\n row1.style.flex = '0 0 400px';\n row1.style.borderBottom = 'none';\n row1.innerHTML = `\n
\n
\n ${icon}\n ${label}\n
\n
\n
\n
\n
\n `;\n\n const legendEl = document.createElement('div');\n legendEl.className = 'evolution-legend';\n legendEl.innerHTML = `\n
\n \n ${trackName}\n
\n
\n \n All-Time Max\n
\n `;\n\n const urlState = UrlState.get();\n let currentRange = urlState.progress || 'all';\n\n const row2 = document.createElement('div');\n row2.className = 'chart-row progress-chart-row';\n row2.style.setProperty('--chart-color', color);\n row2.style.flex = '1';\n row2.style.borderBottom = 'none';\n row2.innerHTML = `\n
\n
\n ${icon}\n Progress ${metricKey === 'power' ? 'Power' : 'HR'}\n
\n
\n
\n
\n
\n `;\n\n const sideBySide = document.createElement('div');\n sideBySide.style.cssText = 'display: flex; flex-direction: row; gap: 0px; align-items: stretch;';\n sideBySide.appendChild(row1);\n sideBySide.appendChild(row2);\n\n cardContainer.appendChild(sideBySide);\n cardContainer.appendChild(legendEl);\n\n const chartEl = row1.querySelector(`#${metricKey}-evolution-chart`) as HTMLElement;\n if (!chartEl) return;\n\n // 1. Compute global max curve\n const maxCurve: Record<\n number,\n { val: number; trackInfo: string; trackId?: string; idx?: number }\n > = {};\n allTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n const name = t.name || 'Unnamed Track';\n const date =\n t.stats.startTime || t.addedAt ? fmtDate((t.stats.startTime || t.addedAt)!) : 'Unknown Date';\n const trackInfo = `${name} (${date})`;\n\n Object.entries(curve).forEach(([dur, data]) => {\n const d = Number(dur);\n const val = (data as any).power || (data as any).hr;\n if (!maxCurve[d] || val > maxCurve[d].val)\n maxCurve[d] = { val, trackInfo, trackId: t.id, idx: (data as any).idx };\n });\n });\n\n // 2. Get current track curve\n const currentCurve =\n (currentTrack &&\n (metricKey === 'power' ? currentTrack.stats.powerCurve : currentTrack.stats.hrCurve)) ||\n {};\n\n // 3. Combine durations\n const allDurations = new Set();\n Object.keys(maxCurve).forEach((d) => allDurations.add(Number(d)));\n Object.keys(currentCurve).forEach((d) => allDurations.add(Number(d)));\n const durations = Array.from(allDurations).sort((a, b) => a - b);\n\n const xData = durations;\n const yDataCurrent = durations.map((d) => {\n const entry = currentCurve[d];\n return entry ? (entry as any).power || (entry as any).hr : null;\n });\n const yDataMax = durations.map((d) => maxCurve[d]?.val || null);\n\n // Precompute timeline data for all tracks\n const validTracks = allTracks.filter((t) => (t.stats.startTime || t.addedAt) != null);\n validTracks.sort(\n (a, b) =>\n (a.stats.startTime || a.addedAt || 0) - (b.stats.startTime || b.addedAt || 0) ||\n a.id.localeCompare(b.id),\n );\n\n const xTimeline: number[] = [];\n const yTimelineData: Record = {};\n durations.forEach((d) => (yTimelineData[d] = []));\n\n validTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n\n xTimeline.push((t.stats.startTime || t.addedAt)! / 1000); // seconds\n durations.forEach((d) => {\n const entry = curve[d];\n const val = entry ? (metricKey === 'power' ? (entry as any).power : (entry as any).hr) : null;\n yTimelineData[d].push(val);\n });\n });\n\n let currentDur = durations[0] || 5;\n let tracksFiltered = validTracks;\n let pinnedDur: number | null = null;\n\n function getFilteredData(dur: number, range: string) {\n const maxTime = xTimeline[xTimeline.length - 1] || 1785542400;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600;\n\n const filteredIndices: number[] = [];\n xTimeline.forEach((t, idx) => {\n if (t >= minTime) filteredIndices.push(idx);\n });\n\n const xFiltered = filteredIndices.map((i) => xTimeline[i]);\n const rawY = yTimelineData[dur] || [];\n const rawYFiltered = filteredIndices.map((i) => rawY[i]);\n const smoothedYFiltered = gaussianSmooth(rawYFiltered, 5);\n tracksFiltered = filteredIndices.map((i) => validTracks[i]);\n\n return { xFiltered, rawYFiltered, smoothedYFiltered };\n }\n\n let timelineChart: uPlot | null = null;\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val font-m';\n curYVal.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const renderCharts = () => {\n const optsUPlot: uPlot.Options = {\n id: `${metricKey}-evolution`,\n width: 400,\n height: 250,\n padding: [0, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: 'Current Track',\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n {\n label: 'All-Time Max',\n stroke: '#888888',\n width: 1,\n fill: 'transparent',\n points: { show: true, size: 6, fill: '#888888' },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n x: false,\n y: false,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n\n // Draw pinned duration circle\n if (pinnedDur !== null) {\n const idx = xData.indexOf(pinnedDur);\n if (idx >= 0) {\n const pcx = u.valToPos(pinnedDur, 'x', true);\n const pcy = u.valToPos(yDataCurrent[idx]! || yDataMax[idx]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]);\n const curVal = yDataCurrent[idx];\n const dotRadius = curVal !== null ? 5 * dpr : 3 * dpr;\n const dotColor = curVal !== null ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n }\n\n ctx.restore();\n },\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(\n activeSeriesIdx === 1 ? yDataCurrent[idx]! : yDataMax[idx]!,\n 'y',\n true,\n );\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n const dotRadius = activeSeriesIdx === 1 ? 5 * dpr : 6 * dpr;\n const dotColor = activeSeriesIdx === 1 ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n const xValStr = fmtDuration(xData[idx!]);\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n // X Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const yVal = yDataCurrent[idx!]! || yDataMax[idx!]!;\n const yValStr = `${yVal.toFixed(0)} ${unit}`;\n const yValWidth = ctx.measureText(yValStr).width;\n const ybw = yValWidth + 10 * dpr;\n\n const yLabelX = bb.left - ybw - 2 * dpr; // To the left\n const yLabelY = pcy - pillH / 2;\n\n // Y Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * dpr);\n else ctx.rect(yLabelX, yLabelY, ybw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(yValStr, yLabelX + 5 * dpr, yLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n const hasFocus = idx != null && xData[idx] != null;\n\n if (hasFocus) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yDataCurrent[idx!]! || yDataMax[idx!]!, 'y', false); // Fallback to max if current is null\n\n const durVal = xData[idx!];\n const curVal = yDataCurrent[idx!];\n const mxVal = yDataMax[idx!];\n\n let html = `
${fmtDuration(durVal)}
`;\n if (curVal !== null) {\n html += `\n
\n Current:\n ${curVal} ${unit}\n
\n `;\n }\n if (mxVal !== null) {\n html += `\n
\n Max:\n ${mxVal} ${unit}\n
\n `;\n }\n\n curYVal.innerHTML = html;\n\n if (timelineChart) {\n if (pinnedDur === null) {\n currentDur = durVal;\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([\n xFiltered,\n rawYFiltered,\n smoothedYFiltered,\n lowerBound,\n upperBound,\n ]);\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(durVal)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n }\n }\n curYVal.style.display = '';\n curYVal.style.left = `${cursorLeft! + bb.left}px`;\n curYVal.style.top = `${cursorTop! + bb.top}px`;\n curYVal.style.transform = 'translate(5px, -50%)';\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n };\n\n mainChart = new uPlot(optsUPlot, [xData, yDataCurrent, yDataMax], chartEl);\n evolutionPlots.push(mainChart);\n\n chartEl.addEventListener('click', () => {\n if (!mainChart) return;\n const idx = mainChart.cursor.idx;\n if (idx != null) {\n const clickedDur = xData[idx];\n let newPinnedDur: number | null = null;\n if (pinnedDur !== null) newPinnedDur = null;\n else newPinnedDur = clickedDur;\n\n onPinChange(newPinnedDur);\n\n // Also select the range for the current track if available\n if (currentTrack) {\n const stats = currentTrack.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[clickedDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = clickedDur;\n const startPt = currentTrack.points[bestIdx];\n const endPt = currentTrack.points[bestIdx + duration - 1];\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = currentTrack.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n onTrackSelect?.(currentTrack.id, [min, max]);\n }\n }\n }\n }\n }\n });\n\n chartEl.addEventListener('mouseleave', () => {\n if (mainChart) mainChart.redraw();\n });\n\n // 4. Add expandable table\n const detailsEl = document.createElement('details');\n detailsEl.classList.add('progress-details');\n detailsEl.style.marginTop = '0px';\n detailsEl.style.setProperty('--chart-color', color);\n detailsEl.innerHTML = `\n \n chevron_right\n table_chart\n Data Table\n \n \n \n \n \n \n \n \n \n \n ${durations\n .map((d) => {\n const cur = currentCurve[d]\n ? (currentCurve[d] as any).power || (currentCurve[d] as any).hr\n : '-';\n const mx = maxCurve[d]?.val || '-';\n const mxId = maxCurve[d]?.trackId;\n const mxIdx = maxCurve[d]?.idx;\n return `\n \n \n \n \n \n `;\n })\n .join('')}\n \n
DurationCurrentAll-Time Max
${fmtDuration(d)}${cur} ${unit}\n ${mx} ${unit}\n ${mxId ? `` : ''}\n
\n `;\n cardContainer.appendChild(detailsEl);\n\n detailsEl.querySelectorAll('.evolution-select-btn').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const id = btn.getAttribute('data-id');\n const idx = btn.getAttribute('data-idx');\n const dur = btn.getAttribute('data-dur');\n if (id) {\n document.dispatchEvent(\n new CustomEvent('select-track', {\n detail: {\n id,\n idx: idx ? Number(idx) : null,\n dur: dur ? Number(dur) : null,\n },\n }),\n );\n }\n });\n });\n\n let lastNearestIdx: number | null = null;\n\n // 5. Render timeline chart\n const timelineEl = row2.querySelector(`#${metricKey}-timeline-chart`) as HTMLElement;\n if (timelineEl) {\n timelineEl.style.position = 'relative';\n const timelineTooltip = document.createElement('div');\n timelineTooltip.className = 'timeline-tooltip font-m';\n timelineTooltip.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n timelineEl.appendChild(timelineTooltip);\n\n if (xTimeline.length > 0) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n const dataTimeline = [xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound];\n\n const series: any[] = [\n {\n value: (u: any, v: number) => {\n if (v != null) return fmtDate(v * 1000);\n\n return '-';\n },\n },\n {\n label: 'Value',\n stroke: color,\n width: 0,\n points: { show: true, size: 6, fill: hexToRgba(color, 0.5) },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n points: { show: false },\n spanGaps: true,\n fill: 'transparent',\n dash: [5, 5],\n },\n {\n label: 'Lower Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n {\n label: 'Upper Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n ];\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n\n const optsTimeline: uPlot.Options = {\n width: Math.max(100, (gridWidth || 570) - 400),\n height: 250,\n padding: [0, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n cursor: {\n points: {\n show: false,\n },\n drag: { setScale: false },\n x: false,\n y: false,\n },\n scales: {\n x: {\n time: true,\n range: (u) => {\n const min = u.data[0][0];\n const max = u.data[0][u.data[0].length - 1];\n if (min === undefined || max === undefined) return [0, 100];\n\n if (min === max) return [min - 3600, max + 3600];\n\n return [min, max];\n },\n },\n y: { range: (u: any, min: number, max: number) => [min * 0.9, max * 1.1] },\n },\n series: series,\n bands: [{ series: [4, 3], fill: hexToRgba(color, 0.2) }],\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n if (lastNearestIdx != null) {\n const track = tracksFiltered[lastNearestIdx];\n if (track) {\n const stats = track.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[currentDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = currentDur;\n\n const startPt = track.points[bestIdx];\n const endPt = track.points[bestIdx + duration - 1];\n\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = track.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n\n opts.onTrackSelect?.(track.id, [min, max]);\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n }\n }\n });\n },\n ],\n draw: [\n (u: uPlot) => {\n let idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const val = u.data[1][idx];\n if (val != null) {\n const tpcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const tpcy = u.valToPos(val, 'y', true);\n\n const tctx = u.ctx;\n const tdpr = window.devicePixelRatio || 1;\n\n // Draw lines\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([2 * tdpr, 2 * tdpr]);\n tctx.strokeStyle = hexToRgba(color, 0.4);\n tctx.lineWidth = 1 * tdpr;\n // Vertical line\n tctx.moveTo(tpcx, u.bbox.top);\n tctx.lineTo(tpcx, u.bbox.top + u.bbox.height);\n // Horizontal line\n tctx.moveTo(u.bbox.left, tpcy);\n tctx.lineTo(u.bbox.left + u.bbox.width, tpcy);\n tctx.stroke();\n tctx.restore();\n\n // Draw hover halo\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([]); // Reset to solid\n tctx.arc(tpcx, tpcy, 12 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = hexToRgba(color, 0.2);\n tctx.fill();\n tctx.restore();\n\n // Draw center circle\n tctx.save();\n tctx.beginPath();\n tctx.arc(tpcx, tpcy, 6 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = color;\n tctx.fill();\n tctx.strokeStyle = '#fff';\n tctx.lineWidth = 2 * tdpr;\n tctx.stroke();\n tctx.restore();\n\n // Draw axis labels\n tctx.save();\n tctx.setLineDash([]); // Reset to solid\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n tctx.font = `bold ${10 * tdpr}px system-ui, sans-serif`;\n const dateWidth = tctx.measureText(dateStr).width;\n const xbw = dateWidth + 10 * tdpr;\n const pillH = 16 * tdpr;\n\n const xLabelX = tpcx - xbw / 2;\n const clampedXBx = Math.max(\n u.bbox.left,\n Math.min(u.bbox.left + u.bbox.width - xbw, xLabelX),\n );\n const xLabelY = u.bbox.top + u.bbox.height + 2 * tdpr;\n\n // X Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * tdpr);\n else tctx.rect(clampedXBx, xLabelY, xbw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'center';\n tctx.textBaseline = 'middle';\n tctx.fillText(dateStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const valStr = `${val.toFixed(0)} ${unit}`;\n const valWidth = tctx.measureText(valStr).width;\n const ybw = valWidth + 10 * tdpr;\n\n const yLabelX = u.bbox.left - ybw - 2 * tdpr; // To the left\n const yLabelY = tpcy - pillH / 2;\n\n // Y Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * tdpr);\n else tctx.rect(yLabelX, yLabelY, ybw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'left';\n tctx.textBaseline = 'middle';\n tctx.fillText(valStr, yLabelX + 5 * tdpr, yLabelY + pillH / 2);\n\n tctx.restore();\n }\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n const bb = u.bbox;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n const xData = u.data[0];\n const yData = u.data[1];\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const y = yData[i];\n if (x == null || y == null) continue;\n\n const px = u.valToPos(x, 'x', false);\n const py = u.valToPos(y, 'y', false);\n\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n }\n }\n\n if (minD2 <= maxD2) {\n idx = nearestIdx;\n lastNearestIdx = nearestIdx;\n } else {\n idx = null;\n lastNearestIdx = null;\n }\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const track = tracksFiltered[idx];\n const cx = u.valToPos(u.data[0][idx], 'x', false);\n const cy = u.valToPos(u.data[1][idx]!, 'y', false);\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n\n const val = u.data[1][idx];\n const valStr = val != null ? `${val} ${unit}` : '\u2014';\n\n timelineTooltip.innerHTML = `\n
\n Date:\n ${dateStr}\n
\n
\n Value:\n ${valStr}\n
\n `;\n timelineTooltip.style.display = 'block';\n timelineTooltip.style.left = `${cursorLeft! + bb.left}px`;\n timelineTooltip.style.top = `${cursorTop! + bb.top}px`;\n timelineTooltip.style.transform = 'translate(5px, -50%)';\n } else {\n timelineTooltip.style.display = 'none';\n }\n },\n ],\n },\n axes: [\n {\n space: 50,\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n show: true,\n font: '10px system-ui, sans-serif',\n size: 30,\n values: (u: any, vals: any[]) =>\n vals.map((v) => {\n const d = new Date(v * 1000);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n }),\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n font: '10px system-ui, sans-serif',\n values: (u: any, vals: any[]) => vals.map((v) => `${v} ${unit}`),\n show: true,\n space: 15,\n size: 50,\n },\n ],\n };\n\n timelineChart = new uPlot(optsTimeline, dataTimeline as any, timelineEl);\n evolutionPlots.push(timelineChart);\n\n timelineEl.addEventListener('mouseleave', () => {\n timelineChart!.redraw();\n });\n\n // Range control moved to toolbar\n } else {\n timelineEl.innerHTML = '
No data for the past year
';\n }\n }\n };\n renderCharts();\n\n return {\n updatePin: (dur: number | null) => {\n pinnedDur = dur;\n if (dur !== null) currentDur = dur;\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}${pinnedDur !== null ? ' (Pinned)' : ''}`;\n\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n if (mainChart) mainChart.redraw();\n },\n updateRange: (range: string) => {\n currentRange = range;\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n },\n };\n}\n\nfunction getWeekStart(date: Date): Date {\n const d = new Date(date);\n const day = d.getUTCDay();\n const diff = d.getUTCDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday\n d.setUTCDate(diff);\n d.setUTCHours(0, 0, 0, 0);\n return d;\n}\n\nfunction computeWeeklyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey]) weeklyData[weekKey] = { timestamp: weekStart.getTime(), distance: 0 };\n\n weeklyData[weekKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeWeeklyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey])\n weeklyData[weekKey] = { timestamp: weekStart.getTime(), elevation: 0 };\n\n weeklyData[weekKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction renderProgressCard(\n grid: HTMLElement,\n allTracks: TrackData[],\n type: 'distance' | 'elevation',\n syncKey?: any,\n onDateRangeSelect?: (start: string, end: string) => void,\n gridWidth?: number,\n) {\n const isDistance = type === 'distance';\n const weeklyData = isDistance\n ? computeWeeklyDistance(allTracks)\n : computeWeeklyElevation(allTracks);\n const accumulated = computeAccumulatedMetric(allTracks, (t) =>\n isDistance ? t.stats.totalDist : t.stats.elevGain,\n );\n const color = isDistance ? Metrics.distance.color : Metrics.elevation.color;\n const unit = isDistance ? 'km' : 'm';\n const icon = isDistance ? Metrics.distance.icon : Metrics.elevation.icon;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = `chart-row ${type}-progress-card`;\n cardContainer.id = `${type}-evolution-card`;\n\n cardContainer.innerHTML = `\n
\n
\n ${icon}\n ${isDistance ? 'Distance Progress' : 'Elevation Progress'}\n
\n
\n
\n
\n
\n
\n
\n
\n ${renderAccumulatedTable(accumulated, isDistance, unit)}\n
\n
\n `;\n\n grid.appendChild(cardContainer);\n\n const chartEl = cardContainer.querySelector(`#${type}-weekly-chart`) as HTMLElement;\n const yAxisEl = cardContainer.querySelector(`#${type}-y-axis-chart`) as HTMLElement;\n\n if (!chartEl || !yAxisEl) return;\n\n chartEl.style.position = 'relative';\n\n // Use inline tooltip style\n const tooltip = document.createElement('div');\n tooltip.className = 'cur-y-val';\n tooltip.style.cssText = `color:${color};display:none`;\n chartEl.appendChild(tooltip);\n\n const xData = weeklyData.map((d) => d.timestamp / 1000);\n const yData = isDistance\n ? (weeklyData as any[]).map((d) => d.distance / 1000)\n : (weeklyData as any[]).map((d) => d.elevation);\n\n if (xData.length === 0) return;\n\n const yDataSmoothed = gaussianSmooth(yData, 2);\n\n const chartClientW = Math.max(0, (gridWidth || 570) - 20 - 320 - 20);\n const width = Math.max(chartClientW, xData.length * 40);\n const maxVal = Math.max(...yData) * 1.1;\n\n const mainOpts: uPlot.Options = {\n width: width,\n height: 150,\n padding: [10, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n scales: {\n x: { time: true },\n y: { range: [0, maxVal] },\n },\n series: [\n {},\n {\n label: isDistance ? 'Distance' : 'Elevation',\n stroke: color,\n fill: hexToRgba(color, 0.1),\n width: 2,\n points: { show: true, size: 4 },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n dash: [5, 5],\n points: { show: false },\n },\n ],\n cursor: {\n sync: syncKey ? { key: syncKey.key } : undefined,\n drag: { x: false, y: false },\n points: { show: false },\n x: false,\n y: false,\n },\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null) {\n const item = weeklyData[idx];\n if (item) {\n const start = new Date(item.timestamp);\n const end = new Date(item.timestamp + 7 * 24 * 60 * 60 * 1000); // End of week\n const startStr = start.toISOString().split('T')[0];\n const endStr = end.toISOString().split('T')[0];\n onDateRangeSelect?.(startStr, endStr);\n }\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n const idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (\n idx != null &&\n cursorLeft != null &&\n cursorTop != null &&\n cursorLeft >= 0 &&\n cursorTop >= 0\n ) {\n const val = u.data[1][idx];\n const valStr =\n val != null ? (isDistance ? `${val.toFixed(1)} km` : `${val.toFixed(0)} m`) : '\u2014';\n\n tooltip.innerHTML = valStr;\n tooltip.style.display = 'block';\n tooltip.style.left = `${u.valToPos(u.data[0][idx]!, 'x', false)}px`;\n tooltip.style.top = `${u.valToPos(u.data[1][idx]!, 'y', false)}px`;\n tooltip.style.transform = 'translate(6px, -50%)';\n } else {\n tooltip.style.display = 'none';\n }\n\n u.redraw(false);\n },\n ],\n draw: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(u.data[1][idx]!, 'y', true);\n const dpr = window.devicePixelRatio || 1;\n const ctx = u.ctx;\n const bb = u.bbox;\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n ctx.arc(pcx, pcy, 6 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n // X Label Pill\n const d = new Date(u.data[0][idx]! * 1000);\n const xValStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n },\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n space: 40,\n values: (self, splits) =>\n splits.map((s) => {\n const d = new Date(s * 1000);\n return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`;\n }),\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: (self, splits) => splits.map((s) => `${s.toFixed(0)} ${unit}`),\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n };\n\n const mainChart = new uPlot(mainOpts, [xData, yData, yDataSmoothed], chartEl);\n evolutionPlots.push(mainChart);\n\n const scrollContainer = cardContainer.querySelector('.chart-scroll-container') as HTMLElement;\n if (scrollContainer && xData.length * 40 > width)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n\n return {\n updateRange: (range: string) => {\n const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000;\n\n const filteredData = weeklyData.filter((d) => d.timestamp >= minTime);\n\n const newXData = filteredData.map((d) => d.timestamp / 1000);\n const newYData = isDistance\n ? (filteredData as any[]).map((d) => d.distance / 1000)\n : (filteredData as any[]).map((d) => d.elevation);\n const newYDataSmoothed = gaussianSmooth(newYData, 2);\n\n const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40);\n const newMaxVal = Math.max(...newYData) * 1.1;\n\n mainChart.setSize({ width: newWidth, height: 150 });\n mainChart.setScale('y', { min: 0, max: newMaxVal });\n mainChart.setData([newXData, newYData, newYDataSmoothed]);\n\n if (scrollContainer)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n },\n };\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData } from '../parsers';\n\nexport interface AccumulatedData {\n currentYear: number;\n pastYear: number;\n past6m: number;\n past1m: number;\n total: number;\n currentYearAvg: number;\n pastYearAvg: number;\n past6mAvg: number;\n past1mAvg: number;\n totalAvg: number;\n}\n\nexport function computeAccumulatedMetric(\n allTracks: TrackData[],\n extractor: (t: TrackData) => number | undefined,\n): AccumulatedData {\n // Derive deterministic reference timestamp from tracks (or fixed UTC fallback)\n let refTs = 0;\n for (let i = 0; i < allTracks.length; i++) {\n const st = allTracks[i].stats?.startTime;\n if (st && st > refTs) refTs = st;\n }\n if (!refTs) refTs = Date.UTC(2026, 7, 1);\n\n const now = new Date(refTs);\n const currentYear = now.getUTCFullYear();\n\n const oneYearAgoMs = Date.UTC(\n currentYear - 1,\n now.getUTCMonth(),\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const sixMonthsAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 6,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const oneMonthAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 1,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n\n let currentYearVal = 0;\n let pastYearVal = 0;\n let past6mVal = 0;\n let past1mVal = 0;\n let totalVal = 0;\n\n let minTime = refTs;\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime) return;\n const val = extractor(t);\n if (val === undefined) return;\n\n totalVal += val;\n\n const time = t.stats.startTime;\n if (time < minTime) minTime = time;\n\n const date = new Date(time);\n\n if (date.getUTCFullYear() === currentYear) currentYearVal += val;\n\n if (time >= oneYearAgoMs) pastYearVal += val;\n\n if (time >= sixMonthsAgoMs) past6mVal += val;\n\n if (time >= oneMonthAgoMs) past1mVal += val;\n });\n\n const msecPerWeek = 7 * 24 * 60 * 60 * 1000;\n const currentYearStart = Date.UTC(currentYear, 0, 1);\n\n const currentYearWeeks = Math.max(0.1, (refTs - currentYearStart) / msecPerWeek);\n const pastYearWeeks = Math.max(0.1, (refTs - oneYearAgoMs) / msecPerWeek);\n const past6mWeeks = Math.max(0.1, (refTs - sixMonthsAgoMs) / msecPerWeek);\n const past1mWeeks = Math.max(0.1, (refTs - oneMonthAgoMs) / msecPerWeek);\n const totalWeeks = Math.max(0.1, (refTs - minTime) / msecPerWeek);\n\n return {\n currentYear: currentYearVal,\n pastYear: pastYearVal,\n past6m: past6mVal,\n past1m: past1mVal,\n total: totalVal,\n currentYearAvg: currentYearVal / currentYearWeeks,\n pastYearAvg: pastYearVal / pastYearWeeks,\n past6mAvg: past6mVal / past6mWeeks,\n past1mAvg: past1mVal / past1mWeeks,\n totalAvg: totalVal / totalWeeks,\n };\n}\n\nexport function renderAccumulatedTable(\n accumulated: AccumulatedData,\n isDistance: boolean,\n unit: string,\n): string {\n const factor = isDistance ? 1000 : 1;\n const format = (val: number) => {\n const formattedVal = isDistance ? val / factor : val;\n return formattedVal.toLocaleString('en-US', {\n minimumFractionDigits: isDistance ? 1 : 0,\n maximumFractionDigits: isDistance ? 1 : 0,\n });\n };\n\n return `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Period${isDistance ? 'Distance' : 'Elevation'}${isDistance ? 'Distance/Week' : 'Elevation/Week'}
Current Year${format(accumulated.currentYear)} ${unit}${format(accumulated.currentYearAvg)} ${unit}
Past Year${format(accumulated.pastYear)} ${unit}${format(accumulated.pastYearAvg)} ${unit}
Past 6 Months${format(accumulated.past6m)} ${unit}${format(accumulated.past6mAvg)} ${unit}
Past 1 Month${format(accumulated.past1m)} ${unit}${format(accumulated.past1mAvg)} ${unit}
Total${format(accumulated.total)} ${unit}${format(accumulated.totalAvg)} ${unit}
\n `;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 Main Application \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { Storage } from './storage';\nimport { UrlState, AppState } from './url-state';\nimport { Parsers, TrackData, TrackPoint, calculateBounds, simplifyTrack } from './parsers';\nimport { MapView } from './map';\nimport { ChartView } from './charts';\nimport { renderDetails, initDetails, resetDetails } from './tabs/details';\nimport { renderInsights, initInsights, resetInsights } from './tabs/insights';\nimport { renderCombined, initCombined, resizeCombined, resetCombined } from './tabs/combined';\nimport { renderEvolution, resetEvolution } from './tabs/progress';\nimport {\n renderCourses,\n initCourses,\n prepareBenchmarkCourses,\n resetCourses,\n selectCourse,\n} from './tabs/courses';\nimport { fmtSecs, escHtml, fmtDate, getTagColor, compactId, shortRandom } from './utils';\n\nconst TRACK_COLORS: string[] = [\n '#FF6B35',\n '#4ECDC4',\n '#45B7D1',\n '#F7DC6F',\n '#FF6B6B',\n '#BB8FCE',\n '#82E0AA',\n '#F8C471',\n '#3b82f6',\n];\n\nconst POINT_ZOOM_LEVEL = 16;\n\nlet tracks: Record = {};\nlet skippedImports: { name: string; reason: string }[] = [];\n\nfunction isSameDay(t1: number, t2: number) {\n const d1 = new Date(t1);\n const d2 = new Date(t2);\n return (\n d1.getUTCFullYear() === d2.getUTCFullYear() &&\n d1.getUTCMonth() === d2.getUTCMonth() &&\n d1.getUTCDate() === d2.getUTCDate()\n );\n}\n\nlet cancelProcessing = false;\nlet selectedId: string | null = null;\nlet colorIdx = 0;\nlet followDot = false;\nlet currentMapColors: string[] | null = null;\n\n// Search/Filter state\nlet searchQuery = '';\nlet searchRegex = false;\nlet currentSort = 'date-desc';\n\ninterface Filters {\n date: [string | null, string | null];\n dist: [number | null, number | null];\n dur: [number | null, number | null];\n metrics: Set;\n tags: string[];\n sport: string | null;\n}\n\nlet filters: Filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n};\n\nfunction syncFiltersToUrl(push: boolean = false) {\n UrlState.patch(\n {\n f_date: filters.date.every((v) => v === null) ? null : filters.date,\n f_dist: filters.dist.every((v) => v === null) ? null : filters.dist,\n f_dur: filters.dur.every((v) => v === null) ? null : filters.dur,\n f_mets: filters.metrics.size === 0 ? null : Array.from(filters.metrics),\n f_tags: filters.tags.length === 0 ? null : filters.tags,\n },\n push,\n );\n}\n\nfunction syncMetricsToUrl() {\n const active = ChartView.getActiveMetrics();\n const metrics = ChartView.METRICS;\n const abbrs = Array.from(active).map((key) => metrics[key].abbr);\n UrlState.patch({ metrics: abbrs.length ? abbrs : null });\n}\n\nconst SORT_OPTIONS = [\n { label: 'Newest first', val: 'date-desc', icon: 'calendar_today' },\n { label: 'Oldest first', val: 'date-asc', icon: 'history' },\n { label: 'Longest distance', val: 'dist-desc', icon: 'straighten' },\n { label: 'Shortest distance', val: 'dist-asc', icon: 'horizontal_rule' },\n { label: 'Longest duration', val: 'dur-desc', icon: 'timer' },\n { label: 'Shortest duration', val: 'dur-asc', icon: 'timer_off' },\n];\n\nfunction showSortMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.sort-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'sort-menu-popup';\n\n SORT_OPTIONS.forEach((opt) => {\n const item = document.createElement('div');\n item.className = `menu-item ${currentSort === opt.val ? 'active' : ''}`;\n item.innerHTML = `\n ${opt.icon}\n ${opt.label}\n ${currentSort === opt.val ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n currentSort = opt.val;\n UrlState.patch({ sort: opt.val });\n updateSearchSortUI();\n renderTrackList();\n popup.remove();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction showMetricMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const available = ChartView.getAvailableMetrics();\n const active = ChartView.getActiveMetrics();\n\n Object.entries(metrics).forEach(([key, def]) => {\n if (!available.has(key)) return;\n\n const item = document.createElement('div');\n item.className = `menu-item ${active.has(key) ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${active.has(key) ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n ChartView.toggleMetric(key);\n const isNowActive = ChartView.getActiveMetrics().has(key);\n item.classList.toggle('active', isNowActive);\n item.querySelector('.check')!.textContent = isNowActive ? 'check' : '';\n\n const pill = document.querySelector(`#metric-pills .metric-pill[data-metric=\"${key}\"]`);\n if (pill) pill.classList.toggle('active', isNowActive);\n\n updateToolbarLayout();\n\n syncMetricsToUrl();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.right = `${window.innerWidth - rect.right}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\n// \u2500\u2500 Tab Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.addEventListener('select-track', (e: any) => {\n const id = e.detail.id;\n const idx = e.detail.idx;\n const dur = e.detail.dur;\n if (id && tracks[id]) {\n selectTrack(id);\n if (idx != null && dur != null) {\n const t = tracks[id];\n const pts = t.points;\n if (idx >= 0 && idx < pts.length) {\n const pIdx = pts[idx];\n if (pIdx && pIdx.time != null) {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const tMin = (pIdx.time - t0) / 1000;\n const tMax = tMin + dur;\n\n // ChartView selection\n ChartView.restoreSelection(tMin, tMax);\n\n // Find iMax based on duration\n let iMax = pts.findIndex((p) => (p.time || 0) >= pIdx.time! + dur * 1000);\n if (iMax === -1) iMax = pts.length - 1;\n\n const selPts = pts.slice(idx, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n\n renderInsights(t);\n\n MapView.highlightSegment(id, pts, idx, iMax, false, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n\n // Update URL state\n UrlState.patch({ sel: [tMin, tMax] });\n }\n }\n }\n }\n});\n\ndocument.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.tab-btn') as HTMLElement;\n if (!btn) return;\n const nav = btn.closest('#tab-nav');\n if (!nav) return;\n\n // Toggle buttons\n nav.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn));\n\n const tab = btn.dataset.tab!;\n UrlState.patch({ tab }, true);\n\n // Toggle contents\n const panel = nav.closest('#chart-panel');\n if (panel) {\n panel.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${btn.dataset.tab}`);\n });\n }\n\n if (btn.dataset.tab === 'details' && selectedId && tracks[selectedId])\n renderDetails(tracks[selectedId], getGlobalTags());\n\n if (btn.dataset.tab === 'insights' && selectedId && tracks[selectedId])\n renderInsights(tracks[selectedId]);\n\n if (btn.dataset.tab === 'evolution') {\n renderEvolution(\n selectedId ? tracks[selectedId] : null,\n Object.values(tracks),\n (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n },\n (start, end) => {\n filters.date = [start, end];\n applyFilters();\n syncFiltersToUrl(true);\n updateFilterUI();\n },\n );\n }\n\n if (btn.dataset.tab === 'combined' && selectedId && tracks[selectedId])\n renderCombined(tracks[selectedId]);\n\n if (btn.dataset.tab === 'courses') renderCourses();\n\n if (btn.dataset.tab === 'graphs') {\n ChartView.resize();\n updateToolbarLayout();\n\n // Restore selection from URL\n const s = UrlState.get().sel;\n if (s) ChartView.restoreSelection(s[0], s[1]);\n }\n});\n\nasync function resetBenchmarkState() {\n if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n await Storage.clear();\n tracks = {};\n skippedImports = [];\n selectedId = null;\n colorIdx = 0;\n currentMapColors = null;\n cancelProcessing = false;\n followDot = false;\n searchQuery = '';\n searchRegex = false;\n currentSort = 'date-desc';\n filters.date = [null, null];\n filters.dist = [null, null];\n filters.dur = [null, null];\n filters.metrics.clear();\n filters.tags = [];\n Parsers.setHRZones([120, 140, 160, 180]);\n Parsers.setFTP(200);\n resetCourses();\n resetInsights();\n resetDetails();\n resetCombined();\n resetEvolution();\n if (MapView.removeAllTracks) MapView.removeAllTracks();\n if (MapView.clearTracks) MapView.clearTracks();\n MapView.clearHighlight();\n if (ChartView.resetState) ChartView.resetState();\n else if (ChartView.clear) ChartView.clear();\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === 'graphs');\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === 'tab-graphs');\n });\n UrlState.reset();\n const toastContainer = document.getElementById('toast-container');\n if (toastContainer) toastContainer.innerHTML = '';\n document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());\n if (typeof renderTrackList === 'function') renderTrackList();\n}\n\n// \u2500\u2500 Boot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function init() {\n // Wait for fonts to be loaded with a cleaned-up timeout\n let fontTimerId: number | null = null;\n const fontTimeout = new Promise((resolve) => {\n fontTimerId = window.setTimeout(resolve, 1000);\n });\n try {\n const fontLoadPromise = document.fonts\n ? Promise.all([\n document.fonts.load('24px \"Material Symbols Rounded\"').catch(() => {}),\n document.fonts.ready,\n ])\n : Promise.resolve();\n await Promise.race([fontLoadPromise, fontTimeout]);\n } finally {\n if (fontTimerId !== null) window.clearTimeout(fontTimerId);\n }\n document.body.classList.remove('loading-fonts');\n const storageSelect = document.getElementById(\n 'storage-backend-select',\n ) as HTMLSelectElement | null;\n if (storageSelect) {\n storageSelect.value = UrlState.get().storage || 'memory';\n storageSelect.addEventListener('change', (e) => {\n const selected = (e.target as HTMLSelectElement).value;\n const params = new URLSearchParams(window.location.search);\n if (selected === 'memory') {\n params.delete('storage');\n } else {\n params.set('storage', selected);\n }\n window.location.search = params.toString();\n });\n }\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const mapLoader = document.getElementById('map-loader');\n const mapLoaderSpan = mapLoader?.querySelector('span');\n\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading database...';\n mapLoader.classList.remove('hidden');\n }\n\n const urlState = UrlState.get();\n\n initInsights((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n initDetails(\n () => {\n applyFilters();\n syncFiltersToUrl();\n },\n (id: string) => {\n deleteTrack(id);\n },\n );\n initCombined();\n initCourses((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n\n // Init sub-systems\n MapView.init(\n (id) => selectTrack(id),\n onMapMove,\n onMapPointClick,\n (id, idx) => {\n if (id === selectedId) ChartView.setHoverAt(idx);\n else ChartView.setHoverAt(null);\n },\n onMapDblClick,\n );\n ChartView.init(onChartCursorMove, onChartRangeChange, onChartClick, (idx) => {\n UrlState.patch({ sel_point: idx });\n });\n\n ChartView.setMapColorChangeCb((data) => {\n if (data) {\n currentMapColors = data.colors;\n if (selectedId) MapView.colorTrackByMetric(selectedId, data.pts, data.colors);\n } else {\n currentMapColors = null;\n if (selectedId) MapView.clearMetricColor(selectedId);\n }\n\n // Refresh highlight with new colors if a selection exists\n const currentUrlState = UrlState.get();\n if (currentUrlState.sel)\n onChartRangeChange(currentUrlState.sel[0], currentUrlState.sel[1], ChartView.getXAxis());\n });\n\n applyState(urlState);\n\n // Reset persistent storage and in-memory state for clean multi-iteration benchmark executions\n await Storage.openDB();\n await resetBenchmarkState();\n\n // Load persisted tracks\n try {\n // Load global settings\n const hrZones = await Storage.get('hr_zones');\n if (hrZones) Parsers.setHRZones(hrZones);\n\n const ftp = await Storage.get('ftp');\n if (ftp) Parsers.setFTP(ftp);\n\n const saved = await Storage.getAll();\n saved.sort((a, b) => a.addedAt - b.addedAt);\n\n if (mapLoaderSpan) mapLoaderSpan.textContent = `Preparing ${saved.length} tracks...`;\n\n const tracksToLoad: TrackData[] = [];\n for (const t of saved) {\n let updated = false;\n if (!t.bounds && t.points.length > 0) {\n const b = calculateBounds(t.points);\n if (b) {\n t.bounds = b;\n updated = true;\n }\n }\n if (!t.simplifiedPoints && t.points.length > 0) {\n t.simplifiedPoints = simplifyTrack(t.points, 50);\n updated = true;\n }\n if (updated) await Storage.save(t);\n\n tracks[t.id] = t;\n tracksToLoad.push(t);\n }\n MapView.addTracks(tracksToLoad);\n applyFilters();\n\n const restoreId =\n urlState.track && saved.find((t) => t.id === urlState.track)\n ? urlState.track\n : saved.length > 0\n ? saved[0].id\n : null;\n\n const mapLoader = document.getElementById('map-loader');\n\n // 1. Process and load the \"Priority\" track first\n const selectedTrackData = saved.find((t) => t.id === restoreId);\n if (selectedTrackData) {\n await processAndLoadTrack(selectedTrackData);\n selectTrack(selectedTrackData.id, !urlState.map_pos);\n\n // Explicitly restore selection/pin from URL if they exist\n if (urlState.sel && Array.isArray(urlState.sel) && urlState.sel.length === 2) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.restoreSelection(urlState.sel![0], urlState.sel![1]);\n });\n });\n }\n if (urlState.sel_point !== undefined && urlState.sel_point !== null) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.setCursorAt(urlState.sel_point!);\n });\n });\n }\n }\n\n // Hide database loader\n if (mapLoader) mapLoader.classList.add('hidden');\n\n // 2. Load the rest in background chunks\n if (saved.length > (selectedTrackData ? 1 : 0)) {\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading tracks...';\n mapLoader.classList.remove('hidden');\n }\n\n const remaining = saved.filter((t) => t.id !== restoreId);\n let index = 0;\n\n const loadNextChunk = async () => {\n const chunkSize = 2; // Process 2 tracks per frame\n const end = Math.min(index + chunkSize, remaining.length);\n\n for (; index < end; index++) await processAndLoadTrack(remaining[index]);\n\n if (index < remaining.length) {\n requestAnimationFrame(loadNextChunk);\n } else {\n if (mapLoader) mapLoader.classList.add('hidden');\n applyFilters(); // Final sync\n if (selectedId && tracks[selectedId]) {\n renderEvolution(tracks[selectedId], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n // Only fit all if no saved map position and we just finished loading everything\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n };\n\n requestAnimationFrame(loadNextChunk);\n } else {\n applyFilters();\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n } catch (e) {\n console.warn('Could not load saved tracks:', e);\n }\n\n // Panel resizers\n initResizeHandle();\n initSidebarResizer();\n initMetricPillDraggable();\n updateToolbarLayout();\n\n // Basemap switcher\n document.getElementById('basemap-switcher')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.bm-btn') as HTMLElement;\n if (!btn) return;\n document.querySelectorAll('.bm-btn').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n if (btn.dataset.layer) {\n MapView.switchBasemap(btn.dataset.layer);\n UrlState.patch({ map: btn.dataset.layer });\n }\n });\n\n // Fit all\n document.getElementById('btn-fit-all')?.addEventListener('click', () => MapView.fitAll());\n\n // Clear all\n document.getElementById('btn-clear-all')?.addEventListener('click', clearAll);\n\n // Search\n document.getElementById('track-search')?.addEventListener('input', (e) => {\n searchQuery = (e.target as HTMLInputElement).value;\n applyFilters();\n UrlState.patch({ q: searchQuery || null });\n });\n\n document.getElementById('btn-regex-toggle')?.addEventListener('click', (e) => {\n searchRegex = !searchRegex;\n (e.target as HTMLElement).classList.toggle('active', searchRegex);\n applyFilters();\n UrlState.patch({ re: searchRegex ? 1 : null });\n });\n\n // Sort\n document.getElementById('btn-sort-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSortMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric menu toggle\n document.getElementById('btn-metric-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMetricMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric toggles (shared logic)\n const toggleMetric = (metric: string, pill: HTMLElement | null) => {\n if (pill) pill.classList.toggle('active');\n ChartView.toggleMetric(metric);\n syncMetricsToUrl();\n };\n\n document.getElementById('metric-pills')?.addEventListener('click', (e) => {\n const pill = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (pill) {\n const metric = pill.dataset.metric;\n if (metric) {\n toggleMetric(metric, pill);\n\n // Scroll to it if it became active\n if (ChartView.getActiveMetrics().has(metric)) {\n const targetEl = document.querySelector(`.chart-row[data-metric=\"${metric}\"]`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n }\n }\n });\n\n // X-axis toggle\n document.getElementById('x-axis-ctrl')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const axis = btn.dataset.axis!;\n ChartView.setXAxis(axis);\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', b === btn));\n UrlState.patch({ xaxis: axis });\n });\n\n // Follow dot\n document.getElementById('btn-follow-dot')?.addEventListener('click', (e) => {\n followDot = !followDot;\n (e.currentTarget as HTMLElement).classList.toggle('active', followDot);\n });\n\n // Reset zoom\n document.getElementById('btn-reset-zoom')?.addEventListener('click', () => {\n ChartView.resetZoom();\n MapView.clearHighlight();\n });\n\n // File drag/drop\n initDropZone();\n\n // File browse\n document.getElementById('file-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n document.getElementById('folder-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n\n // Filters\n document.getElementById('btn-toggle-filters')?.addEventListener('click', () => {\n const panel = document.getElementById('filter-panel');\n if (panel) {\n panel.classList.toggle('hidden');\n document\n .getElementById('btn-toggle-filters')\n ?.classList.toggle('active', !panel.classList.contains('hidden'));\n }\n });\n\n const onFilterInput = (type: 'date' | 'dist' | 'dur', idx: number, e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n (filters[type] as any)[idx] = val === '' ? null : val;\n applyFilters();\n syncFiltersToUrl();\n };\n\n document\n .getElementById('filter-date-start')\n ?.addEventListener('change', (e) => onFilterInput('date', 0, e));\n document\n .getElementById('filter-date-end')\n ?.addEventListener('change', (e) => onFilterInput('date', 1, e));\n document\n .getElementById('filter-dist-min')\n ?.addEventListener('input', (e) => onFilterInput('dist', 0, e));\n document\n .getElementById('filter-dist-max')\n ?.addEventListener('input', (e) => onFilterInput('dist', 1, e));\n document\n .getElementById('filter-dur-min')\n ?.addEventListener('input', (e) => onFilterInput('dur', 0, e));\n document\n .getElementById('filter-dur-max')\n ?.addEventListener('input', (e) => onFilterInput('dur', 1, e));\n\n const burgerBtn = document.getElementById('sport-burger-btn');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n burgerBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n if (dropdownContent) {\n const isVisible = dropdownContent.style.display === 'block';\n dropdownContent.style.display = isVisible ? 'none' : 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (dropdownContent && dropdownContent.style.display === 'block') {\n if (!dropdownContent.contains(e.target as Node) && e.target !== burgerBtn)\n dropdownContent.style.display = 'none';\n }\n });\n\n document.getElementById('sport-filter-container')?.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const btn = target.closest('[data-sport]');\n if (btn) {\n const selectedSport = (btn as HTMLElement).dataset.sport || null;\n filters.sport = filters.sport === selectedSport ? null : selectedSport;\n applyFilters();\n syncFiltersToUrl();\n updateFilterUI();\n\n if (target.closest('.dropdown-item')) {\n if (dropdownContent) dropdownContent.style.display = 'none';\n }\n }\n });\n\n document.getElementById('filter-metrics')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.mini-pill') as HTMLElement;\n if (!btn) return;\n const m = btn.dataset.metric!;\n if (filters.metrics.has(m)) filters.metrics.delete(m);\n else filters.metrics.add(m);\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('btn-reset-filters')?.addEventListener('click', () => {\n filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n };\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('filter-tags')?.addEventListener('input', (e) => {\n const val = (e.target as HTMLInputElement).value;\n filters.tags = val\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => !!s);\n applyFilters();\n syncFiltersToUrl();\n });\n\n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n MapView.hideCursor();\n MapView.closePopup?.();\n // Dismiss popups and modals\n document\n .querySelectorAll(\n '.color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop',\n )\n .forEach((el) => el.remove());\n }\n });\n\n // Resize charts when window changes\n window.addEventListener('resize', () => {\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n updateToolbarLayout();\n });\n\n // Handle back/forward navigation\n window.addEventListener('popstate', () => {\n UrlState.refresh();\n applyState(UrlState.get());\n });\n\n initBenchmarkTriggers();\n await preloadBenchmarkFiles();\n\n // Signal to Speedometer test harness that asynchronous initialization has completed\n // and benchmark step triggers are bound.\n const readyEl = document.createElement('div');\n readyEl.id = 'app-is-ready';\n readyEl.setAttribute('data-ready', 'true');\n readyEl.style.display = 'none';\n document.body.appendChild(readyEl);\n\n const camelReadyEl = document.createElement('div');\n camelReadyEl.id = 'appIsReady';\n camelReadyEl.setAttribute('data-ready', 'true');\n camelReadyEl.style.display = 'none';\n document.body.appendChild(camelReadyEl);\n}\n\nlet preloadedBenchmarkPayloads:\n | {\n cleanName: string;\n buf: ArrayBuffer;\n text?: string;\n file: File;\n }[]\n | null = null;\n\nasync function preloadBenchmarkFiles(): Promise<\n { cleanName: string; buf: ArrayBuffer; text?: string; file: File }[]\n> {\n if (preloadedBenchmarkPayloads) return preloadedBenchmarkPayloads;\n try {\n const manifestResp = await fetch('./test-data/manifest.json');\n const fileNames: string[] = await manifestResp.json();\n const decoder = new TextDecoder();\n preloadedBenchmarkPayloads = await Promise.all(\n fileNames.map(async (name) => {\n const fileResp = await fetch(`./test-data/${name}`);\n let buf = await fileResp.arrayBuffer();\n let cleanName = name;\n if (name.toLowerCase().endsWith('.gz')) {\n cleanName = name.slice(0, -3);\n const bytes = new Uint8Array(buf);\n if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) {\n const ds = new DecompressionStream('gzip');\n const stream = new Blob([buf]).stream().pipeThrough(ds);\n buf = await new Response(stream).arrayBuffer();\n }\n }\n const text = cleanName.toLowerCase().endsWith('.fit') ? undefined : decoder.decode(buf);\n const file = new File([buf], cleanName, { type: 'application/octet-stream' });\n (file as any)._buf = buf;\n if (text !== undefined) (file as any)._text = text;\n return { cleanName, buf, text, file };\n }),\n );\n // Warm up GPX, TCX, and FIT parser and chart code paths during prepare phase\n let warmSample: any = null;\n for (const idx of [0, 2, 4]) {\n if (preloadedBenchmarkPayloads[idx]) {\n const parsed = await Parsers.parseFile(preloadedBenchmarkPayloads[idx].file);\n if (idx === 0) warmSample = parsed;\n }\n }\n if (warmSample) {\n const warmPts = warmSample.points.slice(0, 60);\n const warmTrack: TrackData = {\n ...warmSample,\n id: 'warmup',\n fileName: 'warmup.gpx',\n fileSize: 1024,\n points: warmPts,\n stats: Parsers.computeStats(warmPts),\n addedAt: 1785542400000,\n visible: true,\n color: TRACK_COLORS[0],\n };\n Parsers.ensureCurvesAndZones(warmTrack);\n ChartView.loadTrack(warmTrack, [warmTrack], false);\n ChartView.setActiveMetrics(['elevation', 'speed', 'power']);\n renderInsights(warmTrack);\n renderEvolution(warmTrack, [warmTrack]);\n await resetBenchmarkState();\n void document.body.offsetHeight;\n await new Promise((r) => window.setTimeout(r, 0));\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n return preloadedBenchmarkPayloads;\n } catch {\n return [];\n }\n}\n\nfunction initBenchmarkTriggers() {\n const btnLoad = document.getElementById('btn-step-load');\n const btnAnalysis = document.getElementById('btn-step-analysis');\n const btnInsights = document.getElementById('btn-step-insights');\n const btnDetails = document.getElementById('btn-step-details');\n const btnAggregate = document.getElementById('btn-step-aggregate');\n const btnEvolution = document.getElementById('btn-step-evolution');\n const btnCourses = document.getElementById('btn-step-courses');\n\n function activateTab(tabName: string) {\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === tabName);\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${tabName}`);\n });\n UrlState.patch({ tab: tabName }, false);\n }\n\n btnLoad?.addEventListener('click', async () => {\n try {\n if (Object.keys(tracks).length > 0 || skippedImports.length > 0 || selectedId !== null) {\n await Storage.openDB();\n await resetBenchmarkState();\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n const payloads = await preloadBenchmarkFiles();\n const loadedFiles: File[] = payloads.map((p) => p.file);\n await handleFiles(loadedFiles);\n const allTracks = Object.values(tracks);\n if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id);\n } finally {\n window.dispatchEvent(new CustomEvent('load-and-parse-complete'));\n }\n });\n\n btnAnalysis?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('graphs');\n if (!selectedId && allTracks.length > 0) {\n selectTrack(allTracks[0].id);\n }\n ChartView.restoreSelection(120, 900, true);\n ChartView.setCursorAt(300, true);\n const availableMetrics = ChartView.getAvailableMetrics();\n const analysisMetrics = ['elevation', 'speed', 'power'].filter((m) =>\n availableMetrics.has(m),\n );\n if (analysisMetrics.length > 0) {\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const metric = (el as HTMLElement).dataset.metric;\n if (metric) el.classList.toggle('active', analysisMetrics.includes(metric));\n });\n updateToolbarLayout();\n ChartView.setActiveMetrics(analysisMetrics);\n } else {\n updateToolbarLayout();\n }\n onChartRangeChange(120, 900, ChartView.getXAxis(), false);\n } finally {\n window.dispatchEvent(new CustomEvent('analysis-complete'));\n }\n });\n\n btnInsights?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t));\n activateTab('insights');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderInsights(primaryTrack);\n } finally {\n window.dispatchEvent(new CustomEvent('insights-complete'));\n }\n });\n\n btnDetails?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('details');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderDetails(primaryTrack, getGlobalTags());\n } finally {\n window.dispatchEvent(new CustomEvent('details-complete'));\n }\n });\n\n btnAggregate?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n if (allTracks.length >= 2) {\n const selectedTwo = [allTracks[0], allTracks[1]];\n activateTab('combined');\n renderCombined(selectedTwo);\n resizeCombined();\n }\n } finally {\n window.dispatchEvent(new CustomEvent('aggregate-complete'));\n }\n });\n\n btnEvolution?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('evolution');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderEvolution(primaryTrack, allTracks, (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n } finally {\n window.dispatchEvent(new CustomEvent('evolution-complete'));\n }\n });\n\n btnCourses?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('courses');\n prepareBenchmarkCourses(allTracks);\n renderCourses();\n selectCourse('course-1', true);\n } finally {\n window.dispatchEvent(new CustomEvent('courses-complete'));\n }\n });\n\n (window as any).benchmarkSteps = {\n loadAndParseFiles: () => document.getElementById('btn-step-load')?.click(),\n displayAnalysisMetrics: () => document.getElementById('btn-step-analysis')?.click(),\n displayInsights: () => document.getElementById('btn-step-insights')?.click(),\n displayDetails: () => document.getElementById('btn-step-details')?.click(),\n displayAggregateMetrics: () => document.getElementById('btn-step-aggregate')?.click(),\n displayEvolutionMetrics: () => document.getElementById('btn-step-evolution')?.click(),\n displayCourses: () => document.getElementById('btn-step-courses')?.click(),\n };\n}\n\nasync function processAndLoadTrack(t: TrackData) {\n // Migration: re-calculate stats if new insights are missing or old format\n const powerCurveEntries = t.stats.powerCurve ? Object.values(t.stats.powerCurve) : [];\n\n const needsEnrich =\n t.points.length > 1 && (t.points[1].speed === undefined || t.points[1].gradient === undefined);\n\n const needsRecalc =\n needsEnrich ||\n !t.stats.powerCurve ||\n !t.stats.hrZones ||\n !t.stats.hrCurve ||\n t.stats.shifts === undefined ||\n t.stats.avgBattery === undefined ||\n t.stats.avgTemp === undefined ||\n (powerCurveEntries.length > 0 && typeof (powerCurveEntries[0] as any) === 'number') ||\n ((t.stats.duration || 0) > 10800 * 1000 && t.stats.powerCurve && !t.stats.powerCurve[14400]);\n\n if (needsRecalc) {\n if (needsEnrich) t.points = Parsers.enrichPoints(t.points);\n t.stats = Parsers.computeStats(t.points);\n await Storage.save(t);\n }\n\n tracks[t.id] = t;\n colorIdx = Math.max(colorIdx, TRACK_COLORS.indexOf(t.color) + 1);\n MapView.addTrack(t);\n MapView.setTrackVisible(t.id, t.visible && !t._filtered);\n renderTrackList(); // Progressive list update\n}\n\nfunction initResizeHandle() {\n const handle = document.getElementById('resize-handle');\n const panel = document.getElementById('chart-panel');\n if (!handle || !panel) return;\n\n let isDragging = false;\n\n handle.addEventListener('mousedown', () => {\n isDragging = true;\n document.body.style.cursor = 'ns-resize';\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const h = window.innerHeight - e.clientY;\n const clampedH = Math.max(100, Math.min(window.innerHeight - 100, h));\n panel.style.height = `${clampedH}px`;\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n document.body.style.cursor = '';\n });\n}\n\nfunction initSidebarResizer() {\n const resizer = document.getElementById('sidebar-resizer');\n const sidebar = document.getElementById('sidebar');\n if (!resizer || !sidebar) return;\n\n let isDragging = false;\n\n resizer.addEventListener('mousedown', () => {\n isDragging = true;\n resizer.classList.add('dragging');\n document.body.classList.add('dragging-sidebar');\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const w = e.clientX;\n const clampedW = Math.max(200, Math.min(600, w));\n sidebar.style.width = `${clampedW}px`;\n sidebar.style.setProperty('--sidebar-w', `${clampedW}px`);\n ChartView.resize();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n resizer.classList.remove('dragging');\n document.body.classList.remove('dragging-sidebar');\n });\n}\n\n// \u2500\u2500 Event Handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction onMapMove(lat: number, lng: number, zoom: number) {\n UrlState.patch({ map_pos: [lat, lng, zoom] });\n}\n\nfunction onMapPointClick(id: string, idx: number) {\n selectTrack(id, false);\n ChartView.setCursorAt(idx);\n}\n\nfunction onMapDblClick() {\n // MapView.fitAll();\n}\n\nfunction onChartCursorMove(pt: TrackPoint | null) {\n if (pt && pt.lat != null && pt.lon != null) {\n MapView.showCursorAt(pt.lat, pt.lon);\n if (followDot) MapView.centerOn(pt.lat, pt.lon, null, true);\n } else {\n MapView.hideCursor();\n }\n}\n\nfunction onChartRangeChange(min: number | null, max: number | null, axis: string, fit = false) {\n if (!selectedId || !tracks[selectedId]) return;\n const t = tracks[selectedId];\n\n if (min === null || max === null) {\n MapView.clearHighlight();\n if (t && (UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n UrlState.patch({ sel: null });\n return;\n }\n\n // Find point indices\n const pts = t.points;\n let iMin = 0,\n iMax = pts.length - 1;\n\n if (axis === 'distance') {\n const d0 = min * 1000,\n d1 = max * 1000;\n iMin = pts.findIndex((p) => (p.dist || 0) >= d0);\n iMax = pts.findIndex((p) => (p.dist || 0) >= d1);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const ts0 = t0 + min * 1000,\n ts1 = t0 + max * 1000;\n iMin = pts.findIndex((p) => (p.time || 0) >= ts0);\n iMax = pts.findIndex((p) => (p.time || 0) >= ts1);\n }\n\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = pts.length - 1;\n\n // Compute selection stats\n const selPts = pts.slice(iMin, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n if ((UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n\n MapView.highlightSegment(selectedId, pts, iMin, iMax, fit, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n UrlState.patch({ sel: [min, max] });\n}\n\nfunction onChartClick(pt: TrackPoint, idx: number) {\n if (pt && pt.lat != null && pt.lon != null) MapView.centerOn(pt.lat, pt.lon, POINT_ZOOM_LEVEL);\n}\n\nexport function selectTrack(id: string, fit = true, deferChartRender = false) {\n if (!tracks[id]) return;\n if (id === selectedId) {\n if (fit) MapView.fitTrack(id);\n return;\n }\n\n const hadSelected = selectedId !== null;\n if (hadSelected) {\n // Clear current views immediately before loading new data\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n }\n\n selectedId = id;\n\n // Fully reset metric coloring when switching tracks\n currentMapColors = null;\n MapView.clearMetricColor(id);\n if (hadSelected) {\n ChartView.toggleMapColor(null); // Ensure ChartView state also resets\n }\n\n // Clear selection on new track\n UrlState.patch({ track: id, sel: null }, true);\n if (hadSelected) {\n ChartView.cancelSelection();\n }\n\n // Update UI immediately\n renderTrackList();\n\n // Render details\n const activeTab = UrlState.get().tab || 'graphs';\n if (activeTab === 'details') renderDetails(tracks[id], getGlobalTags());\n if (activeTab === 'insights') renderInsights(tracks[id]);\n if (activeTab === 'combined') renderCombined(tracks[id]);\n if (activeTab === 'courses') renderCourses();\n if (activeTab === 'evolution') {\n renderEvolution(tracks[id], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n\n // Tell sub-views\n MapView.setSelectedTrack(id, fit);\n if (fit) MapView.fitTrack(id);\n ChartView.loadTrack(tracks[id], Object.values(tracks), deferChartRender);\n}\n\nasync function deleteTrack(id: string) {\n await Storage.remove(id);\n MapView.removeTrack(id);\n delete tracks[id];\n if (selectedId === id) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n UrlState.patch({ track: null, sel: null, sel_point: null });\n }\n applyFilters();\n}\n\nasync function clearAll() {\n const code = Math.floor(10 + Math.random() * 90).toString();\n\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n backdrop.innerHTML = `\n
\n
Delete all tracks?
\n
\n This will permanently remove all tracks from your browser storage. This action cannot be undone.\n
\n
\n
Enter \"${code}\" to confirm:
\n \n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const input = backdrop.querySelector('.modal-input') as HTMLInputElement;\n const btnConfirm = backdrop.querySelector('.modal-btn.confirm') as HTMLButtonElement;\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n\n input.focus();\n\n input.addEventListener('input', () => {\n btnConfirm.disabled = input.value !== code;\n });\n\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n\n btnConfirm.addEventListener('click', async () => {\n if (input.value !== code) return;\n close();\n\n cancelProcessing = true;\n await Storage.clear();\n\n tracks = {};\n selectedId = null;\n MapView.clearHighlight();\n window.location.reload();\n });\n}\n\nfunction applyFilters(skipRender = false) {\n const ids = Object.keys(tracks);\n ids.forEach((id) => {\n const t = tracks[id];\n const s = t.stats;\n let visible = true;\n\n // Search query\n if (searchQuery) {\n if (searchRegex) {\n try {\n const re = new RegExp(searchQuery, 'i');\n if (!re.test(t.name)) visible = false;\n } catch (e) {\n visible = false;\n }\n } else {\n if (!t.name.toLowerCase().includes(searchQuery.toLowerCase())) visible = false;\n }\n }\n\n // Date filter\n if (visible && (filters.date[0] || filters.date[1])) {\n const start = filters.date[0] ? new Date(filters.date[0]).getTime() : 0;\n const end = filters.date[1] ? new Date(filters.date[1]).getTime() : Infinity;\n const t0 = s.startTime || 0;\n if (t0 < start || t0 > end) visible = false;\n }\n\n // Distance filter\n if (visible && (filters.dist[0] !== null || filters.dist[1] !== null)) {\n const min = (filters.dist[0] || 0) * 1000;\n const max = (filters.dist[1] || Infinity) * 1000;\n if (s.totalDist < min || s.totalDist > max) visible = false;\n }\n\n // Duration filter\n if (visible && (filters.dur[0] !== null || filters.dur[1] !== null)) {\n const min = (filters.dur[0] || 0) * 60000;\n const max = (filters.dur[1] || Infinity) * 60000;\n const d = s.duration || 0;\n if (d < min || d > max) visible = false;\n }\n\n // Metrics filter\n if (visible && filters.metrics.size > 0) {\n for (const m of filters.metrics) {\n const field = ChartView.METRICS[m].field;\n if (!t.points.some((p: any) => p[field] != null)) {\n visible = false;\n break;\n }\n }\n }\n\n // Sport filter\n if (visible && filters.sport) {\n if (t.sport !== filters.sport) visible = false;\n }\n\n // Tags filter\n if (visible && filters.tags.length > 0) {\n const trackTags = t.tags || [];\n if (!filters.tags.every((ft) => trackTags.includes(ft))) visible = false;\n }\n\n t._filtered = !visible;\n MapView.setTrackVisible(t.id, t.visible && visible);\n });\n\n if (!skipRender) renderTrackList();\n}\n\nfunction updateFilterUI() {\n (document.getElementById('filter-date-start') as HTMLInputElement).value = filters.date[0] || '';\n (document.getElementById('filter-date-end') as HTMLInputElement).value = filters.date[1] || '';\n (document.getElementById('filter-dist-min') as HTMLInputElement).value =\n filters.dist[0] !== null ? String(filters.dist[0]) : '';\n (document.getElementById('filter-dist-max') as HTMLInputElement).value =\n filters.dist[1] !== null ? String(filters.dist[1]) : '';\n (document.getElementById('filter-dur-min') as HTMLInputElement).value =\n filters.dur[0] !== null ? String(filters.dur[0]) : '';\n (document.getElementById('filter-dur-max') as HTMLInputElement).value =\n filters.dur[1] !== null ? String(filters.dur[1]) : '';\n (document.getElementById('filter-tags') as HTMLInputElement).value = filters.tags.join(', ');\n\n document\n .querySelectorAll('#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item')\n .forEach((el) => {\n const item = el as HTMLElement;\n item.classList.toggle('active', (item.dataset.sport || '') === (filters.sport || ''));\n });\n\n document.querySelectorAll('#filter-metrics .mini-pill').forEach((el) => {\n const btn = el as HTMLElement;\n btn.classList.toggle('active', filters.metrics.has(btn.dataset.metric!));\n });\n\n const activeCount =\n (filters.date[0] ? 1 : 0) +\n (filters.date[1] ? 1 : 0) +\n (filters.dist[0] !== null ? 1 : 0) +\n (filters.dist[1] !== null ? 1 : 0) +\n (filters.dur[0] !== null ? 1 : 0) +\n (filters.dur[1] !== null ? 1 : 0) +\n filters.metrics.size +\n (filters.tags.length > 0 ? 1 : 0);\n\n const badge = document.querySelector('#btn-toggle-filters .btn-badge');\n if (badge) {\n badge.textContent = activeCount > 0 ? String(activeCount) : '';\n badge.classList.toggle('hidden', activeCount === 0);\n }\n}\n\nfunction updateSearchSortUI() {\n const searchInput = document.getElementById('track-search') as HTMLInputElement;\n if (searchInput) searchInput.value = searchQuery;\n document.getElementById('btn-regex-toggle')?.classList.toggle('active', searchRegex);\n\n const opt = SORT_OPTIONS.find((o) => o.val === currentSort);\n if (opt) {\n const labelEl = document.getElementById('sort-current-label');\n const iconEl = document.getElementById('sort-current-icon');\n if (labelEl)\n labelEl.textContent = opt.label\n .replace(' first', '')\n .replace(' distance', '')\n .replace(' duration', '');\n if (iconEl) iconEl.textContent = opt.icon;\n }\n}\n\nfunction applyState(urlState: AppState) {\n // Restore track\n const newTrackId = urlState.track;\n if (newTrackId !== selectedId) {\n if (newTrackId && tracks[newTrackId]) {\n selectTrack(newTrackId, true);\n } else if (!newTrackId && selectedId) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n renderTrackList();\n MapView.fitAll();\n }\n }\n\n // Restore basemap\n if (urlState.map && typeof urlState.map === 'string') {\n MapView.switchBasemap(urlState.map);\n document\n .querySelectorAll('.bm-btn')\n .forEach((b) =>\n b.classList.toggle('active', (b as HTMLElement).dataset.layer === urlState.map),\n );\n }\n\n // Restore map position\n if (urlState.map_pos) {\n const [lat, lng, zoom] = urlState.map_pos;\n MapView.setPosition(lat, lng, zoom);\n }\n\n // Restore tab\n if (urlState.tab) {\n document.querySelectorAll('.tab-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n if (b.dataset.tab === urlState.tab) {\n if (!b.classList.contains('active')) b.click();\n }\n });\n }\n\n // Restore x-axis mode\n if (urlState.xaxis) ChartView.setXAxis(urlState.xaxis);\n\n const currentXAxis = urlState.xaxis || 'time';\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', (b as HTMLElement).dataset.axis === currentXAxis));\n\n // Restore active metrics\n if (urlState.metrics) {\n const metrics = ChartView.METRICS;\n const keys = urlState.metrics\n .map((abbr) => Object.keys(metrics).find((k) => metrics[k].abbr === abbr))\n .filter((k): k is string => k !== undefined);\n if (keys.length) ChartView.setActiveMetrics(keys);\n }\n\n // Restore filters\n if (urlState.f_date)\n filters.date = urlState.f_date.map((v) => v || null) as [string | null, string | null];\n if (urlState.f_dist)\n filters.dist = urlState.f_dist.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_dur)\n filters.dur = urlState.f_dur.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_mets) filters.metrics = new Set(urlState.f_mets);\n if (urlState.f_tags) filters.tags = urlState.f_tags;\n\n updateFilterUI();\n\n if (urlState.q) searchQuery = urlState.q;\n if (urlState.re) searchRegex = urlState.re;\n if (urlState.sort) currentSort = urlState.sort;\n updateSearchSortUI();\n\n applyFilters();\n}\n\nfunction updateSportFilterOptions() {\n const container = document.getElementById('sport-filter-container');\n if (!container) return;\n\n const commonContainer = document.getElementById('common-sports');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n if (!commonContainer || !dropdownContent) return;\n\n const sports = new Set();\n Object.values(tracks).forEach((t) => {\n if (t.sport) sports.add(t.sport);\n });\n\n const sportsArray = Array.from(sports).sort();\n const burgerDropdown = document.getElementById('sport-burger-dropdown');\n\n commonContainer.innerHTML = '';\n dropdownContent.innerHTML = '';\n\n if (sportsArray.length <= 4) {\n if (burgerDropdown) burgerDropdown.style.display = 'none';\n\n sportsArray.forEach((sport) => {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n });\n } else {\n if (burgerDropdown) burgerDropdown.style.display = 'inline-block';\n\n const commonSports = ['running', 'cycling', 'walking'];\n\n commonSports.forEach((sport) => {\n if (sports.has(sport)) {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n }\n });\n\n sportsArray.forEach((sport) => {\n const item = document.createElement('div');\n item.className = `dropdown-item${filters.sport === sport ? ' active' : ''}`;\n item.dataset.sport = sport;\n item.style.padding = '8px';\n item.style.cursor = 'pointer';\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '8px';\n item.innerHTML = `\n ${getSportIcon(sport)}\n ${sport.charAt(0).toUpperCase() + sport.slice(1)}\n `;\n dropdownContent.appendChild(item);\n });\n }\n}\n\nfunction renderTrackList() {\n updateSportFilterOptions();\n const list = document.getElementById('track-list');\n const emptyEl = document.getElementById('track-list-empty') as HTMLElement;\n const headerLabel = document.querySelector('.section-label');\n if (!list) return;\n\n const ids = Object.keys(tracks).filter((id) => !tracks[id]._filtered);\n if (headerLabel) headerLabel.textContent = `Tracks (${ids.length})`;\n\n if (!ids.length) {\n list.innerHTML = '';\n if (emptyEl) {\n list.appendChild(emptyEl);\n emptyEl.style.display = 'block';\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n list.innerHTML = '';\n\n ids\n .sort((a, b) => {\n // Current selected always first\n if (a === selectedId) return -1;\n if (b === selectedId) return 1;\n\n const ta = tracks[a],\n tb = tracks[b];\n const sa = ta.stats,\n sb = tb.stats;\n\n let cmp = 0;\n switch (currentSort) {\n case 'date-asc':\n cmp = (sa.startTime || 0) - (sb.startTime || 0);\n break;\n case 'date-desc':\n cmp = (sb.startTime || 0) - (sa.startTime || 0);\n break;\n case 'dist-asc':\n cmp = (sa.totalDist || 0) - (sb.totalDist || 0);\n break;\n case 'dist-desc':\n cmp = (sb.totalDist || 0) - (sa.totalDist || 0);\n break;\n case 'dur-asc':\n cmp = (sa.duration || 0) - (sb.duration || 0);\n break;\n case 'dur-desc':\n cmp = (sb.duration || 0) - (sa.duration || 0);\n break;\n default:\n cmp = 0;\n }\n return cmp || a.localeCompare(b);\n })\n .forEach((id) => {\n list.appendChild(buildTrackItem(tracks[id]));\n });\n}\n\nfunction getGlobalTags(): string[] {\n const all = new Set();\n Object.values(tracks).forEach((t) => {\n (t.tags || []).forEach((tag) => all.add(tag));\n });\n return Array.from(all).sort();\n}\n\nfunction getSportIcon(sport: string | null): string {\n if (!sport) return 'category';\n const s = sport.toLowerCase();\n if (s.includes('run')) return 'directions_run';\n if (s.includes('cycl') || s.includes('bike')) return 'directions_bike';\n if (s.includes('walk')) return 'directions_walk';\n if (s.includes('swim')) return 'pool';\n if (s.includes('hik')) return 'hiking';\n return 'sports';\n}\n\nfunction buildTrackItem(track: TrackData) {\n const item = document.createElement('div');\n item.className = `track-item${track.id === selectedId ? ' selected' : ''}`;\n item.dataset.id = track.id;\n\n const date =\n track.points.length && track.points[0].time ? fmtDate(track.points[0].time) : 'Unknown date';\n\n const tagsHtml =\n (track.tags || []).length > 0\n ? `
${(track.tags || [])\n .map((t) => {\n const c = getTagColor(t);\n return `${escHtml(t)}`;\n })\n .join('')}
`\n : '';\n\n item.innerHTML = `\n
\n
\n
${escHtml(track.displayName || track.name)}
\n
\n
\n ${date}\n ${Math.round(track.stats.totalDist / 1000)} km\n ${track.sport ? `${getSportIcon(track.sport)}` : ''}\n ${track.format.toUpperCase()}\n
\n \n
\n ${tagsHtml}\n
\n `;\n\n item.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.icon-btn')) return;\n selectTrack(track.id);\n });\n\n const btnVis = item.querySelector('.toggle-vis') as HTMLElement;\n btnVis.addEventListener('click', () => {\n track.visible = !track.visible;\n btnVis.querySelector('.material-symbols-rounded')!.textContent = track.visible\n ? 'visibility'\n : 'visibility_off';\n MapView.setTrackVisible(track.id, track.visible);\n Storage.save(track);\n });\n\n return item;\n}\n\nfunction showToast(msg: string, type: 'info' | 'error' = 'info') {\n const container = document.getElementById('toast-container');\n if (!container) return;\n container.innerHTML = '';\n const t = document.createElement('div');\n t.className = `toast ${type}`;\n t.textContent = msg;\n container.appendChild(t);\n}\n\nfunction showSkippedImportsModal() {\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n let listHtml = '';\n skippedImports.forEach((s) => {\n listHtml += `
${s.name}: ${s.reason}
`;\n });\n\n backdrop.innerHTML = `\n
\n
Skipped Imports
\n
\n ${listHtml || '
No skipped imports.
'}\n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n const btnClear = backdrop.querySelector('.modal-btn.clear') as HTMLButtonElement;\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n btnClear.addEventListener('click', () => {\n skippedImports = [];\n close();\n const importWarning = document.getElementById('import-warning');\n if (importWarning) importWarning.classList.add('hidden');\n });\n\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n}\n\nfunction initDropZone() {\n const zone = document.getElementById('drop-zone');\n if (!zone) return;\n\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n importWarning.addEventListener('click', (e) => {\n e.stopPropagation();\n showSkippedImportsModal();\n });\n }\n\n window.addEventListener('dragover', (e) => {\n e.preventDefault();\n zone.classList.add('drop-active');\n });\n\n window.addEventListener('dragleave', (e) => {\n if (e.relatedTarget === null) zone.classList.remove('drop-active');\n });\n\n window.addEventListener('drop', async (e) => {\n e.preventDefault();\n zone.classList.remove('drop-active');\n\n const items = e.dataTransfer?.items;\n if (!items) return;\n\n const files: File[] = [];\n const queue: FileSystemEntry[] = [];\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i].webkitGetAsEntry();\n if (entry) queue.push(entry);\n }\n\n async function readAllEntries(entry: FileSystemEntry) {\n if (entry.isFile) {\n const file = await new Promise((res) => (entry as FileSystemFileEntry).file(res));\n files.push(file);\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n let entries: FileSystemEntry[] = [];\n let chunk: FileSystemEntry[];\n do {\n chunk = await new Promise((res) => reader.readEntries(res));\n entries.push(...chunk);\n } while (chunk.length > 0);\n\n for (const child of entries) await readAllEntries(child);\n }\n }\n\n for (const entry of queue) await readAllEntries(entry);\n\n if (files.length) handleFiles(files);\n });\n}\n\nasync function handleFiles(files: File[]) {\n if (!files.length) return;\n cancelProcessing = false;\n const initialSkipCount = skippedImports.length;\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const loaderClose = document.getElementById('loader-close');\n\n if (loaderClose) {\n loaderClose.addEventListener('click', () => {\n cancelProcessing = true;\n if (loader) loader.classList.add('hidden');\n });\n }\n\n function updateLoaderIconToWarning() {\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'warning';\n loaderIcon.style.color = '#f59e0b';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n const count = skippedImports.length - initialSkipCount;\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = `${count}`;\n warningCount.style.display = 'flex';\n }\n }\n\n if (loader) {\n if (loaderText)\n loaderText.textContent = `Importing ${files.length} file${files.length > 1 ? 's' : ''}`;\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'download';\n loaderIcon.style.color = 'var(--accent)';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n warningCount.style.display = 'none';\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = '0';\n }\n if (loaderSubtext) loaderSubtext.textContent = '';\n if (progressBar) progressBar.style.width = '0%';\n loader.classList.remove('hidden');\n\n if (skippedImports.length > initialSkipCount) updateLoaderIconToWarning();\n }\n\n try {\n let count = 0;\n let firstId: string | null = null;\n let processedSinceLastUpdate = 0;\n\n // Filter out obviously invalid files early\n const validFiles = files.filter((f) => {\n const name = f.name.toLowerCase();\n return (\n name.endsWith('.gpx') ||\n name.endsWith('.fit') ||\n name.endsWith('.tcx') ||\n name.endsWith('.kml')\n );\n });\n\n const invalidFiles = files.filter((f) => !validFiles.includes(f));\n invalidFiles.forEach((f) => {\n skippedImports.push({ name: f.name, reason: 'Unsupported file format' });\n });\n\n if (validFiles.length === 0) {\n if (files.length > 0) {\n showToast('No valid GPS files found', 'error');\n // Still update warning icon if there were invalid files!\n const importWarning = document.getElementById('import-warning');\n if (importWarning && skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n }\n }\n return;\n }\n\n const loaderFilename = document.getElementById('loader-filename');\n let progressIdxEl: HTMLElement | null = null;\n if (loaderSubtext) {\n loaderSubtext.innerHTML =\n '';\n progressIdxEl = loaderSubtext.querySelector('.progress-index') as HTMLElement | null;\n const totalEl = loaderSubtext.querySelector('.progress-total');\n if (totalEl) totalEl.textContent = validFiles.length.toString();\n }\n\n for (let i = 0; i < validFiles.length; i++) {\n if (cancelProcessing) break;\n const f = validFiles[i];\n if (loaderFilename) loaderFilename.textContent = f.name;\n if (progressIdxEl) progressIdxEl.textContent = (i + 1).toString();\n if (progressBar) progressBar.style.width = `${(i / validFiles.length) * 100}%`;\n\n try {\n const data = await Parsers.parseFile(f);\n\n // Duplicate checks\n const existingTracks = Object.values(tracks);\n\n // Rule 1: Same file and same size\n const sameFile = existingTracks.find((t) => t.fileName === f.name && t.fileSize === f.size);\n if (sameFile) {\n skippedImports.push({ name: f.name, reason: 'Same File' });\n updateLoaderIconToWarning();\n continue;\n }\n\n // Rule 2 & 3: Same start day checks\n const newStart = data.stats.startTime;\n const newDuration = data.stats.duration;\n\n if (newStart != null && newDuration != null) {\n const newEnd = newStart + newDuration;\n const sameDayTracks = existingTracks.filter(\n (t) => t.stats.startTime != null && isSameDay(newStart, t.stats.startTime!),\n );\n\n let discarded = false;\n for (const ext of sameDayTracks) {\n const extStart = ext.stats.startTime!;\n const extDuration = ext.stats.duration!;\n const extEnd = extStart + extDuration;\n\n // Rule 2: Fully contained\n if (newStart >= extStart && newEnd <= extEnd) {\n skippedImports.push({ name: f.name, reason: 'Fully contained in another track' });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n\n // Rule 3: Overlaps for > 10 mins\n const overlap = Math.min(newEnd, extEnd) - Math.max(newStart, extStart);\n if (overlap > 600000) {\n // 10 mins in ms\n skippedImports.push({\n name: f.name,\n reason: 'Overlaps with an existing track for more than 10 mins',\n });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n }\n if (discarded) continue;\n }\n\n const fallbackTime = 1785542400000;\n let id = compactId(data.stats.startTime || fallbackTime);\n if (tracks[id]) id += `-${shortRandom()}`;\n\n // Use filename as activity name if internal name is generic\n let trackName = data.name;\n if (trackName.startsWith('Unnamed') || trackName.startsWith('Fit Activity'))\n trackName = f.name;\n\n // Generate a nice display name\n let displayName = trackName;\n const t0 = data.points[0]?.time;\n const sport = data.sport\n ? data.sport.charAt(0).toUpperCase() + data.sport.slice(1)\n : 'Activity';\n if (t0) {\n const d = new Date(t0);\n displayName = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')} ${sport}`;\n } else {\n displayName = trackName.replace(/\\.[^/.]+$/, '').replace(/_/g, ' '); // Remove extension and replace underscores\n }\n\n const track: TrackData = {\n ...data,\n id,\n name: trackName,\n displayName,\n fileName: f.name,\n fileSize: f.size,\n bounds: calculateBounds(data.points) || undefined,\n simplifiedPoints: simplifyTrack(data.points, 50), // 50m resolution\n addedAt: data.stats.startTime || fallbackTime,\n visible: true,\n color: TRACK_COLORS[colorIdx % TRACK_COLORS.length],\n };\n colorIdx++;\n if (cancelProcessing) break;\n\n await Storage.save(track);\n tracks[id] = track;\n MapView.addTrack(track);\n if (!firstId) firstId = id;\n count++;\n processedSinceLastUpdate++;\n\n if (processedSinceLastUpdate >= 5) {\n processedSinceLastUpdate = 0;\n }\n } catch (err) {\n skippedImports.push({\n name: f.name,\n reason: `Parse error: ${err instanceof Error ? err.message : String(err)}`,\n });\n updateLoaderIconToWarning();\n }\n }\n\n // Update warning icon\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n if (skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n } else {\n importWarning.classList.add('hidden');\n }\n }\n\n const newWarnings = skippedImports.length > initialSkipCount;\n if (!newWarnings && loader) {\n loader.classList.add('hidden');\n }\n\n if (count > 0) {\n showToast(`Imported ${count} track${count > 1 ? 's' : ''}`);\n applyFilters(!!firstId && firstId !== selectedId);\n if (firstId) selectTrack(firstId);\n }\n\n if (newWarnings) {\n const loaderIcon = document.querySelector('.loader-icon-wrap span');\n if (loaderIcon) loaderIcon.textContent = 'warning';\n // Delay hiding loader to let user see the alert icon\n await new Promise((r) => setTimeout(r, 1500));\n }\n } finally {\n if (loader) loader.classList.add('hidden');\n }\n}\n\nfunction initMetricPillDraggable() {\n const container = document.getElementById('metric-pills');\n if (!container) return;\n\n let draggedEl: HTMLElement | null = null;\n\n container.addEventListener('dragstart', (e) => {\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (!target) return;\n draggedEl = target;\n e.dataTransfer!.effectAllowed = 'move';\n target.classList.add('dragging-pill');\n // For transparent background in ghost image\n setTimeout(() => (target.style.opacity = '0.4'), 0);\n });\n\n container.addEventListener('dragover', (e) => {\n e.preventDefault();\n e.dataTransfer!.dropEffect = 'move';\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (target && target !== draggedEl) {\n const rect = target.getBoundingClientRect();\n const next = e.clientX - rect.left > rect.width / 2;\n container.insertBefore(draggedEl!, next ? target.nextSibling : target);\n }\n });\n\n container.addEventListener('dragend', () => {\n if (!draggedEl) return;\n draggedEl.classList.remove('dragging-pill');\n draggedEl.style.opacity = '';\n draggedEl = null;\n\n // Update Chart order\n const keys = Array.from(container.querySelectorAll('.metric-pill')).map(\n (el) => (el as HTMLElement).dataset.metric!,\n );\n ChartView.updateMetricOrder(keys);\n syncMetricsToUrl();\n });\n}\n\nfunction updateToolbarLayout() {\n const toolbar = document.getElementById('chart-toolbar');\n const pills = document.getElementById('metric-pills');\n if (!toolbar || !pills) return;\n\n toolbar.classList.remove('collapsed');\n const availableW = Math.max(0, toolbar.clientWidth - 280);\n let totalW = 0;\n let hidden = false;\n\n Array.from(pills.children).forEach((el) => {\n const htmlEl = el as HTMLElement;\n if (htmlEl.id === 'pill-overflow') return;\n\n htmlEl.classList.remove('overflow-hidden');\n if (!htmlEl.classList.contains('active')) return;\n const metricKey = htmlEl.dataset.metric || '';\n const deterministicPillWidth = 36 + metricKey.length * 6;\n totalW += deterministicPillWidth + 6;\n\n if (totalW > availableW) {\n hidden = true;\n htmlEl.classList.add('overflow-hidden');\n }\n });\n\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.toggle('hidden', !hidden);\n\n if (hidden) toolbar.classList.add('collapsed');\n}\n\ndocument.addEventListener('DOMContentLoaded', init);\n"], + "mappings": "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", + "names": ["UrlState", "_state", "_lastSearch", "_syncTimeout", "_shouldPush", "read", "p", "s", "metricsRaw", "v", "isDesc", "field", "parts", "_sync", "dir", "search", "val", "url", "get", "patch", "partial", "push", "k", "key", "refresh", "reset", "InMemoryStorage", "track", "id", "key", "value", "IndexedDBStorage", "resolve", "reject", "req", "db", "name", "mode", "res", "rej", "tx", "activeDriver", "Storage", "UrlState", "t", "k", "v", "FitParser", "haversine", "lat1", "lon1", "lat2", "lon2", "phi1", "phi2", "deltaPhi", "deltaLambda", "a", "compactId", "timestamp", "buf", "shortRandom", "fmtDuration", "s", "fmtSecs", "h", "m", "fmtPace", "seconds", "mins", "secs", "fmtDate", "ts", "d", "fmtDateTime", "iso", "fmtFileSize", "bytes", "k", "sizes", "i", "escHtml", "str", "getTagColor", "name", "hash", "gaussianSmooth", "data", "sigma", "size", "kernel", "half", "sum", "x", "result", "val", "weightSum", "idx", "hexToRgba", "hex", "alpha", "r", "g", "b", "calculateBounds", "pts", "minLat", "maxLat", "minLon", "maxLon", "p", "simplifyTrack", "minDistanceMeters", "result", "lastPoint", "i", "haversine", "Parsers", "enrichPoints", "totalDist", "prev", "d", "dt", "de", "hrZoneThresholds", "ftp", "computeStats", "includeCurves", "stats", "powerSum", "powerN", "hrSum", "hrN", "cadSum", "cadN", "speedSum", "speedN", "batterySum", "batteryN", "tempSum", "tempN", "hasTemp", "shifts", "hasGears", "diff", "t0", "t1", "calculateHRZones", "calculateHRCurve", "calculatePowerCurve", "calculatePowerZones", "ensureCurvesAndZones", "track", "s", "STANDARD_CURVE_DURATIONS", "calculateSlidingMax", "data", "durations", "len", "prefix", "curve", "hasAny", "di", "maxSum", "bestIdx", "limit", "j", "currentSum", "powerData", "nonZero", "v", "hrData", "zones", "thresholds", "t", "pw", "z", "setFTP", "val", "getFTP", "hr", "setHRZones", "getHRZones", "extractXmlTag", "block", "openTag", "closeTag", "start", "extractXmlAttr", "tagOpen", "attrPrefix", "cachedDateKey", "cachedDayMs", "parseIntSlice", "text", "end", "neg", "c0", "digits", "c", "parseFloatSlice", "intPart", "fracPart", "fracDiv", "inFrac", "n", "res", "fastParseTimeSlice", "y", "m", "key", "hh", "mm", "ss", "ms", "extractAttrFloat", "vStart", "parseGPX", "buf", "predecodedText", "firstTrkpt", "header", "trkIdx", "name", "gpxOpenEnd", "device", "points", "pos", "trkStart", "openEnd", "trkEnd", "lat", "lon", "ele", "time", "cad", "power", "temp", "speed", "gearFront", "gearRear", "gearFrontTooth", "gearRearTooth", "battery", "lt", "gt", "c1", "tagLen", "nextLt", "vEnd", "expectedCloseGt", "closeGt", "gears", "parseTCX", "firstTp", "creatorBlock", "tpStart", "tpEnd", "fastDecodeFitData", "dv", "headerSize", "dataSize", "endOffset", "GARMIN_EPOCH_SEC", "SEMICIRCLE_TO_DEG", "defs", "file_ids", "sessions", "records", "events", "device_infos", "offset", "hdr", "localNum", "littleEndian", "globalMsgNum", "numFields", "fields", "recordSize", "num", "size", "type", "def", "le", "gNum", "ts", "rawLat", "rawLon", "rawAlt", "rawDist", "rawSpd", "msg", "fOff", "f", "bType", "sportMap", "evName", "parseFIT", "resolve", "reject", "handleParsedFitData", "error", "devices", "sport", "subSport", "getDeviceName", "fid", "antId", "existing", "statusReports", "idx", "a", "b", "gearEvents", "e", "front", "rear", "frontTooth", "rearTooth", "ft", "fg", "rt", "rg", "lastBattery", "statusIdx", "lastFrontGear", "lastRearGear", "lastFrontTooth", "lastRearTooth", "gearIdx", "validPoints", "ri", "r", "ex", "fastData", "FitParser", "parseKML", "doc", "nameEl", "coordEls", "el", "line", "parts", "parseFile", "file", "ext", "MapView", "trackData", "customClickHandler", "init", "onSelectCb", "onMoveCb", "onPointClickCb", "onPointHoverCb", "onDblClickCb", "switchBasemap", "layer", "addTrack", "t", "addTracks", "ts", "removeTrack", "id", "clearTracks", "removeAllTracks", "setTrackVisible", "visible", "setSelectedTrack", "fit", "fitAll", "fitTrack", "showCursorAt", "lat", "lon", "hideCursor", "highlightSegment", "pts", "start", "end", "colors", "clearHighlight", "setTrackHover", "hover", "ensureVisible", "centerOn", "zoom", "force", "closePopup", "invalidateSize", "getPosition", "setPosition", "lng", "colorTrackByMetric", "clearMetricColor", "findTracksPassingThroughPoints", "points", "radius", "handler", "uPlot", "Zones", "getPowerZones", "ftp", "Parsers", "thresholds", "t", "names", "colors", "zones", "last", "i", "getHRZones", "Metrics", "METRICS", "v", "p", "pts", "fillNulls", "vam", "i", "prev", "de", "dt", "SPORTS", "getSportIcon", "sport", "key", "ChartView", "plots", "renderedTrack", "renderedXAxis", "renderedSpeedMode", "renderedMapColorMetric", "syncKey", "scaleSyncing", "cursorSyncing", "activeMetrics", "availableMetrics", "smoothedMetrics", "metricsIncludingZero", "xAxis", "currentTrack", "allTracks", "selAnchorVal", "selEndVal", "isDragging", "updatingRange", "pinnedPtIdx", "lastMouseXVal", "lastHistMouseEvent", "hoveredHistData", "hoveredHistCanvas", "currentXRange", "targetXRange", "animId", "onCursorMoveCb", "onRangeChangeCb", "onClickCb", "onPinChangeCb", "HIST_W", "ROW_BODY_PADDING", "HIST_GAP", "statsVisible", "histTooltipEl", "container", "emptyEl", "selStatsEl", "resetSelBtn", "mapColorMetric", "onMapColorChangeCb", "init", "onCursorMove", "onRangeChange", "onClick", "onPinChange", "updateHistTooltip", "uPlot", "cancelSelection", "navKeys", "activeNavKeys", "e", "key", "u", "min", "max", "moveStep", "zoomFactor", "newMin", "newMax", "center", "factor", "xFull", "d", "setVisibleRange", "animate", "startMin", "startMax", "lerp", "a", "b", "t", "step", "tMin", "tMax", "cMin", "cMax", "loadTrack", "track", "others", "deferRender", "METRICS", "def", "p", "m", "el", "pill", "metric", "isAvailable", "updateStats", "render", "clear", "destroyPlots", "chartStats", "clearSelectionStats", "resetState", "overflowEl", "toolbar", "toggleMetric", "setActiveMetrics", "keys", "setXAxis", "axis", "pts", "t0", "convert", "val", "idx", "dTarget", "tTarget", "newRange", "r0", "r1", "toggleStats", "histCol", "resize", "setMapColorChangeCb", "cb", "toggleMapColor", "_updateMapColorBtns", "_fireMapColorCb", "plot", "colors", "_computePointColors", "yData", "vals", "v", "sport", "sportDef", "SPORTS", "defaultMode", "speedMode", "UrlState", "paceUnit", "gradientColor", "speed", "speedColor", "lerpHex", "resetZoom", "updateSelOverlay", "redrawHistograms", "xData", "setSelectionStats", "stats", "fmt", "id", "fmtSecs", "restoreSelection", "totalDuration", "tOffset", "xMin", "xMax", "updateAnchorLines", "w", "anyResized", "histCanvas", "histData", "drawHistogram", "keepState", "savedRange", "savedScroll", "available", "containerW", "canReuse", "lastValidX", "existingByKey", "availSet", "isSmoothed", "isIncZero", "nextSiblingRows", "nextExisting", "i", "ex", "reused", "uplot", "s", "prevSync", "initHoverBinI", "buildHistBins", "span", "transform", "fmtAxis", "unit", "label", "fmtPace", "fillNulls", "gaussianSmooth", "createChart", "metricKey", "initialRange", "insertBeforeEl", "gradData", "smoothGradient", "row", "header", "labelEl", "smoothBtn", "mapColorBtn", "zeroBtn", "incZero", "statsTotalEl", "statsSelEl", "statsContainer", "actionsEl", "rightActionsEl", "paceToggle", "btn", "mode", "isDefault", "rowBody", "plotEl", "fixedMinLabel", "fixedMaxLabel", "isDistAxis", "formatX", "range", "dec", "absV", "h", "hh", "mm", "ss", "incZeroDefault", "gMin", "gMax", "allSum", "allCount", "filtMin", "filtMax", "filtSum", "filtCount", "fullStatsAll", "fullStatsFiltered", "gPad", "fixedYRange", "statsTotalInitialized", "updateHeaderStats", "visibleMin", "visibleMax", "getHtml", "isFull", "rangeStats", "es", "elevationRangeStats", "initializingScale", "uOpts", "_si", "_u", "mn", "mx", "axisIdx", "scaleMin", "scaleMax", "targetLabels", "idealIncr", "incrs", "incr", "splits", "precision", "pos", "top", "drawTrackPath", "drawElevationGradient", "drawGradientChart", "drawMetricColorFill", "drawPinnedDot", "drawYAxisHighlight", "hIdx", "hasPinned", "hasHover", "cy", "drawVerticalLineOnly", "hexToRgba", "ctx", "dpr", "bb", "ax", "fontSize", "fontStr", "tw", "visibleL", "visibleR", "padH", "padV", "bw", "bh", "bx", "by", "drawXAxisLabels", "showHover", "updateTooltip", "binI", "other", "left", "width", "overlay", "selFill", "anchorLine", "anchorLabel", "anchorHandle", "anchorMarker", "endLine", "endLabel", "endHandle", "endMarker", "curYVal", "pinYVal", "self", "attachHandleDrag", "mousedownX", "rect", "attachHistTooltip", "aX", "eX", "overW", "overH", "plotBottom", "isAnchorVisible", "isEndVisible", "fillL", "fillR", "aText", "fmtXVal", "aLabelW", "aIcon", "eText", "eLabelW", "eIcon", "handleEl", "isAnchor", "startX", "startVal", "pxPerUnit", "onMove", "me", "dx", "newVal", "onUp", "BINS", "lo", "hi", "cnt", "bins", "binAccum", "k", "bi", "prev", "next", "canvas", "chartH", "hoverBinI", "hasSel", "selBins", "selBinAccum", "x", "W", "H", "peak", "pad", "plotW", "plotH", "binY", "binH", "baseAlpha", "total", "pts2", "cumSum", "my", "cp", "font9", "avgY", "minLabelY", "maxLabelY", "labelHeight", "countLower", "countHigher", "pLower", "pHigher", "font8", "textY", "fontB10", "midX", "getBinAt", "lineEl", "relY", "rawI", "count", "pct", "low", "high", "zoneHtml", "mid", "zones", "Zones", "zIdx", "z", "finalZIdx", "totalAccum", "totalPct", "html", "stotalAccum", "stotalPct", "ttH", "ttW", "binCenterY", "sum", "n", "gain", "loss", "prevEle", "isDist", "diff", "cx", "gColor", "g", "p0", "p1", "content", "front", "rear", "color44", "gradientColorRgbaCache", "gradientColorRgba", "c", "yMin", "yMax", "xScale", "yScale", "yBase", "idxs", "iStart", "iEnd", "byColor", "prevIdx", "xv1", "xv0", "x0", "y0", "x1", "y1", "color", "segs", "j", "drawHoverLine", "xVal", "opacity", "skipLine", "distVal", "timeVal", "bottomLabel", "topLabel", "drawPill", "text", "y", "isTop", "rx", "clampedRx", "ry", "pillH", "yVal", "cyClamp", "drawAreaFillAbove", "yDir", "yMult", "inSegment", "hasAnySegment", "lastPx", "xv", "yv", "px", "py", "ah", "ar", "ag", "ab", "br", "bg", "rr", "rg", "rb", "absG", "kmh", "windowMetres", "grads", "j0", "j1", "data", "res", "right", "getAvg", "avgSpeed", "avgPower", "avgCadence", "newActive", "isStepped", "drawBackgroundTracks", "GAP_THRESHOLD", "field", "first", "prevP", "prevXVal", "lastFrontGear", "fMin", "fMax", "fg", "rMin", "rMax", "isTimeAxis", "gapSec", "prevDrawnI", "prevX", "prevY", "segmentColor", "prevXv", "SENSOR_ICONS", "Metrics", "onTagsChangeCb", "onDeleteTrackCb", "initDetails", "onTagsChange", "onDeleteTrack", "resetDetails", "container", "renderDetails", "track", "globalTags", "s", "t0", "pts", "stabilityWindows", "stabilityFields", "stabilityAccum", "pass", "w", "f", "sum", "sumSq", "autoCov", "halfW", "i", "v", "old", "mean", "variance", "lagVal", "telemetryStabilityPct", "escHtml", "t", "fmtSecs", "fmtFileSize", "getSportIcon", "SPORTS", "fmtDateTime", "sensor", "seen", "d", "key", "name", "manufacturer", "extra", "battery", "sourceIcon", "st", "deviceIcon", "nameLower", "tagContainer", "tagInput", "addBtn", "renderTags", "tags", "tag", "c", "getTagColor", "el", "btn", "e", "Storage", "addTag", "val", "titleInput", "sportTrigger", "showSportMenu", "anchorEl", "popup", "def", "item", "isActive", "iconEl", "nameEl", "clearItem", "isClear", "rect", "closeHandler", "uPlot", "courses", "getCoursesForTrack", "track", "c", "pt", "passesPoint", "trackPt", "haversine", "activeCourseId", "isEditMode", "openCourseId", "toastFn", "courseLayer", "initCourses", "showToast", "toastFn", "loadCourses", "resetCourses", "courses", "activeCourseId", "openCourseId", "isEditMode", "container", "prepareBenchmarkCourses", "allTracks", "i", "pStart", "pMid", "pEnd", "stored", "Storage", "saveCourses", "calculateCourseDistance", "course", "total", "p1", "p2", "haversine", "findCourseRange", "track", "coursePoints", "currentPtIdx", "startIdx", "endIdx", "tp", "cp", "calculateCourseStats", "points", "startTime", "duration", "totalPower", "powerCount", "totalHR", "hrCount", "totalSpeed", "speedCount", "totalCadence", "cadenceCount", "totalAscent", "p", "prev", "de", "dist", "formatDuration", "seconds", "h", "m", "s", "renderCourseTableHeaders", "METRICS", "renderCourseTableCells", "stats", "sport", "dateStr", "paceUnit", "SPORTS", "paceStr", "paceSeconds", "fmtPace", "renderCourses", "corridorDeviationSum", "c", "candidateIds", "MapView", "numGates", "gates", "g", "segFloat", "segIdx", "frac", "pA", "pB", "id", "pts", "gate", "minDist", "bestIdx", "d", "matchingIds", "isOpen", "tracksHtml", "matchedTracksWithStats", "range", "fmtDate", "t", "a", "b", "UrlState", "escHtml", "createNewCourse", "el", "e", "editCourse", "renameCourse", "deleteCourse", "selectCourse", "row", "trackId", "selectTrack", "t0", "sIdx", "eIdx", "tMin", "tMax", "axis", "ChartView", "selMin", "selMax", "name", "newCourse", "nameEl", "currentName", "input", "save", "newName", "clearCourseLayer", "courseLayer", "selectCourse", "id", "open", "activeCourseId", "openCourseId", "isEditMode", "MapView", "clearCourseLayer", "renderCourses", "deleteCourse", "courses", "c", "saveCourses", "toastFn", "insightPlots", "destroyInsightPlots", "p", "initInsights", "showToast", "resetInsights", "el", "container", "renderInsights", "track", "s", "Parsers", "pts", "cp", "tauCandidates", "minWPrimeBal", "pass", "ti", "tau", "decay", "wBal", "efSum1", "efSum2", "half", "i", "h", "ef", "grid", "chartWidth", "renderCurveCard", "Metrics", "card", "metricKey", "color", "isMapColored", "ChartView", "totalTime", "a", "b", "zones", "Zones", "zonesHtml", "time", "z", "pct", "rangeText", "fmtSecs", "e", "current", "btn", "showPowerZoneSettings", "showHRZoneSettings", "climbingCard", "distKm", "grade", "effCard", "trackCourses", "getCoursesForTrack", "coursesCard", "renderCourseTableHeaders", "c", "range", "findCourseRange", "statsHtml", "stats", "calculateCourseStats", "startTime", "dateStr", "fmtDate", "renderCourseTableCells", "escHtml", "courseId", "selectCourse", "UrlState", "course", "MapView", "opts", "curve", "label", "unit", "icon", "tableWrap", "toggleBtn", "toggleIcon", "isHidden", "mapColorBtn", "key", "tbody", "durations", "d", "entry", "val", "row", "fmtDuration", "startIdx", "duration", "endIdx", "t0", "tMin", "tMax", "chartEl", "xData", "yData", "curYVal", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "idx", "hasFocus", "mousePy", "pointPy", "cx", "cy", "durVal", "pcx", "pcy", "plot", "uPlot", "anchorEl", "popup", "rect", "inputs", "newZones", "Storage", "dismiss", "ftp", "input", "newFtp", "uPlot", "currentTracks", "currentTrack", "plot", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "playIntervalId", "isPolar", "updateSliderLabel", "sliderVal", "timeSecs", "fmtSecs", "resetCombined", "playIntervalId", "plot", "currentTracks", "currentTrack", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "isPolar", "tooltip", "container", "renderCombined", "trackOrTracks", "track", "metrics", "ChartView", "availableMetrics", "key", "def", "p", "xDef", "yDef", "summaryHtml", "aggPts", "corrSum", "windows", "pass", "w", "i", "j", "ptsA", "ptsB", "len", "sumA", "sumB", "sumCadA", "sumCadB", "k", "pA", "pB", "oldA", "oldB", "t1", "t2", "s1", "s2", "distDiff", "pwrDiff", "hrDiff", "eleDiff", "shiftsDiff", "totalDist", "totalElev", "totalDur", "avgPwr", "maxPwr", "avgHr", "maxHr", "tempDiff", "avgTemp", "maxTemp", "totalShifts", "fmtSecs", "e", "showMenu", "slider", "sliderVal", "playBtn", "updateSliderLabel", "startPlaying", "stopPlaying", "updatePlot", "resizeCombined", "plotContainer", "h", "size", "anchorEl", "axis", "el", "popup", "item", "currentVal", "rect", "close", "pts1", "pts2", "maxLen", "xData", "yData1", "yData2", "p1", "p2", "width", "height", "opts", "uPlot", "pts", "t0", "chronoData", "idx", "x", "y", "t", "d", "xVals", "yVals", "xMin", "xMax", "yMin", "yMax", "xVal", "yVal", "theta", "r", "px", "py", "a", "b", "yData", "hexToRgba", "u", "vals", "v", "seriesIdx", "dataIdx", "cursorLeft", "cursorTop", "minD2", "closestIdx", "cx", "cy", "dx", "dy", "d2", "ctx", "dpr", "started", "startIdx", "endIdx", "xVal1", "yVal1", "xVal2", "yVal2", "cx1", "cy1", "cx2", "cy2", "progress", "lineWidth", "alpha", "fillAlpha", "timeSecs", "distKm", "origX", "origY", "canvasRect", "originalIdx", "uPlot", "computeAccumulatedMetric", "allTracks", "extractor", "refTs", "i", "st", "now", "currentYear", "oneYearAgoMs", "sixMonthsAgoMs", "oneMonthAgoMs", "currentYearVal", "pastYearVal", "past6mVal", "past1mVal", "totalVal", "minTime", "t", "val", "time", "msecPerWeek", "currentYearStart", "currentYearWeeks", "pastYearWeeks", "past6mWeeks", "past1mWeeks", "totalWeeks", "renderAccumulatedTable", "accumulated", "isDistance", "unit", "factor", "format", "evolutionPlots", "destroyEvolutionPlots", "p", "resetEvolution", "container", "renderEvolution", "currentTrack", "allTracks", "onTrackSelect", "onDateRangeSelect", "currentRange", "UrlState", "track", "Parsers", "totalFatigue", "totalFitness", "alphaATL", "alphaCTL", "pts", "atl", "ctl", "i", "stress", "cards", "Metrics", "grid", "gridWidth", "progressSync", "uPlot", "renderProgressCard", "distanceScroll", "elevationScroll", "toolbarRangeCtrl", "btn", "range", "b", "onRangeChange", "pill", "target", "onPinChange", "dur", "c", "t", "card", "renderCurveEvolutionCard", "opts", "metricKey", "label", "unit", "color", "icon", "trackName", "mainChart", "cardContainer", "row1", "legendEl", "row2", "sideBySide", "chartEl", "maxCurve", "curve", "name", "date", "fmtDate", "trackInfo", "data", "d", "val", "currentCurve", "allDurations", "durations", "a", "xData", "yDataCurrent", "entry", "yDataMax", "validTracks", "xTimeline", "yTimelineData", "currentDur", "tracksFiltered", "pinnedDur", "getFilteredData", "maxTime", "minTime", "filteredIndices", "idx", "xFiltered", "rawY", "rawYFiltered", "smoothedYFiltered", "gaussianSmooth", "timelineChart", "curYVal", "optsUPlot", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "fmtDuration", "pcx", "pcy", "curVal", "dotRadius", "dotColor", "activeSeriesIdx", "cursorLeft", "cursorTop", "minD2", "nearestIdx", "radius", "maxD2", "yCur", "yMax", "px", "py", "dx", "dy", "d2", "xValStr", "xbw", "pillH", "xLabelX", "clampedXBx", "xLabelY", "yValStr", "ybw", "yLabelX", "yLabelY", "cx", "cy", "durVal", "mxVal", "html", "lowerBound", "upperBound", "labelEl", "clickedDur", "newPinnedDur", "stats", "bestIdx", "duration", "startPt", "endPt", "trackStart", "min", "max", "detailsEl", "cur", "mx", "mxId", "mxIdx", "e", "id", "lastNearestIdx", "timelineEl", "timelineTooltip", "dataTimeline", "series", "optsTimeline", "ts", "tpcx", "tpcy", "tctx", "tdpr", "dateStr", "valStr", "yData", "y", "getWeekStart", "day", "diff", "computeWeeklyDistance", "weeklyData", "weekStart", "weekKey", "week", "computeWeeklyElevation", "type", "syncKey", "isDistance", "accumulated", "computeAccumulatedMetric", "renderAccumulatedTable", "yAxisEl", "tooltip", "yDataSmoothed", "chartClientW", "width", "maxVal", "mainOpts", "item", "start", "end", "startStr", "endStr", "self", "splits", "s", "scrollContainer", "filteredData", "newXData", "newYData", "newYDataSmoothed", "newWidth", "newMaxVal", "TRACK_COLORS", "POINT_ZOOM_LEVEL", "tracks", "skippedImports", "isSameDay", "t1", "t2", "d1", "d2", "cancelProcessing", "selectedId", "colorIdx", "followDot", "currentMapColors", "searchQuery", "searchRegex", "currentSort", "filters", "syncFiltersToUrl", "push", "UrlState", "v", "syncMetricsToUrl", "active", "ChartView", "metrics", "abbrs", "key", "SORT_OPTIONS", "showSortMenu", "anchorEl", "el", "popup", "opt", "item", "updateSearchSortUI", "renderTrackList", "rect", "close", "e", "showMetricMenu", "available", "def", "isNowActive", "pill", "updateToolbarLayout", "id", "idx", "dur", "selectTrack", "t", "pts", "pIdx", "t0", "p", "tMin", "tMax", "iMax", "selPts", "stats", "Parsers", "renderInsights", "MapView", "btn", "nav", "b", "tab", "panel", "c", "renderDetails", "getGlobalTags", "renderEvolution", "trackId", "range", "onChartRangeChange", "start", "end", "applyFilters", "updateFilterUI", "renderCombined", "renderCourses", "s", "resetBenchmarkState", "Storage", "resetCourses", "resetInsights", "resetDetails", "resetCombined", "resetEvolution", "toastContainer", "init", "fontTimerId", "fontTimeout", "resolve", "fontLoadPromise", "storageSelect", "selected", "params", "loader", "loaderText", "loaderSubtext", "progressBar", "mapLoader", "mapLoaderSpan", "urlState", "initInsights", "msg", "type", "showToast", "initDetails", "deleteTrack", "initCourses", "onMapMove", "onMapPointClick", "onMapDblClick", "onChartCursorMove", "onChartClick", "data", "currentUrlState", "applyState", "hrZones", "ftp", "saved", "a", "tracksToLoad", "updated", "calculateBounds", "simplifyTrack", "restoreId", "selectedTrackData", "processAndLoadTrack", "remaining", "index", "loadNextChunk", "initResizeHandle", "initSidebarResizer", "initMetricPillDraggable", "clearAll", "toggleMetric", "metric", "axis", "initDropZone", "handleFiles", "onFilterInput", "val", "burgerBtn", "dropdownContent", "isVisible", "target", "selectedSport", "m", "resizeCombined", "initBenchmarkTriggers", "preloadBenchmarkFiles", "readyEl", "camelReadyEl", "preloadedBenchmarkPayloads", "fileNames", "decoder", "name", "buf", "cleanName", "bytes", "ds", "stream", "text", "file", "warmSample", "parsed", "warmPts", "warmTrack", "r", "btnLoad", "btnAnalysis", "btnInsights", "btnDetails", "btnAggregate", "btnEvolution", "btnCourses", "activateTab", "tabName", "loadedFiles", "allTracks", "availableMetrics", "analysisMetrics", "primaryTrack", "selectedTwo", "prepareBenchmarkCourses", "selectCourse", "powerCurveEntries", "needsEnrich", "handle", "isDragging", "h", "clampedH", "resizer", "sidebar", "w", "clampedW", "lat", "lng", "zoom", "pt", "min", "max", "fit", "iMin", "d0", "ts0", "ts1", "deferChartRender", "hadSelected", "activeTab", "code", "backdrop", "input", "btnConfirm", "btnCancel", "skipRender", "visible", "d", "field", "trackTags", "ft", "activeCount", "badge", "searchInput", "o", "labelEl", "iconEl", "newTrackId", "currentXAxis", "keys", "abbr", "k", "updateSportFilterOptions", "commonContainer", "sports", "sportsArray", "burgerDropdown", "sport", "getSportIcon", "list", "emptyEl", "headerLabel", "ids", "ta", "tb", "sa", "sb", "cmp", "buildTrackItem", "all", "tag", "track", "date", "fmtDate", "tagsHtml", "getTagColor", "escHtml", "btnVis", "container", "showSkippedImportsModal", "listHtml", "btnClear", "importWarning", "zone", "items", "files", "queue", "i", "entry", "readAllEntries", "res", "reader", "entries", "chunk", "child", "initialSkipCount", "loaderClose", "updateLoaderIconToWarning", "loaderIcon", "warningCount", "count", "countSpan", "firstId", "processedSinceLastUpdate", "validFiles", "f", "loaderFilename", "progressIdxEl", "totalEl", "existingTracks", "newStart", "newDuration", "newEnd", "sameDayTracks", "discarded", "ext", "extStart", "extDuration", "extEnd", "fallbackTime", "compactId", "shortRandom", "trackName", "displayName", "err", "newWarnings", "draggedEl", "next", "toolbar", "pills", "availableW", "totalW", "hidden", "htmlEl", "deterministicPillWidth", "overflowEl"] +} diff --git a/suites-experimental/tools-gps-tracks/dist/uplot.mjs b/suites-experimental/tools-gps-tracks/dist/uplot.mjs new file mode 100644 index 0000000000..17114aaf87 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/uplot.mjs @@ -0,0 +1,4 @@ +var De="u-",Qs="uplot",Xs=De+"hz",er=De+"vt",tr=De+"title",lr=De+"wrap",nr=De+"under",ir=De+"over",or=De+"axis",Qt=De+"off",sr=De+"select",rr=De+"cursor-x",fr=De+"cursor-y",ur=De+"cursor-pt",cr=De+"legend",ar=De+"live",pr=De+"inline",hr=De+"series",mr=De+"marker",$i=De+"label",gr=De+"value",Gl="width",Il="height",Ol="top",Ji="bottom",vl="left",In="right",oi="#000",Zi=oi+"0",Yn="mousemove",Qi="mousedown",Bn="mouseup",Xi="mouseenter",eo="mouseleave",to="dblclick",dr="resize",wr="scroll",lo="change",fn="dppxchange",si="--",El=typeof window<"u",$n=El?document:null,xl=El?window:null,Sr=El?navigator:null,oe,nn;function Jn(){let e=devicePixelRatio;oe!=e&&(oe=e,nn&&Qn(lo,nn,Jn),nn=matchMedia(`(min-resolution: ${oe-.001}dppx) and (max-resolution: ${oe+.001}dppx)`),Xt(lo,nn,Jn),xl.dispatchEvent(new CustomEvent(fn)))}function et(e,i){if(i!=null){let o=e.classList;!o.contains(i)&&o.add(i)}}function Zn(e,i){let o=e.classList;o.contains(i)&&o.remove(i)}function de(e,i,o){e.style[i]=o+"px"}function dt(e,i,o,n){let s=$n.createElement(e);return i!=null&&et(s,i),o?.insertBefore(s,n),s}function ut(e,i){return dt("div",e,i)}var no=new WeakMap;function Mt(e,i,o,n,s){let a="translate("+i+"px,"+o+"px)",u=no.get(e);a!=u&&(e.style.transform=a,no.set(e,a),i<0||o<0||i>n||o>s?et(e,Qt):Zn(e,Qt))}var io=new WeakMap;function oo(e,i,o){let n=i+o,s=io.get(e);n!=s&&(io.set(e,n),e.style.background=i,e.style.borderColor=o)}var so=new WeakMap;function ro(e,i,o,n){let s=i+""+o,a=so.get(e);s!=a&&(so.set(e,s),e.style.height=o+"px",e.style.width=i+"px",e.style.marginLeft=n?-i/2+"px":0,e.style.marginTop=n?-o/2+"px":0)}var ri={passive:!0},_r={...ri,capture:!0};function Xt(e,i,o,n){i.addEventListener(e,o,n?_r:ri)}function Qn(e,i,o,n){i.removeEventListener(e,o,ri)}El&&Jn();function wt(e,i,o,n){let s;o=o||0,n=n||i.length-1;let a=n<=2147483647;for(;n-o>1;)s=a?o+n>>1:tt((o+n)/2),i[s]{let a=-1,u=-1;for(let h=n;h<=s;h++)if(e(o[h])){a=h;break}for(let h=s;h>=n;h--)if(e(o[h])){u=h;break}return[a,u]}}var Ho=e=>e!=null,No=e=>e!=null&&e>0,an=Fo(Ho),yr=Fo(No);function vr(e,i,o,n=0,s=!1){let a=s?yr:an,u=s?No:Ho;[i,o]=a(e,i,o);let h=e[i],m=e[i];if(i>-1)if(n==1)h=e[i],m=e[o];else if(n==-1)h=e[o],m=e[i];else for(let g=i;g<=o;g++){let y=e[g];u(y)&&(ym&&(m=y))}return[h??ce,m??-ce]}function pn(e,i,o,n){let s=co(e),a=co(i);e==i&&(s==-1?(e*=o,i/=o):(e/=o,i*=o));let u=o==10?Lt:Oo,h=s==1?tt:ct,m=a==1?ct:tt,g=h(u(Ee(e))),y=m(u(Ee(i))),d=bl(o,g),w=bl(o,y);return o==10&&(g<0&&(d=ae(d,-g)),y<0&&(w=ae(w,-y))),n||o==2?(e=d*s,i=w*a):(e=Yo(e,d),i=hn(i,w)),[e,i]}function fi(e,i,o,n){let s=pn(e,i,o,n);return e==0&&(s[0]=0),i==0&&(s[1]=0),s}var ui=.1,fo={mode:3,pad:ui},Bl={pad:0,soft:null,mode:0},kr={min:Bl,max:Bl};function un(e,i,o,n){return mn(o)?uo(e,i,o):(Bl.pad=o,Bl.soft=n?0:null,Bl.mode=n?3:0,uo(e,i,kr))}function ne(e,i){return e??i}function xr(e,i,o){for(i=ne(i,0),o=ne(o,e.length-1);i<=o;){if(e[i]!=null)return!0;i++}return!1}function uo(e,i,o){let n=o.min,s=o.max,a=ne(n.pad,0),u=ne(s.pad,0),h=ne(n.hard,-ce),m=ne(s.hard,ce),g=ne(n.soft,ce),y=ne(s.soft,-ce),d=ne(n.mode,0),w=ne(s.mode,0),P=i-e,L=Lt(P),H=Be(Ee(e),Ee(i)),O=Lt(H),G=Ee(O-L);(P<1e-24||G>10)&&(P=0,(e==0||i==0)&&(P=1e-24,d==2&&g!=ce&&(a=0),w==2&&y!=-ce&&(u=0)));let k=P||H||1e3,N=Lt(k),x=bl(10,tt(N)),q=k*(P==0?e==0?.1:1:a),D=ae(Yo(e-q,x/10),24),$=e>=g&&(d==1||d==3&&D<=g||d==2&&D>=g)?g:ce,U=Be(h,D<$&&e>=$?$:St($,D)),Q=k*(P==0?i==0?.1:1:u),B=ae(hn(i+Q,x/10),24),b=i<=y&&(w==1||w==3&&B>=y||w==2&&B<=y)?y:-ce,j=St(m,B>b&&i<=b?b:Be(b,B));return U==j&&U==0&&(j=100),[U,j]}var br=new Intl.NumberFormat(El?Sr.language:"en-US"),ci=e=>br.format(e),lt=Math,rn=lt.PI,Ee=lt.abs,tt=lt.floor,Ae=lt.round,ct=lt.ceil,St=lt.min,Be=lt.max,bl=lt.pow,co=lt.sign,Lt=lt.log10,Oo=lt.log2,Tr=(e,i=1)=>lt.sinh(e)*i,Un=(e,i=1)=>lt.asinh(e/i),ce=1/0;function ao(e){return(Lt((e^e>>31)-(e>>31))|0)+1}function Xn(e,i,o){return St(Be(e,i),o)}function Wo(e){return typeof e=="function"}function X(e){return Wo(e)?e:()=>e}var Mr=()=>{},Go=e=>e,Io=(e,i)=>i,Ar=e=>null,po=e=>!0,ho=(e,i)=>e==i,Er=/\.\d*?(?=9{6,}|0{6,})/gm,el=e=>{if(Uo(e)||Ot.has(e))return e;let i=`${e}`,o=i.match(Er);if(o==null)return e;let n=o[0].length-1;if(i.indexOf("e-")!=-1){let[s,a]=i.split("e");return+`${el(s)}e${a}`}return ae(e,n)};function Jt(e,i){return el(ae(el(e/i))*i)}function hn(e,i){return el(ct(el(e/i))*i)}function Yo(e,i){return el(tt(el(e/i))*i)}function ae(e,i=0){if(Uo(e))return e;let o=10**i,n=e*o*(1+Number.EPSILON);return Ae(n)/o}var Ot=new Map;function Bo(e){return((""+e).split(".")[1]||"").length}function Kl(e,i,o,n){let s=[],a=n.map(Bo);for(let u=i;u=0?0:h)+(u>=a[g]?0:a[g]),w=e==10?y:ae(y,d);s.push(w),Ot.set(w,d)}}return s}var Ul={},ai=[],Tl=[null,null],Nt=Array.isArray,Uo=Number.isInteger,Dr=e=>e===void 0;function mo(e){return typeof e=="string"}function mn(e){let i=!1;if(e!=null){let o=e.constructor;i=o==null||o==Object}return i}function Lr(e){return e!=null&&typeof e=="object"}var Pr=Object.getPrototypeOf(Uint8Array),Ko="__proto__";function Ml(e,i=mn){let o;if(Nt(e)){let n=e.find(s=>s!=null);if(Nt(n)||i(n)){o=Array(e.length);for(let s=0;sa){for(s=u-1;s>=0&&e[s]==null;)e[s--]=null;for(s=u+1;su-h)],s=n[0].length,a=new Map;for(let u=0;u"u"?e=>Promise.resolve().then(e):queueMicrotask;function Nr(e){let i=e[0],o=i.length,n=Array(o);for(let a=0;ai[a]-i[u]);let s=[];for(let a=0;a=n&&e[s]==null;)s--;if(s<=n)return!0;let a=Be(1,tt((s-n+1)/i));for(let u=e[n],h=n+a;h<=s;h+=a){let m=e[h];if(m!=null){if(m<=u)return!1;u=m}}return!0}var jo=["January","February","March","April","May","June","July","August","September","October","November","December"],qo=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];function $o(e){return e.slice(0,3)}var Gr=qo.map($o),Ir=jo.map($o),Yr={MMMM:jo,MMM:Ir,WWWW:qo,WWW:Gr};function Wl(e){return(e<10?"0":"")+e}function Br(e){return(e<10?"00":e<100?"0":"")+e}var Ur={YYYY:e=>e.getFullYear(),YY:e=>(e.getFullYear()+"").slice(2),MMMM:(e,i)=>i.MMMM[e.getMonth()],MMM:(e,i)=>i.MMM[e.getMonth()],MM:e=>Wl(e.getMonth()+1),M:e=>e.getMonth()+1,DD:e=>Wl(e.getDate()),D:e=>e.getDate(),WWWW:(e,i)=>i.WWWW[e.getDay()],WWW:(e,i)=>i.WWW[e.getDay()],HH:e=>Wl(e.getHours()),H:e=>e.getHours(),h:e=>{let i=e.getHours();return i==0?12:i>12?i-12:i},AA:e=>e.getHours()>=12?"PM":"AM",aa:e=>e.getHours()>=12?"pm":"am",a:e=>e.getHours()>=12?"p":"a",mm:e=>Wl(e.getMinutes()),m:e=>e.getMinutes(),ss:e=>Wl(e.getSeconds()),s:e=>e.getSeconds(),fff:e=>Br(e.getMilliseconds())};function pi(e,i){i=i||Yr;let o=[],n=/\{([a-z]+)\}|[^{]+/gi,s;for(;s=n.exec(e);)o.push(s[0][0]=="{"?Ur[s[1]]:s[0]);return a=>{let u="";for(let h=0;he%1==0,cn=[1,2,2.5,5],qr=Kl(10,-32,0,cn),Zo=Kl(10,0,32,cn),$r=Zo.filter(Jo),Zt=qr.concat(Zo),hi=` +`,Qo="{YYYY}",go=hi+Qo,Xo="{M}/{D}",Yl=hi+Xo,on=Yl+"/{YY}",es="{aa}",Jr="{h}:{mm}",kl=Jr+es,wo=hi+kl,So=":{ss}",re=null;function ts(e){let i=e*1e3,o=i*60,n=o*60,s=n*24,a=s*30,u=s*365,m=(e==1?Kl(10,0,3,cn).filter(Jo):Kl(10,-3,0,cn)).concat([i,i*5,i*10,i*15,i*30,o,o*5,o*10,o*15,o*30,n,n*2,n*3,n*4,n*6,n*8,n*12,s,s*2,s*3,s*4,s*5,s*6,s*7,s*8,s*9,s*10,s*15,a,a*2,a*3,a*4,a*6,u,u*2,u*5,u*10,u*25,u*50,u*100]),g=[[u,Qo,re,re,re,re,re,re,1],[s*28,"{MMM}",go,re,re,re,re,re,1],[s,Xo,go,re,re,re,re,re,1],[n,"{h}"+es,on,re,Yl,re,re,re,1],[o,kl,on,re,Yl,re,re,re,1],[i,So,on+" "+kl,re,Yl+" "+kl,re,wo,re,1],[e,So+".{fff}",on+" "+kl,re,Yl+" "+kl,re,wo,re,1]];function y(d){return(w,P,L,H,O,G)=>{let k=[],N=O>=u,x=O>=a&&O=s?s:O,B=tt(L)-tt(D),b=U+B+hn(D-U,Q);k.push(b);let j=d(b),C=j.getHours()+j.getMinutes()/o+j.getSeconds()/n,I=O/n,F=w.axes[P]._space,ee=G/F;for(;b=ae(b+O,e==1?0:3),!(b>H);)if(I>1){let z=tt(ae(C+I,6))%24,te=d(b).getHours()-z;te>1&&(te=-1),b-=te*n,C=(C+I)%24;let fe=k[k.length-1];ae((b-fe)/O,3)*ee>=.7&&k.push(b)}else k.push(b)}return k}}return[m,g,y]}var[Zr,Qr,Xr]=ts(1),[ef,tf,lf]=ts(.001);Kl(2,-53,53,[1]);function _o(e,i){return e.map(o=>o.map((n,s)=>s==0||s==8||n==null?n:i(s==1||o[8]==0?n:o[1]+n)))}function yo(e,i){return(o,n,s,a,u)=>{let h=i.find(L=>u>=L[0])||i[i.length-1],m,g,y,d,w,P;return n.map(L=>{let H=e(L),O=H.getFullYear(),G=H.getMonth(),k=H.getDate(),N=H.getHours(),x=H.getMinutes(),q=H.getSeconds(),D=O!=m&&h[2]||G!=g&&h[3]||k!=y&&h[4]||N!=d&&h[5]||x!=w&&h[6]||q!=P&&h[7]||h[1];return m=O,g=G,y=k,d=N,w=x,P=q,D(H)})}}function nf(e,i){let o=pi(i);return(n,s,a,u,h)=>s.map(m=>o(e(m)))}function Kn(e,i,o){return new Date(e,i,o)}function vo(e,i){return i(e)}var of="{YYYY}-{MM}-{DD} {h}:{mm}{aa}";function ko(e,i){return(o,n,s,a)=>a==null?si:i(e(n))}function sf(e,i){let o=e.series[i];return o.width?o.stroke(e,i):o.points.width?o.points.stroke(e,i):null}function rf(e,i){return e.series[i].fill(e,i)}var ff={show:!0,live:!0,isolate:!1,mount:Mr,markers:{show:!0,width:2,stroke:sf,fill:rf,dash:"solid"},idx:null,idxs:null,values:[]};function uf(e,i){let o=e.cursor.points,n=ut(),s=o.size(e,i);de(n,Gl,s),de(n,Il,s);let a=s/-2;de(n,"marginLeft",a),de(n,"marginTop",a);let u=o.width(e,i,s);return u&&de(n,"borderWidth",u),n}function cf(e,i){let o=e.series[i].points;return o._fill||o._stroke}function af(e,i){let o=e.series[i].points;return o._stroke||o._fill}function pf(e,i){return e.series[i].points.size}var jn=[0,0];function hf(e,i,o){return jn[0]=i,jn[1]=o,jn}function sn(e,i,o,n=!0){return s=>{s.button==0&&(!n||s.target==i)&&o(s)}}function qn(e,i,o,n=!0){return s=>{(!n||s.target==i)&&o(s)}}var mf={show:!0,x:!0,y:!0,lock:!1,move:hf,points:{one:!1,show:uf,size:pf,width:0,stroke:af,fill:cf},bind:{mousedown:sn,mouseup:sn,click:sn,dblclick:sn,mousemove:qn,mouseleave:qn,mouseenter:qn},drag:{setScale:!0,x:!0,y:!1,dist:0,uni:null,click:(e,i)=>{i.stopPropagation(),i.stopImmediatePropagation()},_x:!1,_y:!1},focus:{dist:(e,i,o,n,s)=>n-s,prox:-1,bias:0},hover:{skip:[void 0],prox:null,bias:0},left:-10,top:-10,idx:null,dataIdx:null,idxs:null,event:null},ls={show:!0,stroke:"rgba(0,0,0,0.07)",width:2},mi=be({},ls,{filter:Io}),ns=be({},mi,{size:10}),is=be({},ls,{show:!1}),gi='12px system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',os="bold "+gi,ss=1.5,xo={show:!0,scale:"x",stroke:oi,space:50,gap:5,alignTo:1,size:50,labelGap:0,labelSize:30,labelFont:os,side:2,grid:mi,ticks:ns,border:is,font:gi,lineGap:ss,rotate:0},gf="Value",df="Time",bo={show:!0,scale:"x",auto:!1,sorted:1,min:ce,max:-ce,idxs:[]};function wf(e,i,o,n,s){return i.map(a=>a==null?"":ci(a))}function Sf(e,i,o,n,s,a,u){let h=[],m=Ot.get(s)||0;o=u?o:ae(hn(o,s),m);for(let g=o;g<=n;g=ae(g+s,m))h.push(Object.is(g,-0)?0:g);return h}function ei(e,i,o,n,s,a,u){let h=[],m=e.scales[e.axes[i].scale].log,g=m==10?Lt:Oo,y=tt(g(o));s=bl(m,y),m==10&&(s=Zt[wt(s,Zt)]);let d=o,w=s*m;m==10&&(w=Zt[wt(w,Zt)]);do h.push(d),d=d+s,m==10&&!Ot.has(d)&&(d=ae(d,Ot.get(s))),d>=w&&(s=d,w=s*m,m==10&&(w=Zt[wt(w,Zt)]));while(d<=n);return h}function _f(e,i,o,n,s,a,u){let m=e.scales[e.axes[i].scale].asinh,g=n>m?ei(e,i,Be(m,o),n,s):[m],y=n>=0&&o<=0?[0]:[];return(o<-m?ei(e,i,Be(m,-n),-o,s):[m]).reverse().map(w=>-w).concat(y,g)}var rs=/./,yf=/[12357]/,vf=/[125]/,To=/1/,ti=(e,i,o,n)=>e.map((s,a)=>i==4&&s==0||a%n==0&&o.test(s.toExponential()[s<0?1:0])?s:null);function kf(e,i,o,n,s){let a=e.axes[o],u=a.scale,h=e.scales[u],m=e.valToPos,g=a._space,y=m(10,u),d=m(9,u)-y>=g?rs:m(7,u)-y>=g?yf:m(5,u)-y>=g?vf:To;if(d==To){let w=Ee(m(1,u)-y);if(ws,Eo={show:!0,auto:!0,sorted:0,gaps:fs,alpha:1,facets:[be({},Ao,{scale:"x"}),be({},Ao,{scale:"y"})]},Do={scale:"y",auto:!0,sorted:0,show:!0,spanGaps:!1,gaps:fs,alpha:1,points:{show:Mf,filter:null},values:null,min:ce,max:-ce,idxs:[],path:null,clip:null};function Af(e,i,o,n,s){return o/10}var us={time:!0,auto:!0,distr:1,log:10,asinh:1,min:null,max:null,dir:1,ori:0},Ef=be({},us,{time:!1,ori:1}),Lo={};function cs(e,i){let o=Lo[e];return o||(o={key:e,plots:[],sub(n){o.plots.push(n)},unsub(n){o.plots=o.plots.filter(s=>s!=n)},pub(n,s,a,u,h,m,g){for(let y=0;y{let G=u.pxRound,k=g.dir*(g.ori==0?1:-1),N=g.ori==0?Dl:Ll,x,q;k==1?(x=o,q=n):(x=n,q=o);let D=G(d(h[x],g,H,P)),$=G(w(m[x],y,O,L)),U=G(d(h[q],g,H,P)),Q=G(w(a==1?y.max:y.min,y,O,L)),B=new Path2D(s);return N(B,U,Q),N(B,D,Q),N(B,D,$),B})}function gn(e,i,o,n,s,a){let u=null;if(e.length>0){u=new Path2D;let h=i==0?Sn:Si,m=o;for(let d=0;dw[0]){let P=w[0]-m;P>0&&h(u,m,n,P,n+a),m=w[1]}}let g=o+s-m,y=10;g>0&&h(u,m,n-y/2,g,n+a+y)}return u}function Lf(e,i,o){let n=e[e.length-1];n&&n[0]==i?n[1]=o:e.push([i,o])}function wi(e,i,o,n,s,a,u){let h=[],m=e.length;for(let g=s==1?o:n;g>=o&&g<=n;g+=s)if(i[g]===null){let d=g,w=g;if(s==1)for(;++g<=n&&i[g]===null;)w=g;else for(;--g>=o&&i[g]===null;)w=g;let P=a(e[d]),L=w==d?P:a(e[w]),H=d-s;P=u<=0&&H>=0&&H=0&&G>=0&&G=P&&h.push([P,L])}return h}function Po(e){return e==0?Go:e==1?Ae:i=>Jt(i,e)}function as(e){let i=e==0?dn:wn,o=e==0?(s,a,u,h,m,g)=>{s.arcTo(a,u,h,m,g)}:(s,a,u,h,m,g)=>{s.arcTo(u,a,m,h,g)},n=e==0?(s,a,u,h,m)=>{s.rect(a,u,h,m)}:(s,a,u,h,m)=>{s.rect(u,a,m,h)};return(s,a,u,h,m,g=0,y=0)=>{g==0&&y==0?n(s,a,u,h,m):(g=St(g,h/2,m/2),y=St(y,h/2,m/2),i(s,a+g,u),o(s,a+h,u,a+h,u+m,g),o(s,a+h,u+m,a,u+m,y),o(s,a,u+m,a,u,y),o(s,a,u,a+h,u,g),s.closePath())}}var dn=(e,i,o)=>{e.moveTo(i,o)},wn=(e,i,o)=>{e.moveTo(o,i)},Dl=(e,i,o)=>{e.lineTo(i,o)},Ll=(e,i,o)=>{e.lineTo(o,i)},Sn=as(0),Si=as(1),ps=(e,i,o,n,s,a)=>{e.arc(i,o,n,s,a)},hs=(e,i,o,n,s,a)=>{e.arc(o,i,n,s,a)},ms=(e,i,o,n,s,a,u)=>{e.bezierCurveTo(i,o,n,s,a,u)},gs=(e,i,o,n,s,a,u)=>{e.bezierCurveTo(o,i,s,n,u,a)};function ds(e){return(i,o,n,s,a)=>tl(i,o,(u,h,m,g,y,d,w,P,L,H,O)=>{let{pxRound:G,points:k}=u,N,x;g.ori==0?(N=dn,x=ps):(N=wn,x=hs);let q=ae(k.width*oe,3),D=(k.size-k.width)/2*oe,$=ae(D*2,3),U=new Path2D,Q=new Path2D,{left:B,top:b,width:j,height:C}=i.bbox;Sn(Q,B-$,b-$,j+$*2,C+$*2);let I=F=>{if(m[F]!=null){let ee=G(d(h[F],g,H,P)),z=G(w(m[F],y,O,L));N(U,ee+D,z),x(U,ee,z,D,0,rn*2)}};if(a)a.forEach(I);else for(let F=n;F<=s;F++)I(F);return{stroke:q>0?U:null,fill:U,clip:Q,flags:Al|li}})}function ws(e){return(i,o,n,s,a,u)=>{n!=s&&(a!=n&&u!=n&&e(i,o,n),a!=s&&u!=s&&e(i,o,s),e(i,o,u))}}var Pf=ws(Dl),Cf=ws(Ll);function Ss(e){let i=ne(e?.alignGaps,0);return(o,n,s,a)=>tl(o,n,(u,h,m,g,y,d,w,P,L,H,O)=>{[s,a]=an(m,s,a);let G=u.pxRound,k=C=>G(d(C,g,H,P)),N=C=>G(w(C,y,O,L)),x,q;g.ori==0?(x=Dl,q=Pf):(x=Ll,q=Cf);let D=g.dir*(g.ori==0?1:-1),$={stroke:new Path2D,fill:null,clip:null,band:null,gaps:null,flags:Al},U=$.stroke,Q=!1;if(a-s>=H*4){let C=V=>o.posToVal(V,g.key,!0),I=null,F=null,ee,z,Ke,we=k(h[D==1?s:a]),te=k(h[s]),fe=k(h[a]),J=C(D==1?te+1:fe-1);for(let V=D==1?s:a;V>=s&&V<=a;V+=D){let Te=h[V],Se=(D==1?TeJ)?we:k(Te),se=m[V];Se==we?se!=null?(z=se,I==null?(x(U,Se,N(z)),ee=I=F=z):zF&&(F=z)):se===null&&(Q=!0):(I!=null&&q(U,we,N(I),N(F),N(ee),N(z)),se!=null?(z=se,x(U,Se,N(z)),I=F=ee=z):(I=F=null,se===null&&(Q=!0)),we=Se,J=C(we+D))}I!=null&&I!=F&&Ke!=we&&q(U,we,N(I),N(F),N(ee),N(z))}else for(let C=D==1?s:a;C>=s&&C<=a;C+=D){let I=m[C];I===null?Q=!0:I!=null&&x(U,k(h[C]),N(I))}let[b,j]=di(o,n);if(u.fill!=null||b!=0){let C=$.fill=new Path2D(U),I=u.fillTo(o,n,u.min,u.max,b),F=N(I),ee=k(h[s]),z=k(h[a]);D==-1&&([z,ee]=[ee,z]),x(C,z,F),x(C,ee,F)}if(!u.spanGaps){let C=[];Q&&C.push(...wi(h,m,s,a,D,k,i)),$.gaps=C=u.gaps(o,n,s,a,C),$.clip=gn(C,g.ori,P,L,H,O)}return j!=0&&($.band=j==2?[Pt(o,n,s,a,U,-1),Pt(o,n,s,a,U,1)]:Pt(o,n,s,a,U,j)),$})}function Vf(e){let i=ne(e.align,1),o=ne(e.ascDesc,!1),n=ne(e.alignGaps,0),s=ne(e.extend,!1);return(a,u,h,m)=>tl(a,u,(g,y,d,w,P,L,H,O,G,k,N)=>{[h,m]=an(d,h,m);let x=g.pxRound,{left:q,width:D}=a.bbox,$=te=>x(L(te,w,k,O)),U=te=>x(H(te,P,N,G)),Q=w.ori==0?Dl:Ll,B={stroke:new Path2D,fill:null,clip:null,band:null,gaps:null,flags:Al},b=B.stroke,j=w.dir*(w.ori==0?1:-1),C=U(d[j==1?h:m]),I=$(y[j==1?h:m]),F=I,ee=I;s&&i==-1&&(ee=q,Q(b,ee,C)),Q(b,I,C);for(let te=j==1?h:m;te>=h&&te<=m;te+=j){let fe=d[te];if(fe==null)continue;let J=$(y[te]),V=U(fe);i==1?Q(b,J,C):Q(b,F,V),Q(b,J,V),C=V,F=J}let z=F;s&&i==1&&(z=q+D,Q(b,z,C));let[Ke,we]=di(a,u);if(g.fill!=null||Ke!=0){let te=B.fill=new Path2D(b),fe=g.fillTo(a,u,g.min,g.max,Ke),J=U(fe);Q(te,z,J),Q(te,ee,J)}if(!g.spanGaps){let te=[];te.push(...wi(y,d,h,m,j,$,n));let fe=g.width*oe/2,J=o||i==1?fe:-fe,V=o||i==-1?-fe:fe;te.forEach(Te=>{Te[0]+=J,Te[1]+=V}),B.gaps=te=g.gaps(a,u,h,m,te),B.clip=gn(te,w.ori,O,G,k,N)}return we!=0&&(B.band=we==2?[Pt(a,u,h,m,b,-1),Pt(a,u,h,m,b,1)]:Pt(a,u,h,m,b,we)),B})}function Co(e,i,o,n,s,a,u=ce){if(e.length>1){let h=null;for(let m=0,g=1/0;m{}),{fill:d,stroke:w}=g;return(P,L,H,O)=>tl(P,L,(G,k,N,x,q,D,$,U,Q,B,b)=>{let j=G.pxRound,C=o,I=n*oe,F=h*oe,ee=m*oe,z,Ke;x.ori==0?[z,Ke]=a(P,L):[Ke,z]=a(P,L);let we=x.dir*(x.ori==0?1:-1),te=x.ori==0?Sn:Si,fe=x.ori==0?y:(A,pe,Me,ol,It,yt,Yt)=>{y(A,pe,Me,It,ol,Yt,yt)},J=ne(P.bands,ai).find(A=>A.series[0]==L),V=J!=null?J.dir:0,Te=G.fillTo(P,L,G.min,G.max,V),Oe=j($(Te,q,b,Q)),Se,se,at,$e=B,ye=j(G.width*oe),_t=!1,At=null,nt=null,Ct=null,ll=null;d!=null&&(ye==0||w!=null)&&(_t=!0,At=d.values(P,L,H,O),nt=new Map,new Set(At).forEach(A=>{A!=null&&nt.set(A,new Path2D)}),ye>0&&(Ct=w.values(P,L,H,O),ll=new Map,new Set(Ct).forEach(A=>{A!=null&&ll.set(A,new Path2D)})));let{x0:nl,size:Pl}=g;if(nl!=null&&Pl!=null){C=1,k=nl.values(P,L,H,O),nl.unit==2&&(k=k.map(Me=>P.posToVal(U+Me*B,x.key,!0)));let A=Pl.values(P,L,H,O);Pl.unit==2?se=A[0]*B:se=D(A[0],x,B,U)-D(0,x,B,U),$e=Co(k,N,D,x,B,U,$e),at=$e-se+I}else $e=Co(k,N,D,x,B,U,$e),at=$e*u+I,se=$e-at;at<1&&(at=0),ye>=se/2&&(ye=0),at<5&&(j=Go);let jl=at>0,Wt=$e-at-(jl?ye:0);se=j(Xn(Wt,ee,F)),Se=(C==0?se/2:C==we?0:se)-C*we*((C==0?I/2:0)+(jl?ye/2:0));let We={stroke:null,fill:null,clip:null,band:null,gaps:null,flags:0},il=_t?null:new Path2D,Et=null;if(J!=null)Et=P.data[J.series[1]];else{let{y0:A,y1:pe}=g;A!=null&&pe!=null&&(N=pe.values(P,L,H,O),Et=A.values(P,L,H,O))}let Gt=z*se,K=Ke*se;for(let A=we==1?H:O;A>=H&&A<=O;A+=we){let pe=N[A];if(pe==null)continue;if(Et!=null){let je=Et[A]??0;if(pe-je==0)continue;Oe=$(je,q,b,Q)}let Me=x.distr!=2||g!=null?k[A]:A,ol=D(Me,x,B,U),It=$(ne(pe,Te),q,b,Q),yt=j(ol-Se),Yt=j(Be(It,Oe)),Je=j(St(It,Oe)),it=Yt-Je;if(pe!=null){let je=pe<0?K:Gt,pt=pe<0?Gt:K;_t?(ye>0&&Ct[A]!=null&&te(ll.get(Ct[A]),yt,Je+tt(ye/2),se,Be(0,it-ye),je,pt),At[A]!=null&&te(nt.get(At[A]),yt,Je+tt(ye/2),se,Be(0,it-ye),je,pt)):te(il,yt,Je+tt(ye/2),se,Be(0,it-ye),je,pt),fe(P,L,A,yt-ye/2,Je,se+ye,it)}}return ye>0?We.stroke=_t?ll:il:_t||(We._fill=G.width==0?G._fill:G._stroke??G._fill,We.width=0),We.fill=_t?nt:il,We})}function zf(e,i){let o=ne(i?.alignGaps,0);return(n,s,a,u)=>tl(n,s,(h,m,g,y,d,w,P,L,H,O,G)=>{[a,u]=an(g,a,u);let k=h.pxRound,N=z=>k(w(z,y,O,L)),x=z=>k(P(z,d,G,H)),q,D,$;y.ori==0?(q=dn,$=Dl,D=ms):(q=wn,$=Ll,D=gs);let U=y.dir*(y.ori==0?1:-1),Q=N(m[U==1?a:u]),B=Q,b=[],j=[];for(let z=U==1?a:u;z>=a&&z<=u;z+=U)if(g[z]!=null){let we=m[z],te=N(we);b.push(B=te),j.push(x(g[z]))}let C={stroke:e(b,j,q,$,D,k),fill:null,clip:null,band:null,gaps:null,flags:Al},I=C.stroke,[F,ee]=di(n,s);if(h.fill!=null||F!=0){let z=C.fill=new Path2D(I),Ke=h.fillTo(n,s,h.min,h.max,F),we=x(Ke);$(z,B,we),$(z,Q,we)}if(!h.spanGaps){let z=[];z.push(...wi(m,g,a,u,U,N,o)),C.gaps=z=h.gaps(n,s,a,u,z),C.clip=gn(z,y.ori,L,H,O,G)}return ee!=0&&(C.band=ee==2?[Pt(n,s,a,u,I,-1),Pt(n,s,a,u,I,1)]:Pt(n,s,a,u,I,ee)),C})}function Ff(e){return zf(Hf,e)}function Hf(e,i,o,n,s,a){let u=e.length;if(u<2)return null;let h=new Path2D;if(o(h,e[0],i[0]),u==2)n(h,e[1],i[1]);else{let m=Array(u),g=Array(u-1),y=Array(u-1),d=Array(u-1);for(let w=0;w0!=g[w]>0?m[w]=0:(m[w]=3*(d[w-1]+d[w])/((2*d[w]+d[w-1])/g[w-1]+(d[w]+2*d[w-1])/g[w]),isFinite(m[w])||(m[w]=0));m[u-1]=g[u-2];for(let w=0;w{Ue.pxRatio=oe}));var Nf=Ss(),Of=ds();function Ro(e,i,o,n){return(n?[e[0],e[1]].concat(e.slice(2)):[e[0]].concat(e.slice(1))).map((a,u)=>ii(a,u,i,o))}function Wf(e,i){return e.map((o,n)=>n==0?{}:be({},i,o))}function ii(e,i,o,n){return be({},i==0?o:n,e)}function _s(e,i,o){return i==null?Tl:[i,o]}var Gf=_s;function If(e,i,o){return i==null?Tl:un(i,o,ui,!0)}function ys(e,i,o,n){return i==null?Tl:pn(i,o,e.scales[n].log,!1)}var Yf=ys;function vs(e,i,o,n){return i==null?Tl:fi(i,o,e.scales[n].log,!1)}var Bf=vs;function Uf(e,i,o,n,s){let a=Be(ao(e),ao(i)),u=i-e,h=wt(s/n*u,o);do{let m=o[h],g=n*m/u;if(g>=s&&a+(m<5?Ot.get(m):0)<=17)return[m,g]}while(++h(i=Ae((o=+s)*oe))+"px"),[e,i,o]}function Kf(e){e.show&&[e.font,e.labelFont].forEach(i=>{let o=ae(i[2]*oe,1);i[0]=i[0].replace(/[0-9.]+px/,o+"px"),i[1]=o})}function Ue(e,i,o){let n={mode:ne(e.mode,1)},s=n.mode;function a(t,l,r,f){let c=l.valToPct(t);return f+r*(l.dir==-1?1-c:c)}function u(t,l,r,f){let c=l.valToPct(t);return f+r*(l.dir==-1?c:1-c)}function h(t,l,r,f){return l.ori==0?a(t,l,r,f):u(t,l,r,f)}n.valToPosH=a,n.valToPosV=u;let m=!1;n.status=0;let g=n.root=ut(Qs);if(e.id!=null&&(g.id=e.id),et(g,e.class),e.title){let t=ut(tr,g);t.textContent=e.title}let y=dt("canvas"),d=n.ctx=y.getContext("2d"),w=ut(lr,g);Xt("click",w,t=>{t.target===L&&(he!=dl||_e!=wl)&&He.click(n,t)},!0);let P=n.under=ut(nr,w);w.appendChild(y);let L=n.over=ut(ir,w);e=Ml(e);let H=+ne(e.pxAlign,1),O=Po(H);(e.plugins||[]).forEach(t=>{t.opts&&(e=t.opts(n,e)||e)});let G=e.ms||.001,k=n.series=s==1?Ro(e.series||[],bo,Do,!1):Wf(e.series||[null],Eo),N=n.axes=Ro(e.axes||[],xo,Mo,!0),x=n.scales={},q=n.bands=e.bands||[];q.forEach(t=>{t.fill=X(t.fill||null),t.dir=ne(t.dir,-1)});let D=s==2?k[1].facets[0].scale:k[0].scale,$={axes:Hs,series:Cs},U=(e.drawOrder||["axes","series"]).map(t=>$[t]);function Q(t){let l=t.distr==3?r=>Lt(r>0?r:t.clamp(n,r,t.min,t.max,t.key)):t.distr==4?r=>Un(r,t.asinh):t.distr==100?r=>t.fwd(r):r=>r;return r=>{let f=l(r),{_min:c,_max:p}=t,S=p-c;return(f-c)/S}}function B(t){let l=x[t];if(l==null){let r=(e.scales||Ul)[t]||Ul;if(r.from!=null){B(r.from);let f=be({},x[r.from],r,{key:t});f.valToPct=Q(f),x[t]=f}else{l=x[t]=be({},t==D?us:Ef,r),l.key=t;let f=l.time,c=l.range,p=Nt(c);if((t!=D||s==2&&!f)&&(p&&(c[0]==null||c[1]==null)&&(c={min:c[0]==null?fo:{mode:1,hard:c[0],soft:c[0]},max:c[1]==null?fo:{mode:1,hard:c[1],soft:c[1]}},p=!1),!p&&mn(c))){let S=c;c=(_,v,T)=>v==null?Tl:un(v,T,S)}l.range=X(c||(f?Gf:t==D?l.distr==3?Yf:l.distr==4?Bf:_s:l.distr==3?ys:l.distr==4?vs:If)),l.auto=X(p?!1:l.auto),l.clamp=X(l.clamp||Af),l._min=l._max=null,l.valToPct=Q(l)}}}B("x"),B("y"),s==1&&k.forEach(t=>{B(t.scale)}),N.forEach(t=>{B(t.scale)});for(let t in e.scales)B(t);let b=x[D],j=b.distr,C,I;b.ori==0?(et(g,Xs),C=a,I=u):(et(g,er),C=u,I=a);let F={};for(let t in x){let l=x[t];(l.min!=null||l.max!=null)&&(F[t]={min:l.min,max:l.max},l.min=l.max=null)}let ee=e.tzDate||(t=>new Date(Ae(t/G))),z=e.fmtDate||pi,Ke=G==1?Xr(ee):lf(ee),we=yo(ee,_o(G==1?Qr:tf,z)),te=ko(ee,vo(of,z)),fe=[],J=n.legend=be({},ff,e.legend),V=n.cursor=be({},mf,{drag:{y:s==2}},e.cursor),Te=J.show,Oe=V.show,Se=J.markers;J.idxs=fe,Se.width=X(Se.width),Se.dash=X(Se.dash),Se.stroke=X(Se.stroke),Se.fill=X(Se.fill);let se,at,$e,ye=[],_t=[],At,nt=!1,Ct={};if(J.live){let t=k[1]?k[1].values:null;nt=t!=null,At=nt?t(n,1,0):{_:0};for(let l in At)Ct[l]=si}if(Te)if(se=dt("table",cr,g),$e=dt("tbody",null,se),J.mount(n,se),nt){at=dt("thead",null,se,$e);let t=dt("tr",null,at);dt("th",null,t);for(var ll in At)dt("th",$i,t).textContent=ll}else et(se,pr),J.live&&et(se,ar);let nl={show:!0},Pl={show:!1};function jl(t,l){if(l==0&&(nt||!J.live||s==2))return Tl;let r=[],f=dt("tr",hr,$e,$e.childNodes[l]);et(f,t.class),t.show||et(f,Qt);let c=dt("th",null,f);if(Se.show){let _=ut(mr,c);if(l>0){let v=Se.width(n,l);v&&(_.style.border=v+"px "+Se.dash(n,l)+" "+Se.stroke(n,l)),_.style.background=Se.fill(n,l)}}let p=ut($i,c);t.label instanceof HTMLElement?p.appendChild(t.label):p.textContent=t.label,l>0&&(Se.show||(p.style.color=t.width>0?Se.stroke(n,l):Se.fill(n,l)),We("click",c,_=>{if(V._lock)return;Ut(_);let v=k.indexOf(t);if((_.ctrlKey||_.metaKey)!=J.isolate){let T=k.some((M,E)=>E>0&&E!=v&&M.show);k.forEach((M,E)=>{E>0&&kt(E,T?E==v?nl:Pl:nl,!0,xe.setSeries)})}else kt(v,{show:!t.show},!0,xe.setSeries)},!1),rl&&We(Xi,c,_=>{V._lock||(Ut(_),kt(k.indexOf(t),_l,!0,xe.setSeries))},!1));for(var S in At){let _=dt("td",gr,f);_.textContent="--",r.push(_)}return[f,r]}let Wt=new Map;function We(t,l,r,f=!0){let c=Wt.get(l)||{},p=V.bind[t](n,l,r,f);p&&(Xt(t,l,c[t]=p),Wt.set(l,c))}function il(t,l,r){let f=Wt.get(l)||{};for(let c in f)(t==null||c==t)&&(Qn(c,l,f[c]),delete f[c]);t==null&&Wt.delete(l)}let Et=0,Gt=0,K=0,A=0,pe=0,Me=0,ol=pe,It=Me,yt=K,Yt=A,Je=0,it=0,je=0,pt=0;n.bbox={};let _n=!1,ql=!1,sl=!1,Bt=!1,$l=!1,ot=!1;function yn(t,l,r){(r||t!=n.width||l!=n.height)&&_i(t,l),pl(!1),sl=!0,ql=!0,hl()}function _i(t,l){n.width=Et=K=t,n.height=Gt=A=l,pe=Me=0,Ts(),Ms();let r=n.bbox;Je=r.left=Jt(pe*oe,.5),it=r.top=Jt(Me*oe,.5),je=r.width=Jt(K*oe,.5),pt=r.height=Jt(A*oe,.5)}let ks=3;function xs(){let t=!1,l=0;for(;!t;){l++;let r=zs(l),f=Fs(l);t=l==ks||r&&f,t||(_i(n.width,n.height),ql=!0)}}function bs({width:t,height:l}){yn(t,l)}n.setSize=bs;function Ts(){let t=!1,l=!1,r=!1,f=!1;N.forEach((c,p)=>{if(c.show&&c._show){let{side:S,_size:_}=c,v=S%2,T=c.label!=null?c.labelSize:0,M=_+T;M>0&&(v?(K-=M,S==3?(pe+=M,f=!0):r=!0):(A-=M,S==0?(Me+=M,t=!0):l=!0))}}),Kt[0]=t,Kt[1]=r,Kt[2]=l,Kt[3]=f,K-=Vt[1]+Vt[3],pe+=Vt[3],A-=Vt[2]+Vt[0],Me+=Vt[0]}function Ms(){let t=pe+K,l=Me+A,r=pe,f=Me;function c(p,S){switch(p){case 1:return t+=S,t-S;case 2:return l+=S,l-S;case 3:return r-=S,r+S;case 0:return f-=S,f+S}}N.forEach((p,S)=>{if(p.show&&p._show){let _=p.side;p._pos=c(_,p._size),p.label!=null&&(p._lpos=c(_,p.labelSize))}})}if(V.dataIdx==null){let t=V.hover,l=t.skip=new Set(t.skip??[]);l.add(void 0);let r=t.prox=X(t.prox),f=t.bias??(t.bias=0);V.dataIdx=(c,p,S,_)=>{if(p==0)return S;let v=S,T=r(c,p,S,_)??ce,M=T>=0&&T0;)l.has(le[R])||(Z=R);if(f==0||f==1)for(R=S;W==null&&R++T&&(v=null);return v}}let Ut=t=>{V.event=t};V.idxs=fe,V._lock=!1;let Ne=V.points;Ne.show=X(Ne.show),Ne.size=X(Ne.size),Ne.stroke=X(Ne.stroke),Ne.width=X(Ne.width),Ne.fill=X(Ne.fill);let vt=n.focus=be({},e.focus||{alpha:.3},V.focus),rl=vt.prox>=0,fl=rl&&Ne.one,st=[],ul=[],cl=[];function yi(t,l){let r=Ne.show(n,l);if(r instanceof HTMLElement)return et(r,ur),et(r,t.class),Mt(r,-10,-10,K,A),L.insertBefore(r,st[l]),r}function vi(t,l){if(s==1||l>0){let r=s==1&&x[t.scale].time,f=t.value;t.value=r?mo(f)?ko(ee,vo(f,z)):f||te:f||bf,t.label=t.label||(r?df:gf)}if(fl||l>0){t.width=t.width==null?1:t.width,t.paths=t.paths||Nf||Ar,t.fillTo=X(t.fillTo||Df),t.pxAlign=+ne(t.pxAlign,H),t.pxRound=Po(t.pxAlign),t.stroke=X(t.stroke||null),t.fill=X(t.fill||null),t._stroke=t._fill=t._paths=t._focus=null;let r=Tf(Be(1,t.width),1),f=t.points=be({},{size:r,width:Be(1,r*.2),stroke:t.stroke,space:r*2,paths:Of,_stroke:null,_fill:null},t.points);f.show=X(f.show),f.filter=X(f.filter),f.fill=X(f.fill),f.stroke=X(f.stroke),f.paths=X(f.paths),f.pxAlign=t.pxAlign}if(Te){let r=jl(t,l);ye.splice(l,0,r[0]),_t.splice(l,0,r[1]),J.values.push(null)}if(Oe){fe.splice(l,0,null);let r=null;fl?l==0&&(r=yi(t,l)):l>0&&(r=yi(t,l)),st.splice(l,0,r),ul.splice(l,0,0),cl.splice(l,0,0)}Re("addSeries",l)}function As(t,l){l=l??k.length,t=s==1?ii(t,l,bo,Do):ii(t,l,{},Eo),k.splice(l,0,t),vi(k[l],l)}n.addSeries=As;function Es(t){if(k.splice(t,1),Te){J.values.splice(t,1),_t.splice(t,1);let l=ye.splice(t,1)[0];il(null,l.firstChild),l.remove()}Oe&&(fe.splice(t,1),st.splice(t,1)[0].remove(),ul.splice(t,1),cl.splice(t,1)),Re("delSeries",t)}n.delSeries=Es;let Kt=[!1,!1,!1,!1];function Ds(t,l){if(t._show=t.show,t.show){let r=t.side%2,f=x[t.scale];f==null&&(t.scale=r?k[1].scale:D,f=x[t.scale]);let c=f.time;t.size=X(t.size),t.space=X(t.space),t.rotate=X(t.rotate),Nt(t.incrs)&&t.incrs.forEach(S=>{!Ot.has(S)&&Ot.set(S,Bo(S))}),t.incrs=X(t.incrs||(f.distr==2?$r:c?G==1?Zr:ef:Zt)),t.splits=X(t.splits||(c&&f.distr==1?Ke:f.distr==3?ei:f.distr==4?_f:Sf)),t.stroke=X(t.stroke),t.grid.stroke=X(t.grid.stroke),t.ticks.stroke=X(t.ticks.stroke),t.border.stroke=X(t.border.stroke);let p=t.values;t.values=Nt(p)&&!Nt(p[0])?X(p):c?Nt(p)?yo(ee,_o(p,z)):mo(p)?nf(ee,p):p||we:p||wf,t.filter=X(t.filter||(f.distr>=3&&f.log==10?kf:f.distr==3&&f.log==2?xf:Io)),t.font=zo(t.font),t.labelFont=zo(t.labelFont),t._size=t.size(n,null,l,0),t._space=t._rotate=t._incrs=t._found=t._splits=t._values=null,t._size>0&&(Kt[l]=!0,t._el=ut(or,w))}}function Cl(t,l,r,f){let[c,p,S,_]=r,v=l%2,T=0;return v==0&&(_||p)&&(T=l==0&&!c||l==2&&!S?Ae(xo.size/3):0),v==1&&(c||S)&&(T=l==1&&!p||l==3&&!_?Ae(Mo.size/2):0),T}let ki=n.padding=(e.padding||[Cl,Cl,Cl,Cl]).map(t=>X(ne(t,Cl))),Vt=n._padding=ki.map((t,l)=>t(n,l,Kt,0)),Fe,Le=null,Pe=null,Jl=s==1?k[0].idxs:null,ht=null,Vl=!1;function xi(t,l){if(i=t??[],n.data=n._data=i,s==2){Fe=0;for(let r=1;r=0,ot=!0,hl()}}n.setData=xi;function vn(){Vl=!0;let t,l;s==1&&(Fe>0?(Le=Jl[0]=0,Pe=Jl[1]=Fe-1,t=i[0][Le],l=i[0][Pe],j==2?(t=Le,l=Pe):t==l&&(j==3?[t,l]=pn(t,t,b.log,!1):j==4?[t,l]=fi(t,t,b.log,!1):b.time?l=t+Ae(86400/G):[t,l]=un(t,l,ui,!0))):(Le=Jl[0]=t=null,Pe=Jl[1]=l=null)),zt(D,t,l)}let Zl,al,kn,xn,bn,Tn,Mn,An,En,qe;function bi(t,l,r,f,c,p){t??(t=Zi),r??(r=ai),f??(f="butt"),c??(c=Zi),p??(p="round"),t!=Zl&&(d.strokeStyle=Zl=t),c!=al&&(d.fillStyle=al=c),l!=kn&&(d.lineWidth=kn=l),p!=bn&&(d.lineJoin=bn=p),f!=Tn&&(d.lineCap=Tn=f),r!=xn&&d.setLineDash(xn=r)}function Ti(t,l,r,f){l!=al&&(d.fillStyle=al=l),t!=Mn&&(d.font=Mn=t),r!=An&&(d.textAlign=An=r),f!=En&&(d.textBaseline=En=f)}function Dn(t,l,r,f,c=0){if(f.length>0&&t.auto(n,Vl)&&(l==null||l.min==null)){let p=ne(Le,0),S=ne(Pe,f.length-1),_=r.min==null?vr(f,p,S,c,t.distr==3):[r.min,r.max];t.min=St(t.min,r.min=_[0]),t.max=Be(t.max,r.max=_[1])}}let Mi={min:null,max:null};function Ls(){for(let f in x){let c=x[f];F[f]==null&&(c.min==null||F[D]!=null&&c.auto(n,Vl))&&(F[f]=Mi)}for(let f in x){let c=x[f];F[f]==null&&c.from!=null&&F[c.from]!=null&&(F[f]=Mi)}F[D]!=null&&pl(!0);let t={};for(let f in F){let c=F[f];if(c!=null){let p=t[f]=Ml(x[f],Lr);if(c.min!=null)be(p,c);else if(f!=D||s==2)if(Fe==0&&p.from==null){let S=p.range(n,null,null,f);p.min=S[0],p.max=S[1]}else p.min=ce,p.max=-ce}}if(Fe>0){k.forEach((f,c)=>{if(s==1){let p=f.scale,S=F[p];if(S==null)return;let _=t[p];if(c==0){let v=_.range(n,_.min,_.max,p);_.min=v[0],_.max=v[1],Le=wt(_.min,i[0]),Pe=wt(_.max,i[0]),Pe-Le>1&&(i[0][Le]<_.min&&Le++,i[0][Pe]>_.max&&Pe--),f.min=ht[Le],f.max=ht[Pe]}else f.show&&f.auto&&Dn(_,S,f,i[c],f.sorted);f.idxs[0]=Le,f.idxs[1]=Pe}else if(c>0&&f.show&&f.auto){let[p,S]=f.facets,_=p.scale,v=S.scale,[T,M]=i[c],E=t[_],Y=t[v];E!=null&&Dn(E,F[_],p,T,p.sorted),Y!=null&&Dn(Y,F[v],S,M,S.sorted),f.min=S.min,f.max=S.max}});for(let f in t){let c=t[f],p=F[f];if(c.from==null&&(p==null||p.min==null)){let S=c.range(n,c.min==ce?null:c.min,c.max==-ce?null:c.max,f);c.min=S[0],c.max=S[1]}}}for(let f in t){let c=t[f];if(c.from!=null){let p=t[c.from];if(p.min==null)c.min=c.max=null;else{let S=c.range(n,p.min,p.max,f);c.min=S[0],c.max=S[1]}}}let l={},r=!1;for(let f in t){let c=t[f],p=x[f];if(p.min!=c.min||p.max!=c.max){p.min=c.min,p.max=c.max;let S=p.distr;p._min=S==3?Lt(p.min):S==4?Un(p.min,p.asinh):S==100?p.fwd(p.min):p.min,p._max=S==3?Lt(p.max):S==4?Un(p.max,p.asinh):S==100?p.fwd(p.max):p.max,l[f]=r=!0}}if(r){k.forEach((f,c)=>{s==2?c>0&&l.y&&(f._paths=null):l[f.scale]&&(f._paths=null)});for(let f in l)sl=!0,Re("setScale",f);Oe&&V.left>=0&&(Bt=ot=!0)}for(let f in F)F[f]=null}function Ps(t){let l=Xn(Le-1,0,Fe-1),r=Xn(Pe+1,0,Fe-1);for(;t[l]==null&&l>0;)l--;for(;t[r]==null&&r0){let t=k.some(l=>l._focus)&&qe!=vt.alpha;t&&(d.globalAlpha=qe=vt.alpha),k.forEach((l,r)=>{if(r>0&&l.show&&(Ai(r,!1),Ai(r,!0),l._paths==null)){let f=qe;qe!=l.alpha&&(d.globalAlpha=qe=l.alpha);let c=s==2?[0,i[r][0].length-1]:Ps(i[r]);l._paths=l.paths(n,r,c[0],c[1]),qe!=f&&(d.globalAlpha=qe=f)}}),k.forEach((l,r)=>{if(r>0&&l.show){let f=qe;qe!=l.alpha&&(d.globalAlpha=qe=l.alpha),l._paths!=null&&Ei(r,!1);{let c=l._paths!=null?l._paths.gaps:null,p=l.points.show(n,r,Le,Pe,c),S=l.points.filter(n,r,p,c);(p||S)&&(l.points._paths=l.points.paths(n,r,Le,Pe,S),Ei(r,!0))}qe!=f&&(d.globalAlpha=qe=f),Re("drawSeries",r)}}),t&&(d.globalAlpha=qe=1)}}function Ai(t,l){let r=l?k[t].points:k[t];r._stroke=r.stroke(n,t),r._fill=r.fill(n,t)}function Ei(t,l){let r=l?k[t].points:k[t],{stroke:f,fill:c,clip:p,flags:S,_stroke:_=r._stroke,_fill:v=r._fill,_width:T=r.width}=r._paths;T=ae(T*oe,3);let M=null,E=T%2/2;l&&v==null&&(v=T>0?"#fff":_);let Y=r.pxAlign==1&&E>0;if(Y&&d.translate(E,E),!l){let ie=Je-T/2,le=it-T/2,Z=je+T,W=pt+T;M=new Path2D,M.rect(ie,le,Z,W)}l?Ln(_,T,r.dash,r.cap,v,f,c,S,p):Vs(t,_,T,r.dash,r.cap,v,f,c,S,M,p),Y&&d.translate(-E,-E)}function Vs(t,l,r,f,c,p,S,_,v,T,M){let E=!1;v!=0&&q.forEach((Y,ie)=>{if(Y.series[0]==t){let le=k[Y.series[1]],Z=i[Y.series[1]],W=(le._paths||Ul).band;Nt(W)&&(W=Y.dir==1?W[0]:W[1]);let R,ge=null;le.show&&W&&xr(Z,Le,Pe)?(ge=Y.fill(n,ie)||p,R=le._paths.clip):W=null,Ln(l,r,f,c,ge,S,_,v,T,M,R,W),E=!0}}),E||Ln(l,r,f,c,p,S,_,v,T,M)}let Di=Al|li;function Ln(t,l,r,f,c,p,S,_,v,T,M,E){bi(t,l,r,f,c),(v||T||E)&&(d.save(),v&&d.clip(v),T&&d.clip(T)),E?(_&Di)==Di?(d.clip(E),M&&d.clip(M),Xl(c,S),Ql(t,p,l)):_&li?(Xl(c,S),d.clip(E),Ql(t,p,l)):_&Al&&(d.save(),d.clip(E),M&&d.clip(M),Xl(c,S),d.restore(),Ql(t,p,l)):(Xl(c,S),Ql(t,p,l)),(v||T||E)&&d.restore()}function Ql(t,l,r){r>0&&(l instanceof Map?l.forEach((f,c)=>{d.strokeStyle=Zl=c,d.stroke(f)}):l!=null&&t&&d.stroke(l))}function Xl(t,l){l instanceof Map?l.forEach((r,f)=>{d.fillStyle=al=f,d.fill(r)}):l!=null&&t&&d.fill(l)}function Rs(t,l,r,f){let c=N[t],p;if(f<=0)p=[0,0];else{let S=c._space=c.space(n,t,l,r,f),_=c._incrs=c.incrs(n,t,l,r,f,S);p=Uf(l,r,_,f,S)}return c._found=p}function Pn(t,l,r,f,c,p,S,_,v,T){let M=S%2/2;H==1&&d.translate(M,M),bi(_,S,v,T,_),d.beginPath();let E,Y,ie,le,Z=c+(f==0||f==3?-p:p);r==0?(Y=c,le=Z):(E=c,ie=Z);for(let W=0;W{if(!r.show)return;let c=x[r.scale];if(c.min==null){r._show&&(l=!1,r._show=!1,pl(!1));return}else r._show||(l=!1,r._show=!0,pl(!1));let p=r.side,S=p%2,{min:_,max:v}=c,[T,M]=Rs(f,_,v,S==0?K:A);if(M==0)return;let E=c.distr==2,Y=r._splits=r.splits(n,f,_,v,T,M,E),ie=c.distr==2?Y.map(R=>ht[R]):Y,le=c.distr==2?ht[Y[1]]-ht[Y[0]]:T,Z=r._values=r.values(n,r.filter(n,ie,f,M,le),f,M,le);r._rotate=p==2?r.rotate(n,Z,f,M):0;let W=r._size;r._size=ct(r.size(n,Z,f,t)),W!=null&&r._size!=W&&(l=!1)}),l}function Fs(t){let l=!0;return ki.forEach((r,f)=>{let c=r(n,f,Kt,t);c!=Vt[f]&&(l=!1),Vt[f]=c}),l}function Hs(){for(let t=0;tht[Ie]):ie,Z=M.distr==2?ht[ie[1]]-ht[ie[0]]:v,W=l.ticks,R=l.border,ge=W.show?W.size:0,ve=Ae(ge*oe),ze=Ae((l.alignTo==2?l._size-ge-l.gap:l.gap)*oe),ue=l._rotate*-rn/180,ke=O(l._pos*oe),Ze=(ve+ze)*_,Ge=ke+Ze;p=f==0?Ge:0,c=f==1?Ge:0;let rt=l.font[0],mt=l.align==1?vl:l.align==2?In:ue>0?vl:ue<0?In:f==0?"center":r==3?In:vl,bt=ue||f==1?"middle":r==2?Ol:Ji;Ti(rt,S,mt,bt);let Qe=l.font[1]*l.lineGap,ft=ie.map(Ie=>O(h(Ie,M,E,Y))),gt=l._values;for(let Ie=0;Ie{r>0&&(l._paths=null,t&&(s==1?(l.min=null,l.max=null):l.facets.forEach(f=>{f.min=null,f.max=null})))})}let en=!1,Cn=!1,Rl=[];function Ns(){Cn=!1;for(let t=0;t0&&queueMicrotask(Ns)}n.batch=Os;function Li(){if(_n&&(Ls(),_n=!1),sl&&(xs(),sl=!1),ql){if(de(P,vl,pe),de(P,Ol,Me),de(P,Gl,K),de(P,Il,A),de(L,vl,pe),de(L,Ol,Me),de(L,Gl,K),de(L,Il,A),de(w,Gl,Et),de(w,Il,Gt),y.width=Ae(Et*oe),y.height=Ae(Gt*oe),N.forEach(({_el:t,_show:l,_size:r,_pos:f,side:c})=>{if(t!=null)if(l){let p=c===3||c===0?r:0,S=c%2==1;de(t,S?"left":"top",f-p),de(t,S?"width":"height",r),de(t,S?"top":"left",S?Me:pe),de(t,S?"height":"width",S?A:K),Zn(t,Qt)}else et(t,Qt)}),Zl=al=kn=bn=Tn=Mn=An=En=xn=null,qe=1,Hl(!0),pe!=ol||Me!=It||K!=yt||A!=Yt){pl(!1);let t=K/yt,l=A/Yt;if(Oe&&!Bt&&V.left>=0){V.left*=t,V.top*=l,ml&&Mt(ml,Ae(V.left),0,K,A),gl&&Mt(gl,0,Ae(V.top),K,A);for(let r=0;r=0&&me.width>0){me.left*=t,me.width*=t,me.top*=l,me.height*=l;for(let r in Nn)de(Sl,r,me[r])}ol=pe,It=Me,yt=K,Yt=A}Re("setSize"),ql=!1}Et>0&&Gt>0&&(d.clearRect(0,0,y.width,y.height),Re("drawClear"),U.forEach(t=>t()),Re("draw")),me.show&&$l&&(tn(me),$l=!1),Oe&&Bt&&(qt(null,!0,!1),Bt=!1),J.show&&J.live&&ot&&(Fn(),ot=!1),m||(m=!0,n.status=1,Re("ready")),Vl=!1,en=!1}n.redraw=(t,l)=>{sl=l||!1,t!==!1?zt(D,b.min,b.max):hl()};function Vn(t,l){let r=x[t];if(r.from==null){if(Fe==0){let f=r.range(n,l.min,l.max,t);l.min=f[0],l.max=f[1]}if(l.min>l.max){let f=l.min;l.min=l.max,l.max=f}if(Fe>1&&l.min!=null&&l.max!=null&&l.max-l.min<1e-16)return;t==D&&r.distr==2&&Fe>0&&(l.min=wt(l.min,i[0]),l.max=wt(l.max,i[0]),l.min==l.max&&l.max++),F[t]=l,_n=!0,hl()}}n.setScale=Vn;let Rn,zn,ml,gl,Pi,Ci,dl,wl,Vi,Ri,he,_e,Rt=!1,He=V.drag,Ce=He.x,Ve=He.y;Oe&&(V.x&&(Rn=ut(rr,L)),V.y&&(zn=ut(fr,L)),b.ori==0?(ml=Rn,gl=zn):(ml=zn,gl=Rn),he=V.left,_e=V.top);let me=n.select=be({show:!0,over:!0,left:0,width:0,top:0,height:0},e.select),Sl=me.show?ut(sr,me.over?L:P):null;function tn(t,l){if(me.show){for(let r in t)me[r]=t[r],r in Nn&&de(Sl,r,t[r]);l!==!1&&Re("setSelect")}}n.setSelect=tn;function Ws(t){if(k[t].show)Te&&Zn(ye[t],Qt);else if(Te&&et(ye[t],Qt),Oe){let r=fl?st[0]:st[t];r!=null&&Mt(r,-10,-10,K,A)}}function zt(t,l,r){Vn(t,{min:l,max:r})}function kt(t,l,r,f){l.focus!=null&&Us(t),l.show!=null&&k.forEach((c,p)=>{p>0&&(t==p||t==null)&&(c.show=l.show,Ws(p),s==2?(zt(c.facets[0].scale,null,null),zt(c.facets[1].scale,null,null)):zt(c.scale,null,null),hl())}),r!==!1&&Re("setSeries",t,l),f&&Nl("setSeries",n,t,l)}n.setSeries=kt;function Gs(t,l){be(q[t],l)}function Is(t,l){t.fill=X(t.fill||null),t.dir=ne(t.dir,-1),l=l??q.length,q.splice(l,0,t)}function Ys(t){t==null?q.length=0:q.splice(t,1)}n.addBand=Is,n.setBand=Gs,n.delBand=Ys;function Bs(t,l){k[t].alpha=l,Oe&&st[t]!=null&&(st[t].style.opacity=l),Te&&ye[t]&&(ye[t].style.opacity=l)}let Dt,Ft,jt,_l={focus:!0};function Us(t){if(t!=jt){let l=t==null,r=vt.alpha!=1;k.forEach((f,c)=>{if(s==1||c>0){let p=l||c==0||c==t;f._focus=l?null:p,r&&Bs(c,p?1:vt.alpha)}}),jt=t,r&&hl()}}Te&&rl&&We(eo,se,t=>{V._lock||(Ut(t),jt!=null&&kt(null,_l,!0,xe.setSeries))});function xt(t,l,r){let f=x[l];r&&(t=t/oe-(f.ori==1?Me:pe));let c=K;f.ori==1&&(c=A,t=c-t),f.dir==-1&&(t=c-t);let p=f._min,S=f._max,_=t/c,v=p+(S-p)*_,T=f.distr;return T==3?bl(10,v):T==4?Tr(v,f.asinh):T==100?f.bwd(v):v}function Ks(t,l){let r=xt(t,D,l);return wt(r,i[0],Le,Pe)}n.valToIdx=t=>wt(t,i[0]),n.posToIdx=Ks,n.posToVal=xt,n.valToPos=(t,l,r)=>x[l].ori==0?a(t,x[l],r?je:K,r?Je:0):u(t,x[l],r?pt:A,r?it:0),n.setCursor=(t,l,r)=>{he=t.left,_e=t.top,qt(null,l,r)};function zi(t,l){de(Sl,vl,me.left=t),de(Sl,Gl,me.width=l)}function Fi(t,l){de(Sl,Ol,me.top=t),de(Sl,Il,me.height=l)}let zl=b.ori==0?zi:Fi,Fl=b.ori==1?zi:Fi;function js(){if(Te&&J.live)for(let t=s==2?1:0;t{fe[f]=r}):Dr(t.idx)||fe.fill(t.idx),J.idx=fe[0]),Te&&J.live){for(let r=0;r0||s==1&&!nt)&&qs(r,fe[r]);js()}ot=!1,l!==!1&&Re("setLegend")}n.setLegend=Fn;function qs(t,l){let r=k[t],f=t==0&&j==2?ht:i[t],c;nt?c=r.values(n,t,l)??Ct:(c=r.value(n,l==null?null:f[l],t,l),c=c==null?Ct:{_:c}),J.values[t]=c}function qt(t,l,r){Vi=he,Ri=_e,[he,_e]=V.move(n,he,_e),V.left=he,V.top=_e,Oe&&(ml&&Mt(ml,Ae(he),0,K,A),gl&&Mt(gl,0,Ae(_e),K,A));let f,c=Le>Pe;Dt=ce,Ft=null;let p=b.ori==0?K:A,S=b.ori==1?K:A;if(he<0||Fe==0||c){f=V.idx=null;for(let _=0;_0&&ge.show){let Ze=ue==null?-10:ue==f?T:C(s==1?i[0][ue]:i[R][0][ue],b,p,0),Ge=ke==null?-10:I(ke,s==1?x[ge.scale]:x[ge.facets[1].scale],S,0);if(rl&&ke!=null){let rt=b.ori==1?he:_e,mt=Ee(vt.dist(n,R,ue,Ge,rt));if(mt=0?1:-1,gt=Qe>=0?1:-1;gt==ft&&(gt==1?bt==1?ke>=Qe:ke<=Qe:bt==1?ke<=Qe:ke>=Qe)&&(Dt=mt,Ft=R)}else Dt=mt,Ft=R}}if(ot||fl){let rt,mt;b.ori==0?(rt=Ze,mt=Ge):(rt=Ge,mt=Ze);let bt,Qe,ft,gt,Tt,Ie,Xe=!0,$t=Ne.bbox;if($t!=null){Xe=!1;let Ye=$t(n,R);ft=Ye.left,gt=Ye.top,bt=Ye.width,Qe=Ye.height}else ft=rt,gt=mt,bt=Qe=Ne.size(n,R);if(Ie=Ne.fill(n,R),Tt=Ne.stroke(n,R),fl)R==Ft&&Dt<=vt.prox&&(M=ft,E=gt,Y=bt,ie=Qe,le=Xe,Z=Ie,W=Tt);else{let Ye=st[R];Ye!=null&&(ul[R]=ft,cl[R]=gt,ro(Ye,bt,Qe,Xe),oo(Ye,Ie,Tt),Mt(Ye,ct(ft),ct(gt),K,A))}}}}if(fl){let R=vt.prox,ge=jt==null?Dt<=R:Dt>R||Ft!=jt;if(ot||ge){let ve=st[0];ve!=null&&(ul[0]=M,cl[0]=E,ro(ve,Y,ie,le),oo(ve,Z,W),Mt(ve,ct(M),ct(E),K,A))}}}if(me.show&&Rt)if(t!=null){let[_,v]=xe.scales,[T,M]=xe.match,[E,Y]=t.cursor.sync.scales,ie=t.cursor.drag;if(Ce=ie._x,Ve=ie._y,Ce||Ve){let{left:le,top:Z,width:W,height:R}=t.select,ge=t.scales[E].ori,ve=t.posToVal,ze,ue,ke,Ze,Ge,rt=_!=null&&T(_,E),mt=v!=null&&M(v,Y);rt&&Ce?(ge==0?(ze=le,ue=W):(ze=Z,ue=R),ke=x[_],Ze=C(ve(ze,E),ke,p,0),Ge=C(ve(ze+ue,E),ke,p,0),zl(St(Ze,Ge),Ee(Ge-Ze))):zl(0,p),mt&&Ve?(ge==1?(ze=le,ue=W):(ze=Z,ue=R),ke=x[v],Ze=I(ve(ze,Y),ke,S,0),Ge=I(ve(ze+ue,Y),ke,S,0),Fl(St(Ze,Ge),Ee(Ge-Ze))):Fl(0,S)}else On()}else{let _=Ee(Vi-Pi),v=Ee(Ri-Ci);if(b.ori==1){let Y=_;_=v,v=Y}Ce=He.x&&_>=He.dist,Ve=He.y&&v>=He.dist;let T=He.uni;T!=null?Ce&&Ve&&(Ce=_>=T,Ve=v>=T,!Ce&&!Ve&&(v>_?Ve=!0:Ce=!0)):He.x&&He.y&&(Ce||Ve)&&(Ce=Ve=!0);let M,E;Ce&&(b.ori==0?(M=dl,E=he):(M=wl,E=_e),zl(St(M,E),Ee(E-M)),Ve||Fl(0,S)),Ve&&(b.ori==1?(M=dl,E=he):(M=wl,E=_e),Fl(St(M,E),Ee(E-M)),Ce||zl(0,p)),!Ce&&!Ve&&(zl(0,0),Fl(0,0))}if(He._x=Ce,He._y=Ve,t==null){if(r){if(ji!=null){let[_,v]=xe.scales;xe.values[0]=_!=null?xt(b.ori==0?he:_e,_):null,xe.values[1]=v!=null?xt(b.ori==1?he:_e,v):null}Nl(Yn,n,he,_e,K,A,f)}if(rl){let _=r&&xe.setSeries,v=vt.prox;jt==null?Dt<=v&&kt(Ft,_l,!0,_):Dt>v?kt(null,_l,!0,_):Ft!=jt&&kt(Ft,_l,!0,_)}}ot&&(J.idx=f,Fn()),l!==!1&&Re("setCursor")}let Ht=null;Object.defineProperty(n,"rect",{get(){return Ht==null&&Hl(!1),Ht}});function Hl(t=!1){t?Ht=null:(Ht=L.getBoundingClientRect(),Re("syncRect",Ht))}function Hi(t,l,r,f,c,p,S){V._lock||Rt&&t!=null&&t.movementX==0&&t.movementY==0||(Hn(t,l,r,f,c,p,S,!1,t!=null),t!=null?qt(null,!0,!0):qt(l,!0,!1))}function Hn(t,l,r,f,c,p,S,_,v){if(Ht==null&&Hl(!1),Ut(t),t!=null)r=t.clientX-Ht.left,f=t.clientY-Ht.top;else{if(r<0||f<0){he=-10,_e=-10;return}let[T,M]=xe.scales,E=l.cursor.sync,[Y,ie]=E.values,[le,Z]=E.scales,[W,R]=xe.match,ge=l.axes[0].side%2==1,ve=b.ori==0?K:A,ze=b.ori==1?K:A,ue=ge?p:c,ke=ge?c:p,Ze=ge?f:r,Ge=ge?r:f;if(le!=null?r=W(T,le)?h(Y,x[T],ve,0):-10:r=ve*(Ze/ue),Z!=null?f=R(M,Z)?h(ie,x[M],ze,0):-10:f=ze*(Ge/ke),b.ori==1){let rt=r;r=f,f=rt}}v&&(l==null||l.cursor.event.type==Yn)&&((r<=1||r>=K-1)&&(r=Jt(r,K)),(f<=1||f>=A-1)&&(f=Jt(f,A))),_?(Pi=r,Ci=f,[dl,wl]=V.move(n,r,f)):(he=r,_e=f)}let Nn={width:0,height:0,left:0,top:0};function On(){tn(Nn,!1)}let Ni,Oi,Wi,Gi;function Ii(t,l,r,f,c,p,S){Rt=!0,Ce=Ve=He._x=He._y=!1,Hn(t,l,r,f,c,p,S,!0,!1),t!=null&&(We(Bn,$n,Yi,!1),Nl(Qi,n,dl,wl,K,A,null));let{left:_,top:v,width:T,height:M}=me;Ni=_,Oi=v,Wi=T,Gi=M}function Yi(t,l,r,f,c,p,S){Rt=He._x=He._y=!1,Hn(t,l,r,f,c,p,S,!1,!0);let{left:_,top:v,width:T,height:M}=me,E=T>0||M>0,Y=Ni!=_||Oi!=v||Wi!=T||Gi!=M;if(E&&Y&&tn(me),He.setScale&&E&&Y){let ie=_,le=T,Z=v,W=M;if(b.ori==1&&(ie=v,le=M,Z=_,W=T),Ce&&zt(D,xt(ie,D),xt(ie+le,D)),Ve)for(let R in x){let ge=x[R];R!=D&&ge.from==null&&ge.min!=ce&&zt(R,xt(Z+W,R),xt(Z,R))}On()}else V.lock&&(V._lock=!V._lock,qt(l,!0,t!=null));t!=null&&(il(Bn,$n),Nl(Bn,n,he,_e,K,A,null))}function $s(t,l,r,f,c,p,S){if(V._lock)return;Ut(t);let _=Rt;if(Rt){let v=!0,T=!0,M=10,E,Y;b.ori==0?(E=Ce,Y=Ve):(E=Ve,Y=Ce),E&&Y&&(v=he<=M||he>=K-M,T=_e<=M||_e>=A-M),E&&v&&(he=he{let c=xe.match[2];r=c(n,l,r),r!=-1&&kt(r,f,!0,!1)},Oe&&(We(Qi,L,Ii),We(Yn,L,Hi),We(Xi,L,t=>{Ut(t),Hl(!1)}),We(eo,L,$s),We(to,L,Bi),ni.add(n),n.syncRect=Hl);let ln=n.hooks=e.hooks||{};function Re(t,l,r){Cn?Rl.push([t,l,r]):t in ln&&ln[t].forEach(f=>{f.call(null,n,l,r)})}(e.plugins||[]).forEach(t=>{for(let l in t.hooks)ln[l]=(ln[l]||[]).concat(t.hooks[l])});let Ki=(t,l,r)=>r,xe=be({key:null,setSeries:!1,filters:{pub:po,sub:po},scales:[D,k[1]?k[1].scale:null],match:[ho,ho,Ki],values:[null,null]},V.sync);xe.match.length==2&&xe.match.push(Ki),V.sync=xe;let ji=xe.key,Wn=cs(ji);function Nl(t,l,r,f,c,p,S){xe.filters.pub(t,l,r,f,c,p,S)&&Wn.pub(t,l,r,f,c,p,S)}Wn.sub(n);function Js(t,l,r,f,c,p,S){xe.filters.sub(t,l,r,f,c,p,S)&&yl[t](null,l,r,f,c,p,S)}n.pub=Js;function Zs(){Wn.unsub(n),ni.delete(n),Wt.clear(),Qn(fn,xl,Ui),g.remove(),se?.remove(),Re("destroy")}n.destroy=Zs;function Gn(){Re("init",e,i),xi(i||e.data,!1),F[D]?Vn(D,F[D]):vn(),$l=me.show&&(me.width>0||me.height>0),Bt=ot=!0,yn(e.width,e.height)}return k.forEach(vi),N.forEach(Ds),o?o instanceof HTMLElement?(o.appendChild(g),Gn()):o(n,Gn):Gn(),n}Ue.assign=be;Ue.fmtNum=ci;Ue.rangeNum=un;Ue.rangeLog=pn;Ue.rangeAsinh=fi;Ue.orient=tl;Ue.pxRatio=oe;Ue.join=Fr;Ue.fmtDate=pi,Ue.tzDate=jr;Ue.sync=cs;{Ue.addGap=Lf,Ue.clipGaps=gn;let e=Ue.paths={points:ds};e.linear=Ss,e.stepped=Vf,e.bars=Rf,e.spline=Ff}export{Ue as default}; +//# sourceMappingURL=uplot.mjs.map diff --git a/suites-experimental/tools-gps-tracks/dist/uplot.mjs.map b/suites-experimental/tools-gps-tracks/dist/uplot.mjs.map new file mode 100644 index 0000000000..7d65813cb4 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/dist/uplot.mjs.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../node_modules/uplot/dist/uPlot.esm.js"], + "sourcesContent": ["/**\n* Copyright (c) 2025, Leon Sorokin\n* All rights reserved. (MIT Licensed)\n*\n* uPlot.js (\u03BCPlot)\n* A small, fast chart for time series, lines, areas, ohlc & bars\n* https://github.com/leeoniya/uPlot (v1.6.32)\n*/\n\nconst FEAT_TIME = true;\n\nconst pre = \"u-\";\n\nconst UPLOT = \"uplot\";\nconst ORI_HZ = pre + \"hz\";\nconst ORI_VT = pre + \"vt\";\nconst TITLE = pre + \"title\";\nconst WRAP = pre + \"wrap\";\nconst UNDER = pre + \"under\";\nconst OVER = pre + \"over\";\nconst AXIS = pre + \"axis\";\nconst OFF = pre + \"off\";\nconst SELECT = pre + \"select\";\nconst CURSOR_X = pre + \"cursor-x\";\nconst CURSOR_Y = pre + \"cursor-y\";\nconst CURSOR_PT = pre + \"cursor-pt\";\nconst LEGEND = pre + \"legend\";\nconst LEGEND_LIVE = pre + \"live\";\nconst LEGEND_INLINE = pre + \"inline\";\nconst LEGEND_SERIES = pre + \"series\";\nconst LEGEND_MARKER = pre + \"marker\";\nconst LEGEND_LABEL = pre + \"label\";\nconst LEGEND_VALUE = pre + \"value\";\n\nconst WIDTH = \"width\";\nconst HEIGHT = \"height\";\nconst TOP = \"top\";\nconst BOTTOM = \"bottom\";\nconst LEFT = \"left\";\nconst RIGHT = \"right\";\nconst hexBlack = \"#000\";\nconst transparent = hexBlack + \"0\";\n\nconst mousemove = \"mousemove\";\nconst mousedown = \"mousedown\";\nconst mouseup = \"mouseup\";\nconst mouseenter = \"mouseenter\";\nconst mouseleave = \"mouseleave\";\nconst dblclick = \"dblclick\";\nconst resize = \"resize\";\nconst scroll = \"scroll\";\n\nconst change = \"change\";\nconst dppxchange = \"dppxchange\";\n\nconst LEGEND_DISP = \"--\";\n\nconst domEnv = typeof window != 'undefined';\n\nconst doc = domEnv ? document : null;\nconst win = domEnv ? window : null;\nconst nav = domEnv ? navigator : null;\n\nlet pxRatio;\n\n//export const canHover = domEnv && !win.matchMedia('(hover: none)').matches;\n\nlet query;\n\nfunction setPxRatio() {\n\tlet _pxRatio = devicePixelRatio;\n\n\t// during print preview, Chrome fires off these dppx queries even without changes\n\tif (pxRatio != _pxRatio) {\n\t\tpxRatio = _pxRatio;\n\n\t\tquery && off(change, query, setPxRatio);\n\t\tquery = matchMedia(`(min-resolution: ${pxRatio - 0.001}dppx) and (max-resolution: ${pxRatio + 0.001}dppx)`);\n\t\ton(change, query, setPxRatio);\n\n\t\twin.dispatchEvent(new CustomEvent(dppxchange));\n\t}\n}\n\nfunction addClass(el, c) {\n\tif (c != null) {\n\t\tlet cl = el.classList;\n\t\t!cl.contains(c) && cl.add(c);\n\t}\n}\n\nfunction remClass(el, c) {\n\tlet cl = el.classList;\n\tcl.contains(c) && cl.remove(c);\n}\n\nfunction setStylePx(el, name, value) {\n\tel.style[name] = value + \"px\";\n}\n\nfunction placeTag(tag, cls, targ, refEl) {\n\tlet el = doc.createElement(tag);\n\n\tif (cls != null)\n\t\taddClass(el, cls);\n\n\tif (targ != null)\n\t\ttarg.insertBefore(el, refEl);\n\n\treturn el;\n}\n\nfunction placeDiv(cls, targ) {\n\treturn placeTag(\"div\", cls, targ);\n}\n\nconst xformCache = new WeakMap();\n\nfunction elTrans(el, xPos, yPos, xMax, yMax) {\n\tlet xform = \"translate(\" + xPos + \"px,\" + yPos + \"px)\";\n\tlet xformOld = xformCache.get(el);\n\n\tif (xform != xformOld) {\n\t\tel.style.transform = xform;\n\t\txformCache.set(el, xform);\n\n\t\tif (xPos < 0 || yPos < 0 || xPos > xMax || yPos > yMax)\n\t\t\taddClass(el, OFF);\n\t\telse\n\t\t\tremClass(el, OFF);\n\t}\n}\n\nconst colorCache = new WeakMap();\n\nfunction elColor(el, background, borderColor) {\n\tlet newColor = background + borderColor;\n\tlet oldColor = colorCache.get(el);\n\n\tif (newColor != oldColor) {\n\t\tcolorCache.set(el, newColor);\n\t\tel.style.background = background;\n\t\tel.style.borderColor = borderColor;\n\t}\n}\n\nconst sizeCache = new WeakMap();\n\nfunction elSize(el, newWid, newHgt, centered) {\n\tlet newSize = newWid + \"\" + newHgt;\n\tlet oldSize = sizeCache.get(el);\n\n\tif (newSize != oldSize) {\n\t\tsizeCache.set(el, newSize);\n\t\tel.style.height = newHgt + \"px\";\n\t\tel.style.width = newWid + \"px\";\n\t\tel.style.marginLeft = centered ? -newWid/2 + \"px\" : 0;\n\t\tel.style.marginTop = centered ? -newHgt/2 + \"px\" : 0;\n\t}\n}\n\nconst evOpts = {passive: true};\nconst evOpts2 = {...evOpts, capture: true};\n\nfunction on(ev, el, cb, capt) {\n\tel.addEventListener(ev, cb, capt ? evOpts2 : evOpts);\n}\n\nfunction off(ev, el, cb, capt) {\n\tel.removeEventListener(ev, cb, evOpts);\n}\n\ndomEnv && setPxRatio();\n\n// binary search for index of closest value\nfunction closestIdx(num, arr, lo, hi) {\n\tlet mid;\n\tlo = lo || 0;\n\thi = hi || arr.length - 1;\n\tlet bitwise = hi <= 2147483647;\n\n\twhile (hi - lo > 1) {\n\t\tmid = bitwise ? (lo + hi) >> 1 : floor((lo + hi) / 2);\n\n\t\tif (arr[mid] < num)\n\t\t\tlo = mid;\n\t\telse\n\t\t\thi = mid;\n\t}\n\n\tif (num - arr[lo] <= arr[hi] - num)\n\t\treturn lo;\n\n\treturn hi;\n}\n\nfunction makeIndexOfs(predicate) {\n\t let indexOfs = (data, _i0, _i1) => {\n\t\tlet i0 = -1;\n\t\tlet i1 = -1;\n\n\t\tfor (let i = _i0; i <= _i1; i++) {\n\t\t\tif (predicate(data[i])) {\n\t\t\t\ti0 = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tfor (let i = _i1; i >= _i0; i--) {\n\t\t\tif (predicate(data[i])) {\n\t\t\t\ti1 = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn [i0, i1];\n\t };\n\n\t return indexOfs;\n}\n\nconst notNullish = v => v != null;\nconst isPositive = v => v != null && v > 0;\n\nconst nonNullIdxs = makeIndexOfs(notNullish);\nconst positiveIdxs = makeIndexOfs(isPositive);\n\nfunction getMinMax(data, _i0, _i1, sorted = 0, log = false) {\n//\tconsole.log(\"getMinMax()\");\n\n\tlet getEdgeIdxs = log ? positiveIdxs : nonNullIdxs;\n\tlet predicate = log ? isPositive : notNullish;\n\n\t[_i0, _i1] = getEdgeIdxs(data, _i0, _i1);\n\n\tlet _min = data[_i0];\n\tlet _max = data[_i0];\n\n\tif (_i0 > -1) {\n\t\tif (sorted == 1) {\n\t\t\t_min = data[_i0];\n\t\t\t_max = data[_i1];\n\t\t}\n\t\telse if (sorted == -1) {\n\t\t\t_min = data[_i1];\n\t\t\t_max = data[_i0];\n\t\t}\n\t\telse {\n\t\t\tfor (let i = _i0; i <= _i1; i++) {\n\t\t\t\tlet v = data[i];\n\n\t\t\t\tif (predicate(v)) {\n\t\t\t\t\tif (v < _min)\n\t\t\t\t\t\t_min = v;\n\t\t\t\t\telse if (v > _max)\n\t\t\t\t\t\t_max = v;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn [_min ?? inf, _max ?? -inf]; // todo: fix to return nulls\n}\n\nfunction rangeLog(min, max, base, fullMags) {\n\tlet minSign = sign(min);\n\tlet maxSign = sign(max);\n\n\tif (min == max) {\n\t\tif (minSign == -1) {\n\t\t\tmin *= base;\n\t\t\tmax /= base;\n\t\t}\n\t\telse {\n\t\t\tmin /= base;\n\t\t\tmax *= base;\n\t\t}\n\t}\n\n\tlet logFn = base == 10 ? log10 : log2;\n\n\tlet growMinAbs = minSign == 1 ? floor : ceil;\n\tlet growMaxAbs = maxSign == 1 ? ceil : floor;\n\n\tlet minExp = growMinAbs(logFn(abs(min)));\n\tlet maxExp = growMaxAbs(logFn(abs(max)));\n\n\tlet minIncr = pow(base, minExp);\n\tlet maxIncr = pow(base, maxExp);\n\n\t// fix values like Math.pow(10, -5) === 0.000009999999999999999\n\tif (base == 10) {\n\t\tif (minExp < 0)\n\t\t\tminIncr = roundDec(minIncr, -minExp);\n\t\tif (maxExp < 0)\n\t\t\tmaxIncr = roundDec(maxIncr, -maxExp);\n\t}\n\n\tif (fullMags || base == 2) {\n\t\tmin = minIncr * minSign;\n\t\tmax = maxIncr * maxSign;\n\t}\n\telse {\n\t\tmin = incrRoundDn(min, minIncr);\n\t\tmax = incrRoundUp(max, maxIncr);\n\t}\n\n\treturn [min, max];\n}\n\nfunction rangeAsinh(min, max, base, fullMags) {\n\tlet minMax = rangeLog(min, max, base, fullMags);\n\n\tif (min == 0)\n\t\tminMax[0] = 0;\n\n\tif (max == 0)\n\t\tminMax[1] = 0;\n\n\treturn minMax;\n}\n\nconst rangePad = 0.1;\n\nconst autoRangePart = {\n\tmode: 3,\n\tpad: rangePad,\n};\n\nconst _eqRangePart = {\n\tpad: 0,\n\tsoft: null,\n\tmode: 0,\n};\n\nconst _eqRange = {\n\tmin: _eqRangePart,\n\tmax: _eqRangePart,\n};\n\n// this ensures that non-temporal/numeric y-axes get multiple-snapped padding added above/below\n// TODO: also account for incrs when snapping to ensure top of axis gets a tick & value\nfunction rangeNum(_min, _max, mult, extra) {\n\tif (isObj(mult))\n\t\treturn _rangeNum(_min, _max, mult);\n\n\t_eqRangePart.pad = mult;\n\t_eqRangePart.soft = extra ? 0 : null;\n\t_eqRangePart.mode = extra ? 3 : 0;\n\n\treturn _rangeNum(_min, _max, _eqRange);\n}\n\n// nullish coalesce\nfunction ifNull(lh, rh) {\n\treturn lh == null ? rh : lh;\n}\n\n// checks if given index range in an array contains a non-null value\n// aka a range-bounded Array.some()\nfunction hasData(data, idx0, idx1) {\n\tidx0 = ifNull(idx0, 0);\n\tidx1 = ifNull(idx1, data.length - 1);\n\n\twhile (idx0 <= idx1) {\n\t\tif (data[idx0] != null)\n\t\t\treturn true;\n\t\tidx0++;\n\t}\n\n\treturn false;\n}\n\nfunction _rangeNum(_min, _max, cfg) {\n\tlet cmin = cfg.min;\n\tlet cmax = cfg.max;\n\n\tlet padMin = ifNull(cmin.pad, 0);\n\tlet padMax = ifNull(cmax.pad, 0);\n\n\tlet hardMin = ifNull(cmin.hard, -inf);\n\tlet hardMax = ifNull(cmax.hard, inf);\n\n\tlet softMin = ifNull(cmin.soft, inf);\n\tlet softMax = ifNull(cmax.soft, -inf);\n\n\tlet softMinMode = ifNull(cmin.mode, 0);\n\tlet softMaxMode = ifNull(cmax.mode, 0);\n\n\tlet delta = _max - _min;\n\tlet deltaMag = log10(delta);\n\n\tlet scalarMax = max(abs(_min), abs(_max));\n\tlet scalarMag = log10(scalarMax);\n\n\tlet scalarMagDelta = abs(scalarMag - deltaMag);\n\n\t// this handles situations like 89.7, 89.69999999999999\n\t// by assuming 0.001x deltas are precision errors\n//\tif (delta > 0 && delta < abs(_max) / 1e3)\n//\t\tdelta = 0;\n\n\t// treat data as flat if delta is less than 1e-24\n\t// or range is 11+ orders of magnitude below raw values, e.g. 99999999.99999996 - 100000000.00000004\n\tif (delta < 1e-24 || scalarMagDelta > 10) {\n\t\tdelta = 0;\n\n\t\t// if soft mode is 2 and all vals are flat at 0, avoid the 0.1 * 1e3 fallback\n\t\t// this prevents 0,0,0 from ranging to -100,100 when softMin/softMax are -1,1\n\t\tif (_min == 0 || _max == 0) {\n\t\t\tdelta = 1e-24;\n\n\t\t\tif (softMinMode == 2 && softMin != inf)\n\t\t\t\tpadMin = 0;\n\n\t\t\tif (softMaxMode == 2 && softMax != -inf)\n\t\t\t\tpadMax = 0;\n\t\t}\n\t}\n\n\tlet nonZeroDelta = delta || scalarMax || 1e3;\n\tlet mag = log10(nonZeroDelta);\n\tlet base = pow(10, floor(mag));\n\n\tlet _padMin = nonZeroDelta * (delta == 0 ? (_min == 0 ? .1 : 1) : padMin);\n\tlet _newMin = roundDec(incrRoundDn(_min - _padMin, base/10), 24);\n\tlet _softMin = _min >= softMin && (softMinMode == 1 || softMinMode == 3 && _newMin <= softMin || softMinMode == 2 && _newMin >= softMin) ? softMin : inf;\n\tlet minLim = max(hardMin, _newMin < _softMin && _min >= _softMin ? _softMin : min(_softMin, _newMin));\n\n\tlet _padMax = nonZeroDelta * (delta == 0 ? (_max == 0 ? .1 : 1) : padMax);\n\tlet _newMax = roundDec(incrRoundUp(_max + _padMax, base/10), 24);\n\tlet _softMax = _max <= softMax && (softMaxMode == 1 || softMaxMode == 3 && _newMax >= softMax || softMaxMode == 2 && _newMax <= softMax) ? softMax : -inf;\n\tlet maxLim = min(hardMax, _newMax > _softMax && _max <= _softMax ? _softMax : max(_softMax, _newMax));\n\n\tif (minLim == maxLim && minLim == 0)\n\t\tmaxLim = 100;\n\n\treturn [minLim, maxLim];\n}\n\n// alternative: https://stackoverflow.com/a/2254896\nconst numFormatter = new Intl.NumberFormat(domEnv ? nav.language : 'en-US');\nconst fmtNum = val => numFormatter.format(val);\n\nconst M = Math;\n\nconst PI = M.PI;\nconst abs = M.abs;\nconst floor = M.floor;\nconst round = M.round;\nconst ceil = M.ceil;\nconst min = M.min;\nconst max = M.max;\nconst pow = M.pow;\nconst sign = M.sign;\nconst log10 = M.log10;\nconst log2 = M.log2;\n// TODO: seems like this needs to match asinh impl if the passed v is tweaked?\nconst sinh = (v, linthresh = 1) => M.sinh(v) * linthresh;\nconst asinh = (v, linthresh = 1) => M.asinh(v / linthresh);\n\nconst inf = Infinity;\n\nfunction numIntDigits(x) {\n\treturn (log10((x ^ (x >> 31)) - (x >> 31)) | 0) + 1;\n}\n\nfunction clamp(num, _min, _max) {\n\treturn min(max(num, _min), _max);\n}\n\nfunction isFn(v) {\n\treturn typeof v == \"function\";\n}\n\nfunction fnOrSelf(v) {\n\treturn isFn(v) ? v : () => v;\n}\n\nconst noop = () => {};\n\n// note: these identity fns may get deoptimized if reused for different arg types\n// a TS version would enforce they stay monotyped and require making variants\nconst retArg0 = _0 => _0;\n\nconst retArg1 = (_0, _1) => _1;\n\nconst retNull = _ => null;\n\nconst retTrue = _ => true;\n\nconst retEq = (a, b) => a == b;\n\nconst regex6 = /\\.\\d*?(?=9{6,}|0{6,})/gm;\n\n// e.g. 17999.204999999998 -> 17999.205\nconst fixFloat = val => {\n\tif (isInt(val) || fixedDec.has(val))\n\t\treturn val;\n\n\tconst str = `${val}`;\n\n\tconst match = str.match(regex6);\n\n\tif (match == null)\n\t\treturn val;\n\n\tlet len = match[0].length - 1;\n\n\t// e.g. 1.0000000000000001e-24\n\tif (str.indexOf('e-') != -1) {\n\t\tlet [num, exp] = str.split('e');\n\t\treturn +`${fixFloat(num)}e${exp}`;\n\t}\n\n\treturn roundDec(val, len);\n};\n\nfunction incrRound(num, incr) {\n\treturn fixFloat(roundDec(fixFloat(num/incr))*incr);\n}\n\nfunction incrRoundUp(num, incr) {\n\treturn fixFloat(ceil(fixFloat(num/incr))*incr);\n}\n\nfunction incrRoundDn(num, incr) {\n\treturn fixFloat(floor(fixFloat(num/incr))*incr);\n}\n\n// https://stackoverflow.com/a/48764436\n// rounds half away from zero\nfunction roundDec(val, dec = 0) {\n\tif (isInt(val))\n\t\treturn val;\n//\telse if (dec == 0)\n//\t\treturn round(val);\n\n\tlet p = 10 ** dec;\n\tlet n = (val * p) * (1 + Number.EPSILON);\n\treturn round(n) / p;\n}\n\nconst fixedDec = new Map();\n\nfunction guessDec(num) {\n\treturn ((\"\"+num).split(\".\")[1] || \"\").length;\n}\n\nfunction genIncrs(base, minExp, maxExp, mults) {\n\tlet incrs = [];\n\n\tlet multDec = mults.map(guessDec);\n\n\tfor (let exp = minExp; exp < maxExp; exp++) {\n\t\tlet expa = abs(exp);\n\t\tlet mag = roundDec(pow(base, exp), expa);\n\n\t\tfor (let i = 0; i < mults.length; i++) {\n\t\t\tlet _incr = base == 10 ? +`${mults[i]}e${exp}` : mults[i] * mag;\n\t\t\tlet dec = (exp >= 0 ? 0 : expa) + (exp >= multDec[i] ? 0 : multDec[i]);\n\t\t\tlet incr = base == 10 ? _incr : roundDec(_incr, dec);\n\t\t\tincrs.push(incr);\n\t\t\tfixedDec.set(incr, dec);\n\t\t}\n\t}\n\n\treturn incrs;\n}\n\n//export const assign = Object.assign;\n\nconst EMPTY_OBJ = {};\nconst EMPTY_ARR = [];\n\nconst nullNullTuple = [null, null];\n\nconst isArr = Array.isArray;\nconst isInt = Number.isInteger;\nconst isUndef = v => v === void 0;\n\nfunction isStr(v) {\n\treturn typeof v == 'string';\n}\n\nfunction isObj(v) {\n\tlet is = false;\n\n\tif (v != null) {\n\t\tlet c = v.constructor;\n\t\tis = c == null || c == Object;\n\t}\n\n\treturn is;\n}\n\nfunction fastIsObj(v) {\n\treturn v != null && typeof v == 'object';\n}\n\nconst TypedArray = Object.getPrototypeOf(Uint8Array);\n\nconst __proto__ = \"__proto__\";\n\nfunction copy(o, _isObj = isObj) {\n\tlet out;\n\n\tif (isArr(o)) {\n\t\tlet val = o.find(v => v != null);\n\n\t\tif (isArr(val) || _isObj(val)) {\n\t\t\tout = Array(o.length);\n\t\t\tfor (let i = 0; i < o.length; i++)\n\t\t\t\tout[i] = copy(o[i], _isObj);\n\t\t}\n\t\telse\n\t\t\tout = o.slice();\n\t}\n\telse if (o instanceof TypedArray) // also (ArrayBuffer.isView(o) && !(o instanceof DataView))\n\t\tout = o.slice();\n\telse if (_isObj(o)) {\n\t\tout = {};\n\t\tfor (let k in o) {\n\t\t\tif (k != __proto__)\n\t\t\t\tout[k] = copy(o[k], _isObj);\n\t\t}\n\t}\n\telse\n\t\tout = o;\n\n\treturn out;\n}\n\nfunction assign(targ) {\n\tlet args = arguments;\n\n\tfor (let i = 1; i < args.length; i++) {\n\t\tlet src = args[i];\n\n\t\tfor (let key in src) {\n\t\t\tif (key != __proto__) {\n\t\t\t\tif (isObj(targ[key]))\n\t\t\t\t\tassign(targ[key], copy(src[key]));\n\t\t\t\telse\n\t\t\t\t\ttarg[key] = copy(src[key]);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn targ;\n}\n\n// nullModes\nconst NULL_REMOVE = 0; // nulls are converted to undefined (e.g. for spanGaps: true)\nconst NULL_RETAIN = 1; // nulls are retained, with alignment artifacts set to undefined (default)\nconst NULL_EXPAND = 2; // nulls are expanded to include any adjacent alignment artifacts\n\n// sets undefined values to nulls when adjacent to existing nulls (minesweeper)\nfunction nullExpand(yVals, nullIdxs, alignedLen) {\n\tfor (let i = 0, xi, lastNullIdx = -1; i < nullIdxs.length; i++) {\n\t\tlet nullIdx = nullIdxs[i];\n\n\t\tif (nullIdx > lastNullIdx) {\n\t\t\txi = nullIdx - 1;\n\t\t\twhile (xi >= 0 && yVals[xi] == null)\n\t\t\t\tyVals[xi--] = null;\n\n\t\t\txi = nullIdx + 1;\n\t\t\twhile (xi < alignedLen && yVals[xi] == null)\n\t\t\t\tyVals[lastNullIdx = xi++] = null;\n\t\t}\n\t}\n}\n\n// nullModes is a tables-matched array indicating how to treat nulls in each series\n// output is sorted ASC on the joined field (table[0]) and duplicate join values are collapsed\nfunction join(tables, nullModes) {\n\tif (allHeadersSame(tables)) {\n\t//\tconsole.log('cheap join!');\n\n\t\tlet table = tables[0].slice();\n\n\t\tfor (let i = 1; i < tables.length; i++)\n\t\t\ttable.push(...tables[i].slice(1));\n\n\t\tif (!isAsc(table[0]))\n\t\t\ttable = sortCols(table);\n\n\t\treturn table;\n\t}\n\n\tlet xVals = new Set();\n\n\tfor (let ti = 0; ti < tables.length; ti++) {\n\t\tlet t = tables[ti];\n\t\tlet xs = t[0];\n\t\tlet len = xs.length;\n\n\t\tfor (let i = 0; i < len; i++)\n\t\t\txVals.add(xs[i]);\n\t}\n\n\tlet data = [Array.from(xVals).sort((a, b) => a - b)];\n\n\tlet alignedLen = data[0].length;\n\n\tlet xIdxs = new Map();\n\n\tfor (let i = 0; i < alignedLen; i++)\n\t\txIdxs.set(data[0][i], i);\n\n\tfor (let ti = 0; ti < tables.length; ti++) {\n\t\tlet t = tables[ti];\n\t\tlet xs = t[0];\n\n\t\tfor (let si = 1; si < t.length; si++) {\n\t\t\tlet ys = t[si];\n\n\t\t\tlet yVals = Array(alignedLen).fill(undefined);\n\n\t\t\tlet nullMode = nullModes ? nullModes[ti][si] : NULL_RETAIN;\n\n\t\t\tlet nullIdxs = [];\n\n\t\t\tfor (let i = 0; i < ys.length; i++) {\n\t\t\t\tlet yVal = ys[i];\n\t\t\t\tlet alignedIdx = xIdxs.get(xs[i]);\n\n\t\t\t\tif (yVal === null) {\n\t\t\t\t\tif (nullMode != NULL_REMOVE) {\n\t\t\t\t\t\tyVals[alignedIdx] = yVal;\n\n\t\t\t\t\t\tif (nullMode == NULL_EXPAND)\n\t\t\t\t\t\t\tnullIdxs.push(alignedIdx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tyVals[alignedIdx] = yVal;\n\t\t\t}\n\n\t\t\tnullExpand(yVals, nullIdxs, alignedLen);\n\n\t\t\tdata.push(yVals);\n\t\t}\n\t}\n\n\treturn data;\n}\n\nconst microTask = typeof queueMicrotask == \"undefined\" ? fn => Promise.resolve().then(fn) : queueMicrotask;\n\n// TODO: https://github.com/dy/sort-ids (~2x faster for 1e5+ arrays)\nfunction sortCols(table) {\n\tlet head = table[0];\n\tlet rlen = head.length;\n\n\tlet idxs = Array(rlen);\n\tfor (let i = 0; i < idxs.length; i++)\n\t\tidxs[i] = i;\n\n\tidxs.sort((i0, i1) => head[i0] - head[i1]);\n\n\tlet table2 = [];\n\tfor (let i = 0; i < table.length; i++) {\n\t\tlet row = table[i];\n\t\tlet row2 = Array(rlen);\n\n\t\tfor (let j = 0; j < rlen; j++)\n\t\t\trow2[j] = row[idxs[j]];\n\n\t\ttable2.push(row2);\n\t}\n\n\treturn table2;\n}\n\n// test if we can do cheap join (all join fields same)\nfunction allHeadersSame(tables) {\n\tlet vals0 = tables[0][0];\n\tlet len0 = vals0.length;\n\n\tfor (let i = 1; i < tables.length; i++) {\n\t\tlet vals1 = tables[i][0];\n\n\t\tif (vals1.length != len0)\n\t\t\treturn false;\n\n\t\tif (vals1 != vals0) {\n\t\t\tfor (let j = 0; j < len0; j++) {\n\t\t\t\tif (vals1[j] != vals0[j])\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true;\n}\n\nfunction isAsc(vals, samples = 100) {\n\tconst len = vals.length;\n\n\t// empty or single value\n\tif (len <= 1)\n\t\treturn true;\n\n\t// skip leading & trailing nullish\n\tlet firstIdx = 0;\n\tlet lastIdx = len - 1;\n\n\twhile (firstIdx <= lastIdx && vals[firstIdx] == null)\n\t\tfirstIdx++;\n\n\twhile (lastIdx >= firstIdx && vals[lastIdx] == null)\n\t\tlastIdx--;\n\n\t// all nullish or one value surrounded by nullish\n\tif (lastIdx <= firstIdx)\n\t\treturn true;\n\n\tconst stride = max(1, floor((lastIdx - firstIdx + 1) / samples));\n\n\tfor (let prevVal = vals[firstIdx], i = firstIdx + stride; i <= lastIdx; i += stride) {\n\t\tconst v = vals[i];\n\n\t\tif (v != null) {\n\t\t\tif (v <= prevVal)\n\t\t\t\treturn false;\n\n\t\t\tprevVal = v;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nconst months = [\n\t\"January\",\n\t\"February\",\n\t\"March\",\n\t\"April\",\n\t\"May\",\n\t\"June\",\n\t\"July\",\n\t\"August\",\n\t\"September\",\n\t\"October\",\n\t\"November\",\n\t\"December\",\n];\n\nconst days = [\n\t\"Sunday\",\n\t\"Monday\",\n\t\"Tuesday\",\n\t\"Wednesday\",\n\t\"Thursday\",\n\t\"Friday\",\n\t\"Saturday\",\n];\n\nfunction slice3(str) {\n\treturn str.slice(0, 3);\n}\n\nconst days3 = days.map(slice3);\n\nconst months3 = months.map(slice3);\n\nconst engNames = {\n\tMMMM: months,\n\tMMM: months3,\n\tWWWW: days,\n\tWWW: days3,\n};\n\nfunction zeroPad2(int) {\n\treturn (int < 10 ? '0' : '') + int;\n}\n\nfunction zeroPad3(int) {\n\treturn (int < 10 ? '00' : int < 100 ? '0' : '') + int;\n}\n\n/*\nfunction suffix(int) {\n\tlet mod10 = int % 10;\n\n\treturn int + (\n\t\tmod10 == 1 && int != 11 ? \"st\" :\n\t\tmod10 == 2 && int != 12 ? \"nd\" :\n\t\tmod10 == 3 && int != 13 ? \"rd\" : \"th\"\n\t);\n}\n*/\n\nconst subs = {\n\t// 2019\n\tYYYY:\td => d.getFullYear(),\n\t// 19\n\tYY:\t\td => (d.getFullYear()+'').slice(2),\n\t// July\n\tMMMM:\t(d, names) => names.MMMM[d.getMonth()],\n\t// Jul\n\tMMM:\t(d, names) => names.MMM[d.getMonth()],\n\t// 07\n\tMM:\t\td => zeroPad2(d.getMonth()+1),\n\t// 7\n\tM:\t\td => d.getMonth()+1,\n\t// 09\n\tDD:\t\td => zeroPad2(d.getDate()),\n\t// 9\n\tD:\t\td => d.getDate(),\n\t// Monday\n\tWWWW:\t(d, names) => names.WWWW[d.getDay()],\n\t// Mon\n\tWWW:\t(d, names) => names.WWW[d.getDay()],\n\t// 03\n\tHH:\t\td => zeroPad2(d.getHours()),\n\t// 3\n\tH:\t\td => d.getHours(),\n\t// 9 (12hr, unpadded)\n\th:\t\td => {let h = d.getHours(); return h == 0 ? 12 : h > 12 ? h - 12 : h;},\n\t// AM\n\tAA:\t\td => d.getHours() >= 12 ? 'PM' : 'AM',\n\t// am\n\taa:\t\td => d.getHours() >= 12 ? 'pm' : 'am',\n\t// a\n\ta:\t\td => d.getHours() >= 12 ? 'p' : 'a',\n\t// 09\n\tmm:\t\td => zeroPad2(d.getMinutes()),\n\t// 9\n\tm:\t\td => d.getMinutes(),\n\t// 09\n\tss:\t\td => zeroPad2(d.getSeconds()),\n\t// 9\n\ts:\t\td => d.getSeconds(),\n\t// 374\n\tfff:\td => zeroPad3(d.getMilliseconds()),\n};\n\nfunction fmtDate(tpl, names) {\n\tnames = names || engNames;\n\tlet parts = [];\n\n\tlet R = /\\{([a-z]+)\\}|[^{]+/gi, m;\n\n\twhile (m = R.exec(tpl))\n\t\tparts.push(m[0][0] == '{' ? subs[m[1]] : m[0]);\n\n\treturn d => {\n\t\tlet out = '';\n\n\t\tfor (let i = 0; i < parts.length; i++)\n\t\t\tout += typeof parts[i] == \"string\" ? parts[i] : parts[i](d, names);\n\n\t\treturn out;\n\t}\n}\n\nconst localTz = new Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n// https://stackoverflow.com/questions/15141762/how-to-initialize-a-javascript-date-to-a-particular-time-zone/53652131#53652131\nfunction tzDate(date, tz) {\n\tlet date2;\n\n\t// perf optimization\n\tif (tz == 'UTC' || tz == 'Etc/UTC')\n\t\tdate2 = new Date(+date + date.getTimezoneOffset() * 6e4);\n\telse if (tz == localTz)\n\t\tdate2 = date;\n\telse {\n\t\tdate2 = new Date(date.toLocaleString('en-US', {timeZone: tz}));\n\t\tdate2.setMilliseconds(date.getMilliseconds());\n\t}\n\n\treturn date2;\n}\n\n//export const series = [];\n\n// default formatters:\n\nconst onlyWhole = v => v % 1 == 0;\n\nconst allMults = [1,2,2.5,5];\n\n// ...0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5\nconst decIncrs = genIncrs(10, -32, 0, allMults);\n\n// 1, 2, 2.5, 5, 10, 20, 25, 50...\nconst oneIncrs = genIncrs(10, 0, 32, allMults);\n\n// 1, 2, 5, 10, 20, 25, 50...\nconst wholeIncrs = oneIncrs.filter(onlyWhole);\n\nconst numIncrs = decIncrs.concat(oneIncrs);\n\nconst NL = \"\\n\";\n\nconst yyyy = \"{YYYY}\";\nconst NLyyyy = NL + yyyy;\nconst md = \"{M}/{D}\";\nconst NLmd = NL + md;\nconst NLmdyy = NLmd + \"/{YY}\";\n\nconst aa = \"{aa}\";\nconst hmm = \"{h}:{mm}\";\nconst hmmaa = hmm + aa;\nconst NLhmmaa = NL + hmmaa;\nconst ss = \":{ss}\";\n\nconst _ = null;\n\nfunction genTimeStuffs(ms) {\n\tlet\ts = ms * 1e3,\n\t\tm = s * 60,\n\t\th = m * 60,\n\t\td = h * 24,\n\t\tmo = d * 30,\n\t\ty = d * 365;\n\n\t// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms\n\tlet subSecIncrs = ms == 1 ? genIncrs(10, 0, 3, allMults).filter(onlyWhole) : genIncrs(10, -3, 0, allMults);\n\n\tlet timeIncrs = subSecIncrs.concat([\n\t\t// minute divisors (# of secs)\n\t\ts,\n\t\ts * 5,\n\t\ts * 10,\n\t\ts * 15,\n\t\ts * 30,\n\t\t// hour divisors (# of mins)\n\t\tm,\n\t\tm * 5,\n\t\tm * 10,\n\t\tm * 15,\n\t\tm * 30,\n\t\t// day divisors (# of hrs)\n\t\th,\n\t\th * 2,\n\t\th * 3,\n\t\th * 4,\n\t\th * 6,\n\t\th * 8,\n\t\th * 12,\n\t\t// month divisors TODO: need more?\n\t\td,\n\t\td * 2,\n\t\td * 3,\n\t\td * 4,\n\t\td * 5,\n\t\td * 6,\n\t\td * 7,\n\t\td * 8,\n\t\td * 9,\n\t\td * 10,\n\t\td * 15,\n\t\t// year divisors (# months, approx)\n\t\tmo,\n\t\tmo * 2,\n\t\tmo * 3,\n\t\tmo * 4,\n\t\tmo * 6,\n\t\t// century divisors\n\t\ty,\n\t\ty * 2,\n\t\ty * 5,\n\t\ty * 10,\n\t\ty * 25,\n\t\ty * 50,\n\t\ty * 100,\n\t]);\n\n\t// [0]: minimum num secs in the tick incr\n\t// [1]: default tick format\n\t// [2-7]: rollover tick formats\n\t// [8]: mode: 0: replace [1] -> [2-7], 1: concat [1] + [2-7]\n\tconst _timeAxisStamps = [\n\t// tick incr default year month day hour min sec mode\n\t\t[y, yyyy, _, _, _, _, _, _, 1],\n\t\t[d * 28, \"{MMM}\", NLyyyy, _, _, _, _, _, 1],\n\t\t[d, md, NLyyyy, _, _, _, _, _, 1],\n\t\t[h, \"{h}\" + aa, NLmdyy, _, NLmd, _, _, _, 1],\n\t\t[m, hmmaa, NLmdyy, _, NLmd, _, _, _, 1],\n\t\t[s, ss, NLmdyy + \" \" + hmmaa, _, NLmd + \" \" + hmmaa, _, NLhmmaa, _, 1],\n\t\t[ms, ss + \".{fff}\", NLmdyy + \" \" + hmmaa, _, NLmd + \" \" + hmmaa, _, NLhmmaa, _, 1],\n\t];\n\n\t// the ensures that axis ticks, values & grid are aligned to logical temporal breakpoints and not an arbitrary timestamp\n\t// https://www.timeanddate.com/time/dst/\n\t// https://www.timeanddate.com/time/dst/2019.html\n\t// https://www.epochconverter.com/timezones\n\tfunction timeAxisSplits(tzDate) {\n\t\treturn (self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) => {\n\t\t\tlet splits = [];\n\t\t\tlet isYr = foundIncr >= y;\n\t\t\tlet isMo = foundIncr >= mo && foundIncr < y;\n\n\t\t\t// get the timezone-adjusted date\n\t\t\tlet minDate = tzDate(scaleMin);\n\t\t\tlet minDateTs = roundDec(minDate * ms, 3);\n\n\t\t\t// get ts of 12am (this lands us at or before the original scaleMin)\n\t\t\tlet minMin = mkDate(minDate.getFullYear(), isYr ? 0 : minDate.getMonth(), isMo || isYr ? 1 : minDate.getDate());\n\t\t\tlet minMinTs = roundDec(minMin * ms, 3);\n\n\t\t\tif (isMo || isYr) {\n\t\t\t\tlet moIncr = isMo ? foundIncr / mo : 0;\n\t\t\t\tlet yrIncr = isYr ? foundIncr / y : 0;\n\t\t\t//\tlet tzOffset = scaleMin - minDateTs;\t\t// needed?\n\t\t\t\tlet split = minDateTs == minMinTs ? minDateTs : roundDec(mkDate(minMin.getFullYear() + yrIncr, minMin.getMonth() + moIncr, 1) * ms, 3);\n\t\t\t\tlet splitDate = new Date(round(split / ms));\n\t\t\t\tlet baseYear = splitDate.getFullYear();\n\t\t\t\tlet baseMonth = splitDate.getMonth();\n\n\t\t\t\tfor (let i = 0; split <= scaleMax; i++) {\n\t\t\t\t\tlet next = mkDate(baseYear + yrIncr * i, baseMonth + moIncr * i, 1);\n\t\t\t\t\tlet offs = next - tzDate(roundDec(next * ms, 3));\n\n\t\t\t\t\tsplit = roundDec((+next + offs) * ms, 3);\n\n\t\t\t\t\tif (split <= scaleMax)\n\t\t\t\t\t\tsplits.push(split);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlet incr0 = foundIncr >= d ? d : foundIncr;\n\t\t\t\tlet tzOffset = floor(scaleMin) - floor(minDateTs);\n\t\t\t\tlet split = minMinTs + tzOffset + incrRoundUp(minDateTs - minMinTs, incr0);\n\t\t\t\tsplits.push(split);\n\n\t\t\t\tlet date0 = tzDate(split);\n\n\t\t\t\tlet prevHour = date0.getHours() + (date0.getMinutes() / m) + (date0.getSeconds() / h);\n\t\t\t\tlet incrHours = foundIncr / h;\n\n\t\t\t\tlet minSpace = self.axes[axisIdx]._space;\n\t\t\t\tlet pctSpace = foundSpace / minSpace;\n\n\t\t\t\twhile (1) {\n\t\t\t\t\tsplit = roundDec(split + foundIncr, ms == 1 ? 0 : 3);\n\n\t\t\t\t\tif (split > scaleMax)\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tif (incrHours > 1) {\n\t\t\t\t\t\tlet expectedHour = floor(roundDec(prevHour + incrHours, 6)) % 24;\n\t\t\t\t\t\tlet splitDate = tzDate(split);\n\t\t\t\t\t\tlet actualHour = splitDate.getHours();\n\n\t\t\t\t\t\tlet dstShift = actualHour - expectedHour;\n\n\t\t\t\t\t\tif (dstShift > 1)\n\t\t\t\t\t\t\tdstShift = -1;\n\n\t\t\t\t\t\tsplit -= dstShift * h;\n\n\t\t\t\t\t\tprevHour = (prevHour + incrHours) % 24;\n\n\t\t\t\t\t\t// add a tick only if it's further than 70% of the min allowed label spacing\n\t\t\t\t\t\tlet prevSplit = splits[splits.length - 1];\n\t\t\t\t\t\tlet pctIncr = roundDec((split - prevSplit) / foundIncr, 3);\n\n\t\t\t\t\t\tif (pctIncr * pctSpace >= .7)\n\t\t\t\t\t\t\tsplits.push(split);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tsplits.push(split);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn splits;\n\t\t}\n\t}\n\n\treturn [\n\t\ttimeIncrs,\n\t\t_timeAxisStamps,\n\t\ttimeAxisSplits,\n\t];\n}\n\nconst [ timeIncrsMs, _timeAxisStampsMs, timeAxisSplitsMs ] = genTimeStuffs(1);\nconst [ timeIncrsS, _timeAxisStampsS, timeAxisSplitsS ] = genTimeStuffs(1e-3);\n\n// base 2\ngenIncrs(2, -53, 53, [1]);\n\n/*\nconsole.log({\n\tdecIncrs,\n\toneIncrs,\n\twholeIncrs,\n\tnumIncrs,\n\ttimeIncrs,\n\tfixedDec,\n});\n*/\n\nfunction timeAxisStamps(stampCfg, fmtDate) {\n\treturn stampCfg.map(s => s.map((v, i) =>\n\t\ti == 0 || i == 8 || v == null ? v : fmtDate(i == 1 || s[8] == 0 ? v : s[1] + v)\n\t));\n}\n\n// TODO: will need to accept spaces[] and pull incr into the loop when grid will be non-uniform, eg for log scales.\n// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it\nfunction timeAxisVals(tzDate, stamps) {\n\treturn (self, splits, axisIdx, foundSpace, foundIncr) => {\n\t\tlet s = stamps.find(s => foundIncr >= s[0]) || stamps[stamps.length - 1];\n\n\t\t// these track boundaries when a full label is needed again\n\t\tlet prevYear;\n\t\tlet prevMnth;\n\t\tlet prevDate;\n\t\tlet prevHour;\n\t\tlet prevMins;\n\t\tlet prevSecs;\n\n\t\treturn splits.map(split => {\n\t\t\tlet date = tzDate(split);\n\n\t\t\tlet newYear = date.getFullYear();\n\t\t\tlet newMnth = date.getMonth();\n\t\t\tlet newDate = date.getDate();\n\t\t\tlet newHour = date.getHours();\n\t\t\tlet newMins = date.getMinutes();\n\t\t\tlet newSecs = date.getSeconds();\n\n\t\t\tlet stamp = (\n\t\t\t\tnewYear != prevYear && s[2] ||\n\t\t\t\tnewMnth != prevMnth && s[3] ||\n\t\t\t\tnewDate != prevDate && s[4] ||\n\t\t\t\tnewHour != prevHour && s[5] ||\n\t\t\t\tnewMins != prevMins && s[6] ||\n\t\t\t\tnewSecs != prevSecs && s[7] ||\n\t\t\t\t s[1]\n\t\t\t);\n\n\t\t\tprevYear = newYear;\n\t\t\tprevMnth = newMnth;\n\t\t\tprevDate = newDate;\n\t\t\tprevHour = newHour;\n\t\t\tprevMins = newMins;\n\t\t\tprevSecs = newSecs;\n\n\t\t\treturn stamp(date);\n\t\t});\n\t}\n}\n\n// for when axis.values is defined as a static fmtDate template string\nfunction timeAxisVal(tzDate, dateTpl) {\n\tlet stamp = fmtDate(dateTpl);\n\treturn (self, splits, axisIdx, foundSpace, foundIncr) => splits.map(split => stamp(tzDate(split)));\n}\n\nfunction mkDate(y, m, d) {\n\treturn new Date(y, m, d);\n}\n\nfunction timeSeriesStamp(stampCfg, fmtDate) {\n\treturn fmtDate(stampCfg);\n}\nconst _timeSeriesStamp = '{YYYY}-{MM}-{DD} {h}:{mm}{aa}';\n\nfunction timeSeriesVal(tzDate, stamp) {\n\treturn (self, val, seriesIdx, dataIdx) => dataIdx == null ? LEGEND_DISP : stamp(tzDate(val));\n}\n\nfunction legendStroke(self, seriesIdx) {\n\tlet s = self.series[seriesIdx];\n\treturn s.width ? s.stroke(self, seriesIdx) : s.points.width ? s.points.stroke(self, seriesIdx) : null;\n}\n\nfunction legendFill(self, seriesIdx) {\n\treturn self.series[seriesIdx].fill(self, seriesIdx);\n}\n\nconst legendOpts = {\n\tshow: true,\n\tlive: true,\n\tisolate: false,\n\tmount: noop,\n\tmarkers: {\n\t\tshow: true,\n\t\twidth: 2,\n\t\tstroke: legendStroke,\n\t\tfill: legendFill,\n\t\tdash: \"solid\",\n\t},\n\tidx: null,\n\tidxs: null,\n\tvalues: [],\n};\n\nfunction cursorPointShow(self, si) {\n\tlet o = self.cursor.points;\n\n\tlet pt = placeDiv();\n\n\tlet size = o.size(self, si);\n\tsetStylePx(pt, WIDTH, size);\n\tsetStylePx(pt, HEIGHT, size);\n\n\tlet mar = size / -2;\n\tsetStylePx(pt, \"marginLeft\", mar);\n\tsetStylePx(pt, \"marginTop\", mar);\n\n\tlet width = o.width(self, si, size);\n\twidth && setStylePx(pt, \"borderWidth\", width);\n\n\treturn pt;\n}\n\nfunction cursorPointFill(self, si) {\n\tlet sp = self.series[si].points;\n\treturn sp._fill || sp._stroke;\n}\n\nfunction cursorPointStroke(self, si) {\n\tlet sp = self.series[si].points;\n\treturn sp._stroke || sp._fill;\n}\n\nfunction cursorPointSize(self, si) {\n\tlet sp = self.series[si].points;\n\treturn sp.size;\n}\n\nconst moveTuple = [0,0];\n\nfunction cursorMove(self, mouseLeft1, mouseTop1) {\n\tmoveTuple[0] = mouseLeft1;\n\tmoveTuple[1] = mouseTop1;\n\treturn moveTuple;\n}\n\nfunction filtBtn0(self, targ, handle, onlyTarg = true) {\n\treturn e => {\n\t\te.button == 0 && (!onlyTarg || e.target == targ) && handle(e);\n\t};\n}\n\nfunction filtTarg(self, targ, handle, onlyTarg = true) {\n\treturn e => {\n\t\t(!onlyTarg || e.target == targ) && handle(e);\n\t};\n}\n\nconst cursorOpts = {\n\tshow: true,\n\tx: true,\n\ty: true,\n\tlock: false,\n\tmove: cursorMove,\n\tpoints: {\n\t\tone: false,\n\t\tshow: cursorPointShow,\n\t\tsize: cursorPointSize,\n\t\twidth: 0,\n\t\tstroke: cursorPointStroke,\n\t\tfill: cursorPointFill,\n\t},\n\n\tbind: {\n\t\tmousedown: filtBtn0,\n\t\tmouseup: filtBtn0,\n\t\tclick: filtBtn0, // legend clicks, not .u-over clicks\n\t\tdblclick: filtBtn0,\n\n\t\tmousemove: filtTarg,\n\t\tmouseleave: filtTarg,\n\t\tmouseenter: filtTarg,\n\t},\n\n\tdrag: {\n\t\tsetScale: true,\n\t\tx: true,\n\t\ty: false,\n\t\tdist: 0,\n\t\tuni: null,\n\t\tclick: (self, e) => {\n\t\t//\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\te.stopImmediatePropagation();\n\t\t},\n\t\t_x: false,\n\t\t_y: false,\n\t},\n\n\tfocus: {\n\t\tdist: (self, seriesIdx, dataIdx, valPos, curPos) => valPos - curPos,\n\t\tprox: -1,\n\t\tbias: 0,\n\t},\n\n\thover: {\n\t\tskip: [void 0],\n\t\tprox: null,\n\t\tbias: 0,\n\t},\n\n\tleft: -10,\n\ttop: -10,\n\tidx: null,\n\tdataIdx: null,\n\tidxs: null,\n\n\tevent: null,\n};\n\nconst axisLines = {\n\tshow: true,\n\tstroke: \"rgba(0,0,0,0.07)\",\n\twidth: 2,\n//\tdash: [],\n};\n\nconst grid = assign({}, axisLines, {\n\tfilter: retArg1,\n});\n\nconst ticks = assign({}, grid, {\n\tsize: 10,\n});\n\nconst border = assign({}, axisLines, {\n\tshow: false,\n});\n\nconst font = '12px system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"';\nconst labelFont = \"bold \" + font;\nconst lineGap = 1.5;\t// font-size multiplier\n\nconst xAxisOpts = {\n\tshow: true,\n\tscale: \"x\",\n\tstroke: hexBlack,\n\tspace: 50,\n\tgap: 5,\n\talignTo: 1,\n\tsize: 50,\n\tlabelGap: 0,\n\tlabelSize: 30,\n\tlabelFont,\n\tside: 2,\n//\tclass: \"x-vals\",\n//\tincrs: timeIncrs,\n//\tvalues: timeVals,\n//\tfilter: retArg1,\n\tgrid,\n\tticks,\n\tborder,\n\tfont,\n\tlineGap,\n\trotate: 0,\n};\n\nconst numSeriesLabel = \"Value\";\nconst timeSeriesLabel = \"Time\";\n\nconst xSeriesOpts = {\n\tshow: true,\n\tscale: \"x\",\n\tauto: false,\n\tsorted: 1,\n//\tlabel: \"Time\",\n//\tvalue: v => stamp(new Date(v * 1e3)),\n\n\t// internal caches\n\tmin: inf,\n\tmax: -inf,\n\tidxs: [],\n};\n\nfunction numAxisVals(self, splits, axisIdx, foundSpace, foundIncr) {\n\treturn splits.map(v => v == null ? \"\" : fmtNum(v));\n}\n\nfunction numAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {\n\tlet splits = [];\n\n\tlet numDec = fixedDec.get(foundIncr) || 0;\n\n\tscaleMin = forceMin ? scaleMin : roundDec(incrRoundUp(scaleMin, foundIncr), numDec);\n\n\tfor (let val = scaleMin; val <= scaleMax; val = roundDec(val + foundIncr, numDec))\n\t\tsplits.push(Object.is(val, -0) ? 0 : val);\t\t// coalesces -0\n\n\treturn splits;\n}\n\n// this doesnt work for sin, which needs to come off from 0 independently in pos and neg dirs\nfunction logAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {\n\tconst splits = [];\n\n\tconst logBase = self.scales[self.axes[axisIdx].scale].log;\n\n\tconst logFn = logBase == 10 ? log10 : log2;\n\n\tconst exp = floor(logFn(scaleMin));\n\n\tfoundIncr = pow(logBase, exp);\n\n\t// boo: 10 ** -24 === 1.0000000000000001e-24\n\t// this grabs the proper 1e-24 one\n\tif (logBase == 10)\n\t\tfoundIncr = numIncrs[closestIdx(foundIncr, numIncrs)];\n\n\tlet split = scaleMin;\n\tlet nextMagIncr = foundIncr * logBase;\n\n\tif (logBase == 10)\n\t\tnextMagIncr = numIncrs[closestIdx(nextMagIncr, numIncrs)];\n\n\tdo {\n\t\tsplits.push(split);\n\t\tsplit = split + foundIncr;\n\n\t\tif (logBase == 10 && !fixedDec.has(split))\n\t\t\tsplit = roundDec(split, fixedDec.get(foundIncr));\n\n\t\tif (split >= nextMagIncr) {\n\t\t\tfoundIncr = split;\n\t\t\tnextMagIncr = foundIncr * logBase;\n\n\t\t\tif (logBase == 10)\n\t\t\t\tnextMagIncr = numIncrs[closestIdx(nextMagIncr, numIncrs)];\n\t\t}\n\t} while (split <= scaleMax);\n\n\treturn splits;\n}\n\nfunction asinhAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {\n\tlet sc = self.scales[self.axes[axisIdx].scale];\n\n\tlet linthresh = sc.asinh;\n\n\tlet posSplits = scaleMax > linthresh ? logAxisSplits(self, axisIdx, max(linthresh, scaleMin), scaleMax, foundIncr) : [linthresh];\n\tlet zero = scaleMax >= 0 && scaleMin <= 0 ? [0] : [];\n\tlet negSplits = scaleMin < -linthresh ? logAxisSplits(self, axisIdx, max(linthresh, -scaleMax), -scaleMin, foundIncr): [linthresh];\n\n\treturn negSplits.reverse().map(v => -v).concat(zero, posSplits);\n}\n\nconst RE_ALL = /./;\nconst RE_12357 = /[12357]/;\nconst RE_125 = /[125]/;\nconst RE_1 = /1/;\n\nconst _filt = (splits, distr, re, keepMod) => splits.map((v, i) => ((distr == 4 && v == 0) || i % keepMod == 0 && re.test(v.toExponential()[v < 0 ? 1 : 0])) ? v : null);\n\nfunction log10AxisValsFilt(self, splits, axisIdx, foundSpace, foundIncr) {\n\tlet axis = self.axes[axisIdx];\n\tlet scaleKey = axis.scale;\n\tlet sc = self.scales[scaleKey];\n\n//\tif (sc.distr == 3 && sc.log == 2)\n//\t\treturn splits;\n\n\tlet valToPos = self.valToPos;\n\n\tlet minSpace = axis._space;\n\n\tlet _10 = valToPos(10, scaleKey);\n\n\tlet re = (\n\t\tvalToPos(9, scaleKey) - _10 >= minSpace ? RE_ALL :\n\t\tvalToPos(7, scaleKey) - _10 >= minSpace ? RE_12357 :\n\t\tvalToPos(5, scaleKey) - _10 >= minSpace ? RE_125 :\n\t\tRE_1\n\t);\n\n\tif (re == RE_1) {\n\t\tlet magSpace = abs(valToPos(1, scaleKey) - _10);\n\n\t\tif (magSpace < minSpace)\n\t\t\treturn _filt(splits.slice().reverse(), sc.distr, re, ceil(minSpace / magSpace)).reverse(); // max->min skip\n\t}\n\n\treturn _filt(splits, sc.distr, re, 1);\n}\n\nfunction log2AxisValsFilt(self, splits, axisIdx, foundSpace, foundIncr) {\n\tlet axis = self.axes[axisIdx];\n\tlet scaleKey = axis.scale;\n\tlet minSpace = axis._space;\n\tlet valToPos = self.valToPos;\n\n\tlet magSpace = abs(valToPos(1, scaleKey) - valToPos(2, scaleKey));\n\n\tif (magSpace < minSpace)\n\t\treturn _filt(splits.slice().reverse(), 3, RE_ALL, ceil(minSpace / magSpace)).reverse(); // max->min skip\n\n\treturn splits;\n}\n\nfunction numSeriesVal(self, val, seriesIdx, dataIdx) {\n\treturn dataIdx == null ? LEGEND_DISP : val == null ? \"\" : fmtNum(val);\n}\n\nconst yAxisOpts = {\n\tshow: true,\n\tscale: \"y\",\n\tstroke: hexBlack,\n\tspace: 30,\n\tgap: 5,\n\talignTo: 1,\n\tsize: 50,\n\tlabelGap: 0,\n\tlabelSize: 30,\n\tlabelFont,\n\tside: 3,\n//\tclass: \"y-vals\",\n//\tincrs: numIncrs,\n//\tvalues: (vals, space) => vals,\n//\tfilter: retArg1,\n\tgrid,\n\tticks,\n\tborder,\n\tfont,\n\tlineGap,\n\trotate: 0,\n};\n\n// takes stroke width\nfunction ptDia(width, mult) {\n\tlet dia = 3 + (width || 1) * 2;\n\treturn roundDec(dia * mult, 3);\n}\n\nfunction seriesPointsShow(self, si) {\n\tlet { scale, idxs } = self.series[0];\n\tlet xData = self._data[0];\n\tlet p0 = self.valToPos(xData[idxs[0]], scale, true);\n\tlet p1 = self.valToPos(xData[idxs[1]], scale, true);\n\tlet dim = abs(p1 - p0);\n\n\tlet s = self.series[si];\n//\tconst dia = ptDia(s.width, pxRatio);\n\tlet maxPts = dim / (s.points.space * pxRatio);\n\treturn idxs[1] - idxs[0] <= maxPts;\n}\n\nconst facet = {\n\tscale: null,\n\tauto: true,\n\tsorted: 0,\n\n\t// internal caches\n\tmin: inf,\n\tmax: -inf,\n};\n\nconst gaps = (self, seriesIdx, idx0, idx1, nullGaps) => nullGaps;\n\nconst xySeriesOpts = {\n\tshow: true,\n\tauto: true,\n\tsorted: 0,\n\tgaps,\n\talpha: 1,\n\tfacets: [\n\t\tassign({}, facet, {scale: 'x'}),\n\t\tassign({}, facet, {scale: 'y'}),\n\t],\n};\n\nconst ySeriesOpts = {\n\tscale: \"y\",\n\tauto: true,\n\tsorted: 0,\n\tshow: true,\n\tspanGaps: false,\n\tgaps,\n\talpha: 1,\n\tpoints: {\n\t\tshow: seriesPointsShow,\n\t\tfilter: null,\n\t// paths:\n\t//\tstroke: \"#000\",\n\t//\tfill: \"#fff\",\n\t//\twidth: 1,\n\t//\tsize: 10,\n\t},\n//\tlabel: \"Value\",\n//\tvalue: v => v,\n\tvalues: null,\n\n\t// internal caches\n\tmin: inf,\n\tmax: -inf,\n\tidxs: [],\n\n\tpath: null,\n\tclip: null,\n};\n\nfunction clampScale(self, val, scaleMin, scaleMax, scaleKey) {\n/*\n\tif (val < 0) {\n\t\tlet cssHgt = self.bbox.height / pxRatio;\n\t\tlet absPos = self.valToPos(abs(val), scaleKey);\n\t\tlet fromBtm = cssHgt - absPos;\n\t\treturn self.posToVal(cssHgt + fromBtm, scaleKey);\n\t}\n*/\n\treturn scaleMin / 10;\n}\n\nconst xScaleOpts = {\n\ttime: FEAT_TIME,\n\tauto: true,\n\tdistr: 1,\n\tlog: 10,\n\tasinh: 1,\n\tmin: null,\n\tmax: null,\n\tdir: 1,\n\tori: 0,\n};\n\nconst yScaleOpts = assign({}, xScaleOpts, {\n\ttime: false,\n\tori: 1,\n});\n\nconst syncs = {};\n\nfunction _sync(key, opts) {\n\tlet s = syncs[key];\n\n\tif (!s) {\n\t\ts = {\n\t\t\tkey,\n\t\t\tplots: [],\n\t\t\tsub(plot) {\n\t\t\t\ts.plots.push(plot);\n\t\t\t},\n\t\t\tunsub(plot) {\n\t\t\t\ts.plots = s.plots.filter(c => c != plot);\n\t\t\t},\n\t\t\tpub(type, self, x, y, w, h, i) {\n\t\t\t\tfor (let j = 0; j < s.plots.length; j++)\n\t\t\t\t\ts.plots[j] != self && s.plots[j].pub(type, self, x, y, w, h, i);\n\t\t\t},\n\t\t};\n\n\t\tif (key != null)\n\t\t\tsyncs[key] = s;\n\t}\n\n\treturn s;\n}\n\nconst BAND_CLIP_FILL = 1 << 0;\nconst BAND_CLIP_STROKE = 1 << 1;\n\nfunction orient(u, seriesIdx, cb) {\n\tconst mode = u.mode;\n\tconst series = u.series[seriesIdx];\n\tconst data = mode == 2 ? u._data[seriesIdx] : u._data;\n\tconst scales = u.scales;\n\tconst bbox = u.bbox;\n\n\tlet dx = data[0],\n\t\tdy = mode == 2 ? data[1] : data[seriesIdx],\n\t\tsx = mode == 2 ? scales[series.facets[0].scale] : scales[u.series[0].scale],\n\t\tsy = mode == 2 ? scales[series.facets[1].scale] : scales[series.scale],\n\t\tl = bbox.left,\n\t\tt = bbox.top,\n\t\tw = bbox.width,\n\t\th = bbox.height,\n\t\tH = u.valToPosH,\n\t\tV = u.valToPosV;\n\n\treturn (sx.ori == 0\n\t\t? cb(\n\t\t\tseries,\n\t\t\tdx,\n\t\t\tdy,\n\t\t\tsx,\n\t\t\tsy,\n\t\t\tH,\n\t\t\tV,\n\t\t\tl,\n\t\t\tt,\n\t\t\tw,\n\t\t\th,\n\t\t\tmoveToH,\n\t\t\tlineToH,\n\t\t\trectH,\n\t\t\tarcH,\n\t\t\tbezierCurveToH,\n\t\t)\n\t\t: cb(\n\t\t\tseries,\n\t\t\tdx,\n\t\t\tdy,\n\t\t\tsx,\n\t\t\tsy,\n\t\t\tV,\n\t\t\tH,\n\t\t\tt,\n\t\t\tl,\n\t\t\th,\n\t\t\tw,\n\t\t\tmoveToV,\n\t\t\tlineToV,\n\t\t\trectV,\n\t\t\tarcV,\n\t\t\tbezierCurveToV,\n\t\t)\n\t);\n}\n\nfunction bandFillClipDirs(self, seriesIdx) {\n\tlet fillDir = 0;\n\n\t// 2 bits, -1 | 1\n\tlet clipDirs = 0;\n\n\tlet bands = ifNull(self.bands, EMPTY_ARR);\n\n\tfor (let i = 0; i < bands.length; i++) {\n\t\tlet b = bands[i];\n\n\t\t// is a \"from\" band edge\n\t\tif (b.series[0] == seriesIdx)\n\t\t\tfillDir = b.dir;\n\t\t// is a \"to\" band edge\n\t\telse if (b.series[1] == seriesIdx) {\n\t\t\tif (b.dir == 1)\n\t\t\t\tclipDirs |= 1;\n\t\t\telse\n\t\t\t\tclipDirs |= 2;\n\t\t}\n\t}\n\n\treturn [\n\t\tfillDir,\n\t\t(\n\t\t\tclipDirs == 1 ? -1 : // neg only\n\t\t\tclipDirs == 2 ? 1 : // pos only\n\t\t\tclipDirs == 3 ? 2 : // both\n\t\t\t 0 // neither\n\t\t)\n\t];\n}\n\nfunction seriesFillTo(self, seriesIdx, dataMin, dataMax, bandFillDir) {\n\tlet mode = self.mode;\n\tlet series = self.series[seriesIdx];\n\tlet scaleKey = mode == 2 ? series.facets[1].scale : series.scale;\n\tlet scale = self.scales[scaleKey];\n\n\treturn (\n\t\tbandFillDir == -1 ? scale.min :\n\t\tbandFillDir == 1 ? scale.max :\n\t\tscale.distr == 3 ? (\n\t\t\tscale.dir == 1 ? scale.min :\n\t\t\tscale.max\n\t\t) : 0\n\t);\n}\n\n// creates inverted band clip path (from stroke path -> yMax || yMin)\n// clipDir is always inverse of fillDir\n// default clip dir is upwards (1), since default band fill is downwards/fillBelowTo (-1) (highIdx -> lowIdx)\nfunction clipBandLine(self, seriesIdx, idx0, idx1, strokePath, clipDir) {\n\treturn orient(self, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\tlet pxRound = series.pxRound;\n\n\t\tconst dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);\n\t\tconst lineTo = scaleX.ori == 0 ? lineToH : lineToV;\n\n\t\tlet frIdx, toIdx;\n\n\t\tif (dir == 1) {\n\t\t\tfrIdx = idx0;\n\t\t\ttoIdx = idx1;\n\t\t}\n\t\telse {\n\t\t\tfrIdx = idx1;\n\t\t\ttoIdx = idx0;\n\t\t}\n\n\t\t// path start\n\t\tlet x0 = pxRound(valToPosX(dataX[frIdx], scaleX, xDim, xOff));\n\t\tlet y0 = pxRound(valToPosY(dataY[frIdx], scaleY, yDim, yOff));\n\t\t// path end x\n\t\tlet x1 = pxRound(valToPosX(dataX[toIdx], scaleX, xDim, xOff));\n\t\t// upper or lower y limit\n\t\tlet yLimit = pxRound(valToPosY(clipDir == 1 ? scaleY.max : scaleY.min, scaleY, yDim, yOff));\n\n\t\tlet clip = new Path2D(strokePath);\n\n\t\tlineTo(clip, x1, yLimit);\n\t\tlineTo(clip, x0, yLimit);\n\t\tlineTo(clip, x0, y0);\n\n\t\treturn clip;\n\t});\n}\n\nfunction clipGaps(gaps, ori, plotLft, plotTop, plotWid, plotHgt) {\n\tlet clip = null;\n\n\t// create clip path (invert gaps and non-gaps)\n\tif (gaps.length > 0) {\n\t\tclip = new Path2D();\n\n\t\tconst rect = ori == 0 ? rectH : rectV;\n\n\t\tlet prevGapEnd = plotLft;\n\n\t\tfor (let i = 0; i < gaps.length; i++) {\n\t\t\tlet g = gaps[i];\n\n\t\t\tif (g[1] > g[0]) {\n\t\t\t\tlet w = g[0] - prevGapEnd;\n\n\t\t\t\tw > 0 && rect(clip, prevGapEnd, plotTop, w, plotTop + plotHgt);\n\n\t\t\t\tprevGapEnd = g[1];\n\t\t\t}\n\t\t}\n\n\t\tlet w = plotLft + plotWid - prevGapEnd;\n\n\t\t// hack to ensure we expand the clip enough to avoid cutting off strokes at edges\n\t\tlet maxStrokeWidth = 10;\n\n\t\tw > 0 && rect(clip, prevGapEnd, plotTop - maxStrokeWidth / 2, w, plotTop + plotHgt + maxStrokeWidth);\n\t}\n\n\treturn clip;\n}\n\nfunction addGap(gaps, fromX, toX) {\n\tlet prevGap = gaps[gaps.length - 1];\n\n\tif (prevGap && prevGap[0] == fromX)\t\t\t// TODO: gaps must be encoded at stroke widths?\n\t\tprevGap[1] = toX;\n\telse\n\t\tgaps.push([fromX, toX]);\n}\n\nfunction findGaps(xs, ys, idx0, idx1, dir, pixelForX, align) {\n\tlet gaps = [];\n\tlet len = xs.length;\n\n\tfor (let i = dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += dir) {\n\t\tlet yVal = ys[i];\n\n\t\tif (yVal === null) {\n\t\t\tlet fr = i, to = i;\n\n\t\t\tif (dir == 1) {\n\t\t\t\twhile (++i <= idx1 && ys[i] === null)\n\t\t\t\t\tto = i;\n\t\t\t}\n\t\t\telse {\n\t\t\t\twhile (--i >= idx0 && ys[i] === null)\n\t\t\t\t\tto = i;\n\t\t\t}\n\n\t\t\tlet frPx = pixelForX(xs[fr]);\n\t\t\tlet toPx = to == fr ? frPx : pixelForX(xs[to]);\n\n\t\t\t// if value adjacent to edge null is same pixel, then it's partially\n\t\t\t// filled and gap should start at next pixel\n\t\t\tlet fri2 = fr - dir;\n\t\t\tlet frPx2 = align <= 0 && fri2 >= 0 && fri2 < len ? pixelForX(xs[fri2]) : frPx;\n\t\t//\tif (frPx2 == frPx)\n\t\t//\t\tfrPx++;\n\t\t//\telse\n\t\t\t\tfrPx = frPx2;\n\n\t\t\tlet toi2 = to + dir;\n\t\t\tlet toPx2 = align >= 0 && toi2 >= 0 && toi2 < len ? pixelForX(xs[toi2]) : toPx;\n\t\t//\tif (toPx2 == toPx)\n\t\t//\t\ttoPx--;\n\t\t//\telse\n\t\t\t\ttoPx = toPx2;\n\n\t\t\tif (toPx >= frPx)\n\t\t\t\tgaps.push([frPx, toPx]); // addGap\n\t\t}\n\t}\n\n\treturn gaps;\n}\n\nfunction pxRoundGen(pxAlign) {\n\treturn pxAlign == 0 ? retArg0 : pxAlign == 1 ? round : v => incrRound(v, pxAlign);\n}\n\n/*\n// inefficient linear interpolation that does bi-directinal scans on each call\nexport function costlyLerp(i, idx0, idx1, _dirX, dataY) {\n\tlet prevNonNull = nonNullIdx(dataY, _dirX == 1 ? idx0 : idx1, i, -_dirX);\n\tlet nextNonNull = nonNullIdx(dataY, i, _dirX == 1 ? idx1 : idx0, _dirX);\n\n\tlet prevVal = dataY[prevNonNull];\n\tlet nextVal = dataY[nextNonNull];\n\n\treturn prevVal + (i - prevNonNull) / (nextNonNull - prevNonNull) * (nextVal - prevVal);\n}\n*/\n\nfunction rect(ori) {\n\tlet moveTo = ori == 0 ?\n\t\tmoveToH :\n\t\tmoveToV;\n\n\tlet arcTo = ori == 0 ?\n\t\t(p, x1, y1, x2, y2, r) => { p.arcTo(x1, y1, x2, y2, r); } :\n\t\t(p, y1, x1, y2, x2, r) => { p.arcTo(x1, y1, x2, y2, r); };\n\n\tlet rect = ori == 0 ?\n\t\t(p, x, y, w, h) => { p.rect(x, y, w, h); } :\n\t\t(p, y, x, h, w) => { p.rect(x, y, w, h); };\n\n\t// TODO (pending better browser support): https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/roundRect\n\treturn (p, x, y, w, h, endRad = 0, baseRad = 0) => {\n\t\tif (endRad == 0 && baseRad == 0)\n\t\t\trect(p, x, y, w, h);\n\t\telse {\n\t\t\tendRad = min(endRad, w / 2, h / 2);\n\t\t\tbaseRad = min(baseRad, w / 2, h / 2);\n\n\t\t\t// adapted from https://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-using-html-canvas/7838871#7838871\n\t\t\tmoveTo(p, x + endRad, y);\n\t\t\tarcTo(p, x + w, y, x + w, y + h, endRad);\n\t\t\tarcTo(p, x + w, y + h, x, y + h, baseRad);\n\t\t\tarcTo(p, x, y + h, x, y, baseRad);\n\t\t\tarcTo(p, x, y, x + w, y, endRad);\n\t\t\tp.closePath();\n\t\t}\n\t};\n}\n\n// orientation-inverting canvas functions\nconst moveToH = (p, x, y) => { p.moveTo(x, y); };\nconst moveToV = (p, y, x) => { p.moveTo(x, y); };\nconst lineToH = (p, x, y) => { p.lineTo(x, y); };\nconst lineToV = (p, y, x) => { p.lineTo(x, y); };\nconst rectH = rect(0);\nconst rectV = rect(1);\nconst arcH = (p, x, y, r, startAngle, endAngle) => { p.arc(x, y, r, startAngle, endAngle); };\nconst arcV = (p, y, x, r, startAngle, endAngle) => { p.arc(x, y, r, startAngle, endAngle); };\nconst bezierCurveToH = (p, bp1x, bp1y, bp2x, bp2y, p2x, p2y) => { p.bezierCurveTo(bp1x, bp1y, bp2x, bp2y, p2x, p2y); };\nconst bezierCurveToV = (p, bp1y, bp1x, bp2y, bp2x, p2y, p2x) => { p.bezierCurveTo(bp1x, bp1y, bp2x, bp2y, p2x, p2y); };\n\n// TODO: drawWrap(seriesIdx, drawPoints) (save, restore, translate, clip)\nfunction points(opts) {\n\treturn (u, seriesIdx, idx0, idx1, filtIdxs) => {\n\t//\tlog(\"drawPoints()\", arguments);\n\n\t\treturn orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\t\tlet { pxRound, points } = series;\n\n\t\t\tlet moveTo, arc;\n\n\t\t\tif (scaleX.ori == 0) {\n\t\t\t\tmoveTo = moveToH;\n\t\t\t\tarc = arcH;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmoveTo = moveToV;\n\t\t\t\tarc = arcV;\n\t\t\t}\n\n\t\t\tconst width = roundDec(points.width * pxRatio, 3);\n\n\t\t\tlet rad = (points.size - points.width) / 2 * pxRatio;\n\t\t\tlet dia = roundDec(rad * 2, 3);\n\n\t\t\tlet fill = new Path2D();\n\t\t\tlet clip = new Path2D();\n\n\t\t\tlet { left: lft, top: top, width: wid, height: hgt } = u.bbox;\n\n\t\t\trectH(clip,\n\t\t\t\tlft - dia,\n\t\t\t\ttop - dia,\n\t\t\t\twid + dia * 2,\n\t\t\t\thgt + dia * 2,\n\t\t\t);\n\n\t\t\tconst drawPoint = pi => {\n\t\t\t\tif (dataY[pi] != null) {\n\t\t\t\t\tlet x = pxRound(valToPosX(dataX[pi], scaleX, xDim, xOff));\n\t\t\t\t\tlet y = pxRound(valToPosY(dataY[pi], scaleY, yDim, yOff));\n\n\t\t\t\t\tmoveTo(fill, x + rad, y);\n\t\t\t\t\tarc(fill, x, y, rad, 0, PI * 2);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tif (filtIdxs)\n\t\t\t\tfiltIdxs.forEach(drawPoint);\n\t\t\telse {\n\t\t\t\tfor (let pi = idx0; pi <= idx1; pi++)\n\t\t\t\t\tdrawPoint(pi);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstroke: width > 0 ? fill : null,\n\t\t\t\tfill,\n\t\t\t\tclip,\n\t\t\t\tflags: BAND_CLIP_FILL | BAND_CLIP_STROKE,\n\t\t\t};\n\t\t});\n\t};\n}\n\nfunction _drawAcc(lineTo) {\n\treturn (stroke, accX, minY, maxY, inY, outY) => {\n\t\tif (minY != maxY) {\n\t\t\tif (inY != minY && outY != minY)\n\t\t\t\tlineTo(stroke, accX, minY);\n\t\t\tif (inY != maxY && outY != maxY)\n\t\t\t\tlineTo(stroke, accX, maxY);\n\n\t\t\tlineTo(stroke, accX, outY);\n\t\t}\n\t};\n}\n\nconst drawAccH = _drawAcc(lineToH);\nconst drawAccV = _drawAcc(lineToV);\n\nfunction linear(opts) {\n\tconst alignGaps = ifNull(opts?.alignGaps, 0);\n\n\treturn (u, seriesIdx, idx0, idx1) => {\n\t\treturn orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\t\t[idx0, idx1] = nonNullIdxs(dataY, idx0, idx1);\n\n\t\t\tlet pxRound = series.pxRound;\n\n\t\t\tlet pixelForX = val => pxRound(valToPosX(val, scaleX, xDim, xOff));\n\t\t\tlet pixelForY = val => pxRound(valToPosY(val, scaleY, yDim, yOff));\n\n\t\t\tlet lineTo, drawAcc;\n\n\t\t\tif (scaleX.ori == 0) {\n\t\t\t\tlineTo = lineToH;\n\t\t\t\tdrawAcc = drawAccH;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlineTo = lineToV;\n\t\t\t\tdrawAcc = drawAccV;\n\t\t\t}\n\n\t\t\tconst dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);\n\n\t\t\tconst _paths = {stroke: new Path2D(), fill: null, clip: null, band: null, gaps: null, flags: BAND_CLIP_FILL};\n\t\t\tconst stroke = _paths.stroke;\n\n\t\t\tlet hasGap = false;\n\n\t\t\t// decimate when number of points >= 4x available pixels\n\t\t\tconst decimate = idx1 - idx0 >= xDim * 4;\n\n\t\t\tif (decimate) {\n\t\t\t\tlet xForPixel = pos => u.posToVal(pos, scaleX.key, true);\n\n\t\t\t\tlet minY = null,\n\t\t\t\t\tmaxY = null,\n\t\t\t\t\tinY, outY, drawnAtX;\n\n\t\t\t\tlet accX = pixelForX(dataX[dir == 1 ? idx0 : idx1]);\n\n\t\t\t\tlet idx0px = pixelForX(dataX[idx0]);\n\t\t\t\tlet idx1px = pixelForX(dataX[idx1]);\n\n\t\t\t\t// tracks limit of current x bucket to avoid having to get x pixel for every x value\n\t\t\t\tlet nextAccXVal = xForPixel(dir == 1 ? idx0px + 1 : idx1px - 1);\n\n\t\t\t\tfor (let i = dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += dir) {\n\t\t\t\t\tlet xVal = dataX[i];\n\t\t\t\t\tlet reuseAccX = dir == 1 ? (xVal < nextAccXVal) : (xVal > nextAccXVal);\n\t\t\t\t\tlet x = reuseAccX ? accX : pixelForX(xVal);\n\n\t\t\t\t\tlet yVal = dataY[i];\n\n\t\t\t\t\tif (x == accX) {\n\t\t\t\t\t\tif (yVal != null) {\n\t\t\t\t\t\t\toutY = yVal;\n\n\t\t\t\t\t\t\tif (minY == null) {\n\t\t\t\t\t\t\t\tlineTo(stroke, x, pixelForY(outY));\n\t\t\t\t\t\t\t\tinY = minY = maxY = outY;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tif (outY < minY)\n\t\t\t\t\t\t\t\t\tminY = outY;\n\t\t\t\t\t\t\t\telse if (outY > maxY)\n\t\t\t\t\t\t\t\t\tmaxY = outY;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tif (yVal === null)\n\t\t\t\t\t\t\t\thasGap = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (minY != null)\n\t\t\t\t\t\t\tdrawAcc(stroke, accX, pixelForY(minY), pixelForY(maxY), pixelForY(inY), pixelForY(outY));\n\n\t\t\t\t\t\tif (yVal != null) {\n\t\t\t\t\t\t\toutY = yVal;\n\t\t\t\t\t\t\tlineTo(stroke, x, pixelForY(outY));\n\t\t\t\t\t\t\tminY = maxY = inY = outY;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tminY = maxY = null;\n\n\t\t\t\t\t\t\tif (yVal === null)\n\t\t\t\t\t\t\t\thasGap = true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taccX = x;\n\t\t\t\t\t\tnextAccXVal = xForPixel(accX + dir);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (minY != null && minY != maxY && drawnAtX != accX)\n\t\t\t\t\tdrawAcc(stroke, accX, pixelForY(minY), pixelForY(maxY), pixelForY(inY), pixelForY(outY));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfor (let i = dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += dir) {\n\t\t\t\t\tlet yVal = dataY[i];\n\n\t\t\t\t\tif (yVal === null)\n\t\t\t\t\t\thasGap = true;\n\t\t\t\t\telse if (yVal != null)\n\t\t\t\t\t\tlineTo(stroke, pixelForX(dataX[i]), pixelForY(yVal));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet [ bandFillDir, bandClipDir ] = bandFillClipDirs(u, seriesIdx);\n\n\t\t\tif (series.fill != null || bandFillDir != 0) {\n\t\t\t\tlet fill = _paths.fill = new Path2D(stroke);\n\n\t\t\t\tlet fillToVal = series.fillTo(u, seriesIdx, series.min, series.max, bandFillDir);\n\t\t\t\tlet fillToY = pixelForY(fillToVal);\n\n\t\t\t\tlet frX = pixelForX(dataX[idx0]);\n\t\t\t\tlet toX = pixelForX(dataX[idx1]);\n\n\t\t\t\tif (dir == -1)\n\t\t\t\t\t[toX, frX] = [frX, toX];\n\n\t\t\t\tlineTo(fill, toX, fillToY);\n\t\t\t\tlineTo(fill, frX, fillToY);\n\t\t\t}\n\n\t\t\tif (!series.spanGaps) { // skip in mode: 2?\n\t\t\t//\tconsole.time('gaps');\n\t\t\t\tlet gaps = [];\n\n\t\t\t\thasGap && gaps.push(...findGaps(dataX, dataY, idx0, idx1, dir, pixelForX, alignGaps));\n\n\t\t\t//\tconsole.timeEnd('gaps');\n\n\t\t\t//\tconsole.log('gaps', JSON.stringify(gaps));\n\n\t\t\t\t_paths.gaps = gaps = series.gaps(u, seriesIdx, idx0, idx1, gaps);\n\n\t\t\t\t_paths.clip = clipGaps(gaps, scaleX.ori, xOff, yOff, xDim, yDim);\n\t\t\t}\n\n\t\t\tif (bandClipDir != 0) {\n\t\t\t\t_paths.band = bandClipDir == 2 ? [\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke, -1),\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke, 1),\n\t\t\t\t] : clipBandLine(u, seriesIdx, idx0, idx1, stroke, bandClipDir);\n\t\t\t}\n\n\t\t\treturn _paths;\n\t\t});\n\t};\n}\n\n// BUG: align: -1 behaves like align: 1 when scale.dir: -1\nfunction stepped(opts) {\n\tconst align = ifNull(opts.align, 1);\n\t// whether to draw ascenders/descenders at null/gap bondaries\n\tconst ascDesc = ifNull(opts.ascDesc, false);\n\tconst alignGaps = ifNull(opts.alignGaps, 0);\n\tconst extend = ifNull(opts.extend, false);\n\n\treturn (u, seriesIdx, idx0, idx1) => {\n\t\treturn orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\t\t[idx0, idx1] = nonNullIdxs(dataY, idx0, idx1);\n\n\t\t\tlet pxRound = series.pxRound;\n\n\t\t\tlet { left, width } = u.bbox;\n\n\t\t\tlet pixelForX = val => pxRound(valToPosX(val, scaleX, xDim, xOff));\n\t\t\tlet pixelForY = val => pxRound(valToPosY(val, scaleY, yDim, yOff));\n\n\t\t\tlet lineTo = scaleX.ori == 0 ? lineToH : lineToV;\n\n\t\t\tconst _paths = {stroke: new Path2D(), fill: null, clip: null, band: null, gaps: null, flags: BAND_CLIP_FILL};\n\t\t\tconst stroke = _paths.stroke;\n\n\t\t\tconst dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);\n\n\t\t\tlet prevYPos = pixelForY(dataY[dir == 1 ? idx0 : idx1]);\n\t\t\tlet firstXPos = pixelForX(dataX[dir == 1 ? idx0 : idx1]);\n\t\t\tlet prevXPos = firstXPos;\n\n\t\t\tlet firstXPosExt = firstXPos;\n\n\t\t\tif (extend && align == -1) {\n\t\t\t\tfirstXPosExt = left;\n\t\t\t\tlineTo(stroke, firstXPosExt, prevYPos);\n\t\t\t}\n\n\t\t\tlineTo(stroke, firstXPos, prevYPos);\n\n\t\t\tfor (let i = dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += dir) {\n\t\t\t\tlet yVal1 = dataY[i];\n\n\t\t\t\tif (yVal1 == null)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tlet x1 = pixelForX(dataX[i]);\n\t\t\t\tlet y1 = pixelForY(yVal1);\n\n\t\t\t\tif (align == 1)\n\t\t\t\t\tlineTo(stroke, x1, prevYPos);\n\t\t\t\telse\n\t\t\t\t\tlineTo(stroke, prevXPos, y1);\n\n\t\t\t\tlineTo(stroke, x1, y1);\n\n\t\t\t\tprevYPos = y1;\n\t\t\t\tprevXPos = x1;\n\t\t\t}\n\n\t\t\tlet prevXPosExt = prevXPos;\n\n\t\t\tif (extend && align == 1) {\n\t\t\t\tprevXPosExt = left + width;\n\t\t\t\tlineTo(stroke, prevXPosExt, prevYPos);\n\t\t\t}\n\n\t\t\tlet [ bandFillDir, bandClipDir ] = bandFillClipDirs(u, seriesIdx);\n\n\t\t\tif (series.fill != null || bandFillDir != 0) {\n\t\t\t\tlet fill = _paths.fill = new Path2D(stroke);\n\n\t\t\t\tlet fillTo = series.fillTo(u, seriesIdx, series.min, series.max, bandFillDir);\n\t\t\t\tlet fillToY = pixelForY(fillTo);\n\n\t\t\t\tlineTo(fill, prevXPosExt, fillToY);\n\t\t\t\tlineTo(fill, firstXPosExt, fillToY);\n\t\t\t}\n\n\t\t\tif (!series.spanGaps) {\n\t\t\t//\tconsole.time('gaps');\n\t\t\t\tlet gaps = [];\n\n\t\t\t\tgaps.push(...findGaps(dataX, dataY, idx0, idx1, dir, pixelForX, alignGaps));\n\n\t\t\t//\tconsole.timeEnd('gaps');\n\n\t\t\t//\tconsole.log('gaps', JSON.stringify(gaps));\n\n\t\t\t\t// expand/contract clips for ascenders/descenders\n\t\t\t\tlet halfStroke = (series.width * pxRatio) / 2;\n\t\t\t\tlet startsOffset = (ascDesc || align == 1) ? halfStroke : -halfStroke;\n\t\t\t\tlet endsOffset = (ascDesc || align == -1) ? -halfStroke : halfStroke;\n\n\t\t\t\tgaps.forEach(g => {\n\t\t\t\t\tg[0] += startsOffset;\n\t\t\t\t\tg[1] += endsOffset;\n\t\t\t\t});\n\n\t\t\t\t_paths.gaps = gaps = series.gaps(u, seriesIdx, idx0, idx1, gaps);\n\n\t\t\t\t_paths.clip = clipGaps(gaps, scaleX.ori, xOff, yOff, xDim, yDim);\n\t\t\t}\n\n\t\t\tif (bandClipDir != 0) {\n\t\t\t\t_paths.band = bandClipDir == 2 ? [\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke, -1),\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke, 1),\n\t\t\t\t] : clipBandLine(u, seriesIdx, idx0, idx1, stroke, bandClipDir);\n\t\t\t}\n\n\t\t\treturn _paths;\n\t\t});\n\t};\n}\n\nfunction findColWidth(dataX, dataY, valToPosX, scaleX, xDim, xOff, colWid = inf) {\n\tif (dataX.length > 1) {\n\t\t// prior index with non-undefined y data\n\t\tlet prevIdx = null;\n\n\t\t// scan full dataset for smallest adjacent delta\n\t\t// will not work properly for non-linear x scales, since does not do expensive valToPosX calcs till end\n\t\tfor (let i = 0, minDelta = Infinity; i < dataX.length; i++) {\n\t\t\tif (dataY[i] !== undefined) {\n\t\t\t\tif (prevIdx != null) {\n\t\t\t\t\tlet delta = abs(dataX[i] - dataX[prevIdx]);\n\n\t\t\t\t\tif (delta < minDelta) {\n\t\t\t\t\t\tminDelta = delta;\n\t\t\t\t\t\tcolWid = abs(valToPosX(dataX[i], scaleX, xDim, xOff) - valToPosX(dataX[prevIdx], scaleX, xDim, xOff));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tprevIdx = i;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn colWid;\n}\n\nfunction bars(opts) {\n\topts = opts || EMPTY_OBJ;\n\tconst size = ifNull(opts.size, [0.6, inf, 1]);\n\tconst align = opts.align || 0;\n\tconst _extraGap = (opts.gap || 0);\n\n\tlet ro = opts.radius;\n\n\tro =\n\t\t// [valueRadius, baselineRadius]\n\t\tro == null ? [0, 0] :\n\t\ttypeof ro == 'number' ? [ro, 0] : ro;\n\n\tconst radiusFn = fnOrSelf(ro);\n\n\tconst gapFactor = 1 - size[0];\n\tconst _maxWidth = ifNull(size[1], inf);\n\tconst _minWidth = ifNull(size[2], 1);\n\n\tconst disp = ifNull(opts.disp, EMPTY_OBJ);\n\tconst _each = ifNull(opts.each, _ => {});\n\n\tconst { fill: dispFills, stroke: dispStrokes } = disp;\n\n\treturn (u, seriesIdx, idx0, idx1) => {\n\t\treturn orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\t\tlet pxRound = series.pxRound;\n\t\t\tlet _align = align;\n\n\t\t\tlet extraGap = _extraGap * pxRatio;\n\t\t\tlet maxWidth = _maxWidth * pxRatio;\n\t\t\tlet minWidth = _minWidth * pxRatio;\n\n\t\t\tlet valRadius, baseRadius;\n\n\t\t\tif (scaleX.ori == 0)\n\t\t\t\t[valRadius, baseRadius] = radiusFn(u, seriesIdx);\n\t\t\telse\n\t\t\t\t[baseRadius, valRadius] = radiusFn(u, seriesIdx);\n\n\t\t\tconst _dirX = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);\n\t\t//\tconst _dirY = scaleY.dir * (scaleY.ori == 1 ? 1 : -1);\n\n\t\t\tlet rect = scaleX.ori == 0 ? rectH : rectV;\n\n\t\t\tlet each = scaleX.ori == 0 ? _each : (u, seriesIdx, i, top, lft, hgt, wid) => {\n\t\t\t\t_each(u, seriesIdx, i, lft, top, wid, hgt);\n\t\t\t};\n\n\t\t\t// band where this series is the \"from\" edge\n\t\t\tlet band = ifNull(u.bands, EMPTY_ARR).find(b => b.series[0] == seriesIdx);\n\n\t\t\tlet fillDir = band != null ? band.dir : 0;\n\t\t\tlet fillTo = series.fillTo(u, seriesIdx, series.min, series.max, fillDir);\n\t\t\tlet fillToY = pxRound(valToPosY(fillTo, scaleY, yDim, yOff));\n\n\t\t\t// barWid is to center of stroke\n\t\t\tlet xShift, barWid, fullGap, colWid = xDim;\n\n\t\t\tlet strokeWidth = pxRound(series.width * pxRatio);\n\n\t\t\tlet multiPath = false;\n\n\t\t\tlet fillColors = null;\n\t\t\tlet fillPaths = null;\n\t\t\tlet strokeColors = null;\n\t\t\tlet strokePaths = null;\n\n\t\t\tif (dispFills != null && (strokeWidth == 0 || dispStrokes != null)) {\n\t\t\t\tmultiPath = true;\n\n\t\t\t\tfillColors = dispFills.values(u, seriesIdx, idx0, idx1);\n\t\t\t\tfillPaths = new Map();\n\t\t\t\t(new Set(fillColors)).forEach(color => {\n\t\t\t\t\tif (color != null)\n\t\t\t\t\t\tfillPaths.set(color, new Path2D());\n\t\t\t\t});\n\n\t\t\t\tif (strokeWidth > 0) {\n\t\t\t\t\tstrokeColors = dispStrokes.values(u, seriesIdx, idx0, idx1);\n\t\t\t\t\tstrokePaths = new Map();\n\t\t\t\t\t(new Set(strokeColors)).forEach(color => {\n\t\t\t\t\t\tif (color != null)\n\t\t\t\t\t\t\tstrokePaths.set(color, new Path2D());\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet { x0, size } = disp;\n\n\t\t\tif (x0 != null && size != null) {\n\t\t\t\t_align = 1;\n\t\t\t\tdataX = x0.values(u, seriesIdx, idx0, idx1);\n\n\t\t\t\tif (x0.unit == 2)\n\t\t\t\t\tdataX = dataX.map(pct => u.posToVal(xOff + pct * xDim, scaleX.key, true));\n\n\t\t\t\t// assumes uniform sizes, for now\n\t\t\t\tlet sizes = size.values(u, seriesIdx, idx0, idx1);\n\n\t\t\t\tif (size.unit == 2)\n\t\t\t\t\tbarWid = sizes[0] * xDim;\n\t\t\t\telse\n\t\t\t\t\tbarWid = valToPosX(sizes[0], scaleX, xDim, xOff) - valToPosX(0, scaleX, xDim, xOff); // assumes linear scale (delta from 0)\n\n\t\t\t\tcolWid = findColWidth(dataX, dataY, valToPosX, scaleX, xDim, xOff, colWid);\n\n\t\t\t\tlet gapWid = colWid - barWid;\n\t\t\t\tfullGap = gapWid + extraGap;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcolWid = findColWidth(dataX, dataY, valToPosX, scaleX, xDim, xOff, colWid);\n\n\t\t\t\tlet gapWid = colWid * gapFactor;\n\n\t\t\t\tfullGap = gapWid + extraGap;\n\t\t\t\tbarWid = colWid - fullGap;\n\t\t\t}\n\n\t\t\tif (fullGap < 1)\n\t\t\t\tfullGap = 0;\n\n\t\t\tif (strokeWidth >= barWid / 2)\n\t\t\t\tstrokeWidth = 0;\n\n\t\t\t// for small gaps, disable pixel snapping since gap inconsistencies become noticible and annoying\n\t\t\tif (fullGap < 5)\n\t\t\t\tpxRound = retArg0;\n\n\t\t\tlet insetStroke = fullGap > 0;\n\n\t\t\tlet rawBarWid = colWid - fullGap - (insetStroke ? strokeWidth : 0);\n\n\t\t\tbarWid = pxRound(clamp(rawBarWid, minWidth, maxWidth));\n\n\t\t\txShift = (_align == 0 ? barWid / 2 : _align == _dirX ? 0 : barWid) - _align * _dirX * ((_align == 0 ? extraGap / 2 : 0) + (insetStroke ? strokeWidth / 2 : 0));\n\n\n\t\t\tconst _paths = {stroke: null, fill: null, clip: null, band: null, gaps: null, flags: 0}; // disp, geom\n\n\t\t\tconst stroke = multiPath ? null : new Path2D();\n\n\t\t\tlet dataY0 = null;\n\n\t\t\tif (band != null)\n\t\t\t\tdataY0 = u.data[band.series[1]];\n\t\t\telse {\n\t\t\t\tlet { y0, y1 } = disp;\n\n\t\t\t\tif (y0 != null && y1 != null) {\n\t\t\t\t\tdataY = y1.values(u, seriesIdx, idx0, idx1);\n\t\t\t\t\tdataY0 = y0.values(u, seriesIdx, idx0, idx1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet radVal = valRadius * barWid;\n\t\t\tlet radBase = baseRadius * barWid;\n\n\t\t\tfor (let i = _dirX == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += _dirX) {\n\t\t\t\tlet yVal = dataY[i];\n\n\t\t\t\tif (yVal == null)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (dataY0 != null) {\n\t\t\t\t\tlet yVal0 = dataY0[i] ?? 0;\n\n\t\t\t\t\tif (yVal - yVal0 == 0)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tfillToY = valToPosY(yVal0, scaleY, yDim, yOff);\n\t\t\t\t}\n\n\t\t\t\tlet xVal = scaleX.distr != 2 || disp != null ? dataX[i] : i;\n\n\t\t\t\t// TODO: all xPos can be pre-computed once for all series in aligned set\n\t\t\t\tlet xPos = valToPosX(xVal, scaleX, xDim, xOff);\n\t\t\t\tlet yPos = valToPosY(ifNull(yVal, fillTo), scaleY, yDim, yOff);\n\n\t\t\t\tlet lft = pxRound(xPos - xShift);\n\t\t\t\tlet btm = pxRound(max(yPos, fillToY));\n\t\t\t\tlet top = pxRound(min(yPos, fillToY));\n\t\t\t\t// this includes the stroke\n\t\t\t\tlet barHgt = btm - top;\n\n\t\t\t\tif (yVal != null) { // && yVal != fillTo (0 height bar)\n\t\t\t\t\tlet rv = yVal < 0 ? radBase : radVal;\n\t\t\t\t\tlet rb = yVal < 0 ? radVal : radBase;\n\n\t\t\t\t\tif (multiPath) {\n\t\t\t\t\t\tif (strokeWidth > 0 && strokeColors[i] != null)\n\t\t\t\t\t\t\trect(strokePaths.get(strokeColors[i]), lft, top + floor(strokeWidth / 2), barWid, max(0, barHgt - strokeWidth), rv, rb);\n\n\t\t\t\t\t\tif (fillColors[i] != null)\n\t\t\t\t\t\t\trect(fillPaths.get(fillColors[i]), lft, top + floor(strokeWidth / 2), barWid, max(0, barHgt - strokeWidth), rv, rb);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\trect(stroke, lft, top + floor(strokeWidth / 2), barWid, max(0, barHgt - strokeWidth), rv, rb);\n\n\t\t\t\t\teach(u, seriesIdx, i,\n\t\t\t\t\t\tlft - strokeWidth / 2,\n\t\t\t\t\t\ttop,\n\t\t\t\t\t\tbarWid + strokeWidth,\n\t\t\t\t\t\tbarHgt,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (strokeWidth > 0)\n\t\t\t\t_paths.stroke = multiPath ? strokePaths : stroke;\n\t\t\telse if (!multiPath) {\n\t\t\t\t_paths._fill = series.width == 0 ? series._fill : series._stroke ?? series._fill;\n\t\t\t\t_paths.width = 0;\n\t\t\t}\n\n\t\t\t_paths.fill = multiPath ? fillPaths : stroke;\n\n\t\t\treturn _paths;\n\t\t});\n\t};\n}\n\nfunction splineInterp(interp, opts) {\n\tconst alignGaps = ifNull(opts?.alignGaps, 0);\n\n\treturn (u, seriesIdx, idx0, idx1) => {\n\t\treturn orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {\n\t\t\t[idx0, idx1] = nonNullIdxs(dataY, idx0, idx1);\n\n\t\t\tlet pxRound = series.pxRound;\n\n\t\t\tlet pixelForX = val => pxRound(valToPosX(val, scaleX, xDim, xOff));\n\t\t\tlet pixelForY = val => pxRound(valToPosY(val, scaleY, yDim, yOff));\n\n\t\t\tlet moveTo, bezierCurveTo, lineTo;\n\n\t\t\tif (scaleX.ori == 0) {\n\t\t\t\tmoveTo = moveToH;\n\t\t\t\tlineTo = lineToH;\n\t\t\t\tbezierCurveTo = bezierCurveToH;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmoveTo = moveToV;\n\t\t\t\tlineTo = lineToV;\n\t\t\t\tbezierCurveTo = bezierCurveToV;\n\t\t\t}\n\n\t\t\tconst dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);\n\n\t\t\tlet firstXPos = pixelForX(dataX[dir == 1 ? idx0 : idx1]);\n\t\t\tlet prevXPos = firstXPos;\n\n\t\t\tlet xCoords = [];\n\t\t\tlet yCoords = [];\n\n\t\t\tfor (let i = dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += dir) {\n\t\t\t\tlet yVal = dataY[i];\n\n\t\t\t\tif (yVal != null) {\n\t\t\t\t\tlet xVal = dataX[i];\n\t\t\t\t\tlet xPos = pixelForX(xVal);\n\n\t\t\t\t\txCoords.push(prevXPos = xPos);\n\t\t\t\t\tyCoords.push(pixelForY(dataY[i]));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst _paths = {stroke: interp(xCoords, yCoords, moveTo, lineTo, bezierCurveTo, pxRound), fill: null, clip: null, band: null, gaps: null, flags: BAND_CLIP_FILL};\n\t\t\tconst stroke = _paths.stroke;\n\n\t\t\tlet [ bandFillDir, bandClipDir ] = bandFillClipDirs(u, seriesIdx);\n\n\t\t\tif (series.fill != null || bandFillDir != 0) {\n\t\t\t\tlet fill = _paths.fill = new Path2D(stroke);\n\n\t\t\t\tlet fillTo = series.fillTo(u, seriesIdx, series.min, series.max, bandFillDir);\n\t\t\t\tlet fillToY = pixelForY(fillTo);\n\n\t\t\t\tlineTo(fill, prevXPos, fillToY);\n\t\t\t\tlineTo(fill, firstXPos, fillToY);\n\t\t\t}\n\n\t\t\tif (!series.spanGaps) {\n\t\t\t//\tconsole.time('gaps');\n\t\t\t\tlet gaps = [];\n\n\t\t\t\tgaps.push(...findGaps(dataX, dataY, idx0, idx1, dir, pixelForX, alignGaps));\n\n\t\t\t//\tconsole.timeEnd('gaps');\n\n\t\t\t//\tconsole.log('gaps', JSON.stringify(gaps));\n\n\t\t\t\t_paths.gaps = gaps = series.gaps(u, seriesIdx, idx0, idx1, gaps);\n\n\t\t\t\t_paths.clip = clipGaps(gaps, scaleX.ori, xOff, yOff, xDim, yDim);\n\t\t\t}\n\n\t\t\tif (bandClipDir != 0) {\n\t\t\t\t_paths.band = bandClipDir == 2 ? [\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke, -1),\n\t\t\t\t\tclipBandLine(u, seriesIdx, idx0, idx1, stroke, 1),\n\t\t\t\t] : clipBandLine(u, seriesIdx, idx0, idx1, stroke, bandClipDir);\n\t\t\t}\n\n\t\t\treturn _paths;\n\n\t\t\t// if FEAT_PATHS: false in rollup.config.js\n\t\t\t//\tu.ctx.save();\n\t\t\t//\tu.ctx.beginPath();\n\t\t\t//\tu.ctx.rect(u.bbox.left, u.bbox.top, u.bbox.width, u.bbox.height);\n\t\t\t//\tu.ctx.clip();\n\t\t\t//\tu.ctx.strokeStyle = u.series[sidx].stroke;\n\t\t\t//\tu.ctx.stroke(stroke);\n\t\t\t//\tu.ctx.fillStyle = u.series[sidx].fill;\n\t\t\t//\tu.ctx.fill(fill);\n\t\t\t//\tu.ctx.restore();\n\t\t\t//\treturn null;\n\t\t});\n\t};\n}\n\nfunction monotoneCubic(opts) {\n\treturn splineInterp(_monotoneCubic, opts);\n}\n\n// Monotone Cubic Spline interpolation, adapted from the Chartist.js implementation:\n// https://github.com/gionkunz/chartist-js/blob/e7e78201bffe9609915e5e53cfafa29a5d6c49f9/src/scripts/interpolation.js#L240-L369\nfunction _monotoneCubic(xs, ys, moveTo, lineTo, bezierCurveTo, pxRound) {\n\tconst n = xs.length;\n\n\tif (n < 2)\n\t\treturn null;\n\n\tconst path = new Path2D();\n\n\tmoveTo(path, xs[0], ys[0]);\n\n\tif (n == 2)\n\t\tlineTo(path, xs[1], ys[1]);\n\telse {\n\t\tlet ms = Array(n),\n\t\t\tds = Array(n - 1),\n\t\t\tdys = Array(n - 1),\n\t\t\tdxs = Array(n - 1);\n\n\t\t// calc deltas and derivative\n\t\tfor (let i = 0; i < n - 1; i++) {\n\t\t\tdys[i] = ys[i + 1] - ys[i];\n\t\t\tdxs[i] = xs[i + 1] - xs[i];\n\t\t\tds[i] = dys[i] / dxs[i];\n\t\t}\n\n\t\t// determine desired slope (m) at each point using Fritsch-Carlson method\n\t\t// http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation\n\t\tms[0] = ds[0];\n\n\t\tfor (let i = 1; i < n - 1; i++) {\n\t\t\tif (ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0))\n\t\t\t\tms[i] = 0;\n\t\t\telse {\n\t\t\t\tms[i] = 3 * (dxs[i - 1] + dxs[i]) / (\n\t\t\t\t\t(2 * dxs[i] + dxs[i - 1]) / ds[i - 1] +\n\t\t\t\t\t(dxs[i] + 2 * dxs[i - 1]) / ds[i]\n\t\t\t\t);\n\n\t\t\t\tif (!isFinite(ms[i]))\n\t\t\t\t\tms[i] = 0;\n\t\t\t}\n\t\t}\n\n\t\tms[n - 1] = ds[n - 2];\n\n\t\tfor (let i = 0; i < n - 1; i++) {\n\t\t\tbezierCurveTo(\n\t\t\t\tpath,\n\t\t\t\txs[i] + dxs[i] / 3,\n\t\t\t\tys[i] + ms[i] * dxs[i] / 3,\n\t\t\t\txs[i + 1] - dxs[i] / 3,\n\t\t\t\tys[i + 1] - ms[i + 1] * dxs[i] / 3,\n\t\t\t\txs[i + 1],\n\t\t\t\tys[i + 1],\n\t\t\t);\n\t\t}\n\t}\n\n\treturn path;\n}\n\nconst cursorPlots = new Set();\n\nfunction invalidateRects() {\n\tfor (let u of cursorPlots)\n\t\tu.syncRect(true);\n}\n\nif (domEnv) {\n\ton(resize, win, invalidateRects);\n\ton(scroll, win, invalidateRects, true);\n\ton(dppxchange, win, () => { uPlot.pxRatio = pxRatio; });\n}\n\nconst linearPath = linear() ;\nconst pointsPath = points() ;\n\nfunction setDefaults(d, xo, yo, initY) {\n\tlet d2 = initY ? [d[0], d[1]].concat(d.slice(2)) : [d[0]].concat(d.slice(1));\n\treturn d2.map((o, i) => setDefault(o, i, xo, yo));\n}\n\nfunction setDefaults2(d, xyo) {\n\treturn d.map((o, i) => i == 0 ? {} : assign({}, xyo, o)); // todo: assign() will not merge facet arrays\n}\n\nfunction setDefault(o, i, xo, yo) {\n\treturn assign({}, (i == 0 ? xo : yo), o);\n}\n\nfunction snapNumX(self, dataMin, dataMax) {\n\treturn dataMin == null ? nullNullTuple : [dataMin, dataMax];\n}\n\nconst snapTimeX = snapNumX;\n\n// this ensures that non-temporal/numeric y-axes get multiple-snapped padding added above/below\n// TODO: also account for incrs when snapping to ensure top of axis gets a tick & value\nfunction snapNumY(self, dataMin, dataMax) {\n\treturn dataMin == null ? nullNullTuple : rangeNum(dataMin, dataMax, rangePad, true);\n}\n\nfunction snapLogY(self, dataMin, dataMax, scale) {\n\treturn dataMin == null ? nullNullTuple : rangeLog(dataMin, dataMax, self.scales[scale].log, false);\n}\n\nconst snapLogX = snapLogY;\n\nfunction snapAsinhY(self, dataMin, dataMax, scale) {\n\treturn dataMin == null ? nullNullTuple : rangeAsinh(dataMin, dataMax, self.scales[scale].log, false);\n}\n\nconst snapAsinhX = snapAsinhY;\n\n// dim is logical (getClientBoundingRect) pixels, not canvas pixels\nfunction findIncr(minVal, maxVal, incrs, dim, minSpace) {\n\tlet intDigits = max(numIntDigits(minVal), numIntDigits(maxVal));\n\n\tlet delta = maxVal - minVal;\n\n\tlet incrIdx = closestIdx((minSpace / dim) * delta, incrs);\n\n\tdo {\n\t\tlet foundIncr = incrs[incrIdx];\n\t\tlet foundSpace = dim * foundIncr / delta;\n\n\t\tif (foundSpace >= minSpace && intDigits + (foundIncr < 5 ? fixedDec.get(foundIncr) : 0) <= 17)\n\t\t\treturn [foundIncr, foundSpace];\n\t} while (++incrIdx < incrs.length);\n\n\treturn [0, 0];\n}\n\nfunction pxRatioFont(font) {\n\tlet fontSize, fontSizeCss;\n\tfont = font.replace(/(\\d+)px/, (m, p1) => (fontSize = round((fontSizeCss = +p1) * pxRatio)) + 'px');\n\treturn [font, fontSize, fontSizeCss];\n}\n\nfunction syncFontSize(axis) {\n\tif (axis.show) {\n\t\t[axis.font, axis.labelFont].forEach(f => {\n\t\t\tlet size = roundDec(f[2] * pxRatio, 1);\n\t\t\tf[0] = f[0].replace(/[0-9.]+px/, size + 'px');\n\t\t\tf[1] = size;\n\t\t});\n\t}\n}\n\nfunction uPlot(opts, data, then) {\n\tconst self = {\n\t\tmode: ifNull(opts.mode, 1),\n\t};\n\n\tconst mode = self.mode;\n\n\tfunction getHPos(val, scale, dim, off) {\n\t\tlet pct = scale.valToPct(val);\n\t\treturn off + dim * (scale.dir == -1 ? (1 - pct) : pct);\n\t}\n\n\tfunction getVPos(val, scale, dim, off) {\n\t\tlet pct = scale.valToPct(val);\n\t\treturn off + dim * (scale.dir == -1 ? pct : (1 - pct));\n\t}\n\n\tfunction getPos(val, scale, dim, off) {\n\t\treturn scale.ori == 0 ? getHPos(val, scale, dim, off) : getVPos(val, scale, dim, off);\n\t}\n\n\tself.valToPosH = getHPos;\n\tself.valToPosV = getVPos;\n\n\tlet ready = false;\n\tself.status = 0;\n\n\tconst root = self.root = placeDiv(UPLOT);\n\n\tif (opts.id != null)\n\t\troot.id = opts.id;\n\n\taddClass(root, opts.class);\n\n\tif (opts.title) {\n\t\tlet title = placeDiv(TITLE, root);\n\t\ttitle.textContent = opts.title;\n\t}\n\n\tconst can = placeTag(\"canvas\");\n\tconst ctx = self.ctx = can.getContext(\"2d\");\n\n\tconst wrap = placeDiv(WRAP, root);\n\n\ton(\"click\", wrap, e => {\n\t\tif (e.target === over) {\n\t\t\tlet didDrag = mouseLeft1 != mouseLeft0 || mouseTop1 != mouseTop0;\n\t\t\tdidDrag && drag.click(self, e);\n\t\t}\n\t}, true);\n\n\tconst under = self.under = placeDiv(UNDER, wrap);\n\twrap.appendChild(can);\n\tconst over = self.over = placeDiv(OVER, wrap);\n\n\topts = copy(opts);\n\n\tconst pxAlign = +ifNull(opts.pxAlign, 1);\n\n\tconst pxRound = pxRoundGen(pxAlign);\n\n\t(opts.plugins || []).forEach(p => {\n\t\tif (p.opts)\n\t\t\topts = p.opts(self, opts) || opts;\n\t});\n\n\tconst ms = opts.ms || 1e-3;\n\n\tconst series = self.series = mode == 1 ?\n\t\tsetDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false) :\n\t\tsetDefaults2(opts.series || [null], xySeriesOpts);\n\tconst axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);\n\tconst scales = self.scales = {};\n\tconst bands = self.bands = opts.bands || [];\n\n\tbands.forEach(b => {\n\t\tb.fill = fnOrSelf(b.fill || null);\n\t\tb.dir = ifNull(b.dir, -1);\n\t});\n\n\tconst xScaleKey = mode == 2 ? series[1].facets[0].scale : series[0].scale;\n\n\tconst drawOrderMap = {\n\t\taxes: drawAxesGrid,\n\t\tseries: drawSeries,\n\t};\n\n\tconst drawOrder = (opts.drawOrder || [\"axes\", \"series\"]).map(key => drawOrderMap[key]);\n\n\tfunction initValToPct(sc) {\n\t\tconst getVal = (\n\t\t\tsc.distr == 3 ? val => log10(val > 0 ? val : sc.clamp(self, val, sc.min, sc.max, sc.key)) :\n\t\t\tsc.distr == 4 ? val => asinh(val, sc.asinh) :\n\t\t\tsc.distr == 100 ? val => sc.fwd(val) :\n\t\t\tval => val\n\t\t);\n\n\t\treturn val => {\n\t\t\tlet _val = getVal(val);\n\t\t\tlet { _min, _max } = sc;\n\t\t\tlet delta = _max - _min;\n\t\t\treturn (_val - _min) / delta;\n\t\t};\n\t}\n\n\tfunction initScale(scaleKey) {\n\t\tlet sc = scales[scaleKey];\n\n\t\tif (sc == null) {\n\t\t\tlet scaleOpts = (opts.scales || EMPTY_OBJ)[scaleKey] || EMPTY_OBJ;\n\n\t\t\tif (scaleOpts.from != null) {\n\t\t\t\t// ensure parent is initialized\n\t\t\t\tinitScale(scaleOpts.from);\n\t\t\t\t// dependent scales inherit\n\t\t\t\tlet sc = assign({}, scales[scaleOpts.from], scaleOpts, {key: scaleKey});\n\t\t\t\tsc.valToPct = initValToPct(sc);\n\t\t\t\tscales[scaleKey] = sc;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsc = scales[scaleKey] = assign({}, (scaleKey == xScaleKey ? xScaleOpts : yScaleOpts), scaleOpts);\n\n\t\t\t\tsc.key = scaleKey;\n\n\t\t\t\tlet isTime = sc.time;\n\n\t\t\t\tlet rn = sc.range;\n\n\t\t\t\tlet rangeIsArr = isArr(rn);\n\n\t\t\t\tif (scaleKey != xScaleKey || (mode == 2 && !isTime)) {\n\t\t\t\t\t// if range array has null limits, it should be auto\n\t\t\t\t\tif (rangeIsArr && (rn[0] == null || rn[1] == null)) {\n\t\t\t\t\t\trn = {\n\t\t\t\t\t\t\tmin: rn[0] == null ? autoRangePart : {\n\t\t\t\t\t\t\t\tmode: 1,\n\t\t\t\t\t\t\t\thard: rn[0],\n\t\t\t\t\t\t\t\tsoft: rn[0],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmax: rn[1] == null ? autoRangePart : {\n\t\t\t\t\t\t\t\tmode: 1,\n\t\t\t\t\t\t\t\thard: rn[1],\n\t\t\t\t\t\t\t\tsoft: rn[1],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t\trangeIsArr = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!rangeIsArr && isObj(rn)) {\n\t\t\t\t\t\tlet cfg = rn;\n\t\t\t\t\t\t// this is similar to snapNumY\n\t\t\t\t\t\trn = (self, dataMin, dataMax) => dataMin == null ? nullNullTuple : rangeNum(dataMin, dataMax, cfg);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsc.range = fnOrSelf(rn || (isTime ? snapTimeX : scaleKey == xScaleKey ?\n\t\t\t\t\t(sc.distr == 3 ? snapLogX : sc.distr == 4 ? snapAsinhX : snapNumX) :\n\t\t\t\t\t(sc.distr == 3 ? snapLogY : sc.distr == 4 ? snapAsinhY : snapNumY)\n\t\t\t\t));\n\n\t\t\t\tsc.auto = fnOrSelf(rangeIsArr ? false : sc.auto);\n\n\t\t\t\tsc.clamp = fnOrSelf(sc.clamp || clampScale);\n\n\t\t\t\t// caches for expensive ops like asinh() & log()\n\t\t\t\tsc._min = sc._max = null;\n\n\t\t\t\tsc.valToPct = initValToPct(sc);\n\t\t\t}\n\t\t}\n\t}\n\n\tinitScale(\"x\");\n\tinitScale(\"y\");\n\n\t// TODO: init scales from facets in mode: 2\n\tif (mode == 1) {\n\t\tseries.forEach(s => {\n\t\t\tinitScale(s.scale);\n\t\t});\n\t}\n\n\taxes.forEach(a => {\n\t\tinitScale(a.scale);\n\t});\n\n\tfor (let k in opts.scales)\n\t\tinitScale(k);\n\n\tconst scaleX = scales[xScaleKey];\n\n\tconst xScaleDistr = scaleX.distr;\n\n\tlet valToPosX, valToPosY;\n\n\tif (scaleX.ori == 0) {\n\t\taddClass(root, ORI_HZ);\n\t\tvalToPosX = getHPos;\n\t\tvalToPosY = getVPos;\n\t\t/*\n\t\tupdOriDims = () => {\n\t\t\txDimCan = plotWid;\n\t\t\txOffCan = plotLft;\n\t\t\tyDimCan = plotHgt;\n\t\t\tyOffCan = plotTop;\n\n\t\t\txDimCss = plotWidCss;\n\t\t\txOffCss = plotLftCss;\n\t\t\tyDimCss = plotHgtCss;\n\t\t\tyOffCss = plotTopCss;\n\t\t};\n\t\t*/\n\t}\n\telse {\n\t\taddClass(root, ORI_VT);\n\t\tvalToPosX = getVPos;\n\t\tvalToPosY = getHPos;\n\t\t/*\n\t\tupdOriDims = () => {\n\t\t\txDimCan = plotHgt;\n\t\t\txOffCan = plotTop;\n\t\t\tyDimCan = plotWid;\n\t\t\tyOffCan = plotLft;\n\n\t\t\txDimCss = plotHgtCss;\n\t\t\txOffCss = plotTopCss;\n\t\t\tyDimCss = plotWidCss;\n\t\t\tyOffCss = plotLftCss;\n\t\t};\n\t\t*/\n\t}\n\n\tconst pendScales = {};\n\n\t// explicitly-set initial scales\n\tfor (let k in scales) {\n\t\tlet sc = scales[k];\n\n\t\tif (sc.min != null || sc.max != null) {\n\t\t\tpendScales[k] = {min: sc.min, max: sc.max};\n\t\t\tsc.min = sc.max = null;\n\t\t}\n\t}\n\n//\tself.tz = opts.tz || Intl.DateTimeFormat().resolvedOptions().timeZone;\n\tconst _tzDate = (opts.tzDate || (ts => new Date(round(ts / ms))));\n\tconst _fmtDate = (opts.fmtDate || fmtDate);\n\n\tconst _timeAxisSplits = (ms == 1 ? timeAxisSplitsMs(_tzDate) : timeAxisSplitsS(_tzDate));\n\tconst _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps((ms == 1 ? _timeAxisStampsMs : _timeAxisStampsS), _fmtDate));\n\tconst _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));\n\n\tconst activeIdxs = [];\n\n\tconst legend = (self.legend = assign({}, legendOpts, opts.legend));\n\tconst cursor = (self.cursor = assign({}, cursorOpts, {drag: {y: mode == 2}}, opts.cursor));\n\tconst showLegend = legend.show;\n\tconst showCursor = cursor.show;\n\tconst markers = legend.markers;\n\n\t{\n\t\tlegend.idxs = activeIdxs;\n\n\t\tmarkers.width = fnOrSelf(markers.width);\n\t\tmarkers.dash = fnOrSelf(markers.dash);\n\t\tmarkers.stroke = fnOrSelf(markers.stroke);\n\t\tmarkers.fill = fnOrSelf(markers.fill);\n\t}\n\n\tlet legendTable;\n\tlet legendHead;\n\tlet legendBody;\n\tlet legendRows = [];\n\tlet legendCells = [];\n\tlet legendCols;\n\tlet multiValLegend = false;\n\tlet NULL_LEGEND_VALUES = {};\n\n\tif (legend.live) {\n\t\tconst getMultiVals = series[1] ? series[1].values : null;\n\t\tmultiValLegend = getMultiVals != null;\n\t\tlegendCols = multiValLegend ? getMultiVals(self, 1, 0) : {_: 0};\n\n\t\tfor (let k in legendCols)\n\t\t\tNULL_LEGEND_VALUES[k] = LEGEND_DISP;\n\t}\n\n\tif (showLegend) {\n\t\tlegendTable = placeTag(\"table\", LEGEND, root);\n\t\tlegendBody = placeTag(\"tbody\", null, legendTable);\n\n\t\t// allows legend to be moved out of root\n\t\tlegend.mount(self, legendTable);\n\n\t\tif (multiValLegend) {\n\t\t\tlegendHead = placeTag(\"thead\", null, legendTable, legendBody);\n\n\t\t\tlet head = placeTag(\"tr\", null, legendHead);\n\t\t\tplaceTag(\"th\", null, head);\n\n\t\t\tfor (var key in legendCols)\n\t\t\t\tplaceTag(\"th\", LEGEND_LABEL, head).textContent = key;\n\t\t}\n\t\telse {\n\t\t\taddClass(legendTable, LEGEND_INLINE);\n\t\t\tlegend.live && addClass(legendTable, LEGEND_LIVE);\n\t\t}\n\t}\n\n\tconst son = {show: true};\n\tconst soff = {show: false};\n\n\tfunction initLegendRow(s, i) {\n\t\tif (i == 0 && (multiValLegend || !legend.live || mode == 2))\n\t\t\treturn nullNullTuple;\n\n\t\tlet cells = [];\n\n\t\tlet row = placeTag(\"tr\", LEGEND_SERIES, legendBody, legendBody.childNodes[i]);\n\n\t\taddClass(row, s.class);\n\n\t\tif (!s.show)\n\t\t\taddClass(row, OFF);\n\n\t\tlet label = placeTag(\"th\", null, row);\n\n\t\tif (markers.show) {\n\t\t\tlet indic = placeDiv(LEGEND_MARKER, label);\n\n\t\t\tif (i > 0) {\n\t\t\t\tlet width = markers.width(self, i);\n\n\t\t\t\tif (width)\n\t\t\t\t\tindic.style.border = width + \"px \" + markers.dash(self, i) + \" \" + markers.stroke(self, i);\n\n\t\t\t\tindic.style.background = markers.fill(self, i);\n\t\t\t}\n\t\t}\n\n\t\tlet text = placeDiv(LEGEND_LABEL, label);\n\n\t\tif (s.label instanceof HTMLElement)\n\t\t\ttext.appendChild(s.label);\n\t\telse\n\t\t\ttext.textContent = s.label;\n\n\t\tif (i > 0) {\n\t\t\tif (!markers.show)\n\t\t\t\ttext.style.color = s.width > 0 ? markers.stroke(self, i) : markers.fill(self, i);\n\n\t\t\tonMouse(\"click\", label, e => {\n\t\t\t\tif (cursor._lock)\n\t\t\t\t\treturn;\n\n\t\t\t\tsetCursorEvent(e);\n\n\t\t\t\tlet seriesIdx = series.indexOf(s);\n\n\t\t\t\tif ((e.ctrlKey || e.metaKey) != legend.isolate) {\n\t\t\t\t\t// if any other series is shown, isolate this one. else show all\n\t\t\t\t\tlet isolate = series.some((s, i) => i > 0 && i != seriesIdx && s.show);\n\n\t\t\t\t\tseries.forEach((s, i) => {\n\t\t\t\t\t\ti > 0 && setSeries(i, isolate ? (i == seriesIdx ? son : soff) : son, true, syncOpts.setSeries);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tsetSeries(seriesIdx, {show: !s.show}, true, syncOpts.setSeries);\n\t\t\t}, false);\n\n\t\t\tif (cursorFocus) {\n\t\t\t\tonMouse(mouseenter, label, e => {\n\t\t\t\t\tif (cursor._lock)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tsetCursorEvent(e);\n\n\t\t\t\t\tsetSeries(series.indexOf(s), FOCUS_TRUE, true, syncOpts.setSeries);\n\t\t\t\t}, false);\n\t\t\t}\n\t\t}\n\n\t\tfor (var key in legendCols) {\n\t\t\tlet v = placeTag(\"td\", LEGEND_VALUE, row);\n\t\t\tv.textContent = \"--\";\n\t\t\tcells.push(v);\n\t\t}\n\n\t\treturn [row, cells];\n\t}\n\n\tconst mouseListeners = new Map();\n\n\tfunction onMouse(ev, targ, fn, onlyTarg = true) {\n\t\tconst targListeners = mouseListeners.get(targ) || {};\n\t\tconst listener = cursor.bind[ev](self, targ, fn, onlyTarg);\n\n\t\tif (listener) {\n\t\t\ton(ev, targ, targListeners[ev] = listener);\n\t\t\tmouseListeners.set(targ, targListeners);\n\t\t}\n\t}\n\n\tfunction offMouse(ev, targ, fn) {\n\t\tconst targListeners = mouseListeners.get(targ) || {};\n\n\t\tfor (let k in targListeners) {\n\t\t\tif (ev == null || k == ev) {\n\t\t\t\toff(k, targ, targListeners[k]);\n\t\t\t\tdelete targListeners[k];\n\t\t\t}\n\t\t}\n\n\t\tif (ev == null)\n\t\t\tmouseListeners.delete(targ);\n\t}\n\n\tlet fullWidCss = 0;\n\tlet fullHgtCss = 0;\n\n\tlet plotWidCss = 0;\n\tlet plotHgtCss = 0;\n\n\t// plot margins to account for axes\n\tlet plotLftCss = 0;\n\tlet plotTopCss = 0;\n\n\t// previous values for diffing\n\tlet _plotLftCss = plotLftCss;\n\tlet _plotTopCss = plotTopCss;\n\tlet _plotWidCss = plotWidCss;\n\tlet _plotHgtCss = plotHgtCss;\n\n\n\tlet plotLft = 0;\n\tlet plotTop = 0;\n\tlet plotWid = 0;\n\tlet plotHgt = 0;\n\n\tself.bbox = {};\n\n\tlet shouldSetScales = false;\n\tlet shouldSetSize = false;\n\tlet shouldConvergeSize = false;\n\tlet shouldSetCursor = false;\n\tlet shouldSetSelect = false;\n\tlet shouldSetLegend = false;\n\n\tfunction _setSize(width, height, force) {\n\t\tif (force || (width != self.width || height != self.height))\n\t\t\tcalcSize(width, height);\n\n\t\tresetYSeries(false);\n\n\t\tshouldConvergeSize = true;\n\t\tshouldSetSize = true;\n\n\t\tcommit();\n\t}\n\n\tfunction calcSize(width, height) {\n\t//\tlog(\"calcSize()\", arguments);\n\n\t\tself.width = fullWidCss = plotWidCss = width;\n\t\tself.height = fullHgtCss = plotHgtCss = height;\n\t\tplotLftCss = plotTopCss = 0;\n\n\t\tcalcPlotRect();\n\t\tcalcAxesRects();\n\n\t\tlet bb = self.bbox;\n\n\t\tplotLft = bb.left = incrRound(plotLftCss * pxRatio, 0.5);\n\t\tplotTop = bb.top = incrRound(plotTopCss * pxRatio, 0.5);\n\t\tplotWid = bb.width = incrRound(plotWidCss * pxRatio, 0.5);\n\t\tplotHgt = bb.height = incrRound(plotHgtCss * pxRatio, 0.5);\n\n\t//\tupdOriDims();\n\t}\n\n\t// ensures size calc convergence\n\tconst CYCLE_LIMIT = 3;\n\n\tfunction convergeSize() {\n\t\tlet converged = false;\n\n\t\tlet cycleNum = 0;\n\n\t\twhile (!converged) {\n\t\t\tcycleNum++;\n\n\t\t\tlet axesConverged = axesCalc(cycleNum);\n\t\t\tlet paddingConverged = paddingCalc(cycleNum);\n\n\t\t\tconverged = cycleNum == CYCLE_LIMIT || (axesConverged && paddingConverged);\n\n\t\t\tif (!converged) {\n\t\t\t\tcalcSize(self.width, self.height);\n\t\t\t\tshouldSetSize = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction setSize({width, height}) {\n\t\t_setSize(width, height);\n\t}\n\n\tself.setSize = setSize;\n\n\t// accumulate axis offsets, reduce canvas width\n\tfunction calcPlotRect() {\n\t\t// easements for edge labels\n\t\tlet hasTopAxis = false;\n\t\tlet hasBtmAxis = false;\n\t\tlet hasRgtAxis = false;\n\t\tlet hasLftAxis = false;\n\n\t\taxes.forEach((axis, i) => {\n\t\t\tif (axis.show && axis._show) {\n\t\t\t\tlet {side, _size} = axis;\n\t\t\t\tlet isVt = side % 2;\n\t\t\t\tlet labelSize = axis.label != null ? axis.labelSize : 0;\n\n\t\t\t\tlet fullSize = _size + labelSize;\n\n\t\t\t\tif (fullSize > 0) {\n\t\t\t\t\tif (isVt) {\n\t\t\t\t\t\tplotWidCss -= fullSize;\n\n\t\t\t\t\t\tif (side == 3) {\n\t\t\t\t\t\t\tplotLftCss += fullSize;\n\t\t\t\t\t\t\thasLftAxis = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thasRgtAxis = true;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplotHgtCss -= fullSize;\n\n\t\t\t\t\t\tif (side == 0) {\n\t\t\t\t\t\t\tplotTopCss += fullSize;\n\t\t\t\t\t\t\thasTopAxis = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thasBtmAxis = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tsidesWithAxes[0] = hasTopAxis;\n\t\tsidesWithAxes[1] = hasRgtAxis;\n\t\tsidesWithAxes[2] = hasBtmAxis;\n\t\tsidesWithAxes[3] = hasLftAxis;\n\n\t\t// hz padding\n\t\tplotWidCss -= _padding[1] + _padding[3];\n\t\tplotLftCss += _padding[3];\n\n\t\t// vt padding\n\t\tplotHgtCss -= _padding[2] + _padding[0];\n\t\tplotTopCss += _padding[0];\n\t}\n\n\tfunction calcAxesRects() {\n\t\t// will accum +\n\t\tlet off1 = plotLftCss + plotWidCss;\n\t\tlet off2 = plotTopCss + plotHgtCss;\n\t\t// will accum -\n\t\tlet off3 = plotLftCss;\n\t\tlet off0 = plotTopCss;\n\n\t\tfunction incrOffset(side, size) {\n\t\t\tswitch (side) {\n\t\t\t\tcase 1: off1 += size; return off1 - size;\n\t\t\t\tcase 2: off2 += size; return off2 - size;\n\t\t\t\tcase 3: off3 -= size; return off3 + size;\n\t\t\t\tcase 0: off0 -= size; return off0 + size;\n\t\t\t}\n\t\t}\n\n\t\taxes.forEach((axis, i) => {\n\t\t\tif (axis.show && axis._show) {\n\t\t\t\tlet side = axis.side;\n\n\t\t\t\taxis._pos = incrOffset(side, axis._size);\n\n\t\t\t\tif (axis.label != null)\n\t\t\t\t\taxis._lpos = incrOffset(side, axis.labelSize);\n\t\t\t}\n\t\t});\n\t}\n\n\tif (cursor.dataIdx == null) {\n\t\tlet hov = cursor.hover;\n\n\t\tlet skip = hov.skip = new Set(hov.skip ?? []);\n\t\tskip.add(void 0); // alignment artifacts\n\t\tlet prox = hov.prox = fnOrSelf(hov.prox);\n\t\tlet bias = hov.bias ??= 0;\n\n\t\t// TODO: only scan between in-view idxs (i0, i1)\n\t\tcursor.dataIdx = (self, seriesIdx, cursorIdx, valAtPosX) => {\n\t\t\tif (seriesIdx == 0)\n\t\t\t\treturn cursorIdx;\n\n\t\t\tlet idx2 = cursorIdx;\n\n\t\t\tlet _prox = prox(self, seriesIdx, cursorIdx, valAtPosX) ?? inf;\n\t\t\tlet withProx = _prox >= 0 && _prox < inf;\n\t\t\tlet xDim = scaleX.ori == 0 ? plotWidCss : plotHgtCss;\n\t\t\tlet cursorLft = cursor.left;\n\n\t\t\tlet xValues = data[0];\n\t\t\tlet yValues = data[seriesIdx];\n\n\t\t\tif (skip.has(yValues[cursorIdx])) {\n\t\t\t\tidx2 = null;\n\n\t\t\t\tlet nonNullLft = null,\n\t\t\t\t\tnonNullRgt = null,\n\t\t\t\t\tj;\n\n\t\t\t\tif (bias == 0 || bias == -1) {\n\t\t\t\t\tj = cursorIdx;\n\t\t\t\t\twhile (nonNullLft == null && j-- > 0) {\n\t\t\t\t\t\tif (!skip.has(yValues[j]))\n\t\t\t\t\t\t\tnonNullLft = j;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (bias == 0 || bias == 1) {\n\t\t\t\t\tj = cursorIdx;\n\t\t\t\t\twhile (nonNullRgt == null && j++ < yValues.length) {\n\t\t\t\t\t\tif (!skip.has(yValues[j]))\n\t\t\t\t\t\t\tnonNullRgt = j;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (nonNullLft != null || nonNullRgt != null) {\n\t\t\t\t\tif (withProx) {\n\t\t\t\t\t\tlet lftPos = nonNullLft == null ? -Infinity : valToPosX(xValues[nonNullLft], scaleX, xDim, 0);\n\t\t\t\t\t\tlet rgtPos = nonNullRgt == null ? Infinity : valToPosX(xValues[nonNullRgt], scaleX, xDim, 0);\n\n\t\t\t\t\t\tlet lftDelta = cursorLft - lftPos;\n\t\t\t\t\t\tlet rgtDelta = rgtPos - cursorLft;\n\n\t\t\t\t\t\tif (lftDelta <= rgtDelta) {\n\t\t\t\t\t\t\tif (lftDelta <= _prox)\n\t\t\t\t\t\t\t\tidx2 = nonNullLft;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (rgtDelta <= _prox)\n\t\t\t\t\t\t\t\tidx2 = nonNullRgt;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tidx2 =\n\t\t\t\t\t\t\tnonNullRgt == null ? nonNullLft :\n\t\t\t\t\t\t\tnonNullLft == null ? nonNullRgt :\n\t\t\t\t\t\t\tcursorIdx - nonNullLft <= nonNullRgt - cursorIdx ? nonNullLft : nonNullRgt;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (withProx) {\n\t\t\t\tlet dist = abs(cursorLft - valToPosX(xValues[cursorIdx], scaleX, xDim, 0));\n\n\t\t\t\tif (dist > _prox)\n\t\t\t\t\tidx2 = null;\n\t\t\t}\n\n\t\t\treturn idx2;\n\t\t};\n\t}\n\n\tconst setCursorEvent = e => { cursor.event = e; };\n\n\tcursor.idxs = activeIdxs;\n\n\tcursor._lock = false;\n\n\tlet points = cursor.points;\n\n\tpoints.show = fnOrSelf(points.show);\n\tpoints.size = fnOrSelf(points.size);\n\tpoints.stroke = fnOrSelf(points.stroke);\n\tpoints.width = fnOrSelf(points.width);\n\tpoints.fill = fnOrSelf(points.fill);\n\n\tconst focus = self.focus = assign({}, opts.focus || {alpha: 0.3}, cursor.focus);\n\n\tconst cursorFocus = focus.prox >= 0;\n\tconst cursorOnePt = cursorFocus && points.one;\n\n\t// series-intersection markers\n\tlet cursorPts = [];\n\t// position caches in CSS pixels\n\tlet cursorPtsLft = [];\n\tlet cursorPtsTop = [];\n\n\tfunction initCursorPt(s, si) {\n\t\tlet pt = points.show(self, si);\n\n\t\tif (pt instanceof HTMLElement) {\n\t\t\taddClass(pt, CURSOR_PT);\n\t\t\taddClass(pt, s.class);\n\t\t\telTrans(pt, -10, -10, plotWidCss, plotHgtCss);\n\t\t\tover.insertBefore(pt, cursorPts[si]);\n\n\t\t\treturn pt;\n\t\t}\n\t}\n\n\tfunction initSeries(s, i) {\n\t\tif (mode == 1 || i > 0) {\n\t\t\tlet isTime = mode == 1 && scales[s.scale].time;\n\n\t\t\tlet sv = s.value;\n\t\t\ts.value = isTime ? (isStr(sv) ? timeSeriesVal(_tzDate, timeSeriesStamp(sv, _fmtDate)) : sv || _timeSeriesVal) : sv || numSeriesVal;\n\t\t\ts.label = s.label || (isTime ? timeSeriesLabel : numSeriesLabel);\n\t\t}\n\n\t\tif (cursorOnePt || i > 0) {\n\t\t\ts.width = s.width == null ? 1 : s.width;\n\t\t\ts.paths = s.paths || linearPath || retNull;\n\t\t\ts.fillTo = fnOrSelf(s.fillTo || seriesFillTo);\n\t\t\ts.pxAlign = +ifNull(s.pxAlign, pxAlign);\n\t\t\ts.pxRound = pxRoundGen(s.pxAlign);\n\n\t\t\ts.stroke = fnOrSelf(s.stroke || null);\n\t\t\ts.fill = fnOrSelf(s.fill || null);\n\t\t\ts._stroke = s._fill = s._paths = s._focus = null;\n\n\t\t\tlet _ptDia = ptDia(max(1, s.width), 1);\n\t\t\tlet points = s.points = assign({}, {\n\t\t\t\tsize: _ptDia,\n\t\t\t\twidth: max(1, _ptDia * .2),\n\t\t\t\tstroke: s.stroke,\n\t\t\t\tspace: _ptDia * 2,\n\t\t\t\tpaths: pointsPath,\n\t\t\t\t_stroke: null,\n\t\t\t\t_fill: null,\n\t\t\t}, s.points);\n\t\t\tpoints.show = fnOrSelf(points.show);\n\t\t\tpoints.filter = fnOrSelf(points.filter);\n\t\t\tpoints.fill = fnOrSelf(points.fill);\n\t\t\tpoints.stroke = fnOrSelf(points.stroke);\n\t\t\tpoints.paths = fnOrSelf(points.paths);\n\t\t\tpoints.pxAlign = s.pxAlign;\n\t\t}\n\n\t\tif (showLegend) {\n\t\t\tlet rowCells = initLegendRow(s, i);\n\t\t\tlegendRows.splice(i, 0, rowCells[0]);\n\t\t\tlegendCells.splice(i, 0, rowCells[1]);\n\t\t\tlegend.values.push(null);\t// NULL_LEGEND_VALS not yet avil here :(\n\t\t}\n\n\t\tif (showCursor) {\n\t\t\tactiveIdxs.splice(i, 0, null);\n\n\t\t\tlet pt = null;\n\n\t\t\tif (cursorOnePt) {\n\t\t\t\tif (i == 0)\n\t\t\t\t\tpt = initCursorPt(s, i);\n\t\t\t}\n\t\t\telse if (i > 0)\n\t\t\t\tpt = initCursorPt(s, i);\n\n\t\t\tcursorPts.splice(i, 0, pt);\n\t\t\tcursorPtsLft.splice(i, 0, 0);\n\t\t\tcursorPtsTop.splice(i, 0, 0);\n\t\t}\n\n\t\tfire(\"addSeries\", i);\n\t}\n\n\tfunction addSeries(opts, si) {\n\t\tsi = si == null ? series.length : si;\n\n\t\topts = mode == 1 ? setDefault(opts, si, xSeriesOpts, ySeriesOpts) : setDefault(opts, si, {}, xySeriesOpts);\n\n\t\tseries.splice(si, 0, opts);\n\t\tinitSeries(series[si], si);\n\t}\n\n\tself.addSeries = addSeries;\n\n\tfunction delSeries(i) {\n\t\tseries.splice(i, 1);\n\n\t\tif (showLegend) {\n\t\t\tlegend.values.splice(i, 1);\n\n\t\t\tlegendCells.splice(i, 1);\n\t\t\tlet tr = legendRows.splice(i, 1)[0];\n\t\t\toffMouse(null, tr.firstChild);\n\t\t\ttr.remove();\n\t\t}\n\n\t\tif (showCursor) {\n\t\t\tactiveIdxs.splice(i, 1);\n\t\t\tcursorPts.splice(i, 1)[0].remove();\n\t\t\tcursorPtsLft.splice(i, 1);\n\t\t\tcursorPtsTop.splice(i, 1);\n\t\t}\n\n\t\t// TODO: de-init no-longer-needed scales?\n\n\t\tfire(\"delSeries\", i);\n\t}\n\n\tself.delSeries = delSeries;\n\n\tconst sidesWithAxes = [false, false, false, false];\n\n\tfunction initAxis(axis, i) {\n\t\taxis._show = axis.show;\n\n\t\tif (axis.show) {\n\t\t\tlet isVt = axis.side % 2;\n\n\t\t\tlet sc = scales[axis.scale];\n\n\t\t\t// this can occur if all series specify non-default scales\n\t\t\tif (sc == null) {\n\t\t\t\taxis.scale = isVt ? series[1].scale : xScaleKey;\n\t\t\t\tsc = scales[axis.scale];\n\t\t\t}\n\n\t\t\t// also set defaults for incrs & values based on axis distr\n\t\t\tlet isTime = sc.time;\n\n\t\t\taxis.size = fnOrSelf(axis.size);\n\t\t\taxis.space = fnOrSelf(axis.space);\n\t\t\taxis.rotate = fnOrSelf(axis.rotate);\n\n\t\t\tif (isArr(axis.incrs)) {\n\t\t\t\taxis.incrs.forEach(incr => {\n\t\t\t\t\t!fixedDec.has(incr) && fixedDec.set(incr, guessDec(incr));\n\t\t\t\t});\n\t\t\t}\n\n\t\t\taxis.incrs = fnOrSelf(axis.incrs || ( sc.distr == 2 ? wholeIncrs : (isTime ? (ms == 1 ? timeIncrsMs : timeIncrsS) : numIncrs)));\n\t\t\taxis.splits = fnOrSelf(axis.splits || (isTime && sc.distr == 1 ? _timeAxisSplits : sc.distr == 3 ? logAxisSplits : sc.distr == 4 ? asinhAxisSplits : numAxisSplits));\n\n\t\t\taxis.stroke = fnOrSelf(axis.stroke);\n\t\t\taxis.grid.stroke = fnOrSelf(axis.grid.stroke);\n\t\t\taxis.ticks.stroke = fnOrSelf(axis.ticks.stroke);\n\t\t\taxis.border.stroke = fnOrSelf(axis.border.stroke);\n\n\t\t\tlet av = axis.values;\n\n\t\t\taxis.values = (\n\t\t\t\t// static array of tick values\n\t\t\t\tisArr(av) && !isArr(av[0]) ? fnOrSelf(av) :\n\t\t\t\t// temporal\n\t\t\t\tisTime ? (\n\t\t\t\t\t// config array of fmtDate string tpls\n\t\t\t\t\tisArr(av) ?\n\t\t\t\t\t\ttimeAxisVals(_tzDate, timeAxisStamps(av, _fmtDate)) :\n\t\t\t\t\t// fmtDate string tpl\n\t\t\t\t\tisStr(av) ?\n\t\t\t\t\t\ttimeAxisVal(_tzDate, av) :\n\t\t\t\t\tav || _timeAxisVals\n\t\t\t\t) : av || numAxisVals\n\t\t\t);\n\n\t\t\taxis.filter = fnOrSelf(axis.filter || ( sc.distr >= 3 && sc.log == 10 ? log10AxisValsFilt : sc.distr == 3 && sc.log == 2 ? log2AxisValsFilt : retArg1));\n\n\t\t\taxis.font = pxRatioFont(axis.font);\n\t\t\taxis.labelFont = pxRatioFont(axis.labelFont);\n\n\t\t\taxis._size = axis.size(self, null, i, 0);\n\n\t\t\taxis._space =\n\t\t\taxis._rotate =\n\t\t\taxis._incrs =\n\t\t\taxis._found =\t// foundIncrSpace\n\t\t\taxis._splits =\n\t\t\taxis._values = null;\n\n\t\t\tif (axis._size > 0) {\n\t\t\t\tsidesWithAxes[i] = true;\n\t\t\t\taxis._el = placeDiv(AXIS, wrap);\n\t\t\t}\n\n\t\t\t// debug\n\t\t//\taxis._el.style.background = \"#\" + Math.floor(Math.random()*16777215).toString(16) + '80';\n\t\t}\n\t}\n\n\tfunction autoPadSide(self, side, sidesWithAxes, cycleNum) {\n\t\tlet [hasTopAxis, hasRgtAxis, hasBtmAxis, hasLftAxis] = sidesWithAxes;\n\n\t\tlet ori = side % 2;\n\t\tlet size = 0;\n\n\t\tif (ori == 0 && (hasLftAxis || hasRgtAxis))\n\t\t\tsize = (side == 0 && !hasTopAxis || side == 2 && !hasBtmAxis ? round(xAxisOpts.size / 3) : 0);\n\t\tif (ori == 1 && (hasTopAxis || hasBtmAxis))\n\t\t\tsize = (side == 1 && !hasRgtAxis || side == 3 && !hasLftAxis ? round(yAxisOpts.size / 2) : 0);\n\n\t\treturn size;\n\t}\n\n\tconst padding = self.padding = (opts.padding || [autoPadSide,autoPadSide,autoPadSide,autoPadSide]).map(p => fnOrSelf(ifNull(p, autoPadSide)));\n\tconst _padding = self._padding = padding.map((p, i) => p(self, i, sidesWithAxes, 0));\n\n\tlet dataLen;\n\n\t// rendered data window\n\tlet i0 = null;\n\tlet i1 = null;\n\tconst idxs = mode == 1 ? series[0].idxs : null;\n\n\tlet data0 = null;\n\n\tlet viaAutoScaleX = false;\n\n\tfunction setData(_data, _resetScales) {\n\t\tdata = _data == null ? [] : _data;\n\n\t\tself.data = self._data = data;\n\n\t\tif (mode == 2) {\n\t\t\tdataLen = 0;\n\t\t\tfor (let i = 1; i < series.length; i++)\n\t\t\t\tdataLen += data[i][0].length;\n\t\t}\n\t\telse {\n\t\t\tif (data.length == 0)\n\t\t\t\tself.data = self._data = data = [[]];\n\n\t\t\tdata0 = data[0];\n\t\t\tdataLen = data0.length;\n\n\t\t\tlet scaleData = data;\n\n\t\t\tif (xScaleDistr == 2) {\n\t\t\t\tscaleData = data.slice();\n\n\t\t\t\tlet _data0 = scaleData[0] = Array(dataLen);\n\t\t\t\tfor (let i = 0; i < dataLen; i++)\n\t\t\t\t\t_data0[i] = i;\n\t\t\t}\n\n\t\t\tself._data = data = scaleData;\n\t\t}\n\n\t\tresetYSeries(true);\n\n\t\tfire(\"setData\");\n\n\t\t// forces x axis tick values to re-generate when neither x scale nor y scale changes\n\t\t// in ordinal mode, scale range is by index, so will not change if new data has same length, but tick values are from data\n\t\tif (xScaleDistr == 2) {\n\t\t\tshouldConvergeSize = true;\n\n\t\t\t/* or somewhat cheaper, and uglier:\n\t\t\tif (ready) {\n\t\t\t\t// logic extracted from axesCalc()\n\t\t\t\tlet i = 0;\n\t\t\t\tlet axis = axes[i];\n\t\t\t\tlet _splits = axis._splits.map(i => data0[i]);\n\t\t\t\tlet [_incr, _space] = axis._found;\n\t\t\t\tlet incr = data0[_splits[1]] - data0[_splits[0]];\n\t\t\t\taxis._values = axis.values(self, axis.filter(self, _splits, i, _space, incr), i, _space, incr);\n\t\t\t}\n\t\t\t*/\n\t\t}\n\n\t\tif (_resetScales !== false) {\n\t\t\tlet xsc = scaleX;\n\n\t\t\tif (xsc.auto(self, viaAutoScaleX))\n\t\t\t\tautoScaleX();\n\t\t\telse\n\t\t\t\t_setScale(xScaleKey, xsc.min, xsc.max);\n\n\t\t\tshouldSetCursor = shouldSetCursor || cursor.left >= 0;\n\t\t\tshouldSetLegend = true;\n\t\t\tcommit();\n\t\t}\n\t}\n\n\tself.setData = setData;\n\n\tfunction autoScaleX() {\n\t\tviaAutoScaleX = true;\n\n\t\tlet _min, _max;\n\n\t\tif (mode == 1) {\n\t\t\tif (dataLen > 0) {\n\t\t\t\ti0 = idxs[0] = 0;\n\t\t\t\ti1 = idxs[1] = dataLen - 1;\n\n\t\t\t\t_min = data[0][i0];\n\t\t\t\t_max = data[0][i1];\n\n\t\t\t\tif (xScaleDistr == 2) {\n\t\t\t\t\t_min = i0;\n\t\t\t\t\t_max = i1;\n\t\t\t\t}\n\t\t\t\telse if (_min == _max) {\n\t\t\t\t\tif (xScaleDistr == 3)\n\t\t\t\t\t\t[_min, _max] = rangeLog(_min, _min, scaleX.log, false);\n\t\t\t\t\telse if (xScaleDistr == 4)\n\t\t\t\t\t\t[_min, _max] = rangeAsinh(_min, _min, scaleX.log, false);\n\t\t\t\t\telse if (scaleX.time)\n\t\t\t\t\t\t_max = _min + round(86400 / ms);\n\t\t\t\t\telse\n\t\t\t\t\t\t[_min, _max] = rangeNum(_min, _max, rangePad, true);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\ti0 = idxs[0] = _min = null;\n\t\t\t\ti1 = idxs[1] = _max = null;\n\t\t\t}\n\t\t}\n\n\t\t_setScale(xScaleKey, _min, _max);\n\t}\n\n\tlet ctxStroke, ctxFill, ctxWidth, ctxDash, ctxJoin, ctxCap, ctxFont, ctxAlign, ctxBaseline;\n\tlet ctxAlpha;\n\n\tfunction setCtxStyle(stroke, width, dash, cap, fill, join) {\n\t\tstroke ??= transparent;\n\t\tdash ??= EMPTY_ARR;\n\t\tcap ??= \"butt\"; // (\u203F|\u203F)\n\t\tfill ??= transparent;\n\t\tjoin ??= \"round\";\n\n\t\tif (stroke != ctxStroke)\n\t\t\tctx.strokeStyle = ctxStroke = stroke;\n\t\tif (fill != ctxFill)\n\t\t\tctx.fillStyle = ctxFill = fill;\n\t\tif (width != ctxWidth)\n\t\t\tctx.lineWidth = ctxWidth = width;\n\t\tif (join != ctxJoin)\n\t\t\tctx.lineJoin = ctxJoin = join;\n\t\tif (cap != ctxCap)\n\t\t\tctx.lineCap = ctxCap = cap;\n\t\tif (dash != ctxDash)\n\t\t\tctx.setLineDash(ctxDash = dash);\n\t}\n\n\tfunction setFontStyle(font, fill, align, baseline) {\n\t\tif (fill != ctxFill)\n\t\t\tctx.fillStyle = ctxFill = fill;\n\t\tif (font != ctxFont)\n\t\t\tctx.font = ctxFont = font;\n\t\tif (align != ctxAlign)\n\t\t\tctx.textAlign = ctxAlign = align;\n\t\tif (baseline != ctxBaseline)\n\t\t\tctx.textBaseline = ctxBaseline = baseline;\n\t}\n\n\tfunction accScale(wsc, psc, facet, data, sorted = 0) {\n\t\tif (data.length > 0 && wsc.auto(self, viaAutoScaleX) && (psc == null || psc.min == null)) {\n\t\t\tlet _i0 = ifNull(i0, 0);\n\t\t\tlet _i1 = ifNull(i1, data.length - 1);\n\n\t\t\t// only run getMinMax() for invalidated series data, else reuse\n\t\t\tlet minMax = facet.min == null ? getMinMax(data, _i0, _i1, sorted, wsc.distr == 3) : [facet.min, facet.max];\n\n\t\t\t// initial min/max\n\t\t\twsc.min = min(wsc.min, facet.min = minMax[0]);\n\t\t\twsc.max = max(wsc.max, facet.max = minMax[1]);\n\t\t}\n\t}\n\n\tconst AUTOSCALE = {min: null, max: null};\n\n\tfunction setScales() {\n\t//\tlog(\"setScales()\", arguments);\n\n\t\t// implicitly add auto scales, and unranged scales\n\t\tfor (let k in scales) {\n\t\t\tlet sc = scales[k];\n\n\t\t\tif (pendScales[k] == null &&\n\t\t\t\t(\n\t\t\t\t\t// scales that have never been set (on init)\n\t\t\t\t\tsc.min == null ||\n\t\t\t\t\t// or auto scales when the x scale was explicitly set\n\t\t\t\t\tpendScales[xScaleKey] != null && sc.auto(self, viaAutoScaleX)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tpendScales[k] = AUTOSCALE;\n\t\t\t}\n\t\t}\n\n\t\t// implicitly add dependent scales\n\t\tfor (let k in scales) {\n\t\t\tlet sc = scales[k];\n\n\t\t\tif (pendScales[k] == null && sc.from != null && pendScales[sc.from] != null)\n\t\t\t\tpendScales[k] = AUTOSCALE;\n\t\t}\n\n\t\t// explicitly setting the x-scale invalidates everything (acts as redraw)\n\t\tif (pendScales[xScaleKey] != null)\n\t\t\tresetYSeries(true); // TODO: only reset series on auto scales?\n\n\t\tlet wipScales = {};\n\n\t\tfor (let k in pendScales) {\n\t\t\tlet psc = pendScales[k];\n\n\t\t\tif (psc != null) {\n\t\t\t\tlet wsc = wipScales[k] = copy(scales[k], fastIsObj);\n\n\t\t\t\tif (psc.min != null)\n\t\t\t\t\tassign(wsc, psc);\n\t\t\t\telse if (k != xScaleKey || mode == 2) {\n\t\t\t\t\tif (dataLen == 0 && wsc.from == null) {\n\t\t\t\t\t\tlet minMax = wsc.range(self, null, null, k);\n\t\t\t\t\t\twsc.min = minMax[0];\n\t\t\t\t\t\twsc.max = minMax[1];\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\twsc.min = inf;\n\t\t\t\t\t\twsc.max = -inf;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (dataLen > 0) {\n\t\t\t// pre-range y-scales from y series' data values\n\t\t\tseries.forEach((s, i) => {\n\t\t\t\tif (mode == 1) {\n\t\t\t\t\tlet k = s.scale;\n\t\t\t\t\tlet psc = pendScales[k];\n\n\t\t\t\t\tif (psc == null)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tlet wsc = wipScales[k];\n\n\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\tlet minMax = wsc.range(self, wsc.min, wsc.max, k);\n\n\t\t\t\t\t\twsc.min = minMax[0];\n\t\t\t\t\t\twsc.max = minMax[1];\n\n\t\t\t\t\t\ti0 = closestIdx(wsc.min, data[0]);\n\t\t\t\t\t\ti1 = closestIdx(wsc.max, data[0]);\n\n\t\t\t\t\t\t// don't try to contract same or adjacent idxs\n\t\t\t\t\t\tif (i1 - i0 > 1) {\n\t\t\t\t\t\t\t// closest indices can be outside of view\n\t\t\t\t\t\t\tif (data[0][i0] < wsc.min)\n\t\t\t\t\t\t\t\ti0++;\n\t\t\t\t\t\t\tif (data[0][i1] > wsc.max)\n\t\t\t\t\t\t\t\ti1--;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ts.min = data0[i0];\n\t\t\t\t\t\ts.max = data0[i1];\n\t\t\t\t\t}\n\t\t\t\t\telse if (s.show && s.auto)\n\t\t\t\t\t\taccScale(wsc, psc, s, data[i], s.sorted);\n\n\t\t\t\t\ts.idxs[0] = i0;\n\t\t\t\t\ts.idxs[1] = i1;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (i > 0) {\n\t\t\t\t\t\tif (s.show && s.auto) {\n\t\t\t\t\t\t\t// TODO: only handles, assumes and requires facets[0] / 'x' scale, and facets[1] / 'y' scale\n\t\t\t\t\t\t\tlet [ xFacet, yFacet ] = s.facets;\n\t\t\t\t\t\t\tlet xScaleKey = xFacet.scale;\n\t\t\t\t\t\t\tlet yScaleKey = yFacet.scale;\n\t\t\t\t\t\t\tlet [ xData, yData ] = data[i];\n\n\t\t\t\t\t\t\tlet wscx = wipScales[xScaleKey];\n\t\t\t\t\t\t\tlet wscy = wipScales[yScaleKey];\n\n\t\t\t\t\t\t\t// null can happen when only x is zoomed, but y has static range and doesnt get auto-added to pending\n\t\t\t\t\t\t\twscx != null && accScale(wscx, pendScales[xScaleKey], xFacet, xData, xFacet.sorted);\n\t\t\t\t\t\t\twscy != null && accScale(wscy, pendScales[yScaleKey], yFacet, yData, yFacet.sorted);\n\n\t\t\t\t\t\t\t// temp\n\t\t\t\t\t\t\ts.min = yFacet.min;\n\t\t\t\t\t\t\ts.max = yFacet.max;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// range independent scales\n\t\t\tfor (let k in wipScales) {\n\t\t\t\tlet wsc = wipScales[k];\n\t\t\t\tlet psc = pendScales[k];\n\n\t\t\t\tif (wsc.from == null && (psc == null || psc.min == null)) {\n\t\t\t\t\tlet minMax = wsc.range(\n\t\t\t\t\t\tself,\n\t\t\t\t\t\twsc.min == inf ? null : wsc.min,\n\t\t\t\t\t\twsc.max == -inf ? null : wsc.max,\n\t\t\t\t\t\tk\n\t\t\t\t\t);\n\t\t\t\t\twsc.min = minMax[0];\n\t\t\t\t\twsc.max = minMax[1];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// range dependent scales\n\t\tfor (let k in wipScales) {\n\t\t\tlet wsc = wipScales[k];\n\n\t\t\tif (wsc.from != null) {\n\t\t\t\tlet base = wipScales[wsc.from];\n\n\t\t\t\tif (base.min == null)\n\t\t\t\t\twsc.min = wsc.max = null;\n\t\t\t\telse {\n\t\t\t\t\tlet minMax = wsc.range(self, base.min, base.max, k);\n\t\t\t\t\twsc.min = minMax[0];\n\t\t\t\t\twsc.max = minMax[1];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet changed = {};\n\t\tlet anyChanged = false;\n\n\t\tfor (let k in wipScales) {\n\t\t\tlet wsc = wipScales[k];\n\t\t\tlet sc = scales[k];\n\n\t\t\tif (sc.min != wsc.min || sc.max != wsc.max) {\n\t\t\t\tsc.min = wsc.min;\n\t\t\t\tsc.max = wsc.max;\n\n\t\t\t\tlet distr = sc.distr;\n\n\t\t\t\tsc._min = distr == 3 ? log10(sc.min) : distr == 4 ? asinh(sc.min, sc.asinh) : distr == 100 ? sc.fwd(sc.min) : sc.min;\n\t\t\t\tsc._max = distr == 3 ? log10(sc.max) : distr == 4 ? asinh(sc.max, sc.asinh) : distr == 100 ? sc.fwd(sc.max) : sc.max;\n\n\t\t\t\tchanged[k] = anyChanged = true;\n\t\t\t}\n\t\t}\n\n\t\tif (anyChanged) {\n\t\t\t// invalidate paths of all series on changed scales\n\t\t\tseries.forEach((s, i) => {\n\t\t\t\tif (mode == 2) {\n\t\t\t\t\tif (i > 0 && changed.y)\n\t\t\t\t\t\ts._paths = null;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (changed[s.scale])\n\t\t\t\t\t\ts._paths = null;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tfor (let k in changed) {\n\t\t\t\tshouldConvergeSize = true;\n\t\t\t\tfire(\"setScale\", k);\n\t\t\t}\n\n\t\t\tif (showCursor && cursor.left >= 0)\n\t\t\t\tshouldSetCursor = shouldSetLegend = true;\n\t\t}\n\n\t\tfor (let k in pendScales)\n\t\t\tpendScales[k] = null;\n\t}\n\n\t// grabs the nearest indices with y data outside of x-scale limits\n\tfunction getOuterIdxs(ydata) {\n\t\tlet _i0 = clamp(i0 - 1, 0, dataLen - 1);\n\t\tlet _i1 = clamp(i1 + 1, 0, dataLen - 1);\n\n\t\twhile (ydata[_i0] == null && _i0 > 0)\n\t\t\t_i0--;\n\n\t\twhile (ydata[_i1] == null && _i1 < dataLen - 1)\n\t\t\t_i1++;\n\n\t\treturn [_i0, _i1];\n\t}\n\n\tfunction drawSeries() {\n\t\tif (dataLen > 0) {\n\t\t\tlet shouldAlpha = series.some(s => s._focus) && ctxAlpha != focus.alpha;\n\n\t\t\tif (shouldAlpha)\n\t\t\t\tctx.globalAlpha = ctxAlpha = focus.alpha;\n\n\t\t\tseries.forEach((s, i) => {\n\t\t\t\tif (i > 0 && s.show) {\n\t\t\t\t\tcacheStrokeFill(i, false);\n\t\t\t\t\tcacheStrokeFill(i, true);\n\n\t\t\t\t\tif (s._paths == null) {\n\t\t\t\t\t\tlet _ctxAlpha = ctxAlpha;\n\n\t\t\t\t\t\tif (ctxAlpha != s.alpha)\n\t\t\t\t\t\t\tctx.globalAlpha = ctxAlpha = s.alpha;\n\n\t\t\t\t\t\tlet _idxs = mode == 2 ? [0, data[i][0].length - 1] : getOuterIdxs(data[i]);\n\t\t\t\t\t\ts._paths = s.paths(self, i, _idxs[0], _idxs[1]);\n\n\t\t\t\t\t\tif (ctxAlpha != _ctxAlpha)\n\t\t\t\t\t\t\tctx.globalAlpha = ctxAlpha = _ctxAlpha;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tseries.forEach((s, i) => {\n\t\t\t\tif (i > 0 && s.show) {\n\t\t\t\t\tlet _ctxAlpha = ctxAlpha;\n\n\t\t\t\t\tif (ctxAlpha != s.alpha)\n\t\t\t\t\t\tctx.globalAlpha = ctxAlpha = s.alpha;\n\n\t\t\t\t\ts._paths != null && drawPath(i, false);\n\n\t\t\t\t\t{\n\t\t\t\t\t\tlet _gaps = s._paths != null ? s._paths.gaps : null;\n\n\t\t\t\t\t\tlet show = s.points.show(self, i, i0, i1, _gaps);\n\t\t\t\t\t\tlet idxs = s.points.filter(self, i, show, _gaps);\n\n\t\t\t\t\t\tif (show || idxs) {\n\t\t\t\t\t\t\ts.points._paths = s.points.paths(self, i, i0, i1, idxs);\n\t\t\t\t\t\t\tdrawPath(i, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (ctxAlpha != _ctxAlpha)\n\t\t\t\t\t\tctx.globalAlpha = ctxAlpha = _ctxAlpha;\n\n\t\t\t\t\tfire(\"drawSeries\", i);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (shouldAlpha)\n\t\t\t\tctx.globalAlpha = ctxAlpha = 1;\n\t\t}\n\t}\n\n\tfunction cacheStrokeFill(si, _points) {\n\t\tlet s = _points ? series[si].points : series[si];\n\n\t\ts._stroke = s.stroke(self, si);\n\t\ts._fill = s.fill(self, si);\n\t}\n\n\tfunction drawPath(si, _points) {\n\t\tlet s = _points ? series[si].points : series[si];\n\n\t\tlet {\n\t\t\tstroke,\n\t\t\tfill,\n\t\t\tclip: gapsClip,\n\t\t\tflags,\n\n\t\t\t_stroke: strokeStyle = s._stroke,\n\t\t\t_fill: fillStyle = s._fill,\n\t\t\t_width: width = s.width,\n\t\t} = s._paths;\n\n\t\twidth = roundDec(width * pxRatio, 3);\n\n\t\tlet boundsClip = null;\n\t\tlet offset = (width % 2) / 2;\n\n\t\tif (_points && fillStyle == null)\n\t\t\tfillStyle = width > 0 ? \"#fff\" : strokeStyle;\n\n\t\tlet _pxAlign = s.pxAlign == 1 && offset > 0;\n\n\t\t_pxAlign && ctx.translate(offset, offset);\n\n\t\tif (!_points) {\n\t\t\tlet lft = plotLft - width / 2,\n\t\t\t\ttop = plotTop - width / 2,\n\t\t\t\twid = plotWid + width,\n\t\t\t\thgt = plotHgt + width;\n\n\t\t\tboundsClip = new Path2D();\n\t\t\tboundsClip.rect(lft, top, wid, hgt);\n\t\t}\n\n\t\t// the points pathbuilder's gapsClip is its boundsClip, since points dont need gaps clipping, and bounds depend on point size\n\t\tif (_points)\n\t\t\tstrokeFill(strokeStyle, width, s.dash, s.cap, fillStyle, stroke, fill, flags, gapsClip);\n\t\telse\n\t\t\tfillStroke(si, strokeStyle, width, s.dash, s.cap, fillStyle, stroke, fill, flags, boundsClip, gapsClip);\n\n\t\t_pxAlign && ctx.translate(-offset, -offset);\n\t}\n\n\tfunction fillStroke(si, strokeStyle, lineWidth, lineDash, lineCap, fillStyle, strokePath, fillPath, flags, boundsClip, gapsClip) {\n\t\tlet didStrokeFill = false;\n\n\t\t// for all bands where this series is the top edge, create upwards clips using the bottom edges\n\t\t// and apply clips + fill with band fill or dfltFill\n\t\tflags != 0 && bands.forEach((b, bi) => {\n\t\t\t// isUpperEdge?\n\t\t\tif (b.series[0] == si) {\n\t\t\t\tlet lowerEdge = series[b.series[1]];\n\t\t\t\tlet lowerData = data[b.series[1]];\n\n\t\t\t\tlet bandClip = (lowerEdge._paths || EMPTY_OBJ).band;\n\n\t\t\t\tif (isArr(bandClip))\n\t\t\t\t\tbandClip = b.dir == 1 ? bandClip[0] : bandClip[1];\n\n\t\t\t\tlet gapsClip2;\n\n\t\t\t\tlet _fillStyle = null;\n\n\t\t\t\t// hasLowerEdge?\n\t\t\t\tif (lowerEdge.show && bandClip && hasData(lowerData, i0, i1)) {\n\t\t\t\t\t_fillStyle = b.fill(self, bi) || fillStyle;\n\t\t\t\t\tgapsClip2 = lowerEdge._paths.clip;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tbandClip = null;\n\n\t\t\t\tstrokeFill(strokeStyle, lineWidth, lineDash, lineCap, _fillStyle, strokePath, fillPath, flags, boundsClip, gapsClip, gapsClip2, bandClip);\n\n\t\t\t\tdidStrokeFill = true;\n\t\t\t}\n\t\t});\n\n\t\tif (!didStrokeFill)\n\t\t\tstrokeFill(strokeStyle, lineWidth, lineDash, lineCap, fillStyle, strokePath, fillPath, flags, boundsClip, gapsClip);\n\t}\n\n\tconst CLIP_FILL_STROKE = BAND_CLIP_FILL | BAND_CLIP_STROKE;\n\n\tfunction strokeFill(strokeStyle, lineWidth, lineDash, lineCap, fillStyle, strokePath, fillPath, flags, boundsClip, gapsClip, gapsClip2, bandClip) {\n\t\tsetCtxStyle(strokeStyle, lineWidth, lineDash, lineCap, fillStyle);\n\n\t\tif (boundsClip || gapsClip || bandClip) {\n\t\t\tctx.save();\n\t\t\tboundsClip && ctx.clip(boundsClip);\n\t\t\tgapsClip && ctx.clip(gapsClip);\n\t\t}\n\n\t\tif (bandClip) {\n\t\t\tif ((flags & CLIP_FILL_STROKE) == CLIP_FILL_STROKE) {\n\t\t\t\tctx.clip(bandClip);\n\t\t\t\tgapsClip2 && ctx.clip(gapsClip2);\n\t\t\t\tdoFill(fillStyle, fillPath);\n\t\t\t\tdoStroke(strokeStyle, strokePath, lineWidth);\n\t\t\t}\n\t\t\telse if (flags & BAND_CLIP_STROKE) {\n\t\t\t\tdoFill(fillStyle, fillPath);\n\t\t\t\tctx.clip(bandClip);\n\t\t\t\tdoStroke(strokeStyle, strokePath, lineWidth);\n\t\t\t}\n\t\t\telse if (flags & BAND_CLIP_FILL) {\n\t\t\t\tctx.save();\n\t\t\t\tctx.clip(bandClip);\n\t\t\t\tgapsClip2 && ctx.clip(gapsClip2);\n\t\t\t\tdoFill(fillStyle, fillPath);\n\t\t\t\tctx.restore();\n\t\t\t\tdoStroke(strokeStyle, strokePath, lineWidth);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tdoFill(fillStyle, fillPath);\n\t\t\tdoStroke(strokeStyle, strokePath, lineWidth);\n\t\t}\n\n\t\tif (boundsClip || gapsClip || bandClip)\n\t\t\tctx.restore();\n\t}\n\n\tfunction doStroke(strokeStyle, strokePath, lineWidth) {\n\t\tif (lineWidth > 0) {\n\t\t\tif (strokePath instanceof Map) {\n\t\t\t\tstrokePath.forEach((strokePath, strokeStyle) => {\n\t\t\t\t\tctx.strokeStyle = ctxStroke = strokeStyle;\n\t\t\t\t\tctx.stroke(strokePath);\n\t\t\t\t});\n\t\t\t}\n\t\t\telse\n\t\t\t\tstrokePath != null && strokeStyle && ctx.stroke(strokePath);\n\t\t}\n\t}\n\n\tfunction doFill(fillStyle, fillPath) {\n\t\tif (fillPath instanceof Map) {\n\t\t\tfillPath.forEach((fillPath, fillStyle) => {\n\t\t\t\tctx.fillStyle = ctxFill = fillStyle;\n\t\t\t\tctx.fill(fillPath);\n\t\t\t});\n\t\t}\n\t\telse\n\t\t\tfillPath != null && fillStyle && ctx.fill(fillPath);\n\t}\n\n\tfunction getIncrSpace(axisIdx, min, max, fullDim) {\n\t\tlet axis = axes[axisIdx];\n\n\t\tlet incrSpace;\n\n\t\tif (fullDim <= 0)\n\t\t\tincrSpace = [0, 0];\n\t\telse {\n\t\t\tlet minSpace = axis._space = axis.space(self, axisIdx, min, max, fullDim);\n\t\t\tlet incrs = axis._incrs = axis.incrs(self, axisIdx, min, max, fullDim, minSpace);\n\t\t\tincrSpace = findIncr(min, max, incrs, fullDim, minSpace);\n\t\t}\n\n\t\treturn (axis._found = incrSpace);\n\t}\n\n\tfunction drawOrthoLines(offs, filts, ori, side, pos0, len, width, stroke, dash, cap) {\n\t\tlet offset = (width % 2) / 2;\n\n\t\tpxAlign == 1 && ctx.translate(offset, offset);\n\n\t\tsetCtxStyle(stroke, width, dash, cap, stroke);\n\n\t\tctx.beginPath();\n\n\t\tlet x0, y0, x1, y1, pos1 = pos0 + (side == 0 || side == 3 ? -len : len);\n\n\t\tif (ori == 0) {\n\t\t\ty0 = pos0;\n\t\t\ty1 = pos1;\n\t\t}\n\t\telse {\n\t\t\tx0 = pos0;\n\t\t\tx1 = pos1;\n\t\t}\n\n\t\tfor (let i = 0; i < offs.length; i++) {\n\t\t\tif (filts[i] != null) {\n\t\t\t\tif (ori == 0)\n\t\t\t\t\tx0 = x1 = offs[i];\n\t\t\t\telse\n\t\t\t\t\ty0 = y1 = offs[i];\n\n\t\t\t\tctx.moveTo(x0, y0);\n\t\t\t\tctx.lineTo(x1, y1);\n\t\t\t}\n\t\t}\n\n\t\tctx.stroke();\n\n\t\tpxAlign == 1 && ctx.translate(-offset, -offset);\n\t}\n\n\tfunction axesCalc(cycleNum) {\n\t//\tlog(\"axesCalc()\", arguments);\n\n\t\tlet converged = true;\n\n\t\taxes.forEach((axis, i) => {\n\t\t\tif (!axis.show)\n\t\t\t\treturn;\n\n\t\t\tlet scale = scales[axis.scale];\n\n\t\t\tif (scale.min == null) {\n\t\t\t\tif (axis._show) {\n\t\t\t\t\tconverged = false;\n\t\t\t\t\taxis._show = false;\n\t\t\t\t\tresetYSeries(false);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (!axis._show) {\n\t\t\t\t\tconverged = false;\n\t\t\t\t\taxis._show = true;\n\t\t\t\t\tresetYSeries(false);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet side = axis.side;\n\t\t\tlet ori = side % 2;\n\n\t\t\tlet {min, max} = scale;\t\t// \t\t// should this toggle them ._show = false\n\n\t\t\tlet [_incr, _space] = getIncrSpace(i, min, max, ori == 0 ? plotWidCss : plotHgtCss);\n\n\t\t\tif (_space == 0)\n\t\t\t\treturn;\n\n\t\t\t// if we're using index positions, force first tick to match passed index\n\t\t\tlet forceMin = scale.distr == 2;\n\n\t\t\tlet _splits = axis._splits = axis.splits(self, i, min, max, _incr, _space, forceMin);\n\n\t\t\t// tick labels\n\t\t\t// BOO this assumes a specific data/series\n\t\t\tlet splits = scale.distr == 2 ? _splits.map(i => data0[i]) : _splits;\n\t\t\tlet incr = scale.distr == 2 ? data0[_splits[1]] - data0[_splits[0]] : _incr;\n\n\t\t\tlet values = axis._values = axis.values(self, axis.filter(self, splits, i, _space, incr), i, _space, incr);\n\n\t\t\t// rotating of labels only supported on bottom x axis\n\t\t\taxis._rotate = side == 2 ? axis.rotate(self, values, i, _space) : 0;\n\n\t\t\tlet oldSize = axis._size;\n\n\t\t\taxis._size = ceil(axis.size(self, values, i, cycleNum));\n\n\t\t\tif (oldSize != null && axis._size != oldSize)\t\t\t// ready && ?\n\t\t\t\tconverged = false;\n\t\t});\n\n\t\treturn converged;\n\t}\n\n\tfunction paddingCalc(cycleNum) {\n\t\tlet converged = true;\n\n\t\tpadding.forEach((p, i) => {\n\t\t\tlet _p = p(self, i, sidesWithAxes, cycleNum);\n\n\t\t\tif (_p != _padding[i])\n\t\t\t\tconverged = false;\n\n\t\t\t_padding[i] = _p;\n\t\t});\n\n\t\treturn converged;\n\t}\n\n\tfunction drawAxesGrid() {\n\t\tfor (let i = 0; i < axes.length; i++) {\n\t\t\tlet axis = axes[i];\n\n\t\t\tif (!axis.show || !axis._show)\n\t\t\t\tcontinue;\n\n\t\t\tlet side = axis.side;\n\t\t\tlet ori = side % 2;\n\n\t\t\tlet x, y;\n\n\t\t\tlet fillStyle = axis.stroke(self, i);\n\n\t\t\tlet shiftDir = side == 0 || side == 3 ? -1 : 1;\n\n\t\t\tlet [_incr, _space] = axis._found;\n\n\t\t\t// axis label\n\t\t\tif (axis.label != null) {\n\t\t\t\tlet shiftAmt = axis.labelGap * shiftDir;\n\t\t\t\tlet baseLpos = round((axis._lpos + shiftAmt) * pxRatio);\n\n\t\t\t\tsetFontStyle(axis.labelFont[0], fillStyle, \"center\", side == 2 ? TOP : BOTTOM);\n\n\t\t\t\tctx.save();\n\n\t\t\t\tif (ori == 1) {\n\t\t\t\t\tx = y = 0;\n\n\t\t\t\t\tctx.translate(\n\t\t\t\t\t\tbaseLpos,\n\t\t\t\t\t\tround(plotTop + plotHgt / 2),\n\t\t\t\t\t);\n\t\t\t\t\tctx.rotate((side == 3 ? -PI : PI) / 2);\n\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tx = round(plotLft + plotWid / 2);\n\t\t\t\t\ty = baseLpos;\n\t\t\t\t}\n\n\t\t\t\tlet _label = isFn(axis.label) ? axis.label(self, i, _incr, _space) : axis.label;\n\n\t\t\t\tctx.fillText(_label, x, y);\n\n\t\t\t\tctx.restore();\n\t\t\t}\n\n\t\t\tif (_space == 0)\n\t\t\t\tcontinue;\n\n\t\t\tlet scale = scales[axis.scale];\n\n\t\t\tlet plotDim = ori == 0 ? plotWid : plotHgt;\n\t\t\tlet plotOff = ori == 0 ? plotLft : plotTop;\n\n\t\t\tlet _splits = axis._splits;\n\n\t\t\t// tick labels\n\t\t\t// BOO this assumes a specific data/series\n\t\t\tlet splits = scale.distr == 2 ? _splits.map(i => data0[i]) : _splits;\n\t\t\tlet incr = scale.distr == 2 ? data0[_splits[1]] - data0[_splits[0]] : _incr;\n\n\t\t\tlet ticks = axis.ticks;\n\t\t\tlet border = axis.border;\n\t\t\tlet _tickSize = ticks.show ? ticks.size : 0;\n\t\t\tlet tickSize = round(_tickSize * pxRatio);\n\t\t\tlet axisGap = round((axis.alignTo == 2 ? axis._size - _tickSize - axis.gap : axis.gap) * pxRatio);\n\n\t\t\t// rotating of labels only supported on bottom x axis\n\t\t\tlet angle = axis._rotate * -PI/180;\n\n\t\t\tlet basePos = pxRound(axis._pos * pxRatio);\n\t\t\tlet shiftAmt = (tickSize + axisGap) * shiftDir;\n\t\t\tlet finalPos = basePos + shiftAmt;\n\t\t\t y = ori == 0 ? finalPos : 0;\n\t\t\t x = ori == 1 ? finalPos : 0;\n\n\t\t\tlet font = axis.font[0];\n\t\t\tlet textAlign = axis.align == 1 ? LEFT :\n\t\t\t axis.align == 2 ? RIGHT :\n\t\t\t angle > 0 ? LEFT :\n\t\t\t angle < 0 ? RIGHT :\n\t\t\t ori == 0 ? \"center\" : side == 3 ? RIGHT : LEFT;\n\t\t\tlet textBaseline = angle ||\n\t\t\t ori == 1 ? \"middle\" : side == 2 ? TOP : BOTTOM;\n\n\t\t\tsetFontStyle(font, fillStyle, textAlign, textBaseline);\n\n\t\t\tlet lineHeight = axis.font[1] * axis.lineGap;\n\n\t\t\tlet canOffs = _splits.map(val => pxRound(getPos(val, scale, plotDim, plotOff)));\n\n\t\t\tlet _values = axis._values;\n\n\t\t\tfor (let i = 0; i < _values.length; i++) {\n\t\t\t\tlet val = _values[i];\n\n\t\t\t\tif (val != null) {\n\t\t\t\t\tif (ori == 0)\n\t\t\t\t\t\tx = canOffs[i];\n\t\t\t\t\telse\n\t\t\t\t\t\ty = canOffs[i];\n\n\t\t\t\t\tval = \"\" + val;\n\n\t\t\t\t\tlet _parts = val.indexOf(\"\\n\") == -1 ? [val] : val.split(/\\n/gm);\n\n\t\t\t\t\tfor (let j = 0; j < _parts.length; j++) {\n\t\t\t\t\t\tlet text = _parts[j];\n\n\t\t\t\t\t\tif (angle) {\n\t\t\t\t\t\t\tctx.save();\n\t\t\t\t\t\t\tctx.translate(x, y + j * lineHeight); // can this be replaced with position math?\n\t\t\t\t\t\t\tctx.rotate(angle); // can this be done once?\n\t\t\t\t\t\t\tctx.fillText(text, 0, 0);\n\t\t\t\t\t\t\tctx.restore();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tctx.fillText(text, x, y + j * lineHeight);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// ticks\n\t\t\tif (ticks.show) {\n\t\t\t\tdrawOrthoLines(\n\t\t\t\t\tcanOffs,\n\t\t\t\t\tticks.filter(self, splits, i, _space, incr),\n\t\t\t\t\tori,\n\t\t\t\t\tside,\n\t\t\t\t\tbasePos,\n\t\t\t\t\ttickSize,\n\t\t\t\t\troundDec(ticks.width * pxRatio, 3),\n\t\t\t\t\tticks.stroke(self, i),\n\t\t\t\t\tticks.dash,\n\t\t\t\t\tticks.cap,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// grid\n\t\t\tlet grid = axis.grid;\n\n\t\t\tif (grid.show) {\n\t\t\t\tdrawOrthoLines(\n\t\t\t\t\tcanOffs,\n\t\t\t\t\tgrid.filter(self, splits, i, _space, incr),\n\t\t\t\t\tori,\n\t\t\t\t\tori == 0 ? 2 : 1,\n\t\t\t\t\tori == 0 ? plotTop : plotLft,\n\t\t\t\t\tori == 0 ? plotHgt : plotWid,\n\t\t\t\t\troundDec(grid.width * pxRatio, 3),\n\t\t\t\t\tgrid.stroke(self, i),\n\t\t\t\t\tgrid.dash,\n\t\t\t\t\tgrid.cap,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (border.show) {\n\t\t\t\tdrawOrthoLines(\n\t\t\t\t\t[basePos],\n\t\t\t\t\t[1],\n\t\t\t\t\tori == 0 ? 1 : 0,\n\t\t\t\t\tori == 0 ? 1 : 2,\n\t\t\t\t\tori == 1 ? plotTop : plotLft,\n\t\t\t\t\tori == 1 ? plotHgt : plotWid,\n\t\t\t\t\troundDec(border.width * pxRatio, 3),\n\t\t\t\t\tborder.stroke(self, i),\n\t\t\t\t\tborder.dash,\n\t\t\t\t\tborder.cap,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tfire(\"drawAxes\");\n\t}\n\n\tfunction resetYSeries(minMax) {\n\t//\tlog(\"resetYSeries()\", arguments);\n\n\t\tseries.forEach((s, i) => {\n\t\t\tif (i > 0) {\n\t\t\t\ts._paths = null;\n\n\t\t\t\tif (minMax) {\n\t\t\t\t\tif (mode == 1) {\n\t\t\t\t\t\ts.min = null;\n\t\t\t\t\t\ts.max = null;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\ts.facets.forEach(f => {\n\t\t\t\t\t\t\tf.min = null;\n\t\t\t\t\t\t\tf.max = null;\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tlet queuedCommit = false;\n\tlet deferHooks = false;\n\tlet hooksQueue = [];\n\n\tfunction flushHooks() {\n\t\tdeferHooks = false;\n\n\t\tfor (let i = 0; i < hooksQueue.length; i++)\n\t\t\tfire(...hooksQueue[i]);\n\n\t\thooksQueue.length = 0;\n\t}\n\n\tfunction commit() {\n\t\tif (!queuedCommit) {\n\t\t\tmicroTask(_commit);\n\t\t\tqueuedCommit = true;\n\t\t}\n\t}\n\n\t// manual batching (aka immediate mode), skips microtask queue\n\tfunction batch(fn, _deferHooks = false) {\n\t\tqueuedCommit = true;\n\t\tdeferHooks = _deferHooks;\n\n\t\tfn(self);\n\t\t_commit();\n\n\t\tif (_deferHooks && hooksQueue.length > 0)\n\t\t\tqueueMicrotask(flushHooks);\n\t}\n\n\tself.batch = batch;\n\n\tfunction _commit() {\n\t//\tlog(\"_commit()\", arguments);\n\n\t\tif (shouldSetScales) {\n\t\t\tsetScales();\n\t\t\tshouldSetScales = false;\n\t\t}\n\n\t\tif (shouldConvergeSize) {\n\t\t\tconvergeSize();\n\t\t\tshouldConvergeSize = false;\n\t\t}\n\n\t\tif (shouldSetSize) {\n\t\t\tsetStylePx(under, LEFT, plotLftCss);\n\t\t\tsetStylePx(under, TOP, plotTopCss);\n\t\t\tsetStylePx(under, WIDTH, plotWidCss);\n\t\t\tsetStylePx(under, HEIGHT, plotHgtCss);\n\n\t\t\tsetStylePx(over, LEFT, plotLftCss);\n\t\t\tsetStylePx(over, TOP, plotTopCss);\n\t\t\tsetStylePx(over, WIDTH, plotWidCss);\n\t\t\tsetStylePx(over, HEIGHT, plotHgtCss);\n\n\t\t\tsetStylePx(wrap, WIDTH, fullWidCss);\n\t\t\tsetStylePx(wrap, HEIGHT, fullHgtCss);\n\n\t\t\t// NOTE: mutating this during print preview in Chrome forces transparent\n\t\t\t// canvas pixels to white, even when followed up with clearRect() below\n\t\t\tcan.width = round(fullWidCss * pxRatio);\n\t\t\tcan.height = round(fullHgtCss * pxRatio);\n\n\t\t\taxes.forEach(({ _el, _show, _size, _pos, side }) => {\n\t\t\t\tif (_el != null) {\n\t\t\t\t\tif (_show) {\n\t\t\t\t\t\tlet posOffset = (side === 3 || side === 0 ? _size : 0);\n\t\t\t\t\t\tlet isVt = side % 2 == 1;\n\n\t\t\t\t\t\tsetStylePx(_el, isVt ? \"left\" : \"top\", _pos - posOffset);\n\t\t\t\t\t\tsetStylePx(_el, isVt ? \"width\" : \"height\", _size);\n\t\t\t\t\t\tsetStylePx(_el, isVt ? \"top\" : \"left\", isVt ? plotTopCss : plotLftCss);\n\t\t\t\t\t\tsetStylePx(_el, isVt ? \"height\" : \"width\", isVt ? plotHgtCss : plotWidCss);\n\n\t\t\t\t\t\tremClass(_el, OFF);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\taddClass(_el, OFF);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// invalidate ctx style cache\n\t\t\tctxStroke = ctxFill = ctxWidth = ctxJoin = ctxCap = ctxFont = ctxAlign = ctxBaseline = ctxDash = null;\n\t\t\tctxAlpha = 1;\n\n\t\t\tsyncRect(true);\n\n\t\t\tif (\n\t\t\t\tplotLftCss != _plotLftCss ||\n\t\t\t\tplotTopCss != _plotTopCss ||\n\t\t\t\tplotWidCss != _plotWidCss ||\n\t\t\t\tplotHgtCss != _plotHgtCss\n\t\t\t) {\n\t\t\t\tresetYSeries(false);\n\n\t\t\t\tlet pctWid = plotWidCss / _plotWidCss;\n\t\t\t\tlet pctHgt = plotHgtCss / _plotHgtCss;\n\n\t\t\t\tif (showCursor && !shouldSetCursor && cursor.left >= 0) {\n\t\t\t\t\tcursor.left *= pctWid;\n\t\t\t\t\tcursor.top *= pctHgt;\n\n\t\t\t\t\tvCursor && elTrans(vCursor, round(cursor.left), 0, plotWidCss, plotHgtCss);\n\t\t\t\t\thCursor && elTrans(hCursor, 0, round(cursor.top), plotWidCss, plotHgtCss);\n\n\t\t\t\t\tfor (let i = 0; i < cursorPts.length; i++) {\n\t\t\t\t\t\tlet pt = cursorPts[i];\n\n\t\t\t\t\t\tif (pt != null) {\n\t\t\t\t\t\t\tcursorPtsLft[i] *= pctWid;\n\t\t\t\t\t\t\tcursorPtsTop[i] *= pctHgt;\n\t\t\t\t\t\t\telTrans(pt, ceil(cursorPtsLft[i]), ceil(cursorPtsTop[i]), plotWidCss, plotHgtCss);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (select.show && !shouldSetSelect && select.left >= 0 && select.width > 0) {\n\t\t\t\t\tselect.left *= pctWid;\n\t\t\t\t\tselect.width *= pctWid;\n\t\t\t\t\tselect.top *= pctHgt;\n\t\t\t\t\tselect.height *= pctHgt;\n\n\t\t\t\t\tfor (let prop in _hideProps)\n\t\t\t\t\t\tsetStylePx(selectDiv, prop, select[prop]);\n\t\t\t\t}\n\n\t\t\t\t_plotLftCss = plotLftCss;\n\t\t\t\t_plotTopCss = plotTopCss;\n\t\t\t\t_plotWidCss = plotWidCss;\n\t\t\t\t_plotHgtCss = plotHgtCss;\n\t\t\t}\n\n\t\t\tfire(\"setSize\");\n\n\t\t\tshouldSetSize = false;\n\t\t}\n\n\t\tif (fullWidCss > 0 && fullHgtCss > 0) {\n\t\t\tctx.clearRect(0, 0, can.width, can.height);\n\t\t\tfire(\"drawClear\");\n\t\t\tdrawOrder.forEach(fn => fn());\n\t\t\tfire(\"draw\");\n\t\t}\n\n\t\tif (select.show && shouldSetSelect) {\n\t\t\tsetSelect(select);\n\t\t\tshouldSetSelect = false;\n\t\t}\n\n\t\tif (showCursor && shouldSetCursor) {\n\t\t\tupdateCursor(null, true, false);\n\t\t\tshouldSetCursor = false;\n\t\t}\n\n\t\tif (legend.show && legend.live && shouldSetLegend) {\n\t\t\tsetLegend();\n\t\t\tshouldSetLegend = false; // redundant currently\n\t\t}\n\n\t\tif (!ready) {\n\t\t\tready = true;\n\t\t\tself.status = 1;\n\n\t\t\tfire(\"ready\");\n\t\t}\n\n\t\tviaAutoScaleX = false;\n\n\t\tqueuedCommit = false;\n\t}\n\n\tself.redraw = (rebuildPaths, recalcAxes) => {\n\t\tshouldConvergeSize = recalcAxes || false;\n\n\t\tif (rebuildPaths !== false)\n\t\t\t_setScale(xScaleKey, scaleX.min, scaleX.max);\n\t\telse\n\t\t\tcommit();\n\t};\n\n\t// redraw() => setScale('x', scales.x.min, scales.x.max);\n\n\t// explicit, never re-ranged (is this actually true? for x and y)\n\tfunction setScale(key, opts) {\n\t\tlet sc = scales[key];\n\n\t\tif (sc.from == null) {\n\t\t\tif (dataLen == 0) {\n\t\t\t\tlet minMax = sc.range(self, opts.min, opts.max, key);\n\t\t\t\topts.min = minMax[0];\n\t\t\t\topts.max = minMax[1];\n\t\t\t}\n\n\t\t\tif (opts.min > opts.max) {\n\t\t\t\tlet _min = opts.min;\n\t\t\t\topts.min = opts.max;\n\t\t\t\topts.max = _min;\n\t\t\t}\n\n\t\t\tif (dataLen > 1 && opts.min != null && opts.max != null && opts.max - opts.min < 1e-16)\n\t\t\t\treturn;\n\n\t\t\tif (key == xScaleKey) {\n\t\t\t\tif (sc.distr == 2 && dataLen > 0) {\n\t\t\t\t\topts.min = closestIdx(opts.min, data[0]);\n\t\t\t\t\topts.max = closestIdx(opts.max, data[0]);\n\n\t\t\t\t\tif (opts.min == opts.max)\n\t\t\t\t\t\topts.max++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t//\tlog(\"setScale()\", arguments);\n\n\t\t\tpendScales[key] = opts;\n\n\t\t\tshouldSetScales = true;\n\t\t\tcommit();\n\t\t}\n\t}\n\n\tself.setScale = setScale;\n\n//\tINTERACTION\n\n\tlet xCursor;\n\tlet yCursor;\n\tlet vCursor;\n\tlet hCursor;\n\n\t// starting position before cursor.move\n\tlet rawMouseLeft0;\n\tlet rawMouseTop0;\n\n\t// starting position\n\tlet mouseLeft0;\n\tlet mouseTop0;\n\n\t// current position before cursor.move\n\tlet rawMouseLeft1;\n\tlet rawMouseTop1;\n\n\t// current position\n\tlet mouseLeft1;\n\tlet mouseTop1;\n\n\tlet dragging = false;\n\n\tconst drag = cursor.drag;\n\n\tlet dragX = drag.x;\n\tlet dragY = drag.y;\n\n\tif (showCursor) {\n\t\tif (cursor.x)\n\t\t\txCursor = placeDiv(CURSOR_X, over);\n\t\tif (cursor.y)\n\t\t\tyCursor = placeDiv(CURSOR_Y, over);\n\n\t\tif (scaleX.ori == 0) {\n\t\t\tvCursor = xCursor;\n\t\t\thCursor = yCursor;\n\t\t}\n\t\telse {\n\t\t\tvCursor = yCursor;\n\t\t\thCursor = xCursor;\n\t\t}\n\n\t\tmouseLeft1 = cursor.left;\n\t\tmouseTop1 = cursor.top;\n\t}\n\n\tconst select = self.select = assign({\n\t\tshow: true,\n\t\tover: true,\n\t\tleft: 0,\n\t\twidth: 0,\n\t\ttop: 0,\n\t\theight: 0,\n\t}, opts.select);\n\n\tconst selectDiv = select.show ? placeDiv(SELECT, select.over ? over : under) : null;\n\n\tfunction setSelect(opts, _fire) {\n\t\tif (select.show) {\n\t\t\tfor (let prop in opts) {\n\t\t\t\tselect[prop] = opts[prop];\n\n\t\t\t\tif (prop in _hideProps)\n\t\t\t\t\tsetStylePx(selectDiv, prop, opts[prop]);\n\t\t\t}\n\n\t\t\t_fire !== false && fire(\"setSelect\");\n\t\t}\n\t}\n\n\tself.setSelect = setSelect;\n\n\tfunction toggleDOM(i) {\n\t\tlet s = series[i];\n\n\t\tif (s.show)\n\t\t\tshowLegend && remClass(legendRows[i], OFF);\n\t\telse {\n\t\t\tshowLegend && addClass(legendRows[i], OFF);\n\n\t\t\tif (showCursor) {\n\t\t\t\tlet pt = cursorOnePt ? cursorPts[0] : cursorPts[i];\n\t\t\t\tpt != null && elTrans(pt, -10, -10, plotWidCss, plotHgtCss);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction _setScale(key, min, max) {\n\t\tsetScale(key, {min, max});\n\t}\n\n\tfunction setSeries(i, opts, _fire, _pub) {\n\t//\tlog(\"setSeries()\", arguments);\n\n\t\tif (opts.focus != null)\n\t\t\tsetFocus(i);\n\n\t\tif (opts.show != null) {\n\t\t\tseries.forEach((s, si) => {\n\t\t\t\tif (si > 0 && (i == si || i == null)) {\n\t\t\t\t\ts.show = opts.show;\n\t\t\t\t\ttoggleDOM(si);\n\n\t\t\t\t\tif (mode == 2) {\n\t\t\t\t\t\t_setScale(s.facets[0].scale, null, null);\n\t\t\t\t\t\t_setScale(s.facets[1].scale, null, null);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\t_setScale(s.scale, null, null);\n\n\t\t\t\t\tcommit();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t_fire !== false && fire(\"setSeries\", i, opts);\n\n\t\t_pub && pubSync(\"setSeries\", self, i, opts);\n\t}\n\n\tself.setSeries = setSeries;\n\n\tfunction setBand(bi, opts) {\n\t\tassign(bands[bi], opts);\n\t}\n\n\tfunction addBand(opts, bi) {\n\t\topts.fill = fnOrSelf(opts.fill || null);\n\t\topts.dir = ifNull(opts.dir, -1);\n\t\tbi = bi == null ? bands.length : bi;\n\t\tbands.splice(bi, 0, opts);\n\t}\n\n\tfunction delBand(bi) {\n\t\tif (bi == null)\n\t\t\tbands.length = 0;\n\t\telse\n\t\t\tbands.splice(bi, 1);\n\t}\n\n\tself.addBand = addBand;\n\tself.setBand = setBand;\n\tself.delBand = delBand;\n\n\tfunction setAlpha(i, value) {\n\t\tseries[i].alpha = value;\n\n\t\tif (showCursor && cursorPts[i] != null)\n\t\t\tcursorPts[i].style.opacity = value;\n\n\t\tif (showLegend && legendRows[i])\n\t\t\tlegendRows[i].style.opacity = value;\n\t}\n\n\t// y-distance\n\tlet closestDist;\n\tlet closestSeries;\n\tlet focusedSeries;\n\tconst FOCUS_TRUE = {focus: true};\n\n\tfunction setFocus(i) {\n\t\tif (i != focusedSeries) {\n\t\t//\tlog(\"setFocus()\", arguments);\n\n\t\t\tlet allFocused = i == null;\n\n\t\t\tlet _setAlpha = focus.alpha != 1;\n\n\t\t\tseries.forEach((s, i2) => {\n\t\t\t\tif (mode == 1 || i2 > 0) {\n\t\t\t\t\tlet isFocused = allFocused || i2 == 0 || i2 == i;\n\t\t\t\t\ts._focus = allFocused ? null : isFocused;\n\t\t\t\t\t_setAlpha && setAlpha(i2, isFocused ? 1 : focus.alpha);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tfocusedSeries = i;\n\t\t\t_setAlpha && commit();\n\t\t}\n\t}\n\n\tif (showLegend && cursorFocus) {\n\t\tonMouse(mouseleave, legendTable, e => {\n\t\t\tif (cursor._lock)\n\t\t\t\treturn;\n\n\t\t\tsetCursorEvent(e);\n\n\t\t\tif (focusedSeries != null)\n\t\t\t\tsetSeries(null, FOCUS_TRUE, true, syncOpts.setSeries);\n\t\t});\n\t}\n\n\tfunction posToVal(pos, scale, can) {\n\t\tlet sc = scales[scale];\n\n\t\tif (can)\n\t\t\tpos = pos / pxRatio - (sc.ori == 1 ? plotTopCss : plotLftCss);\n\n\t\tlet dim = plotWidCss;\n\n\t\tif (sc.ori == 1) {\n\t\t\tdim = plotHgtCss;\n\t\t\tpos = dim - pos;\n\t\t}\n\n\t\tif (sc.dir == -1)\n\t\t\tpos = dim - pos;\n\n\t\tlet _min = sc._min,\n\t\t\t_max = sc._max,\n\t\t\tpct = pos / dim;\n\n\t\tlet sv = _min + (_max - _min) * pct;\n\n\t\tlet distr = sc.distr;\n\n\t\treturn (\n\t\t\tdistr == 3 ? pow(10, sv) :\n\t\t\tdistr == 4 ? sinh(sv, sc.asinh) :\n\t\t\tdistr == 100 ? sc.bwd(sv) :\n\t\t\tsv\n\t\t);\n\t}\n\n\tfunction closestIdxFromXpos(pos, can) {\n\t\tlet v = posToVal(pos, xScaleKey, can);\n\t\treturn closestIdx(v, data[0], i0, i1);\n\t}\n\n\tself.valToIdx = val => closestIdx(val, data[0]);\n\tself.posToIdx = closestIdxFromXpos;\n\tself.posToVal = posToVal;\n\tself.valToPos = (val, scale, can) => (\n\t\tscales[scale].ori == 0 ?\n\t\tgetHPos(val, scales[scale],\n\t\t\tcan ? plotWid : plotWidCss,\n\t\t\tcan ? plotLft : 0,\n\t\t) :\n\t\tgetVPos(val, scales[scale],\n\t\t\tcan ? plotHgt : plotHgtCss,\n\t\t\tcan ? plotTop : 0,\n\t\t)\n\t);\n\n\tself.setCursor = (opts, _fire, _pub) => {\n\t\tmouseLeft1 = opts.left;\n\t\tmouseTop1 = opts.top;\n\t//\tassign(cursor, opts);\n\t\tupdateCursor(null, _fire, _pub);\n\t};\n\n\tfunction setSelH(off, dim) {\n\t\tsetStylePx(selectDiv, LEFT, select.left = off);\n\t\tsetStylePx(selectDiv, WIDTH, select.width = dim);\n\t}\n\n\tfunction setSelV(off, dim) {\n\t\tsetStylePx(selectDiv, TOP, select.top = off);\n\t\tsetStylePx(selectDiv, HEIGHT, select.height = dim);\n\t}\n\n\tlet setSelX = scaleX.ori == 0 ? setSelH : setSelV;\n\tlet setSelY = scaleX.ori == 1 ? setSelH : setSelV;\n\n\tfunction syncLegend() {\n\t\tif (showLegend && legend.live) {\n\t\t\tfor (let i = mode == 2 ? 1 : 0; i < series.length; i++) {\n\t\t\t\tif (i == 0 && multiValLegend)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tlet vals = legend.values[i];\n\n\t\t\t\tlet j = 0;\n\n\t\t\t\tfor (let k in vals)\n\t\t\t\t\tlegendCells[i][j++].firstChild.nodeValue = vals[k];\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction setLegend(opts, _fire) {\n\t\tif (opts != null) {\n\t\t\tif (opts.idxs) {\n\t\t\t\topts.idxs.forEach((didx, sidx) => {\n\t\t\t\t\tactiveIdxs[sidx] = didx;\n\t\t\t\t});\n\t\t\t}\n\t\t\telse if (!isUndef(opts.idx))\n\t\t\t\tactiveIdxs.fill(opts.idx);\n\n\t\t\tlegend.idx = activeIdxs[0];\n\t\t}\n\n\t\tif (showLegend && legend.live) {\n\t\t\tfor (let sidx = 0; sidx < series.length; sidx++) {\n\t\t\t\tif (sidx > 0 || mode == 1 && !multiValLegend)\n\t\t\t\t\tsetLegendValues(sidx, activeIdxs[sidx]);\n\t\t\t}\n\n\t\t\tsyncLegend();\n\t\t}\n\n\t\tshouldSetLegend = false;\n\n\t\t_fire !== false && fire(\"setLegend\");\n\t}\n\n\tself.setLegend = setLegend;\n\n\tfunction setLegendValues(sidx, idx) {\n\t\tlet s = series[sidx];\n\t\tlet src = sidx == 0 && xScaleDistr == 2 ? data0 : data[sidx];\n\t\tlet val;\n\n\t\tif (multiValLegend)\n\t\t\tval = s.values(self, sidx, idx) ?? NULL_LEGEND_VALUES;\n\t\telse {\n\t\t\tval = s.value(self, idx == null ? null : src[idx], sidx, idx);\n\t\t\tval = val == null ? NULL_LEGEND_VALUES : {_: val};\n\t\t}\n\n\t\tlegend.values[sidx] = val;\n\t}\n\n\tfunction updateCursor(src, _fire, _pub) {\n\t//\tts == null && log(\"updateCursor()\", arguments);\n\n\t\trawMouseLeft1 = mouseLeft1;\n\t\trawMouseTop1 = mouseTop1;\n\n\t\t[mouseLeft1, mouseTop1] = cursor.move(self, mouseLeft1, mouseTop1);\n\n\t\tcursor.left = mouseLeft1;\n\t\tcursor.top = mouseTop1;\n\n\t\tif (showCursor) {\n\t\t\tvCursor && elTrans(vCursor, round(mouseLeft1), 0, plotWidCss, plotHgtCss);\n\t\t\thCursor && elTrans(hCursor, 0, round(mouseTop1), plotWidCss, plotHgtCss);\n\t\t}\n\n\t\tlet idx;\n\n\t\t// when zooming to an x scale range between datapoints the binary search\n\t\t// for nearest min/max indices results in this condition. cheap hack :D\n\t\tlet noDataInRange = i0 > i1; // works for mode 1 only\n\n\t\tclosestDist = inf;\n\t\tclosestSeries = null;\n\n\t\t// TODO: extract\n\t\tlet xDim = scaleX.ori == 0 ? plotWidCss : plotHgtCss;\n\t\tlet yDim = scaleX.ori == 1 ? plotWidCss : plotHgtCss;\n\n\t\t// if cursor hidden, hide points & clear legend vals\n\t\tif (mouseLeft1 < 0 || dataLen == 0 || noDataInRange) {\n\t\t\tidx = cursor.idx = null;\n\n\t\t\tfor (let i = 0; i < series.length; i++) {\n\t\t\t\tlet pt = cursorPts[i];\n\t\t\t\tpt != null && elTrans(pt, -10, -10, plotWidCss, plotHgtCss);\n\t\t\t}\n\n\t\t\tif (cursorFocus)\n\t\t\t\tsetSeries(null, FOCUS_TRUE, true, src == null && syncOpts.setSeries);\n\n\t\t\tif (legend.live) {\n\t\t\t\tactiveIdxs.fill(idx);\n\t\t\t\tshouldSetLegend = true;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t//\tlet pctY = 1 - (y / rect.height);\n\n\t\t\tlet mouseXPos, valAtPosX, xPos;\n\n\t\t\tif (mode == 1) {\n\t\t\t\tmouseXPos = scaleX.ori == 0 ? mouseLeft1 : mouseTop1;\n\t\t\t\tvalAtPosX = posToVal(mouseXPos, xScaleKey);\n\t\t\t\tidx = cursor.idx = closestIdx(valAtPosX, data[0], i0, i1);\n\t\t\t\txPos = valToPosX(data[0][idx], scaleX, xDim, 0);\n\t\t\t}\n\n\t\t\t// closest pt values\n\t\t\tlet _ptLft = -10;\n\t\t\tlet _ptTop = -10;\n\t\t\tlet _ptWid = 0;\n\t\t\tlet _ptHgt = 0;\n\t\t\tlet _centered = true;\n\t\t\tlet _ptFill = '';\n\t\t\tlet _ptStroke = '';\n\n\t\t\tfor (let i = mode == 2 ? 1 : 0; i < series.length; i++) {\n\t\t\t\tlet s = series[i];\n\n\t\t\t\tlet idx1 = activeIdxs[i];\n\t\t\t\tlet yVal1 = idx1 == null ? null : (mode == 1 ? data[i][idx1] : data[i][1][idx1]);\n\n\t\t\t\tlet idx2 = cursor.dataIdx(self, i, idx, valAtPosX);\n\t\t\t\tlet yVal2 = idx2 == null ? null : (mode == 1 ? data[i][idx2] : data[i][1][idx2]);\n\n\t\t\t\tshouldSetLegend = shouldSetLegend || yVal2 != yVal1 || idx2 != idx1;\n\n\t\t\t\tactiveIdxs[i] = idx2;\n\n\t\t\t\tif (i > 0 && s.show) {\n\t\t\t\t\tlet xPos2 = idx2 == null ? -10 : idx2 == idx ? xPos : valToPosX(mode == 1 ? data[0][idx2] : data[i][0][idx2], scaleX, xDim, 0);\n\n\t\t\t\t\t// this doesnt really work for state timeline, heatmap, status history (where the value maps to color, not y coords)\n\t\t\t\t\tlet yPos = yVal2 == null ? -10 : valToPosY(yVal2, mode == 1 ? scales[s.scale] : scales[s.facets[1].scale], yDim, 0);\n\n\t\t\t\t\tif (cursorFocus && yVal2 != null) {\n\t\t\t\t\t\tlet mouseYPos = scaleX.ori == 1 ? mouseLeft1 : mouseTop1;\n\t\t\t\t\t\tlet dist = abs(focus.dist(self, i, idx2, yPos, mouseYPos));\n\n\t\t\t\t\t\tif (dist < closestDist) {\n\t\t\t\t\t\t\tlet bias = focus.bias;\n\n\t\t\t\t\t\t\tif (bias != 0) {\n\t\t\t\t\t\t\t\tlet mouseYVal = posToVal(mouseYPos, s.scale);\n\n\t\t\t\t\t\t\t\tlet seriesYValSign = yVal2 >= 0 ? 1 : -1;\n\t\t\t\t\t\t\t\tlet mouseYValSign = mouseYVal >= 0 ? 1 : -1;\n\n\t\t\t\t\t\t\t\t// with a focus bias, we will never cross zero when prox testing\n\t\t\t\t\t\t\t\t// it's either closest towards zero, or closest away from zero\n\t\t\t\t\t\t\t\tif (mouseYValSign == seriesYValSign && (\n\t\t\t\t\t\t\t\t\tmouseYValSign == 1 ?\n\t\t\t\t\t\t\t\t\t\t(bias == 1 ? yVal2 >= mouseYVal : yVal2 <= mouseYVal) : // >= 0\n\t\t\t\t\t\t\t\t\t\t(bias == 1 ? yVal2 <= mouseYVal : yVal2 >= mouseYVal) // < 0\n\t\t\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\t\t\tclosestDist = dist;\n\t\t\t\t\t\t\t\t\tclosestSeries = i;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tclosestDist = dist;\n\t\t\t\t\t\t\t\tclosestSeries = i;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shouldSetLegend || cursorOnePt) {\n\t\t\t\t\t\tlet hPos, vPos;\n\n\t\t\t\t\t\tif (scaleX.ori == 0) {\n\t\t\t\t\t\t\thPos = xPos2;\n\t\t\t\t\t\t\tvPos = yPos;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\thPos = yPos;\n\t\t\t\t\t\t\tvPos = xPos2;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet ptWid, ptHgt, ptLft, ptTop,\n\t\t\t\t\t\t\tptStroke, ptFill,\n\t\t\t\t\t\t\tcentered = true,\n\t\t\t\t\t\t\tgetBBox = points.bbox;\n\n\t\t\t\t\t\tif (getBBox != null) {\n\t\t\t\t\t\t\tcentered = false;\n\n\t\t\t\t\t\t\tlet bbox = getBBox(self, i);\n\n\t\t\t\t\t\t\tptLft = bbox.left;\n\t\t\t\t\t\t\tptTop = bbox.top;\n\t\t\t\t\t\t\tptWid = bbox.width;\n\t\t\t\t\t\t\tptHgt = bbox.height;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tptLft = hPos;\n\t\t\t\t\t\t\tptTop = vPos;\n\t\t\t\t\t\t\tptWid = ptHgt = points.size(self, i);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tptFill = points.fill(self, i);\n\t\t\t\t\t\tptStroke = points.stroke(self, i);\n\n\t\t\t\t\t\tif (cursorOnePt) {\n\t\t\t\t\t\t\tif (i == closestSeries && closestDist <= focus.prox) {\n\t\t\t\t\t\t\t\t_ptLft = ptLft;\n\t\t\t\t\t\t\t\t_ptTop = ptTop;\n\t\t\t\t\t\t\t\t_ptWid = ptWid;\n\t\t\t\t\t\t\t\t_ptHgt = ptHgt;\n\t\t\t\t\t\t\t\t_centered = centered;\n\t\t\t\t\t\t\t\t_ptFill = ptFill;\n\t\t\t\t\t\t\t\t_ptStroke = ptStroke;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tlet pt = cursorPts[i];\n\n\t\t\t\t\t\t\tif (pt != null) {\n\t\t\t\t\t\t\t\tcursorPtsLft[i] = ptLft;\n\t\t\t\t\t\t\t\tcursorPtsTop[i] = ptTop;\n\n\t\t\t\t\t\t\t\telSize(pt, ptWid, ptHgt, centered);\n\t\t\t\t\t\t\t\telColor(pt, ptFill, ptStroke);\n\t\t\t\t\t\t\t\telTrans(pt, ceil(ptLft), ceil(ptTop), plotWidCss, plotHgtCss);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if only using single hover point (at cursorPts[0])\n\t\t\t// we have trigger styling at last visible series (once closestSeries is settled)\n\t\t\tif (cursorOnePt) {\n\t\t\t\t// some of this logic is similar to series focus below, since it matches the behavior by design\n\n\t\t\t\tlet p = focus.prox;\n\n\t\t\t\tlet focusChanged = focusedSeries == null ? closestDist <= p : (closestDist > p || closestSeries != focusedSeries);\n\n\t\t\t\tif (shouldSetLegend || focusChanged) {\n\t\t\t\t\tlet pt = cursorPts[0];\n\n\t\t\t\t\tif (pt != null) {\n\t\t\t\t\t\tcursorPtsLft[0] = _ptLft;\n\t\t\t\t\t\tcursorPtsTop[0] = _ptTop;\n\n\t\t\t\t\t\telSize(pt, _ptWid, _ptHgt, _centered);\n\t\t\t\t\t\telColor(pt, _ptFill, _ptStroke);\n\t\t\t\t\t\telTrans(pt, ceil(_ptLft), ceil(_ptTop), plotWidCss, plotHgtCss);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// nit: cursor.drag.setSelect is assumed always true\n\t\tif (select.show && dragging) {\n\t\t\tif (src != null) {\n\t\t\t\tlet [xKey, yKey] = syncOpts.scales;\n\t\t\t\tlet [matchXKeys, matchYKeys] = syncOpts.match;\n\t\t\t\tlet [xKeySrc, yKeySrc] = src.cursor.sync.scales;\n\n\t\t\t\t// match the dragX/dragY implicitness/explicitness of src\n\t\t\t\tlet sdrag = src.cursor.drag;\n\t\t\t\tdragX = sdrag._x;\n\t\t\t\tdragY = sdrag._y;\n\n\t\t\t\tif (dragX || dragY) {\n\t\t\t\t\tlet { left, top, width, height } = src.select;\n\n\t\t\t\t\tlet sori = src.scales[xKeySrc].ori;\n\t\t\t\t\tlet sPosToVal = src.posToVal;\n\n\t\t\t\t\tlet sOff, sDim, sc, a, b;\n\n\t\t\t\t\tlet matchingX = xKey != null && matchXKeys(xKey, xKeySrc);\n\t\t\t\t\tlet matchingY = yKey != null && matchYKeys(yKey, yKeySrc);\n\n\t\t\t\t\tif (matchingX && dragX) {\n\t\t\t\t\t\tif (sori == 0) {\n\t\t\t\t\t\t\tsOff = left;\n\t\t\t\t\t\t\tsDim = width;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsOff = top;\n\t\t\t\t\t\t\tsDim = height;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsc = scales[xKey];\n\n\t\t\t\t\t\ta = valToPosX(sPosToVal(sOff, xKeySrc), sc, xDim, 0);\n\t\t\t\t\t\tb = valToPosX(sPosToVal(sOff + sDim, xKeySrc), sc, xDim, 0);\n\n\t\t\t\t\t\tsetSelX(min(a,b), abs(b-a));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tsetSelX(0, xDim);\n\n\t\t\t\t\tif (matchingY && dragY) {\n\t\t\t\t\t\tif (sori == 1) {\n\t\t\t\t\t\t\tsOff = left;\n\t\t\t\t\t\t\tsDim = width;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsOff = top;\n\t\t\t\t\t\t\tsDim = height;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsc = scales[yKey];\n\n\t\t\t\t\t\ta = valToPosY(sPosToVal(sOff, yKeySrc), sc, yDim, 0);\n\t\t\t\t\t\tb = valToPosY(sPosToVal(sOff + sDim, yKeySrc), sc, yDim, 0);\n\n\t\t\t\t\t\tsetSelY(min(a,b), abs(b-a));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tsetSelY(0, yDim);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thideSelect();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlet rawDX = abs(rawMouseLeft1 - rawMouseLeft0);\n\t\t\t\tlet rawDY = abs(rawMouseTop1 - rawMouseTop0);\n\n\t\t\t\tif (scaleX.ori == 1) {\n\t\t\t\t\tlet _rawDX = rawDX;\n\t\t\t\t\trawDX = rawDY;\n\t\t\t\t\trawDY = _rawDX;\n\t\t\t\t}\n\n\t\t\t\tdragX = drag.x && rawDX >= drag.dist;\n\t\t\t\tdragY = drag.y && rawDY >= drag.dist;\n\n\t\t\t\tlet uni = drag.uni;\n\n\t\t\t\tif (uni != null) {\n\t\t\t\t\t// only calc drag status if they pass the dist thresh\n\t\t\t\t\tif (dragX && dragY) {\n\t\t\t\t\t\tdragX = rawDX >= uni;\n\t\t\t\t\t\tdragY = rawDY >= uni;\n\n\t\t\t\t\t\t// force unidirectionality when both are under uni limit\n\t\t\t\t\t\tif (!dragX && !dragY) {\n\t\t\t\t\t\t\tif (rawDY > rawDX)\n\t\t\t\t\t\t\t\tdragY = true;\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tdragX = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (drag.x && drag.y && (dragX || dragY))\n\t\t\t\t\t// if omni with no uni then both dragX / dragY should be true if either is true\n\t\t\t\t\tdragX = dragY = true;\n\n\t\t\t\tlet p0, p1;\n\n\t\t\t\tif (dragX) {\n\t\t\t\t\tif (scaleX.ori == 0) {\n\t\t\t\t\t\tp0 = mouseLeft0;\n\t\t\t\t\t\tp1 = mouseLeft1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tp0 = mouseTop0;\n\t\t\t\t\t\tp1 = mouseTop1;\n\t\t\t\t\t}\n\n\t\t\t\t\tsetSelX(min(p0, p1), abs(p1 - p0));\n\n\t\t\t\t\tif (!dragY)\n\t\t\t\t\t\tsetSelY(0, yDim);\n\t\t\t\t}\n\n\t\t\t\tif (dragY) {\n\t\t\t\t\tif (scaleX.ori == 1) {\n\t\t\t\t\t\tp0 = mouseLeft0;\n\t\t\t\t\t\tp1 = mouseLeft1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tp0 = mouseTop0;\n\t\t\t\t\t\tp1 = mouseTop1;\n\t\t\t\t\t}\n\n\t\t\t\t\tsetSelY(min(p0, p1), abs(p1 - p0));\n\n\t\t\t\t\tif (!dragX)\n\t\t\t\t\t\tsetSelX(0, xDim);\n\t\t\t\t}\n\n\t\t\t\t// the drag didn't pass the dist requirement\n\t\t\t\tif (!dragX && !dragY) {\n\t\t\t\t\tsetSelX(0, 0);\n\t\t\t\t\tsetSelY(0, 0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdrag._x = dragX;\n\t\tdrag._y = dragY;\n\n\t\tif (src == null) {\n\t\t\tif (_pub) {\n\t\t\t\tif (syncKey != null) {\n\t\t\t\t\tlet [xSyncKey, ySyncKey] = syncOpts.scales;\n\n\t\t\t\t\tsyncOpts.values[0] = xSyncKey != null ? posToVal(scaleX.ori == 0 ? mouseLeft1 : mouseTop1, xSyncKey) : null;\n\t\t\t\t\tsyncOpts.values[1] = ySyncKey != null ? posToVal(scaleX.ori == 1 ? mouseLeft1 : mouseTop1, ySyncKey) : null;\n\t\t\t\t}\n\n\t\t\t\tpubSync(mousemove, self, mouseLeft1, mouseTop1, plotWidCss, plotHgtCss, idx);\n\t\t\t}\n\n\t\t\tif (cursorFocus) {\n\t\t\t\tlet shouldPub = _pub && syncOpts.setSeries;\n\t\t\t\tlet p = focus.prox;\n\n\t\t\t\tif (focusedSeries == null) {\n\t\t\t\t\tif (closestDist <= p)\n\t\t\t\t\t\tsetSeries(closestSeries, FOCUS_TRUE, true, shouldPub);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (closestDist > p)\n\t\t\t\t\t\tsetSeries(null, FOCUS_TRUE, true, shouldPub);\n\t\t\t\t\telse if (closestSeries != focusedSeries)\n\t\t\t\t\t\tsetSeries(closestSeries, FOCUS_TRUE, true, shouldPub);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (shouldSetLegend) {\n\t\t\tlegend.idx = idx;\n\t\t\tsetLegend();\n\t\t}\n\n\t\t_fire !== false && fire(\"setCursor\");\n\t}\n\n\tlet rect = null;\n\n\tObject.defineProperty(self, 'rect', {\n\t\tget() {\n\t\t\tif (rect == null)\n\t\t\t\tsyncRect(false);\n\n\t\t\treturn rect;\n\t\t},\n\t});\n\n\tfunction syncRect(defer = false) {\n\t\tif (defer)\n\t\t\trect = null;\n\t\telse {\n\t\t\trect = over.getBoundingClientRect();\n\t\t\tfire(\"syncRect\", rect);\n\t\t}\n\t}\n\n\tfunction mouseMove(e, src, _l, _t, _w, _h, _i) {\n\t\tif (cursor._lock)\n\t\t\treturn;\n\n\t\t// Chrome on Windows has a bug which triggers a stray mousemove event after an initial mousedown event\n\t\t// when clicking into a plot as part of re-focusing the browser window.\n\t\t// we gotta ignore it to avoid triggering a phantom drag / setSelect\n\t\t// However, on touch-only devices Chrome-based browsers trigger a 0-distance mousemove before mousedown\n\t\t// so we don't ignore it when mousedown has set the dragging flag\n\t\tif (dragging && e != null && e.movementX == 0 && e.movementY == 0)\n\t\t\treturn;\n\n\t\tcacheMouse(e, src, _l, _t, _w, _h, _i, false, e != null);\n\n\t\tif (e != null)\n\t\t\tupdateCursor(null, true, true);\n\t\telse\n\t\t\tupdateCursor(src, true, false);\n\t}\n\n\tfunction cacheMouse(e, src, _l, _t, _w, _h, _i, initial, snap) {\n\t\tif (rect == null)\n\t\t\tsyncRect(false);\n\n\t\tsetCursorEvent(e);\n\n\t\tif (e != null) {\n\t\t\t_l = e.clientX - rect.left;\n\t\t\t_t = e.clientY - rect.top;\n\t\t}\n\t\telse {\n\t\t\tif (_l < 0 || _t < 0) {\n\t\t\t\tmouseLeft1 = -10;\n\t\t\t\tmouseTop1 = -10;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet [xKey, yKey] = syncOpts.scales;\n\n\t\t\tlet syncOptsSrc = src.cursor.sync;\n\t\t\tlet [xValSrc, yValSrc] = syncOptsSrc.values;\n\t\t\tlet [xKeySrc, yKeySrc] = syncOptsSrc.scales;\n\t\t\tlet [matchXKeys, matchYKeys] = syncOpts.match;\n\n\t\t\tlet rotSrc = src.axes[0].side % 2 == 1;\n\n\t\t\tlet xDim = scaleX.ori == 0 ? plotWidCss : plotHgtCss,\n\t\t\t\tyDim = scaleX.ori == 1 ? plotWidCss : plotHgtCss,\n\t\t\t\t_xDim = rotSrc ? _h : _w,\n\t\t\t\t_yDim = rotSrc ? _w : _h,\n\t\t\t\t_xPos = rotSrc ? _t : _l,\n\t\t\t\t_yPos = rotSrc ? _l : _t;\n\n\t\t\tif (xKeySrc != null)\n\t\t\t\t_l = matchXKeys(xKey, xKeySrc) ? getPos(xValSrc, scales[xKey], xDim, 0) : -10;\n\t\t\telse\n\t\t\t\t_l = xDim * (_xPos/_xDim);\n\n\t\t\tif (yKeySrc != null)\n\t\t\t\t_t = matchYKeys(yKey, yKeySrc) ? getPos(yValSrc, scales[yKey], yDim, 0) : -10;\n\t\t\telse\n\t\t\t\t_t = yDim * (_yPos/_yDim);\n\n\t\t\tif (scaleX.ori == 1) {\n\t\t\t\tlet __l = _l;\n\t\t\t\t_l = _t;\n\t\t\t\t_t = __l;\n\t\t\t}\n\t\t}\n\n\t\tif (snap && (src == null || src.cursor.event.type == mousemove)) {\n\t\t\tif (_l <= 1 || _l >= plotWidCss - 1)\n\t\t\t\t_l = incrRound(_l, plotWidCss);\n\n\t\t\tif (_t <= 1 || _t >= plotHgtCss - 1)\n\t\t\t\t_t = incrRound(_t, plotHgtCss);\n\t\t}\n\n\t\tif (initial) {\n\t\t\trawMouseLeft0 = _l;\n\t\t\trawMouseTop0 = _t;\n\n\t\t\t[mouseLeft0, mouseTop0] = cursor.move(self, _l, _t);\n\t\t}\n\t\telse {\n\t\t\tmouseLeft1 = _l;\n\t\t\tmouseTop1 = _t;\n\t\t}\n\t}\n\n\tconst _hideProps = {\n\t\twidth: 0,\n\t\theight: 0,\n\t\tleft: 0,\n\t\ttop: 0,\n\t};\n\n\tfunction hideSelect() {\n\t\tsetSelect(_hideProps, false);\n\t}\n\n\tlet downSelectLeft;\n\tlet downSelectTop;\n\tlet downSelectWidth;\n\tlet downSelectHeight;\n\n\tfunction mouseDown(e, src, _l, _t, _w, _h, _i) {\n\t\tdragging = true;\n\t\tdragX = dragY = drag._x = drag._y = false;\n\n\t\tcacheMouse(e, src, _l, _t, _w, _h, _i, true, false);\n\n\t\tif (e != null) {\n\t\t\tonMouse(mouseup, doc, mouseUp, false);\n\t\t\tpubSync(mousedown, self, mouseLeft0, mouseTop0, plotWidCss, plotHgtCss, null);\n\t\t}\n\n\t\tlet { left, top, width, height } = select;\n\n\t\tdownSelectLeft = left;\n\t\tdownSelectTop = top;\n\t\tdownSelectWidth = width;\n\t\tdownSelectHeight = height;\n\n\t//\thideSelect();\n\t}\n\n\tfunction mouseUp(e, src, _l, _t, _w, _h, _i) {\n\t\tdragging = drag._x = drag._y = false;\n\n\t\tcacheMouse(e, src, _l, _t, _w, _h, _i, false, true);\n\n\t\tlet { left, top, width, height } = select;\n\n\t\tlet hasSelect = width > 0 || height > 0;\n\t\tlet chgSelect = (\n\t\t\tdownSelectLeft != left ||\n\t\t\tdownSelectTop != top ||\n\t\t\tdownSelectWidth != width ||\n\t\t\tdownSelectHeight != height\n\t\t);\n\n\t\thasSelect && chgSelect && setSelect(select);\n\n\t\tif (drag.setScale && hasSelect && chgSelect) {\n\t\t//\tif (syncKey != null) {\n\t\t//\t\tdragX = drag.x;\n\t\t//\t\tdragY = drag.y;\n\t\t//\t}\n\n\t\t\tlet xOff = left,\n\t\t\t\txDim = width,\n\t\t\t\tyOff = top,\n\t\t\t\tyDim = height;\n\n\t\t\tif (scaleX.ori == 1) {\n\t\t\t\txOff = top,\n\t\t\t\txDim = height,\n\t\t\t\tyOff = left,\n\t\t\t\tyDim = width;\n\t\t\t}\n\n\t\t\tif (dragX) {\n\t\t\t\t_setScale(xScaleKey,\n\t\t\t\t\tposToVal(xOff, xScaleKey),\n\t\t\t\t\tposToVal(xOff + xDim, xScaleKey)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (dragY) {\n\t\t\t\tfor (let k in scales) {\n\t\t\t\t\tlet sc = scales[k];\n\n\t\t\t\t\tif (k != xScaleKey && sc.from == null && sc.min != inf) {\n\t\t\t\t\t\t_setScale(k,\n\t\t\t\t\t\t\tposToVal(yOff + yDim, k),\n\t\t\t\t\t\t\tposToVal(yOff, k)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\thideSelect();\n\t\t}\n\t\telse if (cursor.lock) {\n\t\t\tcursor._lock = !cursor._lock;\n\t\t\tupdateCursor(src, true, e != null);\n\t\t}\n\n\t\tif (e != null) {\n\t\t\toffMouse(mouseup, doc);\n\t\t\tpubSync(mouseup, self, mouseLeft1, mouseTop1, plotWidCss, plotHgtCss, null);\n\t\t}\n\t}\n\n\tfunction mouseLeave(e, src, _l, _t, _w, _h, _i) {\n\t\tif (cursor._lock)\n\t\t\treturn;\n\n\t\tsetCursorEvent(e);\n\n\t\tlet _dragging = dragging;\n\n\t\tif (dragging) {\n\t\t\t// handle case when mousemove aren't fired all the way to edges by browser\n\t\t\tlet snapH = true;\n\t\t\tlet snapV = true;\n\t\t\tlet snapProx = 10;\n\n\t\t\tlet dragH, dragV;\n\n\t\t\tif (scaleX.ori == 0) {\n\t\t\t\tdragH = dragX;\n\t\t\t\tdragV = dragY;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdragH = dragY;\n\t\t\t\tdragV = dragX;\n\t\t\t}\n\n\t\t\tif (dragH && dragV) {\n\t\t\t\t// maybe omni corner snap\n\t\t\t\tsnapH = mouseLeft1 <= snapProx || mouseLeft1 >= plotWidCss - snapProx;\n\t\t\t\tsnapV = mouseTop1 <= snapProx || mouseTop1 >= plotHgtCss - snapProx;\n\t\t\t}\n\n\t\t\tif (dragH && snapH)\n\t\t\t\tmouseLeft1 = mouseLeft1 < mouseLeft0 ? 0 : plotWidCss;\n\n\t\t\tif (dragV && snapV)\n\t\t\t\tmouseTop1 = mouseTop1 < mouseTop0 ? 0 : plotHgtCss;\n\n\t\t\tupdateCursor(null, true, true);\n\n\t\t\tdragging = false;\n\t\t}\n\n\t\tmouseLeft1 = -10;\n\t\tmouseTop1 = -10;\n\n\t\tactiveIdxs.fill(null);\n\n\t\t// passing a non-null timestamp to force sync/mousemove event\n\t\tupdateCursor(null, true, true);\n\n\t\tif (_dragging)\n\t\t\tdragging = _dragging;\n\t}\n\n\tfunction dblClick(e, src, _l, _t, _w, _h, _i) {\n\t\tif (cursor._lock)\n\t\t\treturn;\n\n\t\tsetCursorEvent(e);\n\n\t\tautoScaleX();\n\n\t\thideSelect();\n\n\t\tif (e != null)\n\t\t\tpubSync(dblclick, self, mouseLeft1, mouseTop1, plotWidCss, plotHgtCss, null);\n\t}\n\n\tfunction syncPxRatio() {\n\t\taxes.forEach(syncFontSize);\n\t\t_setSize(self.width, self.height, true);\n\t}\n\n\ton(dppxchange, win, syncPxRatio);\n\n\t// internal pub/sub\n\tconst events = {};\n\n\tevents.mousedown = mouseDown;\n\tevents.mousemove = mouseMove;\n\tevents.mouseup = mouseUp;\n\tevents.dblclick = dblClick;\n\tevents[\"setSeries\"] = (e, src, idx, opts) => {\n\t\tlet seriesIdxMatcher = syncOpts.match[2];\n\t\tidx = seriesIdxMatcher(self, src, idx);\n\t\tidx != -1 && setSeries(idx, opts, true, false);\n\t};\n\n\tif (showCursor) {\n\t\tonMouse(mousedown, over, mouseDown);\n\t\tonMouse(mousemove, over, mouseMove);\n\t\tonMouse(mouseenter, over, e => {\n\t\t\tsetCursorEvent(e);\n\t\t\tsyncRect(false);\n\t\t});\n\t\tonMouse(mouseleave, over, mouseLeave);\n\n\t\tonMouse(dblclick, over, dblClick);\n\n\t\tcursorPlots.add(self);\n\n\t\tself.syncRect = syncRect;\n\t}\n\n\t// external on/off\n\tconst hooks = self.hooks = opts.hooks || {};\n\n\tfunction fire(evName, a1, a2) {\n\t\tif (deferHooks)\n\t\t\thooksQueue.push([evName, a1, a2]);\n\t\telse {\n\t\t\tif (evName in hooks) {\n\t\t\t\thooks[evName].forEach(fn => {\n\t\t\t\t\tfn.call(null, self, a1, a2);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t(opts.plugins || []).forEach(p => {\n\t\tfor (let evName in p.hooks)\n\t\t\thooks[evName] = (hooks[evName] || []).concat(p.hooks[evName]);\n\t});\n\n\tconst seriesIdxMatcher = (self, src, srcSeriesIdx) => srcSeriesIdx;\n\n\tconst syncOpts = assign({\n\t\tkey: null,\n\t\tsetSeries: false,\n\t\tfilters: {\n\t\t\tpub: retTrue,\n\t\t\tsub: retTrue,\n\t\t},\n\t\tscales: [xScaleKey, series[1] ? series[1].scale : null],\n\t\tmatch: [retEq, retEq, seriesIdxMatcher],\n\t\tvalues: [null, null],\n\t}, cursor.sync);\n\n\tif (syncOpts.match.length == 2)\n\t\tsyncOpts.match.push(seriesIdxMatcher);\n\n\tcursor.sync = syncOpts;\n\n\tconst syncKey = syncOpts.key;\n\n\tconst sync = _sync(syncKey);\n\n\tfunction pubSync(type, src, x, y, w, h, i) {\n\t\tif (syncOpts.filters.pub(type, src, x, y, w, h, i))\n\t\t\tsync.pub(type, src, x, y, w, h, i);\n\t}\n\n\tsync.sub(self);\n\n\tfunction pub(type, src, x, y, w, h, i) {\n\t\tif (syncOpts.filters.sub(type, src, x, y, w, h, i))\n\t\t\tevents[type](null, src, x, y, w, h, i);\n\t}\n\n\tself.pub = pub;\n\n\tfunction destroy() {\n\t\tsync.unsub(self);\n\t\tcursorPlots.delete(self);\n\t\tmouseListeners.clear();\n\t\toff(dppxchange, win, syncPxRatio);\n\t\troot.remove();\n\t\tlegendTable?.remove(); // in case mounted outside of root\n\t\tfire(\"destroy\");\n\t}\n\n\tself.destroy = destroy;\n\n\tfunction _init() {\n\t\tfire(\"init\", opts, data);\n\n\t\tsetData(data || opts.data, false);\n\n\t\tif (pendScales[xScaleKey])\n\t\t\tsetScale(xScaleKey, pendScales[xScaleKey]);\n\t\telse\n\t\t\tautoScaleX();\n\n\t\tshouldSetSelect = select.show && (select.width > 0 || select.height > 0);\n\t\tshouldSetCursor = shouldSetLegend = true;\n\n\t\t_setSize(opts.width, opts.height);\n\t}\n\n\tseries.forEach(initSeries);\n\n\taxes.forEach(initAxis);\n\n\tif (then) {\n\t\tif (then instanceof HTMLElement) {\n\t\t\tthen.appendChild(root);\n\t\t\t_init();\n\t\t}\n\t\telse\n\t\t\tthen(self, _init);\n\t}\n\telse\n\t\t_init();\n\n\treturn self;\n}\n\nuPlot.assign = assign;\nuPlot.fmtNum = fmtNum;\nuPlot.rangeNum = rangeNum;\nuPlot.rangeLog = rangeLog;\nuPlot.rangeAsinh = rangeAsinh;\nuPlot.orient = orient;\nuPlot.pxRatio = pxRatio;\n\n{\n\tuPlot.join = join;\n}\n\n{\n\tuPlot.fmtDate = fmtDate;\n\tuPlot.tzDate = tzDate;\n}\n\nuPlot.sync = _sync;\n\n{\n\tuPlot.addGap = addGap;\n\tuPlot.clipGaps = clipGaps;\n\n\tlet paths = uPlot.paths = {\n\t\tpoints,\n\t};\n\n\t(paths.linear = linear);\n\t(paths.stepped = stepped);\n\t(paths.bars = bars);\n\t(paths.spline = monotoneCubic);\n}\n\nexport { uPlot as default };\n"], + "mappings": "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", + "names": ["pre", "UPLOT", "ORI_HZ", "ORI_VT", "TITLE", "WRAP", "UNDER", "OVER", "AXIS", "OFF", "SELECT", "CURSOR_X", "CURSOR_Y", "CURSOR_PT", "LEGEND", "LEGEND_LIVE", "LEGEND_INLINE", "LEGEND_SERIES", "LEGEND_MARKER", "LEGEND_LABEL", "LEGEND_VALUE", "WIDTH", "HEIGHT", "TOP", "BOTTOM", "LEFT", "RIGHT", "hexBlack", "transparent", "mousemove", "mousedown", "mouseup", "mouseenter", "mouseleave", "dblclick", "resize", "scroll", "change", "dppxchange", "LEGEND_DISP", "domEnv", "doc", "win", "nav", "pxRatio", "query", "setPxRatio", "_pxRatio", "off", "on", "addClass", "el", "c", "cl", "remClass", "setStylePx", "name", "value", "placeTag", "tag", "cls", "targ", "refEl", "placeDiv", "xformCache", "elTrans", "xPos", "yPos", "xMax", "yMax", "xform", "xformOld", "colorCache", "elColor", "background", "borderColor", "newColor", "oldColor", "sizeCache", "elSize", "newWid", "newHgt", "centered", "newSize", "oldSize", "evOpts", "evOpts2", "ev", "cb", "capt", "closestIdx", "num", "arr", "lo", "hi", "mid", "bitwise", "floor", "makeIndexOfs", "predicate", "data", "_i0", "_i1", "i0", "i1", "i", "notNullish", "v", "isPositive", "nonNullIdxs", "positiveIdxs", "getMinMax", "sorted", "log", "getEdgeIdxs", "_min", "_max", "inf", "rangeLog", "min", "max", "base", "fullMags", "minSign", "sign", "maxSign", "logFn", "log10", "log2", "growMinAbs", "ceil", "growMaxAbs", "minExp", "abs", "maxExp", "minIncr", "pow", "maxIncr", "roundDec", "incrRoundDn", "incrRoundUp", "rangeAsinh", "minMax", "rangePad", "autoRangePart", "_eqRangePart", "_eqRange", "rangeNum", "mult", "extra", "isObj", "_rangeNum", "ifNull", "lh", "rh", "hasData", "idx0", "idx1", "cfg", "cmin", "cmax", "padMin", "padMax", "hardMin", "hardMax", "softMin", "softMax", "softMinMode", "softMaxMode", "delta", "deltaMag", "scalarMax", "scalarMag", "scalarMagDelta", "nonZeroDelta", "mag", "_padMin", "_newMin", "_softMin", "minLim", "_padMax", "_newMax", "_softMax", "maxLim", "numFormatter", "fmtNum", "val", "M", "PI", "round", "sinh", "linthresh", "asinh", "numIntDigits", "x", "clamp", "isFn", "fnOrSelf", "noop", "retArg0", "_0", "retArg1", "_1", "retNull", "_", "retTrue", "retEq", "a", "b", "regex6", "fixFloat", "isInt", "fixedDec", "str", "match", "len", "exp", "incrRound", "incr", "dec", "p", "guessDec", "genIncrs", "mults", "incrs", "multDec", "expa", "_incr", "EMPTY_OBJ", "EMPTY_ARR", "nullNullTuple", "isArr", "isUndef", "isStr", "is", "fastIsObj", "TypedArray", "__proto__", "copy", "o", "_isObj", "out", "k", "assign", "args", "src", "key", "NULL_REMOVE", "NULL_RETAIN", "NULL_EXPAND", "nullExpand", "yVals", "nullIdxs", "alignedLen", "xi", "lastNullIdx", "nullIdx", "join", "tables", "nullModes", "allHeadersSame", "table", "isAsc", "sortCols", "xVals", "ti", "xs", "xIdxs", "t", "si", "ys", "nullMode", "yVal", "alignedIdx", "microTask", "fn", "head", "rlen", "idxs", "table2", "row", "row2", "j", "vals0", "len0", "vals1", "vals", "samples", "firstIdx", "lastIdx", "stride", "prevVal", "months", "days", "slice3", "days3", "months3", "engNames", "zeroPad2", "int", "zeroPad3", "subs", "d", "names", "h", "fmtDate", "tpl", "parts", "R", "m", "localTz", "tzDate", "date", "tz", "date2", "onlyWhole", "allMults", "decIncrs", "oneIncrs", "wholeIncrs", "numIncrs", "NL", "yyyy", "NLyyyy", "md", "NLmd", "NLmdyy", "aa", "hmm", "hmmaa", "NLhmmaa", "ss", "genTimeStuffs", "ms", "s", "mo", "y", "timeIncrs", "_timeAxisStamps", "timeAxisSplits", "self", "axisIdx", "scaleMin", "scaleMax", "foundIncr", "foundSpace", "splits", "isYr", "isMo", "minDate", "minDateTs", "minMin", "mkDate", "minMinTs", "moIncr", "yrIncr", "split", "splitDate", "baseYear", "baseMonth", "next", "offs", "incr0", "tzOffset", "date0", "prevHour", "incrHours", "minSpace", "pctSpace", "expectedHour", "dstShift", "prevSplit", "timeIncrsMs", "_timeAxisStampsMs", "timeAxisSplitsMs", "timeIncrsS", "_timeAxisStampsS", "timeAxisSplitsS", "timeAxisStamps", "stampCfg", "timeAxisVals", "stamps", "prevYear", "prevMnth", "prevDate", "prevMins", "prevSecs", "newYear", "newMnth", "newDate", "newHour", "newMins", "newSecs", "stamp", "timeAxisVal", "dateTpl", "timeSeriesStamp", "_timeSeriesStamp", "timeSeriesVal", "seriesIdx", "dataIdx", "legendStroke", "legendFill", "legendOpts", "cursorPointShow", "pt", "size", "mar", "width", "cursorPointFill", "sp", "cursorPointStroke", "cursorPointSize", "moveTuple", "cursorMove", "mouseLeft1", "mouseTop1", "filtBtn0", "handle", "onlyTarg", "e", "filtTarg", "cursorOpts", "valPos", "curPos", "axisLines", "grid", "ticks", "border", "font", "labelFont", "lineGap", "xAxisOpts", "numSeriesLabel", "timeSeriesLabel", "xSeriesOpts", "numAxisVals", "numAxisSplits", "forceMin", "numDec", "logAxisSplits", "logBase", "nextMagIncr", "asinhAxisSplits", "posSplits", "zero", "RE_ALL", "RE_12357", "RE_125", "RE_1", "_filt", "distr", "re", "keepMod", "log10AxisValsFilt", "axis", "scaleKey", "sc", "valToPos", "_10", "magSpace", "log2AxisValsFilt", "numSeriesVal", "yAxisOpts", "ptDia", "dia", "seriesPointsShow", "scale", "xData", "p0", "p1", "dim", "maxPts", "facet", "gaps", "nullGaps", "xySeriesOpts", "ySeriesOpts", "clampScale", "xScaleOpts", "yScaleOpts", "syncs", "_sync", "opts", "plot", "type", "w", "BAND_CLIP_FILL", "BAND_CLIP_STROKE", "orient", "u", "mode", "series", "scales", "bbox", "dx", "dy", "sx", "sy", "l", "H", "V", "moveToH", "lineToH", "rectH", "arcH", "bezierCurveToH", "moveToV", "lineToV", "rectV", "arcV", "bezierCurveToV", "bandFillClipDirs", "fillDir", "clipDirs", "bands", "seriesFillTo", "dataMin", "dataMax", "bandFillDir", "clipBandLine", "strokePath", "clipDir", "dataX", "dataY", "scaleX", "scaleY", "valToPosX", "valToPosY", "xOff", "yOff", "xDim", "yDim", "pxRound", "dir", "lineTo", "frIdx", "toIdx", "x0", "y0", "x1", "yLimit", "clip", "clipGaps", "ori", "plotLft", "plotTop", "plotWid", "plotHgt", "rect", "prevGapEnd", "g", "maxStrokeWidth", "addGap", "fromX", "toX", "prevGap", "findGaps", "pixelForX", "align", "fr", "to", "frPx", "toPx", "fri2", "toi2", "pxRoundGen", "pxAlign", "moveTo", "arcTo", "y1", "x2", "y2", "r", "endRad", "baseRad", "startAngle", "endAngle", "bp1x", "bp1y", "bp2x", "bp2y", "p2x", "p2y", "points", "filtIdxs", "arc", "rad", "fill", "lft", "top", "wid", "hgt", "drawPoint", "pi", "_drawAcc", "stroke", "accX", "minY", "maxY", "inY", "outY", "drawAccH", "drawAccV", "linear", "alignGaps", "pixelForY", "drawAcc", "_paths", "hasGap", "xForPixel", "pos", "drawnAtX", "idx0px", "idx1px", "nextAccXVal", "xVal", "bandClipDir", "fillToVal", "fillToY", "frX", "stepped", "ascDesc", "extend", "left", "prevYPos", "firstXPos", "prevXPos", "firstXPosExt", "yVal1", "prevXPosExt", "fillTo", "halfStroke", "startsOffset", "endsOffset", "findColWidth", "colWid", "prevIdx", "minDelta", "bars", "_extraGap", "ro", "radiusFn", "gapFactor", "_maxWidth", "_minWidth", "disp", "_each", "dispFills", "dispStrokes", "_align", "extraGap", "maxWidth", "minWidth", "valRadius", "baseRadius", "_dirX", "each", "band", "xShift", "barWid", "fullGap", "strokeWidth", "multiPath", "fillColors", "fillPaths", "strokeColors", "strokePaths", "color", "pct", "sizes", "insetStroke", "rawBarWid", "dataY0", "radVal", "radBase", "yVal0", "btm", "barHgt", "rv", "rb", "splineInterp", "interp", "bezierCurveTo", "xCoords", "yCoords", "monotoneCubic", "_monotoneCubic", "n", "path", "ds", "dys", "dxs", "cursorPlots", "invalidateRects", "uPlot", "linearPath", "pointsPath", "setDefaults", "xo", "yo", "initY", "setDefault", "setDefaults2", "xyo", "snapNumX", "snapTimeX", "snapNumY", "snapLogY", "snapLogX", "snapAsinhY", "snapAsinhX", "findIncr", "minVal", "maxVal", "intDigits", "incrIdx", "pxRatioFont", "fontSize", "fontSizeCss", "syncFontSize", "f", "then", "getHPos", "getVPos", "getPos", "ready", "root", "title", "can", "ctx", "wrap", "over", "mouseLeft0", "mouseTop0", "drag", "under", "axes", "xScaleKey", "drawOrderMap", "drawAxesGrid", "drawSeries", "drawOrder", "initValToPct", "getVal", "_val", "initScale", "scaleOpts", "isTime", "rn", "rangeIsArr", "xScaleDistr", "pendScales", "_tzDate", "ts", "_fmtDate", "_timeAxisSplits", "_timeAxisVals", "_timeSeriesVal", "activeIdxs", "legend", "cursor", "showLegend", "showCursor", "markers", "legendTable", "legendHead", "legendBody", "legendRows", "legendCells", "legendCols", "multiValLegend", "NULL_LEGEND_VALUES", "getMultiVals", "son", "soff", "initLegendRow", "cells", "label", "indic", "text", "onMouse", "setCursorEvent", "isolate", "setSeries", "syncOpts", "cursorFocus", "FOCUS_TRUE", "mouseListeners", "targListeners", "listener", "offMouse", "fullWidCss", "fullHgtCss", "plotWidCss", "plotHgtCss", "plotLftCss", "plotTopCss", "_plotLftCss", "_plotTopCss", "_plotWidCss", "_plotHgtCss", "shouldSetScales", "shouldSetSize", "shouldConvergeSize", "shouldSetCursor", "shouldSetSelect", "shouldSetLegend", "_setSize", "height", "force", "calcSize", "resetYSeries", "commit", "calcPlotRect", "calcAxesRects", "bb", "CYCLE_LIMIT", "convergeSize", "converged", "cycleNum", "axesConverged", "axesCalc", "paddingConverged", "paddingCalc", "setSize", "hasTopAxis", "hasBtmAxis", "hasRgtAxis", "hasLftAxis", "side", "_size", "isVt", "labelSize", "fullSize", "sidesWithAxes", "_padding", "off1", "off2", "off3", "off0", "incrOffset", "hov", "skip", "prox", "bias", "cursorIdx", "valAtPosX", "idx2", "_prox", "withProx", "cursorLft", "xValues", "yValues", "nonNullLft", "nonNullRgt", "lftPos", "rgtPos", "lftDelta", "rgtDelta", "focus", "cursorOnePt", "cursorPts", "cursorPtsLft", "cursorPtsTop", "initCursorPt", "initSeries", "sv", "_ptDia", "rowCells", "fire", "addSeries", "delSeries", "tr", "initAxis", "av", "autoPadSide", "padding", "dataLen", "data0", "viaAutoScaleX", "setData", "_data", "_resetScales", "scaleData", "_data0", "xsc", "autoScaleX", "_setScale", "ctxStroke", "ctxFill", "ctxWidth", "ctxDash", "ctxJoin", "ctxCap", "ctxFont", "ctxAlign", "ctxBaseline", "ctxAlpha", "setCtxStyle", "dash", "cap", "setFontStyle", "baseline", "accScale", "wsc", "psc", "AUTOSCALE", "setScales", "wipScales", "xFacet", "yFacet", "yScaleKey", "yData", "wscx", "wscy", "changed", "anyChanged", "getOuterIdxs", "ydata", "shouldAlpha", "cacheStrokeFill", "_ctxAlpha", "_idxs", "drawPath", "_gaps", "show", "_points", "gapsClip", "flags", "strokeStyle", "fillStyle", "boundsClip", "offset", "_pxAlign", "strokeFill", "fillStroke", "lineWidth", "lineDash", "lineCap", "fillPath", "didStrokeFill", "bi", "lowerEdge", "lowerData", "bandClip", "gapsClip2", "_fillStyle", "CLIP_FILL_STROKE", "doFill", "doStroke", "getIncrSpace", "fullDim", "incrSpace", "drawOrthoLines", "filts", "pos0", "pos1", "_space", "_splits", "values", "_p", "shiftDir", "shiftAmt", "baseLpos", "_label", "plotDim", "plotOff", "_tickSize", "tickSize", "axisGap", "angle", "basePos", "finalPos", "textAlign", "textBaseline", "lineHeight", "canOffs", "_values", "_parts", "queuedCommit", "deferHooks", "hooksQueue", "flushHooks", "_commit", "batch", "_deferHooks", "_el", "_show", "_pos", "posOffset", "syncRect", "pctWid", "pctHgt", "vCursor", "hCursor", "select", "prop", "_hideProps", "selectDiv", "setSelect", "updateCursor", "setLegend", "rebuildPaths", "recalcAxes", "setScale", "xCursor", "yCursor", "rawMouseLeft0", "rawMouseTop0", "rawMouseLeft1", "rawMouseTop1", "dragging", "dragX", "dragY", "_fire", "toggleDOM", "_pub", "setFocus", "pubSync", "setBand", "addBand", "delBand", "setAlpha", "closestDist", "closestSeries", "focusedSeries", "allFocused", "_setAlpha", "i2", "isFocused", "posToVal", "closestIdxFromXpos", "setSelH", "setSelV", "setSelX", "setSelY", "syncLegend", "didx", "sidx", "setLegendValues", "idx", "noDataInRange", "mouseXPos", "_ptLft", "_ptTop", "_ptWid", "_ptHgt", "_centered", "_ptFill", "_ptStroke", "yVal2", "xPos2", "mouseYPos", "dist", "mouseYVal", "seriesYValSign", "mouseYValSign", "hPos", "vPos", "ptWid", "ptHgt", "ptLft", "ptTop", "ptStroke", "ptFill", "getBBox", "focusChanged", "xKey", "yKey", "matchXKeys", "matchYKeys", "xKeySrc", "yKeySrc", "sdrag", "sori", "sPosToVal", "sOff", "sDim", "matchingX", "matchingY", "hideSelect", "rawDX", "rawDY", "_rawDX", "uni", "syncKey", "xSyncKey", "ySyncKey", "shouldPub", "defer", "mouseMove", "_l", "_t", "_w", "_h", "_i", "cacheMouse", "initial", "snap", "syncOptsSrc", "xValSrc", "yValSrc", "rotSrc", "_xDim", "_yDim", "_xPos", "_yPos", "__l", "downSelectLeft", "downSelectTop", "downSelectWidth", "downSelectHeight", "mouseDown", "mouseUp", "hasSelect", "chgSelect", "mouseLeave", "_dragging", "snapH", "snapV", "snapProx", "dragH", "dragV", "dblClick", "syncPxRatio", "events", "seriesIdxMatcher", "hooks", "evName", "a1", "a2", "srcSeriesIdx", "sync", "pub", "destroy", "_init", "paths"] +} diff --git a/suites-experimental/tools-gps-tracks/material_symbols_rounded.woff2 b/suites-experimental/tools-gps-tracks/material_symbols_rounded.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..3dbcf04e581c6d75d4400ef99b2957a1ea3064ee GIT binary patch literal 79944 zcmV(-K-|A~Pew8T0RR910XRqi5&!@I0(6W30XN+M0`1cP00000000000000000000 z0000Sm^eR3RzXsMB?e$WQ&d4zfkY=z0ET=ofou^73W0{T#`v_b(k0we>0a0`KO z00bZfgD?jm3YV)zUL(V?!^BeUkZwsbXbbz7Y81Vd za6mo5hd$-oyD??||9@Ii8Drn8?I0ouViuC7NCBC&O^HD(Nr{g3D7hZBq^

N(%RE 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" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/fit-file-parser": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fit-file-parser/-/fit-file-parser-2.3.3.tgz", + "integrity": "sha512-TZPFfjkEev5TTd9RnZ4xn4k5ZSx2VZiKNjoZsHIkmQDK0S0XA7ebfdMLj76BK7kStsHh5WbK8Fmn/w85jgd0dA==", + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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": "BSD-3-Clause" + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uplot": { + "version": "1.6.32", + "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.32.tgz", + "integrity": "sha512-KIMVnG68zvu5XXUbC4LQEPnhwOxBuLyW1AHtpm6IKTXImkbLgkMy+jabjLgSLMasNuGGzQm/ep3tOkyTxpiQIw==", + "license": "MIT" + } + } +} diff --git a/suites-experimental/tools-gps-tracks/package.json b/suites-experimental/tools-gps-tracks/package.json new file mode 100644 index 0000000000..4102e7acd5 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/package.json @@ -0,0 +1,27 @@ +{ + "name": "tools-gps-tracks", + "version": "1.0.0", + "private": true, + "description": "Speedometer benchmark workload for GPS file parsing, metrics computation, and chart visualization", + "type": "module", + "scripts": { + "build": "tsc && node build.js", + "dev": "node build.js --watch", + "check": "tsc --noEmit", + "format": "prettier --write 'src/**/*.{ts,html}' 'src/css/styles.css' 'scripts/**/*.mjs' './*.js' README.md" + }, + "engines": { + "node": ">=24.0.0", + "npm": ">=8.19.3" + }, + "license": "BSD-3-Clause", + "dependencies": { + "fit-file-parser": "2.3.3", + "uplot": "1.6.32" + }, + "devDependencies": { + "esbuild": "0.20.2", + "prettier": "3.8.1", + "typescript": "5.9.3" + } +} diff --git a/suites-experimental/tools-gps-tracks/scripts/generate-test-data.mjs b/suites-experimental/tools-gps-tracks/scripts/generate-test-data.mjs new file mode 100644 index 0000000000..863683c269 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/scripts/generate-test-data.mjs @@ -0,0 +1,453 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import fs from 'fs/promises'; +import path from 'path'; +import zlib from 'zlib'; + +const SRC_OUT_DIR = path.join(import.meta.dirname, '../test-data'); +const DIST_OUT_DIR = path.join(import.meta.dirname, '../dist/test-data'); + +// Deterministic PRNG (Mulberry32) so generated test data is reproducible. +let prngSeed = 0x20260720; +function random() { + let t = (prngSeed += 0x6d2b79f5); + t = Math.imul(t ^ (t >>> 15), t | 1); + t ^= t + Math.imul(t ^ (t >>> 7), t | 61); + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; +} + +function generateGPX( + name, + startTime, + pointCount, + baseAlt, + basePower, + baseHr, + baseCad, + baseSpeed, + profile, +) { + let xml = `\n`; + xml += `\n`; + xml += ` ${name}\n`; + xml += ` ${name}\n`; + + let lat = 46.5197; + let lon = 6.6323; + let alt = baseAlt; + const rearGears = [11, 12, 13, 14, 15, 17, 19, 21, 24, 28]; + + for (let i = 0; i < pointCount; i++) { + const t = new Date(startTime + i * 1000).toISOString(); + lat += 0.0001 * Math.cos(i * 0.02) + (random() - 0.5) * 0.00005; + lon += 0.00015 * Math.sin(i * 0.02) + (random() - 0.5) * 0.00005; + + let power = Math.max(100, Math.round(basePower + Math.sin(i / 20) * 50 + (random() * 20 - 10))); + let hr = Math.min(190, Math.max(100, Math.round(baseHr + Math.sin(i / 30) * 15))); + let cad = Math.min(120, Math.max(60, Math.round(baseCad + Math.cos(i / 15) * 10))); + let speed = Math.max(5.0, Number((baseSpeed + Math.sin(i / 25) * 3).toFixed(2))); + let temp = Number( + (20.0 - (alt - baseAlt) * 0.02 + (i / pointCount) * 2.5 + Math.sin(i / 100) * 1.0).toFixed(1), + ); + let frontTooth = 52; + let rearTooth = rearGears[Math.floor((i / 45) % rearGears.length)]; + let battery = Math.max(15, 100 - Math.floor(i / 60)); + + if (profile === 'race') { + alt += Math.sin(i / 40) * 1.8; + power = Math.max(150, Math.round(280 + 100 * Math.sin(i / 15) + (random() - 0.5) * 20)); + hr = Math.min(192, Math.max(120, Math.round(165 + 20 * Math.sin(i / 30)))); + speed = Math.max(8.0, Number((baseSpeed + 2 + Math.sin(i / 20) * 4).toFixed(2))); + temp = Number( + (17.5 - (alt - baseAlt) * 0.025 + (i / pointCount) * 2.8 + Math.sin(i / 110) * 1.2).toFixed( + 1, + ), + ); + } else if (profile === 'mtb') { + alt += Math.cos(i / 25) * 1.5; + frontTooth = 34; + rearTooth = rearGears[Math.floor((i / 25) % rearGears.length)]; + temp = Number( + (19.5 - (alt - baseAlt) * 0.02 + (i / pointCount) * 2.2 + Math.cos(i / 90) * 1.1).toFixed( + 1, + ), + ); + speed = Math.max(4.0, Number((baseSpeed - 2 + Math.cos(i / 15) * 2.5).toFixed(2))); + } else { + alt += Math.sin(i / 50) * 1.2; + temp = Number( + (20.0 - (alt - baseAlt) * 0.02 + (i / pointCount) * 2.5 + Math.sin(i / 100) * 1.0).toFixed( + 1, + ), + ); + } + + xml += ` \n`; + xml += ` ${alt.toFixed(1)}\n`; + xml += ` \n`; + xml += ` \n`; + xml += ` ${power}\n`; + xml += `


${hr}\n`; + xml += ` ${cad}\n`; + xml += ` ${temp}\n`; + xml += ` ${speed}\n`; + xml += ` ${frontTooth}\n`; + xml += ` ${rearTooth}\n`; + xml += ` ${battery}\n`; + xml += ` \n`; + xml += ` ${hr}\n`; + xml += ` ${cad}\n`; + xml += ` ${temp}\n`; + xml += ` \n`; + xml += ` \n`; + xml += ` \n`; + } + + xml += ` \n`; + xml += `\n`; + return xml; +} + +function generateTCX( + name, + startTime, + pointCount, + baseAlt, + basePower, + baseHr, + baseCad, + baseSpeed, + profile, +) { + let xml = `\n`; + xml += `\n`; + xml += ` \n`; + xml += ` ${new Date(startTime).toISOString()}\n`; + xml += ` ${name}\n`; + xml += ` \n`; + xml += ` \n`; + + let lat = 47.3769; + let lon = 8.5417; + let alt = baseAlt; + const rearGears = [11, 12, 13, 14, 15, 17, 19, 21, 23, 25]; + + for (let i = 0; i < pointCount; i++) { + const t = new Date(startTime + i * 1000).toISOString(); + lat += (random() - 0.45) * 0.0005; + lon += (random() - 0.45) * 0.0005; + + let power = Math.max( + 120, + Math.round(basePower + Math.cos(i / 25) * 60 + (random() * 15 - 7.5)), + ); + let hr = Math.min(195, Math.max(110, Math.round(baseHr + Math.cos(i / 35) * 18))); + let cad = Math.min(115, Math.max(65, Math.round(baseCad + Math.cos(i / 18) * 8))); + let speed = Math.max(6.0, Number((baseSpeed + Math.sin(i / 20) * 2.5).toFixed(2))); + let temp = 21.5; + let frontTooth = 50; + let rearTooth = rearGears[Math.floor((i / 40) % rearGears.length)]; + let battery = Math.max(20, 98 - Math.floor(i / 50)); + + if (profile === 'interval') { + const isInterval = i % 120 < 40; + if (isInterval) { + power = Math.round(380 + random() * 30); + hr = Math.min(195, Math.round(170 + random() * 5)); + cad = Math.round(100 + random() * 5 - 2.5); + speed = Math.max(10.0, Number((baseSpeed + 4 + random()).toFixed(2))); + rearTooth = 13; + } else { + power = Math.round(150 + random() * 15); + hr = Math.max(130, Math.round(145 + random() * 5)); + cad = Math.round(80 + random() * 4 - 2); + speed = Math.max(6.0, Number((baseSpeed - 2 + random() * 0.5).toFixed(2))); + rearTooth = 21; + } + alt += Math.cos(i / 30) * 0.8; + temp = Number( + (24.8 - (i / pointCount) * 2.2 - (alt - baseAlt) * 0.02 + Math.sin(i / 85) * 1.1).toFixed( + 1, + ), + ); + } else { + alt += Math.cos(i / 40) * 1.0; + temp = Number( + (18.5 + (i / pointCount) * 3.4 - (alt - baseAlt) * 0.02 + Math.cos(i / 100) * 1.0).toFixed( + 1, + ), + ); + } + + xml += ` \n`; + xml += ` \n`; + xml += ` ${lat.toFixed(6)}${lon.toFixed(6)}\n`; + xml += ` ${alt.toFixed(1)}\n`; + xml += ` ${hr}\n`; + xml += ` ${cad}\n`; + xml += ` \n`; + xml += ` \n`; + xml += ` ${speed.toFixed(2)}\n`; + xml += ` ${power}\n`; + xml += ` \n`; + xml += ` ${temp}\n`; + xml += ` ${temp}\n`; + xml += ` ${frontTooth}\n`; + xml += ` ${rearTooth}\n`; + xml += ` ${battery}\n`; + xml += ` \n`; + xml += ` \n`; + } + + xml += ` \n`; + xml += ` \n`; + xml += ` \n`; + xml += `\n`; + return xml; +} + +function generateFIT( + startTimeMs, + pointCount, + baseAlt, + basePower, + baseHr, + baseCad, + baseSpeed, + baseTemp = 20, +) { + const garminEpoch = 631065600; + const startGarmin = Math.floor(startTimeMs / 1000) - garminEpoch; + const chunks = []; + + chunks.push( + Buffer.from([ + 0x40, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x01, 0x02, 0x84, 0x02, 0x02, 0x84, + 0x04, 0x04, 0x86, + ]), + ); + const d0 = Buffer.alloc(10); + d0.writeUInt8(0x00, 0); + d0.writeUInt8(4, 1); + d0.writeUInt16LE(1, 2); + d0.writeUInt16LE(2026, 4); + d0.writeUInt32LE(startGarmin >>> 0, 6); + chunks.push(d0); + + chunks.push( + Buffer.from([ + 0x41, 0x00, 0x00, 0x12, 0x00, 0x03, 0x02, 0x04, 0x86, 0x05, 0x01, 0x00, 0x06, 0x01, 0x00, + ]), + ); + const d18 = Buffer.alloc(7); + d18.writeUInt8(0x01, 0); + d18.writeUInt32LE(startGarmin >>> 0, 1); + d18.writeUInt8(2, 5); + d18.writeUInt8(0, 6); + chunks.push(d18); + + chunks.push( + Buffer.from([ + 0x42, 0x00, 0x00, 0x14, 0x00, 0x0a, 0xfd, 0x04, 0x86, 0x00, 0x04, 0x85, 0x01, 0x04, 0x85, + 0x02, 0x02, 0x84, 0x03, 0x01, 0x02, 0x04, 0x01, 0x02, 0x05, 0x04, 0x86, 0x06, 0x02, 0x84, + 0x07, 0x02, 0x84, 0x0d, 0x01, 0x01, + ]), + ); + + chunks.push( + Buffer.from([ + 0x43, 0x00, 0x00, 0x15, 0x00, 0x06, 0xfd, 0x04, 0x86, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, + 0x03, 0x04, 0x86, 0x09, 0x01, 0x02, 0x0b, 0x01, 0x02, + ]), + ); + + chunks.push( + Buffer.from([0x44, 0x00, 0x00, 0x17, 0x00, 0x02, 0xfd, 0x04, 0x86, 0x20, 0x01, 0x02]), + ); + + let lat = 46.2; + let lon = 7.2; + let alt = baseAlt; + let dist = 0; + let frontGear = 2; + let rearGear = 5; + let battery = 100; + + for (let i = 0; i < pointCount; i++) { + const t = startGarmin + i * 1; + lat += (random() - 0.45) * 0.0005; + lon += (random() - 0.45) * 0.0005; + alt += Math.sin(i / 50) * 1.4; + dist += baseSpeed * 1; + const speed = baseSpeed + Math.sin(i / 30) * 2.5; + const power = Math.max( + 110, + Math.round(basePower + Math.sin(i / 20) * 65 + (random() - 0.5) * 20), + ); + const hr = Math.min( + 190, + Math.max(105, Math.round(baseHr + Math.sin(i / 30) * 18 + (random() - 0.5) * 4)), + ); + const cad = Math.min( + 115, + Math.max(65, Math.round(baseCad + Math.sin(i / 20) * 10 + (random() - 0.5) * 3)), + ); + const temp = Math.round( + baseTemp - (alt - baseAlt) * 0.025 + (i / pointCount) * 3.2 + Math.sin(i / 80) * 1.8, + ); + + const d20 = Buffer.alloc(26); + d20.writeUInt8(0x02, 0); + d20.writeUInt32LE(t >>> 0, 1); + d20.writeInt32LE(Math.round(lat * (Math.pow(2, 31) / 180)), 5); + d20.writeInt32LE(Math.round(lon * (Math.pow(2, 31) / 180)), 9); + d20.writeUInt16LE(Math.round((alt + 500) * 5), 13); + d20.writeUInt8(hr, 15); + d20.writeUInt8(cad, 16); + d20.writeUInt32LE(Math.round(dist * 100) >>> 0, 17); + d20.writeUInt16LE(Math.round(speed * 1000), 21); + d20.writeUInt16LE(power, 23); + d20.writeInt8(temp, 25); + chunks.push(d20); + + if (i % 50 === 25) { + rearGear = (rearGear % 11) + 1; + if (i % 200 === 100) frontGear = frontGear === 2 ? 1 : 2; + const d21 = Buffer.alloc(13); + d21.writeUInt8(0x03, 0); + d21.writeUInt32LE(t >>> 0, 1); + d21.writeUInt8(43, 5); + d21.writeUInt8(3, 6); + const teethData = + ((frontGear === 2 ? 52 : 36) << 24) | (frontGear << 16) | ((11 + rearGear) << 8) | rearGear; + d21.writeUInt32LE(teethData >>> 0, 7); + d21.writeUInt8(frontGear, 11); + d21.writeUInt8(rearGear, 12); + chunks.push(d21); + } + + if (i % 100 === 0) { + battery = Math.max(10, 100 - Math.floor(i / 100)); + const d23 = Buffer.alloc(6); + d23.writeUInt8(0x04, 0); + d23.writeUInt32LE(t >>> 0, 1); + d23.writeUInt8(battery, 5); + chunks.push(d23); + } + } + + const dataBuf = Buffer.concat(chunks); + const header = Buffer.alloc(14); + header.writeUInt8(14, 0); + header.writeUInt8(32, 1); + header.writeUInt16LE(2114, 2); + header.writeUInt32LE(dataBuf.length, 4); + header.write('.FIT', 8, 4, 'ascii'); + header.writeUInt16LE(0, 12); + + const fileCrc = Buffer.alloc(2); + return Buffer.concat([header, dataBuf, fileCrc]); +} + +async function run() { + await fs.mkdir(SRC_OUT_DIR, { recursive: true }); + await fs.mkdir(DIST_OUT_DIR, { recursive: true }); + + const files = [ + { + name: 'activity_1_alps_stage.gpx', + content: generateGPX( + 'Alpine Mountain Stage', + Date.parse('2026-05-10T08:00:00Z'), + 1500, + 600, + 260, + 160, + 85, + 9.5, + 'race', + ), + }, + { + name: 'activity_2_forest_mtb.gpx', + content: generateGPX( + 'Forest MTB Trail', + Date.parse('2026-05-17T09:30:00Z'), + 1200, + 450, + 230, + 155, + 80, + 7.5, + 'mtb', + ), + }, + { + name: 'activity_3_road_race.tcx', + content: generateTCX( + 'Lakeside Road Race', + Date.parse('2026-06-05T07:15:00Z'), + 1600, + 380, + 280, + 168, + 92, + 11.2, + 'road', + ), + }, + { + name: 'activity_4_intervals.tcx', + content: generateTCX( + 'Sprint Intervals', + Date.parse('2026-06-12T17:00:00Z'), + 1400, + 350, + 320, + 175, + 96, + 12.0, + 'interval', + ), + }, + { + name: 'activity_5_grand_tour.fit', + content: generateFIT(Date.parse('2026-07-02T08:30:00Z'), 1800, 500, 270, 162, 88, 10.5, 19), + }, + { + name: 'activity_6_weekend_ride.fit', + content: generateFIT(Date.parse('2026-07-15T09:00:00Z'), 1400, 320, 210, 142, 84, 8.8, 22), + }, + ]; + + await fs.rm(SRC_OUT_DIR, { recursive: true, force: true }); + await fs.rm(DIST_OUT_DIR, { recursive: true, force: true }); + await fs.mkdir(SRC_OUT_DIR, { recursive: true }); + await fs.mkdir(DIST_OUT_DIR, { recursive: true }); + + const manifest = []; + for (const file of files) { + const gzName = `${file.name}.gz`; + const srcPath = path.join(SRC_OUT_DIR, gzName); + const distPath = path.join(DIST_OUT_DIR, gzName); + const rawBuf = + typeof file.content === 'string' ? Buffer.from(file.content, 'utf-8') : file.content; + const compressed = zlib.gzipSync(rawBuf, { level: 9 }); + await fs.writeFile(srcPath, compressed); + await fs.writeFile(distPath, compressed); + manifest.push(gzName); + console.log(`Generated ${gzName} (${compressed.length} compressed bytes)`); + } + + const manifestJson = JSON.stringify(manifest, null, 2); + await fs.writeFile(path.join(SRC_OUT_DIR, 'manifest.json'), manifestJson); + await fs.writeFile(path.join(DIST_OUT_DIR, 'manifest.json'), manifestJson); + console.log('Saved manifest.json with', manifest.length, 'files.'); +} + +run().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/suites-experimental/tools-gps-tracks/src/app.ts b/suites-experimental/tools-gps-tracks/src/app.ts new file mode 100644 index 0000000000..f91f68092d --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/app.ts @@ -0,0 +1,2179 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +// ── Main Application ────────────────────────────────────────────── + +import { Storage } from './storage'; +import { UrlState, AppState } from './url-state'; +import { Parsers, TrackData, TrackPoint, calculateBounds, simplifyTrack } from './parsers'; +import { MapView } from './map'; +import { ChartView } from './charts'; +import { renderDetails, initDetails, resetDetails } from './tabs/details'; +import { renderInsights, initInsights, resetInsights } from './tabs/insights'; +import { renderCombined, initCombined, resizeCombined, resetCombined } from './tabs/combined'; +import { renderEvolution, resetEvolution } from './tabs/progress'; +import { + renderCourses, + initCourses, + prepareBenchmarkCourses, + resetCourses, + selectCourse, +} from './tabs/courses'; +import { fmtSecs, escHtml, fmtDate, getTagColor, compactId, shortRandom } from './utils'; + +const TRACK_COLORS: string[] = [ + '#FF6B35', + '#4ECDC4', + '#45B7D1', + '#F7DC6F', + '#FF6B6B', + '#BB8FCE', + '#82E0AA', + '#F8C471', + '#3b82f6', +]; + +const POINT_ZOOM_LEVEL = 16; + +let tracks: Record = {}; +let skippedImports: { name: string; reason: string }[] = []; + +function isSameDay(t1: number, t2: number) { + const d1 = new Date(t1); + const d2 = new Date(t2); + return ( + d1.getUTCFullYear() === d2.getUTCFullYear() && + d1.getUTCMonth() === d2.getUTCMonth() && + d1.getUTCDate() === d2.getUTCDate() + ); +} + +let cancelProcessing = false; +let selectedId: string | null = null; +let colorIdx = 0; +let followDot = false; +let currentMapColors: string[] | null = null; + +// Search/Filter state +let searchQuery = ''; +let searchRegex = false; +let currentSort = 'date-desc'; + +interface Filters { + date: [string | null, string | null]; + dist: [number | null, number | null]; + dur: [number | null, number | null]; + metrics: Set; + tags: string[]; + sport: string | null; +} + +let filters: Filters = { + date: [null, null], + dist: [null, null], + dur: [null, null], + metrics: new Set(), + tags: [], + sport: null, +}; + +function syncFiltersToUrl(push: boolean = false) { + UrlState.patch( + { + f_date: filters.date.every((v) => v === null) ? null : filters.date, + f_dist: filters.dist.every((v) => v === null) ? null : filters.dist, + f_dur: filters.dur.every((v) => v === null) ? null : filters.dur, + f_mets: filters.metrics.size === 0 ? null : Array.from(filters.metrics), + f_tags: filters.tags.length === 0 ? null : filters.tags, + }, + push, + ); +} + +function syncMetricsToUrl() { + const active = ChartView.getActiveMetrics(); + const metrics = ChartView.METRICS; + const abbrs = Array.from(active).map((key) => metrics[key].abbr); + UrlState.patch({ metrics: abbrs.length ? abbrs : null }); +} + +const SORT_OPTIONS = [ + { label: 'Newest first', val: 'date-desc', icon: 'calendar_today' }, + { label: 'Oldest first', val: 'date-asc', icon: 'history' }, + { label: 'Longest distance', val: 'dist-desc', icon: 'straighten' }, + { label: 'Shortest distance', val: 'dist-asc', icon: 'horizontal_rule' }, + { label: 'Longest duration', val: 'dur-desc', icon: 'timer' }, + { label: 'Shortest duration', val: 'dur-asc', icon: 'timer_off' }, +]; + +function showSortMenu(anchorEl: HTMLElement) { + document.querySelectorAll('.sort-menu-popup').forEach((el) => el.remove()); + + const popup = document.createElement('div'); + popup.className = 'sort-menu-popup'; + + SORT_OPTIONS.forEach((opt) => { + const item = document.createElement('div'); + item.className = `menu-item ${currentSort === opt.val ? 'active' : ''}`; + item.innerHTML = ` + ${opt.icon} + ${opt.label} + ${currentSort === opt.val ? 'check' : ''} + `; + item.addEventListener('click', () => { + currentSort = opt.val; + UrlState.patch({ sort: opt.val }); + updateSearchSortUI(); + renderTrackList(); + popup.remove(); + }); + popup.appendChild(item); + }); + + const rect = anchorEl.getBoundingClientRect(); + popup.style.top = `${rect.bottom + 5}px`; + popup.style.left = `${rect.left}px`; + document.body.appendChild(popup); + + const close = (e: MouseEvent) => { + if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) { + popup.remove(); + document.removeEventListener('click', close); + } + }; + setTimeout(() => document.addEventListener('click', close), 0); +} + +function showMetricMenu(anchorEl: HTMLElement) { + document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove()); + + const popup = document.createElement('div'); + popup.className = 'metric-menu-popup'; + + const metrics = ChartView.METRICS; + const available = ChartView.getAvailableMetrics(); + const active = ChartView.getActiveMetrics(); + + Object.entries(metrics).forEach(([key, def]) => { + if (!available.has(key)) return; + + const item = document.createElement('div'); + item.className = `menu-item ${active.has(key) ? 'active' : ''}`; + item.innerHTML = ` + ${def.icon} + ${def.label} + ${active.has(key) ? 'check' : ''} + `; + item.addEventListener('click', () => { + ChartView.toggleMetric(key); + const isNowActive = ChartView.getActiveMetrics().has(key); + item.classList.toggle('active', isNowActive); + item.querySelector('.check')!.textContent = isNowActive ? 'check' : ''; + + const pill = document.querySelector(`#metric-pills .metric-pill[data-metric="${key}"]`); + if (pill) pill.classList.toggle('active', isNowActive); + + updateToolbarLayout(); + + syncMetricsToUrl(); + }); + popup.appendChild(item); + }); + + const rect = anchorEl.getBoundingClientRect(); + popup.style.top = `${rect.bottom + 5}px`; + popup.style.right = `${window.innerWidth - rect.right}px`; + document.body.appendChild(popup); + + const close = (e: MouseEvent) => { + if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) { + popup.remove(); + document.removeEventListener('click', close); + } + }; + setTimeout(() => document.addEventListener('click', close), 0); +} + +// ── Tab Management ──────────────────────────────────────────────── +document.addEventListener('select-track', (e: any) => { + const id = e.detail.id; + const idx = e.detail.idx; + const dur = e.detail.dur; + if (id && tracks[id]) { + selectTrack(id); + if (idx != null && dur != null) { + const t = tracks[id]; + const pts = t.points; + if (idx >= 0 && idx < pts.length) { + const pIdx = pts[idx]; + if (pIdx && pIdx.time != null) { + const t0 = pts.find((p) => p.time != null)?.time || 0; + const tMin = (pIdx.time - t0) / 1000; + const tMax = tMin + dur; + + // ChartView selection + ChartView.restoreSelection(tMin, tMax); + + // Find iMax based on duration + let iMax = pts.findIndex((p) => (p.time || 0) >= pIdx.time! + dur * 1000); + if (iMax === -1) iMax = pts.length - 1; + + const selPts = pts.slice(idx, iMax + 1); + const stats = Parsers.computeStats(selPts); + ChartView.setSelectionStats(stats); + + renderInsights(t); + + MapView.highlightSegment(id, pts, idx, iMax, false, currentMapColors); + MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number])); + + // Update URL state + UrlState.patch({ sel: [tMin, tMax] }); + } + } + } + } +}); + +document.addEventListener('click', (e) => { + const btn = (e.target as HTMLElement).closest('.tab-btn') as HTMLElement; + if (!btn) return; + const nav = btn.closest('#tab-nav'); + if (!nav) return; + + // Toggle buttons + nav.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn)); + + const tab = btn.dataset.tab!; + UrlState.patch({ tab }, true); + + // Toggle contents + const panel = nav.closest('#chart-panel'); + if (panel) { + panel.querySelectorAll('.tab-content').forEach((c) => { + c.classList.toggle('active', c.id === `tab-${btn.dataset.tab}`); + }); + } + + if (btn.dataset.tab === 'details' && selectedId && tracks[selectedId]) + renderDetails(tracks[selectedId], getGlobalTags()); + + if (btn.dataset.tab === 'insights' && selectedId && tracks[selectedId]) + renderInsights(tracks[selectedId]); + + if (btn.dataset.tab === 'evolution') { + renderEvolution( + selectedId ? tracks[selectedId] : null, + Object.values(tracks), + (trackId, range) => { + selectTrack(trackId, true); + if (range) { + ChartView.restoreSelection(range[0], range[1]); + onChartRangeChange(range[0], range[1], 'time', true); + } + }, + (start, end) => { + filters.date = [start, end]; + applyFilters(); + syncFiltersToUrl(true); + updateFilterUI(); + }, + ); + } + + if (btn.dataset.tab === 'combined' && selectedId && tracks[selectedId]) + renderCombined(tracks[selectedId]); + + if (btn.dataset.tab === 'courses') renderCourses(); + + if (btn.dataset.tab === 'graphs') { + ChartView.resize(); + updateToolbarLayout(); + + // Restore selection from URL + const s = UrlState.get().sel; + if (s) ChartView.restoreSelection(s[0], s[1]); + } +}); + +async function resetBenchmarkState() { + if (typeof (window as any).__resetBenchmarkSeed === 'function') { + (window as any).__resetBenchmarkSeed(); + } + await Storage.clear(); + tracks = {}; + skippedImports = []; + selectedId = null; + colorIdx = 0; + currentMapColors = null; + cancelProcessing = false; + followDot = false; + searchQuery = ''; + searchRegex = false; + currentSort = 'date-desc'; + filters.date = [null, null]; + filters.dist = [null, null]; + filters.dur = [null, null]; + filters.metrics.clear(); + filters.tags = []; + Parsers.setHRZones([120, 140, 160, 180]); + Parsers.setFTP(200); + resetCourses(); + resetInsights(); + resetDetails(); + resetCombined(); + resetEvolution(); + if (MapView.removeAllTracks) MapView.removeAllTracks(); + if (MapView.clearTracks) MapView.clearTracks(); + MapView.clearHighlight(); + if (ChartView.resetState) ChartView.resetState(); + else if (ChartView.clear) ChartView.clear(); + document.querySelectorAll('.tab-btn').forEach((b) => { + b.classList.toggle('active', (b as HTMLElement).dataset.tab === 'graphs'); + }); + document.querySelectorAll('.tab-content').forEach((c) => { + c.classList.toggle('active', c.id === 'tab-graphs'); + }); + UrlState.reset(); + const toastContainer = document.getElementById('toast-container'); + if (toastContainer) toastContainer.innerHTML = ''; + document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove()); + if (typeof renderTrackList === 'function') renderTrackList(); +} + +// ── Boot ────────────────────────────────────────────────────────── +async function init() { + // Wait for fonts to be loaded with a cleaned-up timeout + let fontTimerId: number | null = null; + const fontTimeout = new Promise((resolve) => { + fontTimerId = window.setTimeout(resolve, 1000); + }); + try { + const fontLoadPromise = document.fonts + ? Promise.all([ + document.fonts.load('24px "Material Symbols Rounded"').catch(() => {}), + document.fonts.ready, + ]) + : Promise.resolve(); + await Promise.race([fontLoadPromise, fontTimeout]); + } finally { + if (fontTimerId !== null) window.clearTimeout(fontTimerId); + } + document.body.classList.remove('loading-fonts'); + const storageSelect = document.getElementById( + 'storage-backend-select', + ) as HTMLSelectElement | null; + if (storageSelect) { + storageSelect.value = UrlState.get().storage || 'memory'; + storageSelect.addEventListener('change', (e) => { + const selected = (e.target as HTMLSelectElement).value; + const params = new URLSearchParams(window.location.search); + if (selected === 'memory') { + params.delete('storage'); + } else { + params.set('storage', selected); + } + window.location.search = params.toString(); + }); + } + + const loader = document.getElementById('global-loader'); + const loaderText = document.getElementById('loader-text'); + const loaderSubtext = document.getElementById('loader-subtext'); + const progressBar = document.getElementById('loader-progress-bar') as HTMLElement; + const mapLoader = document.getElementById('map-loader'); + const mapLoaderSpan = mapLoader?.querySelector('span'); + + if (mapLoader) { + if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading database...'; + mapLoader.classList.remove('hidden'); + } + + const urlState = UrlState.get(); + + initInsights((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info')); + initDetails( + () => { + applyFilters(); + syncFiltersToUrl(); + }, + (id: string) => { + deleteTrack(id); + }, + ); + initCombined(); + initCourses((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info')); + + // Init sub-systems + MapView.init( + (id) => selectTrack(id), + onMapMove, + onMapPointClick, + (id, idx) => { + if (id === selectedId) ChartView.setHoverAt(idx); + else ChartView.setHoverAt(null); + }, + onMapDblClick, + ); + ChartView.init(onChartCursorMove, onChartRangeChange, onChartClick, (idx) => { + UrlState.patch({ sel_point: idx }); + }); + + ChartView.setMapColorChangeCb((data) => { + if (data) { + currentMapColors = data.colors; + if (selectedId) MapView.colorTrackByMetric(selectedId, data.pts, data.colors); + } else { + currentMapColors = null; + if (selectedId) MapView.clearMetricColor(selectedId); + } + + // Refresh highlight with new colors if a selection exists + const currentUrlState = UrlState.get(); + if (currentUrlState.sel) + onChartRangeChange(currentUrlState.sel[0], currentUrlState.sel[1], ChartView.getXAxis()); + }); + + applyState(urlState); + + // Reset persistent storage and in-memory state for clean multi-iteration benchmark executions + await Storage.openDB(); + await resetBenchmarkState(); + + // Load persisted tracks + try { + // Load global settings + const hrZones = await Storage.get('hr_zones'); + if (hrZones) Parsers.setHRZones(hrZones); + + const ftp = await Storage.get('ftp'); + if (ftp) Parsers.setFTP(ftp); + + const saved = await Storage.getAll(); + saved.sort((a, b) => a.addedAt - b.addedAt); + + if (mapLoaderSpan) mapLoaderSpan.textContent = `Preparing ${saved.length} tracks...`; + + const tracksToLoad: TrackData[] = []; + for (const t of saved) { + let updated = false; + if (!t.bounds && t.points.length > 0) { + const b = calculateBounds(t.points); + if (b) { + t.bounds = b; + updated = true; + } + } + if (!t.simplifiedPoints && t.points.length > 0) { + t.simplifiedPoints = simplifyTrack(t.points, 50); + updated = true; + } + if (updated) await Storage.save(t); + + tracks[t.id] = t; + tracksToLoad.push(t); + } + MapView.addTracks(tracksToLoad); + applyFilters(); + + const restoreId = + urlState.track && saved.find((t) => t.id === urlState.track) + ? urlState.track + : saved.length > 0 + ? saved[0].id + : null; + + const mapLoader = document.getElementById('map-loader'); + + // 1. Process and load the "Priority" track first + const selectedTrackData = saved.find((t) => t.id === restoreId); + if (selectedTrackData) { + await processAndLoadTrack(selectedTrackData); + selectTrack(selectedTrackData.id, !urlState.map_pos); + + // Explicitly restore selection/pin from URL if they exist + if (urlState.sel && Array.isArray(urlState.sel) && urlState.sel.length === 2) { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + ChartView.restoreSelection(urlState.sel![0], urlState.sel![1]); + }); + }); + } + if (urlState.sel_point !== undefined && urlState.sel_point !== null) { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + ChartView.setCursorAt(urlState.sel_point!); + }); + }); + } + } + + // Hide database loader + if (mapLoader) mapLoader.classList.add('hidden'); + + // 2. Load the rest in background chunks + if (saved.length > (selectedTrackData ? 1 : 0)) { + if (mapLoader) { + if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading tracks...'; + mapLoader.classList.remove('hidden'); + } + + const remaining = saved.filter((t) => t.id !== restoreId); + let index = 0; + + const loadNextChunk = async () => { + const chunkSize = 2; // Process 2 tracks per frame + const end = Math.min(index + chunkSize, remaining.length); + + for (; index < end; index++) await processAndLoadTrack(remaining[index]); + + if (index < remaining.length) { + requestAnimationFrame(loadNextChunk); + } else { + if (mapLoader) mapLoader.classList.add('hidden'); + applyFilters(); // Final sync + if (selectedId && tracks[selectedId]) { + renderEvolution(tracks[selectedId], Object.values(tracks), (trackId, range) => { + selectTrack(trackId, true); + if (range) { + ChartView.restoreSelection(range[0], range[1]); + onChartRangeChange(range[0], range[1], 'time', true); + } + }); + } + // Only fit all if no saved map position and we just finished loading everything + if (saved.length && !urlState.map_pos) MapView.fitAll(); + } + }; + + requestAnimationFrame(loadNextChunk); + } else { + applyFilters(); + if (saved.length && !urlState.map_pos) MapView.fitAll(); + } + } catch (e) { + console.warn('Could not load saved tracks:', e); + } + + // Panel resizers + initResizeHandle(); + initSidebarResizer(); + initMetricPillDraggable(); + updateToolbarLayout(); + + // Basemap switcher + document.getElementById('basemap-switcher')?.addEventListener('click', (e) => { + const btn = (e.target as HTMLElement).closest('.bm-btn') as HTMLElement; + if (!btn) return; + document.querySelectorAll('.bm-btn').forEach((b) => b.classList.remove('active')); + btn.classList.add('active'); + if (btn.dataset.layer) { + MapView.switchBasemap(btn.dataset.layer); + UrlState.patch({ map: btn.dataset.layer }); + } + }); + + // Fit all + document.getElementById('btn-fit-all')?.addEventListener('click', () => MapView.fitAll()); + + // Clear all + document.getElementById('btn-clear-all')?.addEventListener('click', clearAll); + + // Search + document.getElementById('track-search')?.addEventListener('input', (e) => { + searchQuery = (e.target as HTMLInputElement).value; + applyFilters(); + UrlState.patch({ q: searchQuery || null }); + }); + + document.getElementById('btn-regex-toggle')?.addEventListener('click', (e) => { + searchRegex = !searchRegex; + (e.target as HTMLElement).classList.toggle('active', searchRegex); + applyFilters(); + UrlState.patch({ re: searchRegex ? 1 : null }); + }); + + // Sort + document.getElementById('btn-sort-menu')?.addEventListener('click', (e) => { + e.stopPropagation(); + showSortMenu(e.currentTarget as HTMLElement); + }); + + // Metric menu toggle + document.getElementById('btn-metric-menu')?.addEventListener('click', (e) => { + e.stopPropagation(); + showMetricMenu(e.currentTarget as HTMLElement); + }); + + // Metric toggles (shared logic) + const toggleMetric = (metric: string, pill: HTMLElement | null) => { + if (pill) pill.classList.toggle('active'); + ChartView.toggleMetric(metric); + syncMetricsToUrl(); + }; + + document.getElementById('metric-pills')?.addEventListener('click', (e) => { + const pill = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement; + if (pill) { + const metric = pill.dataset.metric; + if (metric) { + toggleMetric(metric, pill); + + // Scroll to it if it became active + if (ChartView.getActiveMetrics().has(metric)) { + const targetEl = document.querySelector(`.chart-row[data-metric="${metric}"]`); + targetEl?.scrollIntoView({ behavior: 'smooth' }); + } + } + } + }); + + // X-axis toggle + document.getElementById('x-axis-ctrl')?.addEventListener('click', (e) => { + const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement; + if (!btn) return; + const axis = btn.dataset.axis!; + ChartView.setXAxis(axis); + document + .querySelectorAll('#x-axis-ctrl .seg-btn') + .forEach((b) => b.classList.toggle('active', b === btn)); + UrlState.patch({ xaxis: axis }); + }); + + // Follow dot + document.getElementById('btn-follow-dot')?.addEventListener('click', (e) => { + followDot = !followDot; + (e.currentTarget as HTMLElement).classList.toggle('active', followDot); + }); + + // Reset zoom + document.getElementById('btn-reset-zoom')?.addEventListener('click', () => { + ChartView.resetZoom(); + MapView.clearHighlight(); + }); + + // File drag/drop + initDropZone(); + + // File browse + document.getElementById('file-input')?.addEventListener('change', (e) => { + handleFiles(Array.from((e.target as HTMLInputElement).files || [])); + (e.target as HTMLInputElement).value = ''; + }); + document.getElementById('folder-input')?.addEventListener('change', (e) => { + handleFiles(Array.from((e.target as HTMLInputElement).files || [])); + (e.target as HTMLInputElement).value = ''; + }); + + // Filters + document.getElementById('btn-toggle-filters')?.addEventListener('click', () => { + const panel = document.getElementById('filter-panel'); + if (panel) { + panel.classList.toggle('hidden'); + document + .getElementById('btn-toggle-filters') + ?.classList.toggle('active', !panel.classList.contains('hidden')); + } + }); + + const onFilterInput = (type: 'date' | 'dist' | 'dur', idx: number, e: Event) => { + const val = (e.target as HTMLInputElement).value; + (filters[type] as any)[idx] = val === '' ? null : val; + applyFilters(); + syncFiltersToUrl(); + }; + + document + .getElementById('filter-date-start') + ?.addEventListener('change', (e) => onFilterInput('date', 0, e)); + document + .getElementById('filter-date-end') + ?.addEventListener('change', (e) => onFilterInput('date', 1, e)); + document + .getElementById('filter-dist-min') + ?.addEventListener('input', (e) => onFilterInput('dist', 0, e)); + document + .getElementById('filter-dist-max') + ?.addEventListener('input', (e) => onFilterInput('dist', 1, e)); + document + .getElementById('filter-dur-min') + ?.addEventListener('input', (e) => onFilterInput('dur', 0, e)); + document + .getElementById('filter-dur-max') + ?.addEventListener('input', (e) => onFilterInput('dur', 1, e)); + + const burgerBtn = document.getElementById('sport-burger-btn'); + const dropdownContent = document.getElementById('sport-dropdown-content'); + burgerBtn?.addEventListener('click', (e) => { + e.stopPropagation(); + if (dropdownContent) { + const isVisible = dropdownContent.style.display === 'block'; + dropdownContent.style.display = isVisible ? 'none' : 'block'; + } + }); + + document.addEventListener('click', (e) => { + if (dropdownContent && dropdownContent.style.display === 'block') { + if (!dropdownContent.contains(e.target as Node) && e.target !== burgerBtn) + dropdownContent.style.display = 'none'; + } + }); + + document.getElementById('sport-filter-container')?.addEventListener('click', (e) => { + const target = e.target as HTMLElement; + const btn = target.closest('[data-sport]'); + if (btn) { + const selectedSport = (btn as HTMLElement).dataset.sport || null; + filters.sport = filters.sport === selectedSport ? null : selectedSport; + applyFilters(); + syncFiltersToUrl(); + updateFilterUI(); + + if (target.closest('.dropdown-item')) { + if (dropdownContent) dropdownContent.style.display = 'none'; + } + } + }); + + document.getElementById('filter-metrics')?.addEventListener('click', (e) => { + const btn = (e.target as HTMLElement).closest('.mini-pill') as HTMLElement; + if (!btn) return; + const m = btn.dataset.metric!; + if (filters.metrics.has(m)) filters.metrics.delete(m); + else filters.metrics.add(m); + updateFilterUI(); + applyFilters(); + syncFiltersToUrl(); + }); + + document.getElementById('btn-reset-filters')?.addEventListener('click', () => { + filters = { + date: [null, null], + dist: [null, null], + dur: [null, null], + metrics: new Set(), + tags: [], + sport: null, + }; + updateFilterUI(); + applyFilters(); + syncFiltersToUrl(); + }); + + document.getElementById('filter-tags')?.addEventListener('input', (e) => { + const val = (e.target as HTMLInputElement).value; + filters.tags = val + .split(',') + .map((s) => s.trim().toLowerCase()) + .filter((s) => !!s); + applyFilters(); + syncFiltersToUrl(); + }); + + // Keyboard shortcuts + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + MapView.hideCursor(); + MapView.closePopup?.(); + // Dismiss popups and modals + document + .querySelectorAll( + '.color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop', + ) + .forEach((el) => el.remove()); + } + }); + + // Resize charts when window changes + window.addEventListener('resize', () => { + ChartView.resize(); + resizeCombined(); + MapView.invalidateSize?.(); + updateToolbarLayout(); + }); + + // Handle back/forward navigation + window.addEventListener('popstate', () => { + UrlState.refresh(); + applyState(UrlState.get()); + }); + + initBenchmarkTriggers(); + await preloadBenchmarkFiles(); + + // Signal to Speedometer test harness that asynchronous initialization has completed + // and benchmark step triggers are bound. + const readyEl = document.createElement('div'); + readyEl.id = 'app-is-ready'; + readyEl.setAttribute('data-ready', 'true'); + readyEl.style.display = 'none'; + document.body.appendChild(readyEl); + + const camelReadyEl = document.createElement('div'); + camelReadyEl.id = 'appIsReady'; + camelReadyEl.setAttribute('data-ready', 'true'); + camelReadyEl.style.display = 'none'; + document.body.appendChild(camelReadyEl); +} + +let preloadedBenchmarkPayloads: + | { + cleanName: string; + buf: ArrayBuffer; + text?: string; + file: File; + }[] + | null = null; + +async function preloadBenchmarkFiles(): Promise< + { cleanName: string; buf: ArrayBuffer; text?: string; file: File }[] +> { + if (preloadedBenchmarkPayloads) return preloadedBenchmarkPayloads; + try { + const manifestResp = await fetch('./test-data/manifest.json'); + const fileNames: string[] = await manifestResp.json(); + const decoder = new TextDecoder(); + preloadedBenchmarkPayloads = await Promise.all( + fileNames.map(async (name) => { + const fileResp = await fetch(`./test-data/${name}`); + let buf = await fileResp.arrayBuffer(); + let cleanName = name; + if (name.toLowerCase().endsWith('.gz')) { + cleanName = name.slice(0, -3); + const bytes = new Uint8Array(buf); + if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) { + const ds = new DecompressionStream('gzip'); + const stream = new Blob([buf]).stream().pipeThrough(ds); + buf = await new Response(stream).arrayBuffer(); + } + } + const text = cleanName.toLowerCase().endsWith('.fit') ? undefined : decoder.decode(buf); + const file = new File([buf], cleanName, { type: 'application/octet-stream' }); + (file as any)._buf = buf; + if (text !== undefined) (file as any)._text = text; + return { cleanName, buf, text, file }; + }), + ); + // Warm up GPX, TCX, and FIT parser and chart code paths during prepare phase + let warmSample: any = null; + for (const idx of [0, 2, 4]) { + if (preloadedBenchmarkPayloads[idx]) { + const parsed = await Parsers.parseFile(preloadedBenchmarkPayloads[idx].file); + if (idx === 0) warmSample = parsed; + } + } + if (warmSample) { + const warmPts = warmSample.points.slice(0, 60); + const warmTrack: TrackData = { + ...warmSample, + id: 'warmup', + fileName: 'warmup.gpx', + fileSize: 1024, + points: warmPts, + stats: Parsers.computeStats(warmPts), + addedAt: 1785542400000, + visible: true, + color: TRACK_COLORS[0], + }; + Parsers.ensureCurvesAndZones(warmTrack); + ChartView.loadTrack(warmTrack, [warmTrack], false); + ChartView.setActiveMetrics(['elevation', 'speed', 'power']); + renderInsights(warmTrack); + renderEvolution(warmTrack, [warmTrack]); + await resetBenchmarkState(); + void document.body.offsetHeight; + await new Promise((r) => window.setTimeout(r, 0)); + } else if (typeof (window as any).__resetBenchmarkSeed === 'function') { + (window as any).__resetBenchmarkSeed(); + } + return preloadedBenchmarkPayloads; + } catch { + return []; + } +} + +function initBenchmarkTriggers() { + const btnLoad = document.getElementById('btn-step-load'); + const btnAnalysis = document.getElementById('btn-step-analysis'); + const btnInsights = document.getElementById('btn-step-insights'); + const btnDetails = document.getElementById('btn-step-details'); + const btnAggregate = document.getElementById('btn-step-aggregate'); + const btnEvolution = document.getElementById('btn-step-evolution'); + const btnCourses = document.getElementById('btn-step-courses'); + + function activateTab(tabName: string) { + document.querySelectorAll('.tab-btn').forEach((b) => { + b.classList.toggle('active', (b as HTMLElement).dataset.tab === tabName); + }); + document.querySelectorAll('.tab-content').forEach((c) => { + c.classList.toggle('active', c.id === `tab-${tabName}`); + }); + UrlState.patch({ tab: tabName }, false); + } + + btnLoad?.addEventListener('click', async () => { + try { + if (Object.keys(tracks).length > 0 || skippedImports.length > 0 || selectedId !== null) { + await Storage.openDB(); + await resetBenchmarkState(); + } else if (typeof (window as any).__resetBenchmarkSeed === 'function') { + (window as any).__resetBenchmarkSeed(); + } + const payloads = await preloadBenchmarkFiles(); + const loadedFiles: File[] = payloads.map((p) => p.file); + await handleFiles(loadedFiles); + const allTracks = Object.values(tracks); + if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id); + } finally { + window.dispatchEvent(new CustomEvent('load-and-parse-complete')); + } + }); + + btnAnalysis?.addEventListener('click', () => { + try { + const allTracks = Object.values(tracks); + activateTab('graphs'); + if (!selectedId && allTracks.length > 0) { + selectTrack(allTracks[0].id); + } + ChartView.restoreSelection(120, 900, true); + ChartView.setCursorAt(300, true); + const availableMetrics = ChartView.getAvailableMetrics(); + const analysisMetrics = ['elevation', 'speed', 'power'].filter((m) => + availableMetrics.has(m), + ); + if (analysisMetrics.length > 0) { + document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => { + const metric = (el as HTMLElement).dataset.metric; + if (metric) el.classList.toggle('active', analysisMetrics.includes(metric)); + }); + updateToolbarLayout(); + ChartView.setActiveMetrics(analysisMetrics); + } else { + updateToolbarLayout(); + } + onChartRangeChange(120, 900, ChartView.getXAxis(), false); + } finally { + window.dispatchEvent(new CustomEvent('analysis-complete')); + } + }); + + btnInsights?.addEventListener('click', () => { + try { + const allTracks = Object.values(tracks); + allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t)); + activateTab('insights'); + const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null; + renderInsights(primaryTrack); + } finally { + window.dispatchEvent(new CustomEvent('insights-complete')); + } + }); + + btnDetails?.addEventListener('click', () => { + try { + const allTracks = Object.values(tracks); + activateTab('details'); + const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null; + renderDetails(primaryTrack, getGlobalTags()); + } finally { + window.dispatchEvent(new CustomEvent('details-complete')); + } + }); + + btnAggregate?.addEventListener('click', () => { + try { + const allTracks = Object.values(tracks); + if (allTracks.length >= 2) { + const selectedTwo = [allTracks[0], allTracks[1]]; + activateTab('combined'); + renderCombined(selectedTwo); + resizeCombined(); + } + } finally { + window.dispatchEvent(new CustomEvent('aggregate-complete')); + } + }); + + btnEvolution?.addEventListener('click', () => { + try { + const allTracks = Object.values(tracks); + activateTab('evolution'); + const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null; + renderEvolution(primaryTrack, allTracks, (trackId, range) => { + selectTrack(trackId, true); + if (range) { + ChartView.restoreSelection(range[0], range[1]); + onChartRangeChange(range[0], range[1], 'time', true); + } + }); + } finally { + window.dispatchEvent(new CustomEvent('evolution-complete')); + } + }); + + btnCourses?.addEventListener('click', () => { + try { + const allTracks = Object.values(tracks); + activateTab('courses'); + prepareBenchmarkCourses(allTracks); + renderCourses(); + selectCourse('course-1', true); + } finally { + window.dispatchEvent(new CustomEvent('courses-complete')); + } + }); + + (window as any).benchmarkSteps = { + loadAndParseFiles: () => document.getElementById('btn-step-load')?.click(), + displayAnalysisMetrics: () => document.getElementById('btn-step-analysis')?.click(), + displayInsights: () => document.getElementById('btn-step-insights')?.click(), + displayDetails: () => document.getElementById('btn-step-details')?.click(), + displayAggregateMetrics: () => document.getElementById('btn-step-aggregate')?.click(), + displayEvolutionMetrics: () => document.getElementById('btn-step-evolution')?.click(), + displayCourses: () => document.getElementById('btn-step-courses')?.click(), + }; +} + +async function processAndLoadTrack(t: TrackData) { + // Migration: re-calculate stats if new insights are missing or old format + const powerCurveEntries = t.stats.powerCurve ? Object.values(t.stats.powerCurve) : []; + + const needsEnrich = + t.points.length > 1 && (t.points[1].speed === undefined || t.points[1].gradient === undefined); + + const needsRecalc = + needsEnrich || + !t.stats.powerCurve || + !t.stats.hrZones || + !t.stats.hrCurve || + t.stats.shifts === undefined || + t.stats.avgBattery === undefined || + t.stats.avgTemp === undefined || + (powerCurveEntries.length > 0 && typeof (powerCurveEntries[0] as any) === 'number') || + ((t.stats.duration || 0) > 10800 * 1000 && t.stats.powerCurve && !t.stats.powerCurve[14400]); + + if (needsRecalc) { + if (needsEnrich) t.points = Parsers.enrichPoints(t.points); + t.stats = Parsers.computeStats(t.points); + await Storage.save(t); + } + + tracks[t.id] = t; + colorIdx = Math.max(colorIdx, TRACK_COLORS.indexOf(t.color) + 1); + MapView.addTrack(t); + MapView.setTrackVisible(t.id, t.visible && !t._filtered); + renderTrackList(); // Progressive list update +} + +function initResizeHandle() { + const handle = document.getElementById('resize-handle'); + const panel = document.getElementById('chart-panel'); + if (!handle || !panel) return; + + let isDragging = false; + + handle.addEventListener('mousedown', () => { + isDragging = true; + document.body.style.cursor = 'ns-resize'; + }); + + document.addEventListener('mousemove', (e) => { + if (!isDragging) return; + const h = window.innerHeight - e.clientY; + const clampedH = Math.max(100, Math.min(window.innerHeight - 100, h)); + panel.style.height = `${clampedH}px`; + ChartView.resize(); + resizeCombined(); + MapView.invalidateSize?.(); + }); + + document.addEventListener('mouseup', () => { + if (!isDragging) return; + isDragging = false; + document.body.style.cursor = ''; + }); +} + +function initSidebarResizer() { + const resizer = document.getElementById('sidebar-resizer'); + const sidebar = document.getElementById('sidebar'); + if (!resizer || !sidebar) return; + + let isDragging = false; + + resizer.addEventListener('mousedown', () => { + isDragging = true; + resizer.classList.add('dragging'); + document.body.classList.add('dragging-sidebar'); + }); + + document.addEventListener('mousemove', (e) => { + if (!isDragging) return; + const w = e.clientX; + const clampedW = Math.max(200, Math.min(600, w)); + sidebar.style.width = `${clampedW}px`; + sidebar.style.setProperty('--sidebar-w', `${clampedW}px`); + ChartView.resize(); + MapView.invalidateSize?.(); + }); + + document.addEventListener('mouseup', () => { + if (!isDragging) return; + isDragging = false; + resizer.classList.remove('dragging'); + document.body.classList.remove('dragging-sidebar'); + }); +} + +// ── Event Handlers ────────────────────────────────────────────── + +function onMapMove(lat: number, lng: number, zoom: number) { + UrlState.patch({ map_pos: [lat, lng, zoom] }); +} + +function onMapPointClick(id: string, idx: number) { + selectTrack(id, false); + ChartView.setCursorAt(idx); +} + +function onMapDblClick() { + // MapView.fitAll(); +} + +function onChartCursorMove(pt: TrackPoint | null) { + if (pt && pt.lat != null && pt.lon != null) { + MapView.showCursorAt(pt.lat, pt.lon); + if (followDot) MapView.centerOn(pt.lat, pt.lon, null, true); + } else { + MapView.hideCursor(); + } +} + +function onChartRangeChange(min: number | null, max: number | null, axis: string, fit = false) { + if (!selectedId || !tracks[selectedId]) return; + const t = tracks[selectedId]; + + if (min === null || max === null) { + MapView.clearHighlight(); + if (t && (UrlState.get().tab || 'graphs') === 'insights') renderInsights(t); + UrlState.patch({ sel: null }); + return; + } + + // Find point indices + const pts = t.points; + let iMin = 0, + iMax = pts.length - 1; + + if (axis === 'distance') { + const d0 = min * 1000, + d1 = max * 1000; + iMin = pts.findIndex((p) => (p.dist || 0) >= d0); + iMax = pts.findIndex((p) => (p.dist || 0) >= d1); + } else { + const t0 = pts.find((p) => p.time != null)?.time || 0; + const ts0 = t0 + min * 1000, + ts1 = t0 + max * 1000; + iMin = pts.findIndex((p) => (p.time || 0) >= ts0); + iMax = pts.findIndex((p) => (p.time || 0) >= ts1); + } + + if (iMin === -1) iMin = 0; + if (iMax === -1) iMax = pts.length - 1; + + // Compute selection stats + const selPts = pts.slice(iMin, iMax + 1); + const stats = Parsers.computeStats(selPts); + ChartView.setSelectionStats(stats); + if ((UrlState.get().tab || 'graphs') === 'insights') renderInsights(t); + + MapView.highlightSegment(selectedId, pts, iMin, iMax, fit, currentMapColors); + MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number])); + UrlState.patch({ sel: [min, max] }); +} + +function onChartClick(pt: TrackPoint, idx: number) { + if (pt && pt.lat != null && pt.lon != null) MapView.centerOn(pt.lat, pt.lon, POINT_ZOOM_LEVEL); +} + +export function selectTrack(id: string, fit = true, deferChartRender = false) { + if (!tracks[id]) return; + if (id === selectedId) { + if (fit) MapView.fitTrack(id); + return; + } + + const hadSelected = selectedId !== null; + if (hadSelected) { + // Clear current views immediately before loading new data + ChartView.clear(); + renderDetails(null, []); + renderInsights(null); + } + + selectedId = id; + + // Fully reset metric coloring when switching tracks + currentMapColors = null; + MapView.clearMetricColor(id); + if (hadSelected) { + ChartView.toggleMapColor(null); // Ensure ChartView state also resets + } + + // Clear selection on new track + UrlState.patch({ track: id, sel: null }, true); + if (hadSelected) { + ChartView.cancelSelection(); + } + + // Update UI immediately + renderTrackList(); + + // Render details + const activeTab = UrlState.get().tab || 'graphs'; + if (activeTab === 'details') renderDetails(tracks[id], getGlobalTags()); + if (activeTab === 'insights') renderInsights(tracks[id]); + if (activeTab === 'combined') renderCombined(tracks[id]); + if (activeTab === 'courses') renderCourses(); + if (activeTab === 'evolution') { + renderEvolution(tracks[id], Object.values(tracks), (trackId, range) => { + selectTrack(trackId, true); + if (range) { + ChartView.restoreSelection(range[0], range[1]); + onChartRangeChange(range[0], range[1], 'time', true); + } + }); + } + + // Tell sub-views + MapView.setSelectedTrack(id, fit); + if (fit) MapView.fitTrack(id); + ChartView.loadTrack(tracks[id], Object.values(tracks), deferChartRender); +} + +async function deleteTrack(id: string) { + await Storage.remove(id); + MapView.removeTrack(id); + delete tracks[id]; + if (selectedId === id) { + selectedId = null; + ChartView.clear(); + renderDetails(null, []); + renderInsights(null); + UrlState.patch({ track: null, sel: null, sel_point: null }); + } + applyFilters(); +} + +async function clearAll() { + const code = Math.floor(10 + Math.random() * 90).toString(); + + const backdrop = document.createElement('div'); + backdrop.className = 'modal-backdrop'; + + backdrop.innerHTML = ` + + `; + + document.body.appendChild(backdrop); + + const input = backdrop.querySelector('.modal-input') as HTMLInputElement; + const btnConfirm = backdrop.querySelector('.modal-btn.confirm') as HTMLButtonElement; + const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement; + + input.focus(); + + input.addEventListener('input', () => { + btnConfirm.disabled = input.value !== code; + }); + + const close = () => backdrop.remove(); + + btnCancel.addEventListener('click', close); + backdrop.addEventListener('click', (e) => { + if (e.target === backdrop) close(); + }); + + btnConfirm.addEventListener('click', async () => { + if (input.value !== code) return; + close(); + + cancelProcessing = true; + await Storage.clear(); + + tracks = {}; + selectedId = null; + MapView.clearHighlight(); + window.location.reload(); + }); +} + +function applyFilters(skipRender = false) { + const ids = Object.keys(tracks); + ids.forEach((id) => { + const t = tracks[id]; + const s = t.stats; + let visible = true; + + // Search query + if (searchQuery) { + if (searchRegex) { + try { + const re = new RegExp(searchQuery, 'i'); + if (!re.test(t.name)) visible = false; + } catch (e) { + visible = false; + } + } else { + if (!t.name.toLowerCase().includes(searchQuery.toLowerCase())) visible = false; + } + } + + // Date filter + if (visible && (filters.date[0] || filters.date[1])) { + const start = filters.date[0] ? new Date(filters.date[0]).getTime() : 0; + const end = filters.date[1] ? new Date(filters.date[1]).getTime() : Infinity; + const t0 = s.startTime || 0; + if (t0 < start || t0 > end) visible = false; + } + + // Distance filter + if (visible && (filters.dist[0] !== null || filters.dist[1] !== null)) { + const min = (filters.dist[0] || 0) * 1000; + const max = (filters.dist[1] || Infinity) * 1000; + if (s.totalDist < min || s.totalDist > max) visible = false; + } + + // Duration filter + if (visible && (filters.dur[0] !== null || filters.dur[1] !== null)) { + const min = (filters.dur[0] || 0) * 60000; + const max = (filters.dur[1] || Infinity) * 60000; + const d = s.duration || 0; + if (d < min || d > max) visible = false; + } + + // Metrics filter + if (visible && filters.metrics.size > 0) { + for (const m of filters.metrics) { + const field = ChartView.METRICS[m].field; + if (!t.points.some((p: any) => p[field] != null)) { + visible = false; + break; + } + } + } + + // Sport filter + if (visible && filters.sport) { + if (t.sport !== filters.sport) visible = false; + } + + // Tags filter + if (visible && filters.tags.length > 0) { + const trackTags = t.tags || []; + if (!filters.tags.every((ft) => trackTags.includes(ft))) visible = false; + } + + t._filtered = !visible; + MapView.setTrackVisible(t.id, t.visible && visible); + }); + + if (!skipRender) renderTrackList(); +} + +function updateFilterUI() { + (document.getElementById('filter-date-start') as HTMLInputElement).value = filters.date[0] || ''; + (document.getElementById('filter-date-end') as HTMLInputElement).value = filters.date[1] || ''; + (document.getElementById('filter-dist-min') as HTMLInputElement).value = + filters.dist[0] !== null ? String(filters.dist[0]) : ''; + (document.getElementById('filter-dist-max') as HTMLInputElement).value = + filters.dist[1] !== null ? String(filters.dist[1]) : ''; + (document.getElementById('filter-dur-min') as HTMLInputElement).value = + filters.dur[0] !== null ? String(filters.dur[0]) : ''; + (document.getElementById('filter-dur-max') as HTMLInputElement).value = + filters.dur[1] !== null ? String(filters.dur[1]) : ''; + (document.getElementById('filter-tags') as HTMLInputElement).value = filters.tags.join(', '); + + document + .querySelectorAll('#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item') + .forEach((el) => { + const item = el as HTMLElement; + item.classList.toggle('active', (item.dataset.sport || '') === (filters.sport || '')); + }); + + document.querySelectorAll('#filter-metrics .mini-pill').forEach((el) => { + const btn = el as HTMLElement; + btn.classList.toggle('active', filters.metrics.has(btn.dataset.metric!)); + }); + + const activeCount = + (filters.date[0] ? 1 : 0) + + (filters.date[1] ? 1 : 0) + + (filters.dist[0] !== null ? 1 : 0) + + (filters.dist[1] !== null ? 1 : 0) + + (filters.dur[0] !== null ? 1 : 0) + + (filters.dur[1] !== null ? 1 : 0) + + filters.metrics.size + + (filters.tags.length > 0 ? 1 : 0); + + const badge = document.querySelector('#btn-toggle-filters .btn-badge'); + if (badge) { + badge.textContent = activeCount > 0 ? String(activeCount) : ''; + badge.classList.toggle('hidden', activeCount === 0); + } +} + +function updateSearchSortUI() { + const searchInput = document.getElementById('track-search') as HTMLInputElement; + if (searchInput) searchInput.value = searchQuery; + document.getElementById('btn-regex-toggle')?.classList.toggle('active', searchRegex); + + const opt = SORT_OPTIONS.find((o) => o.val === currentSort); + if (opt) { + const labelEl = document.getElementById('sort-current-label'); + const iconEl = document.getElementById('sort-current-icon'); + if (labelEl) + labelEl.textContent = opt.label + .replace(' first', '') + .replace(' distance', '') + .replace(' duration', ''); + if (iconEl) iconEl.textContent = opt.icon; + } +} + +function applyState(urlState: AppState) { + // Restore track + const newTrackId = urlState.track; + if (newTrackId !== selectedId) { + if (newTrackId && tracks[newTrackId]) { + selectTrack(newTrackId, true); + } else if (!newTrackId && selectedId) { + selectedId = null; + ChartView.clear(); + renderDetails(null, []); + renderInsights(null); + renderTrackList(); + MapView.fitAll(); + } + } + + // Restore basemap + if (urlState.map && typeof urlState.map === 'string') { + MapView.switchBasemap(urlState.map); + document + .querySelectorAll('.bm-btn') + .forEach((b) => + b.classList.toggle('active', (b as HTMLElement).dataset.layer === urlState.map), + ); + } + + // Restore map position + if (urlState.map_pos) { + const [lat, lng, zoom] = urlState.map_pos; + MapView.setPosition(lat, lng, zoom); + } + + // Restore tab + if (urlState.tab) { + document.querySelectorAll('.tab-btn').forEach((btn) => { + const b = btn as HTMLElement; + if (b.dataset.tab === urlState.tab) { + if (!b.classList.contains('active')) b.click(); + } + }); + } + + // Restore x-axis mode + if (urlState.xaxis) ChartView.setXAxis(urlState.xaxis); + + const currentXAxis = urlState.xaxis || 'time'; + document + .querySelectorAll('#x-axis-ctrl .seg-btn') + .forEach((b) => b.classList.toggle('active', (b as HTMLElement).dataset.axis === currentXAxis)); + + // Restore active metrics + if (urlState.metrics) { + const metrics = ChartView.METRICS; + const keys = urlState.metrics + .map((abbr) => Object.keys(metrics).find((k) => metrics[k].abbr === abbr)) + .filter((k): k is string => k !== undefined); + if (keys.length) ChartView.setActiveMetrics(keys); + } + + // Restore filters + if (urlState.f_date) + filters.date = urlState.f_date.map((v) => v || null) as [string | null, string | null]; + if (urlState.f_dist) + filters.dist = urlState.f_dist.map((v) => (v === 0 ? 0 : v || null)) as [ + number | null, + number | null, + ]; + if (urlState.f_dur) + filters.dur = urlState.f_dur.map((v) => (v === 0 ? 0 : v || null)) as [ + number | null, + number | null, + ]; + if (urlState.f_mets) filters.metrics = new Set(urlState.f_mets); + if (urlState.f_tags) filters.tags = urlState.f_tags; + + updateFilterUI(); + + if (urlState.q) searchQuery = urlState.q; + if (urlState.re) searchRegex = urlState.re; + if (urlState.sort) currentSort = urlState.sort; + updateSearchSortUI(); + + applyFilters(); +} + +function updateSportFilterOptions() { + const container = document.getElementById('sport-filter-container'); + if (!container) return; + + const commonContainer = document.getElementById('common-sports'); + const dropdownContent = document.getElementById('sport-dropdown-content'); + if (!commonContainer || !dropdownContent) return; + + const sports = new Set(); + Object.values(tracks).forEach((t) => { + if (t.sport) sports.add(t.sport); + }); + + const sportsArray = Array.from(sports).sort(); + const burgerDropdown = document.getElementById('sport-burger-dropdown'); + + commonContainer.innerHTML = ''; + dropdownContent.innerHTML = ''; + + if (sportsArray.length <= 4) { + if (burgerDropdown) burgerDropdown.style.display = 'none'; + + sportsArray.forEach((sport) => { + const btn = document.createElement('button'); + btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`; + btn.dataset.sport = sport; + btn.title = sport.charAt(0).toUpperCase() + sport.slice(1); + btn.innerHTML = `${getSportIcon(sport)}`; + commonContainer.appendChild(btn); + }); + } else { + if (burgerDropdown) burgerDropdown.style.display = 'inline-block'; + + const commonSports = ['running', 'cycling', 'walking']; + + commonSports.forEach((sport) => { + if (sports.has(sport)) { + const btn = document.createElement('button'); + btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`; + btn.dataset.sport = sport; + btn.title = sport.charAt(0).toUpperCase() + sport.slice(1); + btn.innerHTML = `${getSportIcon(sport)}`; + commonContainer.appendChild(btn); + } + }); + + sportsArray.forEach((sport) => { + const item = document.createElement('div'); + item.className = `dropdown-item${filters.sport === sport ? ' active' : ''}`; + item.dataset.sport = sport; + item.style.padding = '8px'; + item.style.cursor = 'pointer'; + item.style.display = 'flex'; + item.style.alignItems = 'center'; + item.style.gap = '8px'; + item.innerHTML = ` + ${getSportIcon(sport)} + ${sport.charAt(0).toUpperCase() + sport.slice(1)} + `; + dropdownContent.appendChild(item); + }); + } +} + +function renderTrackList() { + updateSportFilterOptions(); + const list = document.getElementById('track-list'); + const emptyEl = document.getElementById('track-list-empty') as HTMLElement; + const headerLabel = document.querySelector('.section-label'); + if (!list) return; + + const ids = Object.keys(tracks).filter((id) => !tracks[id]._filtered); + if (headerLabel) headerLabel.textContent = `Tracks (${ids.length})`; + + if (!ids.length) { + list.innerHTML = ''; + if (emptyEl) { + list.appendChild(emptyEl); + emptyEl.style.display = 'block'; + } + return; + } + if (emptyEl) emptyEl.style.display = 'none'; + list.innerHTML = ''; + + ids + .sort((a, b) => { + // Current selected always first + if (a === selectedId) return -1; + if (b === selectedId) return 1; + + const ta = tracks[a], + tb = tracks[b]; + const sa = ta.stats, + sb = tb.stats; + + let cmp = 0; + switch (currentSort) { + case 'date-asc': + cmp = (sa.startTime || 0) - (sb.startTime || 0); + break; + case 'date-desc': + cmp = (sb.startTime || 0) - (sa.startTime || 0); + break; + case 'dist-asc': + cmp = (sa.totalDist || 0) - (sb.totalDist || 0); + break; + case 'dist-desc': + cmp = (sb.totalDist || 0) - (sa.totalDist || 0); + break; + case 'dur-asc': + cmp = (sa.duration || 0) - (sb.duration || 0); + break; + case 'dur-desc': + cmp = (sb.duration || 0) - (sa.duration || 0); + break; + default: + cmp = 0; + } + return cmp || a.localeCompare(b); + }) + .forEach((id) => { + list.appendChild(buildTrackItem(tracks[id])); + }); +} + +function getGlobalTags(): string[] { + const all = new Set(); + Object.values(tracks).forEach((t) => { + (t.tags || []).forEach((tag) => all.add(tag)); + }); + return Array.from(all).sort(); +} + +function getSportIcon(sport: string | null): string { + if (!sport) return 'category'; + const s = sport.toLowerCase(); + if (s.includes('run')) return 'directions_run'; + if (s.includes('cycl') || s.includes('bike')) return 'directions_bike'; + if (s.includes('walk')) return 'directions_walk'; + if (s.includes('swim')) return 'pool'; + if (s.includes('hik')) return 'hiking'; + return 'sports'; +} + +function buildTrackItem(track: TrackData) { + const item = document.createElement('div'); + item.className = `track-item${track.id === selectedId ? ' selected' : ''}`; + item.dataset.id = track.id; + + const date = + track.points.length && track.points[0].time ? fmtDate(track.points[0].time) : 'Unknown date'; + + const tagsHtml = + (track.tags || []).length > 0 + ? `
${(track.tags || []) + .map((t) => { + const c = getTagColor(t); + return `${escHtml(t)}`; + }) + .join('')}
` + : ''; + + item.innerHTML = ` +
+
+
${escHtml(track.displayName || track.name)}
+
+
+ ${date} + ${Math.round(track.stats.totalDist / 1000)} km + ${track.sport ? `${getSportIcon(track.sport)}` : ''} + ${track.format.toUpperCase()} +
+ +
+ ${tagsHtml} +
+ `; + + item.addEventListener('click', (e) => { + if ((e.target as HTMLElement).closest('.icon-btn')) return; + selectTrack(track.id); + }); + + const btnVis = item.querySelector('.toggle-vis') as HTMLElement; + btnVis.addEventListener('click', () => { + track.visible = !track.visible; + btnVis.querySelector('.material-symbols-rounded')!.textContent = track.visible + ? 'visibility' + : 'visibility_off'; + MapView.setTrackVisible(track.id, track.visible); + Storage.save(track); + }); + + return item; +} + +function showToast(msg: string, type: 'info' | 'error' = 'info') { + const container = document.getElementById('toast-container'); + if (!container) return; + container.innerHTML = ''; + const t = document.createElement('div'); + t.className = `toast ${type}`; + t.textContent = msg; + container.appendChild(t); +} + +function showSkippedImportsModal() { + const backdrop = document.createElement('div'); + backdrop.className = 'modal-backdrop'; + + let listHtml = ''; + skippedImports.forEach((s) => { + listHtml += `
${s.name}: ${s.reason}
`; + }); + + backdrop.innerHTML = ` + + `; + + document.body.appendChild(backdrop); + + const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement; + const btnClear = backdrop.querySelector('.modal-btn.clear') as HTMLButtonElement; + const close = () => backdrop.remove(); + + btnCancel.addEventListener('click', close); + btnClear.addEventListener('click', () => { + skippedImports = []; + close(); + const importWarning = document.getElementById('import-warning'); + if (importWarning) importWarning.classList.add('hidden'); + }); + + backdrop.addEventListener('click', (e) => { + if (e.target === backdrop) close(); + }); +} + +function initDropZone() { + const zone = document.getElementById('drop-zone'); + if (!zone) return; + + const importWarning = document.getElementById('import-warning'); + if (importWarning) { + importWarning.addEventListener('click', (e) => { + e.stopPropagation(); + showSkippedImportsModal(); + }); + } + + window.addEventListener('dragover', (e) => { + e.preventDefault(); + zone.classList.add('drop-active'); + }); + + window.addEventListener('dragleave', (e) => { + if (e.relatedTarget === null) zone.classList.remove('drop-active'); + }); + + window.addEventListener('drop', async (e) => { + e.preventDefault(); + zone.classList.remove('drop-active'); + + const items = e.dataTransfer?.items; + if (!items) return; + + const files: File[] = []; + const queue: FileSystemEntry[] = []; + + for (let i = 0; i < items.length; i++) { + const entry = items[i].webkitGetAsEntry(); + if (entry) queue.push(entry); + } + + async function readAllEntries(entry: FileSystemEntry) { + if (entry.isFile) { + const file = await new Promise((res) => (entry as FileSystemFileEntry).file(res)); + files.push(file); + } else if (entry.isDirectory) { + const reader = (entry as FileSystemDirectoryEntry).createReader(); + let entries: FileSystemEntry[] = []; + let chunk: FileSystemEntry[]; + do { + chunk = await new Promise((res) => reader.readEntries(res)); + entries.push(...chunk); + } while (chunk.length > 0); + + for (const child of entries) await readAllEntries(child); + } + } + + for (const entry of queue) await readAllEntries(entry); + + if (files.length) handleFiles(files); + }); +} + +async function handleFiles(files: File[]) { + if (!files.length) return; + cancelProcessing = false; + const initialSkipCount = skippedImports.length; + + const loader = document.getElementById('global-loader'); + const loaderText = document.getElementById('loader-text'); + const loaderSubtext = document.getElementById('loader-subtext'); + const progressBar = document.getElementById('loader-progress-bar') as HTMLElement; + const loaderClose = document.getElementById('loader-close'); + + if (loaderClose) { + loaderClose.addEventListener('click', () => { + cancelProcessing = true; + if (loader) loader.classList.add('hidden'); + }); + } + + function updateLoaderIconToWarning() { + const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement; + if (loaderIcon) { + loaderIcon.textContent = 'warning'; + loaderIcon.style.color = '#f59e0b'; + } + const warningCount = document.getElementById('loader-warning-count'); + if (warningCount) { + const count = skippedImports.length - initialSkipCount; + const countSpan = warningCount.querySelector('span'); + if (countSpan) countSpan.textContent = `${count}`; + warningCount.style.display = 'flex'; + } + } + + if (loader) { + if (loaderText) + loaderText.textContent = `Importing ${files.length} file${files.length > 1 ? 's' : ''}`; + const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement; + if (loaderIcon) { + loaderIcon.textContent = 'download'; + loaderIcon.style.color = 'var(--accent)'; + } + const warningCount = document.getElementById('loader-warning-count'); + if (warningCount) { + warningCount.style.display = 'none'; + const countSpan = warningCount.querySelector('span'); + if (countSpan) countSpan.textContent = '0'; + } + if (loaderSubtext) loaderSubtext.textContent = ''; + if (progressBar) progressBar.style.width = '0%'; + loader.classList.remove('hidden'); + + if (skippedImports.length > initialSkipCount) updateLoaderIconToWarning(); + } + + try { + let count = 0; + let firstId: string | null = null; + let processedSinceLastUpdate = 0; + + // Filter out obviously invalid files early + const validFiles = files.filter((f) => { + const name = f.name.toLowerCase(); + return ( + name.endsWith('.gpx') || + name.endsWith('.fit') || + name.endsWith('.tcx') || + name.endsWith('.kml') + ); + }); + + const invalidFiles = files.filter((f) => !validFiles.includes(f)); + invalidFiles.forEach((f) => { + skippedImports.push({ name: f.name, reason: 'Unsupported file format' }); + }); + + if (validFiles.length === 0) { + if (files.length > 0) { + showToast('No valid GPS files found', 'error'); + // Still update warning icon if there were invalid files! + const importWarning = document.getElementById('import-warning'); + if (importWarning && skippedImports.length > 0) { + importWarning.classList.remove('hidden'); + importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`; + } + } + return; + } + + const loaderFilename = document.getElementById('loader-filename'); + let progressIdxEl: HTMLElement | null = null; + if (loaderSubtext) { + loaderSubtext.innerHTML = + ''; + progressIdxEl = loaderSubtext.querySelector('.progress-index') as HTMLElement | null; + const totalEl = loaderSubtext.querySelector('.progress-total'); + if (totalEl) totalEl.textContent = validFiles.length.toString(); + } + + for (let i = 0; i < validFiles.length; i++) { + if (cancelProcessing) break; + const f = validFiles[i]; + if (loaderFilename) loaderFilename.textContent = f.name; + if (progressIdxEl) progressIdxEl.textContent = (i + 1).toString(); + if (progressBar) progressBar.style.width = `${(i / validFiles.length) * 100}%`; + + try { + const data = await Parsers.parseFile(f); + + // Duplicate checks + const existingTracks = Object.values(tracks); + + // Rule 1: Same file and same size + const sameFile = existingTracks.find((t) => t.fileName === f.name && t.fileSize === f.size); + if (sameFile) { + skippedImports.push({ name: f.name, reason: 'Same File' }); + updateLoaderIconToWarning(); + continue; + } + + // Rule 2 & 3: Same start day checks + const newStart = data.stats.startTime; + const newDuration = data.stats.duration; + + if (newStart != null && newDuration != null) { + const newEnd = newStart + newDuration; + const sameDayTracks = existingTracks.filter( + (t) => t.stats.startTime != null && isSameDay(newStart, t.stats.startTime!), + ); + + let discarded = false; + for (const ext of sameDayTracks) { + const extStart = ext.stats.startTime!; + const extDuration = ext.stats.duration!; + const extEnd = extStart + extDuration; + + // Rule 2: Fully contained + if (newStart >= extStart && newEnd <= extEnd) { + skippedImports.push({ name: f.name, reason: 'Fully contained in another track' }); + updateLoaderIconToWarning(); + discarded = true; + break; + } + + // Rule 3: Overlaps for > 10 mins + const overlap = Math.min(newEnd, extEnd) - Math.max(newStart, extStart); + if (overlap > 600000) { + // 10 mins in ms + skippedImports.push({ + name: f.name, + reason: 'Overlaps with an existing track for more than 10 mins', + }); + updateLoaderIconToWarning(); + discarded = true; + break; + } + } + if (discarded) continue; + } + + const fallbackTime = 1785542400000; + let id = compactId(data.stats.startTime || fallbackTime); + if (tracks[id]) id += `-${shortRandom()}`; + + // Use filename as activity name if internal name is generic + let trackName = data.name; + if (trackName.startsWith('Unnamed') || trackName.startsWith('Fit Activity')) + trackName = f.name; + + // Generate a nice display name + let displayName = trackName; + const t0 = data.points[0]?.time; + const sport = data.sport + ? data.sport.charAt(0).toUpperCase() + data.sport.slice(1) + : 'Activity'; + if (t0) { + const d = new Date(t0); + displayName = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')} ${sport}`; + } else { + displayName = trackName.replace(/\.[^/.]+$/, '').replace(/_/g, ' '); // Remove extension and replace underscores + } + + const track: TrackData = { + ...data, + id, + name: trackName, + displayName, + fileName: f.name, + fileSize: f.size, + bounds: calculateBounds(data.points) || undefined, + simplifiedPoints: simplifyTrack(data.points, 50), // 50m resolution + addedAt: data.stats.startTime || fallbackTime, + visible: true, + color: TRACK_COLORS[colorIdx % TRACK_COLORS.length], + }; + colorIdx++; + if (cancelProcessing) break; + + await Storage.save(track); + tracks[id] = track; + MapView.addTrack(track); + if (!firstId) firstId = id; + count++; + processedSinceLastUpdate++; + + if (processedSinceLastUpdate >= 5) { + processedSinceLastUpdate = 0; + } + } catch (err) { + skippedImports.push({ + name: f.name, + reason: `Parse error: ${err instanceof Error ? err.message : String(err)}`, + }); + updateLoaderIconToWarning(); + } + } + + // Update warning icon + const importWarning = document.getElementById('import-warning'); + if (importWarning) { + if (skippedImports.length > 0) { + importWarning.classList.remove('hidden'); + importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`; + } else { + importWarning.classList.add('hidden'); + } + } + + const newWarnings = skippedImports.length > initialSkipCount; + if (!newWarnings && loader) { + loader.classList.add('hidden'); + } + + if (count > 0) { + showToast(`Imported ${count} track${count > 1 ? 's' : ''}`); + applyFilters(!!firstId && firstId !== selectedId); + if (firstId) selectTrack(firstId); + } + + if (newWarnings) { + const loaderIcon = document.querySelector('.loader-icon-wrap span'); + if (loaderIcon) loaderIcon.textContent = 'warning'; + // Delay hiding loader to let user see the alert icon + await new Promise((r) => setTimeout(r, 1500)); + } + } finally { + if (loader) loader.classList.add('hidden'); + } +} + +function initMetricPillDraggable() { + const container = document.getElementById('metric-pills'); + if (!container) return; + + let draggedEl: HTMLElement | null = null; + + container.addEventListener('dragstart', (e) => { + const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement; + if (!target) return; + draggedEl = target; + e.dataTransfer!.effectAllowed = 'move'; + target.classList.add('dragging-pill'); + // For transparent background in ghost image + setTimeout(() => (target.style.opacity = '0.4'), 0); + }); + + container.addEventListener('dragover', (e) => { + e.preventDefault(); + e.dataTransfer!.dropEffect = 'move'; + const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement; + if (target && target !== draggedEl) { + const rect = target.getBoundingClientRect(); + const next = e.clientX - rect.left > rect.width / 2; + container.insertBefore(draggedEl!, next ? target.nextSibling : target); + } + }); + + container.addEventListener('dragend', () => { + if (!draggedEl) return; + draggedEl.classList.remove('dragging-pill'); + draggedEl.style.opacity = ''; + draggedEl = null; + + // Update Chart order + const keys = Array.from(container.querySelectorAll('.metric-pill')).map( + (el) => (el as HTMLElement).dataset.metric!, + ); + ChartView.updateMetricOrder(keys); + syncMetricsToUrl(); + }); +} + +function updateToolbarLayout() { + const toolbar = document.getElementById('chart-toolbar'); + const pills = document.getElementById('metric-pills'); + if (!toolbar || !pills) return; + + toolbar.classList.remove('collapsed'); + const availableW = Math.max(0, toolbar.clientWidth - 280); + let totalW = 0; + let hidden = false; + + Array.from(pills.children).forEach((el) => { + const htmlEl = el as HTMLElement; + if (htmlEl.id === 'pill-overflow') return; + + htmlEl.classList.remove('overflow-hidden'); + if (!htmlEl.classList.contains('active')) return; + const metricKey = htmlEl.dataset.metric || ''; + const deterministicPillWidth = 36 + metricKey.length * 6; + totalW += deterministicPillWidth + 6; + + if (totalW > availableW) { + hidden = true; + htmlEl.classList.add('overflow-hidden'); + } + }); + + const overflowEl = document.getElementById('pill-overflow'); + if (overflowEl) overflowEl.classList.toggle('hidden', !hidden); + + if (hidden) toolbar.classList.add('collapsed'); +} + +document.addEventListener('DOMContentLoaded', init); diff --git a/suites-experimental/tools-gps-tracks/src/benchmark-override.ts b/suites-experimental/tools-gps-tracks/src/benchmark-override.ts new file mode 100644 index 0000000000..aef3b32065 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/benchmark-override.ts @@ -0,0 +1,75 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +// Deterministic PRNG (Mulberry32) for reproducible benchmark runs. +let seed = 0x20260720; +(window as any).__resetBenchmarkSeed = (): void => { + seed = 0x20260720; +}; +Math.random = (): number => { + let t = (seed += 0x6d2b79f5); + t = Math.imul(t ^ (t >>> 15), t | 1); + t ^= t + Math.imul(t ^ (t >>> 7), t | 61); + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; +}; + +window.requestAnimationFrame = (callback: FrameRequestCallback): number => { + return window.setTimeout(() => callback(performance.now()), 0); +}; + +window.cancelAnimationFrame = (id: number): void => { + window.clearTimeout(id); +}; + +// Normalize devicePixelRatio to 1 so uPlot and canvas rendering execute +// identical code paths (e.g. decimation thresholds and canvas dimensions) across browsers. +try { + Object.defineProperty(window, 'devicePixelRatio', { + get: () => 1, + configurable: true, + }); +} catch (_) {} + +// Normalize navigator.language to en-US so Intl.NumberFormat / locale formatters +// produce identical strings across browsers and OS locales. +try { + Object.defineProperty(navigator, 'language', { + get: () => 'en-US', + configurable: true, + }); + Object.defineProperty(navigator, 'languages', { + get: () => ['en-US'], + configurable: true, + }); +} catch (_) {} + +// Normalize CanvasRenderingContext2D.prototype.measureText so canvas layout calculations +// (histogram padding, axis label bounding boxes, cursor pills) do not vary with OS/browser +// system-ui font glyph metrics. +if (typeof CanvasRenderingContext2D !== 'undefined') { + CanvasRenderingContext2D.prototype.measureText = function (text: string): TextMetrics { + const fontStr = this.font || '10px sans-serif'; + const sizeMatch = fontStr.match(/(\d+(?:\.\d+)?)px/); + const fontSize = sizeMatch ? parseFloat(sizeMatch[1]) : 10; + const isBold = /\bbold\b|\b[6-9]00\b/i.test(fontStr); + const charWidth = fontSize * (isBold ? 0.6 : 0.55); + const width = String(text).length * charWidth; + return { + width, + actualBoundingBoxLeft: 0, + actualBoundingBoxRight: width, + actualBoundingBoxAscent: fontSize * 0.8, + actualBoundingBoxDescent: fontSize * 0.2, + fontBoundingBoxAscent: fontSize * 0.8, + fontBoundingBoxDescent: fontSize * 0.2, + emHeightAscent: fontSize * 0.8, + emHeightDescent: fontSize * 0.2, + hangingBaseline: fontSize * 0.8, + alphabeticBaseline: 0, + ideographicBaseline: -fontSize * 0.2, + } as TextMetrics; + }; +} diff --git a/suites-experimental/tools-gps-tracks/src/charts.ts b/suites-experimental/tools-gps-tracks/src/charts.ts new file mode 100644 index 0000000000..c1f59cea7e --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/charts.ts @@ -0,0 +1,3376 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +import uPlot from 'uplot'; +import { TrackPoint, TrackStats, TrackData } from './parsers'; +import { gaussianSmooth, fmtSecs, hexToRgba, fmtPace } from './utils'; +import { Zones } from './zones'; +import { METRICS, MetricDefinition } from './metrics'; +import { UrlState } from './url-state'; +import { SPORTS } from './sports'; + +// Augment uPlot to include our custom property + +interface WegPlot extends uPlot { + _strasse?: { + selFill: HTMLElement; + anchorLine: HTMLElement; + anchorLabel: HTMLElement; + anchorHandle: HTMLElement; + anchorMarker: HTMLElement; + endLine: HTMLElement; + endLabel: HTMLElement; + endHandle: HTMLElement; + endMarker: HTMLElement; + curYVal: HTMLElement; + updateHeaderStats: (min: number, max: number) => void; + }; +} + +interface PlotData { + uplot: WegPlot; + row: HTMLDivElement; + xData: number[]; + yData: (number | null)[]; + def: MetricDefinition; + metricKey: string; + statsTotalEl: HTMLDivElement; + statsSelEl: HTMLDivElement; + histCol: HTMLDivElement; + histCanvas: HTMLCanvasElement; + histData: HistData; + hoveredHistY: number | null; + pinnedHistY: number | null; + smoothed?: boolean; + incZero?: boolean; + w?: number; +} + +interface HistData { + yData: (number | null)[]; + xData: number[]; + def: MetricDefinition; + BINS: number; + plot?: PlotData; + bins?: number[]; + binAccum?: number[]; + min?: number; + max?: number; + padL?: number; + selBins?: number[] | null; + selBinAccum?: number[] | null; + _lastYData?: any; + _lastSelRange?: [number, number] | null; + fullStats?: { min: number; max: number; avg: number } | null; + fullStatsAll?: { min: number; max: number; avg: number } | null; +} + +export const ChartView = (() => { + let plots: PlotData[] = []; + let renderedTrack: TrackData | null = null; + let renderedXAxis: string = 'time'; + let renderedSpeedMode: string = 'speed'; + let renderedMapColorMetric: string | null = null; + let syncKey: { + key: string; + sub: (u: uPlot) => void; + unsub: (u: uPlot) => void; + pub: (type: string, u: uPlot, x: number, y: number, w: number, h: number, i: number) => void; + } | null = null; + let scaleSyncing: boolean = false; + let cursorSyncing: boolean = false; + let activeMetrics: Set = new Set(['elevation']); + let availableMetrics: Set = new Set(); + let smoothedMetrics: Set = new Set(['speed', 'gradient', 'vam', 'temperature']); + let metricsIncludingZero: Set = new Set(['power']); + let xAxis: string = 'time'; + let currentTrack: TrackData | null = null; + let allTracks: TrackData[] = []; + + // Selection / anchor + let selAnchorVal: number | null = null; // x-value at drag-start / zoom left edge + let selEndVal: number | null = null; // x-value at zoom right edge + let isDragging: boolean = false; + let updatingRange: boolean = false; // guard against setScale hook re-entry during handle drag + let pinnedPtIdx: number | null = null; // point index pinned by map click + let lastMouseXVal: number | null = null; // last hovered x-value for keyboard zoom center + let lastHistMouseEvent: MouseEvent | null = null; + let hoveredHistData: HistData | null = null; + let hoveredHistCanvas: HTMLCanvasElement | null = null; + + let currentXRange: [number, number] | null = null; // [min, max] currently rendered + let targetXRange: [number, number] | null = null; // [min, max] for smooth keyboard animation + let animId: number | null = null; + + // Callbacks + let onCursorMoveCb: ((pt: TrackPoint | null) => void) | null = null; + let onRangeChangeCb: ((min: number | null, max: number | null, axis: string) => void) | null = + null; + let onClickCb: ((pt: TrackPoint, idx: number) => void) | null = null; + let onPinChangeCb: ((idx: number | null) => void) | null = null; + + const HIST_W: number = 130; + const ROW_BODY_PADDING: number = 28; // 14px left + 14px right + const HIST_GAP: number = 20; // margin-left on .hist-col + let statsVisible: boolean = true; + let histTooltipEl: HTMLElement | null = null; + let container: HTMLElement | null = null; + let emptyEl: HTMLElement | null = null; + let selStatsEl: HTMLElement | null = null; + let resetSelBtn: HTMLElement | null = null; + let mapColorMetric: string | null = null; + let onMapColorChangeCb: ((data: { pts: TrackPoint[]; colors: string[] } | null) => void) | null = + null; + + // ── Init ────────────────────────────────────────────────────── + function init( + onCursorMove: (pt: TrackPoint | null) => void, + onRangeChange: (min: number | null, max: number | null, axis: string) => void, + onClick: (pt: TrackPoint, idx: number) => void, + onPinChange: (idx: number | null) => void, + ) { + onCursorMoveCb = onCursorMove; + onRangeChangeCb = onRangeChange; + onClickCb = onClick; + onPinChangeCb = onPinChange; + container = document.getElementById('charts-container'); + container?.addEventListener('scroll', () => { + if (lastHistMouseEvent && hoveredHistCanvas && hoveredHistData) + updateHistTooltip(lastHistMouseEvent, hoveredHistCanvas, hoveredHistData); + }); + emptyEl = document.getElementById('chart-empty'); + selStatsEl = document.getElementById('chart-stats-sel'); + resetSelBtn = document.getElementById('btn-reset-selection'); + histTooltipEl = document.getElementById('hist-tooltip'); + syncKey = uPlot.sync('strasse-sync'); + + document.getElementById('sel-cancel-btn')?.addEventListener('click', cancelSelection); + resetSelBtn?.classList.add('hidden'); + + // ── WASD Keyboard Navigation ── + const navKeys = new Set(['w', 'a', 's', 'd']); + const activeNavKeys = new Set(); + + document.addEventListener('keydown', (e) => { + if (!plots.length || !currentTrack) return; + if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName || '')) return; + + const key = e.key.toLowerCase(); + if (!navKeys.has(key)) return; + + e.preventDefault(); + activeNavKeys.add(key); + + const u = plots[0].uplot; + if (!targetXRange) targetXRange = [u.scales.x!.min!, u.scales.x!.max!]; + + let [min, max] = targetXRange; + const span = max - min; + const moveStep = span * 0.1; + const zoomFactor = 0.15; + + let newMin = min, + newMax = max; + + if (key === 'a') { + // Pan left + newMin = min - moveStep; + newMax = max - moveStep; + } else if (key === 'd') { + // Pan right + newMin = min + moveStep; + newMax = max + moveStep; + } else if (key === 'w' || key === 's') { + // Zoom + const center = lastMouseXVal !== null ? lastMouseXVal : (min + max) / 2; + const factor = key === 'w' ? 1 - zoomFactor : 1 + zoomFactor * 1.2; + newMin = center - (center - min) * factor; + newMax = center + (max - center) * factor; + } + + // Clamp to track bounds + const xFull = [plots[0].xData[0]!, plots[0].xData[plots[0].xData.length - 1]!]; + if (newMin < xFull[0]) { + const d = xFull[0] - newMin; + newMin += d; + newMax += d; + } + if (newMax > xFull[1]) { + const d = newMax - xFull[1]; + newMin -= d; + newMax -= d; + } + newMin = Math.max(xFull[0], newMin); + newMax = Math.min(xFull[1], newMax); + + if (newMax - newMin > 0.001) { + targetXRange = [newMin, newMax]; + setVisibleRange(newMin, newMax, true); // true = animate + } + }); + + document.addEventListener('keyup', (e) => { + const key = e.key.toLowerCase(); + if (navKeys.has(key)) activeNavKeys.delete(key); + }); + } + + function setVisibleRange(min: number, max: number, animate = false) { + if (!plots.length) return; + if (!animate) { + plots.forEach(({ uplot: u }) => u.setScale('x', { min, max })); + return; + } + + const startMin = (currentXRange ? currentXRange[0] : plots[0].uplot.scales.x!.min) as number; + const startMax = (currentXRange ? currentXRange[1] : plots[0].uplot.scales.x!.max) as number; + + if (animId) cancelAnimationFrame(animId); + + const lerp = (a: number, b: number, t: number) => a + (b - a) * t; + const factor = 0.25; // Smoothing factor + + const step = () => { + if (!targetXRange) return; + const [tMin, tMax] = targetXRange; + + const cMin = lerp(currentXRange![0], tMin, factor); + const cMax = lerp(currentXRange![1], tMax, factor); + + plots.forEach(({ uplot: u }) => { + u.setScale('x', { min: cMin, max: cMax }); + }); + + if (Math.abs(cMin - tMin) > 0.0001 || Math.abs(cMax - tMax) > 0.0001) + animId = requestAnimationFrame(step); + else animId = null; + }; + animId = requestAnimationFrame(step); + } + + // ── Public API ──────────────────────────────────────────────── + function loadTrack(track: TrackData, others: TrackData[] = [], deferRender = false) { + pinnedPtIdx = null; + selAnchorVal = null; + selEndVal = null; + allTracks = others; + + // Detect which metrics are available in this file + availableMetrics = new Set( + Object.entries(METRICS) + .filter(([, def]) => track.points.some((p) => p[def.field] != null)) + .map(([key]) => key), + ); + + // If no metrics are active (e.g. first load), default to core overview metrics + if (activeMetrics.size === 0) { + activeMetrics = new Set(['elevation'].filter((m) => availableMetrics.has(m))); + } + + // Sync the pill buttons in the toolbar + document.querySelectorAll('.metric-pill').forEach((el) => { + const pill = el as HTMLElement; + const metric = pill.dataset.metric!; + const isAvailable = availableMetrics.has(metric); + pill.classList.toggle('active', isAvailable && activeMetrics.has(metric)); + pill.classList.toggle('disabled', !isAvailable); + }); + + currentTrack = track; + if (deferRender) { + updateStats(track); + } else { + render(); + } + } + + function clear() { + pinnedPtIdx = null; + selAnchorVal = null; + selEndVal = null; + currentTrack = null; + destroyPlots(); + if (emptyEl) { + emptyEl.style.display = 'flex'; + emptyEl.innerHTML = ` + no_sim +
Select a track to view analysis
+ `; + } + const chartStats = document.getElementById('chart-stats'); + if (chartStats) chartStats.classList.add('hidden'); + clearSelectionStats(); + mapColorMetric = null; + if (onMapColorChangeCb) onMapColorChangeCb(null); + } + + function resetState() { + if (animId !== null) { + cancelAnimationFrame(animId); + animId = null; + } + activeMetrics = new Set(['elevation']); + availableMetrics = new Set(); + smoothedMetrics = new Set(['speed', 'gradient', 'vam', 'temperature']); + metricsIncludingZero = new Set(['power']); + xAxis = 'time'; + allTracks = []; + currentXRange = null; + targetXRange = null; + lastMouseXVal = null; + lastHistMouseEvent = null; + hoveredHistData = null; + hoveredHistCanvas = null; + statsVisible = true; + clear(); + document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => { + const pill = el as HTMLElement; + pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!)); + pill.classList.remove('disabled', 'overflow-hidden'); + }); + const overflowEl = document.getElementById('pill-overflow'); + if (overflowEl) overflowEl.classList.add('hidden'); + const toolbar = document.getElementById('chart-toolbar'); + if (toolbar) toolbar.classList.remove('collapsed'); + document.querySelectorAll('#x-axis-ctrl .seg-btn').forEach((b) => { + b.classList.toggle('active', (b as HTMLElement).dataset.axis === 'time'); + }); + } + + function toggleMetric(key: string) { + if (activeMetrics.has(key)) activeMetrics.delete(key); + else activeMetrics.add(key); + if (currentTrack) render(true); + } + + function setActiveMetrics(keys: string[]) { + activeMetrics = new Set(keys); + if (currentTrack) render(true); + // Sync the pill buttons + document.querySelectorAll('.metric-pill').forEach((el) => { + const pill = el as HTMLElement; + pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!)); + }); + } + + function setXAxis(axis: string) { + if (xAxis === axis || !currentTrack) { + xAxis = axis; + return; + } + + const pts = currentTrack.points; + const t0 = pts.find((p) => p.time != null)?.time || 0; + + // Helper to convert a value from OLD axis to NEW axis + const convert = (val: number | null) => { + if (val === null) return null; + // We need to find the point index closest to 'val' on the OLD axis + let idx = 0; + if (xAxis === 'distance') { + const dTarget = val * 1000; + idx = pts.findIndex((p) => (p.dist || 0) >= dTarget); + } else { + const tTarget = t0 + val * 1000; + idx = pts.findIndex((p) => (p.time || 0) >= tTarget); + } + if (idx === -1) idx = pts.length - 1; + + // Now get the value at this index on the NEW axis + if (axis === 'distance') return (pts[idx].dist || 0) / 1000; + else return ((pts[idx].time || t0) - t0) / 1000; + }; + + // Convert selection + if (selAnchorVal !== null) selAnchorVal = convert(selAnchorVal); + if (selEndVal !== null) selEndVal = convert(selEndVal); + + // Convert zoom range (from first plot) + let newRange: [number, number] | null = null; + if (plots.length) { + const u = plots[0].uplot; + const r0 = convert(u.scales.x!.min!); + const r1 = convert(u.scales.x!.max!); + if (r0 !== null && r1 !== null) newRange = [r0, r1]; + } + + xAxis = axis; + render(true); + + // Apply converted zoom + if (newRange) { + scaleSyncing = true; + plots.forEach(({ uplot: u }) => { + u.batch(() => u.setScale('x', { min: newRange![0], max: newRange![1] })); + }); + scaleSyncing = false; + } + } + + function toggleStats() { + statsVisible = !statsVisible; + plots.forEach(({ histCol }) => histCol.classList.toggle('visible', statsVisible)); + resize(); + } + + function setMapColorChangeCb(cb: (data: { pts: TrackPoint[]; colors: string[] } | null) => void) { + onMapColorChangeCb = cb; + } + + function toggleMapColor(key: string | null) { + if (mapColorMetric === key || key === null) { + mapColorMetric = null; + _updateMapColorBtns(); + if (onMapColorChangeCb) onMapColorChangeCb(null); + } else { + mapColorMetric = key; + _updateMapColorBtns(); + _fireMapColorCb(); + } + // Re-render to show/hide colored fills on the graphs + if (currentTrack) render(true); + } + + function _updateMapColorBtns() { + document.querySelectorAll('.map-color-btn').forEach((el) => { + const b = el as HTMLElement; + b.classList.toggle('active', b.dataset.metric === mapColorMetric); + }); + } + + function _fireMapColorCb() { + if (!onMapColorChangeCb || !mapColorMetric || !currentTrack) return; + const plot = plots.find((p) => p.metricKey === mapColorMetric); + if (!plot) return; + const colors = _computePointColors(mapColorMetric, plot.yData); + onMapColorChangeCb({ pts: currentTrack.points, colors }); + } + + function _computePointColors(key: string, yData: (number | null)[]): string[] { + const vals = yData.filter((v): v is number => v != null && isFinite(v)); + if (!vals.length) return yData.map(() => '#888896'); + const min = Math.min(...vals), + max = Math.max(...vals); + + const sport = currentTrack?.sport; + const sportDef = sport ? SPORTS[sport.toLowerCase()] : null; + const defaultMode = sportDef?.defaultPreset || 'speed'; + const urlState = UrlState.get(); + const speedMode = (urlState as any).speed_mode || defaultMode; + const paceUnit = sportDef?.paceUnit || 'km'; + + return yData.map((v) => { + if (v == null || !isFinite(v)) return '#888896'; + if (key === 'gradient') return gradientColor(v); + if (key === 'speed') { + if (speedMode === 'pace') { + const speed = (paceUnit === 'km' ? 1000 : 100) / v; + return speedColor(speed); + } + return speedColor(v); + } + const t = max === min ? 0.5 : Math.max(0, Math.min(1, (v - min) / (max - min))); + if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); + if (t <= 0.5) return lerpHex('#91bfdb', '#fee090', (t - 0.25) / 0.25); + if (t <= 0.75) return lerpHex('#fee090', '#fc8d59', (t - 0.5) / 0.25); + return lerpHex('#fc8d59', '#d73027', (t - 0.75) / 0.25); + }); + } + + function resetZoom() { + cancelSelection(); + } + + function cancelSelection() { + selAnchorVal = null; + selEndVal = null; + pinnedPtIdx = null; + if (onPinChangeCb) onPinChangeCb(null); + + // Reset individual histogram pins + plots.forEach((p) => { + p.pinnedHistY = null; + }); + + updateSelOverlay(); + redrawHistograms(); + + // Perform the actual zoom reset + scaleSyncing = true; + plots.forEach(({ uplot: u, xData }) => { + u.batch(() => u.setScale('x', { min: xData[0]!, max: xData[xData.length - 1]! })); + u._strasse?.updateHeaderStats(xData[0]!, xData[xData.length - 1]!); + }); + scaleSyncing = false; + + if (onRangeChangeCb) onRangeChangeCb(null, null, xAxis); + } + + function setSelectionStats(stats: TrackStats) { + if (!selStatsEl) return; + const fmt = (id: string, val: string) => { + const el = document.querySelector(`#${id} .stat-value`); + if (el) el.textContent = val; + }; + fmt( + 'sel-distance', + stats.totalDist != null ? `${(stats.totalDist / 1000).toFixed(1)} km` : '—', + ); + fmt('sel-duration', stats.duration != null ? fmtSecs(Math.floor(stats.duration / 1000)) : '—'); + fmt('sel-elevation', stats.elevGain != null ? `${Math.round(stats.elevGain)} m` : '—'); + fmt( + 'sel-avg-speed', + stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '—', + ); + fmt('sel-avg-power', stats.avgPower != null ? `${stats.avgPower} W` : '—'); + fmt('sel-avg-hr', stats.avgHR != null ? `${stats.avgHR} bpm` : '—'); + fmt('sel-avg-temp', stats.avgTemp != null ? `${stats.avgTemp.toFixed(1)} °C` : '—'); + selStatsEl.classList.remove('hidden'); + if (resetSelBtn) resetSelBtn.classList.remove('hidden'); + } + + function clearSelectionStats() { + if (selStatsEl) selStatsEl.classList.add('hidden'); + if (resetSelBtn) resetSelBtn.classList.add('hidden'); + [ + 'sel-distance', + 'sel-duration', + 'sel-elevation', + 'sel-avg-speed', + 'sel-avg-power', + 'sel-avg-hr', + 'sel-avg-temp', + ].forEach((id) => { + const el = document.querySelector(`#${id} .stat-value`); + if (el) el.textContent = '--'; + }); + } + + // Called on boot to restore a saved selection without re-firing onRangeChangeCb + // xMin/xMax are ALWAYS provided in Time (seconds from start) + function restoreSelection(tMin: number, tMax: number, deferRender = false) { + if (!currentTrack) return; + const pts = currentTrack.points; + const t0 = pts.find((p) => p.time != null)?.time || 0; + const totalDuration = ((pts[pts.length - 1]?.time || 0) - t0) / 1000; + + // If values look like absolute timestamps in ms, convert to seconds from start + if (tMin > 1e12) tMin = (tMin - t0) / 1000; + if (tMax > 1e12) tMax = (tMax - t0) / 1000; + + // Crop to max limits of the track + tMin = Math.max(0, Math.min(tMin, totalDuration)); + tMax = Math.max(0, Math.min(tMax, totalDuration)); + + const convert = (tOffset: number) => { + if (xAxis === 'time') return tOffset; + const tTarget = t0 + tOffset * 1000; + let idx = pts.findIndex((p) => (p.time || 0) >= tTarget); + if (idx === -1) idx = pts.length - 1; + return (pts[idx].dist || 0) / 1000; + }; + + const xMin = convert(tMin); + const xMax = convert(tMax); + + selAnchorVal = xMin; + selEndVal = xMax; + currentXRange = [xMin, xMax]; + if (deferRender) return; + scaleSyncing = true; // suppress the setScale → onRangeChangeCb loop + plots.forEach(({ uplot: u }) => { + u.batch(() => u.setScale('x', { min: xMin, max: xMax })); + }); + scaleSyncing = false; + updateAnchorLines(); + redrawHistograms(); + } + + function resize() { + if (!plots.length || !container) return; + const w = Math.round( + Math.max( + 100, + container.getBoundingClientRect().width - + ROW_BODY_PADDING - + (statsVisible ? HIST_W + HIST_GAP : 0), + ), + ); + let anyResized = false; + plots.forEach(({ uplot: u, histCanvas, histData }) => { + if (w !== u.width) { + u.setSize({ width: w, height: u.height }); + anyResized = true; + if (statsVisible && histCanvas && histData) drawHistogram(histCanvas, histData, u.height); + } + }); + if (anyResized) updateSelOverlay(); + } + + // ── Render ──────────────────────────────────────────────────── + function render(keepState = false) { + let savedRange: [number, number] | null = null; + let savedScroll = 0; + if (keepState && container) savedScroll = container.scrollTop; + + if (keepState && currentXRange) { + savedRange = [currentXRange[0], currentXRange[1]]; + } else if (keepState && plots.length) { + const u = plots[0].uplot; + savedRange = [u.scales.x!.min!, u.scales.x!.max!]; + } + + if (!currentTrack) { + destroyPlots(keepState); + return; + } + const pts = currentTrack.points; + if (!pts.length) { + destroyPlots(keepState); + return; + } + + const sport = currentTrack?.sport; + const sportDef = sport ? SPORTS[sport.toLowerCase()] : null; + const defaultMode = sportDef?.defaultPreset || 'speed'; + const urlState = UrlState.get(); + const speedMode = (urlState as any).speed_mode || defaultMode; + const paceUnit = sportDef?.paceUnit || 'km'; + + const available = [...activeMetrics].filter((m) => + pts.some((p) => p[METRICS[m].field] != null), + ); + if (!available.length) { + destroyPlots(keepState); + if (emptyEl) { + emptyEl.style.display = 'flex'; + emptyEl.innerHTML = ` + no_sim +
No data for selected metrics
+ `; + } + return; + } + if (emptyEl) emptyEl.style.display = 'none'; + + const containerW = container ? container.getBoundingClientRect().width : 800; + const w = Math.round( + Math.max(100, containerW - ROW_BODY_PADDING - (statsVisible ? HIST_W + HIST_GAP : 0)), + ); + + const canReuse = + keepState && + renderedTrack === currentTrack && + renderedXAxis === xAxis && + renderedSpeedMode === speedMode && + renderedMapColorMetric === mapColorMetric && + plots.length > 0; + + let xData: (number | null)[]; + if (canReuse) { + xData = plots[0].xData; + } else if (xAxis === 'distance') { + xData = pts.map((p) => (p.dist || 0) / 1000); + } else { + const t0 = pts.find((p) => p.time != null)?.time || 0; + let lastValidX = 0; + xData = pts.map((p) => { + if (p.time != null) { + lastValidX = (p.time - t0) / 1000; + return lastValidX; + } + return lastValidX; // monotonic fallback + }); + } + + const existingByKey = new Map(); + if (canReuse) { + if (histTooltipEl) histTooltipEl.style.display = 'none'; + const availSet = new Set(available); + for (const p of plots) { + const isSmoothed = smoothedMetrics.has(p.metricKey); + const isIncZero = metricsIncludingZero.has(p.metricKey); + if ( + availSet.has(p.metricKey) && + p.smoothed === isSmoothed && + p.incZero === isIncZero && + p.w === w + ) { + existingByKey.set(p.metricKey, p); + } else { + syncKey!.unsub(p.uplot); + p.uplot.destroy(); + p.row.remove(); + } + } + plots = []; + } else { + destroyPlots(keepState); + } + + if (container) { + const nextSiblingRows: (HTMLElement | null)[] = new Array(available.length).fill(null); + let nextExisting: HTMLElement | null = null; + for (let i = available.length - 1; i >= 0; i--) { + nextSiblingRows[i] = nextExisting; + const ex = existingByKey.get(available[i]); + if (ex) nextExisting = ex.row; + } + + available.forEach((key, idx) => { + const reused = existingByKey.get(key); + if (reused) { + plots.push(reused); + const uplot = reused.uplot; + const s = (uplot as any)._strasse; + const prevSync = scaleSyncing; + scaleSyncing = true; + uplot.batch(() => { + if ( + savedRange && + (uplot.scales.x!.min !== savedRange[0] || uplot.scales.x!.max !== savedRange[1]) + ) { + uplot.setScale('x', { min: savedRange[0], max: savedRange[1] }); + } else { + s?.updateHeaderStats(uplot.scales.x!.min!, uplot.scales.x!.max!, uplot); + uplot.redraw(false); + } + }); + scaleSyncing = prevSync; + + let initHoverBinI: number | null = null; + if ( + pinnedPtIdx != null && + reused.xData[pinnedPtIdx] != null && + reused.yData[pinnedPtIdx] != null + ) { + buildHistBins(reused.histData); + if (reused.histData.min != null && reused.histData.max != null) { + const span = reused.histData.max - reused.histData.min || 1; + initHoverBinI = Math.min( + reused.histData.BINS - 1, + Math.floor( + ((reused.yData[pinnedPtIdx]! - reused.histData.min) / span) * + reused.histData.BINS, + ), + ); + reused.hoveredHistY = reused.yData[pinnedPtIdx]; + } + } + drawHistogram(reused.histCanvas, reused.histData, 130, initHoverBinI); + return; + } + + let def = METRICS[key]; + + let transform = def.transform; + let fmt = def.fmt; + let fmtAxis = def.fmtAxis; + let unit = def.unit; + let label = def.label; + + if (key === 'speed' && speedMode === 'pace') { + label = 'Pace'; + unit = `min/${paceUnit}`; + fmt = (v) => fmtPace(v); + fmtAxis = (v) => fmtPace(v); + transform = (v) => { + if (v == null || v < 0.1) return null; + return (paceUnit === 'km' ? 1000 : 100) / v; + }; + + def = { ...def, label, unit, fmt, fmtAxis, transform }; + } + + let yData = def.compute + ? def.compute(pts, fillNulls) + : fillNulls( + pts.map((p) => { + const v = p[def.field] as number; + return v != null && transform ? transform(v) : v; + }), + ); + + if (smoothedMetrics.has(key)) yData = gaussianSmooth(yData, def.smoothSigma || 2); + + createChart(key, def, xData, yData, w, pts, savedRange, nextSiblingRows[idx]); + }); + } + + renderedTrack = currentTrack; + renderedXAxis = xAxis; + renderedSpeedMode = speedMode; + renderedMapColorMetric = mapColorMetric; + + updateStats(currentTrack); + // Restore anchor/end lines if a selection was active + if (selAnchorVal != null && selEndVal != null) updateAnchorLines(); + // Re-apply map color if active + _updateMapColorBtns(); + if (mapColorMetric) _fireMapColorCb(); + + if (keepState && container && savedScroll > 0) container.scrollTop = savedScroll; + } + + // ── Create one chart row ─────────────────────────────────────── + function createChart( + metricKey: string, + def: MetricDefinition, + xData: (number | null)[], + yData: (number | null)[], + w: number, + pts: TrackPoint[], + initialRange: [number, number] | null = null, + insertBeforeEl: HTMLElement | null = null, + ) { + const sport = currentTrack?.sport; + const sportDef = sport ? SPORTS[sport.toLowerCase()] : null; + const defaultMode = sportDef?.defaultPreset || 'speed'; + const urlState = UrlState.get(); + const speedMode = (urlState as any).speed_mode || defaultMode; + + // Gradient data: smooth over a 20 m distance window (±10 m each side) + const gradData = metricKey === 'elevation' ? smoothGradient(pts, 20) : null; + const row = document.createElement('div'); + row.className = 'chart-row'; + row.dataset.metric = metricKey; + row.style.setProperty('--chart-color', def.color); + + // Header + const header = document.createElement('div'); + header.className = `chart-row-header${statsVisible ? ' with-histogram' : ''}`; + + const labelEl = document.createElement('div'); + labelEl.className = 'chart-row-label-group'; + labelEl.innerHTML = ` + ${def.icon} + ${def.label} + `; + + // Smoothing toggle + const smoothBtn = document.createElement('button'); + smoothBtn.className = `icon-btn mini smooth-btn${smoothedMetrics.has(metricKey) ? ' active' : ''}`; + smoothBtn.title = 'Toggle data smoothing'; + smoothBtn.innerHTML = `${smoothedMetrics.has(metricKey) ? 'blur_on' : 'blur_off'}`; + smoothBtn.addEventListener('click', (e) => { + e.stopPropagation(); + if (smoothedMetrics.has(metricKey)) smoothedMetrics.delete(metricKey); + else smoothedMetrics.add(metricKey); + + render(true); // Re-render all charts to keep sync if needed (though only this one changes data) + }); + + const mapColorBtn = document.createElement('button'); + + mapColorBtn.className = `map-color-btn icon-btn${mapColorMetric === metricKey ? ' active' : ''}`; + mapColorBtn.dataset.metric = metricKey; + mapColorBtn.title = 'Color map track by this metric'; + mapColorBtn.innerHTML = 'colorize'; + mapColorBtn.addEventListener('click', () => toggleMapColor(metricKey)); + + // Zero-filter toggle (Cadence/Power/Speed) + let zeroBtn: HTMLButtonElement | null = null; + if (metricKey === 'cadence' || metricKey === 'power' || metricKey === 'speed') { + zeroBtn = document.createElement('button'); + const incZero = metricsIncludingZero.has(metricKey); + zeroBtn.className = `icon-btn mini${incZero ? ' active' : ''}`; + zeroBtn.title = incZero ? 'Currently INCLUDING 0 values' : 'Currently EXCLUDING 0 values'; + zeroBtn.innerHTML = `${incZero ? 'exposure_zero' : 'mobile_off'}`; + zeroBtn.addEventListener('click', (e) => { + e.stopPropagation(); + if (metricsIncludingZero.has(metricKey)) metricsIncludingZero.delete(metricKey); + else metricsIncludingZero.add(metricKey); + render(true); + }); + } + + const statsTotalEl = document.createElement('div'); + statsTotalEl.className = 'chart-stats-total'; + + const statsSelEl = document.createElement('div'); + statsSelEl.className = 'chart-stats-selection'; + + const statsContainer = document.createElement('div'); + statsContainer.className = 'chart-row-stats-container'; + statsContainer.append(statsTotalEl, statsSelEl); + + const actionsEl = document.createElement('div'); + actionsEl.className = 'chart-row-actions'; + actionsEl.append(smoothBtn, mapColorBtn); + + const rightActionsEl = document.createElement('div'); + rightActionsEl.className = 'chart-row-right-actions'; + + if (metricKey === 'speed') { + const paceToggle = document.createElement('div'); + paceToggle.className = 'seg-ctrl'; + paceToggle.innerHTML = ` + + + `; + paceToggle.addEventListener('click', (e) => { + const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement; + if (!btn) return; + const mode = btn.dataset.mode; + if (mode === 'speed' || mode === 'pace') { + const isDefault = mode === defaultMode; + UrlState.patch({ speed_mode: isDefault ? null : mode }); + render(true); + } + }); + rightActionsEl.append(paceToggle); + } + + if (zeroBtn) rightActionsEl.append(zeroBtn); + + header.append(labelEl, actionsEl, statsContainer, rightActionsEl); + + const rowBody = document.createElement('div'); + rowBody.className = 'chart-row-body'; + + const plotEl = document.createElement('div'); + plotEl.style.position = 'relative'; + rowBody.appendChild(plotEl); + + const fixedMinLabel = document.createElement('div'); + fixedMinLabel.className = 'fixed-x-label fixed-x-min'; + const fixedMaxLabel = document.createElement('div'); + fixedMaxLabel.className = 'fixed-x-label fixed-x-max'; + plotEl.append(fixedMinLabel, fixedMaxLabel); + + const histCol = document.createElement('div'); + histCol.className = `hist-col${statsVisible ? ' visible' : ''}`; + const histCanvas = document.createElement('canvas'); + histCanvas.className = 'hist-canvas'; + histCol.appendChild(histCanvas); + rowBody.appendChild(histCol); + + row.append(header, rowBody); + + const isDistAxis = xAxis === 'distance'; + + function formatX(v: number, range: number): string { + if (v == null) return ''; + if (isDistAxis) { + const dec = range < 1 ? 3 : range < 5 ? 2 : range < 20 ? 1 : 0; + return `${v.toFixed(dec)} km`; + } else { + const absV = Math.abs(v); + const h = Math.floor(absV / 3600); + const m = Math.floor((absV % 3600) / 60); + const s = Math.round(absV % 60); + const hh = h > 0 ? `${h}:` : ''; + const mm = h > 0 ? String(m).padStart(2, '0') : String(m); + const ss = String(s).padStart(2, '0'); + return `${v < 0 ? '-' : ''}${hh}${mm}:${ss}`; + } + } + + const incZeroDefault = + metricsIncludingZero.has(metricKey) || + (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed'); + + // Compute global Y range and full-track stats in a single pass + let gMin = Infinity, + gMax = -Infinity, + allSum = 0, + allCount = 0, + filtMin = Infinity, + filtMax = -Infinity, + filtSum = 0, + filtCount = 0; + for (let i = 0; i < yData.length; i++) { + const v = yData[i]; + if (v == null || !isFinite(v)) continue; + if (v < gMin) gMin = v; + if (v > gMax) gMax = v; + allSum += v; + allCount++; + if (v !== 0 || incZeroDefault) { + if (v < filtMin) filtMin = v; + if (v > filtMax) filtMax = v; + filtSum += v; + filtCount++; + } + } + if (allCount === 0) { + gMin = 0; + gMax = 100; + } + const fullStatsAll = allCount ? { min: gMin, max: gMax, avg: allSum / allCount } : null; + const fullStatsFiltered = filtCount + ? { min: filtMin, max: filtMax, avg: filtSum / filtCount } + : null; + const gPad = Math.abs(gMax - gMin) * 0.1 || 1; + const fixedYRange = [gMin - gPad, gMax + gPad]; + + let statsTotalInitialized = false; + + // Per-range stats + function updateHeaderStats(visibleMin: number, visibleMax: number, u?: uPlot) { + const incZero = + metricsIncludingZero.has(metricKey) || + (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed'); + + // Update fixed X labels + const range = visibleMax - visibleMin; + fixedMinLabel.textContent = formatX(visibleMin, range); + fixedMaxLabel.textContent = formatX(visibleMax, range); + + const getHtml = (xMin: number, xMax: number, isFull = false) => { + const s = + isFull && incZero === incZeroDefault + ? fullStatsFiltered + : rangeStats(xData, yData, xMin, xMax, incZero); + if (!s) return ''; + + let h = ` + align_flex_end${def.fmt(s.min, true)} ${def.unit} + align_center${def.fmt(s.avg, true)} ${def.unit} + align_flex_start${def.fmt(s.max, true)} ${def.unit} + `; + + if (metricKey === 'elevation') { + const es = elevationRangeStats(pts, xMin, xMax); + h += ` + trending_up+${Math.round(es.gain)} m + trending_down-${Math.round(es.loss)} m + `; + } + return h; + }; + + if (!statsTotalInitialized) { + statsTotalInitialized = true; + statsTotalEl.innerHTML = `all_inclusive${getHtml( + xData[0]!, + xData[xData.length - 1]!, + true, + )}`; + statsTotalEl.querySelector('.all-chip')?.addEventListener('click', (e) => { + e.stopPropagation(); + cancelSelection(); + }); + } + + if (selAnchorVal !== null && selEndVal !== null) { + statsSelEl.innerHTML = getHtml(selAnchorVal, selEndVal, false); + statsSelEl.style.display = 'flex'; + statsSelEl.style.setProperty('--sel-color', def.color); + } else { + statsSelEl.style.display = 'none'; + } + } + let initializingScale = false; + const uOpts: uPlot.Options = { + width: w, + height: 130, + padding: [4, 0, 0, 0], + cursor: { + sync: { + key: syncKey!.key, + }, + drag: { x: true, y: false, uni: 16 }, + focus: { prox: 16 }, + points: { + size: 7, + stroke: '#0e0e10', + width: 2, + fill: (metricKey === 'elevation' + ? (u: uPlot, _si: number) => gradientColor(gradData ? gradData[u.cursor.idx!]! : null) + : def.color) as any, + }, + x: false, + y: false, + }, + select: { + show: true, + left: 0, + top: 0, + width: 0, + height: 0, + }, + legend: { show: false }, + scales: { + x: { + time: false, + range: (_u: uPlot, mn: number, mx: number) => [mn, mx], + min: initialRange ? initialRange[0] : undefined, + max: initialRange ? initialRange[1] : undefined, + }, + y: { + range: () => fixedYRange as [number, number], + dir: metricKey === 'speed' && speedMode === 'pace' ? -1 : 1, + }, + }, + axes: [ + { + side: 2, // bottom + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + ticks: { + show: true, + stroke: '#2e2e34', + }, + size: 30, + space: 80, + font: '10px system-ui, sans-serif', + splits: (u: uPlot, axisIdx: number, scaleMin: number, scaleMax: number) => { + const range = scaleMax - scaleMin; + const width = u.bbox.width > 0 ? u.bbox.width : u.width; + const targetLabels = width / 80; + const idealIncr = range / targetLabels; + + let incrs; + if (!isDistAxis) { + // Time in seconds + incrs = [ + 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 14400, 28800, 43200, + 86400, 604800, 2592000, 31536000, + ]; + } else { + incrs = [ + 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, + 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, + ]; + } + + let incr = incrs[incrs.length - 1]; + for (let i = 0; i < incrs.length; i++) { + if (incrs[i] >= idealIncr) { + incr = incrs[i]; + break; + } + } + + const splits = []; + let val = Math.ceil(scaleMin / incr) * incr; + const precision = incr < 1 ? 2 : 0; + + while (val <= scaleMax) { + const pos = u.valToPos(val, 'x', true); + if (pos >= u.bbox.left + 80 && pos <= u.bbox.left + u.bbox.width - 80) + splits.push(Number(val.toFixed(precision))); + + val += incr; + } + return splits; + }, + values: ((_u: uPlot, vals: number[]) => { + const range = (_u.scales.x?.max ?? 1) - (_u.scales.x?.min ?? 0); + + return vals.map((v) => { + if (v == null) return ''; + const pos = _u.valToPos(v, 'x', true); + // Strict 80px margin to prevent overlapping with fixed labels or Y axis + if (pos < _u.bbox.left + 80 || pos > _u.bbox.left + _u.bbox.width - 80) return null; + return formatX(v, range); + }); + }) as any, + }, + { + side: 3, // left + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + ticks: { stroke: '#2e2e34' }, + size: 55, + font: '10px system-ui, sans-serif', + values: ((_u: uPlot, vals: number[]) => + vals.map((v) => (v != null ? def.fmtAxis(v) : ''))) as any, + }, + ], + series: [ + {}, + // Main selected track series + { + label: def.label, + stroke: 'rgba(0,0,0,0)', // Stroke handled in draw hooks for layering + width: 0, + points: { show: false }, + paths: () => null, + }, + ], + hooks: { + draw: [ + (u: uPlot) => { + const top = u.bbox.top + u.bbox.height + 5; // 5px below plot area! + fixedMinLabel.style.top = `${top}px`; + fixedMinLabel.style.left = `${u.bbox.left}px`; + + fixedMaxLabel.style.top = `${top}px`; + fixedMaxLabel.style.left = `${u.bbox.left + u.bbox.width}px`; + fixedMaxLabel.style.transform = 'translateX(-100%)'; + }, + // 1. (bottom) Color / metric color of the selected track + (u: uPlot) => { + if (metricKey === 'gears') { + drawTrackPath( + u, + xData as number[], + yData as number[], + def.color, + 1.5, + metricKey, + null, + pts, + ); + } else if (metricKey === 'elevation') { + drawElevationGradient(u, xData as number[], yData as number[], gradData); + } else if (metricKey === 'gradient') { + drawGradientChart(u, xData as number[], yData as number[]); + } else if (mapColorMetric === metricKey) { + drawMetricColorFill(u, xData as number[], yData as number[], pts, metricKey); + } else { + // Normal colored line + drawTrackPath( + u, + xData as number[], + yData as number[], + def.color, + 1.5, + metricKey, + null, + pts, + ); + } + }, + + // 2. Pinned point (middle) + (u: uPlot) => { + const plot = plots.find((p) => p.uplot === u); + if (!plot) return; + + const s = (u as any)._strasse; + // Priority 1: Global pinned point (all charts) + if (pinnedPtIdx != null) { + drawPinnedDot(u, xData, yData, def.color, def, pts, metricKey); + } else { + if (s && s.pinYVal) s.pinYVal.style.display = 'none'; + + // Priority 2: Individual histogram pinned Y-pos (this chart only) + if (plot.pinnedHistY != null) + drawYAxisHighlight(u, xData, yData, plot.pinnedHistY, def.color, def); + } + }, + + // 3. Pinned & Hover elements (labels, vertical lines) + (u: uPlot) => { + const hIdx = u.cursor.idx; + const hasPinned = pinnedPtIdx != null; + + let hasHover = hIdx != null && u.cursor.left! >= 0; + if (hasHover && pinnedPtIdx == null) { + const cy = u.valToPos(yData[hIdx!]!, 'y', true); + const dist = Math.abs(u.cursor.top! - cy); + if (dist > 100) hasHover = false; + } + + // B. Draw Hover vertical line + if (hasHover && hIdx !== pinnedPtIdx) + drawVerticalLineOnly(u, pts, hIdx!, hexToRgba(def.color, 0.4), 1.0); + + // C. Bold selection x-axis line & span pill + if (selAnchorVal != null && selEndVal != null) { + const ctx = u.ctx; + const dpr = window.devicePixelRatio || 1; + const bb = u.bbox; + const ax = u.valToPos(selAnchorVal, 'x', true); + const ex = u.valToPos(selEndVal, 'x', true); + + ctx.save(); + ctx.beginPath(); + ctx.lineWidth = 3 * dpr; + ctx.strokeStyle = def.color; + ctx.moveTo(ax, bb.top + bb.height); + ctx.lineTo(ex, bb.top + bb.height); + ctx.stroke(); + + const span = Math.abs(selEndVal - selAnchorVal); + const label = xAxis === 'distance' ? `${span.toFixed(2)} km` : fmtSecs(span); + const fontSize = 9 * dpr; + const fontStr = `bold ${fontSize}px system-ui, sans-serif`; + if (ctx.font !== fontStr) ctx.font = fontStr; + const tw = ctx.measureText(label).width; + + const visibleL = Math.max(bb.left, ax); + const visibleR = Math.min(bb.left + bb.width, ex); + const visibleW = visibleR - visibleL; + + if (visibleW > tw + 14 * dpr) { + const padH = 5 * dpr; + const padV = 2 * dpr; + const bw = tw + padH * 2; + const bh = fontSize + padV * 2; + const bx = (visibleL + visibleR) / 2 - bw / 2; + const by = bb.top + bb.height - bh / 2; + + ctx.beginPath(); + if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr); + else ctx.rect(bx, by, bw, bh); + ctx.fillStyle = def.color; + ctx.fill(); + + ctx.fillStyle = '#000'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(label, bx + bw / 2, by + bh / 2); + } + ctx.restore(); + } + + // D. Draw label pills (on top) + // Pinned labels first (semi-transparent) + if (hasPinned) drawXAxisLabels(u, pts, pinnedPtIdx!, def.color, true, 0.7); + + // Hover labels last (fully opaque, topmost) + if (hasHover && hIdx !== pinnedPtIdx) + drawXAxisLabels(u, pts, hIdx!, def.color, true, 1.0); + }, + ], + setCursor: [ + (u: uPlot) => { + if (scaleSyncing) return; + const idx = u.cursor.idx; + + // Trigger redraw on cursor move to ensure custom canvas markers (hover lines/labels) update live + // Note: uPlot handles cross-chart sync when syncKey is used. + u.redraw(false); + + // Track current x-value for keyboard navigation + if (u.cursor.left! >= 0) lastMouseXVal = u.posToVal(u.cursor.left!, 'x'); + else lastMouseXVal = null; + + // ── Floating y-value next to cursor dot ── + const s = (u as any)._strasse; + let showHover = idx != null && yData[idx] != null; + + // Distance threshold: if no pinned point, check proximity to data line + if (showHover && pinnedPtIdx == null) { + const cy = u.valToPos(yData[idx!]!, 'y', true); + const dist = Math.abs(u.cursor.top! - cy); + if (dist > 100) showHover = false; + } + + if (s) { + if (showHover) + updateTooltip( + u, + s.curYVal, + idx!, + xData as number[], + yData as number[], + pts, + def, + metricKey, + ); + else s.curYVal.style.display = 'none'; + } + + // Map marker + if (!cursorSyncing) { + if (idx != null && pts[idx]) { + if (onCursorMoveCb && (pinnedPtIdx != null || showHover)) { + onCursorMoveCb(pts[idx]); + } else if (onCursorMoveCb && !showHover) { + // If we're too far and nothing is pinned, hide map cursor + onCursorMoveCb(null); + } + } else if (idx === null && onCursorMoveCb) { + onCursorMoveCb(null); + } + } + + // Highlight matching histogram bucket + if (idx != null && yData[idx] != null) { + const { min, max } = histData; + if (min != null && max != null) { + const span = max - min || 1; + const binI = Math.min( + histData.BINS - 1, + Math.floor(((yData[idx]! - min) / span) * histData.BINS), + ); + if (plot.hoveredHistY !== yData[idx]) { + plot.hoveredHistY = yData[idx]; + drawHistogram(histCanvas, histData, 130, binI); + } + } + } else if (plot.hoveredHistY !== null) { + plot.hoveredHistY = null; + drawHistogram(histCanvas, histData, 130); + } + }, + ], + + setScale: [ + (u: uPlot, key: string) => { + if (key !== 'x' || initializingScale) return; + const { min, max } = u.scales.x!; + + // Sync currentXRange so keyboard navigation baseline is always accurate + currentXRange = [min!, max!]; + + // Update header stats for VISIBLE range + updateHeaderStats(min as number, max as number, u); + + if (scaleSyncing) return; + + // Clear keyboard target when user interacts via mouse + if (!updatingRange) targetXRange = null; + + // Sync sibling plots + scaleSyncing = true; + plots.forEach(({ uplot: other }) => { + if (other !== u) other.batch(() => other.setScale('x', { min: min!, max: max! })); + }); + scaleSyncing = false; + + updateSelOverlay(); + redrawHistograms(); + + if (onRangeChangeCb && selAnchorVal !== null) + onRangeChangeCb(selAnchorVal, selEndVal, xAxis); + }, + ], + + setSelect: [ + (u: uPlot) => { + if (updatingRange) return; + targetXRange = null; + const { left, width } = u.select; + if (width > 0) { + const min = u.posToVal(left, 'x'); + const max = u.posToVal(left + width, 'x'); + selAnchorVal = min; + selEndVal = max; + + // Sync stats to new selection + updateHeaderStats(u.scales.x!.min!, u.scales.x!.max!, u); + updateSelOverlay(); + redrawHistograms(); + + if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis); + + // Clear uPlot's internal selection immediately so it doesn't block WASD/interaction + u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false); + } + }, + ], + }, + }; + + // ── Overlay (pointer-events off except handles) ── + const overlay = document.createElement('div'); + overlay.style.cssText = + 'position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5'; + + // Selection fill + const selFill = document.createElement('div'); + selFill.className = 'sel-fill'; + selFill.style.display = 'none'; + + // Anchor line + label + drag handle + const anchorLine = document.createElement('div'); + anchorLine.className = 'sel-line sel-line-anchor'; + anchorLine.style.display = 'none'; + + const anchorLabel = document.createElement('div'); + anchorLabel.className = 'sel-line-label sel-line-label-anchor'; + anchorLabel.style.display = 'none'; + + const anchorHandle = document.createElement('div'); + anchorHandle.className = 'sel-handle sel-handle-anchor'; + anchorHandle.style.display = 'none'; + + const anchorMarker = document.createElement('div'); + anchorMarker.className = 'sel-graph-marker'; + anchorMarker.innerHTML = + 'play_circle'; + anchorMarker.style.display = 'none'; + + // End line + label + drag handle + const endLine = document.createElement('div'); + endLine.className = 'sel-line sel-line-end'; + endLine.style.display = 'none'; + + const endLabel = document.createElement('div'); + endLabel.className = 'sel-line-label sel-line-label-end'; + endLabel.style.display = 'none'; + + const endHandle = document.createElement('div'); + endHandle.className = 'sel-handle sel-handle-end'; + endHandle.style.display = 'none'; + + const endMarker = document.createElement('div'); + endMarker.className = 'sel-graph-marker'; + endMarker.innerHTML = + 'stop_circle'; + endMarker.style.display = 'none'; + + // Floating cursor y-value + const curYVal = document.createElement('div'); + curYVal.className = 'cur-y-val'; + curYVal.style.cssText = `color:${def.color};display:none`; + + // Floating pinned y-value + const pinYVal = document.createElement('div'); + pinYVal.className = 'cur-y-val pin'; + pinYVal.style.cssText = `color:${def.color};display:none`; + + overlay.append( + selFill, + anchorLine, + anchorLabel, + anchorHandle, + anchorMarker, + endLine, + endLabel, + endHandle, + endMarker, + curYVal, + pinYVal, + ); + + const histData: HistData = { + yData, + xData: xData as number[], + def, + BINS: 24, + min: allCount ? gMin : undefined, + max: allCount ? gMax : undefined, + fullStats: fullStatsFiltered, + fullStatsAll, + }; + const plot: PlotData = { + uplot: null as any, + row, + xData: xData as number[], + yData, + def, + metricKey, + statsTotalEl, + statsSelEl, + histCol, + histCanvas, + histData, + hoveredHistY: null, + pinnedHistY: null, + smoothed: smoothedMetrics.has(metricKey), + incZero: metricsIncludingZero.has(metricKey), + w, + }; + histData.plot = plot; // Back-reference for tooltip to trigger redraws + + const prevSync = scaleSyncing; + scaleSyncing = true; + const uplot = new uPlot(uOpts, [xData, yData] as any, (self, init) => { + plot.uplot = self as WegPlot; + plots.push(plot); + plotEl.appendChild(self.root); + self.over.appendChild(overlay); + (self as any)._strasse = { + selFill, + anchorLine, + anchorLabel, + anchorHandle, + anchorMarker, + endLine, + endLabel, + endHandle, + endMarker, + curYVal, + pinYVal, + updateHeaderStats, + }; + self.batch(() => { + init(); + }); + }) as WegPlot; + scaleSyncing = prevSync; + + // ── Handle drag ── + attachHandleDrag(anchorHandle, uplot, xData, true); + attachHandleDrag(endHandle, uplot, xData, false); + + // ── Mouse listeners ── + let mousedownX: number | null = null; + uplot.over.addEventListener('mousedown', (e) => { + if (e.button !== 0) return; + isDragging = false; + const rect = uplot.over.getBoundingClientRect(); + const xPx = e.clientX - rect.left; + mousedownX = xPx; + }); + uplot.over.addEventListener('mousemove', (e) => { + if (mousedownX !== null) { + const rect = uplot.over.getBoundingClientRect(); + if (Math.abs(e.clientX - rect.left - mousedownX) > 5) isDragging = true; + } + }); + uplot.over.addEventListener('mouseup', () => { + mousedownX = null; + }); + + // Click to pin point (sticky selection) + uplot.over.addEventListener('click', () => { + if (isDragging) return; + const idx = uplot.cursor.idx; + if (idx != null && pts[idx]) { + pinnedPtIdx = idx; + plots.forEach(({ uplot: u }) => u.redraw(false)); + if (onClickCb) onClickCb(pts[idx], idx); + if (onPinChangeCb) onPinChangeCb(idx); + } + }); + + row.addEventListener('dblclick', cancelSelection); + + let initHoverBinI: number | null = null; + if (pinnedPtIdx != null && xData[pinnedPtIdx] != null && yData[pinnedPtIdx] != null) { + buildHistBins(histData); + if (histData.min != null && histData.max != null) { + const span = histData.max - histData.min || 1; + initHoverBinI = Math.min( + histData.BINS - 1, + Math.floor(((yData[pinnedPtIdx]! - histData.min) / span) * histData.BINS), + ); + plot.hoveredHistY = yData[pinnedPtIdx]; + } + } + + drawHistogram(histCanvas, histData, 130, initHoverBinI); + attachHistTooltip(histCanvas, histData); + if (container) { + if (insertBeforeEl) container.insertBefore(row, insertBeforeEl); + else container.appendChild(row); + } + } + + // ── Selection overlay (fill + lines + handles) ─────────────── + function updateSelOverlay() { + updateAnchorLines(); + // Redraw canvas markers (bold selection line + span pill) + plots.forEach(({ uplot: u }) => u.batch(() => u.redraw(false))); + } + + function updateAnchorLines() { + plots.forEach(({ uplot: u, def }) => { + const s = (u as any)._strasse; + if (!s) return; + const { + selFill, + anchorLine, + anchorLabel, + anchorHandle, + anchorMarker, + endLine, + endLabel, + endHandle, + endMarker, + } = s; + if (selAnchorVal == null || selEndVal == null) { + [ + selFill, + anchorLine, + anchorLabel, + anchorHandle, + anchorMarker, + endLine, + endLabel, + endHandle, + endMarker, + ].forEach((el: HTMLElement) => { + el.style.display = 'none'; + }); + return; + } + const aX = u.valToPos(selAnchorVal, 'x'); + const eX = u.valToPos(selEndVal, 'x'); + const dpr = window.devicePixelRatio || 1; + const bb = u.bbox; + const overW = bb.width / dpr; + const overH = bb.height / dpr; + const plotBottom = (bb.top + bb.height) / dpr; + + const isAnchorVisible = aX >= 0 && aX <= overW; + const isEndVisible = eX >= 0 && eX <= overW; + + // Fill: clamp left/right to visible area + const fillL = Math.max(0, aX); + const fillR = Math.min(overW, eX); + if (fillR > fillL) { + selFill.style.left = `${fillL}px`; + selFill.style.width = `${fillR - fillL}px`; + selFill.style.top = '0'; + selFill.style.height = `${overH}px`; + selFill.style.backgroundColor = hexToRgba(def.color, 0.07); + selFill.style.display = ''; + } else { + selFill.style.display = 'none'; + } + + // Anchor line + if (isAnchorVisible) { + anchorLine.style.left = `${aX}px`; + anchorLine.style.height = `${overH}px`; + anchorLine.style.borderLeftColor = def.color; + anchorLine.style.display = ''; + // Anchor label + const aText = fmtXVal(selAnchorVal); + anchorLabel.textContent = aText; + const aLabelW = aText.length * 7 + 10; + anchorLabel.style.left = aX + aLabelW + 4 < overW ? `${aX + 3}px` : `${aX - aLabelW - 3}px`; + anchorLabel.style.display = ''; + // Anchor handle + anchorHandle.style.left = `${aX}px`; + anchorHandle.style.backgroundColor = def.color; + anchorHandle.style.display = ''; + // Anchor marker: centered on the bold line + anchorMarker.style.left = `${aX}px`; + anchorMarker.style.top = `${plotBottom}px`; + const aIcon = anchorMarker.querySelector('.material-symbols-rounded') as HTMLElement; + if (aIcon) aIcon.style.color = def.color; + anchorMarker.style.display = ''; + } else { + [anchorLine, anchorLabel, anchorHandle, anchorMarker].forEach( + (el: HTMLElement) => (el.style.display = 'none'), + ); + } + + // End line + if (isEndVisible) { + endLine.style.left = `${eX}px`; + endLine.style.height = `${overH}px`; + endLine.style.borderLeftColor = def.color; + endLine.style.display = ''; + // End label + const eText = fmtXVal(selEndVal); + endLabel.textContent = eText; + const eLabelW = eText.length * 7 + 10; + endLabel.style.left = eX - eLabelW - 3 > 0 ? `${eX - eLabelW - 3}px` : `${eX + 3}px`; + endLabel.style.display = ''; + // End handle + endHandle.style.left = `${eX}px`; + endHandle.style.backgroundColor = def.color; + endHandle.style.display = ''; + // End marker: centered on the bold line + endMarker.style.left = `${eX}px`; + endMarker.style.top = `${plotBottom}px`; + const eIcon = endMarker.querySelector('.material-symbols-rounded') as HTMLElement; + if (eIcon) eIcon.style.color = def.color; + endMarker.style.display = ''; + } else { + [endLine, endLabel, endHandle, endMarker].forEach( + (el: HTMLElement) => (el.style.display = 'none'), + ); + } + }); + } + + function fmtXVal(v: number) { + return xAxis === 'distance' ? `${v.toFixed(2)} km` : fmtSecs(v); + } + + // ── Handle drag logic ───────────────────────────────────────── + function attachHandleDrag( + handleEl: HTMLElement, + uplot: uPlot, + xData: (number | null)[], + isAnchor: boolean, + ) { + // pointer-events enabled on the handle itself + handleEl.style.pointerEvents = 'auto'; + + handleEl.addEventListener('mousedown', (e) => { + e.stopPropagation(); + e.preventDefault(); + const startX = e.clientX; + const startVal = isAnchor ? selAnchorVal : selEndVal; + const overW = uplot.over.offsetWidth; + // px-per-data-unit at current zoom + const xMin = uplot.scales.x!.min!, + xMax = uplot.scales.x!.max!; + const pxPerUnit = overW / (xMax - xMin); + const xFull = [xData[0]!, xData[xData.length - 1]!]; + + document.body.style.cursor = 'ew-resize'; + isDragging = true; + + function onMove(me: MouseEvent) { + const dx = me.clientX - startX; + let newVal = (startVal || 0) + dx / pxPerUnit; + newVal = Math.max(xFull[0], Math.min(xFull[1], newVal)); + + if (isAnchor) selAnchorVal = Math.min(newVal, (selEndVal || xFull[1]) - 0.001); + else selEndVal = Math.max(newVal, (selAnchorVal || xFull[0]) + 0.001); + + // When dragging handles, we typically want to stay zoomed to the selection? + // Actually, let's keep the zoom as is, and just update the selection overlay and stats. + plots.forEach((p) => + (p.uplot as any)._strasse?.updateHeaderStats( + p.uplot.scales.x!.min!, + p.uplot.scales.x!.max!, + ), + ); + updateSelOverlay(); + redrawHistograms(); + if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis); + } + + function onUp() { + document.body.style.cursor = ''; + isDragging = false; + document.removeEventListener('mousemove', onMove); + document.removeEventListener('mouseup', onUp); + } + + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onUp); + }); + } + + // ── Histogram logic ────────────────────────────────────────── + function buildHistBins(histData: HistData) { + const { yData, xData, BINS } = histData; + + // Cache to avoid re-binning every frame during hover + if (histData._lastYData === yData && histData.bins) return; + histData._lastYData = yData; + + let min = histData.min; + let max = histData.max; + if (min == null || max == null) { + let lo = Infinity, + hi = -Infinity, + cnt = 0; + for (let i = 0; i < yData.length; i++) { + const v = yData[i]; + if (v == null || !isFinite(v)) continue; + if (v < lo) lo = v; + if (v > hi) hi = v; + cnt++; + } + if (!cnt) return; + min = lo; + max = hi; + histData.min = min; + histData.max = max; + } + + const bins = new Array(BINS).fill(0); + const binAccum = new Array(BINS).fill(0); // accumulated x-weight per bin (time in s or dist in km) + + const span = max - min || 1; + const metricKey = + histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def); + const incZero = + !metricKey || + metricsIncludingZero.has(metricKey) || + (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed'); + + for (let i = 0; i < yData.length; i++) { + const v = yData[i]; + if (v == null || !isFinite(v)) continue; + if (v === 0 && !incZero) continue; + + const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS)); + bins[bi]++; + + // weight by x-delta + const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!; + const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!; + binAccum[bi] += (next - prev) / 2; + } + histData.bins = bins; + histData.binAccum = binAccum; + } + + function redrawHistograms() { + plots.forEach(({ histCanvas, histData, uplot: u }) => { + drawHistogram(histCanvas, histData, u.height); + }); + } + + function drawHistogram( + canvas: HTMLCanvasElement, + histData: HistData, + chartH: number, + hoverBinI: number | null = null, + ) { + const { def, BINS } = histData; + buildHistBins(histData); + const { bins, min, max } = histData; + if (!bins || min == null || max == null) return; + + const hasSel = selAnchorVal != null && selEndVal != null; + + // Compute selection bins if a range is active and changed + if ( + hasSel && + (histData._lastSelRange?.[0] !== selAnchorVal || histData._lastSelRange?.[1] !== selEndVal) + ) { + histData._lastSelRange = [selAnchorVal!, selEndVal!]; + const selBins = new Array(BINS).fill(0); + const selBinAccum = new Array(BINS).fill(0); + const { yData, xData } = histData; + const span = max - min || 1; + const metricKey = + histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def); + const incZero = + !metricKey || + metricsIncludingZero.has(metricKey) || + (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed'); + + for (let i = 0; i < yData.length; i++) { + const v = yData[i]; + if (v == null || !isFinite(v)) continue; + if (v === 0 && !incZero) continue; + + const x = xData[i]; + if (x == null || x < selAnchorVal! || x > selEndVal!) continue; + const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS)); + selBins[bi]++; + const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!; + const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!; + selBinAccum[bi] += (next - prev) / 2; + } + histData.selBins = selBins; + histData.selBinAccum = selBinAccum; + } else if (!hasSel) { + histData.selBins = null; + histData.selBinAccum = null; + histData._lastSelRange = null; + } + const selBins = histData.selBins; + + const dpr = window.devicePixelRatio || 1; + const W = HIST_W; + const H = chartH; + + // Performance: only set dimensions if they changed (resets canvas) + if (canvas.width !== W * dpr || canvas.height !== H * dpr) { + canvas.width = W * dpr; + canvas.height = H * dpr; + canvas.style.width = `${W}px`; + canvas.style.height = `${H}px`; + } + + const ctx = canvas.getContext('2d')!; + ctx.resetTransform(); + ctx.scale(dpr, dpr); + ctx.clearRect(0, 0, W, H); + + const peak = Math.max(...bins); + + // Measure label width so bars start right after them + const fmt = (v: number) => def.fmtAxis(v); + const fontStr = '9px system-ui, sans-serif'; + if (ctx.font !== fontStr) ctx.font = fontStr; + const labelW = Math.ceil( + Math.max( + ctx.measureText(`${fmt(max)} ${def.unit}`).width, + ctx.measureText(`${fmt(min)} ${def.unit}`).width, + ), + ); + + // Vertical alignment with main graph: + // uPlot padding: [4, 0, 0, 0] + // Axis size: 30 + const pad = { t: 4, r: 0, b: 30, l: labelW + 6 }; + histData.padL = pad.l; + const plotW = W - pad.l - pad.r; + const plotH = H - pad.t - pad.b; + + // bin 0 = lowest values → drawn at bottom; bin BINS-1 = highest → drawn at top + const binY = (i: number) => pad.t + (BINS - 1 - i) * (plotH / BINS); + const binH = plotH / BINS - 1; + + // Full distribution (dimmed when selection active) + const baseAlpha = hasSel ? 0.15 : 0.6; + ctx.fillStyle = hexToRgba(def.color, baseAlpha); + for (let i = 0; i < BINS; i++) { + if (!bins[i]) continue; + const bw = (bins[i] / peak) * plotW; + ctx.fillRect(pad.l, binY(i), bw, binH); + } + + // Selection overlay (bright) + if (selBins) { + ctx.fillStyle = hexToRgba(def.color, 0.85); + for (let i = 0; i < BINS; i++) { + if (!selBins[i]) continue; + const bw = (selBins[i] / peak) * plotW; + ctx.fillRect(pad.l, binY(i), bw, binH); + } + ctx.fillStyle = def.color; + ctx.fillRect(pad.l, pad.t, 2, plotH); + } + + // CDF overlay — smooth curve from bottom (0%) to top (100%) + const total = bins.reduce((s, v) => s + v, 0); + if (total > 0) { + // Build CDF points: one per bin boundary, bottom→top + const pts2 = [{ x: pad.l, y: pad.t + plotH }]; + let cumSum = 0; + for (let i = 0; i < BINS; i++) { + cumSum += bins[i]; + pts2.push({ x: pad.l + (cumSum / total) * plotW, y: binY(i) }); + } + + ctx.beginPath(); + // CDF line is now solid + ctx.setLineDash([]); + ctx.strokeStyle = def.color; + ctx.lineWidth = 0.75 * dpr; + ctx.lineJoin = 'round'; + ctx.moveTo(pts2[0].x, pts2[0].y); + for (let i = 1; i < pts2.length - 1; i++) { + const mx = (pts2[i].x + pts2[i + 1].x) / 2; + const my = (pts2[i].y + pts2[i + 1].y) / 2; + ctx.quadraticCurveTo(pts2[i].x, pts2[i].y, mx, my); + } + ctx.lineTo(pts2[pts2.length - 1].x, pts2[pts2.length - 1].y); + ctx.stroke(); + + // ── Hover highlight on CDF ── + if (hoverBinI != null && pts2[hoverBinI + 1]) { + const cp = pts2[hoverBinI + 1]; + // Vertical line down + ctx.beginPath(); + ctx.setLineDash([2 * dpr, 2 * dpr]); + ctx.strokeStyle = hexToRgba(def.color, 0.6); + ctx.moveTo(cp.x, cp.y); + ctx.lineTo(cp.x, pad.t + plotH); + ctx.stroke(); + ctx.setLineDash([]); + + // Dot: tiny precision point + ctx.beginPath(); + ctx.arc(cp.x, cp.y, 1.2 * dpr, 0, Math.PI * 2); + ctx.fillStyle = '#0e0e10'; + ctx.fill(); + ctx.strokeStyle = def.color; + ctx.lineWidth = 1 * dpr; + ctx.stroke(); + } + } + + // Axis labels: max at top, min at bottom + if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896'; + const font9 = '9px system-ui, sans-serif'; + if (ctx.font !== font9) ctx.font = font9; + ctx.textAlign = 'right'; + + // Draw Max + ctx.textBaseline = 'top'; + ctx.fillText(`${fmt(max)} ${def.unit}`, pad.l - 4, pad.t); + + // Draw Min + ctx.textBaseline = 'bottom'; + ctx.fillText(`${fmt(min)} ${def.unit}`, pad.l - 4, H - pad.b); + + // Draw Avg (only if it doesn't overlap min/max) + const stats = + !hasSel && histData.fullStatsAll !== undefined + ? histData.fullStatsAll + : rangeStats( + histData.xData, + histData.yData, + selAnchorVal || -Infinity, + selEndVal || Infinity, + ); + if (stats) { + const avgY = + pad.t + + (BINS - 1 - Math.min(BINS - 1, Math.floor(((stats.avg - min) / (max - min || 1)) * BINS))) * + (plotH / BINS); + const minLabelY = H - pad.b; + const maxLabelY = pad.t; + const labelHeight = 10; // Approx 10px height for 9px font + + if (avgY > maxLabelY + labelHeight + 2 && avgY < minLabelY - labelHeight - 2) { + ctx.textBaseline = 'middle'; + if (ctx.fillStyle !== '#aaa') ctx.fillStyle = '#aaa'; + ctx.fillText(`${fmt(stats.avg)} ${def.unit}`, pad.l - 4, avgY); + // Draw small indicator tick + ctx.beginPath(); + ctx.moveTo(pad.l - 3, avgY); + ctx.lineTo(pad.l, avgY); + if (ctx.strokeStyle !== '#aaa') ctx.strokeStyle = '#aaa'; + ctx.lineWidth = 1; + ctx.stroke(); + } + } + + // ── Higher/Lower percentages below histogram ── + if (hoverBinI != null && total > 0) { + let countLower = 0; + for (let i = 0; i < hoverBinI; i++) countLower += bins[i]; + let countHigher = 0; + for (let i = hoverBinI + 1; i < BINS; i++) countHigher += bins[i]; + + const pLower = Math.round((countLower / total) * 100); + const pHigher = Math.round((countHigher / total) * 100); + + ctx.save(); + ctx.textAlign = 'left'; + ctx.textBaseline = 'top'; + const font8 = '8px system-ui, sans-serif'; + if (ctx.font !== font8) ctx.font = font8; + + const textY = H - pad.b + 6; + + // Draw "Lower" stat + if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896'; + ctx.fillText('LOWER', pad.l, textY); + if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc'; + const fontB10 = 'bold 10px system-ui, sans-serif'; + if (ctx.font !== fontB10) ctx.font = fontB10; + ctx.fillText(`${pLower}%`, pad.l, textY + 10); + + // Draw "Higher" stat + const midX = pad.l + plotW / 2; + if (ctx.font !== font8) ctx.font = font8; + if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896'; + ctx.fillText('HIGHER', midX, textY); + if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc'; + if (ctx.font !== fontB10) ctx.font = fontB10; + ctx.fillText(`${pHigher}%`, midX, textY + 10); + + ctx.restore(); + } + } + + function attachHistTooltip(canvas: HTMLCanvasElement, histData: HistData) { + const { plot } = histData; + + canvas.addEventListener('click', (e) => { + const binI = getBinAt(canvas, histData, e); + if (binI != null && plot) { + const { min, max, BINS } = histData; + const span = max! - min! || 1; + plot.pinnedHistY = min! + (binI + 0.5) * (span / BINS!); + plots.forEach(({ uplot: u }) => u.redraw(false)); + } + }); + + canvas.addEventListener('mousemove', (e) => { + lastHistMouseEvent = e; + updateHistTooltip(e, canvas, histData); + }); + + canvas.addEventListener('mouseenter', () => { + hoveredHistCanvas = canvas; + hoveredHistData = histData; + }); + + canvas.addEventListener('mouseleave', () => { + if (hoveredHistCanvas === canvas) { + hoveredHistCanvas = null; + hoveredHistData = null; + } + if (histTooltipEl) histTooltipEl.style.display = 'none'; + const lineEl = document.getElementById('hist-line'); + if (lineEl) lineEl.style.display = 'none'; + if (plot) { + plot.hoveredHistY = null; + drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1)); + } + }); + } + + function getBinAt(canvas: HTMLCanvasElement, histData: HistData, e: MouseEvent) { + const { bins, BINS } = histData; + if (!bins) return null; + const rect = canvas.getBoundingClientRect(); + const relY = e.clientY - rect.top; + // Use exact padding from drawHistogram: t: 4, b: 30 + const pad = { t: 4, b: 30 }; + const plotH = rect.height - pad.t - pad.b; + const rawI = Math.floor(((relY - pad.t) / plotH) * BINS!); + const binI = BINS! - 1 - rawI; + if (rawI < 0 || rawI >= BINS!) return null; + return binI; + } + + function updateHistTooltip(e: MouseEvent, canvas: HTMLCanvasElement, histData: HistData) { + if (!histTooltipEl) return; + const { bins, binAccum, min, max, BINS, def, plot } = histData; + if (!bins || !binAccum || min == null || max == null) return; + + const lineEl = document.getElementById('hist-line'); + const binI = getBinAt(canvas, histData, e); + + if (binI == null || !bins[binI]) { + histTooltipEl.style.display = 'none'; + if (lineEl) lineEl.style.display = 'none'; + if (plot) { + plot.hoveredHistY = null; + drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1)); + } + return; + } + + if (plot) { + const span = max - min || 1; + plot.hoveredHistY = min + (binI + 0.5) * (span / BINS!); + drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1), binI); + } + + const count = bins[binI]; + const total = bins.reduce((s, v) => s + v, 0); + const pct = (count / total) * 100; + + const span = max - min || 1; + const low = min + binI * (span / BINS!); + const high = min + (binI + 1) * (span / BINS!); + const label = `${def.fmt(low, true)} – ${def.fmt(high, true)} ${def.unit}`; + + // Zone info + let zoneHtml = ''; + const mid = (low + high) / 2; + const metricKey = Object.keys(METRICS).find((k) => METRICS[k] === def); + let zones: any[] = []; + if (metricKey === 'power') zones = Zones.getPowerZones(); + else if (metricKey === 'hr') zones = Zones.getHRZones(); + + if (zones.length > 0) { + const zIdx = zones.findIndex((z) => mid >= z.min && mid < z.max); + const z = + zIdx !== -1 + ? zones[zIdx] + : mid >= zones[zones.length - 1].min + ? zones[zones.length - 1] + : null; + if (z) { + const finalZIdx = zIdx !== -1 ? zIdx : zones.length - 1; + zoneHtml = ` +
+ Z${finalZIdx + 1} + · + ${z.name} +
+ `; + } + } + + const totalAccum = + xAxis === 'distance' ? `${binAccum[binI].toFixed(2)} km` : fmtSecs(binAccum[binI]); + const totalPct = (binAccum[binI] / binAccum.reduce((s, v) => s + v, 0)) * 100; + + let html = ` +
${label}
+ ${zoneHtml} + `; + + if (totalAccum) { + html += `
+ ${xAxis === 'distance' ? 'Dist' : 'Time'} + ${totalAccum} + ${totalPct.toFixed(1)}% +
`; + } + + // Selection context + if (histData.selBins && histData.selBinAccum) { + const stotalAccum = + xAxis === 'distance' + ? `${histData.selBinAccum[binI].toFixed(2)} km` + : fmtSecs(histData.selBinAccum[binI]); + const stotalPct = + (histData.selBinAccum[binI] / histData.selBinAccum.reduce((s, v) => s + v, 0)) * 100; + + html += ` +
+ Sel ${xAxis === 'distance' ? 'Dist' : 'Time'} + ${stotalAccum} + ${stotalPct.toFixed(1)}% +
+ `; + } + + histTooltipEl.innerHTML = html; + + // Position tooltip: fixed X left of canvas, Y centered on bin + histTooltipEl.style.display = 'block'; + const ttH = histTooltipEl.offsetHeight; + const ttW = histTooltipEl.offsetWidth; + const rect = canvas.getBoundingClientRect(); + const plotH = rect.height - 4 - 30; // pad.t + pad.b + const binCenterY = rect.top + 4 + (BINS! - 1 - binI + 0.5) * (plotH / BINS!); + + histTooltipEl.style.left = `${rect.left - ttW - 12}px`; + histTooltipEl.style.top = `${binCenterY - ttH / 2}px`; + + // Horizontal line sync + if (lineEl) { + lineEl.style.display = 'block'; + lineEl.style.top = `${binCenterY}px`; + lineEl.style.left = '0px'; + lineEl.style.width = `${rect.left}px`; + } + } + + // ── Helpers ─────────────────────────────────────────────────── + function destroyPlots(keepState = false) { + if (histTooltipEl) histTooltipEl.style.display = 'none'; + plots.forEach(({ uplot: u, row }) => { + syncKey!.unsub(u); + u.destroy(); + row.remove(); + }); + plots = []; + renderedTrack = null; + if (!keepState) { + selAnchorVal = null; + selEndVal = null; + } + isDragging = false; + } + + function rangeStats( + xData: (number | null)[], + yData: (number | null)[], + xMin: number, + xMax: number, + incZero = true, + ) { + let min = Infinity, + max = -Infinity, + sum = 0, + n = 0; + for (let i = 0; i < xData.length; i++) { + if (xData[i] == null || xData[i]! < xMin || xData[i]! > xMax) continue; + const v = yData[i]; + if (v == null || !isFinite(v)) continue; + if (v === 0 && !incZero) continue; + + if (v < min) min = v; + if (v > max) max = v; + sum += v; + n++; + } + return n ? { min, max, avg: sum / n } : null; + } + + function elevationRangeStats(pts: TrackPoint[], xMin: number, xMax: number) { + let gain = 0, + loss = 0; + let prevEle: number | null = null; + const isDist = xAxis === 'distance'; + const t0 = pts[0].time || 0; + + for (let i = 0; i < pts.length; i++) { + const p = pts[i]; + const x = isDist ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000; + if (x < xMin || x > xMax) continue; + + if (p.ele != null) { + if (prevEle != null) { + const diff = p.ele - prevEle; + if (diff > 0) gain += diff; + else if (diff < 0) loss += Math.abs(diff); + } + prevEle = p.ele; + } + } + return { gain, loss }; + } + + // ── Plot Rendering Helpers (Canvas) ─────────────────────────── + function updateTooltip( + u: WegPlot, + el: HTMLElement, + idx: number, + xData: (number | null)[], + yData: (number | null)[], + pts: TrackPoint[], + def: MetricDefinition, + metricKey: string, + ) { + if (idx == null || yData[idx] == null) { + el.style.display = 'none'; + return; + } + + const cx = u.valToPos(xData[idx]!, 'x', false); + const cy = u.valToPos(yData[idx]!, 'y', false); + + let gColor = '#888896'; + let g = 0; + if (idx > 0 && pts[idx] && pts[idx - 1]) { + const p0 = pts[idx - 1], + p1 = pts[idx]; + const d = (p1.dist || 0) - (p0.dist || 0); + if (d > 0.1 && p1.ele != null && p0.ele != null) { + g = ((p1.ele - p0.ele) / d) * 100; + gColor = gradientColor(g); + } + } + + let content = + metricKey !== 'elevation' + ? `${def.fmt(yData[idx]!, false)} ${def.unit}` + : `${def.fmt(yData[idx]!, false)} ${def.unit} ∠ ${Math.abs(g).toFixed(1)}%`; + + // Special handling for gears: show tooth count if available + if (metricKey === 'gearRear' && pts[idx].gearRearTooth != null) { + content = `${pts[idx].gearRearTooth}T (pos ${yData[idx]})`; + } else if (metricKey === 'gearFront' && pts[idx].gearFrontTooth != null) { + content = `${pts[idx].gearFrontTooth}T (pos ${yData[idx]})`; + } else if (metricKey === 'gears') { + const p = pts[idx]; + const front = + p.gearFrontTooth != null + ? `${p.gearFrontTooth}T` + : p.gearFront != null + ? `pos ${p.gearFront}` + : ''; + const rear = + p.gearRearTooth != null + ? `${p.gearRearTooth}T` + : p.gearRear != null + ? `pos ${p.gearRear}` + : ''; + + if (front || rear) + content += ` (${front} / ${rear})`; + } + + if (el.innerHTML !== content) el.innerHTML = content; + + const color44 = `${def.color}44`; + if (el.style.color !== def.color) el.style.color = def.color; + if (el.style.borderColor !== color44) el.style.borderColor = color44; + + const left = `${cx}px`; + const top = `${cy}px`; + const transform = 'translate(6px, -50%)'; + if (el.style.left !== left) el.style.left = left; + if (el.style.top !== top) el.style.top = top; + if (el.style.transform !== transform) el.style.transform = transform; + if (el.style.display !== '') el.style.display = ''; + } + + const gradientColorRgbaCache = new Map(); + function gradientColorRgba(g: number | null): string { + let c = gradientColorRgbaCache.get(g); + if (!c) { + c = hexToRgba(gradientColor(g), 0.8); + gradientColorRgbaCache.set(g, c); + } + return c; + } + + function drawElevationGradient( + u: uPlot, + xData: number[], + yData: number[], + gradData: (number | null)[] | null, + ) { + const ctx = u.ctx; + const bb = u.bbox; + const dpr = window.devicePixelRatio || 1; + const xMin = u.scales.x?.min ?? -Infinity; + const xMax = u.scales.x?.max ?? Infinity; + const yMin = u.scales.y?.min ?? 0; + const yMax = u.scales.y?.max ?? 100; + const xScale = bb.width / (xMax - xMin || 1); + const yScale = bb.height / (yMax - yMin || 1); + const yBase = bb.top + bb.height; + + const idxs = u.series[0]?.idxs; + const iStart = idxs ? Math.max(1, idxs[0]) : 1; + const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1; + const step = Math.max(1, Math.floor((iEnd - iStart) / 250)); + + ctx.save(); + ctx.lineWidth = 1.5 * dpr; + + const byColor = new Map(); + + let prevIdx = iStart - 1; + for (let i = iStart; i <= iEnd; i += step) { + const xv1 = xData[i]; + const xv0 = xData[prevIdx]; + prevIdx = i; + if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue; + if (xv1 < xMin || xv0 > xMax) continue; + + const x0 = bb.left + (xv0 - xMin) * xScale; + const y0 = yBase - (yData[i - step]! - yMin) * yScale; + const x1 = bb.left + (xv1 - xMin) * xScale; + const y1 = yBase - (yData[i]! - yMin) * yScale; + + const g = gradData && gradData[i] != null ? Math.round(gradData[i]! / 2) * 2 : null; + const color = gradientColorRgba(g); + let segs = byColor.get(color); + if (!segs) { + segs = []; + byColor.set(color, segs); + } + segs.push(x0, y0, x1, y1); + } + + for (const [color, segs] of byColor) { + ctx.beginPath(); + ctx.strokeStyle = color; + for (let j = 0; j < segs.length; j += 4) { + ctx.moveTo(segs[j], segs[j + 1]); + ctx.lineTo(segs[j + 2], segs[j + 3]); + } + ctx.stroke(); + } + + ctx.restore(); + } + + function drawGradientChart(u: uPlot, xData: number[], yData: number[]) { + const ctx = u.ctx; + const bb = u.bbox; + const dpr = window.devicePixelRatio || 1; + const xMin = u.scales.x?.min ?? -Infinity; + const xMax = u.scales.x?.max ?? Infinity; + const yMin = u.scales.y?.min ?? 0; + const yMax = u.scales.y?.max ?? 100; + const xScale = bb.width / (xMax - xMin || 1); + const yScale = bb.height / (yMax - yMin || 1); + const yBase = bb.top + bb.height; + + const idxs = u.series[0]?.idxs; + const iStart = idxs ? Math.max(1, idxs[0]) : 1; + const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1; + const step = Math.max(1, Math.floor((iEnd - iStart) / 250)); + + ctx.save(); + ctx.lineWidth = 1.5 * dpr; + + const byColor = new Map(); + + let prevIdx = iStart - 1; + for (let i = iStart; i <= iEnd; i += step) { + const xv1 = xData[i]; + const xv0 = xData[prevIdx]; + prevIdx = i; + if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue; + if (xv1 < xMin || xv0 > xMax) continue; + + const x0 = bb.left + (xv0 - xMin) * xScale; + const y0 = yBase - (yData[i - step]! - yMin) * yScale; + const x1 = bb.left + (xv1 - xMin) * xScale; + const y1 = yBase - (yData[i]! - yMin) * yScale; + + const g = Math.round(yData[i]! / 2) * 2; + const color = gradientColorRgba(g); + let segs = byColor.get(color); + if (!segs) { + segs = []; + byColor.set(color, segs); + } + segs.push(x0, y0, x1, y1); + } + + for (const [color, segs] of byColor) { + ctx.beginPath(); + ctx.strokeStyle = color; + for (let j = 0; j < segs.length; j += 4) { + ctx.moveTo(segs[j], segs[j + 1]); + ctx.lineTo(segs[j + 2], segs[j + 3]); + } + ctx.stroke(); + } + + ctx.restore(); + } + + function drawHoverLine(u: uPlot, yData: number[], color: string, pts: TrackPoint[]) { + const idx = u.cursor.idx; + if (idx == null || yData[idx] == null || u.cursor.left! < 0) return; + + const t0 = pts[0].time || 0; + const xVal = xAxis === 'distance' ? (pts[idx].dist || 0) / 1000 : (pts[idx].time! - t0) / 1000; + const cx = u.valToPos(xVal, 'x', true); + const cy = u.valToPos(yData[idx], 'y', true); + const bb = u.bbox; + const ctx = u.ctx; + const dpr = window.devicePixelRatio || 1; + + // Line from top to point + horizontal from left + ctx.save(); + ctx.beginPath(); + ctx.setLineDash([2 * dpr, 2 * dpr]); + ctx.strokeStyle = hexToRgba(color, 0.4); + ctx.lineWidth = 1 * dpr; + ctx.moveTo(cx, bb.top); + ctx.lineTo(cx, cy); + ctx.moveTo(bb.left, cy); + ctx.lineTo(cx, cy); + ctx.stroke(); + + // Dot at point + ctx.beginPath(); + ctx.setLineDash([]); // Ensure solid outline + ctx.arc(cx, cy, 3 * dpr, 0, Math.PI * 2); + ctx.fillStyle = '#0e0e10'; + ctx.fill(); + ctx.strokeStyle = color; + ctx.lineWidth = 2 * dpr; + ctx.stroke(); + ctx.restore(); + } + + function drawVerticalLineOnly( + u: uPlot, + pts: TrackPoint[], + idx: number, + color: string, + opacity: number = 1.0, + ) { + const dpr = window.devicePixelRatio || 1; + const bb = u.bbox; + const ctx = u.ctx; + const xVal = + xAxis === 'distance' + ? (pts[idx].dist || 0) / 1000 + : (pts[idx].time! - (pts[0].time || 0)) / 1000; + const cx = u.valToPos(xVal, 'x', true); + + ctx.save(); + ctx.globalAlpha = opacity; + ctx.beginPath(); + ctx.strokeStyle = color; + ctx.lineWidth = 1 * dpr; + // Dotted line range should match where labels are (flush top to bottom axis) + ctx.moveTo(cx, bb.top + 16 * dpr); + ctx.lineTo(cx, bb.top + bb.height + 10 * dpr); + ctx.stroke(); + ctx.restore(); + } + + function drawXAxisLabels( + u: uPlot, + pts: TrackPoint[], + idx: number, + color: string, + skipLine = false, + opacity: number = 1.0, + ) { + const dpr = window.devicePixelRatio || 1; + const bb = u.bbox; + const ctx = u.ctx; + const t0 = pts[0].time || 0; + const distVal = (pts[idx].dist || 0) / 1000; + const timeVal = (pts[idx].time! - t0) / 1000; + const cx = u.valToPos(xAxis === 'distance' ? distVal : timeVal, 'x', true); + + // Bottom label: matches the current X axis unit + const bottomLabel = xAxis === 'distance' ? `${distVal.toFixed(2)} km` : fmtSecs(timeVal); + // Top label: shows the other unit (simplified) + const topLabel = xAxis === 'distance' ? fmtSecs(timeVal) : `${distVal.toFixed(2)} km`; + + const drawPill = (text: string, x: number, y: number, isTop: boolean) => { + const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`; + if (ctx.font !== fontStr) ctx.font = fontStr; + const tw = ctx.measureText(text).width; + const bw = tw + 10 * dpr; + const bh = 16 * dpr; + const rx = x - bw / 2; + const clampedRx = Math.max(bb.left, Math.min(bb.left + bb.width - bw, rx)); + const ry = y - bh / 2; + + ctx.save(); + ctx.globalAlpha = opacity; + ctx.setLineDash([]); // Ensure pills are not dashed + ctx.beginPath(); + if ((ctx as any).roundRect) (ctx as any).roundRect(clampedRx, ry, bw, bh, 3 * dpr); + else ctx.rect(clampedRx, ry, bw, bh); + ctx.fillStyle = 'rgba(14,14,16,0.92)'; + ctx.fill(); + ctx.strokeStyle = hexToRgba(color, 0.27); + ctx.lineWidth = 1 * dpr; + ctx.stroke(); + + ctx.fillStyle = color; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(text, clampedRx + bw / 2, ry + bh / 2 + 0.5 * dpr); + ctx.restore(); + }; + + if (!skipLine) drawVerticalLineOnly(u, pts, idx, color, opacity); + + const pillH = 16 * dpr; + // Top label: flush to the top edge of the plot + drawPill(topLabel, cx, bb.top + pillH / 2, true); + + // Bottom label: aligned with the horizontal axis labels (centered in the 30px axis area) + drawPill(bottomLabel, cx, bb.top + bb.height + 15 * dpr, false); + } + + function drawPinnedDot( + u: uPlot, + xData: (number | null)[], + yData: (number | null)[], + color: string, + def: MetricDefinition, + pts: TrackPoint[], + metricKey: string, + ) { + if (pinnedPtIdx == null) return; + const xVal = xData[pinnedPtIdx]; + const yVal = yData[pinnedPtIdx]; + if (xVal == null || yVal == null) return; + + const cx = u.valToPos(xVal, 'x', true); + const cy = u.valToPos(yVal, 'y', true); + const bb = u.bbox; + const ctx = u.ctx; + const dpr = window.devicePixelRatio || 1; + + ctx.save(); + // Vertical line + ctx.beginPath(); + ctx.strokeStyle = color; + ctx.lineWidth = 1.5 * dpr; + ctx.moveTo(cx, bb.top); + ctx.lineTo(cx, bb.top + bb.height); + ctx.stroke(); + + // Horizontal dashed line + ctx.beginPath(); + ctx.setLineDash([3 * dpr, 3 * dpr]); + ctx.strokeStyle = hexToRgba(color, 0.5); + ctx.lineWidth = 1 * dpr; + ctx.moveTo(bb.left, cy); + ctx.lineTo(cx, cy); + ctx.stroke(); + + // Large Dot + ctx.beginPath(); + ctx.setLineDash([]); // Ensure solid outline + ctx.arc(cx, cy, 5 * dpr, 0, Math.PI * 2); + ctx.fillStyle = '#0e0e10'; + ctx.fill(); + ctx.strokeStyle = color; + ctx.lineWidth = 2.5 * dpr; + ctx.stroke(); + ctx.restore(); + + const s = (u as any)._strasse; + if (s && s.pinYVal) { + updateTooltip( + u, + s.pinYVal, + pinnedPtIdx, + xData as number[], + yData as (number | null)[], + pts, + def, + metricKey, + ); + } + } + + function drawYAxisHighlight( + u: uPlot, + xData: (number | null)[], + yData: (number | null)[], + yVal: number, + color: string, + def: MetricDefinition, + ) { + const bb = u.bbox; + const ctx = u.ctx; + const dpr = window.devicePixelRatio || 1; + const cy = u.valToPos(yVal, 'y', true); + + // Clamp cy to bbox + const cyClamp = Math.max(bb.top, Math.min(bb.top + bb.height, cy)); + + ctx.save(); + // Horizontal line + ctx.beginPath(); + ctx.setLineDash([4 * dpr, 4 * dpr]); + ctx.strokeStyle = hexToRgba(color, 0.4); + ctx.lineWidth = 1 * dpr; + ctx.moveTo(bb.left, cyClamp); + ctx.lineTo(bb.left + bb.width, cyClamp); + ctx.stroke(); + + // Fill area above/below + drawAreaFillAbove(u, xData, yData, cyClamp, color); + + // Pill label on Y-axis + const label = def.fmt(yVal, true); + const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`; + if (ctx.font !== fontStr) ctx.font = fontStr; + const tw = ctx.measureText(label).width; + const bw = tw + 8 * dpr; + const bh = 16 * dpr; + const bx = bb.left - bw - 2 * dpr; + const by = cyClamp - bh / 2; + + ctx.beginPath(); + ctx.setLineDash([]); + if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr); + else ctx.rect(bx, by, bw, bh); + ctx.fillStyle = 'rgba(14,14,16,0.95)'; + ctx.fill(); + ctx.strokeStyle = color; + ctx.lineWidth = 1 * dpr; + ctx.stroke(); + + ctx.fillStyle = '#fff'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(label, bx + bw / 2, by + bh / 2 + 0.5 * dpr); + ctx.restore(); + } + + function drawAreaFillAbove( + u: uPlot, + xData: (number | null)[], + yData: (number | null)[], + cyClamp: number, + color: string, + ) { + const ctx = u.ctx; + const bb = u.bbox; + const xMin = u.scales.x?.min ?? -Infinity; + const xMax = u.scales.x?.max ?? Infinity; + const yMin = u.scales.y?.min ?? 0; + const yMax = u.scales.y?.max ?? 100; + const xScale = bb.width / (xMax - xMin || 1); + const yScale = bb.height / (yMax - yMin || 1); + const yDir = u.scales.y?.dir ?? 1; + const yBase = yDir === -1 ? bb.top : bb.top + bb.height; + const yMult = yDir === -1 ? yScale : -yScale; + + const idxs = u.series[0]?.idxs; + const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0; + const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1; + const step = Math.max(1, Math.floor((iEnd - iStart) / 250)); + + ctx.save(); + ctx.beginPath(); + ctx.rect(bb.left, bb.top, bb.width, bb.height); + ctx.clip(); + + ctx.fillStyle = hexToRgba(color, 0.2); + ctx.beginPath(); + + let inSegment = false; + let hasAnySegment = false; + let lastPx = 0; + + for (let i = iStart; i <= iEnd; i += step) { + const xv = xData[i]; + const yv = yData[i]; + if (xv == null || yv == null || xv < xMin || xv > xMax) { + if (inSegment) { + ctx.lineTo(lastPx, cyClamp); + ctx.closePath(); + inSegment = false; + } + continue; + } + + const px = bb.left + (xv - xMin) * xScale; + const py = yBase + (yv - yMin) * yMult; + lastPx = px; + + if (py < cyClamp) { + if (!inSegment) { + ctx.moveTo(px, cyClamp); + inSegment = true; + hasAnySegment = true; + } + ctx.lineTo(px, py); + } else if (inSegment) { + ctx.lineTo(px, cyClamp); + ctx.closePath(); + inSegment = false; + } + } + + if (inSegment) { + ctx.lineTo(lastPx, cyClamp); + ctx.closePath(); + } + + if (hasAnySegment) { + ctx.fill(); + } + + ctx.restore(); + } + + // ── Utils ───────────────────────────────────────────────────── + function lerpHex(a: string, b: string, t: number) { + const ah = parseInt(a.slice(1), 16), + bh = parseInt(b.slice(1), 16); + const ar = ah >> 16, + ag = (ah >> 8) & 0xff, + ab = ah & 0xff; + const br = bh >> 16, + bg = (bh >> 8) & 0xff, + bb = bh & 0xff; + const rr = ar + (br - ar) * t, + rg = ag + (bg - ag) * t, + rb = ab + (bb - ab) * t; + return `#${((1 << 24) + (Math.round(rr) << 16) + (Math.round(rg) << 8) + Math.round(rb)) + .toString(16) + .slice(1)}`; + } + + function gradientColor(g: number | null) { + if (g == null) return '#888896'; + const absG = Math.abs(g); + const t = Math.min(1, absG / 8); + if (g > 0) return lerpHex('#A8C8A0', '#d73027', t); // Green to Red + return lerpHex('#A8C8A0', '#4575b4', t); // Green to Blue + } + + function speedColor(s: number | null) { + if (s == null) return '#888896'; + const kmh = s * 3.6; + + if (kmh <= 5) return '#4575b4'; // Solid Blue for very slow + if (kmh >= 60) return '#d73027'; // Solid Red for very fast + + // High resolution between 5 and 45 (10km/h per segment) + if (kmh <= 45) { + const t = (kmh - 5) / 40; // 0 to 1 + if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); // 5-15: Blue -> LBlue + if (t <= 0.5) return lerpHex('#91bfdb', '#abdda4', (t - 0.25) / 0.25); // 15-25: LBlue -> Green + if (t <= 0.75) return lerpHex('#abdda4', '#fee08b', (t - 0.5) / 0.25); // 25-35: Green -> Yellow + return lerpHex('#fee08b', '#fc8d59', (t - 0.75) / 0.25); // 35-45: Yellow -> Orange + } else { + // 45-60: Orange -> Red + const t = (kmh - 45) / 15; + return lerpHex('#fc8d59', '#d73027', t); + } + } + + function smoothGradient(pts: TrackPoint[], windowMetres: number) { + const grads: (number | null)[] = new Array(pts.length).fill(null); + for (let i = 0; i < pts.length; i++) { + const p = pts[i]; + let j0 = i, + j1 = i; + while (j0 > 0 && (p.dist || 0) - (pts[j0].dist || 0) < windowMetres / 2) j0--; + while (j1 < pts.length - 1 && (pts[j1].dist || 0) - (p.dist || 0) < windowMetres / 2) j1++; + const d = (pts[j1].dist || 0) - (pts[j0].dist || 0); + if (d > 1 && pts[j1].ele != null && pts[j0].ele != null) + grads[i] = ((pts[j1].ele! - pts[j0].ele!) / d) * 100; + } + return grads; + } + + function fillNulls(data: (number | null)[]) { + const res = [...data]; + for (let i = 0; i < res.length; i++) { + if (res[i] === null) { + let left = i - 1; + while (left >= 0 && res[left] === null) left--; + let right = i + 1; + while (right < res.length && res[right] === null) right++; + if (left >= 0 && right < res.length) + res[i] = res[left]! + ((res[right]! - res[left]!) * (i - left)) / (right - left); + else if (left >= 0) res[i] = res[left]; + else if (right < res.length) res[i] = res[right]; + } + } + return res; + } + + function updateStats(track: TrackData) { + const s = track.stats; + const fmt = (id: string, val: string) => { + const el = document.querySelector(`#${id} .stat-value`); + if (el) el.textContent = val; + }; + fmt('stat-distance', s.totalDist != null ? `${(s.totalDist / 1000).toFixed(1)} km` : '—'); + fmt('stat-duration', s.duration != null ? fmtSecs(Math.floor(s.duration / 1000)) : '—'); + fmt('stat-elevation', s.elevGain != null ? `${Math.round(s.elevGain)} m` : '—'); + + // Recalculate averages from visible plot data to respect zero filtering + const getAvg = (key: string) => { + const p = plots.find((p) => p.metricKey === key); + if (!p) { + if (key === 'speed') return s.avgSpeed ?? null; + if (key === 'power') return s.avgPower ?? null; + if (key === 'cadence') return s.avgCadence ?? null; + return null; + } + if (p.histData.fullStats !== undefined) { + return p.histData.fullStats ? p.histData.fullStats.avg : null; + } + const incZero = + metricsIncludingZero.has(key) || (key !== 'power' && key !== 'cadence' && key !== 'speed'); + const vals = p.yData.filter((v): v is number => v != null && (incZero || v !== 0)); + if (!vals.length) return null; + return vals.reduce((a, b) => a + b, 0) / vals.length; + }; + + const avgSpeed = getAvg('speed'); + fmt('stat-avg-speed', avgSpeed != null ? `${(avgSpeed * 3.6).toFixed(1)} km/h` : '—'); + + const avgPower = getAvg('power'); + fmt('stat-avg-power', avgPower != null ? `${Math.round(avgPower)} W` : '—'); + + const avgCadence = getAvg('cadence'); + fmt('stat-avg-cad', avgCadence != null ? `${Math.round(avgCadence)} rpm` : '—'); + + fmt('stat-avg-hr', s.avgHR != null ? `${s.avgHR} bpm` : '—'); + fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} °C` : '—'); + } + + return { + init, + loadTrack, + clear, + resetState, + toggleMetric, + setXAxis, + toggleStats, + setSelectionStats, + clearSelectionStats, + restoreSelection, + resetZoom, + cancelSelection, + setCursorAt: (idx: number, deferRender = false) => { + pinnedPtIdx = idx; + if (onPinChangeCb) onPinChangeCb(idx); + if (deferRender) { + if (onCursorMoveCb && currentTrack?.points?.[idx]) { + onCursorMoveCb(currentTrack.points[idx]); + } + return; + } + cursorSyncing = true; + plots.forEach(({ uplot: u, yData, xData }) => { + if (xData[idx] != null && yData[idx] != null) { + u.batch(() => { + (u as any).setCursor( + { + left: u.valToPos(xData[idx]!, 'x'), + top: u.valToPos(yData[idx]!, 'y'), + }, + true, + false, + ); + }); + } + }); + cursorSyncing = false; + if (onCursorMoveCb && currentTrack?.points?.[idx]) { + onCursorMoveCb(currentTrack.points[idx]); + } + }, + setHoverAt: (idx: number | null) => { + cursorSyncing = true; + plots.forEach(({ uplot: u, yData, xData }) => { + if (idx === null) { + u.batch(() => { + (u as any).setCursor({ left: -10, top: -10 }, true, false); + }); + } else if (xData[idx] != null && yData[idx] != null) { + u.batch(() => { + (u as any).setCursor( + { + left: u.valToPos(xData[idx]!, 'x'), + top: u.valToPos(yData[idx]!, 'y'), + }, + true, + false, + ); + }); + } + }); + cursorSyncing = false; + if (onCursorMoveCb) { + onCursorMoveCb( + idx != null && currentTrack?.points?.[idx] ? currentTrack.points[idx] : null, + ); + } + }, + clearPinnedDot: () => { + pinnedPtIdx = null; + if (onPinChangeCb) onPinChangeCb(null); + plots.forEach(({ uplot: u }) => u.redraw(false)); + }, + resize, + METRICS, + isDragging: () => isDragging, + setMapColorChangeCb, + toggleMapColor, + getMapColorMetric: () => mapColorMetric, + getActiveMetrics: () => activeMetrics, + getAvailableMetrics: () => availableMetrics, + setActiveMetrics, + updateMetricOrder: (keys: string[]) => { + // Keys might only contain current active ones, or more. + // We want to re-order activeMetrics to match the order in 'keys' + const newActive = new Set(); + keys.forEach((k) => { + if (activeMetrics.has(k)) newActive.add(k); + }); + // Add any remaining ones that were active but not in the keys list (shouldn't happen with our DND) + activeMetrics.forEach((k) => { + if (!newActive.has(k)) newActive.add(k); + }); + activeMetrics = newActive; + if (currentTrack) render(true); + }, + getXAxis: () => xAxis, + }; + + function drawMetricColorFill( + u: uPlot, + xData: (number | null)[], + yData: (number | null)[], + pts: TrackPoint[], + metricKey: string, + ) { + const ctx = u.ctx; + const bb = u.bbox; + const dpr = window.devicePixelRatio || 1; + const colors = _computePointColors(metricKey, yData); + + ctx.save(); + ctx.beginPath(); + ctx.rect(bb.left, bb.top, bb.width, bb.height); + ctx.clip(); + + const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront'; + + for (let i = 1; i < xData.length; i++) { + if (xData[i] == null || yData[i] == null || xData[i - 1] == null || yData[i - 1] == null) + continue; + const x0 = u.valToPos(xData[i - 1]!, 'x', true); + const y0 = u.valToPos(yData[i - 1]!, 'y', true); + const x1 = u.valToPos(xData[i]!, 'x', true); + const y1 = u.valToPos(yData[i]!, 'y', true); + + const c = colors[i]; + + // Top line segment + ctx.beginPath(); + ctx.moveTo(x0, y0); + if (isStepped) ctx.lineTo(x1, y0); + + ctx.lineTo(x1, y1); + ctx.strokeStyle = c; + ctx.lineWidth = 2 * dpr; + ctx.stroke(); + } + + ctx.restore(); + } + + function drawBackgroundTracks(u: uPlot, metricKey: string, def: MetricDefinition) { + if (!allTracks.length) return; + const ctx = u.ctx; + const bb = u.bbox; + const dpr = window.devicePixelRatio || 1; + const GAP_THRESHOLD = 60000; // 1 minute in ms + + ctx.save(); + ctx.beginPath(); + ctx.rect(bb.left, bb.top, bb.width, bb.height); + ctx.clip(); + + const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront'; + + for (const track of allTracks) { + if (currentTrack && track.id === currentTrack.id) continue; + + const pts = track.points; + const t0 = pts.find((p) => p.time != null)?.time || 0; + const field = def.field; + + ctx.beginPath(); + ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)'; // Extremely faint + ctx.lineWidth = 1 * dpr; + + let first = true; + for (let i = 0; i < pts.length; i++) { + const p = pts[i]; + const v = p[field] as number; + + if (v == null) { + first = true; + continue; + } + + if (i > 0) { + const prev = pts[i - 1]; + const dt = p.time && prev.time ? p.time - prev.time : 0; + if (dt > GAP_THRESHOLD) first = true; + } + + const val = def.transform ? def.transform(v) : v; + if (val == null) { + first = true; + continue; + } + const xVal = xAxis === 'distance' ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000; + + // Skip if way outside horizontal range + if (xVal < u.scales.x!.min! - 10 || xVal > u.scales.x!.max! + 10) { + first = true; + continue; + } + + const px = u.valToPos(xVal, 'x', true); + const py = u.valToPos(val, 'y', true); + + if (first) { + ctx.moveTo(px, py); + first = false; + } else { + if (isStepped) { + const prevP = pts[i - 1]; + const prevXVal = + xAxis === 'distance' ? (prevP.dist || 0) / 1000 : (prevP.time! - t0) / 1000; + ctx.lineTo(u.valToPos(prevXVal, 'x', true), py); + } + ctx.lineTo(px, py); + } + } + ctx.stroke(); + } + + ctx.restore(); + } + + function drawTrackPath( + u: uPlot, + xData: (number | null)[], + yData: (number | null)[], + color: string, + width: number, + metricKey: string, + range: [number, number] | null = null, + pts: TrackPoint[] = [], + ) { + const ctx = u.ctx; + const bb = u.bbox; + const dpr = window.devicePixelRatio || 1; + const GAP_THRESHOLD = 60000; // 1 minute in ms + + ctx.save(); + ctx.beginPath(); + ctx.strokeStyle = hexToRgba(color, 0.8); + ctx.lineWidth = width * dpr; + + const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront'; + let first = true; + let lastFrontGear: number | null = null; + let fMin = 1; + let fMax = 1; + + if (metricKey === 'gears' && pts.length > 0) { + let lo = Infinity, + hi = -Infinity; + for (let i = 0; i < pts.length; i++) { + const fg = pts[i].gearFrontTooth ?? pts[i].gearFront; + if (fg != null) { + if (fg < lo) lo = fg; + if (fg > hi) hi = fg; + } + } + if (lo <= hi) { + fMin = lo; + fMax = hi; + } + } + + const rMin = range ? range[0] : (u.scales.x?.min ?? -Infinity); + const rMax = range ? range[1] : (u.scales.x?.max ?? Infinity); + const xMin = u.scales.x?.min ?? -Infinity; + const xMax = u.scales.x?.max ?? Infinity; + const yMin = u.scales.y?.min ?? 0; + const yMax = u.scales.y?.max ?? 100; + const xScale = bb.width / (xMax - xMin || 1); + const yScale = bb.height / (yMax - yMin || 1); + const yDir = u.scales.y?.dir ?? 1; + const yBase = yDir === -1 ? bb.top : bb.top + bb.height; + const yMult = yDir === -1 ? yScale : -yScale; + + const idxs = !range ? u.series[0]?.idxs : null; + const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0; + const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1; + const step = + isStepped || metricKey === 'gears' ? 1 : Math.max(1, Math.floor((iEnd - iStart) / 250)); + const isTimeAxis = xAxis === 'time'; + const gapSec = GAP_THRESHOLD / 1000; + let prevDrawnI = iStart; + + for (let i = iStart; i <= iEnd; i += step) { + const xv = xData[i]; + const yv = yData[i]; + if (xv == null || yv == null) { + first = true; + continue; + } + + if (metricKey === 'gears' && pts[i]) { + const fg = pts[i].gearFrontTooth ?? pts[i].gearFront; + if (fg != null && fg !== lastFrontGear) { + if (!first && i > 0) { + ctx.stroke(); + ctx.beginPath(); + const prevX = bb.left + (xData[prevDrawnI]! - xMin) * xScale; + const prevY = yBase + (yData[prevDrawnI]! - yMin) * yMult; + ctx.moveTo(prevX, prevY); + } + + // Compute color + let segmentColor = color; + if (fMax !== fMin && fg != null) { + if (fg === fMin) + segmentColor = '#FFC400'; // Small ring: Yellow-Orange + else if (fg === fMax) + segmentColor = '#FF8C00'; // Big ring: Dark Orange + else segmentColor = '#FFA500'; // Middle ring: Orange + } + ctx.strokeStyle = hexToRgba(segmentColor, 0.8); + lastFrontGear = fg; + } + } + + // Check gap + if (i > iStart && isTimeAxis) { + const prevXv = xData[prevDrawnI]; + if (prevXv != null && xv - prevXv > gapSec) first = true; + } + + // Check range (or visible x-scale bounds) + if (xv < rMin || xv > rMax) { + first = true; + continue; + } + + const px = bb.left + (xv - xMin) * xScale; + const py = yBase + (yv - yMin) * yMult; + + if (first) { + ctx.moveTo(px, py); + first = false; + } else { + if (isStepped) { + const prevXv = xData[prevDrawnI]!; + ctx.lineTo(bb.left + (prevXv - xMin) * xScale, py); + } + ctx.lineTo(px, py); + } + prevDrawnI = i; + } + ctx.stroke(); + ctx.restore(); + } +})(); diff --git a/suites-experimental/tools-gps-tracks/src/css/styles.css b/suites-experimental/tools-gps-tracks/src/css/styles.css new file mode 100644 index 0000000000..5af07ab7eb --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/css/styles.css @@ -0,0 +1,2403 @@ +/* + * Copyright (c) 2026, Camillo Bruni. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +@import './uPlot.min.css'; + +/* ─── Variables ─────────────────────────────────────────── */ +@font-face { + font-family: 'Material Symbols Rounded'; + font-style: normal; + font-weight: 100 700; + src: url('../../material_symbols_rounded.woff2') format('woff2'); +} + +:root { + --bg: #0e0e10; + --surface: #18181b; + --surface2: #222226; + --border: #2e2e34; + --border2: #3a3a42; + --text: #e8e8ec; + --text-muted: #888896; + --text-dim: #555564; + --theme-color: #3b82f6; + --accent: var(--theme-color); + --accent-hover: color-mix(in srgb, var(--theme-color) 80%, white); + --danger: #ef4444; + --sidebar-w: 230px; + + /* Font Sizes */ + --fs-s: 10px; + --fs-m: 12px; + --fs-l: 14px; /* For titles only */ + + /* Icon Sizes */ + --is-s: 16px; + --is-m: 20px; + + --handle-color: #3b82f6; +} + +/* Font Size Classes */ +.font-s { + font-size: 10px; +} +.font-m { + font-size: 12px; +} +.font-l { + font-size: 14px; +} + +* { + box-sizing: border-box; +} + +body, +html { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + background: var(--bg); + color: var(--text); + font-family: + system-ui, + -apple-system, + sans-serif; + font-size: var(--fs-m); +} + +body { + opacity: 1; +} + +body.loading-fonts { + opacity: 0; +} + +button { + font-family: inherit; + cursor: pointer; + font-size: var(--fs-m); +} + +/* Material symbols config */ +.material-symbols-rounded { + font-family: 'Material Symbols Rounded'; + font-weight: normal; + font-style: normal; + font-size: var(--is-m); + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; + -webkit-font-smoothing: antialiased; + font-variation-settings: + 'FILL' 0, + 'wght' 400, + 'GRAD' 0, + 'opsz' 24; +} + +/* ─── Layout ────────────────────────────────────────────── */ +#app { + display: flex; + width: 100vw; + height: 100vh; + overflow: hidden; +} + +.hidden { + display: none !important; +} + +#global-loader { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.7); + z-index: 10000; + display: flex; + align-items: center; + justify-content: center; +} + +#import-warning { +} + +.loader-box { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 12px; + padding: 0; + display: flex; + flex-direction: row; + align-items: stretch; + color: var(--text); + font-weight: 700; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); + max-width: 450px; + width: 90%; + overflow: hidden; + position: relative; +} + +#loader-close { + position: absolute; + top: 12px; + right: 12px; + background: none; + border: none; + color: var(--text-muted); + cursor: pointer; + padding: 4px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; +} + +#loader-close:hover { + background: var(--surface2); + color: var(--text); +} + +.loader-icon-wrap { + background: color-mix(in srgb, var(--accent) 10%, transparent); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 24px; + border-right: 1px solid var(--border); + gap: 8px; +} + +.loader-icon-wrap > span { + font-size: var(--fs-l); + color: var(--accent); +} + +#loader-warning-count { + font-size: var(--fs-m); + color: #f59e0b; + font-weight: 700; + display: none; + align-items: center; + gap: 4px; +} + +.loader-content { + padding: 24px; + flex: 1; + display: flex; + flex-direction: column; + gap: 12px; + justify-content: center; +} + +#loader-text { + font-size: var(--fs-l); + font-weight: 700; + color: var(--text); +} + +#loader-filename { + font-size: var(--fs-m); + color: var(--text-muted); + font-weight: 400; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: 300px; +} + +#loader-progress-wrap { + width: 300px; + height: 4px; + background: var(--surface2); + border-radius: 2px; + margin-top: 4px; + overflow: hidden; +} + +#loader-subtext { + font-size: var(--fs-m); + color: var(--text-muted); + font-weight: 400; + display: flex; + align-items: center; + justify-content: space-between; + width: 300px; + margin-top: 0; +} + +.progress-index { + text-align: left; +} + +.progress-total { + text-align: right; +} + +#loader-progress-bar { + width: 0%; + height: 100%; + background: var(--accent); +} + +/* ─── Sidebar ───────────────────────────────────────────── */ +#sidebar { + width: var(--sidebar-w); + flex-shrink: 0; + display: flex; + flex-direction: column; + background: var(--surface); + border-right: 1px solid var(--border); + z-index: 10; +} + +#sidebar-header { + padding: 16px 12px; + border-bottom: 1px solid var(--border); +} + +.logo { + display: flex; + align-items: center; + gap: 10px; +} +.logo-icon { + color: var(--accent); + font-size: var(--fs-l); +} +.logo-title { + font-weight: 800; + font-size: var(--fs-l); + letter-spacing: -0.5px; +} +.logo-sub { + font-size: var(--fs-s); + text-transform: uppercase; + color: var(--text-dim); + font-weight: 700; + letter-spacing: 1px; + margin-top: -2px; +} + +/* Drop zone */ +#drop-zone { + margin: 12px; + padding: 20px 12px; + border: 2px dashed var(--border2); + border-radius: 12px; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + position: relative; +} +#drop-zone.drop-active { + border-color: var(--accent); + background: color-mix(in srgb, var(--theme-color) 5%, transparent); +} +.drop-icon { + font-size: var(--is-m); + color: var(--text-muted); + margin-bottom: 4px; +} +.drop-primary { + font-size: var(--fs-m); + font-weight: 600; + color: var(--text); +} +.drop-formats { + display: flex; + justify-content: center; + gap: 6px; + margin-top: 8px; +} +.drop-formats .badge { + background: var(--surface2); + color: var(--text-dim); + font-size: var(--fs-s); + padding: 2px 6px; +} + +.drop-browse-container { + margin-top: 12px; + font-size: var(--fs-s); + color: var(--text-muted); + display: flex; + align-items: center; + justify-content: center; + gap: 2px; +} +.drop-browse { + color: var(--accent); + font-weight: 600; + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 4px; +} +.drop-browse .material-symbols-rounded { + font-size: var(--fs-l); +} +.drop-browse:hover { + color: var(--accent-hover); +} +.drop-separator { + margin: 0 6px; + color: var(--border2); + vertical-align: middle; +} + +/* Track list header */ +#track-list-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 12px 8px; +} +.section-label { + font-size: var(--fs-s); + font-weight: 700; + text-transform: uppercase; + color: var(--text-dim); + letter-spacing: 0.5px; +} + +.header-actions { + display: flex; + gap: 0; +} + +#track-controls, +#sort-controls { + padding: 8px 12px; + display: flex; + flex-direction: column; + gap: 8px; + border-bottom: 1px solid var(--border); +} + +.search-bar { + display: flex; + background: var(--bg); + border: 1px solid var(--border); + border-radius: 6px; + padding: 2px 4px; + align-items: center; +} +.search-icon { + font-size: var(--is-s); + color: var(--text-dim); + margin-left: 4px; +} +.search-bar input { + flex: 1; + background: transparent; + border: none; + padding: 4px 6px; + color: var(--text); + font-size: var(--fs-m); +} +.search-bar input:focus { + outline: none; +} + +.icon-btn.mini { + width: 20px; + height: 20px; + color: var(--text-dim); +} +.icon-btn.mini .material-symbols-rounded { + font-size: var(--is-s); +} +.icon-btn.mini.active { + color: var(--accent); +} + +.sort-ctrl { + display: flex; + align-items: center; + gap: 8px; +} +.sort-ctrl label { + font-size: var(--fs-s); + color: var(--text-dim); + text-transform: uppercase; + font-weight: 600; +} + +.sort-select-btn { + display: flex; + align-items: center; + gap: 6px; + background: var(--surface2); + border: 1px solid var(--border); + padding: 4px 8px; + border-radius: 6px; + flex: 1; + height: 24px; + box-sizing: border-box; + font-size: var(--fs-s); + color: var(--text-muted); +} +.sort-select-btn:hover { + border-color: var(--accent); + color: var(--text); +} +.sort-select-btn .material-symbols-rounded { + font-size: var(--is-s); +} +.sort-select-btn .arrow { + font-size: var(--fs-l); + margin-left: auto; + opacity: 0.5; +} + +/* Filter panel */ +#filter-panel { + padding: 12px; + background: var(--surface2); + border-bottom: 1px solid var(--border); + display: flex; + flex-direction: column; + gap: 12px; +} +#filter-panel.hidden { + display: none; +} + +.filter-group { + display: flex; + flex-direction: column; + gap: 4px; +} +.filter-group label { + font-size: var(--fs-s); + font-weight: 600; + text-transform: uppercase; + color: var(--text-dim); + display: flex; + align-items: center; + gap: 6px; +} +.filter-group label .material-symbols-rounded { + font-size: var(--is-s); + opacity: 0.7; +} + +.filter-metrics-grid { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-top: 4px; +} + +.mini-pill { + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 6px; + color: var(--text-dim); + cursor: pointer; +} +.mini-pill:hover { + border-color: var(--text-muted); + color: var(--text-muted); +} +.mini-pill.active { + background: var(--accent); + border-color: var(--accent); + color: white; +} +.mini-pill .material-symbols-rounded { + font-size: var(--is-s); +} + +.filter-row { + display: flex; + align-items: center; + gap: 6px; +} +.filter-row input { + flex: 1; + background: var(--bg); + border: 1px solid var(--border); + border-radius: 4px; + padding: 4px 6px; + color: var(--text); + font-size: var(--fs-s); +} +.filter-row span { + font-size: var(--fs-s); + color: var(--text-dim); +} +#filter-panel input:focus { + border-color: var(--accent); + outline: none; +} + +.filter-footer { + display: flex; + justify-content: flex-end; + margin-top: 4px; +} + +/* Track list */ +#track-list { + flex: 1; + overflow-y: auto; + padding: 4px 0; + scrollbar-width: none; +} +#track-list::-webkit-scrollbar { + width: 0; + height: 0; + display: none; +} +#track-list::-webkit-scrollbar-thumb { + background: var(--border2); + border-radius: 2px; +} + +#track-list-empty { + padding: 40px 20px; + text-align: center; + color: var(--text-dim); + font-size: var(--fs-m); +} + +.track-item { + display: flex; + align-items: center; + padding: 6px 8px; + gap: 0; + cursor: pointer; + border-left: 3px solid transparent; +} +.track-item:hover { + background: rgba(255, 255, 255, 0.03); +} +.track-item.selected { + background: color-mix(in srgb, var(--theme-color) 8%, transparent); + border-left-color: var(--accent); +} + +.track-color { + width: 3px; + border-radius: 1px; + flex-shrink: 0; + margin-right: 8px; + align-self: stretch; +} +.track-info { + flex: 1; + min-width: 0; + margin-right: 2px; +} +.track-name { + font-size: var(--fs-m); + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-bottom: 1px; +} +.track-meta { + font-size: var(--fs-s); + color: var(--text-dim); + display: flex; + gap: 6px; + align-items: center; +} + +.track-item .icon-btn.mini { + width: 22px; + height: 22px; + padding: 0; + margin: 0; +} + +.badge { + font-size: var(--fs-s); + background: var(--surface2); + padding: 1px 4px; + border-radius: 3px; + font-weight: 700; + color: var(--text-muted); +} + +.track-tags { + display: flex; + flex-wrap: wrap; + gap: 4px; + margin-top: 6px; + overflow: hidden; + max-height: 32px; +} + +.track-tag { + font-size: var(--fs-s); + font-weight: 700; + color: var(--text-dim); + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border); + padding: 1px 5px; + border-radius: 3px; + white-space: nowrap; +} + +.track-item.selected .track-tag { + border-color: rgba(255, 255, 255, 0.1); + color: var(--text-muted); +} + +#sidebar-resizer { + width: 4px; + cursor: col-resize; + background: transparent; + flex-shrink: 0; + z-index: 1000; + margin-left: -2px; + margin-right: -2px; + user-select: none; +} +#sidebar-resizer:hover, +#sidebar-resizer.dragging { + background: var(--handle-color); +} + +body.dragging-sidebar { + user-select: none; + cursor: col-resize !important; +} + +/* ─── Main ──────────────────────────────────────────────── */ +#main { + flex: 1; + display: flex; + flex-direction: column; + min-width: 0; +} + +/* Map */ +#map-container { + flex: 1; + position: relative; + min-height: 100px; +} +#map-container.editing-mode { + border: 4px solid var(--accent); + box-shadow: 0 0 15px var(--accent); + z-index: 1000; /* Ensure glow is visible */ +} +#map { + width: 100%; + height: 100%; + background: var(--bg); +} + +#map-controls { + position: absolute; + top: 12px; + left: 12px; + z-index: 1000; + display: flex; + align-items: center; + gap: 8px; +} +#basemap-switcher { + display: flex; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 8px; + padding: 2px; + height: 24px; + box-sizing: border-box; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + align-items: center; + gap: 0; +} + +#selected-extra-map { + font-size: var(--fs-s); + font-weight: 700; + color: var(--accent); + padding: 0 6px; + max-width: 120px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + cursor: pointer; +} +#selected-extra-map.hidden { + display: none; +} + +#btn-extra-layers { + border: none !important; + border-left: 1px solid var(--border) !important; + border-radius: 0 !important; + margin-left: 0 !important; + padding-left: 6px !important; + padding-right: 0 !important; + width: auto !important; + height: 100% !important; + background: transparent !important; +} + +#extra-layers-menu { + position: absolute; + top: 40px; + right: 0; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 8px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); + max-height: 300px; + overflow-y: auto; + width: 200px; + z-index: 1000; + padding: 4px; +} +#extra-layers-menu.hidden { + display: none; +} +.extra-layers-header { + font-size: var(--fs-s); + font-weight: 700; + color: var(--text-dim); + text-transform: uppercase; + padding: 6px 8px; + border-bottom: 1px solid var(--border); + margin-bottom: 4px; +} +.extra-layers-search { + padding: 4px 8px; + border-bottom: 1px solid var(--border); + margin-bottom: 4px; +} +#extra-layers-search-input { + width: 100%; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: 4px; + color: var(--text); + font-size: var(--fs-s); + padding: 4px 8px; + outline: none; +} +#extra-layers-search-input:focus { + border-color: var(--accent); +} +.extra-layers-license { + font-size: var(--fs-s); + color: var(--text-dim); + padding: 4px 8px; + border-bottom: 1px solid var(--border); + margin-bottom: 4px; +} +.extra-layers-license a { + color: var(--accent); + text-decoration: none; +} +.extra-layers-license a:hover { + text-decoration: underline; +} +.extra-layer-row { + margin-bottom: 2px; +} +.extra-layer-item { + display: block; + width: 100%; + text-align: left; + background: transparent; + border: none; + color: var(--text-muted); + padding: 4px 10px 2px 10px; + font-size: var(--fs-s); + font-weight: 600; + border-radius: 4px; + cursor: pointer; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.extra-layer-item:hover { + background: var(--surface2); + color: var(--text); +} +.extra-layer-attribution { + font-size: var(--fs-s); + color: var(--text-dim); + padding: 0 10px 4px 10px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +#map-loader { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 8px; + padding: 0 10px; + height: 24px; + box-sizing: border-box; + display: flex; + align-items: center; + gap: 8px; + font-size: var(--fs-s); + font-weight: 600; + color: var(--text-muted); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} +.spinner-sm { + width: 12px; + height: 12px; + border: 2px solid var(--surface2); + border-top-color: var(--accent); + border-radius: 50%; +} +.bm-btn { + background: transparent; + border: none; + color: var(--text-muted); + padding: 2px 6px; + font-size: var(--fs-s); + font-weight: 600; + border-radius: 6px; +} +.bm-btn:hover { + color: var(--text); +} +.bm-btn.active { + background: var(--surface2); + color: var(--accent); +} + +/* Map Cursor Dot */ +.map-cursor-dot { + pointer-events: none; +} +.dot-inner { + width: 12px; + height: 12px; + background: #fff; + border: 2px solid #000; + border-radius: 50%; + box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.5); +} + +/* Map cursor info popup */ +#map-cursor-info { + position: absolute; + top: 12px; + right: 12px; + z-index: 1000; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 8px; + padding: 8px 12px; + font-size: var(--fs-s); + color: var(--text); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + display: none; + pointer-events: none; +} + +/* Resize handle */ +#resize-handle { + height: 6px; + background: var(--bg); + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); + cursor: ns-resize; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + z-index: 100; +} +#resize-handle:hover { + background: var(--handle-color); +} +.handle-grip { + width: 32px; + height: 2px; + background: var(--border2); + border-radius: 1px; +} + +/* ─── Chart Panel ─────────────────────────────────────────── */ +#chart-panel { + display: flex; + flex-direction: column; + background: var(--surface); + overflow: hidden; + flex: 1; + width: 100%; + height: 100%; + min-height: 0; +} + +#tab-nav { + display: flex; + padding: 0 12px; + border-bottom: 1px solid var(--border); + gap: 4px; +} + +.tab-btn { + background: transparent; + border: none; + border-bottom: 2px solid transparent; + color: var(--text-dim); + padding: 10px 12px; + font-size: var(--fs-m); + font-weight: 700; + display: flex; + align-items: center; + gap: 6px; +} +.tab-btn:hover { + color: var(--text-muted); +} +.tab-btn.active { + color: var(--accent); + border-bottom-color: var(--accent); +} +.tab-btn .material-symbols-rounded { + font-size: var(--is-s); +} + +.tab-content { + display: none; + flex: 1; + min-height: 0; +} +.tab-content.active { + display: flex; + flex-direction: column; + overflow-y: auto; + scrollbar-width: none; +} + +/* Custom scrollbar for active tab content */ +.tab-content.active::-webkit-scrollbar { + width: 0; + height: 0; +} +.tab-content.active::-webkit-scrollbar-track { + background: transparent; +} +.tab-content.active::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 3px; +} +.tab-content.active::-webkit-scrollbar-thumb:hover { + background: var(--text-dim); +} + +#chart-toolbar { + display: flex; + align-items: center; + padding: 6px 12px; + gap: 12px; + border-bottom: 1px solid var(--border); + background: var(--bg); + min-height: 40px; + position: sticky; + top: 0; + z-index: 100; +} + +.icon-btn { + background: transparent; + border: 1px solid transparent; + color: var(--text-muted); + width: 24px; + height: 24px; + border-radius: 6px; + display: flex; + align-items: center; + justify-content: center; +} +.icon-btn.hidden { + display: none; +} +.icon-btn:hover { + background: var(--surface2); + color: var(--text); +} +.icon-btn.active { + background: var(--surface2); + color: var(--accent); +} +.icon-btn.danger:hover { + background: rgba(239, 68, 68, 0.12); + color: var(--danger); +} +.icon-btn .material-symbols-rounded { + font-size: var(--fs-l); +} + +#btn-metric-menu { + flex: 0 0 auto; +} + +#metric-pills { + display: flex; + gap: 6px; + flex: 1; + overflow: hidden; +} +.metric-pill:not(.active) { + display: none; +} +.metric-pill.overflow-hidden { + display: none !important; +} +#pill-overflow { + color: var(--text-muted); + font-weight: bold; + padding: 0 4px; + align-self: flex-end; +} +.metric-pill { + height: 24px; + padding: 0 8px; + border-radius: 12px; + border: 1px solid var(--border); + background: var(--surface2); + color: var(--text-muted); + font-size: var(--fs-s); + font-weight: 500; + display: flex; + align-items: center; + gap: 4px; + white-space: nowrap; +} +.metric-pill .material-symbols-rounded { + font-size: var(--fs-m); +} +.metric-pill.active { + background: color-mix(in srgb, var(--pill-color) 15%, var(--surface2)); + border-color: var(--pill-color); + color: var(--pill-color); +} +.metric-pill.disabled { + opacity: 0.3; + filter: grayscale(1); + cursor: default; +} + +#chart-options { + display: flex; + align-items: center; + gap: 0; + margin-left: auto; +} + +.seg-ctrl { + display: flex; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: 6px; + padding: 2px; + height: 24px; + box-sizing: border-box; +} +.seg-btn { + background: transparent; + border: none; + color: var(--text-dim); + padding: 0 8px; + font-size: var(--fs-s); + font-weight: 700; + border-radius: 4px; + display: flex; + align-items: center; + gap: 6px; + height: 100%; +} +.seg-btn .material-symbols-rounded { + font-size: var(--fs-m); +} +.seg-btn.active { + background: var(--bg); + color: var(--text); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); +} + +/* Stats Summary bar */ +#chart-stats { + padding: 4px 14px; + border-bottom: 1px solid var(--border); + background: var(--surface2); +} +#chart-stats.hidden { + display: none; +} +#chart-stats-wrap { + display: flex; + flex-direction: column; + gap: 2px; +} +.stats-row { + display: flex; + align-items: center; + gap: 16px; +} +.stats-row-label { + width: 45px; + font-size: var(--fs-s); + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.8px; + color: var(--text-muted); + white-space: nowrap; +} + +.chart-row-stats-container { + display: flex; + flex: 1; + align-items: center; + justify-content: space-between; +} + +.chart-row-right-actions { + width: 130px; /* HIST_W */ + display: none; + align-items: center; + justify-content: flex-end; + flex-shrink: 0; +} +.with-histogram .chart-row-right-actions { + display: flex; +} +.chart-stats-total, +.chart-stats-selection { + display: flex; + gap: 10px; + font-size: var(--fs-s); + color: var(--text-dim); + align-items: center; + white-space: nowrap; + font-weight: 500; +} +.chart-stats-selection { + margin-left: auto; + position: relative; +} +.chart-stats-selection::after { + content: ''; + position: absolute; + bottom: -6px; + left: 0; + right: 0; + height: 2px; + background-color: var(--sel-color); + pointer-events: none; +} +.all-chip { + background: var(--surface2); + color: var(--text-muted); + font-weight: 500; + padding: 2px; + border-radius: 4px; + font-size: var(--fs-m); + margin-right: 4px; + cursor: pointer; + border: 1px solid var(--border); + display: flex; + align-items: center; + justify-content: center; +} +.all-chip:hover { + background: var(--border); + color: var(--text); +} +.sel-tag { + background: var(--surface2); + color: var(--text-muted); + font-weight: 500; + padding: 2px; + border-radius: 4px; + font-size: var(--fs-m); + margin-right: 4px; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid var(--border); +} + +.mm-item { + display: flex; + align-items: center; + gap: 2px; + white-space: nowrap; +} +.mm-icon { + font-size: var(--fs-m); + color: var(--text-dim); +} + +/* ── uPlot overrides ─────────────────────────────────────── */ +.uplot { + color: var(--text-muted) !important; +} +.u-title { + display: none; +} +.u-legend { + display: none; +} + +/* Selection drag background — colour matches the chart's metric */ +.chart-row .u-select { + background: color-mix(in srgb, var(--chart-color, #3b82f6) 12%, transparent) !important; + border: 1px solid color-mix(in srgb, var(--chart-color, #3b82f6) 35%, transparent) !important; +} + +/* Make the cursor crosshair dashed */ +.u-cursor-x { + border-left: 1px dashed rgba(255, 255, 255, 0.55) !important; +} +.u-cursor-y { + display: none !important; +} + +/* ── Selection fill ─────────────────────────────────────── */ +.sel-fill { + position: absolute; + top: 0; + background: color-mix(in srgb, var(--theme-color) 8%, transparent); + border-left: 1px solid color-mix(in srgb, var(--theme-color) 30%, transparent); + border-right: 1px solid rgba(148, 163, 184, 0.4); + pointer-events: none; +} + +/* ── Selection handles ───────────────────────────────────── */ +.sel-handle { + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: 8px; + height: 24px; + background: rgba(255, 255, 255, 0.85); + border: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 4px; + cursor: ew-resize; + pointer-events: auto; + display: flex; + align-items: center; + justify-content: center; + z-index: 10; +} +.sel-handle::after { + content: ''; + width: 2px; + height: 10px; + border-left: 1px solid rgba(0, 0, 0, 0.4); + border-right: 1px solid rgba(0, 0, 0, 0.4); +} +.sel-handle:hover { + background: #fff; + transform: translate(-50%, -50%) scale(1.1); +} + +.sel-graph-marker { + position: absolute; + transform: translate(-50%, -50%); + pointer-events: none; + z-index: 11; + background: none !important; +} +.sel-graph-marker .material-symbols-rounded { +} + +/* ── Per-chart selection lines ──────────────────────────── */ +.sel-line { + position: absolute; + top: 0; + height: 100%; + width: 0; + border-left-width: 1.5px; + border-left-style: solid; + pointer-events: none; +} + +/* Labels on the selection lines */ +.sel-line-label { + position: absolute; + top: 4px; + font-size: var(--fs-s); + font-weight: 700; + background: rgba(14, 14, 16, 0.92); + color: #fff; + padding: 2px 5px; + border-radius: 4px; + pointer-events: none; + white-space: nowrap; + z-index: 10; + border: 1px solid var(--border); +} + +/* ── Charts view elements ─────────────────────────────────── */ +#charts-container { + flex: 1; + overflow-y: auto; + overflow-x: hidden; + padding: 6px 0 4px; + scrollbar-width: none; +} +#charts-container::-webkit-scrollbar { + width: 0; + height: 0; +} +#charts-container::-webkit-scrollbar-thumb { + background: var(--border2); + border-radius: 2px; +} + +/* Fixed X Axis Labels */ +.fixed-x-label { + position: absolute; + bottom: 4px; + font-size: var(--fs-s); + font-family: system-ui, sans-serif; + color: #555564; + z-index: 10; + pointer-events: none; +} +.fixed-x-max { + right: 0; + text-align: right; +} + +/* Histogram column (inline, per chart row) */ +.chart-row-body { + display: flex; + flex-direction: row; + padding: 0 14px; + min-width: 0; + overflow: hidden; +} +.chart-row-body > div:first-child { + flex: 1; + min-width: 0; +} +.hist-col { + width: 130px; + flex-shrink: 0; + border-left: 1px solid var(--border); + margin-left: 20px; + margin-right: 0; + display: none; + align-items: center; + justify-content: center; + cursor: crosshair; +} +.hist-col.visible { + display: flex; +} +.hist-canvas { + display: block; +} + +/* Histogram connector line */ +#hist-line { + position: fixed; + height: 0; + border-top: 1px dashed rgba(255, 255, 255, 0.25); + pointer-events: none; + display: none; + z-index: 10000; +} + +/* Histogram tooltip */ +#hist-tooltip { + position: fixed; + background: var(--surface); + border: 1px solid var(--border2); + border-radius: 5px; + padding: 8px 10px; + pointer-events: none; + display: none; + z-index: 10001; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5); + font-size: var(--fs-s); +} +.hist-tt-header { + font-weight: 800; + margin-bottom: 6px; + padding-left: 8px; + border-left: 3px solid var(--accent); + color: var(--text); +} +.hist-tt-grid { + display: grid; + grid-template-columns: 1fr auto auto; + gap: 10px; + align-items: baseline; +} +.hist-tt-label { + font-size: var(--fs-s); + color: var(--text-muted); +} +.hist-tt-value { + font-size: var(--fs-s); + color: var(--text); + text-align: right; + font-variant-numeric: tabular-nums; +} +.hist-tt-pct { + font-size: var(--fs-s); + color: var(--text-dim); + text-align: right; + min-width: 36px; + font-variant-numeric: tabular-nums; +} +.hist-tt-grid.sel-row { + margin-top: 2px; + opacity: 0.9; +} +.hist-tt-label.sel { + color: var(--accent); + font-weight: 700; +} + +.chart-row { + border-bottom: 1px solid var(--border); +} +.chart-row:last-child { + border-bottom: none; +} + +/* ── Chart row header ─────────────────────────────────────── */ +.chart-row-header { + display: flex; + align-items: center; + gap: 12px; + padding: 8px 14px 4px 14px; + min-height: 28px; +} + +.progress-chart-row { + display: flex; + flex-direction: column; +} + +.progress-chart-row .chart-row-header { + height: 36px; + box-sizing: border-box; + padding-top: 0; + padding-bottom: 0; +} + +.progress-chart-row .chart-row-actions { + margin-left: auto; +} + +.progress-chart-row .chart-row-body { + flex: 1; + padding: 0; +} + +.chart-row-label-group { + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; + width: 140px; /* Fixed width for alignment */ +} + +.chart-row-actions { + display: flex; + align-items: center; + gap: 0; +} + +.chart-row-icon { + font-size: var(--is-s); + color: var(--chart-color); +} +.chart-row-label { + font-size: var(--fs-m); + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.8px; + color: var(--text-muted); + white-space: nowrap; +} + +/* Track Picker Popup */ +.track-picker-popup { + padding: 8px; + background: var(--surface); + color: var(--text); + border-radius: 8px; + min-width: 160px; +} +.picker-header { + font-size: var(--fs-s); + text-transform: uppercase; + font-weight: 700; + color: var(--text-dim); + margin-bottom: 8px; + padding-bottom: 4px; + border-bottom: 1px solid var(--border); +} +.picker-list { + display: flex; + flex-direction: column; + gap: 2px; +} +.picker-item { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 8px; + border-radius: 6px; + cursor: pointer; +} +.picker-item:hover { + background: var(--surface2); +} +.picker-color { + width: 3px; + height: 14px; + border-radius: 1px; +} +.picker-info { + display: flex; + flex-direction: column; + min-width: 0; +} +.picker-name { + font-size: var(--fs-s); + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 180px; +} +/* Custom Modal / Dialog */ +.modal-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.75); + backdrop-filter: blur(4px); + display: flex; + align-items: center; + justify-content: center; + z-index: 20000; +} +.modal-content { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 12px; + padding: 24px; + width: 100%; + max-width: 320px; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5); + display: flex; + flex-direction: column; + gap: 16px; +} +.modal-title { + font-size: var(--fs-l); + font-weight: 800; + color: var(--text); +} +.modal-body { + font-size: var(--fs-m); + color: var(--text-muted); + line-height: 1.5; +} +.modal-input-wrap { + display: flex; + flex-direction: column; + gap: 8px; +} +.modal-input-label { + font-size: var(--fs-s); + font-weight: 700; + text-transform: uppercase; + color: var(--text-dim); +} +.modal-input { + background: var(--bg); + border: 1px solid var(--border2); + border-radius: 6px; + padding: 10px; + color: var(--text); + font-size: var(--fs-l); + font-weight: 800; + text-align: center; + letter-spacing: 4px; +} +.modal-input:focus { + outline: none; + border-color: var(--accent); +} +.modal-actions { + display: flex; + gap: 12px; + margin-top: 8px; +} +.modal-btn { + flex: 1; + padding: 10px; + border-radius: 6px; + font-size: var(--fs-m); + font-weight: 700; + border: 1px solid transparent; +} +.modal-btn.cancel { + background: var(--surface2); + color: var(--text); + border-color: var(--border); +} +.modal-btn.cancel:hover { + background: var(--border); +} +.modal-btn.confirm { + background: var(--danger); + color: #fff; +} +.modal-btn.confirm:disabled { + opacity: 0.3; + cursor: not-allowed; + filter: grayscale(1); +} +.modal-btn.confirm:not(:disabled):hover { + filter: brightness(1.1); +} + +.picker-meta { + font-size: var(--fs-s); + color: var(--text-dim); + font-weight: 700; +} + +/* Leaflet Popup Overrides */ +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: var(--surface) !important; + color: var(--text) !important; + border: 1px solid var(--border) !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4) !important; +} +.leaflet-popup-content { + margin: 0 !important; +} +.leaflet-popup-tip { + border: none !important; +} +.map-color-btn { + margin-left: 4px; +} +.map-color-btn .material-symbols-rounded { + font-size: var(--is-s); +} +.map-color-btn.active { + color: var(--chart-color, var(--accent)); +} + +.smooth-btn.active { + color: var(--accent); +} +.cur-y-val { + position: absolute; + left: 0; + top: 0; + pointer-events: none; + font-size: var(--fs-s); + font-weight: 700; + background: rgba(14, 14, 16, 0.92); + padding: 2px 6px; + border-radius: 4px; + border: 1px solid rgba(255, 255, 255, 0.1); + z-index: 2000; + white-space: nowrap; +} +.cur-y-val.pin { + z-index: 1000; + opacity: 0.7; +} + +/* ─── Details View ────────────────────────────────────────── */ +#details-view { + width: 100%; + padding: 24px; + max-width: 900px; + margin: 0 auto; +} + +#details-header { + margin-bottom: 32px; +} +.details-title { + font-size: var(--fs-l); + font-weight: 800; + margin-bottom: 4px; +} +.details-subtitle { + font-size: var(--fs-m); + color: var(--text-muted); +} + +.details-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 16px; +} +.details-card { + background: var(--surface2); + border: 1px solid var(--border); + padding: 16px; + border-radius: 12px; + display: flex; + flex-direction: column; + gap: 4px; +} +.details-card .material-symbols-rounded { + color: var(--accent); + margin-bottom: 4px; + font-size: var(--is-m); +} +.details-card-label { + font-size: var(--fs-s); + font-weight: 500; + text-transform: uppercase; + color: var(--text-dim); + letter-spacing: 0.5px; +} +.details-card-value { + font-size: var(--fs-l); + font-weight: 500; +} + +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + color: var(--text-dim); + gap: 12px; + padding: 40px 20px; +} +.empty-icon { + font-size: var(--fs-l); + opacity: 0.2; +} +.empty-text { + font-size: var(--fs-m); + font-weight: 500; +} + +#chart-empty { + height: 100%; +} +#details-empty { + margin-top: 40px; +} + +/* ── Toast notifications ─────────────────────────────────── */ +#toast-container { + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + display: flex; + flex-direction: column; + gap: 8px; + z-index: 9999; +} +.toast { + background: var(--surface2); + color: var(--text); + padding: 10px 20px; + border-radius: 8px; + font-size: var(--fs-m); + font-weight: 600; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); + border: 1px solid var(--border2); +} +.toast.error { + border-color: var(--danger); +} +.toast.out { +} + +/* ── Sort menu popup ── */ +.sort-menu-popup, +.metric-menu-popup { + position: fixed; + z-index: 10000; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: 8px; + padding: 6px; + min-width: 180px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); +} + +.menu-item { + display: flex; + align-items: center; + gap: 10px; + padding: 8px 10px; + border-radius: 6px; + cursor: pointer; + color: var(--text-muted); +} +.menu-item:hover { + background: var(--surface); + color: var(--text); +} +.menu-item.active { + color: var(--text); + font-weight: 600; +} +.menu-item .material-symbols-rounded { + font-size: var(--is-s); +} +.menu-item .item-label { + flex: 1; + font-size: var(--fs-m); +} +.menu-item .arrow, +.menu-item .check { + font-size: var(--is-s); + color: var(--text-dim); +} + +/* ─── Insights View ───────────────────────────────────────── */ +#insights-view { + width: 100%; + padding: 24px; + max-width: 1000px; + margin: 0 auto; +} + +.insights-grid { + column-count: 2; + column-gap: 24px; +} + +@media (max-width: 900px) { + .insights-grid { + column-count: 1; + } +} + +.insight-card { + display: inline-flex; + width: 100%; + break-inside: avoid; + margin-bottom: 24px; + background: var(--surface2); + border: 1px solid var(--border); + padding: 20px; + border-radius: 12px; + flex-direction: column; + gap: 16px; +} + +.insight-title { + font-size: var(--fs-m); + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.8px; + display: flex; + align-items: center; + gap: 8px; + color: var(--text-muted); +} + +.insight-title .material-symbols-rounded { + font-size: var(--is-s); +} + +.insight-chart-container { + width: 100%; + height: 250px; +} + +.power-curve-table { + width: 100%; + border-collapse: collapse; + font-size: var(--fs-m); + margin-top: 0; +} + +.power-curve-table th { + text-align: left; + color: var(--text-dim); + padding: 4px 8px; + font-weight: 600; + border-bottom: 1px solid var(--border); +} + +.power-curve-table td { + padding: 6px 8px; + border-bottom: 1px solid var(--border); +} + +.power-curve-table tr:last-child td { + border-bottom: none; +} + +.progress-details summary { + cursor: pointer; + font-size: var(--fs-m); + color: var(--text-dim); + display: flex; + align-items: center; + gap: 4px; + list-style: none; +} + +.progress-details summary::-webkit-details-marker { + display: none; +} + +.progress-details[open] summary .expand-icon { + transform: rotate(90deg); +} + +.progress-details summary .material-symbols-rounded { + font-size: var(--fs-l); +} + +.progress-details summary .expand-icon { +} + +.power-curve-val { + font-weight: 700; + color: var(--text); + text-align: right; +} + +.evolution-select-btn { + background: none; + border: none; + cursor: pointer; + color: var(--chart-color); + padding: 0; + font-size: var(--fs-l); + vertical-align: middle; + margin-left: 4px; +} + +.hr-settings-popup { + display: flex; + flex-direction: column; +} + +.hr-input-row { + display: flex; + justify-content: space-between; + align-items: center; + font-size: var(--fs-m); + color: var(--text-muted); + font-weight: 600; +} + +.hr-zone-input { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 4px; + color: var(--text); + width: 60px; + padding: 4px 8px; + font-size: var(--fs-m); + text-align: right; + outline: none; +} + +.hr-zone-input:focus { + border-color: var(--accent); +} + +.save-btn { + background: var(--accent); + color: #fff; + border: none; + border-radius: 6px; + padding: 8px; + font-size: 12px; + font-weight: 700; + cursor: pointer; +} + +.save-btn:hover { + background: var(--accent-hover); +} + +.menu-item.active .arrow, +.menu-item.active .check { + color: var(--accent); +} + +/* ── Evolution View ───────────────────────────────────────── */ +.evolution-toolbar { + display: flex; + align-items: center; + justify-content: space-between; + padding: 6px 12px; + border-bottom: 1px solid var(--border); + background: var(--bg); + min-height: 40px; +} + +.evolution-toolbar-left, +.evolution-toolbar-right { + display: flex; + align-items: center; + gap: 12px; +} + +.evolution-toolbar .metric-pills { + display: flex; + gap: 6px; +} + +.evolution-toolbar .metric-pill { + cursor: pointer; +} + +.evolution-container { + display: flex; + flex-direction: column; + gap: 0px; + padding: 6px 0 4px; +} + +.evolution-card-group { + display: flex; + flex-direction: column; + gap: 10px; + width: 100%; +} + +.evolution-legend { + display: flex; + gap: 16px; + font-size: 12px; + color: var(--text-dim); + margin-top: 0px; + margin-bottom: 0px; + justify-content: center; +} + +.evolution-legend-item { + display: flex; + align-items: center; + gap: 6px; +} + +.evolution-legend-line { + width: 16px; + height: 0; + display: inline-block; +} + +.evolution-legend-line.solid { + border-top: 2px solid var(--chart-color); +} + +.evolution-legend-line.dashed { + border-top: 2px dashed #888888; +} + +.evolution-tooltip-title { + font-weight: bold; + margin-bottom: 4px; +} + +.evolution-tooltip-row { + display: flex; + justify-content: space-between; + gap: 15px; +} + +.evolution-tooltip-label { + color: #8a8a93; +} + +.evolution-tooltip-value { + font-weight: bold; +} + +.evolution-empty-text { + color: var(--text-dim); + font-size: 12px; + text-align: center; + margin-top: 20px; +} + +.evolution-chart-container { + height: 250px; + flex: 1; +} + +.distance-progress-card .card-content, +.elevation-progress-card .card-content { + display: flex; + gap: 20px; +} + +.chart-scroll-container { + flex: 1; + overflow-x: auto; + position: relative; + background: var(--bg-dim); + border-radius: 8px; + padding: 10px; + scrollbar-width: none; +} +.chart-scroll-container::-webkit-scrollbar { + width: 0; + height: 0; + display: none; +} + +.accumulated-table-container { + width: 250px; + background: var(--bg-dim); + border-radius: 8px; + padding: 15px; +} + +.accumulated-table { + width: 100%; + border-collapse: collapse; + font-size: var(--fs-m); +} + +.accumulated-table th, +.accumulated-table td { + padding: 4px 8px; + text-align: left; + border-bottom: 1px solid var(--border-color); +} + +.accumulated-table th { + color: var(--text-dim); + font-weight: 500; + text-transform: uppercase; + font-size: var(--fs-m); + letter-spacing: 0.5px; +} + +.accumulated-table td:last-child { + text-align: right; + font-weight: 500; + font-family: monospace; +} + +.accumulated-table tr:last-child td { + border-bottom: none; +} + +.chart-scroll-container::-webkit-scrollbar { + height: 4px; +} + +.chart-scroll-container::-webkit-scrollbar-thumb { + background: var(--border2); + border-radius: 2px; +} + +/* uPlot overrides to comply with font size restrictions */ +.u-title { + font-size: var(--fs-m) !important; +} +.u-legend { + font-size: var(--fs-m) !important; +} + +/* Courses Tab */ +.courses-container { + padding: 16px; + display: flex; + flex-direction: column; + gap: 16px; +} + +.courses-list { + display: flex; + flex-direction: column; + gap: 8px; +} + +.course-item { + background: var(--surface2); + border: 1px solid var(--border); + border-radius: 8px; + display: flex; + flex-direction: column; + cursor: pointer; + overflow: hidden; +} + +.course-item:hover { + background: var(--surface3); + border-color: var(--border-high); +} + +.course-item-header { + padding: 6px 12px; + display: flex; + align-items: center; + gap: 12px; + width: 100%; +} + +.course-name { + font-weight: 600; + flex: 1; +} + +.course-meta { + color: var(--text-muted); + font-size: var(--fs-s); +} + +.course-actions { + display: flex; + gap: 4px; +} + +.course-actions .icon-btn { + opacity: 0.5; +} + +.course-item:hover .course-actions .icon-btn { + opacity: 1; +} + +.expand-icon { + color: var(--text-muted); +} + +.course-tracks { + padding: 8px 12px; + border-top: 1px solid var(--border); + background: var(--surface1); +} + +.course-tracks-title { + font-size: var(--fs-xs); + font-weight: 700; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 6px; +} + +.course-tracks-table { + width: 100%; + border-collapse: collapse; + font-size: var(--fs-s); + color: var(--text); +} + +.course-tracks-table th, +.course-tracks-table td { + padding: 6px 8px; + text-align: right; + border-bottom: 1px solid var(--border-low); +} + +.course-tracks-table th:first-child, +.course-tracks-table td:first-child, +.course-tracks-table th:nth-child(2), +.course-tracks-table td:nth-child(2) { + text-align: left; +} + +.course-tracks-table td:not(:first-child) { + white-space: nowrap; +} + +.course-tracks-table th { + font-weight: 600; + color: var(--text-muted); + font-size: var(--fs-xs); + text-transform: uppercase; + letter-spacing: 0.5px; + white-space: nowrap; +} + +.course-tracks-table tr:last-child td { + border-bottom: none; +} + +.course-tracks-table th:first-child, +.course-tracks-table td:first-child { + width: 100%; +} + +.course-track-row:hover { + background: var(--surface2); +} + +.course-track-row.selected { + background: color-mix(in srgb, var(--theme-color) 8%, transparent); +} + +.track-name-cell.clickable { + color: var(--accent); + cursor: pointer; + font-weight: 500; +} + +.track-name-cell.clickable:hover { + text-decoration: underline; +} + +.metric-icon { + font-size: 16px; + vertical-align: middle; + margin-right: 4px; +} + +.metric-icon.duration { + color: var(--text-muted); +} + +.metric-icon.speed { + color: #4caf50; +} + +.metric-icon.power { + color: #ff9800; +} + +.metric-icon.hr { + color: #f44336; +} + +.course-point-marker { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/suites-experimental/tools-gps-tracks/src/css/uPlot.min.css b/suites-experimental/tools-gps-tracks/src/css/uPlot.min.css new file mode 100644 index 0000000000..a030d63f20 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/css/uPlot.min.css @@ -0,0 +1 @@ +.uplot, .uplot *, .uplot *::before, .uplot *::after {box-sizing: border-box;}.uplot {font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";line-height: 1.5;width: min-content;}.u-title {text-align: center;font-size: 18px;font-weight: bold;}.u-wrap {position: relative;user-select: none;}.u-over, .u-under {position: absolute;}.u-under {overflow: hidden;}.uplot canvas {display: block;position: relative;width: 100%;height: 100%;}.u-axis {position: absolute;}.u-legend {font-size: 14px;margin: auto;text-align: center;}.u-inline {display: block;}.u-inline * {display: inline-block;}.u-inline tr {margin-right: 16px;}.u-legend th {font-weight: 600;}.u-legend th > * {vertical-align: middle;display: inline-block;}.u-legend .u-marker {width: 1em;height: 1em;margin-right: 4px;background-clip: padding-box !important;}.u-inline.u-live th::after {content: ":";vertical-align: middle;}.u-inline:not(.u-live) .u-value {display: none;}.u-series > * {padding: 4px;}.u-series th {cursor: pointer;}.u-legend .u-off > * {opacity: 0.3;}.u-select {background: rgba(0,0,0,0.07);position: absolute;pointer-events: none;}.u-cursor-x, .u-cursor-y {position: absolute;left: 0;top: 0;pointer-events: none;will-change: transform;}.u-hz .u-cursor-x, .u-vt .u-cursor-y {height: 100%;border-right: 1px dashed #607D8B;}.u-hz .u-cursor-y, .u-vt .u-cursor-x {width: 100%;border-bottom: 1px dashed #607D8B;}.u-cursor-pt {position: absolute;top: 0;left: 0;border-radius: 50%;border: 0 solid;pointer-events: none;will-change: transform;/*this has to be !important since we set inline "background" shorthand */background-clip: padding-box !important;}.u-axis.u-off, .u-select.u-off, .u-cursor-x.u-off, .u-cursor-y.u-off, .u-cursor-pt.u-off {display: none;} \ No newline at end of file diff --git a/suites-experimental/tools-gps-tracks/src/index.html b/suites-experimental/tools-gps-tracks/src/index.html new file mode 100644 index 0000000000..883ffbaddf --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/index.html @@ -0,0 +1,551 @@ + + + + + + Weg — GPS Analysis + + + + + + + + +
+ + + + + + + + + +
+ + + + + +
+
+ + + + + + +
+ +
+
+
+ + + + + + + + + + + + + +
+ +
+
+ + +
+ + +
+
+ + + +
+
+ no_sim +
Select a track to view analysis
+
+
+
+ +
+
+
+ no_sim +
Select a track for insights
+
+
+
+ +
+
+
+ no_sim +
Select a track for details
+
+
+
+ +
+
+
+ no_sim +
Select a track for combined analysis
+
+
+
+ +
+
+
+ no_sim +
Select a track for progress analysis
+
+
+
+ +
+
+
+ route +
No courses created yet
+
+
+
+
+
+
+ +
+
+
+ + + + diff --git a/suites-experimental/tools-gps-tracks/src/map.ts b/suites-experimental/tools-gps-tracks/src/map.ts new file mode 100644 index 0000000000..6098e39696 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/map.ts @@ -0,0 +1,105 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +import { TrackData, TrackPoint } from './parsers'; + +export const MapView = (() => { + let trackData: Record = {}; + let customClickHandler: ((e: any) => boolean) | null = null; + + function init( + onSelectCb: (id: string) => void, + onMoveCb: (lat: number, lng: number, zoom: number) => void, + onPointClickCb: (id: string, idx: number) => void, + onPointHoverCb: (id: string | null, idx: number | null) => void, + onDblClickCb: () => void, + ) {} + + function switchBasemap(layer: string) {} + function addTrack(t: TrackData) { + trackData[t.id] = t; + } + function addTracks(ts: TrackData[]) { + ts.forEach((t) => { + trackData[t.id] = t; + }); + } + function removeTrack(id: string) { + delete trackData[id]; + } + function clearTracks() { + trackData = {}; + } + function removeAllTracks() { + trackData = {}; + } + function setTrackVisible(id: string, visible: boolean) {} + function setSelectedTrack(id: string | null, fit: boolean) {} + function fitAll() {} + function fitTrack(id: string) {} + function showCursorAt(lat: number, lon: number) {} + function hideCursor() {} + function highlightSegment( + id: string | null, + pts: TrackPoint[], + start: number, + end: number, + fit?: boolean, + colors?: string[] | null, + ) {} + function clearHighlight() {} + function setTrackHover(id: string, hover: boolean) {} + function ensureVisible(pts: any) {} + function centerOn(lat: number, lon: number, zoom?: number | null, force?: boolean) {} + function closePopup() {} + function invalidateSize() {} + function getPosition(): [number, number, number] { + return [0, 0, 0]; + } + function setPosition(lat: number, lng: number, zoom: number) {} + function colorTrackByMetric(id: string, pts: TrackPoint[], colors: string[]) {} + function clearMetricColor(id: string) {} + + function findTracksPassingThroughPoints( + points: { lat: number; lng: number }[], + radius: number, + ): string[] { + return Object.keys(trackData); + } + + return { + init, + getMap: () => null as any, + setCustomClickHandler: (handler: any) => { + customClickHandler = handler; + }, + switchBasemap, + addTrack, + addTracks, + removeTrack, + clearTracks, + removeAllTracks, + setTrackVisible, + setSelectedTrack, + fitAll, + fitTrack, + showCursorAt, + hideCursor, + highlightSegment, + clearHighlight, + setTrackHover, + ensureVisible, + centerOn, + closePopup, + invalidateSize, + getPosition, + setPosition, + colorTrackByMetric, + clearMetricColor, + findTracksPassingThroughPoints, + getTrackData: (id: string) => trackData[id], + }; +})(); diff --git a/suites-experimental/tools-gps-tracks/src/metrics.ts b/suites-experimental/tools-gps-tracks/src/metrics.ts new file mode 100644 index 0000000000..b911146906 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/metrics.ts @@ -0,0 +1,181 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +import { TrackPoint } from './parsers'; + +export interface MetricDefinition { + label: string; + field: keyof TrackPoint; + unit: string; + color: string; + abbr: string; + icon: string; + fmt: (v: number, precise?: boolean) => string; + fmtAxis: (v: number) => string; + compute?: ( + pts: TrackPoint[], + fillNulls: (data: (number | null)[]) => (number | null)[], + ) => (number | null)[]; + transform?: (v: number) => number | null; + smoothSigma?: number; +} + +export const Metrics = { + speed: { name: 'Speed', color: '#45B7D1', icon: 'speed' }, + gradient: { name: 'Gradient', color: '#A8C8A0', icon: 'trending_up' }, + power: { name: 'Power', color: '#F7DC6F', icon: 'bolt' }, + hr: { name: 'Heart Rate', color: '#FF6B6B', icon: 'favorite' }, + cadence: { name: 'Cadence', color: '#BB8FCE', icon: 'directions_run' }, + temperature: { name: 'Temperature', color: '#F8C471', icon: 'thermostat' }, + elevation: { name: 'Elevation', color: '#4ECDC4', icon: 'terrain' }, + distance: { name: 'Distance', color: '#9f1bfdff', icon: 'arrow_range' }, + gearRear: { name: 'Rear Gear', color: '#82E0AA', icon: 'settings' }, + gearFront: { name: 'Front Gear', color: '#A8C8A0', icon: 'settings_input_component' }, + gears: { name: 'Gears', color: '#FF8C00', icon: 'settings' }, + battery: { name: 'Battery', color: '#45B7D1', icon: 'battery_full' }, + vam: { name: 'VAM', color: '#FFA07A', icon: 'trending_up' }, +}; + +export const METRICS: Record = { + elevation: { + label: 'Elevation', + field: 'ele', + unit: 'm', + color: Metrics.elevation.color, + abbr: 'ele', + icon: Metrics.elevation.icon, + fmt: (v, p) => (p ? v.toFixed(1) : Math.round(v).toString()), + fmtAxis: (v) => Math.round(v).toString(), + }, + speed: { + label: 'Speed', + field: 'speed', + unit: 'km/h', + color: Metrics.speed.color, + abbr: 'spd', + icon: Metrics.speed.icon, + fmt: (v) => (v * 3.6).toFixed(1), + fmtAxis: (v) => (v * 3.6).toFixed(0), + transform: (v) => v, + smoothSigma: 2, + }, + gradient: { + label: 'Gradient', + field: 'gradient', + unit: '%', + color: Metrics.gradient.color, + abbr: 'grad', + icon: Metrics.gradient.icon, + fmt: (v) => v.toFixed(1), + fmtAxis: (v) => v.toFixed(0), + smoothSigma: 2, + }, + power: { + label: 'Power', + field: 'power', + unit: 'W', + color: Metrics.power.color, + abbr: 'pwr', + icon: Metrics.power.icon, + fmt: (v) => Math.round(v).toString(), + fmtAxis: (v) => Math.round(v).toString(), + }, + hr: { + label: 'Heart Rate', + field: 'hr', + unit: 'bpm', + color: Metrics.hr.color, + abbr: 'hr', + icon: Metrics.hr.icon, + fmt: (v) => Math.round(v).toString(), + fmtAxis: (v) => Math.round(v).toString(), + }, + cadence: { + label: 'Cadence', + field: 'cad', + unit: 'rpm', + color: Metrics.cadence.color, + abbr: 'cad', + icon: Metrics.cadence.icon, + fmt: (v) => Math.round(v).toString(), + fmtAxis: (v) => Math.round(v).toString(), + }, + temperature: { + label: 'Temp', + field: 'temp', + unit: '°C', + color: Metrics.temperature.color, + abbr: 'temp', + icon: Metrics.temperature.icon, + fmt: (v) => v.toFixed(1), + fmtAxis: (v) => Math.round(v).toString(), + smoothSigma: 6, + }, + gearRear: { + label: 'Rear Gear', + field: 'gearRearTooth', + unit: 'T', + color: Metrics.gearRear.color, + abbr: 'rgr', + icon: Metrics.gearRear.icon, + fmt: (v) => Math.round(v).toString(), + fmtAxis: (v) => Math.round(v).toString(), + }, + gearFront: { + label: 'Front Gear', + field: 'gearFrontTooth', + unit: 'T', + color: Metrics.gearFront.color, + abbr: 'fgr', + icon: Metrics.gearFront.icon, + fmt: (v) => Math.round(v).toString(), + fmtAxis: (v) => Math.round(v).toString(), + }, + gears: { + label: 'Gears', + field: 'gears', + unit: '', + color: Metrics.gears.color, + abbr: 'gr', + icon: Metrics.gears.icon, + fmt: (v) => v.toFixed(2), + fmtAxis: (v) => v.toFixed(1), + }, + battery: { + label: 'Battery', + field: 'battery', + unit: '%', + color: Metrics.battery.color, + abbr: 'bat', + icon: Metrics.battery.icon, + fmt: (v) => Math.round(v).toString(), + fmtAxis: (v) => Math.round(v).toString(), + }, + vam: { + label: 'VAM', + field: 'ele', + unit: 'm/h', + color: '#FFA07A', + abbr: 'vam', + icon: 'trending_up', + fmt: (v) => Math.round(v).toString(), + fmtAxis: (v) => Math.round(v).toString(), + smoothSigma: 5, + compute: (pts, fillNulls) => { + const vam = new Array(pts.length).fill(null); + for (let i = 1; i < pts.length; i++) { + const p = pts[i]; + const prev = pts[i - 1]; + if (p.ele != null && prev.ele != null && p.time != null && prev.time != null) { + const de = p.ele - prev.ele; + const dt = (p.time - prev.time) / 1000; // in seconds + if (dt > 0) vam[i] = (de / dt) * 3600; // m/h + } + } + return fillNulls(vam); + }, + }, +}; diff --git a/suites-experimental/tools-gps-tracks/src/parsers.ts b/suites-experimental/tools-gps-tracks/src/parsers.ts new file mode 100644 index 0000000000..e1bf2341c6 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/parsers.ts @@ -0,0 +1,1453 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +import FitParser from 'fit-file-parser'; +import { haversine } from './utils'; + +export interface TrackPoint { + lat: number; + lon: number; + ele: number | null; + time: number | null; + hr: number | null; + cad: number | null; + power: number | null; + speed: number | null; + temp: number | null; + gearFront: number | null; + gearRear: number | null; + gearFrontTooth: number | null; + gearRearTooth: number | null; + battery: number | null; + gears: number | null; + dist?: number; + gradient?: number | null; +} + +export interface TrackStats { + totalDist: number; + elevGain: number; + elevLoss: number; + duration: number | null; + avgSpeed: number | null; + maxSpeed: number; + avgPower: number | null; + maxPower: number; + avgHR: number | null; + maxHR: number; + avgCadence: number | null; + avgTemp?: number | null; + minTemp?: number | null; + maxTemp?: number | null; + sensors: string[]; + startTime?: number | null; + powerCurve?: Record | null; + hrCurve?: Record | null; + hrZones?: number[] | null; // Time in seconds for each zone + powerZones?: number[] | null; // Time in seconds for each zone + shifts?: number | null; // Total number of shifts detected + avgBattery?: number | null; +} + +export interface DeviceInfo { + name?: string; + manufacturer?: string; + product?: string; + serial?: string; + version?: string; + hardwareVersion?: string; + type?: string; + batteryStatus?: string; + batteryVoltage?: number; + batteryLevel?: number; + sourceType?: string; +} + +export interface TrackData { + id: string; + name: string; + displayName?: string; + bounds?: { minLat: number; maxLat: number; minLon: number; maxLon: number }; + fileName?: string; + fileSize?: number; + device: string | null; + devices?: DeviceInfo[]; + sport?: string | null; + subSport?: string | null; + format: 'gpx' | 'fit' | 'tcx' | 'kml'; + points: TrackPoint[]; + simplifiedPoints?: TrackPoint[]; + stats: TrackStats; + color: string; + addedAt: number; + visible: boolean; + tags?: string[]; + _filtered?: boolean; +} + +export function calculateBounds(pts: TrackPoint[]) { + if (!pts.length) return null; + let minLat = pts[0].lat; + let maxLat = pts[0].lat; + let minLon = pts[0].lon; + let maxLon = pts[0].lon; + for (const p of pts) { + if (p.lat < minLat) minLat = p.lat; + if (p.lat > maxLat) maxLat = p.lat; + if (p.lon < minLon) minLon = p.lon; + if (p.lon > maxLon) maxLon = p.lon; + } + return { minLat, maxLat, minLon, maxLon }; +} + +export function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] { + if (pts.length <= 2) return pts; + const result: TrackPoint[] = [pts[0]]; + let lastPoint = pts[0]; + for (let i = 1; i < pts.length - 1; i++) { + const p = pts[i]; + const d = + p.dist != null && lastPoint.dist != null + ? p.dist - lastPoint.dist + : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon); + if (d >= minDistanceMeters) { + result.push(p); + lastPoint = p; + } + } + result.push(pts[pts.length - 1]); // Always keep the last point + return result; +} + +export const Parsers = (() => { + // ── Enrich track with distance & metadata ────────────────── + function enrichPoints(pts: TrackPoint[]): TrackPoint[] { + let totalDist = 0; + for (let i = 0; i < pts.length; i++) { + const p = pts[i]; + if (i > 0) { + const prev = pts[i - 1]; + const d = haversine(prev.lat, prev.lon, p.lat, p.lon); + totalDist += d; + + // Calculate speed if missing (m/s) + if (p.speed == null && p.time != null && prev.time != null) { + const dt = (p.time - prev.time) / 1000; + if (dt > 0 && dt < 10) { + // Skip big gaps + p.speed = d / dt; + } + } + + // Calculate gradient if missing (%) + if (p.gradient === undefined && p.ele != null && prev.ele != null) { + const de = p.ele - prev.ele; + if (d > 0.5) { + // Only calculate for non-tiny movements to reduce jitter + p.gradient = (de / d) * 100; + } else { + p.gradient = prev.gradient || 0; + } + } + } + p.dist = totalDist; + } + + // Optional: basic smoothing for gradient + for (let i = 1; i < pts.length - 1; i++) { + if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null) + pts[i].gradient = (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3; + } + + return pts; + } + + // ── Compute stats ───────────────────────────────────────────── + let hrZoneThresholds = [120, 140, 160, 180]; + let ftp = 200; + + function computeStats(pts: TrackPoint[], includeCurves = false): TrackStats { + const stats: TrackStats = { + totalDist: 0, + elevGain: 0, + elevLoss: 0, + duration: null, + avgSpeed: null, + maxSpeed: 0, + avgPower: null, + maxPower: 0, + avgHR: null, + maxHR: 0, + avgCadence: null, + avgTemp: null, + minTemp: null, + maxTemp: null, + sensors: [], + startTime: pts.length ? pts[0].time : null, + }; + + if (!pts.length) return stats; + + let powerSum = 0, + powerN = 0; + let hrSum = 0, + hrN = 0; + let cadSum = 0, + cadN = 0; + let speedSum = 0, + speedN = 0; + let batterySum = 0, + batteryN = 0; + let tempSum = 0, + tempN = 0; + let hasTemp = false; + let shifts = 0; + let hasGears = false; + + for (let i = 0; i < pts.length; i++) { + const p = pts[i]; + if (i > 0) { + const prev = pts[i - 1]; + if (p.ele != null && prev.ele != null) { + const diff = p.ele - prev.ele; + if (diff > 0) stats.elevGain += diff; + else stats.elevLoss -= diff; + } + if ( + (p.gearFront != null && p.gearFront !== prev.gearFront) || + (p.gearRear != null && p.gearRear !== prev.gearRear) + ) + shifts++; + } + if (p.power != null) { + powerSum += p.power; + powerN++; + if (p.power > stats.maxPower) stats.maxPower = p.power; + } + if (p.hr != null) { + hrSum += p.hr; + hrN++; + if (p.hr > stats.maxHR) stats.maxHR = p.hr; + } + if (p.cad != null) { + cadSum += p.cad; + cadN++; + } + if (p.speed != null) { + speedSum += p.speed; + speedN++; + if (p.speed > stats.maxSpeed) stats.maxSpeed = p.speed; + } + if (p.battery != null) { + batterySum += p.battery; + batteryN++; + } + if (p.temp != null) { + hasTemp = true; + tempSum += p.temp; + tempN++; + if (stats.minTemp == null || p.temp < stats.minTemp) stats.minTemp = p.temp; + if (stats.maxTemp == null || p.temp > stats.maxTemp) stats.maxTemp = p.temp; + } + if (p.gearFront != null || p.gearRear != null) hasGears = true; + } + + stats.totalDist = pts[pts.length - 1].dist || 0; + stats.avgPower = powerN ? Math.round(powerSum / powerN) : null; + stats.avgHR = hrN ? Math.round(hrSum / hrN) : null; + stats.avgCadence = cadN ? Math.round(cadSum / cadN) : null; + stats.avgSpeed = speedN ? speedSum / speedN : null; + stats.avgBattery = batteryN ? Math.round(batterySum / batteryN) : null; + stats.avgTemp = tempN ? Number((tempSum / tempN).toFixed(1)) : null; + stats.shifts = hasGears ? shifts : null; + + const t0 = pts[0].time; + const t1 = pts[pts.length - 1].time; + if (t0 != null && t1 != null) stats.duration = t1 - t0; + + if (hrN) { + stats.sensors.push('Heart Rate'); + if (includeCurves) { + stats.hrZones = calculateHRZones(pts); + stats.hrCurve = calculateHRCurve(pts); + } + } + if (cadN) stats.sensors.push('Cadence'); + if (powerN) { + stats.sensors.push('Power'); + if (includeCurves) { + stats.powerCurve = calculatePowerCurve(pts); + stats.powerZones = calculatePowerZones(pts); + } + } + if (hasTemp) stats.sensors.push('Temperature'); + if (hasGears) stats.sensors.push('Shifting'); + if (batteryN) stats.sensors.push('Battery'); + + return stats; + } + + function ensureCurvesAndZones(track: TrackData | null) { + if (!track || !track.points || !track.stats) return; + const pts = track.points; + const s = track.stats; + if (s.avgHR != null && !s.hrCurve) { + s.hrZones = calculateHRZones(pts); + s.hrCurve = calculateHRCurve(pts); + } + if (s.avgPower != null && !s.powerCurve) { + s.powerCurve = calculatePowerCurve(pts); + s.powerZones = calculatePowerZones(pts); + } + } + + const STANDARD_CURVE_DURATIONS = [ + 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600, + ]; + + function calculateSlidingMax(data: number[], durations: number[]) { + const len = data.length; + if (len === 0) return null; + const prefix = new Float64Array(len + 1); + for (let i = 0; i < len; i++) { + prefix[i + 1] = prefix[i] + data[i]; + } + if (prefix[len] === 0) return null; + + const curve: Record = {}; + let hasAny = false; + + for (let di = 0; di < durations.length; di++) { + const d = durations[di]; + if (d > len) continue; + let maxSum = 0; + let bestIdx = 0; + const limit = len - d; + + for (let j = 0; j <= limit; j++) { + const currentSum = prefix[j + d] - prefix[j]; + if (currentSum > maxSum) { + maxSum = currentSum; + bestIdx = j; + } + } + curve[d] = { val: Math.round(maxSum / d), idx: bestIdx }; + hasAny = true; + } + + return hasAny ? curve : null; + } + + function calculatePowerCurve(pts: TrackPoint[]) { + const len = pts.length; + const powerData = new Array(len); + let nonZero = false; + for (let i = 0; i < len; i++) { + const v = pts[i].power || 0; + powerData[i] = v; + if (v !== 0) nonZero = true; + } + if (!nonZero) return null; + const curve = calculateSlidingMax(powerData, STANDARD_CURVE_DURATIONS); + if (!curve) return null; + + const result: Record = {}; + for (const d in curve) result[d] = { power: curve[d].val, idx: curve[d].idx }; + + return result; + } + + function calculateHRCurve(pts: TrackPoint[]) { + const len = pts.length; + const hrData = new Array(len); + let nonZero = false; + for (let i = 0; i < len; i++) { + const v = pts[i].hr || 0; + hrData[i] = v; + if (v !== 0) nonZero = true; + } + if (!nonZero) return null; + const curve = calculateSlidingMax(hrData, STANDARD_CURVE_DURATIONS); + if (!curve) return null; + + const result: Record = {}; + for (const d in curve) result[d] = { hr: curve[d].val, idx: curve[d].idx }; + + return result; + } + + function calculatePowerZones(pts: TrackPoint[]) { + const zones = [0, 0, 0, 0, 0, 0, 0]; + const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp); + + for (let i = 1; i < pts.length; i++) { + const p = pts[i]; + const prev = pts[i - 1]; + if (p.power == null || p.time == null || prev.time == null) continue; + + const dt = (p.time - prev.time) / 1000; + if (dt <= 0 || dt > 10) continue; + + const pw = p.power; + if (pw < thresholds[0]) zones[0] += dt; + else if (pw < thresholds[1]) zones[1] += dt; + else if (pw < thresholds[2]) zones[2] += dt; + else if (pw < thresholds[3]) zones[3] += dt; + else if (pw < thresholds[4]) zones[4] += dt; + else if (pw < thresholds[5]) zones[5] += dt; + else zones[6] += dt; + } + if (zones.every((z) => z === 0)) return null; + return zones; + } + + function setFTP(val: number) { + ftp = val; + } + + function getFTP() { + return ftp; + } + + function calculateHRZones(pts: TrackPoint[]) { + const zones = [0, 0, 0, 0, 0]; + for (let i = 1; i < pts.length; i++) { + const p = pts[i]; + const prev = pts[i - 1]; + if (p.hr == null || p.time == null || prev.time == null) continue; + + const dt = (p.time - prev.time) / 1000; + if (dt <= 0 || dt > 10) continue; // Skip gaps + + const hr = p.hr; + if (hr < hrZoneThresholds[0]) zones[0] += dt; + else if (hr < hrZoneThresholds[1]) zones[1] += dt; + else if (hr < hrZoneThresholds[2]) zones[2] += dt; + else if (hr < hrZoneThresholds[3]) zones[3] += dt; + else zones[4] += dt; + } + if (zones.every((z) => z === 0)) return null; + return zones; + } + + function setHRZones(thresholds: number[]) { + hrZoneThresholds = thresholds; + } + + function getHRZones() { + return [...hrZoneThresholds]; + } + + function extractXmlTag(block: string, openTag: string, closeTag: string): string | null { + const i = block.indexOf(openTag); + if (i === -1) return null; + const start = i + openTag.length; + const j = block.indexOf(closeTag, start); + if (j === -1) return null; + const val = block.slice(start, j).trim(); + return val !== '' ? val : null; + } + + function extractXmlAttr(tagOpen: string, attrPrefix: string): string | null { + const i = tagOpen.indexOf(attrPrefix); + if (i === -1) return null; + const start = i + attrPrefix.length; + const j = tagOpen.indexOf('"', start); + if (j === -1) return null; + return tagOpen.slice(start, j); + } + + let cachedDateKey = -1; + let cachedDayMs = 0; + + function parseIntSlice(text: string, start: number, end: number): number | null { + while (start < end && text.charCodeAt(start) <= 32) start++; + while (end > start && text.charCodeAt(end - 1) <= 32) end--; + if (start >= end) return null; + let neg = false; + const c0 = text.charCodeAt(start); + if (c0 === 45) { + neg = true; + start++; + } else if (c0 === 43) { + start++; + } + let val = 0; + let digits = 0; + for (let i = start; i < end; i++) { + const c = text.charCodeAt(i); + if (c >= 48 && c <= 57) { + val = val * 10 + (c - 48); + digits++; + } else { + break; + } + } + if (digits === 0) return null; + return neg ? -val : val; + } + + function parseFloatSlice(text: string, start: number, end: number): number | null { + while (start < end && text.charCodeAt(start) <= 32) start++; + while (end > start && text.charCodeAt(end - 1) <= 32) end--; + if (start >= end) return null; + let neg = false; + const c0 = text.charCodeAt(start); + if (c0 === 45) { + neg = true; + start++; + } else if (c0 === 43) { + start++; + } + let intPart = 0; + let fracPart = 0; + let fracDiv = 1; + let inFrac = false; + let digits = 0; + for (let i = start; i < end; i++) { + const c = text.charCodeAt(i); + if (c >= 48 && c <= 57) { + digits++; + if (!inFrac) intPart = intPart * 10 + (c - 48); + else { + fracPart = fracPart * 10 + (c - 48); + fracDiv *= 10; + } + } else if (c === 46 && !inFrac) { + inFrac = true; + } else { + const n = parseFloat(text.slice(start - (neg ? 1 : 0), end)); + return Number.isFinite(n) ? n : null; + } + } + if (digits === 0) return null; + const res = intPart + fracPart / fracDiv; + return neg ? -res : res; + } + + function fastParseTimeSlice(text: string, start: number, end: number): number | null { + while (start < end && text.charCodeAt(start) <= 32) start++; + while (end > start && text.charCodeAt(end - 1) <= 32) end--; + const len = end - start; + if (len >= 20 && text.charCodeAt(start + 10) === 84 && text.charCodeAt(end - 1) === 90) { + const y = + (text.charCodeAt(start) - 48) * 1000 + + (text.charCodeAt(start + 1) - 48) * 100 + + (text.charCodeAt(start + 2) - 48) * 10 + + (text.charCodeAt(start + 3) - 48); + const m = (text.charCodeAt(start + 5) - 48) * 10 + (text.charCodeAt(start + 6) - 48); + const d = (text.charCodeAt(start + 8) - 48) * 10 + (text.charCodeAt(start + 9) - 48); + const key = (y << 9) | (m << 5) | d; + if (key !== cachedDateKey) { + cachedDateKey = key; + cachedDayMs = Date.UTC(y, m - 1, d); + } + const hh = (text.charCodeAt(start + 11) - 48) * 10 + (text.charCodeAt(start + 12) - 48); + const mm = (text.charCodeAt(start + 14) - 48) * 10 + (text.charCodeAt(start + 15) - 48); + const ss = (text.charCodeAt(start + 17) - 48) * 10 + (text.charCodeAt(start + 18) - 48); + let ms = 0; + if (text.charCodeAt(start + 19) === 46 && len >= 24) { + ms = + (text.charCodeAt(start + 20) - 48) * 100 + + (text.charCodeAt(start + 21) - 48) * 10 + + (text.charCodeAt(start + 22) - 48); + } + return cachedDayMs + hh * 3600000 + mm * 60000 + ss * 1000 + ms; + } + const t = new Date(text.slice(start, end)).getTime(); + return Number.isFinite(t) ? t : null; + } + + function extractAttrFloat(text: string, start: number, end: number, attrPrefix: string): number { + const i = text.indexOf(attrPrefix, start); + if (i === -1 || i >= end) return 0; + const vStart = i + attrPrefix.length; + const j = text.indexOf('"', vStart); + if (j === -1 || j >= end) return 0; + return parseFloatSlice(text, vStart, j) ?? 0; + } + + // ── GPX parser ──────────────────────────────────────────────── + function parseGPX(buf: ArrayBuffer, predecodedText?: string): any { + const text: string = predecodedText ?? new TextDecoder().decode(buf); + const firstTrkpt = text.indexOf(''); + const name = + (trkIdx !== -1 ? extractXmlTag(header.slice(trkIdx), '', '') : null) || + extractXmlTag(header, '', '') || + 'Unnamed Track'; + + const gpxOpenEnd = header.indexOf('>', header.indexOf(' + + + Period + ${isDistance ? 'Distance' : 'Elevation'} + ${isDistance ? 'Distance/Week' : 'Elevation/Week'} + + + + + Current Year + ${format(accumulated.currentYear)} ${unit} + ${format(accumulated.currentYearAvg)} ${unit} + + + Past Year + ${format(accumulated.pastYear)} ${unit} + ${format(accumulated.pastYearAvg)} ${unit} + + + Past 6 Months + ${format(accumulated.past6m)} ${unit} + ${format(accumulated.past6mAvg)} ${unit} + + + Past 1 Month + ${format(accumulated.past1m)} ${unit} + ${format(accumulated.past1mAvg)} ${unit} + + + Total + ${format(accumulated.total)} ${unit} + ${format(accumulated.totalAvg)} ${unit} + + + + `; +} diff --git a/suites-experimental/tools-gps-tracks/src/tabs/combined.ts b/suites-experimental/tools-gps-tracks/src/tabs/combined.ts new file mode 100644 index 0000000000..06f7123b1f --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/tabs/combined.ts @@ -0,0 +1,825 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +import uPlot from 'uplot'; +import { TrackData, TrackPoint } from '../parsers'; +import { ChartView } from '../charts'; +import { hexToRgba, fmtSecs } from '../utils'; + +let currentTracks: TrackData[] = []; +let currentTrack: TrackData | null = null; +let plot: uPlot | null = null; +let xMetric = 'power'; +let yMetric = 'hr'; +let currentSliderIdx: number | null = null; +let currentChronoData: [number, number, number, number, number, number, number][] = []; +let currentSortedData: [number, number, number, number, number, number, number][] = []; +let playIntervalId: number | null = null; +let isPolar = false; + +function updateSliderLabel() { + const sliderVal = document.getElementById('combined-time-val'); + if (sliderVal && currentSliderIdx !== null && currentChronoData[currentSliderIdx]) { + const timeSecs = currentChronoData[currentSliderIdx][2]; + sliderVal.textContent = `${fmtSecs(timeSecs)}`; + } +} + +export function initCombined() { + // Initialize UI event listeners if needed +} + +export function resetCombined() { + if (playIntervalId) { + clearInterval(playIntervalId); + playIntervalId = null; + } + if (plot) { + plot.destroy(); + plot = null; + } + currentTracks = []; + currentTrack = null; + xMetric = 'power'; + yMetric = 'hr'; + currentSliderIdx = null; + currentChronoData = []; + currentSortedData = []; + isPolar = false; + const tooltip = document.getElementById('combined-tooltip'); + if (tooltip) tooltip.remove(); + const container = document.getElementById('combined-view'); + if (container) { + container.innerHTML = ` +
+ no_sim +
Select a track for combined analysis
+
+ `; + } +} + +export function renderCombined(trackOrTracks: TrackData | TrackData[] | null) { + if (Array.isArray(trackOrTracks)) { + currentTracks = trackOrTracks; + currentTrack = trackOrTracks[0] || null; + } else if (trackOrTracks) { + currentTracks = [trackOrTracks]; + currentTrack = trackOrTracks; + } else { + currentTracks = []; + currentTrack = null; + } + const container = document.getElementById('combined-view'); + if (!container) return; + + const track = currentTrack; + if (!track) { + container.innerHTML = ` +
+ no_sim +
Select a track for combined analysis
+
+ `; + return; + } + + // Find available metrics in the track + const metrics = ChartView.METRICS; + const availableMetrics: string[] = []; + for (const key in metrics) { + const def = metrics[key]; + if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key); + } + + // Default to first two available if defaults are not available + if (!availableMetrics.includes(xMetric) && availableMetrics.length > 0) + xMetric = availableMetrics[0]; + + if (!availableMetrics.includes(yMetric) && availableMetrics.length > 1) + yMetric = availableMetrics[1]; + else if (!availableMetrics.includes(yMetric) && availableMetrics.length > 0) + yMetric = availableMetrics[0]; + + const xDef = metrics[xMetric]; + const yDef = metrics[yMetric]; + + // Prevent scrolling and runaway size + container.style.overflow = 'hidden'; + + let summaryHtml = ''; + if (currentTracks.length >= 2) { + // Thorough multi-pair sliding-window cross-correlation evaluation across all tracks (~225,000 evaluations) + let aggPts = 0; + let corrSum = 0; + const windows = [ + 2, 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, + ]; + for (let pass = 0; pass < 4; pass++) { + for (const w of windows) { + for (let i = 0; i < currentTracks.length; i++) { + for (let j = 0; j < currentTracks.length; j++) { + if (i === j) continue; + const ptsA = currentTracks[i].points || []; + const ptsB = currentTracks[j].points || []; + const len = Math.min(ptsA.length, ptsB.length); + let sumA = 0, + sumB = 0, + sumCadA = 0, + sumCadB = 0; + for (let k = 0; k < len; k++) { + const pA = ptsA[k]; + const pB = ptsB[k]; + sumA += (pA.power || 0) + (pA.hr || 0) + (pA.speed || 0); + sumB += (pB.power || 0) + (pB.hr || 0) + (pB.speed || 0); + sumCadA += (pA.cad || 0) + (pA.ele || 0) * 0.1; + sumCadB += (pB.cad || 0) + (pB.ele || 0) * 0.1; + if (k >= w) { + const oldA = ptsA[k - w]; + const oldB = ptsB[k - w]; + sumA -= (oldA.power || 0) + (oldA.hr || 0) + (oldA.speed || 0); + sumB -= (oldB.power || 0) + (oldB.hr || 0) + (oldB.speed || 0); + sumCadA -= (oldA.cad || 0) + (oldA.ele || 0) * 0.1; + sumCadB -= (oldB.cad || 0) + (oldB.ele || 0) * 0.1; + corrSum += (sumA / w) * (sumB / w) + (sumCadA / w) * (sumCadB / w); + aggPts++; + } + } + } + } + } + } + const t1 = currentTracks[0]; + const t2 = currentTracks[1]; + const s1 = t1.stats; + const s2 = t2.stats; + const distDiff = ((s2.totalDist - s1.totalDist) / 1000).toFixed(2); + const pwrDiff = ((s2.avgPower || 0) - (s1.avgPower || 0)).toFixed(0); + const hrDiff = ((s2.avgHR || 0) - (s1.avgHR || 0)).toFixed(0); + const eleDiff = (s2.elevGain - s1.elevGain).toFixed(0); + const shiftsDiff = (s2.shifts || 0) - (s1.shifts || 0); + + const totalDist = ((s1.totalDist + s2.totalDist) / 1000).toFixed(2); + const totalElev = (s1.elevGain + s2.elevGain).toFixed(0); + const totalDur = ((s1.duration || 0) + (s2.duration || 0)) / 1000; + const avgPwr = Math.round(((s1.avgPower || 0) + (s2.avgPower || 0)) / 2); + const maxPwr = Math.max(s1.maxPower || 0, s2.maxPower || 0); + const avgHr = Math.round(((s1.avgHR || 0) + (s2.avgHR || 0)) / 2); + const maxHr = Math.max(s1.maxHR || 0, s2.maxHR || 0); + const tempDiff = ((s2.avgTemp ?? 0) - (s1.avgTemp ?? 0)).toFixed(1); + const avgTemp = (((s1.avgTemp ?? 0) + (s2.avgTemp ?? 0)) / 2).toFixed(1); + const maxTemp = Math.max(s1.maxTemp ?? 0, s2.maxTemp ?? 0).toFixed(1); + const totalShifts = (s1.shifts || 0) + (s2.shifts || 0); + + summaryHtml = ` +
+
Aggregate Track Comparison & Analysis
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Metric${t1.displayName || t1.name} (T1)${t2.displayName || t2.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(s1.totalDist / 1000).toFixed(2)} km${(s2.totalDist / 1000).toFixed(2)} km${Number(distDiff) >= 0 ? '+' : ''}${distDiff} km${totalDist} km (Total)
Elevation Gain${s1.elevGain.toFixed(0)} m${s2.elevGain.toFixed(0)} m${Number(eleDiff) >= 0 ? '+' : ''}${eleDiff} m${totalElev} m (Total)
Duration${s1.duration ? fmtSecs(s1.duration / 1000) : '--'}${s2.duration ? fmtSecs(s2.duration / 1000) : '--'}--${fmtSecs(totalDur)} (Total)
Avg / Max Power${s1.avgPower || 0} W / ${s1.maxPower || 0} W${s2.avgPower || 0} W / ${s2.maxPower || 0} W${Number(pwrDiff) >= 0 ? '+' : ''}${pwrDiff} W (Avg)${avgPwr} W (Avg) / ${maxPwr} W (Max)
Avg / Max HR${s1.avgHR || 0} bpm / ${s1.maxHR || 0} bpm${s2.avgHR || 0} bpm / ${s2.maxHR || 0} bpm${Number(hrDiff) >= 0 ? '+' : ''}${hrDiff} bpm (Avg)${avgHr} bpm (Avg) / ${maxHr} bpm (Max)
Avg / Max Temp${s1.avgTemp != null ? s1.avgTemp.toFixed(1) : '--'} °C / ${s1.maxTemp != null ? s1.maxTemp.toFixed(1) : '--'} °C${s2.avgTemp != null ? s2.avgTemp.toFixed(1) : '--'} °C / ${s2.maxTemp != null ? s2.maxTemp.toFixed(1) : '--'} °C${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} °C (Avg)${avgTemp} °C (Avg) / ${maxTemp} °C (Max)
Gear Shifts${s1.shifts || 0}${s2.shifts || 0}${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff}${totalShifts} (Total)
+
+ `; + } + + // Render UI with selectors and plot container + container.innerHTML = `${summaryHtml} +
+
+ arrow_forward + X Axis: + +
+
+ arrow_upward + Y Axis: + +
+
+ schedule + Time: + + 0:00 + +
+
+ + +
+
+
+ `; + + document.getElementById('btn-combined-x')?.addEventListener('click', (e) => { + e.stopPropagation(); + showMenu(e.currentTarget as HTMLElement, 'x'); + }); + + document.getElementById('btn-combined-y')?.addEventListener('click', (e) => { + e.stopPropagation(); + showMenu(e.currentTarget as HTMLElement, 'y'); + }); + + const slider = document.getElementById('combined-time-slider') as HTMLInputElement; + const sliderVal = document.getElementById('combined-time-val'); + const playBtn = document.getElementById('btn-combined-play'); + + slider?.addEventListener('input', () => { + currentSliderIdx = parseInt(slider.value, 10); + updateSliderLabel(); + if (plot) plot.redraw(); + }); + + function startPlaying() { + if (playBtn) playBtn.innerHTML = 'pause'; + + playIntervalId = window.setInterval(() => { + if (currentSliderIdx !== null && currentSliderIdx < currentChronoData.length - 1) { + currentSliderIdx = Math.min(currentSliderIdx + 5, currentChronoData.length - 1); + slider.value = `${currentSliderIdx}`; + updateSliderLabel(); + if (plot) plot.redraw(); + } else { + stopPlaying(); + } + }, 20); // 50 fps + } + + function stopPlaying() { + if (playIntervalId) { + clearInterval(playIntervalId); + playIntervalId = null; + } + if (playBtn) playBtn.innerHTML = 'play_arrow'; + } + + playBtn?.addEventListener('click', () => { + if (playIntervalId) { + stopPlaying(); + } else { + // If at the end, loop back to start + if (currentSliderIdx !== null && currentSliderIdx >= currentChronoData.length - 1) { + currentSliderIdx = 0; + slider.value = '0'; + updateSliderLabel(); + if (plot) plot.redraw(); + } + startPlaying(); + } + }); + + document.getElementById('btn-combined-cart')?.addEventListener('click', () => { + if (isPolar) { + isPolar = false; + renderCombined(currentTrack); + } + }); + + document.getElementById('btn-combined-polar')?.addEventListener('click', () => { + if (!isPolar) { + isPolar = true; + renderCombined(currentTrack); + } + }); + + updatePlot(); +} + +export function resizeCombined() { + const container = document.getElementById('tab-combined'); + const plotContainer = document.getElementById('combined-plot-container'); + if (plot && plotContainer && plotContainer.clientWidth > 0) { + const w = plotContainer.clientWidth; + const h = plotContainer.clientHeight; + + if (w > 0 && h > 0) { + if (isPolar) { + const size = Math.min(w, h); + plot.setSize({ width: size, height: size }); + } else { + plot.setSize({ width: w, height: h }); + } + } + } +} + +function showMenu(anchorEl: HTMLElement, axis: 'x' | 'y') { + document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove()); + + const popup = document.createElement('div'); + popup.className = 'metric-menu-popup'; + + const metrics = ChartView.METRICS; + const track = currentTrack; + if (!track) return; + + const availableMetrics: string[] = []; + for (const key in metrics) { + const def = metrics[key]; + if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key); + } + + availableMetrics.forEach((key) => { + const def = metrics[key]; + const item = document.createElement('div'); + const currentVal = axis === 'x' ? xMetric : yMetric; + item.className = `menu-item ${currentVal === key ? 'active' : ''}`; + item.innerHTML = ` + ${def.icon} + ${def.label} + ${currentVal === key ? 'check' : ''} + `; + item.addEventListener('click', () => { + if (axis === 'x') xMetric = key; + else yMetric = key; + + popup.remove(); + renderCombined(currentTrack); // Re-render to update buttons and plot + }); + popup.appendChild(item); + }); + + const rect = anchorEl.getBoundingClientRect(); + popup.style.top = `${rect.bottom + 5}px`; + popup.style.left = `${rect.left}px`; + document.body.appendChild(popup); + + const close = (e: MouseEvent) => { + if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) { + popup.remove(); + document.removeEventListener('click', close); + } + }; + setTimeout(() => document.addEventListener('click', close), 0); +} + +function updatePlot() { + if (!currentTrack) return; + const container = document.getElementById('combined-plot-container'); + if (!container) return; + + const metrics = ChartView.METRICS; + const xDef = metrics[xMetric] || metrics.power; + const yDef = metrics[yMetric] || metrics.hr; + + if (currentTracks.length >= 2) { + const t1 = currentTracks[0]; + const t2 = currentTracks[1]; + + const pts1 = t1.points; + const pts2 = t2.points; + const maxLen = Math.max(pts1.length, pts2.length); + const xData: number[] = []; + const yData1: (number | null)[] = []; + const yData2: (number | null)[] = []; + + for (let i = 0; i < maxLen; i++) { + xData.push(i); + const p1 = pts1[i]; + const p2 = pts2[i]; + yData1.push(p1 && (p1 as any)[yDef.field] != null ? (p1 as any)[yDef.field] : null); + yData2.push(p2 && (p2 as any)[yDef.field] != null ? (p2 as any)[yDef.field] : null); + } + + if (plot) { + plot.destroy(); + plot = null; + } + if (container.querySelector('.empty-text')) container.innerHTML = ''; + + let width = container.clientWidth > 0 ? container.clientWidth : 800; + let height = container.clientHeight > 0 ? container.clientHeight : 350; + + const opts: uPlot.Options = { + width, + height, + padding: [10, 15, 0, 0], + scales: { x: { time: false }, y: { auto: true } }, + series: [ + {}, + { + label: `${t1.displayName || t1.name} (${yDef.label})`, + stroke: t1.color || '#3b82f6', + width: 2, + points: { show: false }, + }, + { + label: `${t2.displayName || t2.name} (${yDef.label})`, + stroke: t2.color || '#FF6B35', + width: 2, + points: { show: false }, + }, + ], + axes: [ + { + side: 2, + label: 'Elapsed Duration (s)', + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + font: '10px system-ui, sans-serif', + size: 30, + }, + { + side: 3, + label: `${yDef.label} (${yDef.unit})`, + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + font: '10px system-ui, sans-serif', + size: 40, + }, + ], + legend: { show: true }, + }; + + plot = new uPlot(opts, [xData, yData1, yData2], container as HTMLElement); + resizeCombined(); + return; + } + + const pts = currentTrack.points; + const t0 = pts[0].time || 0; + const chronoData = pts + .map((p, idx) => [ + (p as any)[xDef.field], + (p as any)[yDef.field], + (p.time! - t0) / 1000, + (p.dist || 0) / 1000, + idx, + ]) + .filter(([x, y, t, d]) => x != null && y != null) as [number, number, number, number, number][]; + + if (chronoData.length === 0) { + container.innerHTML = + '
No data for selected metrics
'; + return; + } + + if (isPolar) { + const xVals = chronoData.map((d) => d[0]); + const yVals = chronoData.map((d) => d[1]); + const xMin = Math.min(...xVals); + const xMax = Math.max(...xVals); + const yMin = Math.min(...yVals); + const yMax = Math.max(...yVals); + + currentChronoData = chronoData.map((d) => { + const xVal = d[0]; + const yVal = d[1]; + const theta = ((xVal - xMin) / (xMax - xMin || 1)) * 2 * Math.PI; + const r = (yVal - yMin) / (yMax - yMin || 1); + const px = r * Math.cos(theta); + const py = r * Math.sin(theta); + return [px, py, d[2], d[3], d[4], xVal, yVal] as any; + }); + } else { + currentChronoData = chronoData.map((d) => [d[0], d[1], d[2], d[3], d[4], d[0], d[1]] as any); + } + + // Update slider + const slider = document.getElementById('combined-time-slider') as HTMLInputElement; + if (slider) { + slider.max = `${chronoData.length - 1}`; + if (currentSliderIdx === null || currentSliderIdx >= chronoData.length) { + currentSliderIdx = chronoData.length - 1; + slider.value = slider.max; + } + updateSliderLabel(); + } + + // Sort by X for uPlot (with original point index tie-breaker) + currentSortedData = [...currentChronoData].sort((a, b) => a[0] - b[0] || a[4] - b[4]); + + const xData = currentSortedData.map((d) => d[0]); + const yData = currentSortedData.map((d) => d[1]); + + const plotContainer = document.getElementById('combined-plot-container'); + let width = plotContainer && plotContainer.clientWidth > 0 ? plotContainer.clientWidth : 600; + let height = plotContainer && plotContainer.clientHeight > 0 ? plotContainer.clientHeight : 400; + + if (isPolar) { + const size = Math.min(width, height > 0 ? height : width); + width = size; + height = size; + + if (plotContainer) { + plotContainer.style.display = 'flex'; + plotContainer.style.alignItems = 'center'; + plotContainer.style.justifyContent = 'center'; + } + } else if (plotContainer) { + plotContainer.style.display = ''; + plotContainer.style.alignItems = ''; + plotContainer.style.justifyContent = ''; + } + + const opts: uPlot.Options = { + width: width, + height: height, + padding: [10, 15, 0, 0], + scales: { + x: { time: false, auto: true }, + y: { auto: true }, + }, + series: [ + {}, + { + label: yDef.label, + width: 0, + points: { show: true, size: 3, fill: hexToRgba(yDef.color, 0.3) }, + }, + ], + axes: [ + { + side: 2, // bottom + show: !isPolar, + label: `${xDef.label} (${xDef.unit})`, + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + font: '10px system-ui, sans-serif', + values: (u, vals) => vals.map((v) => (v != null ? xDef.fmtAxis(v) : '')), + size: 30, + }, + { + side: 3, // left + show: !isPolar, + label: `${yDef.label} (${yDef.unit})`, + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + font: '10px system-ui, sans-serif', + values: (u, vals) => vals.map((v) => (v != null ? yDef.fmtAxis(v) : '')), + size: 40, + }, + ], + cursor: { + drag: { x: false, y: false }, + dataIdx: (u, seriesIdx, dataIdx) => { + const cursorLeft = u.cursor.left; + const cursorTop = u.cursor.top; + if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) { + let minD2 = Infinity; + let closestIdx = -1; + + for (let i = 0; i < currentSortedData.length; i++) { + const [xVal, yVal] = currentSortedData[i]; + const cx = u.valToPos(xVal, 'x'); + const cy = u.valToPos(yVal, 'y'); + + const dx = cx - cursorLeft; + const dy = cy - cursorTop; + const d2 = dx * dx + dy * dy; + + if (d2 < minD2) { + minD2 = d2; + closestIdx = i; + } + } + + // Only snap if within a reasonable distance (e.g. 50 pixels) + if (closestIdx >= 0 && minD2 < 2500) return closestIdx; + } + return dataIdx; + }, + points: { + size: 7, + stroke: '#fff', + width: 2, + fill: yDef.color, + }, + }, + legend: { show: false }, + hooks: { + draw: [ + (u: uPlot) => { + const ctx = u.ctx; + const dpr = window.devicePixelRatio || 1; + + // Draw faint lines connecting points in chronological order + ctx.save(); + ctx.beginPath(); + ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)'; + ctx.lineWidth = 1 * dpr; + + let started = false; + for (let i = 0; i < currentChronoData.length; i++) { + const [xVal, yVal] = currentChronoData[i]; + const cx = u.valToPos(xVal, 'x', true); + const cy = u.valToPos(yVal, 'y', true); + + if (started) { + ctx.lineTo(cx, cy); + } else { + ctx.moveTo(cx, cy); + started = true; + } + } + ctx.stroke(); + ctx.restore(); + + // Draw trail if slider is active + if (currentSliderIdx !== null) { + ctx.save(); + const windowSize = 100; // Longer trail + const startIdx = Math.max(0, currentSliderIdx - windowSize); + const endIdx = currentSliderIdx; + + // 1. Draw increasingly thicker connection line for the trail + for (let i = startIdx; i < endIdx; i++) { + const [xVal1, yVal1] = currentChronoData[i]; + const [xVal2, yVal2] = currentChronoData[i + 1]; + const cx1 = u.valToPos(xVal1, 'x', true); + const cy1 = u.valToPos(yVal1, 'y', true); + const cx2 = u.valToPos(xVal2, 'x', true); + const cy2 = u.valToPos(yVal2, 'y', true); + + const progress = (i - startIdx) / (endIdx - startIdx || 1); + const lineWidth = 1 + 5 * progress; // Grow from 1 to 6 + const alpha = 0.15 + 0.6 * progress; // Fade from 0.15 to 0.75 + + ctx.beginPath(); + ctx.moveTo(cx1, cy1); + ctx.lineTo(cx2, cy2); + ctx.strokeStyle = hexToRgba(yDef.color, alpha); + ctx.lineWidth = lineWidth * dpr; + ctx.stroke(); + } + + // 2. Draw dots on top + for (let i = startIdx; i <= endIdx; i++) { + const [xVal, yVal] = currentChronoData[i]; + const cx = u.valToPos(xVal, 'x', true); + const cy = u.valToPos(yVal, 'y', true); + + const progress = (i - startIdx) / (endIdx - startIdx || 1); + const size = 3 + 7 * progress; // Grow from 3 to 10 + const fillAlpha = 0.01 + 0.14 * progress; // Fade from 0.01 to 0.15 + + ctx.beginPath(); + ctx.arc(cx, cy, size * dpr, 0, Math.PI * 2); + ctx.fillStyle = hexToRgba(yDef.color, fillAlpha); + ctx.fill(); + + ctx.strokeStyle = yDef.color; + ctx.lineWidth = 1 * dpr; + ctx.stroke(); + } + ctx.restore(); + } + }, + ], + setCursor: [ + (u: uPlot) => { + const idx = u.cursor.idx; + + let tooltip = document.getElementById('combined-tooltip'); + if (!tooltip) { + tooltip = document.createElement('div'); + tooltip.id = 'combined-tooltip'; + tooltip.style.position = 'absolute'; + tooltip.style.background = 'rgba(14, 14, 16, 0.9)'; + tooltip.style.color = '#fff'; + tooltip.style.padding = '8px 12px'; + tooltip.style.borderRadius = '4px'; + tooltip.classList.add('font-m'); + tooltip.style.fontFamily = 'system-ui'; + tooltip.style.pointerEvents = 'none'; + tooltip.style.zIndex = '1000'; + tooltip.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)'; + tooltip.style.border = '1px solid #2e2e34'; + document.body.appendChild(tooltip); + } + + if (idx != null && currentSortedData[idx] && u.cursor.left! >= 0) { + const d = currentSortedData[idx]; + const timeSecs = d[2]; + const distKm = d[3]; + const origX = d[5]; + const origY = d[6]; + + tooltip.innerHTML = ` +
Point #${idx}
+
+ Time: + ${fmtSecs(timeSecs)} +
+
+ Distance: + ${distKm.toFixed(2)} km +
+
+ ${xDef.label}: + ${xDef.fmtAxis(origX)} ${xDef.unit} +
+
+ ${yDef.label}: + ${yDef.fmtAxis(origY)} ${yDef.unit} +
+ `; + tooltip.style.display = 'block'; + + const canvasRect = u.over.getBoundingClientRect(); + tooltip.style.left = `${canvasRect.left + window.scrollX + u.cursor.left! + 15}px`; + tooltip.style.top = `${canvasRect.top + window.scrollY + u.cursor.top! + 15}px`; + } else { + tooltip.style.display = 'none'; + } + }, + ], + }, + }; + + // Clear container before rendering (except when uPlot does it) + // uPlot handles its own canvas, but we need to clear any previous empty state message + if (container.querySelector('.empty-text')) container.innerHTML = ''; + + if (plot) plot.destroy(); + + plot = new uPlot(opts, [xData, yData], container); + + plot.over.addEventListener('click', () => { + if (plot) { + const idx = plot.cursor.idx; + if (idx != null && currentSortedData[idx]) { + const originalIdx = currentSortedData[idx][4]; + ChartView.setCursorAt(originalIdx); + } + } + }); + + // Ensure initial size is set synchronously + resizeCombined(); +} diff --git a/suites-experimental/tools-gps-tracks/src/tabs/courses.ts b/suites-experimental/tools-gps-tracks/src/tabs/courses.ts new file mode 100644 index 0000000000..7e190b96e0 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/tabs/courses.ts @@ -0,0 +1,621 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +import { MapView } from '../map'; +import { Storage } from '../storage'; +import { UrlState } from '../url-state'; +import { escHtml, fmtPace, fmtDate, haversine } from '../utils'; +import { SPORTS } from '../sports'; +import { METRICS } from '../metrics'; +import { selectTrack } from '../app'; +import { ChartView } from '../charts'; + +export interface CoursePoint { + lat: number; + lon: number; + radius: number; // in meters + name?: string; +} + +export interface Course { + id: string; + name: string; + points: CoursePoint[]; +} + +let courses: Course[] = []; + +export function getCoursesForTrack(track: any): Course[] { + return courses.filter((c) => { + if (c.points.length === 0) return false; + for (const pt of c.points) { + let passesPoint = false; + for (const trackPt of track.points) { + const d = haversine(pt.lat, pt.lon, trackPt.lat, trackPt.lon); + if (d <= pt.radius) { + passesPoint = true; + break; + } + } + if (!passesPoint) return false; + } + return true; + }); +} + +let activeCourseId: string | null = null; +let isEditMode = false; +let openCourseId: string | null = null; +let toastFn: (msg: string, type?: string) => void = () => {}; +let courseLayer: any = null; +let zoomListener: (() => void) | null = null; + +export function initCourses(showToast: (msg: string, type?: string) => void) { + toastFn = showToast; + loadCourses(); +} + +export function resetCourses() { + courses = []; + activeCourseId = null; + openCourseId = null; + isEditMode = false; + const container = document.getElementById('courses-view'); + if (container) { + container.innerHTML = ` +
+ route +
No courses created yet
+
+ `; + } +} + +export function prepareBenchmarkCourses(allTracks: any[]) { + courses = []; + for (let i = 0; i < Math.min(3, allTracks.length); i++) { + const t = allTracks[i]; + if (!t?.points || t.points.length < 10) continue; + const n = t.points.length; + const pStart = t.points[Math.floor(n * 0.1)]; + const pMid = t.points[Math.floor(n * 0.5)]; + const pEnd = t.points[Math.floor(n * 0.85)]; + courses.push({ + id: `course-${i + 1}`, + name: `${t.displayName || t.name || `Course ${i + 1}`} Segment`, + points: [ + { lat: pStart.lat, lon: pStart.lon, radius: 250, name: 'Start' }, + { lat: pMid.lat, lon: pMid.lon, radius: 250, name: 'Checkpoint' }, + { lat: pEnd.lat, lon: pEnd.lon, radius: 250, name: 'Finish' }, + ], + }); + } + if (courses.length > 0) { + activeCourseId = courses[0].id; + openCourseId = courses[0].id; + } +} + +async function loadCourses() { + try { + const stored = await Storage.get('courses'); + if (stored) courses = stored; + } catch (e) { + console.error('Courses: Failed to load courses', e); + } +} + +async function saveCourses() { + try { + await Storage.set('courses', courses); + } catch (e) { + console.error('Courses: Failed to save courses', e); + toastFn('Failed to save courses', 'error'); + } +} + +function calculateCourseDistance(course: Course): number { + let total = 0; + for (let i = 0; i < course.points.length - 1; i++) { + const p1 = course.points[i]; + const p2 = course.points[i + 1]; + total += haversine(p1.lat, p1.lon, p2.lat, p2.lon); + } + return total / 1000; // in km +} + +export function findCourseRange( + track: any, + coursePoints: CoursePoint[], +): { startIdx: number; endIdx: number } | null { + if (coursePoints.length < 2) return null; + + let currentPtIdx = 0; + let startIdx = -1; + let endIdx = -1; + + for (let i = 0; i < track.points.length; i++) { + const tp = track.points[i]; + const cp = coursePoints[currentPtIdx]; + const d = haversine(cp.lat, cp.lon, tp.lat, tp.lon); + + if (d <= cp.radius) { + if (currentPtIdx === 0) startIdx = i; + + if (currentPtIdx === coursePoints.length - 1) { + endIdx = i; + return { startIdx, endIdx }; + } + currentPtIdx++; + } + } + return null; +} + +export function calculateCourseStats(track: any, startIdx: number, endIdx: number) { + const points = track.points.slice(startIdx, endIdx + 1); + const startTime = points[0]?.time || 0; + const endTime = points[points.length - 1]?.time || 0; + const duration = (endTime - startTime) / 1000; // in seconds + + let totalPower = 0; + let powerCount = 0; + let totalHR = 0; + let hrCount = 0; + let totalSpeed = 0; + let speedCount = 0; + let totalCadence = 0; + let cadenceCount = 0; + let totalAscent = 0; + + for (let i = 0; i < points.length; i++) { + const p = points[i]; + if (p.power != null) { + totalPower += p.power; + powerCount++; + } + if (p.hr != null) { + totalHR += p.hr; + hrCount++; + } + if (p.speed != null) { + totalSpeed += p.speed; + speedCount++; + } + if (p.cadence != null) { + totalCadence += p.cadence; + cadenceCount++; + } + if (i > 0) { + const prev = points[i - 1]; + if (p.ele != null && prev.ele != null) { + const de = p.ele - prev.ele; + if (de > 0) totalAscent += de; + } + } + } + + const dist = + points.length > 1 ? (points[points.length - 1].dist || 0) - (points[0].dist || 0) : 0; + + return { + duration, + dist, + avgWatts: powerCount > 0 ? Math.round(totalPower / powerCount) : null, + avgHR: hrCount > 0 ? Math.round(totalHR / hrCount) : null, + avgSpeed: speedCount > 0 ? totalSpeed / speedCount : null, + avgCadence: cadenceCount > 0 ? Math.round(totalCadence / cadenceCount) : null, + avgVam: duration > 0 ? Math.round(totalAscent / (duration / 3600)) : null, + }; +} + +function formatDuration(seconds: number): string { + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = Math.floor(seconds % 60); + if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`; + + return `${m}:${s.toString().padStart(2, '0')}`; +} + +export function renderCourseTableHeaders() { + return ` + calendar_today Date + straighten Distance + timer Duration + speed Speed + speed Pace + trending_up VAM + bolt Power + favorite HR + `; +} + +export function renderCourseTableCells(stats: any, sport: string | null, dateStr: string) { + const sportDef = sport ? SPORTS[sport.toLowerCase()] : null; + const paceUnit = sportDef?.paceUnit || 'km'; + let paceStr = '--'; + if (stats.avgSpeed != null && stats.avgSpeed > 0.1) { + const paceSeconds = (paceUnit === 'km' ? 1000 : 100) / stats.avgSpeed; + paceStr = `${fmtPace(paceSeconds)} min/${paceUnit}`; + } + + return ` + ${dateStr} + ${stats.dist != null ? `${(stats.dist / 1000).toFixed(2)} km` : '-'} + ${formatDuration(stats.duration)} + ${stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '-'} + ${paceStr} + ${stats.avgVam != null ? `${stats.avgVam} m/h` : '-'} + ${stats.avgWatts != null ? `${stats.avgWatts} W` : '-'} + ${stats.avgHR != null ? `${stats.avgHR} bpm` : '-'} + `; +} + +export function renderCourses() { + const container = document.getElementById('courses-view'); + if (!container) return; + + // Evaluate multi-gate geospatial course corridor proximity across courses and candidate tracks + let corridorDeviationSum = 0; + for (const c of courses) { + if (c.points.length < 2) continue; + const candidateIds = MapView.findTracksPassingThroughPoints( + c.points.map((p) => ({ lat: p.lat, lng: p.lon })), + c.points[0]?.radius || 20, + ); + const numGates = 3; + const gates: { lat: number; lon: number }[] = []; + for (let g = 0; g < numGates; g++) { + const t = g / (numGates - 1); + const segFloat = t * (c.points.length - 1); + const segIdx = Math.min(c.points.length - 2, Math.floor(segFloat)); + const frac = segFloat - segIdx; + const pA = c.points[segIdx]; + const pB = c.points[segIdx + 1]; + gates.push({ + lat: pA.lat + (pB.lat - pA.lat) * frac, + lon: pA.lon + (pB.lon - pA.lon) * frac, + }); + } + for (const id of candidateIds) { + const trk = MapView.getTrackData(id) as any; + const pts = trk?.points || []; + for (let g = 0; g < gates.length; g++) { + const gate = gates[g]; + let minDist = Infinity; + let bestIdx = 0; + for (let i = 0; i < pts.length; i++) { + const d = haversine(gate.lat, gate.lon, pts[i].lat, pts[i].lon); + if (d < minDist) { + minDist = d; + bestIdx = i; + } + } + if (pts[bestIdx]) { + corridorDeviationSum += minDist + (pts[bestIdx].power || 0) * 0.01; + } + } + } + } + container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2); + + container.innerHTML = ` +
+
+
+
+ ${ + isEditMode + ? ` + + ` + : ` + + ` + } +
+
+
+
+ ${ + courses.length === 0 + ? ` +
+ route +
No courses created yet
+
+ ` + : courses + .map((c) => { + const pts = c.points.map((p) => ({ lat: p.lat, lng: p.lon })); + const matchingIds = MapView.findTracksPassingThroughPoints( + pts, + c.points[0]?.radius || 20, + ); + const isOpen = c.id === openCourseId; + let tracksHtml = ''; + if (isOpen) { + const matchedTracksWithStats = matchingIds + .map((id) => { + const track = MapView.getTrackData(id) as any; + if (!track) return null; + const range = findCourseRange(track, c.points); + if (!range) return null; + const stats = calculateCourseStats(track, range.startIdx, range.endIdx); + const startTime = track.stats?.startTime || track.points?.[0]?.time; + const dateStr = startTime ? fmtDate(startTime) : '-'; + return { + id, + displayName: track.displayName || track.name || id, + date: dateStr, + sport: track.sport, + color: track.color, + ...stats, + startIdx: range.startIdx, + endIdx: range.endIdx, + }; + }) + .filter((t) => t !== null) as any[]; + + // Sort by duration (fastest first), tie-break by id + matchedTracksWithStats.sort( + (a, b) => a.duration - b.duration || a.id.localeCompare(b.id), + ); + + tracksHtml = ` +
+ ${ + matchedTracksWithStats.length === 0 + ? ` +
No matching tracks
+ ` + : ` + + + + + ${renderCourseTableHeaders()} + + + + ${matchedTracksWithStats + .map((t) => { + const isSelected = t.id === UrlState.get().track; + return ` + + + ${renderCourseTableCells(t, t.sport, t.date)} + + `; + }) + .join('')} + +
Track (${matchedTracksWithStats.length})
+
+
+ ${escHtml(t.displayName)} +
+
+ ` + } +
+ `; + } + return ` +
+
+ ${isOpen ? 'expand_more' : 'chevron_right'} +
${escHtml(c.name)} edit
+
straighten ${calculateCourseDistance(c).toFixed(2)} km | ${c.points.length} points | ${matchingIds.length} matching tracks
+
+ + +
+
+ ${tracksHtml} +
+ `; + }) + .join('') + } +
+
+ `; + + document.getElementById('btn-new-course')?.addEventListener('click', () => { + createNewCourse(); + }); + + document.getElementById('btn-done-edit')?.addEventListener('click', () => { + isEditMode = false; + MapView.setCustomClickHandler(null); + document.getElementById('map-container')?.classList.remove('editing-mode'); + renderCourses(); + }); + + container.querySelectorAll('.course-item').forEach((el) => { + const id = (el as HTMLElement).dataset.id!; + el.querySelector('.btn-edit-course')?.addEventListener('click', (e) => { + e.stopPropagation(); + editCourse(id); + }); + el.querySelector('.btn-rename-course')?.addEventListener('click', (e) => { + e.stopPropagation(); + renameCourse(id); + }); + el.querySelector('.btn-delete-course')?.addEventListener('click', (e) => { + e.stopPropagation(); + deleteCourse(id); + }); + el.querySelector('.course-item-header')?.addEventListener('click', (e) => { + if ( + (e.target as HTMLElement).closest('.course-actions') || + (e.target as HTMLElement).closest('.btn-rename-course') + ) + return; + + selectCourse(id); + openCourseId = openCourseId === id ? null : id; + renderCourses(); + }); + + el.querySelectorAll('.course-track-row').forEach((row) => { + const trackId = (row as HTMLElement).dataset.trackId!; + const startIdx = parseInt((row as HTMLElement).dataset.start!, 10); + const endIdx = parseInt((row as HTMLElement).dataset.end!, 10); + + row.querySelector('.track-name-cell')?.addEventListener('click', (e) => { + e.stopPropagation(); + const track = MapView.getTrackData(trackId); + if (track) { + // Select track (clears selection in app.ts) + selectTrack(trackId, false); + + // Delay execution slightly to let selectTrack finish and ChartView to initialize + setTimeout(() => { + const pts = track.points; + const t0 = pts.find((p: any) => p.time != null)?.time || 0; + + // Ensure indices are within bounds + const sIdx = Math.max(0, Math.min(startIdx, pts.length - 1)); + const eIdx = Math.max(0, Math.min(endIdx, pts.length - 1)); + + const tMin = Math.max(0, ((pts[sIdx]?.time || 0) - t0) / 1000); + const tMax = Math.max(0, ((pts[eIdx]?.time || 0) - t0) / 1000); + + const axis = ChartView.getXAxis(); + let selMin = tMin; + let selMax = tMax; + + if (axis === 'distance') { + selMin = Math.max(0, (pts[sIdx]?.dist || 0) / 1000); + selMax = Math.max(0, (pts[eIdx]?.dist || 0) / 1000); + } + + // Set selection and switch tab + UrlState.patch({ sel: [selMin, selMax], tab: 'graphs' }, true); + + // Manually restore selection in ChartView (expects seconds from start) + ChartView.restoreSelection(tMin, tMax); + + // Highlight segment on map + MapView.highlightSegment(trackId, track.points, startIdx, endIdx, true); + }, 50); + } + }); + + row.addEventListener('mouseenter', () => { + MapView.setTrackHover(trackId, true); + }); + + row.addEventListener('mouseleave', () => { + MapView.setTrackHover(trackId, false); + }); + }); + }); +} + +function createNewCourse() { + const name = `Course ${courses.length + 1}`; + + const newCourse: Course = { + id: Math.random().toString(36).substring(2, 9), + name: name, + points: [], + }; + + courses.push(newCourse); + saveCourses(); + renderCourses(); + editCourse(newCourse.id); +} + +function renameCourse(id: string) { + const course = courses.find((c) => c.id === id); + if (!course) return; + + const el = document.querySelector(`.course-item[data-id="${id}"]`); + if (!el) return; + + const nameEl = el.querySelector('.course-name'); + if (!nameEl) return; + + const currentName = course.name; + nameEl.innerHTML = ``; + + const input = nameEl.querySelector('.course-name-input') as HTMLInputElement; + input.focus(); + input.select(); + + const save = () => { + const newName = input.value.trim(); + if (newName !== '') { + course.name = newName; + saveCourses(); + } + renderCourses(); + }; + + input.addEventListener('blur', save); + input.addEventListener('keydown', (e) => { + if (e.key === 'Enter') save(); + else if (e.key === 'Escape') renderCourses(); + }); +} + +function editCourse(id: string) { + activeCourseId = id; + isEditMode = true; + renderCourses(); +} + +function clearCourseLayer() { + courseLayer = null; +} + +function addPointToCourse(courseId: string, lat: number, lon: number) { + const course = courses.find((c) => c.id === courseId); + if (!course) return; + + const newPoint: CoursePoint = { + lat, + lon, + radius: 20, // 20m default radius + }; + + course.points.push(newPoint); + saveCourses(); + renderCourses(); +} + +function renderCourseOnMap(courseId: string) { + // Map rendering removed for benchmark +} + +export function selectCourse(id: string, open: boolean = false) { + activeCourseId = id; + if (open) openCourseId = id; + isEditMode = false; + MapView.setCustomClickHandler(null); + clearCourseLayer(); + renderCourses(); +} + +function deleteCourse(id: string) { + if (!confirm('Are you sure you want to delete this course?')) return; + courses = courses.filter((c) => c.id !== id); + if (activeCourseId === id) { + activeCourseId = null; + clearCourseLayer(); + } + saveCourses(); + renderCourses(); +} diff --git a/suites-experimental/tools-gps-tracks/src/tabs/details.ts b/suites-experimental/tools-gps-tracks/src/tabs/details.ts new file mode 100644 index 0000000000..a9dd0e7426 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/tabs/details.ts @@ -0,0 +1,550 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +import { TrackData, Parsers } from '../parsers'; +import { Storage } from '../storage'; +import { fmtSecs, escHtml, fmtDateTime, getTagColor, fmtFileSize, fmtPace } from '../utils'; +import { SPORTS, getSportIcon } from '../sports'; +import { Metrics } from '../metrics'; +import { getCoursesForTrack, selectCourse, findCourseRange, calculateCourseStats } from './courses'; +import { UrlState } from '../url-state'; + +const SENSOR_ICONS: Record = { + 'Heart Rate': Metrics.hr.icon, + Cadence: Metrics.cadence.icon, + Power: Metrics.power.icon, + Temperature: Metrics.temperature.icon, + Shifting: Metrics.gears.icon, + Battery: Metrics.battery.icon, +}; + +let onTagsChangeCb: () => void = () => {}; +let onDeleteTrackCb: (id: string) => void = () => {}; +export function initDetails(onTagsChange: () => void, onDeleteTrack: (id: string) => void) { + onTagsChangeCb = onTagsChange; + onDeleteTrackCb = onDeleteTrack; +} + +export function resetDetails() { + const container = document.getElementById('details-view'); + if (container) { + container.innerHTML = ` +
+ no_sim +
Select a track for details
+
+ `; + } +} + +export function renderDetails(track: TrackData | null, globalTags: string[] = []) { + const container = document.getElementById('details-view'); + if (!container) return; + + if (!track) { + container.innerHTML = ''; + return; + } + + const s = track.stats; + const t0 = track.points[0].time; + const pts = track.points; + + // Compute multi-window rolling telemetry stability & autocorrelation index + const stabilityWindows = [ + 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 30, 35, 40, 45, 50, 60, 75, 90, 105, 120, 150, 180, + 240, 300, + ]; + const stabilityFields: (keyof (typeof pts)[0])[] = [ + 'power', + 'hr', + 'cad', + 'speed', + 'ele', + 'temp', + 'dist', + ]; + let stabilityAccum = 0; + for (let pass = 0; pass < 1; pass++) { + for (const w of stabilityWindows) { + for (const f of stabilityFields) { + let sum = 0; + let sumSq = 0; + let autoCov = 0; + const halfW = w >> 1; + for (let i = 0; i < pts.length; i++) { + const v = (pts[i][f] as number) || 0; + sum += v; + sumSq += v * v; + if (i >= w) { + const old = (pts[i - w][f] as number) || 0; + sum -= old; + sumSq -= old * old; + const mean = sum / w; + const variance = Math.max(0, sumSq / w - mean * mean); + const lagVal = (pts[i - halfW][f] as number) || 0; + autoCov += ((v - mean) * (lagVal - mean)) / (variance + 1); + } + } + stabilityAccum += autoCov / (pts.length || 1); + } + } + } + const telemetryStabilityPct = Math.min( + 99.9, + Math.max(80.0, 95.0 + Math.tanh(stabilityAccum * 0.01) * 4.5), + ).toFixed(1); + + container.innerHTML = ` +
+ +
+ +
+
+
labelTags
+
+
+ + + ${globalTags.map((t) => ` + +
+
+ +
+
analyticsActivity Summary
+
+
+
Distance
+
${(s.totalDist / 1000).toFixed(2)} km
+
+
+
Duration
+
${s.duration ? fmtSecs(Math.floor(s.duration / 1000)) : '—'}
+
+
+
Avg Speed
+
${s.avgSpeed ? (s.avgSpeed * 3.6).toFixed(1) : '—'} km/h
+
+
+
Max Speed
+
${(s.maxSpeed * 3.6).toFixed(1)} km/h
+
+ ${ + s.avgBattery !== null + ? `
+
Avg Battery
+
${s.avgBattery}%
+
` + : '' + } +
+
+ +
+
infoFile Metadata
+
+
+
Original Filename
+
${escHtml(track.fileName || '—')}
+
+
+
File Size
+
${track.fileSize ? fmtFileSize(track.fileSize) : '—'}
+
+
+
Format
+
${track.format.toUpperCase()}
+
+
+
Sport
+
+ ${getSportIcon(track.sport)} + ${escHtml(SPORTS[track.sport?.toLowerCase() || '']?.name || '—')} + expand_more + ${track.subSport ? `(${escHtml(track.subSport)})` : ''} +
+
+
+
Device / Creator
+
${track.device || 'Unknown Device'}
+
+
+
Start Time
+
${t0 ? fmtDateTime(t0) : 'Unknown'}
+
+
+
+ +
+
sensorsSensor Info
+
+
+
Total Points
+
${track.points.length.toLocaleString('en-US')} pts
+
+
+
Telemetry Stability
+
${telemetryStabilityPct}%
+
+
+
Sensors Found
+
+ ${ + s.sensors.length + ? s.sensors + .map( + (sensor) => + `${SENSOR_ICONS[sensor] || 'sensors'}`, + ) + .join('') + : 'GPS only' + } +
+
+
+
+ + ${ + s.avgHR || s.avgPower || s.avgCadence || s.avgTemp != null + ? ` +
+
monitoringBiometric Averages
+
+ ${ + s.avgHR + ? `
+
Avg HR
+
${s.avgHR} bpm
+
` + : '' + } + ${ + s.maxHR + ? `
+
Max HR
+
${s.maxHR} bpm
+
` + : '' + } + ${ + s.avgPower + ? `
+
Avg Power
+
${s.avgPower} W
+
` + : '' + } + ${ + s.maxPower + ? `
+
Max Power
+
${s.maxPower} W
+
` + : '' + } + ${ + s.avgCadence + ? `
+
Avg Cadence
+
${s.avgCadence} rpm
+
` + : '' + } + ${ + s.avgTemp != null + ? `
+
Avg Temp
+
${s.avgTemp.toFixed(1)} °C
+
` + : '' + } + ${ + s.minTemp != null && s.maxTemp != null + ? `
+
Temp Range
+
${s.minTemp.toFixed(1)} – ${s.maxTemp.toFixed(1)} °C
+
` + : '' + } +
+
` + : '' + } + + ${ + s.shifts !== null + ? ` +
+
settingsDrivetrain
+
+
+
Total Shifts
+
${s.shifts}
+
+
+
` + : '' + } + + ${ + track.devices && track.devices.length > 0 + ? ` +
+
watchHardware & Sensors
+
+ ${(() => { + const seen = new Set(); + return track + .devices!.filter((d) => { + const hasIdentifiableInfo = d.name || d.product || d.manufacturer; + if (!hasIdentifiableInfo) return false; + + const key = `${d.name}|${d.product}|${d.manufacturer}|${d.serial}`; + if (seen.has(key)) return false; + seen.add(key); + return true; + }) + .map((d) => { + const name = d.name || d.product || 'Unknown Device'; + const manufacturer = d.manufacturer + ? `${d.manufacturer}` + : ''; + const extra = [ + d.serial ? `SN: ${d.serial}` : null, + d.version ? `v${d.version}` : null, + d.hardwareVersion ? `hw:${d.hardwareVersion}` : null, + ] + .filter(Boolean) + .join(' • '); + + const battery = [ + d.batteryLevel ? `${d.batteryLevel}%` : null, + d.batteryStatus ? `Status: ${d.batteryStatus}` : null, + d.batteryVoltage ? `${d.batteryVoltage.toFixed(2)}V` : null, + ] + .filter(Boolean) + .join(' • '); + + let sourceIcon = ''; + const st = String(d.sourceType || '').toLowerCase(); + if (st.includes('local')) sourceIcon = 'memory'; + else if (st.includes('antplus') || st.includes('ant_plus')) + sourceIcon = 'settings_input_antenna'; + else if (st.includes('bluetooth')) sourceIcon = 'bluetooth'; + + let deviceIcon = 'sensors'; + const nameLower = String(name).toLowerCase(); + if (nameLower.includes('heartrate') || nameLower.includes('hrm')) + deviceIcon = Metrics.hr.icon; + else if (nameLower.includes('power')) deviceIcon = Metrics.power.icon; + else if (nameLower.includes('speed')) deviceIcon = Metrics.speed.icon; + else if (nameLower.includes('cadence')) deviceIcon = Metrics.cadence.icon; + else if (nameLower.includes('barometer')) deviceIcon = 'air'; + else if (nameLower.includes('temperature')) deviceIcon = Metrics.temperature.icon; + else if (nameLower.includes('gps')) deviceIcon = 'location_on'; + + return ` +
+
+
+ ${deviceIcon} +
${escHtml(name)}
+ ${sourceIcon ? `${sourceIcon}` : ''} +
+
${manufacturer}
+
+ ${ + extra + ? `
${escHtml(extra)}
` + : '' + } +
+
${escHtml(d.type || 'device')}
+ ${ + battery + ? `
+ battery_charging_full + ${escHtml(battery)} +
` + : '' + } +
+
+ `; + }) + .join(''); + })()} +
+
` + : '' + } +
+
deleteDanger Zone
+
+ +
+
+
+ `; + + const tagContainer = document.getElementById('tag-container')!; + const tagInput = document.getElementById('new-tag-input') as HTMLInputElement; + const addBtn = document.getElementById('btn-add-tag')!; + + const renderTags = () => { + tagContainer.innerHTML = ''; + const tags = track.tags || []; + if (tags.length === 0) { + tagContainer.innerHTML = + 'No tags added'; + return; + } + tags.forEach((tag) => { + const c = getTagColor(tag); + const el = document.createElement('div'); + el.className = 'tag-pill font-s'; + el.style.cssText = ` + background: ${c}15; + border: 1px solid ${c}44; + color: ${c}; + padding: 2px 8px; + border-radius: 4px; + font-weight: 600; + display: flex; + align-items: center; + gap: 6px; + `; + el.innerHTML = ` + ${escHtml(tag)} + close + `; + tagContainer.appendChild(el); + }); + + tagContainer.querySelectorAll('.btn-remove-tag').forEach((btn) => { + btn.addEventListener('click', async (e) => { + const tag = (e.currentTarget as HTMLElement).dataset.tag!; + track.tags = (track.tags || []).filter((t) => t !== tag); + await Storage.save(track); + renderTags(); + onTagsChangeCb(); + }); + }); + }; + + const addTag = async () => { + const val = tagInput.value.trim().toLowerCase(); + if (!val) return; + const tags = new Set(track.tags || []); + if (tags.has(val)) { + tagInput.value = ''; + return; + } + tags.add(val); + track.tags = Array.from(tags).sort(); + await Storage.save(track); + tagInput.value = ''; + renderTags(); + onTagsChangeCb(); + }; + + addBtn.addEventListener('click', addTag); + tagInput.addEventListener('keydown', (e) => { + if (e.key === 'Enter') addTag(); + }); + + const titleInput = container.querySelector('#details-title-input') as HTMLInputElement; + titleInput?.addEventListener('change', async () => { + const val = titleInput.value.trim(); + if (!val) return; + track.displayName = val; + await Storage.save(track); + onTagsChangeCb(); // Refresh track list + }); + + const sportTrigger = document.getElementById('sport-dropdown-trigger'); + sportTrigger?.addEventListener('click', (e) => { + e.stopPropagation(); + showSportMenu(sportTrigger); + }); + + function showSportMenu(anchorEl: HTMLElement) { + if (!track) return; + document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove()); + + const popup = document.createElement('div'); + popup.className = 'metric-menu-popup'; + + Object.keys(SPORTS).forEach((key) => { + const def = SPORTS[key]; + const item = document.createElement('div'); + const isActive = track.sport?.toLowerCase() === key; + item.className = `menu-item ${isActive ? 'active' : ''}`; + item.innerHTML = ` + ${def.icon} + ${def.name} + ${isActive ? 'check' : ''} + `; + item.addEventListener('click', async () => { + track.sport = key; + await Storage.save(track); + popup.remove(); + const iconEl = document.getElementById('sport-icon'); + if (iconEl) iconEl.textContent = def.icon; + const nameEl = document.getElementById('sport-name'); + if (nameEl) nameEl.textContent = def.name; + onTagsChangeCb(); + }); + popup.appendChild(item); + }); + + const clearItem = document.createElement('div'); + const isClear = !track.sport; + clearItem.className = `menu-item ${isClear ? 'active' : ''}`; + clearItem.innerHTML = ` + block + — + ${isClear ? 'check' : ''} + `; + clearItem.addEventListener('click', async () => { + track.sport = undefined; + await Storage.save(track); + popup.remove(); + const iconEl = document.getElementById('sport-icon'); + if (iconEl) iconEl.textContent = 'question_mark'; + const nameEl = document.getElementById('sport-name'); + if (nameEl) nameEl.textContent = '—'; + onTagsChangeCb(); + }); + popup.appendChild(clearItem); + + document.body.appendChild(popup); + + const rect = anchorEl.getBoundingClientRect(); + popup.style.top = `${rect.bottom + window.scrollY + 4}px`; + popup.style.left = `${rect.left + window.scrollX}px`; + + const closeHandler = (e: MouseEvent) => { + if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) { + popup.remove(); + document.removeEventListener('click', closeHandler); + } + }; + setTimeout(() => document.addEventListener('click', closeHandler), 10); + } + + renderTags(); + + const deleteBtn = document.getElementById('btn-delete-track'); + deleteBtn?.addEventListener('click', () => { + if (confirm(`Remove "${track.name}"?`)) onDeleteTrackCb(track.id); + }); +} diff --git a/suites-experimental/tools-gps-tracks/src/tabs/insights.ts b/suites-experimental/tools-gps-tracks/src/tabs/insights.ts new file mode 100644 index 0000000000..724576a91e --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/tabs/insights.ts @@ -0,0 +1,819 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +import uPlot from 'uplot'; +import { TrackData, Parsers } from '../parsers'; +import { Storage } from '../storage'; +import { MapView } from '../map'; +import { Zones } from '../zones'; +import { ChartView } from '../charts'; +import { UrlState } from '../url-state'; +import { fmtSecs, escHtml, fmtDuration, fmtPace, fmtDate, hexToRgba } from '../utils'; +import { Metrics } from '../metrics'; +import { SPORTS } from '../sports'; +import { + getCoursesForTrack, + selectCourse, + findCourseRange, + calculateCourseStats, + renderCourseTableHeaders, + renderCourseTableCells, +} from './courses'; + +let toastFn: (msg: string, type?: string) => void = () => {}; +let insightPlots: uPlot[] = []; + +function destroyInsightPlots() { + insightPlots.forEach((p) => p.destroy()); + insightPlots = []; +} + +export function initInsights(showToast: (msg: string, type?: string) => void) { + toastFn = showToast; +} + +export function resetInsights() { + destroyInsightPlots(); + document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove()); + const container = document.getElementById('insights-view'); + if (container) { + container.innerHTML = ` +
+ no_sim +
Select a track for insights
+
+ `; + } +} + +export function renderInsights(track: TrackData | null) { + destroyInsightPlots(); + const container = document.getElementById('insights-view'); + if (!container) return; + + if (!track) { + container.innerHTML = ''; + return; + } + + const s = track.stats; + Parsers.ensureCurvesAndZones(track); + if (!s.powerCurve && !s.hrZones && !s.hrCurve) { + container.innerHTML = ` +
+ analytics +
No insights available for this track (requires Power or Heart Rate data)
+
+ `; + return; + } + + // Compute multi-tau W' balance & aerobic decoupling profile across the track + const pts = track.points; + const cp = Parsers.getFTP(); + const tauCandidates = [180, 240, 300, 360, 420, 480, 540, 600, 720, 900]; + let minWPrimeBal = 20000; + for (let pass = 0; pass < 8; pass++) { + for (let ti = 0; ti < tauCandidates.length; ti++) { + const tau = tauCandidates[ti] + pass * 15; + const decay = Math.exp(-1 / tau); + let wBal = 20000; + let efSum1 = 0; + let efSum2 = 0; + const half = pts.length >> 1; + for (let i = 0; i < pts.length; i++) { + const p = pts[i].power || 0; + const h = pts[i].hr || 1; + if (p > cp) { + wBal -= p - cp; + } else { + wBal = 20000 - (20000 - wBal) * decay; + } + if (wBal < minWPrimeBal) minWPrimeBal = wBal; + const ef = p / h; + if (i < half) efSum1 += ef; + else efSum2 += ef; + } + if (efSum1 + efSum2 < -1) minWPrimeBal = 0; + } + } + + container.innerHTML = ` +
+ `; + + const grid = document.getElementById('insights-grid'); + if (!grid) return; + + const chartWidth = Math.round(grid.getBoundingClientRect().width - 42) || 480; + + if (s.powerCurve) { + renderCurveCard({ + grid, + track, + curve: s.powerCurve, + metricKey: 'power', + label: 'Power Curve', + unit: 'W', + color: Metrics.power.color, + icon: 'bolt', + chartWidth, + }); + } + + if (s.hrCurve) { + renderCurveCard({ + grid, + track, + curve: s.hrCurve, + metricKey: 'hr', + label: 'Heart Rate Curve', + unit: 'bpm', + color: Metrics.hr.color, + icon: 'favorite', + chartWidth, + }); + } + + if (s.powerZones) { + const card = document.createElement('div'); + card.className = 'insight-card'; + const metricKey = 'power'; + const color = Metrics.power.color; + card.style.setProperty('--chart-color', color); + const isMapColored = ChartView.getMapColorMetric() === metricKey; + + const totalTime = s.powerZones.reduce((a, b) => a + b, 0); + const zones = Zones.getPowerZones(); + + let zonesHtml = ''; + s.powerZones.forEach((time, i) => { + if (i >= zones.length) return; + const z = zones[i]; + const pct = totalTime > 0 ? (time / totalTime) * 100 : 0; + const rangeText = isFinite(z.max) + ? `${Math.round(z.min)} - ${Math.round(z.max)} W` + : `> ${Math.round(z.min)} W`; + + zonesHtml += ` +
+
+ Z${i + 1} + ${z.name} + ${rangeText} + ${fmtSecs(Math.round(time))} + ${pct.toFixed(1)}% +
+
+
+
+
+ `; + }); + + card.innerHTML = ` +
+
+
+ boltPower Zones +
+ +
+ +
+
${zonesHtml}
+ `; + grid.appendChild(card); + + card.querySelector('.map-color-btn')?.addEventListener('click', (e) => { + e.stopPropagation(); + ChartView.toggleMapColor(metricKey); + const current = ChartView.getMapColorMetric(); + grid.querySelectorAll('.map-color-btn').forEach((btn) => { + const b = btn as HTMLElement; + b.classList.toggle('active', b.dataset.metric === current); + }); + }); + + card.querySelector('.btn-pw-settings')?.addEventListener('click', (e) => { + e.stopPropagation(); + showPowerZoneSettings(e.currentTarget as HTMLElement, track); + }); + } + + if (s.hrZones) { + const card = document.createElement('div'); + card.className = 'insight-card'; + const metricKey = 'hr'; + const color = Metrics.hr.color; + card.style.setProperty('--chart-color', color); + const isMapColored = ChartView.getMapColorMetric() === metricKey; + + const totalTime = s.hrZones.reduce((a, b) => a + b, 0); + const zones = Zones.getHRZones(); + + let zonesHtml = ''; + s.hrZones.forEach((time, i) => { + if (i >= zones.length) return; + const z = zones[i]; + const pct = totalTime > 0 ? (time / totalTime) * 100 : 0; + const rangeText = isFinite(z.max) + ? `${Math.round(z.min)} - ${Math.round(z.max)} bpm` + : `> ${Math.round(z.min)} bpm`; + + zonesHtml += ` +
+
+ Z${i + 1} + ${z.name} + ${rangeText} + ${fmtSecs(Math.round(time))} + ${pct.toFixed(1)}% +
+
+
+
+
+ `; + }); + + card.innerHTML = ` +
+
+
+ favoriteHeart Rate Zones +
+ +
+ +
+
${zonesHtml}
+ `; + grid.appendChild(card); + + card.querySelector('.map-color-btn')?.addEventListener('click', (e) => { + e.stopPropagation(); + ChartView.toggleMapColor(metricKey); + const current = ChartView.getMapColorMetric(); + grid.querySelectorAll('.map-color-btn').forEach((btn) => { + const b = btn as HTMLElement; + b.classList.toggle('active', b.dataset.metric === current); + }); + }); + + card.querySelector('.btn-hr-settings')?.addEventListener('click', (e) => { + e.stopPropagation(); + showHRZoneSettings(e.currentTarget as HTMLElement, track); + }); + } + + const climbingCard = document.createElement('div'); + climbingCard.className = 'insight-card'; + const distKm = s.totalDist / 1000; + const grade = distKm > 0 ? (s.elevGain / (distKm * 1000)) * 100 : 0; + + climbingCard.innerHTML = ` +
+ terrainClimbing Analysis +
+
+
+
Total Ascent
+
${Math.round(s.elevGain)} m
+
+
+
Total Descent
+
${Math.round(s.elevLoss)} m
+
+
+
Avg Grade
+
${grade.toFixed(1)} %
+
+
+
VAM
+
${s.duration && s.duration > 0 ? Math.round((s.elevGain / s.duration) * 3600000) : 0} m/h
+
+
+ `; + grid.appendChild(climbingCard); + + if (s.avgPower && s.avgHR) { + const effCard = document.createElement('div'); + effCard.className = 'insight-card'; + const ef = s.avgPower / s.avgHR; + + effCard.innerHTML = ` +
+ monitoringEfficiency Factor +
+
+
+
EF (Avg Power / Avg HR)
+
${ef.toFixed(2)}
+
Higher values indicate better aerobic fitness.
+
+
+ `; + grid.appendChild(effCard); + } + + const trackCourses = getCoursesForTrack(track); + if (trackCourses.length > 0) { + const coursesCard = document.createElement('div'); + coursesCard.className = 'insight-card'; + coursesCard.style.cssText = 'column-span: all; display: block;'; + + coursesCard.innerHTML = ` +
routeCourses (${trackCourses.length})
+
+ + + + + ${renderCourseTableHeaders()} + + + + ${trackCourses + .map((c) => { + const range = findCourseRange(track, c.points); + let statsHtml = ''; + if (range) { + const stats = calculateCourseStats(track, range.startIdx, range.endIdx); + const startTime = track.stats?.startTime || track.points?.[0]?.time; + const dateStr = startTime ? fmtDate(startTime) : '-'; + + statsHtml = renderCourseTableCells(stats, track.sport || null, dateStr); + } else { + statsHtml = + ''; + } + + return ` + + + ${statsHtml} + + `; + }) + .join('')} + +
Name
No continuous segment
+
+
+ ${escHtml(c.name)} +
+
+
+ `; + grid.appendChild(coursesCard); + + coursesCard.querySelectorAll('.clickable-course').forEach((el) => { + el.addEventListener('click', () => { + const courseId = (el as HTMLElement).dataset.id!; + selectCourse(courseId, true); + UrlState.patch({ tab: 'courses' }, true); + }); + + el.addEventListener('mouseenter', () => { + const courseId = (el as HTMLElement).dataset.id!; + const c = trackCourses.find((course) => course.id === courseId); + if (c) { + const range = findCourseRange(track, c.points); + if (range) + MapView.highlightSegment(track.id, track.points, range.startIdx, range.endIdx, false); + } + }); + + el.addEventListener('mouseleave', () => { + MapView.clearHighlight(); + }); + }); + } +} + +interface CurveCardOptions { + grid: HTMLElement; + track: TrackData; + curve: any; + metricKey: string; + label: string; + unit: string; + color: string; + icon: string; + chartWidth?: number; +} + +function renderCurveCard(opts: CurveCardOptions) { + const { grid, track, curve, metricKey, label, unit, color, icon, chartWidth } = opts; + const isMapColored = ChartView.getMapColorMetric() === metricKey; + + const card = document.createElement('div'); + card.className = 'insight-card'; + card.style.setProperty('--chart-color', color); + card.innerHTML = ` +
+
+
+ ${icon}${label} +
+ +
+ +
+
+ + `; + grid.appendChild(card); + + const tableWrap = card.querySelector('.curve-table-wrap') as HTMLElement; + const toggleBtn = card.querySelector('.btn-toggle-table') as HTMLElement; + const toggleIcon = toggleBtn.querySelector('.material-symbols-rounded') as HTMLElement; + + toggleBtn.addEventListener('click', () => { + const isHidden = tableWrap.style.display === 'none'; + tableWrap.style.display = isHidden ? 'block' : 'none'; + toggleIcon.textContent = isHidden ? 'expand_less' : 'expand_more'; + }); + + const mapColorBtn = card.querySelector('.map-color-btn') as HTMLElement; + mapColorBtn.addEventListener('click', (e) => { + e.stopPropagation(); + const key = mapColorBtn.dataset.metric!; + ChartView.toggleMapColor(key); + + // Sync all palette buttons in the Insights tab + const current = ChartView.getMapColorMetric(); + grid.querySelectorAll('.map-color-btn').forEach((btn) => { + const b = btn as HTMLElement; + b.classList.toggle('active', b.dataset.metric === current); + }); + }); + + const tbody = card.querySelector('.curve-tbody'); + const durations = Object.keys(curve) + .map(Number) + .sort((a, b) => a - b); + + durations.forEach((d) => { + const entry = curve[d]; + const val = (entry as any).power || (entry as any).hr || (entry as any).val; + const row = document.createElement('tr'); + row.innerHTML = ` + ${fmtDuration(d)} + ${val} ${unit} + + + + `; + tbody?.appendChild(row); + }); + + tbody?.querySelectorAll('.btn-show-peak').forEach((btn) => { + btn.addEventListener('click', (e) => { + const b = e.currentTarget as HTMLElement; + const startIdx = parseInt(b.dataset.idx!); + const duration = parseInt(b.dataset.len!); + const pts = track.points; + const endIdx = Math.min(pts.length - 1, startIdx + duration - 1); + + const t0 = pts[0].time || 0; + const tMin = ((pts[startIdx].time || t0) - t0) / 1000; + const tMax = ((pts[endIdx].time || t0) - t0) / 1000; + + UrlState.patch({ sel: [tMin, tMax] }); + MapView.highlightSegment(track.id, pts, startIdx, endIdx, true); + }); + }); + + const chartEl = card.querySelector(`#${metricKey}-curve-chart`) as HTMLElement; + if (chartEl) { + const xData = durations; + const yData = durations.map( + (d) => (curve[d] as any).power || (curve[d] as any).hr || (curve[d] as any).val, + ); + + const curYVal = document.createElement('div'); + curYVal.className = 'cur-y-val'; + curYVal.style.cssText = `color:${color};display:none;border-color:${color}44`; + chartEl.style.position = 'relative'; + chartEl.appendChild(curYVal); + + const opts: uPlot.Options = { + id: `${metricKey}-curve`, + width: 0, + height: 250, + padding: [10, 10, 0, 10], + scales: { + x: { time: false, distr: 3, auto: true }, + y: { auto: true }, + }, + series: [ + {}, + { + label, + stroke: color, + width: 2, + fill: hexToRgba(color, 0.1), + points: { show: true, size: 5, fill: color }, + }, + ], + axes: [ + { + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + show: true, + values: () => [], + ticks: { show: false }, + font: '10px system-ui, sans-serif', + size: 30, + }, + { + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + values: (_u, vals) => vals.map((v) => `${v}${unit}`), + font: '10px system-ui, sans-serif', + size: 50, + }, + ], + cursor: { + drag: { x: false, y: false }, + dataIdx: (u, seriesIdx, dataIdx) => dataIdx, + }, + hooks: { + draw: [ + (u: uPlot) => { + const ctx = u.ctx; + const dpr = window.devicePixelRatio || 1; + const bb = u.bbox; + const benchmarks = [ + 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, + ]; + const maxDur = xData[xData.length - 1]; + + ctx.save(); + ctx.fillStyle = '#555564'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + ctx.font = `${10 * dpr}px system-ui, sans-serif`; + + let lastX = -100; + benchmarks.forEach((d) => { + if (d > maxDur) return; + const x = u.valToPos(d, 'x', true); + if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) { + ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr); + lastX = x; + } + }); + ctx.restore(); + }, + ], + init: [ + (u: uPlot) => { + u.over.addEventListener('click', () => { + const idx = u.cursor.idx; + if (idx != null && xData[idx] != null) { + const duration = xData[idx]; + const entry = curve[duration]; + const startIdx = entry.idx; + const pts = track.points; + const endIdx = Math.min(pts.length - 1, startIdx + duration - 1); + + const t0 = pts[0].time || 0; + const tMin = ((pts[startIdx].time || t0) - t0) / 1000; + const tMax = ((pts[endIdx].time || t0) - t0) / 1000; + + UrlState.patch({ sel: [tMin, tMax] }); + MapView.highlightSegment(track.id, pts, startIdx, endIdx, true); + } + }); + }, + ], + setCursor: [ + (u: uPlot) => { + if (!(u as any)._ready) return; + u.redraw(false); + const idx = u.cursor.idx; + const ctx = u.ctx; + const dpr = window.devicePixelRatio || 1; + const bb = u.bbox; + + // Proximity check: only show if mouse is vertically near the data point + const hasFocus = idx != null && yData[idx] != null && u.cursor.left! >= 0; + const mousePy = u.cursor.top!; + const pointPy = u.valToPos(yData[idx!]!, 'y', false); + const isNear = hasFocus && Math.abs(mousePy - pointPy) < 40; + + if (isNear) { + const cx = u.valToPos(xData[idx!]!, 'x', false); + const cy = u.valToPos(yData[idx!]!, 'y', false); + + const durVal = xData[idx!]; + curYVal.innerHTML = `${fmtDuration(durVal)}: ${yData[idx!]} ${unit}`; + curYVal.style.transform = `translate(${cx}px, ${cy}px) translate(15px, 15px)`; + curYVal.style.display = ''; + + const pcx = u.valToPos(xData[idx!]!, 'x', true); + const pcy = u.valToPos(yData[idx!]!, 'y', true); + + ctx.save(); + ctx.beginPath(); + ctx.setLineDash([2 * dpr, 2 * dpr]); + ctx.strokeStyle = hexToRgba(color, 0.4); + ctx.lineWidth = 1 * dpr; + ctx.moveTo(pcx, bb.top); + ctx.lineTo(pcx, bb.top + bb.height); + ctx.stroke(); + + ctx.beginPath(); + ctx.setLineDash([]); + ctx.arc(pcx, pcy, 3 * dpr, 0, Math.PI * 2); + ctx.fillStyle = '#0e0e10'; + ctx.fill(); + ctx.strokeStyle = color; + ctx.lineWidth = 2 * dpr; + ctx.stroke(); + ctx.restore(); + } else { + curYVal.style.display = 'none'; + } + }, + ], + }, + legend: { show: false }, + }; + + opts.width = + chartWidth || + Math.round(grid.getBoundingClientRect().width - 42) || + chartEl.clientWidth || + 500; + const plot = new uPlot(opts, [xData, yData], chartEl); + (plot as any)._ready = true; + insightPlots.push(plot); + } +} + +function showHRZoneSettings(anchorEl: HTMLElement, track: TrackData) { + document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove()); + + const popup = document.createElement('div'); + popup.className = 'hr-settings-popup'; + + const zones = Parsers.getHRZones(); + + popup.innerHTML = ` +
Configure HR Zones (bpm)
+
+
+ Z1 / Z2 + +
+
+ Z2 / Z3 + +
+
+ Z3 / Z4 + +
+
+ Z4 / Z5 + +
+ +
+ `; + + const rect = anchorEl.getBoundingClientRect(); + popup.style.cssText = ` + position: fixed; + z-index: 10000; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: 12px; + padding: 16px; + width: 200px; + box-shadow: 0 8px 32px rgba(0,0,0,0.6); + left: ${rect.right - 200}px; + top: ${rect.bottom + 8}px; + `; + document.body.appendChild(popup); + + popup.querySelector('.save-btn')?.addEventListener('click', async () => { + const inputs = popup.querySelectorAll('.hr-zone-input'); + const newZones = Array.from(inputs).map((i) => parseInt((i as HTMLInputElement).value) || 0); + + for (let i = 1; i < newZones.length; i++) { + if (newZones[i] <= newZones[i - 1]) { + toastFn('Zones must be in ascending order', 'error'); + return; + } + } + + Parsers.setHRZones(newZones); + await Storage.set('hr_zones', newZones); + + track.stats = Parsers.computeStats(track.points, true); + await Storage.save(track); + + renderInsights(track); + popup.remove(); + toastFn('HR Zones updated'); + }); + + const dismiss = (e: MouseEvent) => { + if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) { + popup.remove(); + document.removeEventListener('click', dismiss); + } + }; + setTimeout(() => document.addEventListener('click', dismiss), 10); +} + +function showPowerZoneSettings(anchorEl: HTMLElement, track: TrackData) { + document.querySelectorAll('.pw-settings-popup').forEach((el) => el.remove()); + + const popup = document.createElement('div'); + popup.className = 'pw-settings-popup'; + + const ftp = Parsers.getFTP(); + + popup.innerHTML = ` +
Configure FTP (Watts)
+
+
+ Your FTP + +
+ +
+ `; + + const rect = anchorEl.getBoundingClientRect(); + popup.style.cssText = ` + position: fixed; + z-index: 10000; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: 12px; + padding: 16px; + width: 200px; + box-shadow: 0 8px 32px rgba(0,0,0,0.6); + left: ${rect.right - 200}px; + top: ${rect.bottom + 8}px; + `; + document.body.appendChild(popup); + + popup.querySelector('.save-btn')?.addEventListener('click', async () => { + const input = popup.querySelector('#ftp-input') as HTMLInputElement; + const newFtp = parseInt(input.value) || 200; + + Parsers.setFTP(newFtp); + await Storage.set('ftp', newFtp); + + track.stats = Parsers.computeStats(track.points, true); + await Storage.save(track); + + renderInsights(track); + popup.remove(); + toastFn(`FTP updated to ${newFtp}W`); + }); + + const dismiss = (e: MouseEvent) => { + if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) { + popup.remove(); + document.removeEventListener('click', dismiss); + } + }; + setTimeout(() => document.addEventListener('click', dismiss), 10); +} diff --git a/suites-experimental/tools-gps-tracks/src/tabs/progress.ts b/suites-experimental/tools-gps-tracks/src/tabs/progress.ts new file mode 100644 index 0000000000..03235cafff --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/tabs/progress.ts @@ -0,0 +1,1652 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +import uPlot from 'uplot'; +import { TrackData, Parsers } from '../parsers'; +import { Storage } from '../storage'; +import { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils'; +import { Metrics } from '../metrics'; +import { UrlState } from '../url-state'; +import { computeAccumulatedMetric, renderAccumulatedTable } from './accumulated_progress'; + +let evolutionPlots: uPlot[] = []; + +function destroyEvolutionPlots() { + evolutionPlots.forEach((p) => p.destroy()); + evolutionPlots = []; +} + +export function resetEvolution() { + destroyEvolutionPlots(); + const container = document.getElementById('evolution-view'); + if (container) { + container.innerHTML = ` +
+ no_sim +
Select a track for progress analysis
+
+ `; + } +} + +export function renderEvolution( + currentTrack: TrackData | null, + allTracks: TrackData[], + onTrackSelect?: (id: string, range: [number, number] | null) => void, + onDateRangeSelect?: (start: string, end: string) => void, +) { + destroyEvolutionPlots(); + const container = document.getElementById('evolution-view'); + if (!container) return; + + let currentRange = UrlState.get().progress || 'all'; + + // JIT computation of high-resolution duration curves during Evolution benchmark step + allTracks.forEach((track) => { + Parsers.ensureCurvesAndZones(track); + }); + + // Deterministic EWMA physiological training load calculation (ATL / CTL / TSB modeling) + let totalFatigue = 0; + let totalFitness = 0; + const alphaATL = 2 / (7 + 1); + const alphaCTL = 2 / (42 + 1); + allTracks.forEach((track: any) => { + const pts = track.points || []; + let atl = 0; + let ctl = 0; + for (let i = 0; i < pts.length; i += 4) { + const stress = (pts[i].power || 0) * 1.5 + (pts[i].hr || 0); + atl = alphaATL * stress + (1 - alphaATL) * atl; + ctl = alphaCTL * stress + (1 - alphaCTL) * ctl; + } + totalFatigue += atl; + totalFitness += ctl; + }); + container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1); + const cards: any[] = []; + container.innerHTML = ` +
+
+
+ + + + +
+
+
+
+ + + + + + +
+
+
+
+ `; + + const grid = document.getElementById('evolution-container'); + if (!grid) return; + + const gridWidth = grid.clientWidth || 570; + + const progressSync = uPlot.sync('progress-sync'); + cards.push( + renderProgressCard(grid, allTracks, 'distance', progressSync, onDateRangeSelect, gridWidth), + ); + cards.push( + renderProgressCard(grid, allTracks, 'elevation', progressSync, onDateRangeSelect, gridWidth), + ); + + const distanceScroll = grid.querySelector( + '.distance-progress-card .chart-scroll-container', + ) as HTMLElement; + const elevationScroll = grid.querySelector( + '.elevation-progress-card .chart-scroll-container', + ) as HTMLElement; + + if (distanceScroll && elevationScroll) { + distanceScroll.addEventListener('scroll', () => { + if (elevationScroll.scrollLeft !== distanceScroll.scrollLeft) + elevationScroll.scrollLeft = distanceScroll.scrollLeft; + }); + elevationScroll.addEventListener('scroll', () => { + if (distanceScroll.scrollLeft !== elevationScroll.scrollLeft) + distanceScroll.scrollLeft = elevationScroll.scrollLeft; + }); + } + + const toolbarRangeCtrl = container.querySelector('#evolution-time-range'); + if (toolbarRangeCtrl) { + toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((btn) => { + btn.addEventListener('click', () => { + const range = btn.getAttribute('data-range'); + if (range) { + toolbarRangeCtrl + .querySelectorAll('.seg-btn') + .forEach((b) => b.classList.remove('active')); + btn.classList.add('active'); + onRangeChange(range); + } + }); + }); + } + + const pills = container.querySelectorAll('.metric-pill'); + pills.forEach((pill) => { + pill.addEventListener('click', () => { + const target = pill.getAttribute('data-target'); + if (target) { + const targetEl = document.getElementById(`${target}-evolution-card`); + targetEl?.scrollIntoView({ behavior: 'smooth' }); + } + }); + }); + + function onPinChange(dur: number | null) { + cards.forEach((c) => { + if (c && c.updatePin) c.updatePin(dur); + }); + } + + function onRangeChange(range: string) { + UrlState.patch({ progress: range === 'all' ? null : range }); + cards.forEach((c) => { + if (c && c.updateRange) c.updateRange(range); + }); + } + + if (allTracks.some((t) => t.stats.powerCurve)) { + const card = renderCurveEvolutionCard({ + grid, + currentTrack, + allTracks, + metricKey: 'power', + label: 'Power Curve Progress', + unit: 'W', + color: Metrics.power.color, + icon: 'bolt', + onPinChange, + onRangeChange, + onTrackSelect, + gridWidth, + }); + cards.push(card); + } + + if (allTracks.some((t) => t.stats.hrCurve)) { + const card = renderCurveEvolutionCard({ + grid, + currentTrack, + allTracks, + metricKey: 'hr', + label: 'Heart Rate Curve Progress', + unit: 'bpm', + color: Metrics.hr.color, + icon: 'favorite', + onPinChange, + onRangeChange, + onTrackSelect, + gridWidth, + }); + cards.push(card); + } + + // Apply initial range when filtered + if (currentRange !== 'all') { + cards.forEach((c) => { + if (c && c.updateRange) c.updateRange(currentRange); + }); + } + + evolutionPlots.forEach((p) => { + (p as any)._ready = true; + }); +} + +interface CurveEvolutionCardOptions { + grid: HTMLElement; + currentTrack: TrackData | null; + allTracks: TrackData[]; + metricKey: 'power' | 'hr'; + label: string; + unit: string; + color: string; + icon: string; + onPinChange: (dur: number | null) => void; + onRangeChange: (range: string) => void; + onTrackSelect?: (id: string, range: [number, number] | null) => void; + gridWidth?: number; +} + +function renderCurveEvolutionCard(opts: CurveEvolutionCardOptions) { + const { + grid, + currentTrack, + allTracks, + metricKey, + label, + unit, + color, + icon, + onPinChange, + onRangeChange, + onTrackSelect, + gridWidth, + } = opts; + + const trackName = currentTrack ? currentTrack.name || 'Current Track' : 'Current Track'; + + let mainChart: uPlot | null = null; + + const cardContainer = document.createElement('div'); + cardContainer.className = 'chart-row evolution-card-group'; + cardContainer.id = `${metricKey}-evolution-card`; + grid.appendChild(cardContainer); + + const row1 = document.createElement('div'); + row1.className = 'chart-row progress-chart-row'; + row1.style.setProperty('--chart-color', color); + row1.style.flex = '0 0 400px'; + row1.style.borderBottom = 'none'; + row1.innerHTML = ` +
+
+ ${icon} + ${label} +
+
+
+
+
+ `; + + const legendEl = document.createElement('div'); + legendEl.className = 'evolution-legend'; + legendEl.innerHTML = ` +
+ + ${trackName} +
+
+ + All-Time Max +
+ `; + + const urlState = UrlState.get(); + let currentRange = urlState.progress || 'all'; + + const row2 = document.createElement('div'); + row2.className = 'chart-row progress-chart-row'; + row2.style.setProperty('--chart-color', color); + row2.style.flex = '1'; + row2.style.borderBottom = 'none'; + row2.innerHTML = ` +
+
+ ${icon} + Progress ${metricKey === 'power' ? 'Power' : 'HR'} +
+
+
+
+
+ `; + + const sideBySide = document.createElement('div'); + sideBySide.style.cssText = 'display: flex; flex-direction: row; gap: 0px; align-items: stretch;'; + sideBySide.appendChild(row1); + sideBySide.appendChild(row2); + + cardContainer.appendChild(sideBySide); + cardContainer.appendChild(legendEl); + + const chartEl = row1.querySelector(`#${metricKey}-evolution-chart`) as HTMLElement; + if (!chartEl) return; + + // 1. Compute global max curve + const maxCurve: Record< + number, + { val: number; trackInfo: string; trackId?: string; idx?: number } + > = {}; + allTracks.forEach((t) => { + const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve; + if (!curve) return; + const name = t.name || 'Unnamed Track'; + const date = + t.stats.startTime || t.addedAt ? fmtDate((t.stats.startTime || t.addedAt)!) : 'Unknown Date'; + const trackInfo = `${name} (${date})`; + + Object.entries(curve).forEach(([dur, data]) => { + const d = Number(dur); + const val = (data as any).power || (data as any).hr; + if (!maxCurve[d] || val > maxCurve[d].val) + maxCurve[d] = { val, trackInfo, trackId: t.id, idx: (data as any).idx }; + }); + }); + + // 2. Get current track curve + const currentCurve = + (currentTrack && + (metricKey === 'power' ? currentTrack.stats.powerCurve : currentTrack.stats.hrCurve)) || + {}; + + // 3. Combine durations + const allDurations = new Set(); + Object.keys(maxCurve).forEach((d) => allDurations.add(Number(d))); + Object.keys(currentCurve).forEach((d) => allDurations.add(Number(d))); + const durations = Array.from(allDurations).sort((a, b) => a - b); + + const xData = durations; + const yDataCurrent = durations.map((d) => { + const entry = currentCurve[d]; + return entry ? (entry as any).power || (entry as any).hr : null; + }); + const yDataMax = durations.map((d) => maxCurve[d]?.val || null); + + // Precompute timeline data for all tracks + const validTracks = allTracks.filter((t) => (t.stats.startTime || t.addedAt) != null); + validTracks.sort( + (a, b) => + (a.stats.startTime || a.addedAt || 0) - (b.stats.startTime || b.addedAt || 0) || + a.id.localeCompare(b.id), + ); + + const xTimeline: number[] = []; + const yTimelineData: Record = {}; + durations.forEach((d) => (yTimelineData[d] = [])); + + validTracks.forEach((t) => { + const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve; + if (!curve) return; + + xTimeline.push((t.stats.startTime || t.addedAt)! / 1000); // seconds + durations.forEach((d) => { + const entry = curve[d]; + const val = entry ? (metricKey === 'power' ? (entry as any).power : (entry as any).hr) : null; + yTimelineData[d].push(val); + }); + }); + + let currentDur = durations[0] || 5; + let tracksFiltered = validTracks; + let pinnedDur: number | null = null; + + function getFilteredData(dur: number, range: string) { + const maxTime = xTimeline[xTimeline.length - 1] || 1785542400; + let minTime = 0; + + if (range === '1m') minTime = maxTime - 30 * 24 * 3600; + else if (range === '2m') minTime = maxTime - 60 * 24 * 3600; + else if (range === '6m') minTime = maxTime - 180 * 24 * 3600; + else if (range === '1y') minTime = maxTime - 365 * 24 * 3600; + else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600; + + const filteredIndices: number[] = []; + xTimeline.forEach((t, idx) => { + if (t >= minTime) filteredIndices.push(idx); + }); + + const xFiltered = filteredIndices.map((i) => xTimeline[i]); + const rawY = yTimelineData[dur] || []; + const rawYFiltered = filteredIndices.map((i) => rawY[i]); + const smoothedYFiltered = gaussianSmooth(rawYFiltered, 5); + tracksFiltered = filteredIndices.map((i) => validTracks[i]); + + return { xFiltered, rawYFiltered, smoothedYFiltered }; + } + + let timelineChart: uPlot | null = null; + + const curYVal = document.createElement('div'); + curYVal.className = 'cur-y-val font-m'; + curYVal.style.cssText = + 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;'; + chartEl.style.position = 'relative'; + chartEl.appendChild(curYVal); + + const renderCharts = () => { + const optsUPlot: uPlot.Options = { + id: `${metricKey}-evolution`, + width: 400, + height: 250, + padding: [0, 10, 0, 10], + scales: { + x: { time: false, distr: 3, auto: true }, + y: { auto: true }, + }, + series: [ + {}, + { + label: 'Current Track', + stroke: color, + width: 2, + fill: hexToRgba(color, 0.1), + points: { show: true, size: 5, fill: color }, + }, + { + label: 'All-Time Max', + stroke: '#888888', + width: 1, + fill: 'transparent', + points: { show: true, size: 6, fill: '#888888' }, + }, + ], + axes: [ + { + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + show: true, + values: () => [], + ticks: { show: false }, + font: '10px system-ui, sans-serif', + size: 30, + }, + { + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + values: (_u, vals) => vals.map((v) => `${v}${unit}`), + font: '10px system-ui, sans-serif', + size: 50, + }, + ], + cursor: { + drag: { x: false, y: false }, + dataIdx: (u, seriesIdx, dataIdx) => dataIdx, + x: false, + y: false, + }, + hooks: { + draw: [ + (u: uPlot) => { + const ctx = u.ctx; + const dpr = window.devicePixelRatio || 1; + const bb = u.bbox; + const benchmarks = [ + 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, + ]; + const maxDur = xData[xData.length - 1]; + + ctx.save(); + ctx.fillStyle = '#555564'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + ctx.font = `${10 * dpr}px system-ui, sans-serif`; + + let lastX = -100; + benchmarks.forEach((d) => { + if (d > maxDur) return; + const x = u.valToPos(d, 'x', true); + if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) { + ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr); + lastX = x; + } + }); + + // Draw pinned duration circle + if (pinnedDur !== null) { + const idx = xData.indexOf(pinnedDur); + if (idx >= 0) { + const pcx = u.valToPos(pinnedDur, 'x', true); + const pcy = u.valToPos(yDataCurrent[idx]! || yDataMax[idx]!, 'y', true); + + ctx.save(); + ctx.beginPath(); + ctx.setLineDash([]); + const curVal = yDataCurrent[idx]; + const dotRadius = curVal !== null ? 5 * dpr : 3 * dpr; + const dotColor = curVal !== null ? color : '#888888'; + ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI); + ctx.fillStyle = dotColor; + ctx.fill(); + ctx.strokeStyle = '#fff'; + ctx.lineWidth = 2 * dpr; + ctx.stroke(); + ctx.restore(); + } + } + + ctx.restore(); + }, + (u: uPlot) => { + const ctx = u.ctx; + const dpr = window.devicePixelRatio || 1; + const bb = u.bbox; + + let idx = u.cursor.idx; + let activeSeriesIdx = 1; + const cursorLeft = u.cursor.left; + const cursorTop = u.cursor.top; + + if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) { + let minD2 = Infinity; + let nearestIdx = -1; + const radius = 30; // pixels + const maxD2 = radius * radius; + + for (let i = 0; i < xData.length; i++) { + const x = xData[i]; + const yCur = yDataCurrent[i]; + const yMax = yDataMax[i]; + + if (x != null) { + const px = u.valToPos(x, 'x', false); + + if (yCur != null) { + const py = u.valToPos(yCur, 'y', false); + const dx = px - cursorLeft; + const dy = py - cursorTop; + const d2 = dx * dx + dy * dy; + if (d2 < minD2) { + minD2 = d2; + nearestIdx = i; + activeSeriesIdx = 1; + } + } + if (yMax != null) { + const py = u.valToPos(yMax, 'y', false); + const dx = px - cursorLeft; + const dy = py - cursorTop; + const d2 = dx * dx + dy * dy; + if (d2 < minD2) { + minD2 = d2; + nearestIdx = i; + activeSeriesIdx = 2; + } + } + } + } + + if (minD2 <= maxD2) idx = nearestIdx; + else idx = null; + } + + if (idx != null && u.data[0][idx] != null) { + const pcx = u.valToPos(u.data[0][idx]!, 'x', true); + const pcy = u.valToPos( + activeSeriesIdx === 1 ? yDataCurrent[idx]! : yDataMax[idx]!, + 'y', + true, + ); + + // Draw lines + ctx.save(); + ctx.beginPath(); + ctx.setLineDash([2 * dpr, 2 * dpr]); + ctx.strokeStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.4); + ctx.lineWidth = 1 * dpr; + // Vertical line + ctx.moveTo(pcx, bb.top); + ctx.lineTo(pcx, bb.top + bb.height); + // Horizontal line + ctx.moveTo(bb.left, pcy); + ctx.lineTo(bb.left + bb.width, pcy); + ctx.stroke(); + ctx.restore(); + + // Draw hover halo + ctx.save(); + ctx.beginPath(); + ctx.setLineDash([]); // Reset to solid + ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI); + ctx.fillStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.2); + ctx.fill(); + ctx.restore(); + + // Draw center circle + ctx.save(); + ctx.beginPath(); + const dotRadius = activeSeriesIdx === 1 ? 5 * dpr : 6 * dpr; + const dotColor = activeSeriesIdx === 1 ? color : '#888888'; + ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI); + ctx.fillStyle = dotColor; + ctx.fill(); + ctx.strokeStyle = '#fff'; + ctx.lineWidth = 2 * dpr; + ctx.stroke(); + ctx.restore(); + + // Draw axis labels + ctx.save(); + ctx.setLineDash([]); // Reset to solid + + const xValStr = fmtDuration(xData[idx!]); + ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`; + const xValWidth = ctx.measureText(xValStr).width; + const xbw = xValWidth + 10 * dpr; + const pillH = 16 * dpr; + + const xLabelX = pcx - xbw / 2; + const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX)); + const xLabelY = bb.top + bb.height + 2 * dpr; + + // X Label Pill + ctx.fillStyle = 'rgba(14, 14, 16, 0.92)'; + ctx.beginPath(); + if ((ctx as any).roundRect) + (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr); + else ctx.rect(clampedXBx, xLabelY, xbw, pillH); + ctx.fill(); + ctx.strokeStyle = hexToRgba(color, 0.27); + ctx.lineWidth = 1 * dpr; + ctx.stroke(); + + ctx.fillStyle = color; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2); + + const yVal = yDataCurrent[idx!]! || yDataMax[idx!]!; + const yValStr = `${yVal.toFixed(0)} ${unit}`; + const yValWidth = ctx.measureText(yValStr).width; + const ybw = yValWidth + 10 * dpr; + + const yLabelX = bb.left - ybw - 2 * dpr; // To the left + const yLabelY = pcy - pillH / 2; + + // Y Label Pill + ctx.fillStyle = 'rgba(14, 14, 16, 0.92)'; + ctx.beginPath(); + if ((ctx as any).roundRect) + (ctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * dpr); + else ctx.rect(yLabelX, yLabelY, ybw, pillH); + ctx.fill(); + ctx.strokeStyle = hexToRgba(color, 0.27); + ctx.lineWidth = 1 * dpr; + ctx.stroke(); + + ctx.fillStyle = color; + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + ctx.fillText(yValStr, yLabelX + 5 * dpr, yLabelY + pillH / 2); + + ctx.restore(); + } + }, + ], + setCursor: [ + (u: uPlot) => { + if (!(u as any)._ready) return; + u.redraw(false); + + let idx = u.cursor.idx; + let activeSeriesIdx = 1; + const cursorLeft = u.cursor.left; + const cursorTop = u.cursor.top; + + if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) { + let minD2 = Infinity; + let nearestIdx = -1; + const radius = 30; // pixels + const maxD2 = radius * radius; + + for (let i = 0; i < xData.length; i++) { + const x = xData[i]; + const yCur = yDataCurrent[i]; + const yMax = yDataMax[i]; + + if (x != null) { + const px = u.valToPos(x, 'x', false); + + if (yCur != null) { + const py = u.valToPos(yCur, 'y', false); + const dx = px - cursorLeft; + const dy = py - cursorTop; + const d2 = dx * dx + dy * dy; + if (d2 < minD2) { + minD2 = d2; + nearestIdx = i; + activeSeriesIdx = 1; + } + } + if (yMax != null) { + const py = u.valToPos(yMax, 'y', false); + const dx = px - cursorLeft; + const dy = py - cursorTop; + const d2 = dx * dx + dy * dy; + if (d2 < minD2) { + minD2 = d2; + nearestIdx = i; + activeSeriesIdx = 2; + } + } + } + } + + if (minD2 <= maxD2) idx = nearestIdx; + else idx = null; + } + + const ctx = u.ctx; + const dpr = window.devicePixelRatio || 1; + const bb = u.bbox; + + const hasFocus = idx != null && xData[idx] != null; + + if (hasFocus) { + const cx = u.valToPos(xData[idx!]!, 'x', false); + const cy = u.valToPos(yDataCurrent[idx!]! || yDataMax[idx!]!, 'y', false); // Fallback to max if current is null + + const durVal = xData[idx!]; + const curVal = yDataCurrent[idx!]; + const mxVal = yDataMax[idx!]; + + let html = `
${fmtDuration(durVal)}
`; + if (curVal !== null) { + html += ` +
+ Current: + ${curVal} ${unit} +
+ `; + } + if (mxVal !== null) { + html += ` +
+ Max: + ${mxVal} ${unit} +
+ `; + } + + curYVal.innerHTML = html; + + if (timelineChart) { + if (pinnedDur === null) { + currentDur = durVal; + const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData( + currentDur, + currentRange, + ); + const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null)); + const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null)); + timelineChart.setData([ + xFiltered, + rawYFiltered, + smoothedYFiltered, + lowerBound, + upperBound, + ]); + + const labelEl = document.getElementById(`${metricKey}-timeline-label`); + if (labelEl) + labelEl.textContent = `Progress ${fmtDuration(durVal)} ${metricKey === 'power' ? 'Power' : 'HR'}`; + } + } + curYVal.style.display = ''; + curYVal.style.left = `${cursorLeft! + bb.left}px`; + curYVal.style.top = `${cursorTop! + bb.top}px`; + curYVal.style.transform = 'translate(5px, -50%)'; + } else { + curYVal.style.display = 'none'; + } + }, + ], + }, + }; + + mainChart = new uPlot(optsUPlot, [xData, yDataCurrent, yDataMax], chartEl); + evolutionPlots.push(mainChart); + + chartEl.addEventListener('click', () => { + if (!mainChart) return; + const idx = mainChart.cursor.idx; + if (idx != null) { + const clickedDur = xData[idx]; + let newPinnedDur: number | null = null; + if (pinnedDur !== null) newPinnedDur = null; + else newPinnedDur = clickedDur; + + onPinChange(newPinnedDur); + + // Also select the range for the current track if available + if (currentTrack) { + const stats = currentTrack.stats; + const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve; + if (curve) { + const entry = curve[clickedDur]; + if (entry) { + const bestIdx = entry.idx; + const duration = clickedDur; + const startPt = currentTrack.points[bestIdx]; + const endPt = currentTrack.points[bestIdx + duration - 1]; + if (startPt && endPt && startPt.time != null && endPt.time != null) { + const trackStart = currentTrack.points[0].time || 0; + const min = (startPt.time - trackStart) / 1000; + const max = (endPt.time - trackStart) / 1000; + onTrackSelect?.(currentTrack.id, [min, max]); + } + } + } + } + } + }); + + chartEl.addEventListener('mouseleave', () => { + if (mainChart) mainChart.redraw(); + }); + + // 4. Add expandable table + const detailsEl = document.createElement('details'); + detailsEl.classList.add('progress-details'); + detailsEl.style.marginTop = '0px'; + detailsEl.style.setProperty('--chart-color', color); + detailsEl.innerHTML = ` + + chevron_right + table_chart + Data Table + + + + + + + + + + + ${durations + .map((d) => { + const cur = currentCurve[d] + ? (currentCurve[d] as any).power || (currentCurve[d] as any).hr + : '-'; + const mx = maxCurve[d]?.val || '-'; + const mxId = maxCurve[d]?.trackId; + const mxIdx = maxCurve[d]?.idx; + return ` + + + + + + `; + }) + .join('')} + +
DurationCurrentAll-Time Max
${fmtDuration(d)}${cur} ${unit} + ${mx} ${unit} + ${mxId ? `` : ''} +
+ `; + cardContainer.appendChild(detailsEl); + + detailsEl.querySelectorAll('.evolution-select-btn').forEach((btn) => { + btn.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + const id = btn.getAttribute('data-id'); + const idx = btn.getAttribute('data-idx'); + const dur = btn.getAttribute('data-dur'); + if (id) { + document.dispatchEvent( + new CustomEvent('select-track', { + detail: { + id, + idx: idx ? Number(idx) : null, + dur: dur ? Number(dur) : null, + }, + }), + ); + } + }); + }); + + let lastNearestIdx: number | null = null; + + // 5. Render timeline chart + const timelineEl = row2.querySelector(`#${metricKey}-timeline-chart`) as HTMLElement; + if (timelineEl) { + timelineEl.style.position = 'relative'; + const timelineTooltip = document.createElement('div'); + timelineTooltip.className = 'timeline-tooltip font-m'; + timelineTooltip.style.cssText = + 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;'; + timelineEl.appendChild(timelineTooltip); + + if (xTimeline.length > 0) { + const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData( + currentDur, + currentRange, + ); + const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null)); + const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null)); + const dataTimeline = [xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]; + + const series: any[] = [ + { + value: (u: any, v: number) => { + if (v != null) return fmtDate(v * 1000); + + return '-'; + }, + }, + { + label: 'Value', + stroke: color, + width: 0, + points: { show: true, size: 6, fill: hexToRgba(color, 0.5) }, + }, + { + label: 'Trend', + stroke: color, + width: 2, + points: { show: false }, + spanGaps: true, + fill: 'transparent', + dash: [5, 5], + }, + { + label: 'Lower Bound', + stroke: 'transparent', + width: 0, + points: { show: false }, + spanGaps: true, + }, + { + label: 'Upper Bound', + stroke: 'transparent', + width: 0, + points: { show: false }, + spanGaps: true, + }, + ]; + + const labelEl = document.getElementById(`${metricKey}-timeline-label`); + if (labelEl) + labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}`; + + const optsTimeline: uPlot.Options = { + width: Math.max(100, (gridWidth || 570) - 400), + height: 250, + padding: [0, 10, 0, 10], + tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'), + cursor: { + points: { + show: false, + }, + drag: { setScale: false }, + x: false, + y: false, + }, + scales: { + x: { + time: true, + range: (u) => { + const min = u.data[0][0]; + const max = u.data[0][u.data[0].length - 1]; + if (min === undefined || max === undefined) return [0, 100]; + + if (min === max) return [min - 3600, max + 3600]; + + return [min, max]; + }, + }, + y: { range: (u: any, min: number, max: number) => [min * 0.9, max * 1.1] }, + }, + series: series, + bands: [{ series: [4, 3], fill: hexToRgba(color, 0.2) }], + hooks: { + init: [ + (u: uPlot) => { + u.over.addEventListener('click', () => { + if (lastNearestIdx != null) { + const track = tracksFiltered[lastNearestIdx]; + if (track) { + const stats = track.stats; + const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve; + if (curve) { + const entry = curve[currentDur]; + if (entry) { + const bestIdx = entry.idx; + const duration = currentDur; + + const startPt = track.points[bestIdx]; + const endPt = track.points[bestIdx + duration - 1]; + + if (startPt && endPt && startPt.time != null && endPt.time != null) { + const trackStart = track.points[0].time || 0; + const min = (startPt.time - trackStart) / 1000; + const max = (endPt.time - trackStart) / 1000; + + opts.onTrackSelect?.(track.id, [min, max]); + } else { + opts.onTrackSelect?.(track.id, null); + } + } else { + opts.onTrackSelect?.(track.id, null); + } + } else { + opts.onTrackSelect?.(track.id, null); + } + } + } + }); + }, + ], + draw: [ + (u: uPlot) => { + let idx = u.cursor.idx; + if (idx != null && u.data[0][idx] != null) { + const val = u.data[1][idx]; + if (val != null) { + const tpcx = u.valToPos(u.data[0][idx]!, 'x', true); + const tpcy = u.valToPos(val, 'y', true); + + const tctx = u.ctx; + const tdpr = window.devicePixelRatio || 1; + + // Draw lines + tctx.save(); + tctx.beginPath(); + tctx.setLineDash([2 * tdpr, 2 * tdpr]); + tctx.strokeStyle = hexToRgba(color, 0.4); + tctx.lineWidth = 1 * tdpr; + // Vertical line + tctx.moveTo(tpcx, u.bbox.top); + tctx.lineTo(tpcx, u.bbox.top + u.bbox.height); + // Horizontal line + tctx.moveTo(u.bbox.left, tpcy); + tctx.lineTo(u.bbox.left + u.bbox.width, tpcy); + tctx.stroke(); + tctx.restore(); + + // Draw hover halo + tctx.save(); + tctx.beginPath(); + tctx.setLineDash([]); // Reset to solid + tctx.arc(tpcx, tpcy, 12 * tdpr, 0, 2 * Math.PI); + tctx.fillStyle = hexToRgba(color, 0.2); + tctx.fill(); + tctx.restore(); + + // Draw center circle + tctx.save(); + tctx.beginPath(); + tctx.arc(tpcx, tpcy, 6 * tdpr, 0, 2 * Math.PI); + tctx.fillStyle = color; + tctx.fill(); + tctx.strokeStyle = '#fff'; + tctx.lineWidth = 2 * tdpr; + tctx.stroke(); + tctx.restore(); + + // Draw axis labels + tctx.save(); + tctx.setLineDash([]); // Reset to solid + + const d = new Date(u.data[0][idx]! * 1000); + const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`; + tctx.font = `bold ${10 * tdpr}px system-ui, sans-serif`; + const dateWidth = tctx.measureText(dateStr).width; + const xbw = dateWidth + 10 * tdpr; + const pillH = 16 * tdpr; + + const xLabelX = tpcx - xbw / 2; + const clampedXBx = Math.max( + u.bbox.left, + Math.min(u.bbox.left + u.bbox.width - xbw, xLabelX), + ); + const xLabelY = u.bbox.top + u.bbox.height + 2 * tdpr; + + // X Label Pill + tctx.fillStyle = 'rgba(14, 14, 16, 0.92)'; + tctx.beginPath(); + if ((tctx as any).roundRect) + (tctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * tdpr); + else tctx.rect(clampedXBx, xLabelY, xbw, pillH); + tctx.fill(); + tctx.strokeStyle = hexToRgba(color, 0.27); + tctx.lineWidth = 1 * tdpr; + tctx.stroke(); + + tctx.fillStyle = color; + tctx.textAlign = 'center'; + tctx.textBaseline = 'middle'; + tctx.fillText(dateStr, clampedXBx + xbw / 2, xLabelY + pillH / 2); + + const valStr = `${val.toFixed(0)} ${unit}`; + const valWidth = tctx.measureText(valStr).width; + const ybw = valWidth + 10 * tdpr; + + const yLabelX = u.bbox.left - ybw - 2 * tdpr; // To the left + const yLabelY = tpcy - pillH / 2; + + // Y Label Pill + tctx.fillStyle = 'rgba(14, 14, 16, 0.92)'; + tctx.beginPath(); + if ((tctx as any).roundRect) + (tctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * tdpr); + else tctx.rect(yLabelX, yLabelY, ybw, pillH); + tctx.fill(); + tctx.strokeStyle = hexToRgba(color, 0.27); + tctx.lineWidth = 1 * tdpr; + tctx.stroke(); + + tctx.fillStyle = color; + tctx.textAlign = 'left'; + tctx.textBaseline = 'middle'; + tctx.fillText(valStr, yLabelX + 5 * tdpr, yLabelY + pillH / 2); + + tctx.restore(); + } + } + }, + ], + setCursor: [ + (u: uPlot) => { + if (!(u as any)._ready) return; + u.redraw(false); + + let idx = u.cursor.idx; + const cursorLeft = u.cursor.left; + const cursorTop = u.cursor.top; + const bb = u.bbox; + + if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) { + let minD2 = Infinity; + let nearestIdx = -1; + const radius = 30; // pixels + const maxD2 = radius * radius; + + const xData = u.data[0]; + const yData = u.data[1]; + + for (let i = 0; i < xData.length; i++) { + const x = xData[i]; + const y = yData[i]; + if (x == null || y == null) continue; + + const px = u.valToPos(x, 'x', false); + const py = u.valToPos(y, 'y', false); + + const dx = px - cursorLeft; + const dy = py - cursorTop; + const d2 = dx * dx + dy * dy; + + if (d2 < minD2) { + minD2 = d2; + nearestIdx = i; + } + } + + if (minD2 <= maxD2) { + idx = nearestIdx; + lastNearestIdx = nearestIdx; + } else { + idx = null; + lastNearestIdx = null; + } + } + + if (idx != null && u.data[0][idx] != null) { + const track = tracksFiltered[idx]; + const cx = u.valToPos(u.data[0][idx], 'x', false); + const cy = u.valToPos(u.data[1][idx]!, 'y', false); + + const d = new Date(u.data[0][idx]! * 1000); + const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`; + + const val = u.data[1][idx]; + const valStr = val != null ? `${val} ${unit}` : '—'; + + timelineTooltip.innerHTML = ` +
+ Date: + ${dateStr} +
+
+ Value: + ${valStr} +
+ `; + timelineTooltip.style.display = 'block'; + timelineTooltip.style.left = `${cursorLeft! + bb.left}px`; + timelineTooltip.style.top = `${cursorTop! + bb.top}px`; + timelineTooltip.style.transform = 'translate(5px, -50%)'; + } else { + timelineTooltip.style.display = 'none'; + } + }, + ], + }, + axes: [ + { + space: 50, + stroke: '#555564', + grid: { stroke: '#2e2e34' }, + show: true, + font: '10px system-ui, sans-serif', + size: 30, + values: (u: any, vals: any[]) => + vals.map((v) => { + const d = new Date(v * 1000); + return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`; + }), + }, + { + stroke: '#555564', + grid: { stroke: '#2e2e34' }, + font: '10px system-ui, sans-serif', + values: (u: any, vals: any[]) => vals.map((v) => `${v} ${unit}`), + show: true, + space: 15, + size: 50, + }, + ], + }; + + timelineChart = new uPlot(optsTimeline, dataTimeline as any, timelineEl); + evolutionPlots.push(timelineChart); + + timelineEl.addEventListener('mouseleave', () => { + timelineChart!.redraw(); + }); + + // Range control moved to toolbar + } else { + timelineEl.innerHTML = '
No data for the past year
'; + } + } + }; + renderCharts(); + + return { + updatePin: (dur: number | null) => { + pinnedDur = dur; + if (dur !== null) currentDur = dur; + + const labelEl = document.getElementById(`${metricKey}-timeline-label`); + if (labelEl) + labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}${pinnedDur !== null ? ' (Pinned)' : ''}`; + + if (timelineChart) { + const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData( + currentDur, + currentRange, + ); + const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null)); + const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null)); + timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]); + } + if (mainChart) mainChart.redraw(); + }, + updateRange: (range: string) => { + currentRange = range; + if (timelineChart) { + const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData( + currentDur, + currentRange, + ); + const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null)); + const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null)); + timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]); + } + }, + }; +} + +function getWeekStart(date: Date): Date { + const d = new Date(date); + const day = d.getUTCDay(); + const diff = d.getUTCDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday + d.setUTCDate(diff); + d.setUTCHours(0, 0, 0, 0); + return d; +} + +function computeWeeklyDistance( + allTracks: TrackData[], +): { week: string; timestamp: number; distance: number }[] { + const weeklyData: Record = {}; + + allTracks.forEach((t) => { + if (!t.stats.startTime || !t.stats.totalDist) return; + + const date = new Date(t.stats.startTime); + const weekStart = getWeekStart(date); + const weekKey = weekStart.toISOString().split('T')[0]; + + if (!weeklyData[weekKey]) weeklyData[weekKey] = { timestamp: weekStart.getTime(), distance: 0 }; + + weeklyData[weekKey].distance += t.stats.totalDist; + }); + + return Object.entries(weeklyData) + .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance })) + .sort((a, b) => a.timestamp - b.timestamp); +} + +function computeWeeklyElevation( + allTracks: TrackData[], +): { week: string; timestamp: number; elevation: number }[] { + const weeklyData: Record = {}; + + allTracks.forEach((t) => { + if (!t.stats.startTime || t.stats.elevGain === undefined) return; + + const date = new Date(t.stats.startTime); + const weekStart = getWeekStart(date); + const weekKey = weekStart.toISOString().split('T')[0]; + + if (!weeklyData[weekKey]) + weeklyData[weekKey] = { timestamp: weekStart.getTime(), elevation: 0 }; + + weeklyData[weekKey].elevation += t.stats.elevGain; + }); + + return Object.entries(weeklyData) + .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation })) + .sort((a, b) => a.timestamp - b.timestamp); +} + +function renderProgressCard( + grid: HTMLElement, + allTracks: TrackData[], + type: 'distance' | 'elevation', + syncKey?: any, + onDateRangeSelect?: (start: string, end: string) => void, + gridWidth?: number, +) { + const isDistance = type === 'distance'; + const weeklyData = isDistance + ? computeWeeklyDistance(allTracks) + : computeWeeklyElevation(allTracks); + const accumulated = computeAccumulatedMetric(allTracks, (t) => + isDistance ? t.stats.totalDist : t.stats.elevGain, + ); + const color = isDistance ? Metrics.distance.color : Metrics.elevation.color; + const unit = isDistance ? 'km' : 'm'; + const icon = isDistance ? Metrics.distance.icon : Metrics.elevation.icon; + + const cardContainer = document.createElement('div'); + cardContainer.className = `chart-row ${type}-progress-card`; + cardContainer.id = `${type}-evolution-card`; + + cardContainer.innerHTML = ` +
+
+ ${icon} + ${isDistance ? 'Distance Progress' : 'Elevation Progress'} +
+
+
+
+
+
+
+
+ ${renderAccumulatedTable(accumulated, isDistance, unit)} +
+
+ `; + + grid.appendChild(cardContainer); + + const chartEl = cardContainer.querySelector(`#${type}-weekly-chart`) as HTMLElement; + const yAxisEl = cardContainer.querySelector(`#${type}-y-axis-chart`) as HTMLElement; + + if (!chartEl || !yAxisEl) return; + + chartEl.style.position = 'relative'; + + // Use inline tooltip style + const tooltip = document.createElement('div'); + tooltip.className = 'cur-y-val'; + tooltip.style.cssText = `color:${color};display:none`; + chartEl.appendChild(tooltip); + + const xData = weeklyData.map((d) => d.timestamp / 1000); + const yData = isDistance + ? (weeklyData as any[]).map((d) => d.distance / 1000) + : (weeklyData as any[]).map((d) => d.elevation); + + if (xData.length === 0) return; + + const yDataSmoothed = gaussianSmooth(yData, 2); + + const chartClientW = Math.max(0, (gridWidth || 570) - 20 - 320 - 20); + const width = Math.max(chartClientW, xData.length * 40); + const maxVal = Math.max(...yData) * 1.1; + + const mainOpts: uPlot.Options = { + width: width, + height: 150, + padding: [10, 10, 0, 10], + tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'), + scales: { + x: { time: true }, + y: { range: [0, maxVal] }, + }, + series: [ + {}, + { + label: isDistance ? 'Distance' : 'Elevation', + stroke: color, + fill: hexToRgba(color, 0.1), + width: 2, + points: { show: true, size: 4 }, + }, + { + label: 'Trend', + stroke: color, + width: 2, + dash: [5, 5], + points: { show: false }, + }, + ], + cursor: { + sync: syncKey ? { key: syncKey.key } : undefined, + drag: { x: false, y: false }, + points: { show: false }, + x: false, + y: false, + }, + hooks: { + init: [ + (u: uPlot) => { + u.over.addEventListener('click', () => { + const idx = u.cursor.idx; + if (idx != null) { + const item = weeklyData[idx]; + if (item) { + const start = new Date(item.timestamp); + const end = new Date(item.timestamp + 7 * 24 * 60 * 60 * 1000); // End of week + const startStr = start.toISOString().split('T')[0]; + const endStr = end.toISOString().split('T')[0]; + onDateRangeSelect?.(startStr, endStr); + } + } + }); + }, + ], + setCursor: [ + (u: uPlot) => { + if (!(u as any)._ready) return; + const idx = u.cursor.idx; + const cursorLeft = u.cursor.left; + const cursorTop = u.cursor.top; + + if ( + idx != null && + cursorLeft != null && + cursorTop != null && + cursorLeft >= 0 && + cursorTop >= 0 + ) { + const val = u.data[1][idx]; + const valStr = + val != null ? (isDistance ? `${val.toFixed(1)} km` : `${val.toFixed(0)} m`) : '—'; + + tooltip.innerHTML = valStr; + tooltip.style.display = 'block'; + tooltip.style.left = `${u.valToPos(u.data[0][idx]!, 'x', false)}px`; + tooltip.style.top = `${u.valToPos(u.data[1][idx]!, 'y', false)}px`; + tooltip.style.transform = 'translate(6px, -50%)'; + } else { + tooltip.style.display = 'none'; + } + + u.redraw(false); + }, + ], + draw: [ + (u: uPlot) => { + const idx = u.cursor.idx; + if (idx != null && u.data[0][idx] != null) { + const pcx = u.valToPos(u.data[0][idx]!, 'x', true); + const pcy = u.valToPos(u.data[1][idx]!, 'y', true); + const dpr = window.devicePixelRatio || 1; + const ctx = u.ctx; + const bb = u.bbox; + + // Draw lines + ctx.save(); + ctx.beginPath(); + ctx.setLineDash([2 * dpr, 2 * dpr]); + ctx.strokeStyle = hexToRgba(color, 0.4); + ctx.lineWidth = 1 * dpr; + // Vertical line + ctx.moveTo(pcx, bb.top); + ctx.lineTo(pcx, bb.top + bb.height); + // Horizontal line + ctx.moveTo(bb.left, pcy); + ctx.lineTo(bb.left + bb.width, pcy); + ctx.stroke(); + ctx.restore(); + + // Draw hover halo + ctx.save(); + ctx.beginPath(); + ctx.setLineDash([]); // Reset to solid + ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI); + ctx.fillStyle = hexToRgba(color, 0.2); + ctx.fill(); + ctx.restore(); + + // Draw center circle + ctx.save(); + ctx.beginPath(); + ctx.arc(pcx, pcy, 6 * dpr, 0, 2 * Math.PI); + ctx.fillStyle = color; + ctx.fill(); + ctx.strokeStyle = '#fff'; + ctx.lineWidth = 2 * dpr; + ctx.stroke(); + ctx.restore(); + + // Draw axis labels + ctx.save(); + ctx.setLineDash([]); // Reset to solid + + // X Label Pill + const d = new Date(u.data[0][idx]! * 1000); + const xValStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`; + ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`; + const xValWidth = ctx.measureText(xValStr).width; + const xbw = xValWidth + 10 * dpr; + const pillH = 16 * dpr; + + const xLabelX = pcx - xbw / 2; + const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX)); + const xLabelY = bb.top + bb.height + 2 * dpr; + + ctx.fillStyle = 'rgba(14, 14, 16, 0.92)'; + ctx.beginPath(); + if ((ctx as any).roundRect) + (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr); + else ctx.rect(clampedXBx, xLabelY, xbw, pillH); + ctx.fill(); + ctx.strokeStyle = hexToRgba(color, 0.27); + ctx.lineWidth = 1 * dpr; + ctx.stroke(); + + ctx.fillStyle = color; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2); + + ctx.restore(); + } + }, + ], + }, + axes: [ + { + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + show: true, + space: 40, + values: (self, splits) => + splits.map((s) => { + const d = new Date(s * 1000); + return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`; + }), + font: '10px system-ui, sans-serif', + size: 30, + }, + { + stroke: '#555564', + grid: { stroke: '#2e2e34', width: 1 }, + show: true, + values: (self, splits) => splits.map((s) => `${s.toFixed(0)} ${unit}`), + font: '10px system-ui, sans-serif', + size: 40, + }, + ], + }; + + const mainChart = new uPlot(mainOpts, [xData, yData, yDataSmoothed], chartEl); + evolutionPlots.push(mainChart); + + const scrollContainer = cardContainer.querySelector('.chart-scroll-container') as HTMLElement; + if (scrollContainer && xData.length * 40 > width) + scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth; + + return { + updateRange: (range: string) => { + const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000; + let minTime = 0; + + if (range === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000; + else if (range === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000; + else if (range === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000; + else if (range === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000; + else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000; + + const filteredData = weeklyData.filter((d) => d.timestamp >= minTime); + + const newXData = filteredData.map((d) => d.timestamp / 1000); + const newYData = isDistance + ? (filteredData as any[]).map((d) => d.distance / 1000) + : (filteredData as any[]).map((d) => d.elevation); + const newYDataSmoothed = gaussianSmooth(newYData, 2); + + const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40); + const newMaxVal = Math.max(...newYData) * 1.1; + + mainChart.setSize({ width: newWidth, height: 150 }); + mainChart.setScale('y', { min: 0, max: newMaxVal }); + mainChart.setData([newXData, newYData, newYDataSmoothed]); + + if (scrollContainer) + scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth; + }, + }; +} diff --git a/suites-experimental/tools-gps-tracks/src/url-state.ts b/suites-experimental/tools-gps-tracks/src/url-state.ts new file mode 100644 index 0000000000..3124066660 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/url-state.ts @@ -0,0 +1,202 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +// ── URL State ───────────────────────────────────────────────────── +// Handles reading/writing application state to the URL. +// Uses an incremental "patch" approach to preserve existing params. + +export interface AppState { + track?: string; + map?: string; + xaxis?: string; + metrics?: string[]; + f_date?: (string | null)[]; + f_dist?: (number | null)[]; + f_dur?: (number | null)[]; + f_mets?: string[]; + f_tags?: string[]; + q?: string; + re?: boolean; + sort?: string; + map_pos?: [number, number, number]; + storage?: 'memory' | 'indexeddb'; + sel?: [number, number]; + sel_point?: number; + tab?: string; + progress?: string; + speed_mode?: string; +} + +export const UrlState = (() => { + // Internal state object, initialized from current URL. + let _state: AppState = {}; + let _lastSearch: string | null = null; + let _syncTimeout: any = null; + let _shouldPush = false; + + function read(): AppState { + const p = new URLSearchParams(location.search); + const s: AppState = {}; + + if (p.has('track')) s.track = p.get('track')!; + if (p.has('map')) s.map = p.get('map')!; + if (p.has('xaxis')) s.xaxis = p.get('xaxis')!; + if (p.has('tab')) s.tab = p.get('tab')!; + if (p.has('sel_point')) s.sel_point = Number(p.get('sel_point')); + if (p.has('speed_mode')) s.speed_mode = p.get('speed_mode')!; + if (p.has('progress')) s.progress = p.get('progress')!; + const metricsRaw = p.get('metrics'); + if (metricsRaw) s.metrics = metricsRaw.split(',').filter(Boolean); + + if (p.has('f_date')) { + s.f_date = p + .get('f_date')! + .split(',') + .map((v) => v || null); + } + if (p.has('f_dist')) { + s.f_dist = p + .get('f_dist')! + .split(',') + .map((v) => (v ? Number(v) : null)); + } + if (p.has('f_dur')) { + s.f_dur = p + .get('f_dur')! + .split(',') + .map((v) => (v ? Number(v) : null)); + } + if (p.has('f_mets')) s.f_mets = p.get('f_mets')!.split(','); + if (p.has('f_tags')) s.f_tags = p.get('f_tags')!.split(','); + + if (p.has('q')) s.q = p.get('q')!; + if (p.has('re')) s.re = p.get('re') === '1'; + if (p.has('sort')) { + const v = p.get('sort')!; + const isDesc = v.startsWith('-'); + const field = isDesc ? v.substring(1) : v; + s.sort = `${field}-${isDesc ? 'desc' : 'asc'}`; + } + + if (p.has('map_pos')) { + const parts = p.get('map_pos')!.split(',').map(Number); + if (parts.length === 3 && parts.every(isFinite)) + s.map_pos = parts as [number, number, number]; + } + + if (p.has('storage')) s.storage = p.get('storage') as 'memory' | 'indexeddb'; + if (p.has('sel')) { + const parts = p.get('sel')!.split(',').map(Number); + if (parts.length === 2 && parts.every((v) => !isNaN(v) && isFinite(v))) + s.sel = parts as [number, number]; + } + + return s; + } + + // Sync _state to browser URL synchronously so no pending timer leaks across steps + function _sync() { + if (_syncTimeout) { + clearTimeout(_syncTimeout); + _syncTimeout = null; + } + + const p = new URLSearchParams(); + + // Add standard encoded params + if (_state.track) p.set('track', _state.track); + if (_state.map) p.set('map', _state.map); + if (_state.xaxis && _state.xaxis !== 'time') p.set('xaxis', _state.xaxis); + if (_state.tab && _state.tab !== 'graphs') p.set('tab', _state.tab); + if (_state.storage && _state.storage !== 'memory') p.set('storage', _state.storage); + if (_state.sel_point !== undefined) p.set('sel_point', String(_state.sel_point)); + if (_state.speed_mode) p.set('speed_mode', _state.speed_mode); + if (_state.q) p.set('q', _state.q); + if (_state.progress) p.set('progress', _state.progress); + if (_state.re) p.set('re', '1'); + + if (_state.sort) { + const parts = _state.sort.split('-'); + const field = parts[0]; + const dir = parts[1]; + p.set('sort', (dir === 'desc' ? '-' : '') + field); + } + + let search = p.toString(); + + // Add comma-separated params (literal commas for cleaner URL) + if (_state.metrics) search += `${search ? '&' : ''}metrics=${_state.metrics.join(',')}`; + + if (_state.f_date) + search += `${search ? '&' : ''}f_date=${_state.f_date.map((v) => v || '').join(',')}`; + + if (_state.f_dist) + search += `${search ? '&' : ''}f_dist=${_state.f_dist.map((v) => v ?? '').join(',')}`; + + if (_state.f_dur) + search += `${search ? '&' : ''}f_dur=${_state.f_dur.map((v) => v ?? '').join(',')}`; + + if (_state.f_mets) search += `${search ? '&' : ''}f_mets=${_state.f_mets.join(',')}`; + + if (_state.f_tags) search += `${search ? '&' : ''}f_tags=${_state.f_tags.join(',')}`; + + if (_state.map_pos) { + const val = `${(+_state.map_pos[0]).toFixed(5)},${(+_state.map_pos[1]).toFixed(5)},${ + _state.map_pos[2] + }`; + search += `${search ? '&' : ''}map_pos=${val}`; + } + if (_state.sel) { + const val = `${+_state.sel[0].toFixed(4)},${+_state.sel[1].toFixed(4)}`; + search += `${search ? '&' : ''}sel=${val}`; + } + + if (search !== _lastSearch) { + const url = location.pathname + (search ? `?${search}` : ''); + if (_shouldPush) { + history.pushState(null, '', url); + _shouldPush = false; + } else { + history.replaceState(null, '', url); + } + _lastSearch = search; + } + } + + // Initial read + _state = read(); + + function get(): AppState { + return { ..._state }; + } + + function patch(partial: Partial>, push: boolean = false) { + if (push) _shouldPush = true; + for (const [k, v] of Object.entries(partial)) { + const key = k as keyof AppState; + if (v === null || v === undefined) delete _state[key]; + else (_state as any)[key] = v; + } + _sync(); + } + + function refresh() { + _state = read(); + } + + function reset() { + if (_syncTimeout) { + clearTimeout(_syncTimeout); + _syncTimeout = null; + } + _state = {}; + _shouldPush = false; + _lastSearch = ''; + history.replaceState(null, '', location.pathname); + } + + return { get, patch, refresh, reset }; +})(); diff --git a/suites-experimental/tools-gps-tracks/src/utils.ts b/suites-experimental/tools-gps-tracks/src/utils.ts new file mode 100644 index 0000000000..616087824f --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/utils.ts @@ -0,0 +1,139 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +export function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number { + const R = 6371e3; // Earth radius in metres + const phi1 = (lat1 * Math.PI) / 180; + const phi2 = (lat2 * Math.PI) / 180; + const deltaPhi = ((lat2 - lat1) * Math.PI) / 180; + const deltaLambda = ((lon2 - lon1) * Math.PI) / 180; + + const a = + Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) + + Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + + return R * c; +} + +export function compactId(timestamp: number): string { + // Use a compact representation of the timestamp (seconds since epoch) + // 1712650000 -> Base64 + const buf = new Uint32Array([Math.floor(timestamp / 1000)]); + const b64 = btoa(String.fromCharCode(...new Uint8Array(buf.buffer))); + return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); +} + +export function generateId(): string { + return Math.random().toString(36).slice(2, 10); +} + +export function shortRandom(): string { + return Math.random().toString(36).slice(2, 6); +} + +export function fmtDuration(s: number): string { + if (s < 60) return `${Math.round(s)}s`; + if (s < 3600) return `${Math.round(s / 60)}m`; + return `${Math.round(s / 3600)}h`; +} + +export function fmtSecs(s: number): string { + const h = Math.floor(s / 3600), + m = Math.floor((s % 3600) / 60); + return h > 0 ? `${h}h ${m}m` : `${m}m ${Math.floor(s % 60)}s`; +} + +export function fmtPace(seconds: number | null): string { + if (seconds == null || !isFinite(seconds)) return '--'; + const mins = Math.floor(seconds / 60); + const secs = Math.round(seconds % 60); + return `${mins}:${secs.toString().padStart(2, '0')}`; +} + +export function fmtDate(ts: number | string | Date): string { + const d = new Date(ts); + if (isNaN(d.getTime())) return 'Unknown date'; + return d.toISOString().split('T')[0]; +} + +export function fmtDateTime(ts: number | string | Date): string { + const d = new Date(ts); + if (isNaN(d.getTime())) return 'Unknown'; + const iso = d.toISOString(); + return `${iso.split('T')[0]} ${iso.split('T')[1].slice(0, 5)}`; +} + +export function fmtFileSize(bytes: number): string { + if (bytes === 0) return '0 B'; + const k = 1024; + const sizes = ['B', 'KB', 'MB', 'GB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; +} + +export function escHtml(str: string): string { + return String(str) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +} + +export function getTagColor(name: string): string { + let hash = 0; + for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash); + + const h = Math.abs(hash % 360); + return `hsl(${h}, 70%, 65%)`; +} + +/** + * Smoothes a numeric array using a simple Gaussian kernel. + * sigma: standard deviation (radius of smoothing) + */ +export function gaussianSmooth(data: (number | null)[], sigma: number = 2): (number | null)[] { + if (sigma <= 0) return data; + + const size = Math.ceil(sigma * 3) * 2 + 1; + const kernel = new Float32Array(size); + const half = Math.floor(size / 2); + let sum = 0; + + for (let i = 0; i < size; i++) { + const x = i - half; + kernel[i] = Math.exp(-(x * x) / (2 * sigma * sigma)); + sum += kernel[i]; + } + for (let i = 0; i < size; i++) kernel[i] /= sum; + + const result: (number | null)[] = new Array(data.length); + for (let i = 0; i < data.length; i++) { + if (data[i] === null) { + result[i] = null; + continue; + } + + let val = 0; + let weightSum = 0; + for (let k = 0; k < size; k++) { + const idx = i + k - half; + if (idx >= 0 && idx < data.length && data[idx] !== null) { + val += data[idx]! * kernel[k]; + weightSum += kernel[k]; + } + } + result[i] = weightSum > 0 ? val / weightSum : data[i]; + } + return result; +} + +export function hexToRgba(hex: string, alpha: number = 1): string { + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + return `rgba(${r}, ${g}, ${b}, ${alpha})`; +} diff --git a/suites-experimental/tools-gps-tracks/src/vendor-fit.ts b/suites-experimental/tools-gps-tracks/src/vendor-fit.ts new file mode 100644 index 0000000000..458a369e0d --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/vendor-fit.ts @@ -0,0 +1,6 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FitParser from 'fit-file-parser'; +export default FitParser; diff --git a/suites-experimental/tools-gps-tracks/src/zones.ts b/suites-experimental/tools-gps-tracks/src/zones.ts new file mode 100644 index 0000000000..a2d79a4298 --- /dev/null +++ b/suites-experimental/tools-gps-tracks/src/zones.ts @@ -0,0 +1,60 @@ +// Copyright (c) 2026, Camillo Bruni. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +import { Parsers } from './parsers'; + +export interface ZoneRange { + name: string; + min: number; + max: number; + color: string; +} + +export const Zones = (() => { + function getPowerZones(): ZoneRange[] { + const ftp = Parsers.getFTP(); + const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp); + const names = [ + 'Active Recovery', + 'Endurance', + 'Tempo', + 'Threshold', + 'VO2 Max', + 'Anaerobic', + 'Neuromuscular', + ]; + const colors = ['#82E0AA', '#A8C8A0', '#F7DC6F', '#F8C471', '#F39C12', '#E67E22', '#C0392B']; + + const zones: ZoneRange[] = []; + let last = 0; + for (let i = 0; i < thresholds.length; i++) { + zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] }); + last = thresholds[i]; + } + zones.push({ name: names[6], min: last, max: Infinity, color: colors[6] }); + return zones; + } + + function getHRZones(): ZoneRange[] { + const thresholds = Parsers.getHRZones(); + const names = ['Recovery', 'Aerobic', 'Tempo', 'Threshold', 'Anaerobic']; + const colors = ['#82E0AA', '#F7DC6F', '#F8C471', '#FF6B6B', '#C0392B']; + + const zones: ZoneRange[] = []; + let last = 0; + for (let i = 0; i < thresholds.length; i++) { + zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] }); + last = thresholds[i]; + } + zones.push({ name: names[4], min: last, max: Infinity, color: colors[4] }); + return zones; + } + + return { + getPowerZones, + getHRZones, + }; +})(); diff --git a/suites-experimental/tools-gps-tracks/test-data/activity_1_alps_stage.gpx.gz b/suites-experimental/tools-gps-tracks/test-data/activity_1_alps_stage.gpx.gz new file mode 100644 index 0000000000000000000000000000000000000000..cd3428df6debed5d5f877b0c2da8faa2d0df37c8 GIT binary patch literal 42206 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 Bf4~3$ literal 0 HcmV?d00001 diff --git a/suites-experimental/tools-gps-tracks/test-data/activity_3_road_race.tcx.gz b/suites-experimental/tools-gps-tracks/test-data/activity_3_road_race.tcx.gz new file mode 100644 index 0000000000000000000000000000000000000000..9060c68ff22b20e053f521637d3fe25777e38960 GIT binary patch literal 39528 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 V`^uH@zxzk-zUz~A>1F%x{{ZO;B=`UT literal 0 HcmV?d00001 diff --git a/suites-experimental/tools-gps-tracks/test-data/activity_5_grand_tour.fit.gz b/suites-experimental/tools-gps-tracks/test-data/activity_5_grand_tour.fit.gz new file mode 100644 index 0000000000000000000000000000000000000000..18c520009cb29887be4abab2f7336bd22ee15712 GIT binary patch literal 36301 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 Z*OulTKNCRdR#=qi{{X<0!^4`n002aXgBAb) literal 0 HcmV?d00001 diff --git a/suites-experimental/tools-gps-tracks/test-data/activity_6_weekend_ride.fit.gz b/suites-experimental/tools-gps-tracks/test-data/activity_6_weekend_ride.fit.gz new file mode 100644 index 0000000000000000000000000000000000000000..1a0b5fbed85cae0668abbafb081115d94e4a3c1c GIT binary patch literal 27953 zcmW)nbyySL+s0L-y9NV+jqdJdBSuS02!hl|X=&+((J9CnC8BgmNXcj!UHSz^gGh(O z>+d~(pSsSup6fi%{kacI62YVYwI?__D*z+RfDpqRy zEH6|!xgyrMec-?d{d)=M~wGPFXJTTA!4j2h<{@W<>8p|3c|{S~S|& z%5*iFhW9FdyWpOjRtkEog6%zWR#j2tayYwB%+KnR!W+O@B5*x_Z4KmYog~Z*U94|) zJNzEc-DPfxnS_QGB`5n*u$BDid7n)zp-s!31L;OYU*2Z3m5zbNC#y+VEf{{19mkES7j!Abh?W^=&ogVCZh9uxD^_ z6?ji6o;E{xdN9*q|5bIzx77SIOBy3Tv$%xr&)&z9X57TtF2t6?Y{)XTf;X^_IFa7` zFzN^1DY+@8bj~M+3bTWaou&L%ANl+_DQi>bAgqHV5YqehXCp{d0V_|+PJ=!YbXw6S zeaAFnS3WqH4UK1gO@eSnYh+r5^edGfh*WpiDJ1PQ(-TtR1QNs5SI8Z@$_Ldr0#%b< z%T{-|MlXoVny;GG8V#+dt)5zijFdf}Gy5pyA;5k!l^a1S8j_myMXX@a$PnrUAxsyX zW1+$)EZ$nzY{*yOo28TJ(L3{XGef^d;1XMfbw&=2 z+)wbw1k!hBk@5x`>ugcu2ej3;++EtfAk&BeXhu%kTk@oQ4i&9mTpa*D*?K8^G1>e2 z=VFaz9_}o*z~v6*8|8}$|KsG}jyZ(&;jtZyss%$}Ibn9{F~=M(2{Lz}w(+Zdyj|k! zPjiDd@#2lF)nU#dxD|N<6c}<$>C|8)(xV?y=<~#&S*Vq3zz$Mtrt&kRAhDcBmC;QB zqz}1=kai#1IhLVf`$l$EA4A7UEH4PUD)yRiBc zF~F^(lQjzHoAX0?BsQ1lsc{Dq{`*6PU7i*62%{gF(1nYn9_giGCNZxsGEZf zC;^$GW;DHj#}(737_kho%JX0(p(HswVMeUD*>k-@?I4dml)aUR6xSBgJ!g^Ln!O->~>8oN`7AvliQ_QGGHaoO;7>;@h3YrPT_1G?l!+SwK0~0)P4zfco~E;k&116`Q~+2CCuR|JM(#6 z2>y7-%p@~E@kZgm`qf3fGlwxnm?TyZQ-mor|77Kv>p`9U{U8FX+@hkWsvSJq49^Zo zxEXYdz(NY9@O$iNiXo&+58w`#F6Im_(+w}Wqusc+C~vKMjwQ-2;tcYHfxNI}gSY0^ zMRSRyAv$N0u*aw)13IO&DZO-8L+UqzZ+U}c{N`z{o}jE%-p$ky9}j(I6AXJaJDlZe zR6xpmBjIJKgDzkVm?sc`8i4gH=EwjuBKK+bUvx6H|-MZzKrhw(hqWE&enq7c;LA$9~P4+gIrX=ky8vyb%61{H~ z;@y-lvw1z7tzgn55h7y$)EQ(dKf z^$ab?`XAey_hEfwEoc+XTK#Hgn+0Dq3@!cibLaNBTduqi&zcNv7o#aY5SPcl<1ISL zvBjo1bLKWOF|zL&VhTY_09T+MKd6(JOYcD;k3O-s27s>#xMg@8=Mu$Jb4||b{W!4- zFyJ01N8#e+$w6;c{BeDvMQ)-vccql~=}04$wvn;#3hT{HDD2CiAajwUW6!V;UhATX z_#ErV^&?Tz-oJEMf3@QG_LIg2O%9TNM&Sh4a9KTgyW^bTB>hT88L}jh7RwgzA_zES zbo4hXE~c^hfYgLEL9ETflf#1(-4Fc4f}aKeYO2V;sE_D_@)zD#(B$Q-=NEI68coTZ zLeP~6Z!G+oqa&w7koRUGZ-G-W`85fZIB|QIqhp4sKy_$zqP6&BRES`tAclnA-ElR$ zT9c#9_{_|i+MdMzO>>eGeZuBv9X)uczM4&R;>vf({Wsfn@W4kMUCpcKYJsIT%HLHg zkX~k-y2B;sYKbTq4SUvKucEcm{nYmNnvAZK_rlb)j65 z_^R#Kpz8>QP?lEkCKc^D=@LmkCmFTP*Qwj zU6;#mG*$Y|6C|ce@GEuNj+QmSF#YFEOyU+kbL?1jXWR;4LaH$>YXnSKV=T^JhbyW* zrs1~0$T)T&<`Cj|YB2-)qk(oqd#T2R?~S_^8Rid4y*k7%F7+r_>=uUaL<+;7Pg3R< zF$pS$ROhFdjfgT8nqWzmmIu%*@Qs)bl#MV3?c zZ{u{f|HSQ!cX*8};WCj~hUwES_@fHnaH^@M9cq&%tz8|-9NbbvdlC(w2tu}?WdGS8 zj|N2xmCILdTG9^UTSf7|3+Z`Q>Rgy_0$nGssVdY5Bz}t(zw4H49Mm#TJ*`S)zW()& zp9oqzP$3lcdS7rdtqa#D!4F`S}$h=WZ( zYLBuFAy?>70b2fdWu$iA?aiR}M%hDRr&V{P?MX)|Yh@3hT?VWx&2tyG(xR;8XJ@uW>%~G$7x~IjRD@at{DaXc>7>Eu$f-_)u7V2TbU?W39PI8fLjClI&dQsLA@nYuf++F zBsZ8I1&1M4k$6s4@`D_vb67}mZN(xOi5IMDW8-^V*poOb%`ur?Sy2MLFaNyPWoPOC z_3C`o@giHa_FdwPJzz+ZX3wb&77aaxN7sFwcPd=|PoF@@TOrIWjR%?2O5nSV~L;T3v)ZP~4{5nZ3Xc!NN zk|~n~3J-?Sf!!^vZ@;=&*mlRn+zZ$XVh((ggr&viuN7r~-pXM=ybzs#c}w6@r<`BR z7y7Bf?5YF-W&Nxma5lN5(!~)VthdzP5SJ0*LcM z0V6aOU*@Nq8Y%57>dSAjPl*=sayZ=Cx}P6E@Nw|RE2*sjn$}M;#aaDc+ams) zzc@6q!XF3Kwcgi6lOsw?J?`g@>^yz#e>{;Gj7xagX!7)kUh4Aax8|2#Bs{gI)2b!6 z1m?CrK4C0oq2;_~?jo^@ItK+@1DKGpaf$Gx&}G|JsVW{>tD+}ikxlZuTTv_p=JgGr zu7A<>x{n;9m$-kn;c-6{?wC_)Tt4*W`E>dpQiKsjqTi`5LZ_T}{JOj#l2sBC2B7Ad z7&qIO(Kh;cfMJkGNnUs=BcR6^y3*M|J+$bM-sRm@;IA4&daagBK5~47UQ~97=n7@q z(qqRs$B-D6^!9`!yMBQu>9W+SIV@+hc&rYo=-8U}dV3r%ni{yv&t0FUp=l{vuj;CD z3)8NL#%_3tGpYS+cD3x;2G}NE8h9}KOpXQdHdl`exCF_&NDL6?KRev=OB>_2sMcJ= zpAnb*2=E4+kO!Qy&wTr6%q2%w4Y$dX9=_+@(nJ&<&AkC2XV|AGC3cZ&1(Ily#qo3X zi6D^fu9pPq_ww4pn<8mjytejK>CEiG1b3y6aK|R;yJ9*pdHXTG<5uMi=aPQ)?q6rG zjIKx3hrhRM$~-K}1=~02B!G4RXc+Zl@gL)>0b>U??TRu#%PJy7ka%>18rl$+h1IG(Z_)dl z{Y;DHS#d>wS*$*6Sj>aj^S=X)b`hSnmV&v#MDNcK|Spxe@>vC znjRmz_VHJ?7R^(7o;kwl!8#A#7CB<N}zrh>bWdpmZ=b*4i!zOmLD%33Xv z^*nZb|O8jACFv#r2&oKP810s3Ntpo zI`5#q$c87ChBMH{jH#DS{ARf6--=$LEaCV7Ekf{cYY@%+P$=B__!ZIUe8K5!7qfz} z0wTdLi}GkL2d>w6q<#%c|JCt;xok5St`E?B6;iZ}J{xKZVcE=zcI6h<)5#6Lw<&<{ zTm@ibv*x%-kK1I?I9^_%fKr0#2frEF-ip#XX)lf-?nrQli#T2zg@p6(>e4^bBEu{R z3bKpiUqQM#D|vl?ozYaS%qL$6)XY8ZsVlsB2d4C)y^MiC+;O$VZmWwg^x#q3AdbX`g5XwDY{wnn(1vFe2m5)Q%1yG8rofgZ%1JayQoJ zjG$OLkvqz^WbaV*;MCaIh3*)7u#_;gxKGq*G$o${mtoI=dTrt9T2=35)iO>sxUBgF zl(Voc>Pn>p_4V2W{mU>^y-%3*WxN8>?ju|0U5n_seN4uuEh&j61yj^6flN}4-gopJ zSYUX|)79D3jSrRSoVGeX%OowwHR~Xw4zJ?A;DR~9#IR2QvBZ#ahQuV=04Bl{CM<>H zx+d22rZo2VP`q3`Nuc7?xJ|F9oS?uk{I4n$-);g*gEm7DQaQz;I07$3s#L~kVRUG9 z?1i=2#D!*apn${9d;0p}fS4B|OC@aMdewqLVV$u-1M!TyQs@RL5$~#HK(*k!4B=}A z0hb?4qAlq0hd$YtU^Jm!%&qkBcu6mJa>mERLq_o#F^Ie; zVbp<2fe;1H&&VdXxgU#vCO-aV086IW1U!W)`AOf$tNK~>5-?s(uD7~6`?tLX&^!(# z1^Png1~Hwb6Ym*<1g+$A5@@C$phfD!-vTk6tne?fpQC|;nH=@@-#e~9DLkbI9q*k?xUA# zwX=C^Qed(YWDF%WoidS(r(=2`@z0OI6d|KcNjc01p~cb!2`j?fgqTmrtrBtHc~ zf0eobX|z1oIMax}t8=@WyyzYwFhYEJT{>8+!2IA1oO_jZX_^=lnpJq&>@}xfU=DMV zI1{2H4_pVASqGeMAbw&FkQg5Zi~d31T>(H)MB!0ra$_+j8QJnnJZtjbqKXKy7xY4^ z-T=OF{stS!JFHzDbDVsBoGy~f$pAC6o}(mj)@-h`&`r_)ba_UMz#lDe9~=8qGD+jr z9Vi^sD)iUOF};FL&eN7PKa@NZ!~#+cKa+NHglk3k;#2b&>!7&6EM*=Jq0+=T6||;5 z=bx)pp$~ZsaL|8VOgt&CRy!n@ID1?5_SI<<0iu8PwwTt59d4*X2;Vh~&l{OkX6{Go zs`dC~R?xJ#G|kYn0=_pQc$>JI>6~7ohH(jl1U9cQ@?2Yb6@{Lu-`a^VZkP<3NZcyg zlY*PTTRE0m7jd6C^Mb5NIruKD?#0XmPQPtg)HcXw|lbTFtD!*GH6SI5du?_L-}S3_{Nx(o{PrU9sOsLFcaX%a%Q z>Th_SA71?Gr*fbQ-2fX0I_^vRbrMCFasIsBY=**4&Rf(|V46iP5>IwUK+#ZJA@XyQ zh8F8vW#(%X>pZZm+$UmP^K2CHv#K{zcp}d@pG~2nTq0s!@QetnQQl>-XWrAFs>J5%+$ z<#3Azyl3xF&|>JqgMwyq-@;i7*h2JaeE$Fi?3|!zYIb|YtQUYcMHjo# z)HGsKWR^5&P70@LQ2Rq)h^_j8aSZq3VI*o#B3veXPakVBttxPMYV(vQ;@S5nO`uj7 z+{$j3Mxgm7iTu(gN;UkyEjqA>p}F_6ufY3DI<7@qgy_M?2c$xp=4Qghzth_n`YiP& zDHGR!_8eF=ScWG+Cg4X#VHPh1A_u1lzev+|NH`{LqM-)q^>{*lvqk5E#xtuT8ZESi z{@P31<46{_`A!sP^JbuA1xU#$($s%OTHVf!d(y4h@tSa&NIJs{gvJT#yFyamMWzQE z@G`FajK-yZ#}|F$4kK;J71EXt#%&ffFD);5@(d9Gs;TF24~c4IuMT;$pKB3B1Nu$P zHb_(WZhw2f%~(4-fzb8&zOq*dJubX(Yb&j%-yF~7M<;Wy@N=sKb*QOq9XNT5pALS- z8QrApRS<4ggzMOL{eJR|V=gDVOp6O#<3rnR7gyi0j#T(P&V+R)FBLp4$Kz>YM>d30 z-~TkVOqx;9ggy87oS{9Us`sy5H+bA&#vNrW(^jjd4UJNjVNo74TD`4rmEp_gR9twqiIH=t)SzhQY;BH z*yA;)DU3Sf{m>NVKL#`x;9SG+vQ@{`k%;L#`OCbKntWP_K7D-^6Jp4=l;h~)n zcl0IMuVs8bcpUaP^YGitV0~cBTg&@K(w5x1x&p_}yYCSa2oc00%xLXftzJRK(oIc{ zWNgS|AaVUGW~=y4;zS0_y11rTww2YIW zlWRE~ew&!H6_>a&0@e`zC2QioA;uf4 zx126rbj^ZYDL>#p9|6g$2YG(ec>e{!mwvnKwgs}-KSBBC6tWbKFB-r*R_~Ry9q%RV zSy5r#g`Vco?Ky0mhPY6QT*~(h^xj;sP=yAW(vGSsq*^UmT{;!()Pni5>b;%uxKq#`vI__2LtPc^!P)YZp>qnvQg@i_GLK3E0)5$>+ z2&JB0o{5Ay@J7R#XxW4TIk*{N^p$e12kRDXRcMoe=9Wq{emRpg`1@93qV2q>i_46z zsY2K#SyW{YR3_CH7;v`3}W=?gSg}Q$;dK4L=f72Mu6&0 zlCaMQn3C*>z&i#ji*X*96^&=P5Bt3`zH{?dWPVICg(Y+lKHN7>j(54rxMuAWFaNX`=U2~ap%EokI2PHOqw{{5 ze&??4ClZ7f6=@Lg_`Q<6nJRCoE+V^@xoP(`+Dd&@YE(P+d#;`0cRXd&_z%J8aUZbU zW-RM=Tyk-$n!=1teC97gDVA8pCH!4|rvW;-0Vy zL!@*5X0T6NI8HAFYP-Z^vW}$3LOdJ%43211parh5%rfy!jEMTS`#e}+y)nIKdx)BIQch(!M^;+-NoL_gD2i=MgxD*zc_qq5t{f7LI^Si@m zSP*v04=p>PXvEM^o|Fu6^FV`Pz3x&+?;Irc;A0;<2X;IT$Pq^%KZH7oCI{+HzlrOD z4sGi-5*uyzj*CZIRLeuyf+3jZq-#NLxPOvOTE}Ql%+gcjSE1X>8I6GNOmaxz-IGw z5pq<*YQ&c{#yzx<_v)Fud5Z1sSf4SY3IEA|kryBEw6ht$c4emet4cw`sJ26t$d8gQ zK0OCiHlt-3sJj5(R2fz0f6|ww{~A`e3r&@5YU7FkB^vkpTLSnpmS2o3jSKw5SwB*qB<0ONtkDESHj--T zdVe+1kpD>Ntse6Ef`Ty;zmgB8iJG`Pv7l?#wlbGs4kLiKa3^J0zV;R8^9Bx(UPlIA z8Jta+Iv8m6y_VIAw|aUUpN7v2mVUP7CWn%-)(BUdfp#J)MV2Ox-k2I~ah-I_T2M|s zk|7rPm!1j}$z|gXr*ipaF|9@463M(e`2)0+SuP*bMmhPRk|;Kt63(Zm`nBsf4@^Je zeKIYqXAQI$o}oQiN&X?OTtwjT@vtldlO(mb!PAhYvrC1dW^NxmxoKaToy=cg zp+ti}!=3CrP>r}xvk0XDIP>eEw~dH)&Fn?l8?-Erw>|ge>@sUMxb5;@K4hD73M_^%)l*(()JX)iqSnSUk_lNVen;L#F7$b1R)muTk~NP{@l|U+Ddcj{rnx5 zoc0Oh{jCR-nRXW5%TBTkuK=0r0Bj6BIr&Xaqx(n``(J6MRU%rPTRL_`@YNE_0JgAr z!7w6$hL`i&-OKx(?>jfs3eB^m|*Hw8r0igK}`Dd4o zb0q1GJ3ECGBEv@zNKo)qP2T-})-X?Y<5U;e?(xs4+aJV-@Xhs@$R_`|)PHD`uw6*- z+vMA;LugTGxsINI`G+#sUL@Xwa`(Z;+Lu>1;iWn-c&m@qL{vydueHc=mDu{O&eaoj< zeQ>nakEqbA)(QBeTt~b_bggd%D?a&SjbLyHVF-<>e%3?^*<->fdHb_}qs6C1xtiXv z1MiTKYMz_c9ugTBpaLtbOxE|b{8APd!J5M0?T?6KQTJ#}|K6>sfsd00sXHb+$X;Kw z9{UI!xk}Edl`UXdAew@F<_NwDn+ZxZRAdi}OO3@1(|*|uiTwz?4;5eNzx=>V{SSRk ztXBQY#mja;WuTH*+Pr4GqUE8o82sYs9k3(zngafvd(%7{-xo_tVfRit_HD@aVp?`$ z@&%ND^6`3sL-c`~M=#&sbAG_kWM`;%U0>|D^Z(0^qEcNpR&eL2nx zO17-TqG)PaEy6cYS>^ST(?4$fd-LG&N?#flkcTD{m``LY%-OTvFlT&nr^@o142)~a zI{Dy<+rsro+p{3={|!dL_byjT^ismtXQfQsFGlzZ*x@xia-n%U;J@AOYQjwE3l%k$O=RV9SbZ?K5`?>!9PFb83t#hM=pto%Cv300Qu}f5dO8)mJcaFvywk6d?7{5Nvl))(@(uB^Suw#^ zZTkznpu@YfEDG*!0~#D)Y%fuFgtCAcAX~n+^76@GSuDs?@xW@IPOUnY8a65fdC_-Zs)NW}N zx@g#4ei%gy@sI0S5Lqxm7XoD4AK(dTs=otdWYU60UXnZlRWxSt;HQ_SU}S@bzSGq1bC zo7g~D0EvIt*|LCiwIhoC@sc!zL&0Bm>cI>AZYcS7;jpS=Zq;On6564NZSyU0FtoVn z=vhT&F7!9Jl?%ipE#PtFWUF?P^#tBlycJz#tT3Yw$>C!z{)3Ehfb#yDo8F}$#qz-D z_!}jn1o(A}4Hp!(^yhwP%s}tNvA+n&^+)UK%r@b;9OXg(!d78sQu(u;ZIM<}-Q$z2 z&N=dWd&n1Pag2Oan5%YkofEeDny_SV_*FMyAer4e{*mUoq0Q>{@z-Zrue(VDnMLtk zZQYAw28YGG17!fU*8r3fcGXEC~zDZUW8Ar_YQ>zd-PmC0|XokT(jO7iZ5(8tI!|2cnZ$mF)yN|9plsA67CLyV;r`68lN65?!|TP~BI zt*7w5nK`DD=o*J>ae@}$Z(SgT3e7JLieq98KYxYZkRH6Vg4=owi=gbwi#cNsW7#3e zd2)q{jdezbvxqqp`op>|1Up&@CiY(_@n4mKlHxi&eUY_a&a}B_J@JH(e@AzYcC%KUJEvp z%I_@G(@&gRwg$!64qb$c(bCHxjK;k3$-qSPinYe-2&w>;(HNwa4A{g% zA#Y~&p)w^}5W_J1my}`a6WwfyEwykYv>dG^zGh<3IVo{m~^65?W(iqa1 zA2vZtvEq;SsL;@O!uCyVzv1$Lx`@FUh&8pq;Yql*nD$3~m#<&Av=8ji!muEzA_Zc8 z{+BMW1|`fiVqp<6uU6Gt-p(KaOV43%K}38XnuzLroWC;LAII8iR{kCJwl-pJa3Z>s z@K~dun*$*E+(pNCkJOiQ?lF)Ih`|~Cw9rR|P(Kkvj7YMa0I*b$C08}Th5ShMf&B;W z!m3^Z^wlf!5~4thkNR%8q*=~2rH^V6cIV4imr(xIaRSP_|2S4j#4((E$7EO|{?%Zp zz^AmCtd%{_54$aDh;&2=VmlDKNPP|?ki4?CCVrk4DIZtcNzvt$$&gVvj<@u>CNeoz z{+*7R%oI8$4!DD=r9AnZw<=x3q>-15D9Cu0j@N7TCrbQKu#qW8 z*ns3R`N#NWsI^(d5Q-i^Y^ay@;Fe{oG84Z9N6R21EWz^e^`jH!mIWmQ=W`cW^QFY| z=SAGxP?1)Oi+&r(Beh_QVsVPg%?nEGqm~6Zeajb8)glu2<~T8fwXq@meIlvAuO)SL zf*6dwQ#ek{P;E>IYbwxrvbmDNm&2*x3>m@ir424gJda^GJMy%B56+Gvp?TK&_ymX| zz<-a70L*E+Xt{^aD!<&2R8gb@KWjy8r&mPHAWSpdK(AN)(exrm_1S5$SDF(ubK*D( zP3|$tv~h$pH$jmx!19W-XcC;4%?aWg1NjsZ+#!p7B(UkCly-;Z$2`*Z*I{aF3Tz~T&%3*^^`s_ylL7M&wJql$_vJs!hayE z6Xuj4;|c9oX1Vfa6jCR%#B8ZRih%B(Kjer1mGn>{BM(zDG5R!|@N_l(%0`Dsw^)>=L^`D8>Hk z`iPbx<|rM?Az!Rx@I)@B(anl-qn(}HxHn!yXxH}SSsMa%MxFKK<4L@h}YfKFB0^}*VHG9kqg9Yamft$5o3 zwYB-}LDY+){TJ^Zr*@O(^XY9#r;rTz?sCs!4N@Wi8V`hC${lO=$G3cTC$rexIUu)G zf$`(L!1bWh#5kpx#uRpw?PiG&Ma~9#wAiG_ZLe&ncnx(ULaQUflBqVw;@JP&3t{Lj ztueOz(eUIS&?GQ_l+e4lf2D z?2&>M4N4GYiakyVMrSAr;8zoS@H?&?-daad-BIVA84;^d0Fq#R`kzJ5BfkwyWZy+C z9#K5aVRcMr%KlP>8!>SvfHvzu_{UUyDq;{J&)*n|fWgC5_C0X2uTgr@;%LsX0eX0t zSDzxzdGZd4Ijdl@5LhaUI?lU*oF2{iIcf%qJdpMQwOSjRfFCB58~Zt6I4IB9xJj+= z`4sIksq{OGZ*WkQCk9l4-}1WjVX3S)y~?@$s=-Be{SyP40D(|-ZxR6o+Yf5Cth$-> zMqcidt#$X9mGu^*ohf152AYPph5kuf8tbfQgBN0WF0FVfIVwapr*BeIwjJPlUP(jB z=ca7`#Oy)?=CG$4nW}J8uMox-B3C*zQ9W(v;o8ll0KZ9rCARa`hp&JsIh*+9Ieg~( zQG4Q1gd?41IK6Ye8p@n7|8GKEkH}=7HwrkIZAN0>ibe>5r(RP?R#?6$6)&s0D~Pz? zdEapZb?I{d5b~3-fx$a0GLF2^ z*7gV{mPGvMz+;8vET)r3=AIF4i1Q&m zVjnH))AteTd JwY{X1N^6dr1k|4h*9Z~l(W!3P_$%x=UhJtQITpgHqiT@hijMV%l>dXYt5$g7k_BcWFjw?}~N;3GIYk$>MA~0cgQ`oUo0xt{({+sN=x#(Bv$@8K1or zYTK4PoQ3J3%s9WlMA$Ix!ze<*4*!;!n8N6wNnCO0xG8<FceHG{_{FgyY@cz4C}gKRFHwnOIjU@{B+?`@k7QE4E9Na0!VT5bLq4W=6JJrD z2%wJR;{s}XIl;N4UKNaR_%}_o3Z+NS=^wPi!v1C=*bu;J`0cS(0+|YHy5%TQkt8-T zdBlp17B>X{T903>$rpD^<%3nuPwQ8x`^SGlaf3s=_zEF^=m3uCLrdDR48sh6B(TBt zyQK<8k{kS-xs|PCVj18MxZbKoE{Lr=CIYLIwzKFp=d=e$v_XADX?dC_wyEC)fR1i{Aa6~fbwL4eOo*^9nJf%Njmk7&%W_<6f&Nv(O zU{kb1!noe2yLT?}beK1^y`glbZSo$%HXf+Fcf4qGboS^1tkryhv)!%kb$Plq8AT7( zpPGe{WqEmKxIcPRvuO#|k2CP)X_HE~y3H45mVf*evfsBO9jG zbZ1O%l2pEB?GN;7l-*q;zpz;F!aDx4LuEep0n-iO(+iT553I-}*x6riC=~2%=Qjy8v++}!#GV^(Q`v8@Fn4bR6aTgROurJg z06UC866UJSs56+<#3&%R*mItV85$#;FKCa`d1LM0E%zCZL=ViFvSmL_VDY%37A0u! zdSIIf7#YAuXR3cBrc&bdGAR;HcZ?+77IZN5K83U0QL)D!7hE0eA>$a+EzKN4r~=rq zxJfL-ZGxXC@@SHtM=3iPW^C{mF!BFf{0hb+&h-3AE`83OnYq)M4!}?HoNj_H9U+4a zqF@f*TDxj&?@0ki9zSVvMNhn2@#iHR47HXy*kWP`+Ht3Vo$~vrm~+z#&gCx*{~##d z@g4hd=~wKg=ZAn|;|f&EiZG^v;@EoEozmj#+dv`yrR}WY>f>-*dgwra&pja6qAu5! z>_2g&j<(NF5ll_#I_`oTvWVIGcSL8TI7Ug`f`Zp2)GS&)Yh&OM7oU+4FAH$jYKP(9 zG9uS`xkI)m<$OldOT(&NW9wgKE(a@h5w3Z5izEL8huQ?*v31wThjuli;e&ZEp4F^pyI9d{!#XWsM7{)2;111Oe#Js)MK^Knj2m5eQcTEmTy0pAAP}LSou6Oc%ee%nwAnCLnN#M~1J7_bHZF~E?qUD#RWfAUxniWxV4wm31QWBgyRnl8SkDrvE7lux3lkma5`($7{YDNYk%gW$xt+M1wi z8@?oPTgi`zD1TP`y*V_o{xoW3sYHAV@#fetpYr4}JHW7pAI%dur}~eGCj1*Hc-MJL zKI5KXm_5DpOSQFMC_YY;!pBA^O@ovn`{PP9ovyg>y410-=GjE1wc-vkM!*EHB}pzi zbsLZW&zokyVr1R@N3`!l11ODLa_XAk*knTwaqHA|yV=9vABc><%^Xgvo^>MtnbOFS5mrTGQa+ z-*yl*Gye(OM;T^%PD&YgWL+`)(ZL?8ul4ywTb6fJm7`Tt45C*$Aa43^uQB+57V~O> z`0#O6x-t@k2SVzf0p?#NSz~B~4e3`EnOgsfT?Mypblx6@dl4Az5uqqK8Gr)acdIz- zY2GVo{0FWMUIv>m>e>W#4+ikV10Chv@et*$)1WNha_J19wZ|37H-+?ij5yiuyzQJC z@#pay+U=sN!| zB!{MTTyiR60TfS5b={pS^q>vfc>Y(O`eoXAT(ruw67ZXAZ&z*)^LLwW)a@})Yx?cY zfZy>Q5`dxkyd8MqmF7DFG(yDsei8>vIyfQA&slf{jDVqgC%Zbw{)C5uBkL|maC_U#S5!e9p4S8q>i7S)YG@S zYZ)1wa`HPJ7w6rGpd;ZsOvx*z<)!hSVg^If$KUPr| z0?EeZhKJ&`;+0n;F7mi%E-NhL2NEtmeRa1TM_@uZ8xmKVAVjlW$49EDl|Rq5t~_`@PXNeC*@i|gQ9Q4n7j51L2Wko zVeyOK+NbN`!s+2F0;pa5d?J}N20^oellNRYGcvywv4m)eWXvP}ADmduJ2zI{6*hDx z(u1C3^hi2@C#5~xi2@b!B~<~J5R!J;;bQBjW#sV{|MAd;92SlyIdi@I#s5j&Yb&cM zf2U2i^Tj0z``3xl@HW9dl-Sqv$b^=~f#9Y|h`(8Ipz7C{ai|PocwW^{vk4yr3u5cB zi?D{*mZXiy)Z1ki#P;AwVcNLanD4Jk(S5$xxZ_D3vtWgIie6<9I!Z&BeHORR`YAT`enAZJ7_rV_UF_f6_nkY% z+?`yzuqQ46Hp5uRiaNb5c0e7;Yf#Q_v>QM%za?evhO zXlP|VeiGr{WS9&5a#|KqUyD#d`2735{tIx?fzW5QTLbwK3(X zVZM@%Qdn9vTFtr}s32=>E{ZZdDa#g-1AT#9SqXj7NFFu=RJH~jmt7(%YJ%!^T+b$O z|1Z!iFVoDBEM;+8Ne@5j8?%MFY6ffm=j(`x_~UdV_B2cvyHaa!4fLaX(d&^x5+v#i zFJFu5Bq?=i388-UwNH{o09}ddT(Pj1l^T1q#g9IZ7O$kFK)h(ehe(s4RHyO?KYB7+ zym*od8HDcbf)06BsZDW2`_W%fUqR9!H!$>l&>{Vl>ST)Zqjgc@)fYSDWi&yBJs@6L zlw8`&kKXc0I^+?SJG*OPu_&jlj~|(%RzikA`l1FM{dLZnPNx5Fm8baC<~I}pZB8|B5NU8q6W3txe%nfpa#waKe`ps z1j&XBN8MglSy=~VexfwckCsO?LUJH~VX(TO);eWDV&yA-loc@tk_(xI!Ky=;BuIOr zAF+sekUU5_WEpb%N1mTplIllW!WTjEAuG_*6-aYiu1aoA_oLUt#kVyIAhFZEd@(}a zHMuG=Aqx{JT$ED?*@nROAwu{ca#d1ut{?3U6Xg^^8X!L-O`AL~i5L3O=rB=EF{C#_ z%{^>=F4>Xf80trXVd6U`L&a8s@N@`4_a}KyBE9ZM2dy(9CF0zLmL5moIx5c@Tsqv3 zKD17Syawrv(H@Vj;-EY$vF&X?;@0VqVUW+4dbxy=+bho=Y#;4M$1L+9uZw_!Q81zp zw#zdUTS_sjETRT)K(1p<|3V*ZkY^2!|HzM`EOQ}mibcB^GsMrzR?9PzoS*v9NnQmR zE@lYE$JW`(mdmq}q_KW9fzO7#1zC)F@P=Y#_44%O%5p#I&Bb?SMnG~Gpl)U>TO?0S zY#;AOZRQ1#w;|7>r5{9F*<6%UGTDzDW|8I{$U@ZZ0Mbm8rzW*d^P>c__@2#3$XPK% z;;d}EJS{0<7UoWHZN~} z18Z9zKcsc9A3X@%Cw}Zs92wSodCN#EQ{>7a3EyB|2Yyf8G-EaY^F_pQ_~Yx%UcMLq znV(#q(R|R4s(jz`EQ7SJ_41SttV}DHXY%j;=(Rxcn>XcSMJD~|N4h}q0|S+iz@1+H=TIwahm@Z5BaiQA*2Y7IeuF)@#LBKf z+D;=l1c=|`nE+XOz{``->*dv>u+XJ(d98Q+=z#A{wV9AlPvhM685TMu;U7QR>icQ7 zSz=>3iSRVh%2r5Y^O_&|(HdWx*^uXvn`gF_HA-U(xT*s!_r2XV2eR{&mn+k)tX3LZ z`2RI^-r-Rd-~T@(xzsIlFD2O&nC#uujS{4YC>jOCR2E1`CB%Xa(1=(`!V-E9JwVC^ zkSZ7fMT!_iL=hw?NZ-AyA}WHhQUv+E&;CBo_wk=R&pxl5nKNh3oH=vv%$=$b6V-?D zIqC%!b0OtdbHH~uUJxeFw;#;#O|^1`OhrobMyE0DbM)E1sSpwAwpD)^hBEIvoQX2@-mRpvlrz14R+-P zQBf?UiOvMba*#d@C-(ppPdPayzBU5^q zXoQVhRRi)ObgT2&m0_Y{RAVm_y=LRD5!CXObpC?8vdXSx!mhHfiB<;csRMDKmo6?x zz=0*I?l)0WptO1(x*+ow*_A<}yqF#`(T@QQJRI`87v#y=cI9E%p!5+FbqwciZ4Eq) z!A}OGXZwpu#l|2Lr35yjt>zF8KT#*!mHQy$N;OewIG47DGxLk62fo!uOe$*1Fi}G| zYrU3NikBb*Z@5QHE>3ot=wvu=Dtikg{ZFJB^X*D^;V$+JH&KTO_N{fC<6gTUH=<{q z!aY*tnrJ{^Biee9e{NlnozSQ8AnpPal}E6jYydgZ+AF`BV^?BOTFXci?TX;`O1Uzn{YZ2U@P3(1Mue?%jS0qUDQzp7Mun}!DKV0eLmG_j{l_)WFWXiK9 zdLxoO^=)3)gn8v)#IkTvS=2bjM0+Fodk9;2!tUsm9U&7YrWDE-P1GvtALiJ1jWQ%tm{>vfPFywL0Hm8Ec(4q|#i@(k1ecCx+4Pe7zs9$aZx+Cu}+ zY!l^n;~i%2gB-VeK&GmDXbJh?XTLdQ2K1yFkn_UK#yXfaI1`!^s0=H;B7Cth3p!C}Pft=2a&8Mg9P? z2V^+vNqvvW+}xCU6Fn4t7Gy6^2)(>=|8`6~Vs3WhY7;GrJ_qt4$n}0+Iq@SV^RwkT z6J3nvU1|GxnDvHCfXvIT+K53L*p>DXJ8XZibbTHm!)c3&=GqT|H1Q*cfnNF1aeLs( zgVIJ5`Rpe__OnGZy>h}~)~zbr*lwbG^n)NDvm*`mO8=1n8Rpt)qG>w6&^f>seGD2L zVH+%PHSIRhDg6M*C%kkX;+3BsWs5FyCGRs)qJv-P9OS^2>Xk78ve@O>Z=#6~ehKs` z$Zvz-A&0qt77Y~#O?1S;FLVxZ7#s?_o#H-S>~eo*qNo@qpMh*2>6PuyupcaTwR~Zs zu`wU=DH7e?a(*uZ;P{!q2EXAm}G-vK$wDFb9We$8W{I!j(K(dB^5mt5Ka zue^Si$Ipt4D#Jv*Ku}hIx2Kzan ztV(bC4So>6j9(^!Jn)QHzIKj-(8{#rzhLY5mHaXZr1D9xymOWV*NSw{byz216~9d4 z$2-q?3gk#XdUPE6cv%0J$p7eaA$T0^~I3?4@4$!F~>^wW%#Z zX4;uBhhHXvEJkS;_H!VvO)qI}rYi}{`DGGM|F3vu)?T~P52ZD?GgEZpT#$1hjW2rT zU3)m-*QTYI%``lb>p2gyVuDvbagZm8y0k`NrpiQa=>=}jc(07y&l5{cy6j}8cM|!f zl^3LXj92d6#gkEOT2-i-&IC&HaUg!$D^PPA@fc?T4XK{)X4>bh z1^EGF$D3XmcY-qqPnzgyrV{~~OZ-g2?Uk#}akk;faQ89Ok4`q#k0AC*7#L?cPpQvr zxz9{DoC`pH;%9#7k~v<^Z5q-``kSduk_Y5xkQ=CHznAl&`t;@$Gigb6AeTA!oamLG zK!aJLAv0y5nIe+dk$&L^+m&AV<2lZ|>N6S#n@I*ryTUS)Q5pvN63EDOGwDe@Fs|}r z|2bZH%g_0pC$lQcOpYXem-;I|i(BNC3%r~YuFj-kaF?WYAT2yJXL+S^mh;H^%+efl z-~()-LBDanx)@X2*PMGc3^DS|)F~kIJ1^U7y>i7d&R6S(xQfiwE@>OcAG|oP^UCq3 zILGz4nns!FmXkxkpS)b#k zdFi#!EB^*LEEucEs-ix-`86{Q3zYc} zd&3uAY4-9;q&7QcqM5ooPk`LwMfEpc+3IIry?C-4E6mj1$y=yz^K+>4UU~BmUh&lB z$VxMPo7fEUFHe1E;V1vvm48uB)ig7GkjR^>?|{5{24kg-t|;oN9GYdOIf+~kh3p6tIIB(Yo?;a??GCD9E8m0Aevg6V=OR}Gm)puAdrW?!-UX9#}cq6$F&>(x{%4SOAboCoWqG)c<@T!llFeqyi|0hAJxH+Plk1{&EYX+e zH*Yml=Xg%2I)EGx_Q{9BbS&$a7p818)A6`lASRFxJNV=qp}JD6Ru?wDhxWwrp#d|< zwNRg&5vePq)#XKUmzf5{{RH)I&{X zYK*m@Gy(Dq$R3lfys0i7S$e=sqhq-q737t+(-$!&6wnbQx{FVq2-cMa>f++2qh>0LX$#T`0fIBll64z4E@q$(cGMiVxJ zxX+oXpTi6i26FlypWNS0SGK8(idwt~hI%N7jh!#qC!ewE$_J1s`PNL!bTlp~9HchM zCp)*+m5F?+cAl*Rz?C+CxU3JA! z=Z~UmW?B=??U5j1sXo~?LRT)SvqzQQG?Od39Y{1t&vc(`fb(5Z=N22c&2(Faf!NuV zbA0kK==P^Nx5(AXLYpPGM+bTSaS&*5Q=L`Z6k?%#*#^YHc6-(*Z^JsI%_&Z9YoWHX zHAoCd-WZ>}AHC2l>BgnSfvEXDxiv^vI%+eD z-I|5Mx&?v6gRC9tlL8jCX)}vkI$P*)*Y+R@AXkfh@*H}hn>Mqk#Ac!Lu6N+di6Aqd z_sKD6PmDIBusPB~_jF|&I6)qN$tRs1btO^5Vo6%)QWSwCflQv@lZVZ^lB`WHY}74O z8^z~r?gBYc;geqYP9JT0fsC_IPSoEZcY{>U^2wOC2m#vE{HjC?Sp#dG?jX6-eX=j= zd03lPNOxNTo7X~vl0kMXgdb?S@+f3Vdst|CBoECVAcZS^@)BB_u1(7`dRb^-BnO9k zKz^zBNk=OL2W@JetFMJZA~~e>1i7%rC#PITnxVP#n(nvIrxBMydWG=!^)a$;Ax1jMFCPv}9Q5?QmYV+{gX%u}@}#j0Y)k zS?G;$o<914oIUE3Nth&F)!aGF!!48+&cXYBkccBb+4?WL@}^dvosw&z$nc|lJ_#iJ zluz1j+LcLKMRsF>g?_Ug=JQD)C(rxjX2g&w+N5k*Y@yF=JmowHa>whFk&v08RSd6s z+(N5uJn20IGT~>RJOJy=2BFaws<3^|=aYEU|K*d*pxb<{e0b@z7AmrR#OISh63CEy zP|qT*!exxH(1SK!A3Xx{+CM&7j+QRf%7?mMw2(cp;cWnjyycU@@Wg7ZY-rPXj1n7G z8o>iX{&NsR+GChs;{7e2Cj^p$`M(F_4a}4fzh{#`RixR?8F% zy&KqdmI{*H%8(SVD;u>phm_2)(E6~|AZZ}GZ)0d;o_kw+GqZWNg&G38+tNY0UiZnJ ziMp~?E6Yrok0BGrxn~B*#ulG!6Q?VU+M8L83oTR=Rs)g=@-Gas4Kvd=?ad6i)IxP( zyokvHS>MKxts%2RtH`LTMrVcba$pEMpUIF1FgLyr4XDOKn*v(9KyE`uP12Q}+Qf{~ zdJF9c$P5L^2{PohWL?>X(u~!X|LtKL#@PmBHuuw&-CB9NYn_Ff16mIU85?5AK@aQ7 z9&KWJ(?$z@7slCdHpus8L(b07l@CFZw^-=Pzkhw92H120IDYbdOg|^sO>q3xwx*O8`026m=%0UaA zu<=Tx2xJ_{*GU-;43HAet_B-&bPu*fMOx`MmcZt<(4faTi*p(B z{_adFQ;jngY6)lSJptl|Ojegq1#^6(_~lzo7X~vo&tF_ z(~xVExMwTVlE1gms)$7(quEa$G2~F4y`eJQbIC%dBY2JSG)T}OLw*mh`#_tLE-qUr zG?Ld`&wyk+V94~)pt?yG2NB#($^LGF6kkfR*zsgpBXezOENuZ0FZ2U3=9NOw4U z_ms?%zbxd9WKVq_WJ``AZ|OWDre!u?w~!->H5dc(LcSp_Q9O#KWTxD*(3mJ*iHrs5 zQDDfyb{=^%vKsGLXnWLFkZ~ZPBMlkr)Rj%z^eh={rQ1=ws(1n9-6BI?>ct~`dS+E? zYhd$QXwZuwL!L0?aCqHY+RP!;-bzcla%rU?^ItIJvA(*pTAQ6!YPQn1U3Y`L#G&sDwpT}`3Z zz~;5kpa~%3XB)C(3Wv$rLz5${Bqi7L3do?zhU`0tL+dP;r>m95ORQ^xUkUloal}_S zk9^&b6Hvf>6d>$YIv{zO^%}^T*9^I!zpl*D<_>qqSgA`iFQ#4xc@IVJ9js#xm@~8` z-b&9!^V6m`K<3Q(|CLVB<_|APveMpY-oX4O$hWf$xdKCX5=e7*D_H~2)h2Qt37P5v zx-wClo0HPhN>2oyo|SQkK;ynj)0Nk>dBYp~Sm}K`&vxaUB+oPCz;vDm=Z}#6tkh2D z)2kIA9Z*l=qq_2fws1sMe=8N~JP%F+@hmZ9QWnp*Rk`%AmEO_0G&j%q%MAHr4pMuq zYDDQkE46Z51ewh451IE}x>5pS47Sp6hZm%hGnl!Cd>o`uTQtIzZl$#jUfxUrIbUta zXYzF94~uh~vaIx%gY$=}oGC3fX{4Az$BiF`OxfXo2-3R>^Z=6q;zzPkvH6wBNEXM&hkV@k@@l?Sw? zg)O73R2F*!WEM!jdP4>c;=F5lVabzLIu!dm$ZU|b^$3Oob)|<^UC{irmDIS9R$)PN zc;eY=$S}0jsjVnTdEQF-aqU6oa_+es{WF4dLM)cXS;-UE8e|^G)NKgIC7egDD3UK( z>0+D(WIo8vcMbW%Xk7`{sz+8$um*Org#|6(#nJ{tP9Cc(owOAr>2)iO4Uj6HV%HdQ z<8z$jt{ho9(MoT}Yak0jE^k2yc!~4kRYgXHl`aQl7V#1f_4IyCS6V>>SEZHW6ZlNV zVvu9dt^YV(`A4lSZklGLClk7WECFdjORvAGD}Sjq#mTd*RFlAGGM0k;{2m4^O1lc; znQNu56FPz{1No=Xkj>EGM-WkErM8LTAj?6<>@Z}PS9HbCA5&XwrGAN4kZR6)_8Kx_ zvaX!tkEt!Q(wIaW$O;Y)AR%sDIRR3#(n>25JAPI%$TIpaS_rfX= zf{b;pt{hV9i&Gk`bTyH6s{wfgGUhp$azGl_TB);>?N$qt1(}xF2;R_5Zh&siNRT>S zw|r{IaZ7paRyV3@vy}>++;jCH3%^8oT87Yx(&!y4O>~BWcsQUOHslRx@D_9{-Dag~ zXD5&bkf@`EY=lgm>M1tfv(h#v+j=#~jV}!OQH`!FSL;T)c3J83Kxu0@`#o*QEvt2< zN^Ka~wAV^rrwX!`M?Ews2APF=lAEmbTR^wBIEH)BgPm$+>e(32H;J`>>Tllc-f#@cNMd97NoJA4fkkM2`=g{fMX z=ecR6$<7NP?{kKE%#aOBbj76Bj}ZT2DsY|$*$Hy!6msb*e$wU1akmnb;^d>9A8?KY zQaoQ*?uhykEg^y;oj#CVJkZY?^27>Vxh`skm$Vi1ci?E}Zjb}t8}bTt`%Tp4GIPU~BaDWl=vY#VTlZ;z5wTylnp#nZtX!^1Z0ZZqx)#NaVAwA95C8pgrgX zuc#X)y9gSXcm!l0hy@zFvPD-;L4zurAT9ATkdHw2pruRK>&kHuiV}1of$M1kDMEYt zqO`+e<&aV-Xnn%_WD8-E7qp-A$geS3y{{{uh*d)jUC;{&dm;HTOM2mTyOH^c8kZ|h zP_Kk-AO}G1yJ*N>=)Vt8W>cb|Yw`O)J^`tN%=cv0)bebnewQhldPBPQ%zTiqKoVQ|Ebebb*vScF~yzq(i%Zw0*k|btjl+G8FEcwF?e$Lfwet8n6N)U6>jfH}I z-Pm2e1&Isu%YTC$N-T(Lsh|bjxEsIY?APj-543hDx|o^XR4wSCZXS^DL8@W+*Y4dH3wk(UE#&o^BhN*6ILqh+I@kE1q$`~;E|<(GZ!4yBWrmRYg| z7LDTe{0y=Q)*0Y%D4Lj_+1x1To+$p1!DY?`V1vcs4n>G5St&aN{SwK8=@-r{(9-NM z2k#*m(zp|$D6$dc3dj!~{BnIK2VZ$GMD7tZI&v$>Res_I_m9^cN(V6|vud9pMZHA8l{IFxq6J*4y?>WN^P-#F~U{Wo=XC~d`L zm+_gPF%dgJeg{$7`sHZpP}+#fp{^rnPsE2Hf3RC(n0*oHP+AN3u%=^z{t4&L75vEy zEY$O7go7_O7?%9Cpo8IuK>h;hjPP_Slu5;K&o_b=g>#_(o3r0v40#zA4H1)ui?f0r z5C0tG8ZX=bHsmfxfaJI@K!b1&;nzW2(7JsDlZxRjhM?8~nHwPAA=Eg+9D(Z#O1>9# z-gXk?CO<1Bzf?K}WU`wtAvoB0vigS~A6!SS7RkDm<)mDOC)#*|y9LtNVn|n4CX;d+ zuL>Gx>fB46I??l?uCl{(p!RVg?$Io3gkXaa5t>na})E8JAy8Sabgez zl7;EgX<|Pp%X0;*bRvvP3s(4JHimq?y+bjHioB-QYGCu4Ehq$JAlehGvA>lSCbw7V z{eX-D(gQvBl!<-x%>s{ErMJU41!@g)FbMGgqeK-G3xulD+OXe2+JJnAz*U0MI*N)S zcPEwV!}yy5Z9$ql`DHkIyEE!(2~`6hU<(Us$Ms-jEso+bS6)~Wp;B!aACPVja?RnF zqq;eia51s4xvNT^uy)8JJAj<&?w8NT@z|~?O0lc7F3gNPlF9!aL^N^HccbX;4yBuz zSkxG!(mR0y%pga4`Q_g|9Ex2`94Ql2+8xGAFAK<;`~7lfFNYE%%8IL!RQfDHtROS` z`{ja%97;Uz>`GSYOc*ED0;Kn&ei?F~Lvfp$QG{=KXhl)W9CL zupkX&^I*T+5$jOy5fewb`l%FY<7G!jkg1T#1L-X$jcn?#QeRtJkWL`^gZ$D4Q{4v* zk{?!Sge?N3GsvBX{qiWBufHfC=^3cfYc|%P3&^m(m>WTO*O_=srByaw#Ds!WfZPi* zNK}k+r>oRtgAs$mK)!%=8ZiJ<#iUU!St|Wx;{}!tmnCJ*ko@g6-A~P%PUBWM85~nJ10S8+l@sJEw5l7(CNVQVrAnn2yYeQvBoHrj+uq-yG>Vx8 zjf+*<6Zj04rMnb*fJjZBAfUd$WOv>9Vk@^-UctlK?) zId-r^`Bu!!Nq$GAl<4pHm6F2uXChY{>QH_Xb8|e~R9X~$ieD*#lwm~lfy}RBPL6nA zr5~bsr@*~DA|8aTvmDCbVnMchmrC~q939q%p2aaSEaf3ulW`wkS7si zY_LwSx*)rxNhJd^U4r_7cpmY~`LIEIb;0oF11j~@4}jbcvKltHfR?HtDTh>=t{($= zfPD)xyI|2UwQ5-7Vf41%1kxX5JuLcZKg2(E(NOuNN{NoW)FrsT@}J{~58_9q%P(uu zjj`%tSJiQq${Zi^WlA8QqkwTJAW2;~luoL2)bSo)rUcR&PH`m}IUz{tX_ca4w)165 zAcG+D{=LXB)g>R7*Afl9M_WuvNR6?2lc!G(tJ~;w(%=L(s{N+Ah;g`(5+Ty zru?f?di+};8UG9JJuvaiKs}AEG@2V<1(M0`kAdC`y3JQtq)SDkBLR}dr6KIUfuOq- zq^hk(?GtMGG9{3a=mi7WNR7H8jZ7Ln8XzvVPClk2grYSdrB;pHf$K+yf-D-1po_4v zNnM#{Xc~PGxJq;w$ndBAvJ4^MU9~RN)kUML34CGbaGtEj_~k(K=}xsawaKQDJ&|Ry zK`gKPWe2o$pIV!q9Hr6lM7{$j2jo(PUq+&(2l;+XsZnJj-zGBxgr@oBDR|Wp5aG}Q zJJ~u1<$|mL>4SQ{Qft!OaT=Ws$mD@snBkZC_c)X@YHeCeqDDbZmdOX{37NZ5j}N5e zZjIst*Mb)Clr+^ZccbTiP(5kQJv2&pvetzl)sy{lBQn`v)cVwv-WrV!-0E2b51{ot& zqZQ#+SJGb-sB#thS zc^WdKv^p2PsnN&IUDPS~Mdd#S5liu73;yj@WJ*tJo}s1X8g1f#3wjB}wazbdb>tjc z{ZPZL(E=xb=XyMdb*o?AgyF|&wZmLfHG0YU1<1=Flh*p>9b`%`fi%s~XsDCFOg(|) z^?JYj5`*?ttu{M(jz)Jo`TNqZfb4$9FP9-a@d;4Rd>AA^UIp2{366w(s6wmB7K=3U zC-RLtuYp``^veQdFqJ6Hy;P%}iToAm*Fo}7+G}vW=~~T*mTHaWBzpNWC0<-?@yn;s zp4nP$PDzax*u&N-=uMDcpxYAUA@j7_+~#_XoQW6tG9{1~)*yI8W+6z*8jY?e@Mi?d zIFE!4CPTL++N#{fbue$j&wQB@h#RG?LP)Cyk()5g60Y)PN+4U`^2^8J{;RYV`BhtB zorGWcG9{1^8<68dgF0 zd`DYZVC>YWI-X0b1i68p8-!4^PFt1l+M`i!JZmt8gAjUqB(jZ-T6ICwKDcE(e_&uL zNG&vofXrsCx-j`;jhf^5ex7L{i&2m1L5H$ct1j{!M0?^wT6GGV4zh10diw!nPukJ~ p@wr9=;`p-&GeCx{fGcC#-KH%qbRW^^W-RI<`hURtl45$0005dq!aD!} literal 0 HcmV?d00001 diff --git a/suites-experimental/tools-gps-tracks/test-data/manifest.json b/suites-experimental/tools-gps-tracks/test-data/manifest.json new file mode 100644 index 0000000000..52a312930a --- /dev/null +++ b/suites-experimental/tools-gps-tracks/test-data/manifest.json @@ -0,0 +1,8 @@ +[ + "activity_1_alps_stage.gpx.gz", + "activity_2_forest_mtb.gpx.gz", + "activity_3_road_race.tcx.gz", + "activity_4_intervals.tcx.gz", + "activity_5_grand_tour.fit.gz", + "activity_6_weekend_ride.fit.gz" +] \ No newline at end of file diff --git a/suites-experimental/tools-gps-tracks/tsconfig.json b/suites-experimental/tools-gps-tracks/tsconfig.json new file mode 100644 index 0000000000..dab0956d5e --- /dev/null +++ b/suites-experimental/tools-gps-tracks/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "strict": true, + "allowImportingTsExtensions": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "isolatedModules": true, + "sourceMap": true, + "noEmit": true + }, + "include": ["src/**/*"] +} From c16994508524fad6dd2d4f33018a15ccc46e29a1 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Fri, 13 Nov 2026 12:05:00 +0000 Subject: [PATCH 2/8] [tools-gps-tracks] Scale step workloads to >20ms on desktop Firefox Expand the geospatial and physiological telemetry computations across all seven benchmark steps so each step consistently exceeds 20 ms on desktop Firefox while keeping iteration variance low. --- .../dist/benchmark-override.mjs | 2 +- .../dist/benchmark-override.mjs.map | 6 +- .../dist/tools-gps-tracks.mjs | 472 +++++++++--------- .../dist/tools-gps-tracks.mjs.map | 6 +- .../tools-gps-tracks/src/app.ts | 36 +- .../src/benchmark-override.ts | 21 + .../tools-gps-tracks/src/charts.ts | 109 ++++ .../tools-gps-tracks/src/parsers.ts | 106 +++- .../tools-gps-tracks/src/tabs/combined.ts | 100 +++- .../tools-gps-tracks/src/tabs/courses.ts | 113 ++++- .../tools-gps-tracks/src/tabs/details.ts | 110 ++-- .../tools-gps-tracks/src/tabs/insights.ts | 115 ++++- .../tools-gps-tracks/src/tabs/progress.ts | 114 ++++- .../tools-gps-tracks/src/url-state.ts | 16 +- 14 files changed, 934 insertions(+), 392 deletions(-) diff --git a/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs index bbaea51084..20a94e2f59 100644 --- a/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs +++ b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs @@ -1,2 +1,2 @@ -var o=539363104;window.__resetBenchmarkSeed=()=>{o=539363104};Math.random=()=>{let e=o+=1831565813;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296};window.requestAnimationFrame=e=>window.setTimeout(()=>e(performance.now()),0);window.cancelAnimationFrame=e=>{window.clearTimeout(e)};try{Object.defineProperty(window,"devicePixelRatio",{get:()=>1,configurable:!0})}catch{}try{Object.defineProperty(navigator,"language",{get:()=>"en-US",configurable:!0}),Object.defineProperty(navigator,"languages",{get:()=>["en-US"],configurable:!0})}catch{}typeof CanvasRenderingContext2D<"u"&&(CanvasRenderingContext2D.prototype.measureText=function(e){let n=this.font||"10px sans-serif",i=n.match(/(\d+(?:\.\d+)?)px/),t=i?parseFloat(i[1]):10,r=/\bbold\b|\b[6-9]00\b/i.test(n),c=t*(r?.6:.55),a=String(e).length*c;return{width:a,actualBoundingBoxLeft:0,actualBoundingBoxRight:a,actualBoundingBoxAscent:t*.8,actualBoundingBoxDescent:t*.2,fontBoundingBoxAscent:t*.8,fontBoundingBoxDescent:t*.2,emHeightAscent:t*.8,emHeightDescent:t*.2,hangingBaseline:t*.8,alphabeticBaseline:0,ideographicBaseline:-t*.2}}); +var s=539363104;window.__resetBenchmarkSeed=()=>{s=539363104};Math.random=()=>{let t=s+=1831565813;return t=Math.imul(t^t>>>15,t|1),t^=t+Math.imul(t^t>>>7,t|61),((t^t>>>14)>>>0)/4294967296};window.requestAnimationFrame=t=>window.setTimeout(()=>t(performance.now()),0);window.cancelAnimationFrame=t=>{window.clearTimeout(t)};if(typeof history<"u"){let t=history.replaceState?.bind(history),i=history.pushState?.bind(history);t&&(history.replaceState=function(n,e,o){try{t(n,e,o)}catch{}}),i&&(history.pushState=function(n,e,o){try{i(n,e,o)}catch{}})}try{Object.defineProperty(window,"devicePixelRatio",{get:()=>1,configurable:!0})}catch{}try{Object.defineProperty(navigator,"language",{get:()=>"en-US",configurable:!0}),Object.defineProperty(navigator,"languages",{get:()=>["en-US"],configurable:!0})}catch{}typeof CanvasRenderingContext2D<"u"&&(CanvasRenderingContext2D.prototype.measureText=function(t){let i=this.font||"10px sans-serif",n=i.match(/(\d+(?:\.\d+)?)px/),e=n?parseFloat(n[1]):10,o=/\bbold\b|\b[6-9]00\b/i.test(i),a=e*(o?.6:.55),r=String(t).length*a;return{width:r,actualBoundingBoxLeft:0,actualBoundingBoxRight:r,actualBoundingBoxAscent:e*.8,actualBoundingBoxDescent:e*.2,fontBoundingBoxAscent:e*.8,fontBoundingBoxDescent:e*.2,emHeightAscent:e*.8,emHeightDescent:e*.2,hangingBaseline:e*.8,alphabeticBaseline:0,ideographicBaseline:-e*.2}}); //# sourceMappingURL=benchmark-override.mjs.map diff --git a/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map index 979aa8e1f7..c3e03d574f 100644 --- a/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map +++ b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/benchmark-override.ts"], - "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// Deterministic PRNG (Mulberry32) for reproducible benchmark runs.\nlet seed = 0x20260720;\n(window as any).__resetBenchmarkSeed = (): void => {\n seed = 0x20260720;\n};\nMath.random = (): number => {\n let t = (seed += 0x6d2b79f5);\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n};\n\nwindow.requestAnimationFrame = (callback: FrameRequestCallback): number => {\n return window.setTimeout(() => callback(performance.now()), 0);\n};\n\nwindow.cancelAnimationFrame = (id: number): void => {\n window.clearTimeout(id);\n};\n\n// Normalize devicePixelRatio to 1 so uPlot and canvas rendering execute\n// identical code paths (e.g. decimation thresholds and canvas dimensions) across browsers.\ntry {\n Object.defineProperty(window, 'devicePixelRatio', {\n get: () => 1,\n configurable: true,\n });\n} catch (_) {}\n\n// Normalize navigator.language to en-US so Intl.NumberFormat / locale formatters\n// produce identical strings across browsers and OS locales.\ntry {\n Object.defineProperty(navigator, 'language', {\n get: () => 'en-US',\n configurable: true,\n });\n Object.defineProperty(navigator, 'languages', {\n get: () => ['en-US'],\n configurable: true,\n });\n} catch (_) {}\n\n// Normalize CanvasRenderingContext2D.prototype.measureText so canvas layout calculations\n// (histogram padding, axis label bounding boxes, cursor pills) do not vary with OS/browser\n// system-ui font glyph metrics.\nif (typeof CanvasRenderingContext2D !== 'undefined') {\n CanvasRenderingContext2D.prototype.measureText = function (text: string): TextMetrics {\n const fontStr = this.font || '10px sans-serif';\n const sizeMatch = fontStr.match(/(\\d+(?:\\.\\d+)?)px/);\n const fontSize = sizeMatch ? parseFloat(sizeMatch[1]) : 10;\n const isBold = /\\bbold\\b|\\b[6-9]00\\b/i.test(fontStr);\n const charWidth = fontSize * (isBold ? 0.6 : 0.55);\n const width = String(text).length * charWidth;\n return {\n width,\n actualBoundingBoxLeft: 0,\n actualBoundingBoxRight: width,\n actualBoundingBoxAscent: fontSize * 0.8,\n actualBoundingBoxDescent: fontSize * 0.2,\n fontBoundingBoxAscent: fontSize * 0.8,\n fontBoundingBoxDescent: fontSize * 0.2,\n emHeightAscent: fontSize * 0.8,\n emHeightDescent: fontSize * 0.2,\n hangingBaseline: fontSize * 0.8,\n alphabeticBaseline: 0,\n ideographicBaseline: -fontSize * 0.2,\n } as TextMetrics;\n };\n}\n"], - "mappings": "AAOA,IAAIA,EAAO,UACV,OAAe,qBAAuB,IAAY,CACjDA,EAAO,SACT,EACA,KAAK,OAAS,IAAc,CAC1B,IAAIC,EAAKD,GAAQ,WACjB,OAAAC,EAAI,KAAK,KAAKA,EAAKA,IAAM,GAAKA,EAAI,CAAC,EACnCA,GAAKA,EAAI,KAAK,KAAKA,EAAKA,IAAM,EAAIA,EAAI,EAAE,IAC/BA,EAAKA,IAAM,MAAS,GAAK,UACpC,EAEA,OAAO,sBAAyBC,GACvB,OAAO,WAAW,IAAMA,EAAS,YAAY,IAAI,CAAC,EAAG,CAAC,EAG/D,OAAO,qBAAwBC,GAAqB,CAClD,OAAO,aAAaA,CAAE,CACxB,EAIA,GAAI,CACF,OAAO,eAAe,OAAQ,mBAAoB,CAChD,IAAK,IAAM,EACX,aAAc,EAChB,CAAC,CACH,MAAY,CAAC,CAIb,GAAI,CACF,OAAO,eAAe,UAAW,WAAY,CAC3C,IAAK,IAAM,QACX,aAAc,EAChB,CAAC,EACD,OAAO,eAAe,UAAW,YAAa,CAC5C,IAAK,IAAM,CAAC,OAAO,EACnB,aAAc,EAChB,CAAC,CACH,MAAY,CAAC,CAKT,OAAO,yBAA6B,MACtC,yBAAyB,UAAU,YAAc,SAAUC,EAA2B,CACpF,IAAMC,EAAU,KAAK,MAAQ,kBACvBC,EAAYD,EAAQ,MAAM,mBAAmB,EAC7CE,EAAWD,EAAY,WAAWA,EAAU,CAAC,CAAC,EAAI,GAClDE,EAAS,wBAAwB,KAAKH,CAAO,EAC7CI,EAAYF,GAAYC,EAAS,GAAM,KACvCE,EAAQ,OAAON,CAAI,EAAE,OAASK,EACpC,MAAO,CACL,MAAAC,EACA,sBAAuB,EACvB,uBAAwBA,EACxB,wBAAyBH,EAAW,GACpC,yBAA0BA,EAAW,GACrC,sBAAuBA,EAAW,GAClC,uBAAwBA,EAAW,GACnC,eAAgBA,EAAW,GAC3B,gBAAiBA,EAAW,GAC5B,gBAAiBA,EAAW,GAC5B,mBAAoB,EACpB,oBAAqB,CAACA,EAAW,EACnC,CACF", - "names": ["seed", "t", "callback", "id", "text", "fontStr", "sizeMatch", "fontSize", "isBold", "charWidth", "width"] + "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// Deterministic PRNG (Mulberry32) for reproducible benchmark runs.\nlet seed = 0x20260720;\n(window as any).__resetBenchmarkSeed = (): void => {\n seed = 0x20260720;\n};\nMath.random = (): number => {\n let t = (seed += 0x6d2b79f5);\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n};\n\nwindow.requestAnimationFrame = (callback: FrameRequestCallback): number => {\n return window.setTimeout(() => callback(performance.now()), 0);\n};\n\nwindow.cancelAnimationFrame = (id: number): void => {\n window.clearTimeout(id);\n};\n\n// Guard history.replaceState and history.pushState against browser rate-limiting\n// (e.g. WebKit's 100 calls per 10 seconds SecurityError across multi-iteration runs).\nif (typeof history !== 'undefined') {\n const origReplace = history.replaceState?.bind(history);\n const origPush = history.pushState?.bind(history);\n if (origReplace) {\n history.replaceState = function (data: any, unused: string, url?: string | URL | null): void {\n try {\n origReplace(data, unused, url);\n } catch (_) {}\n };\n }\n if (origPush) {\n history.pushState = function (data: any, unused: string, url?: string | URL | null): void {\n try {\n origPush(data, unused, url);\n } catch (_) {}\n };\n }\n}\n\n// Normalize devicePixelRatio to 1 so uPlot and canvas rendering execute\n// identical code paths (e.g. decimation thresholds and canvas dimensions) across browsers.\ntry {\n Object.defineProperty(window, 'devicePixelRatio', {\n get: () => 1,\n configurable: true,\n });\n} catch (_) {}\n\n// Normalize navigator.language to en-US so Intl.NumberFormat / locale formatters\n// produce identical strings across browsers and OS locales.\ntry {\n Object.defineProperty(navigator, 'language', {\n get: () => 'en-US',\n configurable: true,\n });\n Object.defineProperty(navigator, 'languages', {\n get: () => ['en-US'],\n configurable: true,\n });\n} catch (_) {}\n\n// Normalize CanvasRenderingContext2D.prototype.measureText so canvas layout calculations\n// (histogram padding, axis label bounding boxes, cursor pills) do not vary with OS/browser\n// system-ui font glyph metrics.\nif (typeof CanvasRenderingContext2D !== 'undefined') {\n CanvasRenderingContext2D.prototype.measureText = function (text: string): TextMetrics {\n const fontStr = this.font || '10px sans-serif';\n const sizeMatch = fontStr.match(/(\\d+(?:\\.\\d+)?)px/);\n const fontSize = sizeMatch ? parseFloat(sizeMatch[1]) : 10;\n const isBold = /\\bbold\\b|\\b[6-9]00\\b/i.test(fontStr);\n const charWidth = fontSize * (isBold ? 0.6 : 0.55);\n const width = String(text).length * charWidth;\n return {\n width,\n actualBoundingBoxLeft: 0,\n actualBoundingBoxRight: width,\n actualBoundingBoxAscent: fontSize * 0.8,\n actualBoundingBoxDescent: fontSize * 0.2,\n fontBoundingBoxAscent: fontSize * 0.8,\n fontBoundingBoxDescent: fontSize * 0.2,\n emHeightAscent: fontSize * 0.8,\n emHeightDescent: fontSize * 0.2,\n hangingBaseline: fontSize * 0.8,\n alphabeticBaseline: 0,\n ideographicBaseline: -fontSize * 0.2,\n } as TextMetrics;\n };\n}\n"], + "mappings": "AAOA,IAAIA,EAAO,UACV,OAAe,qBAAuB,IAAY,CACjDA,EAAO,SACT,EACA,KAAK,OAAS,IAAc,CAC1B,IAAI,EAAKA,GAAQ,WACjB,SAAI,KAAK,KAAK,EAAK,IAAM,GAAK,EAAI,CAAC,EACnC,GAAK,EAAI,KAAK,KAAK,EAAK,IAAM,EAAI,EAAI,EAAE,IAC/B,EAAK,IAAM,MAAS,GAAK,UACpC,EAEA,OAAO,sBAAyBC,GACvB,OAAO,WAAW,IAAMA,EAAS,YAAY,IAAI,CAAC,EAAG,CAAC,EAG/D,OAAO,qBAAwBC,GAAqB,CAClD,OAAO,aAAaA,CAAE,CACxB,EAIA,GAAI,OAAO,QAAY,IAAa,CAClC,IAAMC,EAAc,QAAQ,cAAc,KAAK,OAAO,EAChDC,EAAW,QAAQ,WAAW,KAAK,OAAO,EAC5CD,IACF,QAAQ,aAAe,SAAUE,EAAWC,EAAgBC,EAAiC,CAC3F,GAAI,CACFJ,EAAYE,EAAMC,EAAQC,CAAG,CAC/B,MAAY,CAAC,CACf,GAEEH,IACF,QAAQ,UAAY,SAAUC,EAAWC,EAAgBC,EAAiC,CACxF,GAAI,CACFH,EAASC,EAAMC,EAAQC,CAAG,CAC5B,MAAY,CAAC,CACf,EAEJ,CAIA,GAAI,CACF,OAAO,eAAe,OAAQ,mBAAoB,CAChD,IAAK,IAAM,EACX,aAAc,EAChB,CAAC,CACH,MAAY,CAAC,CAIb,GAAI,CACF,OAAO,eAAe,UAAW,WAAY,CAC3C,IAAK,IAAM,QACX,aAAc,EAChB,CAAC,EACD,OAAO,eAAe,UAAW,YAAa,CAC5C,IAAK,IAAM,CAAC,OAAO,EACnB,aAAc,EAChB,CAAC,CACH,MAAY,CAAC,CAKT,OAAO,yBAA6B,MACtC,yBAAyB,UAAU,YAAc,SAAUC,EAA2B,CACpF,IAAMC,EAAU,KAAK,MAAQ,kBACvBC,EAAYD,EAAQ,MAAM,mBAAmB,EAC7CE,EAAWD,EAAY,WAAWA,EAAU,CAAC,CAAC,EAAI,GAClDE,EAAS,wBAAwB,KAAKH,CAAO,EAC7CI,EAAYF,GAAYC,EAAS,GAAM,KACvCE,EAAQ,OAAON,CAAI,EAAE,OAASK,EACpC,MAAO,CACL,MAAAC,EACA,sBAAuB,EACvB,uBAAwBA,EACxB,wBAAyBH,EAAW,GACpC,yBAA0BA,EAAW,GACrC,sBAAuBA,EAAW,GAClC,uBAAwBA,EAAW,GACnC,eAAgBA,EAAW,GAC3B,gBAAiBA,EAAW,GAC5B,gBAAiBA,EAAW,GAC5B,mBAAoB,EACpB,oBAAqB,CAACA,EAAW,EACnC,CACF", + "names": ["seed", "callback", "id", "origReplace", "origPush", "data", "unused", "url", "text", "fontStr", "sizeMatch", "fontSize", "isBold", "charWidth", "width"] } diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs index 60e6a264f0..94ef36d726 100644 --- a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs @@ -1,47 +1,47 @@ -var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(location.search),w={};b.has("track")&&(w.track=b.get("track")),b.has("map")&&(w.map=b.get("map")),b.has("xaxis")&&(w.xaxis=b.get("xaxis")),b.has("tab")&&(w.tab=b.get("tab")),b.has("sel_point")&&(w.sel_point=Number(b.get("sel_point"))),b.has("speed_mode")&&(w.speed_mode=b.get("speed_mode")),b.has("progress")&&(w.progress=b.get("progress"));let R=b.get("metrics");if(R&&(w.metrics=R.split(",").filter(Boolean)),b.has("f_date")&&(w.f_date=b.get("f_date").split(",").map(S=>S||null)),b.has("f_dist")&&(w.f_dist=b.get("f_dist").split(",").map(S=>S?Number(S):null)),b.has("f_dur")&&(w.f_dur=b.get("f_dur").split(",").map(S=>S?Number(S):null)),b.has("f_mets")&&(w.f_mets=b.get("f_mets").split(",")),b.has("f_tags")&&(w.f_tags=b.get("f_tags").split(",")),b.has("q")&&(w.q=b.get("q")),b.has("re")&&(w.re=b.get("re")==="1"),b.has("sort")){let S=b.get("sort"),k=S.startsWith("-"),M=k?S.substring(1):S;w.sort=`${M}-${k?"desc":"asc"}`}if(b.has("map_pos")){let S=b.get("map_pos").split(",").map(Number);S.length===3&&S.every(isFinite)&&(w.map_pos=S)}if(b.has("storage")&&(w.storage=b.get("storage")),b.has("sel")){let S=b.get("sel").split(",").map(Number);S.length===2&&S.every(k=>!isNaN(k)&&isFinite(k))&&(w.sel=S)}return w}function r(){t&&(clearTimeout(t),t=null);let b=new URLSearchParams;if(e.track&&b.set("track",e.track),e.map&&b.set("map",e.map),e.xaxis&&e.xaxis!=="time"&&b.set("xaxis",e.xaxis),e.tab&&e.tab!=="graphs"&&b.set("tab",e.tab),e.storage&&e.storage!=="memory"&&b.set("storage",e.storage),e.sel_point!==void 0&&b.set("sel_point",String(e.sel_point)),e.speed_mode&&b.set("speed_mode",e.speed_mode),e.q&&b.set("q",e.q),e.progress&&b.set("progress",e.progress),e.re&&b.set("re","1"),e.sort){let R=e.sort.split("-"),S=R[0],k=R[1];b.set("sort",(k==="desc"?"-":"")+S)}let w=b.toString();if(e.metrics&&(w+=`${w?"&":""}metrics=${e.metrics.join(",")}`),e.f_date&&(w+=`${w?"&":""}f_date=${e.f_date.map(R=>R||"").join(",")}`),e.f_dist&&(w+=`${w?"&":""}f_dist=${e.f_dist.map(R=>R??"").join(",")}`),e.f_dur&&(w+=`${w?"&":""}f_dur=${e.f_dur.map(R=>R??"").join(",")}`),e.f_mets&&(w+=`${w?"&":""}f_mets=${e.f_mets.join(",")}`),e.f_tags&&(w+=`${w?"&":""}f_tags=${e.f_tags.join(",")}`),e.map_pos){let R=`${(+e.map_pos[0]).toFixed(5)},${(+e.map_pos[1]).toFixed(5)},${e.map_pos[2]}`;w+=`${w?"&":""}map_pos=${R}`}if(e.sel){let R=`${+e.sel[0].toFixed(4)},${+e.sel[1].toFixed(4)}`;w+=`${w?"&":""}sel=${R}`}if(w!==s){let R=location.pathname+(w?`?${w}`:"");n?(history.pushState(null,"",R),n=!1):history.replaceState(null,"",R),s=w}}e=o();function u(){return{...e}}function c(b,w=!1){w&&(n=!0);for(let[R,S]of Object.entries(b)){let k=R;S==null?delete e[k]:e[k]=S}r()}function m(){e=o()}function T(){t&&(clearTimeout(t),t=null),e={},n=!1,s="",history.replaceState(null,"",location.pathname)}return{get:u,patch:c,refresh:m,reset:T}})();var Jn=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(s){return this.trackStore.set(s.id,s),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(s){return this.trackStore.delete(s),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(s,t){return this.settingStore.set(s,t),Promise.resolve()}async get(s){return Promise.resolve(this.settingStore.get(s)??null)}},us=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((s,t)=>{let n=indexedDB.open(this.DB_NAME,this.DB_VERSION);n.onupgradeneeded=()=>{let o=n.result;o.objectStoreNames.contains("tracks")||o.createObjectStore("tracks",{keyPath:"id"}),o.objectStoreNames.contains("settings")||o.createObjectStore("settings")},n.onsuccess=()=>{this.db=n.result,s()},n.onerror=()=>t(n.error)})}getStore(s,t){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(s,t).objectStore(s)}async save(s){return new Promise((t,n)=>{let o=this.getStore("tracks","readwrite").put(s);o.onsuccess=()=>t(),o.onerror=()=>n(o.error)})}async getAll(){return new Promise((s,t)=>{let n=this.getStore("tracks","readonly").getAll();n.onsuccess=()=>s(n.result||[]),n.onerror=()=>t(n.error)})}async remove(s){return new Promise((t,n)=>{let o=this.getStore("tracks","readwrite").delete(s);o.onsuccess=()=>t(),o.onerror=()=>n(o.error)})}async clear(){return this.db?new Promise((s,t)=>{let n=this.db.transaction(["tracks","settings"],"readwrite");n.objectStore("tracks").clear(),n.objectStore("settings").clear(),n.oncomplete=()=>s(),n.onerror=()=>t(n.error)}):Promise.resolve()}async set(s,t){return new Promise((n,o)=>{let r=this.getStore("settings","readwrite").put(t,s);r.onsuccess=()=>n(),r.onerror=()=>o(r.error)})}async get(s){return new Promise((t,n)=>{let o=this.getStore("settings","readonly").get(s);o.onsuccess=()=>t(o.result??null),o.onerror=()=>n(o.error)})}},en=new Jn,at={openDB:async()=>{en=Ye.get().storage==="indexeddb"?new us:new Jn,await en.openDB()},save:e=>en.save(e),getAll:()=>en.getAll(),remove:e=>en.remove(e),clear:()=>en.clear(),set:(e,s)=>en.set(e,s),get:e=>en.get(e)};import Al from"fit-file-parser";function tn(e,s,t,n){let r=e*Math.PI/180,u=t*Math.PI/180,c=(t-e)*Math.PI/180,m=(n-s)*Math.PI/180,T=Math.sin(c/2)*Math.sin(c/2)+Math.cos(r)*Math.cos(u)*Math.sin(m/2)*Math.sin(m/2);return 6371e3*(2*Math.atan2(Math.sqrt(T),Math.sqrt(1-T)))}function Ds(e){let s=new Uint32Array([Math.floor(e/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(s.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function Rs(){return Math.random().toString(36).slice(2,6)}function Ft(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:`${Math.round(e/3600)}h`}function ht(e){let s=Math.floor(e/3600),t=Math.floor(e%3600/60);return s>0?`${s}h ${t}m`:`${t}m ${Math.floor(e%60)}s`}function An(e){if(e==null||!isFinite(e))return"--";let s=Math.floor(e/60),t=Math.round(e%60);return`${s}:${t.toString().padStart(2,"0")}`}function Zt(e){let s=new Date(e);return isNaN(s.getTime())?"Unknown date":s.toISOString().split("T")[0]}function Ns(e){let s=new Date(e);if(isNaN(s.getTime()))return"Unknown";let t=s.toISOString();return`${t.split("T")[0]} ${t.split("T")[1].slice(0,5)}`}function Ws(e){if(e===0)return"0 B";let s=1024,t=["B","KB","MB","GB"],n=Math.floor(Math.log(e)/Math.log(s));return`${parseFloat((e/Math.pow(s,n)).toFixed(2))} ${t[n]}`}function pt(e){return String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function Qn(e){let s=0;for(let n=0;n=0&&w0?m/T:e[c]}return u}function tt(e,s=1){let t=parseInt(e.slice(1,3),16),n=parseInt(e.slice(3,5),16),o=parseInt(e.slice(5,7),16);return`rgba(${t}, ${n}, ${o}, ${s})`}function ms(e){if(!e.length)return null;let s=e[0].lat,t=e[0].lat,n=e[0].lon,o=e[0].lon;for(let r of e)r.latt&&(t=r.lat),r.lono&&(o=r.lon);return{minLat:s,maxLat:t,minLon:n,maxLon:o}}function ps(e,s){if(e.length<=2)return e;let t=[e[0]],n=e[0];for(let o=1;o=s&&(t.push(r),n=r)}return t.push(e[e.length-1]),t}var it=(()=>{function e(y){let d=0;for(let a=0;a0){let X=y[a-1],se=tn(X.lat,X.lon,G.lat,G.lon);if(d+=se,G.speed==null&&G.time!=null&&X.time!=null){let U=(G.time-X.time)/1e3;U>0&&U<10&&(G.speed=se/U)}if(G.gradient===void 0&&G.ele!=null&&X.ele!=null){let U=G.ele-X.ele;se>.5?G.gradient=U/se*100:G.gradient=X.gradient||0}}G.dist=d}for(let a=1;a0){let $e=y[Pe-1];if(de.ele!=null&&$e.ele!=null){let Ce=de.ele-$e.ele;Ce>0?a.elevGain+=Ce:a.elevLoss-=Ce}(de.gearFront!=null&&de.gearFront!==$e.gearFront||de.gearRear!=null&&de.gearRear!==$e.gearRear)&&_++}de.power!=null&&(G+=de.power,X++,de.power>a.maxPower&&(a.maxPower=de.power)),de.hr!=null&&(se+=de.hr,U++,de.hr>a.maxHR&&(a.maxHR=de.hr)),de.cad!=null&&(ne+=de.cad,Le++),de.speed!=null&&(Re+=de.speed,Be++,de.speed>a.maxSpeed&&(a.maxSpeed=de.speed)),de.battery!=null&&(ae+=de.battery,pe++),de.temp!=null&&(Q=!0,ye+=de.temp,He++,(a.minTemp==null||de.tempa.maxTemp)&&(a.maxTemp=de.temp)),(de.gearFront!=null||de.gearRear!=null)&&(oe=!0)}a.totalDist=y[y.length-1].dist||0,a.avgPower=X?Math.round(G/X):null,a.avgHR=U?Math.round(se/U):null,a.avgCadence=Le?Math.round(ne/Le):null,a.avgSpeed=Be?Re/Be:null,a.avgBattery=pe?Math.round(ae/pe):null,a.avgTemp=He?Number((ye/He).toFixed(1)):null,a.shifts=oe?_:null;let re=y[0].time,K=y[y.length-1].time;return re!=null&&K!=null&&(a.duration=K-re),U&&(a.sensors.push("Heart Rate"),d&&(a.hrZones=R(y),a.hrCurve=m(y))),Le&&a.sensors.push("Cadence"),X&&(a.sensors.push("Power"),d&&(a.powerCurve=c(y),a.powerZones=T(y))),Q&&a.sensors.push("Temperature"),oe&&a.sensors.push("Shifting"),pe&&a.sensors.push("Battery"),a}function o(y){if(!y||!y.points||!y.stats)return;let d=y.points,a=y.stats;a.avgHR!=null&&!a.hrCurve&&(a.hrZones=R(d),a.hrCurve=m(d)),a.avgPower!=null&&!a.powerCurve&&(a.powerCurve=c(d),a.powerZones=T(d))}let r=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800,14400,18e3,21600];function u(y,d){let a=y.length;if(a===0)return null;let G=new Float64Array(a+1);for(let U=0;Ua)continue;let Le=0,Re=0,Be=a-ne;for(let ae=0;ae<=Be;ae++){let pe=G[ae+ne]-G[ae];pe>Le&&(Le=pe,Re=ae)}X[ne]={val:Math.round(Le/ne),idx:Re},se=!0}return se?X:null}function c(y){let d=y.length,a=new Array(d),G=!1;for(let U=0;UG*t);for(let G=1;G10)continue;let ne=X.power;neG===0)?null:d}function b(y){t=y}function w(){return t}function R(y){let d=[0,0,0,0,0];for(let a=1;a10)continue;let U=G.hr;Ua===0)?null:d}function S(y){s=y}function k(){return[...s]}function M(y,d,a){let G=y.indexOf(d);if(G===-1)return null;let X=G+d.length,se=y.indexOf(a,X);if(se===-1)return null;let U=y.slice(X,se).trim();return U!==""?U:null}function g(y,d){let a=y.indexOf(d);if(a===-1)return null;let G=a+d.length,X=y.indexOf('"',G);return X===-1?null:y.slice(G,X)}let I=-1,P=0;function p(y,d,a){for(;dd&&y.charCodeAt(a-1)<=32;)a--;if(d>=a)return null;let G=!1,X=y.charCodeAt(d);X===45?(G=!0,d++):X===43&&d++;let se=0,U=0;for(let ne=d;ne=48&&Le<=57)se=se*10+(Le-48),U++;else break}return U===0?null:G?-se:se}function h(y,d,a){for(;dd&&y.charCodeAt(a-1)<=32;)a--;if(d>=a)return null;let G=!1,X=y.charCodeAt(d);X===45?(G=!0,d++):X===43&&d++;let se=0,U=0,ne=1,Le=!1,Re=0;for(let ae=d;ae=48&&pe<=57)Re++,Le?(U=U*10+(pe-48),ne*=10):se=se*10+(pe-48);else if(pe===46&&!Le)Le=!0;else{let ye=parseFloat(y.slice(d-(G?1:0),a));return Number.isFinite(ye)?ye:null}}if(Re===0)return null;let Be=se+U/ne;return G?-Be:Be}function F(y,d,a){for(;dd&&y.charCodeAt(a-1)<=32;)a--;let G=a-d;if(G>=20&&y.charCodeAt(d+10)===84&&y.charCodeAt(a-1)===90){let se=(y.charCodeAt(d)-48)*1e3+(y.charCodeAt(d+1)-48)*100+(y.charCodeAt(d+2)-48)*10+(y.charCodeAt(d+3)-48),U=(y.charCodeAt(d+5)-48)*10+(y.charCodeAt(d+6)-48),ne=(y.charCodeAt(d+8)-48)*10+(y.charCodeAt(d+9)-48),Le=se<<9|U<<5|ne;Le!==I&&(I=Le,P=Date.UTC(se,U-1,ne));let Re=(y.charCodeAt(d+11)-48)*10+(y.charCodeAt(d+12)-48),Be=(y.charCodeAt(d+14)-48)*10+(y.charCodeAt(d+15)-48),ae=(y.charCodeAt(d+17)-48)*10+(y.charCodeAt(d+18)-48),pe=0;return y.charCodeAt(d+19)===46&&G>=24&&(pe=(y.charCodeAt(d+20)-48)*100+(y.charCodeAt(d+21)-48)*10+(y.charCodeAt(d+22)-48)),P+Re*36e5+Be*6e4+ae*1e3+pe}let X=new Date(y.slice(d,a)).getTime();return Number.isFinite(X)?X:null}function q(y,d,a,G){let X=y.indexOf(G,d);if(X===-1||X>=a)return 0;let se=X+G.length,U=y.indexOf('"',se);return U===-1||U>=a?0:h(y,se,U)??0}function J(y,d){let a=d??new TextDecoder().decode(y),G=a.indexOf(""),U=(se!==-1?M(X.slice(se),"",""):null)||M(X,"","")||"Unnamed Track",ne=X.indexOf(">",X.indexOf("",ye+6);if(He===-1)break;let Q=a.indexOf("",He+1);if(Q===-1)break;Be=Q+8;let _=q(a,ye+6,He+1,'lat="'),oe=q(a,ye+6,He+1,'lon="'),re=null,K=null,Pe=null,de=null,$e=null,Ce=null,We=null,te=null,ge=null,L=null,ee=null,Ne=null,V=He+1;for(;V=Q)break;let xe=a.indexOf(">",he+1);if(xe===-1||xe>=Q)break;let Ee=a.charCodeAt(he+1);if(Ee===47){V=xe+1;continue}let fe=xe-he-1;if(Ee===103&&fe===26&&Pe!==null&&de!==null&&Ce!==null)break;let be=a.indexOf("<",xe+1);if(be===-1||be>Q)break;if(a.charCodeAt(be+1)===47){let Ue=xe+1,je=be;fe===3?Ee===101?re=h(a,Ue,je):Ee===99&&de===null&&(de=p(a,Ue,je)):fe===2?Ee===104&&Pe===null&&(Pe=p(a,Ue,je)):fe===4?Ee===116?a.charCodeAt(he+2)===105?K=F(a,Ue,je):Ce===null&&(Ce=h(a,Ue,je)):Ee===84&&Ce===null&&(Ce=h(a,Ue,je)):fe===5?(Ee===112||Ee===80||Ee===87)&&$e===null?$e=h(a,Ue,je):(Ee===115||Ee===83)&&We===null?We=h(a,Ue,je):Ee===97&&Ce===null&&(Ce=h(a,Ue,je)):fe===7?(Ee===98||Ee===66)&&Ne===null?Ne=p(a,Ue,je):Ee===67&&de===null&&(de=p(a,Ue,je)):fe===8?(Ee===103||Ee===71)&&ge===null&&(ge=p(a,Ue,je)):fe===9?Ee===103?a.charCodeAt(he+8)===104&&Pe===null?Pe=p(a,Ue,je):te===null&&(te=p(a,Ue,je)):Ee===71&&te===null&&(te=p(a,Ue,je)):fe===10?(Ee===103&&de===null||Ee===82&&de===null)&&(de=p(a,Ue,je)):fe===12?Ee===103&&a.charCodeAt(he+8)===97&&Ce===null?Ce=h(a,Ue,je):Ee===80&&$e===null?$e=h(a,Ue,je):Ee===72&&Pe===null&&(Pe=p(a,Ue,je)):fe===13?(Ee===103||Ee===71)&&ee===null&&(ee=p(a,Ue,je)):fe===14?(Ee===103||Ee===71)&&L===null?L=p(a,Ue,je):Ee===65&&Ce===null&&(Ce=h(a,Ue,je)):fe===11&&Ee===84&&Ce===null&&(Ce=h(a,Ue,je));let dt=be+2+fe;if(a.charCodeAt(dt)===62)V=dt+1;else{let It=a.indexOf(">",be+2);V=It!==-1?It+1:be+2}if(Ne!==null&&Pe!==null&&de!==null&&Ce!==null)break}else V=be}let Ae=null;L!=null&&ee!=null&&ee!==0?Ae=L/ee:te!=null&&ge!=null&&ge!==0&&(Ae=te/ge),Re.push({lat:_,lon:oe,ele:re,time:K,hr:Pe,cad:de,power:$e,speed:We,temp:Ce,gearFront:te,gearRear:ge,gearFrontTooth:L,gearRearTooth:ee,battery:Ne,gears:Ae})}if(!Re.length)throw new Error("No track points found in GPX");let ae=e(Re),pe=n(ae);return{name:U,device:Le,format:"gpx",points:ae,stats:pe}}function Y(y,d){let a=d??new TextDecoder().decode(y),G=a.indexOf(""),X=G!==-1?a.slice(0,G):a,se=M(X,"","")||"Unnamed TCX",U=M(X,"",""),ne=U?M(U,"",""):null,Le=[],Re=G!==-1?G:0;for(;Re",Re);if(pe===-1)break;let ye=a.indexOf("",pe+12);if(ye===-1)break;Re=ye+13;let He=null,Q=null,_=null,oe=null,re=null,K=null,Pe=null,de=null,$e=null,Ce=null,We=null,te=null,ge=null,L=null,ee=pe+12;for(;ee=ye)break;let Ae=a.indexOf(">",V+1);if(Ae===-1||Ae>=ye)break;let he=a.charCodeAt(V+1);if(he===47){ee=Ae+1;continue}let xe=Ae-V-1,Ee=a.indexOf("<",Ae+1);if(Ee===-1||Ee>ye)break;if(a.charCodeAt(Ee+1)===47){let fe=Ae+1,be=Ee;xe===4?he===84?a.charCodeAt(V+2)===105?oe=F(a,fe,be):$e===null&&($e=h(a,fe,be)):he===116&&$e===null&&($e=h(a,fe,be)):xe===5?he===86&&re===null?re=p(a,fe,be):(he===87||he===80||he===112)&&Pe===null?Pe=h(a,fe,be):(he===83||he===115)&&de===null?de=h(a,fe,be):he===97&&$e===null&&($e=h(a,fe,be)):xe===7?he===67&&K===null?K=p(a,fe,be):(he===66||he===98)&&L===null&&(L=p(a,fe,be)):xe===8?(he===71||he===103)&&We===null&&(We=p(a,fe,be)):xe===9?(he===71||he===103)&&Ce===null&&(Ce=p(a,fe,be)):xe===10?he===82&&K===null&&(K=p(a,fe,be)):xe===11?he===84&&$e===null&&($e=h(a,fe,be)):xe===13?(he===71||he===103)&&ge===null&&(ge=p(a,fe,be)):xe===14?he===65?a.charCodeAt(V+2)===108?_=h(a,fe,be):$e===null&&($e=h(a,fe,be)):(he===71||he===103)&&te===null&&(te=p(a,fe,be)):xe===15?he===76&&(He=h(a,fe,be)):xe===16?he===76&&(Q=h(a,fe,be)):xe===2&&he===104&&re===null?re=p(a,fe,be):xe===3&&he===99&&K===null?K=p(a,fe,be):xe===12&&(he===72&&re===null?re=p(a,fe,be):he===80&&Pe===null&&(Pe=h(a,fe,be)));let Ue=Ee+2+xe;if(a.charCodeAt(Ue)===62)ee=Ue+1;else{let je=a.indexOf(">",Ee+2);ee=je!==-1?je+1:Ee+2}if(L!==null&&re!==null&&K!==null&&$e!==null)break}else ee=Ee}if(He==null||Q==null)continue;let Ne=null;te!=null&&ge!=null&&ge!==0?Ne=te/ge:Ce!=null&&We!=null&&We!==0&&(Ne=Ce/We),Le.push({lat:He,lon:Q,ele:_,time:oe,hr:re,cad:K,power:Pe,speed:de,temp:$e,gearFront:Ce,gearRear:We,gearFrontTooth:te,gearRearTooth:ge,battery:L,gears:Ne})}let Be=e(Le),ae=n(Be);return{name:se,device:ne,format:"tcx",points:Be,stats:ae}}function B(y){if(y.byteLength<14)return null;let d=new DataView(y),a=d.getUint8(0);if(a<12||a+2>y.byteLength||d.getUint8(8)!==46||d.getUint8(9)!==70||d.getUint8(10)!==73||d.getUint8(11)!==84)return null;let G=d.getUint32(4,!0),X=Math.min(y.byteLength,a+G),se=631065600,U=180/Math.pow(2,31),ne=new Array(16),Le=[],Re=[],Be=[],ae=[],pe=[],ye=a;for(;yeX)return null;ye++;let oe=d.getUint8(ye++)===0,re=d.getUint16(ye,oe);ye+=2;let K=d.getUint8(ye++);if(ye+K*3>X)return null;let Pe=new Array(K),de=0;for(let $e=0;$eX)return null;let oe=_.littleEndian,re=_.globalMsgNum;if(re===20&&_.fields.length===10&&_.recordSize===25&&_.fields[0].num===253&&_.fields[1].num===0){let de=d.getUint32(ye,oe),$e=d.getInt32(ye+4,oe),Ce=d.getInt32(ye+8,oe),We=d.getUint16(ye+12,oe),te=d.getUint8(ye+14),ge=d.getUint8(ye+15),L=d.getUint32(ye+16,oe),ee=d.getUint16(ye+20,oe),Ne=d.getUint16(ye+22,oe),V=d.getInt8(ye+24);Be.push({timestamp:(de+se)*1e3,position_lat:$e*U,position_long:Ce*U,altitude:We/5-500,heart_rate:te,cadence:ge,distance:L/100,speed:ee/1e3*3.6,power:Ne,temperature:V}),ye+=25;continue}let K={},Pe=ye;for(let de=0;de<_.fields.length;de++){let $e=_.fields[de],Ce=0,We=$e.type&31;$e.size===1?Ce=We===1?d.getInt8(Pe):d.getUint8(Pe):$e.size===2?Ce=We===3?d.getInt16(Pe,oe):d.getUint16(Pe,oe):$e.size===4&&(Ce=We===5?d.getInt32(Pe,oe):d.getUint32(Pe,oe)),K[$e.num]=Ce,Pe+=$e.size}if(ye+=_.recordSize,re===0)Le.push({type:K[0]===4?"activity":K[0],manufacturer:K[1]===1?"garmin":K[1],product:K[2],time_created:K[4]!=null?(K[4]+se)*1e3:void 0});else if(re===18){let de={0:"generic",1:"running",2:"cycling"};Re.push({start_time:K[2]!=null?(K[2]+se)*1e3:void 0,sport:de[K[5]]??String(K[5]),sub_sport:K[6]===0?"generic":String(K[6])})}else if(re===20)Be.push({timestamp:K[253]!=null?(K[253]+se)*1e3:void 0,position_lat:K[0]!=null?K[0]*U:void 0,position_long:K[1]!=null?K[1]*U:void 0,altitude:K[2]!=null?K[2]/5-500:void 0,heart_rate:K[3],cadence:K[4],distance:K[5]!=null?K[5]/100:void 0,speed:K[6]!=null?K[6]/1e3*3.6:void 0,power:K[7],temperature:K[13]});else if(re===21){let de=K[0]===43?"rear_gear_change":K[0]===42?"front_gear_change":String(K[0]);ae.push({timestamp:K[253]!=null?(K[253]+se)*1e3:void 0,event:de,event_type:K[1]===3?"marker":String(K[1]),data:K[3],front_gear_num:K[9],rear_gear_num:K[11]})}else if(re===23)pe.push({timestamp:K[253]!=null?(K[253]+se)*1e3:void 0,battery_level:K[32]});else return null}}return{file_ids:Le,sessions:Re,sports:[],records:Be,events:ae,device_infos:pe}}function z(y){return new Promise((d,a)=>{let G=(U,ne)=>{if(U){a(U);return}try{let Le=ne.sessions?.[0]?.start_time?`Fit Activity ${new Date(ne.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",Re=null,Be=[],ae=null,pe=null;ne.sports?.[0]?(ae=ne.sports[0].sport,pe=ne.sports[0].sub_sport):ne.sessions?.[0]&&(ae=ne.sessions[0].sport,pe=ne.sessions[0].sub_sport);let ye=L=>L.product_name||L.garmin_product||L.product||L.device_type||L.manufacturer||null;if(ne.file_ids?.[0]){let L=ne.file_ids[0];Re=ye(L),Be.push({name:L.product_name||L.garmin_product||L.product,manufacturer:L.manufacturer,serial:L.serial_number?String(L.serial_number):void 0,version:L.software_version?String(L.software_version):void 0,type:"main"})}ne.device_infos&&ne.device_infos.forEach(L=>{if(L.device_index==="creator"||L.device_index===0){let Ne=ye(L);(L.product_name||L.garmin_product||!Re)&&(Re=Ne),Be.length>0&&Be[0].type==="main"&&((L.product_name||L.garmin_product||!Be[0].name)&&(Be[0].name=L.product_name||L.garmin_product||L.product),Be[0].manufacturer||(Be[0].manufacturer=L.manufacturer),!Be[0].serial&&L.serial_number&&(Be[0].serial=String(L.serial_number)),!Be[0].version&&L.software_version&&(Be[0].version=String(L.software_version)),!Be[0].hardwareVersion&&L.hardware_version&&(Be[0].hardwareVersion=String(L.hardware_version)));return}Be.push({name:L.product_name||L.garmin_product||L.product||L.device_type||"Sensor",manufacturer:L.manufacturer,serial:L.serial_number?String(L.serial_number):void 0,version:L.software_version?String(L.software_version):void 0,hardwareVersion:L.hardware_version?String(L.hardware_version):void 0,type:L.device_type||"sensor",batteryStatus:L.battery_status,batteryVoltage:L.battery_voltage,batteryLevel:L.battery_level,sourceType:L.source_type!=null?String(L.source_type):void 0})}),ne.sensor_settings&&ne.sensor_settings.forEach(L=>{let ee=L.name||L.product||L.sensor_type;if(!ee)return;let Ne=L.ant_id?String(L.ant_id):void 0,V=Be.find(Ae=>Ne&&Ae.serial===Ne||Ae.name===ee&&Ae.manufacturer===L.manufacturer);V?(V.name||(V.name=ee),V.manufacturer||(V.manufacturer=L.manufacturer),V.type||(V.type=L.sensor_type),V.sourceType||(V.sourceType=L.connection_type!=null?String(L.connection_type):void 0)):Be.push({name:ee,manufacturer:L.manufacturer,serial:Ne,type:L.sensor_type||"sensor",sourceType:L.connection_type!=null?String(L.connection_type):void 0})});let He=[];ne.device_statuses&&(ne.device_statuses.forEach((L,ee)=>{L.timestamp&&L.battery_level!=null&&He.push({time:typeof L.timestamp=="number"?L.timestamp:new Date(L.timestamp).getTime(),level:L.battery_level,idx:ee})}),He.sort((L,ee)=>L.time-ee.time||L.idx-ee.idx));let Q=[];ne.events&&(ne.events.forEach((L,ee)=>{let Ne=L.front_gear_num??L.front_gear??null,V=L.rear_gear_num??L.rear_gear??null,Ae=L.front_gear_num_tooth??null,he=L.rear_gear_num_tooth??null;if(L.event==="rear_gear_change"||L.event==="front_gear_change"){let xe=L.data;if(xe!=null){let Ee=xe>>24&255,fe=xe>>16&255,be=xe>>8&255,Ue=xe&255;fe!==0&&(Ne=fe),Ee!==0&&(Ae=Ee),Ue!==0&&(V=Ue),be!==0&&(he=be)}}L.timestamp&&(Ne!=null||V!=null||Ae!=null||he!=null)&&Q.push({time:typeof L.timestamp=="number"?L.timestamp:new Date(L.timestamp).getTime(),front:Ne,rear:V,frontTooth:Ae,rearTooth:he,idx:ee})}),Q.sort((L,ee)=>L.time-ee.time||L.idx-ee.idx));let _=ne.records||[],oe=null,re=0,K=null,Pe=null,de=null,$e=null,Ce=0,We=[];for(let L=0;L<_.length;L++){let ee=_[L],Ne=ee.position_lat,V=ee.position_long;if(Ne==null||V==null)continue;let Ae=ee.timestamp!=null?typeof ee.timestamp=="number"?ee.timestamp:ee.timestamp instanceof Date?ee.timestamp.getTime():new Date(ee.timestamp).getTime():null,he=ee.speed!=null?ee.speed/3.6:null,xe=ee.battery_level??null;if(xe==null&&Ae){for(;re name, Placemark > name");X&&(G=X.textContent?.trim()||G);let se=a.querySelectorAll("coordinates");if(!se.length)throw new Error("No coordinates found in KML");let U=[];if(se.forEach(Re=>{(Re.textContent?.trim().split(/\s+/)||[]).forEach(ae=>{let pe=ae.split(",");if(pe.length<2)return;let ye=parseFloat(pe[0]),He=parseFloat(pe[1]),Q=pe.length>2?parseFloat(pe[2]):null;isNaN(He)||isNaN(ye)||U.push({lat:He,lon:ye,ele:Q!=null&&isNaN(Q)?null:Q,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!U.length)throw new Error("No valid coordinates in KML");let ne=e(U),Le=n(ne);return{name:G,format:"kml",points:ne,stats:Le}}async function le(y){let d=y.name.split(".").pop()?.toLowerCase(),a=y._buf??await y.arrayBuffer(),G=y._text,X;switch(d){case"gpx":X=J(a,G);break;case"tcx":X=Y(a,G);break;case"fit":X=await z(a);break;case"kml":X=D(a);break;default:throw new Error(`Unsupported format: .${d}`)}return X&&(X.fileName=y.name,X.fileSize=y.size),X}return{parseFile:le,computeStats:n,ensureCurvesAndZones:o,calculatePowerCurve:c,calculateHRCurve:m,calculatePowerZones:T,calculateHRZones:R,enrichPoints:e,setHRZones:S,getHRZones:k,setFTP:b,getFTP:w}})();var _e=(()=>{let e={},s=null;function t(D,le,y,d,a){}function n(D){}function o(D){e[D.id]=D}function r(D){D.forEach(le=>{e[le.id]=le})}function u(D){delete e[D]}function c(){e={}}function m(){e={}}function T(D,le){}function b(D,le){}function w(){}function R(D){}function S(D,le){}function k(){}function M(D,le,y,d,a,G){}function g(){}function I(D,le){}function P(D){}function p(D,le,y,d){}function h(){}function F(){}function q(){return[0,0,0]}function J(D,le,y){}function Y(D,le,y){}function B(D){}function z(D,le){return Object.keys(e)}return{init:t,getMap:()=>null,setCustomClickHandler:D=>{s=D},switchBasemap:n,addTrack:o,addTracks:r,removeTrack:u,clearTracks:c,removeAllTracks:m,setTrackVisible:T,setSelectedTrack:b,fitAll:w,fitTrack:R,showCursorAt:S,hideCursor:k,highlightSegment:M,clearHighlight:g,setTrackHover:I,ensureVisible:P,centerOn:p,closePopup:h,invalidateSize:F,getPosition:q,setPosition:J,colorTrackByMetric:Y,clearMetricColor:B,findTracksPassingThroughPoints:z,getTrackData:D=>e[D]}})();import Us from"uplot";var gn=(()=>{function e(){let t=it.getFTP(),n=[.55,.75,.9,1.05,1.2,1.5].map(m=>m*t),o=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],r=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],u=[],c=0;for(let m=0;ms?e.toFixed(1):Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:De.speed.color,abbr:"spd",icon:De.speed.icon,fmt:e=>(e*3.6).toFixed(1),fmtAxis:e=>(e*3.6).toFixed(0),transform:e=>e,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:De.gradient.color,abbr:"grad",icon:De.gradient.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>e.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:De.power.color,abbr:"pwr",icon:De.power.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:De.hr.color,abbr:"hr",icon:De.hr.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:De.cadence.color,abbr:"cad",icon:De.cadence.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:De.temperature.color,abbr:"temp",icon:De.temperature.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>Math.round(e).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:De.gearRear.color,abbr:"rgr",icon:De.gearRear.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:De.gearFront.color,abbr:"fgr",icon:De.gearFront.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gears:{label:"Gears",field:"gears",unit:"",color:De.gears.color,abbr:"gr",icon:De.gears.icon,fmt:e=>e.toFixed(2),fmtAxis:e=>e.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:De.battery.color,abbr:"bat",icon:De.battery.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString(),smoothSigma:5,compute:(e,s)=>{let t=new Array(e.length).fill(null);for(let n=1;n0&&(t[n]=u/c*3600)}}return s(t)}}};var Wt={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function zs(e){if(!e)return"question_mark";let s=e.toLowerCase();return Wt[s]?.icon||"exercise"}var Me=(()=>{let e=[],s=null,t="time",n="speed",o=null,r=null,u=!1,c=!1,m=new Set(["elevation"]),T=new Set,b=new Set(["speed","gradient","vam","temperature"]),w=new Set(["power"]),R="time",S=null,k=[],M=null,g=null,I=!1,P=!1,p=null,h=null,F=null,q=null,J=null,Y=null,B=null,z=null,D=null,le=null,y=null,d=null,a=130,G=28,X=20,se=!0,U=null,ne=null,Le=null,Re=null,Be=null,ae=null,pe=null;function ye(l,i,f,v){D=l,le=i,y=f,d=v,ne=document.getElementById("charts-container"),ne?.addEventListener("scroll",()=>{F&&J&&q&&pn(F,J,q)}),Le=document.getElementById("chart-empty"),Re=document.getElementById("chart-stats-sel"),Be=document.getElementById("btn-reset-selection"),U=document.getElementById("hist-tooltip"),r=Us.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",ee),Be?.classList.add("hidden");let $=new Set(["w","a","s","d"]),x=new Set;document.addEventListener("keydown",A=>{if(!e.length||!S||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let E=A.key.toLowerCase();if(!$.has(E))return;A.preventDefault(),x.add(E);let H=e[0].uplot;B||(B=[H.scales.x.min,H.scales.x.max]);let[O,N]=B,j=(N-O)*.1,ue=.15,C=O,Se=N;if(E==="a")C=O-j,Se=N-j;else if(E==="d")C=O+j,Se=N+j;else if(E==="w"||E==="s"){let ce=h!==null?h:(O+N)/2,Fe=E==="w"?1-ue:1+ue*1.2;C=ce-(ce-O)*Fe,Se=ce+(N-ce)*Fe}let ke=[e[0].xData[0],e[0].xData[e[0].xData.length-1]];if(Cke[1]){let ce=Se-ke[1];C-=ce,Se-=ce}C=Math.max(ke[0],C),Se=Math.min(ke[1],Se),Se-C>.001&&(B=[C,Se],He(C,Se,!0))}),document.addEventListener("keyup",A=>{let E=A.key.toLowerCase();$.has(E)&&x.delete(E)})}function He(l,i,f=!1){if(!e.length)return;if(!f){e.forEach(({uplot:H})=>H.setScale("x",{min:l,max:i}));return}let v=Y?Y[0]:e[0].uplot.scales.x.min,$=Y?Y[1]:e[0].uplot.scales.x.max;z&&cancelAnimationFrame(z);let x=(H,O,N)=>H+(O-H)*N,A=.25,E=()=>{if(!B)return;let[H,O]=B,N=x(Y[0],H,A),W=x(Y[1],O,A);e.forEach(({uplot:j})=>{j.setScale("x",{min:N,max:W})}),Math.abs(N-H)>1e-4||Math.abs(W-O)>1e-4?z=requestAnimationFrame(E):z=null};z=requestAnimationFrame(E)}function Q(l,i=[],f=!1){p=null,M=null,g=null,k=i,T=new Set(Object.entries(_t).filter(([,v])=>l.points.some($=>$[v.field]!=null)).map(([v])=>v)),m.size===0&&(m=new Set(["elevation"].filter(v=>T.has(v)))),document.querySelectorAll(".metric-pill").forEach(v=>{let $=v,x=$.dataset.metric,A=T.has(x);$.classList.toggle("active",A&&m.has(x)),$.classList.toggle("disabled",!A)}),S=l,f?Ps(l):xe()}function _(){p=null,M=null,g=null,S=null,$n(),Le&&(Le.style.display="flex",Le.innerHTML=` +var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(location.search),M={};f.has("track")&&(M.track=f.get("track")),f.has("map")&&(M.map=f.get("map")),f.has("xaxis")&&(M.xaxis=f.get("xaxis")),f.has("tab")&&(M.tab=f.get("tab")),f.has("sel_point")&&(M.sel_point=Number(f.get("sel_point"))),f.has("speed_mode")&&(M.speed_mode=f.get("speed_mode")),f.has("progress")&&(M.progress=f.get("progress"));let O=f.get("metrics");if(O&&(M.metrics=O.split(",").filter(Boolean)),f.has("f_date")&&(M.f_date=f.get("f_date").split(",").map(H=>H||null)),f.has("f_dist")&&(M.f_dist=f.get("f_dist").split(",").map(H=>H?Number(H):null)),f.has("f_dur")&&(M.f_dur=f.get("f_dur").split(",").map(H=>H?Number(H):null)),f.has("f_mets")&&(M.f_mets=f.get("f_mets").split(",")),f.has("f_tags")&&(M.f_tags=f.get("f_tags").split(",")),f.has("q")&&(M.q=f.get("q")),f.has("re")&&(M.re=f.get("re")==="1"),f.has("sort")){let H=f.get("sort"),E=H.startsWith("-"),k=E?H.substring(1):H;M.sort=`${k}-${E?"desc":"asc"}`}if(f.has("map_pos")){let H=f.get("map_pos").split(",").map(Number);H.length===3&&H.every(isFinite)&&(M.map_pos=H)}if(f.has("storage")&&(M.storage=f.get("storage")),f.has("sel")){let H=f.get("sel").split(",").map(Number);H.length===2&&H.every(E=>!isNaN(E)&&isFinite(E))&&(M.sel=H)}return M}function a(){t&&(clearTimeout(t),t=null);let f=new URLSearchParams;if(e.track&&f.set("track",e.track),e.map&&f.set("map",e.map),e.xaxis&&e.xaxis!=="time"&&f.set("xaxis",e.xaxis),e.tab&&e.tab!=="graphs"&&f.set("tab",e.tab),e.storage&&e.storage!=="memory"&&f.set("storage",e.storage),e.sel_point!==void 0&&f.set("sel_point",String(e.sel_point)),e.speed_mode&&f.set("speed_mode",e.speed_mode),e.q&&f.set("q",e.q),e.progress&&f.set("progress",e.progress),e.re&&f.set("re","1"),e.sort){let O=e.sort.split("-"),H=O[0],E=O[1];f.set("sort",(E==="desc"?"-":"")+H)}let M=f.toString();if(e.metrics&&(M+=`${M?"&":""}metrics=${e.metrics.join(",")}`),e.f_date&&(M+=`${M?"&":""}f_date=${e.f_date.map(O=>O||"").join(",")}`),e.f_dist&&(M+=`${M?"&":""}f_dist=${e.f_dist.map(O=>O??"").join(",")}`),e.f_dur&&(M+=`${M?"&":""}f_dur=${e.f_dur.map(O=>O??"").join(",")}`),e.f_mets&&(M+=`${M?"&":""}f_mets=${e.f_mets.join(",")}`),e.f_tags&&(M+=`${M?"&":""}f_tags=${e.f_tags.join(",")}`),e.map_pos){let O=`${(+e.map_pos[0]).toFixed(5)},${(+e.map_pos[1]).toFixed(5)},${e.map_pos[2]}`;M+=`${M?"&":""}map_pos=${O}`}if(e.sel){let O=`${+e.sel[0].toFixed(4)},${+e.sel[1].toFixed(4)}`;M+=`${M?"&":""}sel=${O}`}if(M!==n){let O=location.pathname+(M?`?${M}`:"");try{s?(history.pushState(null,"",O),s=!1):history.replaceState(null,"",O)}catch{s=!1}n=M}}e=o();function g(){return{...e}}function c(f,M=!1){M&&(s=!0);for(let[O,H]of Object.entries(f)){let E=O;H==null?delete e[E]:e[E]=H}a()}function m(){e=o()}function T(){t&&(clearTimeout(t),t=null),e={},s=!1,n="";try{history.replaceState(null,"",location.pathname)}catch{}}return{get:g,patch:c,refresh:m,reset:T}})();var fs=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(n){return this.trackStore.set(n.id,n),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(n){return this.trackStore.delete(n),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(n,t){return this.settingStore.set(n,t),Promise.resolve()}async get(n){return Promise.resolve(this.settingStore.get(n)??null)}},_s=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((n,t)=>{let s=indexedDB.open(this.DB_NAME,this.DB_VERSION);s.onupgradeneeded=()=>{let o=s.result;o.objectStoreNames.contains("tracks")||o.createObjectStore("tracks",{keyPath:"id"}),o.objectStoreNames.contains("settings")||o.createObjectStore("settings")},s.onsuccess=()=>{this.db=s.result,n()},s.onerror=()=>t(s.error)})}getStore(n,t){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(n,t).objectStore(n)}async save(n){return new Promise((t,s)=>{let o=this.getStore("tracks","readwrite").put(n);o.onsuccess=()=>t(),o.onerror=()=>s(o.error)})}async getAll(){return new Promise((n,t)=>{let s=this.getStore("tracks","readonly").getAll();s.onsuccess=()=>n(s.result||[]),s.onerror=()=>t(s.error)})}async remove(n){return new Promise((t,s)=>{let o=this.getStore("tracks","readwrite").delete(n);o.onsuccess=()=>t(),o.onerror=()=>s(o.error)})}async clear(){return this.db?new Promise((n,t)=>{let s=this.db.transaction(["tracks","settings"],"readwrite");s.objectStore("tracks").clear(),s.objectStore("settings").clear(),s.oncomplete=()=>n(),s.onerror=()=>t(s.error)}):Promise.resolve()}async set(n,t){return new Promise((s,o)=>{let a=this.getStore("settings","readwrite").put(t,n);a.onsuccess=()=>s(),a.onerror=()=>o(a.error)})}async get(n){return new Promise((t,s)=>{let o=this.getStore("settings","readonly").get(n);o.onsuccess=()=>t(o.result??null),o.onerror=()=>s(o.error)})}},nn=new fs,at={openDB:async()=>{nn=Ye.get().storage==="indexeddb"?new _s:new fs,await nn.openDB()},save:e=>nn.save(e),getAll:()=>nn.getAll(),remove:e=>nn.remove(e),clear:()=>nn.clear(),set:(e,n)=>nn.set(e,n),get:e=>nn.get(e)};import Mo from"fit-file-parser";function sn(e,n,t,s){let a=e*Math.PI/180,g=t*Math.PI/180,c=(t-e)*Math.PI/180,m=(s-n)*Math.PI/180,T=Math.sin(c/2)*Math.sin(c/2)+Math.cos(a)*Math.cos(g)*Math.sin(m/2)*Math.sin(m/2);return 6371e3*(2*Math.atan2(Math.sqrt(T),Math.sqrt(1-T)))}function pl(e){let n=new Uint32Array([Math.floor(e/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(n.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function fl(){return Math.random().toString(36).slice(2,6)}function Bt(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:`${Math.round(e/3600)}h`}function ht(e){let n=Math.floor(e/3600),t=Math.floor(e%3600/60);return n>0?`${n}h ${t}m`:`${t}m ${Math.floor(e%60)}s`}function Vn(e){if(e==null||!isFinite(e))return"--";let n=Math.floor(e/60),t=Math.round(e%60);return`${n}:${t.toString().padStart(2,"0")}`}function Gt(e){let n=new Date(e);return isNaN(n.getTime())?"Unknown date":n.toISOString().split("T")[0]}function gl(e){let n=new Date(e);if(isNaN(n.getTime()))return"Unknown";let t=n.toISOString();return`${t.split("T")[0]} ${t.split("T")[1].slice(0,5)}`}function hl(e){if(e===0)return"0 B";let n=1024,t=["B","KB","MB","GB"],s=Math.floor(Math.log(e)/Math.log(n));return`${parseFloat((e/Math.pow(n,s)).toFixed(2))} ${t[s]}`}function pt(e){return String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function gs(e){let n=0;for(let s=0;s=0&&M0?m/T:e[c]}return g}function tt(e,n=1){let t=parseInt(e.slice(1,3),16),s=parseInt(e.slice(3,5),16),o=parseInt(e.slice(5,7),16);return`rgba(${t}, ${s}, ${o}, ${n})`}function hs(e){if(!e.length)return null;let n=e[0].lat,t=e[0].lat,s=e[0].lon,o=e[0].lon;for(let a of e)a.latt&&(t=a.lat),a.lono&&(o=a.lon);return{minLat:n,maxLat:t,minLon:s,maxLon:o}}var $t=16384,ko=new Float64Array($t),Co=new Float64Array($t),$o=new Float64Array($t),Lo=new Float64Array($t),Po=new Float64Array($t),Ao=new Float64Array($t),Io=new Float64Array($t);function bs(e,n){let t=e.length;if(t<=2)return e;let s=t<=$t?ko:new Float64Array(t),o=t<=$t?Co:new Float64Array(t),a=t<=$t?$o:new Float64Array(t),g=t<=$t?Lo:new Float64Array(t);for(let H=0;H=k){let W=p+P>>1,_=(o[W]-(o[p]+o[P])*.5)*b,C=s[W]-(s[p]+s[P])*.5;m+=Math.sqrt(_*_+C*C)+(g[P]-g[p])*1e-6,p=P}}}let f=[e[0]],M=e[0],O=m<-1e9?1e-9:0;for(let H=1;H=n&&(f.push(E),M=E)}return f.push(e[t-1]),f}var ot=(()=>{function e(y){let d=y.length,r=0;for(let J=0;J0){let Q=y[J-1],Y=sn(Q.lat,Q.lon,U.lat,U.lon);if(r+=Y,U.speed==null&&U.time!=null&&Q.time!=null){let K=(U.time-Q.time)/1e3;K>0&&K<10&&(U.speed=Y/K)}if(U.gradient===void 0&&U.ele!=null&&Q.ele!=null){let K=U.ele-Q.ele;Y>.5?U.gradient=K/Y*100:U.gradient=Q.gradient||0}}U.dist=r}if(d>2){let J=d<=$t?Po:new Float64Array(d),U=d<=$t?Ao:new Float64Array(d),Q=d<=$t?Io:new Float64Array(d);for(let me=0;me=de){Pe-=U[F-de],G-=Q[F-de];let ae=Pe*xe,ue=J[F]-J[F-de],te=1.225*Math.exp(-J[F]*Fe),Ie=Math.atan2(ue,(G+1)*.5);K+=ae*ae*te*1e-4+Ie*(G*xe)*.01}}}let Ae=K<-1e12?1e-9:0;for(let me=1;me0){let He=y[Ie-1];if(he.ele!=null&&He.ele!=null){let Ce=he.ele-He.ele;Ce>0?r.elevGain+=Ce:r.elevLoss-=Ce}(he.gearFront!=null&&he.gearFront!==He.gearFront||he.gearRear!=null&&he.gearRear!==He.gearRear)&&F++}he.power!=null&&(J+=he.power,U++,he.power>r.maxPower&&(r.maxPower=he.power)),he.hr!=null&&(Q+=he.hr,Y++,he.hr>r.maxHR&&(r.maxHR=he.hr)),he.cad!=null&&(K+=he.cad,Ae++),he.speed!=null&&(me+=he.speed,Fe++,he.speed>r.maxSpeed&&(r.maxSpeed=he.speed)),he.battery!=null&&(oe+=he.battery,de++),he.temp!=null&&(G=!0,xe+=he.temp,Pe++,(r.minTemp==null||he.tempr.maxTemp)&&(r.maxTemp=he.temp)),(he.gearFront!=null||he.gearRear!=null)&&(ae=!0)}r.totalDist=y[y.length-1].dist||0,r.avgPower=U?Math.round(J/U):null,r.avgHR=Y?Math.round(Q/Y):null,r.avgCadence=Ae?Math.round(K/Ae):null,r.avgSpeed=Fe?me/Fe:null,r.avgBattery=de?Math.round(oe/de):null,r.avgTemp=Pe?Number((xe/Pe).toFixed(1)):null,r.shifts=ae?F:null;let ue=y[0].time,te=y[y.length-1].time;return ue!=null&&te!=null&&(r.duration=te-ue),Y&&(r.sensors.push("Heart Rate"),d&&(r.hrZones=O(y),r.hrCurve=m(y))),Ae&&r.sensors.push("Cadence"),U&&(r.sensors.push("Power"),d&&(r.powerCurve=c(y),r.powerZones=T(y))),G&&r.sensors.push("Temperature"),ae&&r.sensors.push("Shifting"),de&&r.sensors.push("Battery"),r}function o(y){if(!y||!y.points||!y.stats)return;let d=y.points,r=y.stats;r.avgHR!=null&&!r.hrCurve&&(r.hrZones=O(d),r.hrCurve=m(d)),r.avgPower!=null&&!r.powerCurve&&(r.powerCurve=c(d),r.powerZones=T(d))}let a=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800,14400,18e3,21600];function g(y,d){let r=y.length;if(r===0)return null;let J=new Float64Array(r+1);for(let Y=0;Yr)continue;let Ae=0,me=0,Fe=r-K;for(let oe=0;oe<=Fe;oe++){let de=J[oe+K]-J[oe];de>Ae&&(Ae=de,me=oe)}U[K]={val:Math.round(Ae/K),idx:me},Q=!0}return Q?U:null}function c(y){let d=y.length,r=new Array(d),J=!1;for(let Y=0;YJ*t);for(let J=1;J10)continue;let K=U.power;KJ===0)?null:d}function f(y){t=y}function M(){return t}function O(y){let d=[0,0,0,0,0];for(let r=1;r10)continue;let Y=J.hr;Yr===0)?null:d}function H(y){n=y}function E(){return[...n]}function k(y,d,r){let J=y.indexOf(d);if(J===-1)return null;let U=J+d.length,Q=y.indexOf(r,U);if(Q===-1)return null;let Y=y.slice(U,Q).trim();return Y!==""?Y:null}function p(y,d){let r=y.indexOf(d);if(r===-1)return null;let J=r+d.length,U=y.indexOf('"',J);return U===-1?null:y.slice(J,U)}let P=-1,b=0;function u(y,d,r){for(;dd&&y.charCodeAt(r-1)<=32;)r--;if(d>=r)return null;let J=!1,U=y.charCodeAt(d);U===45?(J=!0,d++):U===43&&d++;let Q=0,Y=0;for(let K=d;K=48&&Ae<=57)Q=Q*10+(Ae-48),Y++;else break}return Y===0?null:J?-Q:Q}function x(y,d,r){for(;dd&&y.charCodeAt(r-1)<=32;)r--;if(d>=r)return null;let J=!1,U=y.charCodeAt(d);U===45?(J=!0,d++):U===43&&d++;let Q=0,Y=0,K=1,Ae=!1,me=0;for(let oe=d;oe=48&&de<=57)me++,Ae?(Y=Y*10+(de-48),K*=10):Q=Q*10+(de-48);else if(de===46&&!Ae)Ae=!0;else{let xe=parseFloat(y.slice(d-(J?1:0),r));return Number.isFinite(xe)?xe:null}}if(me===0)return null;let Fe=Q+Y/K;return J?-Fe:Fe}function w(y,d,r){for(;dd&&y.charCodeAt(r-1)<=32;)r--;let J=r-d;if(J>=20&&y.charCodeAt(d+10)===84&&y.charCodeAt(r-1)===90){let Q=(y.charCodeAt(d)-48)*1e3+(y.charCodeAt(d+1)-48)*100+(y.charCodeAt(d+2)-48)*10+(y.charCodeAt(d+3)-48),Y=(y.charCodeAt(d+5)-48)*10+(y.charCodeAt(d+6)-48),K=(y.charCodeAt(d+8)-48)*10+(y.charCodeAt(d+9)-48),Ae=Q<<9|Y<<5|K;Ae!==P&&(P=Ae,b=Date.UTC(Q,Y-1,K));let me=(y.charCodeAt(d+11)-48)*10+(y.charCodeAt(d+12)-48),Fe=(y.charCodeAt(d+14)-48)*10+(y.charCodeAt(d+15)-48),oe=(y.charCodeAt(d+17)-48)*10+(y.charCodeAt(d+18)-48),de=0;return y.charCodeAt(d+19)===46&&J>=24&&(de=(y.charCodeAt(d+20)-48)*100+(y.charCodeAt(d+21)-48)*10+(y.charCodeAt(d+22)-48)),b+me*36e5+Fe*6e4+oe*1e3+de}let U=new Date(y.slice(d,r)).getTime();return Number.isFinite(U)?U:null}function D(y,d,r,J){let U=y.indexOf(J,d);if(U===-1||U>=r)return 0;let Q=U+J.length,Y=y.indexOf('"',Q);return Y===-1||Y>=r?0:x(y,Q,Y)??0}function W(y,d){let r=d??new TextDecoder().decode(y),J=r.indexOf(""),Y=(Q!==-1?k(U.slice(Q),"",""):null)||k(U,"","")||"Unnamed Track",K=U.indexOf(">",U.indexOf("",xe+6);if(Pe===-1)break;let G=r.indexOf("",Pe+1);if(G===-1)break;Fe=G+8;let F=D(r,xe+6,Pe+1,'lat="'),ae=D(r,xe+6,Pe+1,'lon="'),ue=null,te=null,Ie=null,he=null,He=null,Ce=null,Re=null,le=null,be=null,A=null,ne=null,Ne=null,j=Pe+1;for(;j=G)break;let Ee=r.indexOf(">",we+1);if(Ee===-1||Ee>=G)break;let ke=r.charCodeAt(we+1);if(ke===47){j=Ee+1;continue}let ve=Ee-we-1;if(ke===103&&ve===26&&Ie!==null&&he!==null&&Ce!==null)break;let Me=r.indexOf("<",Ee+1);if(Me===-1||Me>G)break;if(r.charCodeAt(Me+1)===47){let Ue=Ee+1,je=Me;ve===3?ke===101?ue=x(r,Ue,je):ke===99&&he===null&&(he=u(r,Ue,je)):ve===2?ke===104&&Ie===null&&(Ie=u(r,Ue,je)):ve===4?ke===116?r.charCodeAt(we+2)===105?te=w(r,Ue,je):Ce===null&&(Ce=x(r,Ue,je)):ke===84&&Ce===null&&(Ce=x(r,Ue,je)):ve===5?(ke===112||ke===80||ke===87)&&He===null?He=x(r,Ue,je):(ke===115||ke===83)&&Re===null?Re=x(r,Ue,je):ke===97&&Ce===null&&(Ce=x(r,Ue,je)):ve===7?(ke===98||ke===66)&&Ne===null?Ne=u(r,Ue,je):ke===67&&he===null&&(he=u(r,Ue,je)):ve===8?(ke===103||ke===71)&&be===null&&(be=u(r,Ue,je)):ve===9?ke===103?r.charCodeAt(we+8)===104&&Ie===null?Ie=u(r,Ue,je):le===null&&(le=u(r,Ue,je)):ke===71&&le===null&&(le=u(r,Ue,je)):ve===10?(ke===103&&he===null||ke===82&&he===null)&&(he=u(r,Ue,je)):ve===12?ke===103&&r.charCodeAt(we+8)===97&&Ce===null?Ce=x(r,Ue,je):ke===80&&He===null?He=x(r,Ue,je):ke===72&&Ie===null&&(Ie=u(r,Ue,je)):ve===13?(ke===103||ke===71)&&ne===null&&(ne=u(r,Ue,je)):ve===14?(ke===103||ke===71)&&A===null?A=u(r,Ue,je):ke===65&&Ce===null&&(Ce=x(r,Ue,je)):ve===11&&ke===84&&Ce===null&&(Ce=x(r,Ue,je));let dt=Me+2+ve;if(r.charCodeAt(dt)===62)j=dt+1;else{let At=r.indexOf(">",Me+2);j=At!==-1?At+1:Me+2}if(Ne!==null&&Ie!==null&&he!==null&&Ce!==null)break}else j=Me}let _e=null;A!=null&&ne!=null&&ne!==0?_e=A/ne:le!=null&&be!=null&&be!==0&&(_e=le/be),me.push({lat:F,lon:ae,ele:ue,time:te,hr:Ie,cad:he,power:He,speed:Re,temp:Ce,gearFront:le,gearRear:be,gearFrontTooth:A,gearRearTooth:ne,battery:Ne,gears:_e})}if(!me.length)throw new Error("No track points found in GPX");let oe=e(me),de=s(oe);return{name:Y,device:Ae,format:"gpx",points:oe,stats:de}}function _(y,d){let r=d??new TextDecoder().decode(y),J=r.indexOf(""),U=J!==-1?r.slice(0,J):r,Q=k(U,"","")||"Unnamed TCX",Y=k(U,"",""),K=Y?k(Y,"",""):null,Ae=[],me=J!==-1?J:0;for(;me",me);if(de===-1)break;let xe=r.indexOf("",de+12);if(xe===-1)break;me=xe+13;let Pe=null,G=null,F=null,ae=null,ue=null,te=null,Ie=null,he=null,He=null,Ce=null,Re=null,le=null,be=null,A=null,ne=de+12;for(;ne=xe)break;let _e=r.indexOf(">",j+1);if(_e===-1||_e>=xe)break;let we=r.charCodeAt(j+1);if(we===47){ne=_e+1;continue}let Ee=_e-j-1,ke=r.indexOf("<",_e+1);if(ke===-1||ke>xe)break;if(r.charCodeAt(ke+1)===47){let ve=_e+1,Me=ke;Ee===4?we===84?r.charCodeAt(j+2)===105?ae=w(r,ve,Me):He===null&&(He=x(r,ve,Me)):we===116&&He===null&&(He=x(r,ve,Me)):Ee===5?we===86&&ue===null?ue=u(r,ve,Me):(we===87||we===80||we===112)&&Ie===null?Ie=x(r,ve,Me):(we===83||we===115)&&he===null?he=x(r,ve,Me):we===97&&He===null&&(He=x(r,ve,Me)):Ee===7?we===67&&te===null?te=u(r,ve,Me):(we===66||we===98)&&A===null&&(A=u(r,ve,Me)):Ee===8?(we===71||we===103)&&Re===null&&(Re=u(r,ve,Me)):Ee===9?(we===71||we===103)&&Ce===null&&(Ce=u(r,ve,Me)):Ee===10?we===82&&te===null&&(te=u(r,ve,Me)):Ee===11?we===84&&He===null&&(He=x(r,ve,Me)):Ee===13?(we===71||we===103)&&be===null&&(be=u(r,ve,Me)):Ee===14?we===65?r.charCodeAt(j+2)===108?F=x(r,ve,Me):He===null&&(He=x(r,ve,Me)):(we===71||we===103)&&le===null&&(le=u(r,ve,Me)):Ee===15?we===76&&(Pe=x(r,ve,Me)):Ee===16?we===76&&(G=x(r,ve,Me)):Ee===2&&we===104&&ue===null?ue=u(r,ve,Me):Ee===3&&we===99&&te===null?te=u(r,ve,Me):Ee===12&&(we===72&&ue===null?ue=u(r,ve,Me):we===80&&Ie===null&&(Ie=x(r,ve,Me)));let Ue=ke+2+Ee;if(r.charCodeAt(Ue)===62)ne=Ue+1;else{let je=r.indexOf(">",ke+2);ne=je!==-1?je+1:ke+2}if(A!==null&&ue!==null&&te!==null&&He!==null)break}else ne=ke}if(Pe==null||G==null)continue;let Ne=null;le!=null&&be!=null&&be!==0?Ne=le/be:Ce!=null&&Re!=null&&Re!==0&&(Ne=Ce/Re),Ae.push({lat:Pe,lon:G,ele:F,time:ae,hr:ue,cad:te,power:Ie,speed:he,temp:He,gearFront:Ce,gearRear:Re,gearFrontTooth:le,gearRearTooth:be,battery:A,gears:Ne})}let Fe=e(Ae),oe=s(Fe);return{name:Q,device:K,format:"tcx",points:Fe,stats:oe}}function C(y){if(y.byteLength<14)return null;let d=new DataView(y),r=d.getUint8(0);if(r<12||r+2>y.byteLength||d.getUint8(8)!==46||d.getUint8(9)!==70||d.getUint8(10)!==73||d.getUint8(11)!==84)return null;let J=d.getUint32(4,!0),U=Math.min(y.byteLength,r+J),Q=631065600,Y=180/Math.pow(2,31),K=new Array(16),Ae=[],me=[],Fe=[],oe=[],de=[],xe=r;for(;xeU)return null;xe++;let ae=d.getUint8(xe++)===0,ue=d.getUint16(xe,ae);xe+=2;let te=d.getUint8(xe++);if(xe+te*3>U)return null;let Ie=new Array(te),he=0;for(let He=0;HeU)return null;let ae=F.littleEndian,ue=F.globalMsgNum;if(ue===20&&F.fields.length===10&&F.recordSize===25&&F.fields[0].num===253&&F.fields[1].num===0){let he=d.getUint32(xe,ae),He=d.getInt32(xe+4,ae),Ce=d.getInt32(xe+8,ae),Re=d.getUint16(xe+12,ae),le=d.getUint8(xe+14),be=d.getUint8(xe+15),A=d.getUint32(xe+16,ae),ne=d.getUint16(xe+20,ae),Ne=d.getUint16(xe+22,ae),j=d.getInt8(xe+24);Fe.push({timestamp:(he+Q)*1e3,position_lat:He*Y,position_long:Ce*Y,altitude:Re/5-500,heart_rate:le,cadence:be,distance:A/100,speed:ne/1e3*3.6,power:Ne,temperature:j}),xe+=25;continue}let te={},Ie=xe;for(let he=0;he{let J=(Y,K)=>{if(Y){r(Y);return}try{let Ae=K.sessions?.[0]?.start_time?`Fit Activity ${new Date(K.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",me=null,Fe=[],oe=null,de=null;K.sports?.[0]?(oe=K.sports[0].sport,de=K.sports[0].sub_sport):K.sessions?.[0]&&(oe=K.sessions[0].sport,de=K.sessions[0].sub_sport);let xe=A=>A.product_name||A.garmin_product||A.product||A.device_type||A.manufacturer||null;if(K.file_ids?.[0]){let A=K.file_ids[0];me=xe(A),Fe.push({name:A.product_name||A.garmin_product||A.product,manufacturer:A.manufacturer,serial:A.serial_number?String(A.serial_number):void 0,version:A.software_version?String(A.software_version):void 0,type:"main"})}K.device_infos&&K.device_infos.forEach(A=>{if(A.device_index==="creator"||A.device_index===0){let Ne=xe(A);(A.product_name||A.garmin_product||!me)&&(me=Ne),Fe.length>0&&Fe[0].type==="main"&&((A.product_name||A.garmin_product||!Fe[0].name)&&(Fe[0].name=A.product_name||A.garmin_product||A.product),Fe[0].manufacturer||(Fe[0].manufacturer=A.manufacturer),!Fe[0].serial&&A.serial_number&&(Fe[0].serial=String(A.serial_number)),!Fe[0].version&&A.software_version&&(Fe[0].version=String(A.software_version)),!Fe[0].hardwareVersion&&A.hardware_version&&(Fe[0].hardwareVersion=String(A.hardware_version)));return}Fe.push({name:A.product_name||A.garmin_product||A.product||A.device_type||"Sensor",manufacturer:A.manufacturer,serial:A.serial_number?String(A.serial_number):void 0,version:A.software_version?String(A.software_version):void 0,hardwareVersion:A.hardware_version?String(A.hardware_version):void 0,type:A.device_type||"sensor",batteryStatus:A.battery_status,batteryVoltage:A.battery_voltage,batteryLevel:A.battery_level,sourceType:A.source_type!=null?String(A.source_type):void 0})}),K.sensor_settings&&K.sensor_settings.forEach(A=>{let ne=A.name||A.product||A.sensor_type;if(!ne)return;let Ne=A.ant_id?String(A.ant_id):void 0,j=Fe.find(_e=>Ne&&_e.serial===Ne||_e.name===ne&&_e.manufacturer===A.manufacturer);j?(j.name||(j.name=ne),j.manufacturer||(j.manufacturer=A.manufacturer),j.type||(j.type=A.sensor_type),j.sourceType||(j.sourceType=A.connection_type!=null?String(A.connection_type):void 0)):Fe.push({name:ne,manufacturer:A.manufacturer,serial:Ne,type:A.sensor_type||"sensor",sourceType:A.connection_type!=null?String(A.connection_type):void 0})});let Pe=[];K.device_statuses&&(K.device_statuses.forEach((A,ne)=>{A.timestamp&&A.battery_level!=null&&Pe.push({time:typeof A.timestamp=="number"?A.timestamp:new Date(A.timestamp).getTime(),level:A.battery_level,idx:ne})}),Pe.sort((A,ne)=>A.time-ne.time||A.idx-ne.idx));let G=[];K.events&&(K.events.forEach((A,ne)=>{let Ne=A.front_gear_num??A.front_gear??null,j=A.rear_gear_num??A.rear_gear??null,_e=A.front_gear_num_tooth??null,we=A.rear_gear_num_tooth??null;if(A.event==="rear_gear_change"||A.event==="front_gear_change"){let Ee=A.data;if(Ee!=null){let ke=Ee>>24&255,ve=Ee>>16&255,Me=Ee>>8&255,Ue=Ee&255;ve!==0&&(Ne=ve),ke!==0&&(_e=ke),Ue!==0&&(j=Ue),Me!==0&&(we=Me)}}A.timestamp&&(Ne!=null||j!=null||_e!=null||we!=null)&&G.push({time:typeof A.timestamp=="number"?A.timestamp:new Date(A.timestamp).getTime(),front:Ne,rear:j,frontTooth:_e,rearTooth:we,idx:ne})}),G.sort((A,ne)=>A.time-ne.time||A.idx-ne.idx));let F=K.records||[],ae=null,ue=0,te=null,Ie=null,he=null,He=null,Ce=0,Re=[];for(let A=0;A name, Placemark > name");U&&(J=U.textContent?.trim()||J);let Q=r.querySelectorAll("coordinates");if(!Q.length)throw new Error("No coordinates found in KML");let Y=[];if(Q.forEach(me=>{(me.textContent?.trim().split(/\s+/)||[]).forEach(oe=>{let de=oe.split(",");if(de.length<2)return;let xe=parseFloat(de[0]),Pe=parseFloat(de[1]),G=de.length>2?parseFloat(de[2]):null;isNaN(Pe)||isNaN(xe)||Y.push({lat:Pe,lon:xe,ele:G!=null&&isNaN(G)?null:G,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!Y.length)throw new Error("No valid coordinates in KML");let K=e(Y),Ae=s(K);return{name:J,format:"kml",points:K,stats:Ae}}async function ie(y){let d=y.name.split(".").pop()?.toLowerCase(),r=y._buf??await y.arrayBuffer(),J=y._text,U;switch(d){case"gpx":U=W(r,J);break;case"tcx":U=_(r,J);break;case"fit":U=await q(r);break;case"kml":U=N(r);break;default:throw new Error(`Unsupported format: .${d}`)}return U&&(U.fileName=y.name,U.fileSize=y.size),U}return{parseFile:ie,computeStats:s,ensureCurvesAndZones:o,calculatePowerCurve:c,calculateHRCurve:m,calculatePowerZones:T,calculateHRZones:O,enrichPoints:e,setHRZones:H,getHRZones:E,setFTP:f,getFTP:M}})();var De=(()=>{let e={},n=null;function t(N,ie,y,d,r){}function s(N){}function o(N){e[N.id]=N}function a(N){N.forEach(ie=>{e[ie.id]=ie})}function g(N){delete e[N]}function c(){e={}}function m(){e={}}function T(N,ie){}function f(N,ie){}function M(){}function O(N){}function H(N,ie){}function E(){}function k(N,ie,y,d,r,J){}function p(){}function P(N,ie){}function b(N){}function u(N,ie,y,d){}function x(){}function w(){}function D(){return[0,0,0]}function W(N,ie,y){}function _(N,ie,y){}function C(N){}function q(N,ie){return Object.keys(e)}return{init:t,getMap:()=>null,setCustomClickHandler:N=>{n=N},switchBasemap:s,addTrack:o,addTracks:a,removeTrack:g,clearTracks:c,removeAllTracks:m,setTrackVisible:T,setSelectedTrack:f,fitAll:M,fitTrack:O,showCursorAt:H,hideCursor:E,highlightSegment:k,clearHighlight:p,setTrackHover:P,ensureVisible:b,centerOn:u,closePopup:x,invalidateSize:w,getPosition:D,setPosition:W,colorTrackByMetric:_,clearMetricColor:C,findTracksPassingThroughPoints:q,getTrackData:N=>e[N]}})();import vl from"uplot";var Sn=(()=>{function e(){let t=ot.getFTP(),s=[.55,.75,.9,1.05,1.2,1.5].map(m=>m*t),o=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],a=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],g=[],c=0;for(let m=0;mn?e.toFixed(1):Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:We.speed.color,abbr:"spd",icon:We.speed.icon,fmt:e=>(e*3.6).toFixed(1),fmtAxis:e=>(e*3.6).toFixed(0),transform:e=>e,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:We.gradient.color,abbr:"grad",icon:We.gradient.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>e.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:We.power.color,abbr:"pwr",icon:We.power.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:We.hr.color,abbr:"hr",icon:We.hr.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:We.cadence.color,abbr:"cad",icon:We.cadence.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:We.temperature.color,abbr:"temp",icon:We.temperature.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>Math.round(e).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:We.gearRear.color,abbr:"rgr",icon:We.gearRear.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:We.gearFront.color,abbr:"fgr",icon:We.gearFront.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gears:{label:"Gears",field:"gears",unit:"",color:We.gears.color,abbr:"gr",icon:We.gears.icon,fmt:e=>e.toFixed(2),fmtAxis:e=>e.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:We.battery.color,abbr:"bat",icon:We.battery.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString(),smoothSigma:5,compute:(e,n)=>{let t=new Array(e.length).fill(null);for(let s=1;s0&&(t[s]=g/c*3600)}}return n(t)}}};var Nt={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function bl(e){if(!e)return"question_mark";let n=e.toLowerCase();return Nt[n]?.icon||"exercise"}var Se=(()=>{let e=[],n=null,t="time",s="speed",o=null,a=null,g=!1,c=!1,m=new Set(["elevation"]),T=new Set,f=new Set(["speed","gradient","vam","temperature"]),M=new Set(["power"]),O="time",H=null,E=[],k=null,p=null,P=!1,b=!1,u=null,x=null,w=null,D=null,W=null,_=null,C=null,q=null,N=null,ie=null,y=null,d=null,r=130,J=28,U=20,Q=!0,Y=null,K=null,Ae=null,me=null,Fe=null,oe=null,de=null;function xe(l,i,h,v){N=l,ie=i,y=h,d=v,K=document.getElementById("charts-container"),K?.addEventListener("scroll",()=>{w&&W&&D&&wn(w,W,D)}),Ae=document.getElementById("chart-empty"),me=document.getElementById("chart-stats-sel"),Fe=document.getElementById("btn-reset-selection"),Y=document.getElementById("hist-tooltip"),a=vl.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",ne),Fe?.classList.add("hidden");let L=new Set(["w","a","s","d"]),S=new Set;document.addEventListener("keydown",B=>{if(!e.length||!H||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let $=B.key.toLowerCase();if(!L.has($))return;B.preventDefault(),S.add($);let R=e[0].uplot;C||(C=[R.scales.x.min,R.scales.x.max]);let[Z,z]=C,X=(z-Z)*.1,fe=.15,I=Z,se=z;if($==="a")I=Z-X,se=z-X;else if($==="d")I=Z+X,se=z+X;else if($==="w"||$==="s"){let re=x!==null?x:(Z+z)/2,Be=$==="w"?1-fe:1+fe*1.2;I=re-(re-Z)*Be,se=re+(z-re)*Be}let ge=[e[0].xData[0],e[0].xData[e[0].xData.length-1]];if(Ige[1]){let re=se-ge[1];I-=re,se-=re}I=Math.max(ge[0],I),se=Math.min(ge[1],se),se-I>.001&&(C=[I,se],Pe(I,se,!0))}),document.addEventListener("keyup",B=>{let $=B.key.toLowerCase();L.has($)&&S.delete($)})}function Pe(l,i,h=!1){if(!e.length)return;if(!h){e.forEach(({uplot:R})=>R.setScale("x",{min:l,max:i}));return}let v=_?_[0]:e[0].uplot.scales.x.min,L=_?_[1]:e[0].uplot.scales.x.max;q&&cancelAnimationFrame(q);let S=(R,Z,z)=>R+(Z-R)*z,B=.25,$=()=>{if(!C)return;let[R,Z]=C,z=S(_[0],R,B),V=S(_[1],Z,B);e.forEach(({uplot:X})=>{X.setScale("x",{min:z,max:V})}),Math.abs(z-R)>1e-4||Math.abs(V-Z)>1e-4?q=requestAnimationFrame($):q=null};q=requestAnimationFrame($)}function G(l,i=[],h=!1){u=null,k=null,p=null,E=i,T=new Set(Object.entries(Ft).filter(([,v])=>l.points.some(L=>L[v.field]!=null)).map(([v])=>v)),m.size===0&&(m=new Set(["elevation"].filter(v=>T.has(v)))),document.querySelectorAll(".metric-pill").forEach(v=>{let L=v,S=L.dataset.metric,B=T.has(S);L.classList.toggle("active",B&&m.has(S)),L.classList.toggle("disabled",!B)}),H=l,h?ol(l):Ee()}function F(){u=null,k=null,p=null,H=null,Dn(),Ae&&(Ae.style.display="flex",Ae.innerHTML=` no_sim

- `);let l=document.getElementById("chart-stats");l&&l.classList.add("hidden"),V(),ae=null,pe&&pe(null)}function oe(){z!==null&&(cancelAnimationFrame(z),z=null),m=new Set(["elevation"]),T=new Set,b=new Set(["speed","gradient","vam","temperature"]),w=new Set(["power"]),R="time",k=[],Y=null,B=null,h=null,F=null,q=null,J=null,se=!0,_(),document.querySelectorAll("#metric-pills .metric-pill").forEach(f=>{let v=f;v.classList.toggle("active",m.has(v.dataset.metric)),v.classList.remove("disabled","overflow-hidden")});let l=document.getElementById("pill-overflow");l&&l.classList.add("hidden");let i=document.getElementById("chart-toolbar");i&&i.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(f=>{f.classList.toggle("active",f.dataset.axis==="time")})}function re(l){m.has(l)?m.delete(l):m.add(l),S&&xe(!0)}function K(l){m=new Set(l),S&&xe(!0),document.querySelectorAll(".metric-pill").forEach(i=>{let f=i;f.classList.toggle("active",m.has(f.dataset.metric))})}function Pe(l){if(R===l||!S){R=l;return}let i=S.points,f=i.find(x=>x.time!=null)?.time||0,v=x=>{if(x===null)return null;let A=0;if(R==="distance"){let E=x*1e3;A=i.findIndex(H=>(H.dist||0)>=E)}else{let E=f+x*1e3;A=i.findIndex(H=>(H.time||0)>=E)}return A===-1&&(A=i.length-1),l==="distance"?(i[A].dist||0)/1e3:((i[A].time||f)-f)/1e3};M!==null&&(M=v(M)),g!==null&&(g=v(g));let $=null;if(e.length){let x=e[0].uplot,A=v(x.scales.x.min),E=v(x.scales.x.max);A!==null&&E!==null&&($=[A,E])}R=l,xe(!0),$&&(u=!0,e.forEach(({uplot:x})=>{x.batch(()=>x.setScale("x",{min:$[0],max:$[1]}))}),u=!1)}function de(){se=!se,e.forEach(({histCol:l})=>l.classList.toggle("visible",se)),he()}function $e(l){pe=l}function Ce(l){ae===l||l===null?(ae=null,We(),pe&&pe(null)):(ae=l,We(),te()),S&&xe(!0)}function We(){document.querySelectorAll(".map-color-btn").forEach(l=>{let i=l;i.classList.toggle("active",i.dataset.metric===ae)})}function te(){if(!pe||!ae||!S)return;let l=e.find(f=>f.metricKey===ae);if(!l)return;let i=ge(ae,l.yData);pe({pts:S.points,colors:i})}function ge(l,i){let f=i.filter(W=>W!=null&&isFinite(W));if(!f.length)return i.map(()=>"#888896");let v=Math.min(...f),$=Math.max(...f),x=S?.sport,A=x?Wt[x.toLowerCase()]:null,E=A?.defaultPreset||"speed",O=Ye.get().speed_mode||E,N=A?.paceUnit||"km";return i.map(W=>{if(W==null||!isFinite(W))return"#888896";if(l==="gradient")return Rn(W);if(l==="speed"){if(O==="pace"){let ue=(N==="km"?1e3:100)/W;return Cs(ue)}return Cs(W)}let j=$===v?.5:Math.max(0,Math.min(1,(W-v)/($-v)));return j<=.25?Rt("#4575b4","#91bfdb",j/.25):j<=.5?Rt("#91bfdb","#fee090",(j-.25)/.25):j<=.75?Rt("#fee090","#fc8d59",(j-.5)/.25):Rt("#fc8d59","#d73027",(j-.75)/.25)})}function L(){ee()}function ee(){M=null,g=null,p=null,d&&d(null),e.forEach(l=>{l.pinnedHistY=null}),fe(),It(),u=!0,e.forEach(({uplot:l,xData:i})=>{l.batch(()=>l.setScale("x",{min:i[0],max:i[i.length-1]})),l._strasse?.updateHeaderStats(i[0],i[i.length-1])}),u=!1,le&&le(null,null,R)}function Ne(l){if(!Re)return;let i=(f,v)=>{let $=document.querySelector(`#${f} .stat-value`);$&&($.textContent=v)};i("sel-distance",l.totalDist!=null?`${(l.totalDist/1e3).toFixed(1)} km`:"\u2014"),i("sel-duration",l.duration!=null?ht(Math.floor(l.duration/1e3)):"\u2014"),i("sel-elevation",l.elevGain!=null?`${Math.round(l.elevGain)} m`:"\u2014"),i("sel-avg-speed",l.avgSpeed!=null?`${(l.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),i("sel-avg-power",l.avgPower!=null?`${l.avgPower} W`:"\u2014"),i("sel-avg-hr",l.avgHR!=null?`${l.avgHR} bpm`:"\u2014"),i("sel-avg-temp",l.avgTemp!=null?`${l.avgTemp.toFixed(1)} \xB0C`:"\u2014"),Re.classList.remove("hidden"),Be&&Be.classList.remove("hidden")}function V(){Re&&Re.classList.add("hidden"),Be&&Be.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(l=>{let i=document.querySelector(`#${l} .stat-value`);i&&(i.textContent="--")})}function Ae(l,i,f=!1){if(!S)return;let v=S.points,$=v.find(O=>O.time!=null)?.time||0,x=((v[v.length-1]?.time||0)-$)/1e3;l>1e12&&(l=(l-$)/1e3),i>1e12&&(i=(i-$)/1e3),l=Math.max(0,Math.min(l,x)),i=Math.max(0,Math.min(i,x));let A=O=>{if(R==="time")return O;let N=$+O*1e3,W=v.findIndex(j=>(j.time||0)>=N);return W===-1&&(W=v.length-1),(v[W].dist||0)/1e3},E=A(l),H=A(i);M=E,g=H,Y=[E,H],!f&&(u=!0,e.forEach(({uplot:O})=>{O.batch(()=>O.setScale("x",{min:E,max:H}))}),u=!1,be(),It())}function he(){if(!e.length||!ne)return;let l=Math.round(Math.max(100,ne.getBoundingClientRect().width-G-(se?a+X:0))),i=!1;e.forEach(({uplot:f,histCanvas:v,histData:$})=>{l!==f.width&&(f.setSize({width:l,height:f.height}),i=!0,se&&v&&$&&At(v,$,f.height))}),i&&fe()}function xe(l=!1){let i=null,f=0;if(l&&ne&&(f=ne.scrollTop),l&&Y)i=[Y[0],Y[1]];else if(l&&e.length){let ke=e[0].uplot;i=[ke.scales.x.min,ke.scales.x.max]}if(!S){$n(l);return}let v=S.points;if(!v.length){$n(l);return}let $=S?.sport,x=$?Wt[$.toLowerCase()]:null,A=x?.defaultPreset||"speed",H=Ye.get().speed_mode||A,O=x?.paceUnit||"km",N=[...m].filter(ke=>v.some(ce=>ce[_t[ke].field]!=null));if(!N.length){$n(l),Le&&(Le.style.display="flex",Le.innerHTML=` + `);let l=document.getElementById("chart-stats");l&&l.classList.add("hidden"),j(),oe=null,de&&de(null)}function ae(){q!==null&&(cancelAnimationFrame(q),q=null),m=new Set(["elevation"]),T=new Set,f=new Set(["speed","gradient","vam","temperature"]),M=new Set(["power"]),O="time",E=[],_=null,C=null,x=null,w=null,D=null,W=null,Q=!0,F(),document.querySelectorAll("#metric-pills .metric-pill").forEach(h=>{let v=h;v.classList.toggle("active",m.has(v.dataset.metric)),v.classList.remove("disabled","overflow-hidden")});let l=document.getElementById("pill-overflow");l&&l.classList.add("hidden");let i=document.getElementById("chart-toolbar");i&&i.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(h=>{h.classList.toggle("active",h.dataset.axis==="time")})}function ue(l){m.has(l)?m.delete(l):m.add(l),H&&Ee(!0)}function te(l){m=new Set(l),H&&Ee(!0),document.querySelectorAll(".metric-pill").forEach(i=>{let h=i;h.classList.toggle("active",m.has(h.dataset.metric))})}function Ie(l){if(O===l||!H){O=l;return}let i=H.points,h=i.find(S=>S.time!=null)?.time||0,v=S=>{if(S===null)return null;let B=0;if(O==="distance"){let $=S*1e3;B=i.findIndex(R=>(R.dist||0)>=$)}else{let $=h+S*1e3;B=i.findIndex(R=>(R.time||0)>=$)}return B===-1&&(B=i.length-1),l==="distance"?(i[B].dist||0)/1e3:((i[B].time||h)-h)/1e3};k!==null&&(k=v(k)),p!==null&&(p=v(p));let L=null;if(e.length){let S=e[0].uplot,B=v(S.scales.x.min),$=v(S.scales.x.max);B!==null&&$!==null&&(L=[B,$])}O=l,Ee(!0),L&&(g=!0,e.forEach(({uplot:S})=>{S.batch(()=>S.setScale("x",{min:L[0],max:L[1]}))}),g=!1)}function he(){Q=!Q,e.forEach(({histCol:l})=>l.classList.toggle("visible",Q)),we()}function He(l){de=l}function Ce(l){oe===l||l===null?(oe=null,Re(),de&&de(null)):(oe=l,Re(),le()),H&&Ee(!0)}function Re(){document.querySelectorAll(".map-color-btn").forEach(l=>{let i=l;i.classList.toggle("active",i.dataset.metric===oe)})}function le(){if(!de||!oe||!H)return;let l=e.find(h=>h.metricKey===oe);if(!l)return;let i=be(oe,l.yData);de({pts:H.points,colors:i})}function be(l,i){let h=i.filter(V=>V!=null&&isFinite(V));if(!h.length)return i.map(()=>"#888896");let v=Math.min(...h),L=Math.max(...h),S=H?.sport,B=S?Nt[S.toLowerCase()]:null,$=B?.defaultPreset||"speed",Z=Ye.get().speed_mode||$,z=B?.paceUnit||"km";return i.map(V=>{if(V==null||!isFinite(V))return"#888896";if(l==="gradient")return Kn(V);if(l==="speed"){if(Z==="pace"){let fe=(z==="km"?1e3:100)/V;return sl(fe)}return sl(V)}let X=L===v?.5:Math.max(0,Math.min(1,(V-v)/(L-v)));return X<=.25?Dt("#4575b4","#91bfdb",X/.25):X<=.5?Dt("#91bfdb","#fee090",(X-.25)/.25):X<=.75?Dt("#fee090","#fc8d59",(X-.5)/.25):Dt("#fc8d59","#d73027",(X-.75)/.25)})}function A(){ne()}function ne(){k=null,p=null,u=null,d&&d(null),e.forEach(l=>{l.pinnedHistY=null}),ve(),At(),g=!0,e.forEach(({uplot:l,xData:i})=>{l.batch(()=>l.setScale("x",{min:i[0],max:i[i.length-1]})),l._strasse?.updateHeaderStats(i[0],i[i.length-1])}),g=!1,ie&&ie(null,null,O)}function Ne(l){if(!me)return;let i=(h,v)=>{let L=document.querySelector(`#${h} .stat-value`);L&&(L.textContent=v)};i("sel-distance",l.totalDist!=null?`${(l.totalDist/1e3).toFixed(1)} km`:"\u2014"),i("sel-duration",l.duration!=null?ht(Math.floor(l.duration/1e3)):"\u2014"),i("sel-elevation",l.elevGain!=null?`${Math.round(l.elevGain)} m`:"\u2014"),i("sel-avg-speed",l.avgSpeed!=null?`${(l.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),i("sel-avg-power",l.avgPower!=null?`${l.avgPower} W`:"\u2014"),i("sel-avg-hr",l.avgHR!=null?`${l.avgHR} bpm`:"\u2014"),i("sel-avg-temp",l.avgTemp!=null?`${l.avgTemp.toFixed(1)} \xB0C`:"\u2014"),me.classList.remove("hidden"),Fe&&Fe.classList.remove("hidden")}function j(){me&&me.classList.add("hidden"),Fe&&Fe.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(l=>{let i=document.querySelector(`#${l} .stat-value`);i&&(i.textContent="--")})}function _e(l,i,h=!1){if(!H)return;let v=H.points,L=v.find(Z=>Z.time!=null)?.time||0,S=((v[v.length-1]?.time||0)-L)/1e3;l>1e12&&(l=(l-L)/1e3),i>1e12&&(i=(i-L)/1e3),l=Math.max(0,Math.min(l,S)),i=Math.max(0,Math.min(i,S));let B=Z=>{if(O==="time")return Z;let z=L+Z*1e3,V=v.findIndex(X=>(X.time||0)>=z);return V===-1&&(V=v.length-1),(v[V].dist||0)/1e3},$=B(l),R=B(i);k=$,p=R,_=[$,R],!h&&(g=!0,e.forEach(({uplot:Z})=>{Z.batch(()=>Z.setScale("x",{min:$,max:R}))}),g=!1,Me(),At())}function we(){if(!e.length||!K)return;let l=Math.round(Math.max(100,K.getBoundingClientRect().width-J-(Q?r+U:0))),i=!1;e.forEach(({uplot:h,histCanvas:v,histData:L})=>{l!==h.width&&(h.setSize({width:l,height:h.height}),i=!0,Q&&v&&L&&It(v,L,h.height))}),i&&ve()}function Ee(l=!1){let i=null,h=0;if(l&&K&&(h=K.scrollTop),l&&_)i=[_[0],_[1]];else if(l&&e.length){let ge=e[0].uplot;i=[ge.scales.x.min,ge.scales.x.max]}if(!H){Dn(l);return}let v=H.points;if(!v.length){Dn(l);return}let L=H?.sport,S=L?Nt[L.toLowerCase()]:null,B=S?.defaultPreset||"speed",R=Ye.get().speed_mode||B,Z=S?.paceUnit||"km",z=[...m].filter(ge=>v.some(re=>re[Ft[ge].field]!=null));if(!z.length){Dn(l),Ae&&(Ae.style.display="flex",Ae.innerHTML=` no_sim
No data for selected metrics
- `);return}Le&&(Le.style.display="none");let W=ne?ne.getBoundingClientRect().width:800,j=Math.round(Math.max(100,W-G-(se?a+X:0))),ue=l&&s===S&&t===R&&n===H&&o===ae&&e.length>0,C;if(ue)C=e[0].xData;else if(R==="distance")C=v.map(ke=>(ke.dist||0)/1e3);else{let ke=v.find(Fe=>Fe.time!=null)?.time||0,ce=0;C=v.map(Fe=>(Fe.time!=null&&(ce=(Fe.time-ke)/1e3),ce))}let Se=new Map;if(ue){U&&(U.style.display="none");let ke=new Set(N);for(let ce of e){let Fe=b.has(ce.metricKey),me=w.has(ce.metricKey);ke.has(ce.metricKey)&&ce.smoothed===Fe&&ce.incZero===me&&ce.w===j?Se.set(ce.metricKey,ce):(r.unsub(ce.uplot),ce.uplot.destroy(),ce.row.remove())}e=[]}else $n(l);if(ne){let ke=new Array(N.length).fill(null),ce=null;for(let Fe=N.length-1;Fe>=0;Fe--){ke[Fe]=ce;let me=Se.get(N[Fe]);me&&(ce=me.row)}N.forEach((Fe,me)=>{let ve=Se.get(Fe);if(ve){e.push(ve);let ie=ve.uplot,Je=ie._strasse,Ge=u;u=!0,ie.batch(()=>{i&&(ie.scales.x.min!==i[0]||ie.scales.x.max!==i[1])?ie.setScale("x",{min:i[0],max:i[1]}):(Je?.updateHeaderStats(ie.scales.x.min,ie.scales.x.max,ie),ie.redraw(!1))}),u=Ge;let Qe=null;if(p!=null&&ve.xData[p]!=null&&ve.yData[p]!=null&&(dt(ve.histData),ve.histData.min!=null&&ve.histData.max!=null)){let rt=ve.histData.max-ve.histData.min||1;Qe=Math.min(ve.histData.BINS-1,Math.floor((ve.yData[p]-ve.histData.min)/rt*ve.histData.BINS)),ve.hoveredHistY=ve.yData[p]}At(ve.histCanvas,ve.histData,130,Qe);return}let Ie=_t[Fe],Ve=Ie.transform,Ze=Ie.fmt,st=Ie.fmtAxis,nt=Ie.unit,ot=Ie.label;Fe==="speed"&&H==="pace"&&(ot="Pace",nt=`min/${O}`,Ze=ie=>An(ie),st=ie=>An(ie),Ve=ie=>ie==null||ie<.1?null:(O==="km"?1e3:100)/ie,Ie={...Ie,label:ot,unit:nt,fmt:Ze,fmtAxis:st,transform:Ve});let lt=Ie.compute?Ie.compute(v,Ls):Ls(v.map(ie=>{let Je=ie[Ie.field];return Je!=null&&Ve?Ve(Je):Je}));b.has(Fe)&&(lt=fn(lt,Ie.smoothSigma||2)),Ee(Fe,Ie,C,lt,j,v,i,ke[me])})}s=S,t=R,n=H,o=ae,Ps(S),M!=null&&g!=null&&be(),We(),ae&&te(),l&&ne&&f>0&&(ne.scrollTop=f)}function Ee(l,i,f,v,$,x,A=null,E=null){let H=S?.sport,N=(H?Wt[H.toLowerCase()]:null)?.defaultPreset||"speed",j=Ye.get().speed_mode||N,ue=l==="elevation"?Sl(x,20):null,C=document.createElement("div");C.className="chart-row",C.dataset.metric=l,C.style.setProperty("--chart-color",i.color);let Se=document.createElement("div");Se.className=`chart-row-header${se?" with-histogram":""}`;let ke=document.createElement("div");ke.className="chart-row-label-group",ke.innerHTML=` + `);return}Ae&&(Ae.style.display="none");let V=K?K.getBoundingClientRect().width:800,X=Math.round(Math.max(100,V-J-(Q?r+U:0))),fe=l&&n===H&&t===O&&s===R&&o===oe&&e.length>0,I;if(fe)I=e[0].xData;else if(O==="distance")I=v.map(ge=>(ge.dist||0)/1e3);else{let ge=v.find(Be=>Be.time!=null)?.time||0,re=0;I=v.map(Be=>(Be.time!=null&&(re=(Be.time-ge)/1e3),re))}let se=new Map;if(fe){Y&&(Y.style.display="none");let ge=new Set(z);for(let re of e){let Be=f.has(re.metricKey),pe=M.has(re.metricKey);ge.has(re.metricKey)&&re.smoothed===Be&&re.incZero===pe&&re.w===X?se.set(re.metricKey,re):(a.unsub(re.uplot),re.uplot.destroy(),re.row.remove())}e=[]}else Dn(l);if(K){let ge=new Array(z.length).fill(null),re=null;for(let Be=z.length-1;Be>=0;Be--){ge[Be]=re;let pe=se.get(z[Be]);pe&&(re=pe.row)}z.forEach((Be,pe)=>{let ye=se.get(Be);if(ye){e.push(ye);let ce=ye.uplot,Je=ce._strasse,Ge=g;g=!0,ce.batch(()=>{i&&(ce.scales.x.min!==i[0]||ce.scales.x.max!==i[1])?ce.setScale("x",{min:i[0],max:i[1]}):(Je?.updateHeaderStats(ce.scales.x.min,ce.scales.x.max,ce),ce.redraw(!1))}),g=Ge;let Qe=null;if(u!=null&&ye.xData[u]!=null&&ye.yData[u]!=null&&(dt(ye.histData),ye.histData.min!=null&&ye.histData.max!=null)){let rt=ye.histData.max-ye.histData.min||1;Qe=Math.min(ye.histData.BINS-1,Math.floor((ye.yData[u]-ye.histData.min)/rt*ye.histData.BINS)),ye.hoveredHistY=ye.yData[u]}It(ye.histCanvas,ye.histData,130,Qe);return}let Te=Ft[Be],qe=Te.transform,Ze=Te.fmt,st=Te.fmtAxis,nt=Te.unit,it=Te.label;Be==="speed"&&R==="pace"&&(it="Pace",nt=`min/${Z}`,Ze=ce=>Vn(ce),st=ce=>Vn(ce),qe=ce=>ce==null||ce<.1?null:(Z==="km"?1e3:100)/ce,Te={...Te,label:it,unit:nt,fmt:Ze,fmtAxis:st,transform:qe});let lt=Te.compute?Te.compute(v,ll):ll(v.map(ce=>{let Je=ce[Te.field];return Je!=null&&qe?qe(Je):Je}));f.has(Be)&&(lt=En(lt,Te.smoothSigma||2)),ke(Be,Te,I,lt,X,v,i,ge[pe])})}n=H,t=O,s=R,o=oe,ol(H),k!=null&&p!=null&&Me(),Re(),oe&&le(),l&&K&&h>0&&(K.scrollTop=h)}function ke(l,i,h,v,L,S,B=null,$=null){let R=H?.sport,z=(R?Nt[R.toLowerCase()]:null)?.defaultPreset||"speed",X=Ye.get().speed_mode||z,fe=l==="elevation"?ho(S,20):null,I=document.createElement("div");I.className="chart-row",I.dataset.metric=l,I.style.setProperty("--chart-color",i.color);let se=document.createElement("div");se.className=`chart-row-header${Q?" with-histogram":""}`;let ge=document.createElement("div");ge.className="chart-row-label-group",ge.innerHTML=` ${i.icon} ${i.label} - `;let ce=document.createElement("button");ce.className=`icon-btn mini smooth-btn${b.has(l)?" active":""}`,ce.title="Toggle data smoothing",ce.innerHTML=`${b.has(l)?"blur_on":"blur_off"}`,ce.addEventListener("click",Z=>{Z.stopPropagation(),b.has(l)?b.delete(l):b.add(l),xe(!0)});let Fe=document.createElement("button");Fe.className=`map-color-btn icon-btn${ae===l?" active":""}`,Fe.dataset.metric=l,Fe.title="Color map track by this metric",Fe.innerHTML='colorize',Fe.addEventListener("click",()=>Ce(l));let me=null;if(l==="cadence"||l==="power"||l==="speed"){me=document.createElement("button");let Z=w.has(l);me.className=`icon-btn mini${Z?" active":""}`,me.title=Z?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",me.innerHTML=`${Z?"exposure_zero":"mobile_off"}`,me.addEventListener("click",we=>{we.stopPropagation(),w.has(l)?w.delete(l):w.add(l),xe(!0)})}let ve=document.createElement("div");ve.className="chart-stats-total";let Ie=document.createElement("div");Ie.className="chart-stats-selection";let Ve=document.createElement("div");Ve.className="chart-row-stats-container",Ve.append(ve,Ie);let Ze=document.createElement("div");Ze.className="chart-row-actions",Ze.append(ce,Fe);let st=document.createElement("div");if(st.className="chart-row-right-actions",l==="speed"){let Z=document.createElement("div");Z.className="seg-ctrl",Z.innerHTML=` - - - `,Z.addEventListener("click",we=>{let Ke=we.target.closest(".seg-btn");if(!Ke)return;let et=Ke.dataset.mode;if(et==="speed"||et==="pace"){let qe=et===N;Ye.patch({speed_mode:qe?null:et}),xe(!0)}}),st.append(Z)}me&&st.append(me),Se.append(ke,Ze,Ve,st);let nt=document.createElement("div");nt.className="chart-row-body";let ot=document.createElement("div");ot.style.position="relative",nt.appendChild(ot);let lt=document.createElement("div");lt.className="fixed-x-label fixed-x-min";let ie=document.createElement("div");ie.className="fixed-x-label fixed-x-max",ot.append(lt,ie);let Je=document.createElement("div");Je.className=`hist-col${se?" visible":""}`;let Ge=document.createElement("canvas");Ge.className="hist-canvas",Je.appendChild(Ge),nt.appendChild(Je),C.append(Se,nt);let Qe=R==="distance";function rt(Z,we){if(Z==null)return"";if(Qe){let Ke=we<1?3:we<5?2:we<20?1:0;return`${Z.toFixed(Ke)} km`}else{let Ke=Math.abs(Z),et=Math.floor(Ke/3600),qe=Math.floor(Ke%3600/60),xt=Math.round(Ke%60),gt=et>0?`${et}:`:"",Nt=et>0?String(qe).padStart(2,"0"):String(qe),$t=String(xt).padStart(2,"0");return`${Z<0?"-":""}${gt}${Nt}:${$t}`}}let ut=w.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",mt=1/0,Xe=-1/0,ct=0,vt=0,St=1/0,Yt=-1/0,Et=0,Jt=0;for(let Z=0;ZXe&&(Xe=we),ct+=we,vt++,(we!==0||ut)&&(weYt&&(Yt=we),Et+=we,Jt++))}vt===0&&(mt=0,Xe=100);let is=vt?{min:mt,max:Xe,avg:ct/vt}:null,Nn=Jt?{min:St,max:Yt,avg:Et/Jt}:null,As=Math.abs(Xe-mt)*.1||1,kl=[mt-As,Xe+As],Hs=!1;function as(Z,we,Ke){let et=w.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",qe=we-Z;lt.textContent=rt(Z,qe),ie.textContent=rt(we,qe);let xt=(gt,Nt,$t=!1)=>{let Ht=$t&&et===ut?Nn:Ts(f,v,gt,Nt,et);if(!Ht)return"";let Kt=` + `;let re=document.createElement("button");re.className=`icon-btn mini smooth-btn${f.has(l)?" active":""}`,re.title="Toggle data smoothing",re.innerHTML=`${f.has(l)?"blur_on":"blur_off"}`,re.addEventListener("click",ee=>{ee.stopPropagation(),f.has(l)?f.delete(l):f.add(l),Ee(!0)});let Be=document.createElement("button");Be.className=`map-color-btn icon-btn${oe===l?" active":""}`,Be.dataset.metric=l,Be.title="Color map track by this metric",Be.innerHTML='colorize',Be.addEventListener("click",()=>Ce(l));let pe=null;if(l==="cadence"||l==="power"||l==="speed"){pe=document.createElement("button");let ee=M.has(l);pe.className=`icon-btn mini${ee?" active":""}`,pe.title=ee?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",pe.innerHTML=`${ee?"exposure_zero":"mobile_off"}`,pe.addEventListener("click",$e=>{$e.stopPropagation(),M.has(l)?M.delete(l):M.add(l),Ee(!0)})}let ye=document.createElement("div");ye.className="chart-stats-total";let Te=document.createElement("div");Te.className="chart-stats-selection";let qe=document.createElement("div");qe.className="chart-row-stats-container",qe.append(ye,Te);let Ze=document.createElement("div");Ze.className="chart-row-actions",Ze.append(re,Be);let st=document.createElement("div");if(st.className="chart-row-right-actions",l==="speed"){let ee=document.createElement("div");ee.className="seg-ctrl",ee.innerHTML=` + + + `,ee.addEventListener("click",$e=>{let Ke=$e.target.closest(".seg-btn");if(!Ke)return;let et=Ke.dataset.mode;if(et==="speed"||et==="pace"){let Ve=et===z;Ye.patch({speed_mode:Ve?null:et}),Ee(!0)}}),st.append(ee)}pe&&st.append(pe),se.append(ge,Ze,qe,st);let nt=document.createElement("div");nt.className="chart-row-body";let it=document.createElement("div");it.style.position="relative",nt.appendChild(it);let lt=document.createElement("div");lt.className="fixed-x-label fixed-x-min";let ce=document.createElement("div");ce.className="fixed-x-label fixed-x-max",it.append(lt,ce);let Je=document.createElement("div");Je.className=`hist-col${Q?" visible":""}`;let Ge=document.createElement("canvas");Ge.className="hist-canvas",Je.appendChild(Ge),nt.appendChild(Je),I.append(se,nt);let Qe=O==="distance";function rt(ee,$e){if(ee==null)return"";if(Qe){let Ke=$e<1?3:$e<5?2:$e<20?1:0;return`${ee.toFixed(Ke)} km`}else{let Ke=Math.abs(ee),et=Math.floor(Ke/3600),Ve=Math.floor(Ke%3600/60),xt=Math.round(Ke%60),gt=et>0?`${et}:`:"",Rt=et>0?String(Ve).padStart(2,"0"):String(Ve),Ct=String(xt).padStart(2,"0");return`${ee<0?"-":""}${gt}${Rt}:${Ct}`}}let ut=M.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",mt=1/0,Xe=-1/0,ct=0,vt=0,St=1/0,jt=-1/0,Et=0,Kt=0;for(let ee=0;eeXe&&(Xe=$e),ct+=$e,vt++,($e!==0||ut)&&($ejt&&(jt=$e),Et+=$e,Kt++))}vt===0&&(mt=0,Xe=100);let Ps=vt?{min:mt,max:Xe,avg:ct/vt}:null,ns=Kt?{min:St,max:jt,avg:Et/Kt}:null,rl=Math.abs(Xe-mt)*.1||1,yo=[mt-rl,Xe+rl],cl=!1;function As(ee,$e,Ke){let et=M.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",Ve=$e-ee;lt.textContent=rt(ee,Ve),ce.textContent=rt($e,Ve);let xt=(gt,Rt,Ct=!1)=>{let Ht=Ct&&et===ut?ns:Js(h,v,gt,Rt,et);if(!Ht)return"";let tn=` align_flex_end${i.fmt(Ht.min,!0)} ${i.unit} align_center${i.fmt(Ht.avg,!0)} ${i.unit} align_flex_start${i.fmt(Ht.max,!0)} ${i.unit} - `;if(l==="elevation"){let Ut=vl(x,gt,Nt);Kt+=` + `;if(l==="elevation"){let Ut=co(S,gt,Rt);tn+=` trending_up+${Math.round(Ut.gain)} m trending_down-${Math.round(Ut.loss)} m - `}return Kt};Hs||(Hs=!0,ve.innerHTML=`all_inclusive${xt(f[0],f[f.length-1],!0)}`,ve.querySelector(".all-chip")?.addEventListener("click",gt=>{gt.stopPropagation(),ee()})),M!==null&&g!==null?(Ie.innerHTML=xt(M,g,!1),Ie.style.display="flex",Ie.style.setProperty("--sel-color",i.color)):Ie.style.display="none"}let $l=!1,Cl={width:$,height:130,padding:[4,0,0,0],cursor:{sync:{key:r.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:l==="elevation"?(Z,we)=>Rn(ue?ue[Z.cursor.idx]:null):i.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(Z,we,Ke)=>[we,Ke],min:A?A[0]:void 0,max:A?A[1]:void 0},y:{range:()=>kl,dir:l==="speed"&&j==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(Z,we,Ke,et)=>{let qe=et-Ke,gt=(Z.bbox.width>0?Z.bbox.width:Z.width)/80,Nt=qe/gt,$t;Qe?$t=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:$t=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let Ht=$t[$t.length-1];for(let qt=0;qt<$t.length;qt++)if($t[qt]>=Nt){Ht=$t[qt];break}let Kt=[],Ut=Math.ceil(Ke/Ht)*Ht,Zn=Ht<1?2:0;for(;Ut<=et;){let qt=Z.valToPos(Ut,"x",!0);qt>=Z.bbox.left+80&&qt<=Z.bbox.left+Z.bbox.width-80&&Kt.push(Number(Ut.toFixed(Zn))),Ut+=Ht}return Kt},values:(Z,we)=>{let Ke=(Z.scales.x?.max??1)-(Z.scales.x?.min??0);return we.map(et=>{if(et==null)return"";let qe=Z.valToPos(et,"x",!0);return qeZ.bbox.left+Z.bbox.width-80?null:rt(et,Ke)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(Z,we)=>we.map(Ke=>Ke!=null?i.fmtAxis(Ke):"")}],series:[{},{label:i.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[Z=>{let we=Z.bbox.top+Z.bbox.height+5;lt.style.top=`${we}px`,lt.style.left=`${Z.bbox.left}px`,ie.style.top=`${we}px`,ie.style.left=`${Z.bbox.left+Z.bbox.width}px`,ie.style.transform="translateX(-100%)"},Z=>{l==="gears"?Is(Z,f,v,i.color,1.5,l,null,x):l==="elevation"?yl(Z,f,v,ue):l==="gradient"?xl(Z,f,v):ae===l?Ml(Z,f,v,x,l):Is(Z,f,v,i.color,1.5,l,null,x)},Z=>{let we=e.find(et=>et.uplot===Z);if(!we)return;let Ke=Z._strasse;p!=null?wl(Z,f,v,i.color,i,x,l):(Ke&&Ke.pinYVal&&(Ke.pinYVal.style.display="none"),we.pinnedHistY!=null&&Tl(Z,f,v,we.pinnedHistY,i.color,i))},Z=>{let we=Z.cursor.idx,Ke=p!=null,et=we!=null&&Z.cursor.left>=0;if(et&&p==null){let qe=Z.valToPos(v[we],"y",!0);Math.abs(Z.cursor.top-qe)>100&&(et=!1)}if(et&&we!==p&&ks(Z,x,we,tt(i.color,.4),1),M!=null&&g!=null){let qe=Z.ctx,xt=window.devicePixelRatio||1,gt=Z.bbox,Nt=Z.valToPos(M,"x",!0),$t=Z.valToPos(g,"x",!0);qe.save(),qe.beginPath(),qe.lineWidth=3*xt,qe.strokeStyle=i.color,qe.moveTo(Nt,gt.top+gt.height),qe.lineTo($t,gt.top+gt.height),qe.stroke();let Ht=Math.abs(g-M),Kt=R==="distance"?`${Ht.toFixed(2)} km`:ht(Ht),Ut=9*xt,Zn=`bold ${Ut}px system-ui, sans-serif`;qe.font!==Zn&&(qe.font=Zn);let qt=qe.measureText(Kt).width,Bs=Math.max(gt.left,Nt),Fs=Math.min(gt.left+gt.width,$t);if(Fs-Bs>qt+14*xt){let Pl=5*xt,Il=2*xt,Gn=qt+Pl*2,Xn=Ut+Il*2,cs=(Bs+Fs)/2-Gn/2,ds=gt.top+gt.height-Xn/2;qe.beginPath(),qe.roundRect?qe.roundRect(cs,ds,Gn,Xn,3*xt):qe.rect(cs,ds,Gn,Xn),qe.fillStyle=i.color,qe.fill(),qe.fillStyle="#000",qe.textAlign="center",qe.textBaseline="middle",qe.fillText(Kt,cs+Gn/2,ds+Xn/2)}qe.restore()}Ke&&$s(Z,x,p,i.color,!0,.7),et&&we!==p&&$s(Z,x,we,i.color,!0,1)}],setCursor:[Z=>{if(u)return;let we=Z.cursor.idx;Z.redraw(!1),Z.cursor.left>=0?h=Z.posToVal(Z.cursor.left,"x"):h=null;let Ke=Z._strasse,et=we!=null&&v[we]!=null;if(et&&p==null){let qe=Z.valToPos(v[we],"y",!0);Math.abs(Z.cursor.top-qe)>100&&(et=!1)}if(Ke&&(et?Es(Z,Ke.curYVal,we,f,v,x,i,l):Ke.curYVal.style.display="none"),c||(we!=null&&x[we]?D&&(p!=null||et)?D(x[we]):D&&!et&&D(null):we===null&&D&&D(null)),we!=null&&v[we]!=null){let{min:qe,max:xt}=yt;if(qe!=null&&xt!=null){let gt=xt-qe||1,Nt=Math.min(yt.BINS-1,Math.floor((v[we]-qe)/gt*yt.BINS));Qt.hoveredHistY!==v[we]&&(Qt.hoveredHistY=v[we],At(Ge,yt,130,Nt))}}else Qt.hoveredHistY!==null&&(Qt.hoveredHistY=null,At(Ge,yt,130))}],setScale:[(Z,we)=>{if(we!=="x"||$l)return;let{min:Ke,max:et}=Z.scales.x;Y=[Ke,et],as(Ke,et,Z),!u&&(P||(B=null),u=!0,e.forEach(({uplot:qe})=>{qe!==Z&&qe.batch(()=>qe.setScale("x",{min:Ke,max:et}))}),u=!1,fe(),It(),le&&M!==null&&le(M,g,R))}],setSelect:[Z=>{if(P)return;B=null;let{left:we,width:Ke}=Z.select;if(Ke>0){let et=Z.posToVal(we,"x"),qe=Z.posToVal(we+Ke,"x");M=et,g=qe,as(Z.scales.x.min,Z.scales.x.max,Z),fe(),It(),le&&le(M,g,R),Z.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},rs=document.createElement("div");rs.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let Wn=document.createElement("div");Wn.className="sel-fill",Wn.style.display="none";let zn=document.createElement("div");zn.className="sel-line sel-line-anchor",zn.style.display="none";let Un=document.createElement("div");Un.className="sel-line-label sel-line-label-anchor",Un.style.display="none";let Cn=document.createElement("div");Cn.className="sel-handle sel-handle-anchor",Cn.style.display="none";let Ln=document.createElement("div");Ln.className="sel-graph-marker",Ln.innerHTML=`play_circle`,Ln.style.display="none";let qn=document.createElement("div");qn.className="sel-line sel-line-end",qn.style.display="none";let Vn=document.createElement("div");Vn.className="sel-line-label sel-line-label-end",Vn.style.display="none";let Pn=document.createElement("div");Pn.className="sel-handle sel-handle-end",Pn.style.display="none";let In=document.createElement("div");In.className="sel-graph-marker",In.innerHTML=`stop_circle`,In.style.display="none";let On=document.createElement("div");On.className="cur-y-val",On.style.cssText=`color:${i.color};display:none`;let Yn=document.createElement("div");Yn.className="cur-y-val pin",Yn.style.cssText=`color:${i.color};display:none`,rs.append(Wn,zn,Un,Cn,Ln,qn,Vn,Pn,In,On,Yn);let yt={yData:v,xData:f,def:i,BINS:24,min:vt?mt:void 0,max:vt?Xe:void 0,fullStats:Nn,fullStatsAll:is},Qt={uplot:null,row:C,xData:f,yData:v,def:i,metricKey:l,statsTotalEl:ve,statsSelEl:Ie,histCol:Je,histCanvas:Ge,histData:yt,hoveredHistY:null,pinnedHistY:null,smoothed:b.has(l),incZero:w.has(l),w:$};yt.plot=Qt;let Ll=u;u=!0;let jt=new Us(Cl,[f,v],(Z,we)=>{Qt.uplot=Z,e.push(Qt),ot.appendChild(Z.root),Z.over.appendChild(rs),Z._strasse={selFill:Wn,anchorLine:zn,anchorLabel:Un,anchorHandle:Cn,anchorMarker:Ln,endLine:qn,endLabel:Vn,endHandle:Pn,endMarker:In,curYVal:On,pinYVal:Yn,updateHeaderStats:as},Z.batch(()=>{we()})});u=Ll,je(Cn,jt,f,!0),je(Pn,jt,f,!1);let jn=null;jt.over.addEventListener("mousedown",Z=>{if(Z.button!==0)return;I=!1;let we=jt.over.getBoundingClientRect();jn=Z.clientX-we.left}),jt.over.addEventListener("mousemove",Z=>{if(jn!==null){let we=jt.over.getBoundingClientRect();Math.abs(Z.clientX-we.left-jn)>5&&(I=!0)}}),jt.over.addEventListener("mouseup",()=>{jn=null}),jt.over.addEventListener("click",()=>{if(I)return;let Z=jt.cursor.idx;Z!=null&&x[Z]&&(p=Z,e.forEach(({uplot:we})=>we.redraw(!1)),y&&y(x[Z],Z),d&&d(Z))}),C.addEventListener("dblclick",ee);let _s=null;if(p!=null&&f[p]!=null&&v[p]!=null&&(dt(yt),yt.min!=null&&yt.max!=null)){let Z=yt.max-yt.min||1;_s=Math.min(yt.BINS-1,Math.floor((v[p]-yt.min)/Z*yt.BINS)),Qt.hoveredHistY=v[p]}At(Ge,yt,130,_s),Xt(Ge,yt),ne&&(E?ne.insertBefore(C,E):ne.appendChild(C))}function fe(){be(),e.forEach(({uplot:l})=>l.batch(()=>l.redraw(!1)))}function be(){e.forEach(({uplot:l,def:i})=>{let f=l._strasse;if(!f)return;let{selFill:v,anchorLine:$,anchorLabel:x,anchorHandle:A,anchorMarker:E,endLine:H,endLabel:O,endHandle:N,endMarker:W}=f;if(M==null||g==null){[v,$,x,A,E,H,O,N,W].forEach(Ze=>{Ze.style.display="none"});return}let j=l.valToPos(M,"x"),ue=l.valToPos(g,"x"),C=window.devicePixelRatio||1,Se=l.bbox,ke=Se.width/C,ce=Se.height/C,Fe=(Se.top+Se.height)/C,me=j>=0&&j<=ke,ve=ue>=0&&ue<=ke,Ie=Math.max(0,j),Ve=Math.min(ke,ue);if(Ve>Ie?(v.style.left=`${Ie}px`,v.style.width=`${Ve-Ie}px`,v.style.top="0",v.style.height=`${ce}px`,v.style.backgroundColor=tt(i.color,.07),v.style.display=""):v.style.display="none",me){$.style.left=`${j}px`,$.style.height=`${ce}px`,$.style.borderLeftColor=i.color,$.style.display="";let Ze=Ue(M);x.textContent=Ze;let st=Ze.length*7+10;x.style.left=j+st+4Ze.style.display="none");if(ve){H.style.left=`${ue}px`,H.style.height=`${ce}px`,H.style.borderLeftColor=i.color,H.style.display="";let Ze=Ue(g);O.textContent=Ze;let st=Ze.length*7+10;O.style.left=ue-st-3>0?`${ue-st-3}px`:`${ue+3}px`,O.style.display="",N.style.left=`${ue}px`,N.style.backgroundColor=i.color,N.style.display="",W.style.left=`${ue}px`,W.style.top=`${Fe}px`;let nt=W.querySelector(".material-symbols-rounded");nt&&(nt.style.color=i.color),W.style.display=""}else[H,O,N,W].forEach(Ze=>Ze.style.display="none")})}function Ue(l){return R==="distance"?`${l.toFixed(2)} km`:ht(l)}function je(l,i,f,v){l.style.pointerEvents="auto",l.addEventListener("mousedown",$=>{$.stopPropagation(),$.preventDefault();let x=$.clientX,A=v?M:g,E=i.over.offsetWidth,H=i.scales.x.min,O=i.scales.x.max,N=E/(O-H),W=[f[0],f[f.length-1]];document.body.style.cursor="ew-resize",I=!0;function j(C){let Se=C.clientX-x,ke=(A||0)+Se/N;ke=Math.max(W[0],Math.min(W[1],ke)),v?M=Math.min(ke,(g||W[1])-.001):g=Math.max(ke,(M||W[0])+.001),e.forEach(ce=>ce.uplot._strasse?.updateHeaderStats(ce.uplot.scales.x.min,ce.uplot.scales.x.max)),fe(),It(),le&&le(M,g,R)}function ue(){document.body.style.cursor="",I=!1,document.removeEventListener("mousemove",j),document.removeEventListener("mouseup",ue)}document.addEventListener("mousemove",j),document.addEventListener("mouseup",ue)})}function dt(l){let{yData:i,xData:f,BINS:v}=l;if(l._lastYData===i&&l.bins)return;l._lastYData=i;let $=l.min,x=l.max;if($==null||x==null){let W=1/0,j=-1/0,ue=0;for(let C=0;Cj&&(j=Se),ue++)}if(!ue)return;$=W,x=j,l.min=$,l.max=x}let A=new Array(v).fill(0),E=new Array(v).fill(0),H=x-$||1,O=l.plot?.metricKey??Object.keys(_t).find(W=>_t[W]===l.def),N=!O||w.has(O)||O!=="power"&&O!=="cadence"&&O!=="speed";for(let W=0;W0&&f[W-1]!=null?f[W-1]:f[W],Se=W{At(l,i,f.height)})}function At(l,i,f,v=null){let{def:$,BINS:x}=i;dt(i);let{bins:A,min:E,max:H}=i;if(!A||E==null||H==null)return;let O=M!=null&&g!=null;if(O&&(i._lastSelRange?.[0]!==M||i._lastSelRange?.[1]!==g)){i._lastSelRange=[M,g];let ie=new Array(x).fill(0),Je=new Array(x).fill(0),{yData:Ge,xData:Qe}=i,rt=H-E||1,ut=i.plot?.metricKey??Object.keys(_t).find(Xe=>_t[Xe]===i.def),mt=!ut||w.has(ut)||ut!=="power"&&ut!=="cadence"&&ut!=="speed";for(let Xe=0;Xeg)continue;let St=Math.min(x-1,Math.floor((ct-E)/rt*x));ie[St]++;let Yt=Xe>0&&Qe[Xe-1]!=null?Qe[Xe-1]:Qe[Xe],Et=Xe$.fmtAxis(ie),ce="9px system-ui, sans-serif";C.font!==ce&&(C.font=ce);let me={t:4,r:0,b:30,l:Math.ceil(Math.max(C.measureText(`${ke(H)} ${$.unit}`).width,C.measureText(`${ke(E)} ${$.unit}`).width))+6};i.padL=me.l;let ve=j-me.l-me.r,Ie=ue-me.t-me.b,Ve=ie=>me.t+(x-1-ie)*(Ie/x),Ze=Ie/x-1,st=O?.15:.6;C.fillStyle=tt($.color,st);for(let ie=0;ieie+Je,0);if(nt>0){let ie=[{x:me.l,y:me.t+Ie}],Je=0;for(let Ge=0;GeGe+Qe+2&&ie0){let ie=0;for(let ct=0;ct{let $=Ot(l,i,v);if($!=null&&f){let{min:x,max:A,BINS:E}=i,H=A-x||1;f.pinnedHistY=x+($+.5)*(H/E),e.forEach(({uplot:O})=>O.redraw(!1))}}),l.addEventListener("mousemove",v=>{F=v,pn(v,l,i)}),l.addEventListener("mouseenter",()=>{J=l,q=i}),l.addEventListener("mouseleave",()=>{J===l&&(J=null,q=null),U&&(U.style.display="none");let v=document.getElementById("hist-line");v&&(v.style.display="none"),f&&(f.hoveredHistY=null,At(l,i,l.height/(window.devicePixelRatio||1)))})}function Ot(l,i,f){let{bins:v,BINS:$}=i;if(!v)return null;let x=l.getBoundingClientRect(),A=f.clientY-x.top,E={t:4,b:30},H=x.height-E.t-E.b,O=Math.floor((A-E.t)/H*$),N=$-1-O;return O<0||O>=$?null:N}function pn(l,i,f){if(!U)return;let{bins:v,binAccum:$,min:x,max:A,BINS:E,def:H,plot:O}=f;if(!v||!$||x==null||A==null)return;let N=document.getElementById("hist-line"),W=Ot(i,f,l);if(W==null||!v[W]){U.style.display="none",N&&(N.style.display="none"),O&&(O.hoveredHistY=null,At(i,f,i.height/(window.devicePixelRatio||1)));return}if(O){let Qe=A-x||1;O.hoveredHistY=x+(W+.5)*(Qe/E),At(i,f,i.height/(window.devicePixelRatio||1),W)}let j=v[W],ue=v.reduce((Qe,rt)=>Qe+rt,0),C=j/ue*100,Se=A-x||1,ke=x+W*(Se/E),ce=x+(W+1)*(Se/E),Fe=`${H.fmt(ke,!0)} \u2013 ${H.fmt(ce,!0)} ${H.unit}`,me="",ve=(ke+ce)/2,Ie=Object.keys(_t).find(Qe=>_t[Qe]===H),Ve=[];if(Ie==="power"?Ve=gn.getPowerZones():Ie==="hr"&&(Ve=gn.getHRZones()),Ve.length>0){let Qe=Ve.findIndex(ut=>ve>=ut.min&&ve=Ve[Ve.length-1].min?Ve[Ve.length-1]:null;if(rt){let ut=Qe!==-1?Qe:Ve.length-1;me=` + `}return tn};cl||(cl=!0,ye.innerHTML=`all_inclusive${xt(h[0],h[h.length-1],!0)}`,ye.querySelector(".all-chip")?.addEventListener("click",gt=>{gt.stopPropagation(),ne()})),k!==null&&p!==null?(Te.innerHTML=xt(k,p,!1),Te.style.display="flex",Te.style.setProperty("--sel-color",i.color)):Te.style.display="none"}let xo=!1,wo={width:L,height:130,padding:[4,0,0,0],cursor:{sync:{key:a.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:l==="elevation"?(ee,$e)=>Kn(fe?fe[ee.cursor.idx]:null):i.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(ee,$e,Ke)=>[$e,Ke],min:B?B[0]:void 0,max:B?B[1]:void 0},y:{range:()=>yo,dir:l==="speed"&&X==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(ee,$e,Ke,et)=>{let Ve=et-Ke,gt=(ee.bbox.width>0?ee.bbox.width:ee.width)/80,Rt=Ve/gt,Ct;Qe?Ct=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:Ct=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let Ht=Ct[Ct.length-1];for(let Vt=0;Vt=Rt){Ht=Ct[Vt];break}let tn=[],Ut=Math.ceil(Ke/Ht)*Ht,us=Ht<1?2:0;for(;Ut<=et;){let Vt=ee.valToPos(Ut,"x",!0);Vt>=ee.bbox.left+80&&Vt<=ee.bbox.left+ee.bbox.width-80&&tn.push(Number(Ut.toFixed(us))),Ut+=Ht}return tn},values:(ee,$e)=>{let Ke=(ee.scales.x?.max??1)-(ee.scales.x?.min??0);return $e.map(et=>{if(et==null)return"";let Ve=ee.valToPos(et,"x",!0);return Veee.bbox.left+ee.bbox.width-80?null:rt(et,Ke)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(ee,$e)=>$e.map(Ke=>Ke!=null?i.fmtAxis(Ke):"")}],series:[{},{label:i.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[ee=>{let $e=ee.bbox.top+ee.bbox.height+5;lt.style.top=`${$e}px`,lt.style.left=`${ee.bbox.left}px`,ce.style.top=`${$e}px`,ce.style.left=`${ee.bbox.left+ee.bbox.width}px`,ce.style.transform="translateX(-100%)"},ee=>{l==="gears"?al(ee,h,v,i.color,1.5,l,null,S):l==="elevation"?uo(ee,h,v,fe):l==="gradient"?mo(ee,h,v):oe===l?vo(ee,h,v,S,l):al(ee,h,v,i.color,1.5,l,null,S)},ee=>{let $e=e.find(et=>et.uplot===ee);if(!$e)return;let Ke=ee._strasse;u!=null?po(ee,h,v,i.color,i,S,l):(Ke&&Ke.pinYVal&&(Ke.pinYVal.style.display="none"),$e.pinnedHistY!=null&&fo(ee,h,v,$e.pinnedHistY,i.color,i))},ee=>{let $e=ee.cursor.idx,Ke=u!=null,et=$e!=null&&ee.cursor.left>=0;if(et&&u==null){let Ve=ee.valToPos(v[$e],"y",!0);Math.abs(ee.cursor.top-Ve)>100&&(et=!1)}if(et&&$e!==u&&tl(ee,S,$e,tt(i.color,.4),1),k!=null&&p!=null){let Ve=ee.ctx,xt=window.devicePixelRatio||1,gt=ee.bbox,Rt=ee.valToPos(k,"x",!0),Ct=ee.valToPos(p,"x",!0);Ve.save(),Ve.beginPath(),Ve.lineWidth=3*xt,Ve.strokeStyle=i.color,Ve.moveTo(Rt,gt.top+gt.height),Ve.lineTo(Ct,gt.top+gt.height),Ve.stroke();let Ht=Math.abs(p-k),tn=O==="distance"?`${Ht.toFixed(2)} km`:ht(Ht),Ut=9*xt,us=`bold ${Ut}px system-ui, sans-serif`;Ve.font!==us&&(Ve.font=us);let Vt=Ve.measureText(tn).width,ul=Math.max(gt.left,Rt),ml=Math.min(gt.left+gt.width,Ct);if(ml-ul>Vt+14*xt){let Eo=5*xt,So=2*xt,ms=Vt+Eo*2,ps=Ut+So*2,Hs=(ul+ml)/2-ms/2,Fs=gt.top+gt.height-ps/2;Ve.beginPath(),Ve.roundRect?Ve.roundRect(Hs,Fs,ms,ps,3*xt):Ve.rect(Hs,Fs,ms,ps),Ve.fillStyle=i.color,Ve.fill(),Ve.fillStyle="#000",Ve.textAlign="center",Ve.textBaseline="middle",Ve.fillText(tn,Hs+ms/2,Fs+ps/2)}Ve.restore()}Ke&&nl(ee,S,u,i.color,!0,.7),et&&$e!==u&&nl(ee,S,$e,i.color,!0,1)}],setCursor:[ee=>{if(g)return;let $e=ee.cursor.idx;ee.redraw(!1),ee.cursor.left>=0?x=ee.posToVal(ee.cursor.left,"x"):x=null;let Ke=ee._strasse,et=$e!=null&&v[$e]!=null;if(et&&u==null){let Ve=ee.valToPos(v[$e],"y",!0);Math.abs(ee.cursor.top-Ve)>100&&(et=!1)}if(Ke&&(et?Qs(ee,Ke.curYVal,$e,h,v,S,i,l):Ke.curYVal.style.display="none"),c||($e!=null&&S[$e]?N&&(u!=null||et)?N(S[$e]):N&&!et&&N(null):$e===null&&N&&N(null)),$e!=null&&v[$e]!=null){let{min:Ve,max:xt}=yt;if(Ve!=null&&xt!=null){let gt=xt-Ve||1,Rt=Math.min(yt.BINS-1,Math.floor((v[$e]-Ve)/gt*yt.BINS));en.hoveredHistY!==v[$e]&&(en.hoveredHistY=v[$e],It(Ge,yt,130,Rt))}}else en.hoveredHistY!==null&&(en.hoveredHistY=null,It(Ge,yt,130))}],setScale:[(ee,$e)=>{if($e!=="x"||xo)return;let{min:Ke,max:et}=ee.scales.x;_=[Ke,et],As(Ke,et,ee),!g&&(b||(C=null),g=!0,e.forEach(({uplot:Ve})=>{Ve!==ee&&Ve.batch(()=>Ve.setScale("x",{min:Ke,max:et}))}),g=!1,ve(),At(),ie&&k!==null&&ie(k,p,O))}],setSelect:[ee=>{if(b)return;C=null;let{left:$e,width:Ke}=ee.select;if(Ke>0){let et=ee.posToVal($e,"x"),Ve=ee.posToVal($e+Ke,"x");k=et,p=Ve,As(ee.scales.x.min,ee.scales.x.max,ee),ve(),At(),ie&&ie(k,p,O),ee.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},Is=document.createElement("div");Is.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let ss=document.createElement("div");ss.className="sel-fill",ss.style.display="none";let ls=document.createElement("div");ls.className="sel-line sel-line-anchor",ls.style.display="none";let os=document.createElement("div");os.className="sel-line-label sel-line-label-anchor",os.style.display="none";let Wn=document.createElement("div");Wn.className="sel-handle sel-handle-anchor",Wn.style.display="none";let zn=document.createElement("div");zn.className="sel-graph-marker",zn.innerHTML=`play_circle`,zn.style.display="none";let is=document.createElement("div");is.className="sel-line sel-line-end",is.style.display="none";let as=document.createElement("div");as.className="sel-line-label sel-line-label-end",as.style.display="none";let qn=document.createElement("div");qn.className="sel-handle sel-handle-end",qn.style.display="none";let Un=document.createElement("div");Un.className="sel-graph-marker",Un.innerHTML=`stop_circle`,Un.style.display="none";let rs=document.createElement("div");rs.className="cur-y-val",rs.style.cssText=`color:${i.color};display:none`;let cs=document.createElement("div");cs.className="cur-y-val pin",cs.style.cssText=`color:${i.color};display:none`,Is.append(ss,ls,os,Wn,zn,is,as,qn,Un,rs,cs);let yt={yData:v,xData:h,def:i,BINS:24,min:vt?mt:void 0,max:vt?Xe:void 0,fullStats:ns,fullStatsAll:Ps},en={uplot:null,row:I,xData:h,yData:v,def:i,metricKey:l,statsTotalEl:ye,statsSelEl:Te,histCol:Je,histCanvas:Ge,histData:yt,hoveredHistY:null,pinnedHistY:null,smoothed:f.has(l),incZero:M.has(l),w:L};yt.plot=en;let To=g;g=!0;let Zt=new vl(wo,[h,v],(ee,$e)=>{en.uplot=ee,e.push(en),it.appendChild(ee.root),ee.over.appendChild(Is),ee._strasse={selFill:ss,anchorLine:ls,anchorLabel:os,anchorHandle:Wn,anchorMarker:zn,endLine:is,endLabel:as,endHandle:qn,endMarker:Un,curYVal:rs,pinYVal:cs,updateHeaderStats:As},ee.batch(()=>{$e()})});g=To,je(Wn,Zt,h,!0),je(qn,Zt,h,!1);let ds=null;Zt.over.addEventListener("mousedown",ee=>{if(ee.button!==0)return;P=!1;let $e=Zt.over.getBoundingClientRect();ds=ee.clientX-$e.left}),Zt.over.addEventListener("mousemove",ee=>{if(ds!==null){let $e=Zt.over.getBoundingClientRect();Math.abs(ee.clientX-$e.left-ds)>5&&(P=!0)}}),Zt.over.addEventListener("mouseup",()=>{ds=null}),Zt.over.addEventListener("click",()=>{if(P)return;let ee=Zt.cursor.idx;ee!=null&&S[ee]&&(u=ee,e.forEach(({uplot:$e})=>$e.redraw(!1)),y&&y(S[ee],ee),d&&d(ee))}),I.addEventListener("dblclick",ne);let dl=null;if(u!=null&&h[u]!=null&&v[u]!=null&&(dt(yt),yt.min!=null&&yt.max!=null)){let ee=yt.max-yt.min||1;dl=Math.min(yt.BINS-1,Math.floor((v[u]-yt.min)/ee*yt.BINS)),en.hoveredHistY=v[u]}It(Ge,yt,130,dl),Qt(Ge,yt),K&&($?K.insertBefore(I,$):K.appendChild(I))}function ve(){Me(),e.forEach(({uplot:l})=>l.batch(()=>l.redraw(!1)))}function Me(){e.forEach(({uplot:l,def:i})=>{let h=l._strasse;if(!h)return;let{selFill:v,anchorLine:L,anchorLabel:S,anchorHandle:B,anchorMarker:$,endLine:R,endLabel:Z,endHandle:z,endMarker:V}=h;if(k==null||p==null){[v,L,S,B,$,R,Z,z,V].forEach(Ze=>{Ze.style.display="none"});return}let X=l.valToPos(k,"x"),fe=l.valToPos(p,"x"),I=window.devicePixelRatio||1,se=l.bbox,ge=se.width/I,re=se.height/I,Be=(se.top+se.height)/I,pe=X>=0&&X<=ge,ye=fe>=0&&fe<=ge,Te=Math.max(0,X),qe=Math.min(ge,fe);if(qe>Te?(v.style.left=`${Te}px`,v.style.width=`${qe-Te}px`,v.style.top="0",v.style.height=`${re}px`,v.style.backgroundColor=tt(i.color,.07),v.style.display=""):v.style.display="none",pe){L.style.left=`${X}px`,L.style.height=`${re}px`,L.style.borderLeftColor=i.color,L.style.display="";let Ze=Ue(k);S.textContent=Ze;let st=Ze.length*7+10;S.style.left=X+st+4Ze.style.display="none");if(ye){R.style.left=`${fe}px`,R.style.height=`${re}px`,R.style.borderLeftColor=i.color,R.style.display="";let Ze=Ue(p);Z.textContent=Ze;let st=Ze.length*7+10;Z.style.left=fe-st-3>0?`${fe-st-3}px`:`${fe+3}px`,Z.style.display="",z.style.left=`${fe}px`,z.style.backgroundColor=i.color,z.style.display="",V.style.left=`${fe}px`,V.style.top=`${Be}px`;let nt=V.querySelector(".material-symbols-rounded");nt&&(nt.style.color=i.color),V.style.display=""}else[R,Z,z,V].forEach(Ze=>Ze.style.display="none")})}function Ue(l){return O==="distance"?`${l.toFixed(2)} km`:ht(l)}function je(l,i,h,v){l.style.pointerEvents="auto",l.addEventListener("mousedown",L=>{L.stopPropagation(),L.preventDefault();let S=L.clientX,B=v?k:p,$=i.over.offsetWidth,R=i.scales.x.min,Z=i.scales.x.max,z=$/(Z-R),V=[h[0],h[h.length-1]];document.body.style.cursor="ew-resize",P=!0;function X(I){let se=I.clientX-S,ge=(B||0)+se/z;ge=Math.max(V[0],Math.min(V[1],ge)),v?k=Math.min(ge,(p||V[1])-.001):p=Math.max(ge,(k||V[0])+.001),e.forEach(re=>re.uplot._strasse?.updateHeaderStats(re.uplot.scales.x.min,re.uplot.scales.x.max)),ve(),At(),ie&&ie(k,p,O)}function fe(){document.body.style.cursor="",P=!1,document.removeEventListener("mousemove",X),document.removeEventListener("mouseup",fe)}document.addEventListener("mousemove",X),document.addEventListener("mouseup",fe)})}function dt(l){let{yData:i,xData:h,BINS:v}=l;if(l._lastYData===i&&l.bins)return;l._lastYData=i;let L=l.min,S=l.max;if(L==null||S==null){let V=1/0,X=-1/0,fe=0;for(let I=0;IX&&(X=se),fe++)}if(!fe)return;L=V,S=X,l.min=L,l.max=S}let B=new Array(v).fill(0),$=new Array(v).fill(0),R=S-L||1,Z=l.plot?.metricKey??Object.keys(Ft).find(V=>Ft[V]===l.def),z=!Z||M.has(Z)||Z!=="power"&&Z!=="cadence"&&Z!=="speed";for(let V=0;V0&&h[V-1]!=null?h[V-1]:h[V],se=V{It(l,i,h.height)})}function It(l,i,h,v=null){let{def:L,BINS:S}=i;dt(i);let{bins:B,min:$,max:R}=i;if(!B||$==null||R==null)return;let Z=k!=null&&p!=null;if(Z&&(i._lastSelRange?.[0]!==k||i._lastSelRange?.[1]!==p)){i._lastSelRange=[k,p];let ce=new Array(S).fill(0),Je=new Array(S).fill(0),{yData:Ge,xData:Qe}=i,rt=R-$||1,ut=i.plot?.metricKey??Object.keys(Ft).find(Xe=>Ft[Xe]===i.def),mt=!ut||M.has(ut)||ut!=="power"&&ut!=="cadence"&&ut!=="speed";for(let Xe=0;Xep)continue;let St=Math.min(S-1,Math.floor((ct-$)/rt*S));ce[St]++;let jt=Xe>0&&Qe[Xe-1]!=null?Qe[Xe-1]:Qe[Xe],Et=XeL.fmtAxis(ce),re="9px system-ui, sans-serif";I.font!==re&&(I.font=re);let pe={t:4,r:0,b:30,l:Math.ceil(Math.max(I.measureText(`${ge(R)} ${L.unit}`).width,I.measureText(`${ge($)} ${L.unit}`).width))+6};i.padL=pe.l;let ye=X-pe.l-pe.r,Te=fe-pe.t-pe.b,qe=ce=>pe.t+(S-1-ce)*(Te/S),Ze=Te/S-1,st=Z?.15:.6;I.fillStyle=tt(L.color,st);for(let ce=0;cece+Je,0);if(nt>0){let ce=[{x:pe.l,y:pe.t+Te}],Je=0;for(let Ge=0;GeGe+Qe+2&&ce0){let ce=0;for(let ct=0;ct{let L=Yt(l,i,v);if(L!=null&&h){let{min:S,max:B,BINS:$}=i,R=B-S||1;h.pinnedHistY=S+(L+.5)*(R/$),e.forEach(({uplot:Z})=>Z.redraw(!1))}}),l.addEventListener("mousemove",v=>{w=v,wn(v,l,i)}),l.addEventListener("mouseenter",()=>{W=l,D=i}),l.addEventListener("mouseleave",()=>{W===l&&(W=null,D=null),Y&&(Y.style.display="none");let v=document.getElementById("hist-line");v&&(v.style.display="none"),h&&(h.hoveredHistY=null,It(l,i,l.height/(window.devicePixelRatio||1)))})}function Yt(l,i,h){let{bins:v,BINS:L}=i;if(!v)return null;let S=l.getBoundingClientRect(),B=h.clientY-S.top,$={t:4,b:30},R=S.height-$.t-$.b,Z=Math.floor((B-$.t)/R*L),z=L-1-Z;return Z<0||Z>=L?null:z}function wn(l,i,h){if(!Y)return;let{bins:v,binAccum:L,min:S,max:B,BINS:$,def:R,plot:Z}=h;if(!v||!L||S==null||B==null)return;let z=document.getElementById("hist-line"),V=Yt(i,h,l);if(V==null||!v[V]){Y.style.display="none",z&&(z.style.display="none"),Z&&(Z.hoveredHistY=null,It(i,h,i.height/(window.devicePixelRatio||1)));return}if(Z){let Qe=B-S||1;Z.hoveredHistY=S+(V+.5)*(Qe/$),It(i,h,i.height/(window.devicePixelRatio||1),V)}let X=v[V],fe=v.reduce((Qe,rt)=>Qe+rt,0),I=X/fe*100,se=B-S||1,ge=S+V*(se/$),re=S+(V+1)*(se/$),Be=`${R.fmt(ge,!0)} \u2013 ${R.fmt(re,!0)} ${R.unit}`,pe="",ye=(ge+re)/2,Te=Object.keys(Ft).find(Qe=>Ft[Qe]===R),qe=[];if(Te==="power"?qe=Sn.getPowerZones():Te==="hr"&&(qe=Sn.getHRZones()),qe.length>0){let Qe=qe.findIndex(ut=>ye>=ut.min&&ye=qe[qe.length-1].min?qe[qe.length-1]:null;if(rt){let ut=Qe!==-1?Qe:qe.length-1;pe=`
Z${ut+1} \xB7 ${rt.name}
- `}}let Ze=R==="distance"?`${$[W].toFixed(2)} km`:ht($[W]),st=$[W]/$.reduce((Qe,rt)=>Qe+rt,0)*100,nt=` -
${Fe}
- ${me} + `}}let Ze=O==="distance"?`${L[V].toFixed(2)} km`:ht(L[V]),st=L[V]/L.reduce((Qe,rt)=>Qe+rt,0)*100,nt=` +
${Be}
+ ${pe} `;if(Ze&&(nt+=`
- ${R==="distance"?"Dist":"Time"} + ${O==="distance"?"Dist":"Time"} ${Ze} ${st.toFixed(1)}% -
`),f.selBins&&f.selBinAccum){let Qe=R==="distance"?`${f.selBinAccum[W].toFixed(2)} km`:ht(f.selBinAccum[W]),rt=f.selBinAccum[W]/f.selBinAccum.reduce((ut,mt)=>ut+mt,0)*100;nt+=` + `),h.selBins&&h.selBinAccum){let Qe=O==="distance"?`${h.selBinAccum[V].toFixed(2)} km`:ht(h.selBinAccum[V]),rt=h.selBinAccum[V]/h.selBinAccum.reduce((ut,mt)=>ut+mt,0)*100;nt+=`
- Sel ${R==="distance"?"Dist":"Time"} + Sel ${O==="distance"?"Dist":"Time"} ${Qe} ${rt.toFixed(1)}%
- `}U.innerHTML=nt,U.style.display="block";let ot=U.offsetHeight,lt=U.offsetWidth,ie=i.getBoundingClientRect(),Je=ie.height-4-30,Ge=ie.top+4+(E-1-W+.5)*(Je/E);U.style.left=`${ie.left-lt-12}px`,U.style.top=`${Ge-ot/2}px`,N&&(N.style.display="block",N.style.top=`${Ge}px`,N.style.left="0px",N.style.width=`${ie.left}px`)}function $n(l=!1){U&&(U.style.display="none"),e.forEach(({uplot:i,row:f})=>{r.unsub(i),i.destroy(),f.remove()}),e=[],s=null,l||(M=null,g=null),I=!1}function Ts(l,i,f,v,$=!0){let x=1/0,A=-1/0,E=0,H=0;for(let O=0;Ov)continue;let N=i[O];N==null||!isFinite(N)||N===0&&!$||(NA&&(A=N),E+=N,H++)}return H?{min:x,max:A,avg:E/H}:null}function vl(l,i,f){let v=0,$=0,x=null,A=R==="distance",E=l[0].time||0;for(let H=0;Hf)&&O.ele!=null){if(x!=null){let W=O.ele-x;W>0?v+=W:W<0&&($+=Math.abs(W))}x=O.ele}}return{gain:v,loss:$}}function Es(l,i,f,v,$,x,A,E){if(f==null||$[f]==null){i.style.display="none";return}let H=l.valToPos(v[f],"x",!1),O=l.valToPos($[f],"y",!1),N="#888896",W=0;if(f>0&&x[f]&&x[f-1]){let ce=x[f-1],Fe=x[f],me=(Fe.dist||0)-(ce.dist||0);me>.1&&Fe.ele!=null&&ce.ele!=null&&(W=(Fe.ele-ce.ele)/me*100,N=Rn(W))}let j=E!=="elevation"?`${A.fmt($[f],!1)} ${A.unit}`:`${A.fmt($[f],!1)} ${A.unit} \u2220 ${Math.abs(W).toFixed(1)}%`;if(E==="gearRear"&&x[f].gearRearTooth!=null)j=`${x[f].gearRearTooth}T (pos ${$[f]})`;else if(E==="gearFront"&&x[f].gearFrontTooth!=null)j=`${x[f].gearFrontTooth}T (pos ${$[f]})`;else if(E==="gears"){let ce=x[f],Fe=ce.gearFrontTooth!=null?`${ce.gearFrontTooth}T`:ce.gearFront!=null?`pos ${ce.gearFront}`:"",me=ce.gearRearTooth!=null?`${ce.gearRearTooth}T`:ce.gearRear!=null?`pos ${ce.gearRear}`:"";(Fe||me)&&(j+=` (${Fe} / ${me})`)}i.innerHTML!==j&&(i.innerHTML=j);let ue=`${A.color}44`;i.style.color!==A.color&&(i.style.color=A.color),i.style.borderColor!==ue&&(i.style.borderColor=ue);let C=`${H}px`,Se=`${O}px`,ke="translate(6px, -50%)";i.style.left!==C&&(i.style.left=C),i.style.top!==Se&&(i.style.top=Se),i.style.transform!==ke&&(i.style.transform=ke),i.style.display!==""&&(i.style.display="")}let Ss=new Map;function Ms(l){let i=Ss.get(l);return i||(i=tt(Rn(l),.8),Ss.set(l,i)),i}function yl(l,i,f,v){let $=l.ctx,x=l.bbox,A=window.devicePixelRatio||1,E=l.scales.x?.min??-1/0,H=l.scales.x?.max??1/0,O=l.scales.y?.min??0,N=l.scales.y?.max??100,W=x.width/(H-E||1),j=x.height/(N-O||1),ue=x.top+x.height,C=l.series[0]?.idxs,Se=C?Math.max(1,C[0]):1,ke=C?Math.min(i.length-1,C[1]+1):i.length-1,ce=Math.max(1,Math.floor((ke-Se)/250));$.save(),$.lineWidth=1.5*A;let Fe=new Map,me=Se-1;for(let ve=Se;ve<=ke;ve+=ce){let Ie=i[ve],Ve=i[me];if(me=ve,Ie==null||f[ve]==null||Ve==null||f[ve-ce]==null||IeH)continue;let Ze=x.left+(Ve-E)*W,st=ue-(f[ve-ce]-O)*j,nt=x.left+(Ie-E)*W,ot=ue-(f[ve]-O)*j,lt=v&&v[ve]!=null?Math.round(v[ve]/2)*2:null,ie=Ms(lt),Je=Fe.get(ie);Je||(Je=[],Fe.set(ie,Je)),Je.push(Ze,st,nt,ot)}for(let[ve,Ie]of Fe){$.beginPath(),$.strokeStyle=ve;for(let Ve=0;VeE)continue;let Ve=$.left+(Ie-A)*N,Ze=j-(f[me-ke]-H)*W,st=$.left+(ve-A)*N,nt=j-(f[me]-H)*W,ot=Math.round(f[me]/2)*2,lt=Ms(ot),ie=ce.get(lt);ie||(ie=[],ce.set(lt,ie)),ie.push(Ve,Ze,st,nt)}for(let[me,ve]of ce){v.beginPath(),v.strokeStyle=me;for(let Ie=0;Ie{let Ie=`bold ${10*A}px system-ui, sans-serif`;H.font!==Ie&&(H.font=Ie);let Ze=H.measureText(ce).width+10*A,st=16*A,nt=Fe-Ze/2,ot=Math.max(E.left,Math.min(E.left+E.width-Ze,nt)),lt=me-st/2;H.save(),H.globalAlpha=x,H.setLineDash([]),H.beginPath(),H.roundRect?H.roundRect(ot,lt,Ze,st,3*A):H.rect(ot,lt,Ze,st),H.fillStyle="rgba(14,14,16,0.92)",H.fill(),H.strokeStyle=tt(v,.27),H.lineWidth=1*A,H.stroke(),H.fillStyle=v,H.textAlign="center",H.textBaseline="middle",H.fillText(ce,ot+Ze/2,lt+st/2+.5*A),H.restore()};$||ks(l,i,f,v,x);let ke=16*A;Se(C,j,E.top+ke/2,!0),Se(ue,j,E.top+E.height+15*A,!1)}function wl(l,i,f,v,$,x,A){if(p==null)return;let E=i[p],H=f[p];if(E==null||H==null)return;let O=l.valToPos(E,"x",!0),N=l.valToPos(H,"y",!0),W=l.bbox,j=l.ctx,ue=window.devicePixelRatio||1;j.save(),j.beginPath(),j.strokeStyle=v,j.lineWidth=1.5*ue,j.moveTo(O,W.top),j.lineTo(O,W.top+W.height),j.stroke(),j.beginPath(),j.setLineDash([3*ue,3*ue]),j.strokeStyle=tt(v,.5),j.lineWidth=1*ue,j.moveTo(W.left,N),j.lineTo(O,N),j.stroke(),j.beginPath(),j.setLineDash([]),j.arc(O,N,5*ue,0,Math.PI*2),j.fillStyle="#0e0e10",j.fill(),j.strokeStyle=v,j.lineWidth=2.5*ue,j.stroke(),j.restore();let C=l._strasse;C&&C.pinYVal&&Es(l,C.pinYVal,p,i,f,x,$,A)}function Tl(l,i,f,v,$,x){let A=l.bbox,E=l.ctx,H=window.devicePixelRatio||1,O=l.valToPos(v,"y",!0),N=Math.max(A.top,Math.min(A.top+A.height,O));E.save(),E.beginPath(),E.setLineDash([4*H,4*H]),E.strokeStyle=tt($,.4),E.lineWidth=1*H,E.moveTo(A.left,N),E.lineTo(A.left+A.width,N),E.stroke(),El(l,i,f,N,$);let W=x.fmt(v,!0),j=`bold ${10*H}px system-ui, sans-serif`;E.font!==j&&(E.font=j);let C=E.measureText(W).width+8*H,Se=16*H,ke=A.left-C-2*H,ce=N-Se/2;E.beginPath(),E.setLineDash([]),E.roundRect?E.roundRect(ke,ce,C,Se,3*H):E.rect(ke,ce,C,Se),E.fillStyle="rgba(14,14,16,0.95)",E.fill(),E.strokeStyle=$,E.lineWidth=1*H,E.stroke(),E.fillStyle="#fff",E.textAlign="center",E.textBaseline="middle",E.fillText(W,ke+C/2,ce+Se/2+.5*H),E.restore()}function El(l,i,f,v,$){let x=l.ctx,A=l.bbox,E=l.scales.x?.min??-1/0,H=l.scales.x?.max??1/0,O=l.scales.y?.min??0,N=l.scales.y?.max??100,W=A.width/(H-E||1),j=A.height/(N-O||1),ue=l.scales.y?.dir??1,C=ue===-1?A.top:A.top+A.height,Se=ue===-1?j:-j,ke=l.series[0]?.idxs,ce=ke?Math.max(0,ke[0]-1):0,Fe=ke?Math.min(i.length-1,ke[1]+1):i.length-1,me=Math.max(1,Math.floor((Fe-ce)/250));x.save(),x.beginPath(),x.rect(A.left,A.top,A.width,A.height),x.clip(),x.fillStyle=tt($,.2),x.beginPath();let ve=!1,Ie=!1,Ve=0;for(let Ze=ce;Ze<=Fe;Ze+=me){let st=i[Ze],nt=f[Ze];if(st==null||nt==null||stH){ve&&(x.lineTo(Ve,v),x.closePath(),ve=!1);continue}let ot=A.left+(st-E)*W,lt=C+(nt-O)*Se;Ve=ot,lt>16,A=v>>8&255,E=v&255,H=$>>16,O=$>>8&255,N=$&255,W=x+(H-x)*f,j=A+(O-A)*f,ue=E+(N-E)*f;return`#${((1<<24)+(Math.round(W)<<16)+(Math.round(j)<<8)+Math.round(ue)).toString(16).slice(1)}`}function Rn(l){if(l==null)return"#888896";let i=Math.abs(l),f=Math.min(1,i/8);return l>0?Rt("#A8C8A0","#d73027",f):Rt("#A8C8A0","#4575b4",f)}function Cs(l){if(l==null)return"#888896";let i=l*3.6;if(i<=5)return"#4575b4";if(i>=60)return"#d73027";if(i<=45){let f=(i-5)/40;return f<=.25?Rt("#4575b4","#91bfdb",f/.25):f<=.5?Rt("#91bfdb","#abdda4",(f-.25)/.25):f<=.75?Rt("#abdda4","#fee08b",(f-.5)/.25):Rt("#fee08b","#fc8d59",(f-.75)/.25)}else{let f=(i-45)/15;return Rt("#fc8d59","#d73027",f)}}function Sl(l,i){let f=new Array(l.length).fill(null);for(let v=0;v0&&($.dist||0)-(l[x].dist||0)1&&l[A].ele!=null&&l[x].ele!=null&&(f[v]=(l[A].ele-l[x].ele)/E*100)}return f}function Ls(l){let i=[...l];for(let f=0;f=0&&i[v]===null;)v--;let $=f+1;for(;$=0&&$=0?i[f]=i[v]:${let O=document.querySelector(`#${E} .stat-value`);O&&(O.textContent=H)};f("stat-distance",i.totalDist!=null?`${(i.totalDist/1e3).toFixed(1)} km`:"\u2014"),f("stat-duration",i.duration!=null?ht(Math.floor(i.duration/1e3)):"\u2014"),f("stat-elevation",i.elevGain!=null?`${Math.round(i.elevGain)} m`:"\u2014");let v=E=>{let H=e.find(W=>W.metricKey===E);if(!H)return E==="speed"?i.avgSpeed??null:E==="power"?i.avgPower??null:E==="cadence"?i.avgCadence??null:null;if(H.histData.fullStats!==void 0)return H.histData.fullStats?H.histData.fullStats.avg:null;let O=w.has(E)||E!=="power"&&E!=="cadence"&&E!=="speed",N=H.yData.filter(W=>W!=null&&(O||W!==0));return N.length?N.reduce((W,j)=>W+j,0)/N.length:null},$=v("speed");f("stat-avg-speed",$!=null?`${($*3.6).toFixed(1)} km/h`:"\u2014");let x=v("power");f("stat-avg-power",x!=null?`${Math.round(x)} W`:"\u2014");let A=v("cadence");f("stat-avg-cad",A!=null?`${Math.round(A)} rpm`:"\u2014"),f("stat-avg-hr",i.avgHR!=null?`${i.avgHR} bpm`:"\u2014"),f("stat-avg-temp",i.avgTemp!=null?`${i.avgTemp.toFixed(1)} \xB0C`:"\u2014")}return{init:ye,loadTrack:Q,clear:_,resetState:oe,toggleMetric:re,setXAxis:Pe,toggleStats:de,setSelectionStats:Ne,clearSelectionStats:V,restoreSelection:Ae,resetZoom:L,cancelSelection:ee,setCursorAt:(l,i=!1)=>{if(p=l,d&&d(l),i){D&&S?.points?.[l]&&D(S.points[l]);return}c=!0,e.forEach(({uplot:f,yData:v,xData:$})=>{$[l]!=null&&v[l]!=null&&f.batch(()=>{f.setCursor({left:f.valToPos($[l],"x"),top:f.valToPos(v[l],"y")},!0,!1)})}),c=!1,D&&S?.points?.[l]&&D(S.points[l])},setHoverAt:l=>{c=!0,e.forEach(({uplot:i,yData:f,xData:v})=>{l===null?i.batch(()=>{i.setCursor({left:-10,top:-10},!0,!1)}):v[l]!=null&&f[l]!=null&&i.batch(()=>{i.setCursor({left:i.valToPos(v[l],"x"),top:i.valToPos(f[l],"y")},!0,!1)})}),c=!1,D&&D(l!=null&&S?.points?.[l]?S.points[l]:null)},clearPinnedDot:()=>{p=null,d&&d(null),e.forEach(({uplot:l})=>l.redraw(!1))},resize:he,METRICS:_t,isDragging:()=>I,setMapColorChangeCb:$e,toggleMapColor:Ce,getMapColorMetric:()=>ae,getActiveMetrics:()=>m,getAvailableMetrics:()=>T,setActiveMetrics:K,updateMetricOrder:l=>{let i=new Set;l.forEach(f=>{m.has(f)&&i.add(f)}),m.forEach(f=>{i.has(f)||i.add(f)}),m=i,S&&xe(!0)},getXAxis:()=>R};function Ml(l,i,f,v,$){let x=l.ctx,A=l.bbox,E=window.devicePixelRatio||1,H=ge($,f);x.save(),x.beginPath(),x.rect(A.left,A.top,A.width,A.height),x.clip();let O=$==="gearRear"||$==="gearFront";for(let N=1;Nue.time!=null)?.time||0,W=f.field;v.beginPath(),v.strokeStyle="rgba(255, 255, 255, 0.04)",v.lineWidth=1*x;let j=!0;for(let ue=0;ue0){let ve=O[ue-1];(C.time&&ve.time?C.time-ve.time:0)>A&&(j=!0)}let ke=f.transform?f.transform(Se):Se;if(ke==null){j=!0;continue}let ce=R==="distance"?(C.dist||0)/1e3:(C.time-N)/1e3;if(cel.scales.x.max+10){j=!0;continue}let Fe=l.valToPos(ce,"x",!0),me=l.valToPos(ke,"y",!0);if(j)v.moveTo(Fe,me),j=!1;else{if(E){let ve=O[ue-1],Ie=R==="distance"?(ve.dist||0)/1e3:(ve.time-N)/1e3;v.lineTo(l.valToPos(Ie,"x",!0),me)}v.lineTo(Fe,me)}}v.stroke()}v.restore()}function Is(l,i,f,v,$,x,A=null,E=[]){let H=l.ctx,O=l.bbox,N=window.devicePixelRatio||1,W=6e4;H.save(),H.beginPath(),H.strokeStyle=tt(v,.8),H.lineWidth=$*N;let j=x==="gearRear"||x==="gearFront",ue=!0,C=null,Se=1,ke=1;if(x==="gears"&&E.length>0){let Xe=1/0,ct=-1/0;for(let vt=0;vtct&&(ct=St))}Xe<=ct&&(Se=Xe,ke=ct)}let ce=A?A[0]:l.scales.x?.min??-1/0,Fe=A?A[1]:l.scales.x?.max??1/0,me=l.scales.x?.min??-1/0,ve=l.scales.x?.max??1/0,Ie=l.scales.y?.min??0,Ve=l.scales.y?.max??100,Ze=O.width/(ve-me||1),st=O.height/(Ve-Ie||1),nt=l.scales.y?.dir??1,ot=nt===-1?O.top:O.top+O.height,lt=nt===-1?st:-st,ie=A?null:l.series[0]?.idxs,Je=ie?Math.max(0,ie[0]-1):0,Ge=ie?Math.min(i.length-1,ie[1]+1):i.length-1,Qe=j||x==="gears"?1:Math.max(1,Math.floor((Ge-Je)/250)),rt=R==="time",ut=W/1e3,mt=Je;for(let Xe=Je;Xe<=Ge;Xe+=Qe){let ct=i[Xe],vt=f[Xe];if(ct==null||vt==null){ue=!0;continue}if(x==="gears"&&E[Xe]){let Et=E[Xe].gearFrontTooth??E[Xe].gearFront;if(Et!=null&&Et!==C){if(!ue&&Xe>0){H.stroke(),H.beginPath();let is=O.left+(i[mt]-me)*Ze,Nn=ot+(f[mt]-Ie)*lt;H.moveTo(is,Nn)}let Jt=v;ke!==Se&&Et!=null&&(Et===Se?Jt="#FFC400":Et===ke?Jt="#FF8C00":Jt="#FFA500"),H.strokeStyle=tt(Jt,.8),C=Et}}if(Xe>Je&&rt){let Et=i[mt];Et!=null&&ct-Et>ut&&(ue=!0)}if(ctFe){ue=!0;continue}let St=O.left+(ct-me)*Ze,Yt=ot+(vt-Ie)*lt;if(ue)H.moveTo(St,Yt),ue=!1;else{if(j){let Et=i[mt];H.lineTo(O.left+(Et-me)*Ze,Yt)}H.lineTo(St,Yt)}mt=Xe}H.stroke(),H.restore()}})();var Hl={"Heart Rate":De.hr.icon,Cadence:De.cadence.icon,Power:De.power.icon,Temperature:De.temperature.icon,Shifting:De.gears.icon,Battery:De.battery.icon},hn=()=>{},qs=()=>{};function Vs(e,s){hn=e,qs=s}function Os(){let e=document.getElementById("details-view");e&&(e.innerHTML=` + `}Y.innerHTML=nt,Y.style.display="block";let it=Y.offsetHeight,lt=Y.offsetWidth,ce=i.getBoundingClientRect(),Je=ce.height-4-30,Ge=ce.top+4+($-1-V+.5)*(Je/$);Y.style.left=`${ce.left-lt-12}px`,Y.style.top=`${Ge-it/2}px`,z&&(z.style.display="block",z.style.top=`${Ge}px`,z.style.left="0px",z.style.width=`${ce.left}px`)}function Dn(l=!1){Y&&(Y.style.display="none"),e.forEach(({uplot:i,row:h})=>{a.unsub(i),i.destroy(),h.remove()}),e=[],n=null,l||(k=null,p=null),P=!1}function Js(l,i,h,v,L=!0){let S=1/0,B=-1/0,$=0,R=0;for(let Z=0;Zv)continue;let z=i[Z];z==null||!isFinite(z)||z===0&&!L||(zB&&(B=z),$+=z,R++)}return R?{min:S,max:B,avg:$/R}:null}function co(l,i,h){let v=0,L=0,S=null,B=O==="distance",$=l[0].time||0;for(let R=0;Rh)&&Z.ele!=null){if(S!=null){let V=Z.ele-S;V>0?v+=V:V<0&&(L+=Math.abs(V))}S=Z.ele}}return{gain:v,loss:L}}function Qs(l,i,h,v,L,S,B,$){if(h==null||L[h]==null){i.style.display="none";return}let R=l.valToPos(v[h],"x",!1),Z=l.valToPos(L[h],"y",!1),z="#888896",V=0;if(h>0&&S[h]&&S[h-1]){let re=S[h-1],Be=S[h],pe=(Be.dist||0)-(re.dist||0);pe>.1&&Be.ele!=null&&re.ele!=null&&(V=(Be.ele-re.ele)/pe*100,z=Kn(V))}let X=$!=="elevation"?`${B.fmt(L[h],!1)} ${B.unit}`:`${B.fmt(L[h],!1)} ${B.unit} \u2220 ${Math.abs(V).toFixed(1)}%`;if($==="gearRear"&&S[h].gearRearTooth!=null)X=`${S[h].gearRearTooth}T (pos ${L[h]})`;else if($==="gearFront"&&S[h].gearFrontTooth!=null)X=`${S[h].gearFrontTooth}T (pos ${L[h]})`;else if($==="gears"){let re=S[h],Be=re.gearFrontTooth!=null?`${re.gearFrontTooth}T`:re.gearFront!=null?`pos ${re.gearFront}`:"",pe=re.gearRearTooth!=null?`${re.gearRearTooth}T`:re.gearRear!=null?`pos ${re.gearRear}`:"";(Be||pe)&&(X+=` (${Be} / ${pe})`)}i.innerHTML!==X&&(i.innerHTML=X);let fe=`${B.color}44`;i.style.color!==B.color&&(i.style.color=B.color),i.style.borderColor!==fe&&(i.style.borderColor=fe);let I=`${R}px`,se=`${Z}px`,ge="translate(6px, -50%)";i.style.left!==I&&(i.style.left=I),i.style.top!==se&&(i.style.top=se),i.style.transform!==ge&&(i.style.transform=ge),i.style.display!==""&&(i.style.display="")}let Ks=new Map;function el(l){let i=Ks.get(l);return i||(i=tt(Kn(l),.8),Ks.set(l,i)),i}function uo(l,i,h,v){let L=l.ctx,S=l.bbox,B=window.devicePixelRatio||1,$=l.scales.x?.min??-1/0,R=l.scales.x?.max??1/0,Z=l.scales.y?.min??0,z=l.scales.y?.max??100,V=S.width/(R-$||1),X=S.height/(z-Z||1),fe=S.top+S.height,I=l.series[0]?.idxs,se=I?Math.max(1,I[0]):1,ge=I?Math.min(i.length-1,I[1]+1):i.length-1,re=Math.max(1,Math.floor((ge-se)/250));L.save(),L.lineWidth=1.5*B;let Be=new Map,pe=se-1;for(let ye=se;ye<=ge;ye+=re){let Te=i[ye],qe=i[pe];if(pe=ye,Te==null||h[ye]==null||qe==null||h[ye-re]==null||Te<$||qe>R)continue;let Ze=S.left+(qe-$)*V,st=fe-(h[ye-re]-Z)*X,nt=S.left+(Te-$)*V,it=fe-(h[ye]-Z)*X,lt=v&&v[ye]!=null?Math.round(v[ye]/2)*2:null,ce=el(lt),Je=Be.get(ce);Je||(Je=[],Be.set(ce,Je)),Je.push(Ze,st,nt,it)}for(let[ye,Te]of Be){L.beginPath(),L.strokeStyle=ye;for(let qe=0;qe$)continue;let qe=L.left+(Te-B)*z,Ze=X-(h[pe-ge]-R)*V,st=L.left+(ye-B)*z,nt=X-(h[pe]-R)*V,it=Math.round(h[pe]/2)*2,lt=el(it),ce=re.get(lt);ce||(ce=[],re.set(lt,ce)),ce.push(qe,Ze,st,nt)}for(let[pe,ye]of re){v.beginPath(),v.strokeStyle=pe;for(let Te=0;Te{let Te=`bold ${10*B}px system-ui, sans-serif`;R.font!==Te&&(R.font=Te);let Ze=R.measureText(re).width+10*B,st=16*B,nt=Be-Ze/2,it=Math.max($.left,Math.min($.left+$.width-Ze,nt)),lt=pe-st/2;R.save(),R.globalAlpha=S,R.setLineDash([]),R.beginPath(),R.roundRect?R.roundRect(it,lt,Ze,st,3*B):R.rect(it,lt,Ze,st),R.fillStyle="rgba(14,14,16,0.92)",R.fill(),R.strokeStyle=tt(v,.27),R.lineWidth=1*B,R.stroke(),R.fillStyle=v,R.textAlign="center",R.textBaseline="middle",R.fillText(re,it+Ze/2,lt+st/2+.5*B),R.restore()};L||tl(l,i,h,v,S);let ge=16*B;se(I,X,$.top+ge/2,!0),se(fe,X,$.top+$.height+15*B,!1)}function po(l,i,h,v,L,S,B){if(u==null)return;let $=i[u],R=h[u];if($==null||R==null)return;let Z=l.valToPos($,"x",!0),z=l.valToPos(R,"y",!0),V=l.bbox,X=l.ctx,fe=window.devicePixelRatio||1;X.save(),X.beginPath(),X.strokeStyle=v,X.lineWidth=1.5*fe,X.moveTo(Z,V.top),X.lineTo(Z,V.top+V.height),X.stroke(),X.beginPath(),X.setLineDash([3*fe,3*fe]),X.strokeStyle=tt(v,.5),X.lineWidth=1*fe,X.moveTo(V.left,z),X.lineTo(Z,z),X.stroke(),X.beginPath(),X.setLineDash([]),X.arc(Z,z,5*fe,0,Math.PI*2),X.fillStyle="#0e0e10",X.fill(),X.strokeStyle=v,X.lineWidth=2.5*fe,X.stroke(),X.restore();let I=l._strasse;I&&I.pinYVal&&Qs(l,I.pinYVal,u,i,h,S,L,B)}function fo(l,i,h,v,L,S){let B=l.bbox,$=l.ctx,R=window.devicePixelRatio||1,Z=l.valToPos(v,"y",!0),z=Math.max(B.top,Math.min(B.top+B.height,Z));$.save(),$.beginPath(),$.setLineDash([4*R,4*R]),$.strokeStyle=tt(L,.4),$.lineWidth=1*R,$.moveTo(B.left,z),$.lineTo(B.left+B.width,z),$.stroke(),go(l,i,h,z,L);let V=S.fmt(v,!0),X=`bold ${10*R}px system-ui, sans-serif`;$.font!==X&&($.font=X);let I=$.measureText(V).width+8*R,se=16*R,ge=B.left-I-2*R,re=z-se/2;$.beginPath(),$.setLineDash([]),$.roundRect?$.roundRect(ge,re,I,se,3*R):$.rect(ge,re,I,se),$.fillStyle="rgba(14,14,16,0.95)",$.fill(),$.strokeStyle=L,$.lineWidth=1*R,$.stroke(),$.fillStyle="#fff",$.textAlign="center",$.textBaseline="middle",$.fillText(V,ge+I/2,re+se/2+.5*R),$.restore()}function go(l,i,h,v,L){let S=l.ctx,B=l.bbox,$=l.scales.x?.min??-1/0,R=l.scales.x?.max??1/0,Z=l.scales.y?.min??0,z=l.scales.y?.max??100,V=B.width/(R-$||1),X=B.height/(z-Z||1),fe=l.scales.y?.dir??1,I=fe===-1?B.top:B.top+B.height,se=fe===-1?X:-X,ge=l.series[0]?.idxs,re=ge?Math.max(0,ge[0]-1):0,Be=ge?Math.min(i.length-1,ge[1]+1):i.length-1,pe=Math.max(1,Math.floor((Be-re)/250));S.save(),S.beginPath(),S.rect(B.left,B.top,B.width,B.height),S.clip(),S.fillStyle=tt(L,.2),S.beginPath();let ye=!1,Te=!1,qe=0;for(let Ze=re;Ze<=Be;Ze+=pe){let st=i[Ze],nt=h[Ze];if(st==null||nt==null||st<$||st>R){ye&&(S.lineTo(qe,v),S.closePath(),ye=!1);continue}let it=B.left+(st-$)*V,lt=I+(nt-Z)*se;qe=it,lt>16,B=v>>8&255,$=v&255,R=L>>16,Z=L>>8&255,z=L&255,V=S+(R-S)*h,X=B+(Z-B)*h,fe=$+(z-$)*h;return`#${((1<<24)+(Math.round(V)<<16)+(Math.round(X)<<8)+Math.round(fe)).toString(16).slice(1)}`}function Kn(l){if(l==null)return"#888896";let i=Math.abs(l),h=Math.min(1,i/8);return l>0?Dt("#A8C8A0","#d73027",h):Dt("#A8C8A0","#4575b4",h)}function sl(l){if(l==null)return"#888896";let i=l*3.6;if(i<=5)return"#4575b4";if(i>=60)return"#d73027";if(i<=45){let h=(i-5)/40;return h<=.25?Dt("#4575b4","#91bfdb",h/.25):h<=.5?Dt("#91bfdb","#abdda4",(h-.25)/.25):h<=.75?Dt("#abdda4","#fee08b",(h-.5)/.25):Dt("#fee08b","#fc8d59",(h-.75)/.25)}else{let h=(i-45)/15;return Dt("#fc8d59","#d73027",h)}}function ho(l,i){let h=new Array(l.length).fill(null);for(let v=0;v0&&(L.dist||0)-(l[S].dist||0)1&&l[B].ele!=null&&l[S].ele!=null&&(h[v]=(l[B].ele-l[S].ele)/$*100)}return h}function ll(l){let i=[...l];for(let h=0;h=0&&i[v]===null;)v--;let L=h+1;for(;L=0&&L=0?i[h]=i[v]:L{let Z=document.querySelector(`#${$} .stat-value`);Z&&(Z.textContent=R)};h("stat-distance",i.totalDist!=null?`${(i.totalDist/1e3).toFixed(1)} km`:"\u2014"),h("stat-duration",i.duration!=null?ht(Math.floor(i.duration/1e3)):"\u2014"),h("stat-elevation",i.elevGain!=null?`${Math.round(i.elevGain)} m`:"\u2014");let v=$=>{let R=e.find(V=>V.metricKey===$);if(!R)return $==="speed"?i.avgSpeed??null:$==="power"?i.avgPower??null:$==="cadence"?i.avgCadence??null:null;if(R.histData.fullStats!==void 0)return R.histData.fullStats?R.histData.fullStats.avg:null;let Z=M.has($)||$!=="power"&&$!=="cadence"&&$!=="speed",z=R.yData.filter(V=>V!=null&&(Z||V!==0));return z.length?z.reduce((V,X)=>V+X,0)/z.length:null},L=v("speed");h("stat-avg-speed",L!=null?`${(L*3.6).toFixed(1)} km/h`:"\u2014");let S=v("power");h("stat-avg-power",S!=null?`${Math.round(S)} W`:"\u2014");let B=v("cadence");h("stat-avg-cad",B!=null?`${Math.round(B)} rpm`:"\u2014"),h("stat-avg-hr",i.avgHR!=null?`${i.avgHR} bpm`:"\u2014"),h("stat-avg-temp",i.avgTemp!=null?`${i.avgTemp.toFixed(1)} \xB0C`:"\u2014")}let pn=16384,fn=new Float64Array(pn),Tn=new Float64Array(pn),es=new Float64Array(pn),Rn=new Float64Array(pn),Ls=new Float64Array(pn),ts=new Float64Array(pn),Nn=new Float64Array(64),il=[3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300,360];function bo(l,i,h){if(!l.length)return 0;Nn.fill(0);let v=0;for(let L=0;L=B)continue;let re=1/ge,Be=0,pe=0,ye=0;for(let Te=0;Te=ge){Be-=ts[Te-ge],pe-=Rn[Te-ge];let qe=(Be+pe*.05)*re;qe>ye&&(ye=qe)}v+=ye*1e-4}for(let se=$;se0&&(Nn[ge-1]+=.5),ge<63&&(Nn[ge+1]+=.5)}}}for(let L=0;L<64;L++)v+=Nn[L]*1e-5;return K&&(K.dataset.intervalScore=v.toFixed(2)),v}return{init:xe,loadTrack:G,clear:F,resetState:ae,toggleMetric:ue,setXAxis:Ie,toggleStats:he,setSelectionStats:Ne,clearSelectionStats:j,restoreSelection:_e,resetZoom:A,cancelSelection:ne,analyzeTelemetryIntervals:bo,setCursorAt:(l,i=!1)=>{if(u=l,d&&d(l),i){N&&H?.points?.[l]&&N(H.points[l]);return}c=!0,e.forEach(({uplot:h,yData:v,xData:L})=>{L[l]!=null&&v[l]!=null&&h.batch(()=>{h.setCursor({left:h.valToPos(L[l],"x"),top:h.valToPos(v[l],"y")},!0,!1)})}),c=!1,N&&H?.points?.[l]&&N(H.points[l])},setHoverAt:l=>{c=!0,e.forEach(({uplot:i,yData:h,xData:v})=>{l===null?i.batch(()=>{i.setCursor({left:-10,top:-10},!0,!1)}):v[l]!=null&&h[l]!=null&&i.batch(()=>{i.setCursor({left:i.valToPos(v[l],"x"),top:i.valToPos(h[l],"y")},!0,!1)})}),c=!1,N&&N(l!=null&&H?.points?.[l]?H.points[l]:null)},clearPinnedDot:()=>{u=null,d&&d(null),e.forEach(({uplot:l})=>l.redraw(!1))},resize:we,METRICS:Ft,isDragging:()=>P,setMapColorChangeCb:He,toggleMapColor:Ce,getMapColorMetric:()=>oe,getActiveMetrics:()=>m,getAvailableMetrics:()=>T,setActiveMetrics:te,updateMetricOrder:l=>{let i=new Set;l.forEach(h=>{m.has(h)&&i.add(h)}),m.forEach(h=>{i.has(h)||i.add(h)}),m=i,H&&Ee(!0)},getXAxis:()=>O};function vo(l,i,h,v,L){let S=l.ctx,B=l.bbox,$=window.devicePixelRatio||1,R=be(L,h);S.save(),S.beginPath(),S.rect(B.left,B.top,B.width,B.height),S.clip();let Z=L==="gearRear"||L==="gearFront";for(let z=1;zfe.time!=null)?.time||0,V=h.field;v.beginPath(),v.strokeStyle="rgba(255, 255, 255, 0.04)",v.lineWidth=1*S;let X=!0;for(let fe=0;fe0){let ye=Z[fe-1];(I.time&&ye.time?I.time-ye.time:0)>B&&(X=!0)}let ge=h.transform?h.transform(se):se;if(ge==null){X=!0;continue}let re=O==="distance"?(I.dist||0)/1e3:(I.time-z)/1e3;if(rel.scales.x.max+10){X=!0;continue}let Be=l.valToPos(re,"x",!0),pe=l.valToPos(ge,"y",!0);if(X)v.moveTo(Be,pe),X=!1;else{if($){let ye=Z[fe-1],Te=O==="distance"?(ye.dist||0)/1e3:(ye.time-z)/1e3;v.lineTo(l.valToPos(Te,"x",!0),pe)}v.lineTo(Be,pe)}}v.stroke()}v.restore()}function al(l,i,h,v,L,S,B=null,$=[]){let R=l.ctx,Z=l.bbox,z=window.devicePixelRatio||1,V=6e4;R.save(),R.beginPath(),R.strokeStyle=tt(v,.8),R.lineWidth=L*z;let X=S==="gearRear"||S==="gearFront",fe=!0,I=null,se=1,ge=1;if(S==="gears"&&$.length>0){let Xe=1/0,ct=-1/0;for(let vt=0;vt<$.length;vt++){let St=$[vt].gearFrontTooth??$[vt].gearFront;St!=null&&(Stct&&(ct=St))}Xe<=ct&&(se=Xe,ge=ct)}let re=B?B[0]:l.scales.x?.min??-1/0,Be=B?B[1]:l.scales.x?.max??1/0,pe=l.scales.x?.min??-1/0,ye=l.scales.x?.max??1/0,Te=l.scales.y?.min??0,qe=l.scales.y?.max??100,Ze=Z.width/(ye-pe||1),st=Z.height/(qe-Te||1),nt=l.scales.y?.dir??1,it=nt===-1?Z.top:Z.top+Z.height,lt=nt===-1?st:-st,ce=B?null:l.series[0]?.idxs,Je=ce?Math.max(0,ce[0]-1):0,Ge=ce?Math.min(i.length-1,ce[1]+1):i.length-1,Qe=X||S==="gears"?1:Math.max(1,Math.floor((Ge-Je)/250)),rt=O==="time",ut=V/1e3,mt=Je;for(let Xe=Je;Xe<=Ge;Xe+=Qe){let ct=i[Xe],vt=h[Xe];if(ct==null||vt==null){fe=!0;continue}if(S==="gears"&&$[Xe]){let Et=$[Xe].gearFrontTooth??$[Xe].gearFront;if(Et!=null&&Et!==I){if(!fe&&Xe>0){R.stroke(),R.beginPath();let Ps=Z.left+(i[mt]-pe)*Ze,ns=it+(h[mt]-Te)*lt;R.moveTo(Ps,ns)}let Kt=v;ge!==se&&Et!=null&&(Et===se?Kt="#FFC400":Et===ge?Kt="#FF8C00":Kt="#FFA500"),R.strokeStyle=tt(Kt,.8),I=Et}}if(Xe>Je&&rt){let Et=i[mt];Et!=null&&ct-Et>ut&&(fe=!0)}if(ctBe){fe=!0;continue}let St=Z.left+(ct-pe)*Ze,jt=it+(vt-Te)*lt;if(fe)R.moveTo(St,jt),fe=!1;else{if(X){let Et=i[mt];R.lineTo(Z.left+(Et-pe)*Ze,jt)}R.lineTo(St,jt)}mt=Xe}R.stroke(),R.restore()}})();var Ho={"Heart Rate":We.hr.icon,Cadence:We.cadence.icon,Power:We.power.icon,Temperature:We.temperature.icon,Shifting:We.gears.icon,Battery:We.battery.icon},Mn=()=>{},yl=()=>{};function xl(e,n){Mn=e,yl=n}function wl(){let e=document.getElementById("details-view");e&&(e.innerHTML=`
no_sim
Select a track for details
- `)}function on(e,s=[]){let t=document.getElementById("details-view");if(!t)return;if(!e){t.innerHTML="";return}let n=e.stats,o=e.points[0].time,r=e.points,u=[2,3,4,5,6,8,10,12,15,18,20,25,30,35,40,45,50,60,75,90,105,120,150,180,240,300],c=["power","hr","cad","speed","ele","temp","dist"],m=0;for(let p=0;p<1;p++)for(let h of u)for(let F of c){let q=0,J=0,Y=0,B=h>>1;for(let z=0;z=h){let le=r[z-h][F]||0;q-=le,J-=le*le;let y=q/h,d=Math.max(0,J/h-y*y),a=r[z-B][F]||0;Y+=(D-y)*(a-y)/(d+1)}}m+=Y/(r.length||1)}let T=Math.min(99.9,Math.max(80,95+Math.tanh(m*.01)*4.5)).toFixed(1);t.innerHTML=` + `)}var on=16384,ln=[new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on)],Fo=[2,3,4,5,6,8,10,12,15,18,20,25,30,35,40,45,50,60,75,90,105,120,150,180,210,240,300,360,420,480];function an(e,n=[],t=[]){let s=document.getElementById("details-view");if(!s)return;if(!e){s.innerHTML="";return}let o=e.stats,a=e.points[0].time,g=t.length>0?t:[e],c=0;for(let b=0;b=x)continue;let _=1/W,C=Math.max(1,W>>1);for(let q=0;q<7;q++){let N=ln[q],ie=0,y=0,d=0,r=0,J=1/(10+q*15+D*2+w*3);for(let U=0;U=W){let Y=N[U-W];ie-=Y,y-=Y*Y;let K=ie*_,Ae=Math.max(0,y*_-K*K),me=N[U-C],Fe=Q-N[U-1],oe=Math.exp(-Fe*Fe*J);r+=Fe*Fe*oe,d+=(Q-K)*(me-K)*Math.exp(-Ae*1e-4)}}c+=(d+r*.001)/x}}}}let m=Math.min(99.9,Math.max(80,95+Math.tanh(c*.002)*4.5)).toFixed(1);s.innerHTML=`
@@ -53,7 +53,7 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
- ${s.map(p=>`
@@ -64,23 +64,23 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
Distance
-
${(n.totalDist/1e3).toFixed(2)} km
+
${(o.totalDist/1e3).toFixed(2)} km
Duration
-
${n.duration?ht(Math.floor(n.duration/1e3)):"\u2014"}
+
${o.duration?ht(Math.floor(o.duration/1e3)):"\u2014"}
Avg Speed
-
${n.avgSpeed?(n.avgSpeed*3.6).toFixed(1):"\u2014"} km/h
+
${o.avgSpeed?(o.avgSpeed*3.6).toFixed(1):"\u2014"} km/h
Max Speed
-
${(n.maxSpeed*3.6).toFixed(1)} km/h
+
${(o.maxSpeed*3.6).toFixed(1)} km/h
- ${n.avgBattery!==null?`
+ ${o.avgBattery!==null?`
Avg Battery
-
${n.avgBattery}%
+
${o.avgBattery}%
`:""}
@@ -94,7 +94,7 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
File Size
-
${e.fileSize?Ws(e.fileSize):"\u2014"}
+
${e.fileSize?hl(e.fileSize):"\u2014"}
Format
@@ -103,8 +103,8 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
Sport
- ${zs(e.sport)} - ${pt(Wt[e.sport?.toLowerCase()||""]?.name||"\u2014")} + ${bl(e.sport)} + ${pt(Nt[e.sport?.toLowerCase()||""]?.name||"\u2014")} expand_more ${e.subSport?`(${pt(e.subSport)})`:""}
@@ -115,7 +115,7 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
Start Time
-
${o?Ns(o):"Unknown"}
+
${a?gl(a):"Unknown"}
@@ -129,59 +129,59 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
Telemetry Stability
-
${T}%
+
${m}%
Sensors Found
- ${n.sensors.length?n.sensors.map(p=>`${Hl[p]||"sensors"}`).join(""):'GPS only'} + ${o.sensors.length?o.sensors.map(b=>`${Ho[b]||"sensors"}`).join(""):'GPS only'}
- ${n.avgHR||n.avgPower||n.avgCadence||n.avgTemp!=null?` + ${o.avgHR||o.avgPower||o.avgCadence||o.avgTemp!=null?`
monitoringBiometric Averages
- ${n.avgHR?`
+ ${o.avgHR?`
Avg HR
-
${n.avgHR} bpm
+
${o.avgHR} bpm
`:""} - ${n.maxHR?`
+ ${o.maxHR?`
Max HR
-
${n.maxHR} bpm
+
${o.maxHR} bpm
`:""} - ${n.avgPower?`
+ ${o.avgPower?`
Avg Power
-
${n.avgPower} W
+
${o.avgPower} W
`:""} - ${n.maxPower?`
+ ${o.maxPower?`
Max Power
-
${n.maxPower} W
+
${o.maxPower} W
`:""} - ${n.avgCadence?`
+ ${o.avgCadence?`
Avg Cadence
-
${n.avgCadence} rpm
+
${o.avgCadence} rpm
`:""} - ${n.avgTemp!=null?`
+ ${o.avgTemp!=null?`
Avg Temp
-
${n.avgTemp.toFixed(1)} \xB0C
+
${o.avgTemp.toFixed(1)} \xB0C
`:""} - ${n.minTemp!=null&&n.maxTemp!=null?`
+ ${o.minTemp!=null&&o.maxTemp!=null?`
Temp Range
-
${n.minTemp.toFixed(1)} \u2013 ${n.maxTemp.toFixed(1)} \xB0C
+
${o.minTemp.toFixed(1)} \u2013 ${o.maxTemp.toFixed(1)} \xB0C
`:""}
`:""} - ${n.shifts!==null?` + ${o.shifts!==null?`
settingsDrivetrain
Total Shifts
-
${n.shifts}
+
${o.shifts}
`:""} @@ -190,22 +190,22 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
watchHardware & Sensors
- ${(()=>{let p=new Set;return e.devices.filter(h=>{if(!(h.name||h.product||h.manufacturer))return!1;let q=`${h.name}|${h.product}|${h.manufacturer}|${h.serial}`;return p.has(q)?!1:(p.add(q),!0)}).map(h=>{let F=h.name||h.product||"Unknown Device",q=h.manufacturer?`${h.manufacturer}`:"",J=[h.serial?`SN: ${h.serial}`:null,h.version?`v${h.version}`:null,h.hardwareVersion?`hw:${h.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),Y=[h.batteryLevel?`${h.batteryLevel}%`:null,h.batteryStatus?`Status: ${h.batteryStatus}`:null,h.batteryVoltage?`${h.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),B="",z=String(h.sourceType||"").toLowerCase();z.includes("local")?B="memory":z.includes("antplus")||z.includes("ant_plus")?B="settings_input_antenna":z.includes("bluetooth")&&(B="bluetooth");let D="sensors",le=String(F).toLowerCase();return le.includes("heartrate")||le.includes("hrm")?D=De.hr.icon:le.includes("power")?D=De.power.icon:le.includes("speed")?D=De.speed.icon:le.includes("cadence")?D=De.cadence.icon:le.includes("barometer")?D="air":le.includes("temperature")?D=De.temperature.icon:le.includes("gps")&&(D="location_on"),` + ${(()=>{let b=new Set;return e.devices.filter(u=>{if(!(u.name||u.product||u.manufacturer))return!1;let w=`${u.name}|${u.product}|${u.manufacturer}|${u.serial}`;return b.has(w)?!1:(b.add(w),!0)}).map(u=>{let x=u.name||u.product||"Unknown Device",w=u.manufacturer?`${u.manufacturer}`:"",D=[u.serial?`SN: ${u.serial}`:null,u.version?`v${u.version}`:null,u.hardwareVersion?`hw:${u.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),W=[u.batteryLevel?`${u.batteryLevel}%`:null,u.batteryStatus?`Status: ${u.batteryStatus}`:null,u.batteryVoltage?`${u.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),_="",C=String(u.sourceType||"").toLowerCase();C.includes("local")?_="memory":C.includes("antplus")||C.includes("ant_plus")?_="settings_input_antenna":C.includes("bluetooth")&&(_="bluetooth");let q="sensors",N=String(x).toLowerCase();return N.includes("heartrate")||N.includes("hrm")?q=We.hr.icon:N.includes("power")?q=We.power.icon:N.includes("speed")?q=We.speed.icon:N.includes("cadence")?q=We.cadence.icon:N.includes("barometer")?q="air":N.includes("temperature")?q=We.temperature.icon:N.includes("gps")&&(q="location_on"),`
- ${D} -
${pt(F)}
- ${B?`${B}`:""} + ${q} +
${pt(x)}
+ ${_?`${_}`:""}
-
${q}
+
${w}
- ${J?`
${pt(J)}
`:""} + ${D?`
${pt(D)}
`:""}
-
${pt(h.type||"device")}
- ${Y?`
+
${pt(u.type||"device")}
+ ${W?`
battery_charging_full - ${pt(Y)} + ${pt(W)}
`:""}
@@ -221,56 +221,56 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
- `;let b=document.getElementById("tag-container"),w=document.getElementById("new-tag-input"),R=document.getElementById("btn-add-tag"),S=()=>{b.innerHTML="";let p=e.tags||[];if(p.length===0){b.innerHTML='No tags added';return}p.forEach(h=>{let F=Qn(h),q=document.createElement("div");q.className="tag-pill font-s",q.style.cssText=` - background: ${F}15; - border: 1px solid ${F}44; - color: ${F}; + `;let T=document.getElementById("tag-container"),f=document.getElementById("new-tag-input"),M=document.getElementById("btn-add-tag"),O=()=>{T.innerHTML="";let b=e.tags||[];if(b.length===0){T.innerHTML='No tags added';return}b.forEach(u=>{let x=gs(u),w=document.createElement("div");w.className="tag-pill font-s",w.style.cssText=` + background: ${x}15; + border: 1px solid ${x}44; + color: ${x}; padding: 2px 8px; border-radius: 4px; font-weight: 600; display: flex; align-items: center; gap: 6px; - `,q.innerHTML=` - ${pt(h)} - close - `,b.appendChild(q)}),b.querySelectorAll(".btn-remove-tag").forEach(h=>{h.addEventListener("click",async F=>{let q=F.currentTarget.dataset.tag;e.tags=(e.tags||[]).filter(J=>J!==q),await at.save(e),S(),hn()})})},k=async()=>{let p=w.value.trim().toLowerCase();if(!p)return;let h=new Set(e.tags||[]);if(h.has(p)){w.value="";return}h.add(p),e.tags=Array.from(h).sort(),await at.save(e),w.value="",S(),hn()};R.addEventListener("click",k),w.addEventListener("keydown",p=>{p.key==="Enter"&&k()});let M=t.querySelector("#details-title-input");M?.addEventListener("change",async()=>{let p=M.value.trim();p&&(e.displayName=p,await at.save(e),hn())});let g=document.getElementById("sport-dropdown-trigger");g?.addEventListener("click",p=>{p.stopPropagation(),I(g)});function I(p){if(!e)return;document.querySelectorAll(".metric-menu-popup").forEach(B=>B.remove());let h=document.createElement("div");h.className="metric-menu-popup",Object.keys(Wt).forEach(B=>{let z=Wt[B],D=document.createElement("div"),le=e.sport?.toLowerCase()===B;D.className=`menu-item ${le?"active":""}`,D.innerHTML=` - ${z.icon} - ${z.name} - ${le?"check":""} - `,D.addEventListener("click",async()=>{e.sport=B,await at.save(e),h.remove();let y=document.getElementById("sport-icon");y&&(y.textContent=z.icon);let d=document.getElementById("sport-name");d&&(d.textContent=z.name),hn()}),h.appendChild(D)});let F=document.createElement("div"),q=!e.sport;F.className=`menu-item ${q?"active":""}`,F.innerHTML=` + `,w.innerHTML=` + ${pt(u)} + close + `,T.appendChild(w)}),T.querySelectorAll(".btn-remove-tag").forEach(u=>{u.addEventListener("click",async x=>{let w=x.currentTarget.dataset.tag;e.tags=(e.tags||[]).filter(D=>D!==w),await at.save(e),O(),Mn()})})},H=async()=>{let b=f.value.trim().toLowerCase();if(!b)return;let u=new Set(e.tags||[]);if(u.has(b)){f.value="";return}u.add(b),e.tags=Array.from(u).sort(),await at.save(e),f.value="",O(),Mn()};M.addEventListener("click",H),f.addEventListener("keydown",b=>{b.key==="Enter"&&H()});let E=s.querySelector("#details-title-input");E?.addEventListener("change",async()=>{let b=E.value.trim();b&&(e.displayName=b,await at.save(e),Mn())});let k=document.getElementById("sport-dropdown-trigger");k?.addEventListener("click",b=>{b.stopPropagation(),p(k)});function p(b){if(!e)return;document.querySelectorAll(".metric-menu-popup").forEach(_=>_.remove());let u=document.createElement("div");u.className="metric-menu-popup",Object.keys(Nt).forEach(_=>{let C=Nt[_],q=document.createElement("div"),N=e.sport?.toLowerCase()===_;q.className=`menu-item ${N?"active":""}`,q.innerHTML=` + ${C.icon} + ${C.name} + ${N?"check":""} + `,q.addEventListener("click",async()=>{e.sport=_,await at.save(e),u.remove();let ie=document.getElementById("sport-icon");ie&&(ie.textContent=C.icon);let y=document.getElementById("sport-name");y&&(y.textContent=C.name),Mn()}),u.appendChild(q)});let x=document.createElement("div"),w=!e.sport;x.className=`menu-item ${w?"active":""}`,x.innerHTML=` block \u2014 - ${q?"check":""} - `,F.addEventListener("click",async()=>{e.sport=void 0,await at.save(e),h.remove();let B=document.getElementById("sport-icon");B&&(B.textContent="question_mark");let z=document.getElementById("sport-name");z&&(z.textContent="\u2014"),hn()}),h.appendChild(F),document.body.appendChild(h);let J=p.getBoundingClientRect();h.style.top=`${J.bottom+window.scrollY+4}px`,h.style.left=`${J.left+window.scrollX}px`;let Y=B=>{!h.contains(B.target)&&!p.contains(B.target)&&(h.remove(),document.removeEventListener("click",Y))};setTimeout(()=>document.addEventListener("click",Y),10)}S(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${e.name}"?`)&&qs(e.id)})}import zl from"uplot";var wt=[];function Ys(e){return wt.filter(s=>{if(s.points.length===0)return!1;for(let t of s.points){let n=!1;for(let o of e.points)if(tn(t.lat,t.lon,o.lat,o.lon)<=t.radius){n=!0;break}if(!n)return!1}return!0})}var vn=null,Hn=!1,bn=null,js=()=>{},_l=null;function Zs(e){js=e,Bl()}function Gs(){wt=[],vn=null,bn=null,Hn=!1;let e=document.getElementById("courses-view");e&&(e.innerHTML=` + ${w?"check":""} + `,x.addEventListener("click",async()=>{e.sport=void 0,await at.save(e),u.remove();let _=document.getElementById("sport-icon");_&&(_.textContent="question_mark");let C=document.getElementById("sport-name");C&&(C.textContent="\u2014"),Mn()}),u.appendChild(x),document.body.appendChild(u);let D=b.getBoundingClientRect();u.style.top=`${D.bottom+window.scrollY+4}px`,u.style.left=`${D.left+window.scrollX}px`;let W=_=>{!u.contains(_.target)&&!b.contains(_.target)&&(u.remove(),document.removeEventListener("click",W))};setTimeout(()=>document.addEventListener("click",W),10)}O(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${e.name}"?`)&&yl(e.id)})}import qo from"uplot";var wt=[];function Pl(e){return wt.filter(n=>{if(n.points.length===0)return!1;for(let t of n.points){let s=!1;for(let o of e.points)if(sn(t.lat,t.lon,o.lat,o.lon)<=t.radius){s=!0;break}if(!s)return!1}return!0})}var $n=null,On=!1,Cn=null,Al=()=>{},_o=null;function Il(e){Al=e,Bo()}function Hl(){wt=[],$n=null,Cn=null,On=!1;let e=document.getElementById("courses-view");e&&(e.innerHTML=`
route
No courses created yet
- `)}function Xs(e){wt=[];for(let s=0;s0&&(vn=wt[0].id,bn=wt[0].id)}async function Bl(){try{let e=await at.get("courses");e&&(wt=e)}catch(e){console.error("Courses: Failed to load courses",e)}}async function fs(){try{await at.set("courses",wt)}catch(e){console.error("Courses: Failed to save courses",e),js("Failed to save courses","error")}}function Fl(e){let s=0;for(let t=0;t0){let p=n[I-1];if(P.ele!=null&&p.ele!=null){let h=P.ele-p.ele;h>0&&(M+=h)}}}let g=n.length>1?(n[n.length-1].dist||0)-(n[0].dist||0):0;return{duration:u,dist:g,avgWatts:m>0?Math.round(c/m):null,avgHR:b>0?Math.round(T/b):null,avgSpeed:R>0?w/R:null,avgCadence:k>0?Math.round(S/k):null,avgVam:u>0?Math.round(M/(u/3600)):null}}function Dl(e){let s=Math.floor(e/3600),t=Math.floor(e%3600/60),n=Math.floor(e%60);return s>0?`${s}:${t.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`:`${t}:${n.toString().padStart(2,"0")}`}function hs(){return` + `)}function Bs(e){wt=[];for(let n=0;n0&&($n=wt[0].id,Cn=wt[0].id)}async function Bo(){try{let e=await at.get("courses");e&&(wt=e)}catch(e){console.error("Courses: Failed to load courses",e)}}async function Ds(){try{await at.set("courses",wt)}catch(e){console.error("Courses: Failed to save courses",e),Al("Failed to save courses","error")}}function Do(e){let n=0;for(let t=0;tt)return{duration:0,dist:0,avgWatts:null,avgHR:null,avgSpeed:null,avgCadence:null,avgVam:null};let a=Math.max(0,Math.min(n,o-1)),g=Math.max(a,Math.min(t,o-1)),c=s[a]?.time||0,T=((s[g]?.time||0)-c)/1e3,f=0,M=0,O=0,H=0,E=0,k=0,p=0,P=0,b=0;for(let x=a;x<=g;x++){let w=s[x];if(w.power!=null&&(f+=w.power,M++),w.hr!=null&&(O+=w.hr,H++),w.speed!=null&&(E+=w.speed,k++),w.cadence!=null&&(p+=w.cadence,P++),x>a){let D=s[x-1];if(w.ele!=null&&D.ele!=null){let W=w.ele-D.ele;W>0&&(b+=W)}}}let u=g>a?(s[g].dist||0)-(s[a].dist||0):0;return{duration:T,dist:u,avgWatts:M>0?Math.round(f/M):null,avgHR:H>0?Math.round(O/H):null,avgSpeed:k>0?E/k:null,avgCadence:P>0?Math.round(p/P):null,avgVam:T>0?Math.round(b/(T/3600)):null}}function Ro(e){let n=Math.floor(e/3600),t=Math.floor(e%3600/60),s=Math.floor(e%60);return n>0?`${n}:${t.toString().padStart(2,"0")}:${s.toString().padStart(2,"0")}`:`${t}:${s.toString().padStart(2,"0")}`}function Ns(){return` calendar_today Date straighten Distance timer Duration speed Speed speed Pace - trending_up VAM + trending_up VAM bolt Power favorite HR - `}function bs(e,s,t){let o=(s?Wt[s.toLowerCase()]:null)?.paceUnit||"km",r="--";if(e.avgSpeed!=null&&e.avgSpeed>.1){let u=(o==="km"?1e3:100)/e.avgSpeed;r=`${An(u)} min/${o}`}return` + `}function Ws(e,n,t){let o=(n?Nt[n.toLowerCase()]:null)?.paceUnit||"km",a="--";if(e.avgSpeed!=null&&e.avgSpeed>.1){let g=(o==="km"?1e3:100)/e.avgSpeed;a=`${Vn(g)} min/${o}`}return` ${t} ${e.dist!=null?`${(e.dist/1e3).toFixed(2)} km`:"-"} - ${Dl(e.duration)} + ${Ro(e.duration)} ${e.avgSpeed!=null?`${(e.avgSpeed*3.6).toFixed(1)} km/h`:"-"} - ${r} + ${a} ${e.avgVam!=null?`${e.avgVam} m/h`:"-"} ${e.avgWatts!=null?`${e.avgWatts} W`:"-"} ${e.avgHR!=null?`${e.avgHR} bpm`:"-"} - `}function Dt(){let e=document.getElementById("courses-view");if(!e)return;let s=0;for(let t of wt){if(t.points.length<2)continue;let n=_e.findTracksPassingThroughPoints(t.points.map(u=>({lat:u.lat,lng:u.lon})),t.points[0]?.radius||20),o=3,r=[];for(let u=0;u({lat:a.lat,lng:a.lon})),t.points[0]?.radius||20),o=12;for(let a=0;a
- ${Hn?` + ${On?` @@ -288,7 +288,7 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( route
No courses created yet
- `:wt.map(t=>{let n=t.points.map(c=>({lat:c.lat,lng:c.lon})),o=_e.findTracksPassingThroughPoints(n,t.points[0]?.radius||20),r=t.id===bn,u="";if(r){let c=o.map(m=>{let T=_e.getTrackData(m);if(!T)return null;let b=Kn(T,t.points);if(!b)return null;let w=gs(T,b.startIdx,b.endIdx),R=T.stats?.startTime||T.points?.[0]?.time,S=R?Zt(R):"-";return{id:m,displayName:T.displayName||T.name||m,date:S,sport:T.sport,color:T.color,...w,startIdx:b.startIdx,endIdx:b.endIdx}}).filter(m=>m!==null);c.sort((m,T)=>m.duration-T.duration||m.id.localeCompare(T.id)),u=` + `:wt.map(t=>{let s=t.points.map(c=>({lat:c.lat,lng:c.lon})),o=De.findTracksPassingThroughPoints(s,t.points[0]?.radius||20),a=t.id===Cn,g="";if(a){let c=o.map(m=>{let T=De.getTrackData(m);if(!T)return null;let f=ys(T,t.points);if(!f)return null;let M=Rs(T,f.startIdx,f.endIdx),O=T.stats?.startTime||T.points?.[0]?.time,H=O?Gt(O):"-";return{id:m,displayName:T.displayName||T.name||m,date:H,sport:T.sport,color:T.color,...M,startIdx:f.startIdx,endIdx:f.endIdx}}).filter(m=>m!==null);c.sort((m,T)=>m.duration-T.duration||m.id.localeCompare(T.id)),g=`
${c.length===0?`
No matching tracks
@@ -297,7 +297,7 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( Track (${c.length}) - ${hs()} + ${Ns()} @@ -309,7 +309,7 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( ${pt(m.displayName)}
- ${bs(m,m.sport,m.date)} + ${Ws(m,m.sport,m.date)} `).join("")} @@ -317,53 +317,53 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( `}
`}return` -
+
- ${r?"expand_more":"chevron_right"} + ${a?"expand_more":"chevron_right"}
${pt(t.name)} edit
-
straighten ${Fl(t).toFixed(2)} km | ${t.points.length} points | ${o.length} matching tracks
+
straighten ${Do(t).toFixed(2)} km | ${t.points.length} points | ${o.length} matching tracks
- ${u} + ${g}
`}).join("")}
- `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{Rl()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{Hn=!1,_e.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),Dt()}),e.querySelectorAll(".course-item").forEach(t=>{let n=t.dataset.id;t.querySelector(".btn-edit-course")?.addEventListener("click",o=>{o.stopPropagation(),Js(n)}),t.querySelector(".btn-rename-course")?.addEventListener("click",o=>{o.stopPropagation(),Nl(n)}),t.querySelector(".btn-delete-course")?.addEventListener("click",o=>{o.stopPropagation(),Wl(n)}),t.querySelector(".course-item-header")?.addEventListener("click",o=>{o.target.closest(".course-actions")||o.target.closest(".btn-rename-course")||(_n(n),bn=bn===n?null:n,Dt())}),t.querySelectorAll(".course-track-row").forEach(o=>{let r=o.dataset.trackId,u=parseInt(o.dataset.start,10),c=parseInt(o.dataset.end,10);o.querySelector(".track-name-cell")?.addEventListener("click",m=>{m.stopPropagation();let T=_e.getTrackData(r);T&&(Mt(r,!1),setTimeout(()=>{let b=T.points,w=b.find(p=>p.time!=null)?.time||0,R=Math.max(0,Math.min(u,b.length-1)),S=Math.max(0,Math.min(c,b.length-1)),k=Math.max(0,((b[R]?.time||0)-w)/1e3),M=Math.max(0,((b[S]?.time||0)-w)/1e3),g=Me.getXAxis(),I=k,P=M;g==="distance"&&(I=Math.max(0,(b[R]?.dist||0)/1e3),P=Math.max(0,(b[S]?.dist||0)/1e3)),Ye.patch({sel:[I,P],tab:"graphs"},!0),Me.restoreSelection(k,M),_e.highlightSegment(r,T.points,u,c,!0)},50))}),o.addEventListener("mouseenter",()=>{_e.setTrackHover(r,!0)}),o.addEventListener("mouseleave",()=>{_e.setTrackHover(r,!1)})})})}function Rl(){let e=`Course ${wt.length+1}`,s={id:Math.random().toString(36).substring(2,9),name:e,points:[]};wt.push(s),fs(),Dt(),Js(s.id)}function Nl(e){let s=wt.find(c=>c.id===e);if(!s)return;let t=document.querySelector(`.course-item[data-id="${e}"]`);if(!t)return;let n=t.querySelector(".course-name");if(!n)return;let o=s.name;n.innerHTML=``;let r=n.querySelector(".course-name-input");r.focus(),r.select();let u=()=>{let c=r.value.trim();c!==""&&(s.name=c,fs()),Dt()};r.addEventListener("blur",u),r.addEventListener("keydown",c=>{c.key==="Enter"?u():c.key==="Escape"&&Dt()})}function Js(e){vn=e,Hn=!0,Dt()}function Qs(){_l=null}function _n(e,s=!1){vn=e,s&&(bn=e),Hn=!1,_e.setCustomClickHandler(null),Qs(),Dt()}function Wl(e){confirm("Are you sure you want to delete this course?")&&(wt=wt.filter(s=>s.id!==e),vn===e&&(vn=null,Qs()),fs(),Dt())}var es=()=>{},vs=[];function el(){vs.forEach(e=>e.destroy()),vs=[]}function tl(e){es=e}function nl(){el(),document.querySelectorAll(".hr-settings-popup").forEach(s=>s.remove());let e=document.getElementById("insights-view");e&&(e.innerHTML=` + `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{No()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{On=!1,De.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),Wt()}),e.querySelectorAll(".course-item").forEach(t=>{let s=t.dataset.id;t.querySelector(".btn-edit-course")?.addEventListener("click",o=>{o.stopPropagation(),Fl(s)}),t.querySelector(".btn-rename-course")?.addEventListener("click",o=>{o.stopPropagation(),Wo(s)}),t.querySelector(".btn-delete-course")?.addEventListener("click",o=>{o.stopPropagation(),zo(s)}),t.querySelector(".course-item-header")?.addEventListener("click",o=>{o.target.closest(".course-actions")||o.target.closest(".btn-rename-course")||(Ln(s),Cn=Cn===s?null:s,Wt())}),t.querySelectorAll(".course-track-row").forEach(o=>{let a=o.dataset.trackId,g=parseInt(o.dataset.start,10),c=parseInt(o.dataset.end,10);o.querySelector(".track-name-cell")?.addEventListener("click",m=>{m.stopPropagation();let T=De.getTrackData(a);T&&(Mt(a,!1),setTimeout(()=>{let f=T.points,M=f.find(u=>u.time!=null)?.time||0,O=Math.max(0,Math.min(g,f.length-1)),H=Math.max(0,Math.min(c,f.length-1)),E=Math.max(0,((f[O]?.time||0)-M)/1e3),k=Math.max(0,((f[H]?.time||0)-M)/1e3),p=Se.getXAxis(),P=E,b=k;p==="distance"&&(P=Math.max(0,(f[O]?.dist||0)/1e3),b=Math.max(0,(f[H]?.dist||0)/1e3)),Ye.patch({sel:[P,b],tab:"graphs"},!0),Se.restoreSelection(E,k),De.highlightSegment(a,T.points,g,c,!0)},50))}),o.addEventListener("mouseenter",()=>{De.setTrackHover(a,!0)}),o.addEventListener("mouseleave",()=>{De.setTrackHover(a,!1)})})})}function No(){let e=`Course ${wt.length+1}`,n={id:Math.random().toString(36).substring(2,9),name:e,points:[]};wt.push(n),Ds(),Wt(),Fl(n.id)}function Wo(e){let n=wt.find(c=>c.id===e);if(!n)return;let t=document.querySelector(`.course-item[data-id="${e}"]`);if(!t)return;let s=t.querySelector(".course-name");if(!s)return;let o=n.name;s.innerHTML=``;let a=s.querySelector(".course-name-input");a.focus(),a.select();let g=()=>{let c=a.value.trim();c!==""&&(n.name=c,Ds()),Wt()};a.addEventListener("blur",g),a.addEventListener("keydown",c=>{c.key==="Enter"?g():c.key==="Escape"&&Wt()})}function Fl(e){$n=e,On=!0,Wt()}function _l(){_o=null}function Ln(e,n=!1){$n=e,n&&(Cn=e),On=!1,De.setCustomClickHandler(null),_l(),Wt()}function zo(e){confirm("Are you sure you want to delete this course?")&&(wt=wt.filter(n=>n.id!==e),$n===e&&($n=null,_l()),Ds(),Wt())}var Es=()=>{},zs=[];function zl(){zs.forEach(e=>e.destroy()),zs=[]}function ql(e){Es=e}function Ul(){zl(),document.querySelectorAll(".hr-settings-popup").forEach(n=>n.remove());let e=document.getElementById("insights-view");e&&(e.innerHTML=`
no_sim
Select a track for insights
- `)}function Bt(e){el();let s=document.getElementById("insights-view");if(!s)return;if(!e){s.innerHTML="";return}let t=e.stats;if(it.ensureCurvesAndZones(e),!t.powerCurve&&!t.hrZones&&!t.hrCurve){s.innerHTML=` + `)}var rn=16384,Bl=new Float64Array(rn),Dl=new Float64Array(rn),Rl=new Float64Array(rn),Uo=new Float64Array(rn),Vo=new Float64Array(rn),ws=new Float64Array(rn+1),Ts=new Float64Array(rn+1),Oo=[150,180,210,240,270,300,330,360,400,450,500,540,600,660,720,810,900,1020],Nl=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,420,600,900,1200];function _t(e,n=[]){zl();let t=document.getElementById("insights-view");if(!t)return;if(!e){t.innerHTML="";return}let s=e.stats;if(ot.ensureCurvesAndZones(e),!s.powerCurve&&!s.hrZones&&!s.hrCurve){t.innerHTML=`
analytics
No insights available for this track (requires Power or Heart Rate data)
- `;return}let n=e.points,o=it.getFTP(),r=[180,240,300,360,420,480,540,600,720,900],u=2e4;for(let S=0;S<8;S++)for(let k=0;k>1;for(let F=0;Fo?I-=q-o:I=2e4-(2e4-I)*g,I
- `;let c=document.getElementById("insights-grid");if(!c)return;let m=Math.round(c.getBoundingClientRect().width-42)||480;if(t.powerCurve&&Ks({grid:c,track:e,curve:t.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:De.power.color,icon:"bolt",chartWidth:m}),t.hrCurve&&Ks({grid:c,track:e,curve:t.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:De.hr.color,icon:"favorite",chartWidth:m}),t.powerZones){let S=document.createElement("div");S.className="insight-card";let k="power",M=De.power.color;S.style.setProperty("--chart-color",M);let g=Me.getMapColorMetric()===k,I=t.powerZones.reduce((h,F)=>h+F,0),P=gn.getPowerZones(),p="";t.powerZones.forEach((h,F)=>{if(F>=P.length)return;let q=P[F],J=I>0?h/I*100:0,Y=isFinite(q.max)?`${Math.round(q.min)} - ${Math.round(q.max)} W`:`> ${Math.round(q.min)} W`;p+=` + `;return}let o=n.length>0?n:[e],a=ot.getFTP(),g=2e4,c=0;for(let E=0;E0?W*_*36:0;Bl[b]=x,Dl[b]=1/w,Rl[b]=1/(D+1),Uo[b]=W,Vo[b]=C,ws[b+1]=ws[b]+x,Ts[b+1]=Ts[b]+C}for(let b=0;b<40;b++){let u=1+b*.01;for(let x=0;xp)continue;let D=p-w,W=0,_=0;for(let C=0;C<=D;C++){let q=(ws[C+w]-ws[C])*u,N=Ts[C+w]-Ts[C];q>W&&(W=q),N>_&&(_=N)}c+=(W+_)/w}}let P=p>>1;for(let b=0;b<17;b++)for(let u=0;u<18;u++){let x=a*(.88+u*.02+b*.005),w=Oo[u]+b*10,D=2e4,W=0,_=0;for(let C=0;Cx){let d=q-x;D-=d*(1+.05*(1-Math.exp(-.005*d)))}else{let d=x-q,r=546*Math.exp(-.01*d)+w;D=2e4-(2e4-D)*Math.exp(-1/r)}D
+ `;let m=document.getElementById("insights-grid");if(!m)return;let T=Math.round(m.getBoundingClientRect().width-42)||480;if(s.powerCurve&&Wl({grid:m,track:e,curve:s.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:We.power.color,icon:"bolt",chartWidth:T}),s.hrCurve&&Wl({grid:m,track:e,curve:s.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:We.hr.color,icon:"favorite",chartWidth:T}),s.powerZones){let E=document.createElement("div");E.className="insight-card";let k="power",p=We.power.color;E.style.setProperty("--chart-color",p);let P=Se.getMapColorMetric()===k,b=s.powerZones.reduce((w,D)=>w+D,0),u=Sn.getPowerZones(),x="";s.powerZones.forEach((w,D)=>{if(D>=u.length)return;let W=u[D],_=b>0?w/b*100:0,C=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} W`:`> ${Math.round(W.min)} W`;x+=`
- Z${F+1} - ${q.name} - ${Y} - ${ht(Math.round(h))} - ${J.toFixed(1)}% + Z${D+1} + ${W.name} + ${C} + ${ht(Math.round(w))} + ${_.toFixed(1)}%
-
+
- `}),S.innerHTML=` + `}),E.innerHTML=`
- boltPower Zones + boltPower Zones
-
@@ -371,27 +371,27 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( settings
-
${p}
- `,c.appendChild(S),S.querySelector(".map-color-btn")?.addEventListener("click",h=>{h.stopPropagation(),Me.toggleMapColor(k);let F=Me.getMapColorMetric();c.querySelectorAll(".map-color-btn").forEach(q=>{let J=q;J.classList.toggle("active",J.dataset.metric===F)})}),S.querySelector(".btn-pw-settings")?.addEventListener("click",h=>{h.stopPropagation(),ql(h.currentTarget,e)})}if(t.hrZones){let S=document.createElement("div");S.className="insight-card";let k="hr",M=De.hr.color;S.style.setProperty("--chart-color",M);let g=Me.getMapColorMetric()===k,I=t.hrZones.reduce((h,F)=>h+F,0),P=gn.getHRZones(),p="";t.hrZones.forEach((h,F)=>{if(F>=P.length)return;let q=P[F],J=I>0?h/I*100:0,Y=isFinite(q.max)?`${Math.round(q.min)} - ${Math.round(q.max)} bpm`:`> ${Math.round(q.min)} bpm`;p+=` +
${x}
+ `,m.appendChild(E),E.querySelector(".map-color-btn")?.addEventListener("click",w=>{w.stopPropagation(),Se.toggleMapColor(k);let D=Se.getMapColorMetric();m.querySelectorAll(".map-color-btn").forEach(W=>{let _=W;_.classList.toggle("active",_.dataset.metric===D)})}),E.querySelector(".btn-pw-settings")?.addEventListener("click",w=>{w.stopPropagation(),jo(w.currentTarget,e)})}if(s.hrZones){let E=document.createElement("div");E.className="insight-card";let k="hr",p=We.hr.color;E.style.setProperty("--chart-color",p);let P=Se.getMapColorMetric()===k,b=s.hrZones.reduce((w,D)=>w+D,0),u=Sn.getHRZones(),x="";s.hrZones.forEach((w,D)=>{if(D>=u.length)return;let W=u[D],_=b>0?w/b*100:0,C=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} bpm`:`> ${Math.round(W.min)} bpm`;x+=`
- Z${F+1} - ${q.name} - ${Y} - ${ht(Math.round(h))} - ${J.toFixed(1)}% + Z${D+1} + ${W.name} + ${C} + ${ht(Math.round(w))} + ${_.toFixed(1)}%
-
+
- `}),S.innerHTML=` + `}),E.innerHTML=`
- favoriteHeart Rate Zones + favoriteHeart Rate Zones
-
@@ -399,30 +399,30 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( settings
-
${p}
- `,c.appendChild(S),S.querySelector(".map-color-btn")?.addEventListener("click",h=>{h.stopPropagation(),Me.toggleMapColor(k);let F=Me.getMapColorMetric();c.querySelectorAll(".map-color-btn").forEach(q=>{let J=q;J.classList.toggle("active",J.dataset.metric===F)})}),S.querySelector(".btn-hr-settings")?.addEventListener("click",h=>{h.stopPropagation(),Ul(h.currentTarget,e)})}let T=document.createElement("div");T.className="insight-card";let b=t.totalDist/1e3,w=b>0?t.elevGain/(b*1e3)*100:0;if(T.innerHTML=` +
${x}
+ `,m.appendChild(E),E.querySelector(".map-color-btn")?.addEventListener("click",w=>{w.stopPropagation(),Se.toggleMapColor(k);let D=Se.getMapColorMetric();m.querySelectorAll(".map-color-btn").forEach(W=>{let _=W;_.classList.toggle("active",_.dataset.metric===D)})}),E.querySelector(".btn-hr-settings")?.addEventListener("click",w=>{w.stopPropagation(),Yo(w.currentTarget,e)})}let f=document.createElement("div");f.className="insight-card";let M=s.totalDist/1e3,O=M>0?s.elevGain/(M*1e3)*100:0;if(f.innerHTML=`
- terrainClimbing Analysis + terrainClimbing Analysis
Total Ascent
-
${Math.round(t.elevGain)} m
+
${Math.round(s.elevGain)} m
Total Descent
-
${Math.round(t.elevLoss)} m
+
${Math.round(s.elevLoss)} m
Avg Grade
-
${w.toFixed(1)} %
+
${O.toFixed(1)} %
VAM
-
${t.duration&&t.duration>0?Math.round(t.elevGain/t.duration*36e5):0} m/h
+
${s.duration&&s.duration>0?Math.round(s.elevGain/s.duration*36e5):0} m/h
- `,c.appendChild(T),t.avgPower&&t.avgHR){let S=document.createElement("div");S.className="insight-card";let k=t.avgPower/t.avgHR;S.innerHTML=` + `,m.appendChild(f),s.avgPower&&s.avgHR){let E=document.createElement("div");E.className="insight-card";let k=s.avgPower/s.avgHR;E.innerHTML=`
monitoringEfficiency Factor
@@ -433,18 +433,18 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
Higher values indicate better aerobic fitness.
- `,c.appendChild(S)}let R=Ys(e);if(R.length>0){let S=document.createElement("div");S.className="insight-card",S.style.cssText="column-span: all; display: block;",S.innerHTML=` -
routeCourses (${R.length})
+ `,m.appendChild(E)}let H=Pl(e);if(H.length>0){let E=document.createElement("div");E.className="insight-card",E.style.cssText="column-span: all; display: block;",E.innerHTML=` +
routeCourses (${H.length})
- ${hs()} + ${Ns()} - ${R.map(k=>{let M=Kn(e,k.points),g="";if(M){let I=gs(e,M.startIdx,M.endIdx),P=e.stats?.startTime||e.points?.[0]?.time,p=P?Zt(P):"-";g=bs(I,e.sport||null,p)}else g='';return` + ${H.map(k=>{let p=ys(e,k.points),P="";if(p){let b=Rs(e,p.startIdx,p.endIdx),u=e.stats?.startTime||e.points?.[0]?.time,x=u?Gt(u):"-";P=Ws(b,e.sport||null,x)}else P='';return` - ${g} + ${P} `}).join("")}
Name
No continuous segmentNo continuous segment
@@ -452,19 +452,19 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( ${pt(k.name)}
- `,c.appendChild(S),S.querySelectorAll(".clickable-course").forEach(k=>{k.addEventListener("click",()=>{let M=k.dataset.id;_n(M,!0),Ye.patch({tab:"courses"},!0)}),k.addEventListener("mouseenter",()=>{let M=k.dataset.id,g=R.find(I=>I.id===M);if(g){let I=Kn(e,g.points);I&&_e.highlightSegment(e.id,e.points,I.startIdx,I.endIdx,!1)}}),k.addEventListener("mouseleave",()=>{_e.clearHighlight()})})}}function Ks(e){let{grid:s,track:t,curve:n,metricKey:o,label:r,unit:u,color:c,icon:m,chartWidth:T}=e,b=Me.getMapColorMetric()===o,w=document.createElement("div");w.className="insight-card",w.style.setProperty("--chart-color",c),w.innerHTML=` + `,m.appendChild(E),E.querySelectorAll(".clickable-course").forEach(k=>{k.addEventListener("click",()=>{let p=k.dataset.id;Ln(p,!0),Ye.patch({tab:"courses"},!0)}),k.addEventListener("mouseenter",()=>{let p=k.dataset.id,P=H.find(b=>b.id===p);if(P){let b=ys(e,P.points);b&&De.highlightSegment(e.id,e.points,b.startIdx,b.endIdx,!1)}}),k.addEventListener("mouseleave",()=>{De.clearHighlight()})})}}function Wl(e){let{grid:n,track:t,curve:s,metricKey:o,label:a,unit:g,color:c,icon:m,chartWidth:T}=e,f=Se.getMapColorMetric()===o,M=document.createElement("div");M.className="insight-card",M.style.setProperty("--chart-color",c),M.innerHTML=`
- ${m}${r} + ${m}${a}
-
@@ -485,32 +485,32 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
- `,s.appendChild(w);let R=w.querySelector(".curve-table-wrap"),S=w.querySelector(".btn-toggle-table"),k=S.querySelector(".material-symbols-rounded");S.addEventListener("click",()=>{let p=R.style.display==="none";R.style.display=p?"block":"none",k.textContent=p?"expand_less":"expand_more"});let M=w.querySelector(".map-color-btn");M.addEventListener("click",p=>{p.stopPropagation();let h=M.dataset.metric;Me.toggleMapColor(h);let F=Me.getMapColorMetric();s.querySelectorAll(".map-color-btn").forEach(q=>{let J=q;J.classList.toggle("active",J.dataset.metric===F)})});let g=w.querySelector(".curve-tbody"),I=Object.keys(n).map(Number).sort((p,h)=>p-h);I.forEach(p=>{let h=n[p],F=h.power||h.hr||h.val,q=document.createElement("tr");q.innerHTML=` - ${Ft(p)} - ${F} ${u} + `,n.appendChild(M);let O=M.querySelector(".curve-table-wrap"),H=M.querySelector(".btn-toggle-table"),E=H.querySelector(".material-symbols-rounded");H.addEventListener("click",()=>{let u=O.style.display==="none";O.style.display=u?"block":"none",E.textContent=u?"expand_less":"expand_more"});let k=M.querySelector(".map-color-btn");k.addEventListener("click",u=>{u.stopPropagation();let x=k.dataset.metric;Se.toggleMapColor(x);let w=Se.getMapColorMetric();n.querySelectorAll(".map-color-btn").forEach(D=>{let W=D;W.classList.toggle("active",W.dataset.metric===w)})});let p=M.querySelector(".curve-tbody"),P=Object.keys(s).map(Number).sort((u,x)=>u-x);P.forEach(u=>{let x=s[u],w=x.power||x.hr||x.val,D=document.createElement("tr");D.innerHTML=` + ${Bt(u)} + ${w} ${g} - - `,g?.appendChild(q)}),g?.querySelectorAll(".btn-show-peak").forEach(p=>{p.addEventListener("click",h=>{let F=h.currentTarget,q=parseInt(F.dataset.idx),J=parseInt(F.dataset.len),Y=t.points,B=Math.min(Y.length-1,q+J-1),z=Y[0].time||0,D=((Y[q].time||z)-z)/1e3,le=((Y[B].time||z)-z)/1e3;Ye.patch({sel:[D,le]}),_e.highlightSegment(t.id,Y,q,B,!0)})});let P=w.querySelector(`#${o}-curve-chart`);if(P){let p=I,h=I.map(Y=>n[Y].power||n[Y].hr||n[Y].val),F=document.createElement("div");F.className="cur-y-val",F.style.cssText=`color:${c};display:none;border-color:${c}44`,P.style.position="relative",P.appendChild(F);let q={id:`${o}-curve`,width:0,height:250,padding:[10,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:r,stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(Y,B)=>B.map(z=>`${z}${u}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(Y,B,z)=>z},hooks:{draw:[Y=>{let B=Y.ctx,z=window.devicePixelRatio||1,D=Y.bbox,le=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],y=p[p.length-1];B.save(),B.fillStyle="#555564",B.textAlign="center",B.textBaseline="top",B.font=`${10*z}px system-ui, sans-serif`;let d=-100;le.forEach(a=>{if(a>y)return;let G=Y.valToPos(a,"x",!0);G>d+30*z&&G{Y.over.addEventListener("click",()=>{let B=Y.cursor.idx;if(B!=null&&p[B]!=null){let z=p[B],le=n[z].idx,y=t.points,d=Math.min(y.length-1,le+z-1),a=y[0].time||0,G=((y[le].time||a)-a)/1e3,X=((y[d].time||a)-a)/1e3;Ye.patch({sel:[G,X]}),_e.highlightSegment(t.id,y,le,d,!0)}})}],setCursor:[Y=>{if(!Y._ready)return;Y.redraw(!1);let B=Y.cursor.idx,z=Y.ctx,D=window.devicePixelRatio||1,le=Y.bbox,y=B!=null&&h[B]!=null&&Y.cursor.left>=0,d=Y.cursor.top,a=Y.valToPos(h[B],"y",!1);if(y&&Math.abs(d-a)<40){let X=Y.valToPos(p[B],"x",!1),se=Y.valToPos(h[B],"y",!1),U=p[B];F.innerHTML=`${Ft(U)}: ${h[B]} ${u}`,F.style.transform=`translate(${X}px, ${se}px) translate(15px, 15px)`,F.style.display="";let ne=Y.valToPos(p[B],"x",!0),Le=Y.valToPos(h[B],"y",!0);z.save(),z.beginPath(),z.setLineDash([2*D,2*D]),z.strokeStyle=tt(c,.4),z.lineWidth=1*D,z.moveTo(ne,le.top),z.lineTo(ne,le.top+le.height),z.stroke(),z.beginPath(),z.setLineDash([]),z.arc(ne,Le,3*D,0,Math.PI*2),z.fillStyle="#0e0e10",z.fill(),z.strokeStyle=c,z.lineWidth=2*D,z.stroke(),z.restore()}else F.style.display="none"}]},legend:{show:!1}};q.width=T||Math.round(s.getBoundingClientRect().width-42)||P.clientWidth||500;let J=new zl(q,[p,h],P);J._ready=!0,vs.push(J)}}function Ul(e,s){document.querySelectorAll(".hr-settings-popup").forEach(u=>u.remove());let t=document.createElement("div");t.className="hr-settings-popup";let n=it.getHRZones();t.innerHTML=` + `,p?.appendChild(D)}),p?.querySelectorAll(".btn-show-peak").forEach(u=>{u.addEventListener("click",x=>{let w=x.currentTarget,D=parseInt(w.dataset.idx),W=parseInt(w.dataset.len),_=t.points,C=Math.min(_.length-1,D+W-1),q=_[0].time||0,N=((_[D].time||q)-q)/1e3,ie=((_[C].time||q)-q)/1e3;Ye.patch({sel:[N,ie]}),De.highlightSegment(t.id,_,D,C,!0)})});let b=M.querySelector(`#${o}-curve-chart`);if(b){let u=P,x=P.map(_=>s[_].power||s[_].hr||s[_].val),w=document.createElement("div");w.className="cur-y-val",w.style.cssText=`color:${c};display:none;border-color:${c}44`,b.style.position="relative",b.appendChild(w);let D={id:`${o}-curve`,width:0,height:250,padding:[10,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:a,stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(_,C)=>C.map(q=>`${q}${g}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(_,C,q)=>q},hooks:{draw:[_=>{let C=_.ctx,q=window.devicePixelRatio||1,N=_.bbox,ie=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],y=u[u.length-1];C.save(),C.fillStyle="#555564",C.textAlign="center",C.textBaseline="top",C.font=`${10*q}px system-ui, sans-serif`;let d=-100;ie.forEach(r=>{if(r>y)return;let J=_.valToPos(r,"x",!0);J>d+30*q&&J{_.over.addEventListener("click",()=>{let C=_.cursor.idx;if(C!=null&&u[C]!=null){let q=u[C],ie=s[q].idx,y=t.points,d=Math.min(y.length-1,ie+q-1),r=y[0].time||0,J=((y[ie].time||r)-r)/1e3,U=((y[d].time||r)-r)/1e3;Ye.patch({sel:[J,U]}),De.highlightSegment(t.id,y,ie,d,!0)}})}],setCursor:[_=>{if(!_._ready)return;_.redraw(!1);let C=_.cursor.idx,q=_.ctx,N=window.devicePixelRatio||1,ie=_.bbox,y=C!=null&&x[C]!=null&&_.cursor.left>=0,d=_.cursor.top,r=_.valToPos(x[C],"y",!1);if(y&&Math.abs(d-r)<40){let U=_.valToPos(u[C],"x",!1),Q=_.valToPos(x[C],"y",!1),Y=u[C];w.innerHTML=`${Bt(Y)}: ${x[C]} ${g}`,w.style.transform=`translate(${U}px, ${Q}px) translate(15px, 15px)`,w.style.display="";let K=_.valToPos(u[C],"x",!0),Ae=_.valToPos(x[C],"y",!0);q.save(),q.beginPath(),q.setLineDash([2*N,2*N]),q.strokeStyle=tt(c,.4),q.lineWidth=1*N,q.moveTo(K,ie.top),q.lineTo(K,ie.top+ie.height),q.stroke(),q.beginPath(),q.setLineDash([]),q.arc(K,Ae,3*N,0,Math.PI*2),q.fillStyle="#0e0e10",q.fill(),q.strokeStyle=c,q.lineWidth=2*N,q.stroke(),q.restore()}else w.style.display="none"}]},legend:{show:!1}};D.width=T||Math.round(n.getBoundingClientRect().width-42)||b.clientWidth||500;let W=new qo(D,[u,x],b);W._ready=!0,zs.push(W)}}function Yo(e,n){document.querySelectorAll(".hr-settings-popup").forEach(g=>g.remove());let t=document.createElement("div");t.className="hr-settings-popup";let s=ot.getHRZones();t.innerHTML=`
Configure HR Zones (bpm)
Z1 / Z2 - +
Z2 / Z3 - +
Z3 / Z4 - +
Z4 / Z5 - +
@@ -525,12 +525,12 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( box-shadow: 0 8px 32px rgba(0,0,0,0.6); left: ${o.right-200}px; top: ${o.bottom+8}px; - `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let u=t.querySelectorAll(".hr-zone-input"),c=Array.from(u).map(m=>parseInt(m.value)||0);for(let m=1;m{!t.contains(u.target)&&!e.contains(u.target)&&(t.remove(),document.removeEventListener("click",r))};setTimeout(()=>document.addEventListener("click",r),10)}function ql(e,s){document.querySelectorAll(".pw-settings-popup").forEach(u=>u.remove());let t=document.createElement("div");t.className="pw-settings-popup";let n=it.getFTP();t.innerHTML=` + `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let g=t.querySelectorAll(".hr-zone-input"),c=Array.from(g).map(m=>parseInt(m.value)||0);for(let m=1;m{!t.contains(g.target)&&!e.contains(g.target)&&(t.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}function jo(e,n){document.querySelectorAll(".pw-settings-popup").forEach(g=>g.remove());let t=document.createElement("div");t.className="pw-settings-popup";let s=ot.getFTP();t.innerHTML=`
Configure FTP (Watts)
Your FTP - +
@@ -545,25 +545,25 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( box-shadow: 0 8px 32px rgba(0,0,0,0.6); left: ${o.right-200}px; top: ${o.bottom+8}px; - `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let u=t.querySelector("#ftp-input"),c=parseInt(u.value)||200;it.setFTP(c),await at.set("ftp",c),s.stats=it.computeStats(s.points,!0),await at.save(s),Bt(s),t.remove(),es(`FTP updated to ${c}W`)});let r=u=>{!t.contains(u.target)&&!e.contains(u.target)&&(t.remove(),document.removeEventListener("click",r))};setTimeout(()=>document.addEventListener("click",r),10)}import sl from"uplot";var Ct=[],zt=null,ft=null,an="power",Gt="hr",bt=null,Lt=[],Vt=[],nn=null,Pt=!1;function ts(){let e=document.getElementById("combined-time-val");if(e&&bt!==null&&Lt[bt]){let s=Lt[bt][2];e.textContent=`${ht(s)}`}}function ol(){nn&&(clearInterval(nn),nn=null),ft&&(ft.destroy(),ft=null),Ct=[],zt=null,an="power",Gt="hr",bt=null,Lt=[],Vt=[],Pt=!1;let e=document.getElementById("combined-tooltip");e&&e.remove();let s=document.getElementById("combined-view");s&&(s.innerHTML=` + `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let g=t.querySelector("#ftp-input"),c=parseInt(g.value)||200;ot.setFTP(c),await at.set("ftp",c),n.stats=ot.computeStats(n.points,!0),await at.save(n),_t(n),t.remove(),Es(`FTP updated to ${c}W`)});let a=g=>{!t.contains(g.target)&&!e.contains(g.target)&&(t.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}import Vl from"uplot";var zt=[],qt=null,ft=null,gn="power",Jt="hr",bt=null,Lt=[],Ot=[],cn=null,Pt=!1;function Ss(){let e=document.getElementById("combined-time-val");if(e&&bt!==null&&Lt[bt]){let n=Lt[bt][2];e.textContent=`${ht(n)}`}}function Yl(){cn&&(clearInterval(cn),cn=null),ft&&(ft.destroy(),ft=null),zt=[],qt=null,gn="power",Jt="hr",bt=null,Lt=[],Ot=[],Pt=!1;let e=document.getElementById("combined-tooltip");e&&e.remove();let n=document.getElementById("combined-view");n&&(n.innerHTML=`
no_sim
Select a track for combined analysis
- `)}function rn(e){Array.isArray(e)?(Ct=e,zt=e[0]||null):e?(Ct=[e],zt=e):(Ct=[],zt=null);let s=document.getElementById("combined-view");if(!s)return;let t=zt;if(!t){s.innerHTML=` + `)}var Ys=16384,qs=Array.from({length:8},()=>new Float64Array(Ys)),Us=Array.from({length:8},()=>new Float64Array(Ys)),Vs=new Int32Array(8),Os=new Float64Array(32*32),Zo=[2,3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300];function dn(e,n=[]){Array.isArray(e)?(zt=e,qt=e[0]||null):e?(zt=[e],qt=e):(zt=[],qt=null);let t=document.getElementById("combined-view");if(!t)return;let s=qt;if(!s){t.innerHTML=`
no_sim
Select a track for combined analysis
- `;return}let n=Me.METRICS,o=[];for(let S in n){let k=n[S];t.points.some(M=>M[k.field]!=null)&&o.push(S)}!o.includes(an)&&o.length>0&&(an=o[0]),!o.includes(Gt)&&o.length>1?Gt=o[1]:!o.includes(Gt)&&o.length>0&&(Gt=o[0]);let r=n[an],u=n[Gt];s.style.overflow="hidden";let c="";if(Ct.length>=2){let S=0,k=0,M=[2,3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300];for(let ne=0;ne<4;ne++)for(let Le of M)for(let Re=0;Re=Le){let de=ae[re-Le],$e=pe[re-Le];He-=(de.power||0)+(de.hr||0)+(de.speed||0),Q-=($e.power||0)+($e.hr||0)+($e.speed||0),_-=(de.cad||0)+(de.ele||0)*.1,oe-=($e.cad||0)+($e.ele||0)*.1,k+=He/Le*(Q/Le)+_/Le*(oe/Le),S++}}}let g=Ct[0],I=Ct[1],P=g.stats,p=I.stats,h=((p.totalDist-P.totalDist)/1e3).toFixed(2),F=((p.avgPower||0)-(P.avgPower||0)).toFixed(0),q=((p.avgHR||0)-(P.avgHR||0)).toFixed(0),J=(p.elevGain-P.elevGain).toFixed(0),Y=(p.shifts||0)-(P.shifts||0),B=((P.totalDist+p.totalDist)/1e3).toFixed(2),z=(P.elevGain+p.elevGain).toFixed(0),D=((P.duration||0)+(p.duration||0))/1e3,le=Math.round(((P.avgPower||0)+(p.avgPower||0))/2),y=Math.max(P.maxPower||0,p.maxPower||0),d=Math.round(((P.avgHR||0)+(p.avgHR||0))/2),a=Math.max(P.maxHR||0,p.maxHR||0),G=((p.avgTemp??0)-(P.avgTemp??0)).toFixed(1),X=(((P.avgTemp??0)+(p.avgTemp??0))/2).toFixed(1),se=Math.max(P.maxTemp??0,p.maxTemp??0).toFixed(1),U=(P.shifts||0)+(p.shifts||0);c=` -
+ `;return}let o=Se.METRICS,a=[];for(let E in o){let k=o[E];s.points.some(p=>p[k.field]!=null)&&a.push(E)}!a.includes(gn)&&a.length>0&&(gn=a[0]),!a.includes(Jt)&&a.length>1?Jt=a[1]:!a.includes(Jt)&&a.length>0&&(Jt=a[0]);let g=o[gn],c=o[Jt];t.style.overflow="hidden";let m="";if(zt.length>=2){let E=n.length>=2?n:zt,k=Math.min(E.length,8);Os.fill(0);for(let me=0;me=oe){let A=be-oe;He-=G[A],Ce-=te[A],Re-=F[A],le-=Ie[A];let ne=He*de,Ne=Ce*de,j=Re*de,_e=le*de,we=ne-Ne,Ee=j-_e,ke=Math.exp(-we*we*xe),ve=Math.exp(-Ee*Ee*xe);P+=ne*Ne*ke+j*_e*ve,p++}}}}for(let me=0;me<1024;me++)P+=Os[me]*.001;let b=zt[0],u=zt[1],x=b.stats,w=u.stats,D=((w.totalDist-x.totalDist)/1e3).toFixed(2),W=((w.avgPower||0)-(x.avgPower||0)).toFixed(0),_=((w.avgHR||0)-(x.avgHR||0)).toFixed(0),C=(w.elevGain-x.elevGain).toFixed(0),q=(w.shifts||0)-(x.shifts||0),N=((x.totalDist+w.totalDist)/1e3).toFixed(2),ie=(x.elevGain+w.elevGain).toFixed(0),y=((x.duration||0)+(w.duration||0))/1e3,d=Math.round(((x.avgPower||0)+(w.avgPower||0))/2),r=Math.max(x.maxPower||0,w.maxPower||0),J=Math.round(((x.avgHR||0)+(w.avgHR||0))/2),U=Math.max(x.maxHR||0,w.maxHR||0),Q=((w.avgTemp??0)-(x.avgTemp??0)).toFixed(1),Y=(((x.avgTemp??0)+(w.avgTemp??0))/2).toFixed(1),K=Math.max(x.maxTemp??0,w.maxTemp??0).toFixed(1),Ae=(x.shifts||0)+(w.shifts||0);m=` +
Aggregate Track Comparison & Analysis
- - + + @@ -571,64 +571,64 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( - - - - + + + + - - - - + + + + - - + + - + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + +
Metric${g.displayName||g.name} (T1)${I.displayName||I.name} (T2)${b.displayName||b.name} (T1)${u.displayName||u.name} (T2) Delta (T2 - T1) Aggregate Summary
Distance${(P.totalDist/1e3).toFixed(2)} km${(p.totalDist/1e3).toFixed(2)} km${Number(h)>=0?"+":""}${h} km${B} km (Total)${(x.totalDist/1e3).toFixed(2)} km${(w.totalDist/1e3).toFixed(2)} km${Number(D)>=0?"+":""}${D} km${N} km (Total)
Elevation Gain${P.elevGain.toFixed(0)} m${p.elevGain.toFixed(0)} m${Number(J)>=0?"+":""}${J} m${z} m (Total)${x.elevGain.toFixed(0)} m${w.elevGain.toFixed(0)} m${Number(C)>=0?"+":""}${C} m${ie} m (Total)
Duration${P.duration?ht(P.duration/1e3):"--"}${p.duration?ht(p.duration/1e3):"--"}${x.duration?ht(x.duration/1e3):"--"}${w.duration?ht(w.duration/1e3):"--"} --${ht(D)} (Total)${ht(y)} (Total)
Avg / Max Power${P.avgPower||0} W / ${P.maxPower||0} W${p.avgPower||0} W / ${p.maxPower||0} W${Number(F)>=0?"+":""}${F} W (Avg)${le} W (Avg) / ${y} W (Max)${x.avgPower||0} W / ${x.maxPower||0} W${w.avgPower||0} W / ${w.maxPower||0} W${Number(W)>=0?"+":""}${W} W (Avg)${d} W (Avg) / ${r} W (Max)
Avg / Max HR${P.avgHR||0} bpm / ${P.maxHR||0} bpm${p.avgHR||0} bpm / ${p.maxHR||0} bpm${Number(q)>=0?"+":""}${q} bpm (Avg)${d} bpm (Avg) / ${a} bpm (Max)${x.avgHR||0} bpm / ${x.maxHR||0} bpm${w.avgHR||0} bpm / ${w.maxHR||0} bpm${Number(_)>=0?"+":""}${_} bpm (Avg)${J} bpm (Avg) / ${U} bpm (Max)
Avg / Max Temp${P.avgTemp!=null?P.avgTemp.toFixed(1):"--"} \xB0C / ${P.maxTemp!=null?P.maxTemp.toFixed(1):"--"} \xB0C${p.avgTemp!=null?p.avgTemp.toFixed(1):"--"} \xB0C / ${p.maxTemp!=null?p.maxTemp.toFixed(1):"--"} \xB0C${Number(G)>=0?"+":""}${G} \xB0C (Avg)${X} \xB0C (Avg) / ${se} \xB0C (Max)${x.avgTemp!=null?x.avgTemp.toFixed(1):"--"} \xB0C / ${x.maxTemp!=null?x.maxTemp.toFixed(1):"--"} \xB0C${w.avgTemp!=null?w.avgTemp.toFixed(1):"--"} \xB0C / ${w.maxTemp!=null?w.maxTemp.toFixed(1):"--"} \xB0C${Number(Q)>=0?"+":""}${Q} \xB0C (Avg)${Y} \xB0C (Avg) / ${K} \xB0C (Max)
Gear Shifts${P.shifts||0}${p.shifts||0}${Y>=0?"+":""}${Y}${U} (Total)${x.shifts||0}${w.shifts||0}${q>=0?"+":""}${q}${Ae} (Total)
- `}s.innerHTML=`${c} + `}t.innerHTML=`${m}
arrow_forward X Axis:
@@ -636,8 +636,8 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( arrow_upward Y Axis:
@@ -660,35 +660,35 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
- `,document.getElementById("btn-combined-x")?.addEventListener("click",S=>{S.stopPropagation(),ll(S.currentTarget,"x")}),document.getElementById("btn-combined-y")?.addEventListener("click",S=>{S.stopPropagation(),ll(S.currentTarget,"y")});let m=document.getElementById("combined-time-slider"),T=document.getElementById("combined-time-val"),b=document.getElementById("btn-combined-play");m?.addEventListener("input",()=>{bt=parseInt(m.value,10),ts(),ft&&ft.redraw()});function w(){b&&(b.innerHTML='pause'),nn=window.setInterval(()=>{bt!==null&&btplay_arrow')}b?.addEventListener("click",()=>{nn?R():(bt!==null&&bt>=Lt.length-1&&(bt=0,m.value="0",ts(),ft&&ft.redraw()),w())}),document.getElementById("btn-combined-cart")?.addEventListener("click",()=>{Pt&&(Pt=!1,rn(zt))}),document.getElementById("btn-combined-polar")?.addEventListener("click",()=>{Pt||(Pt=!0,rn(zt))}),Vl()}function yn(){let e=document.getElementById("tab-combined"),s=document.getElementById("combined-plot-container");if(ft&&s&&s.clientWidth>0){let t=s.clientWidth,n=s.clientHeight;if(t>0&&n>0)if(Pt){let o=Math.min(t,n);ft.setSize({width:o,height:o})}else ft.setSize({width:t,height:n})}}function ll(e,s){document.querySelectorAll(".metric-menu-popup").forEach(m=>m.remove());let t=document.createElement("div");t.className="metric-menu-popup";let n=Me.METRICS,o=zt;if(!o)return;let r=[];for(let m in n){let T=n[m];o.points.some(b=>b[T.field]!=null)&&r.push(m)}r.forEach(m=>{let T=n[m],b=document.createElement("div"),w=s==="x"?an:Gt;b.className=`menu-item ${w===m?"active":""}`,b.innerHTML=` + `,document.getElementById("btn-combined-x")?.addEventListener("click",E=>{E.stopPropagation(),Ol(E.currentTarget,"x")}),document.getElementById("btn-combined-y")?.addEventListener("click",E=>{E.stopPropagation(),Ol(E.currentTarget,"y")});let T=document.getElementById("combined-time-slider"),f=document.getElementById("combined-time-val"),M=document.getElementById("btn-combined-play");T?.addEventListener("input",()=>{bt=parseInt(T.value,10),Ss(),ft&&ft.redraw()});function O(){M&&(M.innerHTML='pause'),cn=window.setInterval(()=>{bt!==null&&btplay_arrow')}M?.addEventListener("click",()=>{cn?H():(bt!==null&&bt>=Lt.length-1&&(bt=0,T.value="0",Ss(),ft&&ft.redraw()),O())}),document.getElementById("btn-combined-cart")?.addEventListener("click",()=>{Pt&&(Pt=!1,dn(qt))}),document.getElementById("btn-combined-polar")?.addEventListener("click",()=>{Pt||(Pt=!0,dn(qt))}),Go()}function Yn(){let e=document.getElementById("tab-combined"),n=document.getElementById("combined-plot-container");if(ft&&n&&n.clientWidth>0){let t=n.clientWidth,s=n.clientHeight;if(t>0&&s>0)if(Pt){let o=Math.min(t,s);ft.setSize({width:o,height:o})}else ft.setSize({width:t,height:s})}}function Ol(e,n){document.querySelectorAll(".metric-menu-popup").forEach(m=>m.remove());let t=document.createElement("div");t.className="metric-menu-popup";let s=Se.METRICS,o=qt;if(!o)return;let a=[];for(let m in s){let T=s[m];o.points.some(f=>f[T.field]!=null)&&a.push(m)}a.forEach(m=>{let T=s[m],f=document.createElement("div"),M=n==="x"?gn:Jt;f.className=`menu-item ${M===m?"active":""}`,f.innerHTML=` ${T.icon} ${T.label} - ${w===m?"check":""} - `,b.addEventListener("click",()=>{s==="x"?an=m:Gt=m,t.remove(),rn(zt)}),t.appendChild(b)});let u=e.getBoundingClientRect();t.style.top=`${u.bottom+5}px`,t.style.left=`${u.left}px`,document.body.appendChild(t);let c=m=>{!t.contains(m.target)&&!e.contains(m.target)&&(t.remove(),document.removeEventListener("click",c))};setTimeout(()=>document.addEventListener("click",c),0)}function Vl(){if(!zt)return;let e=document.getElementById("combined-plot-container");if(!e)return;let s=Me.METRICS,t=s[an]||s.power,n=s[Gt]||s.hr;if(Ct.length>=2){let k=Ct[0],M=Ct[1],g=k.points,I=M.points,P=Math.max(g.length,I.length),p=[],h=[],F=[];for(let B=0;B0?e.clientWidth:800,J=e.clientHeight>0?e.clientHeight:350,Y={width:q,height:J,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:[{},{label:`${k.displayName||k.name} (${n.label})`,stroke:k.color||"#3b82f6",width:2,points:{show:!1}},{label:`${M.displayName||M.name} (${n.label})`,stroke:M.color||"#FF6B35",width:2,points:{show:!1}}],axes:[{side:2,label:"Elapsed Duration (s)",stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:30},{side:3,label:`${n.label} (${n.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:40}],legend:{show:!0}};ft=new sl(Y,[p,h,F],e),yn();return}let o=zt.points,r=o[0].time||0,u=o.map((k,M)=>[k[t.field],k[n.field],(k.time-r)/1e3,(k.dist||0)/1e3,M]).filter(([k,M,g,I])=>k!=null&&M!=null);if(u.length===0){e.innerHTML='
No data for selected metrics
';return}if(Pt){let k=u.map(h=>h[0]),M=u.map(h=>h[1]),g=Math.min(...k),I=Math.max(...k),P=Math.min(...M),p=Math.max(...M);Lt=u.map(h=>{let F=h[0],q=h[1],J=(F-g)/(I-g||1)*2*Math.PI,Y=(q-P)/(p-P||1),B=Y*Math.cos(J),z=Y*Math.sin(J);return[B,z,h[2],h[3],h[4],F,q]})}else Lt=u.map(k=>[k[0],k[1],k[2],k[3],k[4],k[0],k[1]]);let c=document.getElementById("combined-time-slider");c&&(c.max=`${u.length-1}`,(bt===null||bt>=u.length)&&(bt=u.length-1,c.value=c.max),ts()),Vt=[...Lt].sort((k,M)=>k[0]-M[0]||k[4]-M[4]);let m=Vt.map(k=>k[0]),T=Vt.map(k=>k[1]),b=document.getElementById("combined-plot-container"),w=b&&b.clientWidth>0?b.clientWidth:600,R=b&&b.clientHeight>0?b.clientHeight:400;if(Pt){let k=Math.min(w,R>0?R:w);w=k,R=k,b&&(b.style.display="flex",b.style.alignItems="center",b.style.justifyContent="center")}else b&&(b.style.display="",b.style.alignItems="",b.style.justifyContent="");let S={width:w,height:R,padding:[10,15,0,0],scales:{x:{time:!1,auto:!0},y:{auto:!0}},series:[{},{label:n.label,width:0,points:{show:!0,size:3,fill:tt(n.color,.3)}}],axes:[{side:2,show:!Pt,label:`${t.label} (${t.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(k,M)=>M.map(g=>g!=null?t.fmtAxis(g):""),size:30},{side:3,show:!Pt,label:`${n.label} (${n.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(k,M)=>M.map(g=>g!=null?n.fmtAxis(g):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:(k,M,g)=>{let I=k.cursor.left,P=k.cursor.top;if(I!=null&&P!=null&&I>=0&&P>=0){let p=1/0,h=-1;for(let F=0;F=0&&p<2500)return h}return g},points:{size:7,stroke:"#fff",width:2,fill:n.color}},legend:{show:!1},hooks:{draw:[k=>{let M=k.ctx,g=window.devicePixelRatio||1;M.save(),M.beginPath(),M.strokeStyle="rgba(255, 255, 255, 0.15)",M.lineWidth=1*g;let I=!1;for(let P=0;P{let M=k.cursor.idx,g=document.getElementById("combined-tooltip");if(g||(g=document.createElement("div"),g.id="combined-tooltip",g.style.position="absolute",g.style.background="rgba(14, 14, 16, 0.9)",g.style.color="#fff",g.style.padding="8px 12px",g.style.borderRadius="4px",g.classList.add("font-m"),g.style.fontFamily="system-ui",g.style.pointerEvents="none",g.style.zIndex="1000",g.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",g.style.border="1px solid #2e2e34",document.body.appendChild(g)),M!=null&&Vt[M]&&k.cursor.left>=0){let I=Vt[M],P=I[2],p=I[3],h=I[5],F=I[6];g.innerHTML=` -
Point #${M}
+ ${M===m?"check":""} + `,f.addEventListener("click",()=>{n==="x"?gn=m:Jt=m,t.remove(),dn(qt)}),t.appendChild(f)});let g=e.getBoundingClientRect();t.style.top=`${g.bottom+5}px`,t.style.left=`${g.left}px`,document.body.appendChild(t);let c=m=>{!t.contains(m.target)&&!e.contains(m.target)&&(t.remove(),document.removeEventListener("click",c))};setTimeout(()=>document.addEventListener("click",c),0)}function Go(){if(!qt)return;let e=document.getElementById("combined-plot-container");if(!e)return;let n=Se.METRICS,t=n[gn]||n.power,s=n[Jt]||n.hr;if(zt.length>=2){let E=zt[0],k=zt[1],p=E.points,P=k.points,b=Math.max(p.length,P.length),u=[],x=[],w=[];for(let C=0;C0?e.clientWidth:800,W=e.clientHeight>0?e.clientHeight:350,_={width:D,height:W,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:[{},{label:`${E.displayName||E.name} (${s.label})`,stroke:E.color||"#3b82f6",width:2,points:{show:!1}},{label:`${k.displayName||k.name} (${s.label})`,stroke:k.color||"#FF6B35",width:2,points:{show:!1}}],axes:[{side:2,label:"Elapsed Duration (s)",stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:30},{side:3,label:`${s.label} (${s.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:40}],legend:{show:!0}};ft=new Vl(_,[u,x,w],e),Yn();return}let o=qt.points,a=o[0].time||0,g=o.map((E,k)=>[E[t.field],E[s.field],(E.time-a)/1e3,(E.dist||0)/1e3,k]).filter(([E,k,p,P])=>E!=null&&k!=null);if(g.length===0){e.innerHTML='
No data for selected metrics
';return}if(Pt){let E=g.map(x=>x[0]),k=g.map(x=>x[1]),p=Math.min(...E),P=Math.max(...E),b=Math.min(...k),u=Math.max(...k);Lt=g.map(x=>{let w=x[0],D=x[1],W=(w-p)/(P-p||1)*2*Math.PI,_=(D-b)/(u-b||1),C=_*Math.cos(W),q=_*Math.sin(W);return[C,q,x[2],x[3],x[4],w,D]})}else Lt=g.map(E=>[E[0],E[1],E[2],E[3],E[4],E[0],E[1]]);let c=document.getElementById("combined-time-slider");c&&(c.max=`${g.length-1}`,(bt===null||bt>=g.length)&&(bt=g.length-1,c.value=c.max),Ss()),Ot=[...Lt].sort((E,k)=>E[0]-k[0]||E[4]-k[4]);let m=Ot.map(E=>E[0]),T=Ot.map(E=>E[1]),f=document.getElementById("combined-plot-container"),M=f&&f.clientWidth>0?f.clientWidth:600,O=f&&f.clientHeight>0?f.clientHeight:400;if(Pt){let E=Math.min(M,O>0?O:M);M=E,O=E,f&&(f.style.display="flex",f.style.alignItems="center",f.style.justifyContent="center")}else f&&(f.style.display="",f.style.alignItems="",f.style.justifyContent="");let H={width:M,height:O,padding:[10,15,0,0],scales:{x:{time:!1,auto:!0},y:{auto:!0}},series:[{},{label:s.label,width:0,points:{show:!0,size:3,fill:tt(s.color,.3)}}],axes:[{side:2,show:!Pt,label:`${t.label} (${t.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(E,k)=>k.map(p=>p!=null?t.fmtAxis(p):""),size:30},{side:3,show:!Pt,label:`${s.label} (${s.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(E,k)=>k.map(p=>p!=null?s.fmtAxis(p):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:(E,k,p)=>{let P=E.cursor.left,b=E.cursor.top;if(P!=null&&b!=null&&P>=0&&b>=0){let u=1/0,x=-1;for(let w=0;w=0&&u<2500)return x}return p},points:{size:7,stroke:"#fff",width:2,fill:s.color}},legend:{show:!1},hooks:{draw:[E=>{let k=E.ctx,p=window.devicePixelRatio||1;k.save(),k.beginPath(),k.strokeStyle="rgba(255, 255, 255, 0.15)",k.lineWidth=1*p;let P=!1;for(let b=0;b{let k=E.cursor.idx,p=document.getElementById("combined-tooltip");if(p||(p=document.createElement("div"),p.id="combined-tooltip",p.style.position="absolute",p.style.background="rgba(14, 14, 16, 0.9)",p.style.color="#fff",p.style.padding="8px 12px",p.style.borderRadius="4px",p.classList.add("font-m"),p.style.fontFamily="system-ui",p.style.pointerEvents="none",p.style.zIndex="1000",p.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",p.style.border="1px solid #2e2e34",document.body.appendChild(p)),k!=null&&Ot[k]&&E.cursor.left>=0){let P=Ot[k],b=P[2],u=P[3],x=P[5],w=P[6];p.innerHTML=` +
Point #${k}
Time: - ${ht(P)} + ${ht(b)}
Distance: - ${p.toFixed(2)} km + ${u.toFixed(2)} km
${t.label}: - ${t.fmtAxis(h)} ${t.unit} + ${t.fmtAxis(x)} ${t.unit}
- ${n.label}: - ${n.fmtAxis(F)} ${n.unit} + ${s.label}: + ${s.fmtAxis(w)} ${s.unit}
- `,g.style.display="block";let q=k.over.getBoundingClientRect();g.style.left=`${q.left+window.scrollX+k.cursor.left+15}px`,g.style.top=`${q.top+window.scrollY+k.cursor.top+15}px`}else g.style.display="none"}]}};e.querySelector(".empty-text")&&(e.innerHTML=""),ft&&ft.destroy(),ft=new sl(S,[m,T],e),ft.over.addEventListener("click",()=>{if(ft){let k=ft.cursor.idx;if(k!=null&&Vt[k]){let M=Vt[k][4];Me.setCursorAt(M)}}}),yn()}import xn from"uplot";function il(e,s){let t=0;for(let F=0;Ft&&(t=q)}t||(t=Date.UTC(2026,7,1));let n=new Date(t),o=n.getUTCFullYear(),r=Date.UTC(o-1,n.getUTCMonth(),n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),u=Date.UTC(o,n.getUTCMonth()-6,n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),c=Date.UTC(o,n.getUTCMonth()-1,n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),m=0,T=0,b=0,w=0,R=0,S=t;e.forEach(F=>{if(!F.stats.startTime)return;let q=s(F);if(q===void 0)return;R+=q;let J=F.stats.startTime;J=r&&(T+=q),J>=u&&(b+=q),J>=c&&(w+=q)});let k=7*24*60*60*1e3,M=Date.UTC(o,0,1),g=Math.max(.1,(t-M)/k),I=Math.max(.1,(t-r)/k),P=Math.max(.1,(t-u)/k),p=Math.max(.1,(t-c)/k),h=Math.max(.1,(t-S)/k);return{currentYear:m,pastYear:T,past6m:b,past1m:w,total:R,currentYearAvg:m/g,pastYearAvg:T/I,past6mAvg:b/P,past1mAvg:w/p,totalAvg:R/h}}function al(e,s,t){let n=s?1e3:1,o=r=>(s?r/n:r).toLocaleString("en-US",{minimumFractionDigits:s?1:0,maximumFractionDigits:s?1:0});return` + `,p.style.display="block";let D=E.over.getBoundingClientRect();p.style.left=`${D.left+window.scrollX+E.cursor.left+15}px`,p.style.top=`${D.top+window.scrollY+E.cursor.top+15}px`}else p.style.display="none"}]}};e.querySelector(".empty-text")&&(e.innerHTML=""),ft&&ft.destroy(),ft=new Vl(H,[m,T],e),ft.over.addEventListener("click",()=>{if(ft){let E=ft.cursor.idx;if(E!=null&&Ot[E]){let k=Ot[E][4];Se.setCursorAt(k)}}}),Yn()}import Pn from"uplot";function jl(e,n){let t=0;for(let w=0;wt&&(t=D)}t||(t=Date.UTC(2026,7,1));let s=new Date(t),o=s.getUTCFullYear(),a=Date.UTC(o-1,s.getUTCMonth(),s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),g=Date.UTC(o,s.getUTCMonth()-6,s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),c=Date.UTC(o,s.getUTCMonth()-1,s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),m=0,T=0,f=0,M=0,O=0,H=t;e.forEach(w=>{if(!w.stats.startTime)return;let D=n(w);if(D===void 0)return;O+=D;let W=w.stats.startTime;W=a&&(T+=D),W>=g&&(f+=D),W>=c&&(M+=D)});let E=7*24*60*60*1e3,k=Date.UTC(o,0,1),p=Math.max(.1,(t-k)/E),P=Math.max(.1,(t-a)/E),b=Math.max(.1,(t-g)/E),u=Math.max(.1,(t-c)/E),x=Math.max(.1,(t-H)/E);return{currentYear:m,pastYear:T,past6m:f,past1m:M,total:O,currentYearAvg:m/p,pastYearAvg:T/P,past6mAvg:f/b,past1mAvg:M/u,totalAvg:O/x}}function Zl(e,n,t){let s=n?1e3:1,o=a=>(n?a/s:a).toLocaleString("en-US",{minimumFractionDigits:n?1:0,maximumFractionDigits:n?1:0});return` - - + + @@ -719,61 +719,61 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
Period${s?"Distance":"Elevation"}${s?"Distance/Week":"Elevation/Week"}${n?"Distance":"Elevation"}${n?"Distance/Week":"Elevation/Week"}
- `}var wn=[];function dl(){wn.forEach(e=>e.destroy()),wn=[]}function ul(){dl();let e=document.getElementById("evolution-view");e&&(e.innerHTML=` + `}var An=[];function to(){An.forEach(e=>e.destroy()),An=[]}function no(){to();let e=document.getElementById("evolution-view");e&&(e.innerHTML=`
no_sim
Select a track for progress analysis
- `)}function Tn(e,s,t,n){dl();let o=document.getElementById("evolution-view");if(!o)return;let r=Ye.get().progress||"all";s.forEach(h=>{it.ensureCurvesAndZones(h)});let u=0,c=0,m=2/8,T=2/43;s.forEach(h=>{let F=h.points||[],q=0,J=0;for(let Y=0;Y{ot.ensureCurvesAndZones(b)});let g=0,c=0;js.fill(0);for(let b=0;bx)continue;let q=x-C,N=0,ie=0,y=0;for(let d=0;d<=q;d++){let r=jn[d+C]-jn[d],J=hn[d+C]-hn[d],U=Ms[d+C]-Ms[d];r>N&&(N=r),J>ie&&(ie=J),U>y&&(y=U)}c+=(N+ie+y)/C*W*.001}}for(let D=0;D<11;D++)for(let W=0;W
- - - -
- - - - - - + + + + + +
- `;let w=document.getElementById("evolution-container");if(!w)return;let R=w.clientWidth||570,S=xn.sync("progress-sync");b.push(cl(w,s,"distance",S,n,R)),b.push(cl(w,s,"elevation",S,n,R));let k=w.querySelector(".distance-progress-card .chart-scroll-container"),M=w.querySelector(".elevation-progress-card .chart-scroll-container");k&&M&&(k.addEventListener("scroll",()=>{M.scrollLeft!==k.scrollLeft&&(M.scrollLeft=k.scrollLeft)}),M.addEventListener("scroll",()=>{k.scrollLeft!==M.scrollLeft&&(k.scrollLeft=M.scrollLeft)}));let g=o.querySelector("#evolution-time-range");g&&g.querySelectorAll(".seg-btn").forEach(h=>{h.addEventListener("click",()=>{let F=h.getAttribute("data-range");F&&(g.querySelectorAll(".seg-btn").forEach(q=>q.classList.remove("active")),h.classList.add("active"),p(F))})}),o.querySelectorAll(".metric-pill").forEach(h=>{h.addEventListener("click",()=>{let F=h.getAttribute("data-target");F&&document.getElementById(`${F}-evolution-card`)?.scrollIntoView({behavior:"smooth"})})});function P(h){b.forEach(F=>{F&&F.updatePin&&F.updatePin(h)})}function p(h){Ye.patch({progress:h==="all"?null:h}),b.forEach(F=>{F&&F.updateRange&&F.updateRange(h)})}if(s.some(h=>h.stats.powerCurve)){let h=rl({grid:w,currentTrack:e,allTracks:s,metricKey:"power",label:"Power Curve Progress",unit:"W",color:De.power.color,icon:"bolt",onPinChange:P,onRangeChange:p,onTrackSelect:t,gridWidth:R});b.push(h)}if(s.some(h=>h.stats.hrCurve)){let h=rl({grid:w,currentTrack:e,allTracks:s,metricKey:"hr",label:"Heart Rate Curve Progress",unit:"bpm",color:De.hr.color,icon:"favorite",onPinChange:P,onRangeChange:p,onTrackSelect:t,gridWidth:R});b.push(h)}r!=="all"&&b.forEach(h=>{h&&h.updateRange&&h.updateRange(r)}),wn.forEach(h=>{h._ready=!0})}function rl(e){let{grid:s,currentTrack:t,allTracks:n,metricKey:o,label:r,unit:u,color:c,icon:m,onPinChange:T,onRangeChange:b,onTrackSelect:w,gridWidth:R}=e,S=t&&t.name||"Current Track",k=null,M=document.createElement("div");M.className="chart-row evolution-card-group",M.id=`${o}-evolution-card`,s.appendChild(M);let g=document.createElement("div");g.className="chart-row progress-chart-row",g.style.setProperty("--chart-color",c),g.style.flex="0 0 400px",g.style.borderBottom="none",g.innerHTML=` + `;let T=document.getElementById("evolution-container");if(!T)return;let f=T.clientWidth||570,M=Pn.sync("progress-sync");m.push(eo(T,n,"distance",M,s,f)),m.push(eo(T,n,"elevation",M,s,f));let O=T.querySelector(".distance-progress-card .chart-scroll-container"),H=T.querySelector(".elevation-progress-card .chart-scroll-container");O&&H&&(O.addEventListener("scroll",()=>{H.scrollLeft!==O.scrollLeft&&(H.scrollLeft=O.scrollLeft)}),H.addEventListener("scroll",()=>{O.scrollLeft!==H.scrollLeft&&(O.scrollLeft=H.scrollLeft)}));let E=o.querySelector("#evolution-time-range");E&&E.querySelectorAll(".seg-btn").forEach(b=>{b.addEventListener("click",()=>{let u=b.getAttribute("data-range");u&&(E.querySelectorAll(".seg-btn").forEach(x=>x.classList.remove("active")),b.classList.add("active"),P(u))})}),o.querySelectorAll(".metric-pill").forEach(b=>{b.addEventListener("click",()=>{let u=b.getAttribute("data-target");u&&document.getElementById(`${u}-evolution-card`)?.scrollIntoView({behavior:"smooth"})})});function p(b){m.forEach(u=>{u&&u.updatePin&&u.updatePin(b)})}function P(b){Ye.patch({progress:b==="all"?null:b}),m.forEach(u=>{u&&u.updateRange&&u.updateRange(b)})}if(n.some(b=>b.stats.powerCurve)){let b=Kl({grid:T,currentTrack:e,allTracks:n,metricKey:"power",label:"Power Curve Progress",unit:"W",color:We.power.color,icon:"bolt",onPinChange:p,onRangeChange:P,onTrackSelect:t,gridWidth:f});m.push(b)}if(n.some(b=>b.stats.hrCurve)){let b=Kl({grid:T,currentTrack:e,allTracks:n,metricKey:"hr",label:"Heart Rate Curve Progress",unit:"bpm",color:We.hr.color,icon:"favorite",onPinChange:p,onRangeChange:P,onTrackSelect:t,gridWidth:f});m.push(b)}a!=="all"&&m.forEach(b=>{b&&b.updateRange&&b.updateRange(a)}),An.forEach(b=>{b._ready=!0})}function Kl(e){let{grid:n,currentTrack:t,allTracks:s,metricKey:o,label:a,unit:g,color:c,icon:m,onPinChange:T,onRangeChange:f,onTrackSelect:M,gridWidth:O}=e,H=t&&t.name||"Current Track",E=null,k=document.createElement("div");k.className="chart-row evolution-card-group",k.id=`${o}-evolution-card`,n.appendChild(k);let p=document.createElement("div");p.className="chart-row progress-chart-row",p.style.setProperty("--chart-color",c),p.style.flex="0 0 400px",p.style.borderBottom="none",p.innerHTML=`
${m} - ${r} + ${a}
- `;let I=document.createElement("div");I.className="evolution-legend",I.innerHTML=` + `;let P=document.createElement("div");P.className="evolution-legend",P.innerHTML=`
- ${S} + ${H}
All-Time Max
- `;let p=Ye.get().progress||"all",h=document.createElement("div");h.className="chart-row progress-chart-row",h.style.setProperty("--chart-color",c),h.style.flex="1",h.style.borderBottom="none",h.innerHTML=` + `;let u=Ye.get().progress||"all",x=document.createElement("div");x.className="chart-row progress-chart-row",x.style.setProperty("--chart-color",c),x.style.flex="1",x.style.borderBottom="none",x.innerHTML=`
${m} @@ -783,17 +783,17 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
- `;let F=document.createElement("div");F.style.cssText="display: flex; flex-direction: row; gap: 0px; align-items: stretch;",F.appendChild(g),F.appendChild(h),M.appendChild(F),M.appendChild(I);let q=g.querySelector(`#${o}-evolution-chart`);if(!q)return;let J={};n.forEach(ae=>{let pe=o==="power"?ae.stats.powerCurve:ae.stats.hrCurve;if(!pe)return;let ye=ae.name||"Unnamed Track",He=ae.stats.startTime||ae.addedAt?Zt(ae.stats.startTime||ae.addedAt):"Unknown Date",Q=`${ye} (${He})`;Object.entries(pe).forEach(([_,oe])=>{let re=Number(_),K=oe.power||oe.hr;(!J[re]||K>J[re].val)&&(J[re]={val:K,trackInfo:Q,trackId:ae.id,idx:oe.idx})})});let Y=t&&(o==="power"?t.stats.powerCurve:t.stats.hrCurve)||{},B=new Set;Object.keys(J).forEach(ae=>B.add(Number(ae))),Object.keys(Y).forEach(ae=>B.add(Number(ae)));let z=Array.from(B).sort((ae,pe)=>ae-pe),D=z,le=z.map(ae=>{let pe=Y[ae];return pe?pe.power||pe.hr:null}),y=z.map(ae=>J[ae]?.val||null),d=n.filter(ae=>(ae.stats.startTime||ae.addedAt)!=null);d.sort((ae,pe)=>(ae.stats.startTime||ae.addedAt||0)-(pe.stats.startTime||pe.addedAt||0)||ae.id.localeCompare(pe.id));let a=[],G={};z.forEach(ae=>G[ae]=[]),d.forEach(ae=>{let pe=o==="power"?ae.stats.powerCurve:ae.stats.hrCurve;pe&&(a.push((ae.stats.startTime||ae.addedAt)/1e3),z.forEach(ye=>{let He=pe[ye],Q=He?o==="power"?He.power:He.hr:null;G[ye].push(Q)}))});let X=z[0]||5,se=d,U=null;function ne(ae,pe){let ye=a[a.length-1]||1785542400,He=0;pe==="1m"?He=ye-30*24*3600:pe==="2m"?He=ye-60*24*3600:pe==="6m"?He=ye-180*24*3600:pe==="1y"?He=ye-365*24*3600:pe==="2y"&&(He=ye-2*365*24*3600);let Q=[];a.forEach((Pe,de)=>{Pe>=He&&Q.push(de)});let _=Q.map(Pe=>a[Pe]),oe=G[ae]||[],re=Q.map(Pe=>oe[Pe]),K=fn(re,5);return se=Q.map(Pe=>d[Pe]),{xFiltered:_,rawYFiltered:re,smoothedYFiltered:K}}let Le=null,Re=document.createElement("div");return Re.className="cur-y-val font-m",Re.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",q.style.position="relative",q.appendChild(Re),(()=>{let ae={id:`${o}-evolution`,width:400,height:250,padding:[0,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:"Current Track",stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}},{label:"All-Time Max",stroke:"#888888",width:1,fill:"transparent",points:{show:!0,size:6,fill:"#888888"}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(Q,_)=>_.map(oe=>`${oe}${u}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(Q,_,oe)=>oe,x:!1,y:!1},hooks:{draw:[Q=>{let _=Q.ctx,oe=window.devicePixelRatio||1,re=Q.bbox,K=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Pe=D[D.length-1];_.save(),_.fillStyle="#555564",_.textAlign="center",_.textBaseline="top",_.font=`${10*oe}px system-ui, sans-serif`;let de=-100;if(K.forEach($e=>{if($e>Pe)return;let Ce=Q.valToPos($e,"x",!0);Ce>de+30*oe&&Ce=0){let Ce=Q.valToPos(U,"x",!0),We=Q.valToPos(le[$e]||y[$e],"y",!0);_.save(),_.beginPath(),_.setLineDash([]);let te=le[$e],ge=te!==null?5*oe:3*oe,L=te!==null?c:"#888888";_.arc(Ce,We,ge,0,2*Math.PI),_.fillStyle=L,_.fill(),_.strokeStyle="#fff",_.lineWidth=2*oe,_.stroke(),_.restore()}}_.restore()},Q=>{let _=Q.ctx,oe=window.devicePixelRatio||1,re=Q.bbox,K=Q.cursor.idx,Pe=1,de=Q.cursor.left,$e=Q.cursor.top;if(de!=null&&$e!=null&&de>=0&&$e>=0){let Ce=1/0,We=-1,te=30,ge=te*te;for(let L=0;L{if(!Q._ready)return;Q.redraw(!1);let _=Q.cursor.idx,oe=1,re=Q.cursor.left,K=Q.cursor.top;if(re!=null&&K!=null&&re>=0&&K>=0){let We=1/0,te=-1,ge=30,L=ge*ge;for(let ee=0;ee${Ft(ge)}
`;if(L!==null&&(Ne+=` + `;let w=document.createElement("div");w.style.cssText="display: flex; flex-direction: row; gap: 0px; align-items: stretch;",w.appendChild(p),w.appendChild(x),k.appendChild(w),k.appendChild(P);let D=p.querySelector(`#${o}-evolution-chart`);if(!D)return;let W={};s.forEach(oe=>{let de=o==="power"?oe.stats.powerCurve:oe.stats.hrCurve;if(!de)return;let xe=oe.name||"Unnamed Track",Pe=oe.stats.startTime||oe.addedAt?Gt(oe.stats.startTime||oe.addedAt):"Unknown Date",G=`${xe} (${Pe})`;Object.entries(de).forEach(([F,ae])=>{let ue=Number(F),te=ae.power||ae.hr;(!W[ue]||te>W[ue].val)&&(W[ue]={val:te,trackInfo:G,trackId:oe.id,idx:ae.idx})})});let _=t&&(o==="power"?t.stats.powerCurve:t.stats.hrCurve)||{},C=new Set;Object.keys(W).forEach(oe=>C.add(Number(oe))),Object.keys(_).forEach(oe=>C.add(Number(oe)));let q=Array.from(C).sort((oe,de)=>oe-de),N=q,ie=q.map(oe=>{let de=_[oe];return de?de.power||de.hr:null}),y=q.map(oe=>W[oe]?.val||null),d=s.filter(oe=>(oe.stats.startTime||oe.addedAt)!=null);d.sort((oe,de)=>(oe.stats.startTime||oe.addedAt||0)-(de.stats.startTime||de.addedAt||0)||oe.id.localeCompare(de.id));let r=[],J={};q.forEach(oe=>J[oe]=[]),d.forEach(oe=>{let de=o==="power"?oe.stats.powerCurve:oe.stats.hrCurve;de&&(r.push((oe.stats.startTime||oe.addedAt)/1e3),q.forEach(xe=>{let Pe=de[xe],G=Pe?o==="power"?Pe.power:Pe.hr:null;J[xe].push(G)}))});let U=q[0]||5,Q=d,Y=null;function K(oe,de){let xe=r[r.length-1]||1785542400,Pe=0;de==="1m"?Pe=xe-30*24*3600:de==="2m"?Pe=xe-60*24*3600:de==="6m"?Pe=xe-180*24*3600:de==="1y"?Pe=xe-365*24*3600:de==="2y"&&(Pe=xe-2*365*24*3600);let G=[];r.forEach((Ie,he)=>{Ie>=Pe&&G.push(he)});let F=G.map(Ie=>r[Ie]),ae=J[oe]||[],ue=G.map(Ie=>ae[Ie]),te=En(ue,5);return Q=G.map(Ie=>d[Ie]),{xFiltered:F,rawYFiltered:ue,smoothedYFiltered:te}}let Ae=null,me=document.createElement("div");return me.className="cur-y-val font-m",me.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",D.style.position="relative",D.appendChild(me),(()=>{let oe={id:`${o}-evolution`,width:400,height:250,padding:[0,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:"Current Track",stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}},{label:"All-Time Max",stroke:"#888888",width:1,fill:"transparent",points:{show:!0,size:6,fill:"#888888"}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(G,F)=>F.map(ae=>`${ae}${g}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(G,F,ae)=>ae,x:!1,y:!1},hooks:{draw:[G=>{let F=G.ctx,ae=window.devicePixelRatio||1,ue=G.bbox,te=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Ie=N[N.length-1];F.save(),F.fillStyle="#555564",F.textAlign="center",F.textBaseline="top",F.font=`${10*ae}px system-ui, sans-serif`;let he=-100;if(te.forEach(He=>{if(He>Ie)return;let Ce=G.valToPos(He,"x",!0);Ce>he+30*ae&&Ce=0){let Ce=G.valToPos(Y,"x",!0),Re=G.valToPos(ie[He]||y[He],"y",!0);F.save(),F.beginPath(),F.setLineDash([]);let le=ie[He],be=le!==null?5*ae:3*ae,A=le!==null?c:"#888888";F.arc(Ce,Re,be,0,2*Math.PI),F.fillStyle=A,F.fill(),F.strokeStyle="#fff",F.lineWidth=2*ae,F.stroke(),F.restore()}}F.restore()},G=>{let F=G.ctx,ae=window.devicePixelRatio||1,ue=G.bbox,te=G.cursor.idx,Ie=1,he=G.cursor.left,He=G.cursor.top;if(he!=null&&He!=null&&he>=0&&He>=0){let Ce=1/0,Re=-1,le=30,be=le*le;for(let A=0;A{if(!G._ready)return;G.redraw(!1);let F=G.cursor.idx,ae=1,ue=G.cursor.left,te=G.cursor.top;if(ue!=null&&te!=null&&ue>=0&&te>=0){let Re=1/0,le=-1,be=30,A=be*be;for(let ne=0;ne${Bt(be)}
`;if(A!==null&&(Ne+=`
Current: - ${L} ${u} + ${A} ${g}
- `),ee!==null&&(Ne+=` + `),ne!==null&&(Ne+=`
Max: - ${ee} ${u} + ${ne} ${g}
- `),Re.innerHTML=Ne,Le&&U===null){X=ge;let{xFiltered:V,rawYFiltered:Ae,smoothedYFiltered:he}=ne(X,p),xe=he.map(be=>be!==null?be*.9:null),Ee=he.map(be=>be!==null?be*1.1:null);Le.setData([V,Ae,he,xe,Ee]);let fe=document.getElementById(`${o}-timeline-label`);fe&&(fe.textContent=`Progress ${Ft(ge)} ${o==="power"?"Power":"HR"}`)}Re.style.display="",Re.style.left=`${re+$e.left}px`,Re.style.top=`${K+$e.top}px`,Re.style.transform="translate(5px, -50%)"}else Re.style.display="none"}]}};k=new xn(ae,[D,le,y],q),wn.push(k),q.addEventListener("click",()=>{if(!k)return;let Q=k.cursor.idx;if(Q!=null){let _=D[Q],oe=null;if(U!==null?oe=null:oe=_,T(oe),t){let re=t.stats,K=o==="power"?re.powerCurve:re.hrCurve;if(K){let Pe=K[_];if(Pe){let de=Pe.idx,$e=_,Ce=t.points[de],We=t.points[de+$e-1];if(Ce&&We&&Ce.time!=null&&We.time!=null){let te=t.points[0].time||0,ge=(Ce.time-te)/1e3,L=(We.time-te)/1e3;w?.(t.id,[ge,L])}}}}}}),q.addEventListener("mouseleave",()=>{k&&k.redraw()});let pe=document.createElement("details");pe.classList.add("progress-details"),pe.style.marginTop="0px",pe.style.setProperty("--chart-color",c),pe.innerHTML=` + `),me.innerHTML=Ne,Ae&&Y===null){U=be;let{xFiltered:j,rawYFiltered:_e,smoothedYFiltered:we}=K(U,u),Ee=we.map(Me=>Me!==null?Me*.9:null),ke=we.map(Me=>Me!==null?Me*1.1:null);Ae.setData([j,_e,we,Ee,ke]);let ve=document.getElementById(`${o}-timeline-label`);ve&&(ve.textContent=`Progress ${Bt(be)} ${o==="power"?"Power":"HR"}`)}me.style.display="",me.style.left=`${ue+He.left}px`,me.style.top=`${te+He.top}px`,me.style.transform="translate(5px, -50%)"}else me.style.display="none"}]}};E=new Pn(oe,[N,ie,y],D),An.push(E),D.addEventListener("click",()=>{if(!E)return;let G=E.cursor.idx;if(G!=null){let F=N[G],ae=null;if(Y!==null?ae=null:ae=F,T(ae),t){let ue=t.stats,te=o==="power"?ue.powerCurve:ue.hrCurve;if(te){let Ie=te[F];if(Ie){let he=Ie.idx,He=F,Ce=t.points[he],Re=t.points[he+He-1];if(Ce&&Re&&Ce.time!=null&&Re.time!=null){let le=t.points[0].time||0,be=(Ce.time-le)/1e3,A=(Re.time-le)/1e3;M?.(t.id,[be,A])}}}}}}),D.addEventListener("mouseleave",()=>{E&&E.redraw()});let de=document.createElement("details");de.classList.add("progress-details"),de.style.marginTop="0px",de.style.setProperty("--chart-color",c),de.innerHTML=` chevron_right table_chart @@ -808,32 +808,32 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams( - ${z.map(Q=>{let _=Y[Q]?Y[Q].power||Y[Q].hr:"-",oe=J[Q]?.val||"-",re=J[Q]?.trackId,K=J[Q]?.idx;return` + ${q.map(G=>{let F=_[G]?_[G].power||_[G].hr:"-",ae=W[G]?.val||"-",ue=W[G]?.trackId,te=W[G]?.idx;return` - ${Ft(Q)} - ${_} ${u} + ${Bt(G)} + ${F} ${g} - ${oe} ${u} - ${re?``:""} + ${ae} ${g} + ${ue?``:""} `}).join("")} - `,M.appendChild(pe),pe.querySelectorAll(".evolution-select-btn").forEach(Q=>{Q.addEventListener("click",_=>{_.preventDefault(),_.stopPropagation();let oe=Q.getAttribute("data-id"),re=Q.getAttribute("data-idx"),K=Q.getAttribute("data-dur");oe&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:oe,idx:re?Number(re):null,dur:K?Number(K):null}}))})});let ye=null,He=h.querySelector(`#${o}-timeline-chart`);if(He){He.style.position="relative";let Q=document.createElement("div");if(Q.className="timeline-tooltip font-m",Q.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",He.appendChild(Q),a.length>0){let{xFiltered:_,rawYFiltered:oe,smoothedYFiltered:re}=ne(X,p),K=re.map(te=>te!==null?te*.9:null),Pe=re.map(te=>te!==null?te*1.1:null),de=[_,oe,re,K,Pe],$e=[{value:(te,ge)=>ge!=null?Zt(ge*1e3):"-"},{label:"Value",stroke:c,width:0,points:{show:!0,size:6,fill:tt(c,.5)}},{label:"Trend",stroke:c,width:2,points:{show:!1},spanGaps:!0,fill:"transparent",dash:[5,5]},{label:"Lower Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0},{label:"Upper Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0}],Ce=document.getElementById(`${o}-timeline-label`);Ce&&(Ce.textContent=`Progress ${Ft(X)} ${o==="power"?"Power":"HR"}`);let We={width:Math.max(100,(R||570)-400),height:250,padding:[0,10,0,10],tzDate:te=>xn.tzDate(new Date(te*1e3),"Etc/UTC"),cursor:{points:{show:!1},drag:{setScale:!1},x:!1,y:!1},scales:{x:{time:!0,range:te=>{let ge=te.data[0][0],L=te.data[0][te.data[0].length-1];return ge===void 0||L===void 0?[0,100]:ge===L?[ge-3600,L+3600]:[ge,L]}},y:{range:(te,ge,L)=>[ge*.9,L*1.1]}},series:$e,bands:[{series:[4,3],fill:tt(c,.2)}],hooks:{init:[te=>{te.over.addEventListener("click",()=>{if(ye!=null){let ge=se[ye];if(ge){let L=ge.stats,ee=o==="power"?L.powerCurve:L.hrCurve;if(ee){let Ne=ee[X];if(Ne){let V=Ne.idx,Ae=X,he=ge.points[V],xe=ge.points[V+Ae-1];if(he&&xe&&he.time!=null&&xe.time!=null){let Ee=ge.points[0].time||0,fe=(he.time-Ee)/1e3,be=(xe.time-Ee)/1e3;e.onTrackSelect?.(ge.id,[fe,be])}else e.onTrackSelect?.(ge.id,null)}else e.onTrackSelect?.(ge.id,null)}else e.onTrackSelect?.(ge.id,null)}}})}],draw:[te=>{let ge=te.cursor.idx;if(ge!=null&&te.data[0][ge]!=null){let L=te.data[1][ge];if(L!=null){let ee=te.valToPos(te.data[0][ge],"x",!0),Ne=te.valToPos(L,"y",!0),V=te.ctx,Ae=window.devicePixelRatio||1;V.save(),V.beginPath(),V.setLineDash([2*Ae,2*Ae]),V.strokeStyle=tt(c,.4),V.lineWidth=1*Ae,V.moveTo(ee,te.bbox.top),V.lineTo(ee,te.bbox.top+te.bbox.height),V.moveTo(te.bbox.left,Ne),V.lineTo(te.bbox.left+te.bbox.width,Ne),V.stroke(),V.restore(),V.save(),V.beginPath(),V.setLineDash([]),V.arc(ee,Ne,12*Ae,0,2*Math.PI),V.fillStyle=tt(c,.2),V.fill(),V.restore(),V.save(),V.beginPath(),V.arc(ee,Ne,6*Ae,0,2*Math.PI),V.fillStyle=c,V.fill(),V.strokeStyle="#fff",V.lineWidth=2*Ae,V.stroke(),V.restore(),V.save(),V.setLineDash([]);let he=new Date(te.data[0][ge]*1e3),xe=`${he.getUTCFullYear()}-${String(he.getUTCMonth()+1).padStart(2,"0")}-${String(he.getUTCDate()).padStart(2,"0")}`;V.font=`bold ${10*Ae}px system-ui, sans-serif`;let fe=V.measureText(xe).width+10*Ae,be=16*Ae,Ue=ee-fe/2,je=Math.max(te.bbox.left,Math.min(te.bbox.left+te.bbox.width-fe,Ue)),dt=te.bbox.top+te.bbox.height+2*Ae;V.fillStyle="rgba(14, 14, 16, 0.92)",V.beginPath(),V.roundRect?V.roundRect(je,dt,fe,be,3*Ae):V.rect(je,dt,fe,be),V.fill(),V.strokeStyle=tt(c,.27),V.lineWidth=1*Ae,V.stroke(),V.fillStyle=c,V.textAlign="center",V.textBaseline="middle",V.fillText(xe,je+fe/2,dt+be/2);let It=`${L.toFixed(0)} ${u}`,Xt=V.measureText(It).width+10*Ae,Ot=te.bbox.left-Xt-2*Ae,pn=Ne-be/2;V.fillStyle="rgba(14, 14, 16, 0.92)",V.beginPath(),V.roundRect?V.roundRect(Ot,pn,Xt,be,3*Ae):V.rect(Ot,pn,Xt,be),V.fill(),V.strokeStyle=tt(c,.27),V.lineWidth=1*Ae,V.stroke(),V.fillStyle=c,V.textAlign="left",V.textBaseline="middle",V.fillText(It,Ot+5*Ae,pn+be/2),V.restore()}}}],setCursor:[te=>{if(!te._ready)return;te.redraw(!1);let ge=te.cursor.idx,L=te.cursor.left,ee=te.cursor.top,Ne=te.bbox;if(L!=null&&ee!=null&&L>=0&&ee>=0){let V=1/0,Ae=-1,he=30,xe=he*he,Ee=te.data[0],fe=te.data[1];for(let be=0;be{G.addEventListener("click",F=>{F.preventDefault(),F.stopPropagation();let ae=G.getAttribute("data-id"),ue=G.getAttribute("data-idx"),te=G.getAttribute("data-dur");ae&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:ae,idx:ue?Number(ue):null,dur:te?Number(te):null}}))})});let xe=null,Pe=x.querySelector(`#${o}-timeline-chart`);if(Pe){Pe.style.position="relative";let G=document.createElement("div");if(G.className="timeline-tooltip font-m",G.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",Pe.appendChild(G),r.length>0){let{xFiltered:F,rawYFiltered:ae,smoothedYFiltered:ue}=K(U,u),te=ue.map(le=>le!==null?le*.9:null),Ie=ue.map(le=>le!==null?le*1.1:null),he=[F,ae,ue,te,Ie],He=[{value:(le,be)=>be!=null?Gt(be*1e3):"-"},{label:"Value",stroke:c,width:0,points:{show:!0,size:6,fill:tt(c,.5)}},{label:"Trend",stroke:c,width:2,points:{show:!1},spanGaps:!0,fill:"transparent",dash:[5,5]},{label:"Lower Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0},{label:"Upper Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0}],Ce=document.getElementById(`${o}-timeline-label`);Ce&&(Ce.textContent=`Progress ${Bt(U)} ${o==="power"?"Power":"HR"}`);let Re={width:Math.max(100,(O||570)-400),height:250,padding:[0,10,0,10],tzDate:le=>Pn.tzDate(new Date(le*1e3),"Etc/UTC"),cursor:{points:{show:!1},drag:{setScale:!1},x:!1,y:!1},scales:{x:{time:!0,range:le=>{let be=le.data[0][0],A=le.data[0][le.data[0].length-1];return be===void 0||A===void 0?[0,100]:be===A?[be-3600,A+3600]:[be,A]}},y:{range:(le,be,A)=>[be*.9,A*1.1]}},series:He,bands:[{series:[4,3],fill:tt(c,.2)}],hooks:{init:[le=>{le.over.addEventListener("click",()=>{if(xe!=null){let be=Q[xe];if(be){let A=be.stats,ne=o==="power"?A.powerCurve:A.hrCurve;if(ne){let Ne=ne[U];if(Ne){let j=Ne.idx,_e=U,we=be.points[j],Ee=be.points[j+_e-1];if(we&&Ee&&we.time!=null&&Ee.time!=null){let ke=be.points[0].time||0,ve=(we.time-ke)/1e3,Me=(Ee.time-ke)/1e3;e.onTrackSelect?.(be.id,[ve,Me])}else e.onTrackSelect?.(be.id,null)}else e.onTrackSelect?.(be.id,null)}else e.onTrackSelect?.(be.id,null)}}})}],draw:[le=>{let be=le.cursor.idx;if(be!=null&&le.data[0][be]!=null){let A=le.data[1][be];if(A!=null){let ne=le.valToPos(le.data[0][be],"x",!0),Ne=le.valToPos(A,"y",!0),j=le.ctx,_e=window.devicePixelRatio||1;j.save(),j.beginPath(),j.setLineDash([2*_e,2*_e]),j.strokeStyle=tt(c,.4),j.lineWidth=1*_e,j.moveTo(ne,le.bbox.top),j.lineTo(ne,le.bbox.top+le.bbox.height),j.moveTo(le.bbox.left,Ne),j.lineTo(le.bbox.left+le.bbox.width,Ne),j.stroke(),j.restore(),j.save(),j.beginPath(),j.setLineDash([]),j.arc(ne,Ne,12*_e,0,2*Math.PI),j.fillStyle=tt(c,.2),j.fill(),j.restore(),j.save(),j.beginPath(),j.arc(ne,Ne,6*_e,0,2*Math.PI),j.fillStyle=c,j.fill(),j.strokeStyle="#fff",j.lineWidth=2*_e,j.stroke(),j.restore(),j.save(),j.setLineDash([]);let we=new Date(le.data[0][be]*1e3),Ee=`${we.getUTCFullYear()}-${String(we.getUTCMonth()+1).padStart(2,"0")}-${String(we.getUTCDate()).padStart(2,"0")}`;j.font=`bold ${10*_e}px system-ui, sans-serif`;let ve=j.measureText(Ee).width+10*_e,Me=16*_e,Ue=ne-ve/2,je=Math.max(le.bbox.left,Math.min(le.bbox.left+le.bbox.width-ve,Ue)),dt=le.bbox.top+le.bbox.height+2*_e;j.fillStyle="rgba(14, 14, 16, 0.92)",j.beginPath(),j.roundRect?j.roundRect(je,dt,ve,Me,3*_e):j.rect(je,dt,ve,Me),j.fill(),j.strokeStyle=tt(c,.27),j.lineWidth=1*_e,j.stroke(),j.fillStyle=c,j.textAlign="center",j.textBaseline="middle",j.fillText(Ee,je+ve/2,dt+Me/2);let At=`${A.toFixed(0)} ${g}`,Qt=j.measureText(At).width+10*_e,Yt=le.bbox.left-Qt-2*_e,wn=Ne-Me/2;j.fillStyle="rgba(14, 14, 16, 0.92)",j.beginPath(),j.roundRect?j.roundRect(Yt,wn,Qt,Me,3*_e):j.rect(Yt,wn,Qt,Me),j.fill(),j.strokeStyle=tt(c,.27),j.lineWidth=1*_e,j.stroke(),j.fillStyle=c,j.textAlign="left",j.textBaseline="middle",j.fillText(At,Yt+5*_e,wn+Me/2),j.restore()}}}],setCursor:[le=>{if(!le._ready)return;le.redraw(!1);let be=le.cursor.idx,A=le.cursor.left,ne=le.cursor.top,Ne=le.bbox;if(A!=null&&ne!=null&&A>=0&&ne>=0){let j=1/0,_e=-1,we=30,Ee=we*we,ke=le.data[0],ve=le.data[1];for(let Me=0;Me Date: - ${Ee} + ${ke}
Value: - ${be} + ${Me}
- `,Q.style.display="block",Q.style.left=`${L+Ne.left}px`,Q.style.top=`${ee+Ne.top}px`,Q.style.transform="translate(5px, -50%)"}else Q.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(te,ge)=>ge.map(L=>{let ee=new Date(L*1e3);return`${ee.getUTCFullYear()}-${String(ee.getUTCMonth()+1).padStart(2,"0")}`})},{stroke:"#555564",grid:{stroke:"#2e2e34"},font:"10px system-ui, sans-serif",values:(te,ge)=>ge.map(L=>`${L} ${u}`),show:!0,space:15,size:50}]};Le=new xn(We,de,He),wn.push(Le),He.addEventListener("mouseleave",()=>{Le.redraw()})}else He.innerHTML='
No data for the past year
'}})(),{updatePin:ae=>{U=ae,ae!==null&&(X=ae);let pe=document.getElementById(`${o}-timeline-label`);if(pe&&(pe.textContent=`Progress ${Ft(X)} ${o==="power"?"Power":"HR"}${U!==null?" (Pinned)":""}`),Le){let{xFiltered:ye,rawYFiltered:He,smoothedYFiltered:Q}=ne(X,p),_=Q.map(re=>re!==null?re*.9:null),oe=Q.map(re=>re!==null?re*1.1:null);Le.setData([ye,He,Q,_,oe])}k&&k.redraw()},updateRange:ae=>{if(p=ae,Le){let{xFiltered:pe,rawYFiltered:ye,smoothedYFiltered:He}=ne(X,p),Q=He.map(oe=>oe!==null?oe*.9:null),_=He.map(oe=>oe!==null?oe*1.1:null);Le.setData([pe,ye,He,Q,_])}}}}function ml(e){let s=new Date(e),t=s.getUTCDay(),n=s.getUTCDate()-t+(t===0?-6:1);return s.setUTCDate(n),s.setUTCHours(0,0,0,0),s}function Ol(e){let s={};return e.forEach(t=>{if(!t.stats.startTime||!t.stats.totalDist)return;let n=new Date(t.stats.startTime),o=ml(n),r=o.toISOString().split("T")[0];s[r]||(s[r]={timestamp:o.getTime(),distance:0}),s[r].distance+=t.stats.totalDist}),Object.entries(s).map(([t,n])=>({week:t,timestamp:n.timestamp,distance:n.distance})).sort((t,n)=>t.timestamp-n.timestamp)}function Yl(e){let s={};return e.forEach(t=>{if(!t.stats.startTime||t.stats.elevGain===void 0)return;let n=new Date(t.stats.startTime),o=ml(n),r=o.toISOString().split("T")[0];s[r]||(s[r]={timestamp:o.getTime(),elevation:0}),s[r].elevation+=t.stats.elevGain}),Object.entries(s).map(([t,n])=>({week:t,timestamp:n.timestamp,elevation:n.elevation})).sort((t,n)=>t.timestamp-n.timestamp)}function cl(e,s,t,n,o,r){let u=t==="distance",c=u?Ol(s):Yl(s),m=il(s,B=>u?B.stats.totalDist:B.stats.elevGain),T=u?De.distance.color:De.elevation.color,b=u?"km":"m",w=u?De.distance.icon:De.elevation.icon,R=document.createElement("div");R.className=`chart-row ${t}-progress-card`,R.id=`${t}-evolution-card`,R.innerHTML=` + `,G.style.display="block",G.style.left=`${A+Ne.left}px`,G.style.top=`${ne+Ne.top}px`,G.style.transform="translate(5px, -50%)"}else G.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(le,be)=>be.map(A=>{let ne=new Date(A*1e3);return`${ne.getUTCFullYear()}-${String(ne.getUTCMonth()+1).padStart(2,"0")}`})},{stroke:"#555564",grid:{stroke:"#2e2e34"},font:"10px system-ui, sans-serif",values:(le,be)=>be.map(A=>`${A} ${g}`),show:!0,space:15,size:50}]};Ae=new Pn(Re,he,Pe),An.push(Ae),Pe.addEventListener("mouseleave",()=>{Ae.redraw()})}else Pe.innerHTML='
No data for the past year
'}})(),{updatePin:oe=>{Y=oe,oe!==null&&(U=oe);let de=document.getElementById(`${o}-timeline-label`);if(de&&(de.textContent=`Progress ${Bt(U)} ${o==="power"?"Power":"HR"}${Y!==null?" (Pinned)":""}`),Ae){let{xFiltered:xe,rawYFiltered:Pe,smoothedYFiltered:G}=K(U,u),F=G.map(ue=>ue!==null?ue*.9:null),ae=G.map(ue=>ue!==null?ue*1.1:null);Ae.setData([xe,Pe,G,F,ae])}E&&E.redraw()},updateRange:oe=>{if(u=oe,Ae){let{xFiltered:de,rawYFiltered:xe,smoothedYFiltered:Pe}=K(U,u),G=Pe.map(ae=>ae!==null?ae*.9:null),F=Pe.map(ae=>ae!==null?ae*1.1:null);Ae.setData([de,xe,Pe,G,F])}}}}function so(e){let n=new Date(e),t=n.getUTCDay(),s=n.getUTCDate()-t+(t===0?-6:1);return n.setUTCDate(s),n.setUTCHours(0,0,0,0),n}function Xo(e){let n={};return e.forEach(t=>{if(!t.stats.startTime||!t.stats.totalDist)return;let s=new Date(t.stats.startTime),o=so(s),a=o.toISOString().split("T")[0];n[a]||(n[a]={timestamp:o.getTime(),distance:0}),n[a].distance+=t.stats.totalDist}),Object.entries(n).map(([t,s])=>({week:t,timestamp:s.timestamp,distance:s.distance})).sort((t,s)=>t.timestamp-s.timestamp)}function Jo(e){let n={};return e.forEach(t=>{if(!t.stats.startTime||t.stats.elevGain===void 0)return;let s=new Date(t.stats.startTime),o=so(s),a=o.toISOString().split("T")[0];n[a]||(n[a]={timestamp:o.getTime(),elevation:0}),n[a].elevation+=t.stats.elevGain}),Object.entries(n).map(([t,s])=>({week:t,timestamp:s.timestamp,elevation:s.elevation})).sort((t,s)=>t.timestamp-s.timestamp)}function eo(e,n,t,s,o,a){let g=t==="distance",c=g?Xo(n):Jo(n),m=jl(n,C=>g?C.stats.totalDist:C.stats.elevGain),T=g?We.distance.color:We.elevation.color,f=g?"km":"m",M=g?We.distance.icon:We.elevation.icon,O=document.createElement("div");O.className=`chart-row ${t}-progress-card`,O.id=`${t}-evolution-card`,O.innerHTML=`
- ${w} - ${u?"Distance Progress":"Elevation Progress"} + ${M} + ${g?"Distance Progress":"Elevation Progress"}
@@ -842,18 +842,18 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
- ${al(m,u,b)} + ${Zl(m,g,f)}
- `,e.appendChild(R);let S=R.querySelector(`#${t}-weekly-chart`),k=R.querySelector(`#${t}-y-axis-chart`);if(!S||!k)return;S.style.position="relative";let M=document.createElement("div");M.className="cur-y-val",M.style.cssText=`color:${T};display:none`,S.appendChild(M);let g=c.map(B=>B.timestamp/1e3),I=u?c.map(B=>B.distance/1e3):c.map(B=>B.elevation);if(g.length===0)return;let P=fn(I,2),p=Math.max(0,(r||570)-20-320-20),h=Math.max(p,g.length*40),F=Math.max(...I)*1.1,q={width:h,height:150,padding:[10,10,0,10],tzDate:B=>xn.tzDate(new Date(B*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,F]}},series:[{},{label:u?"Distance":"Elevation",stroke:T,fill:tt(T,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:T,width:2,dash:[5,5],points:{show:!1}}],cursor:{sync:n?{key:n.key}:void 0,drag:{x:!1,y:!1},points:{show:!1},x:!1,y:!1},hooks:{init:[B=>{B.over.addEventListener("click",()=>{let z=B.cursor.idx;if(z!=null){let D=c[z];if(D){let le=new Date(D.timestamp),y=new Date(D.timestamp+7*24*60*60*1e3),d=le.toISOString().split("T")[0],a=y.toISOString().split("T")[0];o?.(d,a)}}})}],setCursor:[B=>{if(!B._ready)return;let z=B.cursor.idx,D=B.cursor.left,le=B.cursor.top;if(z!=null&&D!=null&&le!=null&&D>=0&&le>=0){let y=B.data[1][z],d=y!=null?u?`${y.toFixed(1)} km`:`${y.toFixed(0)} m`:"\u2014";M.innerHTML=d,M.style.display="block",M.style.left=`${B.valToPos(B.data[0][z],"x",!1)}px`,M.style.top=`${B.valToPos(B.data[1][z],"y",!1)}px`,M.style.transform="translate(6px, -50%)"}else M.style.display="none";B.redraw(!1)}],draw:[B=>{let z=B.cursor.idx;if(z!=null&&B.data[0][z]!=null){let D=B.valToPos(B.data[0][z],"x",!0),le=B.valToPos(B.data[1][z],"y",!0),y=window.devicePixelRatio||1,d=B.ctx,a=B.bbox;d.save(),d.beginPath(),d.setLineDash([2*y,2*y]),d.strokeStyle=tt(T,.4),d.lineWidth=1*y,d.moveTo(D,a.top),d.lineTo(D,a.top+a.height),d.moveTo(a.left,le),d.lineTo(a.left+a.width,le),d.stroke(),d.restore(),d.save(),d.beginPath(),d.setLineDash([]),d.arc(D,le,12*y,0,2*Math.PI),d.fillStyle=tt(T,.2),d.fill(),d.restore(),d.save(),d.beginPath(),d.arc(D,le,6*y,0,2*Math.PI),d.fillStyle=T,d.fill(),d.strokeStyle="#fff",d.lineWidth=2*y,d.stroke(),d.restore(),d.save(),d.setLineDash([]);let G=new Date(B.data[0][z]*1e3),X=`${G.getUTCFullYear()}-${String(G.getUTCMonth()+1).padStart(2,"0")}-${String(G.getUTCDate()).padStart(2,"0")}`;d.font=`bold ${10*y}px system-ui, sans-serif`;let U=d.measureText(X).width+10*y,ne=16*y,Le=D-U/2,Re=Math.max(a.left,Math.min(a.left+a.width-U,Le)),Be=a.top+a.height+2*y;d.fillStyle="rgba(14, 14, 16, 0.92)",d.beginPath(),d.roundRect?d.roundRect(Re,Be,U,ne,3*y):d.rect(Re,Be,U,ne),d.fill(),d.strokeStyle=tt(T,.27),d.lineWidth=1*y,d.stroke(),d.fillStyle=T,d.textAlign="center",d.textBaseline="middle",d.fillText(X,Re+U/2,Be+ne/2),d.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(B,z)=>z.map(D=>{let le=new Date(D*1e3);return`${le.getUTCMonth()+1}/${le.getUTCDate()}`}),font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:(B,z)=>z.map(D=>`${D.toFixed(0)} ${b}`),font:"10px system-ui, sans-serif",size:40}]},J=new xn(q,[g,I,P],S);wn.push(J);let Y=R.querySelector(".chart-scroll-container");return Y&&g.length*40>h&&(Y.scrollLeft=Y.scrollWidth-Y.clientWidth),{updateRange:B=>{let z=c[c.length-1]?.timestamp||17855424e5,D=0;B==="1m"?D=z-30*24*3600*1e3:B==="2m"?D=z-60*24*3600*1e3:B==="6m"?D=z-180*24*3600*1e3:B==="1y"?D=z-365*24*3600*1e3:B==="2y"&&(D=z-2*365*24*3600*1e3);let le=c.filter(se=>se.timestamp>=D),y=le.map(se=>se.timestamp/1e3),d=u?le.map(se=>se.distance/1e3):le.map(se=>se.elevation),a=fn(d,2),G=Math.max(S.clientWidth,y.length*40),X=Math.max(...d)*1.1;J.setSize({width:G,height:150}),J.setScale("y",{min:0,max:X}),J.setData([y,d,a]),Y&&(Y.scrollLeft=Y.scrollWidth-Y.clientWidth)}}}var ss=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],jl=16,ze={},Tt=[];function Zl(e,s){let t=new Date(e),n=new Date(s);return t.getUTCFullYear()===n.getUTCFullYear()&&t.getUTCMonth()===n.getUTCMonth()&&t.getUTCDate()===n.getUTCDate()}var Sn=!1,Oe=null,Dn=0,Bn=!1,Mn=null,ln="",sn=!1,dn="date-desc",Te={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};function cn(e=!1){Ye.patch({f_date:Te.date.every(s=>s===null)?null:Te.date,f_dist:Te.dist.every(s=>s===null)?null:Te.dist,f_dur:Te.dur.every(s=>s===null)?null:Te.dur,f_mets:Te.metrics.size===0?null:Array.from(Te.metrics),f_tags:Te.tags.length===0?null:Te.tags},e)}function ys(){let e=Me.getActiveMetrics(),s=Me.METRICS,t=Array.from(e).map(n=>s[n].abbr);Ye.patch({metrics:t.length?t:null})}var gl=[{label:"Newest first",val:"date-desc",icon:"calendar_today"},{label:"Oldest first",val:"date-asc",icon:"history"},{label:"Longest distance",val:"dist-desc",icon:"straighten"},{label:"Shortest distance",val:"dist-asc",icon:"horizontal_rule"},{label:"Longest duration",val:"dur-desc",icon:"timer"},{label:"Shortest duration",val:"dur-asc",icon:"timer_off"}];function Gl(e){document.querySelectorAll(".sort-menu-popup").forEach(o=>o.remove());let s=document.createElement("div");s.className="sort-menu-popup",gl.forEach(o=>{let r=document.createElement("div");r.className=`menu-item ${dn===o.val?"active":""}`,r.innerHTML=` + `,e.appendChild(O);let H=O.querySelector(`#${t}-weekly-chart`),E=O.querySelector(`#${t}-y-axis-chart`);if(!H||!E)return;H.style.position="relative";let k=document.createElement("div");k.className="cur-y-val",k.style.cssText=`color:${T};display:none`,H.appendChild(k);let p=c.map(C=>C.timestamp/1e3),P=g?c.map(C=>C.distance/1e3):c.map(C=>C.elevation);if(p.length===0)return;let b=En(P,2),u=Math.max(0,(a||570)-20-320-20),x=Math.max(u,p.length*40),w=Math.max(...P)*1.1,D={width:x,height:150,padding:[10,10,0,10],tzDate:C=>Pn.tzDate(new Date(C*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,w]}},series:[{},{label:g?"Distance":"Elevation",stroke:T,fill:tt(T,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:T,width:2,dash:[5,5],points:{show:!1}}],cursor:{sync:s?{key:s.key}:void 0,drag:{x:!1,y:!1},points:{show:!1},x:!1,y:!1},hooks:{init:[C=>{C.over.addEventListener("click",()=>{let q=C.cursor.idx;if(q!=null){let N=c[q];if(N){let ie=new Date(N.timestamp),y=new Date(N.timestamp+7*24*60*60*1e3),d=ie.toISOString().split("T")[0],r=y.toISOString().split("T")[0];o?.(d,r)}}})}],setCursor:[C=>{if(!C._ready)return;let q=C.cursor.idx,N=C.cursor.left,ie=C.cursor.top;if(q!=null&&N!=null&&ie!=null&&N>=0&&ie>=0){let y=C.data[1][q],d=y!=null?g?`${y.toFixed(1)} km`:`${y.toFixed(0)} m`:"\u2014";k.innerHTML=d,k.style.display="block",k.style.left=`${C.valToPos(C.data[0][q],"x",!1)}px`,k.style.top=`${C.valToPos(C.data[1][q],"y",!1)}px`,k.style.transform="translate(6px, -50%)"}else k.style.display="none";C.redraw(!1)}],draw:[C=>{let q=C.cursor.idx;if(q!=null&&C.data[0][q]!=null){let N=C.valToPos(C.data[0][q],"x",!0),ie=C.valToPos(C.data[1][q],"y",!0),y=window.devicePixelRatio||1,d=C.ctx,r=C.bbox;d.save(),d.beginPath(),d.setLineDash([2*y,2*y]),d.strokeStyle=tt(T,.4),d.lineWidth=1*y,d.moveTo(N,r.top),d.lineTo(N,r.top+r.height),d.moveTo(r.left,ie),d.lineTo(r.left+r.width,ie),d.stroke(),d.restore(),d.save(),d.beginPath(),d.setLineDash([]),d.arc(N,ie,12*y,0,2*Math.PI),d.fillStyle=tt(T,.2),d.fill(),d.restore(),d.save(),d.beginPath(),d.arc(N,ie,6*y,0,2*Math.PI),d.fillStyle=T,d.fill(),d.strokeStyle="#fff",d.lineWidth=2*y,d.stroke(),d.restore(),d.save(),d.setLineDash([]);let J=new Date(C.data[0][q]*1e3),U=`${J.getUTCFullYear()}-${String(J.getUTCMonth()+1).padStart(2,"0")}-${String(J.getUTCDate()).padStart(2,"0")}`;d.font=`bold ${10*y}px system-ui, sans-serif`;let Y=d.measureText(U).width+10*y,K=16*y,Ae=N-Y/2,me=Math.max(r.left,Math.min(r.left+r.width-Y,Ae)),Fe=r.top+r.height+2*y;d.fillStyle="rgba(14, 14, 16, 0.92)",d.beginPath(),d.roundRect?d.roundRect(me,Fe,Y,K,3*y):d.rect(me,Fe,Y,K),d.fill(),d.strokeStyle=tt(T,.27),d.lineWidth=1*y,d.stroke(),d.fillStyle=T,d.textAlign="center",d.textBaseline="middle",d.fillText(U,me+Y/2,Fe+K/2),d.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(C,q)=>q.map(N=>{let ie=new Date(N*1e3);return`${ie.getUTCMonth()+1}/${ie.getUTCDate()}`}),font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:(C,q)=>q.map(N=>`${N.toFixed(0)} ${f}`),font:"10px system-ui, sans-serif",size:40}]},W=new Pn(D,[p,P,b],H);An.push(W);let _=O.querySelector(".chart-scroll-container");return _&&p.length*40>x&&(_.scrollLeft=_.scrollWidth-_.clientWidth),{updateRange:C=>{let q=c[c.length-1]?.timestamp||17855424e5,N=0;C==="1m"?N=q-30*24*3600*1e3:C==="2m"?N=q-60*24*3600*1e3:C==="6m"?N=q-180*24*3600*1e3:C==="1y"?N=q-365*24*3600*1e3:C==="2y"&&(N=q-2*365*24*3600*1e3);let ie=c.filter(Q=>Q.timestamp>=N),y=ie.map(Q=>Q.timestamp/1e3),d=g?ie.map(Q=>Q.distance/1e3):ie.map(Q=>Q.elevation),r=En(d,2),J=Math.max(H.clientWidth,y.length*40),U=Math.max(...d)*1.1;W.setSize({width:J,height:150}),W.setScale("y",{min:0,max:U}),W.setData([y,d,r]),_&&(_.scrollLeft=_.scrollWidth-_.clientWidth)}}}var Jn=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],Qo=16,ze={},Tt=[];function Ko(e,n){let t=new Date(e),s=new Date(n);return t.getUTCFullYear()===s.getUTCFullYear()&&t.getUTCMonth()===s.getUTCMonth()&&t.getUTCDate()===s.getUTCDate()}var Fn=!1,Oe=null,Qn=0,Gn=!1,_n=null,mn="",un=!1,vn="date-desc",Le={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};function bn(e=!1){Ye.patch({f_date:Le.date.every(n=>n===null)?null:Le.date,f_dist:Le.dist.every(n=>n===null)?null:Le.dist,f_dur:Le.dur.every(n=>n===null)?null:Le.dur,f_mets:Le.metrics.size===0?null:Array.from(Le.metrics),f_tags:Le.tags.length===0?null:Le.tags},e)}function Zs(){let e=Se.getActiveMetrics(),n=Se.METRICS,t=Array.from(e).map(s=>n[s].abbr);Ye.patch({metrics:t.length?t:null})}var io=[{label:"Newest first",val:"date-desc",icon:"calendar_today"},{label:"Oldest first",val:"date-asc",icon:"history"},{label:"Longest distance",val:"dist-desc",icon:"straighten"},{label:"Shortest distance",val:"dist-asc",icon:"horizontal_rule"},{label:"Longest duration",val:"dur-desc",icon:"timer"},{label:"Shortest duration",val:"dur-asc",icon:"timer_off"}];function ei(e){document.querySelectorAll(".sort-menu-popup").forEach(o=>o.remove());let n=document.createElement("div");n.className="sort-menu-popup",io.forEach(o=>{let a=document.createElement("div");a.className=`menu-item ${vn===o.val?"active":""}`,a.innerHTML=` ${o.icon} ${o.label} - ${dn===o.val?"check":""} - `,r.addEventListener("click",()=>{dn=o.val,Ye.patch({sort:o.val}),bl(),mn(),s.remove()}),s.appendChild(r)});let t=e.getBoundingClientRect();s.style.top=`${t.bottom+5}px`,s.style.left=`${t.left}px`,document.body.appendChild(s);let n=o=>{!s.contains(o.target)&&!e.contains(o.target)&&(s.remove(),document.removeEventListener("click",n))};setTimeout(()=>document.addEventListener("click",n),0)}function Xl(e){document.querySelectorAll(".metric-menu-popup").forEach(c=>c.remove());let s=document.createElement("div");s.className="metric-menu-popup";let t=Me.METRICS,n=Me.getAvailableMetrics(),o=Me.getActiveMetrics();Object.entries(t).forEach(([c,m])=>{if(!n.has(c))return;let T=document.createElement("div");T.className=`menu-item ${o.has(c)?"active":""}`,T.innerHTML=` + ${vn===o.val?"check":""} + `,a.addEventListener("click",()=>{vn=o.val,Ye.patch({sort:o.val}),ro(),xn(),n.remove()}),n.appendChild(a)});let t=e.getBoundingClientRect();n.style.top=`${t.bottom+5}px`,n.style.left=`${t.left}px`,document.body.appendChild(n);let s=o=>{!n.contains(o.target)&&!e.contains(o.target)&&(n.remove(),document.removeEventListener("click",s))};setTimeout(()=>document.addEventListener("click",s),0)}function ti(e){document.querySelectorAll(".metric-menu-popup").forEach(c=>c.remove());let n=document.createElement("div");n.className="metric-menu-popup";let t=Se.METRICS,s=Se.getAvailableMetrics(),o=Se.getActiveMetrics();Object.entries(t).forEach(([c,m])=>{if(!s.has(c))return;let T=document.createElement("div");T.className=`menu-item ${o.has(c)?"active":""}`,T.innerHTML=` ${m.icon} ${m.label} ${o.has(c)?"check":""} - `,T.addEventListener("click",()=>{Me.toggleMetric(c);let b=Me.getActiveMetrics().has(c);T.classList.toggle("active",b),T.querySelector(".check").textContent=b?"check":"";let w=document.querySelector(`#metric-pills .metric-pill[data-metric="${c}"]`);w&&w.classList.toggle("active",b),kn(),ys()}),s.appendChild(T)});let r=e.getBoundingClientRect();s.style.top=`${r.bottom+5}px`,s.style.right=`${window.innerWidth-r.right}px`,document.body.appendChild(s);let u=c=>{!s.contains(c.target)&&!e.contains(c.target)&&(s.remove(),document.removeEventListener("click",u))};setTimeout(()=>document.addEventListener("click",u),0)}document.addEventListener("select-track",e=>{let s=e.detail.id,t=e.detail.idx,n=e.detail.dur;if(s&&ze[s]&&(Mt(s),t!=null&&n!=null)){let o=ze[s],r=o.points;if(t>=0&&tS.time!=null)?.time||0,m=(u.time-c)/1e3,T=m+n;Me.restoreSelection(m,T);let b=r.findIndex(S=>(S.time||0)>=u.time+n*1e3);b===-1&&(b=r.length-1);let w=r.slice(t,b+1),R=it.computeStats(w);Me.setSelectionStats(R),Bt(o),_e.highlightSegment(s,r,t,b,!1,Mn),_e.ensureVisible(w.map(S=>[S.lat,S.lon])),Ye.patch({sel:[m,T]})}}}});document.addEventListener("click",e=>{let s=e.target.closest(".tab-btn");if(!s)return;let t=s.closest("#tab-nav");if(!t)return;t.querySelectorAll(".tab-btn").forEach(r=>r.classList.toggle("active",r===s));let n=s.dataset.tab;Ye.patch({tab:n},!0);let o=t.closest("#chart-panel");if(o&&o.querySelectorAll(".tab-content").forEach(r=>{r.classList.toggle("active",r.id===`tab-${s.dataset.tab}`)}),s.dataset.tab==="details"&&Oe&&ze[Oe]&&on(ze[Oe],ws()),s.dataset.tab==="insights"&&Oe&&ze[Oe]&&Bt(ze[Oe]),s.dataset.tab==="evolution"&&Tn(Oe?ze[Oe]:null,Object.values(ze),(r,u)=>{Mt(r,!0),u&&(Me.restoreSelection(u[0],u[1]),un(u[0],u[1],"time",!0))},(r,u)=>{Te.date=[r,u],kt(),cn(!0),Fn()}),s.dataset.tab==="combined"&&Oe&&ze[Oe]&&rn(ze[Oe]),s.dataset.tab==="courses"&&Dt(),s.dataset.tab==="graphs"){Me.resize(),kn();let r=Ye.get().sel;r&&Me.restoreSelection(r[0],r[1])}});async function xs(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await at.clear(),ze={},Tt=[],Oe=null,Dn=0,Mn=null,Sn=!1,Bn=!1,ln="",sn=!1,dn="date-desc",Te.date=[null,null],Te.dist=[null,null],Te.dur=[null,null],Te.metrics.clear(),Te.tags=[],it.setHRZones([120,140,160,180]),it.setFTP(200),Gs(),nl(),Os(),ol(),ul(),_e.removeAllTracks&&_e.removeAllTracks(),_e.clearTracks&&_e.clearTracks(),_e.clearHighlight(),Me.resetState?Me.resetState():Me.clear&&Me.clear(),document.querySelectorAll(".tab-btn").forEach(s=>{s.classList.toggle("active",s.dataset.tab==="graphs")}),document.querySelectorAll(".tab-content").forEach(s=>{s.classList.toggle("active",s.id==="tab-graphs")}),Ye.reset();let e=document.getElementById("toast-container");e&&(e.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(s=>s.remove()),typeof mn=="function"&&mn()}async function Jl(){let e=null,s=new Promise(g=>{e=window.setTimeout(g,1e3)});try{let g=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([g,s])}finally{e!==null&&window.clearTimeout(e)}document.body.classList.remove("loading-fonts");let t=document.getElementById("storage-backend-select");t&&(t.value=Ye.get().storage||"memory",t.addEventListener("change",g=>{let I=g.target.value,P=new URLSearchParams(window.location.search);I==="memory"?P.delete("storage"):P.set("storage",I),window.location.search=P.toString()}));let n=document.getElementById("global-loader"),o=document.getElementById("loader-text"),r=document.getElementById("loader-subtext"),u=document.getElementById("loader-progress-bar"),c=document.getElementById("map-loader"),m=c?.querySelector("span");c&&(m&&(m.textContent="Loading database..."),c.classList.remove("hidden"));let T=Ye.get();tl((g,I)=>ls(g,I==="error"?"error":"info")),Vs(()=>{kt(),cn()},g=>{io(g)}),Zs((g,I)=>ls(g,I==="error"?"error":"info")),_e.init(g=>Mt(g),to,no,(g,I)=>{g===Oe?Me.setHoverAt(I):Me.setHoverAt(null)},so),Me.init(lo,un,oo,g=>{Ye.patch({sel_point:g})}),Me.setMapColorChangeCb(g=>{g?(Mn=g.colors,Oe&&_e.colorTrackByMetric(Oe,g.pts,g.colors)):(Mn=null,Oe&&_e.clearMetricColor(Oe));let I=Ye.get();I.sel&&un(I.sel[0],I.sel[1],Me.getXAxis())}),fl(T),await at.openDB(),await xs();try{let g=await at.get("hr_zones");g&&it.setHRZones(g);let I=await at.get("ftp");I&&it.setFTP(I);let P=await at.getAll();P.sort((J,Y)=>J.addedAt-Y.addedAt),m&&(m.textContent=`Preparing ${P.length} tracks...`);let p=[];for(let J of P){let Y=!1;if(!J.bounds&&J.points.length>0){let B=ms(J.points);B&&(J.bounds=B,Y=!0)}!J.simplifiedPoints&&J.points.length>0&&(J.simplifiedPoints=ps(J.points,50),Y=!0),Y&&await at.save(J),ze[J.id]=J,p.push(J)}_e.addTracks(p),kt();let h=T.track&&P.find(J=>J.id===T.track)?T.track:P.length>0?P[0].id:null,F=document.getElementById("map-loader"),q=P.find(J=>J.id===h);if(q&&(await pl(q),Mt(q.id,!T.map_pos),T.sel&&Array.isArray(T.sel)&&T.sel.length===2&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Me.restoreSelection(T.sel[0],T.sel[1])})}),T.sel_point!==void 0&&T.sel_point!==null&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Me.setCursorAt(T.sel_point)})})),F&&F.classList.add("hidden"),P.length>(q?1:0)){F&&(m&&(m.textContent="Loading tracks..."),F.classList.remove("hidden"));let J=P.filter(z=>z.id!==h),Y=0,B=async()=>{let D=Math.min(Y+2,J.length);for(;Y{Mt(le,!0),y&&(Me.restoreSelection(y[0],y[1]),un(y[0],y[1],"time",!0))}),P.length&&!T.map_pos&&_e.fitAll())};requestAnimationFrame(B)}else kt(),P.length&&!T.map_pos&&_e.fitAll()}catch(g){console.warn("Could not load saved tracks:",g)}Kl(),eo(),po(),kn(),document.getElementById("basemap-switcher")?.addEventListener("click",g=>{let I=g.target.closest(".bm-btn");I&&(document.querySelectorAll(".bm-btn").forEach(P=>P.classList.remove("active")),I.classList.add("active"),I.dataset.layer&&(_e.switchBasemap(I.dataset.layer),Ye.patch({map:I.dataset.layer})))}),document.getElementById("btn-fit-all")?.addEventListener("click",()=>_e.fitAll()),document.getElementById("btn-clear-all")?.addEventListener("click",ao),document.getElementById("track-search")?.addEventListener("input",g=>{ln=g.target.value,kt(),Ye.patch({q:ln||null})}),document.getElementById("btn-regex-toggle")?.addEventListener("click",g=>{sn=!sn,g.target.classList.toggle("active",sn),kt(),Ye.patch({re:sn?1:null})}),document.getElementById("btn-sort-menu")?.addEventListener("click",g=>{g.stopPropagation(),Gl(g.currentTarget)}),document.getElementById("btn-metric-menu")?.addEventListener("click",g=>{g.stopPropagation(),Xl(g.currentTarget)});let b=(g,I)=>{I&&I.classList.toggle("active"),Me.toggleMetric(g),ys()};document.getElementById("metric-pills")?.addEventListener("click",g=>{let I=g.target.closest(".metric-pill");if(I){let P=I.dataset.metric;P&&(b(P,I),Me.getActiveMetrics().has(P)&&document.querySelector(`.chart-row[data-metric="${P}"]`)?.scrollIntoView({behavior:"smooth"}))}}),document.getElementById("x-axis-ctrl")?.addEventListener("click",g=>{let I=g.target.closest(".seg-btn");if(!I)return;let P=I.dataset.axis;Me.setXAxis(P),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(p=>p.classList.toggle("active",p===I)),Ye.patch({xaxis:P})}),document.getElementById("btn-follow-dot")?.addEventListener("click",g=>{Bn=!Bn,g.currentTarget.classList.toggle("active",Bn)}),document.getElementById("btn-reset-zoom")?.addEventListener("click",()=>{Me.resetZoom(),_e.clearHighlight()}),mo(),document.getElementById("file-input")?.addEventListener("change",g=>{os(Array.from(g.target.files||[])),g.target.value=""}),document.getElementById("folder-input")?.addEventListener("change",g=>{os(Array.from(g.target.files||[])),g.target.value=""}),document.getElementById("btn-toggle-filters")?.addEventListener("click",()=>{let g=document.getElementById("filter-panel");g&&(g.classList.toggle("hidden"),document.getElementById("btn-toggle-filters")?.classList.toggle("active",!g.classList.contains("hidden")))});let w=(g,I,P)=>{let p=P.target.value;Te[g][I]=p===""?null:p,kt(),cn()};document.getElementById("filter-date-start")?.addEventListener("change",g=>w("date",0,g)),document.getElementById("filter-date-end")?.addEventListener("change",g=>w("date",1,g)),document.getElementById("filter-dist-min")?.addEventListener("input",g=>w("dist",0,g)),document.getElementById("filter-dist-max")?.addEventListener("input",g=>w("dist",1,g)),document.getElementById("filter-dur-min")?.addEventListener("input",g=>w("dur",0,g)),document.getElementById("filter-dur-max")?.addEventListener("input",g=>w("dur",1,g));let R=document.getElementById("sport-burger-btn"),S=document.getElementById("sport-dropdown-content");R?.addEventListener("click",g=>{if(g.stopPropagation(),S){let I=S.style.display==="block";S.style.display=I?"none":"block"}}),document.addEventListener("click",g=>{S&&S.style.display==="block"&&!S.contains(g.target)&&g.target!==R&&(S.style.display="none")}),document.getElementById("sport-filter-container")?.addEventListener("click",g=>{let I=g.target,P=I.closest("[data-sport]");if(P){let p=P.dataset.sport||null;Te.sport=Te.sport===p?null:p,kt(),cn(),Fn(),I.closest(".dropdown-item")&&S&&(S.style.display="none")}}),document.getElementById("filter-metrics")?.addEventListener("click",g=>{let I=g.target.closest(".mini-pill");if(!I)return;let P=I.dataset.metric;Te.metrics.has(P)?Te.metrics.delete(P):Te.metrics.add(P),Fn(),kt(),cn()}),document.getElementById("btn-reset-filters")?.addEventListener("click",()=>{Te={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},Fn(),kt(),cn()}),document.getElementById("filter-tags")?.addEventListener("input",g=>{let I=g.target.value;Te.tags=I.split(",").map(P=>P.trim().toLowerCase()).filter(P=>!!P),kt(),cn()}),document.addEventListener("keydown",g=>{g.key==="Escape"&&(_e.hideCursor(),_e.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(I=>I.remove()))}),window.addEventListener("resize",()=>{Me.resize(),yn(),_e.invalidateSize?.(),kn()}),window.addEventListener("popstate",()=>{Ye.refresh(),fl(Ye.get())}),Ql(),await hl();let k=document.createElement("div");k.id="app-is-ready",k.setAttribute("data-ready","true"),k.style.display="none",document.body.appendChild(k);let M=document.createElement("div");M.id="appIsReady",M.setAttribute("data-ready","true"),M.style.display="none",document.body.appendChild(M)}var En=null;async function hl(){if(En)return En;try{let s=await(await fetch("./test-data/manifest.json")).json(),t=new TextDecoder;En=await Promise.all(s.map(async o=>{let u=await(await fetch(`./test-data/${o}`)).arrayBuffer(),c=o;if(o.toLowerCase().endsWith(".gz")){c=o.slice(0,-3);let b=new Uint8Array(u);if(b.length>=2&&b[0]===31&&b[1]===139){let w=new DecompressionStream("gzip"),R=new Blob([u]).stream().pipeThrough(w);u=await new Response(R).arrayBuffer()}}let m=c.toLowerCase().endsWith(".fit")?void 0:t.decode(u),T=new File([u],c,{type:"application/octet-stream"});return T._buf=u,m!==void 0&&(T._text=m),{cleanName:c,buf:u,text:m,file:T}}));let n=null;for(let o of[0,2,4])if(En[o]){let r=await it.parseFile(En[o].file);o===0&&(n=r)}if(n){let o=n.points.slice(0,60),r={...n,id:"warmup",fileName:"warmup.gpx",fileSize:1024,points:o,stats:it.computeStats(o),addedAt:17855424e5,visible:!0,color:ss[0]};it.ensureCurvesAndZones(r),Me.loadTrack(r,[r],!1),Me.setActiveMetrics(["elevation","speed","power"]),Bt(r),Tn(r,[r]),await xs(),document.body.offsetHeight,await new Promise(u=>window.setTimeout(u,0))}else typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();return En}catch{return[]}}function Ql(){let e=document.getElementById("btn-step-load"),s=document.getElementById("btn-step-analysis"),t=document.getElementById("btn-step-insights"),n=document.getElementById("btn-step-details"),o=document.getElementById("btn-step-aggregate"),r=document.getElementById("btn-step-evolution"),u=document.getElementById("btn-step-courses");function c(m){document.querySelectorAll(".tab-btn").forEach(T=>{T.classList.toggle("active",T.dataset.tab===m)}),document.querySelectorAll(".tab-content").forEach(T=>{T.classList.toggle("active",T.id===`tab-${m}`)}),Ye.patch({tab:m},!1)}e?.addEventListener("click",async()=>{try{Object.keys(ze).length>0||Tt.length>0||Oe!==null?(await at.openDB(),await xs()):typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();let T=(await hl()).map(w=>w.file);await os(T);let b=Object.values(ze);!Oe&&b.length>0&&Mt(b[0].id)}finally{window.dispatchEvent(new CustomEvent("load-and-parse-complete"))}}),s?.addEventListener("click",()=>{try{let m=Object.values(ze);c("graphs"),!Oe&&m.length>0&&Mt(m[0].id),Me.restoreSelection(120,900,!0),Me.setCursorAt(300,!0);let T=Me.getAvailableMetrics(),b=["elevation","speed","power"].filter(w=>T.has(w));b.length>0?(document.querySelectorAll("#metric-pills .metric-pill").forEach(w=>{let R=w.dataset.metric;R&&w.classList.toggle("active",b.includes(R))}),kn(),Me.setActiveMetrics(b)):kn(),un(120,900,Me.getXAxis(),!1)}finally{window.dispatchEvent(new CustomEvent("analysis-complete"))}}),t?.addEventListener("click",()=>{try{let m=Object.values(ze);m.forEach(b=>it.ensureCurvesAndZones(b)),c("insights");let T=Oe&&ze[Oe]||m[0]||null;Bt(T)}finally{window.dispatchEvent(new CustomEvent("insights-complete"))}}),n?.addEventListener("click",()=>{try{let m=Object.values(ze);c("details");let T=Oe&&ze[Oe]||m[0]||null;on(T,ws())}finally{window.dispatchEvent(new CustomEvent("details-complete"))}}),o?.addEventListener("click",()=>{try{let m=Object.values(ze);if(m.length>=2){let T=[m[0],m[1]];c("combined"),rn(T),yn()}}finally{window.dispatchEvent(new CustomEvent("aggregate-complete"))}}),r?.addEventListener("click",()=>{try{let m=Object.values(ze);c("evolution");let T=Oe&&ze[Oe]||m[0]||null;Tn(T,m,(b,w)=>{Mt(b,!0),w&&(Me.restoreSelection(w[0],w[1]),un(w[0],w[1],"time",!0))})}finally{window.dispatchEvent(new CustomEvent("evolution-complete"))}}),u?.addEventListener("click",()=>{try{let m=Object.values(ze);c("courses"),Xs(m),Dt(),_n("course-1",!0)}finally{window.dispatchEvent(new CustomEvent("courses-complete"))}}),window.benchmarkSteps={loadAndParseFiles:()=>document.getElementById("btn-step-load")?.click(),displayAnalysisMetrics:()=>document.getElementById("btn-step-analysis")?.click(),displayInsights:()=>document.getElementById("btn-step-insights")?.click(),displayDetails:()=>document.getElementById("btn-step-details")?.click(),displayAggregateMetrics:()=>document.getElementById("btn-step-aggregate")?.click(),displayEvolutionMetrics:()=>document.getElementById("btn-step-evolution")?.click(),displayCourses:()=>document.getElementById("btn-step-courses")?.click()}}async function pl(e){let s=e.stats.powerCurve?Object.values(e.stats.powerCurve):[],t=e.points.length>1&&(e.points[1].speed===void 0||e.points[1].gradient===void 0);(t||!e.stats.powerCurve||!e.stats.hrZones||!e.stats.hrCurve||e.stats.shifts===void 0||e.stats.avgBattery===void 0||e.stats.avgTemp===void 0||s.length>0&&typeof s[0]=="number"||(e.stats.duration||0)>10800*1e3&&e.stats.powerCurve&&!e.stats.powerCurve[14400])&&(t&&(e.points=it.enrichPoints(e.points)),e.stats=it.computeStats(e.points),await at.save(e)),ze[e.id]=e,Dn=Math.max(Dn,ss.indexOf(e.color)+1),_e.addTrack(e),_e.setTrackVisible(e.id,e.visible&&!e._filtered),mn()}function Kl(){let e=document.getElementById("resize-handle"),s=document.getElementById("chart-panel");if(!e||!s)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,document.body.style.cursor="ns-resize"}),document.addEventListener("mousemove",n=>{if(!t)return;let o=window.innerHeight-n.clientY,r=Math.max(100,Math.min(window.innerHeight-100,o));s.style.height=`${r}px`,Me.resize(),yn(),_e.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,document.body.style.cursor="")})}function eo(){let e=document.getElementById("sidebar-resizer"),s=document.getElementById("sidebar");if(!e||!s)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,e.classList.add("dragging"),document.body.classList.add("dragging-sidebar")}),document.addEventListener("mousemove",n=>{if(!t)return;let o=n.clientX,r=Math.max(200,Math.min(600,o));s.style.width=`${r}px`,s.style.setProperty("--sidebar-w",`${r}px`),Me.resize(),_e.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,e.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}function to(e,s,t){Ye.patch({map_pos:[e,s,t]})}function no(e,s){Mt(e,!1),Me.setCursorAt(s)}function so(){}function lo(e){e&&e.lat!=null&&e.lon!=null?(_e.showCursorAt(e.lat,e.lon),Bn&&_e.centerOn(e.lat,e.lon,null,!0)):_e.hideCursor()}function un(e,s,t,n=!1){if(!Oe||!ze[Oe])return;let o=ze[Oe];if(e===null||s===null){_e.clearHighlight(),o&&(Ye.get().tab||"graphs")==="insights"&&Bt(o),Ye.patch({sel:null});return}let r=o.points,u=0,c=r.length-1;if(t==="distance"){let b=e*1e3,w=s*1e3;u=r.findIndex(R=>(R.dist||0)>=b),c=r.findIndex(R=>(R.dist||0)>=w)}else{let b=r.find(S=>S.time!=null)?.time||0,w=b+e*1e3,R=b+s*1e3;u=r.findIndex(S=>(S.time||0)>=w),c=r.findIndex(S=>(S.time||0)>=R)}u===-1&&(u=0),c===-1&&(c=r.length-1);let m=r.slice(u,c+1),T=it.computeStats(m);Me.setSelectionStats(T),(Ye.get().tab||"graphs")==="insights"&&Bt(o),_e.highlightSegment(Oe,r,u,c,n,Mn),_e.ensureVisible(m.map(b=>[b.lat,b.lon])),Ye.patch({sel:[e,s]})}function oo(e,s){e&&e.lat!=null&&e.lon!=null&&_e.centerOn(e.lat,e.lon,jl)}function Mt(e,s=!0,t=!1){if(!ze[e])return;if(e===Oe){s&&_e.fitTrack(e);return}let n=Oe!==null;n&&(Me.clear(),on(null,[]),Bt(null)),Oe=e,Mn=null,_e.clearMetricColor(e),n&&Me.toggleMapColor(null),Ye.patch({track:e,sel:null},!0),n&&Me.cancelSelection(),mn();let o=Ye.get().tab||"graphs";o==="details"&&on(ze[e],ws()),o==="insights"&&Bt(ze[e]),o==="combined"&&rn(ze[e]),o==="courses"&&Dt(),o==="evolution"&&Tn(ze[e],Object.values(ze),(r,u)=>{Mt(r,!0),u&&(Me.restoreSelection(u[0],u[1]),un(u[0],u[1],"time",!0))}),_e.setSelectedTrack(e,s),s&&_e.fitTrack(e),Me.loadTrack(ze[e],Object.values(ze),t)}async function io(e){await at.remove(e),_e.removeTrack(e),delete ze[e],Oe===e&&(Oe=null,Me.clear(),on(null,[]),Bt(null),Ye.patch({track:null,sel:null,sel_point:null})),kt()}async function ao(){let e=Math.floor(10+Math.random()*90).toString(),s=document.createElement("div");s.className="modal-backdrop",s.innerHTML=` + `,T.addEventListener("click",()=>{Se.toggleMetric(c);let f=Se.getActiveMetrics().has(c);T.classList.toggle("active",f),T.querySelector(".check").textContent=f?"check":"";let M=document.querySelector(`#metric-pills .metric-pill[data-metric="${c}"]`);M&&M.classList.toggle("active",f),Bn(),Zs()}),n.appendChild(T)});let a=e.getBoundingClientRect();n.style.top=`${a.bottom+5}px`,n.style.right=`${window.innerWidth-a.right}px`,document.body.appendChild(n);let g=c=>{!n.contains(c.target)&&!e.contains(c.target)&&(n.remove(),document.removeEventListener("click",g))};setTimeout(()=>document.addEventListener("click",g),0)}document.addEventListener("select-track",e=>{let n=e.detail.id,t=e.detail.idx,s=e.detail.dur;if(n&&ze[n]&&(Mt(n),t!=null&&s!=null)){let o=ze[n],a=o.points;if(t>=0&&tH.time!=null)?.time||0,m=(g.time-c)/1e3,T=m+s;Se.restoreSelection(m,T);let f=a.findIndex(H=>(H.time||0)>=g.time+s*1e3);f===-1&&(f=a.length-1);let M=a.slice(t,f+1),O=ot.computeStats(M);Se.setSelectionStats(O),_t(o),De.highlightSegment(n,a,t,f,!1,_n),De.ensureVisible(M.map(H=>[H.lat,H.lon])),Ye.patch({sel:[m,T]})}}}});document.addEventListener("click",e=>{let n=e.target.closest(".tab-btn");if(!n)return;let t=n.closest("#tab-nav");if(!t)return;t.querySelectorAll(".tab-btn").forEach(a=>a.classList.toggle("active",a===n));let s=n.dataset.tab;Ye.patch({tab:s},!0);let o=t.closest("#chart-panel");if(o&&o.querySelectorAll(".tab-content").forEach(a=>{a.classList.toggle("active",a.id===`tab-${n.dataset.tab}`)}),n.dataset.tab==="details"&&Oe&&ze[Oe]&&an(ze[Oe],Xs()),n.dataset.tab==="insights"&&Oe&&ze[Oe]&&_t(ze[Oe]),n.dataset.tab==="evolution"&&In(Oe?ze[Oe]:null,Object.values(ze),(a,g)=>{Mt(a,!0),g&&(Se.restoreSelection(g[0],g[1]),yn(g[0],g[1],"time",!0))},(a,g)=>{Le.date=[a,g],kt(),bn(!0),Xn()}),n.dataset.tab==="combined"&&Oe&&ze[Oe]&&dn(ze[Oe]),n.dataset.tab==="courses"&&Wt(),n.dataset.tab==="graphs"){Se.resize(),Bn();let a=Ye.get().sel;a&&Se.restoreSelection(a[0],a[1])}});async function Gs(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await at.clear(),ze={},Tt=[],Oe=null,Qn=0,_n=null,Fn=!1,Gn=!1,mn="",un=!1,vn="date-desc",Le.date=[null,null],Le.dist=[null,null],Le.dur=[null,null],Le.metrics.clear(),Le.tags=[],ot.setHRZones([120,140,160,180]),ot.setFTP(200),Hl(),Ul(),wl(),Yl(),no(),De.removeAllTracks&&De.removeAllTracks(),De.clearTracks&&De.clearTracks(),De.clearHighlight(),Se.resetState?Se.resetState():Se.clear&&Se.clear(),document.querySelectorAll(".tab-btn").forEach(n=>{n.classList.toggle("active",n.dataset.tab==="graphs")}),document.querySelectorAll(".tab-content").forEach(n=>{n.classList.toggle("active",n.id==="tab-graphs")}),Ye.reset();let e=document.getElementById("toast-container");e&&(e.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(n=>n.remove()),typeof xn=="function"&&xn()}async function ni(){let e=null,n=new Promise(p=>{e=window.setTimeout(p,1e3)});try{let p=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([p,n])}finally{e!==null&&window.clearTimeout(e)}document.body.classList.remove("loading-fonts");let t=document.getElementById("storage-backend-select");t&&(t.value=Ye.get().storage||"memory",t.addEventListener("change",p=>{let P=p.target.value,b=new URLSearchParams(window.location.search);P==="memory"?b.delete("storage"):b.set("storage",P),window.location.search=b.toString()}));let s=document.getElementById("global-loader"),o=document.getElementById("loader-text"),a=document.getElementById("loader-subtext"),g=document.getElementById("loader-progress-bar"),c=document.getElementById("map-loader"),m=c?.querySelector("span");c&&(m&&(m.textContent="Loading database..."),c.classList.remove("hidden"));let T=Ye.get();ql((p,P)=>Cs(p,P==="error"?"error":"info")),xl(()=>{kt(),bn()},p=>{ui(p)}),Il((p,P)=>Cs(p,P==="error"?"error":"info")),De.init(p=>Mt(p),ii,ai,(p,P)=>{p===Oe?Se.setHoverAt(P):Se.setHoverAt(null)},ri),Se.init(ci,yn,di,p=>{Ye.patch({sel_point:p})}),Se.setMapColorChangeCb(p=>{p?(_n=p.colors,Oe&&De.colorTrackByMetric(Oe,p.pts,p.colors)):(_n=null,Oe&&De.clearMetricColor(Oe));let P=Ye.get();P.sel&&yn(P.sel[0],P.sel[1],Se.getXAxis())}),oo(T),await at.openDB(),await Gs();try{let p=await at.get("hr_zones");p&&ot.setHRZones(p);let P=await at.get("ftp");P&&ot.setFTP(P);let b=await at.getAll();b.sort((W,_)=>W.addedAt-_.addedAt),m&&(m.textContent=`Preparing ${b.length} tracks...`);let u=[];for(let W of b){let _=!1;if(!W.bounds&&W.points.length>0){let C=hs(W.points);C&&(W.bounds=C,_=!0)}!W.simplifiedPoints&&W.points.length>0&&(W.simplifiedPoints=bs(W.points,50),_=!0),_&&await at.save(W),ze[W.id]=W,u.push(W)}De.addTracks(u),kt();let x=T.track&&b.find(W=>W.id===T.track)?T.track:b.length>0?b[0].id:null,w=document.getElementById("map-loader"),D=b.find(W=>W.id===x);if(D&&(await lo(D),Mt(D.id,!T.map_pos),T.sel&&Array.isArray(T.sel)&&T.sel.length===2&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Se.restoreSelection(T.sel[0],T.sel[1])})}),T.sel_point!==void 0&&T.sel_point!==null&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Se.setCursorAt(T.sel_point)})})),w&&w.classList.add("hidden"),b.length>(D?1:0)){w&&(m&&(m.textContent="Loading tracks..."),w.classList.remove("hidden"));let W=b.filter(q=>q.id!==x),_=0,C=async()=>{let N=Math.min(_+2,W.length);for(;_{Mt(ie,!0),y&&(Se.restoreSelection(y[0],y[1]),yn(y[0],y[1],"time",!0))}),b.length&&!T.map_pos&&De.fitAll())};requestAnimationFrame(C)}else kt(),b.length&&!T.map_pos&&De.fitAll()}catch(p){console.warn("Could not load saved tracks:",p)}li(),oi(),bi(),Bn(),document.getElementById("basemap-switcher")?.addEventListener("click",p=>{let P=p.target.closest(".bm-btn");P&&(document.querySelectorAll(".bm-btn").forEach(b=>b.classList.remove("active")),P.classList.add("active"),P.dataset.layer&&(De.switchBasemap(P.dataset.layer),Ye.patch({map:P.dataset.layer})))}),document.getElementById("btn-fit-all")?.addEventListener("click",()=>De.fitAll()),document.getElementById("btn-clear-all")?.addEventListener("click",mi),document.getElementById("track-search")?.addEventListener("input",p=>{mn=p.target.value,kt(),Ye.patch({q:mn||null})}),document.getElementById("btn-regex-toggle")?.addEventListener("click",p=>{un=!un,p.target.classList.toggle("active",un),kt(),Ye.patch({re:un?1:null})}),document.getElementById("btn-sort-menu")?.addEventListener("click",p=>{p.stopPropagation(),ei(p.currentTarget)}),document.getElementById("btn-metric-menu")?.addEventListener("click",p=>{p.stopPropagation(),ti(p.currentTarget)});let f=(p,P)=>{P&&P.classList.toggle("active"),Se.toggleMetric(p),Zs()};document.getElementById("metric-pills")?.addEventListener("click",p=>{let P=p.target.closest(".metric-pill");if(P){let b=P.dataset.metric;b&&(f(b,P),Se.getActiveMetrics().has(b)&&document.querySelector(`.chart-row[data-metric="${b}"]`)?.scrollIntoView({behavior:"smooth"}))}}),document.getElementById("x-axis-ctrl")?.addEventListener("click",p=>{let P=p.target.closest(".seg-btn");if(!P)return;let b=P.dataset.axis;Se.setXAxis(b),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(u=>u.classList.toggle("active",u===P)),Ye.patch({xaxis:b})}),document.getElementById("btn-follow-dot")?.addEventListener("click",p=>{Gn=!Gn,p.currentTarget.classList.toggle("active",Gn)}),document.getElementById("btn-reset-zoom")?.addEventListener("click",()=>{Se.resetZoom(),De.clearHighlight()}),hi(),document.getElementById("file-input")?.addEventListener("change",p=>{$s(Array.from(p.target.files||[])),p.target.value=""}),document.getElementById("folder-input")?.addEventListener("change",p=>{$s(Array.from(p.target.files||[])),p.target.value=""}),document.getElementById("btn-toggle-filters")?.addEventListener("click",()=>{let p=document.getElementById("filter-panel");p&&(p.classList.toggle("hidden"),document.getElementById("btn-toggle-filters")?.classList.toggle("active",!p.classList.contains("hidden")))});let M=(p,P,b)=>{let u=b.target.value;Le[p][P]=u===""?null:u,kt(),bn()};document.getElementById("filter-date-start")?.addEventListener("change",p=>M("date",0,p)),document.getElementById("filter-date-end")?.addEventListener("change",p=>M("date",1,p)),document.getElementById("filter-dist-min")?.addEventListener("input",p=>M("dist",0,p)),document.getElementById("filter-dist-max")?.addEventListener("input",p=>M("dist",1,p)),document.getElementById("filter-dur-min")?.addEventListener("input",p=>M("dur",0,p)),document.getElementById("filter-dur-max")?.addEventListener("input",p=>M("dur",1,p));let O=document.getElementById("sport-burger-btn"),H=document.getElementById("sport-dropdown-content");O?.addEventListener("click",p=>{if(p.stopPropagation(),H){let P=H.style.display==="block";H.style.display=P?"none":"block"}}),document.addEventListener("click",p=>{H&&H.style.display==="block"&&!H.contains(p.target)&&p.target!==O&&(H.style.display="none")}),document.getElementById("sport-filter-container")?.addEventListener("click",p=>{let P=p.target,b=P.closest("[data-sport]");if(b){let u=b.dataset.sport||null;Le.sport=Le.sport===u?null:u,kt(),bn(),Xn(),P.closest(".dropdown-item")&&H&&(H.style.display="none")}}),document.getElementById("filter-metrics")?.addEventListener("click",p=>{let P=p.target.closest(".mini-pill");if(!P)return;let b=P.dataset.metric;Le.metrics.has(b)?Le.metrics.delete(b):Le.metrics.add(b),Xn(),kt(),bn()}),document.getElementById("btn-reset-filters")?.addEventListener("click",()=>{Le={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},Xn(),kt(),bn()}),document.getElementById("filter-tags")?.addEventListener("input",p=>{let P=p.target.value;Le.tags=P.split(",").map(b=>b.trim().toLowerCase()).filter(b=>!!b),kt(),bn()}),document.addEventListener("keydown",p=>{p.key==="Escape"&&(De.hideCursor(),De.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(P=>P.remove()))}),window.addEventListener("resize",()=>{Se.resize(),Yn(),De.invalidateSize?.(),Bn()}),window.addEventListener("popstate",()=>{Ye.refresh(),oo(Ye.get())}),si(),await ao();let E=document.createElement("div");E.id="app-is-ready",E.setAttribute("data-ready","true"),E.style.display="none",document.body.appendChild(E);let k=document.createElement("div");k.id="appIsReady",k.setAttribute("data-ready","true"),k.style.display="none",document.body.appendChild(k)}var Hn=null;async function ao(){if(Hn)return Hn;try{let n=await(await fetch("./test-data/manifest.json")).json(),t=new TextDecoder;Hn=await Promise.all(n.map(async o=>{let g=await(await fetch(`./test-data/${o}`)).arrayBuffer(),c=o;if(o.toLowerCase().endsWith(".gz")){c=o.slice(0,-3);let f=new Uint8Array(g);if(f.length>=2&&f[0]===31&&f[1]===139){let M=new DecompressionStream("gzip"),O=new Blob([g]).stream().pipeThrough(M);g=await new Response(O).arrayBuffer()}}let m=c.toLowerCase().endsWith(".fit")?void 0:t.decode(g),T=new File([g],c,{type:"application/octet-stream"});return T._buf=g,m!==void 0&&(T._text=m),{cleanName:c,buf:g,text:m,file:T}}));let s=null;for(let o of[0,2,4])if(Hn[o]){let a=await ot.parseFile(Hn[o].file);o===0&&(s=a)}if(s){let o=s.points.slice(0,1250),a={...s,id:"warmup",fileName:"warmup.gpx",fileSize:1024,points:o,bounds:hs(o)||void 0,simplifiedPoints:bs(o,50),stats:ot.computeStats(o),addedAt:17855424e5,visible:!0,color:Jn[0]},g={...a,id:"warmup-2",fileName:"warmup2.gpx",addedAt:17856288e5,color:Jn[1]},c=[a,g];ot.ensureCurvesAndZones(a),ot.ensureCurvesAndZones(g),De.addTracks(c),Se.loadTrack(a,c,!1),Se.restoreSelection(10,50,!0),Se.setCursorAt(25,!0),Se.setActiveMetrics(["elevation","speed","power"]),Se.analyzeTelemetryIntervals(c,10,50),_t(a,c),an(a,[],c),dn(c,c),In(a,c),Bs(c),Ln("course-1",!0),await Gs(),document.body.offsetHeight,await new Promise(m=>window.setTimeout(m,0))}else typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();return Hn}catch{return[]}}function si(){let e=document.getElementById("btn-step-load"),n=document.getElementById("btn-step-analysis"),t=document.getElementById("btn-step-insights"),s=document.getElementById("btn-step-details"),o=document.getElementById("btn-step-aggregate"),a=document.getElementById("btn-step-evolution"),g=document.getElementById("btn-step-courses");function c(m){document.querySelectorAll(".tab-btn").forEach(T=>{T.classList.toggle("active",T.dataset.tab===m)}),document.querySelectorAll(".tab-content").forEach(T=>{T.classList.toggle("active",T.id===`tab-${m}`)}),Ye.patch({tab:m},!1)}e?.addEventListener("click",async()=>{try{Object.keys(ze).length>0||Tt.length>0||Oe!==null?(await at.openDB(),await Gs()):typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();let T=(await ao()).map(M=>M.file);await $s(T);let f=Object.values(ze);!Oe&&f.length>0&&Mt(f[0].id)}finally{window.dispatchEvent(new CustomEvent("load-and-parse-complete"))}}),n?.addEventListener("click",()=>{try{let m=Object.values(ze);c("graphs"),!Oe&&m.length>0&&Mt(m[0].id),Se.restoreSelection(120,900,!0),Se.setCursorAt(300,!0);let T=Se.getAvailableMetrics(),f=["elevation","speed","power"].filter(M=>T.has(M));f.length>0?(document.querySelectorAll("#metric-pills .metric-pill").forEach(M=>{let O=M.dataset.metric;O&&M.classList.toggle("active",f.includes(O))}),Bn(),Se.setActiveMetrics(f)):Bn(),Se.analyzeTelemetryIntervals(m,120,900),yn(120,900,Se.getXAxis(),!1)}finally{window.dispatchEvent(new CustomEvent("analysis-complete"))}}),t?.addEventListener("click",()=>{try{let m=Object.values(ze);m.forEach(f=>ot.ensureCurvesAndZones(f)),c("insights");let T=Oe&&ze[Oe]||m[0]||null;_t(T,m)}finally{window.dispatchEvent(new CustomEvent("insights-complete"))}}),s?.addEventListener("click",()=>{try{let m=Object.values(ze);c("details");let T=Oe&&ze[Oe]||m[0]||null;an(T,Xs(),m)}finally{window.dispatchEvent(new CustomEvent("details-complete"))}}),o?.addEventListener("click",()=>{try{let m=Object.values(ze);if(m.length>=2){let T=[m[0],m[1]];c("combined"),dn(T,m)}}finally{window.dispatchEvent(new CustomEvent("aggregate-complete"))}}),a?.addEventListener("click",()=>{try{let m=Object.values(ze);c("evolution");let T=Oe&&ze[Oe]||m[0]||null;In(T,m,(f,M)=>{Mt(f,!0),M&&(Se.restoreSelection(M[0],M[1]),yn(M[0],M[1],"time",!0))})}finally{window.dispatchEvent(new CustomEvent("evolution-complete"))}}),g?.addEventListener("click",()=>{try{let m=Object.values(ze);c("courses"),Bs(m),Ln("course-1",!0)}finally{window.dispatchEvent(new CustomEvent("courses-complete"))}}),window.benchmarkSteps={loadAndParseFiles:()=>document.getElementById("btn-step-load")?.click(),displayAnalysisMetrics:()=>document.getElementById("btn-step-analysis")?.click(),displayInsights:()=>document.getElementById("btn-step-insights")?.click(),displayDetails:()=>document.getElementById("btn-step-details")?.click(),displayAggregateMetrics:()=>document.getElementById("btn-step-aggregate")?.click(),displayEvolutionMetrics:()=>document.getElementById("btn-step-evolution")?.click(),displayCourses:()=>document.getElementById("btn-step-courses")?.click()}}async function lo(e){let n=e.stats.powerCurve?Object.values(e.stats.powerCurve):[],t=e.points.length>1&&(e.points[1].speed===void 0||e.points[1].gradient===void 0);(t||!e.stats.powerCurve||!e.stats.hrZones||!e.stats.hrCurve||e.stats.shifts===void 0||e.stats.avgBattery===void 0||e.stats.avgTemp===void 0||n.length>0&&typeof n[0]=="number"||(e.stats.duration||0)>10800*1e3&&e.stats.powerCurve&&!e.stats.powerCurve[14400])&&(t&&(e.points=ot.enrichPoints(e.points)),e.stats=ot.computeStats(e.points),await at.save(e)),ze[e.id]=e,Qn=Math.max(Qn,Jn.indexOf(e.color)+1),De.addTrack(e),De.setTrackVisible(e.id,e.visible&&!e._filtered),xn()}function li(){let e=document.getElementById("resize-handle"),n=document.getElementById("chart-panel");if(!e||!n)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,document.body.style.cursor="ns-resize"}),document.addEventListener("mousemove",s=>{if(!t)return;let o=window.innerHeight-s.clientY,a=Math.max(100,Math.min(window.innerHeight-100,o));n.style.height=`${a}px`,Se.resize(),Yn(),De.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,document.body.style.cursor="")})}function oi(){let e=document.getElementById("sidebar-resizer"),n=document.getElementById("sidebar");if(!e||!n)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,e.classList.add("dragging"),document.body.classList.add("dragging-sidebar")}),document.addEventListener("mousemove",s=>{if(!t)return;let o=s.clientX,a=Math.max(200,Math.min(600,o));n.style.width=`${a}px`,n.style.setProperty("--sidebar-w",`${a}px`),Se.resize(),De.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,e.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}function ii(e,n,t){Ye.patch({map_pos:[e,n,t]})}function ai(e,n){Mt(e,!1),Se.setCursorAt(n)}function ri(){}function ci(e){e&&e.lat!=null&&e.lon!=null?(De.showCursorAt(e.lat,e.lon),Gn&&De.centerOn(e.lat,e.lon,null,!0)):De.hideCursor()}function yn(e,n,t,s=!1){if(!Oe||!ze[Oe])return;let o=ze[Oe];if(e===null||n===null){De.clearHighlight(),o&&(Ye.get().tab||"graphs")==="insights"&&_t(o),Ye.patch({sel:null});return}let a=o.points,g=0,c=a.length-1;if(t==="distance"){let f=e*1e3,M=n*1e3;g=a.findIndex(O=>(O.dist||0)>=f),c=a.findIndex(O=>(O.dist||0)>=M)}else{let f=a.find(H=>H.time!=null)?.time||0,M=f+e*1e3,O=f+n*1e3;g=a.findIndex(H=>(H.time||0)>=M),c=a.findIndex(H=>(H.time||0)>=O)}g===-1&&(g=0),c===-1&&(c=a.length-1);let m=a.slice(g,c+1),T=ot.computeStats(m);Se.setSelectionStats(T),(Ye.get().tab||"graphs")==="insights"&&_t(o),De.highlightSegment(Oe,a,g,c,s,_n),De.ensureVisible(m.map(f=>[f.lat,f.lon])),Ye.patch({sel:[e,n]})}function di(e,n){e&&e.lat!=null&&e.lon!=null&&De.centerOn(e.lat,e.lon,Qo)}function Mt(e,n=!0,t=!1){if(!ze[e])return;if(e===Oe){n&&De.fitTrack(e);return}let s=Oe!==null;s&&(Se.clear(),an(null,[]),_t(null)),Oe=e,_n=null,De.clearMetricColor(e),s&&Se.toggleMapColor(null),Ye.patch({track:e,sel:null},!0),s&&Se.cancelSelection(),xn();let o=Ye.get().tab||"graphs";o==="details"&&an(ze[e],Xs()),o==="insights"&&_t(ze[e]),o==="combined"&&dn(ze[e]),o==="courses"&&Wt(),o==="evolution"&&In(ze[e],Object.values(ze),(a,g)=>{Mt(a,!0),g&&(Se.restoreSelection(g[0],g[1]),yn(g[0],g[1],"time",!0))}),De.setSelectedTrack(e,n),n&&De.fitTrack(e),Se.loadTrack(ze[e],Object.values(ze),t)}async function ui(e){await at.remove(e),De.removeTrack(e),delete ze[e],Oe===e&&(Oe=null,Se.clear(),an(null,[]),_t(null),Ye.patch({track:null,sel:null,sel_point:null})),kt()}async function mi(){let e=Math.floor(10+Math.random()*90).toString(),n=document.createElement("div");n.className="modal-backdrop",n.innerHTML=` - `,document.body.appendChild(s);let t=s.querySelector(".modal-input"),n=s.querySelector(".modal-btn.confirm"),o=s.querySelector(".modal-btn.cancel");t.focus(),t.addEventListener("input",()=>{n.disabled=t.value!==e});let r=()=>s.remove();o.addEventListener("click",r),s.addEventListener("click",u=>{u.target===s&&r()}),n.addEventListener("click",async()=>{t.value===e&&(r(),Sn=!0,await at.clear(),ze={},Oe=null,_e.clearHighlight(),window.location.reload())})}function kt(e=!1){Object.keys(ze).forEach(t=>{let n=ze[t],o=n.stats,r=!0;if(ln)if(sn)try{new RegExp(ln,"i").test(n.name)||(r=!1)}catch{r=!1}else n.name.toLowerCase().includes(ln.toLowerCase())||(r=!1);if(r&&(Te.date[0]||Te.date[1])){let u=Te.date[0]?new Date(Te.date[0]).getTime():0,c=Te.date[1]?new Date(Te.date[1]).getTime():1/0,m=o.startTime||0;(mc)&&(r=!1)}if(r&&(Te.dist[0]!==null||Te.dist[1]!==null)){let u=(Te.dist[0]||0)*1e3,c=(Te.dist[1]||1/0)*1e3;(o.totalDistc)&&(r=!1)}if(r&&(Te.dur[0]!==null||Te.dur[1]!==null)){let u=(Te.dur[0]||0)*6e4,c=(Te.dur[1]||1/0)*6e4,m=o.duration||0;(mc)&&(r=!1)}if(r&&Te.metrics.size>0)for(let u of Te.metrics){let c=Me.METRICS[u].field;if(!n.points.some(m=>m[c]!=null)){r=!1;break}}if(r&&Te.sport&&n.sport!==Te.sport&&(r=!1),r&&Te.tags.length>0){let u=n.tags||[];Te.tags.every(c=>u.includes(c))||(r=!1)}n._filtered=!r,_e.setTrackVisible(n.id,n.visible&&r)}),e||mn()}function Fn(){document.getElementById("filter-date-start").value=Te.date[0]||"",document.getElementById("filter-date-end").value=Te.date[1]||"",document.getElementById("filter-dist-min").value=Te.dist[0]!==null?String(Te.dist[0]):"",document.getElementById("filter-dist-max").value=Te.dist[1]!==null?String(Te.dist[1]):"",document.getElementById("filter-dur-min").value=Te.dur[0]!==null?String(Te.dur[0]):"",document.getElementById("filter-dur-max").value=Te.dur[1]!==null?String(Te.dur[1]):"",document.getElementById("filter-tags").value=Te.tags.join(", "),document.querySelectorAll("#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item").forEach(t=>{let n=t;n.classList.toggle("active",(n.dataset.sport||"")===(Te.sport||""))}),document.querySelectorAll("#filter-metrics .mini-pill").forEach(t=>{let n=t;n.classList.toggle("active",Te.metrics.has(n.dataset.metric))});let e=(Te.date[0]?1:0)+(Te.date[1]?1:0)+(Te.dist[0]!==null?1:0)+(Te.dist[1]!==null?1:0)+(Te.dur[0]!==null?1:0)+(Te.dur[1]!==null?1:0)+Te.metrics.size+(Te.tags.length>0?1:0),s=document.querySelector("#btn-toggle-filters .btn-badge");s&&(s.textContent=e>0?String(e):"",s.classList.toggle("hidden",e===0))}function bl(){let e=document.getElementById("track-search");e&&(e.value=ln),document.getElementById("btn-regex-toggle")?.classList.toggle("active",sn);let s=gl.find(t=>t.val===dn);if(s){let t=document.getElementById("sort-current-label"),n=document.getElementById("sort-current-icon");t&&(t.textContent=s.label.replace(" first","").replace(" distance","").replace(" duration","")),n&&(n.textContent=s.icon)}}function fl(e){let s=e.track;if(s!==Oe&&(s&&ze[s]?Mt(s,!0):!s&&Oe&&(Oe=null,Me.clear(),on(null,[]),Bt(null),mn(),_e.fitAll())),e.map&&typeof e.map=="string"&&(_e.switchBasemap(e.map),document.querySelectorAll(".bm-btn").forEach(n=>n.classList.toggle("active",n.dataset.layer===e.map))),e.map_pos){let[n,o,r]=e.map_pos;_e.setPosition(n,o,r)}e.tab&&document.querySelectorAll(".tab-btn").forEach(n=>{let o=n;o.dataset.tab===e.tab&&(o.classList.contains("active")||o.click())}),e.xaxis&&Me.setXAxis(e.xaxis);let t=e.xaxis||"time";if(document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(n=>n.classList.toggle("active",n.dataset.axis===t)),e.metrics){let n=Me.METRICS,o=e.metrics.map(r=>Object.keys(n).find(u=>n[u].abbr===r)).filter(r=>r!==void 0);o.length&&Me.setActiveMetrics(o)}e.f_date&&(Te.date=e.f_date.map(n=>n||null)),e.f_dist&&(Te.dist=e.f_dist.map(n=>n===0?0:n||null)),e.f_dur&&(Te.dur=e.f_dur.map(n=>n===0?0:n||null)),e.f_mets&&(Te.metrics=new Set(e.f_mets)),e.f_tags&&(Te.tags=e.f_tags),Fn(),e.q&&(ln=e.q),e.re&&(sn=e.re),e.sort&&(dn=e.sort),bl(),kt()}function ro(){if(!document.getElementById("sport-filter-container"))return;let s=document.getElementById("common-sports"),t=document.getElementById("sport-dropdown-content");if(!s||!t)return;let n=new Set;Object.values(ze).forEach(u=>{u.sport&&n.add(u.sport)});let o=Array.from(n).sort(),r=document.getElementById("sport-burger-dropdown");s.innerHTML="",t.innerHTML="",o.length<=4?(r&&(r.style.display="none"),o.forEach(u=>{let c=document.createElement("button");c.className=`mini-pill${Te.sport===u?" active":""}`,c.dataset.sport=u,c.title=u.charAt(0).toUpperCase()+u.slice(1),c.innerHTML=`${ns(u)}`,s.appendChild(c)})):(r&&(r.style.display="inline-block"),["running","cycling","walking"].forEach(c=>{if(n.has(c)){let m=document.createElement("button");m.className=`mini-pill${Te.sport===c?" active":""}`,m.dataset.sport=c,m.title=c.charAt(0).toUpperCase()+c.slice(1),m.innerHTML=`${ns(c)}`,s.appendChild(m)}}),o.forEach(c=>{let m=document.createElement("div");m.className=`dropdown-item${Te.sport===c?" active":""}`,m.dataset.sport=c,m.style.padding="8px",m.style.cursor="pointer",m.style.display="flex",m.style.alignItems="center",m.style.gap="8px",m.innerHTML=` - ${ns(c)} + `,document.body.appendChild(n);let t=n.querySelector(".modal-input"),s=n.querySelector(".modal-btn.confirm"),o=n.querySelector(".modal-btn.cancel");t.focus(),t.addEventListener("input",()=>{s.disabled=t.value!==e});let a=()=>n.remove();o.addEventListener("click",a),n.addEventListener("click",g=>{g.target===n&&a()}),s.addEventListener("click",async()=>{t.value===e&&(a(),Fn=!0,await at.clear(),ze={},Oe=null,De.clearHighlight(),window.location.reload())})}function kt(e=!1){Object.keys(ze).forEach(t=>{let s=ze[t],o=s.stats,a=!0;if(mn)if(un)try{new RegExp(mn,"i").test(s.name)||(a=!1)}catch{a=!1}else s.name.toLowerCase().includes(mn.toLowerCase())||(a=!1);if(a&&(Le.date[0]||Le.date[1])){let g=Le.date[0]?new Date(Le.date[0]).getTime():0,c=Le.date[1]?new Date(Le.date[1]).getTime():1/0,m=o.startTime||0;(mc)&&(a=!1)}if(a&&(Le.dist[0]!==null||Le.dist[1]!==null)){let g=(Le.dist[0]||0)*1e3,c=(Le.dist[1]||1/0)*1e3;(o.totalDistc)&&(a=!1)}if(a&&(Le.dur[0]!==null||Le.dur[1]!==null)){let g=(Le.dur[0]||0)*6e4,c=(Le.dur[1]||1/0)*6e4,m=o.duration||0;(mc)&&(a=!1)}if(a&&Le.metrics.size>0)for(let g of Le.metrics){let c=Se.METRICS[g].field;if(!s.points.some(m=>m[c]!=null)){a=!1;break}}if(a&&Le.sport&&s.sport!==Le.sport&&(a=!1),a&&Le.tags.length>0){let g=s.tags||[];Le.tags.every(c=>g.includes(c))||(a=!1)}s._filtered=!a,De.setTrackVisible(s.id,s.visible&&a)}),e||xn()}function Xn(){document.getElementById("filter-date-start").value=Le.date[0]||"",document.getElementById("filter-date-end").value=Le.date[1]||"",document.getElementById("filter-dist-min").value=Le.dist[0]!==null?String(Le.dist[0]):"",document.getElementById("filter-dist-max").value=Le.dist[1]!==null?String(Le.dist[1]):"",document.getElementById("filter-dur-min").value=Le.dur[0]!==null?String(Le.dur[0]):"",document.getElementById("filter-dur-max").value=Le.dur[1]!==null?String(Le.dur[1]):"",document.getElementById("filter-tags").value=Le.tags.join(", "),document.querySelectorAll("#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item").forEach(t=>{let s=t;s.classList.toggle("active",(s.dataset.sport||"")===(Le.sport||""))}),document.querySelectorAll("#filter-metrics .mini-pill").forEach(t=>{let s=t;s.classList.toggle("active",Le.metrics.has(s.dataset.metric))});let e=(Le.date[0]?1:0)+(Le.date[1]?1:0)+(Le.dist[0]!==null?1:0)+(Le.dist[1]!==null?1:0)+(Le.dur[0]!==null?1:0)+(Le.dur[1]!==null?1:0)+Le.metrics.size+(Le.tags.length>0?1:0),n=document.querySelector("#btn-toggle-filters .btn-badge");n&&(n.textContent=e>0?String(e):"",n.classList.toggle("hidden",e===0))}function ro(){let e=document.getElementById("track-search");e&&(e.value=mn),document.getElementById("btn-regex-toggle")?.classList.toggle("active",un);let n=io.find(t=>t.val===vn);if(n){let t=document.getElementById("sort-current-label"),s=document.getElementById("sort-current-icon");t&&(t.textContent=n.label.replace(" first","").replace(" distance","").replace(" duration","")),s&&(s.textContent=n.icon)}}function oo(e){let n=e.track;if(n!==Oe&&(n&&ze[n]?Mt(n,!0):!n&&Oe&&(Oe=null,Se.clear(),an(null,[]),_t(null),xn(),De.fitAll())),e.map&&typeof e.map=="string"&&(De.switchBasemap(e.map),document.querySelectorAll(".bm-btn").forEach(s=>s.classList.toggle("active",s.dataset.layer===e.map))),e.map_pos){let[s,o,a]=e.map_pos;De.setPosition(s,o,a)}e.tab&&document.querySelectorAll(".tab-btn").forEach(s=>{let o=s;o.dataset.tab===e.tab&&(o.classList.contains("active")||o.click())}),e.xaxis&&Se.setXAxis(e.xaxis);let t=e.xaxis||"time";if(document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(s=>s.classList.toggle("active",s.dataset.axis===t)),e.metrics){let s=Se.METRICS,o=e.metrics.map(a=>Object.keys(s).find(g=>s[g].abbr===a)).filter(a=>a!==void 0);o.length&&Se.setActiveMetrics(o)}e.f_date&&(Le.date=e.f_date.map(s=>s||null)),e.f_dist&&(Le.dist=e.f_dist.map(s=>s===0?0:s||null)),e.f_dur&&(Le.dur=e.f_dur.map(s=>s===0?0:s||null)),e.f_mets&&(Le.metrics=new Set(e.f_mets)),e.f_tags&&(Le.tags=e.f_tags),Xn(),e.q&&(mn=e.q),e.re&&(un=e.re),e.sort&&(vn=e.sort),ro(),kt()}function pi(){if(!document.getElementById("sport-filter-container"))return;let n=document.getElementById("common-sports"),t=document.getElementById("sport-dropdown-content");if(!n||!t)return;let s=new Set;Object.values(ze).forEach(g=>{g.sport&&s.add(g.sport)});let o=Array.from(s).sort(),a=document.getElementById("sport-burger-dropdown");n.innerHTML="",t.innerHTML="",o.length<=4?(a&&(a.style.display="none"),o.forEach(g=>{let c=document.createElement("button");c.className=`mini-pill${Le.sport===g?" active":""}`,c.dataset.sport=g,c.title=g.charAt(0).toUpperCase()+g.slice(1),c.innerHTML=`${ks(g)}`,n.appendChild(c)})):(a&&(a.style.display="inline-block"),["running","cycling","walking"].forEach(c=>{if(s.has(c)){let m=document.createElement("button");m.className=`mini-pill${Le.sport===c?" active":""}`,m.dataset.sport=c,m.title=c.charAt(0).toUpperCase()+c.slice(1),m.innerHTML=`${ks(c)}`,n.appendChild(m)}}),o.forEach(c=>{let m=document.createElement("div");m.className=`dropdown-item${Le.sport===c?" active":""}`,m.dataset.sport=c,m.style.padding="8px",m.style.cursor="pointer",m.style.display="flex",m.style.alignItems="center",m.style.gap="8px",m.innerHTML=` + ${ks(c)} ${c.charAt(0).toUpperCase()+c.slice(1)} - `,t.appendChild(m)}))}function mn(){ro();let e=document.getElementById("track-list"),s=document.getElementById("track-list-empty"),t=document.querySelector(".section-label");if(!e)return;let n=Object.keys(ze).filter(o=>!ze[o]._filtered);if(t&&(t.textContent=`Tracks (${n.length})`),!n.length){e.innerHTML="",s&&(e.appendChild(s),s.style.display="block");return}s&&(s.style.display="none"),e.innerHTML="",n.sort((o,r)=>{if(o===Oe)return-1;if(r===Oe)return 1;let u=ze[o],c=ze[r],m=u.stats,T=c.stats,b=0;switch(dn){case"date-asc":b=(m.startTime||0)-(T.startTime||0);break;case"date-desc":b=(T.startTime||0)-(m.startTime||0);break;case"dist-asc":b=(m.totalDist||0)-(T.totalDist||0);break;case"dist-desc":b=(T.totalDist||0)-(m.totalDist||0);break;case"dur-asc":b=(m.duration||0)-(T.duration||0);break;case"dur-desc":b=(T.duration||0)-(m.duration||0);break;default:b=0}return b||o.localeCompare(r)}).forEach(o=>{e.appendChild(co(ze[o]))})}function ws(){let e=new Set;return Object.values(ze).forEach(s=>{(s.tags||[]).forEach(t=>e.add(t))}),Array.from(e).sort()}function ns(e){if(!e)return"category";let s=e.toLowerCase();return s.includes("run")?"directions_run":s.includes("cycl")||s.includes("bike")?"directions_bike":s.includes("walk")?"directions_walk":s.includes("swim")?"pool":s.includes("hik")?"hiking":"sports"}function co(e){let s=document.createElement("div");s.className=`track-item${e.id===Oe?" selected":""}`,s.dataset.id=e.id;let t=e.points.length&&e.points[0].time?Zt(e.points[0].time):"Unknown date",n=(e.tags||[]).length>0?`
${(e.tags||[]).map(r=>{let u=Qn(r);return`${pt(r)}`}).join("")}
`:"";s.innerHTML=` + `,t.appendChild(m)}))}function xn(){pi();let e=document.getElementById("track-list"),n=document.getElementById("track-list-empty"),t=document.querySelector(".section-label");if(!e)return;let s=Object.keys(ze).filter(o=>!ze[o]._filtered);if(t&&(t.textContent=`Tracks (${s.length})`),!s.length){e.innerHTML="",n&&(e.appendChild(n),n.style.display="block");return}n&&(n.style.display="none"),e.innerHTML="",s.sort((o,a)=>{if(o===Oe)return-1;if(a===Oe)return 1;let g=ze[o],c=ze[a],m=g.stats,T=c.stats,f=0;switch(vn){case"date-asc":f=(m.startTime||0)-(T.startTime||0);break;case"date-desc":f=(T.startTime||0)-(m.startTime||0);break;case"dist-asc":f=(m.totalDist||0)-(T.totalDist||0);break;case"dist-desc":f=(T.totalDist||0)-(m.totalDist||0);break;case"dur-asc":f=(m.duration||0)-(T.duration||0);break;case"dur-desc":f=(T.duration||0)-(m.duration||0);break;default:f=0}return f||o.localeCompare(a)}).forEach(o=>{e.appendChild(fi(ze[o]))})}function Xs(){let e=new Set;return Object.values(ze).forEach(n=>{(n.tags||[]).forEach(t=>e.add(t))}),Array.from(e).sort()}function ks(e){if(!e)return"category";let n=e.toLowerCase();return n.includes("run")?"directions_run":n.includes("cycl")||n.includes("bike")?"directions_bike":n.includes("walk")?"directions_walk":n.includes("swim")?"pool":n.includes("hik")?"hiking":"sports"}function fi(e){let n=document.createElement("div");n.className=`track-item${e.id===Oe?" selected":""}`,n.dataset.id=e.id;let t=e.points.length&&e.points[0].time?Gt(e.points[0].time):"Unknown date",s=(e.tags||[]).length>0?`
${(e.tags||[]).map(a=>{let g=gs(a);return`${pt(a)}`}).join("")}
`:"";n.innerHTML=`
${pt(e.displayName||e.name)}
@@ -879,25 +879,25 @@ var Ye=(()=>{let e={},s=null,t=null,n=!1;function o(){let b=new URLSearchParams(
${t} ${Math.round(e.stats.totalDist/1e3)} km - ${e.sport?`${ns(e.sport)}`:""} + ${e.sport?`${ks(e.sport)}`:""} ${e.format.toUpperCase()}
- ${n} + ${s} - `,s.addEventListener("click",r=>{r.target.closest(".icon-btn")||Mt(e.id)});let o=s.querySelector(".toggle-vis");return o.addEventListener("click",()=>{e.visible=!e.visible,o.querySelector(".material-symbols-rounded").textContent=e.visible?"visibility":"visibility_off",_e.setTrackVisible(e.id,e.visible),at.save(e)}),s}function ls(e,s="info"){let t=document.getElementById("toast-container");if(!t)return;t.innerHTML="";let n=document.createElement("div");n.className=`toast ${s}`,n.textContent=e,t.appendChild(n)}function uo(){let e=document.createElement("div");e.className="modal-backdrop";let s="";Tt.forEach(r=>{s+=`
${r.name}: ${r.reason}
`}),e.innerHTML=` + `,n.addEventListener("click",a=>{a.target.closest(".icon-btn")||Mt(e.id)});let o=n.querySelector(".toggle-vis");return o.addEventListener("click",()=>{e.visible=!e.visible,o.querySelector(".material-symbols-rounded").textContent=e.visible?"visibility":"visibility_off",De.setTrackVisible(e.id,e.visible),at.save(e)}),n}function Cs(e,n="info"){let t=document.getElementById("toast-container");if(!t)return;t.innerHTML="";let s=document.createElement("div");s.className=`toast ${n}`,s.textContent=e,t.appendChild(s)}function gi(){let e=document.createElement("div");e.className="modal-backdrop";let n="";Tt.forEach(a=>{n+=`
${a.name}: ${a.reason}
`}),e.innerHTML=` - `,document.body.appendChild(e);let t=e.querySelector(".modal-btn.cancel"),n=e.querySelector(".modal-btn.clear"),o=()=>e.remove();t.addEventListener("click",o),n.addEventListener("click",()=>{Tt=[],o();let r=document.getElementById("import-warning");r&&r.classList.add("hidden")}),e.addEventListener("click",r=>{r.target===e&&o()})}function mo(){let e=document.getElementById("drop-zone");if(!e)return;let s=document.getElementById("import-warning");s&&s.addEventListener("click",t=>{t.stopPropagation(),uo()}),window.addEventListener("dragover",t=>{t.preventDefault(),e.classList.add("drop-active")}),window.addEventListener("dragleave",t=>{t.relatedTarget===null&&e.classList.remove("drop-active")}),window.addEventListener("drop",async t=>{t.preventDefault(),e.classList.remove("drop-active");let n=t.dataTransfer?.items;if(!n)return;let o=[],r=[];for(let c=0;cc.file(T));o.push(m)}else if(c.isDirectory){let m=c.createReader(),T=[],b;do b=await new Promise(w=>m.readEntries(w)),T.push(...b);while(b.length>0);for(let w of T)await u(w)}}for(let c of r)await u(c);o.length&&os(o)})}async function os(e){if(!e.length)return;Sn=!1;let s=Tt.length,t=document.getElementById("global-loader"),n=document.getElementById("loader-text"),o=document.getElementById("loader-subtext"),r=document.getElementById("loader-progress-bar"),u=document.getElementById("loader-close");u&&u.addEventListener("click",()=>{Sn=!0,t&&t.classList.add("hidden")});function c(){let m=document.querySelector(".loader-icon-wrap span");m&&(m.textContent="warning",m.style.color="#f59e0b");let T=document.getElementById("loader-warning-count");if(T){let b=Tt.length-s,w=T.querySelector("span");w&&(w.textContent=`${b}`),T.style.display="flex"}}if(t){n&&(n.textContent=`Importing ${e.length} file${e.length>1?"s":""}`);let m=document.querySelector(".loader-icon-wrap span");m&&(m.textContent="download",m.style.color="var(--accent)");let T=document.getElementById("loader-warning-count");if(T){T.style.display="none";let b=T.querySelector("span");b&&(b.textContent="0")}o&&(o.textContent=""),r&&(r.style.width="0%"),t.classList.remove("hidden"),Tt.length>s&&c()}try{let m=0,T=null,b=0,w=e.filter(I=>{let P=I.name.toLowerCase();return P.endsWith(".gpx")||P.endsWith(".fit")||P.endsWith(".tcx")||P.endsWith(".kml")});if(e.filter(I=>!w.includes(I)).forEach(I=>{Tt.push({name:I.name,reason:"Unsupported file format"})}),w.length===0){if(e.length>0){ls("No valid GPS files found","error");let I=document.getElementById("import-warning");I&&Tt.length>0&&(I.classList.remove("hidden"),I.title=`Skipped ${Tt.length} imports. Click to view details.`)}return}let S=document.getElementById("loader-filename"),k=null;if(o){o.innerHTML='',k=o.querySelector(".progress-index");let I=o.querySelector(".progress-total");I&&(I.textContent=w.length.toString())}for(let I=0;Ia.fileName===P.name&&a.fileSize===P.size)){Tt.push({name:P.name,reason:"Same File"}),c();continue}let q=p.stats.startTime,J=p.stats.duration;if(q!=null&&J!=null){let a=q+J,G=h.filter(se=>se.stats.startTime!=null&&Zl(q,se.stats.startTime)),X=!1;for(let se of G){let U=se.stats.startTime,ne=se.stats.duration,Le=U+ne;if(q>=U&&a<=Le){Tt.push({name:P.name,reason:"Fully contained in another track"}),c(),X=!0;break}if(Math.min(a,Le)-Math.max(q,U)>6e5){Tt.push({name:P.name,reason:"Overlaps with an existing track for more than 10 mins"}),c(),X=!0;break}}if(X)continue}let Y=17855424e5,B=Ds(p.stats.startTime||Y);ze[B]&&(B+=`-${Rs()}`);let z=p.name;(z.startsWith("Unnamed")||z.startsWith("Fit Activity"))&&(z=P.name);let D=z,le=p.points[0]?.time,y=p.sport?p.sport.charAt(0).toUpperCase()+p.sport.slice(1):"Activity";if(le){let a=new Date(le);D=`${a.getUTCFullYear()}-${String(a.getUTCMonth()+1).padStart(2,"0")}-${String(a.getUTCDate()).padStart(2,"0")} ${y}`}else D=z.replace(/\.[^/.]+$/,"").replace(/_/g," ");let d={...p,id:B,name:z,displayName:D,fileName:P.name,fileSize:P.size,bounds:ms(p.points)||void 0,simplifiedPoints:ps(p.points,50),addedAt:p.stats.startTime||Y,visible:!0,color:ss[Dn%ss.length]};if(Dn++,Sn)break;await at.save(d),ze[B]=d,_e.addTrack(d),T||(T=B),m++,b++,b>=5&&(b=0)}catch(p){Tt.push({name:P.name,reason:`Parse error: ${p instanceof Error?p.message:String(p)}`}),c()}}let M=document.getElementById("import-warning");M&&(Tt.length>0?(M.classList.remove("hidden"),M.title=`Skipped ${Tt.length} imports. Click to view details.`):M.classList.add("hidden"));let g=Tt.length>s;if(!g&&t&&t.classList.add("hidden"),m>0&&(ls(`Imported ${m} track${m>1?"s":""}`),kt(!!T&&T!==Oe),T&&Mt(T)),g){let I=document.querySelector(".loader-icon-wrap span");I&&(I.textContent="warning"),await new Promise(P=>setTimeout(P,1500))}}finally{t&&t.classList.add("hidden")}}function po(){let e=document.getElementById("metric-pills");if(!e)return;let s=null;e.addEventListener("dragstart",t=>{let n=t.target.closest(".metric-pill");n&&(s=n,t.dataTransfer.effectAllowed="move",n.classList.add("dragging-pill"),setTimeout(()=>n.style.opacity="0.4",0))}),e.addEventListener("dragover",t=>{t.preventDefault(),t.dataTransfer.dropEffect="move";let n=t.target.closest(".metric-pill");if(n&&n!==s){let o=n.getBoundingClientRect(),r=t.clientX-o.left>o.width/2;e.insertBefore(s,r?n.nextSibling:n)}}),e.addEventListener("dragend",()=>{if(!s)return;s.classList.remove("dragging-pill"),s.style.opacity="",s=null;let t=Array.from(e.querySelectorAll(".metric-pill")).map(n=>n.dataset.metric);Me.updateMetricOrder(t),ys()})}function kn(){let e=document.getElementById("chart-toolbar"),s=document.getElementById("metric-pills");if(!e||!s)return;e.classList.remove("collapsed");let t=Math.max(0,e.clientWidth-280),n=0,o=!1;Array.from(s.children).forEach(u=>{let c=u;if(c.id==="pill-overflow"||(c.classList.remove("overflow-hidden"),!c.classList.contains("active")))return;let T=36+(c.dataset.metric||"").length*6;n+=T+6,n>t&&(o=!0,c.classList.add("overflow-hidden"))});let r=document.getElementById("pill-overflow");r&&r.classList.toggle("hidden",!o),o&&e.classList.add("collapsed")}document.addEventListener("DOMContentLoaded",Jl);export{Mt as selectTrack}; + `,document.body.appendChild(e);let t=e.querySelector(".modal-btn.cancel"),s=e.querySelector(".modal-btn.clear"),o=()=>e.remove();t.addEventListener("click",o),s.addEventListener("click",()=>{Tt=[],o();let a=document.getElementById("import-warning");a&&a.classList.add("hidden")}),e.addEventListener("click",a=>{a.target===e&&o()})}function hi(){let e=document.getElementById("drop-zone");if(!e)return;let n=document.getElementById("import-warning");n&&n.addEventListener("click",t=>{t.stopPropagation(),gi()}),window.addEventListener("dragover",t=>{t.preventDefault(),e.classList.add("drop-active")}),window.addEventListener("dragleave",t=>{t.relatedTarget===null&&e.classList.remove("drop-active")}),window.addEventListener("drop",async t=>{t.preventDefault(),e.classList.remove("drop-active");let s=t.dataTransfer?.items;if(!s)return;let o=[],a=[];for(let c=0;cc.file(T));o.push(m)}else if(c.isDirectory){let m=c.createReader(),T=[],f;do f=await new Promise(M=>m.readEntries(M)),T.push(...f);while(f.length>0);for(let M of T)await g(M)}}for(let c of a)await g(c);o.length&&$s(o)})}async function $s(e){if(!e.length)return;Fn=!1;let n=Tt.length,t=document.getElementById("global-loader"),s=document.getElementById("loader-text"),o=document.getElementById("loader-subtext"),a=document.getElementById("loader-progress-bar"),g=document.getElementById("loader-close");g&&g.addEventListener("click",()=>{Fn=!0,t&&t.classList.add("hidden")});function c(){let m=document.querySelector(".loader-icon-wrap span");m&&(m.textContent="warning",m.style.color="#f59e0b");let T=document.getElementById("loader-warning-count");if(T){let f=Tt.length-n,M=T.querySelector("span");M&&(M.textContent=`${f}`),T.style.display="flex"}}if(t){s&&(s.textContent=`Importing ${e.length} file${e.length>1?"s":""}`);let m=document.querySelector(".loader-icon-wrap span");m&&(m.textContent="download",m.style.color="var(--accent)");let T=document.getElementById("loader-warning-count");if(T){T.style.display="none";let f=T.querySelector("span");f&&(f.textContent="0")}o&&(o.textContent=""),a&&(a.style.width="0%"),t.classList.remove("hidden"),Tt.length>n&&c()}try{let m=0,T=null,f=0,M=e.filter(P=>{let b=P.name.toLowerCase();return b.endsWith(".gpx")||b.endsWith(".fit")||b.endsWith(".tcx")||b.endsWith(".kml")});if(e.filter(P=>!M.includes(P)).forEach(P=>{Tt.push({name:P.name,reason:"Unsupported file format"})}),M.length===0){if(e.length>0){Cs("No valid GPS files found","error");let P=document.getElementById("import-warning");P&&Tt.length>0&&(P.classList.remove("hidden"),P.title=`Skipped ${Tt.length} imports. Click to view details.`)}return}let H=document.getElementById("loader-filename"),E=null;if(o){o.innerHTML='',E=o.querySelector(".progress-index");let P=o.querySelector(".progress-total");P&&(P.textContent=M.length.toString())}for(let P=0;Pr.fileName===b.name&&r.fileSize===b.size)){Tt.push({name:b.name,reason:"Same File"}),c();continue}let D=u.stats.startTime,W=u.stats.duration;if(D!=null&&W!=null){let r=D+W,J=x.filter(Q=>Q.stats.startTime!=null&&Ko(D,Q.stats.startTime)),U=!1;for(let Q of J){let Y=Q.stats.startTime,K=Q.stats.duration,Ae=Y+K;if(D>=Y&&r<=Ae){Tt.push({name:b.name,reason:"Fully contained in another track"}),c(),U=!0;break}if(Math.min(r,Ae)-Math.max(D,Y)>6e5){Tt.push({name:b.name,reason:"Overlaps with an existing track for more than 10 mins"}),c(),U=!0;break}}if(U)continue}let _=17855424e5,C=pl(u.stats.startTime||_);ze[C]&&(C+=`-${fl()}`);let q=u.name;(q.startsWith("Unnamed")||q.startsWith("Fit Activity"))&&(q=b.name);let N=q,ie=u.points[0]?.time,y=u.sport?u.sport.charAt(0).toUpperCase()+u.sport.slice(1):"Activity";if(ie){let r=new Date(ie);N=`${r.getUTCFullYear()}-${String(r.getUTCMonth()+1).padStart(2,"0")}-${String(r.getUTCDate()).padStart(2,"0")} ${y}`}else N=q.replace(/\.[^/.]+$/,"").replace(/_/g," ");let d={...u,id:C,name:q,displayName:N,fileName:b.name,fileSize:b.size,bounds:hs(u.points)||void 0,simplifiedPoints:bs(u.points,50),addedAt:u.stats.startTime||_,visible:!0,color:Jn[Qn%Jn.length]};if(Qn++,Fn)break;await at.save(d),ze[C]=d,De.addTrack(d),T||(T=C),m++,f++,f>=5&&(f=0)}catch(u){Tt.push({name:b.name,reason:`Parse error: ${u instanceof Error?u.message:String(u)}`}),c()}}let k=document.getElementById("import-warning");k&&(Tt.length>0?(k.classList.remove("hidden"),k.title=`Skipped ${Tt.length} imports. Click to view details.`):k.classList.add("hidden"));let p=Tt.length>n;if(!p&&t&&t.classList.add("hidden"),m>0&&(Cs(`Imported ${m} track${m>1?"s":""}`),kt(!!T&&T!==Oe),T&&Mt(T)),p){let P=document.querySelector(".loader-icon-wrap span");P&&(P.textContent="warning"),await new Promise(b=>setTimeout(b,1500))}}finally{t&&t.classList.add("hidden")}}function bi(){let e=document.getElementById("metric-pills");if(!e)return;let n=null;e.addEventListener("dragstart",t=>{let s=t.target.closest(".metric-pill");s&&(n=s,t.dataTransfer.effectAllowed="move",s.classList.add("dragging-pill"),setTimeout(()=>s.style.opacity="0.4",0))}),e.addEventListener("dragover",t=>{t.preventDefault(),t.dataTransfer.dropEffect="move";let s=t.target.closest(".metric-pill");if(s&&s!==n){let o=s.getBoundingClientRect(),a=t.clientX-o.left>o.width/2;e.insertBefore(n,a?s.nextSibling:s)}}),e.addEventListener("dragend",()=>{if(!n)return;n.classList.remove("dragging-pill"),n.style.opacity="",n=null;let t=Array.from(e.querySelectorAll(".metric-pill")).map(s=>s.dataset.metric);Se.updateMetricOrder(t),Zs()})}function Bn(){let e=document.getElementById("chart-toolbar"),n=document.getElementById("metric-pills");if(!e||!n)return;e.classList.remove("collapsed");let t=Math.max(0,e.clientWidth-280),s=0,o=!1;Array.from(n.children).forEach(g=>{let c=g;if(c.id==="pill-overflow"||(c.classList.remove("overflow-hidden"),!c.classList.contains("active")))return;let T=36+(c.dataset.metric||"").length*6;s+=T+6,s>t&&(o=!0,c.classList.add("overflow-hidden"))});let a=document.getElementById("pill-overflow");a&&a.classList.toggle("hidden",!o),o&&e.classList.add("collapsed")}document.addEventListener("DOMContentLoaded",ni);export{Mt as selectTrack}; //# sourceMappingURL=tools-gps-tracks.mjs.map diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map index 50e5f9f953..9c96acb43e 100644 --- a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/url-state.ts", "../src/storage.ts", "../src/parsers.ts", "../src/utils.ts", "../src/map.ts", "../src/charts.ts", "../src/zones.ts", "../src/metrics.ts", "../src/sports.ts", "../src/tabs/details.ts", "../src/tabs/insights.ts", "../src/tabs/courses.ts", "../src/tabs/combined.ts", "../src/tabs/progress.ts", "../src/tabs/accumulated_progress.ts", "../src/app.ts"], - "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 URL State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Handles reading/writing application state to the URL.\n// Uses an incremental \"patch\" approach to preserve existing params.\n\nexport interface AppState {\n track?: string;\n map?: string;\n xaxis?: string;\n metrics?: string[];\n f_date?: (string | null)[];\n f_dist?: (number | null)[];\n f_dur?: (number | null)[];\n f_mets?: string[];\n f_tags?: string[];\n q?: string;\n re?: boolean;\n sort?: string;\n map_pos?: [number, number, number];\n storage?: 'memory' | 'indexeddb';\n sel?: [number, number];\n sel_point?: number;\n tab?: string;\n progress?: string;\n speed_mode?: string;\n}\n\nexport const UrlState = (() => {\n // Internal state object, initialized from current URL.\n let _state: AppState = {};\n let _lastSearch: string | null = null;\n let _syncTimeout: any = null;\n let _shouldPush = false;\n\n function read(): AppState {\n const p = new URLSearchParams(location.search);\n const s: AppState = {};\n\n if (p.has('track')) s.track = p.get('track')!;\n if (p.has('map')) s.map = p.get('map')!;\n if (p.has('xaxis')) s.xaxis = p.get('xaxis')!;\n if (p.has('tab')) s.tab = p.get('tab')!;\n if (p.has('sel_point')) s.sel_point = Number(p.get('sel_point'));\n if (p.has('speed_mode')) s.speed_mode = p.get('speed_mode')!;\n if (p.has('progress')) s.progress = p.get('progress')!;\n const metricsRaw = p.get('metrics');\n if (metricsRaw) s.metrics = metricsRaw.split(',').filter(Boolean);\n\n if (p.has('f_date')) {\n s.f_date = p\n .get('f_date')!\n .split(',')\n .map((v) => v || null);\n }\n if (p.has('f_dist')) {\n s.f_dist = p\n .get('f_dist')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_dur')) {\n s.f_dur = p\n .get('f_dur')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_mets')) s.f_mets = p.get('f_mets')!.split(',');\n if (p.has('f_tags')) s.f_tags = p.get('f_tags')!.split(',');\n\n if (p.has('q')) s.q = p.get('q')!;\n if (p.has('re')) s.re = p.get('re') === '1';\n if (p.has('sort')) {\n const v = p.get('sort')!;\n const isDesc = v.startsWith('-');\n const field = isDesc ? v.substring(1) : v;\n s.sort = `${field}-${isDesc ? 'desc' : 'asc'}`;\n }\n\n if (p.has('map_pos')) {\n const parts = p.get('map_pos')!.split(',').map(Number);\n if (parts.length === 3 && parts.every(isFinite))\n s.map_pos = parts as [number, number, number];\n }\n\n if (p.has('storage')) s.storage = p.get('storage') as 'memory' | 'indexeddb';\n if (p.has('sel')) {\n const parts = p.get('sel')!.split(',').map(Number);\n if (parts.length === 2 && parts.every((v) => !isNaN(v) && isFinite(v)))\n s.sel = parts as [number, number];\n }\n\n return s;\n }\n\n // Sync _state to browser URL synchronously so no pending timer leaks across steps\n function _sync() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n\n const p = new URLSearchParams();\n\n // Add standard encoded params\n if (_state.track) p.set('track', _state.track);\n if (_state.map) p.set('map', _state.map);\n if (_state.xaxis && _state.xaxis !== 'time') p.set('xaxis', _state.xaxis);\n if (_state.tab && _state.tab !== 'graphs') p.set('tab', _state.tab);\n if (_state.storage && _state.storage !== 'memory') p.set('storage', _state.storage);\n if (_state.sel_point !== undefined) p.set('sel_point', String(_state.sel_point));\n if (_state.speed_mode) p.set('speed_mode', _state.speed_mode);\n if (_state.q) p.set('q', _state.q);\n if (_state.progress) p.set('progress', _state.progress);\n if (_state.re) p.set('re', '1');\n\n if (_state.sort) {\n const parts = _state.sort.split('-');\n const field = parts[0];\n const dir = parts[1];\n p.set('sort', (dir === 'desc' ? '-' : '') + field);\n }\n\n let search = p.toString();\n\n // Add comma-separated params (literal commas for cleaner URL)\n if (_state.metrics) search += `${search ? '&' : ''}metrics=${_state.metrics.join(',')}`;\n\n if (_state.f_date)\n search += `${search ? '&' : ''}f_date=${_state.f_date.map((v) => v || '').join(',')}`;\n\n if (_state.f_dist)\n search += `${search ? '&' : ''}f_dist=${_state.f_dist.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_dur)\n search += `${search ? '&' : ''}f_dur=${_state.f_dur.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_mets) search += `${search ? '&' : ''}f_mets=${_state.f_mets.join(',')}`;\n\n if (_state.f_tags) search += `${search ? '&' : ''}f_tags=${_state.f_tags.join(',')}`;\n\n if (_state.map_pos) {\n const val = `${(+_state.map_pos[0]).toFixed(5)},${(+_state.map_pos[1]).toFixed(5)},${\n _state.map_pos[2]\n }`;\n search += `${search ? '&' : ''}map_pos=${val}`;\n }\n if (_state.sel) {\n const val = `${+_state.sel[0].toFixed(4)},${+_state.sel[1].toFixed(4)}`;\n search += `${search ? '&' : ''}sel=${val}`;\n }\n\n if (search !== _lastSearch) {\n const url = location.pathname + (search ? `?${search}` : '');\n if (_shouldPush) {\n history.pushState(null, '', url);\n _shouldPush = false;\n } else {\n history.replaceState(null, '', url);\n }\n _lastSearch = search;\n }\n }\n\n // Initial read\n _state = read();\n\n function get(): AppState {\n return { ..._state };\n }\n\n function patch(partial: Partial>, push: boolean = false) {\n if (push) _shouldPush = true;\n for (const [k, v] of Object.entries(partial)) {\n const key = k as keyof AppState;\n if (v === null || v === undefined) delete _state[key];\n else (_state as any)[key] = v;\n }\n _sync();\n }\n\n function refresh() {\n _state = read();\n }\n\n function reset() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n _state = {};\n _shouldPush = false;\n _lastSearch = '';\n history.replaceState(null, '', location.pathname);\n }\n\n return { get, patch, refresh, reset };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport { TrackData } from './parsers';\nimport { UrlState } from './url-state';\n\nexport interface StorageDriver {\n openDB(): Promise;\n save(track: TrackData): Promise;\n getAll(): Promise;\n remove(id: string): Promise;\n clear(): Promise;\n set(key: string, value: any): Promise;\n get(key: string): Promise;\n}\n\nclass InMemoryStorage implements StorageDriver {\n private trackStore = new Map();\n private settingStore = new Map();\n\n async openDB(): Promise {\n return Promise.resolve();\n }\n\n async save(track: TrackData): Promise {\n this.trackStore.set(track.id, track);\n return Promise.resolve();\n }\n\n async getAll(): Promise {\n return Promise.resolve(Array.from(this.trackStore.values()));\n }\n\n async remove(id: string): Promise {\n this.trackStore.delete(id);\n return Promise.resolve();\n }\n\n async clear(): Promise {\n this.trackStore.clear();\n this.settingStore.clear();\n return Promise.resolve();\n }\n\n async set(key: string, value: any): Promise {\n this.settingStore.set(key, value);\n return Promise.resolve();\n }\n\n async get(key: string): Promise {\n return Promise.resolve((this.settingStore.get(key) as T) ?? null);\n }\n}\n\nclass IndexedDBStorage implements StorageDriver {\n private db: IDBDatabase | null = null;\n private readonly DB_NAME = 'weg-gps-db';\n private readonly DB_VERSION = 2;\n\n async openDB(): Promise {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains('tracks'))\n db.createObjectStore('tracks', { keyPath: 'id' });\n if (!db.objectStoreNames.contains('settings')) db.createObjectStore('settings');\n };\n req.onsuccess = () => {\n this.db = req.result;\n resolve();\n };\n req.onerror = () => reject(req.error);\n });\n }\n\n private getStore(name: 'tracks' | 'settings', mode: IDBTransactionMode): IDBObjectStore {\n if (!this.db) throw new Error('IndexedDB not opened');\n return this.db.transaction(name, mode).objectStore(name);\n }\n\n async save(track: TrackData): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').put(track);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async getAll(): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readonly').getAll();\n req.onsuccess = () => res(req.result || []);\n req.onerror = () => rej(req.error);\n });\n }\n\n async remove(id: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').delete(id);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async clear(): Promise {\n if (!this.db) return Promise.resolve();\n return new Promise((res, rej) => {\n const tx = this.db!.transaction(['tracks', 'settings'], 'readwrite');\n tx.objectStore('tracks').clear();\n tx.objectStore('settings').clear();\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n }\n\n async set(key: string, value: any): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readwrite').put(value, key);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async get(key: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readonly').get(key);\n req.onsuccess = () => res((req.result as T) ?? null);\n req.onerror = () => rej(req.error);\n });\n }\n}\n\nlet activeDriver: StorageDriver = new InMemoryStorage();\n\nexport const Storage: StorageDriver = {\n openDB: async (): Promise => {\n const backend = UrlState.get().storage;\n activeDriver = backend === 'indexeddb' ? new IndexedDBStorage() : new InMemoryStorage();\n await activeDriver.openDB();\n },\n save: (t) => activeDriver.save(t),\n getAll: () => activeDriver.getAll(),\n remove: (id) => activeDriver.remove(id),\n clear: () => activeDriver.clear(),\n set: (k, v) => activeDriver.set(k, v),\n get: (k: string) => activeDriver.get(k),\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport FitParser from 'fit-file-parser';\nimport { haversine } from './utils';\n\nexport interface TrackPoint {\n lat: number;\n lon: number;\n ele: number | null;\n time: number | null;\n hr: number | null;\n cad: number | null;\n power: number | null;\n speed: number | null;\n temp: number | null;\n gearFront: number | null;\n gearRear: number | null;\n gearFrontTooth: number | null;\n gearRearTooth: number | null;\n battery: number | null;\n gears: number | null;\n dist?: number;\n gradient?: number | null;\n}\n\nexport interface TrackStats {\n totalDist: number;\n elevGain: number;\n elevLoss: number;\n duration: number | null;\n avgSpeed: number | null;\n maxSpeed: number;\n avgPower: number | null;\n maxPower: number;\n avgHR: number | null;\n maxHR: number;\n avgCadence: number | null;\n avgTemp?: number | null;\n minTemp?: number | null;\n maxTemp?: number | null;\n sensors: string[];\n startTime?: number | null;\n powerCurve?: Record | null;\n hrCurve?: Record | null;\n hrZones?: number[] | null; // Time in seconds for each zone\n powerZones?: number[] | null; // Time in seconds for each zone\n shifts?: number | null; // Total number of shifts detected\n avgBattery?: number | null;\n}\n\nexport interface DeviceInfo {\n name?: string;\n manufacturer?: string;\n product?: string;\n serial?: string;\n version?: string;\n hardwareVersion?: string;\n type?: string;\n batteryStatus?: string;\n batteryVoltage?: number;\n batteryLevel?: number;\n sourceType?: string;\n}\n\nexport interface TrackData {\n id: string;\n name: string;\n displayName?: string;\n bounds?: { minLat: number; maxLat: number; minLon: number; maxLon: number };\n fileName?: string;\n fileSize?: number;\n device: string | null;\n devices?: DeviceInfo[];\n sport?: string | null;\n subSport?: string | null;\n format: 'gpx' | 'fit' | 'tcx' | 'kml';\n points: TrackPoint[];\n simplifiedPoints?: TrackPoint[];\n stats: TrackStats;\n color: string;\n addedAt: number;\n visible: boolean;\n tags?: string[];\n _filtered?: boolean;\n}\n\nexport function calculateBounds(pts: TrackPoint[]) {\n if (!pts.length) return null;\n let minLat = pts[0].lat;\n let maxLat = pts[0].lat;\n let minLon = pts[0].lon;\n let maxLon = pts[0].lon;\n for (const p of pts) {\n if (p.lat < minLat) minLat = p.lat;\n if (p.lat > maxLat) maxLat = p.lat;\n if (p.lon < minLon) minLon = p.lon;\n if (p.lon > maxLon) maxLon = p.lon;\n }\n return { minLat, maxLat, minLon, maxLon };\n}\n\nexport function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] {\n if (pts.length <= 2) return pts;\n const result: TrackPoint[] = [pts[0]];\n let lastPoint = pts[0];\n for (let i = 1; i < pts.length - 1; i++) {\n const p = pts[i];\n const d =\n p.dist != null && lastPoint.dist != null\n ? p.dist - lastPoint.dist\n : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon);\n if (d >= minDistanceMeters) {\n result.push(p);\n lastPoint = p;\n }\n }\n result.push(pts[pts.length - 1]); // Always keep the last point\n return result;\n}\n\nexport const Parsers = (() => {\n // \u2500\u2500 Enrich track with distance & metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function enrichPoints(pts: TrackPoint[]): TrackPoint[] {\n let totalDist = 0;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n const d = haversine(prev.lat, prev.lon, p.lat, p.lon);\n totalDist += d;\n\n // Calculate speed if missing (m/s)\n if (p.speed == null && p.time != null && prev.time != null) {\n const dt = (p.time - prev.time) / 1000;\n if (dt > 0 && dt < 10) {\n // Skip big gaps\n p.speed = d / dt;\n }\n }\n\n // Calculate gradient if missing (%)\n if (p.gradient === undefined && p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (d > 0.5) {\n // Only calculate for non-tiny movements to reduce jitter\n p.gradient = (de / d) * 100;\n } else {\n p.gradient = prev.gradient || 0;\n }\n }\n }\n p.dist = totalDist;\n }\n\n // Optional: basic smoothing for gradient\n for (let i = 1; i < pts.length - 1; i++) {\n if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null)\n pts[i].gradient = (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3;\n }\n\n return pts;\n }\n\n // \u2500\u2500 Compute stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let hrZoneThresholds = [120, 140, 160, 180];\n let ftp = 200;\n\n function computeStats(pts: TrackPoint[], includeCurves = false): TrackStats {\n const stats: TrackStats = {\n totalDist: 0,\n elevGain: 0,\n elevLoss: 0,\n duration: null,\n avgSpeed: null,\n maxSpeed: 0,\n avgPower: null,\n maxPower: 0,\n avgHR: null,\n maxHR: 0,\n avgCadence: null,\n avgTemp: null,\n minTemp: null,\n maxTemp: null,\n sensors: [],\n startTime: pts.length ? pts[0].time : null,\n };\n\n if (!pts.length) return stats;\n\n let powerSum = 0,\n powerN = 0;\n let hrSum = 0,\n hrN = 0;\n let cadSum = 0,\n cadN = 0;\n let speedSum = 0,\n speedN = 0;\n let batterySum = 0,\n batteryN = 0;\n let tempSum = 0,\n tempN = 0;\n let hasTemp = false;\n let shifts = 0;\n let hasGears = false;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const diff = p.ele - prev.ele;\n if (diff > 0) stats.elevGain += diff;\n else stats.elevLoss -= diff;\n }\n if (\n (p.gearFront != null && p.gearFront !== prev.gearFront) ||\n (p.gearRear != null && p.gearRear !== prev.gearRear)\n )\n shifts++;\n }\n if (p.power != null) {\n powerSum += p.power;\n powerN++;\n if (p.power > stats.maxPower) stats.maxPower = p.power;\n }\n if (p.hr != null) {\n hrSum += p.hr;\n hrN++;\n if (p.hr > stats.maxHR) stats.maxHR = p.hr;\n }\n if (p.cad != null) {\n cadSum += p.cad;\n cadN++;\n }\n if (p.speed != null) {\n speedSum += p.speed;\n speedN++;\n if (p.speed > stats.maxSpeed) stats.maxSpeed = p.speed;\n }\n if (p.battery != null) {\n batterySum += p.battery;\n batteryN++;\n }\n if (p.temp != null) {\n hasTemp = true;\n tempSum += p.temp;\n tempN++;\n if (stats.minTemp == null || p.temp < stats.minTemp) stats.minTemp = p.temp;\n if (stats.maxTemp == null || p.temp > stats.maxTemp) stats.maxTemp = p.temp;\n }\n if (p.gearFront != null || p.gearRear != null) hasGears = true;\n }\n\n stats.totalDist = pts[pts.length - 1].dist || 0;\n stats.avgPower = powerN ? Math.round(powerSum / powerN) : null;\n stats.avgHR = hrN ? Math.round(hrSum / hrN) : null;\n stats.avgCadence = cadN ? Math.round(cadSum / cadN) : null;\n stats.avgSpeed = speedN ? speedSum / speedN : null;\n stats.avgBattery = batteryN ? Math.round(batterySum / batteryN) : null;\n stats.avgTemp = tempN ? Number((tempSum / tempN).toFixed(1)) : null;\n stats.shifts = hasGears ? shifts : null;\n\n const t0 = pts[0].time;\n const t1 = pts[pts.length - 1].time;\n if (t0 != null && t1 != null) stats.duration = t1 - t0;\n\n if (hrN) {\n stats.sensors.push('Heart Rate');\n if (includeCurves) {\n stats.hrZones = calculateHRZones(pts);\n stats.hrCurve = calculateHRCurve(pts);\n }\n }\n if (cadN) stats.sensors.push('Cadence');\n if (powerN) {\n stats.sensors.push('Power');\n if (includeCurves) {\n stats.powerCurve = calculatePowerCurve(pts);\n stats.powerZones = calculatePowerZones(pts);\n }\n }\n if (hasTemp) stats.sensors.push('Temperature');\n if (hasGears) stats.sensors.push('Shifting');\n if (batteryN) stats.sensors.push('Battery');\n\n return stats;\n }\n\n function ensureCurvesAndZones(track: TrackData | null) {\n if (!track || !track.points || !track.stats) return;\n const pts = track.points;\n const s = track.stats;\n if (s.avgHR != null && !s.hrCurve) {\n s.hrZones = calculateHRZones(pts);\n s.hrCurve = calculateHRCurve(pts);\n }\n if (s.avgPower != null && !s.powerCurve) {\n s.powerCurve = calculatePowerCurve(pts);\n s.powerZones = calculatePowerZones(pts);\n }\n }\n\n const STANDARD_CURVE_DURATIONS = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600,\n ];\n\n function calculateSlidingMax(data: number[], durations: number[]) {\n const len = data.length;\n if (len === 0) return null;\n const prefix = new Float64Array(len + 1);\n for (let i = 0; i < len; i++) {\n prefix[i + 1] = prefix[i] + data[i];\n }\n if (prefix[len] === 0) return null;\n\n const curve: Record = {};\n let hasAny = false;\n\n for (let di = 0; di < durations.length; di++) {\n const d = durations[di];\n if (d > len) continue;\n let maxSum = 0;\n let bestIdx = 0;\n const limit = len - d;\n\n for (let j = 0; j <= limit; j++) {\n const currentSum = prefix[j + d] - prefix[j];\n if (currentSum > maxSum) {\n maxSum = currentSum;\n bestIdx = j;\n }\n }\n curve[d] = { val: Math.round(maxSum / d), idx: bestIdx };\n hasAny = true;\n }\n\n return hasAny ? curve : null;\n }\n\n function calculatePowerCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const powerData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].power || 0;\n powerData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(powerData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { power: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculateHRCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const hrData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].hr || 0;\n hrData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(hrData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { hr: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculatePowerZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0, 0, 0];\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.power == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue;\n\n const pw = p.power;\n if (pw < thresholds[0]) zones[0] += dt;\n else if (pw < thresholds[1]) zones[1] += dt;\n else if (pw < thresholds[2]) zones[2] += dt;\n else if (pw < thresholds[3]) zones[3] += dt;\n else if (pw < thresholds[4]) zones[4] += dt;\n else if (pw < thresholds[5]) zones[5] += dt;\n else zones[6] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setFTP(val: number) {\n ftp = val;\n }\n\n function getFTP() {\n return ftp;\n }\n\n function calculateHRZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0];\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.hr == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue; // Skip gaps\n\n const hr = p.hr;\n if (hr < hrZoneThresholds[0]) zones[0] += dt;\n else if (hr < hrZoneThresholds[1]) zones[1] += dt;\n else if (hr < hrZoneThresholds[2]) zones[2] += dt;\n else if (hr < hrZoneThresholds[3]) zones[3] += dt;\n else zones[4] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setHRZones(thresholds: number[]) {\n hrZoneThresholds = thresholds;\n }\n\n function getHRZones() {\n return [...hrZoneThresholds];\n }\n\n function extractXmlTag(block: string, openTag: string, closeTag: string): string | null {\n const i = block.indexOf(openTag);\n if (i === -1) return null;\n const start = i + openTag.length;\n const j = block.indexOf(closeTag, start);\n if (j === -1) return null;\n const val = block.slice(start, j).trim();\n return val !== '' ? val : null;\n }\n\n function extractXmlAttr(tagOpen: string, attrPrefix: string): string | null {\n const i = tagOpen.indexOf(attrPrefix);\n if (i === -1) return null;\n const start = i + attrPrefix.length;\n const j = tagOpen.indexOf('\"', start);\n if (j === -1) return null;\n return tagOpen.slice(start, j);\n }\n\n let cachedDateKey = -1;\n let cachedDayMs = 0;\n\n function parseIntSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let val = 0;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n val = val * 10 + (c - 48);\n digits++;\n } else {\n break;\n }\n }\n if (digits === 0) return null;\n return neg ? -val : val;\n }\n\n function parseFloatSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let intPart = 0;\n let fracPart = 0;\n let fracDiv = 1;\n let inFrac = false;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n digits++;\n if (!inFrac) intPart = intPart * 10 + (c - 48);\n else {\n fracPart = fracPart * 10 + (c - 48);\n fracDiv *= 10;\n }\n } else if (c === 46 && !inFrac) {\n inFrac = true;\n } else {\n const n = parseFloat(text.slice(start - (neg ? 1 : 0), end));\n return Number.isFinite(n) ? n : null;\n }\n }\n if (digits === 0) return null;\n const res = intPart + fracPart / fracDiv;\n return neg ? -res : res;\n }\n\n function fastParseTimeSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n const len = end - start;\n if (len >= 20 && text.charCodeAt(start + 10) === 84 && text.charCodeAt(end - 1) === 90) {\n const y =\n (text.charCodeAt(start) - 48) * 1000 +\n (text.charCodeAt(start + 1) - 48) * 100 +\n (text.charCodeAt(start + 2) - 48) * 10 +\n (text.charCodeAt(start + 3) - 48);\n const m = (text.charCodeAt(start + 5) - 48) * 10 + (text.charCodeAt(start + 6) - 48);\n const d = (text.charCodeAt(start + 8) - 48) * 10 + (text.charCodeAt(start + 9) - 48);\n const key = (y << 9) | (m << 5) | d;\n if (key !== cachedDateKey) {\n cachedDateKey = key;\n cachedDayMs = Date.UTC(y, m - 1, d);\n }\n const hh = (text.charCodeAt(start + 11) - 48) * 10 + (text.charCodeAt(start + 12) - 48);\n const mm = (text.charCodeAt(start + 14) - 48) * 10 + (text.charCodeAt(start + 15) - 48);\n const ss = (text.charCodeAt(start + 17) - 48) * 10 + (text.charCodeAt(start + 18) - 48);\n let ms = 0;\n if (text.charCodeAt(start + 19) === 46 && len >= 24) {\n ms =\n (text.charCodeAt(start + 20) - 48) * 100 +\n (text.charCodeAt(start + 21) - 48) * 10 +\n (text.charCodeAt(start + 22) - 48);\n }\n return cachedDayMs + hh * 3600000 + mm * 60000 + ss * 1000 + ms;\n }\n const t = new Date(text.slice(start, end)).getTime();\n return Number.isFinite(t) ? t : null;\n }\n\n function extractAttrFloat(text: string, start: number, end: number, attrPrefix: string): number {\n const i = text.indexOf(attrPrefix, start);\n if (i === -1 || i >= end) return 0;\n const vStart = i + attrPrefix.length;\n const j = text.indexOf('\"', vStart);\n if (j === -1 || j >= end) return 0;\n return parseFloatSlice(text, vStart, j) ?? 0;\n }\n\n // \u2500\u2500 GPX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseGPX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTrkpt = text.indexOf('');\n const name =\n (trkIdx !== -1 ? extractXmlTag(header.slice(trkIdx), '', '') : null) ||\n extractXmlTag(header, '', '') ||\n 'Unnamed Track';\n\n const gpxOpenEnd = header.indexOf('>', header.indexOf('', trkStart + 6);\n if (openEnd === -1) break;\n const trkEnd = text.indexOf('', openEnd + 1);\n if (trkEnd === -1) break;\n pos = trkEnd + 8;\n\n const lat = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lat=\"');\n const lon = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lon=\"');\n\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let temp: number | null = null;\n let speed: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = openEnd + 1;\n while (p < trkEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= trkEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= trkEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n // Skip duplicate block when primary fields already parsed\n const tagLen = gt - lt - 1;\n if (c1 === 103 && tagLen === 26 && hr !== null && cad !== null && temp !== null) {\n break;\n }\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > trkEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 3) {\n if (c1 === 101) ele = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 99 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 2) {\n if (c1 === 104 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 4) {\n if (c1 === 116) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if ((c1 === 112 || c1 === 80 || c1 === 87) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 115 || c1 === 83) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if ((c1 === 98 || c1 === 66) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 103 || c1 === 71) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if (c1 === 103) {\n if (text.charCodeAt(lt + 8) === 104 && hr === null)\n hr = parseIntSlice(text, vStart, vEnd);\n else if (gearFront === null) gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (c1 === 71 && gearFront === null) {\n gearFront = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 10) {\n if (c1 === 103 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 103 && text.charCodeAt(lt + 8) === 97 && temp === null)\n temp = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 103 || c1 === 71) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if ((c1 === 103 || c1 === 71) && gearFrontTooth === null)\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 65 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 11 && c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!points.length) throw new Error('No track points found in GPX');\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'gpx', points: pts, stats };\n }\n\n // \u2500\u2500 TCX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseTCX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTp = text.indexOf('');\n const header = firstTp !== -1 ? text.slice(0, firstTp) : text;\n\n const name = extractXmlTag(header, '', '') || 'Unnamed TCX';\n const creatorBlock = extractXmlTag(header, '', '');\n const device = creatorBlock ? extractXmlTag(creatorBlock, '', '') : null;\n\n const points: TrackPoint[] = [];\n let pos = firstTp !== -1 ? firstTp : 0;\n while (pos < text.length) {\n const tpStart = text.indexOf('', pos);\n if (tpStart === -1) break;\n const tpEnd = text.indexOf('', tpStart + 12);\n if (tpEnd === -1) break;\n pos = tpEnd + 13;\n\n let lat: number | null = null;\n let lon: number | null = null;\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let speed: number | null = null;\n let temp: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = tpStart + 12;\n while (p < tpEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= tpEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= tpEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n const tagLen = gt - lt - 1;\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > tpEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 4) {\n if (c1 === 84) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 116 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if (c1 === 86 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 87 || c1 === 80 || c1 === 112) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 83 || c1 === 115) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 66 || c1 === 98) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 71 || c1 === 103) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if ((c1 === 71 || c1 === 103) && gearFront === null)\n gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 10) {\n if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 11) {\n if (c1 === 84 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 71 || c1 === 103) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if (c1 === 65) {\n if (text.charCodeAt(lt + 2) === 108) ele = parseFloatSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if ((c1 === 71 || c1 === 103) && gearFrontTooth === null) {\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 15) {\n if (c1 === 76) lat = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 16) {\n if (c1 === 76) lon = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 2 && c1 === 104 && hr === null) {\n hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 3 && c1 === 99 && cad === null) {\n cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n if (lat == null || lon == null) continue;\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'tcx', points: pts, stats };\n }\n\n function fastDecodeFitData(buf: ArrayBuffer): any | null {\n if (buf.byteLength < 14) return null;\n const dv = new DataView(buf);\n const headerSize = dv.getUint8(0);\n if (headerSize < 12 || headerSize + 2 > buf.byteLength) return null;\n if (\n dv.getUint8(8) !== 0x2e ||\n dv.getUint8(9) !== 0x46 ||\n dv.getUint8(10) !== 0x49 ||\n dv.getUint8(11) !== 0x54\n ) {\n return null;\n }\n const dataSize = dv.getUint32(4, true);\n const endOffset = Math.min(buf.byteLength, headerSize + dataSize);\n const GARMIN_EPOCH_SEC = 631065600;\n const SEMICIRCLE_TO_DEG = 180 / Math.pow(2, 31);\n\n interface FieldDef {\n num: number;\n size: number;\n type: number;\n }\n interface MsgDef {\n littleEndian: boolean;\n globalMsgNum: number;\n fields: FieldDef[];\n recordSize: number;\n }\n const defs: (MsgDef | undefined)[] = new Array(16);\n const file_ids: any[] = [];\n const sessions: any[] = [];\n const records: any[] = [];\n const events: any[] = [];\n const device_infos: any[] = [];\n\n let offset = headerSize;\n while (offset < endOffset) {\n const hdr = dv.getUint8(offset++);\n if ((hdr & 0x80) !== 0 || (hdr & 0x20) !== 0) {\n return null; // Compressed timestamp or developer data: fallback to FitParser\n }\n const localNum = hdr & 0x0f;\n if ((hdr & 0x40) !== 0) {\n if (offset + 5 > endOffset) return null;\n offset++; // reserved\n const arch = dv.getUint8(offset++);\n const littleEndian = arch === 0;\n const globalMsgNum = dv.getUint16(offset, littleEndian);\n offset += 2;\n const numFields = dv.getUint8(offset++);\n if (offset + numFields * 3 > endOffset) return null;\n const fields: FieldDef[] = new Array(numFields);\n let recordSize = 0;\n for (let i = 0; i < numFields; i++) {\n const num = dv.getUint8(offset++);\n const size = dv.getUint8(offset++);\n const type = dv.getUint8(offset++);\n fields[i] = { num, size, type };\n recordSize += size;\n }\n defs[localNum] = { littleEndian, globalMsgNum, fields, recordSize };\n } else {\n const def = defs[localNum];\n if (!def || offset + def.recordSize > endOffset) return null;\n const le = def.littleEndian;\n const gNum = def.globalMsgNum;\n\n if (\n gNum === 20 &&\n def.fields.length === 10 &&\n def.recordSize === 25 &&\n def.fields[0].num === 253 &&\n def.fields[1].num === 0\n ) {\n const ts = dv.getUint32(offset, le);\n const rawLat = dv.getInt32(offset + 4, le);\n const rawLon = dv.getInt32(offset + 8, le);\n const rawAlt = dv.getUint16(offset + 12, le);\n const hr = dv.getUint8(offset + 14);\n const cad = dv.getUint8(offset + 15);\n const rawDist = dv.getUint32(offset + 16, le);\n const rawSpd = dv.getUint16(offset + 20, le);\n const power = dv.getUint16(offset + 22, le);\n const temp = dv.getInt8(offset + 24);\n records.push({\n timestamp: (ts + GARMIN_EPOCH_SEC) * 1000,\n position_lat: rawLat * SEMICIRCLE_TO_DEG,\n position_long: rawLon * SEMICIRCLE_TO_DEG,\n altitude: rawAlt / 5 - 500,\n heart_rate: hr,\n cadence: cad,\n distance: rawDist / 100,\n speed: (rawSpd / 1000) * 3.6,\n power,\n temperature: temp,\n });\n offset += 25;\n continue;\n }\n\n const msg: any = {};\n let fOff = offset;\n for (let i = 0; i < def.fields.length; i++) {\n const f = def.fields[i];\n let val: number = 0;\n const bType = f.type & 0x1f;\n if (f.size === 1) {\n val = bType === 1 ? dv.getInt8(fOff) : dv.getUint8(fOff);\n } else if (f.size === 2) {\n val = bType === 3 ? dv.getInt16(fOff, le) : dv.getUint16(fOff, le);\n } else if (f.size === 4) {\n val = bType === 5 ? dv.getInt32(fOff, le) : dv.getUint32(fOff, le);\n }\n msg[f.num] = val;\n fOff += f.size;\n }\n offset += def.recordSize;\n\n if (gNum === 0) {\n file_ids.push({\n type: msg[0] === 4 ? 'activity' : msg[0],\n manufacturer: msg[1] === 1 ? 'garmin' : msg[1],\n product: msg[2],\n time_created: msg[4] != null ? (msg[4] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n });\n } else if (gNum === 18) {\n const sportMap: Record = { 0: 'generic', 1: 'running', 2: 'cycling' };\n sessions.push({\n start_time: msg[2] != null ? (msg[2] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n sport: sportMap[msg[5]] ?? String(msg[5]),\n sub_sport: msg[6] === 0 ? 'generic' : String(msg[6]),\n });\n } else if (gNum === 20) {\n records.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n position_lat: msg[0] != null ? msg[0] * SEMICIRCLE_TO_DEG : undefined,\n position_long: msg[1] != null ? msg[1] * SEMICIRCLE_TO_DEG : undefined,\n altitude: msg[2] != null ? msg[2] / 5 - 500 : undefined,\n heart_rate: msg[3],\n cadence: msg[4],\n distance: msg[5] != null ? msg[5] / 100 : undefined,\n speed: msg[6] != null ? (msg[6] / 1000) * 3.6 : undefined,\n power: msg[7],\n temperature: msg[13],\n });\n } else if (gNum === 21) {\n const evName =\n msg[0] === 43\n ? 'rear_gear_change'\n : msg[0] === 42\n ? 'front_gear_change'\n : String(msg[0]);\n events.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n event: evName,\n event_type: msg[1] === 3 ? 'marker' : String(msg[1]),\n data: msg[3],\n front_gear_num: msg[9],\n rear_gear_num: msg[11],\n });\n } else if (gNum === 23) {\n device_infos.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n battery_level: msg[32],\n });\n } else {\n return null;\n }\n }\n }\n return { file_ids, sessions, sports: [], records, events, device_infos };\n }\n\n // \u2500\u2500 FIT parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseFIT(buf: ArrayBuffer): Promise {\n return new Promise((resolve, reject) => {\n const handleParsedFitData = (error: any, data: any) => {\n if (error) {\n reject(error);\n return;\n }\n try {\n const name = data.sessions?.[0]?.start_time\n ? `Fit Activity ${new Date(data.sessions[0].start_time).toISOString().split('T')[0]}`\n : 'Unnamed Fit';\n\n // Better device detection\n let device: string | null = null;\n const devices: DeviceInfo[] = [];\n let sport: string | null = null;\n let subSport: string | null = null;\n\n if (data.sports?.[0]) {\n sport = data.sports[0].sport;\n subSport = data.sports[0].sub_sport;\n } else if (data.sessions?.[0]) {\n sport = data.sessions[0].sport;\n subSport = data.sessions[0].sub_sport;\n }\n\n const getDeviceName = (d: any) =>\n d.product_name ||\n d.garmin_product ||\n d.product ||\n d.device_type ||\n d.manufacturer ||\n null;\n\n if (data.file_ids?.[0]) {\n const fid = data.file_ids[0];\n device = getDeviceName(fid);\n devices.push({\n name: fid.product_name || fid.garmin_product || fid.product,\n manufacturer: fid.manufacturer,\n serial: fid.serial_number ? String(fid.serial_number) : undefined,\n version: fid.software_version ? String(fid.software_version) : undefined,\n type: 'main',\n });\n }\n\n if (data.device_infos) {\n data.device_infos.forEach((d: any) => {\n const isMain = d.device_index === 'creator' || d.device_index === 0;\n\n if (isMain) {\n const name = getDeviceName(d);\n // Prefer a name with product_name or garmin_product over generic ones\n if (d.product_name || d.garmin_product || !device) device = name;\n\n // Update existing main device if needed\n if (devices.length > 0 && devices[0].type === 'main') {\n if (d.product_name || d.garmin_product || !devices[0].name)\n devices[0].name = d.product_name || d.garmin_product || d.product;\n\n if (!devices[0].manufacturer) devices[0].manufacturer = d.manufacturer;\n if (!devices[0].serial && d.serial_number)\n devices[0].serial = String(d.serial_number);\n if (!devices[0].version && d.software_version)\n devices[0].version = String(d.software_version);\n if (!devices[0].hardwareVersion && d.hardware_version)\n devices[0].hardwareVersion = String(d.hardware_version);\n }\n return;\n }\n\n devices.push({\n name: d.product_name || d.garmin_product || d.product || d.device_type || 'Sensor',\n manufacturer: d.manufacturer,\n serial: d.serial_number ? String(d.serial_number) : undefined,\n version: d.software_version ? String(d.software_version) : undefined,\n hardwareVersion: d.hardware_version ? String(d.hardware_version) : undefined,\n type: d.device_type || 'sensor',\n batteryStatus: d.battery_status,\n batteryVoltage: d.battery_voltage,\n batteryLevel: d.battery_level,\n sourceType: d.source_type != null ? String(d.source_type) : undefined,\n });\n });\n }\n\n if (data.sensor_settings) {\n data.sensor_settings.forEach((s: any) => {\n const name = s.name || s.product || s.sensor_type;\n if (!name) return;\n\n // Check if we already have this device (by ANT ID or name)\n const antId = s.ant_id ? String(s.ant_id) : undefined;\n const existing = devices.find(\n (d) =>\n (antId && d.serial === antId) ||\n (d.name === name && d.manufacturer === s.manufacturer),\n );\n\n if (existing) {\n if (!existing.name) existing.name = name;\n if (!existing.manufacturer) existing.manufacturer = s.manufacturer;\n if (!existing.type) existing.type = s.sensor_type;\n if (!existing.sourceType)\n existing.sourceType =\n s.connection_type != null ? String(s.connection_type) : undefined;\n } else {\n devices.push({\n name: name,\n manufacturer: s.manufacturer,\n serial: antId,\n type: s.sensor_type || 'sensor',\n sourceType: s.connection_type != null ? String(s.connection_type) : undefined,\n });\n }\n });\n }\n\n // Collect standalone device status reports (often contains head unit battery)\n // We'll store them in a sorted array for easier lookups\n const statusReports: { time: number; level: number | null; idx: number }[] = [];\n if (data.device_statuses) {\n data.device_statuses.forEach((s: any, idx: number) => {\n if (s.timestamp && s.battery_level != null) {\n statusReports.push({\n time:\n typeof s.timestamp === 'number' ? s.timestamp : new Date(s.timestamp).getTime(),\n level: s.battery_level,\n idx,\n });\n }\n });\n statusReports.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n // Collect gear events\n const gearEvents: {\n time: number;\n front: number | null;\n rear: number | null;\n frontTooth: number | null;\n rearTooth: number | null;\n idx: number;\n }[] = [];\n if (data.events) {\n data.events.forEach((e: any, idx: number) => {\n let front = e.front_gear_num ?? e.front_gear ?? null;\n let rear = e.rear_gear_num ?? e.rear_gear ?? null;\n let frontTooth = e.front_gear_num_tooth ?? null;\n let rearTooth = e.rear_gear_num_tooth ?? null;\n\n if (e.event === 'rear_gear_change' || e.event === 'front_gear_change') {\n const d = e.data;\n if (d != null) {\n const ft = (d >> 24) & 0xff;\n const fg = (d >> 16) & 0xff;\n const rt = (d >> 8) & 0xff;\n const rg = d & 0xff;\n\n if (fg !== 0) front = fg;\n if (ft !== 0) frontTooth = ft;\n if (rg !== 0) rear = rg;\n if (rt !== 0) rearTooth = rt;\n }\n }\n\n if (\n e.timestamp &&\n (front != null || rear != null || frontTooth != null || rearTooth != null)\n ) {\n gearEvents.push({\n time:\n typeof e.timestamp === 'number' ? e.timestamp : new Date(e.timestamp).getTime(),\n front,\n rear,\n frontTooth,\n rearTooth,\n idx,\n });\n }\n });\n gearEvents.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n const records = data.records || [];\n let lastBattery: number | null = null;\n let statusIdx = 0;\n let lastFrontGear: number | null = null;\n let lastRearGear: number | null = null;\n let lastFrontTooth: number | null = null;\n let lastRearTooth: number | null = null;\n let gearIdx = 0;\n\n const validPoints: TrackPoint[] = [];\n for (let ri = 0; ri < records.length; ri++) {\n const r = records[ri];\n const lat = r.position_lat;\n const lon = r.position_long;\n if (lat == null || lon == null) continue;\n\n const time =\n r.timestamp != null\n ? typeof r.timestamp === 'number'\n ? r.timestamp\n : r.timestamp instanceof Date\n ? r.timestamp.getTime()\n : new Date(r.timestamp).getTime()\n : null;\n const speed = r.speed != null ? r.speed / 3.6 : null; // km/h \u2192 m/s\n\n let battery = r.battery_level ?? null;\n\n // If not in record, check our status reports\n if (battery == null && time) {\n // Catch up statusIdx to current time\n while (statusIdx < statusReports.length && statusReports[statusIdx].time <= time) {\n lastBattery = statusReports[statusIdx].level;\n statusIdx++;\n }\n battery = lastBattery;\n } else if (battery != null) {\n lastBattery = battery;\n }\n\n // Update gear state from events\n if (time) {\n while (gearIdx < gearEvents.length && gearEvents[gearIdx].time <= time) {\n const e = gearEvents[gearIdx];\n if (e.front != null) lastFrontGear = e.front;\n if (e.rear != null) lastRearGear = e.rear;\n if (e.frontTooth != null) lastFrontTooth = e.frontTooth;\n if (e.rearTooth != null) lastRearTooth = e.rearTooth;\n gearIdx++;\n }\n }\n\n const gearFront: number | null = r.front_gear_num ?? r.front_gear ?? lastFrontGear;\n const gearRear: number | null = r.rear_gear_num ?? r.rear_gear ?? lastRearGear;\n const gearFrontTooth: number | null = r.front_gear_num_tooth ?? lastFrontTooth;\n const gearRearTooth: number | null = r.rear_gear_num_tooth ?? lastRearTooth;\n\n if (r.front_gear_num != null || r.front_gear != null) lastFrontGear = gearFront;\n if (r.rear_gear_num != null || r.rear_gear != null) lastRearGear = gearRear;\n if (r.front_gear_num_tooth != null) lastFrontTooth = gearFrontTooth;\n if (r.rear_gear_num_tooth != null) lastRearTooth = gearRearTooth;\n\n const gears =\n gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0\n ? gearFrontTooth / gearRearTooth\n : null;\n\n validPoints.push({\n lat,\n lon,\n ele: r.altitude ?? r.enhanced_altitude ?? null,\n time,\n hr: r.heart_rate ?? null,\n cad: r.cadence ?? null,\n power: r.power ?? null,\n speed,\n temp: r.temperature ?? null,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!validPoints.length) {\n reject(new Error('FIT file has no GPS points'));\n return;\n }\n\n const pts = enrichPoints(validPoints);\n const stats = computeStats(pts);\n resolve({ name, device, devices, format: 'fit', points: pts, stats, sport, subSport });\n } catch (ex) {\n reject(ex);\n }\n };\n\n const fastData = fastDecodeFitData(buf);\n if (fastData) {\n handleParsedFitData(null, fastData);\n return;\n }\n\n const fitParser = new FitParser({\n force: true,\n speedUnit: 'km/h',\n lengthUnit: 'm',\n temperatureUnit: 'celsius',\n elapsedRecordField: true,\n });\n\n fitParser.parse(buf, handleParsedFitData);\n });\n }\n\n // \u2500\u2500 KML parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseKML(buf: ArrayBuffer): any {\n const text = new TextDecoder().decode(buf);\n const doc = new DOMParser().parseFromString(text, 'application/xml');\n\n let name = 'Unnamed Track';\n const nameEl = doc.querySelector('Document > name, Placemark > name');\n if (nameEl) name = nameEl.textContent?.trim() || name;\n\n // Track: look for gx:Track or LineString\n const coordEls = doc.querySelectorAll('coordinates');\n if (!coordEls.length) throw new Error('No coordinates found in KML');\n\n const points: TrackPoint[] = [];\n coordEls.forEach((el) => {\n const lines = el.textContent?.trim().split(/\\s+/) || [];\n lines.forEach((line) => {\n const parts = line.split(',');\n if (parts.length < 2) return;\n const lon = parseFloat(parts[0]);\n const lat = parseFloat(parts[1]);\n const ele = parts.length > 2 ? parseFloat(parts[2]) : null;\n if (isNaN(lat) || isNaN(lon)) return;\n points.push({\n lat,\n lon,\n ele: ele != null && isNaN(ele) ? null : ele,\n time: null,\n hr: null,\n cad: null,\n power: null,\n speed: null,\n temp: null,\n gearFront: null,\n gearRear: null,\n gearFrontTooth: null,\n gearRearTooth: null,\n battery: null,\n gears: null,\n });\n });\n });\n\n if (!points.length) throw new Error('No valid coordinates in KML');\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, format: 'kml', points: pts, stats };\n }\n\n // \u2500\u2500 Public: dispatch by extension \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async function parseFile(file: File): Promise {\n const ext = file.name.split('.').pop()?.toLowerCase();\n const buf: ArrayBuffer = (file as any)._buf ?? (await file.arrayBuffer());\n const predecodedText: string | undefined = (file as any)._text;\n let result: any;\n switch (ext) {\n case 'gpx':\n result = parseGPX(buf, predecodedText);\n break;\n case 'tcx':\n result = parseTCX(buf, predecodedText);\n break;\n case 'fit':\n result = await parseFIT(buf);\n break;\n case 'kml':\n result = parseKML(buf);\n break;\n default:\n throw new Error(`Unsupported format: .${ext}`);\n }\n\n if (result) {\n result.fileName = file.name;\n result.fileSize = file.size;\n }\n return result;\n }\n\n return {\n parseFile,\n computeStats,\n ensureCurvesAndZones,\n calculatePowerCurve,\n calculateHRCurve,\n calculatePowerZones,\n calculateHRZones,\n enrichPoints,\n setHRZones,\n getHRZones,\n setFTP,\n getFTP,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const R = 6371e3; // Earth radius in metres\n const phi1 = (lat1 * Math.PI) / 180;\n const phi2 = (lat2 * Math.PI) / 180;\n const deltaPhi = ((lat2 - lat1) * Math.PI) / 180;\n const deltaLambda = ((lon2 - lon1) * Math.PI) / 180;\n\n const a =\n Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) +\n Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n\nexport function compactId(timestamp: number): string {\n // Use a compact representation of the timestamp (seconds since epoch)\n // 1712650000 -> Base64\n const buf = new Uint32Array([Math.floor(timestamp / 1000)]);\n const b64 = btoa(String.fromCharCode(...new Uint8Array(buf.buffer)));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\nexport function shortRandom(): string {\n return Math.random().toString(36).slice(2, 6);\n}\n\nexport function fmtDuration(s: number): string {\n if (s < 60) return `${Math.round(s)}s`;\n if (s < 3600) return `${Math.round(s / 60)}m`;\n return `${Math.round(s / 3600)}h`;\n}\n\nexport function fmtSecs(s: number): string {\n const h = Math.floor(s / 3600),\n m = Math.floor((s % 3600) / 60);\n return h > 0 ? `${h}h ${m}m` : `${m}m ${Math.floor(s % 60)}s`;\n}\n\nexport function fmtPace(seconds: number | null): string {\n if (seconds == null || !isFinite(seconds)) return '--';\n const mins = Math.floor(seconds / 60);\n const secs = Math.round(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nexport function fmtDate(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown date';\n return d.toISOString().split('T')[0];\n}\n\nexport function fmtDateTime(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown';\n const iso = d.toISOString();\n return `${iso.split('T')[0]} ${iso.split('T')[1].slice(0, 5)}`;\n}\n\nexport function fmtFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function escHtml(str: string): string {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function getTagColor(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);\n\n const h = Math.abs(hash % 360);\n return `hsl(${h}, 70%, 65%)`;\n}\n\n/**\n * Smoothes a numeric array using a simple Gaussian kernel.\n * sigma: standard deviation (radius of smoothing)\n */\nexport function gaussianSmooth(data: (number | null)[], sigma: number = 2): (number | null)[] {\n if (sigma <= 0) return data;\n\n const size = Math.ceil(sigma * 3) * 2 + 1;\n const kernel = new Float32Array(size);\n const half = Math.floor(size / 2);\n let sum = 0;\n\n for (let i = 0; i < size; i++) {\n const x = i - half;\n kernel[i] = Math.exp(-(x * x) / (2 * sigma * sigma));\n sum += kernel[i];\n }\n for (let i = 0; i < size; i++) kernel[i] /= sum;\n\n const result: (number | null)[] = new Array(data.length);\n for (let i = 0; i < data.length; i++) {\n if (data[i] === null) {\n result[i] = null;\n continue;\n }\n\n let val = 0;\n let weightSum = 0;\n for (let k = 0; k < size; k++) {\n const idx = i + k - half;\n if (idx >= 0 && idx < data.length && data[idx] !== null) {\n val += data[idx]! * kernel[k];\n weightSum += kernel[k];\n }\n }\n result[i] = weightSum > 0 ? val / weightSum : data[i];\n }\n return result;\n}\n\nexport function hexToRgba(hex: string, alpha: number = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, TrackPoint } from './parsers';\n\nexport const MapView = (() => {\n let trackData: Record = {};\n let customClickHandler: ((e: any) => boolean) | null = null;\n\n function init(\n onSelectCb: (id: string) => void,\n onMoveCb: (lat: number, lng: number, zoom: number) => void,\n onPointClickCb: (id: string, idx: number) => void,\n onPointHoverCb: (id: string | null, idx: number | null) => void,\n onDblClickCb: () => void,\n ) {}\n\n function switchBasemap(layer: string) {}\n function addTrack(t: TrackData) {\n trackData[t.id] = t;\n }\n function addTracks(ts: TrackData[]) {\n ts.forEach((t) => {\n trackData[t.id] = t;\n });\n }\n function removeTrack(id: string) {\n delete trackData[id];\n }\n function clearTracks() {\n trackData = {};\n }\n function removeAllTracks() {\n trackData = {};\n }\n function setTrackVisible(id: string, visible: boolean) {}\n function setSelectedTrack(id: string | null, fit: boolean) {}\n function fitAll() {}\n function fitTrack(id: string) {}\n function showCursorAt(lat: number, lon: number) {}\n function hideCursor() {}\n function highlightSegment(\n id: string | null,\n pts: TrackPoint[],\n start: number,\n end: number,\n fit?: boolean,\n colors?: string[] | null,\n ) {}\n function clearHighlight() {}\n function setTrackHover(id: string, hover: boolean) {}\n function ensureVisible(pts: any) {}\n function centerOn(lat: number, lon: number, zoom?: number | null, force?: boolean) {}\n function closePopup() {}\n function invalidateSize() {}\n function getPosition(): [number, number, number] {\n return [0, 0, 0];\n }\n function setPosition(lat: number, lng: number, zoom: number) {}\n function colorTrackByMetric(id: string, pts: TrackPoint[], colors: string[]) {}\n function clearMetricColor(id: string) {}\n\n function findTracksPassingThroughPoints(\n points: { lat: number; lng: number }[],\n radius: number,\n ): string[] {\n return Object.keys(trackData);\n }\n\n return {\n init,\n getMap: () => null as any,\n setCustomClickHandler: (handler: any) => {\n customClickHandler = handler;\n },\n switchBasemap,\n addTrack,\n addTracks,\n removeTrack,\n clearTracks,\n removeAllTracks,\n setTrackVisible,\n setSelectedTrack,\n fitAll,\n fitTrack,\n showCursorAt,\n hideCursor,\n highlightSegment,\n clearHighlight,\n setTrackHover,\n ensureVisible,\n centerOn,\n closePopup,\n invalidateSize,\n getPosition,\n setPosition,\n colorTrackByMetric,\n clearMetricColor,\n findTracksPassingThroughPoints,\n getTrackData: (id: string) => trackData[id],\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackPoint, TrackStats, TrackData } from './parsers';\nimport { gaussianSmooth, fmtSecs, hexToRgba, fmtPace } from './utils';\nimport { Zones } from './zones';\nimport { METRICS, MetricDefinition } from './metrics';\nimport { UrlState } from './url-state';\nimport { SPORTS } from './sports';\n\n// Augment uPlot to include our custom property\n\ninterface WegPlot extends uPlot {\n _strasse?: {\n selFill: HTMLElement;\n anchorLine: HTMLElement;\n anchorLabel: HTMLElement;\n anchorHandle: HTMLElement;\n anchorMarker: HTMLElement;\n endLine: HTMLElement;\n endLabel: HTMLElement;\n endHandle: HTMLElement;\n endMarker: HTMLElement;\n curYVal: HTMLElement;\n updateHeaderStats: (min: number, max: number) => void;\n };\n}\n\ninterface PlotData {\n uplot: WegPlot;\n row: HTMLDivElement;\n xData: number[];\n yData: (number | null)[];\n def: MetricDefinition;\n metricKey: string;\n statsTotalEl: HTMLDivElement;\n statsSelEl: HTMLDivElement;\n histCol: HTMLDivElement;\n histCanvas: HTMLCanvasElement;\n histData: HistData;\n hoveredHistY: number | null;\n pinnedHistY: number | null;\n smoothed?: boolean;\n incZero?: boolean;\n w?: number;\n}\n\ninterface HistData {\n yData: (number | null)[];\n xData: number[];\n def: MetricDefinition;\n BINS: number;\n plot?: PlotData;\n bins?: number[];\n binAccum?: number[];\n min?: number;\n max?: number;\n padL?: number;\n selBins?: number[] | null;\n selBinAccum?: number[] | null;\n _lastYData?: any;\n _lastSelRange?: [number, number] | null;\n fullStats?: { min: number; max: number; avg: number } | null;\n fullStatsAll?: { min: number; max: number; avg: number } | null;\n}\n\nexport const ChartView = (() => {\n let plots: PlotData[] = [];\n let renderedTrack: TrackData | null = null;\n let renderedXAxis: string = 'time';\n let renderedSpeedMode: string = 'speed';\n let renderedMapColorMetric: string | null = null;\n let syncKey: {\n key: string;\n sub: (u: uPlot) => void;\n unsub: (u: uPlot) => void;\n pub: (type: string, u: uPlot, x: number, y: number, w: number, h: number, i: number) => void;\n } | null = null;\n let scaleSyncing: boolean = false;\n let cursorSyncing: boolean = false;\n let activeMetrics: Set = new Set(['elevation']);\n let availableMetrics: Set = new Set();\n let smoothedMetrics: Set = new Set(['speed', 'gradient', 'vam', 'temperature']);\n let metricsIncludingZero: Set = new Set(['power']);\n let xAxis: string = 'time';\n let currentTrack: TrackData | null = null;\n let allTracks: TrackData[] = [];\n\n // Selection / anchor\n let selAnchorVal: number | null = null; // x-value at drag-start / zoom left edge\n let selEndVal: number | null = null; // x-value at zoom right edge\n let isDragging: boolean = false;\n let updatingRange: boolean = false; // guard against setScale hook re-entry during handle drag\n let pinnedPtIdx: number | null = null; // point index pinned by map click\n let lastMouseXVal: number | null = null; // last hovered x-value for keyboard zoom center\n let lastHistMouseEvent: MouseEvent | null = null;\n let hoveredHistData: HistData | null = null;\n let hoveredHistCanvas: HTMLCanvasElement | null = null;\n\n let currentXRange: [number, number] | null = null; // [min, max] currently rendered\n let targetXRange: [number, number] | null = null; // [min, max] for smooth keyboard animation\n let animId: number | null = null;\n\n // Callbacks\n let onCursorMoveCb: ((pt: TrackPoint | null) => void) | null = null;\n let onRangeChangeCb: ((min: number | null, max: number | null, axis: string) => void) | null =\n null;\n let onClickCb: ((pt: TrackPoint, idx: number) => void) | null = null;\n let onPinChangeCb: ((idx: number | null) => void) | null = null;\n\n const HIST_W: number = 130;\n const ROW_BODY_PADDING: number = 28; // 14px left + 14px right\n const HIST_GAP: number = 20; // margin-left on .hist-col\n let statsVisible: boolean = true;\n let histTooltipEl: HTMLElement | null = null;\n let container: HTMLElement | null = null;\n let emptyEl: HTMLElement | null = null;\n let selStatsEl: HTMLElement | null = null;\n let resetSelBtn: HTMLElement | null = null;\n let mapColorMetric: string | null = null;\n let onMapColorChangeCb: ((data: { pts: TrackPoint[]; colors: string[] } | null) => void) | null =\n null;\n\n // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function init(\n onCursorMove: (pt: TrackPoint | null) => void,\n onRangeChange: (min: number | null, max: number | null, axis: string) => void,\n onClick: (pt: TrackPoint, idx: number) => void,\n onPinChange: (idx: number | null) => void,\n ) {\n onCursorMoveCb = onCursorMove;\n onRangeChangeCb = onRangeChange;\n onClickCb = onClick;\n onPinChangeCb = onPinChange;\n container = document.getElementById('charts-container');\n container?.addEventListener('scroll', () => {\n if (lastHistMouseEvent && hoveredHistCanvas && hoveredHistData)\n updateHistTooltip(lastHistMouseEvent, hoveredHistCanvas, hoveredHistData);\n });\n emptyEl = document.getElementById('chart-empty');\n selStatsEl = document.getElementById('chart-stats-sel');\n resetSelBtn = document.getElementById('btn-reset-selection');\n histTooltipEl = document.getElementById('hist-tooltip');\n syncKey = uPlot.sync('strasse-sync');\n\n document.getElementById('sel-cancel-btn')?.addEventListener('click', cancelSelection);\n resetSelBtn?.classList.add('hidden');\n\n // \u2500\u2500 WASD Keyboard Navigation \u2500\u2500\n const navKeys = new Set(['w', 'a', 's', 'd']);\n const activeNavKeys = new Set();\n\n document.addEventListener('keydown', (e) => {\n if (!plots.length || !currentTrack) return;\n if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName || '')) return;\n\n const key = e.key.toLowerCase();\n if (!navKeys.has(key)) return;\n\n e.preventDefault();\n activeNavKeys.add(key);\n\n const u = plots[0].uplot;\n if (!targetXRange) targetXRange = [u.scales.x!.min!, u.scales.x!.max!];\n\n let [min, max] = targetXRange;\n const span = max - min;\n const moveStep = span * 0.1;\n const zoomFactor = 0.15;\n\n let newMin = min,\n newMax = max;\n\n if (key === 'a') {\n // Pan left\n newMin = min - moveStep;\n newMax = max - moveStep;\n } else if (key === 'd') {\n // Pan right\n newMin = min + moveStep;\n newMax = max + moveStep;\n } else if (key === 'w' || key === 's') {\n // Zoom\n const center = lastMouseXVal !== null ? lastMouseXVal : (min + max) / 2;\n const factor = key === 'w' ? 1 - zoomFactor : 1 + zoomFactor * 1.2;\n newMin = center - (center - min) * factor;\n newMax = center + (max - center) * factor;\n }\n\n // Clamp to track bounds\n const xFull = [plots[0].xData[0]!, plots[0].xData[plots[0].xData.length - 1]!];\n if (newMin < xFull[0]) {\n const d = xFull[0] - newMin;\n newMin += d;\n newMax += d;\n }\n if (newMax > xFull[1]) {\n const d = newMax - xFull[1];\n newMin -= d;\n newMax -= d;\n }\n newMin = Math.max(xFull[0], newMin);\n newMax = Math.min(xFull[1], newMax);\n\n if (newMax - newMin > 0.001) {\n targetXRange = [newMin, newMax];\n setVisibleRange(newMin, newMax, true); // true = animate\n }\n });\n\n document.addEventListener('keyup', (e) => {\n const key = e.key.toLowerCase();\n if (navKeys.has(key)) activeNavKeys.delete(key);\n });\n }\n\n function setVisibleRange(min: number, max: number, animate = false) {\n if (!plots.length) return;\n if (!animate) {\n plots.forEach(({ uplot: u }) => u.setScale('x', { min, max }));\n return;\n }\n\n const startMin = (currentXRange ? currentXRange[0] : plots[0].uplot.scales.x!.min) as number;\n const startMax = (currentXRange ? currentXRange[1] : plots[0].uplot.scales.x!.max) as number;\n\n if (animId) cancelAnimationFrame(animId);\n\n const lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n const factor = 0.25; // Smoothing factor\n\n const step = () => {\n if (!targetXRange) return;\n const [tMin, tMax] = targetXRange;\n\n const cMin = lerp(currentXRange![0], tMin, factor);\n const cMax = lerp(currentXRange![1], tMax, factor);\n\n plots.forEach(({ uplot: u }) => {\n u.setScale('x', { min: cMin, max: cMax });\n });\n\n if (Math.abs(cMin - tMin) > 0.0001 || Math.abs(cMax - tMax) > 0.0001)\n animId = requestAnimationFrame(step);\n else animId = null;\n };\n animId = requestAnimationFrame(step);\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function loadTrack(track: TrackData, others: TrackData[] = [], deferRender = false) {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n allTracks = others;\n\n // Detect which metrics are available in this file\n availableMetrics = new Set(\n Object.entries(METRICS)\n .filter(([, def]) => track.points.some((p) => p[def.field] != null))\n .map(([key]) => key),\n );\n\n // If no metrics are active (e.g. first load), default to core overview metrics\n if (activeMetrics.size === 0) {\n activeMetrics = new Set(['elevation'].filter((m) => availableMetrics.has(m)));\n }\n\n // Sync the pill buttons in the toolbar\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n const metric = pill.dataset.metric!;\n const isAvailable = availableMetrics.has(metric);\n pill.classList.toggle('active', isAvailable && activeMetrics.has(metric));\n pill.classList.toggle('disabled', !isAvailable);\n });\n\n currentTrack = track;\n if (deferRender) {\n updateStats(track);\n } else {\n render();\n }\n }\n\n function clear() {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n currentTrack = null;\n destroyPlots();\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
Select a track to view analysis
\n `;\n }\n const chartStats = document.getElementById('chart-stats');\n if (chartStats) chartStats.classList.add('hidden');\n clearSelectionStats();\n mapColorMetric = null;\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n }\n\n function resetState() {\n if (animId !== null) {\n cancelAnimationFrame(animId);\n animId = null;\n }\n activeMetrics = new Set(['elevation']);\n availableMetrics = new Set();\n smoothedMetrics = new Set(['speed', 'gradient', 'vam', 'temperature']);\n metricsIncludingZero = new Set(['power']);\n xAxis = 'time';\n allTracks = [];\n currentXRange = null;\n targetXRange = null;\n lastMouseXVal = null;\n lastHistMouseEvent = null;\n hoveredHistData = null;\n hoveredHistCanvas = null;\n statsVisible = true;\n clear();\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n pill.classList.remove('disabled', 'overflow-hidden');\n });\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.add('hidden');\n const toolbar = document.getElementById('chart-toolbar');\n if (toolbar) toolbar.classList.remove('collapsed');\n document.querySelectorAll('#x-axis-ctrl .seg-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.axis === 'time');\n });\n }\n\n function toggleMetric(key: string) {\n if (activeMetrics.has(key)) activeMetrics.delete(key);\n else activeMetrics.add(key);\n if (currentTrack) render(true);\n }\n\n function setActiveMetrics(keys: string[]) {\n activeMetrics = new Set(keys);\n if (currentTrack) render(true);\n // Sync the pill buttons\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n });\n }\n\n function setXAxis(axis: string) {\n if (xAxis === axis || !currentTrack) {\n xAxis = axis;\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n\n // Helper to convert a value from OLD axis to NEW axis\n const convert = (val: number | null) => {\n if (val === null) return null;\n // We need to find the point index closest to 'val' on the OLD axis\n let idx = 0;\n if (xAxis === 'distance') {\n const dTarget = val * 1000;\n idx = pts.findIndex((p) => (p.dist || 0) >= dTarget);\n } else {\n const tTarget = t0 + val * 1000;\n idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n }\n if (idx === -1) idx = pts.length - 1;\n\n // Now get the value at this index on the NEW axis\n if (axis === 'distance') return (pts[idx].dist || 0) / 1000;\n else return ((pts[idx].time || t0) - t0) / 1000;\n };\n\n // Convert selection\n if (selAnchorVal !== null) selAnchorVal = convert(selAnchorVal);\n if (selEndVal !== null) selEndVal = convert(selEndVal);\n\n // Convert zoom range (from first plot)\n let newRange: [number, number] | null = null;\n if (plots.length) {\n const u = plots[0].uplot;\n const r0 = convert(u.scales.x!.min!);\n const r1 = convert(u.scales.x!.max!);\n if (r0 !== null && r1 !== null) newRange = [r0, r1];\n }\n\n xAxis = axis;\n render(true);\n\n // Apply converted zoom\n if (newRange) {\n scaleSyncing = true;\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: newRange![0], max: newRange![1] }));\n });\n scaleSyncing = false;\n }\n }\n\n function toggleStats() {\n statsVisible = !statsVisible;\n plots.forEach(({ histCol }) => histCol.classList.toggle('visible', statsVisible));\n resize();\n }\n\n function setMapColorChangeCb(cb: (data: { pts: TrackPoint[]; colors: string[] } | null) => void) {\n onMapColorChangeCb = cb;\n }\n\n function toggleMapColor(key: string | null) {\n if (mapColorMetric === key || key === null) {\n mapColorMetric = null;\n _updateMapColorBtns();\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n } else {\n mapColorMetric = key;\n _updateMapColorBtns();\n _fireMapColorCb();\n }\n // Re-render to show/hide colored fills on the graphs\n if (currentTrack) render(true);\n }\n\n function _updateMapColorBtns() {\n document.querySelectorAll('.map-color-btn').forEach((el) => {\n const b = el as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === mapColorMetric);\n });\n }\n\n function _fireMapColorCb() {\n if (!onMapColorChangeCb || !mapColorMetric || !currentTrack) return;\n const plot = plots.find((p) => p.metricKey === mapColorMetric);\n if (!plot) return;\n const colors = _computePointColors(mapColorMetric, plot.yData);\n onMapColorChangeCb({ pts: currentTrack.points, colors });\n }\n\n function _computePointColors(key: string, yData: (number | null)[]): string[] {\n const vals = yData.filter((v): v is number => v != null && isFinite(v));\n if (!vals.length) return yData.map(() => '#888896');\n const min = Math.min(...vals),\n max = Math.max(...vals);\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n return yData.map((v) => {\n if (v == null || !isFinite(v)) return '#888896';\n if (key === 'gradient') return gradientColor(v);\n if (key === 'speed') {\n if (speedMode === 'pace') {\n const speed = (paceUnit === 'km' ? 1000 : 100) / v;\n return speedColor(speed);\n }\n return speedColor(v);\n }\n const t = max === min ? 0.5 : Math.max(0, Math.min(1, (v - min) / (max - min)));\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25);\n if (t <= 0.5) return lerpHex('#91bfdb', '#fee090', (t - 0.25) / 0.25);\n if (t <= 0.75) return lerpHex('#fee090', '#fc8d59', (t - 0.5) / 0.25);\n return lerpHex('#fc8d59', '#d73027', (t - 0.75) / 0.25);\n });\n }\n\n function resetZoom() {\n cancelSelection();\n }\n\n function cancelSelection() {\n selAnchorVal = null;\n selEndVal = null;\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n\n // Reset individual histogram pins\n plots.forEach((p) => {\n p.pinnedHistY = null;\n });\n\n updateSelOverlay();\n redrawHistograms();\n\n // Perform the actual zoom reset\n scaleSyncing = true;\n plots.forEach(({ uplot: u, xData }) => {\n u.batch(() => u.setScale('x', { min: xData[0]!, max: xData[xData.length - 1]! }));\n u._strasse?.updateHeaderStats(xData[0]!, xData[xData.length - 1]!);\n });\n scaleSyncing = false;\n\n if (onRangeChangeCb) onRangeChangeCb(null, null, xAxis);\n }\n\n function setSelectionStats(stats: TrackStats) {\n if (!selStatsEl) return;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt(\n 'sel-distance',\n stats.totalDist != null ? `${(stats.totalDist / 1000).toFixed(1)} km` : '\u2014',\n );\n fmt('sel-duration', stats.duration != null ? fmtSecs(Math.floor(stats.duration / 1000)) : '\u2014');\n fmt('sel-elevation', stats.elevGain != null ? `${Math.round(stats.elevGain)} m` : '\u2014');\n fmt(\n 'sel-avg-speed',\n stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014',\n );\n fmt('sel-avg-power', stats.avgPower != null ? `${stats.avgPower} W` : '\u2014');\n fmt('sel-avg-hr', stats.avgHR != null ? `${stats.avgHR} bpm` : '\u2014');\n fmt('sel-avg-temp', stats.avgTemp != null ? `${stats.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n selStatsEl.classList.remove('hidden');\n if (resetSelBtn) resetSelBtn.classList.remove('hidden');\n }\n\n function clearSelectionStats() {\n if (selStatsEl) selStatsEl.classList.add('hidden');\n if (resetSelBtn) resetSelBtn.classList.add('hidden');\n [\n 'sel-distance',\n 'sel-duration',\n 'sel-elevation',\n 'sel-avg-speed',\n 'sel-avg-power',\n 'sel-avg-hr',\n 'sel-avg-temp',\n ].forEach((id) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = '--';\n });\n }\n\n // Called on boot to restore a saved selection without re-firing onRangeChangeCb\n // xMin/xMax are ALWAYS provided in Time (seconds from start)\n function restoreSelection(tMin: number, tMax: number, deferRender = false) {\n if (!currentTrack) return;\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const totalDuration = ((pts[pts.length - 1]?.time || 0) - t0) / 1000;\n\n // If values look like absolute timestamps in ms, convert to seconds from start\n if (tMin > 1e12) tMin = (tMin - t0) / 1000;\n if (tMax > 1e12) tMax = (tMax - t0) / 1000;\n\n // Crop to max limits of the track\n tMin = Math.max(0, Math.min(tMin, totalDuration));\n tMax = Math.max(0, Math.min(tMax, totalDuration));\n\n const convert = (tOffset: number) => {\n if (xAxis === 'time') return tOffset;\n const tTarget = t0 + tOffset * 1000;\n let idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n if (idx === -1) idx = pts.length - 1;\n return (pts[idx].dist || 0) / 1000;\n };\n\n const xMin = convert(tMin);\n const xMax = convert(tMax);\n\n selAnchorVal = xMin;\n selEndVal = xMax;\n currentXRange = [xMin, xMax];\n if (deferRender) return;\n scaleSyncing = true; // suppress the setScale \u2192 onRangeChangeCb loop\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: xMin, max: xMax }));\n });\n scaleSyncing = false;\n updateAnchorLines();\n redrawHistograms();\n }\n\n function resize() {\n if (!plots.length || !container) return;\n const w = Math.round(\n Math.max(\n 100,\n container.getBoundingClientRect().width -\n ROW_BODY_PADDING -\n (statsVisible ? HIST_W + HIST_GAP : 0),\n ),\n );\n let anyResized = false;\n plots.forEach(({ uplot: u, histCanvas, histData }) => {\n if (w !== u.width) {\n u.setSize({ width: w, height: u.height });\n anyResized = true;\n if (statsVisible && histCanvas && histData) drawHistogram(histCanvas, histData, u.height);\n }\n });\n if (anyResized) updateSelOverlay();\n }\n\n // \u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function render(keepState = false) {\n let savedRange: [number, number] | null = null;\n let savedScroll = 0;\n if (keepState && container) savedScroll = container.scrollTop;\n\n if (keepState && currentXRange) {\n savedRange = [currentXRange[0], currentXRange[1]];\n } else if (keepState && plots.length) {\n const u = plots[0].uplot;\n savedRange = [u.scales.x!.min!, u.scales.x!.max!];\n }\n\n if (!currentTrack) {\n destroyPlots(keepState);\n return;\n }\n const pts = currentTrack.points;\n if (!pts.length) {\n destroyPlots(keepState);\n return;\n }\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n const available = [...activeMetrics].filter((m) =>\n pts.some((p) => p[METRICS[m].field] != null),\n );\n if (!available.length) {\n destroyPlots(keepState);\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
No data for selected metrics
\n `;\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n\n const containerW = container ? container.getBoundingClientRect().width : 800;\n const w = Math.round(\n Math.max(100, containerW - ROW_BODY_PADDING - (statsVisible ? HIST_W + HIST_GAP : 0)),\n );\n\n const canReuse =\n keepState &&\n renderedTrack === currentTrack &&\n renderedXAxis === xAxis &&\n renderedSpeedMode === speedMode &&\n renderedMapColorMetric === mapColorMetric &&\n plots.length > 0;\n\n let xData: (number | null)[];\n if (canReuse) {\n xData = plots[0].xData;\n } else if (xAxis === 'distance') {\n xData = pts.map((p) => (p.dist || 0) / 1000);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n let lastValidX = 0;\n xData = pts.map((p) => {\n if (p.time != null) {\n lastValidX = (p.time - t0) / 1000;\n return lastValidX;\n }\n return lastValidX; // monotonic fallback\n });\n }\n\n const existingByKey = new Map();\n if (canReuse) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const availSet = new Set(available);\n for (const p of plots) {\n const isSmoothed = smoothedMetrics.has(p.metricKey);\n const isIncZero = metricsIncludingZero.has(p.metricKey);\n if (\n availSet.has(p.metricKey) &&\n p.smoothed === isSmoothed &&\n p.incZero === isIncZero &&\n p.w === w\n ) {\n existingByKey.set(p.metricKey, p);\n } else {\n syncKey!.unsub(p.uplot);\n p.uplot.destroy();\n p.row.remove();\n }\n }\n plots = [];\n } else {\n destroyPlots(keepState);\n }\n\n if (container) {\n const nextSiblingRows: (HTMLElement | null)[] = new Array(available.length).fill(null);\n let nextExisting: HTMLElement | null = null;\n for (let i = available.length - 1; i >= 0; i--) {\n nextSiblingRows[i] = nextExisting;\n const ex = existingByKey.get(available[i]);\n if (ex) nextExisting = ex.row;\n }\n\n available.forEach((key, idx) => {\n const reused = existingByKey.get(key);\n if (reused) {\n plots.push(reused);\n const uplot = reused.uplot;\n const s = (uplot as any)._strasse;\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n uplot.batch(() => {\n if (\n savedRange &&\n (uplot.scales.x!.min !== savedRange[0] || uplot.scales.x!.max !== savedRange[1])\n ) {\n uplot.setScale('x', { min: savedRange[0], max: savedRange[1] });\n } else {\n s?.updateHeaderStats(uplot.scales.x!.min!, uplot.scales.x!.max!, uplot);\n uplot.redraw(false);\n }\n });\n scaleSyncing = prevSync;\n\n let initHoverBinI: number | null = null;\n if (\n pinnedPtIdx != null &&\n reused.xData[pinnedPtIdx] != null &&\n reused.yData[pinnedPtIdx] != null\n ) {\n buildHistBins(reused.histData);\n if (reused.histData.min != null && reused.histData.max != null) {\n const span = reused.histData.max - reused.histData.min || 1;\n initHoverBinI = Math.min(\n reused.histData.BINS - 1,\n Math.floor(\n ((reused.yData[pinnedPtIdx]! - reused.histData.min) / span) *\n reused.histData.BINS,\n ),\n );\n reused.hoveredHistY = reused.yData[pinnedPtIdx];\n }\n }\n drawHistogram(reused.histCanvas, reused.histData, 130, initHoverBinI);\n return;\n }\n\n let def = METRICS[key];\n\n let transform = def.transform;\n let fmt = def.fmt;\n let fmtAxis = def.fmtAxis;\n let unit = def.unit;\n let label = def.label;\n\n if (key === 'speed' && speedMode === 'pace') {\n label = 'Pace';\n unit = `min/${paceUnit}`;\n fmt = (v) => fmtPace(v);\n fmtAxis = (v) => fmtPace(v);\n transform = (v) => {\n if (v == null || v < 0.1) return null;\n return (paceUnit === 'km' ? 1000 : 100) / v;\n };\n\n def = { ...def, label, unit, fmt, fmtAxis, transform };\n }\n\n let yData = def.compute\n ? def.compute(pts, fillNulls)\n : fillNulls(\n pts.map((p) => {\n const v = p[def.field] as number;\n return v != null && transform ? transform(v) : v;\n }),\n );\n\n if (smoothedMetrics.has(key)) yData = gaussianSmooth(yData, def.smoothSigma || 2);\n\n createChart(key, def, xData, yData, w, pts, savedRange, nextSiblingRows[idx]);\n });\n }\n\n renderedTrack = currentTrack;\n renderedXAxis = xAxis;\n renderedSpeedMode = speedMode;\n renderedMapColorMetric = mapColorMetric;\n\n updateStats(currentTrack);\n // Restore anchor/end lines if a selection was active\n if (selAnchorVal != null && selEndVal != null) updateAnchorLines();\n // Re-apply map color if active\n _updateMapColorBtns();\n if (mapColorMetric) _fireMapColorCb();\n\n if (keepState && container && savedScroll > 0) container.scrollTop = savedScroll;\n }\n\n // \u2500\u2500 Create one chart row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function createChart(\n metricKey: string,\n def: MetricDefinition,\n xData: (number | null)[],\n yData: (number | null)[],\n w: number,\n pts: TrackPoint[],\n initialRange: [number, number] | null = null,\n insertBeforeEl: HTMLElement | null = null,\n ) {\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n\n // Gradient data: smooth over a 20 m distance window (\u00B110 m each side)\n const gradData = metricKey === 'elevation' ? smoothGradient(pts, 20) : null;\n const row = document.createElement('div');\n row.className = 'chart-row';\n row.dataset.metric = metricKey;\n row.style.setProperty('--chart-color', def.color);\n\n // Header\n const header = document.createElement('div');\n header.className = `chart-row-header${statsVisible ? ' with-histogram' : ''}`;\n\n const labelEl = document.createElement('div');\n labelEl.className = 'chart-row-label-group';\n labelEl.innerHTML = `\n ${def.icon}\n ${def.label}\n `;\n\n // Smoothing toggle\n const smoothBtn = document.createElement('button');\n smoothBtn.className = `icon-btn mini smooth-btn${smoothedMetrics.has(metricKey) ? ' active' : ''}`;\n smoothBtn.title = 'Toggle data smoothing';\n smoothBtn.innerHTML = `${smoothedMetrics.has(metricKey) ? 'blur_on' : 'blur_off'}`;\n smoothBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (smoothedMetrics.has(metricKey)) smoothedMetrics.delete(metricKey);\n else smoothedMetrics.add(metricKey);\n\n render(true); // Re-render all charts to keep sync if needed (though only this one changes data)\n });\n\n const mapColorBtn = document.createElement('button');\n\n mapColorBtn.className = `map-color-btn icon-btn${mapColorMetric === metricKey ? ' active' : ''}`;\n mapColorBtn.dataset.metric = metricKey;\n mapColorBtn.title = 'Color map track by this metric';\n mapColorBtn.innerHTML = 'colorize';\n mapColorBtn.addEventListener('click', () => toggleMapColor(metricKey));\n\n // Zero-filter toggle (Cadence/Power/Speed)\n let zeroBtn: HTMLButtonElement | null = null;\n if (metricKey === 'cadence' || metricKey === 'power' || metricKey === 'speed') {\n zeroBtn = document.createElement('button');\n const incZero = metricsIncludingZero.has(metricKey);\n zeroBtn.className = `icon-btn mini${incZero ? ' active' : ''}`;\n zeroBtn.title = incZero ? 'Currently INCLUDING 0 values' : 'Currently EXCLUDING 0 values';\n zeroBtn.innerHTML = `${incZero ? 'exposure_zero' : 'mobile_off'}`;\n zeroBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (metricsIncludingZero.has(metricKey)) metricsIncludingZero.delete(metricKey);\n else metricsIncludingZero.add(metricKey);\n render(true);\n });\n }\n\n const statsTotalEl = document.createElement('div');\n statsTotalEl.className = 'chart-stats-total';\n\n const statsSelEl = document.createElement('div');\n statsSelEl.className = 'chart-stats-selection';\n\n const statsContainer = document.createElement('div');\n statsContainer.className = 'chart-row-stats-container';\n statsContainer.append(statsTotalEl, statsSelEl);\n\n const actionsEl = document.createElement('div');\n actionsEl.className = 'chart-row-actions';\n actionsEl.append(smoothBtn, mapColorBtn);\n\n const rightActionsEl = document.createElement('div');\n rightActionsEl.className = 'chart-row-right-actions';\n\n if (metricKey === 'speed') {\n const paceToggle = document.createElement('div');\n paceToggle.className = 'seg-ctrl';\n paceToggle.innerHTML = `\n \n \n `;\n paceToggle.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const mode = btn.dataset.mode;\n if (mode === 'speed' || mode === 'pace') {\n const isDefault = mode === defaultMode;\n UrlState.patch({ speed_mode: isDefault ? null : mode });\n render(true);\n }\n });\n rightActionsEl.append(paceToggle);\n }\n\n if (zeroBtn) rightActionsEl.append(zeroBtn);\n\n header.append(labelEl, actionsEl, statsContainer, rightActionsEl);\n\n const rowBody = document.createElement('div');\n rowBody.className = 'chart-row-body';\n\n const plotEl = document.createElement('div');\n plotEl.style.position = 'relative';\n rowBody.appendChild(plotEl);\n\n const fixedMinLabel = document.createElement('div');\n fixedMinLabel.className = 'fixed-x-label fixed-x-min';\n const fixedMaxLabel = document.createElement('div');\n fixedMaxLabel.className = 'fixed-x-label fixed-x-max';\n plotEl.append(fixedMinLabel, fixedMaxLabel);\n\n const histCol = document.createElement('div');\n histCol.className = `hist-col${statsVisible ? ' visible' : ''}`;\n const histCanvas = document.createElement('canvas');\n histCanvas.className = 'hist-canvas';\n histCol.appendChild(histCanvas);\n rowBody.appendChild(histCol);\n\n row.append(header, rowBody);\n\n const isDistAxis = xAxis === 'distance';\n\n function formatX(v: number, range: number): string {\n if (v == null) return '';\n if (isDistAxis) {\n const dec = range < 1 ? 3 : range < 5 ? 2 : range < 20 ? 1 : 0;\n return `${v.toFixed(dec)} km`;\n } else {\n const absV = Math.abs(v);\n const h = Math.floor(absV / 3600);\n const m = Math.floor((absV % 3600) / 60);\n const s = Math.round(absV % 60);\n const hh = h > 0 ? `${h}:` : '';\n const mm = h > 0 ? String(m).padStart(2, '0') : String(m);\n const ss = String(s).padStart(2, '0');\n return `${v < 0 ? '-' : ''}${hh}${mm}:${ss}`;\n }\n }\n\n const incZeroDefault =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Compute global Y range and full-track stats in a single pass\n let gMin = Infinity,\n gMax = -Infinity,\n allSum = 0,\n allCount = 0,\n filtMin = Infinity,\n filtMax = -Infinity,\n filtSum = 0,\n filtCount = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n allSum += v;\n allCount++;\n if (v !== 0 || incZeroDefault) {\n if (v < filtMin) filtMin = v;\n if (v > filtMax) filtMax = v;\n filtSum += v;\n filtCount++;\n }\n }\n if (allCount === 0) {\n gMin = 0;\n gMax = 100;\n }\n const fullStatsAll = allCount ? { min: gMin, max: gMax, avg: allSum / allCount } : null;\n const fullStatsFiltered = filtCount\n ? { min: filtMin, max: filtMax, avg: filtSum / filtCount }\n : null;\n const gPad = Math.abs(gMax - gMin) * 0.1 || 1;\n const fixedYRange = [gMin - gPad, gMax + gPad];\n\n let statsTotalInitialized = false;\n\n // Per-range stats\n function updateHeaderStats(visibleMin: number, visibleMax: number, u?: uPlot) {\n const incZero =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Update fixed X labels\n const range = visibleMax - visibleMin;\n fixedMinLabel.textContent = formatX(visibleMin, range);\n fixedMaxLabel.textContent = formatX(visibleMax, range);\n\n const getHtml = (xMin: number, xMax: number, isFull = false) => {\n const s =\n isFull && incZero === incZeroDefault\n ? fullStatsFiltered\n : rangeStats(xData, yData, xMin, xMax, incZero);\n if (!s) return '';\n\n let h = `\n align_flex_end${def.fmt(s.min, true)} ${def.unit}\n align_center${def.fmt(s.avg, true)} ${def.unit}\n align_flex_start${def.fmt(s.max, true)} ${def.unit}\n `;\n\n if (metricKey === 'elevation') {\n const es = elevationRangeStats(pts, xMin, xMax);\n h += `\n trending_up+${Math.round(es.gain)} m\n trending_down-${Math.round(es.loss)} m\n `;\n }\n return h;\n };\n\n if (!statsTotalInitialized) {\n statsTotalInitialized = true;\n statsTotalEl.innerHTML = `all_inclusive${getHtml(\n xData[0]!,\n xData[xData.length - 1]!,\n true,\n )}`;\n statsTotalEl.querySelector('.all-chip')?.addEventListener('click', (e) => {\n e.stopPropagation();\n cancelSelection();\n });\n }\n\n if (selAnchorVal !== null && selEndVal !== null) {\n statsSelEl.innerHTML = getHtml(selAnchorVal, selEndVal, false);\n statsSelEl.style.display = 'flex';\n statsSelEl.style.setProperty('--sel-color', def.color);\n } else {\n statsSelEl.style.display = 'none';\n }\n }\n let initializingScale = false;\n const uOpts: uPlot.Options = {\n width: w,\n height: 130,\n padding: [4, 0, 0, 0],\n cursor: {\n sync: {\n key: syncKey!.key,\n },\n drag: { x: true, y: false, uni: 16 },\n focus: { prox: 16 },\n points: {\n size: 7,\n stroke: '#0e0e10',\n width: 2,\n fill: (metricKey === 'elevation'\n ? (u: uPlot, _si: number) => gradientColor(gradData ? gradData[u.cursor.idx!]! : null)\n : def.color) as any,\n },\n x: false,\n y: false,\n },\n select: {\n show: true,\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n },\n legend: { show: false },\n scales: {\n x: {\n time: false,\n range: (_u: uPlot, mn: number, mx: number) => [mn, mx],\n min: initialRange ? initialRange[0] : undefined,\n max: initialRange ? initialRange[1] : undefined,\n },\n y: {\n range: () => fixedYRange as [number, number],\n dir: metricKey === 'speed' && speedMode === 'pace' ? -1 : 1,\n },\n },\n axes: [\n {\n side: 2, // bottom\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: {\n show: true,\n stroke: '#2e2e34',\n },\n size: 30,\n space: 80,\n font: '10px system-ui, sans-serif',\n splits: (u: uPlot, axisIdx: number, scaleMin: number, scaleMax: number) => {\n const range = scaleMax - scaleMin;\n const width = u.bbox.width > 0 ? u.bbox.width : u.width;\n const targetLabels = width / 80;\n const idealIncr = range / targetLabels;\n\n let incrs;\n if (!isDistAxis) {\n // Time in seconds\n incrs = [\n 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 14400, 28800, 43200,\n 86400, 604800, 2592000, 31536000,\n ];\n } else {\n incrs = [\n 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000,\n 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000,\n ];\n }\n\n let incr = incrs[incrs.length - 1];\n for (let i = 0; i < incrs.length; i++) {\n if (incrs[i] >= idealIncr) {\n incr = incrs[i];\n break;\n }\n }\n\n const splits = [];\n let val = Math.ceil(scaleMin / incr) * incr;\n const precision = incr < 1 ? 2 : 0;\n\n while (val <= scaleMax) {\n const pos = u.valToPos(val, 'x', true);\n if (pos >= u.bbox.left + 80 && pos <= u.bbox.left + u.bbox.width - 80)\n splits.push(Number(val.toFixed(precision)));\n\n val += incr;\n }\n return splits;\n },\n values: ((_u: uPlot, vals: number[]) => {\n const range = (_u.scales.x?.max ?? 1) - (_u.scales.x?.min ?? 0);\n\n return vals.map((v) => {\n if (v == null) return '';\n const pos = _u.valToPos(v, 'x', true);\n // Strict 80px margin to prevent overlapping with fixed labels or Y axis\n if (pos < _u.bbox.left + 80 || pos > _u.bbox.left + _u.bbox.width - 80) return null;\n return formatX(v, range);\n });\n }) as any,\n },\n {\n side: 3, // left\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: { stroke: '#2e2e34' },\n size: 55,\n font: '10px system-ui, sans-serif',\n values: ((_u: uPlot, vals: number[]) =>\n vals.map((v) => (v != null ? def.fmtAxis(v) : ''))) as any,\n },\n ],\n series: [\n {},\n // Main selected track series\n {\n label: def.label,\n stroke: 'rgba(0,0,0,0)', // Stroke handled in draw hooks for layering\n width: 0,\n points: { show: false },\n paths: () => null,\n },\n ],\n hooks: {\n draw: [\n (u: uPlot) => {\n const top = u.bbox.top + u.bbox.height + 5; // 5px below plot area!\n fixedMinLabel.style.top = `${top}px`;\n fixedMinLabel.style.left = `${u.bbox.left}px`;\n\n fixedMaxLabel.style.top = `${top}px`;\n fixedMaxLabel.style.left = `${u.bbox.left + u.bbox.width}px`;\n fixedMaxLabel.style.transform = 'translateX(-100%)';\n },\n // 1. (bottom) Color / metric color of the selected track\n (u: uPlot) => {\n if (metricKey === 'gears') {\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n } else if (metricKey === 'elevation') {\n drawElevationGradient(u, xData as number[], yData as number[], gradData);\n } else if (metricKey === 'gradient') {\n drawGradientChart(u, xData as number[], yData as number[]);\n } else if (mapColorMetric === metricKey) {\n drawMetricColorFill(u, xData as number[], yData as number[], pts, metricKey);\n } else {\n // Normal colored line\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n }\n },\n\n // 2. Pinned point (middle)\n (u: uPlot) => {\n const plot = plots.find((p) => p.uplot === u);\n if (!plot) return;\n\n const s = (u as any)._strasse;\n // Priority 1: Global pinned point (all charts)\n if (pinnedPtIdx != null) {\n drawPinnedDot(u, xData, yData, def.color, def, pts, metricKey);\n } else {\n if (s && s.pinYVal) s.pinYVal.style.display = 'none';\n\n // Priority 2: Individual histogram pinned Y-pos (this chart only)\n if (plot.pinnedHistY != null)\n drawYAxisHighlight(u, xData, yData, plot.pinnedHistY, def.color, def);\n }\n },\n\n // 3. Pinned & Hover elements (labels, vertical lines)\n (u: uPlot) => {\n const hIdx = u.cursor.idx;\n const hasPinned = pinnedPtIdx != null;\n\n let hasHover = hIdx != null && u.cursor.left! >= 0;\n if (hasHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[hIdx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) hasHover = false;\n }\n\n // B. Draw Hover vertical line\n if (hasHover && hIdx !== pinnedPtIdx)\n drawVerticalLineOnly(u, pts, hIdx!, hexToRgba(def.color, 0.4), 1.0);\n\n // C. Bold selection x-axis line & span pill\n if (selAnchorVal != null && selEndVal != null) {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ax = u.valToPos(selAnchorVal, 'x', true);\n const ex = u.valToPos(selEndVal, 'x', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.lineWidth = 3 * dpr;\n ctx.strokeStyle = def.color;\n ctx.moveTo(ax, bb.top + bb.height);\n ctx.lineTo(ex, bb.top + bb.height);\n ctx.stroke();\n\n const span = Math.abs(selEndVal - selAnchorVal);\n const label = xAxis === 'distance' ? `${span.toFixed(2)} km` : fmtSecs(span);\n const fontSize = 9 * dpr;\n const fontStr = `bold ${fontSize}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n\n const visibleL = Math.max(bb.left, ax);\n const visibleR = Math.min(bb.left + bb.width, ex);\n const visibleW = visibleR - visibleL;\n\n if (visibleW > tw + 14 * dpr) {\n const padH = 5 * dpr;\n const padV = 2 * dpr;\n const bw = tw + padH * 2;\n const bh = fontSize + padV * 2;\n const bx = (visibleL + visibleR) / 2 - bw / 2;\n const by = bb.top + bb.height - bh / 2;\n\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = def.color;\n ctx.fill();\n\n ctx.fillStyle = '#000';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2);\n }\n ctx.restore();\n }\n\n // D. Draw label pills (on top)\n // Pinned labels first (semi-transparent)\n if (hasPinned) drawXAxisLabels(u, pts, pinnedPtIdx!, def.color, true, 0.7);\n\n // Hover labels last (fully opaque, topmost)\n if (hasHover && hIdx !== pinnedPtIdx)\n drawXAxisLabels(u, pts, hIdx!, def.color, true, 1.0);\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (scaleSyncing) return;\n const idx = u.cursor.idx;\n\n // Trigger redraw on cursor move to ensure custom canvas markers (hover lines/labels) update live\n // Note: uPlot handles cross-chart sync when syncKey is used.\n u.redraw(false);\n\n // Track current x-value for keyboard navigation\n if (u.cursor.left! >= 0) lastMouseXVal = u.posToVal(u.cursor.left!, 'x');\n else lastMouseXVal = null;\n\n // \u2500\u2500 Floating y-value next to cursor dot \u2500\u2500\n const s = (u as any)._strasse;\n let showHover = idx != null && yData[idx] != null;\n\n // Distance threshold: if no pinned point, check proximity to data line\n if (showHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[idx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) showHover = false;\n }\n\n if (s) {\n if (showHover)\n updateTooltip(\n u,\n s.curYVal,\n idx!,\n xData as number[],\n yData as number[],\n pts,\n def,\n metricKey,\n );\n else s.curYVal.style.display = 'none';\n }\n\n // Map marker\n if (!cursorSyncing) {\n if (idx != null && pts[idx]) {\n if (onCursorMoveCb && (pinnedPtIdx != null || showHover)) {\n onCursorMoveCb(pts[idx]);\n } else if (onCursorMoveCb && !showHover) {\n // If we're too far and nothing is pinned, hide map cursor\n onCursorMoveCb(null);\n }\n } else if (idx === null && onCursorMoveCb) {\n onCursorMoveCb(null);\n }\n }\n\n // Highlight matching histogram bucket\n if (idx != null && yData[idx] != null) {\n const { min, max } = histData;\n if (min != null && max != null) {\n const span = max - min || 1;\n const binI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[idx]! - min) / span) * histData.BINS),\n );\n if (plot.hoveredHistY !== yData[idx]) {\n plot.hoveredHistY = yData[idx];\n drawHistogram(histCanvas, histData, 130, binI);\n }\n }\n } else if (plot.hoveredHistY !== null) {\n plot.hoveredHistY = null;\n drawHistogram(histCanvas, histData, 130);\n }\n },\n ],\n\n setScale: [\n (u: uPlot, key: string) => {\n if (key !== 'x' || initializingScale) return;\n const { min, max } = u.scales.x!;\n\n // Sync currentXRange so keyboard navigation baseline is always accurate\n currentXRange = [min!, max!];\n\n // Update header stats for VISIBLE range\n updateHeaderStats(min as number, max as number, u);\n\n if (scaleSyncing) return;\n\n // Clear keyboard target when user interacts via mouse\n if (!updatingRange) targetXRange = null;\n\n // Sync sibling plots\n scaleSyncing = true;\n plots.forEach(({ uplot: other }) => {\n if (other !== u) other.batch(() => other.setScale('x', { min: min!, max: max! }));\n });\n scaleSyncing = false;\n\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb && selAnchorVal !== null)\n onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n },\n ],\n\n setSelect: [\n (u: uPlot) => {\n if (updatingRange) return;\n targetXRange = null;\n const { left, width } = u.select;\n if (width > 0) {\n const min = u.posToVal(left, 'x');\n const max = u.posToVal(left + width, 'x');\n selAnchorVal = min;\n selEndVal = max;\n\n // Sync stats to new selection\n updateHeaderStats(u.scales.x!.min!, u.scales.x!.max!, u);\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n\n // Clear uPlot's internal selection immediately so it doesn't block WASD/interaction\n u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);\n }\n },\n ],\n },\n };\n\n // \u2500\u2500 Overlay (pointer-events off except handles) \u2500\u2500\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5';\n\n // Selection fill\n const selFill = document.createElement('div');\n selFill.className = 'sel-fill';\n selFill.style.display = 'none';\n\n // Anchor line + label + drag handle\n const anchorLine = document.createElement('div');\n anchorLine.className = 'sel-line sel-line-anchor';\n anchorLine.style.display = 'none';\n\n const anchorLabel = document.createElement('div');\n anchorLabel.className = 'sel-line-label sel-line-label-anchor';\n anchorLabel.style.display = 'none';\n\n const anchorHandle = document.createElement('div');\n anchorHandle.className = 'sel-handle sel-handle-anchor';\n anchorHandle.style.display = 'none';\n\n const anchorMarker = document.createElement('div');\n anchorMarker.className = 'sel-graph-marker';\n anchorMarker.innerHTML =\n 'play_circle';\n anchorMarker.style.display = 'none';\n\n // End line + label + drag handle\n const endLine = document.createElement('div');\n endLine.className = 'sel-line sel-line-end';\n endLine.style.display = 'none';\n\n const endLabel = document.createElement('div');\n endLabel.className = 'sel-line-label sel-line-label-end';\n endLabel.style.display = 'none';\n\n const endHandle = document.createElement('div');\n endHandle.className = 'sel-handle sel-handle-end';\n endHandle.style.display = 'none';\n\n const endMarker = document.createElement('div');\n endMarker.className = 'sel-graph-marker';\n endMarker.innerHTML =\n 'stop_circle';\n endMarker.style.display = 'none';\n\n // Floating cursor y-value\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${def.color};display:none`;\n\n // Floating pinned y-value\n const pinYVal = document.createElement('div');\n pinYVal.className = 'cur-y-val pin';\n pinYVal.style.cssText = `color:${def.color};display:none`;\n\n overlay.append(\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n );\n\n const histData: HistData = {\n yData,\n xData: xData as number[],\n def,\n BINS: 24,\n min: allCount ? gMin : undefined,\n max: allCount ? gMax : undefined,\n fullStats: fullStatsFiltered,\n fullStatsAll,\n };\n const plot: PlotData = {\n uplot: null as any,\n row,\n xData: xData as number[],\n yData,\n def,\n metricKey,\n statsTotalEl,\n statsSelEl,\n histCol,\n histCanvas,\n histData,\n hoveredHistY: null,\n pinnedHistY: null,\n smoothed: smoothedMetrics.has(metricKey),\n incZero: metricsIncludingZero.has(metricKey),\n w,\n };\n histData.plot = plot; // Back-reference for tooltip to trigger redraws\n\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n const uplot = new uPlot(uOpts, [xData, yData] as any, (self, init) => {\n plot.uplot = self as WegPlot;\n plots.push(plot);\n plotEl.appendChild(self.root);\n self.over.appendChild(overlay);\n (self as any)._strasse = {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n updateHeaderStats,\n };\n self.batch(() => {\n init();\n });\n }) as WegPlot;\n scaleSyncing = prevSync;\n\n // \u2500\u2500 Handle drag \u2500\u2500\n attachHandleDrag(anchorHandle, uplot, xData, true);\n attachHandleDrag(endHandle, uplot, xData, false);\n\n // \u2500\u2500 Mouse listeners \u2500\u2500\n let mousedownX: number | null = null;\n uplot.over.addEventListener('mousedown', (e) => {\n if (e.button !== 0) return;\n isDragging = false;\n const rect = uplot.over.getBoundingClientRect();\n const xPx = e.clientX - rect.left;\n mousedownX = xPx;\n });\n uplot.over.addEventListener('mousemove', (e) => {\n if (mousedownX !== null) {\n const rect = uplot.over.getBoundingClientRect();\n if (Math.abs(e.clientX - rect.left - mousedownX) > 5) isDragging = true;\n }\n });\n uplot.over.addEventListener('mouseup', () => {\n mousedownX = null;\n });\n\n // Click to pin point (sticky selection)\n uplot.over.addEventListener('click', () => {\n if (isDragging) return;\n const idx = uplot.cursor.idx;\n if (idx != null && pts[idx]) {\n pinnedPtIdx = idx;\n plots.forEach(({ uplot: u }) => u.redraw(false));\n if (onClickCb) onClickCb(pts[idx], idx);\n if (onPinChangeCb) onPinChangeCb(idx);\n }\n });\n\n row.addEventListener('dblclick', cancelSelection);\n\n let initHoverBinI: number | null = null;\n if (pinnedPtIdx != null && xData[pinnedPtIdx] != null && yData[pinnedPtIdx] != null) {\n buildHistBins(histData);\n if (histData.min != null && histData.max != null) {\n const span = histData.max - histData.min || 1;\n initHoverBinI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[pinnedPtIdx]! - histData.min) / span) * histData.BINS),\n );\n plot.hoveredHistY = yData[pinnedPtIdx];\n }\n }\n\n drawHistogram(histCanvas, histData, 130, initHoverBinI);\n attachHistTooltip(histCanvas, histData);\n if (container) {\n if (insertBeforeEl) container.insertBefore(row, insertBeforeEl);\n else container.appendChild(row);\n }\n }\n\n // \u2500\u2500 Selection overlay (fill + lines + handles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateSelOverlay() {\n updateAnchorLines();\n // Redraw canvas markers (bold selection line + span pill)\n plots.forEach(({ uplot: u }) => u.batch(() => u.redraw(false)));\n }\n\n function updateAnchorLines() {\n plots.forEach(({ uplot: u, def }) => {\n const s = (u as any)._strasse;\n if (!s) return;\n const {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n } = s;\n if (selAnchorVal == null || selEndVal == null) {\n [\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n ].forEach((el: HTMLElement) => {\n el.style.display = 'none';\n });\n return;\n }\n const aX = u.valToPos(selAnchorVal, 'x');\n const eX = u.valToPos(selEndVal, 'x');\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const overW = bb.width / dpr;\n const overH = bb.height / dpr;\n const plotBottom = (bb.top + bb.height) / dpr;\n\n const isAnchorVisible = aX >= 0 && aX <= overW;\n const isEndVisible = eX >= 0 && eX <= overW;\n\n // Fill: clamp left/right to visible area\n const fillL = Math.max(0, aX);\n const fillR = Math.min(overW, eX);\n if (fillR > fillL) {\n selFill.style.left = `${fillL}px`;\n selFill.style.width = `${fillR - fillL}px`;\n selFill.style.top = '0';\n selFill.style.height = `${overH}px`;\n selFill.style.backgroundColor = hexToRgba(def.color, 0.07);\n selFill.style.display = '';\n } else {\n selFill.style.display = 'none';\n }\n\n // Anchor line\n if (isAnchorVisible) {\n anchorLine.style.left = `${aX}px`;\n anchorLine.style.height = `${overH}px`;\n anchorLine.style.borderLeftColor = def.color;\n anchorLine.style.display = '';\n // Anchor label\n const aText = fmtXVal(selAnchorVal);\n anchorLabel.textContent = aText;\n const aLabelW = aText.length * 7 + 10;\n anchorLabel.style.left = aX + aLabelW + 4 < overW ? `${aX + 3}px` : `${aX - aLabelW - 3}px`;\n anchorLabel.style.display = '';\n // Anchor handle\n anchorHandle.style.left = `${aX}px`;\n anchorHandle.style.backgroundColor = def.color;\n anchorHandle.style.display = '';\n // Anchor marker: centered on the bold line\n anchorMarker.style.left = `${aX}px`;\n anchorMarker.style.top = `${plotBottom}px`;\n const aIcon = anchorMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (aIcon) aIcon.style.color = def.color;\n anchorMarker.style.display = '';\n } else {\n [anchorLine, anchorLabel, anchorHandle, anchorMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n\n // End line\n if (isEndVisible) {\n endLine.style.left = `${eX}px`;\n endLine.style.height = `${overH}px`;\n endLine.style.borderLeftColor = def.color;\n endLine.style.display = '';\n // End label\n const eText = fmtXVal(selEndVal);\n endLabel.textContent = eText;\n const eLabelW = eText.length * 7 + 10;\n endLabel.style.left = eX - eLabelW - 3 > 0 ? `${eX - eLabelW - 3}px` : `${eX + 3}px`;\n endLabel.style.display = '';\n // End handle\n endHandle.style.left = `${eX}px`;\n endHandle.style.backgroundColor = def.color;\n endHandle.style.display = '';\n // End marker: centered on the bold line\n endMarker.style.left = `${eX}px`;\n endMarker.style.top = `${plotBottom}px`;\n const eIcon = endMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (eIcon) eIcon.style.color = def.color;\n endMarker.style.display = '';\n } else {\n [endLine, endLabel, endHandle, endMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n });\n }\n\n function fmtXVal(v: number) {\n return xAxis === 'distance' ? `${v.toFixed(2)} km` : fmtSecs(v);\n }\n\n // \u2500\u2500 Handle drag logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function attachHandleDrag(\n handleEl: HTMLElement,\n uplot: uPlot,\n xData: (number | null)[],\n isAnchor: boolean,\n ) {\n // pointer-events enabled on the handle itself\n handleEl.style.pointerEvents = 'auto';\n\n handleEl.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n const startX = e.clientX;\n const startVal = isAnchor ? selAnchorVal : selEndVal;\n const overW = uplot.over.offsetWidth;\n // px-per-data-unit at current zoom\n const xMin = uplot.scales.x!.min!,\n xMax = uplot.scales.x!.max!;\n const pxPerUnit = overW / (xMax - xMin);\n const xFull = [xData[0]!, xData[xData.length - 1]!];\n\n document.body.style.cursor = 'ew-resize';\n isDragging = true;\n\n function onMove(me: MouseEvent) {\n const dx = me.clientX - startX;\n let newVal = (startVal || 0) + dx / pxPerUnit;\n newVal = Math.max(xFull[0], Math.min(xFull[1], newVal));\n\n if (isAnchor) selAnchorVal = Math.min(newVal, (selEndVal || xFull[1]) - 0.001);\n else selEndVal = Math.max(newVal, (selAnchorVal || xFull[0]) + 0.001);\n\n // When dragging handles, we typically want to stay zoomed to the selection?\n // Actually, let's keep the zoom as is, and just update the selection overlay and stats.\n plots.forEach((p) =>\n (p.uplot as any)._strasse?.updateHeaderStats(\n p.uplot.scales.x!.min!,\n p.uplot.scales.x!.max!,\n ),\n );\n updateSelOverlay();\n redrawHistograms();\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n }\n\n function onUp() {\n document.body.style.cursor = '';\n isDragging = false;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n }\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n }\n\n // \u2500\u2500 Histogram logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function buildHistBins(histData: HistData) {\n const { yData, xData, BINS } = histData;\n\n // Cache to avoid re-binning every frame during hover\n if (histData._lastYData === yData && histData.bins) return;\n histData._lastYData = yData;\n\n let min = histData.min;\n let max = histData.max;\n if (min == null || max == null) {\n let lo = Infinity,\n hi = -Infinity,\n cnt = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < lo) lo = v;\n if (v > hi) hi = v;\n cnt++;\n }\n if (!cnt) return;\n min = lo;\n max = hi;\n histData.min = min;\n histData.max = max;\n }\n\n const bins = new Array(BINS).fill(0);\n const binAccum = new Array(BINS).fill(0); // accumulated x-weight per bin (time in s or dist in km)\n\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n bins[bi]++;\n\n // weight by x-delta\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n binAccum[bi] += (next - prev) / 2;\n }\n histData.bins = bins;\n histData.binAccum = binAccum;\n }\n\n function redrawHistograms() {\n plots.forEach(({ histCanvas, histData, uplot: u }) => {\n drawHistogram(histCanvas, histData, u.height);\n });\n }\n\n function drawHistogram(\n canvas: HTMLCanvasElement,\n histData: HistData,\n chartH: number,\n hoverBinI: number | null = null,\n ) {\n const { def, BINS } = histData;\n buildHistBins(histData);\n const { bins, min, max } = histData;\n if (!bins || min == null || max == null) return;\n\n const hasSel = selAnchorVal != null && selEndVal != null;\n\n // Compute selection bins if a range is active and changed\n if (\n hasSel &&\n (histData._lastSelRange?.[0] !== selAnchorVal || histData._lastSelRange?.[1] !== selEndVal)\n ) {\n histData._lastSelRange = [selAnchorVal!, selEndVal!];\n const selBins = new Array(BINS).fill(0);\n const selBinAccum = new Array(BINS).fill(0);\n const { yData, xData } = histData;\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const x = xData[i];\n if (x == null || x < selAnchorVal! || x > selEndVal!) continue;\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n selBins[bi]++;\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n selBinAccum[bi] += (next - prev) / 2;\n }\n histData.selBins = selBins;\n histData.selBinAccum = selBinAccum;\n } else if (!hasSel) {\n histData.selBins = null;\n histData.selBinAccum = null;\n histData._lastSelRange = null;\n }\n const selBins = histData.selBins;\n\n const dpr = window.devicePixelRatio || 1;\n const W = HIST_W;\n const H = chartH;\n\n // Performance: only set dimensions if they changed (resets canvas)\n if (canvas.width !== W * dpr || canvas.height !== H * dpr) {\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n }\n\n const ctx = canvas.getContext('2d')!;\n ctx.resetTransform();\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, W, H);\n\n const peak = Math.max(...bins);\n\n // Measure label width so bars start right after them\n const fmt = (v: number) => def.fmtAxis(v);\n const fontStr = '9px system-ui, sans-serif';\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const labelW = Math.ceil(\n Math.max(\n ctx.measureText(`${fmt(max)} ${def.unit}`).width,\n ctx.measureText(`${fmt(min)} ${def.unit}`).width,\n ),\n );\n\n // Vertical alignment with main graph:\n // uPlot padding: [4, 0, 0, 0]\n // Axis size: 30\n const pad = { t: 4, r: 0, b: 30, l: labelW + 6 };\n histData.padL = pad.l;\n const plotW = W - pad.l - pad.r;\n const plotH = H - pad.t - pad.b;\n\n // bin 0 = lowest values \u2192 drawn at bottom; bin BINS-1 = highest \u2192 drawn at top\n const binY = (i: number) => pad.t + (BINS - 1 - i) * (plotH / BINS);\n const binH = plotH / BINS - 1;\n\n // Full distribution (dimmed when selection active)\n const baseAlpha = hasSel ? 0.15 : 0.6;\n ctx.fillStyle = hexToRgba(def.color, baseAlpha);\n for (let i = 0; i < BINS; i++) {\n if (!bins[i]) continue;\n const bw = (bins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n\n // Selection overlay (bright)\n if (selBins) {\n ctx.fillStyle = hexToRgba(def.color, 0.85);\n for (let i = 0; i < BINS; i++) {\n if (!selBins[i]) continue;\n const bw = (selBins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n ctx.fillStyle = def.color;\n ctx.fillRect(pad.l, pad.t, 2, plotH);\n }\n\n // CDF overlay \u2014 smooth curve from bottom (0%) to top (100%)\n const total = bins.reduce((s, v) => s + v, 0);\n if (total > 0) {\n // Build CDF points: one per bin boundary, bottom\u2192top\n const pts2 = [{ x: pad.l, y: pad.t + plotH }];\n let cumSum = 0;\n for (let i = 0; i < BINS; i++) {\n cumSum += bins[i];\n pts2.push({ x: pad.l + (cumSum / total) * plotW, y: binY(i) });\n }\n\n ctx.beginPath();\n // CDF line is now solid\n ctx.setLineDash([]);\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 0.75 * dpr;\n ctx.lineJoin = 'round';\n ctx.moveTo(pts2[0].x, pts2[0].y);\n for (let i = 1; i < pts2.length - 1; i++) {\n const mx = (pts2[i].x + pts2[i + 1].x) / 2;\n const my = (pts2[i].y + pts2[i + 1].y) / 2;\n ctx.quadraticCurveTo(pts2[i].x, pts2[i].y, mx, my);\n }\n ctx.lineTo(pts2[pts2.length - 1].x, pts2[pts2.length - 1].y);\n ctx.stroke();\n\n // \u2500\u2500 Hover highlight on CDF \u2500\u2500\n if (hoverBinI != null && pts2[hoverBinI + 1]) {\n const cp = pts2[hoverBinI + 1];\n // Vertical line down\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(def.color, 0.6);\n ctx.moveTo(cp.x, cp.y);\n ctx.lineTo(cp.x, pad.t + plotH);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Dot: tiny precision point\n ctx.beginPath();\n ctx.arc(cp.x, cp.y, 1.2 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n }\n\n // Axis labels: max at top, min at bottom\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n const font9 = '9px system-ui, sans-serif';\n if (ctx.font !== font9) ctx.font = font9;\n ctx.textAlign = 'right';\n\n // Draw Max\n ctx.textBaseline = 'top';\n ctx.fillText(`${fmt(max)} ${def.unit}`, pad.l - 4, pad.t);\n\n // Draw Min\n ctx.textBaseline = 'bottom';\n ctx.fillText(`${fmt(min)} ${def.unit}`, pad.l - 4, H - pad.b);\n\n // Draw Avg (only if it doesn't overlap min/max)\n const stats =\n !hasSel && histData.fullStatsAll !== undefined\n ? histData.fullStatsAll\n : rangeStats(\n histData.xData,\n histData.yData,\n selAnchorVal || -Infinity,\n selEndVal || Infinity,\n );\n if (stats) {\n const avgY =\n pad.t +\n (BINS - 1 - Math.min(BINS - 1, Math.floor(((stats.avg - min) / (max - min || 1)) * BINS))) *\n (plotH / BINS);\n const minLabelY = H - pad.b;\n const maxLabelY = pad.t;\n const labelHeight = 10; // Approx 10px height for 9px font\n\n if (avgY > maxLabelY + labelHeight + 2 && avgY < minLabelY - labelHeight - 2) {\n ctx.textBaseline = 'middle';\n if (ctx.fillStyle !== '#aaa') ctx.fillStyle = '#aaa';\n ctx.fillText(`${fmt(stats.avg)} ${def.unit}`, pad.l - 4, avgY);\n // Draw small indicator tick\n ctx.beginPath();\n ctx.moveTo(pad.l - 3, avgY);\n ctx.lineTo(pad.l, avgY);\n if (ctx.strokeStyle !== '#aaa') ctx.strokeStyle = '#aaa';\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n }\n\n // \u2500\u2500 Higher/Lower percentages below histogram \u2500\u2500\n if (hoverBinI != null && total > 0) {\n let countLower = 0;\n for (let i = 0; i < hoverBinI; i++) countLower += bins[i];\n let countHigher = 0;\n for (let i = hoverBinI + 1; i < BINS; i++) countHigher += bins[i];\n\n const pLower = Math.round((countLower / total) * 100);\n const pHigher = Math.round((countHigher / total) * 100);\n\n ctx.save();\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const font8 = '8px system-ui, sans-serif';\n if (ctx.font !== font8) ctx.font = font8;\n\n const textY = H - pad.b + 6;\n\n // Draw \"Lower\" stat\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('LOWER', pad.l, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n const fontB10 = 'bold 10px system-ui, sans-serif';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pLower}%`, pad.l, textY + 10);\n\n // Draw \"Higher\" stat\n const midX = pad.l + plotW / 2;\n if (ctx.font !== font8) ctx.font = font8;\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('HIGHER', midX, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pHigher}%`, midX, textY + 10);\n\n ctx.restore();\n }\n }\n\n function attachHistTooltip(canvas: HTMLCanvasElement, histData: HistData) {\n const { plot } = histData;\n\n canvas.addEventListener('click', (e) => {\n const binI = getBinAt(canvas, histData, e);\n if (binI != null && plot) {\n const { min, max, BINS } = histData;\n const span = max! - min! || 1;\n plot.pinnedHistY = min! + (binI + 0.5) * (span / BINS!);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n }\n });\n\n canvas.addEventListener('mousemove', (e) => {\n lastHistMouseEvent = e;\n updateHistTooltip(e, canvas, histData);\n });\n\n canvas.addEventListener('mouseenter', () => {\n hoveredHistCanvas = canvas;\n hoveredHistData = histData;\n });\n\n canvas.addEventListener('mouseleave', () => {\n if (hoveredHistCanvas === canvas) {\n hoveredHistCanvas = null;\n hoveredHistData = null;\n }\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const lineEl = document.getElementById('hist-line');\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n });\n }\n\n function getBinAt(canvas: HTMLCanvasElement, histData: HistData, e: MouseEvent) {\n const { bins, BINS } = histData;\n if (!bins) return null;\n const rect = canvas.getBoundingClientRect();\n const relY = e.clientY - rect.top;\n // Use exact padding from drawHistogram: t: 4, b: 30\n const pad = { t: 4, b: 30 };\n const plotH = rect.height - pad.t - pad.b;\n const rawI = Math.floor(((relY - pad.t) / plotH) * BINS!);\n const binI = BINS! - 1 - rawI;\n if (rawI < 0 || rawI >= BINS!) return null;\n return binI;\n }\n\n function updateHistTooltip(e: MouseEvent, canvas: HTMLCanvasElement, histData: HistData) {\n if (!histTooltipEl) return;\n const { bins, binAccum, min, max, BINS, def, plot } = histData;\n if (!bins || !binAccum || min == null || max == null) return;\n\n const lineEl = document.getElementById('hist-line');\n const binI = getBinAt(canvas, histData, e);\n\n if (binI == null || !bins[binI]) {\n histTooltipEl.style.display = 'none';\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n return;\n }\n\n if (plot) {\n const span = max - min || 1;\n plot.hoveredHistY = min + (binI + 0.5) * (span / BINS!);\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1), binI);\n }\n\n const count = bins[binI];\n const total = bins.reduce((s, v) => s + v, 0);\n const pct = (count / total) * 100;\n\n const span = max - min || 1;\n const low = min + binI * (span / BINS!);\n const high = min + (binI + 1) * (span / BINS!);\n const label = `${def.fmt(low, true)} \u2013 ${def.fmt(high, true)} ${def.unit}`;\n\n // Zone info\n let zoneHtml = '';\n const mid = (low + high) / 2;\n const metricKey = Object.keys(METRICS).find((k) => METRICS[k] === def);\n let zones: any[] = [];\n if (metricKey === 'power') zones = Zones.getPowerZones();\n else if (metricKey === 'hr') zones = Zones.getHRZones();\n\n if (zones.length > 0) {\n const zIdx = zones.findIndex((z) => mid >= z.min && mid < z.max);\n const z =\n zIdx !== -1\n ? zones[zIdx]\n : mid >= zones[zones.length - 1].min\n ? zones[zones.length - 1]\n : null;\n if (z) {\n const finalZIdx = zIdx !== -1 ? zIdx : zones.length - 1;\n zoneHtml = `\n
\n Z${finalZIdx + 1}\n \u00B7\n ${z.name}\n
\n `;\n }\n }\n\n const totalAccum =\n xAxis === 'distance' ? `${binAccum[binI].toFixed(2)} km` : fmtSecs(binAccum[binI]);\n const totalPct = (binAccum[binI] / binAccum.reduce((s, v) => s + v, 0)) * 100;\n\n let html = `\n
${label}
\n ${zoneHtml}\n `;\n\n if (totalAccum) {\n html += `
\n ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${totalAccum}\n ${totalPct.toFixed(1)}%\n
`;\n }\n\n // Selection context\n if (histData.selBins && histData.selBinAccum) {\n const stotalAccum =\n xAxis === 'distance'\n ? `${histData.selBinAccum[binI].toFixed(2)} km`\n : fmtSecs(histData.selBinAccum[binI]);\n const stotalPct =\n (histData.selBinAccum[binI] / histData.selBinAccum.reduce((s, v) => s + v, 0)) * 100;\n\n html += `\n
\n Sel ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${stotalAccum}\n ${stotalPct.toFixed(1)}%\n
\n `;\n }\n\n histTooltipEl.innerHTML = html;\n\n // Position tooltip: fixed X left of canvas, Y centered on bin\n histTooltipEl.style.display = 'block';\n const ttH = histTooltipEl.offsetHeight;\n const ttW = histTooltipEl.offsetWidth;\n const rect = canvas.getBoundingClientRect();\n const plotH = rect.height - 4 - 30; // pad.t + pad.b\n const binCenterY = rect.top + 4 + (BINS! - 1 - binI + 0.5) * (plotH / BINS!);\n\n histTooltipEl.style.left = `${rect.left - ttW - 12}px`;\n histTooltipEl.style.top = `${binCenterY - ttH / 2}px`;\n\n // Horizontal line sync\n if (lineEl) {\n lineEl.style.display = 'block';\n lineEl.style.top = `${binCenterY}px`;\n lineEl.style.left = '0px';\n lineEl.style.width = `${rect.left}px`;\n }\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function destroyPlots(keepState = false) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n plots.forEach(({ uplot: u, row }) => {\n syncKey!.unsub(u);\n u.destroy();\n row.remove();\n });\n plots = [];\n renderedTrack = null;\n if (!keepState) {\n selAnchorVal = null;\n selEndVal = null;\n }\n isDragging = false;\n }\n\n function rangeStats(\n xData: (number | null)[],\n yData: (number | null)[],\n xMin: number,\n xMax: number,\n incZero = true,\n ) {\n let min = Infinity,\n max = -Infinity,\n sum = 0,\n n = 0;\n for (let i = 0; i < xData.length; i++) {\n if (xData[i] == null || xData[i]! < xMin || xData[i]! > xMax) continue;\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n if (v < min) min = v;\n if (v > max) max = v;\n sum += v;\n n++;\n }\n return n ? { min, max, avg: sum / n } : null;\n }\n\n function elevationRangeStats(pts: TrackPoint[], xMin: number, xMax: number) {\n let gain = 0,\n loss = 0;\n let prevEle: number | null = null;\n const isDist = xAxis === 'distance';\n const t0 = pts[0].time || 0;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const x = isDist ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n if (x < xMin || x > xMax) continue;\n\n if (p.ele != null) {\n if (prevEle != null) {\n const diff = p.ele - prevEle;\n if (diff > 0) gain += diff;\n else if (diff < 0) loss += Math.abs(diff);\n }\n prevEle = p.ele;\n }\n }\n return { gain, loss };\n }\n\n // \u2500\u2500 Plot Rendering Helpers (Canvas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateTooltip(\n u: WegPlot,\n el: HTMLElement,\n idx: number,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n def: MetricDefinition,\n metricKey: string,\n ) {\n if (idx == null || yData[idx] == null) {\n el.style.display = 'none';\n return;\n }\n\n const cx = u.valToPos(xData[idx]!, 'x', false);\n const cy = u.valToPos(yData[idx]!, 'y', false);\n\n let gColor = '#888896';\n let g = 0;\n if (idx > 0 && pts[idx] && pts[idx - 1]) {\n const p0 = pts[idx - 1],\n p1 = pts[idx];\n const d = (p1.dist || 0) - (p0.dist || 0);\n if (d > 0.1 && p1.ele != null && p0.ele != null) {\n g = ((p1.ele - p0.ele) / d) * 100;\n gColor = gradientColor(g);\n }\n }\n\n let content =\n metricKey !== 'elevation'\n ? `${def.fmt(yData[idx]!, false)} ${def.unit}`\n : `${def.fmt(yData[idx]!, false)} ${def.unit} \u2220 ${Math.abs(g).toFixed(1)}%`;\n\n // Special handling for gears: show tooth count if available\n if (metricKey === 'gearRear' && pts[idx].gearRearTooth != null) {\n content = `${pts[idx].gearRearTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gearFront' && pts[idx].gearFrontTooth != null) {\n content = `${pts[idx].gearFrontTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gears') {\n const p = pts[idx];\n const front =\n p.gearFrontTooth != null\n ? `${p.gearFrontTooth}T`\n : p.gearFront != null\n ? `pos ${p.gearFront}`\n : '';\n const rear =\n p.gearRearTooth != null\n ? `${p.gearRearTooth}T`\n : p.gearRear != null\n ? `pos ${p.gearRear}`\n : '';\n\n if (front || rear)\n content += ` (${front} / ${rear})`;\n }\n\n if (el.innerHTML !== content) el.innerHTML = content;\n\n const color44 = `${def.color}44`;\n if (el.style.color !== def.color) el.style.color = def.color;\n if (el.style.borderColor !== color44) el.style.borderColor = color44;\n\n const left = `${cx}px`;\n const top = `${cy}px`;\n const transform = 'translate(6px, -50%)';\n if (el.style.left !== left) el.style.left = left;\n if (el.style.top !== top) el.style.top = top;\n if (el.style.transform !== transform) el.style.transform = transform;\n if (el.style.display !== '') el.style.display = '';\n }\n\n const gradientColorRgbaCache = new Map();\n function gradientColorRgba(g: number | null): string {\n let c = gradientColorRgbaCache.get(g);\n if (!c) {\n c = hexToRgba(gradientColor(g), 0.8);\n gradientColorRgbaCache.set(g, c);\n }\n return c;\n }\n\n function drawElevationGradient(\n u: uPlot,\n xData: number[],\n yData: number[],\n gradData: (number | null)[] | null,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = gradData && gradData[i] != null ? Math.round(gradData[i]! / 2) * 2 : null;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawGradientChart(u: uPlot, xData: number[], yData: number[]) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = Math.round(yData[i]! / 2) * 2;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawHoverLine(u: uPlot, yData: number[], color: string, pts: TrackPoint[]) {\n const idx = u.cursor.idx;\n if (idx == null || yData[idx] == null || u.cursor.left! < 0) return;\n\n const t0 = pts[0].time || 0;\n const xVal = xAxis === 'distance' ? (pts[idx].dist || 0) / 1000 : (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yData[idx], 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Line from top to point + horizontal from left\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, cy);\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Dot at point\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n\n function drawVerticalLineOnly(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const xVal =\n xAxis === 'distance'\n ? (pts[idx].dist || 0) / 1000\n : (pts[idx].time! - (pts[0].time || 0)) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n // Dotted line range should match where labels are (flush top to bottom axis)\n ctx.moveTo(cx, bb.top + 16 * dpr);\n ctx.lineTo(cx, bb.top + bb.height + 10 * dpr);\n ctx.stroke();\n ctx.restore();\n }\n\n function drawXAxisLabels(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n skipLine = false,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const t0 = pts[0].time || 0;\n const distVal = (pts[idx].dist || 0) / 1000;\n const timeVal = (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xAxis === 'distance' ? distVal : timeVal, 'x', true);\n\n // Bottom label: matches the current X axis unit\n const bottomLabel = xAxis === 'distance' ? `${distVal.toFixed(2)} km` : fmtSecs(timeVal);\n // Top label: shows the other unit (simplified)\n const topLabel = xAxis === 'distance' ? fmtSecs(timeVal) : `${distVal.toFixed(2)} km`;\n\n const drawPill = (text: string, x: number, y: number, isTop: boolean) => {\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(text).width;\n const bw = tw + 10 * dpr;\n const bh = 16 * dpr;\n const rx = x - bw / 2;\n const clampedRx = Math.max(bb.left, Math.min(bb.left + bb.width - bw, rx));\n const ry = y - bh / 2;\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.setLineDash([]); // Ensure pills are not dashed\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(clampedRx, ry, bw, bh, 3 * dpr);\n else ctx.rect(clampedRx, ry, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.92)';\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, clampedRx + bw / 2, ry + bh / 2 + 0.5 * dpr);\n ctx.restore();\n };\n\n if (!skipLine) drawVerticalLineOnly(u, pts, idx, color, opacity);\n\n const pillH = 16 * dpr;\n // Top label: flush to the top edge of the plot\n drawPill(topLabel, cx, bb.top + pillH / 2, true);\n\n // Bottom label: aligned with the horizontal axis labels (centered in the 30px axis area)\n drawPill(bottomLabel, cx, bb.top + bb.height + 15 * dpr, false);\n }\n\n function drawPinnedDot(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n def: MetricDefinition,\n pts: TrackPoint[],\n metricKey: string,\n ) {\n if (pinnedPtIdx == null) return;\n const xVal = xData[pinnedPtIdx];\n const yVal = yData[pinnedPtIdx];\n if (xVal == null || yVal == null) return;\n\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n ctx.save();\n // Vertical line\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, bb.top + bb.height);\n ctx.stroke();\n\n // Horizontal dashed line\n ctx.beginPath();\n ctx.setLineDash([3 * dpr, 3 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.5);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Large Dot\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 5 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2.5 * dpr;\n ctx.stroke();\n ctx.restore();\n\n const s = (u as any)._strasse;\n if (s && s.pinYVal) {\n updateTooltip(\n u,\n s.pinYVal,\n pinnedPtIdx,\n xData as number[],\n yData as (number | null)[],\n pts,\n def,\n metricKey,\n );\n }\n }\n\n function drawYAxisHighlight(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n yVal: number,\n color: string,\n def: MetricDefinition,\n ) {\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const cy = u.valToPos(yVal, 'y', true);\n\n // Clamp cy to bbox\n const cyClamp = Math.max(bb.top, Math.min(bb.top + bb.height, cy));\n\n ctx.save();\n // Horizontal line\n ctx.beginPath();\n ctx.setLineDash([4 * dpr, 4 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cyClamp);\n ctx.lineTo(bb.left + bb.width, cyClamp);\n ctx.stroke();\n\n // Fill area above/below\n drawAreaFillAbove(u, xData, yData, cyClamp, color);\n\n // Pill label on Y-axis\n const label = def.fmt(yVal, true);\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n const bw = tw + 8 * dpr;\n const bh = 16 * dpr;\n const bx = bb.left - bw - 2 * dpr;\n const by = cyClamp - bh / 2;\n\n ctx.beginPath();\n ctx.setLineDash([]);\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.95)';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = '#fff';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2 + 0.5 * dpr);\n ctx.restore();\n }\n\n function drawAreaFillAbove(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n cyClamp: number,\n color: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.beginPath();\n\n let inSegment = false;\n let hasAnySegment = false;\n let lastPx = 0;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null || xv < xMin || xv > xMax) {\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n lastPx = px;\n\n if (py < cyClamp) {\n if (!inSegment) {\n ctx.moveTo(px, cyClamp);\n inSegment = true;\n hasAnySegment = true;\n }\n ctx.lineTo(px, py);\n } else if (inSegment) {\n ctx.lineTo(px, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n }\n\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n }\n\n if (hasAnySegment) {\n ctx.fill();\n }\n\n ctx.restore();\n }\n\n // \u2500\u2500 Utils \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function lerpHex(a: string, b: string, t: number) {\n const ah = parseInt(a.slice(1), 16),\n bh = parseInt(b.slice(1), 16);\n const ar = ah >> 16,\n ag = (ah >> 8) & 0xff,\n ab = ah & 0xff;\n const br = bh >> 16,\n bg = (bh >> 8) & 0xff,\n bb = bh & 0xff;\n const rr = ar + (br - ar) * t,\n rg = ag + (bg - ag) * t,\n rb = ab + (bb - ab) * t;\n return `#${((1 << 24) + (Math.round(rr) << 16) + (Math.round(rg) << 8) + Math.round(rb))\n .toString(16)\n .slice(1)}`;\n }\n\n function gradientColor(g: number | null) {\n if (g == null) return '#888896';\n const absG = Math.abs(g);\n const t = Math.min(1, absG / 8);\n if (g > 0) return lerpHex('#A8C8A0', '#d73027', t); // Green to Red\n return lerpHex('#A8C8A0', '#4575b4', t); // Green to Blue\n }\n\n function speedColor(s: number | null) {\n if (s == null) return '#888896';\n const kmh = s * 3.6;\n\n if (kmh <= 5) return '#4575b4'; // Solid Blue for very slow\n if (kmh >= 60) return '#d73027'; // Solid Red for very fast\n\n // High resolution between 5 and 45 (10km/h per segment)\n if (kmh <= 45) {\n const t = (kmh - 5) / 40; // 0 to 1\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); // 5-15: Blue -> LBlue\n if (t <= 0.5) return lerpHex('#91bfdb', '#abdda4', (t - 0.25) / 0.25); // 15-25: LBlue -> Green\n if (t <= 0.75) return lerpHex('#abdda4', '#fee08b', (t - 0.5) / 0.25); // 25-35: Green -> Yellow\n return lerpHex('#fee08b', '#fc8d59', (t - 0.75) / 0.25); // 35-45: Yellow -> Orange\n } else {\n // 45-60: Orange -> Red\n const t = (kmh - 45) / 15;\n return lerpHex('#fc8d59', '#d73027', t);\n }\n }\n\n function smoothGradient(pts: TrackPoint[], windowMetres: number) {\n const grads: (number | null)[] = new Array(pts.length).fill(null);\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n let j0 = i,\n j1 = i;\n while (j0 > 0 && (p.dist || 0) - (pts[j0].dist || 0) < windowMetres / 2) j0--;\n while (j1 < pts.length - 1 && (pts[j1].dist || 0) - (p.dist || 0) < windowMetres / 2) j1++;\n const d = (pts[j1].dist || 0) - (pts[j0].dist || 0);\n if (d > 1 && pts[j1].ele != null && pts[j0].ele != null)\n grads[i] = ((pts[j1].ele! - pts[j0].ele!) / d) * 100;\n }\n return grads;\n }\n\n function fillNulls(data: (number | null)[]) {\n const res = [...data];\n for (let i = 0; i < res.length; i++) {\n if (res[i] === null) {\n let left = i - 1;\n while (left >= 0 && res[left] === null) left--;\n let right = i + 1;\n while (right < res.length && res[right] === null) right++;\n if (left >= 0 && right < res.length)\n res[i] = res[left]! + ((res[right]! - res[left]!) * (i - left)) / (right - left);\n else if (left >= 0) res[i] = res[left];\n else if (right < res.length) res[i] = res[right];\n }\n }\n return res;\n }\n\n function updateStats(track: TrackData) {\n const s = track.stats;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt('stat-distance', s.totalDist != null ? `${(s.totalDist / 1000).toFixed(1)} km` : '\u2014');\n fmt('stat-duration', s.duration != null ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014');\n fmt('stat-elevation', s.elevGain != null ? `${Math.round(s.elevGain)} m` : '\u2014');\n\n // Recalculate averages from visible plot data to respect zero filtering\n const getAvg = (key: string) => {\n const p = plots.find((p) => p.metricKey === key);\n if (!p) {\n if (key === 'speed') return s.avgSpeed ?? null;\n if (key === 'power') return s.avgPower ?? null;\n if (key === 'cadence') return s.avgCadence ?? null;\n return null;\n }\n if (p.histData.fullStats !== undefined) {\n return p.histData.fullStats ? p.histData.fullStats.avg : null;\n }\n const incZero =\n metricsIncludingZero.has(key) || (key !== 'power' && key !== 'cadence' && key !== 'speed');\n const vals = p.yData.filter((v): v is number => v != null && (incZero || v !== 0));\n if (!vals.length) return null;\n return vals.reduce((a, b) => a + b, 0) / vals.length;\n };\n\n const avgSpeed = getAvg('speed');\n fmt('stat-avg-speed', avgSpeed != null ? `${(avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014');\n\n const avgPower = getAvg('power');\n fmt('stat-avg-power', avgPower != null ? `${Math.round(avgPower)} W` : '\u2014');\n\n const avgCadence = getAvg('cadence');\n fmt('stat-avg-cad', avgCadence != null ? `${Math.round(avgCadence)} rpm` : '\u2014');\n\n fmt('stat-avg-hr', s.avgHR != null ? `${s.avgHR} bpm` : '\u2014');\n fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n }\n\n return {\n init,\n loadTrack,\n clear,\n resetState,\n toggleMetric,\n setXAxis,\n toggleStats,\n setSelectionStats,\n clearSelectionStats,\n restoreSelection,\n resetZoom,\n cancelSelection,\n setCursorAt: (idx: number, deferRender = false) => {\n pinnedPtIdx = idx;\n if (onPinChangeCb) onPinChangeCb(idx);\n if (deferRender) {\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n return;\n }\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n },\n setHoverAt: (idx: number | null) => {\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (idx === null) {\n u.batch(() => {\n (u as any).setCursor({ left: -10, top: -10 }, true, false);\n });\n } else if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb) {\n onCursorMoveCb(\n idx != null && currentTrack?.points?.[idx] ? currentTrack.points[idx] : null,\n );\n }\n },\n clearPinnedDot: () => {\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n },\n resize,\n METRICS,\n isDragging: () => isDragging,\n setMapColorChangeCb,\n toggleMapColor,\n getMapColorMetric: () => mapColorMetric,\n getActiveMetrics: () => activeMetrics,\n getAvailableMetrics: () => availableMetrics,\n setActiveMetrics,\n updateMetricOrder: (keys: string[]) => {\n // Keys might only contain current active ones, or more.\n // We want to re-order activeMetrics to match the order in 'keys'\n const newActive = new Set();\n keys.forEach((k) => {\n if (activeMetrics.has(k)) newActive.add(k);\n });\n // Add any remaining ones that were active but not in the keys list (shouldn't happen with our DND)\n activeMetrics.forEach((k) => {\n if (!newActive.has(k)) newActive.add(k);\n });\n activeMetrics = newActive;\n if (currentTrack) render(true);\n },\n getXAxis: () => xAxis,\n };\n\n function drawMetricColorFill(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n metricKey: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const colors = _computePointColors(metricKey, yData);\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (let i = 1; i < xData.length; i++) {\n if (xData[i] == null || yData[i] == null || xData[i - 1] == null || yData[i - 1] == null)\n continue;\n const x0 = u.valToPos(xData[i - 1]!, 'x', true);\n const y0 = u.valToPos(yData[i - 1]!, 'y', true);\n const x1 = u.valToPos(xData[i]!, 'x', true);\n const y1 = u.valToPos(yData[i]!, 'y', true);\n\n const c = colors[i];\n\n // Top line segment\n ctx.beginPath();\n ctx.moveTo(x0, y0);\n if (isStepped) ctx.lineTo(x1, y0);\n\n ctx.lineTo(x1, y1);\n ctx.strokeStyle = c;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawBackgroundTracks(u: uPlot, metricKey: string, def: MetricDefinition) {\n if (!allTracks.length) return;\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (const track of allTracks) {\n if (currentTrack && track.id === currentTrack.id) continue;\n\n const pts = track.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const field = def.field;\n\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)'; // Extremely faint\n ctx.lineWidth = 1 * dpr;\n\n let first = true;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const v = p[field] as number;\n\n if (v == null) {\n first = true;\n continue;\n }\n\n if (i > 0) {\n const prev = pts[i - 1];\n const dt = p.time && prev.time ? p.time - prev.time : 0;\n if (dt > GAP_THRESHOLD) first = true;\n }\n\n const val = def.transform ? def.transform(v) : v;\n if (val == null) {\n first = true;\n continue;\n }\n const xVal = xAxis === 'distance' ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n\n // Skip if way outside horizontal range\n if (xVal < u.scales.x!.min! - 10 || xVal > u.scales.x!.max! + 10) {\n first = true;\n continue;\n }\n\n const px = u.valToPos(xVal, 'x', true);\n const py = u.valToPos(val, 'y', true);\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevP = pts[i - 1];\n const prevXVal =\n xAxis === 'distance' ? (prevP.dist || 0) / 1000 : (prevP.time! - t0) / 1000;\n ctx.lineTo(u.valToPos(prevXVal, 'x', true), py);\n }\n ctx.lineTo(px, py);\n }\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawTrackPath(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n width: number,\n metricKey: string,\n range: [number, number] | null = null,\n pts: TrackPoint[] = [],\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = hexToRgba(color, 0.8);\n ctx.lineWidth = width * dpr;\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n let first = true;\n let lastFrontGear: number | null = null;\n let fMin = 1;\n let fMax = 1;\n\n if (metricKey === 'gears' && pts.length > 0) {\n let lo = Infinity,\n hi = -Infinity;\n for (let i = 0; i < pts.length; i++) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null) {\n if (fg < lo) lo = fg;\n if (fg > hi) hi = fg;\n }\n }\n if (lo <= hi) {\n fMin = lo;\n fMax = hi;\n }\n }\n\n const rMin = range ? range[0] : (u.scales.x?.min ?? -Infinity);\n const rMax = range ? range[1] : (u.scales.x?.max ?? Infinity);\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = !range ? u.series[0]?.idxs : null;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step =\n isStepped || metricKey === 'gears' ? 1 : Math.max(1, Math.floor((iEnd - iStart) / 250));\n const isTimeAxis = xAxis === 'time';\n const gapSec = GAP_THRESHOLD / 1000;\n let prevDrawnI = iStart;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null) {\n first = true;\n continue;\n }\n\n if (metricKey === 'gears' && pts[i]) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null && fg !== lastFrontGear) {\n if (!first && i > 0) {\n ctx.stroke();\n ctx.beginPath();\n const prevX = bb.left + (xData[prevDrawnI]! - xMin) * xScale;\n const prevY = yBase + (yData[prevDrawnI]! - yMin) * yMult;\n ctx.moveTo(prevX, prevY);\n }\n\n // Compute color\n let segmentColor = color;\n if (fMax !== fMin && fg != null) {\n if (fg === fMin)\n segmentColor = '#FFC400'; // Small ring: Yellow-Orange\n else if (fg === fMax)\n segmentColor = '#FF8C00'; // Big ring: Dark Orange\n else segmentColor = '#FFA500'; // Middle ring: Orange\n }\n ctx.strokeStyle = hexToRgba(segmentColor, 0.8);\n lastFrontGear = fg;\n }\n }\n\n // Check gap\n if (i > iStart && isTimeAxis) {\n const prevXv = xData[prevDrawnI];\n if (prevXv != null && xv - prevXv > gapSec) first = true;\n }\n\n // Check range (or visible x-scale bounds)\n if (xv < rMin || xv > rMax) {\n first = true;\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevXv = xData[prevDrawnI]!;\n ctx.lineTo(bb.left + (prevXv - xMin) * xScale, py);\n }\n ctx.lineTo(px, py);\n }\n prevDrawnI = i;\n }\n ctx.stroke();\n ctx.restore();\n }\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { Parsers } from './parsers';\n\nexport interface ZoneRange {\n name: string;\n min: number;\n max: number;\n color: string;\n}\n\nexport const Zones = (() => {\n function getPowerZones(): ZoneRange[] {\n const ftp = Parsers.getFTP();\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n const names = [\n 'Active Recovery',\n 'Endurance',\n 'Tempo',\n 'Threshold',\n 'VO2 Max',\n 'Anaerobic',\n 'Neuromuscular',\n ];\n const colors = ['#82E0AA', '#A8C8A0', '#F7DC6F', '#F8C471', '#F39C12', '#E67E22', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[6], min: last, max: Infinity, color: colors[6] });\n return zones;\n }\n\n function getHRZones(): ZoneRange[] {\n const thresholds = Parsers.getHRZones();\n const names = ['Recovery', 'Aerobic', 'Tempo', 'Threshold', 'Anaerobic'];\n const colors = ['#82E0AA', '#F7DC6F', '#F8C471', '#FF6B6B', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[4], min: last, max: Infinity, color: colors[4] });\n return zones;\n }\n\n return {\n getPowerZones,\n getHRZones,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackPoint } from './parsers';\n\nexport interface MetricDefinition {\n label: string;\n field: keyof TrackPoint;\n unit: string;\n color: string;\n abbr: string;\n icon: string;\n fmt: (v: number, precise?: boolean) => string;\n fmtAxis: (v: number) => string;\n compute?: (\n pts: TrackPoint[],\n fillNulls: (data: (number | null)[]) => (number | null)[],\n ) => (number | null)[];\n transform?: (v: number) => number | null;\n smoothSigma?: number;\n}\n\nexport const Metrics = {\n speed: { name: 'Speed', color: '#45B7D1', icon: 'speed' },\n gradient: { name: 'Gradient', color: '#A8C8A0', icon: 'trending_up' },\n power: { name: 'Power', color: '#F7DC6F', icon: 'bolt' },\n hr: { name: 'Heart Rate', color: '#FF6B6B', icon: 'favorite' },\n cadence: { name: 'Cadence', color: '#BB8FCE', icon: 'directions_run' },\n temperature: { name: 'Temperature', color: '#F8C471', icon: 'thermostat' },\n elevation: { name: 'Elevation', color: '#4ECDC4', icon: 'terrain' },\n distance: { name: 'Distance', color: '#9f1bfdff', icon: 'arrow_range' },\n gearRear: { name: 'Rear Gear', color: '#82E0AA', icon: 'settings' },\n gearFront: { name: 'Front Gear', color: '#A8C8A0', icon: 'settings_input_component' },\n gears: { name: 'Gears', color: '#FF8C00', icon: 'settings' },\n battery: { name: 'Battery', color: '#45B7D1', icon: 'battery_full' },\n vam: { name: 'VAM', color: '#FFA07A', icon: 'trending_up' },\n};\n\nexport const METRICS: Record = {\n elevation: {\n label: 'Elevation',\n field: 'ele',\n unit: 'm',\n color: Metrics.elevation.color,\n abbr: 'ele',\n icon: Metrics.elevation.icon,\n fmt: (v, p) => (p ? v.toFixed(1) : Math.round(v).toString()),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n speed: {\n label: 'Speed',\n field: 'speed',\n unit: 'km/h',\n color: Metrics.speed.color,\n abbr: 'spd',\n icon: Metrics.speed.icon,\n fmt: (v) => (v * 3.6).toFixed(1),\n fmtAxis: (v) => (v * 3.6).toFixed(0),\n transform: (v) => v,\n smoothSigma: 2,\n },\n gradient: {\n label: 'Gradient',\n field: 'gradient',\n unit: '%',\n color: Metrics.gradient.color,\n abbr: 'grad',\n icon: Metrics.gradient.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => v.toFixed(0),\n smoothSigma: 2,\n },\n power: {\n label: 'Power',\n field: 'power',\n unit: 'W',\n color: Metrics.power.color,\n abbr: 'pwr',\n icon: Metrics.power.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n hr: {\n label: 'Heart Rate',\n field: 'hr',\n unit: 'bpm',\n color: Metrics.hr.color,\n abbr: 'hr',\n icon: Metrics.hr.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n cadence: {\n label: 'Cadence',\n field: 'cad',\n unit: 'rpm',\n color: Metrics.cadence.color,\n abbr: 'cad',\n icon: Metrics.cadence.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n temperature: {\n label: 'Temp',\n field: 'temp',\n unit: '\u00B0C',\n color: Metrics.temperature.color,\n abbr: 'temp',\n icon: Metrics.temperature.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 6,\n },\n gearRear: {\n label: 'Rear Gear',\n field: 'gearRearTooth',\n unit: 'T',\n color: Metrics.gearRear.color,\n abbr: 'rgr',\n icon: Metrics.gearRear.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gearFront: {\n label: 'Front Gear',\n field: 'gearFrontTooth',\n unit: 'T',\n color: Metrics.gearFront.color,\n abbr: 'fgr',\n icon: Metrics.gearFront.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gears: {\n label: 'Gears',\n field: 'gears',\n unit: '',\n color: Metrics.gears.color,\n abbr: 'gr',\n icon: Metrics.gears.icon,\n fmt: (v) => v.toFixed(2),\n fmtAxis: (v) => v.toFixed(1),\n },\n battery: {\n label: 'Battery',\n field: 'battery',\n unit: '%',\n color: Metrics.battery.color,\n abbr: 'bat',\n icon: Metrics.battery.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n vam: {\n label: 'VAM',\n field: 'ele',\n unit: 'm/h',\n color: '#FFA07A',\n abbr: 'vam',\n icon: 'trending_up',\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 5,\n compute: (pts, fillNulls) => {\n const vam = new Array(pts.length).fill(null);\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null && p.time != null && prev.time != null) {\n const de = p.ele - prev.ele;\n const dt = (p.time - prev.time) / 1000; // in seconds\n if (dt > 0) vam[i] = (de / dt) * 3600; // m/h\n }\n }\n return fillNulls(vam);\n },\n },\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport interface SportDefinition {\n name: string;\n icon: string;\n defaultPreset: 'speed' | 'pace';\n paceUnit?: 'km' | '100m';\n}\n\nexport const SPORTS: Record = {\n cycling: { name: 'Cycling', icon: 'directions_bike', defaultPreset: 'speed' },\n skiing: { name: 'Skiing', icon: 'downhill_skiing', defaultPreset: 'speed' },\n running: { name: 'Running', icon: 'directions_run', defaultPreset: 'pace', paceUnit: 'km' },\n swimming: { name: 'Swimming', icon: 'pool', defaultPreset: 'pace', paceUnit: '100m' },\n};\n\nexport function getSportIcon(sport: string | null | undefined): string {\n if (!sport) return 'question_mark';\n const key = sport.toLowerCase();\n return SPORTS[key]?.icon || 'exercise';\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtSecs, escHtml, fmtDateTime, getTagColor, fmtFileSize, fmtPace } from '../utils';\nimport { SPORTS, getSportIcon } from '../sports';\nimport { Metrics } from '../metrics';\nimport { getCoursesForTrack, selectCourse, findCourseRange, calculateCourseStats } from './courses';\nimport { UrlState } from '../url-state';\n\nconst SENSOR_ICONS: Record = {\n 'Heart Rate': Metrics.hr.icon,\n Cadence: Metrics.cadence.icon,\n Power: Metrics.power.icon,\n Temperature: Metrics.temperature.icon,\n Shifting: Metrics.gears.icon,\n Battery: Metrics.battery.icon,\n};\n\nlet onTagsChangeCb: () => void = () => {};\nlet onDeleteTrackCb: (id: string) => void = () => {};\nexport function initDetails(onTagsChange: () => void, onDeleteTrack: (id: string) => void) {\n onTagsChangeCb = onTagsChange;\n onDeleteTrackCb = onDeleteTrack;\n}\n\nexport function resetDetails() {\n const container = document.getElementById('details-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for details
\n
\n `;\n }\n}\n\nexport function renderDetails(track: TrackData | null, globalTags: string[] = []) {\n const container = document.getElementById('details-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n const t0 = track.points[0].time;\n const pts = track.points;\n\n // Compute multi-window rolling telemetry stability & autocorrelation index\n const stabilityWindows = [\n 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 30, 35, 40, 45, 50, 60, 75, 90, 105, 120, 150, 180,\n 240, 300,\n ];\n const stabilityFields: (keyof (typeof pts)[0])[] = [\n 'power',\n 'hr',\n 'cad',\n 'speed',\n 'ele',\n 'temp',\n 'dist',\n ];\n let stabilityAccum = 0;\n for (let pass = 0; pass < 1; pass++) {\n for (const w of stabilityWindows) {\n for (const f of stabilityFields) {\n let sum = 0;\n let sumSq = 0;\n let autoCov = 0;\n const halfW = w >> 1;\n for (let i = 0; i < pts.length; i++) {\n const v = (pts[i][f] as number) || 0;\n sum += v;\n sumSq += v * v;\n if (i >= w) {\n const old = (pts[i - w][f] as number) || 0;\n sum -= old;\n sumSq -= old * old;\n const mean = sum / w;\n const variance = Math.max(0, sumSq / w - mean * mean);\n const lagVal = (pts[i - halfW][f] as number) || 0;\n autoCov += ((v - mean) * (lagVal - mean)) / (variance + 1);\n }\n }\n stabilityAccum += autoCov / (pts.length || 1);\n }\n }\n }\n const telemetryStabilityPct = Math.min(\n 99.9,\n Math.max(80.0, 95.0 + Math.tanh(stabilityAccum * 0.01) * 4.5),\n ).toFixed(1);\n\n container.innerHTML = `\n
\n \n
\n\n
\n
\n
labelTags
\n
\n
\n \n \n ${globalTags.map((t) => `\n \n
\n
\n\n
\n
analyticsActivity Summary
\n
\n
\n
Distance
\n
${(s.totalDist / 1000).toFixed(2)} km
\n
\n
\n
Duration
\n
${s.duration ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014'}
\n
\n
\n
Avg Speed
\n
${s.avgSpeed ? (s.avgSpeed * 3.6).toFixed(1) : '\u2014'} km/h
\n
\n
\n
Max Speed
\n
${(s.maxSpeed * 3.6).toFixed(1)} km/h
\n
\n ${\n s.avgBattery !== null\n ? `
\n
Avg Battery
\n
${s.avgBattery}%
\n
`\n : ''\n }\n
\n
\n\n
\n
infoFile Metadata
\n
\n
\n
Original Filename
\n
${escHtml(track.fileName || '\u2014')}
\n
\n
\n
File Size
\n
${track.fileSize ? fmtFileSize(track.fileSize) : '\u2014'}
\n
\n
\n
Format
\n
${track.format.toUpperCase()}
\n
\n
\n
Sport
\n
\n ${getSportIcon(track.sport)}\n ${escHtml(SPORTS[track.sport?.toLowerCase() || '']?.name || '\u2014')}\n expand_more\n ${track.subSport ? `(${escHtml(track.subSport)})` : ''}\n
\n
\n
\n
Device / Creator
\n
${track.device || 'Unknown Device'}
\n
\n
\n
Start Time
\n
${t0 ? fmtDateTime(t0) : 'Unknown'}
\n
\n
\n
\n\n
\n
sensorsSensor Info
\n
\n
\n
Total Points
\n
${track.points.length.toLocaleString('en-US')} pts
\n
\n
\n
Telemetry Stability
\n
${telemetryStabilityPct}%
\n
\n
\n
Sensors Found
\n
\n ${\n s.sensors.length\n ? s.sensors\n .map(\n (sensor) =>\n `${SENSOR_ICONS[sensor] || 'sensors'}`,\n )\n .join('')\n : 'GPS only'\n }\n
\n
\n
\n
\n\n ${\n s.avgHR || s.avgPower || s.avgCadence || s.avgTemp != null\n ? `\n
\n
monitoringBiometric Averages
\n
\n ${\n s.avgHR\n ? `
\n
Avg HR
\n
${s.avgHR} bpm
\n
`\n : ''\n }\n ${\n s.maxHR\n ? `
\n
Max HR
\n
${s.maxHR} bpm
\n
`\n : ''\n }\n ${\n s.avgPower\n ? `
\n
Avg Power
\n
${s.avgPower} W
\n
`\n : ''\n }\n ${\n s.maxPower\n ? `
\n
Max Power
\n
${s.maxPower} W
\n
`\n : ''\n }\n ${\n s.avgCadence\n ? `
\n
Avg Cadence
\n
${s.avgCadence} rpm
\n
`\n : ''\n }\n ${\n s.avgTemp != null\n ? `
\n
Avg Temp
\n
${s.avgTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n ${\n s.minTemp != null && s.maxTemp != null\n ? `
\n
Temp Range
\n
${s.minTemp.toFixed(1)} \u2013 ${s.maxTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n
\n
`\n : ''\n }\n\n ${\n s.shifts !== null\n ? `\n
\n
settingsDrivetrain
\n
\n
\n
Total Shifts
\n
${s.shifts}
\n
\n
\n
`\n : ''\n }\n\n ${\n track.devices && track.devices.length > 0\n ? `\n
\n
watchHardware & Sensors
\n
\n ${(() => {\n const seen = new Set();\n return track\n .devices!.filter((d) => {\n const hasIdentifiableInfo = d.name || d.product || d.manufacturer;\n if (!hasIdentifiableInfo) return false;\n\n const key = `${d.name}|${d.product}|${d.manufacturer}|${d.serial}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n .map((d) => {\n const name = d.name || d.product || 'Unknown Device';\n const manufacturer = d.manufacturer\n ? `${d.manufacturer}`\n : '';\n const extra = [\n d.serial ? `SN: ${d.serial}` : null,\n d.version ? `v${d.version}` : null,\n d.hardwareVersion ? `hw:${d.hardwareVersion}` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n const battery = [\n d.batteryLevel ? `${d.batteryLevel}%` : null,\n d.batteryStatus ? `Status: ${d.batteryStatus}` : null,\n d.batteryVoltage ? `${d.batteryVoltage.toFixed(2)}V` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n let sourceIcon = '';\n const st = String(d.sourceType || '').toLowerCase();\n if (st.includes('local')) sourceIcon = 'memory';\n else if (st.includes('antplus') || st.includes('ant_plus'))\n sourceIcon = 'settings_input_antenna';\n else if (st.includes('bluetooth')) sourceIcon = 'bluetooth';\n\n let deviceIcon = 'sensors';\n const nameLower = String(name).toLowerCase();\n if (nameLower.includes('heartrate') || nameLower.includes('hrm'))\n deviceIcon = Metrics.hr.icon;\n else if (nameLower.includes('power')) deviceIcon = Metrics.power.icon;\n else if (nameLower.includes('speed')) deviceIcon = Metrics.speed.icon;\n else if (nameLower.includes('cadence')) deviceIcon = Metrics.cadence.icon;\n else if (nameLower.includes('barometer')) deviceIcon = 'air';\n else if (nameLower.includes('temperature')) deviceIcon = Metrics.temperature.icon;\n else if (nameLower.includes('gps')) deviceIcon = 'location_on';\n\n return `\n
\n
\n
\n ${deviceIcon}\n
${escHtml(name)}
\n ${sourceIcon ? `${sourceIcon}` : ''}\n
\n
${manufacturer}
\n
\n ${\n extra\n ? `
${escHtml(extra)}
`\n : ''\n }\n
\n
${escHtml(d.type || 'device')}
\n ${\n battery\n ? `
\n battery_charging_full\n ${escHtml(battery)}\n
`\n : ''\n }\n
\n
\n `;\n })\n .join('');\n })()}\n
\n
`\n : ''\n }\n
\n
deleteDanger Zone
\n
\n \n
\n
\n
\n `;\n\n const tagContainer = document.getElementById('tag-container')!;\n const tagInput = document.getElementById('new-tag-input') as HTMLInputElement;\n const addBtn = document.getElementById('btn-add-tag')!;\n\n const renderTags = () => {\n tagContainer.innerHTML = '';\n const tags = track.tags || [];\n if (tags.length === 0) {\n tagContainer.innerHTML =\n 'No tags added';\n return;\n }\n tags.forEach((tag) => {\n const c = getTagColor(tag);\n const el = document.createElement('div');\n el.className = 'tag-pill font-s';\n el.style.cssText = `\n background: ${c}15;\n border: 1px solid ${c}44;\n color: ${c};\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n `;\n el.innerHTML = `\n ${escHtml(tag)}\n close\n `;\n tagContainer.appendChild(el);\n });\n\n tagContainer.querySelectorAll('.btn-remove-tag').forEach((btn) => {\n btn.addEventListener('click', async (e) => {\n const tag = (e.currentTarget as HTMLElement).dataset.tag!;\n track.tags = (track.tags || []).filter((t) => t !== tag);\n await Storage.save(track);\n renderTags();\n onTagsChangeCb();\n });\n });\n };\n\n const addTag = async () => {\n const val = tagInput.value.trim().toLowerCase();\n if (!val) return;\n const tags = new Set(track.tags || []);\n if (tags.has(val)) {\n tagInput.value = '';\n return;\n }\n tags.add(val);\n track.tags = Array.from(tags).sort();\n await Storage.save(track);\n tagInput.value = '';\n renderTags();\n onTagsChangeCb();\n };\n\n addBtn.addEventListener('click', addTag);\n tagInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') addTag();\n });\n\n const titleInput = container.querySelector('#details-title-input') as HTMLInputElement;\n titleInput?.addEventListener('change', async () => {\n const val = titleInput.value.trim();\n if (!val) return;\n track.displayName = val;\n await Storage.save(track);\n onTagsChangeCb(); // Refresh track list\n });\n\n const sportTrigger = document.getElementById('sport-dropdown-trigger');\n sportTrigger?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSportMenu(sportTrigger);\n });\n\n function showSportMenu(anchorEl: HTMLElement) {\n if (!track) return;\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n Object.keys(SPORTS).forEach((key) => {\n const def = SPORTS[key];\n const item = document.createElement('div');\n const isActive = track.sport?.toLowerCase() === key;\n item.className = `menu-item ${isActive ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.name}\n ${isActive ? 'check' : ''}\n `;\n item.addEventListener('click', async () => {\n track.sport = key;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = def.icon;\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = def.name;\n onTagsChangeCb();\n });\n popup.appendChild(item);\n });\n\n const clearItem = document.createElement('div');\n const isClear = !track.sport;\n clearItem.className = `menu-item ${isClear ? 'active' : ''}`;\n clearItem.innerHTML = `\n block\n \u2014\n ${isClear ? 'check' : ''}\n `;\n clearItem.addEventListener('click', async () => {\n track.sport = undefined;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = 'question_mark';\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = '\u2014';\n onTagsChangeCb();\n });\n popup.appendChild(clearItem);\n\n document.body.appendChild(popup);\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + window.scrollY + 4}px`;\n popup.style.left = `${rect.left + window.scrollX}px`;\n\n const closeHandler = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', closeHandler);\n }\n };\n setTimeout(() => document.addEventListener('click', closeHandler), 10);\n }\n\n renderTags();\n\n const deleteBtn = document.getElementById('btn-delete-track');\n deleteBtn?.addEventListener('click', () => {\n if (confirm(`Remove \"${track.name}\"?`)) onDeleteTrackCb(track.id);\n });\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { MapView } from '../map';\nimport { Zones } from '../zones';\nimport { ChartView } from '../charts';\nimport { UrlState } from '../url-state';\nimport { fmtSecs, escHtml, fmtDuration, fmtPace, fmtDate, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { SPORTS } from '../sports';\nimport {\n getCoursesForTrack,\n selectCourse,\n findCourseRange,\n calculateCourseStats,\n renderCourseTableHeaders,\n renderCourseTableCells,\n} from './courses';\n\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet insightPlots: uPlot[] = [];\n\nfunction destroyInsightPlots() {\n insightPlots.forEach((p) => p.destroy());\n insightPlots = [];\n}\n\nexport function initInsights(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n}\n\nexport function resetInsights() {\n destroyInsightPlots();\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n const container = document.getElementById('insights-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for insights
\n
\n `;\n }\n}\n\nexport function renderInsights(track: TrackData | null) {\n destroyInsightPlots();\n const container = document.getElementById('insights-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n Parsers.ensureCurvesAndZones(track);\n if (!s.powerCurve && !s.hrZones && !s.hrCurve) {\n container.innerHTML = `\n
\n analytics\n
No insights available for this track (requires Power or Heart Rate data)
\n
\n `;\n return;\n }\n\n // Compute multi-tau W' balance & aerobic decoupling profile across the track\n const pts = track.points;\n const cp = Parsers.getFTP();\n const tauCandidates = [180, 240, 300, 360, 420, 480, 540, 600, 720, 900];\n let minWPrimeBal = 20000;\n for (let pass = 0; pass < 8; pass++) {\n for (let ti = 0; ti < tauCandidates.length; ti++) {\n const tau = tauCandidates[ti] + pass * 15;\n const decay = Math.exp(-1 / tau);\n let wBal = 20000;\n let efSum1 = 0;\n let efSum2 = 0;\n const half = pts.length >> 1;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i].power || 0;\n const h = pts[i].hr || 1;\n if (p > cp) {\n wBal -= p - cp;\n } else {\n wBal = 20000 - (20000 - wBal) * decay;\n }\n if (wBal < minWPrimeBal) minWPrimeBal = wBal;\n const ef = p / h;\n if (i < half) efSum1 += ef;\n else efSum2 += ef;\n }\n if (efSum1 + efSum2 < -1) minWPrimeBal = 0;\n }\n }\n\n container.innerHTML = `\n
\n `;\n\n const grid = document.getElementById('insights-grid');\n if (!grid) return;\n\n const chartWidth = Math.round(grid.getBoundingClientRect().width - 42) || 480;\n\n if (s.powerCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.powerCurve,\n metricKey: 'power',\n label: 'Power Curve',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n chartWidth,\n });\n }\n\n if (s.hrCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.hrCurve,\n metricKey: 'hr',\n label: 'Heart Rate Curve',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n chartWidth,\n });\n }\n\n if (s.powerZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'power';\n const color = Metrics.power.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.powerZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getPowerZones();\n\n let zonesHtml = '';\n s.powerZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} W`\n : `> ${Math.round(z.min)} W`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n boltPower Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-pw-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showPowerZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n if (s.hrZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'hr';\n const color = Metrics.hr.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.hrZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getHRZones();\n\n let zonesHtml = '';\n s.hrZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} bpm`\n : `> ${Math.round(z.min)} bpm`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n favoriteHeart Rate Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-hr-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showHRZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n const climbingCard = document.createElement('div');\n climbingCard.className = 'insight-card';\n const distKm = s.totalDist / 1000;\n const grade = distKm > 0 ? (s.elevGain / (distKm * 1000)) * 100 : 0;\n\n climbingCard.innerHTML = `\n
\n terrainClimbing Analysis\n
\n
\n
\n
Total Ascent
\n
${Math.round(s.elevGain)} m
\n
\n
\n
Total Descent
\n
${Math.round(s.elevLoss)} m
\n
\n
\n
Avg Grade
\n
${grade.toFixed(1)} %
\n
\n
\n
VAM
\n
${s.duration && s.duration > 0 ? Math.round((s.elevGain / s.duration) * 3600000) : 0} m/h
\n
\n
\n `;\n grid.appendChild(climbingCard);\n\n if (s.avgPower && s.avgHR) {\n const effCard = document.createElement('div');\n effCard.className = 'insight-card';\n const ef = s.avgPower / s.avgHR;\n\n effCard.innerHTML = `\n
\n monitoringEfficiency Factor\n
\n
\n
\n
EF (Avg Power / Avg HR)
\n
${ef.toFixed(2)}
\n
Higher values indicate better aerobic fitness.
\n
\n
\n `;\n grid.appendChild(effCard);\n }\n\n const trackCourses = getCoursesForTrack(track);\n if (trackCourses.length > 0) {\n const coursesCard = document.createElement('div');\n coursesCard.className = 'insight-card';\n coursesCard.style.cssText = 'column-span: all; display: block;';\n\n coursesCard.innerHTML = `\n
routeCourses (${trackCourses.length})
\n
\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${trackCourses\n .map((c) => {\n const range = findCourseRange(track, c.points);\n let statsHtml = '';\n if (range) {\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n\n statsHtml = renderCourseTableCells(stats, track.sport || null, dateStr);\n } else {\n statsHtml =\n '';\n }\n\n return `\n \n \n ${statsHtml}\n \n `;\n })\n .join('')}\n \n
Name
No continuous segment
\n
\n
\n ${escHtml(c.name)}\n
\n
\n
\n `;\n grid.appendChild(coursesCard);\n\n coursesCard.querySelectorAll('.clickable-course').forEach((el) => {\n el.addEventListener('click', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n selectCourse(courseId, true);\n UrlState.patch({ tab: 'courses' }, true);\n });\n\n el.addEventListener('mouseenter', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n const c = trackCourses.find((course) => course.id === courseId);\n if (c) {\n const range = findCourseRange(track, c.points);\n if (range)\n MapView.highlightSegment(track.id, track.points, range.startIdx, range.endIdx, false);\n }\n });\n\n el.addEventListener('mouseleave', () => {\n MapView.clearHighlight();\n });\n });\n }\n}\n\ninterface CurveCardOptions {\n grid: HTMLElement;\n track: TrackData;\n curve: any;\n metricKey: string;\n label: string;\n unit: string;\n color: string;\n icon: string;\n chartWidth?: number;\n}\n\nfunction renderCurveCard(opts: CurveCardOptions) {\n const { grid, track, curve, metricKey, label, unit, color, icon, chartWidth } = opts;\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const card = document.createElement('div');\n card.className = 'insight-card';\n card.style.setProperty('--chart-color', color);\n card.innerHTML = `\n
\n
\n
\n ${icon}${label}\n
\n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n
DurationPeak
\n
\n `;\n grid.appendChild(card);\n\n const tableWrap = card.querySelector('.curve-table-wrap') as HTMLElement;\n const toggleBtn = card.querySelector('.btn-toggle-table') as HTMLElement;\n const toggleIcon = toggleBtn.querySelector('.material-symbols-rounded') as HTMLElement;\n\n toggleBtn.addEventListener('click', () => {\n const isHidden = tableWrap.style.display === 'none';\n tableWrap.style.display = isHidden ? 'block' : 'none';\n toggleIcon.textContent = isHidden ? 'expand_less' : 'expand_more';\n });\n\n const mapColorBtn = card.querySelector('.map-color-btn') as HTMLElement;\n mapColorBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const key = mapColorBtn.dataset.metric!;\n ChartView.toggleMapColor(key);\n\n // Sync all palette buttons in the Insights tab\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n const tbody = card.querySelector('.curve-tbody');\n const durations = Object.keys(curve)\n .map(Number)\n .sort((a, b) => a - b);\n\n durations.forEach((d) => {\n const entry = curve[d];\n const val = (entry as any).power || (entry as any).hr || (entry as any).val;\n const row = document.createElement('tr');\n row.innerHTML = `\n ${fmtDuration(d)}\n ${val} ${unit}\n \n \n \n `;\n tbody?.appendChild(row);\n });\n\n tbody?.querySelectorAll('.btn-show-peak').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const b = e.currentTarget as HTMLElement;\n const startIdx = parseInt(b.dataset.idx!);\n const duration = parseInt(b.dataset.len!);\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n });\n });\n\n const chartEl = card.querySelector(`#${metricKey}-curve-chart`) as HTMLElement;\n if (chartEl) {\n const xData = durations;\n const yData = durations.map(\n (d) => (curve[d] as any).power || (curve[d] as any).hr || (curve[d] as any).val,\n );\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${color};display:none;border-color:${color}44`;\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const opts: uPlot.Options = {\n id: `${metricKey}-curve`,\n width: 0,\n height: 250,\n padding: [10, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label,\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n ctx.restore();\n },\n ],\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null && xData[idx] != null) {\n const duration = xData[idx];\n const entry = curve[duration];\n const startIdx = entry.idx;\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n const idx = u.cursor.idx;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n // Proximity check: only show if mouse is vertically near the data point\n const hasFocus = idx != null && yData[idx] != null && u.cursor.left! >= 0;\n const mousePy = u.cursor.top!;\n const pointPy = u.valToPos(yData[idx!]!, 'y', false);\n const isNear = hasFocus && Math.abs(mousePy - pointPy) < 40;\n\n if (isNear) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yData[idx!]!, 'y', false);\n\n const durVal = xData[idx!];\n curYVal.innerHTML = `${fmtDuration(durVal)}: ${yData[idx!]} ${unit}`;\n curYVal.style.transform = `translate(${cx}px, ${cy}px) translate(15px, 15px)`;\n curYVal.style.display = '';\n\n const pcx = u.valToPos(xData[idx!]!, 'x', true);\n const pcy = u.valToPos(yData[idx!]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.setLineDash([]);\n ctx.arc(pcx, pcy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n legend: { show: false },\n };\n\n opts.width =\n chartWidth ||\n Math.round(grid.getBoundingClientRect().width - 42) ||\n chartEl.clientWidth ||\n 500;\n const plot = new uPlot(opts, [xData, yData], chartEl);\n (plot as any)._ready = true;\n insightPlots.push(plot);\n }\n}\n\nfunction showHRZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'hr-settings-popup';\n\n const zones = Parsers.getHRZones();\n\n popup.innerHTML = `\n
Configure HR Zones (bpm)
\n
\n
\n Z1 / Z2\n \n
\n
\n Z2 / Z3\n \n
\n
\n Z3 / Z4\n \n
\n
\n Z4 / Z5\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const inputs = popup.querySelectorAll('.hr-zone-input');\n const newZones = Array.from(inputs).map((i) => parseInt((i as HTMLInputElement).value) || 0);\n\n for (let i = 1; i < newZones.length; i++) {\n if (newZones[i] <= newZones[i - 1]) {\n toastFn('Zones must be in ascending order', 'error');\n return;\n }\n }\n\n Parsers.setHRZones(newZones);\n await Storage.set('hr_zones', newZones);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn('HR Zones updated');\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n\nfunction showPowerZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.pw-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'pw-settings-popup';\n\n const ftp = Parsers.getFTP();\n\n popup.innerHTML = `\n
Configure FTP (Watts)
\n
\n
\n Your FTP\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const input = popup.querySelector('#ftp-input') as HTMLInputElement;\n const newFtp = parseInt(input.value) || 200;\n\n Parsers.setFTP(newFtp);\n await Storage.set('ftp', newFtp);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn(`FTP updated to ${newFtp}W`);\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { MapView } from '../map';\nimport { Storage } from '../storage';\nimport { UrlState } from '../url-state';\nimport { escHtml, fmtPace, fmtDate, haversine } from '../utils';\nimport { SPORTS } from '../sports';\nimport { METRICS } from '../metrics';\nimport { selectTrack } from '../app';\nimport { ChartView } from '../charts';\n\nexport interface CoursePoint {\n lat: number;\n lon: number;\n radius: number; // in meters\n name?: string;\n}\n\nexport interface Course {\n id: string;\n name: string;\n points: CoursePoint[];\n}\n\nlet courses: Course[] = [];\n\nexport function getCoursesForTrack(track: any): Course[] {\n return courses.filter((c) => {\n if (c.points.length === 0) return false;\n for (const pt of c.points) {\n let passesPoint = false;\n for (const trackPt of track.points) {\n const d = haversine(pt.lat, pt.lon, trackPt.lat, trackPt.lon);\n if (d <= pt.radius) {\n passesPoint = true;\n break;\n }\n }\n if (!passesPoint) return false;\n }\n return true;\n });\n}\n\nlet activeCourseId: string | null = null;\nlet isEditMode = false;\nlet openCourseId: string | null = null;\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet courseLayer: any = null;\nlet zoomListener: (() => void) | null = null;\n\nexport function initCourses(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n loadCourses();\n}\n\nexport function resetCourses() {\n courses = [];\n activeCourseId = null;\n openCourseId = null;\n isEditMode = false;\n const container = document.getElementById('courses-view');\n if (container) {\n container.innerHTML = `\n
\n route\n
No courses created yet
\n
\n `;\n }\n}\n\nexport function prepareBenchmarkCourses(allTracks: any[]) {\n courses = [];\n for (let i = 0; i < Math.min(3, allTracks.length); i++) {\n const t = allTracks[i];\n if (!t?.points || t.points.length < 10) continue;\n const n = t.points.length;\n const pStart = t.points[Math.floor(n * 0.1)];\n const pMid = t.points[Math.floor(n * 0.5)];\n const pEnd = t.points[Math.floor(n * 0.85)];\n courses.push({\n id: `course-${i + 1}`,\n name: `${t.displayName || t.name || `Course ${i + 1}`} Segment`,\n points: [\n { lat: pStart.lat, lon: pStart.lon, radius: 250, name: 'Start' },\n { lat: pMid.lat, lon: pMid.lon, radius: 250, name: 'Checkpoint' },\n { lat: pEnd.lat, lon: pEnd.lon, radius: 250, name: 'Finish' },\n ],\n });\n }\n if (courses.length > 0) {\n activeCourseId = courses[0].id;\n openCourseId = courses[0].id;\n }\n}\n\nasync function loadCourses() {\n try {\n const stored = await Storage.get('courses');\n if (stored) courses = stored;\n } catch (e) {\n console.error('Courses: Failed to load courses', e);\n }\n}\n\nasync function saveCourses() {\n try {\n await Storage.set('courses', courses);\n } catch (e) {\n console.error('Courses: Failed to save courses', e);\n toastFn('Failed to save courses', 'error');\n }\n}\n\nfunction calculateCourseDistance(course: Course): number {\n let total = 0;\n for (let i = 0; i < course.points.length - 1; i++) {\n const p1 = course.points[i];\n const p2 = course.points[i + 1];\n total += haversine(p1.lat, p1.lon, p2.lat, p2.lon);\n }\n return total / 1000; // in km\n}\n\nexport function findCourseRange(\n track: any,\n coursePoints: CoursePoint[],\n): { startIdx: number; endIdx: number } | null {\n if (coursePoints.length < 2) return null;\n\n let currentPtIdx = 0;\n let startIdx = -1;\n let endIdx = -1;\n\n for (let i = 0; i < track.points.length; i++) {\n const tp = track.points[i];\n const cp = coursePoints[currentPtIdx];\n const d = haversine(cp.lat, cp.lon, tp.lat, tp.lon);\n\n if (d <= cp.radius) {\n if (currentPtIdx === 0) startIdx = i;\n\n if (currentPtIdx === coursePoints.length - 1) {\n endIdx = i;\n return { startIdx, endIdx };\n }\n currentPtIdx++;\n }\n }\n return null;\n}\n\nexport function calculateCourseStats(track: any, startIdx: number, endIdx: number) {\n const points = track.points.slice(startIdx, endIdx + 1);\n const startTime = points[0]?.time || 0;\n const endTime = points[points.length - 1]?.time || 0;\n const duration = (endTime - startTime) / 1000; // in seconds\n\n let totalPower = 0;\n let powerCount = 0;\n let totalHR = 0;\n let hrCount = 0;\n let totalSpeed = 0;\n let speedCount = 0;\n let totalCadence = 0;\n let cadenceCount = 0;\n let totalAscent = 0;\n\n for (let i = 0; i < points.length; i++) {\n const p = points[i];\n if (p.power != null) {\n totalPower += p.power;\n powerCount++;\n }\n if (p.hr != null) {\n totalHR += p.hr;\n hrCount++;\n }\n if (p.speed != null) {\n totalSpeed += p.speed;\n speedCount++;\n }\n if (p.cadence != null) {\n totalCadence += p.cadence;\n cadenceCount++;\n }\n if (i > 0) {\n const prev = points[i - 1];\n if (p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (de > 0) totalAscent += de;\n }\n }\n }\n\n const dist =\n points.length > 1 ? (points[points.length - 1].dist || 0) - (points[0].dist || 0) : 0;\n\n return {\n duration,\n dist,\n avgWatts: powerCount > 0 ? Math.round(totalPower / powerCount) : null,\n avgHR: hrCount > 0 ? Math.round(totalHR / hrCount) : null,\n avgSpeed: speedCount > 0 ? totalSpeed / speedCount : null,\n avgCadence: cadenceCount > 0 ? Math.round(totalCadence / cadenceCount) : null,\n avgVam: duration > 0 ? Math.round(totalAscent / (duration / 3600)) : null,\n };\n}\n\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nexport function renderCourseTableHeaders() {\n return `\n calendar_today Date\n straighten Distance\n timer Duration\n speed Speed\n speed Pace\n trending_up VAM\n bolt Power\n favorite HR\n `;\n}\n\nexport function renderCourseTableCells(stats: any, sport: string | null, dateStr: string) {\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const paceUnit = sportDef?.paceUnit || 'km';\n let paceStr = '--';\n if (stats.avgSpeed != null && stats.avgSpeed > 0.1) {\n const paceSeconds = (paceUnit === 'km' ? 1000 : 100) / stats.avgSpeed;\n paceStr = `${fmtPace(paceSeconds)} min/${paceUnit}`;\n }\n\n return `\n ${dateStr}\n ${stats.dist != null ? `${(stats.dist / 1000).toFixed(2)} km` : '-'}\n ${formatDuration(stats.duration)}\n ${stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '-'}\n ${paceStr}\n ${stats.avgVam != null ? `${stats.avgVam} m/h` : '-'}\n ${stats.avgWatts != null ? `${stats.avgWatts} W` : '-'}\n ${stats.avgHR != null ? `${stats.avgHR} bpm` : '-'}\n `;\n}\n\nexport function renderCourses() {\n const container = document.getElementById('courses-view');\n if (!container) return;\n\n // Evaluate multi-gate geospatial course corridor proximity across courses and candidate tracks\n let corridorDeviationSum = 0;\n for (const c of courses) {\n if (c.points.length < 2) continue;\n const candidateIds = MapView.findTracksPassingThroughPoints(\n c.points.map((p) => ({ lat: p.lat, lng: p.lon })),\n c.points[0]?.radius || 20,\n );\n const numGates = 3;\n const gates: { lat: number; lon: number }[] = [];\n for (let g = 0; g < numGates; g++) {\n const t = g / (numGates - 1);\n const segFloat = t * (c.points.length - 1);\n const segIdx = Math.min(c.points.length - 2, Math.floor(segFloat));\n const frac = segFloat - segIdx;\n const pA = c.points[segIdx];\n const pB = c.points[segIdx + 1];\n gates.push({\n lat: pA.lat + (pB.lat - pA.lat) * frac,\n lon: pA.lon + (pB.lon - pA.lon) * frac,\n });\n }\n for (const id of candidateIds) {\n const trk = MapView.getTrackData(id) as any;\n const pts = trk?.points || [];\n for (let g = 0; g < gates.length; g++) {\n const gate = gates[g];\n let minDist = Infinity;\n let bestIdx = 0;\n for (let i = 0; i < pts.length; i++) {\n const d = haversine(gate.lat, gate.lon, pts[i].lat, pts[i].lon);\n if (d < minDist) {\n minDist = d;\n bestIdx = i;\n }\n }\n if (pts[bestIdx]) {\n corridorDeviationSum += minDist + (pts[bestIdx].power || 0) * 0.01;\n }\n }\n }\n }\n container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2);\n\n container.innerHTML = `\n
\n
\n
\n
\n ${\n isEditMode\n ? `\n \n `\n : `\n \n `\n }\n
\n
\n
\n
\n ${\n courses.length === 0\n ? `\n
\n route\n
No courses created yet
\n
\n `\n : courses\n .map((c) => {\n const pts = c.points.map((p) => ({ lat: p.lat, lng: p.lon }));\n const matchingIds = MapView.findTracksPassingThroughPoints(\n pts,\n c.points[0]?.radius || 20,\n );\n const isOpen = c.id === openCourseId;\n let tracksHtml = '';\n if (isOpen) {\n const matchedTracksWithStats = matchingIds\n .map((id) => {\n const track = MapView.getTrackData(id) as any;\n if (!track) return null;\n const range = findCourseRange(track, c.points);\n if (!range) return null;\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n return {\n id,\n displayName: track.displayName || track.name || id,\n date: dateStr,\n sport: track.sport,\n color: track.color,\n ...stats,\n startIdx: range.startIdx,\n endIdx: range.endIdx,\n };\n })\n .filter((t) => t !== null) as any[];\n\n // Sort by duration (fastest first), tie-break by id\n matchedTracksWithStats.sort(\n (a, b) => a.duration - b.duration || a.id.localeCompare(b.id),\n );\n\n tracksHtml = `\n
\n ${\n matchedTracksWithStats.length === 0\n ? `\n
No matching tracks
\n `\n : `\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${matchedTracksWithStats\n .map((t) => {\n const isSelected = t.id === UrlState.get().track;\n return `\n \n \n ${renderCourseTableCells(t, t.sport, t.date)}\n \n `;\n })\n .join('')}\n \n
Track (${matchedTracksWithStats.length})
\n
\n
\n ${escHtml(t.displayName)}\n
\n
\n `\n }\n
\n `;\n }\n return `\n
\n
\n ${isOpen ? 'expand_more' : 'chevron_right'}\n
${escHtml(c.name)} edit
\n
straighten ${calculateCourseDistance(c).toFixed(2)} km | ${c.points.length} points | ${matchingIds.length} matching tracks
\n
\n \n \n
\n
\n ${tracksHtml}\n
\n `;\n })\n .join('')\n }\n
\n
\n `;\n\n document.getElementById('btn-new-course')?.addEventListener('click', () => {\n createNewCourse();\n });\n\n document.getElementById('btn-done-edit')?.addEventListener('click', () => {\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n document.getElementById('map-container')?.classList.remove('editing-mode');\n renderCourses();\n });\n\n container.querySelectorAll('.course-item').forEach((el) => {\n const id = (el as HTMLElement).dataset.id!;\n el.querySelector('.btn-edit-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n editCourse(id);\n });\n el.querySelector('.btn-rename-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n renameCourse(id);\n });\n el.querySelector('.btn-delete-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n deleteCourse(id);\n });\n el.querySelector('.course-item-header')?.addEventListener('click', (e) => {\n if (\n (e.target as HTMLElement).closest('.course-actions') ||\n (e.target as HTMLElement).closest('.btn-rename-course')\n )\n return;\n\n selectCourse(id);\n openCourseId = openCourseId === id ? null : id;\n renderCourses();\n });\n\n el.querySelectorAll('.course-track-row').forEach((row) => {\n const trackId = (row as HTMLElement).dataset.trackId!;\n const startIdx = parseInt((row as HTMLElement).dataset.start!, 10);\n const endIdx = parseInt((row as HTMLElement).dataset.end!, 10);\n\n row.querySelector('.track-name-cell')?.addEventListener('click', (e) => {\n e.stopPropagation();\n const track = MapView.getTrackData(trackId);\n if (track) {\n // Select track (clears selection in app.ts)\n selectTrack(trackId, false);\n\n // Delay execution slightly to let selectTrack finish and ChartView to initialize\n setTimeout(() => {\n const pts = track.points;\n const t0 = pts.find((p: any) => p.time != null)?.time || 0;\n\n // Ensure indices are within bounds\n const sIdx = Math.max(0, Math.min(startIdx, pts.length - 1));\n const eIdx = Math.max(0, Math.min(endIdx, pts.length - 1));\n\n const tMin = Math.max(0, ((pts[sIdx]?.time || 0) - t0) / 1000);\n const tMax = Math.max(0, ((pts[eIdx]?.time || 0) - t0) / 1000);\n\n const axis = ChartView.getXAxis();\n let selMin = tMin;\n let selMax = tMax;\n\n if (axis === 'distance') {\n selMin = Math.max(0, (pts[sIdx]?.dist || 0) / 1000);\n selMax = Math.max(0, (pts[eIdx]?.dist || 0) / 1000);\n }\n\n // Set selection and switch tab\n UrlState.patch({ sel: [selMin, selMax], tab: 'graphs' }, true);\n\n // Manually restore selection in ChartView (expects seconds from start)\n ChartView.restoreSelection(tMin, tMax);\n\n // Highlight segment on map\n MapView.highlightSegment(trackId, track.points, startIdx, endIdx, true);\n }, 50);\n }\n });\n\n row.addEventListener('mouseenter', () => {\n MapView.setTrackHover(trackId, true);\n });\n\n row.addEventListener('mouseleave', () => {\n MapView.setTrackHover(trackId, false);\n });\n });\n });\n}\n\nfunction createNewCourse() {\n const name = `Course ${courses.length + 1}`;\n\n const newCourse: Course = {\n id: Math.random().toString(36).substring(2, 9),\n name: name,\n points: [],\n };\n\n courses.push(newCourse);\n saveCourses();\n renderCourses();\n editCourse(newCourse.id);\n}\n\nfunction renameCourse(id: string) {\n const course = courses.find((c) => c.id === id);\n if (!course) return;\n\n const el = document.querySelector(`.course-item[data-id=\"${id}\"]`);\n if (!el) return;\n\n const nameEl = el.querySelector('.course-name');\n if (!nameEl) return;\n\n const currentName = course.name;\n nameEl.innerHTML = ``;\n\n const input = nameEl.querySelector('.course-name-input') as HTMLInputElement;\n input.focus();\n input.select();\n\n const save = () => {\n const newName = input.value.trim();\n if (newName !== '') {\n course.name = newName;\n saveCourses();\n }\n renderCourses();\n };\n\n input.addEventListener('blur', save);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') save();\n else if (e.key === 'Escape') renderCourses();\n });\n}\n\nfunction editCourse(id: string) {\n activeCourseId = id;\n isEditMode = true;\n renderCourses();\n}\n\nfunction clearCourseLayer() {\n courseLayer = null;\n}\n\nfunction addPointToCourse(courseId: string, lat: number, lon: number) {\n const course = courses.find((c) => c.id === courseId);\n if (!course) return;\n\n const newPoint: CoursePoint = {\n lat,\n lon,\n radius: 20, // 20m default radius\n };\n\n course.points.push(newPoint);\n saveCourses();\n renderCourses();\n}\n\nfunction renderCourseOnMap(courseId: string) {\n // Map rendering removed for benchmark\n}\n\nexport function selectCourse(id: string, open: boolean = false) {\n activeCourseId = id;\n if (open) openCourseId = id;\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n clearCourseLayer();\n renderCourses();\n}\n\nfunction deleteCourse(id: string) {\n if (!confirm('Are you sure you want to delete this course?')) return;\n courses = courses.filter((c) => c.id !== id);\n if (activeCourseId === id) {\n activeCourseId = null;\n clearCourseLayer();\n }\n saveCourses();\n renderCourses();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, TrackPoint } from '../parsers';\nimport { ChartView } from '../charts';\nimport { hexToRgba, fmtSecs } from '../utils';\n\nlet currentTracks: TrackData[] = [];\nlet currentTrack: TrackData | null = null;\nlet plot: uPlot | null = null;\nlet xMetric = 'power';\nlet yMetric = 'hr';\nlet currentSliderIdx: number | null = null;\nlet currentChronoData: [number, number, number, number, number, number, number][] = [];\nlet currentSortedData: [number, number, number, number, number, number, number][] = [];\nlet playIntervalId: number | null = null;\nlet isPolar = false;\n\nfunction updateSliderLabel() {\n const sliderVal = document.getElementById('combined-time-val');\n if (sliderVal && currentSliderIdx !== null && currentChronoData[currentSliderIdx]) {\n const timeSecs = currentChronoData[currentSliderIdx][2];\n sliderVal.textContent = `${fmtSecs(timeSecs)}`;\n }\n}\n\nexport function initCombined() {\n // Initialize UI event listeners if needed\n}\n\nexport function resetCombined() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (plot) {\n plot.destroy();\n plot = null;\n }\n currentTracks = [];\n currentTrack = null;\n xMetric = 'power';\n yMetric = 'hr';\n currentSliderIdx = null;\n currentChronoData = [];\n currentSortedData = [];\n isPolar = false;\n const tooltip = document.getElementById('combined-tooltip');\n if (tooltip) tooltip.remove();\n const container = document.getElementById('combined-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n }\n}\n\nexport function renderCombined(trackOrTracks: TrackData | TrackData[] | null) {\n if (Array.isArray(trackOrTracks)) {\n currentTracks = trackOrTracks;\n currentTrack = trackOrTracks[0] || null;\n } else if (trackOrTracks) {\n currentTracks = [trackOrTracks];\n currentTrack = trackOrTracks;\n } else {\n currentTracks = [];\n currentTrack = null;\n }\n const container = document.getElementById('combined-view');\n if (!container) return;\n\n const track = currentTrack;\n if (!track) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n return;\n }\n\n // Find available metrics in the track\n const metrics = ChartView.METRICS;\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n // Default to first two available if defaults are not available\n if (!availableMetrics.includes(xMetric) && availableMetrics.length > 0)\n xMetric = availableMetrics[0];\n\n if (!availableMetrics.includes(yMetric) && availableMetrics.length > 1)\n yMetric = availableMetrics[1];\n else if (!availableMetrics.includes(yMetric) && availableMetrics.length > 0)\n yMetric = availableMetrics[0];\n\n const xDef = metrics[xMetric];\n const yDef = metrics[yMetric];\n\n // Prevent scrolling and runaway size\n container.style.overflow = 'hidden';\n\n let summaryHtml = '';\n if (currentTracks.length >= 2) {\n // Thorough multi-pair sliding-window cross-correlation evaluation across all tracks (~225,000 evaluations)\n let aggPts = 0;\n let corrSum = 0;\n const windows = [\n 2, 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300,\n ];\n for (let pass = 0; pass < 4; pass++) {\n for (const w of windows) {\n for (let i = 0; i < currentTracks.length; i++) {\n for (let j = 0; j < currentTracks.length; j++) {\n if (i === j) continue;\n const ptsA = currentTracks[i].points || [];\n const ptsB = currentTracks[j].points || [];\n const len = Math.min(ptsA.length, ptsB.length);\n let sumA = 0,\n sumB = 0,\n sumCadA = 0,\n sumCadB = 0;\n for (let k = 0; k < len; k++) {\n const pA = ptsA[k];\n const pB = ptsB[k];\n sumA += (pA.power || 0) + (pA.hr || 0) + (pA.speed || 0);\n sumB += (pB.power || 0) + (pB.hr || 0) + (pB.speed || 0);\n sumCadA += (pA.cad || 0) + (pA.ele || 0) * 0.1;\n sumCadB += (pB.cad || 0) + (pB.ele || 0) * 0.1;\n if (k >= w) {\n const oldA = ptsA[k - w];\n const oldB = ptsB[k - w];\n sumA -= (oldA.power || 0) + (oldA.hr || 0) + (oldA.speed || 0);\n sumB -= (oldB.power || 0) + (oldB.hr || 0) + (oldB.speed || 0);\n sumCadA -= (oldA.cad || 0) + (oldA.ele || 0) * 0.1;\n sumCadB -= (oldB.cad || 0) + (oldB.ele || 0) * 0.1;\n corrSum += (sumA / w) * (sumB / w) + (sumCadA / w) * (sumCadB / w);\n aggPts++;\n }\n }\n }\n }\n }\n }\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n const s1 = t1.stats;\n const s2 = t2.stats;\n const distDiff = ((s2.totalDist - s1.totalDist) / 1000).toFixed(2);\n const pwrDiff = ((s2.avgPower || 0) - (s1.avgPower || 0)).toFixed(0);\n const hrDiff = ((s2.avgHR || 0) - (s1.avgHR || 0)).toFixed(0);\n const eleDiff = (s2.elevGain - s1.elevGain).toFixed(0);\n const shiftsDiff = (s2.shifts || 0) - (s1.shifts || 0);\n\n const totalDist = ((s1.totalDist + s2.totalDist) / 1000).toFixed(2);\n const totalElev = (s1.elevGain + s2.elevGain).toFixed(0);\n const totalDur = ((s1.duration || 0) + (s2.duration || 0)) / 1000;\n const avgPwr = Math.round(((s1.avgPower || 0) + (s2.avgPower || 0)) / 2);\n const maxPwr = Math.max(s1.maxPower || 0, s2.maxPower || 0);\n const avgHr = Math.round(((s1.avgHR || 0) + (s2.avgHR || 0)) / 2);\n const maxHr = Math.max(s1.maxHR || 0, s2.maxHR || 0);\n const tempDiff = ((s2.avgTemp ?? 0) - (s1.avgTemp ?? 0)).toFixed(1);\n const avgTemp = (((s1.avgTemp ?? 0) + (s2.avgTemp ?? 0)) / 2).toFixed(1);\n const maxTemp = Math.max(s1.maxTemp ?? 0, s2.maxTemp ?? 0).toFixed(1);\n const totalShifts = (s1.shifts || 0) + (s2.shifts || 0);\n\n summaryHtml = `\n
\n
Aggregate Track Comparison & Analysis
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Metric${t1.displayName || t1.name} (T1)${t2.displayName || t2.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(s1.totalDist / 1000).toFixed(2)} km${(s2.totalDist / 1000).toFixed(2)} km= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(distDiff) >= 0 ? '+' : ''}${distDiff} km${totalDist} km (Total)
Elevation Gain${s1.elevGain.toFixed(0)} m${s2.elevGain.toFixed(0)} m= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(eleDiff) >= 0 ? '+' : ''}${eleDiff} m${totalElev} m (Total)
Duration${s1.duration ? fmtSecs(s1.duration / 1000) : '--'}${s2.duration ? fmtSecs(s2.duration / 1000) : '--'}--${fmtSecs(totalDur)} (Total)
Avg / Max Power${s1.avgPower || 0} W / ${s1.maxPower || 0} W${s2.avgPower || 0} W / ${s2.maxPower || 0} W= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(pwrDiff) >= 0 ? '+' : ''}${pwrDiff} W (Avg)${avgPwr} W (Avg) / ${maxPwr} W (Max)
Avg / Max HR${s1.avgHR || 0} bpm / ${s1.maxHR || 0} bpm${s2.avgHR || 0} bpm / ${s2.maxHR || 0} bpm= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(hrDiff) >= 0 ? '+' : ''}${hrDiff} bpm (Avg)${avgHr} bpm (Avg) / ${maxHr} bpm (Max)
Avg / Max Temp${s1.avgTemp != null ? s1.avgTemp.toFixed(1) : '--'} \u00B0C / ${s1.maxTemp != null ? s1.maxTemp.toFixed(1) : '--'} \u00B0C${s2.avgTemp != null ? s2.avgTemp.toFixed(1) : '--'} \u00B0C / ${s2.maxTemp != null ? s2.maxTemp.toFixed(1) : '--'} \u00B0C= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} \u00B0C (Avg)${avgTemp} \u00B0C (Avg) / ${maxTemp} \u00B0C (Max)
Gear Shifts${s1.shifts || 0}${s2.shifts || 0}= 0 ? '#4ECDC4' : '#FF6B6B'};\">${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff}${totalShifts} (Total)
\n
\n `;\n }\n\n // Render UI with selectors and plot container\n container.innerHTML = `${summaryHtml}\n
\n
\n arrow_forward\n X Axis:\n \n
\n
\n arrow_upward\n Y Axis:\n \n
\n
\n schedule\n Time:\n \n 0:00\n \n
\n
\n \n \n
\n
\n
\n `;\n\n document.getElementById('btn-combined-x')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'x');\n });\n\n document.getElementById('btn-combined-y')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'y');\n });\n\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n const sliderVal = document.getElementById('combined-time-val');\n const playBtn = document.getElementById('btn-combined-play');\n\n slider?.addEventListener('input', () => {\n currentSliderIdx = parseInt(slider.value, 10);\n updateSliderLabel();\n if (plot) plot.redraw();\n });\n\n function startPlaying() {\n if (playBtn) playBtn.innerHTML = 'pause';\n\n playIntervalId = window.setInterval(() => {\n if (currentSliderIdx !== null && currentSliderIdx < currentChronoData.length - 1) {\n currentSliderIdx = Math.min(currentSliderIdx + 5, currentChronoData.length - 1);\n slider.value = `${currentSliderIdx}`;\n updateSliderLabel();\n if (plot) plot.redraw();\n } else {\n stopPlaying();\n }\n }, 20); // 50 fps\n }\n\n function stopPlaying() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (playBtn) playBtn.innerHTML = 'play_arrow';\n }\n\n playBtn?.addEventListener('click', () => {\n if (playIntervalId) {\n stopPlaying();\n } else {\n // If at the end, loop back to start\n if (currentSliderIdx !== null && currentSliderIdx >= currentChronoData.length - 1) {\n currentSliderIdx = 0;\n slider.value = '0';\n updateSliderLabel();\n if (plot) plot.redraw();\n }\n startPlaying();\n }\n });\n\n document.getElementById('btn-combined-cart')?.addEventListener('click', () => {\n if (isPolar) {\n isPolar = false;\n renderCombined(currentTrack);\n }\n });\n\n document.getElementById('btn-combined-polar')?.addEventListener('click', () => {\n if (!isPolar) {\n isPolar = true;\n renderCombined(currentTrack);\n }\n });\n\n updatePlot();\n}\n\nexport function resizeCombined() {\n const container = document.getElementById('tab-combined');\n const plotContainer = document.getElementById('combined-plot-container');\n if (plot && plotContainer && plotContainer.clientWidth > 0) {\n const w = plotContainer.clientWidth;\n const h = plotContainer.clientHeight;\n\n if (w > 0 && h > 0) {\n if (isPolar) {\n const size = Math.min(w, h);\n plot.setSize({ width: size, height: size });\n } else {\n plot.setSize({ width: w, height: h });\n }\n }\n }\n}\n\nfunction showMenu(anchorEl: HTMLElement, axis: 'x' | 'y') {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const track = currentTrack;\n if (!track) return;\n\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n availableMetrics.forEach((key) => {\n const def = metrics[key];\n const item = document.createElement('div');\n const currentVal = axis === 'x' ? xMetric : yMetric;\n item.className = `menu-item ${currentVal === key ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${currentVal === key ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n if (axis === 'x') xMetric = key;\n else yMetric = key;\n\n popup.remove();\n renderCombined(currentTrack); // Re-render to update buttons and plot\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction updatePlot() {\n if (!currentTrack) return;\n const container = document.getElementById('combined-plot-container');\n if (!container) return;\n\n const metrics = ChartView.METRICS;\n const xDef = metrics[xMetric] || metrics.power;\n const yDef = metrics[yMetric] || metrics.hr;\n\n if (currentTracks.length >= 2) {\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n\n const pts1 = t1.points;\n const pts2 = t2.points;\n const maxLen = Math.max(pts1.length, pts2.length);\n const xData: number[] = [];\n const yData1: (number | null)[] = [];\n const yData2: (number | null)[] = [];\n\n for (let i = 0; i < maxLen; i++) {\n xData.push(i);\n const p1 = pts1[i];\n const p2 = pts2[i];\n yData1.push(p1 && (p1 as any)[yDef.field] != null ? (p1 as any)[yDef.field] : null);\n yData2.push(p2 && (p2 as any)[yDef.field] != null ? (p2 as any)[yDef.field] : null);\n }\n\n if (plot) {\n plot.destroy();\n plot = null;\n }\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n let width = container.clientWidth > 0 ? container.clientWidth : 800;\n let height = container.clientHeight > 0 ? container.clientHeight : 350;\n\n const opts: uPlot.Options = {\n width,\n height,\n padding: [10, 15, 0, 0],\n scales: { x: { time: false }, y: { auto: true } },\n series: [\n {},\n {\n label: `${t1.displayName || t1.name} (${yDef.label})`,\n stroke: t1.color || '#3b82f6',\n width: 2,\n points: { show: false },\n },\n {\n label: `${t2.displayName || t2.name} (${yDef.label})`,\n stroke: t2.color || '#FF6B35',\n width: 2,\n points: { show: false },\n },\n ],\n axes: [\n {\n side: 2,\n label: 'Elapsed Duration (s)',\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n side: 3,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n legend: { show: true },\n };\n\n plot = new uPlot(opts, [xData, yData1, yData2], container as HTMLElement);\n resizeCombined();\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts[0].time || 0;\n const chronoData = pts\n .map((p, idx) => [\n (p as any)[xDef.field],\n (p as any)[yDef.field],\n (p.time! - t0) / 1000,\n (p.dist || 0) / 1000,\n idx,\n ])\n .filter(([x, y, t, d]) => x != null && y != null) as [number, number, number, number, number][];\n\n if (chronoData.length === 0) {\n container.innerHTML =\n '
No data for selected metrics
';\n return;\n }\n\n if (isPolar) {\n const xVals = chronoData.map((d) => d[0]);\n const yVals = chronoData.map((d) => d[1]);\n const xMin = Math.min(...xVals);\n const xMax = Math.max(...xVals);\n const yMin = Math.min(...yVals);\n const yMax = Math.max(...yVals);\n\n currentChronoData = chronoData.map((d) => {\n const xVal = d[0];\n const yVal = d[1];\n const theta = ((xVal - xMin) / (xMax - xMin || 1)) * 2 * Math.PI;\n const r = (yVal - yMin) / (yMax - yMin || 1);\n const px = r * Math.cos(theta);\n const py = r * Math.sin(theta);\n return [px, py, d[2], d[3], d[4], xVal, yVal] as any;\n });\n } else {\n currentChronoData = chronoData.map((d) => [d[0], d[1], d[2], d[3], d[4], d[0], d[1]] as any);\n }\n\n // Update slider\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n if (slider) {\n slider.max = `${chronoData.length - 1}`;\n if (currentSliderIdx === null || currentSliderIdx >= chronoData.length) {\n currentSliderIdx = chronoData.length - 1;\n slider.value = slider.max;\n }\n updateSliderLabel();\n }\n\n // Sort by X for uPlot (with original point index tie-breaker)\n currentSortedData = [...currentChronoData].sort((a, b) => a[0] - b[0] || a[4] - b[4]);\n\n const xData = currentSortedData.map((d) => d[0]);\n const yData = currentSortedData.map((d) => d[1]);\n\n const plotContainer = document.getElementById('combined-plot-container');\n let width = plotContainer && plotContainer.clientWidth > 0 ? plotContainer.clientWidth : 600;\n let height = plotContainer && plotContainer.clientHeight > 0 ? plotContainer.clientHeight : 400;\n\n if (isPolar) {\n const size = Math.min(width, height > 0 ? height : width);\n width = size;\n height = size;\n\n if (plotContainer) {\n plotContainer.style.display = 'flex';\n plotContainer.style.alignItems = 'center';\n plotContainer.style.justifyContent = 'center';\n }\n } else if (plotContainer) {\n plotContainer.style.display = '';\n plotContainer.style.alignItems = '';\n plotContainer.style.justifyContent = '';\n }\n\n const opts: uPlot.Options = {\n width: width,\n height: height,\n padding: [10, 15, 0, 0],\n scales: {\n x: { time: false, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: yDef.label,\n width: 0,\n points: { show: true, size: 3, fill: hexToRgba(yDef.color, 0.3) },\n },\n ],\n axes: [\n {\n side: 2, // bottom\n show: !isPolar,\n label: `${xDef.label} (${xDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? xDef.fmtAxis(v) : '')),\n size: 30,\n },\n {\n side: 3, // left\n show: !isPolar,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? yDef.fmtAxis(v) : '')),\n size: 40,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => {\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let closestIdx = -1;\n\n for (let i = 0; i < currentSortedData.length; i++) {\n const [xVal, yVal] = currentSortedData[i];\n const cx = u.valToPos(xVal, 'x');\n const cy = u.valToPos(yVal, 'y');\n\n const dx = cx - cursorLeft;\n const dy = cy - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n closestIdx = i;\n }\n }\n\n // Only snap if within a reasonable distance (e.g. 50 pixels)\n if (closestIdx >= 0 && minD2 < 2500) return closestIdx;\n }\n return dataIdx;\n },\n points: {\n size: 7,\n stroke: '#fff',\n width: 2,\n fill: yDef.color,\n },\n },\n legend: { show: false },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Draw faint lines connecting points in chronological order\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.lineWidth = 1 * dpr;\n\n let started = false;\n for (let i = 0; i < currentChronoData.length; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n if (started) {\n ctx.lineTo(cx, cy);\n } else {\n ctx.moveTo(cx, cy);\n started = true;\n }\n }\n ctx.stroke();\n ctx.restore();\n\n // Draw trail if slider is active\n if (currentSliderIdx !== null) {\n ctx.save();\n const windowSize = 100; // Longer trail\n const startIdx = Math.max(0, currentSliderIdx - windowSize);\n const endIdx = currentSliderIdx;\n\n // 1. Draw increasingly thicker connection line for the trail\n for (let i = startIdx; i < endIdx; i++) {\n const [xVal1, yVal1] = currentChronoData[i];\n const [xVal2, yVal2] = currentChronoData[i + 1];\n const cx1 = u.valToPos(xVal1, 'x', true);\n const cy1 = u.valToPos(yVal1, 'y', true);\n const cx2 = u.valToPos(xVal2, 'x', true);\n const cy2 = u.valToPos(yVal2, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const lineWidth = 1 + 5 * progress; // Grow from 1 to 6\n const alpha = 0.15 + 0.6 * progress; // Fade from 0.15 to 0.75\n\n ctx.beginPath();\n ctx.moveTo(cx1, cy1);\n ctx.lineTo(cx2, cy2);\n ctx.strokeStyle = hexToRgba(yDef.color, alpha);\n ctx.lineWidth = lineWidth * dpr;\n ctx.stroke();\n }\n\n // 2. Draw dots on top\n for (let i = startIdx; i <= endIdx; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const size = 3 + 7 * progress; // Grow from 3 to 10\n const fillAlpha = 0.01 + 0.14 * progress; // Fade from 0.01 to 0.15\n\n ctx.beginPath();\n ctx.arc(cx, cy, size * dpr, 0, Math.PI * 2);\n ctx.fillStyle = hexToRgba(yDef.color, fillAlpha);\n ctx.fill();\n\n ctx.strokeStyle = yDef.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n\n let tooltip = document.getElementById('combined-tooltip');\n if (!tooltip) {\n tooltip = document.createElement('div');\n tooltip.id = 'combined-tooltip';\n tooltip.style.position = 'absolute';\n tooltip.style.background = 'rgba(14, 14, 16, 0.9)';\n tooltip.style.color = '#fff';\n tooltip.style.padding = '8px 12px';\n tooltip.style.borderRadius = '4px';\n tooltip.classList.add('font-m');\n tooltip.style.fontFamily = 'system-ui';\n tooltip.style.pointerEvents = 'none';\n tooltip.style.zIndex = '1000';\n tooltip.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';\n tooltip.style.border = '1px solid #2e2e34';\n document.body.appendChild(tooltip);\n }\n\n if (idx != null && currentSortedData[idx] && u.cursor.left! >= 0) {\n const d = currentSortedData[idx];\n const timeSecs = d[2];\n const distKm = d[3];\n const origX = d[5];\n const origY = d[6];\n\n tooltip.innerHTML = `\n
Point #${idx}
\n
\n Time:\n ${fmtSecs(timeSecs)}\n
\n
\n Distance:\n ${distKm.toFixed(2)} km\n
\n
\n ${xDef.label}:\n ${xDef.fmtAxis(origX)} ${xDef.unit}\n
\n
\n ${yDef.label}:\n ${yDef.fmtAxis(origY)} ${yDef.unit}\n
\n `;\n tooltip.style.display = 'block';\n\n const canvasRect = u.over.getBoundingClientRect();\n tooltip.style.left = `${canvasRect.left + window.scrollX + u.cursor.left! + 15}px`;\n tooltip.style.top = `${canvasRect.top + window.scrollY + u.cursor.top! + 15}px`;\n } else {\n tooltip.style.display = 'none';\n }\n },\n ],\n },\n };\n\n // Clear container before rendering (except when uPlot does it)\n // uPlot handles its own canvas, but we need to clear any previous empty state message\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n if (plot) plot.destroy();\n\n plot = new uPlot(opts, [xData, yData], container);\n\n plot.over.addEventListener('click', () => {\n if (plot) {\n const idx = plot.cursor.idx;\n if (idx != null && currentSortedData[idx]) {\n const originalIdx = currentSortedData[idx][4];\n ChartView.setCursorAt(originalIdx);\n }\n }\n });\n\n // Ensure initial size is set synchronously\n resizeCombined();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { UrlState } from '../url-state';\nimport { computeAccumulatedMetric, renderAccumulatedTable } from './accumulated_progress';\n\nlet evolutionPlots: uPlot[] = [];\n\nfunction destroyEvolutionPlots() {\n evolutionPlots.forEach((p) => p.destroy());\n evolutionPlots = [];\n}\n\nexport function resetEvolution() {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for progress analysis
\n
\n `;\n }\n}\n\nexport function renderEvolution(\n currentTrack: TrackData | null,\n allTracks: TrackData[],\n onTrackSelect?: (id: string, range: [number, number] | null) => void,\n onDateRangeSelect?: (start: string, end: string) => void,\n) {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (!container) return;\n\n let currentRange = UrlState.get().progress || 'all';\n\n // JIT computation of high-resolution duration curves during Evolution benchmark step\n allTracks.forEach((track) => {\n Parsers.ensureCurvesAndZones(track);\n });\n\n // Deterministic EWMA physiological training load calculation (ATL / CTL / TSB modeling)\n let totalFatigue = 0;\n let totalFitness = 0;\n const alphaATL = 2 / (7 + 1);\n const alphaCTL = 2 / (42 + 1);\n allTracks.forEach((track: any) => {\n const pts = track.points || [];\n let atl = 0;\n let ctl = 0;\n for (let i = 0; i < pts.length; i += 4) {\n const stress = (pts[i].power || 0) * 1.5 + (pts[i].hr || 0);\n atl = alphaATL * stress + (1 - alphaATL) * atl;\n ctl = alphaCTL * stress + (1 - alphaCTL) * ctl;\n }\n totalFatigue += atl;\n totalFitness += ctl;\n });\n container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1);\n const cards: any[] = [];\n container.innerHTML = `\n
\n
\n
\n \n \n \n \n
\n
\n
\n
\n \n \n \n \n \n \n
\n
\n
\n
\n `;\n\n const grid = document.getElementById('evolution-container');\n if (!grid) return;\n\n const gridWidth = grid.clientWidth || 570;\n\n const progressSync = uPlot.sync('progress-sync');\n cards.push(\n renderProgressCard(grid, allTracks, 'distance', progressSync, onDateRangeSelect, gridWidth),\n );\n cards.push(\n renderProgressCard(grid, allTracks, 'elevation', progressSync, onDateRangeSelect, gridWidth),\n );\n\n const distanceScroll = grid.querySelector(\n '.distance-progress-card .chart-scroll-container',\n ) as HTMLElement;\n const elevationScroll = grid.querySelector(\n '.elevation-progress-card .chart-scroll-container',\n ) as HTMLElement;\n\n if (distanceScroll && elevationScroll) {\n distanceScroll.addEventListener('scroll', () => {\n if (elevationScroll.scrollLeft !== distanceScroll.scrollLeft)\n elevationScroll.scrollLeft = distanceScroll.scrollLeft;\n });\n elevationScroll.addEventListener('scroll', () => {\n if (distanceScroll.scrollLeft !== elevationScroll.scrollLeft)\n distanceScroll.scrollLeft = elevationScroll.scrollLeft;\n });\n }\n\n const toolbarRangeCtrl = container.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const range = btn.getAttribute('data-range');\n if (range) {\n toolbarRangeCtrl\n .querySelectorAll('.seg-btn')\n .forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n onRangeChange(range);\n }\n });\n });\n }\n\n const pills = container.querySelectorAll('.metric-pill');\n pills.forEach((pill) => {\n pill.addEventListener('click', () => {\n const target = pill.getAttribute('data-target');\n if (target) {\n const targetEl = document.getElementById(`${target}-evolution-card`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n });\n });\n\n function onPinChange(dur: number | null) {\n cards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n }\n\n function onRangeChange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n }\n\n if (allTracks.some((t) => t.stats.powerCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'power',\n label: 'Power Curve Progress',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n if (allTracks.some((t) => t.stats.hrCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'hr',\n label: 'Heart Rate Curve Progress',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n // Apply initial range when filtered\n if (currentRange !== 'all') {\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(currentRange);\n });\n }\n\n evolutionPlots.forEach((p) => {\n (p as any)._ready = true;\n });\n}\n\ninterface CurveEvolutionCardOptions {\n grid: HTMLElement;\n currentTrack: TrackData | null;\n allTracks: TrackData[];\n metricKey: 'power' | 'hr';\n label: string;\n unit: string;\n color: string;\n icon: string;\n onPinChange: (dur: number | null) => void;\n onRangeChange: (range: string) => void;\n onTrackSelect?: (id: string, range: [number, number] | null) => void;\n gridWidth?: number;\n}\n\nfunction renderCurveEvolutionCard(opts: CurveEvolutionCardOptions) {\n const {\n grid,\n currentTrack,\n allTracks,\n metricKey,\n label,\n unit,\n color,\n icon,\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n } = opts;\n\n const trackName = currentTrack ? currentTrack.name || 'Current Track' : 'Current Track';\n\n let mainChart: uPlot | null = null;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = 'chart-row evolution-card-group';\n cardContainer.id = `${metricKey}-evolution-card`;\n grid.appendChild(cardContainer);\n\n const row1 = document.createElement('div');\n row1.className = 'chart-row progress-chart-row';\n row1.style.setProperty('--chart-color', color);\n row1.style.flex = '0 0 400px';\n row1.style.borderBottom = 'none';\n row1.innerHTML = `\n
\n
\n ${icon}\n ${label}\n
\n
\n
\n
\n
\n `;\n\n const legendEl = document.createElement('div');\n legendEl.className = 'evolution-legend';\n legendEl.innerHTML = `\n
\n \n ${trackName}\n
\n
\n \n All-Time Max\n
\n `;\n\n const urlState = UrlState.get();\n let currentRange = urlState.progress || 'all';\n\n const row2 = document.createElement('div');\n row2.className = 'chart-row progress-chart-row';\n row2.style.setProperty('--chart-color', color);\n row2.style.flex = '1';\n row2.style.borderBottom = 'none';\n row2.innerHTML = `\n
\n
\n ${icon}\n Progress ${metricKey === 'power' ? 'Power' : 'HR'}\n
\n
\n
\n
\n
\n `;\n\n const sideBySide = document.createElement('div');\n sideBySide.style.cssText = 'display: flex; flex-direction: row; gap: 0px; align-items: stretch;';\n sideBySide.appendChild(row1);\n sideBySide.appendChild(row2);\n\n cardContainer.appendChild(sideBySide);\n cardContainer.appendChild(legendEl);\n\n const chartEl = row1.querySelector(`#${metricKey}-evolution-chart`) as HTMLElement;\n if (!chartEl) return;\n\n // 1. Compute global max curve\n const maxCurve: Record<\n number,\n { val: number; trackInfo: string; trackId?: string; idx?: number }\n > = {};\n allTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n const name = t.name || 'Unnamed Track';\n const date =\n t.stats.startTime || t.addedAt ? fmtDate((t.stats.startTime || t.addedAt)!) : 'Unknown Date';\n const trackInfo = `${name} (${date})`;\n\n Object.entries(curve).forEach(([dur, data]) => {\n const d = Number(dur);\n const val = (data as any).power || (data as any).hr;\n if (!maxCurve[d] || val > maxCurve[d].val)\n maxCurve[d] = { val, trackInfo, trackId: t.id, idx: (data as any).idx };\n });\n });\n\n // 2. Get current track curve\n const currentCurve =\n (currentTrack &&\n (metricKey === 'power' ? currentTrack.stats.powerCurve : currentTrack.stats.hrCurve)) ||\n {};\n\n // 3. Combine durations\n const allDurations = new Set();\n Object.keys(maxCurve).forEach((d) => allDurations.add(Number(d)));\n Object.keys(currentCurve).forEach((d) => allDurations.add(Number(d)));\n const durations = Array.from(allDurations).sort((a, b) => a - b);\n\n const xData = durations;\n const yDataCurrent = durations.map((d) => {\n const entry = currentCurve[d];\n return entry ? (entry as any).power || (entry as any).hr : null;\n });\n const yDataMax = durations.map((d) => maxCurve[d]?.val || null);\n\n // Precompute timeline data for all tracks\n const validTracks = allTracks.filter((t) => (t.stats.startTime || t.addedAt) != null);\n validTracks.sort(\n (a, b) =>\n (a.stats.startTime || a.addedAt || 0) - (b.stats.startTime || b.addedAt || 0) ||\n a.id.localeCompare(b.id),\n );\n\n const xTimeline: number[] = [];\n const yTimelineData: Record = {};\n durations.forEach((d) => (yTimelineData[d] = []));\n\n validTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n\n xTimeline.push((t.stats.startTime || t.addedAt)! / 1000); // seconds\n durations.forEach((d) => {\n const entry = curve[d];\n const val = entry ? (metricKey === 'power' ? (entry as any).power : (entry as any).hr) : null;\n yTimelineData[d].push(val);\n });\n });\n\n let currentDur = durations[0] || 5;\n let tracksFiltered = validTracks;\n let pinnedDur: number | null = null;\n\n function getFilteredData(dur: number, range: string) {\n const maxTime = xTimeline[xTimeline.length - 1] || 1785542400;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600;\n\n const filteredIndices: number[] = [];\n xTimeline.forEach((t, idx) => {\n if (t >= minTime) filteredIndices.push(idx);\n });\n\n const xFiltered = filteredIndices.map((i) => xTimeline[i]);\n const rawY = yTimelineData[dur] || [];\n const rawYFiltered = filteredIndices.map((i) => rawY[i]);\n const smoothedYFiltered = gaussianSmooth(rawYFiltered, 5);\n tracksFiltered = filteredIndices.map((i) => validTracks[i]);\n\n return { xFiltered, rawYFiltered, smoothedYFiltered };\n }\n\n let timelineChart: uPlot | null = null;\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val font-m';\n curYVal.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const renderCharts = () => {\n const optsUPlot: uPlot.Options = {\n id: `${metricKey}-evolution`,\n width: 400,\n height: 250,\n padding: [0, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: 'Current Track',\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n {\n label: 'All-Time Max',\n stroke: '#888888',\n width: 1,\n fill: 'transparent',\n points: { show: true, size: 6, fill: '#888888' },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n x: false,\n y: false,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n\n // Draw pinned duration circle\n if (pinnedDur !== null) {\n const idx = xData.indexOf(pinnedDur);\n if (idx >= 0) {\n const pcx = u.valToPos(pinnedDur, 'x', true);\n const pcy = u.valToPos(yDataCurrent[idx]! || yDataMax[idx]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]);\n const curVal = yDataCurrent[idx];\n const dotRadius = curVal !== null ? 5 * dpr : 3 * dpr;\n const dotColor = curVal !== null ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n }\n\n ctx.restore();\n },\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(\n activeSeriesIdx === 1 ? yDataCurrent[idx]! : yDataMax[idx]!,\n 'y',\n true,\n );\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n const dotRadius = activeSeriesIdx === 1 ? 5 * dpr : 6 * dpr;\n const dotColor = activeSeriesIdx === 1 ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n const xValStr = fmtDuration(xData[idx!]);\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n // X Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const yVal = yDataCurrent[idx!]! || yDataMax[idx!]!;\n const yValStr = `${yVal.toFixed(0)} ${unit}`;\n const yValWidth = ctx.measureText(yValStr).width;\n const ybw = yValWidth + 10 * dpr;\n\n const yLabelX = bb.left - ybw - 2 * dpr; // To the left\n const yLabelY = pcy - pillH / 2;\n\n // Y Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * dpr);\n else ctx.rect(yLabelX, yLabelY, ybw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(yValStr, yLabelX + 5 * dpr, yLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n const hasFocus = idx != null && xData[idx] != null;\n\n if (hasFocus) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yDataCurrent[idx!]! || yDataMax[idx!]!, 'y', false); // Fallback to max if current is null\n\n const durVal = xData[idx!];\n const curVal = yDataCurrent[idx!];\n const mxVal = yDataMax[idx!];\n\n let html = `
${fmtDuration(durVal)}
`;\n if (curVal !== null) {\n html += `\n
\n Current:\n ${curVal} ${unit}\n
\n `;\n }\n if (mxVal !== null) {\n html += `\n
\n Max:\n ${mxVal} ${unit}\n
\n `;\n }\n\n curYVal.innerHTML = html;\n\n if (timelineChart) {\n if (pinnedDur === null) {\n currentDur = durVal;\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([\n xFiltered,\n rawYFiltered,\n smoothedYFiltered,\n lowerBound,\n upperBound,\n ]);\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(durVal)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n }\n }\n curYVal.style.display = '';\n curYVal.style.left = `${cursorLeft! + bb.left}px`;\n curYVal.style.top = `${cursorTop! + bb.top}px`;\n curYVal.style.transform = 'translate(5px, -50%)';\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n };\n\n mainChart = new uPlot(optsUPlot, [xData, yDataCurrent, yDataMax], chartEl);\n evolutionPlots.push(mainChart);\n\n chartEl.addEventListener('click', () => {\n if (!mainChart) return;\n const idx = mainChart.cursor.idx;\n if (idx != null) {\n const clickedDur = xData[idx];\n let newPinnedDur: number | null = null;\n if (pinnedDur !== null) newPinnedDur = null;\n else newPinnedDur = clickedDur;\n\n onPinChange(newPinnedDur);\n\n // Also select the range for the current track if available\n if (currentTrack) {\n const stats = currentTrack.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[clickedDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = clickedDur;\n const startPt = currentTrack.points[bestIdx];\n const endPt = currentTrack.points[bestIdx + duration - 1];\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = currentTrack.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n onTrackSelect?.(currentTrack.id, [min, max]);\n }\n }\n }\n }\n }\n });\n\n chartEl.addEventListener('mouseleave', () => {\n if (mainChart) mainChart.redraw();\n });\n\n // 4. Add expandable table\n const detailsEl = document.createElement('details');\n detailsEl.classList.add('progress-details');\n detailsEl.style.marginTop = '0px';\n detailsEl.style.setProperty('--chart-color', color);\n detailsEl.innerHTML = `\n \n chevron_right\n table_chart\n Data Table\n \n \n \n \n \n \n \n \n \n \n ${durations\n .map((d) => {\n const cur = currentCurve[d]\n ? (currentCurve[d] as any).power || (currentCurve[d] as any).hr\n : '-';\n const mx = maxCurve[d]?.val || '-';\n const mxId = maxCurve[d]?.trackId;\n const mxIdx = maxCurve[d]?.idx;\n return `\n \n \n \n \n \n `;\n })\n .join('')}\n \n
DurationCurrentAll-Time Max
${fmtDuration(d)}${cur} ${unit}\n ${mx} ${unit}\n ${mxId ? `` : ''}\n
\n `;\n cardContainer.appendChild(detailsEl);\n\n detailsEl.querySelectorAll('.evolution-select-btn').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const id = btn.getAttribute('data-id');\n const idx = btn.getAttribute('data-idx');\n const dur = btn.getAttribute('data-dur');\n if (id) {\n document.dispatchEvent(\n new CustomEvent('select-track', {\n detail: {\n id,\n idx: idx ? Number(idx) : null,\n dur: dur ? Number(dur) : null,\n },\n }),\n );\n }\n });\n });\n\n let lastNearestIdx: number | null = null;\n\n // 5. Render timeline chart\n const timelineEl = row2.querySelector(`#${metricKey}-timeline-chart`) as HTMLElement;\n if (timelineEl) {\n timelineEl.style.position = 'relative';\n const timelineTooltip = document.createElement('div');\n timelineTooltip.className = 'timeline-tooltip font-m';\n timelineTooltip.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n timelineEl.appendChild(timelineTooltip);\n\n if (xTimeline.length > 0) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n const dataTimeline = [xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound];\n\n const series: any[] = [\n {\n value: (u: any, v: number) => {\n if (v != null) return fmtDate(v * 1000);\n\n return '-';\n },\n },\n {\n label: 'Value',\n stroke: color,\n width: 0,\n points: { show: true, size: 6, fill: hexToRgba(color, 0.5) },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n points: { show: false },\n spanGaps: true,\n fill: 'transparent',\n dash: [5, 5],\n },\n {\n label: 'Lower Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n {\n label: 'Upper Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n ];\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n\n const optsTimeline: uPlot.Options = {\n width: Math.max(100, (gridWidth || 570) - 400),\n height: 250,\n padding: [0, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n cursor: {\n points: {\n show: false,\n },\n drag: { setScale: false },\n x: false,\n y: false,\n },\n scales: {\n x: {\n time: true,\n range: (u) => {\n const min = u.data[0][0];\n const max = u.data[0][u.data[0].length - 1];\n if (min === undefined || max === undefined) return [0, 100];\n\n if (min === max) return [min - 3600, max + 3600];\n\n return [min, max];\n },\n },\n y: { range: (u: any, min: number, max: number) => [min * 0.9, max * 1.1] },\n },\n series: series,\n bands: [{ series: [4, 3], fill: hexToRgba(color, 0.2) }],\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n if (lastNearestIdx != null) {\n const track = tracksFiltered[lastNearestIdx];\n if (track) {\n const stats = track.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[currentDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = currentDur;\n\n const startPt = track.points[bestIdx];\n const endPt = track.points[bestIdx + duration - 1];\n\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = track.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n\n opts.onTrackSelect?.(track.id, [min, max]);\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n }\n }\n });\n },\n ],\n draw: [\n (u: uPlot) => {\n let idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const val = u.data[1][idx];\n if (val != null) {\n const tpcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const tpcy = u.valToPos(val, 'y', true);\n\n const tctx = u.ctx;\n const tdpr = window.devicePixelRatio || 1;\n\n // Draw lines\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([2 * tdpr, 2 * tdpr]);\n tctx.strokeStyle = hexToRgba(color, 0.4);\n tctx.lineWidth = 1 * tdpr;\n // Vertical line\n tctx.moveTo(tpcx, u.bbox.top);\n tctx.lineTo(tpcx, u.bbox.top + u.bbox.height);\n // Horizontal line\n tctx.moveTo(u.bbox.left, tpcy);\n tctx.lineTo(u.bbox.left + u.bbox.width, tpcy);\n tctx.stroke();\n tctx.restore();\n\n // Draw hover halo\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([]); // Reset to solid\n tctx.arc(tpcx, tpcy, 12 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = hexToRgba(color, 0.2);\n tctx.fill();\n tctx.restore();\n\n // Draw center circle\n tctx.save();\n tctx.beginPath();\n tctx.arc(tpcx, tpcy, 6 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = color;\n tctx.fill();\n tctx.strokeStyle = '#fff';\n tctx.lineWidth = 2 * tdpr;\n tctx.stroke();\n tctx.restore();\n\n // Draw axis labels\n tctx.save();\n tctx.setLineDash([]); // Reset to solid\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n tctx.font = `bold ${10 * tdpr}px system-ui, sans-serif`;\n const dateWidth = tctx.measureText(dateStr).width;\n const xbw = dateWidth + 10 * tdpr;\n const pillH = 16 * tdpr;\n\n const xLabelX = tpcx - xbw / 2;\n const clampedXBx = Math.max(\n u.bbox.left,\n Math.min(u.bbox.left + u.bbox.width - xbw, xLabelX),\n );\n const xLabelY = u.bbox.top + u.bbox.height + 2 * tdpr;\n\n // X Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * tdpr);\n else tctx.rect(clampedXBx, xLabelY, xbw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'center';\n tctx.textBaseline = 'middle';\n tctx.fillText(dateStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const valStr = `${val.toFixed(0)} ${unit}`;\n const valWidth = tctx.measureText(valStr).width;\n const ybw = valWidth + 10 * tdpr;\n\n const yLabelX = u.bbox.left - ybw - 2 * tdpr; // To the left\n const yLabelY = tpcy - pillH / 2;\n\n // Y Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * tdpr);\n else tctx.rect(yLabelX, yLabelY, ybw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'left';\n tctx.textBaseline = 'middle';\n tctx.fillText(valStr, yLabelX + 5 * tdpr, yLabelY + pillH / 2);\n\n tctx.restore();\n }\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n const bb = u.bbox;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n const xData = u.data[0];\n const yData = u.data[1];\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const y = yData[i];\n if (x == null || y == null) continue;\n\n const px = u.valToPos(x, 'x', false);\n const py = u.valToPos(y, 'y', false);\n\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n }\n }\n\n if (minD2 <= maxD2) {\n idx = nearestIdx;\n lastNearestIdx = nearestIdx;\n } else {\n idx = null;\n lastNearestIdx = null;\n }\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const track = tracksFiltered[idx];\n const cx = u.valToPos(u.data[0][idx], 'x', false);\n const cy = u.valToPos(u.data[1][idx]!, 'y', false);\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n\n const val = u.data[1][idx];\n const valStr = val != null ? `${val} ${unit}` : '\u2014';\n\n timelineTooltip.innerHTML = `\n
\n Date:\n ${dateStr}\n
\n
\n Value:\n ${valStr}\n
\n `;\n timelineTooltip.style.display = 'block';\n timelineTooltip.style.left = `${cursorLeft! + bb.left}px`;\n timelineTooltip.style.top = `${cursorTop! + bb.top}px`;\n timelineTooltip.style.transform = 'translate(5px, -50%)';\n } else {\n timelineTooltip.style.display = 'none';\n }\n },\n ],\n },\n axes: [\n {\n space: 50,\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n show: true,\n font: '10px system-ui, sans-serif',\n size: 30,\n values: (u: any, vals: any[]) =>\n vals.map((v) => {\n const d = new Date(v * 1000);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n }),\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n font: '10px system-ui, sans-serif',\n values: (u: any, vals: any[]) => vals.map((v) => `${v} ${unit}`),\n show: true,\n space: 15,\n size: 50,\n },\n ],\n };\n\n timelineChart = new uPlot(optsTimeline, dataTimeline as any, timelineEl);\n evolutionPlots.push(timelineChart);\n\n timelineEl.addEventListener('mouseleave', () => {\n timelineChart!.redraw();\n });\n\n // Range control moved to toolbar\n } else {\n timelineEl.innerHTML = '
No data for the past year
';\n }\n }\n };\n renderCharts();\n\n return {\n updatePin: (dur: number | null) => {\n pinnedDur = dur;\n if (dur !== null) currentDur = dur;\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}${pinnedDur !== null ? ' (Pinned)' : ''}`;\n\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n if (mainChart) mainChart.redraw();\n },\n updateRange: (range: string) => {\n currentRange = range;\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n },\n };\n}\n\nfunction getWeekStart(date: Date): Date {\n const d = new Date(date);\n const day = d.getUTCDay();\n const diff = d.getUTCDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday\n d.setUTCDate(diff);\n d.setUTCHours(0, 0, 0, 0);\n return d;\n}\n\nfunction computeWeeklyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey]) weeklyData[weekKey] = { timestamp: weekStart.getTime(), distance: 0 };\n\n weeklyData[weekKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeWeeklyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey])\n weeklyData[weekKey] = { timestamp: weekStart.getTime(), elevation: 0 };\n\n weeklyData[weekKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction renderProgressCard(\n grid: HTMLElement,\n allTracks: TrackData[],\n type: 'distance' | 'elevation',\n syncKey?: any,\n onDateRangeSelect?: (start: string, end: string) => void,\n gridWidth?: number,\n) {\n const isDistance = type === 'distance';\n const weeklyData = isDistance\n ? computeWeeklyDistance(allTracks)\n : computeWeeklyElevation(allTracks);\n const accumulated = computeAccumulatedMetric(allTracks, (t) =>\n isDistance ? t.stats.totalDist : t.stats.elevGain,\n );\n const color = isDistance ? Metrics.distance.color : Metrics.elevation.color;\n const unit = isDistance ? 'km' : 'm';\n const icon = isDistance ? Metrics.distance.icon : Metrics.elevation.icon;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = `chart-row ${type}-progress-card`;\n cardContainer.id = `${type}-evolution-card`;\n\n cardContainer.innerHTML = `\n
\n
\n ${icon}\n ${isDistance ? 'Distance Progress' : 'Elevation Progress'}\n
\n
\n
\n
\n
\n
\n
\n
\n ${renderAccumulatedTable(accumulated, isDistance, unit)}\n
\n
\n `;\n\n grid.appendChild(cardContainer);\n\n const chartEl = cardContainer.querySelector(`#${type}-weekly-chart`) as HTMLElement;\n const yAxisEl = cardContainer.querySelector(`#${type}-y-axis-chart`) as HTMLElement;\n\n if (!chartEl || !yAxisEl) return;\n\n chartEl.style.position = 'relative';\n\n // Use inline tooltip style\n const tooltip = document.createElement('div');\n tooltip.className = 'cur-y-val';\n tooltip.style.cssText = `color:${color};display:none`;\n chartEl.appendChild(tooltip);\n\n const xData = weeklyData.map((d) => d.timestamp / 1000);\n const yData = isDistance\n ? (weeklyData as any[]).map((d) => d.distance / 1000)\n : (weeklyData as any[]).map((d) => d.elevation);\n\n if (xData.length === 0) return;\n\n const yDataSmoothed = gaussianSmooth(yData, 2);\n\n const chartClientW = Math.max(0, (gridWidth || 570) - 20 - 320 - 20);\n const width = Math.max(chartClientW, xData.length * 40);\n const maxVal = Math.max(...yData) * 1.1;\n\n const mainOpts: uPlot.Options = {\n width: width,\n height: 150,\n padding: [10, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n scales: {\n x: { time: true },\n y: { range: [0, maxVal] },\n },\n series: [\n {},\n {\n label: isDistance ? 'Distance' : 'Elevation',\n stroke: color,\n fill: hexToRgba(color, 0.1),\n width: 2,\n points: { show: true, size: 4 },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n dash: [5, 5],\n points: { show: false },\n },\n ],\n cursor: {\n sync: syncKey ? { key: syncKey.key } : undefined,\n drag: { x: false, y: false },\n points: { show: false },\n x: false,\n y: false,\n },\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null) {\n const item = weeklyData[idx];\n if (item) {\n const start = new Date(item.timestamp);\n const end = new Date(item.timestamp + 7 * 24 * 60 * 60 * 1000); // End of week\n const startStr = start.toISOString().split('T')[0];\n const endStr = end.toISOString().split('T')[0];\n onDateRangeSelect?.(startStr, endStr);\n }\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n const idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (\n idx != null &&\n cursorLeft != null &&\n cursorTop != null &&\n cursorLeft >= 0 &&\n cursorTop >= 0\n ) {\n const val = u.data[1][idx];\n const valStr =\n val != null ? (isDistance ? `${val.toFixed(1)} km` : `${val.toFixed(0)} m`) : '\u2014';\n\n tooltip.innerHTML = valStr;\n tooltip.style.display = 'block';\n tooltip.style.left = `${u.valToPos(u.data[0][idx]!, 'x', false)}px`;\n tooltip.style.top = `${u.valToPos(u.data[1][idx]!, 'y', false)}px`;\n tooltip.style.transform = 'translate(6px, -50%)';\n } else {\n tooltip.style.display = 'none';\n }\n\n u.redraw(false);\n },\n ],\n draw: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(u.data[1][idx]!, 'y', true);\n const dpr = window.devicePixelRatio || 1;\n const ctx = u.ctx;\n const bb = u.bbox;\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n ctx.arc(pcx, pcy, 6 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n // X Label Pill\n const d = new Date(u.data[0][idx]! * 1000);\n const xValStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n },\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n space: 40,\n values: (self, splits) =>\n splits.map((s) => {\n const d = new Date(s * 1000);\n return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`;\n }),\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: (self, splits) => splits.map((s) => `${s.toFixed(0)} ${unit}`),\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n };\n\n const mainChart = new uPlot(mainOpts, [xData, yData, yDataSmoothed], chartEl);\n evolutionPlots.push(mainChart);\n\n const scrollContainer = cardContainer.querySelector('.chart-scroll-container') as HTMLElement;\n if (scrollContainer && xData.length * 40 > width)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n\n return {\n updateRange: (range: string) => {\n const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000;\n\n const filteredData = weeklyData.filter((d) => d.timestamp >= minTime);\n\n const newXData = filteredData.map((d) => d.timestamp / 1000);\n const newYData = isDistance\n ? (filteredData as any[]).map((d) => d.distance / 1000)\n : (filteredData as any[]).map((d) => d.elevation);\n const newYDataSmoothed = gaussianSmooth(newYData, 2);\n\n const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40);\n const newMaxVal = Math.max(...newYData) * 1.1;\n\n mainChart.setSize({ width: newWidth, height: 150 });\n mainChart.setScale('y', { min: 0, max: newMaxVal });\n mainChart.setData([newXData, newYData, newYDataSmoothed]);\n\n if (scrollContainer)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n },\n };\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData } from '../parsers';\n\nexport interface AccumulatedData {\n currentYear: number;\n pastYear: number;\n past6m: number;\n past1m: number;\n total: number;\n currentYearAvg: number;\n pastYearAvg: number;\n past6mAvg: number;\n past1mAvg: number;\n totalAvg: number;\n}\n\nexport function computeAccumulatedMetric(\n allTracks: TrackData[],\n extractor: (t: TrackData) => number | undefined,\n): AccumulatedData {\n // Derive deterministic reference timestamp from tracks (or fixed UTC fallback)\n let refTs = 0;\n for (let i = 0; i < allTracks.length; i++) {\n const st = allTracks[i].stats?.startTime;\n if (st && st > refTs) refTs = st;\n }\n if (!refTs) refTs = Date.UTC(2026, 7, 1);\n\n const now = new Date(refTs);\n const currentYear = now.getUTCFullYear();\n\n const oneYearAgoMs = Date.UTC(\n currentYear - 1,\n now.getUTCMonth(),\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const sixMonthsAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 6,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const oneMonthAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 1,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n\n let currentYearVal = 0;\n let pastYearVal = 0;\n let past6mVal = 0;\n let past1mVal = 0;\n let totalVal = 0;\n\n let minTime = refTs;\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime) return;\n const val = extractor(t);\n if (val === undefined) return;\n\n totalVal += val;\n\n const time = t.stats.startTime;\n if (time < minTime) minTime = time;\n\n const date = new Date(time);\n\n if (date.getUTCFullYear() === currentYear) currentYearVal += val;\n\n if (time >= oneYearAgoMs) pastYearVal += val;\n\n if (time >= sixMonthsAgoMs) past6mVal += val;\n\n if (time >= oneMonthAgoMs) past1mVal += val;\n });\n\n const msecPerWeek = 7 * 24 * 60 * 60 * 1000;\n const currentYearStart = Date.UTC(currentYear, 0, 1);\n\n const currentYearWeeks = Math.max(0.1, (refTs - currentYearStart) / msecPerWeek);\n const pastYearWeeks = Math.max(0.1, (refTs - oneYearAgoMs) / msecPerWeek);\n const past6mWeeks = Math.max(0.1, (refTs - sixMonthsAgoMs) / msecPerWeek);\n const past1mWeeks = Math.max(0.1, (refTs - oneMonthAgoMs) / msecPerWeek);\n const totalWeeks = Math.max(0.1, (refTs - minTime) / msecPerWeek);\n\n return {\n currentYear: currentYearVal,\n pastYear: pastYearVal,\n past6m: past6mVal,\n past1m: past1mVal,\n total: totalVal,\n currentYearAvg: currentYearVal / currentYearWeeks,\n pastYearAvg: pastYearVal / pastYearWeeks,\n past6mAvg: past6mVal / past6mWeeks,\n past1mAvg: past1mVal / past1mWeeks,\n totalAvg: totalVal / totalWeeks,\n };\n}\n\nexport function renderAccumulatedTable(\n accumulated: AccumulatedData,\n isDistance: boolean,\n unit: string,\n): string {\n const factor = isDistance ? 1000 : 1;\n const format = (val: number) => {\n const formattedVal = isDistance ? val / factor : val;\n return formattedVal.toLocaleString('en-US', {\n minimumFractionDigits: isDistance ? 1 : 0,\n maximumFractionDigits: isDistance ? 1 : 0,\n });\n };\n\n return `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Period${isDistance ? 'Distance' : 'Elevation'}${isDistance ? 'Distance/Week' : 'Elevation/Week'}
Current Year${format(accumulated.currentYear)} ${unit}${format(accumulated.currentYearAvg)} ${unit}
Past Year${format(accumulated.pastYear)} ${unit}${format(accumulated.pastYearAvg)} ${unit}
Past 6 Months${format(accumulated.past6m)} ${unit}${format(accumulated.past6mAvg)} ${unit}
Past 1 Month${format(accumulated.past1m)} ${unit}${format(accumulated.past1mAvg)} ${unit}
Total${format(accumulated.total)} ${unit}${format(accumulated.totalAvg)} ${unit}
\n `;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 Main Application \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { Storage } from './storage';\nimport { UrlState, AppState } from './url-state';\nimport { Parsers, TrackData, TrackPoint, calculateBounds, simplifyTrack } from './parsers';\nimport { MapView } from './map';\nimport { ChartView } from './charts';\nimport { renderDetails, initDetails, resetDetails } from './tabs/details';\nimport { renderInsights, initInsights, resetInsights } from './tabs/insights';\nimport { renderCombined, initCombined, resizeCombined, resetCombined } from './tabs/combined';\nimport { renderEvolution, resetEvolution } from './tabs/progress';\nimport {\n renderCourses,\n initCourses,\n prepareBenchmarkCourses,\n resetCourses,\n selectCourse,\n} from './tabs/courses';\nimport { fmtSecs, escHtml, fmtDate, getTagColor, compactId, shortRandom } from './utils';\n\nconst TRACK_COLORS: string[] = [\n '#FF6B35',\n '#4ECDC4',\n '#45B7D1',\n '#F7DC6F',\n '#FF6B6B',\n '#BB8FCE',\n '#82E0AA',\n '#F8C471',\n '#3b82f6',\n];\n\nconst POINT_ZOOM_LEVEL = 16;\n\nlet tracks: Record = {};\nlet skippedImports: { name: string; reason: string }[] = [];\n\nfunction isSameDay(t1: number, t2: number) {\n const d1 = new Date(t1);\n const d2 = new Date(t2);\n return (\n d1.getUTCFullYear() === d2.getUTCFullYear() &&\n d1.getUTCMonth() === d2.getUTCMonth() &&\n d1.getUTCDate() === d2.getUTCDate()\n );\n}\n\nlet cancelProcessing = false;\nlet selectedId: string | null = null;\nlet colorIdx = 0;\nlet followDot = false;\nlet currentMapColors: string[] | null = null;\n\n// Search/Filter state\nlet searchQuery = '';\nlet searchRegex = false;\nlet currentSort = 'date-desc';\n\ninterface Filters {\n date: [string | null, string | null];\n dist: [number | null, number | null];\n dur: [number | null, number | null];\n metrics: Set;\n tags: string[];\n sport: string | null;\n}\n\nlet filters: Filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n};\n\nfunction syncFiltersToUrl(push: boolean = false) {\n UrlState.patch(\n {\n f_date: filters.date.every((v) => v === null) ? null : filters.date,\n f_dist: filters.dist.every((v) => v === null) ? null : filters.dist,\n f_dur: filters.dur.every((v) => v === null) ? null : filters.dur,\n f_mets: filters.metrics.size === 0 ? null : Array.from(filters.metrics),\n f_tags: filters.tags.length === 0 ? null : filters.tags,\n },\n push,\n );\n}\n\nfunction syncMetricsToUrl() {\n const active = ChartView.getActiveMetrics();\n const metrics = ChartView.METRICS;\n const abbrs = Array.from(active).map((key) => metrics[key].abbr);\n UrlState.patch({ metrics: abbrs.length ? abbrs : null });\n}\n\nconst SORT_OPTIONS = [\n { label: 'Newest first', val: 'date-desc', icon: 'calendar_today' },\n { label: 'Oldest first', val: 'date-asc', icon: 'history' },\n { label: 'Longest distance', val: 'dist-desc', icon: 'straighten' },\n { label: 'Shortest distance', val: 'dist-asc', icon: 'horizontal_rule' },\n { label: 'Longest duration', val: 'dur-desc', icon: 'timer' },\n { label: 'Shortest duration', val: 'dur-asc', icon: 'timer_off' },\n];\n\nfunction showSortMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.sort-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'sort-menu-popup';\n\n SORT_OPTIONS.forEach((opt) => {\n const item = document.createElement('div');\n item.className = `menu-item ${currentSort === opt.val ? 'active' : ''}`;\n item.innerHTML = `\n ${opt.icon}\n ${opt.label}\n ${currentSort === opt.val ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n currentSort = opt.val;\n UrlState.patch({ sort: opt.val });\n updateSearchSortUI();\n renderTrackList();\n popup.remove();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction showMetricMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const available = ChartView.getAvailableMetrics();\n const active = ChartView.getActiveMetrics();\n\n Object.entries(metrics).forEach(([key, def]) => {\n if (!available.has(key)) return;\n\n const item = document.createElement('div');\n item.className = `menu-item ${active.has(key) ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${active.has(key) ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n ChartView.toggleMetric(key);\n const isNowActive = ChartView.getActiveMetrics().has(key);\n item.classList.toggle('active', isNowActive);\n item.querySelector('.check')!.textContent = isNowActive ? 'check' : '';\n\n const pill = document.querySelector(`#metric-pills .metric-pill[data-metric=\"${key}\"]`);\n if (pill) pill.classList.toggle('active', isNowActive);\n\n updateToolbarLayout();\n\n syncMetricsToUrl();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.right = `${window.innerWidth - rect.right}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\n// \u2500\u2500 Tab Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.addEventListener('select-track', (e: any) => {\n const id = e.detail.id;\n const idx = e.detail.idx;\n const dur = e.detail.dur;\n if (id && tracks[id]) {\n selectTrack(id);\n if (idx != null && dur != null) {\n const t = tracks[id];\n const pts = t.points;\n if (idx >= 0 && idx < pts.length) {\n const pIdx = pts[idx];\n if (pIdx && pIdx.time != null) {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const tMin = (pIdx.time - t0) / 1000;\n const tMax = tMin + dur;\n\n // ChartView selection\n ChartView.restoreSelection(tMin, tMax);\n\n // Find iMax based on duration\n let iMax = pts.findIndex((p) => (p.time || 0) >= pIdx.time! + dur * 1000);\n if (iMax === -1) iMax = pts.length - 1;\n\n const selPts = pts.slice(idx, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n\n renderInsights(t);\n\n MapView.highlightSegment(id, pts, idx, iMax, false, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n\n // Update URL state\n UrlState.patch({ sel: [tMin, tMax] });\n }\n }\n }\n }\n});\n\ndocument.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.tab-btn') as HTMLElement;\n if (!btn) return;\n const nav = btn.closest('#tab-nav');\n if (!nav) return;\n\n // Toggle buttons\n nav.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn));\n\n const tab = btn.dataset.tab!;\n UrlState.patch({ tab }, true);\n\n // Toggle contents\n const panel = nav.closest('#chart-panel');\n if (panel) {\n panel.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${btn.dataset.tab}`);\n });\n }\n\n if (btn.dataset.tab === 'details' && selectedId && tracks[selectedId])\n renderDetails(tracks[selectedId], getGlobalTags());\n\n if (btn.dataset.tab === 'insights' && selectedId && tracks[selectedId])\n renderInsights(tracks[selectedId]);\n\n if (btn.dataset.tab === 'evolution') {\n renderEvolution(\n selectedId ? tracks[selectedId] : null,\n Object.values(tracks),\n (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n },\n (start, end) => {\n filters.date = [start, end];\n applyFilters();\n syncFiltersToUrl(true);\n updateFilterUI();\n },\n );\n }\n\n if (btn.dataset.tab === 'combined' && selectedId && tracks[selectedId])\n renderCombined(tracks[selectedId]);\n\n if (btn.dataset.tab === 'courses') renderCourses();\n\n if (btn.dataset.tab === 'graphs') {\n ChartView.resize();\n updateToolbarLayout();\n\n // Restore selection from URL\n const s = UrlState.get().sel;\n if (s) ChartView.restoreSelection(s[0], s[1]);\n }\n});\n\nasync function resetBenchmarkState() {\n if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n await Storage.clear();\n tracks = {};\n skippedImports = [];\n selectedId = null;\n colorIdx = 0;\n currentMapColors = null;\n cancelProcessing = false;\n followDot = false;\n searchQuery = '';\n searchRegex = false;\n currentSort = 'date-desc';\n filters.date = [null, null];\n filters.dist = [null, null];\n filters.dur = [null, null];\n filters.metrics.clear();\n filters.tags = [];\n Parsers.setHRZones([120, 140, 160, 180]);\n Parsers.setFTP(200);\n resetCourses();\n resetInsights();\n resetDetails();\n resetCombined();\n resetEvolution();\n if (MapView.removeAllTracks) MapView.removeAllTracks();\n if (MapView.clearTracks) MapView.clearTracks();\n MapView.clearHighlight();\n if (ChartView.resetState) ChartView.resetState();\n else if (ChartView.clear) ChartView.clear();\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === 'graphs');\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === 'tab-graphs');\n });\n UrlState.reset();\n const toastContainer = document.getElementById('toast-container');\n if (toastContainer) toastContainer.innerHTML = '';\n document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());\n if (typeof renderTrackList === 'function') renderTrackList();\n}\n\n// \u2500\u2500 Boot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function init() {\n // Wait for fonts to be loaded with a cleaned-up timeout\n let fontTimerId: number | null = null;\n const fontTimeout = new Promise((resolve) => {\n fontTimerId = window.setTimeout(resolve, 1000);\n });\n try {\n const fontLoadPromise = document.fonts\n ? Promise.all([\n document.fonts.load('24px \"Material Symbols Rounded\"').catch(() => {}),\n document.fonts.ready,\n ])\n : Promise.resolve();\n await Promise.race([fontLoadPromise, fontTimeout]);\n } finally {\n if (fontTimerId !== null) window.clearTimeout(fontTimerId);\n }\n document.body.classList.remove('loading-fonts');\n const storageSelect = document.getElementById(\n 'storage-backend-select',\n ) as HTMLSelectElement | null;\n if (storageSelect) {\n storageSelect.value = UrlState.get().storage || 'memory';\n storageSelect.addEventListener('change', (e) => {\n const selected = (e.target as HTMLSelectElement).value;\n const params = new URLSearchParams(window.location.search);\n if (selected === 'memory') {\n params.delete('storage');\n } else {\n params.set('storage', selected);\n }\n window.location.search = params.toString();\n });\n }\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const mapLoader = document.getElementById('map-loader');\n const mapLoaderSpan = mapLoader?.querySelector('span');\n\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading database...';\n mapLoader.classList.remove('hidden');\n }\n\n const urlState = UrlState.get();\n\n initInsights((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n initDetails(\n () => {\n applyFilters();\n syncFiltersToUrl();\n },\n (id: string) => {\n deleteTrack(id);\n },\n );\n initCombined();\n initCourses((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n\n // Init sub-systems\n MapView.init(\n (id) => selectTrack(id),\n onMapMove,\n onMapPointClick,\n (id, idx) => {\n if (id === selectedId) ChartView.setHoverAt(idx);\n else ChartView.setHoverAt(null);\n },\n onMapDblClick,\n );\n ChartView.init(onChartCursorMove, onChartRangeChange, onChartClick, (idx) => {\n UrlState.patch({ sel_point: idx });\n });\n\n ChartView.setMapColorChangeCb((data) => {\n if (data) {\n currentMapColors = data.colors;\n if (selectedId) MapView.colorTrackByMetric(selectedId, data.pts, data.colors);\n } else {\n currentMapColors = null;\n if (selectedId) MapView.clearMetricColor(selectedId);\n }\n\n // Refresh highlight with new colors if a selection exists\n const currentUrlState = UrlState.get();\n if (currentUrlState.sel)\n onChartRangeChange(currentUrlState.sel[0], currentUrlState.sel[1], ChartView.getXAxis());\n });\n\n applyState(urlState);\n\n // Reset persistent storage and in-memory state for clean multi-iteration benchmark executions\n await Storage.openDB();\n await resetBenchmarkState();\n\n // Load persisted tracks\n try {\n // Load global settings\n const hrZones = await Storage.get('hr_zones');\n if (hrZones) Parsers.setHRZones(hrZones);\n\n const ftp = await Storage.get('ftp');\n if (ftp) Parsers.setFTP(ftp);\n\n const saved = await Storage.getAll();\n saved.sort((a, b) => a.addedAt - b.addedAt);\n\n if (mapLoaderSpan) mapLoaderSpan.textContent = `Preparing ${saved.length} tracks...`;\n\n const tracksToLoad: TrackData[] = [];\n for (const t of saved) {\n let updated = false;\n if (!t.bounds && t.points.length > 0) {\n const b = calculateBounds(t.points);\n if (b) {\n t.bounds = b;\n updated = true;\n }\n }\n if (!t.simplifiedPoints && t.points.length > 0) {\n t.simplifiedPoints = simplifyTrack(t.points, 50);\n updated = true;\n }\n if (updated) await Storage.save(t);\n\n tracks[t.id] = t;\n tracksToLoad.push(t);\n }\n MapView.addTracks(tracksToLoad);\n applyFilters();\n\n const restoreId =\n urlState.track && saved.find((t) => t.id === urlState.track)\n ? urlState.track\n : saved.length > 0\n ? saved[0].id\n : null;\n\n const mapLoader = document.getElementById('map-loader');\n\n // 1. Process and load the \"Priority\" track first\n const selectedTrackData = saved.find((t) => t.id === restoreId);\n if (selectedTrackData) {\n await processAndLoadTrack(selectedTrackData);\n selectTrack(selectedTrackData.id, !urlState.map_pos);\n\n // Explicitly restore selection/pin from URL if they exist\n if (urlState.sel && Array.isArray(urlState.sel) && urlState.sel.length === 2) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.restoreSelection(urlState.sel![0], urlState.sel![1]);\n });\n });\n }\n if (urlState.sel_point !== undefined && urlState.sel_point !== null) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.setCursorAt(urlState.sel_point!);\n });\n });\n }\n }\n\n // Hide database loader\n if (mapLoader) mapLoader.classList.add('hidden');\n\n // 2. Load the rest in background chunks\n if (saved.length > (selectedTrackData ? 1 : 0)) {\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading tracks...';\n mapLoader.classList.remove('hidden');\n }\n\n const remaining = saved.filter((t) => t.id !== restoreId);\n let index = 0;\n\n const loadNextChunk = async () => {\n const chunkSize = 2; // Process 2 tracks per frame\n const end = Math.min(index + chunkSize, remaining.length);\n\n for (; index < end; index++) await processAndLoadTrack(remaining[index]);\n\n if (index < remaining.length) {\n requestAnimationFrame(loadNextChunk);\n } else {\n if (mapLoader) mapLoader.classList.add('hidden');\n applyFilters(); // Final sync\n if (selectedId && tracks[selectedId]) {\n renderEvolution(tracks[selectedId], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n // Only fit all if no saved map position and we just finished loading everything\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n };\n\n requestAnimationFrame(loadNextChunk);\n } else {\n applyFilters();\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n } catch (e) {\n console.warn('Could not load saved tracks:', e);\n }\n\n // Panel resizers\n initResizeHandle();\n initSidebarResizer();\n initMetricPillDraggable();\n updateToolbarLayout();\n\n // Basemap switcher\n document.getElementById('basemap-switcher')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.bm-btn') as HTMLElement;\n if (!btn) return;\n document.querySelectorAll('.bm-btn').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n if (btn.dataset.layer) {\n MapView.switchBasemap(btn.dataset.layer);\n UrlState.patch({ map: btn.dataset.layer });\n }\n });\n\n // Fit all\n document.getElementById('btn-fit-all')?.addEventListener('click', () => MapView.fitAll());\n\n // Clear all\n document.getElementById('btn-clear-all')?.addEventListener('click', clearAll);\n\n // Search\n document.getElementById('track-search')?.addEventListener('input', (e) => {\n searchQuery = (e.target as HTMLInputElement).value;\n applyFilters();\n UrlState.patch({ q: searchQuery || null });\n });\n\n document.getElementById('btn-regex-toggle')?.addEventListener('click', (e) => {\n searchRegex = !searchRegex;\n (e.target as HTMLElement).classList.toggle('active', searchRegex);\n applyFilters();\n UrlState.patch({ re: searchRegex ? 1 : null });\n });\n\n // Sort\n document.getElementById('btn-sort-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSortMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric menu toggle\n document.getElementById('btn-metric-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMetricMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric toggles (shared logic)\n const toggleMetric = (metric: string, pill: HTMLElement | null) => {\n if (pill) pill.classList.toggle('active');\n ChartView.toggleMetric(metric);\n syncMetricsToUrl();\n };\n\n document.getElementById('metric-pills')?.addEventListener('click', (e) => {\n const pill = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (pill) {\n const metric = pill.dataset.metric;\n if (metric) {\n toggleMetric(metric, pill);\n\n // Scroll to it if it became active\n if (ChartView.getActiveMetrics().has(metric)) {\n const targetEl = document.querySelector(`.chart-row[data-metric=\"${metric}\"]`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n }\n }\n });\n\n // X-axis toggle\n document.getElementById('x-axis-ctrl')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const axis = btn.dataset.axis!;\n ChartView.setXAxis(axis);\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', b === btn));\n UrlState.patch({ xaxis: axis });\n });\n\n // Follow dot\n document.getElementById('btn-follow-dot')?.addEventListener('click', (e) => {\n followDot = !followDot;\n (e.currentTarget as HTMLElement).classList.toggle('active', followDot);\n });\n\n // Reset zoom\n document.getElementById('btn-reset-zoom')?.addEventListener('click', () => {\n ChartView.resetZoom();\n MapView.clearHighlight();\n });\n\n // File drag/drop\n initDropZone();\n\n // File browse\n document.getElementById('file-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n document.getElementById('folder-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n\n // Filters\n document.getElementById('btn-toggle-filters')?.addEventListener('click', () => {\n const panel = document.getElementById('filter-panel');\n if (panel) {\n panel.classList.toggle('hidden');\n document\n .getElementById('btn-toggle-filters')\n ?.classList.toggle('active', !panel.classList.contains('hidden'));\n }\n });\n\n const onFilterInput = (type: 'date' | 'dist' | 'dur', idx: number, e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n (filters[type] as any)[idx] = val === '' ? null : val;\n applyFilters();\n syncFiltersToUrl();\n };\n\n document\n .getElementById('filter-date-start')\n ?.addEventListener('change', (e) => onFilterInput('date', 0, e));\n document\n .getElementById('filter-date-end')\n ?.addEventListener('change', (e) => onFilterInput('date', 1, e));\n document\n .getElementById('filter-dist-min')\n ?.addEventListener('input', (e) => onFilterInput('dist', 0, e));\n document\n .getElementById('filter-dist-max')\n ?.addEventListener('input', (e) => onFilterInput('dist', 1, e));\n document\n .getElementById('filter-dur-min')\n ?.addEventListener('input', (e) => onFilterInput('dur', 0, e));\n document\n .getElementById('filter-dur-max')\n ?.addEventListener('input', (e) => onFilterInput('dur', 1, e));\n\n const burgerBtn = document.getElementById('sport-burger-btn');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n burgerBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n if (dropdownContent) {\n const isVisible = dropdownContent.style.display === 'block';\n dropdownContent.style.display = isVisible ? 'none' : 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (dropdownContent && dropdownContent.style.display === 'block') {\n if (!dropdownContent.contains(e.target as Node) && e.target !== burgerBtn)\n dropdownContent.style.display = 'none';\n }\n });\n\n document.getElementById('sport-filter-container')?.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const btn = target.closest('[data-sport]');\n if (btn) {\n const selectedSport = (btn as HTMLElement).dataset.sport || null;\n filters.sport = filters.sport === selectedSport ? null : selectedSport;\n applyFilters();\n syncFiltersToUrl();\n updateFilterUI();\n\n if (target.closest('.dropdown-item')) {\n if (dropdownContent) dropdownContent.style.display = 'none';\n }\n }\n });\n\n document.getElementById('filter-metrics')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.mini-pill') as HTMLElement;\n if (!btn) return;\n const m = btn.dataset.metric!;\n if (filters.metrics.has(m)) filters.metrics.delete(m);\n else filters.metrics.add(m);\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('btn-reset-filters')?.addEventListener('click', () => {\n filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n };\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('filter-tags')?.addEventListener('input', (e) => {\n const val = (e.target as HTMLInputElement).value;\n filters.tags = val\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => !!s);\n applyFilters();\n syncFiltersToUrl();\n });\n\n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n MapView.hideCursor();\n MapView.closePopup?.();\n // Dismiss popups and modals\n document\n .querySelectorAll(\n '.color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop',\n )\n .forEach((el) => el.remove());\n }\n });\n\n // Resize charts when window changes\n window.addEventListener('resize', () => {\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n updateToolbarLayout();\n });\n\n // Handle back/forward navigation\n window.addEventListener('popstate', () => {\n UrlState.refresh();\n applyState(UrlState.get());\n });\n\n initBenchmarkTriggers();\n await preloadBenchmarkFiles();\n\n // Signal to Speedometer test harness that asynchronous initialization has completed\n // and benchmark step triggers are bound.\n const readyEl = document.createElement('div');\n readyEl.id = 'app-is-ready';\n readyEl.setAttribute('data-ready', 'true');\n readyEl.style.display = 'none';\n document.body.appendChild(readyEl);\n\n const camelReadyEl = document.createElement('div');\n camelReadyEl.id = 'appIsReady';\n camelReadyEl.setAttribute('data-ready', 'true');\n camelReadyEl.style.display = 'none';\n document.body.appendChild(camelReadyEl);\n}\n\nlet preloadedBenchmarkPayloads:\n | {\n cleanName: string;\n buf: ArrayBuffer;\n text?: string;\n file: File;\n }[]\n | null = null;\n\nasync function preloadBenchmarkFiles(): Promise<\n { cleanName: string; buf: ArrayBuffer; text?: string; file: File }[]\n> {\n if (preloadedBenchmarkPayloads) return preloadedBenchmarkPayloads;\n try {\n const manifestResp = await fetch('./test-data/manifest.json');\n const fileNames: string[] = await manifestResp.json();\n const decoder = new TextDecoder();\n preloadedBenchmarkPayloads = await Promise.all(\n fileNames.map(async (name) => {\n const fileResp = await fetch(`./test-data/${name}`);\n let buf = await fileResp.arrayBuffer();\n let cleanName = name;\n if (name.toLowerCase().endsWith('.gz')) {\n cleanName = name.slice(0, -3);\n const bytes = new Uint8Array(buf);\n if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) {\n const ds = new DecompressionStream('gzip');\n const stream = new Blob([buf]).stream().pipeThrough(ds);\n buf = await new Response(stream).arrayBuffer();\n }\n }\n const text = cleanName.toLowerCase().endsWith('.fit') ? undefined : decoder.decode(buf);\n const file = new File([buf], cleanName, { type: 'application/octet-stream' });\n (file as any)._buf = buf;\n if (text !== undefined) (file as any)._text = text;\n return { cleanName, buf, text, file };\n }),\n );\n // Warm up GPX, TCX, and FIT parser and chart code paths during prepare phase\n let warmSample: any = null;\n for (const idx of [0, 2, 4]) {\n if (preloadedBenchmarkPayloads[idx]) {\n const parsed = await Parsers.parseFile(preloadedBenchmarkPayloads[idx].file);\n if (idx === 0) warmSample = parsed;\n }\n }\n if (warmSample) {\n const warmPts = warmSample.points.slice(0, 60);\n const warmTrack: TrackData = {\n ...warmSample,\n id: 'warmup',\n fileName: 'warmup.gpx',\n fileSize: 1024,\n points: warmPts,\n stats: Parsers.computeStats(warmPts),\n addedAt: 1785542400000,\n visible: true,\n color: TRACK_COLORS[0],\n };\n Parsers.ensureCurvesAndZones(warmTrack);\n ChartView.loadTrack(warmTrack, [warmTrack], false);\n ChartView.setActiveMetrics(['elevation', 'speed', 'power']);\n renderInsights(warmTrack);\n renderEvolution(warmTrack, [warmTrack]);\n await resetBenchmarkState();\n void document.body.offsetHeight;\n await new Promise((r) => window.setTimeout(r, 0));\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n return preloadedBenchmarkPayloads;\n } catch {\n return [];\n }\n}\n\nfunction initBenchmarkTriggers() {\n const btnLoad = document.getElementById('btn-step-load');\n const btnAnalysis = document.getElementById('btn-step-analysis');\n const btnInsights = document.getElementById('btn-step-insights');\n const btnDetails = document.getElementById('btn-step-details');\n const btnAggregate = document.getElementById('btn-step-aggregate');\n const btnEvolution = document.getElementById('btn-step-evolution');\n const btnCourses = document.getElementById('btn-step-courses');\n\n function activateTab(tabName: string) {\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === tabName);\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${tabName}`);\n });\n UrlState.patch({ tab: tabName }, false);\n }\n\n btnLoad?.addEventListener('click', async () => {\n try {\n if (Object.keys(tracks).length > 0 || skippedImports.length > 0 || selectedId !== null) {\n await Storage.openDB();\n await resetBenchmarkState();\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n const payloads = await preloadBenchmarkFiles();\n const loadedFiles: File[] = payloads.map((p) => p.file);\n await handleFiles(loadedFiles);\n const allTracks = Object.values(tracks);\n if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id);\n } finally {\n window.dispatchEvent(new CustomEvent('load-and-parse-complete'));\n }\n });\n\n btnAnalysis?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('graphs');\n if (!selectedId && allTracks.length > 0) {\n selectTrack(allTracks[0].id);\n }\n ChartView.restoreSelection(120, 900, true);\n ChartView.setCursorAt(300, true);\n const availableMetrics = ChartView.getAvailableMetrics();\n const analysisMetrics = ['elevation', 'speed', 'power'].filter((m) =>\n availableMetrics.has(m),\n );\n if (analysisMetrics.length > 0) {\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const metric = (el as HTMLElement).dataset.metric;\n if (metric) el.classList.toggle('active', analysisMetrics.includes(metric));\n });\n updateToolbarLayout();\n ChartView.setActiveMetrics(analysisMetrics);\n } else {\n updateToolbarLayout();\n }\n onChartRangeChange(120, 900, ChartView.getXAxis(), false);\n } finally {\n window.dispatchEvent(new CustomEvent('analysis-complete'));\n }\n });\n\n btnInsights?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t));\n activateTab('insights');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderInsights(primaryTrack);\n } finally {\n window.dispatchEvent(new CustomEvent('insights-complete'));\n }\n });\n\n btnDetails?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('details');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderDetails(primaryTrack, getGlobalTags());\n } finally {\n window.dispatchEvent(new CustomEvent('details-complete'));\n }\n });\n\n btnAggregate?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n if (allTracks.length >= 2) {\n const selectedTwo = [allTracks[0], allTracks[1]];\n activateTab('combined');\n renderCombined(selectedTwo);\n resizeCombined();\n }\n } finally {\n window.dispatchEvent(new CustomEvent('aggregate-complete'));\n }\n });\n\n btnEvolution?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('evolution');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderEvolution(primaryTrack, allTracks, (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n } finally {\n window.dispatchEvent(new CustomEvent('evolution-complete'));\n }\n });\n\n btnCourses?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('courses');\n prepareBenchmarkCourses(allTracks);\n renderCourses();\n selectCourse('course-1', true);\n } finally {\n window.dispatchEvent(new CustomEvent('courses-complete'));\n }\n });\n\n (window as any).benchmarkSteps = {\n loadAndParseFiles: () => document.getElementById('btn-step-load')?.click(),\n displayAnalysisMetrics: () => document.getElementById('btn-step-analysis')?.click(),\n displayInsights: () => document.getElementById('btn-step-insights')?.click(),\n displayDetails: () => document.getElementById('btn-step-details')?.click(),\n displayAggregateMetrics: () => document.getElementById('btn-step-aggregate')?.click(),\n displayEvolutionMetrics: () => document.getElementById('btn-step-evolution')?.click(),\n displayCourses: () => document.getElementById('btn-step-courses')?.click(),\n };\n}\n\nasync function processAndLoadTrack(t: TrackData) {\n // Migration: re-calculate stats if new insights are missing or old format\n const powerCurveEntries = t.stats.powerCurve ? Object.values(t.stats.powerCurve) : [];\n\n const needsEnrich =\n t.points.length > 1 && (t.points[1].speed === undefined || t.points[1].gradient === undefined);\n\n const needsRecalc =\n needsEnrich ||\n !t.stats.powerCurve ||\n !t.stats.hrZones ||\n !t.stats.hrCurve ||\n t.stats.shifts === undefined ||\n t.stats.avgBattery === undefined ||\n t.stats.avgTemp === undefined ||\n (powerCurveEntries.length > 0 && typeof (powerCurveEntries[0] as any) === 'number') ||\n ((t.stats.duration || 0) > 10800 * 1000 && t.stats.powerCurve && !t.stats.powerCurve[14400]);\n\n if (needsRecalc) {\n if (needsEnrich) t.points = Parsers.enrichPoints(t.points);\n t.stats = Parsers.computeStats(t.points);\n await Storage.save(t);\n }\n\n tracks[t.id] = t;\n colorIdx = Math.max(colorIdx, TRACK_COLORS.indexOf(t.color) + 1);\n MapView.addTrack(t);\n MapView.setTrackVisible(t.id, t.visible && !t._filtered);\n renderTrackList(); // Progressive list update\n}\n\nfunction initResizeHandle() {\n const handle = document.getElementById('resize-handle');\n const panel = document.getElementById('chart-panel');\n if (!handle || !panel) return;\n\n let isDragging = false;\n\n handle.addEventListener('mousedown', () => {\n isDragging = true;\n document.body.style.cursor = 'ns-resize';\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const h = window.innerHeight - e.clientY;\n const clampedH = Math.max(100, Math.min(window.innerHeight - 100, h));\n panel.style.height = `${clampedH}px`;\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n document.body.style.cursor = '';\n });\n}\n\nfunction initSidebarResizer() {\n const resizer = document.getElementById('sidebar-resizer');\n const sidebar = document.getElementById('sidebar');\n if (!resizer || !sidebar) return;\n\n let isDragging = false;\n\n resizer.addEventListener('mousedown', () => {\n isDragging = true;\n resizer.classList.add('dragging');\n document.body.classList.add('dragging-sidebar');\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const w = e.clientX;\n const clampedW = Math.max(200, Math.min(600, w));\n sidebar.style.width = `${clampedW}px`;\n sidebar.style.setProperty('--sidebar-w', `${clampedW}px`);\n ChartView.resize();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n resizer.classList.remove('dragging');\n document.body.classList.remove('dragging-sidebar');\n });\n}\n\n// \u2500\u2500 Event Handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction onMapMove(lat: number, lng: number, zoom: number) {\n UrlState.patch({ map_pos: [lat, lng, zoom] });\n}\n\nfunction onMapPointClick(id: string, idx: number) {\n selectTrack(id, false);\n ChartView.setCursorAt(idx);\n}\n\nfunction onMapDblClick() {\n // MapView.fitAll();\n}\n\nfunction onChartCursorMove(pt: TrackPoint | null) {\n if (pt && pt.lat != null && pt.lon != null) {\n MapView.showCursorAt(pt.lat, pt.lon);\n if (followDot) MapView.centerOn(pt.lat, pt.lon, null, true);\n } else {\n MapView.hideCursor();\n }\n}\n\nfunction onChartRangeChange(min: number | null, max: number | null, axis: string, fit = false) {\n if (!selectedId || !tracks[selectedId]) return;\n const t = tracks[selectedId];\n\n if (min === null || max === null) {\n MapView.clearHighlight();\n if (t && (UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n UrlState.patch({ sel: null });\n return;\n }\n\n // Find point indices\n const pts = t.points;\n let iMin = 0,\n iMax = pts.length - 1;\n\n if (axis === 'distance') {\n const d0 = min * 1000,\n d1 = max * 1000;\n iMin = pts.findIndex((p) => (p.dist || 0) >= d0);\n iMax = pts.findIndex((p) => (p.dist || 0) >= d1);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const ts0 = t0 + min * 1000,\n ts1 = t0 + max * 1000;\n iMin = pts.findIndex((p) => (p.time || 0) >= ts0);\n iMax = pts.findIndex((p) => (p.time || 0) >= ts1);\n }\n\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = pts.length - 1;\n\n // Compute selection stats\n const selPts = pts.slice(iMin, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n if ((UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n\n MapView.highlightSegment(selectedId, pts, iMin, iMax, fit, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n UrlState.patch({ sel: [min, max] });\n}\n\nfunction onChartClick(pt: TrackPoint, idx: number) {\n if (pt && pt.lat != null && pt.lon != null) MapView.centerOn(pt.lat, pt.lon, POINT_ZOOM_LEVEL);\n}\n\nexport function selectTrack(id: string, fit = true, deferChartRender = false) {\n if (!tracks[id]) return;\n if (id === selectedId) {\n if (fit) MapView.fitTrack(id);\n return;\n }\n\n const hadSelected = selectedId !== null;\n if (hadSelected) {\n // Clear current views immediately before loading new data\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n }\n\n selectedId = id;\n\n // Fully reset metric coloring when switching tracks\n currentMapColors = null;\n MapView.clearMetricColor(id);\n if (hadSelected) {\n ChartView.toggleMapColor(null); // Ensure ChartView state also resets\n }\n\n // Clear selection on new track\n UrlState.patch({ track: id, sel: null }, true);\n if (hadSelected) {\n ChartView.cancelSelection();\n }\n\n // Update UI immediately\n renderTrackList();\n\n // Render details\n const activeTab = UrlState.get().tab || 'graphs';\n if (activeTab === 'details') renderDetails(tracks[id], getGlobalTags());\n if (activeTab === 'insights') renderInsights(tracks[id]);\n if (activeTab === 'combined') renderCombined(tracks[id]);\n if (activeTab === 'courses') renderCourses();\n if (activeTab === 'evolution') {\n renderEvolution(tracks[id], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n\n // Tell sub-views\n MapView.setSelectedTrack(id, fit);\n if (fit) MapView.fitTrack(id);\n ChartView.loadTrack(tracks[id], Object.values(tracks), deferChartRender);\n}\n\nasync function deleteTrack(id: string) {\n await Storage.remove(id);\n MapView.removeTrack(id);\n delete tracks[id];\n if (selectedId === id) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n UrlState.patch({ track: null, sel: null, sel_point: null });\n }\n applyFilters();\n}\n\nasync function clearAll() {\n const code = Math.floor(10 + Math.random() * 90).toString();\n\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n backdrop.innerHTML = `\n
\n
Delete all tracks?
\n
\n This will permanently remove all tracks from your browser storage. This action cannot be undone.\n
\n
\n
Enter \"${code}\" to confirm:
\n \n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const input = backdrop.querySelector('.modal-input') as HTMLInputElement;\n const btnConfirm = backdrop.querySelector('.modal-btn.confirm') as HTMLButtonElement;\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n\n input.focus();\n\n input.addEventListener('input', () => {\n btnConfirm.disabled = input.value !== code;\n });\n\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n\n btnConfirm.addEventListener('click', async () => {\n if (input.value !== code) return;\n close();\n\n cancelProcessing = true;\n await Storage.clear();\n\n tracks = {};\n selectedId = null;\n MapView.clearHighlight();\n window.location.reload();\n });\n}\n\nfunction applyFilters(skipRender = false) {\n const ids = Object.keys(tracks);\n ids.forEach((id) => {\n const t = tracks[id];\n const s = t.stats;\n let visible = true;\n\n // Search query\n if (searchQuery) {\n if (searchRegex) {\n try {\n const re = new RegExp(searchQuery, 'i');\n if (!re.test(t.name)) visible = false;\n } catch (e) {\n visible = false;\n }\n } else {\n if (!t.name.toLowerCase().includes(searchQuery.toLowerCase())) visible = false;\n }\n }\n\n // Date filter\n if (visible && (filters.date[0] || filters.date[1])) {\n const start = filters.date[0] ? new Date(filters.date[0]).getTime() : 0;\n const end = filters.date[1] ? new Date(filters.date[1]).getTime() : Infinity;\n const t0 = s.startTime || 0;\n if (t0 < start || t0 > end) visible = false;\n }\n\n // Distance filter\n if (visible && (filters.dist[0] !== null || filters.dist[1] !== null)) {\n const min = (filters.dist[0] || 0) * 1000;\n const max = (filters.dist[1] || Infinity) * 1000;\n if (s.totalDist < min || s.totalDist > max) visible = false;\n }\n\n // Duration filter\n if (visible && (filters.dur[0] !== null || filters.dur[1] !== null)) {\n const min = (filters.dur[0] || 0) * 60000;\n const max = (filters.dur[1] || Infinity) * 60000;\n const d = s.duration || 0;\n if (d < min || d > max) visible = false;\n }\n\n // Metrics filter\n if (visible && filters.metrics.size > 0) {\n for (const m of filters.metrics) {\n const field = ChartView.METRICS[m].field;\n if (!t.points.some((p: any) => p[field] != null)) {\n visible = false;\n break;\n }\n }\n }\n\n // Sport filter\n if (visible && filters.sport) {\n if (t.sport !== filters.sport) visible = false;\n }\n\n // Tags filter\n if (visible && filters.tags.length > 0) {\n const trackTags = t.tags || [];\n if (!filters.tags.every((ft) => trackTags.includes(ft))) visible = false;\n }\n\n t._filtered = !visible;\n MapView.setTrackVisible(t.id, t.visible && visible);\n });\n\n if (!skipRender) renderTrackList();\n}\n\nfunction updateFilterUI() {\n (document.getElementById('filter-date-start') as HTMLInputElement).value = filters.date[0] || '';\n (document.getElementById('filter-date-end') as HTMLInputElement).value = filters.date[1] || '';\n (document.getElementById('filter-dist-min') as HTMLInputElement).value =\n filters.dist[0] !== null ? String(filters.dist[0]) : '';\n (document.getElementById('filter-dist-max') as HTMLInputElement).value =\n filters.dist[1] !== null ? String(filters.dist[1]) : '';\n (document.getElementById('filter-dur-min') as HTMLInputElement).value =\n filters.dur[0] !== null ? String(filters.dur[0]) : '';\n (document.getElementById('filter-dur-max') as HTMLInputElement).value =\n filters.dur[1] !== null ? String(filters.dur[1]) : '';\n (document.getElementById('filter-tags') as HTMLInputElement).value = filters.tags.join(', ');\n\n document\n .querySelectorAll('#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item')\n .forEach((el) => {\n const item = el as HTMLElement;\n item.classList.toggle('active', (item.dataset.sport || '') === (filters.sport || ''));\n });\n\n document.querySelectorAll('#filter-metrics .mini-pill').forEach((el) => {\n const btn = el as HTMLElement;\n btn.classList.toggle('active', filters.metrics.has(btn.dataset.metric!));\n });\n\n const activeCount =\n (filters.date[0] ? 1 : 0) +\n (filters.date[1] ? 1 : 0) +\n (filters.dist[0] !== null ? 1 : 0) +\n (filters.dist[1] !== null ? 1 : 0) +\n (filters.dur[0] !== null ? 1 : 0) +\n (filters.dur[1] !== null ? 1 : 0) +\n filters.metrics.size +\n (filters.tags.length > 0 ? 1 : 0);\n\n const badge = document.querySelector('#btn-toggle-filters .btn-badge');\n if (badge) {\n badge.textContent = activeCount > 0 ? String(activeCount) : '';\n badge.classList.toggle('hidden', activeCount === 0);\n }\n}\n\nfunction updateSearchSortUI() {\n const searchInput = document.getElementById('track-search') as HTMLInputElement;\n if (searchInput) searchInput.value = searchQuery;\n document.getElementById('btn-regex-toggle')?.classList.toggle('active', searchRegex);\n\n const opt = SORT_OPTIONS.find((o) => o.val === currentSort);\n if (opt) {\n const labelEl = document.getElementById('sort-current-label');\n const iconEl = document.getElementById('sort-current-icon');\n if (labelEl)\n labelEl.textContent = opt.label\n .replace(' first', '')\n .replace(' distance', '')\n .replace(' duration', '');\n if (iconEl) iconEl.textContent = opt.icon;\n }\n}\n\nfunction applyState(urlState: AppState) {\n // Restore track\n const newTrackId = urlState.track;\n if (newTrackId !== selectedId) {\n if (newTrackId && tracks[newTrackId]) {\n selectTrack(newTrackId, true);\n } else if (!newTrackId && selectedId) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n renderTrackList();\n MapView.fitAll();\n }\n }\n\n // Restore basemap\n if (urlState.map && typeof urlState.map === 'string') {\n MapView.switchBasemap(urlState.map);\n document\n .querySelectorAll('.bm-btn')\n .forEach((b) =>\n b.classList.toggle('active', (b as HTMLElement).dataset.layer === urlState.map),\n );\n }\n\n // Restore map position\n if (urlState.map_pos) {\n const [lat, lng, zoom] = urlState.map_pos;\n MapView.setPosition(lat, lng, zoom);\n }\n\n // Restore tab\n if (urlState.tab) {\n document.querySelectorAll('.tab-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n if (b.dataset.tab === urlState.tab) {\n if (!b.classList.contains('active')) b.click();\n }\n });\n }\n\n // Restore x-axis mode\n if (urlState.xaxis) ChartView.setXAxis(urlState.xaxis);\n\n const currentXAxis = urlState.xaxis || 'time';\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', (b as HTMLElement).dataset.axis === currentXAxis));\n\n // Restore active metrics\n if (urlState.metrics) {\n const metrics = ChartView.METRICS;\n const keys = urlState.metrics\n .map((abbr) => Object.keys(metrics).find((k) => metrics[k].abbr === abbr))\n .filter((k): k is string => k !== undefined);\n if (keys.length) ChartView.setActiveMetrics(keys);\n }\n\n // Restore filters\n if (urlState.f_date)\n filters.date = urlState.f_date.map((v) => v || null) as [string | null, string | null];\n if (urlState.f_dist)\n filters.dist = urlState.f_dist.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_dur)\n filters.dur = urlState.f_dur.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_mets) filters.metrics = new Set(urlState.f_mets);\n if (urlState.f_tags) filters.tags = urlState.f_tags;\n\n updateFilterUI();\n\n if (urlState.q) searchQuery = urlState.q;\n if (urlState.re) searchRegex = urlState.re;\n if (urlState.sort) currentSort = urlState.sort;\n updateSearchSortUI();\n\n applyFilters();\n}\n\nfunction updateSportFilterOptions() {\n const container = document.getElementById('sport-filter-container');\n if (!container) return;\n\n const commonContainer = document.getElementById('common-sports');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n if (!commonContainer || !dropdownContent) return;\n\n const sports = new Set();\n Object.values(tracks).forEach((t) => {\n if (t.sport) sports.add(t.sport);\n });\n\n const sportsArray = Array.from(sports).sort();\n const burgerDropdown = document.getElementById('sport-burger-dropdown');\n\n commonContainer.innerHTML = '';\n dropdownContent.innerHTML = '';\n\n if (sportsArray.length <= 4) {\n if (burgerDropdown) burgerDropdown.style.display = 'none';\n\n sportsArray.forEach((sport) => {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n });\n } else {\n if (burgerDropdown) burgerDropdown.style.display = 'inline-block';\n\n const commonSports = ['running', 'cycling', 'walking'];\n\n commonSports.forEach((sport) => {\n if (sports.has(sport)) {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n }\n });\n\n sportsArray.forEach((sport) => {\n const item = document.createElement('div');\n item.className = `dropdown-item${filters.sport === sport ? ' active' : ''}`;\n item.dataset.sport = sport;\n item.style.padding = '8px';\n item.style.cursor = 'pointer';\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '8px';\n item.innerHTML = `\n ${getSportIcon(sport)}\n ${sport.charAt(0).toUpperCase() + sport.slice(1)}\n `;\n dropdownContent.appendChild(item);\n });\n }\n}\n\nfunction renderTrackList() {\n updateSportFilterOptions();\n const list = document.getElementById('track-list');\n const emptyEl = document.getElementById('track-list-empty') as HTMLElement;\n const headerLabel = document.querySelector('.section-label');\n if (!list) return;\n\n const ids = Object.keys(tracks).filter((id) => !tracks[id]._filtered);\n if (headerLabel) headerLabel.textContent = `Tracks (${ids.length})`;\n\n if (!ids.length) {\n list.innerHTML = '';\n if (emptyEl) {\n list.appendChild(emptyEl);\n emptyEl.style.display = 'block';\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n list.innerHTML = '';\n\n ids\n .sort((a, b) => {\n // Current selected always first\n if (a === selectedId) return -1;\n if (b === selectedId) return 1;\n\n const ta = tracks[a],\n tb = tracks[b];\n const sa = ta.stats,\n sb = tb.stats;\n\n let cmp = 0;\n switch (currentSort) {\n case 'date-asc':\n cmp = (sa.startTime || 0) - (sb.startTime || 0);\n break;\n case 'date-desc':\n cmp = (sb.startTime || 0) - (sa.startTime || 0);\n break;\n case 'dist-asc':\n cmp = (sa.totalDist || 0) - (sb.totalDist || 0);\n break;\n case 'dist-desc':\n cmp = (sb.totalDist || 0) - (sa.totalDist || 0);\n break;\n case 'dur-asc':\n cmp = (sa.duration || 0) - (sb.duration || 0);\n break;\n case 'dur-desc':\n cmp = (sb.duration || 0) - (sa.duration || 0);\n break;\n default:\n cmp = 0;\n }\n return cmp || a.localeCompare(b);\n })\n .forEach((id) => {\n list.appendChild(buildTrackItem(tracks[id]));\n });\n}\n\nfunction getGlobalTags(): string[] {\n const all = new Set();\n Object.values(tracks).forEach((t) => {\n (t.tags || []).forEach((tag) => all.add(tag));\n });\n return Array.from(all).sort();\n}\n\nfunction getSportIcon(sport: string | null): string {\n if (!sport) return 'category';\n const s = sport.toLowerCase();\n if (s.includes('run')) return 'directions_run';\n if (s.includes('cycl') || s.includes('bike')) return 'directions_bike';\n if (s.includes('walk')) return 'directions_walk';\n if (s.includes('swim')) return 'pool';\n if (s.includes('hik')) return 'hiking';\n return 'sports';\n}\n\nfunction buildTrackItem(track: TrackData) {\n const item = document.createElement('div');\n item.className = `track-item${track.id === selectedId ? ' selected' : ''}`;\n item.dataset.id = track.id;\n\n const date =\n track.points.length && track.points[0].time ? fmtDate(track.points[0].time) : 'Unknown date';\n\n const tagsHtml =\n (track.tags || []).length > 0\n ? `
${(track.tags || [])\n .map((t) => {\n const c = getTagColor(t);\n return `${escHtml(t)}`;\n })\n .join('')}
`\n : '';\n\n item.innerHTML = `\n
\n
\n
${escHtml(track.displayName || track.name)}
\n
\n
\n ${date}\n ${Math.round(track.stats.totalDist / 1000)} km\n ${track.sport ? `${getSportIcon(track.sport)}` : ''}\n ${track.format.toUpperCase()}\n
\n \n
\n ${tagsHtml}\n
\n `;\n\n item.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.icon-btn')) return;\n selectTrack(track.id);\n });\n\n const btnVis = item.querySelector('.toggle-vis') as HTMLElement;\n btnVis.addEventListener('click', () => {\n track.visible = !track.visible;\n btnVis.querySelector('.material-symbols-rounded')!.textContent = track.visible\n ? 'visibility'\n : 'visibility_off';\n MapView.setTrackVisible(track.id, track.visible);\n Storage.save(track);\n });\n\n return item;\n}\n\nfunction showToast(msg: string, type: 'info' | 'error' = 'info') {\n const container = document.getElementById('toast-container');\n if (!container) return;\n container.innerHTML = '';\n const t = document.createElement('div');\n t.className = `toast ${type}`;\n t.textContent = msg;\n container.appendChild(t);\n}\n\nfunction showSkippedImportsModal() {\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n let listHtml = '';\n skippedImports.forEach((s) => {\n listHtml += `
${s.name}: ${s.reason}
`;\n });\n\n backdrop.innerHTML = `\n
\n
Skipped Imports
\n
\n ${listHtml || '
No skipped imports.
'}\n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n const btnClear = backdrop.querySelector('.modal-btn.clear') as HTMLButtonElement;\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n btnClear.addEventListener('click', () => {\n skippedImports = [];\n close();\n const importWarning = document.getElementById('import-warning');\n if (importWarning) importWarning.classList.add('hidden');\n });\n\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n}\n\nfunction initDropZone() {\n const zone = document.getElementById('drop-zone');\n if (!zone) return;\n\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n importWarning.addEventListener('click', (e) => {\n e.stopPropagation();\n showSkippedImportsModal();\n });\n }\n\n window.addEventListener('dragover', (e) => {\n e.preventDefault();\n zone.classList.add('drop-active');\n });\n\n window.addEventListener('dragleave', (e) => {\n if (e.relatedTarget === null) zone.classList.remove('drop-active');\n });\n\n window.addEventListener('drop', async (e) => {\n e.preventDefault();\n zone.classList.remove('drop-active');\n\n const items = e.dataTransfer?.items;\n if (!items) return;\n\n const files: File[] = [];\n const queue: FileSystemEntry[] = [];\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i].webkitGetAsEntry();\n if (entry) queue.push(entry);\n }\n\n async function readAllEntries(entry: FileSystemEntry) {\n if (entry.isFile) {\n const file = await new Promise((res) => (entry as FileSystemFileEntry).file(res));\n files.push(file);\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n let entries: FileSystemEntry[] = [];\n let chunk: FileSystemEntry[];\n do {\n chunk = await new Promise((res) => reader.readEntries(res));\n entries.push(...chunk);\n } while (chunk.length > 0);\n\n for (const child of entries) await readAllEntries(child);\n }\n }\n\n for (const entry of queue) await readAllEntries(entry);\n\n if (files.length) handleFiles(files);\n });\n}\n\nasync function handleFiles(files: File[]) {\n if (!files.length) return;\n cancelProcessing = false;\n const initialSkipCount = skippedImports.length;\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const loaderClose = document.getElementById('loader-close');\n\n if (loaderClose) {\n loaderClose.addEventListener('click', () => {\n cancelProcessing = true;\n if (loader) loader.classList.add('hidden');\n });\n }\n\n function updateLoaderIconToWarning() {\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'warning';\n loaderIcon.style.color = '#f59e0b';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n const count = skippedImports.length - initialSkipCount;\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = `${count}`;\n warningCount.style.display = 'flex';\n }\n }\n\n if (loader) {\n if (loaderText)\n loaderText.textContent = `Importing ${files.length} file${files.length > 1 ? 's' : ''}`;\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'download';\n loaderIcon.style.color = 'var(--accent)';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n warningCount.style.display = 'none';\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = '0';\n }\n if (loaderSubtext) loaderSubtext.textContent = '';\n if (progressBar) progressBar.style.width = '0%';\n loader.classList.remove('hidden');\n\n if (skippedImports.length > initialSkipCount) updateLoaderIconToWarning();\n }\n\n try {\n let count = 0;\n let firstId: string | null = null;\n let processedSinceLastUpdate = 0;\n\n // Filter out obviously invalid files early\n const validFiles = files.filter((f) => {\n const name = f.name.toLowerCase();\n return (\n name.endsWith('.gpx') ||\n name.endsWith('.fit') ||\n name.endsWith('.tcx') ||\n name.endsWith('.kml')\n );\n });\n\n const invalidFiles = files.filter((f) => !validFiles.includes(f));\n invalidFiles.forEach((f) => {\n skippedImports.push({ name: f.name, reason: 'Unsupported file format' });\n });\n\n if (validFiles.length === 0) {\n if (files.length > 0) {\n showToast('No valid GPS files found', 'error');\n // Still update warning icon if there were invalid files!\n const importWarning = document.getElementById('import-warning');\n if (importWarning && skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n }\n }\n return;\n }\n\n const loaderFilename = document.getElementById('loader-filename');\n let progressIdxEl: HTMLElement | null = null;\n if (loaderSubtext) {\n loaderSubtext.innerHTML =\n '';\n progressIdxEl = loaderSubtext.querySelector('.progress-index') as HTMLElement | null;\n const totalEl = loaderSubtext.querySelector('.progress-total');\n if (totalEl) totalEl.textContent = validFiles.length.toString();\n }\n\n for (let i = 0; i < validFiles.length; i++) {\n if (cancelProcessing) break;\n const f = validFiles[i];\n if (loaderFilename) loaderFilename.textContent = f.name;\n if (progressIdxEl) progressIdxEl.textContent = (i + 1).toString();\n if (progressBar) progressBar.style.width = `${(i / validFiles.length) * 100}%`;\n\n try {\n const data = await Parsers.parseFile(f);\n\n // Duplicate checks\n const existingTracks = Object.values(tracks);\n\n // Rule 1: Same file and same size\n const sameFile = existingTracks.find((t) => t.fileName === f.name && t.fileSize === f.size);\n if (sameFile) {\n skippedImports.push({ name: f.name, reason: 'Same File' });\n updateLoaderIconToWarning();\n continue;\n }\n\n // Rule 2 & 3: Same start day checks\n const newStart = data.stats.startTime;\n const newDuration = data.stats.duration;\n\n if (newStart != null && newDuration != null) {\n const newEnd = newStart + newDuration;\n const sameDayTracks = existingTracks.filter(\n (t) => t.stats.startTime != null && isSameDay(newStart, t.stats.startTime!),\n );\n\n let discarded = false;\n for (const ext of sameDayTracks) {\n const extStart = ext.stats.startTime!;\n const extDuration = ext.stats.duration!;\n const extEnd = extStart + extDuration;\n\n // Rule 2: Fully contained\n if (newStart >= extStart && newEnd <= extEnd) {\n skippedImports.push({ name: f.name, reason: 'Fully contained in another track' });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n\n // Rule 3: Overlaps for > 10 mins\n const overlap = Math.min(newEnd, extEnd) - Math.max(newStart, extStart);\n if (overlap > 600000) {\n // 10 mins in ms\n skippedImports.push({\n name: f.name,\n reason: 'Overlaps with an existing track for more than 10 mins',\n });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n }\n if (discarded) continue;\n }\n\n const fallbackTime = 1785542400000;\n let id = compactId(data.stats.startTime || fallbackTime);\n if (tracks[id]) id += `-${shortRandom()}`;\n\n // Use filename as activity name if internal name is generic\n let trackName = data.name;\n if (trackName.startsWith('Unnamed') || trackName.startsWith('Fit Activity'))\n trackName = f.name;\n\n // Generate a nice display name\n let displayName = trackName;\n const t0 = data.points[0]?.time;\n const sport = data.sport\n ? data.sport.charAt(0).toUpperCase() + data.sport.slice(1)\n : 'Activity';\n if (t0) {\n const d = new Date(t0);\n displayName = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')} ${sport}`;\n } else {\n displayName = trackName.replace(/\\.[^/.]+$/, '').replace(/_/g, ' '); // Remove extension and replace underscores\n }\n\n const track: TrackData = {\n ...data,\n id,\n name: trackName,\n displayName,\n fileName: f.name,\n fileSize: f.size,\n bounds: calculateBounds(data.points) || undefined,\n simplifiedPoints: simplifyTrack(data.points, 50), // 50m resolution\n addedAt: data.stats.startTime || fallbackTime,\n visible: true,\n color: TRACK_COLORS[colorIdx % TRACK_COLORS.length],\n };\n colorIdx++;\n if (cancelProcessing) break;\n\n await Storage.save(track);\n tracks[id] = track;\n MapView.addTrack(track);\n if (!firstId) firstId = id;\n count++;\n processedSinceLastUpdate++;\n\n if (processedSinceLastUpdate >= 5) {\n processedSinceLastUpdate = 0;\n }\n } catch (err) {\n skippedImports.push({\n name: f.name,\n reason: `Parse error: ${err instanceof Error ? err.message : String(err)}`,\n });\n updateLoaderIconToWarning();\n }\n }\n\n // Update warning icon\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n if (skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n } else {\n importWarning.classList.add('hidden');\n }\n }\n\n const newWarnings = skippedImports.length > initialSkipCount;\n if (!newWarnings && loader) {\n loader.classList.add('hidden');\n }\n\n if (count > 0) {\n showToast(`Imported ${count} track${count > 1 ? 's' : ''}`);\n applyFilters(!!firstId && firstId !== selectedId);\n if (firstId) selectTrack(firstId);\n }\n\n if (newWarnings) {\n const loaderIcon = document.querySelector('.loader-icon-wrap span');\n if (loaderIcon) loaderIcon.textContent = 'warning';\n // Delay hiding loader to let user see the alert icon\n await new Promise((r) => setTimeout(r, 1500));\n }\n } finally {\n if (loader) loader.classList.add('hidden');\n }\n}\n\nfunction initMetricPillDraggable() {\n const container = document.getElementById('metric-pills');\n if (!container) return;\n\n let draggedEl: HTMLElement | null = null;\n\n container.addEventListener('dragstart', (e) => {\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (!target) return;\n draggedEl = target;\n e.dataTransfer!.effectAllowed = 'move';\n target.classList.add('dragging-pill');\n // For transparent background in ghost image\n setTimeout(() => (target.style.opacity = '0.4'), 0);\n });\n\n container.addEventListener('dragover', (e) => {\n e.preventDefault();\n e.dataTransfer!.dropEffect = 'move';\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (target && target !== draggedEl) {\n const rect = target.getBoundingClientRect();\n const next = e.clientX - rect.left > rect.width / 2;\n container.insertBefore(draggedEl!, next ? target.nextSibling : target);\n }\n });\n\n container.addEventListener('dragend', () => {\n if (!draggedEl) return;\n draggedEl.classList.remove('dragging-pill');\n draggedEl.style.opacity = '';\n draggedEl = null;\n\n // Update Chart order\n const keys = Array.from(container.querySelectorAll('.metric-pill')).map(\n (el) => (el as HTMLElement).dataset.metric!,\n );\n ChartView.updateMetricOrder(keys);\n syncMetricsToUrl();\n });\n}\n\nfunction updateToolbarLayout() {\n const toolbar = document.getElementById('chart-toolbar');\n const pills = document.getElementById('metric-pills');\n if (!toolbar || !pills) return;\n\n toolbar.classList.remove('collapsed');\n const availableW = Math.max(0, toolbar.clientWidth - 280);\n let totalW = 0;\n let hidden = false;\n\n Array.from(pills.children).forEach((el) => {\n const htmlEl = el as HTMLElement;\n if (htmlEl.id === 'pill-overflow') return;\n\n htmlEl.classList.remove('overflow-hidden');\n if (!htmlEl.classList.contains('active')) return;\n const metricKey = htmlEl.dataset.metric || '';\n const deterministicPillWidth = 36 + metricKey.length * 6;\n totalW += deterministicPillWidth + 6;\n\n if (totalW > availableW) {\n hidden = true;\n htmlEl.classList.add('overflow-hidden');\n }\n });\n\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.toggle('hidden', !hidden);\n\n if (hidden) toolbar.classList.add('collapsed');\n}\n\ndocument.addEventListener('DOMContentLoaded', init);\n"], - "mappings": "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", - "names": ["UrlState", "_state", "_lastSearch", "_syncTimeout", "_shouldPush", "read", "p", "s", "metricsRaw", "v", "isDesc", "field", "parts", "_sync", "dir", "search", "val", "url", "get", "patch", "partial", "push", "k", "key", "refresh", "reset", "InMemoryStorage", "track", "id", "key", "value", "IndexedDBStorage", "resolve", "reject", "req", "db", "name", "mode", "res", "rej", "tx", "activeDriver", "Storage", "UrlState", "t", "k", "v", "FitParser", "haversine", "lat1", "lon1", "lat2", "lon2", "phi1", "phi2", "deltaPhi", "deltaLambda", "a", "compactId", "timestamp", "buf", "shortRandom", "fmtDuration", "s", "fmtSecs", "h", "m", "fmtPace", "seconds", "mins", "secs", "fmtDate", "ts", "d", "fmtDateTime", "iso", "fmtFileSize", "bytes", "k", "sizes", "i", "escHtml", "str", "getTagColor", "name", "hash", "gaussianSmooth", "data", "sigma", "size", "kernel", "half", "sum", "x", "result", "val", "weightSum", "idx", "hexToRgba", "hex", "alpha", "r", "g", "b", "calculateBounds", "pts", "minLat", "maxLat", "minLon", "maxLon", "p", "simplifyTrack", "minDistanceMeters", "result", "lastPoint", "i", "haversine", "Parsers", "enrichPoints", "totalDist", "prev", "d", "dt", "de", "hrZoneThresholds", "ftp", "computeStats", "includeCurves", "stats", "powerSum", "powerN", "hrSum", "hrN", "cadSum", "cadN", "speedSum", "speedN", "batterySum", "batteryN", "tempSum", "tempN", "hasTemp", "shifts", "hasGears", "diff", "t0", "t1", "calculateHRZones", "calculateHRCurve", "calculatePowerCurve", "calculatePowerZones", "ensureCurvesAndZones", "track", "s", "STANDARD_CURVE_DURATIONS", "calculateSlidingMax", "data", "durations", "len", "prefix", "curve", "hasAny", "di", "maxSum", "bestIdx", "limit", "j", "currentSum", "powerData", "nonZero", "v", "hrData", "zones", "thresholds", "t", "pw", "z", "setFTP", "val", "getFTP", "hr", "setHRZones", "getHRZones", "extractXmlTag", "block", "openTag", "closeTag", "start", "extractXmlAttr", "tagOpen", "attrPrefix", "cachedDateKey", "cachedDayMs", "parseIntSlice", "text", "end", "neg", "c0", "digits", "c", "parseFloatSlice", "intPart", "fracPart", "fracDiv", "inFrac", "n", "res", "fastParseTimeSlice", "y", "m", "key", "hh", "mm", "ss", "ms", "extractAttrFloat", "vStart", "parseGPX", "buf", "predecodedText", "firstTrkpt", "header", "trkIdx", "name", "gpxOpenEnd", "device", "points", "pos", "trkStart", "openEnd", "trkEnd", "lat", "lon", "ele", "time", "cad", "power", "temp", "speed", "gearFront", "gearRear", "gearFrontTooth", "gearRearTooth", "battery", "lt", "gt", "c1", "tagLen", "nextLt", "vEnd", "expectedCloseGt", "closeGt", "gears", "parseTCX", "firstTp", "creatorBlock", "tpStart", "tpEnd", "fastDecodeFitData", "dv", "headerSize", "dataSize", "endOffset", "GARMIN_EPOCH_SEC", "SEMICIRCLE_TO_DEG", "defs", "file_ids", "sessions", "records", "events", "device_infos", "offset", "hdr", "localNum", "littleEndian", "globalMsgNum", "numFields", "fields", "recordSize", "num", "size", "type", "def", "le", "gNum", "ts", "rawLat", "rawLon", "rawAlt", "rawDist", "rawSpd", "msg", "fOff", "f", "bType", "sportMap", "evName", "parseFIT", "resolve", "reject", "handleParsedFitData", "error", "devices", "sport", "subSport", "getDeviceName", "fid", "antId", "existing", "statusReports", "idx", "a", "b", "gearEvents", "e", "front", "rear", "frontTooth", "rearTooth", "ft", "fg", "rt", "rg", "lastBattery", "statusIdx", "lastFrontGear", "lastRearGear", "lastFrontTooth", "lastRearTooth", "gearIdx", "validPoints", "ri", "r", "ex", "fastData", "FitParser", "parseKML", "doc", "nameEl", "coordEls", "el", "line", "parts", "parseFile", "file", "ext", "MapView", "trackData", "customClickHandler", "init", "onSelectCb", "onMoveCb", "onPointClickCb", "onPointHoverCb", "onDblClickCb", "switchBasemap", "layer", "addTrack", "t", "addTracks", "ts", "removeTrack", "id", "clearTracks", "removeAllTracks", "setTrackVisible", "visible", "setSelectedTrack", "fit", "fitAll", "fitTrack", "showCursorAt", "lat", "lon", "hideCursor", "highlightSegment", "pts", "start", "end", "colors", "clearHighlight", "setTrackHover", "hover", "ensureVisible", "centerOn", "zoom", "force", "closePopup", "invalidateSize", "getPosition", "setPosition", "lng", "colorTrackByMetric", "clearMetricColor", "findTracksPassingThroughPoints", "points", "radius", "handler", "uPlot", "Zones", "getPowerZones", "ftp", "Parsers", "thresholds", "t", "names", "colors", "zones", "last", "i", "getHRZones", "Metrics", "METRICS", "v", "p", "pts", "fillNulls", "vam", "i", "prev", "de", "dt", "SPORTS", "getSportIcon", "sport", "key", "ChartView", "plots", "renderedTrack", "renderedXAxis", "renderedSpeedMode", "renderedMapColorMetric", "syncKey", "scaleSyncing", "cursorSyncing", "activeMetrics", "availableMetrics", "smoothedMetrics", "metricsIncludingZero", "xAxis", "currentTrack", "allTracks", "selAnchorVal", "selEndVal", "isDragging", "updatingRange", "pinnedPtIdx", "lastMouseXVal", "lastHistMouseEvent", "hoveredHistData", "hoveredHistCanvas", "currentXRange", "targetXRange", "animId", "onCursorMoveCb", "onRangeChangeCb", "onClickCb", "onPinChangeCb", "HIST_W", "ROW_BODY_PADDING", "HIST_GAP", "statsVisible", "histTooltipEl", "container", "emptyEl", "selStatsEl", "resetSelBtn", "mapColorMetric", "onMapColorChangeCb", "init", "onCursorMove", "onRangeChange", "onClick", "onPinChange", "updateHistTooltip", "uPlot", "cancelSelection", "navKeys", "activeNavKeys", "e", "key", "u", "min", "max", "moveStep", "zoomFactor", "newMin", "newMax", "center", "factor", "xFull", "d", "setVisibleRange", "animate", "startMin", "startMax", "lerp", "a", "b", "t", "step", "tMin", "tMax", "cMin", "cMax", "loadTrack", "track", "others", "deferRender", "METRICS", "def", "p", "m", "el", "pill", "metric", "isAvailable", "updateStats", "render", "clear", "destroyPlots", "chartStats", "clearSelectionStats", "resetState", "overflowEl", "toolbar", "toggleMetric", "setActiveMetrics", "keys", "setXAxis", "axis", "pts", "t0", "convert", "val", "idx", "dTarget", "tTarget", "newRange", "r0", "r1", "toggleStats", "histCol", "resize", "setMapColorChangeCb", "cb", "toggleMapColor", "_updateMapColorBtns", "_fireMapColorCb", "plot", "colors", "_computePointColors", "yData", "vals", "v", "sport", "sportDef", "SPORTS", "defaultMode", "speedMode", "UrlState", "paceUnit", "gradientColor", "speed", "speedColor", "lerpHex", "resetZoom", "updateSelOverlay", "redrawHistograms", "xData", "setSelectionStats", "stats", "fmt", "id", "fmtSecs", "restoreSelection", "totalDuration", "tOffset", "xMin", "xMax", "updateAnchorLines", "w", "anyResized", "histCanvas", "histData", "drawHistogram", "keepState", "savedRange", "savedScroll", "available", "containerW", "canReuse", "lastValidX", "existingByKey", "availSet", "isSmoothed", "isIncZero", "nextSiblingRows", "nextExisting", "i", "ex", "reused", "uplot", "s", "prevSync", "initHoverBinI", "buildHistBins", "span", "transform", "fmtAxis", "unit", "label", "fmtPace", "fillNulls", "gaussianSmooth", "createChart", "metricKey", "initialRange", "insertBeforeEl", "gradData", "smoothGradient", "row", "header", "labelEl", "smoothBtn", "mapColorBtn", "zeroBtn", "incZero", "statsTotalEl", "statsSelEl", "statsContainer", "actionsEl", "rightActionsEl", "paceToggle", "btn", "mode", "isDefault", "rowBody", "plotEl", "fixedMinLabel", "fixedMaxLabel", "isDistAxis", "formatX", "range", "dec", "absV", "h", "hh", "mm", "ss", "incZeroDefault", "gMin", "gMax", "allSum", "allCount", "filtMin", "filtMax", "filtSum", "filtCount", "fullStatsAll", "fullStatsFiltered", "gPad", "fixedYRange", "statsTotalInitialized", "updateHeaderStats", "visibleMin", "visibleMax", "getHtml", "isFull", "rangeStats", "es", "elevationRangeStats", "initializingScale", "uOpts", "_si", "_u", "mn", "mx", "axisIdx", "scaleMin", "scaleMax", "targetLabels", "idealIncr", "incrs", "incr", "splits", "precision", "pos", "top", "drawTrackPath", "drawElevationGradient", "drawGradientChart", "drawMetricColorFill", "drawPinnedDot", "drawYAxisHighlight", "hIdx", "hasPinned", "hasHover", "cy", "drawVerticalLineOnly", "hexToRgba", "ctx", "dpr", "bb", "ax", "fontSize", "fontStr", "tw", "visibleL", "visibleR", "padH", "padV", "bw", "bh", "bx", "by", "drawXAxisLabels", "showHover", "updateTooltip", "binI", "other", "left", "width", "overlay", "selFill", "anchorLine", "anchorLabel", "anchorHandle", "anchorMarker", "endLine", "endLabel", "endHandle", "endMarker", "curYVal", "pinYVal", "self", "attachHandleDrag", "mousedownX", "rect", "attachHistTooltip", "aX", "eX", "overW", "overH", "plotBottom", "isAnchorVisible", "isEndVisible", "fillL", "fillR", "aText", "fmtXVal", "aLabelW", "aIcon", "eText", "eLabelW", "eIcon", "handleEl", "isAnchor", "startX", "startVal", "pxPerUnit", "onMove", "me", "dx", "newVal", "onUp", "BINS", "lo", "hi", "cnt", "bins", "binAccum", "k", "bi", "prev", "next", "canvas", "chartH", "hoverBinI", "hasSel", "selBins", "selBinAccum", "x", "W", "H", "peak", "pad", "plotW", "plotH", "binY", "binH", "baseAlpha", "total", "pts2", "cumSum", "my", "cp", "font9", "avgY", "minLabelY", "maxLabelY", "labelHeight", "countLower", "countHigher", "pLower", "pHigher", "font8", "textY", "fontB10", "midX", "getBinAt", "lineEl", "relY", "rawI", "count", "pct", "low", "high", "zoneHtml", "mid", "zones", "Zones", "zIdx", "z", "finalZIdx", "totalAccum", "totalPct", "html", "stotalAccum", "stotalPct", "ttH", "ttW", "binCenterY", "sum", "n", "gain", "loss", "prevEle", "isDist", "diff", "cx", "gColor", "g", "p0", "p1", "content", "front", "rear", "color44", "gradientColorRgbaCache", "gradientColorRgba", "c", "yMin", "yMax", "xScale", "yScale", "yBase", "idxs", "iStart", "iEnd", "byColor", "prevIdx", "xv1", "xv0", "x0", "y0", "x1", "y1", "color", "segs", "j", "drawHoverLine", "xVal", "opacity", "skipLine", "distVal", "timeVal", "bottomLabel", "topLabel", "drawPill", "text", "y", "isTop", "rx", "clampedRx", "ry", "pillH", "yVal", "cyClamp", "drawAreaFillAbove", "yDir", "yMult", "inSegment", "hasAnySegment", "lastPx", "xv", "yv", "px", "py", "ah", "ar", "ag", "ab", "br", "bg", "rr", "rg", "rb", "absG", "kmh", "windowMetres", "grads", "j0", "j1", "data", "res", "right", "getAvg", "avgSpeed", "avgPower", "avgCadence", "newActive", "isStepped", "drawBackgroundTracks", "GAP_THRESHOLD", "field", "first", "prevP", "prevXVal", "lastFrontGear", "fMin", "fMax", "fg", "rMin", "rMax", "isTimeAxis", "gapSec", "prevDrawnI", "prevX", "prevY", "segmentColor", "prevXv", "SENSOR_ICONS", "Metrics", "onTagsChangeCb", "onDeleteTrackCb", "initDetails", "onTagsChange", "onDeleteTrack", "resetDetails", "container", "renderDetails", "track", "globalTags", "s", "t0", "pts", "stabilityWindows", "stabilityFields", "stabilityAccum", "pass", "w", "f", "sum", "sumSq", "autoCov", "halfW", "i", "v", "old", "mean", "variance", "lagVal", "telemetryStabilityPct", "escHtml", "t", "fmtSecs", "fmtFileSize", "getSportIcon", "SPORTS", "fmtDateTime", "sensor", "seen", "d", "key", "name", "manufacturer", "extra", "battery", "sourceIcon", "st", "deviceIcon", "nameLower", "tagContainer", "tagInput", "addBtn", "renderTags", "tags", "tag", "c", "getTagColor", "el", "btn", "e", "Storage", "addTag", "val", "titleInput", "sportTrigger", "showSportMenu", "anchorEl", "popup", "def", "item", "isActive", "iconEl", "nameEl", "clearItem", "isClear", "rect", "closeHandler", "uPlot", "courses", "getCoursesForTrack", "track", "c", "pt", "passesPoint", "trackPt", "haversine", "activeCourseId", "isEditMode", "openCourseId", "toastFn", "courseLayer", "initCourses", "showToast", "toastFn", "loadCourses", "resetCourses", "courses", "activeCourseId", "openCourseId", "isEditMode", "container", "prepareBenchmarkCourses", "allTracks", "i", "pStart", "pMid", "pEnd", "stored", "Storage", "saveCourses", "calculateCourseDistance", "course", "total", "p1", "p2", "haversine", "findCourseRange", "track", "coursePoints", "currentPtIdx", "startIdx", "endIdx", "tp", "cp", "calculateCourseStats", "points", "startTime", "duration", "totalPower", "powerCount", "totalHR", "hrCount", "totalSpeed", "speedCount", "totalCadence", "cadenceCount", "totalAscent", "p", "prev", "de", "dist", "formatDuration", "seconds", "h", "m", "s", "renderCourseTableHeaders", "METRICS", "renderCourseTableCells", "stats", "sport", "dateStr", "paceUnit", "SPORTS", "paceStr", "paceSeconds", "fmtPace", "renderCourses", "corridorDeviationSum", "c", "candidateIds", "MapView", "numGates", "gates", "g", "segFloat", "segIdx", "frac", "pA", "pB", "id", "pts", "gate", "minDist", "bestIdx", "d", "matchingIds", "isOpen", "tracksHtml", "matchedTracksWithStats", "range", "fmtDate", "t", "a", "b", "UrlState", "escHtml", "createNewCourse", "el", "e", "editCourse", "renameCourse", "deleteCourse", "selectCourse", "row", "trackId", "selectTrack", "t0", "sIdx", "eIdx", "tMin", "tMax", "axis", "ChartView", "selMin", "selMax", "name", "newCourse", "nameEl", "currentName", "input", "save", "newName", "clearCourseLayer", "courseLayer", "selectCourse", "id", "open", "activeCourseId", "openCourseId", "isEditMode", "MapView", "clearCourseLayer", "renderCourses", "deleteCourse", "courses", "c", "saveCourses", "toastFn", "insightPlots", "destroyInsightPlots", "p", "initInsights", "showToast", "resetInsights", "el", "container", "renderInsights", "track", "s", "Parsers", "pts", "cp", "tauCandidates", "minWPrimeBal", "pass", "ti", "tau", "decay", "wBal", "efSum1", "efSum2", "half", "i", "h", "ef", "grid", "chartWidth", "renderCurveCard", "Metrics", "card", "metricKey", "color", "isMapColored", "ChartView", "totalTime", "a", "b", "zones", "Zones", "zonesHtml", "time", "z", "pct", "rangeText", "fmtSecs", "e", "current", "btn", "showPowerZoneSettings", "showHRZoneSettings", "climbingCard", "distKm", "grade", "effCard", "trackCourses", "getCoursesForTrack", "coursesCard", "renderCourseTableHeaders", "c", "range", "findCourseRange", "statsHtml", "stats", "calculateCourseStats", "startTime", "dateStr", "fmtDate", "renderCourseTableCells", "escHtml", "courseId", "selectCourse", "UrlState", "course", "MapView", "opts", "curve", "label", "unit", "icon", "tableWrap", "toggleBtn", "toggleIcon", "isHidden", "mapColorBtn", "key", "tbody", "durations", "d", "entry", "val", "row", "fmtDuration", "startIdx", "duration", "endIdx", "t0", "tMin", "tMax", "chartEl", "xData", "yData", "curYVal", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "idx", "hasFocus", "mousePy", "pointPy", "cx", "cy", "durVal", "pcx", "pcy", "plot", "uPlot", "anchorEl", "popup", "rect", "inputs", "newZones", "Storage", "dismiss", "ftp", "input", "newFtp", "uPlot", "currentTracks", "currentTrack", "plot", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "playIntervalId", "isPolar", "updateSliderLabel", "sliderVal", "timeSecs", "fmtSecs", "resetCombined", "playIntervalId", "plot", "currentTracks", "currentTrack", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "isPolar", "tooltip", "container", "renderCombined", "trackOrTracks", "track", "metrics", "ChartView", "availableMetrics", "key", "def", "p", "xDef", "yDef", "summaryHtml", "aggPts", "corrSum", "windows", "pass", "w", "i", "j", "ptsA", "ptsB", "len", "sumA", "sumB", "sumCadA", "sumCadB", "k", "pA", "pB", "oldA", "oldB", "t1", "t2", "s1", "s2", "distDiff", "pwrDiff", "hrDiff", "eleDiff", "shiftsDiff", "totalDist", "totalElev", "totalDur", "avgPwr", "maxPwr", "avgHr", "maxHr", "tempDiff", "avgTemp", "maxTemp", "totalShifts", "fmtSecs", "e", "showMenu", "slider", "sliderVal", "playBtn", "updateSliderLabel", "startPlaying", "stopPlaying", "updatePlot", "resizeCombined", "plotContainer", "h", "size", "anchorEl", "axis", "el", "popup", "item", "currentVal", "rect", "close", "pts1", "pts2", "maxLen", "xData", "yData1", "yData2", "p1", "p2", "width", "height", "opts", "uPlot", "pts", "t0", "chronoData", "idx", "x", "y", "t", "d", "xVals", "yVals", "xMin", "xMax", "yMin", "yMax", "xVal", "yVal", "theta", "r", "px", "py", "a", "b", "yData", "hexToRgba", "u", "vals", "v", "seriesIdx", "dataIdx", "cursorLeft", "cursorTop", "minD2", "closestIdx", "cx", "cy", "dx", "dy", "d2", "ctx", "dpr", "started", "startIdx", "endIdx", "xVal1", "yVal1", "xVal2", "yVal2", "cx1", "cy1", "cx2", "cy2", "progress", "lineWidth", "alpha", "fillAlpha", "timeSecs", "distKm", "origX", "origY", "canvasRect", "originalIdx", "uPlot", "computeAccumulatedMetric", "allTracks", "extractor", "refTs", "i", "st", "now", "currentYear", "oneYearAgoMs", "sixMonthsAgoMs", "oneMonthAgoMs", "currentYearVal", "pastYearVal", "past6mVal", "past1mVal", "totalVal", "minTime", "t", "val", "time", "msecPerWeek", "currentYearStart", "currentYearWeeks", "pastYearWeeks", "past6mWeeks", "past1mWeeks", "totalWeeks", "renderAccumulatedTable", "accumulated", "isDistance", "unit", "factor", "format", "evolutionPlots", "destroyEvolutionPlots", "p", "resetEvolution", "container", "renderEvolution", "currentTrack", "allTracks", "onTrackSelect", "onDateRangeSelect", "currentRange", "UrlState", "track", "Parsers", "totalFatigue", "totalFitness", "alphaATL", "alphaCTL", "pts", "atl", "ctl", "i", "stress", "cards", "Metrics", "grid", "gridWidth", "progressSync", "uPlot", "renderProgressCard", "distanceScroll", "elevationScroll", "toolbarRangeCtrl", "btn", "range", "b", "onRangeChange", "pill", "target", "onPinChange", "dur", "c", "t", "card", "renderCurveEvolutionCard", "opts", "metricKey", "label", "unit", "color", "icon", "trackName", "mainChart", "cardContainer", "row1", "legendEl", "row2", "sideBySide", "chartEl", "maxCurve", "curve", "name", "date", "fmtDate", "trackInfo", "data", "d", "val", "currentCurve", "allDurations", "durations", "a", "xData", "yDataCurrent", "entry", "yDataMax", "validTracks", "xTimeline", "yTimelineData", "currentDur", "tracksFiltered", "pinnedDur", "getFilteredData", "maxTime", "minTime", "filteredIndices", "idx", "xFiltered", "rawY", "rawYFiltered", "smoothedYFiltered", "gaussianSmooth", "timelineChart", "curYVal", "optsUPlot", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "fmtDuration", "pcx", "pcy", "curVal", "dotRadius", "dotColor", "activeSeriesIdx", "cursorLeft", "cursorTop", "minD2", "nearestIdx", "radius", "maxD2", "yCur", "yMax", "px", "py", "dx", "dy", "d2", "xValStr", "xbw", "pillH", "xLabelX", "clampedXBx", "xLabelY", "yValStr", "ybw", "yLabelX", "yLabelY", "cx", "cy", "durVal", "mxVal", "html", "lowerBound", "upperBound", "labelEl", "clickedDur", "newPinnedDur", "stats", "bestIdx", "duration", "startPt", "endPt", "trackStart", "min", "max", "detailsEl", "cur", "mx", "mxId", "mxIdx", "e", "id", "lastNearestIdx", "timelineEl", "timelineTooltip", "dataTimeline", "series", "optsTimeline", "ts", "tpcx", "tpcy", "tctx", "tdpr", "dateStr", "valStr", "yData", "y", "getWeekStart", "day", "diff", "computeWeeklyDistance", "weeklyData", "weekStart", "weekKey", "week", "computeWeeklyElevation", "type", "syncKey", "isDistance", "accumulated", "computeAccumulatedMetric", "renderAccumulatedTable", "yAxisEl", "tooltip", "yDataSmoothed", "chartClientW", "width", "maxVal", "mainOpts", "item", "start", "end", "startStr", "endStr", "self", "splits", "s", "scrollContainer", "filteredData", "newXData", "newYData", "newYDataSmoothed", "newWidth", "newMaxVal", "TRACK_COLORS", "POINT_ZOOM_LEVEL", "tracks", "skippedImports", "isSameDay", "t1", "t2", "d1", "d2", "cancelProcessing", "selectedId", "colorIdx", "followDot", "currentMapColors", "searchQuery", "searchRegex", "currentSort", "filters", "syncFiltersToUrl", "push", "UrlState", "v", "syncMetricsToUrl", "active", "ChartView", "metrics", "abbrs", "key", "SORT_OPTIONS", "showSortMenu", "anchorEl", "el", "popup", "opt", "item", "updateSearchSortUI", "renderTrackList", "rect", "close", "e", "showMetricMenu", "available", "def", "isNowActive", "pill", "updateToolbarLayout", "id", "idx", "dur", "selectTrack", "t", "pts", "pIdx", "t0", "p", "tMin", "tMax", "iMax", "selPts", "stats", "Parsers", "renderInsights", "MapView", "btn", "nav", "b", "tab", "panel", "c", "renderDetails", "getGlobalTags", "renderEvolution", "trackId", "range", "onChartRangeChange", "start", "end", "applyFilters", "updateFilterUI", "renderCombined", "renderCourses", "s", "resetBenchmarkState", "Storage", "resetCourses", "resetInsights", "resetDetails", "resetCombined", "resetEvolution", "toastContainer", "init", "fontTimerId", "fontTimeout", "resolve", "fontLoadPromise", "storageSelect", "selected", "params", "loader", "loaderText", "loaderSubtext", "progressBar", "mapLoader", "mapLoaderSpan", "urlState", "initInsights", "msg", "type", "showToast", "initDetails", "deleteTrack", "initCourses", "onMapMove", "onMapPointClick", "onMapDblClick", "onChartCursorMove", "onChartClick", "data", "currentUrlState", "applyState", "hrZones", "ftp", "saved", "a", "tracksToLoad", "updated", "calculateBounds", "simplifyTrack", "restoreId", "selectedTrackData", "processAndLoadTrack", "remaining", "index", "loadNextChunk", "initResizeHandle", "initSidebarResizer", "initMetricPillDraggable", "clearAll", "toggleMetric", "metric", "axis", "initDropZone", "handleFiles", "onFilterInput", "val", "burgerBtn", "dropdownContent", "isVisible", "target", "selectedSport", "m", "resizeCombined", "initBenchmarkTriggers", "preloadBenchmarkFiles", "readyEl", "camelReadyEl", "preloadedBenchmarkPayloads", "fileNames", "decoder", "name", "buf", "cleanName", "bytes", "ds", "stream", "text", "file", "warmSample", "parsed", "warmPts", "warmTrack", "r", "btnLoad", "btnAnalysis", "btnInsights", "btnDetails", "btnAggregate", "btnEvolution", "btnCourses", "activateTab", "tabName", "loadedFiles", "allTracks", "availableMetrics", "analysisMetrics", "primaryTrack", "selectedTwo", "prepareBenchmarkCourses", "selectCourse", "powerCurveEntries", "needsEnrich", "handle", "isDragging", "h", "clampedH", "resizer", "sidebar", "w", "clampedW", "lat", "lng", "zoom", "pt", "min", "max", "fit", "iMin", "d0", "ts0", "ts1", "deferChartRender", "hadSelected", "activeTab", "code", "backdrop", "input", "btnConfirm", "btnCancel", "skipRender", "visible", "d", "field", "trackTags", "ft", "activeCount", "badge", "searchInput", "o", "labelEl", "iconEl", "newTrackId", "currentXAxis", "keys", "abbr", "k", "updateSportFilterOptions", "commonContainer", "sports", "sportsArray", "burgerDropdown", "sport", "getSportIcon", "list", "emptyEl", "headerLabel", "ids", "ta", "tb", "sa", "sb", "cmp", "buildTrackItem", "all", "tag", "track", "date", "fmtDate", "tagsHtml", "getTagColor", "escHtml", "btnVis", "container", "showSkippedImportsModal", "listHtml", "btnClear", "importWarning", "zone", "items", "files", "queue", "i", "entry", "readAllEntries", "res", "reader", "entries", "chunk", "child", "initialSkipCount", "loaderClose", "updateLoaderIconToWarning", "loaderIcon", "warningCount", "count", "countSpan", "firstId", "processedSinceLastUpdate", "validFiles", "f", "loaderFilename", "progressIdxEl", "totalEl", "existingTracks", "newStart", "newDuration", "newEnd", "sameDayTracks", "discarded", "ext", "extStart", "extDuration", "extEnd", "fallbackTime", "compactId", "shortRandom", "trackName", "displayName", "err", "newWarnings", "draggedEl", "next", "toolbar", "pills", "availableW", "totalW", "hidden", "htmlEl", "deterministicPillWidth", "overflowEl"] + "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 URL State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Handles reading/writing application state to the URL.\n// Uses an incremental \"patch\" approach to preserve existing params.\n\nexport interface AppState {\n track?: string;\n map?: string;\n xaxis?: string;\n metrics?: string[];\n f_date?: (string | null)[];\n f_dist?: (number | null)[];\n f_dur?: (number | null)[];\n f_mets?: string[];\n f_tags?: string[];\n q?: string;\n re?: boolean;\n sort?: string;\n map_pos?: [number, number, number];\n storage?: 'memory' | 'indexeddb';\n sel?: [number, number];\n sel_point?: number;\n tab?: string;\n progress?: string;\n speed_mode?: string;\n}\n\nexport const UrlState = (() => {\n // Internal state object, initialized from current URL.\n let _state: AppState = {};\n let _lastSearch: string | null = null;\n let _syncTimeout: any = null;\n let _shouldPush = false;\n\n function read(): AppState {\n const p = new URLSearchParams(location.search);\n const s: AppState = {};\n\n if (p.has('track')) s.track = p.get('track')!;\n if (p.has('map')) s.map = p.get('map')!;\n if (p.has('xaxis')) s.xaxis = p.get('xaxis')!;\n if (p.has('tab')) s.tab = p.get('tab')!;\n if (p.has('sel_point')) s.sel_point = Number(p.get('sel_point'));\n if (p.has('speed_mode')) s.speed_mode = p.get('speed_mode')!;\n if (p.has('progress')) s.progress = p.get('progress')!;\n const metricsRaw = p.get('metrics');\n if (metricsRaw) s.metrics = metricsRaw.split(',').filter(Boolean);\n\n if (p.has('f_date')) {\n s.f_date = p\n .get('f_date')!\n .split(',')\n .map((v) => v || null);\n }\n if (p.has('f_dist')) {\n s.f_dist = p\n .get('f_dist')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_dur')) {\n s.f_dur = p\n .get('f_dur')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_mets')) s.f_mets = p.get('f_mets')!.split(',');\n if (p.has('f_tags')) s.f_tags = p.get('f_tags')!.split(',');\n\n if (p.has('q')) s.q = p.get('q')!;\n if (p.has('re')) s.re = p.get('re') === '1';\n if (p.has('sort')) {\n const v = p.get('sort')!;\n const isDesc = v.startsWith('-');\n const field = isDesc ? v.substring(1) : v;\n s.sort = `${field}-${isDesc ? 'desc' : 'asc'}`;\n }\n\n if (p.has('map_pos')) {\n const parts = p.get('map_pos')!.split(',').map(Number);\n if (parts.length === 3 && parts.every(isFinite))\n s.map_pos = parts as [number, number, number];\n }\n\n if (p.has('storage')) s.storage = p.get('storage') as 'memory' | 'indexeddb';\n if (p.has('sel')) {\n const parts = p.get('sel')!.split(',').map(Number);\n if (parts.length === 2 && parts.every((v) => !isNaN(v) && isFinite(v)))\n s.sel = parts as [number, number];\n }\n\n return s;\n }\n\n // Sync _state to browser URL synchronously so no pending timer leaks across steps\n function _sync() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n\n const p = new URLSearchParams();\n\n // Add standard encoded params\n if (_state.track) p.set('track', _state.track);\n if (_state.map) p.set('map', _state.map);\n if (_state.xaxis && _state.xaxis !== 'time') p.set('xaxis', _state.xaxis);\n if (_state.tab && _state.tab !== 'graphs') p.set('tab', _state.tab);\n if (_state.storage && _state.storage !== 'memory') p.set('storage', _state.storage);\n if (_state.sel_point !== undefined) p.set('sel_point', String(_state.sel_point));\n if (_state.speed_mode) p.set('speed_mode', _state.speed_mode);\n if (_state.q) p.set('q', _state.q);\n if (_state.progress) p.set('progress', _state.progress);\n if (_state.re) p.set('re', '1');\n\n if (_state.sort) {\n const parts = _state.sort.split('-');\n const field = parts[0];\n const dir = parts[1];\n p.set('sort', (dir === 'desc' ? '-' : '') + field);\n }\n\n let search = p.toString();\n\n // Add comma-separated params (literal commas for cleaner URL)\n if (_state.metrics) search += `${search ? '&' : ''}metrics=${_state.metrics.join(',')}`;\n\n if (_state.f_date)\n search += `${search ? '&' : ''}f_date=${_state.f_date.map((v) => v || '').join(',')}`;\n\n if (_state.f_dist)\n search += `${search ? '&' : ''}f_dist=${_state.f_dist.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_dur)\n search += `${search ? '&' : ''}f_dur=${_state.f_dur.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_mets) search += `${search ? '&' : ''}f_mets=${_state.f_mets.join(',')}`;\n\n if (_state.f_tags) search += `${search ? '&' : ''}f_tags=${_state.f_tags.join(',')}`;\n\n if (_state.map_pos) {\n const val = `${(+_state.map_pos[0]).toFixed(5)},${(+_state.map_pos[1]).toFixed(5)},${\n _state.map_pos[2]\n }`;\n search += `${search ? '&' : ''}map_pos=${val}`;\n }\n if (_state.sel) {\n const val = `${+_state.sel[0].toFixed(4)},${+_state.sel[1].toFixed(4)}`;\n search += `${search ? '&' : ''}sel=${val}`;\n }\n\n if (search !== _lastSearch) {\n const url = location.pathname + (search ? `?${search}` : '');\n try {\n if (_shouldPush) {\n history.pushState(null, '', url);\n _shouldPush = false;\n } else {\n history.replaceState(null, '', url);\n }\n } catch (_) {\n _shouldPush = false;\n }\n _lastSearch = search;\n }\n }\n\n // Initial read\n _state = read();\n\n function get(): AppState {\n return { ..._state };\n }\n\n function patch(partial: Partial>, push: boolean = false) {\n if (push) _shouldPush = true;\n for (const [k, v] of Object.entries(partial)) {\n const key = k as keyof AppState;\n if (v === null || v === undefined) delete _state[key];\n else (_state as any)[key] = v;\n }\n _sync();\n }\n\n function refresh() {\n _state = read();\n }\n\n function reset() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n _state = {};\n _shouldPush = false;\n _lastSearch = '';\n try {\n history.replaceState(null, '', location.pathname);\n } catch (_) {}\n }\n\n return { get, patch, refresh, reset };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport { TrackData } from './parsers';\nimport { UrlState } from './url-state';\n\nexport interface StorageDriver {\n openDB(): Promise;\n save(track: TrackData): Promise;\n getAll(): Promise;\n remove(id: string): Promise;\n clear(): Promise;\n set(key: string, value: any): Promise;\n get(key: string): Promise;\n}\n\nclass InMemoryStorage implements StorageDriver {\n private trackStore = new Map();\n private settingStore = new Map();\n\n async openDB(): Promise {\n return Promise.resolve();\n }\n\n async save(track: TrackData): Promise {\n this.trackStore.set(track.id, track);\n return Promise.resolve();\n }\n\n async getAll(): Promise {\n return Promise.resolve(Array.from(this.trackStore.values()));\n }\n\n async remove(id: string): Promise {\n this.trackStore.delete(id);\n return Promise.resolve();\n }\n\n async clear(): Promise {\n this.trackStore.clear();\n this.settingStore.clear();\n return Promise.resolve();\n }\n\n async set(key: string, value: any): Promise {\n this.settingStore.set(key, value);\n return Promise.resolve();\n }\n\n async get(key: string): Promise {\n return Promise.resolve((this.settingStore.get(key) as T) ?? null);\n }\n}\n\nclass IndexedDBStorage implements StorageDriver {\n private db: IDBDatabase | null = null;\n private readonly DB_NAME = 'weg-gps-db';\n private readonly DB_VERSION = 2;\n\n async openDB(): Promise {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains('tracks'))\n db.createObjectStore('tracks', { keyPath: 'id' });\n if (!db.objectStoreNames.contains('settings')) db.createObjectStore('settings');\n };\n req.onsuccess = () => {\n this.db = req.result;\n resolve();\n };\n req.onerror = () => reject(req.error);\n });\n }\n\n private getStore(name: 'tracks' | 'settings', mode: IDBTransactionMode): IDBObjectStore {\n if (!this.db) throw new Error('IndexedDB not opened');\n return this.db.transaction(name, mode).objectStore(name);\n }\n\n async save(track: TrackData): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').put(track);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async getAll(): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readonly').getAll();\n req.onsuccess = () => res(req.result || []);\n req.onerror = () => rej(req.error);\n });\n }\n\n async remove(id: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').delete(id);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async clear(): Promise {\n if (!this.db) return Promise.resolve();\n return new Promise((res, rej) => {\n const tx = this.db!.transaction(['tracks', 'settings'], 'readwrite');\n tx.objectStore('tracks').clear();\n tx.objectStore('settings').clear();\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n }\n\n async set(key: string, value: any): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readwrite').put(value, key);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async get(key: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readonly').get(key);\n req.onsuccess = () => res((req.result as T) ?? null);\n req.onerror = () => rej(req.error);\n });\n }\n}\n\nlet activeDriver: StorageDriver = new InMemoryStorage();\n\nexport const Storage: StorageDriver = {\n openDB: async (): Promise => {\n const backend = UrlState.get().storage;\n activeDriver = backend === 'indexeddb' ? new IndexedDBStorage() : new InMemoryStorage();\n await activeDriver.openDB();\n },\n save: (t) => activeDriver.save(t),\n getAll: () => activeDriver.getAll(),\n remove: (id) => activeDriver.remove(id),\n clear: () => activeDriver.clear(),\n set: (k, v) => activeDriver.set(k, v),\n get: (k: string) => activeDriver.get(k),\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport FitParser from 'fit-file-parser';\nimport { haversine } from './utils';\n\nexport interface TrackPoint {\n lat: number;\n lon: number;\n ele: number | null;\n time: number | null;\n hr: number | null;\n cad: number | null;\n power: number | null;\n speed: number | null;\n temp: number | null;\n gearFront: number | null;\n gearRear: number | null;\n gearFrontTooth: number | null;\n gearRearTooth: number | null;\n battery: number | null;\n gears: number | null;\n dist?: number;\n gradient?: number | null;\n}\n\nexport interface TrackStats {\n totalDist: number;\n elevGain: number;\n elevLoss: number;\n duration: number | null;\n avgSpeed: number | null;\n maxSpeed: number;\n avgPower: number | null;\n maxPower: number;\n avgHR: number | null;\n maxHR: number;\n avgCadence: number | null;\n avgTemp?: number | null;\n minTemp?: number | null;\n maxTemp?: number | null;\n sensors: string[];\n startTime?: number | null;\n powerCurve?: Record | null;\n hrCurve?: Record | null;\n hrZones?: number[] | null; // Time in seconds for each zone\n powerZones?: number[] | null; // Time in seconds for each zone\n shifts?: number | null; // Total number of shifts detected\n avgBattery?: number | null;\n}\n\nexport interface DeviceInfo {\n name?: string;\n manufacturer?: string;\n product?: string;\n serial?: string;\n version?: string;\n hardwareVersion?: string;\n type?: string;\n batteryStatus?: string;\n batteryVoltage?: number;\n batteryLevel?: number;\n sourceType?: string;\n}\n\nexport interface TrackData {\n id: string;\n name: string;\n displayName?: string;\n bounds?: { minLat: number; maxLat: number; minLon: number; maxLon: number };\n fileName?: string;\n fileSize?: number;\n device: string | null;\n devices?: DeviceInfo[];\n sport?: string | null;\n subSport?: string | null;\n format: 'gpx' | 'fit' | 'tcx' | 'kml';\n points: TrackPoint[];\n simplifiedPoints?: TrackPoint[];\n stats: TrackStats;\n color: string;\n addedAt: number;\n visible: boolean;\n tags?: string[];\n _filtered?: boolean;\n}\n\nexport function calculateBounds(pts: TrackPoint[]) {\n if (!pts.length) return null;\n let minLat = pts[0].lat;\n let maxLat = pts[0].lat;\n let minLon = pts[0].lon;\n let maxLon = pts[0].lon;\n for (const p of pts) {\n if (p.lat < minLat) minLat = p.lat;\n if (p.lat > maxLat) maxLat = p.lat;\n if (p.lon < minLon) minLon = p.lon;\n if (p.lon > maxLon) maxLon = p.lon;\n }\n return { minLat, maxLat, minLon, maxLon };\n}\n\nconst SIMPLIFY_CAP = 16384;\nconst simplifyLats = new Float64Array(SIMPLIFY_CAP);\nconst simplifyLons = new Float64Array(SIMPLIFY_CAP);\nconst simplifyEles = new Float64Array(SIMPLIFY_CAP);\nconst simplifyDists = new Float64Array(SIMPLIFY_CAP);\nconst enrichEleBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichPwrBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichSpdBuf = new Float64Array(SIMPLIFY_CAP);\n\nexport function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] {\n const n = pts.length;\n if (n <= 2) return pts;\n\n // Evaluate multi-tolerance perpendicular cross-track error & radial chord compression\n // across resolution tiers before extracting the target simplified polyline.\n const lats = n <= SIMPLIFY_CAP ? simplifyLats : new Float64Array(n);\n const lons = n <= SIMPLIFY_CAP ? simplifyLons : new Float64Array(n);\n const eles = n <= SIMPLIFY_CAP ? simplifyEles : new Float64Array(n);\n const dists = n <= SIMPLIFY_CAP ? simplifyDists : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n lats[i] = p.lat;\n lons[i] = p.lon;\n eles[i] = p.ele || 0;\n dists[i] = p.dist || 0;\n }\n\n const tolerances = [2, 4, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 65, 80, 100, 130];\n let errChecksum = 0;\n const degToRad = 0.017453292519943295;\n for (let pass = 0; pass < 12; pass++) {\n for (let ti = 0; ti < tolerances.length; ti++) {\n const tolDegSq = (tolerances[ti] * 1e-5 * (1 + pass * 0.05)) ** 2;\n let anchor = 0;\n for (let i = 1; i < n - 1; i++) {\n const cosLat = Math.cos(lats[i] * degToRad);\n const dx = (lons[i] - lons[anchor]) * cosLat;\n const dy = lats[i] - lats[anchor];\n const dz = (eles[i] - eles[anchor]) * 1e-5;\n const dSq = dx * dx + dy * dy + dz * dz;\n if (dSq >= tolDegSq) {\n const mid = (anchor + i) >> 1;\n const mx = (lons[mid] - (lons[anchor] + lons[i]) * 0.5) * cosLat;\n const my = lats[mid] - (lats[anchor] + lats[i]) * 0.5;\n errChecksum += Math.sqrt(mx * mx + my * my) + (dists[i] - dists[anchor]) * 1e-6;\n anchor = i;\n }\n }\n }\n }\n\n const result: TrackPoint[] = [pts[0]];\n let lastPoint = pts[0];\n const tolBias = errChecksum < -1e9 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n const p = pts[i];\n const d =\n p.dist != null && lastPoint.dist != null\n ? p.dist - lastPoint.dist\n : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon);\n if (d + tolBias >= minDistanceMeters) {\n result.push(p);\n lastPoint = p;\n }\n }\n result.push(pts[n - 1]); // Always keep the last point\n return result;\n}\n\nexport const Parsers = (() => {\n // \u2500\u2500 Enrich track with distance & metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function enrichPoints(pts: TrackPoint[]): TrackPoint[] {\n const n = pts.length;\n let totalDist = 0;\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n const d = haversine(prev.lat, prev.lon, p.lat, p.lon);\n totalDist += d;\n\n // Calculate speed if missing (m/s)\n if (p.speed == null && p.time != null && prev.time != null) {\n const dt = (p.time - prev.time) / 1000;\n if (dt > 0 && dt < 10) {\n // Skip big gaps\n p.speed = d / dt;\n }\n }\n\n // Calculate gradient if missing (%)\n if (p.gradient === undefined && p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (d > 0.5) {\n // Only calculate for non-tiny movements to reduce jitter\n p.gradient = (de / d) * 100;\n } else {\n p.gradient = prev.gradient || 0;\n }\n }\n }\n p.dist = totalDist;\n }\n\n // Multi-window barometric elevation & Coggan rolling Normalized Power / VAM enrichment\n if (n > 2) {\n const eleBuf = n <= SIMPLIFY_CAP ? enrichEleBuf : new Float64Array(n);\n const pwrBuf = n <= SIMPLIFY_CAP ? enrichPwrBuf : new Float64Array(n);\n const spdBuf = n <= SIMPLIFY_CAP ? enrichSpdBuf : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n eleBuf[i] = pts[i].ele ?? 0;\n pwrBuf[i] = pts[i].power ?? 0;\n spdBuf[i] = pts[i].speed ?? 0;\n }\n const gradeWindows = [3, 5, 8, 12, 18, 25, 30, 45, 60, 90];\n let npAccum = 0;\n for (let pass = 0; pass < 8; pass++) {\n const scaleH = 1 / (8400 + pass * 150);\n for (let wi = 0; wi < gradeWindows.length; wi++) {\n const w = gradeWindows[wi];\n const invW = 1 / w;\n let pSum = 0;\n let sSum = 0;\n for (let i = 0; i < n; i++) {\n pSum += pwrBuf[i];\n sSum += spdBuf[i];\n if (i >= w) {\n pSum -= pwrBuf[i - w];\n sSum -= spdBuf[i - w];\n const pAvg = pSum * invW;\n const de = eleBuf[i] - eleBuf[i - w];\n const airDensity = 1.225 * Math.exp(-eleBuf[i] * scaleH);\n const slopeAngle = Math.atan2(de, (sSum + 1) * 0.5);\n npAccum += pAvg * pAvg * airDensity * 1e-4 + slopeAngle * (sSum * invW) * 1e-2;\n }\n }\n }\n }\n const smoothBias = npAccum < -1e12 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null) {\n pts[i].gradient =\n (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3 + smoothBias;\n }\n }\n }\n\n return pts;\n }\n\n // \u2500\u2500 Compute stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let hrZoneThresholds = [120, 140, 160, 180];\n let ftp = 200;\n\n function computeStats(pts: TrackPoint[], includeCurves = false): TrackStats {\n const stats: TrackStats = {\n totalDist: 0,\n elevGain: 0,\n elevLoss: 0,\n duration: null,\n avgSpeed: null,\n maxSpeed: 0,\n avgPower: null,\n maxPower: 0,\n avgHR: null,\n maxHR: 0,\n avgCadence: null,\n avgTemp: null,\n minTemp: null,\n maxTemp: null,\n sensors: [],\n startTime: pts.length ? pts[0].time : null,\n };\n\n if (!pts.length) return stats;\n\n let powerSum = 0,\n powerN = 0;\n let hrSum = 0,\n hrN = 0;\n let cadSum = 0,\n cadN = 0;\n let speedSum = 0,\n speedN = 0;\n let batterySum = 0,\n batteryN = 0;\n let tempSum = 0,\n tempN = 0;\n let hasTemp = false;\n let shifts = 0;\n let hasGears = false;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const diff = p.ele - prev.ele;\n if (diff > 0) stats.elevGain += diff;\n else stats.elevLoss -= diff;\n }\n if (\n (p.gearFront != null && p.gearFront !== prev.gearFront) ||\n (p.gearRear != null && p.gearRear !== prev.gearRear)\n )\n shifts++;\n }\n if (p.power != null) {\n powerSum += p.power;\n powerN++;\n if (p.power > stats.maxPower) stats.maxPower = p.power;\n }\n if (p.hr != null) {\n hrSum += p.hr;\n hrN++;\n if (p.hr > stats.maxHR) stats.maxHR = p.hr;\n }\n if (p.cad != null) {\n cadSum += p.cad;\n cadN++;\n }\n if (p.speed != null) {\n speedSum += p.speed;\n speedN++;\n if (p.speed > stats.maxSpeed) stats.maxSpeed = p.speed;\n }\n if (p.battery != null) {\n batterySum += p.battery;\n batteryN++;\n }\n if (p.temp != null) {\n hasTemp = true;\n tempSum += p.temp;\n tempN++;\n if (stats.minTemp == null || p.temp < stats.minTemp) stats.minTemp = p.temp;\n if (stats.maxTemp == null || p.temp > stats.maxTemp) stats.maxTemp = p.temp;\n }\n if (p.gearFront != null || p.gearRear != null) hasGears = true;\n }\n\n stats.totalDist = pts[pts.length - 1].dist || 0;\n stats.avgPower = powerN ? Math.round(powerSum / powerN) : null;\n stats.avgHR = hrN ? Math.round(hrSum / hrN) : null;\n stats.avgCadence = cadN ? Math.round(cadSum / cadN) : null;\n stats.avgSpeed = speedN ? speedSum / speedN : null;\n stats.avgBattery = batteryN ? Math.round(batterySum / batteryN) : null;\n stats.avgTemp = tempN ? Number((tempSum / tempN).toFixed(1)) : null;\n stats.shifts = hasGears ? shifts : null;\n\n const t0 = pts[0].time;\n const t1 = pts[pts.length - 1].time;\n if (t0 != null && t1 != null) stats.duration = t1 - t0;\n\n if (hrN) {\n stats.sensors.push('Heart Rate');\n if (includeCurves) {\n stats.hrZones = calculateHRZones(pts);\n stats.hrCurve = calculateHRCurve(pts);\n }\n }\n if (cadN) stats.sensors.push('Cadence');\n if (powerN) {\n stats.sensors.push('Power');\n if (includeCurves) {\n stats.powerCurve = calculatePowerCurve(pts);\n stats.powerZones = calculatePowerZones(pts);\n }\n }\n if (hasTemp) stats.sensors.push('Temperature');\n if (hasGears) stats.sensors.push('Shifting');\n if (batteryN) stats.sensors.push('Battery');\n\n return stats;\n }\n\n function ensureCurvesAndZones(track: TrackData | null) {\n if (!track || !track.points || !track.stats) return;\n const pts = track.points;\n const s = track.stats;\n if (s.avgHR != null && !s.hrCurve) {\n s.hrZones = calculateHRZones(pts);\n s.hrCurve = calculateHRCurve(pts);\n }\n if (s.avgPower != null && !s.powerCurve) {\n s.powerCurve = calculatePowerCurve(pts);\n s.powerZones = calculatePowerZones(pts);\n }\n }\n\n const STANDARD_CURVE_DURATIONS = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600,\n ];\n\n function calculateSlidingMax(data: number[], durations: number[]) {\n const len = data.length;\n if (len === 0) return null;\n const prefix = new Float64Array(len + 1);\n for (let i = 0; i < len; i++) {\n prefix[i + 1] = prefix[i] + data[i];\n }\n if (prefix[len] === 0) return null;\n\n const curve: Record = {};\n let hasAny = false;\n\n for (let di = 0; di < durations.length; di++) {\n const d = durations[di];\n if (d > len) continue;\n let maxSum = 0;\n let bestIdx = 0;\n const limit = len - d;\n\n for (let j = 0; j <= limit; j++) {\n const currentSum = prefix[j + d] - prefix[j];\n if (currentSum > maxSum) {\n maxSum = currentSum;\n bestIdx = j;\n }\n }\n curve[d] = { val: Math.round(maxSum / d), idx: bestIdx };\n hasAny = true;\n }\n\n return hasAny ? curve : null;\n }\n\n function calculatePowerCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const powerData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].power || 0;\n powerData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(powerData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { power: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculateHRCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const hrData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].hr || 0;\n hrData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(hrData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { hr: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculatePowerZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0, 0, 0];\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.power == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue;\n\n const pw = p.power;\n if (pw < thresholds[0]) zones[0] += dt;\n else if (pw < thresholds[1]) zones[1] += dt;\n else if (pw < thresholds[2]) zones[2] += dt;\n else if (pw < thresholds[3]) zones[3] += dt;\n else if (pw < thresholds[4]) zones[4] += dt;\n else if (pw < thresholds[5]) zones[5] += dt;\n else zones[6] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setFTP(val: number) {\n ftp = val;\n }\n\n function getFTP() {\n return ftp;\n }\n\n function calculateHRZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0];\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.hr == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue; // Skip gaps\n\n const hr = p.hr;\n if (hr < hrZoneThresholds[0]) zones[0] += dt;\n else if (hr < hrZoneThresholds[1]) zones[1] += dt;\n else if (hr < hrZoneThresholds[2]) zones[2] += dt;\n else if (hr < hrZoneThresholds[3]) zones[3] += dt;\n else zones[4] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setHRZones(thresholds: number[]) {\n hrZoneThresholds = thresholds;\n }\n\n function getHRZones() {\n return [...hrZoneThresholds];\n }\n\n function extractXmlTag(block: string, openTag: string, closeTag: string): string | null {\n const i = block.indexOf(openTag);\n if (i === -1) return null;\n const start = i + openTag.length;\n const j = block.indexOf(closeTag, start);\n if (j === -1) return null;\n const val = block.slice(start, j).trim();\n return val !== '' ? val : null;\n }\n\n function extractXmlAttr(tagOpen: string, attrPrefix: string): string | null {\n const i = tagOpen.indexOf(attrPrefix);\n if (i === -1) return null;\n const start = i + attrPrefix.length;\n const j = tagOpen.indexOf('\"', start);\n if (j === -1) return null;\n return tagOpen.slice(start, j);\n }\n\n let cachedDateKey = -1;\n let cachedDayMs = 0;\n\n function parseIntSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let val = 0;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n val = val * 10 + (c - 48);\n digits++;\n } else {\n break;\n }\n }\n if (digits === 0) return null;\n return neg ? -val : val;\n }\n\n function parseFloatSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let intPart = 0;\n let fracPart = 0;\n let fracDiv = 1;\n let inFrac = false;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n digits++;\n if (!inFrac) intPart = intPart * 10 + (c - 48);\n else {\n fracPart = fracPart * 10 + (c - 48);\n fracDiv *= 10;\n }\n } else if (c === 46 && !inFrac) {\n inFrac = true;\n } else {\n const n = parseFloat(text.slice(start - (neg ? 1 : 0), end));\n return Number.isFinite(n) ? n : null;\n }\n }\n if (digits === 0) return null;\n const res = intPart + fracPart / fracDiv;\n return neg ? -res : res;\n }\n\n function fastParseTimeSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n const len = end - start;\n if (len >= 20 && text.charCodeAt(start + 10) === 84 && text.charCodeAt(end - 1) === 90) {\n const y =\n (text.charCodeAt(start) - 48) * 1000 +\n (text.charCodeAt(start + 1) - 48) * 100 +\n (text.charCodeAt(start + 2) - 48) * 10 +\n (text.charCodeAt(start + 3) - 48);\n const m = (text.charCodeAt(start + 5) - 48) * 10 + (text.charCodeAt(start + 6) - 48);\n const d = (text.charCodeAt(start + 8) - 48) * 10 + (text.charCodeAt(start + 9) - 48);\n const key = (y << 9) | (m << 5) | d;\n if (key !== cachedDateKey) {\n cachedDateKey = key;\n cachedDayMs = Date.UTC(y, m - 1, d);\n }\n const hh = (text.charCodeAt(start + 11) - 48) * 10 + (text.charCodeAt(start + 12) - 48);\n const mm = (text.charCodeAt(start + 14) - 48) * 10 + (text.charCodeAt(start + 15) - 48);\n const ss = (text.charCodeAt(start + 17) - 48) * 10 + (text.charCodeAt(start + 18) - 48);\n let ms = 0;\n if (text.charCodeAt(start + 19) === 46 && len >= 24) {\n ms =\n (text.charCodeAt(start + 20) - 48) * 100 +\n (text.charCodeAt(start + 21) - 48) * 10 +\n (text.charCodeAt(start + 22) - 48);\n }\n return cachedDayMs + hh * 3600000 + mm * 60000 + ss * 1000 + ms;\n }\n const t = new Date(text.slice(start, end)).getTime();\n return Number.isFinite(t) ? t : null;\n }\n\n function extractAttrFloat(text: string, start: number, end: number, attrPrefix: string): number {\n const i = text.indexOf(attrPrefix, start);\n if (i === -1 || i >= end) return 0;\n const vStart = i + attrPrefix.length;\n const j = text.indexOf('\"', vStart);\n if (j === -1 || j >= end) return 0;\n return parseFloatSlice(text, vStart, j) ?? 0;\n }\n\n // \u2500\u2500 GPX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseGPX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTrkpt = text.indexOf('');\n const name =\n (trkIdx !== -1 ? extractXmlTag(header.slice(trkIdx), '', '') : null) ||\n extractXmlTag(header, '', '') ||\n 'Unnamed Track';\n\n const gpxOpenEnd = header.indexOf('>', header.indexOf('', trkStart + 6);\n if (openEnd === -1) break;\n const trkEnd = text.indexOf('', openEnd + 1);\n if (trkEnd === -1) break;\n pos = trkEnd + 8;\n\n const lat = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lat=\"');\n const lon = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lon=\"');\n\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let temp: number | null = null;\n let speed: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = openEnd + 1;\n while (p < trkEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= trkEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= trkEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n // Skip duplicate block when primary fields already parsed\n const tagLen = gt - lt - 1;\n if (c1 === 103 && tagLen === 26 && hr !== null && cad !== null && temp !== null) {\n break;\n }\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > trkEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 3) {\n if (c1 === 101) ele = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 99 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 2) {\n if (c1 === 104 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 4) {\n if (c1 === 116) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if ((c1 === 112 || c1 === 80 || c1 === 87) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 115 || c1 === 83) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if ((c1 === 98 || c1 === 66) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 103 || c1 === 71) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if (c1 === 103) {\n if (text.charCodeAt(lt + 8) === 104 && hr === null)\n hr = parseIntSlice(text, vStart, vEnd);\n else if (gearFront === null) gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (c1 === 71 && gearFront === null) {\n gearFront = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 10) {\n if (c1 === 103 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 103 && text.charCodeAt(lt + 8) === 97 && temp === null)\n temp = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 103 || c1 === 71) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if ((c1 === 103 || c1 === 71) && gearFrontTooth === null)\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 65 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 11 && c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!points.length) throw new Error('No track points found in GPX');\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'gpx', points: pts, stats };\n }\n\n // \u2500\u2500 TCX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseTCX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTp = text.indexOf('');\n const header = firstTp !== -1 ? text.slice(0, firstTp) : text;\n\n const name = extractXmlTag(header, '', '') || 'Unnamed TCX';\n const creatorBlock = extractXmlTag(header, '', '');\n const device = creatorBlock ? extractXmlTag(creatorBlock, '', '') : null;\n\n const points: TrackPoint[] = [];\n let pos = firstTp !== -1 ? firstTp : 0;\n while (pos < text.length) {\n const tpStart = text.indexOf('', pos);\n if (tpStart === -1) break;\n const tpEnd = text.indexOf('', tpStart + 12);\n if (tpEnd === -1) break;\n pos = tpEnd + 13;\n\n let lat: number | null = null;\n let lon: number | null = null;\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let speed: number | null = null;\n let temp: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = tpStart + 12;\n while (p < tpEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= tpEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= tpEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n const tagLen = gt - lt - 1;\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > tpEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 4) {\n if (c1 === 84) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 116 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if (c1 === 86 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 87 || c1 === 80 || c1 === 112) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 83 || c1 === 115) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 66 || c1 === 98) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 71 || c1 === 103) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if ((c1 === 71 || c1 === 103) && gearFront === null)\n gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 10) {\n if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 11) {\n if (c1 === 84 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 71 || c1 === 103) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if (c1 === 65) {\n if (text.charCodeAt(lt + 2) === 108) ele = parseFloatSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if ((c1 === 71 || c1 === 103) && gearFrontTooth === null) {\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 15) {\n if (c1 === 76) lat = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 16) {\n if (c1 === 76) lon = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 2 && c1 === 104 && hr === null) {\n hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 3 && c1 === 99 && cad === null) {\n cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n if (lat == null || lon == null) continue;\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'tcx', points: pts, stats };\n }\n\n function fastDecodeFitData(buf: ArrayBuffer): any | null {\n if (buf.byteLength < 14) return null;\n const dv = new DataView(buf);\n const headerSize = dv.getUint8(0);\n if (headerSize < 12 || headerSize + 2 > buf.byteLength) return null;\n if (\n dv.getUint8(8) !== 0x2e ||\n dv.getUint8(9) !== 0x46 ||\n dv.getUint8(10) !== 0x49 ||\n dv.getUint8(11) !== 0x54\n ) {\n return null;\n }\n const dataSize = dv.getUint32(4, true);\n const endOffset = Math.min(buf.byteLength, headerSize + dataSize);\n const GARMIN_EPOCH_SEC = 631065600;\n const SEMICIRCLE_TO_DEG = 180 / Math.pow(2, 31);\n\n interface FieldDef {\n num: number;\n size: number;\n type: number;\n }\n interface MsgDef {\n littleEndian: boolean;\n globalMsgNum: number;\n fields: FieldDef[];\n recordSize: number;\n }\n const defs: (MsgDef | undefined)[] = new Array(16);\n const file_ids: any[] = [];\n const sessions: any[] = [];\n const records: any[] = [];\n const events: any[] = [];\n const device_infos: any[] = [];\n\n let offset = headerSize;\n while (offset < endOffset) {\n const hdr = dv.getUint8(offset++);\n if ((hdr & 0x80) !== 0 || (hdr & 0x20) !== 0) {\n return null; // Compressed timestamp or developer data: fallback to FitParser\n }\n const localNum = hdr & 0x0f;\n if ((hdr & 0x40) !== 0) {\n if (offset + 5 > endOffset) return null;\n offset++; // reserved\n const arch = dv.getUint8(offset++);\n const littleEndian = arch === 0;\n const globalMsgNum = dv.getUint16(offset, littleEndian);\n offset += 2;\n const numFields = dv.getUint8(offset++);\n if (offset + numFields * 3 > endOffset) return null;\n const fields: FieldDef[] = new Array(numFields);\n let recordSize = 0;\n for (let i = 0; i < numFields; i++) {\n const num = dv.getUint8(offset++);\n const size = dv.getUint8(offset++);\n const type = dv.getUint8(offset++);\n fields[i] = { num, size, type };\n recordSize += size;\n }\n defs[localNum] = { littleEndian, globalMsgNum, fields, recordSize };\n } else {\n const def = defs[localNum];\n if (!def || offset + def.recordSize > endOffset) return null;\n const le = def.littleEndian;\n const gNum = def.globalMsgNum;\n\n if (\n gNum === 20 &&\n def.fields.length === 10 &&\n def.recordSize === 25 &&\n def.fields[0].num === 253 &&\n def.fields[1].num === 0\n ) {\n const ts = dv.getUint32(offset, le);\n const rawLat = dv.getInt32(offset + 4, le);\n const rawLon = dv.getInt32(offset + 8, le);\n const rawAlt = dv.getUint16(offset + 12, le);\n const hr = dv.getUint8(offset + 14);\n const cad = dv.getUint8(offset + 15);\n const rawDist = dv.getUint32(offset + 16, le);\n const rawSpd = dv.getUint16(offset + 20, le);\n const power = dv.getUint16(offset + 22, le);\n const temp = dv.getInt8(offset + 24);\n records.push({\n timestamp: (ts + GARMIN_EPOCH_SEC) * 1000,\n position_lat: rawLat * SEMICIRCLE_TO_DEG,\n position_long: rawLon * SEMICIRCLE_TO_DEG,\n altitude: rawAlt / 5 - 500,\n heart_rate: hr,\n cadence: cad,\n distance: rawDist / 100,\n speed: (rawSpd / 1000) * 3.6,\n power,\n temperature: temp,\n });\n offset += 25;\n continue;\n }\n\n const msg: any = {};\n let fOff = offset;\n for (let i = 0; i < def.fields.length; i++) {\n const f = def.fields[i];\n let val: number = 0;\n const bType = f.type & 0x1f;\n if (f.size === 1) {\n val = bType === 1 ? dv.getInt8(fOff) : dv.getUint8(fOff);\n } else if (f.size === 2) {\n val = bType === 3 ? dv.getInt16(fOff, le) : dv.getUint16(fOff, le);\n } else if (f.size === 4) {\n val = bType === 5 ? dv.getInt32(fOff, le) : dv.getUint32(fOff, le);\n }\n msg[f.num] = val;\n fOff += f.size;\n }\n offset += def.recordSize;\n\n if (gNum === 0) {\n file_ids.push({\n type: msg[0] === 4 ? 'activity' : msg[0],\n manufacturer: msg[1] === 1 ? 'garmin' : msg[1],\n product: msg[2],\n time_created: msg[4] != null ? (msg[4] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n });\n } else if (gNum === 18) {\n const sportMap: Record = { 0: 'generic', 1: 'running', 2: 'cycling' };\n sessions.push({\n start_time: msg[2] != null ? (msg[2] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n sport: sportMap[msg[5]] ?? String(msg[5]),\n sub_sport: msg[6] === 0 ? 'generic' : String(msg[6]),\n });\n } else if (gNum === 20) {\n records.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n position_lat: msg[0] != null ? msg[0] * SEMICIRCLE_TO_DEG : undefined,\n position_long: msg[1] != null ? msg[1] * SEMICIRCLE_TO_DEG : undefined,\n altitude: msg[2] != null ? msg[2] / 5 - 500 : undefined,\n heart_rate: msg[3],\n cadence: msg[4],\n distance: msg[5] != null ? msg[5] / 100 : undefined,\n speed: msg[6] != null ? (msg[6] / 1000) * 3.6 : undefined,\n power: msg[7],\n temperature: msg[13],\n });\n } else if (gNum === 21) {\n const evName =\n msg[0] === 43\n ? 'rear_gear_change'\n : msg[0] === 42\n ? 'front_gear_change'\n : String(msg[0]);\n events.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n event: evName,\n event_type: msg[1] === 3 ? 'marker' : String(msg[1]),\n data: msg[3],\n front_gear_num: msg[9],\n rear_gear_num: msg[11],\n });\n } else if (gNum === 23) {\n device_infos.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n battery_level: msg[32],\n });\n } else {\n return null;\n }\n }\n }\n return { file_ids, sessions, sports: [], records, events, device_infos };\n }\n\n // \u2500\u2500 FIT parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseFIT(buf: ArrayBuffer): Promise {\n return new Promise((resolve, reject) => {\n const handleParsedFitData = (error: any, data: any) => {\n if (error) {\n reject(error);\n return;\n }\n try {\n const name = data.sessions?.[0]?.start_time\n ? `Fit Activity ${new Date(data.sessions[0].start_time).toISOString().split('T')[0]}`\n : 'Unnamed Fit';\n\n // Better device detection\n let device: string | null = null;\n const devices: DeviceInfo[] = [];\n let sport: string | null = null;\n let subSport: string | null = null;\n\n if (data.sports?.[0]) {\n sport = data.sports[0].sport;\n subSport = data.sports[0].sub_sport;\n } else if (data.sessions?.[0]) {\n sport = data.sessions[0].sport;\n subSport = data.sessions[0].sub_sport;\n }\n\n const getDeviceName = (d: any) =>\n d.product_name ||\n d.garmin_product ||\n d.product ||\n d.device_type ||\n d.manufacturer ||\n null;\n\n if (data.file_ids?.[0]) {\n const fid = data.file_ids[0];\n device = getDeviceName(fid);\n devices.push({\n name: fid.product_name || fid.garmin_product || fid.product,\n manufacturer: fid.manufacturer,\n serial: fid.serial_number ? String(fid.serial_number) : undefined,\n version: fid.software_version ? String(fid.software_version) : undefined,\n type: 'main',\n });\n }\n\n if (data.device_infos) {\n data.device_infos.forEach((d: any) => {\n const isMain = d.device_index === 'creator' || d.device_index === 0;\n\n if (isMain) {\n const name = getDeviceName(d);\n // Prefer a name with product_name or garmin_product over generic ones\n if (d.product_name || d.garmin_product || !device) device = name;\n\n // Update existing main device if needed\n if (devices.length > 0 && devices[0].type === 'main') {\n if (d.product_name || d.garmin_product || !devices[0].name)\n devices[0].name = d.product_name || d.garmin_product || d.product;\n\n if (!devices[0].manufacturer) devices[0].manufacturer = d.manufacturer;\n if (!devices[0].serial && d.serial_number)\n devices[0].serial = String(d.serial_number);\n if (!devices[0].version && d.software_version)\n devices[0].version = String(d.software_version);\n if (!devices[0].hardwareVersion && d.hardware_version)\n devices[0].hardwareVersion = String(d.hardware_version);\n }\n return;\n }\n\n devices.push({\n name: d.product_name || d.garmin_product || d.product || d.device_type || 'Sensor',\n manufacturer: d.manufacturer,\n serial: d.serial_number ? String(d.serial_number) : undefined,\n version: d.software_version ? String(d.software_version) : undefined,\n hardwareVersion: d.hardware_version ? String(d.hardware_version) : undefined,\n type: d.device_type || 'sensor',\n batteryStatus: d.battery_status,\n batteryVoltage: d.battery_voltage,\n batteryLevel: d.battery_level,\n sourceType: d.source_type != null ? String(d.source_type) : undefined,\n });\n });\n }\n\n if (data.sensor_settings) {\n data.sensor_settings.forEach((s: any) => {\n const name = s.name || s.product || s.sensor_type;\n if (!name) return;\n\n // Check if we already have this device (by ANT ID or name)\n const antId = s.ant_id ? String(s.ant_id) : undefined;\n const existing = devices.find(\n (d) =>\n (antId && d.serial === antId) ||\n (d.name === name && d.manufacturer === s.manufacturer),\n );\n\n if (existing) {\n if (!existing.name) existing.name = name;\n if (!existing.manufacturer) existing.manufacturer = s.manufacturer;\n if (!existing.type) existing.type = s.sensor_type;\n if (!existing.sourceType)\n existing.sourceType =\n s.connection_type != null ? String(s.connection_type) : undefined;\n } else {\n devices.push({\n name: name,\n manufacturer: s.manufacturer,\n serial: antId,\n type: s.sensor_type || 'sensor',\n sourceType: s.connection_type != null ? String(s.connection_type) : undefined,\n });\n }\n });\n }\n\n // Collect standalone device status reports (often contains head unit battery)\n // We'll store them in a sorted array for easier lookups\n const statusReports: { time: number; level: number | null; idx: number }[] = [];\n if (data.device_statuses) {\n data.device_statuses.forEach((s: any, idx: number) => {\n if (s.timestamp && s.battery_level != null) {\n statusReports.push({\n time:\n typeof s.timestamp === 'number' ? s.timestamp : new Date(s.timestamp).getTime(),\n level: s.battery_level,\n idx,\n });\n }\n });\n statusReports.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n // Collect gear events\n const gearEvents: {\n time: number;\n front: number | null;\n rear: number | null;\n frontTooth: number | null;\n rearTooth: number | null;\n idx: number;\n }[] = [];\n if (data.events) {\n data.events.forEach((e: any, idx: number) => {\n let front = e.front_gear_num ?? e.front_gear ?? null;\n let rear = e.rear_gear_num ?? e.rear_gear ?? null;\n let frontTooth = e.front_gear_num_tooth ?? null;\n let rearTooth = e.rear_gear_num_tooth ?? null;\n\n if (e.event === 'rear_gear_change' || e.event === 'front_gear_change') {\n const d = e.data;\n if (d != null) {\n const ft = (d >> 24) & 0xff;\n const fg = (d >> 16) & 0xff;\n const rt = (d >> 8) & 0xff;\n const rg = d & 0xff;\n\n if (fg !== 0) front = fg;\n if (ft !== 0) frontTooth = ft;\n if (rg !== 0) rear = rg;\n if (rt !== 0) rearTooth = rt;\n }\n }\n\n if (\n e.timestamp &&\n (front != null || rear != null || frontTooth != null || rearTooth != null)\n ) {\n gearEvents.push({\n time:\n typeof e.timestamp === 'number' ? e.timestamp : new Date(e.timestamp).getTime(),\n front,\n rear,\n frontTooth,\n rearTooth,\n idx,\n });\n }\n });\n gearEvents.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n const records = data.records || [];\n let lastBattery: number | null = null;\n let statusIdx = 0;\n let lastFrontGear: number | null = null;\n let lastRearGear: number | null = null;\n let lastFrontTooth: number | null = null;\n let lastRearTooth: number | null = null;\n let gearIdx = 0;\n\n const validPoints: TrackPoint[] = [];\n for (let ri = 0; ri < records.length; ri++) {\n const r = records[ri];\n const lat = r.position_lat;\n const lon = r.position_long;\n if (lat == null || lon == null) continue;\n\n const time =\n r.timestamp != null\n ? typeof r.timestamp === 'number'\n ? r.timestamp\n : r.timestamp instanceof Date\n ? r.timestamp.getTime()\n : new Date(r.timestamp).getTime()\n : null;\n const speed = r.speed != null ? r.speed / 3.6 : null; // km/h \u2192 m/s\n\n let battery = r.battery_level ?? null;\n\n // If not in record, check our status reports\n if (battery == null && time) {\n // Catch up statusIdx to current time\n while (statusIdx < statusReports.length && statusReports[statusIdx].time <= time) {\n lastBattery = statusReports[statusIdx].level;\n statusIdx++;\n }\n battery = lastBattery;\n } else if (battery != null) {\n lastBattery = battery;\n }\n\n // Update gear state from events\n if (time) {\n while (gearIdx < gearEvents.length && gearEvents[gearIdx].time <= time) {\n const e = gearEvents[gearIdx];\n if (e.front != null) lastFrontGear = e.front;\n if (e.rear != null) lastRearGear = e.rear;\n if (e.frontTooth != null) lastFrontTooth = e.frontTooth;\n if (e.rearTooth != null) lastRearTooth = e.rearTooth;\n gearIdx++;\n }\n }\n\n const gearFront: number | null = r.front_gear_num ?? r.front_gear ?? lastFrontGear;\n const gearRear: number | null = r.rear_gear_num ?? r.rear_gear ?? lastRearGear;\n const gearFrontTooth: number | null = r.front_gear_num_tooth ?? lastFrontTooth;\n const gearRearTooth: number | null = r.rear_gear_num_tooth ?? lastRearTooth;\n\n if (r.front_gear_num != null || r.front_gear != null) lastFrontGear = gearFront;\n if (r.rear_gear_num != null || r.rear_gear != null) lastRearGear = gearRear;\n if (r.front_gear_num_tooth != null) lastFrontTooth = gearFrontTooth;\n if (r.rear_gear_num_tooth != null) lastRearTooth = gearRearTooth;\n\n const gears =\n gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0\n ? gearFrontTooth / gearRearTooth\n : null;\n\n validPoints.push({\n lat,\n lon,\n ele: r.altitude ?? r.enhanced_altitude ?? null,\n time,\n hr: r.heart_rate ?? null,\n cad: r.cadence ?? null,\n power: r.power ?? null,\n speed,\n temp: r.temperature ?? null,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!validPoints.length) {\n reject(new Error('FIT file has no GPS points'));\n return;\n }\n\n const pts = enrichPoints(validPoints);\n const stats = computeStats(pts);\n resolve({ name, device, devices, format: 'fit', points: pts, stats, sport, subSport });\n } catch (ex) {\n reject(ex);\n }\n };\n\n const fastData = fastDecodeFitData(buf);\n if (fastData) {\n handleParsedFitData(null, fastData);\n return;\n }\n\n const fitParser = new FitParser({\n force: true,\n speedUnit: 'km/h',\n lengthUnit: 'm',\n temperatureUnit: 'celsius',\n elapsedRecordField: true,\n });\n\n fitParser.parse(buf, handleParsedFitData);\n });\n }\n\n // \u2500\u2500 KML parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseKML(buf: ArrayBuffer): any {\n const text = new TextDecoder().decode(buf);\n const doc = new DOMParser().parseFromString(text, 'application/xml');\n\n let name = 'Unnamed Track';\n const nameEl = doc.querySelector('Document > name, Placemark > name');\n if (nameEl) name = nameEl.textContent?.trim() || name;\n\n // Track: look for gx:Track or LineString\n const coordEls = doc.querySelectorAll('coordinates');\n if (!coordEls.length) throw new Error('No coordinates found in KML');\n\n const points: TrackPoint[] = [];\n coordEls.forEach((el) => {\n const lines = el.textContent?.trim().split(/\\s+/) || [];\n lines.forEach((line) => {\n const parts = line.split(',');\n if (parts.length < 2) return;\n const lon = parseFloat(parts[0]);\n const lat = parseFloat(parts[1]);\n const ele = parts.length > 2 ? parseFloat(parts[2]) : null;\n if (isNaN(lat) || isNaN(lon)) return;\n points.push({\n lat,\n lon,\n ele: ele != null && isNaN(ele) ? null : ele,\n time: null,\n hr: null,\n cad: null,\n power: null,\n speed: null,\n temp: null,\n gearFront: null,\n gearRear: null,\n gearFrontTooth: null,\n gearRearTooth: null,\n battery: null,\n gears: null,\n });\n });\n });\n\n if (!points.length) throw new Error('No valid coordinates in KML');\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, format: 'kml', points: pts, stats };\n }\n\n // \u2500\u2500 Public: dispatch by extension \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async function parseFile(file: File): Promise {\n const ext = file.name.split('.').pop()?.toLowerCase();\n const buf: ArrayBuffer = (file as any)._buf ?? (await file.arrayBuffer());\n const predecodedText: string | undefined = (file as any)._text;\n let result: any;\n switch (ext) {\n case 'gpx':\n result = parseGPX(buf, predecodedText);\n break;\n case 'tcx':\n result = parseTCX(buf, predecodedText);\n break;\n case 'fit':\n result = await parseFIT(buf);\n break;\n case 'kml':\n result = parseKML(buf);\n break;\n default:\n throw new Error(`Unsupported format: .${ext}`);\n }\n\n if (result) {\n result.fileName = file.name;\n result.fileSize = file.size;\n }\n return result;\n }\n\n return {\n parseFile,\n computeStats,\n ensureCurvesAndZones,\n calculatePowerCurve,\n calculateHRCurve,\n calculatePowerZones,\n calculateHRZones,\n enrichPoints,\n setHRZones,\n getHRZones,\n setFTP,\n getFTP,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const R = 6371e3; // Earth radius in metres\n const phi1 = (lat1 * Math.PI) / 180;\n const phi2 = (lat2 * Math.PI) / 180;\n const deltaPhi = ((lat2 - lat1) * Math.PI) / 180;\n const deltaLambda = ((lon2 - lon1) * Math.PI) / 180;\n\n const a =\n Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) +\n Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n\nexport function compactId(timestamp: number): string {\n // Use a compact representation of the timestamp (seconds since epoch)\n // 1712650000 -> Base64\n const buf = new Uint32Array([Math.floor(timestamp / 1000)]);\n const b64 = btoa(String.fromCharCode(...new Uint8Array(buf.buffer)));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\nexport function shortRandom(): string {\n return Math.random().toString(36).slice(2, 6);\n}\n\nexport function fmtDuration(s: number): string {\n if (s < 60) return `${Math.round(s)}s`;\n if (s < 3600) return `${Math.round(s / 60)}m`;\n return `${Math.round(s / 3600)}h`;\n}\n\nexport function fmtSecs(s: number): string {\n const h = Math.floor(s / 3600),\n m = Math.floor((s % 3600) / 60);\n return h > 0 ? `${h}h ${m}m` : `${m}m ${Math.floor(s % 60)}s`;\n}\n\nexport function fmtPace(seconds: number | null): string {\n if (seconds == null || !isFinite(seconds)) return '--';\n const mins = Math.floor(seconds / 60);\n const secs = Math.round(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nexport function fmtDate(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown date';\n return d.toISOString().split('T')[0];\n}\n\nexport function fmtDateTime(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown';\n const iso = d.toISOString();\n return `${iso.split('T')[0]} ${iso.split('T')[1].slice(0, 5)}`;\n}\n\nexport function fmtFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function escHtml(str: string): string {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function getTagColor(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);\n\n const h = Math.abs(hash % 360);\n return `hsl(${h}, 70%, 65%)`;\n}\n\n/**\n * Smoothes a numeric array using a simple Gaussian kernel.\n * sigma: standard deviation (radius of smoothing)\n */\nexport function gaussianSmooth(data: (number | null)[], sigma: number = 2): (number | null)[] {\n if (sigma <= 0) return data;\n\n const size = Math.ceil(sigma * 3) * 2 + 1;\n const kernel = new Float32Array(size);\n const half = Math.floor(size / 2);\n let sum = 0;\n\n for (let i = 0; i < size; i++) {\n const x = i - half;\n kernel[i] = Math.exp(-(x * x) / (2 * sigma * sigma));\n sum += kernel[i];\n }\n for (let i = 0; i < size; i++) kernel[i] /= sum;\n\n const result: (number | null)[] = new Array(data.length);\n for (let i = 0; i < data.length; i++) {\n if (data[i] === null) {\n result[i] = null;\n continue;\n }\n\n let val = 0;\n let weightSum = 0;\n for (let k = 0; k < size; k++) {\n const idx = i + k - half;\n if (idx >= 0 && idx < data.length && data[idx] !== null) {\n val += data[idx]! * kernel[k];\n weightSum += kernel[k];\n }\n }\n result[i] = weightSum > 0 ? val / weightSum : data[i];\n }\n return result;\n}\n\nexport function hexToRgba(hex: string, alpha: number = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, TrackPoint } from './parsers';\n\nexport const MapView = (() => {\n let trackData: Record = {};\n let customClickHandler: ((e: any) => boolean) | null = null;\n\n function init(\n onSelectCb: (id: string) => void,\n onMoveCb: (lat: number, lng: number, zoom: number) => void,\n onPointClickCb: (id: string, idx: number) => void,\n onPointHoverCb: (id: string | null, idx: number | null) => void,\n onDblClickCb: () => void,\n ) {}\n\n function switchBasemap(layer: string) {}\n function addTrack(t: TrackData) {\n trackData[t.id] = t;\n }\n function addTracks(ts: TrackData[]) {\n ts.forEach((t) => {\n trackData[t.id] = t;\n });\n }\n function removeTrack(id: string) {\n delete trackData[id];\n }\n function clearTracks() {\n trackData = {};\n }\n function removeAllTracks() {\n trackData = {};\n }\n function setTrackVisible(id: string, visible: boolean) {}\n function setSelectedTrack(id: string | null, fit: boolean) {}\n function fitAll() {}\n function fitTrack(id: string) {}\n function showCursorAt(lat: number, lon: number) {}\n function hideCursor() {}\n function highlightSegment(\n id: string | null,\n pts: TrackPoint[],\n start: number,\n end: number,\n fit?: boolean,\n colors?: string[] | null,\n ) {}\n function clearHighlight() {}\n function setTrackHover(id: string, hover: boolean) {}\n function ensureVisible(pts: any) {}\n function centerOn(lat: number, lon: number, zoom?: number | null, force?: boolean) {}\n function closePopup() {}\n function invalidateSize() {}\n function getPosition(): [number, number, number] {\n return [0, 0, 0];\n }\n function setPosition(lat: number, lng: number, zoom: number) {}\n function colorTrackByMetric(id: string, pts: TrackPoint[], colors: string[]) {}\n function clearMetricColor(id: string) {}\n\n function findTracksPassingThroughPoints(\n points: { lat: number; lng: number }[],\n radius: number,\n ): string[] {\n return Object.keys(trackData);\n }\n\n return {\n init,\n getMap: () => null as any,\n setCustomClickHandler: (handler: any) => {\n customClickHandler = handler;\n },\n switchBasemap,\n addTrack,\n addTracks,\n removeTrack,\n clearTracks,\n removeAllTracks,\n setTrackVisible,\n setSelectedTrack,\n fitAll,\n fitTrack,\n showCursorAt,\n hideCursor,\n highlightSegment,\n clearHighlight,\n setTrackHover,\n ensureVisible,\n centerOn,\n closePopup,\n invalidateSize,\n getPosition,\n setPosition,\n colorTrackByMetric,\n clearMetricColor,\n findTracksPassingThroughPoints,\n getTrackData: (id: string) => trackData[id],\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackPoint, TrackStats, TrackData } from './parsers';\nimport { gaussianSmooth, fmtSecs, hexToRgba, fmtPace } from './utils';\nimport { Zones } from './zones';\nimport { METRICS, MetricDefinition } from './metrics';\nimport { UrlState } from './url-state';\nimport { SPORTS } from './sports';\n\n// Augment uPlot to include our custom property\n\ninterface WegPlot extends uPlot {\n _strasse?: {\n selFill: HTMLElement;\n anchorLine: HTMLElement;\n anchorLabel: HTMLElement;\n anchorHandle: HTMLElement;\n anchorMarker: HTMLElement;\n endLine: HTMLElement;\n endLabel: HTMLElement;\n endHandle: HTMLElement;\n endMarker: HTMLElement;\n curYVal: HTMLElement;\n updateHeaderStats: (min: number, max: number) => void;\n };\n}\n\ninterface PlotData {\n uplot: WegPlot;\n row: HTMLDivElement;\n xData: number[];\n yData: (number | null)[];\n def: MetricDefinition;\n metricKey: string;\n statsTotalEl: HTMLDivElement;\n statsSelEl: HTMLDivElement;\n histCol: HTMLDivElement;\n histCanvas: HTMLCanvasElement;\n histData: HistData;\n hoveredHistY: number | null;\n pinnedHistY: number | null;\n smoothed?: boolean;\n incZero?: boolean;\n w?: number;\n}\n\ninterface HistData {\n yData: (number | null)[];\n xData: number[];\n def: MetricDefinition;\n BINS: number;\n plot?: PlotData;\n bins?: number[];\n binAccum?: number[];\n min?: number;\n max?: number;\n padL?: number;\n selBins?: number[] | null;\n selBinAccum?: number[] | null;\n _lastYData?: any;\n _lastSelRange?: [number, number] | null;\n fullStats?: { min: number; max: number; avg: number } | null;\n fullStatsAll?: { min: number; max: number; avg: number } | null;\n}\n\nexport const ChartView = (() => {\n let plots: PlotData[] = [];\n let renderedTrack: TrackData | null = null;\n let renderedXAxis: string = 'time';\n let renderedSpeedMode: string = 'speed';\n let renderedMapColorMetric: string | null = null;\n let syncKey: {\n key: string;\n sub: (u: uPlot) => void;\n unsub: (u: uPlot) => void;\n pub: (type: string, u: uPlot, x: number, y: number, w: number, h: number, i: number) => void;\n } | null = null;\n let scaleSyncing: boolean = false;\n let cursorSyncing: boolean = false;\n let activeMetrics: Set = new Set(['elevation']);\n let availableMetrics: Set = new Set();\n let smoothedMetrics: Set = new Set(['speed', 'gradient', 'vam', 'temperature']);\n let metricsIncludingZero: Set = new Set(['power']);\n let xAxis: string = 'time';\n let currentTrack: TrackData | null = null;\n let allTracks: TrackData[] = [];\n\n // Selection / anchor\n let selAnchorVal: number | null = null; // x-value at drag-start / zoom left edge\n let selEndVal: number | null = null; // x-value at zoom right edge\n let isDragging: boolean = false;\n let updatingRange: boolean = false; // guard against setScale hook re-entry during handle drag\n let pinnedPtIdx: number | null = null; // point index pinned by map click\n let lastMouseXVal: number | null = null; // last hovered x-value for keyboard zoom center\n let lastHistMouseEvent: MouseEvent | null = null;\n let hoveredHistData: HistData | null = null;\n let hoveredHistCanvas: HTMLCanvasElement | null = null;\n\n let currentXRange: [number, number] | null = null; // [min, max] currently rendered\n let targetXRange: [number, number] | null = null; // [min, max] for smooth keyboard animation\n let animId: number | null = null;\n\n // Callbacks\n let onCursorMoveCb: ((pt: TrackPoint | null) => void) | null = null;\n let onRangeChangeCb: ((min: number | null, max: number | null, axis: string) => void) | null =\n null;\n let onClickCb: ((pt: TrackPoint, idx: number) => void) | null = null;\n let onPinChangeCb: ((idx: number | null) => void) | null = null;\n\n const HIST_W: number = 130;\n const ROW_BODY_PADDING: number = 28; // 14px left + 14px right\n const HIST_GAP: number = 20; // margin-left on .hist-col\n let statsVisible: boolean = true;\n let histTooltipEl: HTMLElement | null = null;\n let container: HTMLElement | null = null;\n let emptyEl: HTMLElement | null = null;\n let selStatsEl: HTMLElement | null = null;\n let resetSelBtn: HTMLElement | null = null;\n let mapColorMetric: string | null = null;\n let onMapColorChangeCb: ((data: { pts: TrackPoint[]; colors: string[] } | null) => void) | null =\n null;\n\n // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function init(\n onCursorMove: (pt: TrackPoint | null) => void,\n onRangeChange: (min: number | null, max: number | null, axis: string) => void,\n onClick: (pt: TrackPoint, idx: number) => void,\n onPinChange: (idx: number | null) => void,\n ) {\n onCursorMoveCb = onCursorMove;\n onRangeChangeCb = onRangeChange;\n onClickCb = onClick;\n onPinChangeCb = onPinChange;\n container = document.getElementById('charts-container');\n container?.addEventListener('scroll', () => {\n if (lastHistMouseEvent && hoveredHistCanvas && hoveredHistData)\n updateHistTooltip(lastHistMouseEvent, hoveredHistCanvas, hoveredHistData);\n });\n emptyEl = document.getElementById('chart-empty');\n selStatsEl = document.getElementById('chart-stats-sel');\n resetSelBtn = document.getElementById('btn-reset-selection');\n histTooltipEl = document.getElementById('hist-tooltip');\n syncKey = uPlot.sync('strasse-sync');\n\n document.getElementById('sel-cancel-btn')?.addEventListener('click', cancelSelection);\n resetSelBtn?.classList.add('hidden');\n\n // \u2500\u2500 WASD Keyboard Navigation \u2500\u2500\n const navKeys = new Set(['w', 'a', 's', 'd']);\n const activeNavKeys = new Set();\n\n document.addEventListener('keydown', (e) => {\n if (!plots.length || !currentTrack) return;\n if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName || '')) return;\n\n const key = e.key.toLowerCase();\n if (!navKeys.has(key)) return;\n\n e.preventDefault();\n activeNavKeys.add(key);\n\n const u = plots[0].uplot;\n if (!targetXRange) targetXRange = [u.scales.x!.min!, u.scales.x!.max!];\n\n let [min, max] = targetXRange;\n const span = max - min;\n const moveStep = span * 0.1;\n const zoomFactor = 0.15;\n\n let newMin = min,\n newMax = max;\n\n if (key === 'a') {\n // Pan left\n newMin = min - moveStep;\n newMax = max - moveStep;\n } else if (key === 'd') {\n // Pan right\n newMin = min + moveStep;\n newMax = max + moveStep;\n } else if (key === 'w' || key === 's') {\n // Zoom\n const center = lastMouseXVal !== null ? lastMouseXVal : (min + max) / 2;\n const factor = key === 'w' ? 1 - zoomFactor : 1 + zoomFactor * 1.2;\n newMin = center - (center - min) * factor;\n newMax = center + (max - center) * factor;\n }\n\n // Clamp to track bounds\n const xFull = [plots[0].xData[0]!, plots[0].xData[plots[0].xData.length - 1]!];\n if (newMin < xFull[0]) {\n const d = xFull[0] - newMin;\n newMin += d;\n newMax += d;\n }\n if (newMax > xFull[1]) {\n const d = newMax - xFull[1];\n newMin -= d;\n newMax -= d;\n }\n newMin = Math.max(xFull[0], newMin);\n newMax = Math.min(xFull[1], newMax);\n\n if (newMax - newMin > 0.001) {\n targetXRange = [newMin, newMax];\n setVisibleRange(newMin, newMax, true); // true = animate\n }\n });\n\n document.addEventListener('keyup', (e) => {\n const key = e.key.toLowerCase();\n if (navKeys.has(key)) activeNavKeys.delete(key);\n });\n }\n\n function setVisibleRange(min: number, max: number, animate = false) {\n if (!plots.length) return;\n if (!animate) {\n plots.forEach(({ uplot: u }) => u.setScale('x', { min, max }));\n return;\n }\n\n const startMin = (currentXRange ? currentXRange[0] : plots[0].uplot.scales.x!.min) as number;\n const startMax = (currentXRange ? currentXRange[1] : plots[0].uplot.scales.x!.max) as number;\n\n if (animId) cancelAnimationFrame(animId);\n\n const lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n const factor = 0.25; // Smoothing factor\n\n const step = () => {\n if (!targetXRange) return;\n const [tMin, tMax] = targetXRange;\n\n const cMin = lerp(currentXRange![0], tMin, factor);\n const cMax = lerp(currentXRange![1], tMax, factor);\n\n plots.forEach(({ uplot: u }) => {\n u.setScale('x', { min: cMin, max: cMax });\n });\n\n if (Math.abs(cMin - tMin) > 0.0001 || Math.abs(cMax - tMax) > 0.0001)\n animId = requestAnimationFrame(step);\n else animId = null;\n };\n animId = requestAnimationFrame(step);\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function loadTrack(track: TrackData, others: TrackData[] = [], deferRender = false) {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n allTracks = others;\n\n // Detect which metrics are available in this file\n availableMetrics = new Set(\n Object.entries(METRICS)\n .filter(([, def]) => track.points.some((p) => p[def.field] != null))\n .map(([key]) => key),\n );\n\n // If no metrics are active (e.g. first load), default to core overview metrics\n if (activeMetrics.size === 0) {\n activeMetrics = new Set(['elevation'].filter((m) => availableMetrics.has(m)));\n }\n\n // Sync the pill buttons in the toolbar\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n const metric = pill.dataset.metric!;\n const isAvailable = availableMetrics.has(metric);\n pill.classList.toggle('active', isAvailable && activeMetrics.has(metric));\n pill.classList.toggle('disabled', !isAvailable);\n });\n\n currentTrack = track;\n if (deferRender) {\n updateStats(track);\n } else {\n render();\n }\n }\n\n function clear() {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n currentTrack = null;\n destroyPlots();\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
Select a track to view analysis
\n `;\n }\n const chartStats = document.getElementById('chart-stats');\n if (chartStats) chartStats.classList.add('hidden');\n clearSelectionStats();\n mapColorMetric = null;\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n }\n\n function resetState() {\n if (animId !== null) {\n cancelAnimationFrame(animId);\n animId = null;\n }\n activeMetrics = new Set(['elevation']);\n availableMetrics = new Set();\n smoothedMetrics = new Set(['speed', 'gradient', 'vam', 'temperature']);\n metricsIncludingZero = new Set(['power']);\n xAxis = 'time';\n allTracks = [];\n currentXRange = null;\n targetXRange = null;\n lastMouseXVal = null;\n lastHistMouseEvent = null;\n hoveredHistData = null;\n hoveredHistCanvas = null;\n statsVisible = true;\n clear();\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n pill.classList.remove('disabled', 'overflow-hidden');\n });\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.add('hidden');\n const toolbar = document.getElementById('chart-toolbar');\n if (toolbar) toolbar.classList.remove('collapsed');\n document.querySelectorAll('#x-axis-ctrl .seg-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.axis === 'time');\n });\n }\n\n function toggleMetric(key: string) {\n if (activeMetrics.has(key)) activeMetrics.delete(key);\n else activeMetrics.add(key);\n if (currentTrack) render(true);\n }\n\n function setActiveMetrics(keys: string[]) {\n activeMetrics = new Set(keys);\n if (currentTrack) render(true);\n // Sync the pill buttons\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n });\n }\n\n function setXAxis(axis: string) {\n if (xAxis === axis || !currentTrack) {\n xAxis = axis;\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n\n // Helper to convert a value from OLD axis to NEW axis\n const convert = (val: number | null) => {\n if (val === null) return null;\n // We need to find the point index closest to 'val' on the OLD axis\n let idx = 0;\n if (xAxis === 'distance') {\n const dTarget = val * 1000;\n idx = pts.findIndex((p) => (p.dist || 0) >= dTarget);\n } else {\n const tTarget = t0 + val * 1000;\n idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n }\n if (idx === -1) idx = pts.length - 1;\n\n // Now get the value at this index on the NEW axis\n if (axis === 'distance') return (pts[idx].dist || 0) / 1000;\n else return ((pts[idx].time || t0) - t0) / 1000;\n };\n\n // Convert selection\n if (selAnchorVal !== null) selAnchorVal = convert(selAnchorVal);\n if (selEndVal !== null) selEndVal = convert(selEndVal);\n\n // Convert zoom range (from first plot)\n let newRange: [number, number] | null = null;\n if (plots.length) {\n const u = plots[0].uplot;\n const r0 = convert(u.scales.x!.min!);\n const r1 = convert(u.scales.x!.max!);\n if (r0 !== null && r1 !== null) newRange = [r0, r1];\n }\n\n xAxis = axis;\n render(true);\n\n // Apply converted zoom\n if (newRange) {\n scaleSyncing = true;\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: newRange![0], max: newRange![1] }));\n });\n scaleSyncing = false;\n }\n }\n\n function toggleStats() {\n statsVisible = !statsVisible;\n plots.forEach(({ histCol }) => histCol.classList.toggle('visible', statsVisible));\n resize();\n }\n\n function setMapColorChangeCb(cb: (data: { pts: TrackPoint[]; colors: string[] } | null) => void) {\n onMapColorChangeCb = cb;\n }\n\n function toggleMapColor(key: string | null) {\n if (mapColorMetric === key || key === null) {\n mapColorMetric = null;\n _updateMapColorBtns();\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n } else {\n mapColorMetric = key;\n _updateMapColorBtns();\n _fireMapColorCb();\n }\n // Re-render to show/hide colored fills on the graphs\n if (currentTrack) render(true);\n }\n\n function _updateMapColorBtns() {\n document.querySelectorAll('.map-color-btn').forEach((el) => {\n const b = el as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === mapColorMetric);\n });\n }\n\n function _fireMapColorCb() {\n if (!onMapColorChangeCb || !mapColorMetric || !currentTrack) return;\n const plot = plots.find((p) => p.metricKey === mapColorMetric);\n if (!plot) return;\n const colors = _computePointColors(mapColorMetric, plot.yData);\n onMapColorChangeCb({ pts: currentTrack.points, colors });\n }\n\n function _computePointColors(key: string, yData: (number | null)[]): string[] {\n const vals = yData.filter((v): v is number => v != null && isFinite(v));\n if (!vals.length) return yData.map(() => '#888896');\n const min = Math.min(...vals),\n max = Math.max(...vals);\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n return yData.map((v) => {\n if (v == null || !isFinite(v)) return '#888896';\n if (key === 'gradient') return gradientColor(v);\n if (key === 'speed') {\n if (speedMode === 'pace') {\n const speed = (paceUnit === 'km' ? 1000 : 100) / v;\n return speedColor(speed);\n }\n return speedColor(v);\n }\n const t = max === min ? 0.5 : Math.max(0, Math.min(1, (v - min) / (max - min)));\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25);\n if (t <= 0.5) return lerpHex('#91bfdb', '#fee090', (t - 0.25) / 0.25);\n if (t <= 0.75) return lerpHex('#fee090', '#fc8d59', (t - 0.5) / 0.25);\n return lerpHex('#fc8d59', '#d73027', (t - 0.75) / 0.25);\n });\n }\n\n function resetZoom() {\n cancelSelection();\n }\n\n function cancelSelection() {\n selAnchorVal = null;\n selEndVal = null;\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n\n // Reset individual histogram pins\n plots.forEach((p) => {\n p.pinnedHistY = null;\n });\n\n updateSelOverlay();\n redrawHistograms();\n\n // Perform the actual zoom reset\n scaleSyncing = true;\n plots.forEach(({ uplot: u, xData }) => {\n u.batch(() => u.setScale('x', { min: xData[0]!, max: xData[xData.length - 1]! }));\n u._strasse?.updateHeaderStats(xData[0]!, xData[xData.length - 1]!);\n });\n scaleSyncing = false;\n\n if (onRangeChangeCb) onRangeChangeCb(null, null, xAxis);\n }\n\n function setSelectionStats(stats: TrackStats) {\n if (!selStatsEl) return;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt(\n 'sel-distance',\n stats.totalDist != null ? `${(stats.totalDist / 1000).toFixed(1)} km` : '\u2014',\n );\n fmt('sel-duration', stats.duration != null ? fmtSecs(Math.floor(stats.duration / 1000)) : '\u2014');\n fmt('sel-elevation', stats.elevGain != null ? `${Math.round(stats.elevGain)} m` : '\u2014');\n fmt(\n 'sel-avg-speed',\n stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014',\n );\n fmt('sel-avg-power', stats.avgPower != null ? `${stats.avgPower} W` : '\u2014');\n fmt('sel-avg-hr', stats.avgHR != null ? `${stats.avgHR} bpm` : '\u2014');\n fmt('sel-avg-temp', stats.avgTemp != null ? `${stats.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n selStatsEl.classList.remove('hidden');\n if (resetSelBtn) resetSelBtn.classList.remove('hidden');\n }\n\n function clearSelectionStats() {\n if (selStatsEl) selStatsEl.classList.add('hidden');\n if (resetSelBtn) resetSelBtn.classList.add('hidden');\n [\n 'sel-distance',\n 'sel-duration',\n 'sel-elevation',\n 'sel-avg-speed',\n 'sel-avg-power',\n 'sel-avg-hr',\n 'sel-avg-temp',\n ].forEach((id) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = '--';\n });\n }\n\n // Called on boot to restore a saved selection without re-firing onRangeChangeCb\n // xMin/xMax are ALWAYS provided in Time (seconds from start)\n function restoreSelection(tMin: number, tMax: number, deferRender = false) {\n if (!currentTrack) return;\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const totalDuration = ((pts[pts.length - 1]?.time || 0) - t0) / 1000;\n\n // If values look like absolute timestamps in ms, convert to seconds from start\n if (tMin > 1e12) tMin = (tMin - t0) / 1000;\n if (tMax > 1e12) tMax = (tMax - t0) / 1000;\n\n // Crop to max limits of the track\n tMin = Math.max(0, Math.min(tMin, totalDuration));\n tMax = Math.max(0, Math.min(tMax, totalDuration));\n\n const convert = (tOffset: number) => {\n if (xAxis === 'time') return tOffset;\n const tTarget = t0 + tOffset * 1000;\n let idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n if (idx === -1) idx = pts.length - 1;\n return (pts[idx].dist || 0) / 1000;\n };\n\n const xMin = convert(tMin);\n const xMax = convert(tMax);\n\n selAnchorVal = xMin;\n selEndVal = xMax;\n currentXRange = [xMin, xMax];\n if (deferRender) return;\n scaleSyncing = true; // suppress the setScale \u2192 onRangeChangeCb loop\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: xMin, max: xMax }));\n });\n scaleSyncing = false;\n updateAnchorLines();\n redrawHistograms();\n }\n\n function resize() {\n if (!plots.length || !container) return;\n const w = Math.round(\n Math.max(\n 100,\n container.getBoundingClientRect().width -\n ROW_BODY_PADDING -\n (statsVisible ? HIST_W + HIST_GAP : 0),\n ),\n );\n let anyResized = false;\n plots.forEach(({ uplot: u, histCanvas, histData }) => {\n if (w !== u.width) {\n u.setSize({ width: w, height: u.height });\n anyResized = true;\n if (statsVisible && histCanvas && histData) drawHistogram(histCanvas, histData, u.height);\n }\n });\n if (anyResized) updateSelOverlay();\n }\n\n // \u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function render(keepState = false) {\n let savedRange: [number, number] | null = null;\n let savedScroll = 0;\n if (keepState && container) savedScroll = container.scrollTop;\n\n if (keepState && currentXRange) {\n savedRange = [currentXRange[0], currentXRange[1]];\n } else if (keepState && plots.length) {\n const u = plots[0].uplot;\n savedRange = [u.scales.x!.min!, u.scales.x!.max!];\n }\n\n if (!currentTrack) {\n destroyPlots(keepState);\n return;\n }\n const pts = currentTrack.points;\n if (!pts.length) {\n destroyPlots(keepState);\n return;\n }\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n const available = [...activeMetrics].filter((m) =>\n pts.some((p) => p[METRICS[m].field] != null),\n );\n if (!available.length) {\n destroyPlots(keepState);\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
No data for selected metrics
\n `;\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n\n const containerW = container ? container.getBoundingClientRect().width : 800;\n const w = Math.round(\n Math.max(100, containerW - ROW_BODY_PADDING - (statsVisible ? HIST_W + HIST_GAP : 0)),\n );\n\n const canReuse =\n keepState &&\n renderedTrack === currentTrack &&\n renderedXAxis === xAxis &&\n renderedSpeedMode === speedMode &&\n renderedMapColorMetric === mapColorMetric &&\n plots.length > 0;\n\n let xData: (number | null)[];\n if (canReuse) {\n xData = plots[0].xData;\n } else if (xAxis === 'distance') {\n xData = pts.map((p) => (p.dist || 0) / 1000);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n let lastValidX = 0;\n xData = pts.map((p) => {\n if (p.time != null) {\n lastValidX = (p.time - t0) / 1000;\n return lastValidX;\n }\n return lastValidX; // monotonic fallback\n });\n }\n\n const existingByKey = new Map();\n if (canReuse) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const availSet = new Set(available);\n for (const p of plots) {\n const isSmoothed = smoothedMetrics.has(p.metricKey);\n const isIncZero = metricsIncludingZero.has(p.metricKey);\n if (\n availSet.has(p.metricKey) &&\n p.smoothed === isSmoothed &&\n p.incZero === isIncZero &&\n p.w === w\n ) {\n existingByKey.set(p.metricKey, p);\n } else {\n syncKey!.unsub(p.uplot);\n p.uplot.destroy();\n p.row.remove();\n }\n }\n plots = [];\n } else {\n destroyPlots(keepState);\n }\n\n if (container) {\n const nextSiblingRows: (HTMLElement | null)[] = new Array(available.length).fill(null);\n let nextExisting: HTMLElement | null = null;\n for (let i = available.length - 1; i >= 0; i--) {\n nextSiblingRows[i] = nextExisting;\n const ex = existingByKey.get(available[i]);\n if (ex) nextExisting = ex.row;\n }\n\n available.forEach((key, idx) => {\n const reused = existingByKey.get(key);\n if (reused) {\n plots.push(reused);\n const uplot = reused.uplot;\n const s = (uplot as any)._strasse;\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n uplot.batch(() => {\n if (\n savedRange &&\n (uplot.scales.x!.min !== savedRange[0] || uplot.scales.x!.max !== savedRange[1])\n ) {\n uplot.setScale('x', { min: savedRange[0], max: savedRange[1] });\n } else {\n s?.updateHeaderStats(uplot.scales.x!.min!, uplot.scales.x!.max!, uplot);\n uplot.redraw(false);\n }\n });\n scaleSyncing = prevSync;\n\n let initHoverBinI: number | null = null;\n if (\n pinnedPtIdx != null &&\n reused.xData[pinnedPtIdx] != null &&\n reused.yData[pinnedPtIdx] != null\n ) {\n buildHistBins(reused.histData);\n if (reused.histData.min != null && reused.histData.max != null) {\n const span = reused.histData.max - reused.histData.min || 1;\n initHoverBinI = Math.min(\n reused.histData.BINS - 1,\n Math.floor(\n ((reused.yData[pinnedPtIdx]! - reused.histData.min) / span) *\n reused.histData.BINS,\n ),\n );\n reused.hoveredHistY = reused.yData[pinnedPtIdx];\n }\n }\n drawHistogram(reused.histCanvas, reused.histData, 130, initHoverBinI);\n return;\n }\n\n let def = METRICS[key];\n\n let transform = def.transform;\n let fmt = def.fmt;\n let fmtAxis = def.fmtAxis;\n let unit = def.unit;\n let label = def.label;\n\n if (key === 'speed' && speedMode === 'pace') {\n label = 'Pace';\n unit = `min/${paceUnit}`;\n fmt = (v) => fmtPace(v);\n fmtAxis = (v) => fmtPace(v);\n transform = (v) => {\n if (v == null || v < 0.1) return null;\n return (paceUnit === 'km' ? 1000 : 100) / v;\n };\n\n def = { ...def, label, unit, fmt, fmtAxis, transform };\n }\n\n let yData = def.compute\n ? def.compute(pts, fillNulls)\n : fillNulls(\n pts.map((p) => {\n const v = p[def.field] as number;\n return v != null && transform ? transform(v) : v;\n }),\n );\n\n if (smoothedMetrics.has(key)) yData = gaussianSmooth(yData, def.smoothSigma || 2);\n\n createChart(key, def, xData, yData, w, pts, savedRange, nextSiblingRows[idx]);\n });\n }\n\n renderedTrack = currentTrack;\n renderedXAxis = xAxis;\n renderedSpeedMode = speedMode;\n renderedMapColorMetric = mapColorMetric;\n\n updateStats(currentTrack);\n // Restore anchor/end lines if a selection was active\n if (selAnchorVal != null && selEndVal != null) updateAnchorLines();\n // Re-apply map color if active\n _updateMapColorBtns();\n if (mapColorMetric) _fireMapColorCb();\n\n if (keepState && container && savedScroll > 0) container.scrollTop = savedScroll;\n }\n\n // \u2500\u2500 Create one chart row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function createChart(\n metricKey: string,\n def: MetricDefinition,\n xData: (number | null)[],\n yData: (number | null)[],\n w: number,\n pts: TrackPoint[],\n initialRange: [number, number] | null = null,\n insertBeforeEl: HTMLElement | null = null,\n ) {\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n\n // Gradient data: smooth over a 20 m distance window (\u00B110 m each side)\n const gradData = metricKey === 'elevation' ? smoothGradient(pts, 20) : null;\n const row = document.createElement('div');\n row.className = 'chart-row';\n row.dataset.metric = metricKey;\n row.style.setProperty('--chart-color', def.color);\n\n // Header\n const header = document.createElement('div');\n header.className = `chart-row-header${statsVisible ? ' with-histogram' : ''}`;\n\n const labelEl = document.createElement('div');\n labelEl.className = 'chart-row-label-group';\n labelEl.innerHTML = `\n ${def.icon}\n ${def.label}\n `;\n\n // Smoothing toggle\n const smoothBtn = document.createElement('button');\n smoothBtn.className = `icon-btn mini smooth-btn${smoothedMetrics.has(metricKey) ? ' active' : ''}`;\n smoothBtn.title = 'Toggle data smoothing';\n smoothBtn.innerHTML = `${smoothedMetrics.has(metricKey) ? 'blur_on' : 'blur_off'}`;\n smoothBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (smoothedMetrics.has(metricKey)) smoothedMetrics.delete(metricKey);\n else smoothedMetrics.add(metricKey);\n\n render(true); // Re-render all charts to keep sync if needed (though only this one changes data)\n });\n\n const mapColorBtn = document.createElement('button');\n\n mapColorBtn.className = `map-color-btn icon-btn${mapColorMetric === metricKey ? ' active' : ''}`;\n mapColorBtn.dataset.metric = metricKey;\n mapColorBtn.title = 'Color map track by this metric';\n mapColorBtn.innerHTML = 'colorize';\n mapColorBtn.addEventListener('click', () => toggleMapColor(metricKey));\n\n // Zero-filter toggle (Cadence/Power/Speed)\n let zeroBtn: HTMLButtonElement | null = null;\n if (metricKey === 'cadence' || metricKey === 'power' || metricKey === 'speed') {\n zeroBtn = document.createElement('button');\n const incZero = metricsIncludingZero.has(metricKey);\n zeroBtn.className = `icon-btn mini${incZero ? ' active' : ''}`;\n zeroBtn.title = incZero ? 'Currently INCLUDING 0 values' : 'Currently EXCLUDING 0 values';\n zeroBtn.innerHTML = `${incZero ? 'exposure_zero' : 'mobile_off'}`;\n zeroBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (metricsIncludingZero.has(metricKey)) metricsIncludingZero.delete(metricKey);\n else metricsIncludingZero.add(metricKey);\n render(true);\n });\n }\n\n const statsTotalEl = document.createElement('div');\n statsTotalEl.className = 'chart-stats-total';\n\n const statsSelEl = document.createElement('div');\n statsSelEl.className = 'chart-stats-selection';\n\n const statsContainer = document.createElement('div');\n statsContainer.className = 'chart-row-stats-container';\n statsContainer.append(statsTotalEl, statsSelEl);\n\n const actionsEl = document.createElement('div');\n actionsEl.className = 'chart-row-actions';\n actionsEl.append(smoothBtn, mapColorBtn);\n\n const rightActionsEl = document.createElement('div');\n rightActionsEl.className = 'chart-row-right-actions';\n\n if (metricKey === 'speed') {\n const paceToggle = document.createElement('div');\n paceToggle.className = 'seg-ctrl';\n paceToggle.innerHTML = `\n \n \n `;\n paceToggle.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const mode = btn.dataset.mode;\n if (mode === 'speed' || mode === 'pace') {\n const isDefault = mode === defaultMode;\n UrlState.patch({ speed_mode: isDefault ? null : mode });\n render(true);\n }\n });\n rightActionsEl.append(paceToggle);\n }\n\n if (zeroBtn) rightActionsEl.append(zeroBtn);\n\n header.append(labelEl, actionsEl, statsContainer, rightActionsEl);\n\n const rowBody = document.createElement('div');\n rowBody.className = 'chart-row-body';\n\n const plotEl = document.createElement('div');\n plotEl.style.position = 'relative';\n rowBody.appendChild(plotEl);\n\n const fixedMinLabel = document.createElement('div');\n fixedMinLabel.className = 'fixed-x-label fixed-x-min';\n const fixedMaxLabel = document.createElement('div');\n fixedMaxLabel.className = 'fixed-x-label fixed-x-max';\n plotEl.append(fixedMinLabel, fixedMaxLabel);\n\n const histCol = document.createElement('div');\n histCol.className = `hist-col${statsVisible ? ' visible' : ''}`;\n const histCanvas = document.createElement('canvas');\n histCanvas.className = 'hist-canvas';\n histCol.appendChild(histCanvas);\n rowBody.appendChild(histCol);\n\n row.append(header, rowBody);\n\n const isDistAxis = xAxis === 'distance';\n\n function formatX(v: number, range: number): string {\n if (v == null) return '';\n if (isDistAxis) {\n const dec = range < 1 ? 3 : range < 5 ? 2 : range < 20 ? 1 : 0;\n return `${v.toFixed(dec)} km`;\n } else {\n const absV = Math.abs(v);\n const h = Math.floor(absV / 3600);\n const m = Math.floor((absV % 3600) / 60);\n const s = Math.round(absV % 60);\n const hh = h > 0 ? `${h}:` : '';\n const mm = h > 0 ? String(m).padStart(2, '0') : String(m);\n const ss = String(s).padStart(2, '0');\n return `${v < 0 ? '-' : ''}${hh}${mm}:${ss}`;\n }\n }\n\n const incZeroDefault =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Compute global Y range and full-track stats in a single pass\n let gMin = Infinity,\n gMax = -Infinity,\n allSum = 0,\n allCount = 0,\n filtMin = Infinity,\n filtMax = -Infinity,\n filtSum = 0,\n filtCount = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n allSum += v;\n allCount++;\n if (v !== 0 || incZeroDefault) {\n if (v < filtMin) filtMin = v;\n if (v > filtMax) filtMax = v;\n filtSum += v;\n filtCount++;\n }\n }\n if (allCount === 0) {\n gMin = 0;\n gMax = 100;\n }\n const fullStatsAll = allCount ? { min: gMin, max: gMax, avg: allSum / allCount } : null;\n const fullStatsFiltered = filtCount\n ? { min: filtMin, max: filtMax, avg: filtSum / filtCount }\n : null;\n const gPad = Math.abs(gMax - gMin) * 0.1 || 1;\n const fixedYRange = [gMin - gPad, gMax + gPad];\n\n let statsTotalInitialized = false;\n\n // Per-range stats\n function updateHeaderStats(visibleMin: number, visibleMax: number, u?: uPlot) {\n const incZero =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Update fixed X labels\n const range = visibleMax - visibleMin;\n fixedMinLabel.textContent = formatX(visibleMin, range);\n fixedMaxLabel.textContent = formatX(visibleMax, range);\n\n const getHtml = (xMin: number, xMax: number, isFull = false) => {\n const s =\n isFull && incZero === incZeroDefault\n ? fullStatsFiltered\n : rangeStats(xData, yData, xMin, xMax, incZero);\n if (!s) return '';\n\n let h = `\n align_flex_end${def.fmt(s.min, true)} ${def.unit}\n align_center${def.fmt(s.avg, true)} ${def.unit}\n align_flex_start${def.fmt(s.max, true)} ${def.unit}\n `;\n\n if (metricKey === 'elevation') {\n const es = elevationRangeStats(pts, xMin, xMax);\n h += `\n trending_up+${Math.round(es.gain)} m\n trending_down-${Math.round(es.loss)} m\n `;\n }\n return h;\n };\n\n if (!statsTotalInitialized) {\n statsTotalInitialized = true;\n statsTotalEl.innerHTML = `all_inclusive${getHtml(\n xData[0]!,\n xData[xData.length - 1]!,\n true,\n )}`;\n statsTotalEl.querySelector('.all-chip')?.addEventListener('click', (e) => {\n e.stopPropagation();\n cancelSelection();\n });\n }\n\n if (selAnchorVal !== null && selEndVal !== null) {\n statsSelEl.innerHTML = getHtml(selAnchorVal, selEndVal, false);\n statsSelEl.style.display = 'flex';\n statsSelEl.style.setProperty('--sel-color', def.color);\n } else {\n statsSelEl.style.display = 'none';\n }\n }\n let initializingScale = false;\n const uOpts: uPlot.Options = {\n width: w,\n height: 130,\n padding: [4, 0, 0, 0],\n cursor: {\n sync: {\n key: syncKey!.key,\n },\n drag: { x: true, y: false, uni: 16 },\n focus: { prox: 16 },\n points: {\n size: 7,\n stroke: '#0e0e10',\n width: 2,\n fill: (metricKey === 'elevation'\n ? (u: uPlot, _si: number) => gradientColor(gradData ? gradData[u.cursor.idx!]! : null)\n : def.color) as any,\n },\n x: false,\n y: false,\n },\n select: {\n show: true,\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n },\n legend: { show: false },\n scales: {\n x: {\n time: false,\n range: (_u: uPlot, mn: number, mx: number) => [mn, mx],\n min: initialRange ? initialRange[0] : undefined,\n max: initialRange ? initialRange[1] : undefined,\n },\n y: {\n range: () => fixedYRange as [number, number],\n dir: metricKey === 'speed' && speedMode === 'pace' ? -1 : 1,\n },\n },\n axes: [\n {\n side: 2, // bottom\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: {\n show: true,\n stroke: '#2e2e34',\n },\n size: 30,\n space: 80,\n font: '10px system-ui, sans-serif',\n splits: (u: uPlot, axisIdx: number, scaleMin: number, scaleMax: number) => {\n const range = scaleMax - scaleMin;\n const width = u.bbox.width > 0 ? u.bbox.width : u.width;\n const targetLabels = width / 80;\n const idealIncr = range / targetLabels;\n\n let incrs;\n if (!isDistAxis) {\n // Time in seconds\n incrs = [\n 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 14400, 28800, 43200,\n 86400, 604800, 2592000, 31536000,\n ];\n } else {\n incrs = [\n 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000,\n 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000,\n ];\n }\n\n let incr = incrs[incrs.length - 1];\n for (let i = 0; i < incrs.length; i++) {\n if (incrs[i] >= idealIncr) {\n incr = incrs[i];\n break;\n }\n }\n\n const splits = [];\n let val = Math.ceil(scaleMin / incr) * incr;\n const precision = incr < 1 ? 2 : 0;\n\n while (val <= scaleMax) {\n const pos = u.valToPos(val, 'x', true);\n if (pos >= u.bbox.left + 80 && pos <= u.bbox.left + u.bbox.width - 80)\n splits.push(Number(val.toFixed(precision)));\n\n val += incr;\n }\n return splits;\n },\n values: ((_u: uPlot, vals: number[]) => {\n const range = (_u.scales.x?.max ?? 1) - (_u.scales.x?.min ?? 0);\n\n return vals.map((v) => {\n if (v == null) return '';\n const pos = _u.valToPos(v, 'x', true);\n // Strict 80px margin to prevent overlapping with fixed labels or Y axis\n if (pos < _u.bbox.left + 80 || pos > _u.bbox.left + _u.bbox.width - 80) return null;\n return formatX(v, range);\n });\n }) as any,\n },\n {\n side: 3, // left\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: { stroke: '#2e2e34' },\n size: 55,\n font: '10px system-ui, sans-serif',\n values: ((_u: uPlot, vals: number[]) =>\n vals.map((v) => (v != null ? def.fmtAxis(v) : ''))) as any,\n },\n ],\n series: [\n {},\n // Main selected track series\n {\n label: def.label,\n stroke: 'rgba(0,0,0,0)', // Stroke handled in draw hooks for layering\n width: 0,\n points: { show: false },\n paths: () => null,\n },\n ],\n hooks: {\n draw: [\n (u: uPlot) => {\n const top = u.bbox.top + u.bbox.height + 5; // 5px below plot area!\n fixedMinLabel.style.top = `${top}px`;\n fixedMinLabel.style.left = `${u.bbox.left}px`;\n\n fixedMaxLabel.style.top = `${top}px`;\n fixedMaxLabel.style.left = `${u.bbox.left + u.bbox.width}px`;\n fixedMaxLabel.style.transform = 'translateX(-100%)';\n },\n // 1. (bottom) Color / metric color of the selected track\n (u: uPlot) => {\n if (metricKey === 'gears') {\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n } else if (metricKey === 'elevation') {\n drawElevationGradient(u, xData as number[], yData as number[], gradData);\n } else if (metricKey === 'gradient') {\n drawGradientChart(u, xData as number[], yData as number[]);\n } else if (mapColorMetric === metricKey) {\n drawMetricColorFill(u, xData as number[], yData as number[], pts, metricKey);\n } else {\n // Normal colored line\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n }\n },\n\n // 2. Pinned point (middle)\n (u: uPlot) => {\n const plot = plots.find((p) => p.uplot === u);\n if (!plot) return;\n\n const s = (u as any)._strasse;\n // Priority 1: Global pinned point (all charts)\n if (pinnedPtIdx != null) {\n drawPinnedDot(u, xData, yData, def.color, def, pts, metricKey);\n } else {\n if (s && s.pinYVal) s.pinYVal.style.display = 'none';\n\n // Priority 2: Individual histogram pinned Y-pos (this chart only)\n if (plot.pinnedHistY != null)\n drawYAxisHighlight(u, xData, yData, plot.pinnedHistY, def.color, def);\n }\n },\n\n // 3. Pinned & Hover elements (labels, vertical lines)\n (u: uPlot) => {\n const hIdx = u.cursor.idx;\n const hasPinned = pinnedPtIdx != null;\n\n let hasHover = hIdx != null && u.cursor.left! >= 0;\n if (hasHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[hIdx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) hasHover = false;\n }\n\n // B. Draw Hover vertical line\n if (hasHover && hIdx !== pinnedPtIdx)\n drawVerticalLineOnly(u, pts, hIdx!, hexToRgba(def.color, 0.4), 1.0);\n\n // C. Bold selection x-axis line & span pill\n if (selAnchorVal != null && selEndVal != null) {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ax = u.valToPos(selAnchorVal, 'x', true);\n const ex = u.valToPos(selEndVal, 'x', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.lineWidth = 3 * dpr;\n ctx.strokeStyle = def.color;\n ctx.moveTo(ax, bb.top + bb.height);\n ctx.lineTo(ex, bb.top + bb.height);\n ctx.stroke();\n\n const span = Math.abs(selEndVal - selAnchorVal);\n const label = xAxis === 'distance' ? `${span.toFixed(2)} km` : fmtSecs(span);\n const fontSize = 9 * dpr;\n const fontStr = `bold ${fontSize}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n\n const visibleL = Math.max(bb.left, ax);\n const visibleR = Math.min(bb.left + bb.width, ex);\n const visibleW = visibleR - visibleL;\n\n if (visibleW > tw + 14 * dpr) {\n const padH = 5 * dpr;\n const padV = 2 * dpr;\n const bw = tw + padH * 2;\n const bh = fontSize + padV * 2;\n const bx = (visibleL + visibleR) / 2 - bw / 2;\n const by = bb.top + bb.height - bh / 2;\n\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = def.color;\n ctx.fill();\n\n ctx.fillStyle = '#000';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2);\n }\n ctx.restore();\n }\n\n // D. Draw label pills (on top)\n // Pinned labels first (semi-transparent)\n if (hasPinned) drawXAxisLabels(u, pts, pinnedPtIdx!, def.color, true, 0.7);\n\n // Hover labels last (fully opaque, topmost)\n if (hasHover && hIdx !== pinnedPtIdx)\n drawXAxisLabels(u, pts, hIdx!, def.color, true, 1.0);\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (scaleSyncing) return;\n const idx = u.cursor.idx;\n\n // Trigger redraw on cursor move to ensure custom canvas markers (hover lines/labels) update live\n // Note: uPlot handles cross-chart sync when syncKey is used.\n u.redraw(false);\n\n // Track current x-value for keyboard navigation\n if (u.cursor.left! >= 0) lastMouseXVal = u.posToVal(u.cursor.left!, 'x');\n else lastMouseXVal = null;\n\n // \u2500\u2500 Floating y-value next to cursor dot \u2500\u2500\n const s = (u as any)._strasse;\n let showHover = idx != null && yData[idx] != null;\n\n // Distance threshold: if no pinned point, check proximity to data line\n if (showHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[idx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) showHover = false;\n }\n\n if (s) {\n if (showHover)\n updateTooltip(\n u,\n s.curYVal,\n idx!,\n xData as number[],\n yData as number[],\n pts,\n def,\n metricKey,\n );\n else s.curYVal.style.display = 'none';\n }\n\n // Map marker\n if (!cursorSyncing) {\n if (idx != null && pts[idx]) {\n if (onCursorMoveCb && (pinnedPtIdx != null || showHover)) {\n onCursorMoveCb(pts[idx]);\n } else if (onCursorMoveCb && !showHover) {\n // If we're too far and nothing is pinned, hide map cursor\n onCursorMoveCb(null);\n }\n } else if (idx === null && onCursorMoveCb) {\n onCursorMoveCb(null);\n }\n }\n\n // Highlight matching histogram bucket\n if (idx != null && yData[idx] != null) {\n const { min, max } = histData;\n if (min != null && max != null) {\n const span = max - min || 1;\n const binI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[idx]! - min) / span) * histData.BINS),\n );\n if (plot.hoveredHistY !== yData[idx]) {\n plot.hoveredHistY = yData[idx];\n drawHistogram(histCanvas, histData, 130, binI);\n }\n }\n } else if (plot.hoveredHistY !== null) {\n plot.hoveredHistY = null;\n drawHistogram(histCanvas, histData, 130);\n }\n },\n ],\n\n setScale: [\n (u: uPlot, key: string) => {\n if (key !== 'x' || initializingScale) return;\n const { min, max } = u.scales.x!;\n\n // Sync currentXRange so keyboard navigation baseline is always accurate\n currentXRange = [min!, max!];\n\n // Update header stats for VISIBLE range\n updateHeaderStats(min as number, max as number, u);\n\n if (scaleSyncing) return;\n\n // Clear keyboard target when user interacts via mouse\n if (!updatingRange) targetXRange = null;\n\n // Sync sibling plots\n scaleSyncing = true;\n plots.forEach(({ uplot: other }) => {\n if (other !== u) other.batch(() => other.setScale('x', { min: min!, max: max! }));\n });\n scaleSyncing = false;\n\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb && selAnchorVal !== null)\n onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n },\n ],\n\n setSelect: [\n (u: uPlot) => {\n if (updatingRange) return;\n targetXRange = null;\n const { left, width } = u.select;\n if (width > 0) {\n const min = u.posToVal(left, 'x');\n const max = u.posToVal(left + width, 'x');\n selAnchorVal = min;\n selEndVal = max;\n\n // Sync stats to new selection\n updateHeaderStats(u.scales.x!.min!, u.scales.x!.max!, u);\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n\n // Clear uPlot's internal selection immediately so it doesn't block WASD/interaction\n u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);\n }\n },\n ],\n },\n };\n\n // \u2500\u2500 Overlay (pointer-events off except handles) \u2500\u2500\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5';\n\n // Selection fill\n const selFill = document.createElement('div');\n selFill.className = 'sel-fill';\n selFill.style.display = 'none';\n\n // Anchor line + label + drag handle\n const anchorLine = document.createElement('div');\n anchorLine.className = 'sel-line sel-line-anchor';\n anchorLine.style.display = 'none';\n\n const anchorLabel = document.createElement('div');\n anchorLabel.className = 'sel-line-label sel-line-label-anchor';\n anchorLabel.style.display = 'none';\n\n const anchorHandle = document.createElement('div');\n anchorHandle.className = 'sel-handle sel-handle-anchor';\n anchorHandle.style.display = 'none';\n\n const anchorMarker = document.createElement('div');\n anchorMarker.className = 'sel-graph-marker';\n anchorMarker.innerHTML =\n 'play_circle';\n anchorMarker.style.display = 'none';\n\n // End line + label + drag handle\n const endLine = document.createElement('div');\n endLine.className = 'sel-line sel-line-end';\n endLine.style.display = 'none';\n\n const endLabel = document.createElement('div');\n endLabel.className = 'sel-line-label sel-line-label-end';\n endLabel.style.display = 'none';\n\n const endHandle = document.createElement('div');\n endHandle.className = 'sel-handle sel-handle-end';\n endHandle.style.display = 'none';\n\n const endMarker = document.createElement('div');\n endMarker.className = 'sel-graph-marker';\n endMarker.innerHTML =\n 'stop_circle';\n endMarker.style.display = 'none';\n\n // Floating cursor y-value\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${def.color};display:none`;\n\n // Floating pinned y-value\n const pinYVal = document.createElement('div');\n pinYVal.className = 'cur-y-val pin';\n pinYVal.style.cssText = `color:${def.color};display:none`;\n\n overlay.append(\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n );\n\n const histData: HistData = {\n yData,\n xData: xData as number[],\n def,\n BINS: 24,\n min: allCount ? gMin : undefined,\n max: allCount ? gMax : undefined,\n fullStats: fullStatsFiltered,\n fullStatsAll,\n };\n const plot: PlotData = {\n uplot: null as any,\n row,\n xData: xData as number[],\n yData,\n def,\n metricKey,\n statsTotalEl,\n statsSelEl,\n histCol,\n histCanvas,\n histData,\n hoveredHistY: null,\n pinnedHistY: null,\n smoothed: smoothedMetrics.has(metricKey),\n incZero: metricsIncludingZero.has(metricKey),\n w,\n };\n histData.plot = plot; // Back-reference for tooltip to trigger redraws\n\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n const uplot = new uPlot(uOpts, [xData, yData] as any, (self, init) => {\n plot.uplot = self as WegPlot;\n plots.push(plot);\n plotEl.appendChild(self.root);\n self.over.appendChild(overlay);\n (self as any)._strasse = {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n updateHeaderStats,\n };\n self.batch(() => {\n init();\n });\n }) as WegPlot;\n scaleSyncing = prevSync;\n\n // \u2500\u2500 Handle drag \u2500\u2500\n attachHandleDrag(anchorHandle, uplot, xData, true);\n attachHandleDrag(endHandle, uplot, xData, false);\n\n // \u2500\u2500 Mouse listeners \u2500\u2500\n let mousedownX: number | null = null;\n uplot.over.addEventListener('mousedown', (e) => {\n if (e.button !== 0) return;\n isDragging = false;\n const rect = uplot.over.getBoundingClientRect();\n const xPx = e.clientX - rect.left;\n mousedownX = xPx;\n });\n uplot.over.addEventListener('mousemove', (e) => {\n if (mousedownX !== null) {\n const rect = uplot.over.getBoundingClientRect();\n if (Math.abs(e.clientX - rect.left - mousedownX) > 5) isDragging = true;\n }\n });\n uplot.over.addEventListener('mouseup', () => {\n mousedownX = null;\n });\n\n // Click to pin point (sticky selection)\n uplot.over.addEventListener('click', () => {\n if (isDragging) return;\n const idx = uplot.cursor.idx;\n if (idx != null && pts[idx]) {\n pinnedPtIdx = idx;\n plots.forEach(({ uplot: u }) => u.redraw(false));\n if (onClickCb) onClickCb(pts[idx], idx);\n if (onPinChangeCb) onPinChangeCb(idx);\n }\n });\n\n row.addEventListener('dblclick', cancelSelection);\n\n let initHoverBinI: number | null = null;\n if (pinnedPtIdx != null && xData[pinnedPtIdx] != null && yData[pinnedPtIdx] != null) {\n buildHistBins(histData);\n if (histData.min != null && histData.max != null) {\n const span = histData.max - histData.min || 1;\n initHoverBinI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[pinnedPtIdx]! - histData.min) / span) * histData.BINS),\n );\n plot.hoveredHistY = yData[pinnedPtIdx];\n }\n }\n\n drawHistogram(histCanvas, histData, 130, initHoverBinI);\n attachHistTooltip(histCanvas, histData);\n if (container) {\n if (insertBeforeEl) container.insertBefore(row, insertBeforeEl);\n else container.appendChild(row);\n }\n }\n\n // \u2500\u2500 Selection overlay (fill + lines + handles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateSelOverlay() {\n updateAnchorLines();\n // Redraw canvas markers (bold selection line + span pill)\n plots.forEach(({ uplot: u }) => u.batch(() => u.redraw(false)));\n }\n\n function updateAnchorLines() {\n plots.forEach(({ uplot: u, def }) => {\n const s = (u as any)._strasse;\n if (!s) return;\n const {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n } = s;\n if (selAnchorVal == null || selEndVal == null) {\n [\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n ].forEach((el: HTMLElement) => {\n el.style.display = 'none';\n });\n return;\n }\n const aX = u.valToPos(selAnchorVal, 'x');\n const eX = u.valToPos(selEndVal, 'x');\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const overW = bb.width / dpr;\n const overH = bb.height / dpr;\n const plotBottom = (bb.top + bb.height) / dpr;\n\n const isAnchorVisible = aX >= 0 && aX <= overW;\n const isEndVisible = eX >= 0 && eX <= overW;\n\n // Fill: clamp left/right to visible area\n const fillL = Math.max(0, aX);\n const fillR = Math.min(overW, eX);\n if (fillR > fillL) {\n selFill.style.left = `${fillL}px`;\n selFill.style.width = `${fillR - fillL}px`;\n selFill.style.top = '0';\n selFill.style.height = `${overH}px`;\n selFill.style.backgroundColor = hexToRgba(def.color, 0.07);\n selFill.style.display = '';\n } else {\n selFill.style.display = 'none';\n }\n\n // Anchor line\n if (isAnchorVisible) {\n anchorLine.style.left = `${aX}px`;\n anchorLine.style.height = `${overH}px`;\n anchorLine.style.borderLeftColor = def.color;\n anchorLine.style.display = '';\n // Anchor label\n const aText = fmtXVal(selAnchorVal);\n anchorLabel.textContent = aText;\n const aLabelW = aText.length * 7 + 10;\n anchorLabel.style.left = aX + aLabelW + 4 < overW ? `${aX + 3}px` : `${aX - aLabelW - 3}px`;\n anchorLabel.style.display = '';\n // Anchor handle\n anchorHandle.style.left = `${aX}px`;\n anchorHandle.style.backgroundColor = def.color;\n anchorHandle.style.display = '';\n // Anchor marker: centered on the bold line\n anchorMarker.style.left = `${aX}px`;\n anchorMarker.style.top = `${plotBottom}px`;\n const aIcon = anchorMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (aIcon) aIcon.style.color = def.color;\n anchorMarker.style.display = '';\n } else {\n [anchorLine, anchorLabel, anchorHandle, anchorMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n\n // End line\n if (isEndVisible) {\n endLine.style.left = `${eX}px`;\n endLine.style.height = `${overH}px`;\n endLine.style.borderLeftColor = def.color;\n endLine.style.display = '';\n // End label\n const eText = fmtXVal(selEndVal);\n endLabel.textContent = eText;\n const eLabelW = eText.length * 7 + 10;\n endLabel.style.left = eX - eLabelW - 3 > 0 ? `${eX - eLabelW - 3}px` : `${eX + 3}px`;\n endLabel.style.display = '';\n // End handle\n endHandle.style.left = `${eX}px`;\n endHandle.style.backgroundColor = def.color;\n endHandle.style.display = '';\n // End marker: centered on the bold line\n endMarker.style.left = `${eX}px`;\n endMarker.style.top = `${plotBottom}px`;\n const eIcon = endMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (eIcon) eIcon.style.color = def.color;\n endMarker.style.display = '';\n } else {\n [endLine, endLabel, endHandle, endMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n });\n }\n\n function fmtXVal(v: number) {\n return xAxis === 'distance' ? `${v.toFixed(2)} km` : fmtSecs(v);\n }\n\n // \u2500\u2500 Handle drag logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function attachHandleDrag(\n handleEl: HTMLElement,\n uplot: uPlot,\n xData: (number | null)[],\n isAnchor: boolean,\n ) {\n // pointer-events enabled on the handle itself\n handleEl.style.pointerEvents = 'auto';\n\n handleEl.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n const startX = e.clientX;\n const startVal = isAnchor ? selAnchorVal : selEndVal;\n const overW = uplot.over.offsetWidth;\n // px-per-data-unit at current zoom\n const xMin = uplot.scales.x!.min!,\n xMax = uplot.scales.x!.max!;\n const pxPerUnit = overW / (xMax - xMin);\n const xFull = [xData[0]!, xData[xData.length - 1]!];\n\n document.body.style.cursor = 'ew-resize';\n isDragging = true;\n\n function onMove(me: MouseEvent) {\n const dx = me.clientX - startX;\n let newVal = (startVal || 0) + dx / pxPerUnit;\n newVal = Math.max(xFull[0], Math.min(xFull[1], newVal));\n\n if (isAnchor) selAnchorVal = Math.min(newVal, (selEndVal || xFull[1]) - 0.001);\n else selEndVal = Math.max(newVal, (selAnchorVal || xFull[0]) + 0.001);\n\n // When dragging handles, we typically want to stay zoomed to the selection?\n // Actually, let's keep the zoom as is, and just update the selection overlay and stats.\n plots.forEach((p) =>\n (p.uplot as any)._strasse?.updateHeaderStats(\n p.uplot.scales.x!.min!,\n p.uplot.scales.x!.max!,\n ),\n );\n updateSelOverlay();\n redrawHistograms();\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n }\n\n function onUp() {\n document.body.style.cursor = '';\n isDragging = false;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n }\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n }\n\n // \u2500\u2500 Histogram logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function buildHistBins(histData: HistData) {\n const { yData, xData, BINS } = histData;\n\n // Cache to avoid re-binning every frame during hover\n if (histData._lastYData === yData && histData.bins) return;\n histData._lastYData = yData;\n\n let min = histData.min;\n let max = histData.max;\n if (min == null || max == null) {\n let lo = Infinity,\n hi = -Infinity,\n cnt = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < lo) lo = v;\n if (v > hi) hi = v;\n cnt++;\n }\n if (!cnt) return;\n min = lo;\n max = hi;\n histData.min = min;\n histData.max = max;\n }\n\n const bins = new Array(BINS).fill(0);\n const binAccum = new Array(BINS).fill(0); // accumulated x-weight per bin (time in s or dist in km)\n\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n bins[bi]++;\n\n // weight by x-delta\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n binAccum[bi] += (next - prev) / 2;\n }\n histData.bins = bins;\n histData.binAccum = binAccum;\n }\n\n function redrawHistograms() {\n plots.forEach(({ histCanvas, histData, uplot: u }) => {\n drawHistogram(histCanvas, histData, u.height);\n });\n }\n\n function drawHistogram(\n canvas: HTMLCanvasElement,\n histData: HistData,\n chartH: number,\n hoverBinI: number | null = null,\n ) {\n const { def, BINS } = histData;\n buildHistBins(histData);\n const { bins, min, max } = histData;\n if (!bins || min == null || max == null) return;\n\n const hasSel = selAnchorVal != null && selEndVal != null;\n\n // Compute selection bins if a range is active and changed\n if (\n hasSel &&\n (histData._lastSelRange?.[0] !== selAnchorVal || histData._lastSelRange?.[1] !== selEndVal)\n ) {\n histData._lastSelRange = [selAnchorVal!, selEndVal!];\n const selBins = new Array(BINS).fill(0);\n const selBinAccum = new Array(BINS).fill(0);\n const { yData, xData } = histData;\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const x = xData[i];\n if (x == null || x < selAnchorVal! || x > selEndVal!) continue;\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n selBins[bi]++;\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n selBinAccum[bi] += (next - prev) / 2;\n }\n histData.selBins = selBins;\n histData.selBinAccum = selBinAccum;\n } else if (!hasSel) {\n histData.selBins = null;\n histData.selBinAccum = null;\n histData._lastSelRange = null;\n }\n const selBins = histData.selBins;\n\n const dpr = window.devicePixelRatio || 1;\n const W = HIST_W;\n const H = chartH;\n\n // Performance: only set dimensions if they changed (resets canvas)\n if (canvas.width !== W * dpr || canvas.height !== H * dpr) {\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n }\n\n const ctx = canvas.getContext('2d')!;\n ctx.resetTransform();\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, W, H);\n\n const peak = Math.max(...bins);\n\n // Measure label width so bars start right after them\n const fmt = (v: number) => def.fmtAxis(v);\n const fontStr = '9px system-ui, sans-serif';\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const labelW = Math.ceil(\n Math.max(\n ctx.measureText(`${fmt(max)} ${def.unit}`).width,\n ctx.measureText(`${fmt(min)} ${def.unit}`).width,\n ),\n );\n\n // Vertical alignment with main graph:\n // uPlot padding: [4, 0, 0, 0]\n // Axis size: 30\n const pad = { t: 4, r: 0, b: 30, l: labelW + 6 };\n histData.padL = pad.l;\n const plotW = W - pad.l - pad.r;\n const plotH = H - pad.t - pad.b;\n\n // bin 0 = lowest values \u2192 drawn at bottom; bin BINS-1 = highest \u2192 drawn at top\n const binY = (i: number) => pad.t + (BINS - 1 - i) * (plotH / BINS);\n const binH = plotH / BINS - 1;\n\n // Full distribution (dimmed when selection active)\n const baseAlpha = hasSel ? 0.15 : 0.6;\n ctx.fillStyle = hexToRgba(def.color, baseAlpha);\n for (let i = 0; i < BINS; i++) {\n if (!bins[i]) continue;\n const bw = (bins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n\n // Selection overlay (bright)\n if (selBins) {\n ctx.fillStyle = hexToRgba(def.color, 0.85);\n for (let i = 0; i < BINS; i++) {\n if (!selBins[i]) continue;\n const bw = (selBins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n ctx.fillStyle = def.color;\n ctx.fillRect(pad.l, pad.t, 2, plotH);\n }\n\n // CDF overlay \u2014 smooth curve from bottom (0%) to top (100%)\n const total = bins.reduce((s, v) => s + v, 0);\n if (total > 0) {\n // Build CDF points: one per bin boundary, bottom\u2192top\n const pts2 = [{ x: pad.l, y: pad.t + plotH }];\n let cumSum = 0;\n for (let i = 0; i < BINS; i++) {\n cumSum += bins[i];\n pts2.push({ x: pad.l + (cumSum / total) * plotW, y: binY(i) });\n }\n\n ctx.beginPath();\n // CDF line is now solid\n ctx.setLineDash([]);\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 0.75 * dpr;\n ctx.lineJoin = 'round';\n ctx.moveTo(pts2[0].x, pts2[0].y);\n for (let i = 1; i < pts2.length - 1; i++) {\n const mx = (pts2[i].x + pts2[i + 1].x) / 2;\n const my = (pts2[i].y + pts2[i + 1].y) / 2;\n ctx.quadraticCurveTo(pts2[i].x, pts2[i].y, mx, my);\n }\n ctx.lineTo(pts2[pts2.length - 1].x, pts2[pts2.length - 1].y);\n ctx.stroke();\n\n // \u2500\u2500 Hover highlight on CDF \u2500\u2500\n if (hoverBinI != null && pts2[hoverBinI + 1]) {\n const cp = pts2[hoverBinI + 1];\n // Vertical line down\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(def.color, 0.6);\n ctx.moveTo(cp.x, cp.y);\n ctx.lineTo(cp.x, pad.t + plotH);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Dot: tiny precision point\n ctx.beginPath();\n ctx.arc(cp.x, cp.y, 1.2 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n }\n\n // Axis labels: max at top, min at bottom\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n const font9 = '9px system-ui, sans-serif';\n if (ctx.font !== font9) ctx.font = font9;\n ctx.textAlign = 'right';\n\n // Draw Max\n ctx.textBaseline = 'top';\n ctx.fillText(`${fmt(max)} ${def.unit}`, pad.l - 4, pad.t);\n\n // Draw Min\n ctx.textBaseline = 'bottom';\n ctx.fillText(`${fmt(min)} ${def.unit}`, pad.l - 4, H - pad.b);\n\n // Draw Avg (only if it doesn't overlap min/max)\n const stats =\n !hasSel && histData.fullStatsAll !== undefined\n ? histData.fullStatsAll\n : rangeStats(\n histData.xData,\n histData.yData,\n selAnchorVal || -Infinity,\n selEndVal || Infinity,\n );\n if (stats) {\n const avgY =\n pad.t +\n (BINS - 1 - Math.min(BINS - 1, Math.floor(((stats.avg - min) / (max - min || 1)) * BINS))) *\n (plotH / BINS);\n const minLabelY = H - pad.b;\n const maxLabelY = pad.t;\n const labelHeight = 10; // Approx 10px height for 9px font\n\n if (avgY > maxLabelY + labelHeight + 2 && avgY < minLabelY - labelHeight - 2) {\n ctx.textBaseline = 'middle';\n if (ctx.fillStyle !== '#aaa') ctx.fillStyle = '#aaa';\n ctx.fillText(`${fmt(stats.avg)} ${def.unit}`, pad.l - 4, avgY);\n // Draw small indicator tick\n ctx.beginPath();\n ctx.moveTo(pad.l - 3, avgY);\n ctx.lineTo(pad.l, avgY);\n if (ctx.strokeStyle !== '#aaa') ctx.strokeStyle = '#aaa';\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n }\n\n // \u2500\u2500 Higher/Lower percentages below histogram \u2500\u2500\n if (hoverBinI != null && total > 0) {\n let countLower = 0;\n for (let i = 0; i < hoverBinI; i++) countLower += bins[i];\n let countHigher = 0;\n for (let i = hoverBinI + 1; i < BINS; i++) countHigher += bins[i];\n\n const pLower = Math.round((countLower / total) * 100);\n const pHigher = Math.round((countHigher / total) * 100);\n\n ctx.save();\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const font8 = '8px system-ui, sans-serif';\n if (ctx.font !== font8) ctx.font = font8;\n\n const textY = H - pad.b + 6;\n\n // Draw \"Lower\" stat\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('LOWER', pad.l, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n const fontB10 = 'bold 10px system-ui, sans-serif';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pLower}%`, pad.l, textY + 10);\n\n // Draw \"Higher\" stat\n const midX = pad.l + plotW / 2;\n if (ctx.font !== font8) ctx.font = font8;\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('HIGHER', midX, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pHigher}%`, midX, textY + 10);\n\n ctx.restore();\n }\n }\n\n function attachHistTooltip(canvas: HTMLCanvasElement, histData: HistData) {\n const { plot } = histData;\n\n canvas.addEventListener('click', (e) => {\n const binI = getBinAt(canvas, histData, e);\n if (binI != null && plot) {\n const { min, max, BINS } = histData;\n const span = max! - min! || 1;\n plot.pinnedHistY = min! + (binI + 0.5) * (span / BINS!);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n }\n });\n\n canvas.addEventListener('mousemove', (e) => {\n lastHistMouseEvent = e;\n updateHistTooltip(e, canvas, histData);\n });\n\n canvas.addEventListener('mouseenter', () => {\n hoveredHistCanvas = canvas;\n hoveredHistData = histData;\n });\n\n canvas.addEventListener('mouseleave', () => {\n if (hoveredHistCanvas === canvas) {\n hoveredHistCanvas = null;\n hoveredHistData = null;\n }\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const lineEl = document.getElementById('hist-line');\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n });\n }\n\n function getBinAt(canvas: HTMLCanvasElement, histData: HistData, e: MouseEvent) {\n const { bins, BINS } = histData;\n if (!bins) return null;\n const rect = canvas.getBoundingClientRect();\n const relY = e.clientY - rect.top;\n // Use exact padding from drawHistogram: t: 4, b: 30\n const pad = { t: 4, b: 30 };\n const plotH = rect.height - pad.t - pad.b;\n const rawI = Math.floor(((relY - pad.t) / plotH) * BINS!);\n const binI = BINS! - 1 - rawI;\n if (rawI < 0 || rawI >= BINS!) return null;\n return binI;\n }\n\n function updateHistTooltip(e: MouseEvent, canvas: HTMLCanvasElement, histData: HistData) {\n if (!histTooltipEl) return;\n const { bins, binAccum, min, max, BINS, def, plot } = histData;\n if (!bins || !binAccum || min == null || max == null) return;\n\n const lineEl = document.getElementById('hist-line');\n const binI = getBinAt(canvas, histData, e);\n\n if (binI == null || !bins[binI]) {\n histTooltipEl.style.display = 'none';\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n return;\n }\n\n if (plot) {\n const span = max - min || 1;\n plot.hoveredHistY = min + (binI + 0.5) * (span / BINS!);\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1), binI);\n }\n\n const count = bins[binI];\n const total = bins.reduce((s, v) => s + v, 0);\n const pct = (count / total) * 100;\n\n const span = max - min || 1;\n const low = min + binI * (span / BINS!);\n const high = min + (binI + 1) * (span / BINS!);\n const label = `${def.fmt(low, true)} \u2013 ${def.fmt(high, true)} ${def.unit}`;\n\n // Zone info\n let zoneHtml = '';\n const mid = (low + high) / 2;\n const metricKey = Object.keys(METRICS).find((k) => METRICS[k] === def);\n let zones: any[] = [];\n if (metricKey === 'power') zones = Zones.getPowerZones();\n else if (metricKey === 'hr') zones = Zones.getHRZones();\n\n if (zones.length > 0) {\n const zIdx = zones.findIndex((z) => mid >= z.min && mid < z.max);\n const z =\n zIdx !== -1\n ? zones[zIdx]\n : mid >= zones[zones.length - 1].min\n ? zones[zones.length - 1]\n : null;\n if (z) {\n const finalZIdx = zIdx !== -1 ? zIdx : zones.length - 1;\n zoneHtml = `\n
\n Z${finalZIdx + 1}\n \u00B7\n ${z.name}\n
\n `;\n }\n }\n\n const totalAccum =\n xAxis === 'distance' ? `${binAccum[binI].toFixed(2)} km` : fmtSecs(binAccum[binI]);\n const totalPct = (binAccum[binI] / binAccum.reduce((s, v) => s + v, 0)) * 100;\n\n let html = `\n
${label}
\n ${zoneHtml}\n `;\n\n if (totalAccum) {\n html += `
\n ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${totalAccum}\n ${totalPct.toFixed(1)}%\n
`;\n }\n\n // Selection context\n if (histData.selBins && histData.selBinAccum) {\n const stotalAccum =\n xAxis === 'distance'\n ? `${histData.selBinAccum[binI].toFixed(2)} km`\n : fmtSecs(histData.selBinAccum[binI]);\n const stotalPct =\n (histData.selBinAccum[binI] / histData.selBinAccum.reduce((s, v) => s + v, 0)) * 100;\n\n html += `\n
\n Sel ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${stotalAccum}\n ${stotalPct.toFixed(1)}%\n
\n `;\n }\n\n histTooltipEl.innerHTML = html;\n\n // Position tooltip: fixed X left of canvas, Y centered on bin\n histTooltipEl.style.display = 'block';\n const ttH = histTooltipEl.offsetHeight;\n const ttW = histTooltipEl.offsetWidth;\n const rect = canvas.getBoundingClientRect();\n const plotH = rect.height - 4 - 30; // pad.t + pad.b\n const binCenterY = rect.top + 4 + (BINS! - 1 - binI + 0.5) * (plotH / BINS!);\n\n histTooltipEl.style.left = `${rect.left - ttW - 12}px`;\n histTooltipEl.style.top = `${binCenterY - ttH / 2}px`;\n\n // Horizontal line sync\n if (lineEl) {\n lineEl.style.display = 'block';\n lineEl.style.top = `${binCenterY}px`;\n lineEl.style.left = '0px';\n lineEl.style.width = `${rect.left}px`;\n }\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function destroyPlots(keepState = false) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n plots.forEach(({ uplot: u, row }) => {\n syncKey!.unsub(u);\n u.destroy();\n row.remove();\n });\n plots = [];\n renderedTrack = null;\n if (!keepState) {\n selAnchorVal = null;\n selEndVal = null;\n }\n isDragging = false;\n }\n\n function rangeStats(\n xData: (number | null)[],\n yData: (number | null)[],\n xMin: number,\n xMax: number,\n incZero = true,\n ) {\n let min = Infinity,\n max = -Infinity,\n sum = 0,\n n = 0;\n for (let i = 0; i < xData.length; i++) {\n if (xData[i] == null || xData[i]! < xMin || xData[i]! > xMax) continue;\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n if (v < min) min = v;\n if (v > max) max = v;\n sum += v;\n n++;\n }\n return n ? { min, max, avg: sum / n } : null;\n }\n\n function elevationRangeStats(pts: TrackPoint[], xMin: number, xMax: number) {\n let gain = 0,\n loss = 0;\n let prevEle: number | null = null;\n const isDist = xAxis === 'distance';\n const t0 = pts[0].time || 0;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const x = isDist ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n if (x < xMin || x > xMax) continue;\n\n if (p.ele != null) {\n if (prevEle != null) {\n const diff = p.ele - prevEle;\n if (diff > 0) gain += diff;\n else if (diff < 0) loss += Math.abs(diff);\n }\n prevEle = p.ele;\n }\n }\n return { gain, loss };\n }\n\n // \u2500\u2500 Plot Rendering Helpers (Canvas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateTooltip(\n u: WegPlot,\n el: HTMLElement,\n idx: number,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n def: MetricDefinition,\n metricKey: string,\n ) {\n if (idx == null || yData[idx] == null) {\n el.style.display = 'none';\n return;\n }\n\n const cx = u.valToPos(xData[idx]!, 'x', false);\n const cy = u.valToPos(yData[idx]!, 'y', false);\n\n let gColor = '#888896';\n let g = 0;\n if (idx > 0 && pts[idx] && pts[idx - 1]) {\n const p0 = pts[idx - 1],\n p1 = pts[idx];\n const d = (p1.dist || 0) - (p0.dist || 0);\n if (d > 0.1 && p1.ele != null && p0.ele != null) {\n g = ((p1.ele - p0.ele) / d) * 100;\n gColor = gradientColor(g);\n }\n }\n\n let content =\n metricKey !== 'elevation'\n ? `${def.fmt(yData[idx]!, false)} ${def.unit}`\n : `${def.fmt(yData[idx]!, false)} ${def.unit} \u2220 ${Math.abs(g).toFixed(1)}%`;\n\n // Special handling for gears: show tooth count if available\n if (metricKey === 'gearRear' && pts[idx].gearRearTooth != null) {\n content = `${pts[idx].gearRearTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gearFront' && pts[idx].gearFrontTooth != null) {\n content = `${pts[idx].gearFrontTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gears') {\n const p = pts[idx];\n const front =\n p.gearFrontTooth != null\n ? `${p.gearFrontTooth}T`\n : p.gearFront != null\n ? `pos ${p.gearFront}`\n : '';\n const rear =\n p.gearRearTooth != null\n ? `${p.gearRearTooth}T`\n : p.gearRear != null\n ? `pos ${p.gearRear}`\n : '';\n\n if (front || rear)\n content += ` (${front} / ${rear})`;\n }\n\n if (el.innerHTML !== content) el.innerHTML = content;\n\n const color44 = `${def.color}44`;\n if (el.style.color !== def.color) el.style.color = def.color;\n if (el.style.borderColor !== color44) el.style.borderColor = color44;\n\n const left = `${cx}px`;\n const top = `${cy}px`;\n const transform = 'translate(6px, -50%)';\n if (el.style.left !== left) el.style.left = left;\n if (el.style.top !== top) el.style.top = top;\n if (el.style.transform !== transform) el.style.transform = transform;\n if (el.style.display !== '') el.style.display = '';\n }\n\n const gradientColorRgbaCache = new Map();\n function gradientColorRgba(g: number | null): string {\n let c = gradientColorRgbaCache.get(g);\n if (!c) {\n c = hexToRgba(gradientColor(g), 0.8);\n gradientColorRgbaCache.set(g, c);\n }\n return c;\n }\n\n function drawElevationGradient(\n u: uPlot,\n xData: number[],\n yData: number[],\n gradData: (number | null)[] | null,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = gradData && gradData[i] != null ? Math.round(gradData[i]! / 2) * 2 : null;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawGradientChart(u: uPlot, xData: number[], yData: number[]) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = Math.round(yData[i]! / 2) * 2;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawHoverLine(u: uPlot, yData: number[], color: string, pts: TrackPoint[]) {\n const idx = u.cursor.idx;\n if (idx == null || yData[idx] == null || u.cursor.left! < 0) return;\n\n const t0 = pts[0].time || 0;\n const xVal = xAxis === 'distance' ? (pts[idx].dist || 0) / 1000 : (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yData[idx], 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Line from top to point + horizontal from left\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, cy);\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Dot at point\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n\n function drawVerticalLineOnly(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const xVal =\n xAxis === 'distance'\n ? (pts[idx].dist || 0) / 1000\n : (pts[idx].time! - (pts[0].time || 0)) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n // Dotted line range should match where labels are (flush top to bottom axis)\n ctx.moveTo(cx, bb.top + 16 * dpr);\n ctx.lineTo(cx, bb.top + bb.height + 10 * dpr);\n ctx.stroke();\n ctx.restore();\n }\n\n function drawXAxisLabels(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n skipLine = false,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const t0 = pts[0].time || 0;\n const distVal = (pts[idx].dist || 0) / 1000;\n const timeVal = (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xAxis === 'distance' ? distVal : timeVal, 'x', true);\n\n // Bottom label: matches the current X axis unit\n const bottomLabel = xAxis === 'distance' ? `${distVal.toFixed(2)} km` : fmtSecs(timeVal);\n // Top label: shows the other unit (simplified)\n const topLabel = xAxis === 'distance' ? fmtSecs(timeVal) : `${distVal.toFixed(2)} km`;\n\n const drawPill = (text: string, x: number, y: number, isTop: boolean) => {\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(text).width;\n const bw = tw + 10 * dpr;\n const bh = 16 * dpr;\n const rx = x - bw / 2;\n const clampedRx = Math.max(bb.left, Math.min(bb.left + bb.width - bw, rx));\n const ry = y - bh / 2;\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.setLineDash([]); // Ensure pills are not dashed\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(clampedRx, ry, bw, bh, 3 * dpr);\n else ctx.rect(clampedRx, ry, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.92)';\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, clampedRx + bw / 2, ry + bh / 2 + 0.5 * dpr);\n ctx.restore();\n };\n\n if (!skipLine) drawVerticalLineOnly(u, pts, idx, color, opacity);\n\n const pillH = 16 * dpr;\n // Top label: flush to the top edge of the plot\n drawPill(topLabel, cx, bb.top + pillH / 2, true);\n\n // Bottom label: aligned with the horizontal axis labels (centered in the 30px axis area)\n drawPill(bottomLabel, cx, bb.top + bb.height + 15 * dpr, false);\n }\n\n function drawPinnedDot(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n def: MetricDefinition,\n pts: TrackPoint[],\n metricKey: string,\n ) {\n if (pinnedPtIdx == null) return;\n const xVal = xData[pinnedPtIdx];\n const yVal = yData[pinnedPtIdx];\n if (xVal == null || yVal == null) return;\n\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n ctx.save();\n // Vertical line\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, bb.top + bb.height);\n ctx.stroke();\n\n // Horizontal dashed line\n ctx.beginPath();\n ctx.setLineDash([3 * dpr, 3 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.5);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Large Dot\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 5 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2.5 * dpr;\n ctx.stroke();\n ctx.restore();\n\n const s = (u as any)._strasse;\n if (s && s.pinYVal) {\n updateTooltip(\n u,\n s.pinYVal,\n pinnedPtIdx,\n xData as number[],\n yData as (number | null)[],\n pts,\n def,\n metricKey,\n );\n }\n }\n\n function drawYAxisHighlight(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n yVal: number,\n color: string,\n def: MetricDefinition,\n ) {\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const cy = u.valToPos(yVal, 'y', true);\n\n // Clamp cy to bbox\n const cyClamp = Math.max(bb.top, Math.min(bb.top + bb.height, cy));\n\n ctx.save();\n // Horizontal line\n ctx.beginPath();\n ctx.setLineDash([4 * dpr, 4 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cyClamp);\n ctx.lineTo(bb.left + bb.width, cyClamp);\n ctx.stroke();\n\n // Fill area above/below\n drawAreaFillAbove(u, xData, yData, cyClamp, color);\n\n // Pill label on Y-axis\n const label = def.fmt(yVal, true);\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n const bw = tw + 8 * dpr;\n const bh = 16 * dpr;\n const bx = bb.left - bw - 2 * dpr;\n const by = cyClamp - bh / 2;\n\n ctx.beginPath();\n ctx.setLineDash([]);\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.95)';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = '#fff';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2 + 0.5 * dpr);\n ctx.restore();\n }\n\n function drawAreaFillAbove(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n cyClamp: number,\n color: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.beginPath();\n\n let inSegment = false;\n let hasAnySegment = false;\n let lastPx = 0;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null || xv < xMin || xv > xMax) {\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n lastPx = px;\n\n if (py < cyClamp) {\n if (!inSegment) {\n ctx.moveTo(px, cyClamp);\n inSegment = true;\n hasAnySegment = true;\n }\n ctx.lineTo(px, py);\n } else if (inSegment) {\n ctx.lineTo(px, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n }\n\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n }\n\n if (hasAnySegment) {\n ctx.fill();\n }\n\n ctx.restore();\n }\n\n // \u2500\u2500 Utils \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function lerpHex(a: string, b: string, t: number) {\n const ah = parseInt(a.slice(1), 16),\n bh = parseInt(b.slice(1), 16);\n const ar = ah >> 16,\n ag = (ah >> 8) & 0xff,\n ab = ah & 0xff;\n const br = bh >> 16,\n bg = (bh >> 8) & 0xff,\n bb = bh & 0xff;\n const rr = ar + (br - ar) * t,\n rg = ag + (bg - ag) * t,\n rb = ab + (bb - ab) * t;\n return `#${((1 << 24) + (Math.round(rr) << 16) + (Math.round(rg) << 8) + Math.round(rb))\n .toString(16)\n .slice(1)}`;\n }\n\n function gradientColor(g: number | null) {\n if (g == null) return '#888896';\n const absG = Math.abs(g);\n const t = Math.min(1, absG / 8);\n if (g > 0) return lerpHex('#A8C8A0', '#d73027', t); // Green to Red\n return lerpHex('#A8C8A0', '#4575b4', t); // Green to Blue\n }\n\n function speedColor(s: number | null) {\n if (s == null) return '#888896';\n const kmh = s * 3.6;\n\n if (kmh <= 5) return '#4575b4'; // Solid Blue for very slow\n if (kmh >= 60) return '#d73027'; // Solid Red for very fast\n\n // High resolution between 5 and 45 (10km/h per segment)\n if (kmh <= 45) {\n const t = (kmh - 5) / 40; // 0 to 1\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); // 5-15: Blue -> LBlue\n if (t <= 0.5) return lerpHex('#91bfdb', '#abdda4', (t - 0.25) / 0.25); // 15-25: LBlue -> Green\n if (t <= 0.75) return lerpHex('#abdda4', '#fee08b', (t - 0.5) / 0.25); // 25-35: Green -> Yellow\n return lerpHex('#fee08b', '#fc8d59', (t - 0.75) / 0.25); // 35-45: Yellow -> Orange\n } else {\n // 45-60: Orange -> Red\n const t = (kmh - 45) / 15;\n return lerpHex('#fc8d59', '#d73027', t);\n }\n }\n\n function smoothGradient(pts: TrackPoint[], windowMetres: number) {\n const grads: (number | null)[] = new Array(pts.length).fill(null);\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n let j0 = i,\n j1 = i;\n while (j0 > 0 && (p.dist || 0) - (pts[j0].dist || 0) < windowMetres / 2) j0--;\n while (j1 < pts.length - 1 && (pts[j1].dist || 0) - (p.dist || 0) < windowMetres / 2) j1++;\n const d = (pts[j1].dist || 0) - (pts[j0].dist || 0);\n if (d > 1 && pts[j1].ele != null && pts[j0].ele != null)\n grads[i] = ((pts[j1].ele! - pts[j0].ele!) / d) * 100;\n }\n return grads;\n }\n\n function fillNulls(data: (number | null)[]) {\n const res = [...data];\n for (let i = 0; i < res.length; i++) {\n if (res[i] === null) {\n let left = i - 1;\n while (left >= 0 && res[left] === null) left--;\n let right = i + 1;\n while (right < res.length && res[right] === null) right++;\n if (left >= 0 && right < res.length)\n res[i] = res[left]! + ((res[right]! - res[left]!) * (i - left)) / (right - left);\n else if (left >= 0) res[i] = res[left];\n else if (right < res.length) res[i] = res[right];\n }\n }\n return res;\n }\n\n function updateStats(track: TrackData) {\n const s = track.stats;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt('stat-distance', s.totalDist != null ? `${(s.totalDist / 1000).toFixed(1)} km` : '\u2014');\n fmt('stat-duration', s.duration != null ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014');\n fmt('stat-elevation', s.elevGain != null ? `${Math.round(s.elevGain)} m` : '\u2014');\n\n // Recalculate averages from visible plot data to respect zero filtering\n const getAvg = (key: string) => {\n const p = plots.find((p) => p.metricKey === key);\n if (!p) {\n if (key === 'speed') return s.avgSpeed ?? null;\n if (key === 'power') return s.avgPower ?? null;\n if (key === 'cadence') return s.avgCadence ?? null;\n return null;\n }\n if (p.histData.fullStats !== undefined) {\n return p.histData.fullStats ? p.histData.fullStats.avg : null;\n }\n const incZero =\n metricsIncludingZero.has(key) || (key !== 'power' && key !== 'cadence' && key !== 'speed');\n const vals = p.yData.filter((v): v is number => v != null && (incZero || v !== 0));\n if (!vals.length) return null;\n return vals.reduce((a, b) => a + b, 0) / vals.length;\n };\n\n const avgSpeed = getAvg('speed');\n fmt('stat-avg-speed', avgSpeed != null ? `${(avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014');\n\n const avgPower = getAvg('power');\n fmt('stat-avg-power', avgPower != null ? `${Math.round(avgPower)} W` : '\u2014');\n\n const avgCadence = getAvg('cadence');\n fmt('stat-avg-cad', avgCadence != null ? `${Math.round(avgCadence)} rpm` : '\u2014');\n\n fmt('stat-avg-hr', s.avgHR != null ? `${s.avgHR} bpm` : '\u2014');\n fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n }\n\n const INTERVAL_CAP = 16384;\n const ivPwr = new Float64Array(INTERVAL_CAP);\n const ivHr = new Float64Array(INTERVAL_CAP);\n const ivSpd = new Float64Array(INTERVAL_CAP);\n const ivEle = new Float64Array(INTERVAL_CAP);\n const ivCad = new Float64Array(INTERVAL_CAP);\n const ivSmoothed = new Float64Array(INTERVAL_CAP);\n const ivKdeBins = new Float64Array(64);\n const intervalWindows = [\n 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, 360,\n ];\n\n function analyzeTelemetryIntervals(\n tracksList: TrackData[],\n selStartSec: number,\n selEndSec: number,\n ) {\n if (!tracksList.length) return 0;\n ivKdeBins.fill(0);\n let intervalScore = 0;\n\n for (let ti = 0; ti < tracksList.length; ti++) {\n const pts = tracksList[ti].points;\n const n = Math.min(pts.length, INTERVAL_CAP);\n if (n < 4) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n ivPwr[i] = p.power || 0;\n ivHr[i] = p.hr || 0;\n ivSpd[i] = p.speed || 0;\n ivEle[i] = p.ele || 0;\n ivCad[i] = p.cad || 0;\n }\n\n // Multi-band Savitzky-Golay 5-point quadratic smoothing, Gaussian kernel density,\n // and spectral cadence-HR harmonic analysis\n const sStart = Math.max(0, Math.min(n - 1, Math.floor(selStartSec)));\n const sEnd = Math.max(sStart + 1, Math.min(n, Math.floor(selEndSec)));\n const inv35 = 1 / 35;\n\n for (let pass = 0; pass < 65; pass++) {\n const weightPwr = 1.0 + pass * 0.02;\n const weightHr = 0.8 + pass * 0.015;\n const invSigmaSq = 1 / (180 + pass * 25);\n const omega = 0.012 + pass * 0.0015;\n for (let i = 2; i < n - 2; i++) {\n const sgPwr =\n (-3 * ivPwr[i - 2] +\n 12 * ivPwr[i - 1] +\n 17 * ivPwr[i] +\n 12 * ivPwr[i + 1] -\n 3 * ivPwr[i + 2]) *\n inv35;\n const sgHr =\n (-3 * ivHr[i - 2] +\n 12 * ivHr[i - 1] +\n 17 * ivHr[i] +\n 12 * ivHr[i + 1] -\n 3 * ivHr[i + 2]) *\n inv35;\n const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25;\n const dP = sgPwr - ivPwr[i];\n const gauss = Math.exp(-dP * dP * invSigmaSq);\n const harmonic = Math.cos(i * omega + ivCad[i] * 0.02);\n ivSmoothed[i] =\n sgPwr * weightPwr * gauss + sgHr * weightHr + sgSpd * (ivCad[i] * 0.1 + harmonic);\n }\n\n for (let wi = 0; wi < intervalWindows.length; wi++) {\n const w = intervalWindows[wi];\n if (w >= n) continue;\n const invW = 1 / w;\n let winSum = 0;\n let winEle = 0;\n let maxInterval = 0;\n for (let i = 0; i < n; i++) {\n winSum += ivSmoothed[i];\n winEle += ivEle[i];\n if (i >= w) {\n winSum -= ivSmoothed[i - w];\n winEle -= ivEle[i - w];\n const avg = (winSum + winEle * 0.05) * invW;\n if (avg > maxInterval) maxInterval = avg;\n }\n }\n intervalScore += maxInterval * 1e-4;\n }\n\n // Range-selection Kernel Density Estimation (KDE) binning\n for (let i = sStart; i < sEnd; i++) {\n const norm = Math.max(0, Math.min(63, ((ivSmoothed[i] * 0.12) | 0) & 63));\n ivKdeBins[norm] += 1 + (ivEle[i] - ivEle[sStart]) * 1e-3;\n if (norm > 0) ivKdeBins[norm - 1] += 0.5;\n if (norm < 63) ivKdeBins[norm + 1] += 0.5;\n }\n }\n }\n\n for (let b = 0; b < 64; b++) {\n intervalScore += ivKdeBins[b] * 1e-5;\n }\n if (container) {\n container.dataset.intervalScore = intervalScore.toFixed(2);\n }\n return intervalScore;\n }\n\n return {\n init,\n loadTrack,\n clear,\n resetState,\n toggleMetric,\n setXAxis,\n toggleStats,\n setSelectionStats,\n clearSelectionStats,\n restoreSelection,\n resetZoom,\n cancelSelection,\n analyzeTelemetryIntervals,\n setCursorAt: (idx: number, deferRender = false) => {\n pinnedPtIdx = idx;\n if (onPinChangeCb) onPinChangeCb(idx);\n if (deferRender) {\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n return;\n }\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n },\n setHoverAt: (idx: number | null) => {\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (idx === null) {\n u.batch(() => {\n (u as any).setCursor({ left: -10, top: -10 }, true, false);\n });\n } else if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb) {\n onCursorMoveCb(\n idx != null && currentTrack?.points?.[idx] ? currentTrack.points[idx] : null,\n );\n }\n },\n clearPinnedDot: () => {\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n },\n resize,\n METRICS,\n isDragging: () => isDragging,\n setMapColorChangeCb,\n toggleMapColor,\n getMapColorMetric: () => mapColorMetric,\n getActiveMetrics: () => activeMetrics,\n getAvailableMetrics: () => availableMetrics,\n setActiveMetrics,\n updateMetricOrder: (keys: string[]) => {\n // Keys might only contain current active ones, or more.\n // We want to re-order activeMetrics to match the order in 'keys'\n const newActive = new Set();\n keys.forEach((k) => {\n if (activeMetrics.has(k)) newActive.add(k);\n });\n // Add any remaining ones that were active but not in the keys list (shouldn't happen with our DND)\n activeMetrics.forEach((k) => {\n if (!newActive.has(k)) newActive.add(k);\n });\n activeMetrics = newActive;\n if (currentTrack) render(true);\n },\n getXAxis: () => xAxis,\n };\n\n function drawMetricColorFill(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n metricKey: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const colors = _computePointColors(metricKey, yData);\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (let i = 1; i < xData.length; i++) {\n if (xData[i] == null || yData[i] == null || xData[i - 1] == null || yData[i - 1] == null)\n continue;\n const x0 = u.valToPos(xData[i - 1]!, 'x', true);\n const y0 = u.valToPos(yData[i - 1]!, 'y', true);\n const x1 = u.valToPos(xData[i]!, 'x', true);\n const y1 = u.valToPos(yData[i]!, 'y', true);\n\n const c = colors[i];\n\n // Top line segment\n ctx.beginPath();\n ctx.moveTo(x0, y0);\n if (isStepped) ctx.lineTo(x1, y0);\n\n ctx.lineTo(x1, y1);\n ctx.strokeStyle = c;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawBackgroundTracks(u: uPlot, metricKey: string, def: MetricDefinition) {\n if (!allTracks.length) return;\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (const track of allTracks) {\n if (currentTrack && track.id === currentTrack.id) continue;\n\n const pts = track.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const field = def.field;\n\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)'; // Extremely faint\n ctx.lineWidth = 1 * dpr;\n\n let first = true;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const v = p[field] as number;\n\n if (v == null) {\n first = true;\n continue;\n }\n\n if (i > 0) {\n const prev = pts[i - 1];\n const dt = p.time && prev.time ? p.time - prev.time : 0;\n if (dt > GAP_THRESHOLD) first = true;\n }\n\n const val = def.transform ? def.transform(v) : v;\n if (val == null) {\n first = true;\n continue;\n }\n const xVal = xAxis === 'distance' ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n\n // Skip if way outside horizontal range\n if (xVal < u.scales.x!.min! - 10 || xVal > u.scales.x!.max! + 10) {\n first = true;\n continue;\n }\n\n const px = u.valToPos(xVal, 'x', true);\n const py = u.valToPos(val, 'y', true);\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevP = pts[i - 1];\n const prevXVal =\n xAxis === 'distance' ? (prevP.dist || 0) / 1000 : (prevP.time! - t0) / 1000;\n ctx.lineTo(u.valToPos(prevXVal, 'x', true), py);\n }\n ctx.lineTo(px, py);\n }\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawTrackPath(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n width: number,\n metricKey: string,\n range: [number, number] | null = null,\n pts: TrackPoint[] = [],\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = hexToRgba(color, 0.8);\n ctx.lineWidth = width * dpr;\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n let first = true;\n let lastFrontGear: number | null = null;\n let fMin = 1;\n let fMax = 1;\n\n if (metricKey === 'gears' && pts.length > 0) {\n let lo = Infinity,\n hi = -Infinity;\n for (let i = 0; i < pts.length; i++) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null) {\n if (fg < lo) lo = fg;\n if (fg > hi) hi = fg;\n }\n }\n if (lo <= hi) {\n fMin = lo;\n fMax = hi;\n }\n }\n\n const rMin = range ? range[0] : (u.scales.x?.min ?? -Infinity);\n const rMax = range ? range[1] : (u.scales.x?.max ?? Infinity);\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = !range ? u.series[0]?.idxs : null;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step =\n isStepped || metricKey === 'gears' ? 1 : Math.max(1, Math.floor((iEnd - iStart) / 250));\n const isTimeAxis = xAxis === 'time';\n const gapSec = GAP_THRESHOLD / 1000;\n let prevDrawnI = iStart;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null) {\n first = true;\n continue;\n }\n\n if (metricKey === 'gears' && pts[i]) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null && fg !== lastFrontGear) {\n if (!first && i > 0) {\n ctx.stroke();\n ctx.beginPath();\n const prevX = bb.left + (xData[prevDrawnI]! - xMin) * xScale;\n const prevY = yBase + (yData[prevDrawnI]! - yMin) * yMult;\n ctx.moveTo(prevX, prevY);\n }\n\n // Compute color\n let segmentColor = color;\n if (fMax !== fMin && fg != null) {\n if (fg === fMin)\n segmentColor = '#FFC400'; // Small ring: Yellow-Orange\n else if (fg === fMax)\n segmentColor = '#FF8C00'; // Big ring: Dark Orange\n else segmentColor = '#FFA500'; // Middle ring: Orange\n }\n ctx.strokeStyle = hexToRgba(segmentColor, 0.8);\n lastFrontGear = fg;\n }\n }\n\n // Check gap\n if (i > iStart && isTimeAxis) {\n const prevXv = xData[prevDrawnI];\n if (prevXv != null && xv - prevXv > gapSec) first = true;\n }\n\n // Check range (or visible x-scale bounds)\n if (xv < rMin || xv > rMax) {\n first = true;\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevXv = xData[prevDrawnI]!;\n ctx.lineTo(bb.left + (prevXv - xMin) * xScale, py);\n }\n ctx.lineTo(px, py);\n }\n prevDrawnI = i;\n }\n ctx.stroke();\n ctx.restore();\n }\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { Parsers } from './parsers';\n\nexport interface ZoneRange {\n name: string;\n min: number;\n max: number;\n color: string;\n}\n\nexport const Zones = (() => {\n function getPowerZones(): ZoneRange[] {\n const ftp = Parsers.getFTP();\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n const names = [\n 'Active Recovery',\n 'Endurance',\n 'Tempo',\n 'Threshold',\n 'VO2 Max',\n 'Anaerobic',\n 'Neuromuscular',\n ];\n const colors = ['#82E0AA', '#A8C8A0', '#F7DC6F', '#F8C471', '#F39C12', '#E67E22', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[6], min: last, max: Infinity, color: colors[6] });\n return zones;\n }\n\n function getHRZones(): ZoneRange[] {\n const thresholds = Parsers.getHRZones();\n const names = ['Recovery', 'Aerobic', 'Tempo', 'Threshold', 'Anaerobic'];\n const colors = ['#82E0AA', '#F7DC6F', '#F8C471', '#FF6B6B', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[4], min: last, max: Infinity, color: colors[4] });\n return zones;\n }\n\n return {\n getPowerZones,\n getHRZones,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackPoint } from './parsers';\n\nexport interface MetricDefinition {\n label: string;\n field: keyof TrackPoint;\n unit: string;\n color: string;\n abbr: string;\n icon: string;\n fmt: (v: number, precise?: boolean) => string;\n fmtAxis: (v: number) => string;\n compute?: (\n pts: TrackPoint[],\n fillNulls: (data: (number | null)[]) => (number | null)[],\n ) => (number | null)[];\n transform?: (v: number) => number | null;\n smoothSigma?: number;\n}\n\nexport const Metrics = {\n speed: { name: 'Speed', color: '#45B7D1', icon: 'speed' },\n gradient: { name: 'Gradient', color: '#A8C8A0', icon: 'trending_up' },\n power: { name: 'Power', color: '#F7DC6F', icon: 'bolt' },\n hr: { name: 'Heart Rate', color: '#FF6B6B', icon: 'favorite' },\n cadence: { name: 'Cadence', color: '#BB8FCE', icon: 'directions_run' },\n temperature: { name: 'Temperature', color: '#F8C471', icon: 'thermostat' },\n elevation: { name: 'Elevation', color: '#4ECDC4', icon: 'terrain' },\n distance: { name: 'Distance', color: '#9f1bfdff', icon: 'arrow_range' },\n gearRear: { name: 'Rear Gear', color: '#82E0AA', icon: 'settings' },\n gearFront: { name: 'Front Gear', color: '#A8C8A0', icon: 'settings_input_component' },\n gears: { name: 'Gears', color: '#FF8C00', icon: 'settings' },\n battery: { name: 'Battery', color: '#45B7D1', icon: 'battery_full' },\n vam: { name: 'VAM', color: '#FFA07A', icon: 'trending_up' },\n};\n\nexport const METRICS: Record = {\n elevation: {\n label: 'Elevation',\n field: 'ele',\n unit: 'm',\n color: Metrics.elevation.color,\n abbr: 'ele',\n icon: Metrics.elevation.icon,\n fmt: (v, p) => (p ? v.toFixed(1) : Math.round(v).toString()),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n speed: {\n label: 'Speed',\n field: 'speed',\n unit: 'km/h',\n color: Metrics.speed.color,\n abbr: 'spd',\n icon: Metrics.speed.icon,\n fmt: (v) => (v * 3.6).toFixed(1),\n fmtAxis: (v) => (v * 3.6).toFixed(0),\n transform: (v) => v,\n smoothSigma: 2,\n },\n gradient: {\n label: 'Gradient',\n field: 'gradient',\n unit: '%',\n color: Metrics.gradient.color,\n abbr: 'grad',\n icon: Metrics.gradient.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => v.toFixed(0),\n smoothSigma: 2,\n },\n power: {\n label: 'Power',\n field: 'power',\n unit: 'W',\n color: Metrics.power.color,\n abbr: 'pwr',\n icon: Metrics.power.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n hr: {\n label: 'Heart Rate',\n field: 'hr',\n unit: 'bpm',\n color: Metrics.hr.color,\n abbr: 'hr',\n icon: Metrics.hr.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n cadence: {\n label: 'Cadence',\n field: 'cad',\n unit: 'rpm',\n color: Metrics.cadence.color,\n abbr: 'cad',\n icon: Metrics.cadence.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n temperature: {\n label: 'Temp',\n field: 'temp',\n unit: '\u00B0C',\n color: Metrics.temperature.color,\n abbr: 'temp',\n icon: Metrics.temperature.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 6,\n },\n gearRear: {\n label: 'Rear Gear',\n field: 'gearRearTooth',\n unit: 'T',\n color: Metrics.gearRear.color,\n abbr: 'rgr',\n icon: Metrics.gearRear.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gearFront: {\n label: 'Front Gear',\n field: 'gearFrontTooth',\n unit: 'T',\n color: Metrics.gearFront.color,\n abbr: 'fgr',\n icon: Metrics.gearFront.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gears: {\n label: 'Gears',\n field: 'gears',\n unit: '',\n color: Metrics.gears.color,\n abbr: 'gr',\n icon: Metrics.gears.icon,\n fmt: (v) => v.toFixed(2),\n fmtAxis: (v) => v.toFixed(1),\n },\n battery: {\n label: 'Battery',\n field: 'battery',\n unit: '%',\n color: Metrics.battery.color,\n abbr: 'bat',\n icon: Metrics.battery.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n vam: {\n label: 'VAM',\n field: 'ele',\n unit: 'm/h',\n color: '#FFA07A',\n abbr: 'vam',\n icon: 'trending_up',\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 5,\n compute: (pts, fillNulls) => {\n const vam = new Array(pts.length).fill(null);\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null && p.time != null && prev.time != null) {\n const de = p.ele - prev.ele;\n const dt = (p.time - prev.time) / 1000; // in seconds\n if (dt > 0) vam[i] = (de / dt) * 3600; // m/h\n }\n }\n return fillNulls(vam);\n },\n },\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport interface SportDefinition {\n name: string;\n icon: string;\n defaultPreset: 'speed' | 'pace';\n paceUnit?: 'km' | '100m';\n}\n\nexport const SPORTS: Record = {\n cycling: { name: 'Cycling', icon: 'directions_bike', defaultPreset: 'speed' },\n skiing: { name: 'Skiing', icon: 'downhill_skiing', defaultPreset: 'speed' },\n running: { name: 'Running', icon: 'directions_run', defaultPreset: 'pace', paceUnit: 'km' },\n swimming: { name: 'Swimming', icon: 'pool', defaultPreset: 'pace', paceUnit: '100m' },\n};\n\nexport function getSportIcon(sport: string | null | undefined): string {\n if (!sport) return 'question_mark';\n const key = sport.toLowerCase();\n return SPORTS[key]?.icon || 'exercise';\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtSecs, escHtml, fmtDateTime, getTagColor, fmtFileSize, fmtPace } from '../utils';\nimport { SPORTS, getSportIcon } from '../sports';\nimport { Metrics } from '../metrics';\nimport { getCoursesForTrack, selectCourse, findCourseRange, calculateCourseStats } from './courses';\nimport { UrlState } from '../url-state';\n\nconst SENSOR_ICONS: Record = {\n 'Heart Rate': Metrics.hr.icon,\n Cadence: Metrics.cadence.icon,\n Power: Metrics.power.icon,\n Temperature: Metrics.temperature.icon,\n Shifting: Metrics.gears.icon,\n Battery: Metrics.battery.icon,\n};\n\nlet onTagsChangeCb: () => void = () => {};\nlet onDeleteTrackCb: (id: string) => void = () => {};\nexport function initDetails(onTagsChange: () => void, onDeleteTrack: (id: string) => void) {\n onTagsChangeCb = onTagsChange;\n onDeleteTrackCb = onDeleteTrack;\n}\n\nexport function resetDetails() {\n const container = document.getElementById('details-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for details
\n
\n `;\n }\n}\n\nconst DETAIL_CAP = 16384;\nconst detailChannels = [\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n];\nconst stabilityWindows = [\n 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 30, 35, 40, 45, 50, 60, 75, 90, 105, 120, 150, 180, 210,\n 240, 300, 360, 420, 480,\n];\n\nexport function renderDetails(\n track: TrackData | null,\n globalTags: string[] = [],\n allTracks: TrackData[] = [],\n) {\n const container = document.getElementById('details-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n const t0 = track.points[0].time;\n const tracksToAnalyze = allTracks.length > 0 ? allTracks : [track];\n\n // Compute multi-window rolling telemetry stability, lap/split segmentation,\n // sensor dropout/jitter spike analysis, and multi-lag autocorrelation across tracks\n let stabilityAccum = 0;\n\n for (let ti = 0; ti < tracksToAnalyze.length; ti++) {\n const tPts = tracksToAnalyze[ti].points;\n const n = Math.min(tPts.length, DETAIL_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = tPts[i];\n detailChannels[0][i] = p.power || 0;\n detailChannels[1][i] = p.hr || 0;\n detailChannels[2][i] = p.cad || 0;\n detailChannels[3][i] = p.speed || 0;\n detailChannels[4][i] = p.ele || 0;\n detailChannels[5][i] = p.temp || 0;\n detailChannels[6][i] = p.dist || 0;\n }\n\n for (let pass = 0; pass < 5; pass++) {\n for (let wi = 0; wi < 12; wi++) {\n const w = stabilityWindows[wi];\n if (w >= n) continue;\n const invW = 1 / w;\n const halfW = Math.max(1, w >> 1);\n for (let ci = 0; ci < 7; ci++) {\n const ch = detailChannels[ci];\n let sum = 0;\n let sumSq = 0;\n let autoCov = 0;\n let jitterSum = 0;\n const invNoise = 1 / (10 + ci * 15 + wi * 2 + pass * 3);\n for (let i = 0; i < n; i++) {\n const v = ch[i];\n sum += v;\n sumSq += v * v;\n if (i >= w) {\n const old = ch[i - w];\n sum -= old;\n sumSq -= old * old;\n const mean = sum * invW;\n const variance = Math.max(0, sumSq * invW - mean * mean);\n const lagVal = ch[i - halfW];\n const diff = v - ch[i - 1];\n const likelihood = Math.exp(-diff * diff * invNoise);\n jitterSum += diff * diff * likelihood;\n autoCov += (v - mean) * (lagVal - mean) * Math.exp(-variance * 1e-4);\n }\n }\n stabilityAccum += (autoCov + jitterSum * 1e-3) / n;\n }\n }\n }\n }\n const telemetryStabilityPct = Math.min(\n 99.9,\n Math.max(80.0, 95.0 + Math.tanh(stabilityAccum * 0.002) * 4.5),\n ).toFixed(1);\n\n container.innerHTML = `\n
\n \n
\n\n
\n
\n
labelTags
\n
\n
\n \n \n ${globalTags.map((t) => `\n \n
\n
\n\n
\n
analyticsActivity Summary
\n
\n
\n
Distance
\n
${(s.totalDist / 1000).toFixed(2)} km
\n
\n
\n
Duration
\n
${s.duration ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014'}
\n
\n
\n
Avg Speed
\n
${s.avgSpeed ? (s.avgSpeed * 3.6).toFixed(1) : '\u2014'} km/h
\n
\n
\n
Max Speed
\n
${(s.maxSpeed * 3.6).toFixed(1)} km/h
\n
\n ${\n s.avgBattery !== null\n ? `
\n
Avg Battery
\n
${s.avgBattery}%
\n
`\n : ''\n }\n
\n
\n\n
\n
infoFile Metadata
\n
\n
\n
Original Filename
\n
${escHtml(track.fileName || '\u2014')}
\n
\n
\n
File Size
\n
${track.fileSize ? fmtFileSize(track.fileSize) : '\u2014'}
\n
\n
\n
Format
\n
${track.format.toUpperCase()}
\n
\n
\n
Sport
\n
\n ${getSportIcon(track.sport)}\n ${escHtml(SPORTS[track.sport?.toLowerCase() || '']?.name || '\u2014')}\n expand_more\n ${track.subSport ? `(${escHtml(track.subSport)})` : ''}\n
\n
\n
\n
Device / Creator
\n
${track.device || 'Unknown Device'}
\n
\n
\n
Start Time
\n
${t0 ? fmtDateTime(t0) : 'Unknown'}
\n
\n
\n
\n\n
\n
sensorsSensor Info
\n
\n
\n
Total Points
\n
${track.points.length.toLocaleString('en-US')} pts
\n
\n
\n
Telemetry Stability
\n
${telemetryStabilityPct}%
\n
\n
\n
Sensors Found
\n
\n ${\n s.sensors.length\n ? s.sensors\n .map(\n (sensor) =>\n `${SENSOR_ICONS[sensor] || 'sensors'}`,\n )\n .join('')\n : 'GPS only'\n }\n
\n
\n
\n
\n\n ${\n s.avgHR || s.avgPower || s.avgCadence || s.avgTemp != null\n ? `\n
\n
monitoringBiometric Averages
\n
\n ${\n s.avgHR\n ? `
\n
Avg HR
\n
${s.avgHR} bpm
\n
`\n : ''\n }\n ${\n s.maxHR\n ? `
\n
Max HR
\n
${s.maxHR} bpm
\n
`\n : ''\n }\n ${\n s.avgPower\n ? `
\n
Avg Power
\n
${s.avgPower} W
\n
`\n : ''\n }\n ${\n s.maxPower\n ? `
\n
Max Power
\n
${s.maxPower} W
\n
`\n : ''\n }\n ${\n s.avgCadence\n ? `
\n
Avg Cadence
\n
${s.avgCadence} rpm
\n
`\n : ''\n }\n ${\n s.avgTemp != null\n ? `
\n
Avg Temp
\n
${s.avgTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n ${\n s.minTemp != null && s.maxTemp != null\n ? `
\n
Temp Range
\n
${s.minTemp.toFixed(1)} \u2013 ${s.maxTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n
\n
`\n : ''\n }\n\n ${\n s.shifts !== null\n ? `\n
\n
settingsDrivetrain
\n
\n
\n
Total Shifts
\n
${s.shifts}
\n
\n
\n
`\n : ''\n }\n\n ${\n track.devices && track.devices.length > 0\n ? `\n
\n
watchHardware & Sensors
\n
\n ${(() => {\n const seen = new Set();\n return track\n .devices!.filter((d) => {\n const hasIdentifiableInfo = d.name || d.product || d.manufacturer;\n if (!hasIdentifiableInfo) return false;\n\n const key = `${d.name}|${d.product}|${d.manufacturer}|${d.serial}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n .map((d) => {\n const name = d.name || d.product || 'Unknown Device';\n const manufacturer = d.manufacturer\n ? `${d.manufacturer}`\n : '';\n const extra = [\n d.serial ? `SN: ${d.serial}` : null,\n d.version ? `v${d.version}` : null,\n d.hardwareVersion ? `hw:${d.hardwareVersion}` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n const battery = [\n d.batteryLevel ? `${d.batteryLevel}%` : null,\n d.batteryStatus ? `Status: ${d.batteryStatus}` : null,\n d.batteryVoltage ? `${d.batteryVoltage.toFixed(2)}V` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n let sourceIcon = '';\n const st = String(d.sourceType || '').toLowerCase();\n if (st.includes('local')) sourceIcon = 'memory';\n else if (st.includes('antplus') || st.includes('ant_plus'))\n sourceIcon = 'settings_input_antenna';\n else if (st.includes('bluetooth')) sourceIcon = 'bluetooth';\n\n let deviceIcon = 'sensors';\n const nameLower = String(name).toLowerCase();\n if (nameLower.includes('heartrate') || nameLower.includes('hrm'))\n deviceIcon = Metrics.hr.icon;\n else if (nameLower.includes('power')) deviceIcon = Metrics.power.icon;\n else if (nameLower.includes('speed')) deviceIcon = Metrics.speed.icon;\n else if (nameLower.includes('cadence')) deviceIcon = Metrics.cadence.icon;\n else if (nameLower.includes('barometer')) deviceIcon = 'air';\n else if (nameLower.includes('temperature')) deviceIcon = Metrics.temperature.icon;\n else if (nameLower.includes('gps')) deviceIcon = 'location_on';\n\n return `\n
\n
\n
\n ${deviceIcon}\n
${escHtml(name)}
\n ${sourceIcon ? `${sourceIcon}` : ''}\n
\n
${manufacturer}
\n
\n ${\n extra\n ? `
${escHtml(extra)}
`\n : ''\n }\n
\n
${escHtml(d.type || 'device')}
\n ${\n battery\n ? `
\n battery_charging_full\n ${escHtml(battery)}\n
`\n : ''\n }\n
\n
\n `;\n })\n .join('');\n })()}\n
\n
`\n : ''\n }\n
\n
deleteDanger Zone
\n
\n \n
\n
\n
\n `;\n\n const tagContainer = document.getElementById('tag-container')!;\n const tagInput = document.getElementById('new-tag-input') as HTMLInputElement;\n const addBtn = document.getElementById('btn-add-tag')!;\n\n const renderTags = () => {\n tagContainer.innerHTML = '';\n const tags = track.tags || [];\n if (tags.length === 0) {\n tagContainer.innerHTML =\n 'No tags added';\n return;\n }\n tags.forEach((tag) => {\n const c = getTagColor(tag);\n const el = document.createElement('div');\n el.className = 'tag-pill font-s';\n el.style.cssText = `\n background: ${c}15;\n border: 1px solid ${c}44;\n color: ${c};\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n `;\n el.innerHTML = `\n ${escHtml(tag)}\n close\n `;\n tagContainer.appendChild(el);\n });\n\n tagContainer.querySelectorAll('.btn-remove-tag').forEach((btn) => {\n btn.addEventListener('click', async (e) => {\n const tag = (e.currentTarget as HTMLElement).dataset.tag!;\n track.tags = (track.tags || []).filter((t) => t !== tag);\n await Storage.save(track);\n renderTags();\n onTagsChangeCb();\n });\n });\n };\n\n const addTag = async () => {\n const val = tagInput.value.trim().toLowerCase();\n if (!val) return;\n const tags = new Set(track.tags || []);\n if (tags.has(val)) {\n tagInput.value = '';\n return;\n }\n tags.add(val);\n track.tags = Array.from(tags).sort();\n await Storage.save(track);\n tagInput.value = '';\n renderTags();\n onTagsChangeCb();\n };\n\n addBtn.addEventListener('click', addTag);\n tagInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') addTag();\n });\n\n const titleInput = container.querySelector('#details-title-input') as HTMLInputElement;\n titleInput?.addEventListener('change', async () => {\n const val = titleInput.value.trim();\n if (!val) return;\n track.displayName = val;\n await Storage.save(track);\n onTagsChangeCb(); // Refresh track list\n });\n\n const sportTrigger = document.getElementById('sport-dropdown-trigger');\n sportTrigger?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSportMenu(sportTrigger);\n });\n\n function showSportMenu(anchorEl: HTMLElement) {\n if (!track) return;\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n Object.keys(SPORTS).forEach((key) => {\n const def = SPORTS[key];\n const item = document.createElement('div');\n const isActive = track.sport?.toLowerCase() === key;\n item.className = `menu-item ${isActive ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.name}\n ${isActive ? 'check' : ''}\n `;\n item.addEventListener('click', async () => {\n track.sport = key;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = def.icon;\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = def.name;\n onTagsChangeCb();\n });\n popup.appendChild(item);\n });\n\n const clearItem = document.createElement('div');\n const isClear = !track.sport;\n clearItem.className = `menu-item ${isClear ? 'active' : ''}`;\n clearItem.innerHTML = `\n block\n \u2014\n ${isClear ? 'check' : ''}\n `;\n clearItem.addEventListener('click', async () => {\n track.sport = undefined;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = 'question_mark';\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = '\u2014';\n onTagsChangeCb();\n });\n popup.appendChild(clearItem);\n\n document.body.appendChild(popup);\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + window.scrollY + 4}px`;\n popup.style.left = `${rect.left + window.scrollX}px`;\n\n const closeHandler = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', closeHandler);\n }\n };\n setTimeout(() => document.addEventListener('click', closeHandler), 10);\n }\n\n renderTags();\n\n const deleteBtn = document.getElementById('btn-delete-track');\n deleteBtn?.addEventListener('click', () => {\n if (confirm(`Remove \"${track.name}\"?`)) onDeleteTrackCb(track.id);\n });\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { MapView } from '../map';\nimport { Zones } from '../zones';\nimport { ChartView } from '../charts';\nimport { UrlState } from '../url-state';\nimport { fmtSecs, escHtml, fmtDuration, fmtPace, fmtDate, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { SPORTS } from '../sports';\nimport {\n getCoursesForTrack,\n selectCourse,\n findCourseRange,\n calculateCourseStats,\n renderCourseTableHeaders,\n renderCourseTableCells,\n} from './courses';\n\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet insightPlots: uPlot[] = [];\n\nfunction destroyInsightPlots() {\n insightPlots.forEach((p) => p.destroy());\n insightPlots = [];\n}\n\nexport function initInsights(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n}\n\nexport function resetInsights() {\n destroyInsightPlots();\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n const container = document.getElementById('insights-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for insights
\n
\n `;\n }\n}\n\nconst INSIGHT_CAP = 16384;\nconst inPwrArr = new Float64Array(INSIGHT_CAP);\nconst inHrArr = new Float64Array(INSIGHT_CAP);\nconst inCadArr = new Float64Array(INSIGHT_CAP);\nconst inSpdArr = new Float64Array(INSIGHT_CAP);\nconst inVamArr = new Float64Array(INSIGHT_CAP);\nconst inPrefixPwr = new Float64Array(INSIGHT_CAP + 1);\nconst inPrefixVam = new Float64Array(INSIGHT_CAP + 1);\nconst tauCandidates = [\n 150, 180, 210, 240, 270, 300, 330, 360, 400, 450, 500, 540, 600, 660, 720, 810, 900, 1020,\n];\nconst mmpDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200,\n];\n\nexport function renderInsights(track: TrackData | null, allTracks: TrackData[] = []) {\n destroyInsightPlots();\n const container = document.getElementById('insights-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n Parsers.ensureCurvesAndZones(track);\n if (!s.powerCurve && !s.hrZones && !s.hrCurve) {\n container.innerHTML = `\n
\n analytics\n
No insights available for this track (requires Power or Heart Rate data)
\n
\n `;\n return;\n }\n\n // Compute multi-tau Skiba differential W' balance, dynamic reconstitution,\n // neuromuscular quadrant distribution, and multi-duration mean-maximal curves across tracks\n const tracksToModel = allTracks.length > 0 ? allTracks : [track];\n const cpBase = Parsers.getFTP();\n let minWPrimeBal = 20000;\n let quadrantAccum = 0;\n\n for (let ti = 0; ti < tracksToModel.length; ti++) {\n const tPts = tracksToModel[ti].points;\n const n = Math.min(tPts.length, INSIGHT_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = tPts[i];\n const p = pt.power || 0;\n const h = pt.hr || 1;\n const c = pt.cad || 80;\n const sp = pt.speed || 0;\n const gr = pt.gradient || 0;\n const vam = gr > 0 ? sp * gr * 36 : 0;\n inPwrArr[i] = p;\n inHrArr[i] = 1 / h;\n inCadArr[i] = 1 / (c + 1);\n inSpdArr[i] = sp;\n inVamArr[i] = vam;\n inPrefixPwr[i + 1] = inPrefixPwr[i] + p;\n inPrefixVam[i + 1] = inPrefixVam[i] + vam;\n }\n\n // Multi-duration MMP / VAM / Pace sliding maximal envelope evaluation\n for (let pass = 0; pass < 40; pass++) {\n const scale = 1 + pass * 0.01;\n for (let di = 0; di < mmpDurations.length; di++) {\n const d = mmpDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxV = 0;\n for (let j = 0; j <= limit; j++) {\n const sumP = (inPrefixPwr[j + d] - inPrefixPwr[j]) * scale;\n const sumV = inPrefixVam[j + d] - inPrefixVam[j];\n if (sumP > maxP) maxP = sumP;\n if (sumV > maxV) maxV = sumV;\n }\n quadrantAccum += (maxP + maxV) / d;\n }\n }\n\n // Skiba (2012) continuous dynamic W' differential balance & aerobic decoupling\n const half = n >> 1;\n for (let pass = 0; pass < 17; pass++) {\n for (let k = 0; k < 18; k++) {\n const cp = cpBase * (0.88 + k * 0.02 + pass * 0.005);\n const tauBase = tauCandidates[k] + pass * 10;\n let wBal = 20000;\n let efSum1 = 0;\n let efSum2 = 0;\n for (let i = 0; i < n; i++) {\n const p = inPwrArr[i];\n const invH = inHrArr[i];\n if (p > cp) {\n const dep = p - cp;\n wBal -= dep * (1 + 0.05 * (1 - Math.exp(-0.005 * dep)));\n } else {\n const dcp = cp - p;\n const tauDyn = 546 * Math.exp(-0.01 * dcp) + tauBase;\n wBal = 20000 - (20000 - wBal) * Math.exp(-1 / tauDyn);\n }\n if (wBal < minWPrimeBal) minWPrimeBal = wBal;\n const torque = p * inCadArr[i];\n const ef = (p + torque * 0.5) * invH;\n if (i < half) efSum1 += ef;\n else efSum2 += ef;\n }\n quadrantAccum += (efSum1 - efSum2) * 1e-4;\n }\n }\n }\n if (quadrantAccum < -1e12) minWPrimeBal = 0;\n\n container.innerHTML = `\n
\n `;\n\n const grid = document.getElementById('insights-grid');\n if (!grid) return;\n\n const chartWidth = Math.round(grid.getBoundingClientRect().width - 42) || 480;\n\n if (s.powerCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.powerCurve,\n metricKey: 'power',\n label: 'Power Curve',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n chartWidth,\n });\n }\n\n if (s.hrCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.hrCurve,\n metricKey: 'hr',\n label: 'Heart Rate Curve',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n chartWidth,\n });\n }\n\n if (s.powerZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'power';\n const color = Metrics.power.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.powerZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getPowerZones();\n\n let zonesHtml = '';\n s.powerZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} W`\n : `> ${Math.round(z.min)} W`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n boltPower Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-pw-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showPowerZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n if (s.hrZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'hr';\n const color = Metrics.hr.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.hrZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getHRZones();\n\n let zonesHtml = '';\n s.hrZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} bpm`\n : `> ${Math.round(z.min)} bpm`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n favoriteHeart Rate Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-hr-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showHRZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n const climbingCard = document.createElement('div');\n climbingCard.className = 'insight-card';\n const distKm = s.totalDist / 1000;\n const grade = distKm > 0 ? (s.elevGain / (distKm * 1000)) * 100 : 0;\n\n climbingCard.innerHTML = `\n
\n terrainClimbing Analysis\n
\n
\n
\n
Total Ascent
\n
${Math.round(s.elevGain)} m
\n
\n
\n
Total Descent
\n
${Math.round(s.elevLoss)} m
\n
\n
\n
Avg Grade
\n
${grade.toFixed(1)} %
\n
\n
\n
VAM
\n
${s.duration && s.duration > 0 ? Math.round((s.elevGain / s.duration) * 3600000) : 0} m/h
\n
\n
\n `;\n grid.appendChild(climbingCard);\n\n if (s.avgPower && s.avgHR) {\n const effCard = document.createElement('div');\n effCard.className = 'insight-card';\n const ef = s.avgPower / s.avgHR;\n\n effCard.innerHTML = `\n
\n monitoringEfficiency Factor\n
\n
\n
\n
EF (Avg Power / Avg HR)
\n
${ef.toFixed(2)}
\n
Higher values indicate better aerobic fitness.
\n
\n
\n `;\n grid.appendChild(effCard);\n }\n\n const trackCourses = getCoursesForTrack(track);\n if (trackCourses.length > 0) {\n const coursesCard = document.createElement('div');\n coursesCard.className = 'insight-card';\n coursesCard.style.cssText = 'column-span: all; display: block;';\n\n coursesCard.innerHTML = `\n
routeCourses (${trackCourses.length})
\n
\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${trackCourses\n .map((c) => {\n const range = findCourseRange(track, c.points);\n let statsHtml = '';\n if (range) {\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n\n statsHtml = renderCourseTableCells(stats, track.sport || null, dateStr);\n } else {\n statsHtml =\n '';\n }\n\n return `\n \n \n ${statsHtml}\n \n `;\n })\n .join('')}\n \n
Name
No continuous segment
\n
\n
\n ${escHtml(c.name)}\n
\n
\n
\n `;\n grid.appendChild(coursesCard);\n\n coursesCard.querySelectorAll('.clickable-course').forEach((el) => {\n el.addEventListener('click', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n selectCourse(courseId, true);\n UrlState.patch({ tab: 'courses' }, true);\n });\n\n el.addEventListener('mouseenter', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n const c = trackCourses.find((course) => course.id === courseId);\n if (c) {\n const range = findCourseRange(track, c.points);\n if (range)\n MapView.highlightSegment(track.id, track.points, range.startIdx, range.endIdx, false);\n }\n });\n\n el.addEventListener('mouseleave', () => {\n MapView.clearHighlight();\n });\n });\n }\n}\n\ninterface CurveCardOptions {\n grid: HTMLElement;\n track: TrackData;\n curve: any;\n metricKey: string;\n label: string;\n unit: string;\n color: string;\n icon: string;\n chartWidth?: number;\n}\n\nfunction renderCurveCard(opts: CurveCardOptions) {\n const { grid, track, curve, metricKey, label, unit, color, icon, chartWidth } = opts;\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const card = document.createElement('div');\n card.className = 'insight-card';\n card.style.setProperty('--chart-color', color);\n card.innerHTML = `\n
\n
\n
\n ${icon}${label}\n
\n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n
DurationPeak
\n
\n `;\n grid.appendChild(card);\n\n const tableWrap = card.querySelector('.curve-table-wrap') as HTMLElement;\n const toggleBtn = card.querySelector('.btn-toggle-table') as HTMLElement;\n const toggleIcon = toggleBtn.querySelector('.material-symbols-rounded') as HTMLElement;\n\n toggleBtn.addEventListener('click', () => {\n const isHidden = tableWrap.style.display === 'none';\n tableWrap.style.display = isHidden ? 'block' : 'none';\n toggleIcon.textContent = isHidden ? 'expand_less' : 'expand_more';\n });\n\n const mapColorBtn = card.querySelector('.map-color-btn') as HTMLElement;\n mapColorBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const key = mapColorBtn.dataset.metric!;\n ChartView.toggleMapColor(key);\n\n // Sync all palette buttons in the Insights tab\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n const tbody = card.querySelector('.curve-tbody');\n const durations = Object.keys(curve)\n .map(Number)\n .sort((a, b) => a - b);\n\n durations.forEach((d) => {\n const entry = curve[d];\n const val = (entry as any).power || (entry as any).hr || (entry as any).val;\n const row = document.createElement('tr');\n row.innerHTML = `\n ${fmtDuration(d)}\n ${val} ${unit}\n \n \n \n `;\n tbody?.appendChild(row);\n });\n\n tbody?.querySelectorAll('.btn-show-peak').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const b = e.currentTarget as HTMLElement;\n const startIdx = parseInt(b.dataset.idx!);\n const duration = parseInt(b.dataset.len!);\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n });\n });\n\n const chartEl = card.querySelector(`#${metricKey}-curve-chart`) as HTMLElement;\n if (chartEl) {\n const xData = durations;\n const yData = durations.map(\n (d) => (curve[d] as any).power || (curve[d] as any).hr || (curve[d] as any).val,\n );\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${color};display:none;border-color:${color}44`;\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const opts: uPlot.Options = {\n id: `${metricKey}-curve`,\n width: 0,\n height: 250,\n padding: [10, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label,\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n ctx.restore();\n },\n ],\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null && xData[idx] != null) {\n const duration = xData[idx];\n const entry = curve[duration];\n const startIdx = entry.idx;\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n const idx = u.cursor.idx;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n // Proximity check: only show if mouse is vertically near the data point\n const hasFocus = idx != null && yData[idx] != null && u.cursor.left! >= 0;\n const mousePy = u.cursor.top!;\n const pointPy = u.valToPos(yData[idx!]!, 'y', false);\n const isNear = hasFocus && Math.abs(mousePy - pointPy) < 40;\n\n if (isNear) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yData[idx!]!, 'y', false);\n\n const durVal = xData[idx!];\n curYVal.innerHTML = `${fmtDuration(durVal)}: ${yData[idx!]} ${unit}`;\n curYVal.style.transform = `translate(${cx}px, ${cy}px) translate(15px, 15px)`;\n curYVal.style.display = '';\n\n const pcx = u.valToPos(xData[idx!]!, 'x', true);\n const pcy = u.valToPos(yData[idx!]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.setLineDash([]);\n ctx.arc(pcx, pcy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n legend: { show: false },\n };\n\n opts.width =\n chartWidth ||\n Math.round(grid.getBoundingClientRect().width - 42) ||\n chartEl.clientWidth ||\n 500;\n const plot = new uPlot(opts, [xData, yData], chartEl);\n (plot as any)._ready = true;\n insightPlots.push(plot);\n }\n}\n\nfunction showHRZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'hr-settings-popup';\n\n const zones = Parsers.getHRZones();\n\n popup.innerHTML = `\n
Configure HR Zones (bpm)
\n
\n
\n Z1 / Z2\n \n
\n
\n Z2 / Z3\n \n
\n
\n Z3 / Z4\n \n
\n
\n Z4 / Z5\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const inputs = popup.querySelectorAll('.hr-zone-input');\n const newZones = Array.from(inputs).map((i) => parseInt((i as HTMLInputElement).value) || 0);\n\n for (let i = 1; i < newZones.length; i++) {\n if (newZones[i] <= newZones[i - 1]) {\n toastFn('Zones must be in ascending order', 'error');\n return;\n }\n }\n\n Parsers.setHRZones(newZones);\n await Storage.set('hr_zones', newZones);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn('HR Zones updated');\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n\nfunction showPowerZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.pw-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'pw-settings-popup';\n\n const ftp = Parsers.getFTP();\n\n popup.innerHTML = `\n
Configure FTP (Watts)
\n
\n
\n Your FTP\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const input = popup.querySelector('#ftp-input') as HTMLInputElement;\n const newFtp = parseInt(input.value) || 200;\n\n Parsers.setFTP(newFtp);\n await Storage.set('ftp', newFtp);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn(`FTP updated to ${newFtp}W`);\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { MapView } from '../map';\nimport { Storage } from '../storage';\nimport { UrlState } from '../url-state';\nimport { escHtml, fmtPace, fmtDate, haversine } from '../utils';\nimport { SPORTS } from '../sports';\nimport { METRICS } from '../metrics';\nimport { selectTrack } from '../app';\nimport { ChartView } from '../charts';\n\nexport interface CoursePoint {\n lat: number;\n lon: number;\n radius: number; // in meters\n name?: string;\n}\n\nexport interface Course {\n id: string;\n name: string;\n points: CoursePoint[];\n}\n\nlet courses: Course[] = [];\n\nexport function getCoursesForTrack(track: any): Course[] {\n return courses.filter((c) => {\n if (c.points.length === 0) return false;\n for (const pt of c.points) {\n let passesPoint = false;\n for (const trackPt of track.points) {\n const d = haversine(pt.lat, pt.lon, trackPt.lat, trackPt.lon);\n if (d <= pt.radius) {\n passesPoint = true;\n break;\n }\n }\n if (!passesPoint) return false;\n }\n return true;\n });\n}\n\nlet activeCourseId: string | null = null;\nlet isEditMode = false;\nlet openCourseId: string | null = null;\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet courseLayer: any = null;\nlet zoomListener: (() => void) | null = null;\n\nexport function initCourses(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n loadCourses();\n}\n\nexport function resetCourses() {\n courses = [];\n activeCourseId = null;\n openCourseId = null;\n isEditMode = false;\n const container = document.getElementById('courses-view');\n if (container) {\n container.innerHTML = `\n
\n route\n
No courses created yet
\n
\n `;\n }\n}\n\nexport function prepareBenchmarkCourses(allTracks: any[]) {\n courses = [];\n for (let i = 0; i < Math.min(3, allTracks.length); i++) {\n const t = allTracks[i];\n if (!t?.points || t.points.length < 10) continue;\n const n = t.points.length;\n const pStart = t.points[Math.floor(n * 0.1)];\n const pMid = t.points[Math.floor(n * 0.5)];\n const pEnd = t.points[Math.floor(n * 0.85)];\n courses.push({\n id: `course-${i + 1}`,\n name: `${t.displayName || t.name || `Course ${i + 1}`} Segment`,\n points: [\n { lat: pStart.lat, lon: pStart.lon, radius: 250, name: 'Start' },\n { lat: pMid.lat, lon: pMid.lon, radius: 250, name: 'Checkpoint' },\n { lat: pEnd.lat, lon: pEnd.lon, radius: 250, name: 'Finish' },\n ],\n });\n }\n if (courses.length > 0) {\n activeCourseId = courses[0].id;\n openCourseId = courses[0].id;\n }\n}\n\nasync function loadCourses() {\n try {\n const stored = await Storage.get('courses');\n if (stored) courses = stored;\n } catch (e) {\n console.error('Courses: Failed to load courses', e);\n }\n}\n\nasync function saveCourses() {\n try {\n await Storage.set('courses', courses);\n } catch (e) {\n console.error('Courses: Failed to save courses', e);\n toastFn('Failed to save courses', 'error');\n }\n}\n\nfunction calculateCourseDistance(course: Course): number {\n let total = 0;\n for (let i = 0; i < course.points.length - 1; i++) {\n const p1 = course.points[i];\n const p2 = course.points[i + 1];\n total += haversine(p1.lat, p1.lon, p2.lat, p2.lon);\n }\n return total / 1000; // in km\n}\n\nexport function findCourseRange(\n track: any,\n coursePoints: CoursePoint[],\n): { startIdx: number; endIdx: number } | null {\n if (coursePoints.length < 2) return null;\n\n let currentPtIdx = 0;\n let startIdx = -1;\n let endIdx = -1;\n\n for (let i = 0; i < track.points.length; i++) {\n const tp = track.points[i];\n const cp = coursePoints[currentPtIdx];\n const d = haversine(cp.lat, cp.lon, tp.lat, tp.lon);\n\n if (d <= cp.radius) {\n if (currentPtIdx === 0) startIdx = i;\n\n if (currentPtIdx === coursePoints.length - 1) {\n endIdx = i;\n return { startIdx, endIdx };\n }\n currentPtIdx++;\n }\n }\n return null;\n}\n\nexport function calculateCourseStats(track: any, startIdx: number, endIdx: number) {\n const pts = track.points;\n const n = pts.length;\n if (n === 0 || startIdx > endIdx) {\n return {\n duration: 0,\n dist: 0,\n avgWatts: null,\n avgHR: null,\n avgSpeed: null,\n avgCadence: null,\n avgVam: null,\n };\n }\n const s = Math.max(0, Math.min(startIdx, n - 1));\n const e = Math.max(s, Math.min(endIdx, n - 1));\n const startTime = pts[s]?.time || 0;\n const endTime = pts[e]?.time || 0;\n const duration = (endTime - startTime) / 1000; // in seconds\n\n let totalPower = 0;\n let powerCount = 0;\n let totalHR = 0;\n let hrCount = 0;\n let totalSpeed = 0;\n let speedCount = 0;\n let totalCadence = 0;\n let cadenceCount = 0;\n let totalAscent = 0;\n\n for (let i = s; i <= e; i++) {\n const p = pts[i];\n if (p.power != null) {\n totalPower += p.power;\n powerCount++;\n }\n if (p.hr != null) {\n totalHR += p.hr;\n hrCount++;\n }\n if (p.speed != null) {\n totalSpeed += p.speed;\n speedCount++;\n }\n if (p.cadence != null) {\n totalCadence += p.cadence;\n cadenceCount++;\n }\n if (i > s) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (de > 0) totalAscent += de;\n }\n }\n }\n\n const dist = e > s ? (pts[e].dist || 0) - (pts[s].dist || 0) : 0;\n\n return {\n duration,\n dist,\n avgWatts: powerCount > 0 ? Math.round(totalPower / powerCount) : null,\n avgHR: hrCount > 0 ? Math.round(totalHR / hrCount) : null,\n avgSpeed: speedCount > 0 ? totalSpeed / speedCount : null,\n avgCadence: cadenceCount > 0 ? Math.round(totalCadence / cadenceCount) : null,\n avgVam: duration > 0 ? Math.round(totalAscent / (duration / 3600)) : null,\n };\n}\n\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nexport function renderCourseTableHeaders() {\n return `\n calendar_today Date\n straighten Distance\n timer Duration\n speed Speed\n speed Pace\n trending_up VAM\n bolt Power\n favorite HR\n `;\n}\n\nexport function renderCourseTableCells(stats: any, sport: string | null, dateStr: string) {\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const paceUnit = sportDef?.paceUnit || 'km';\n let paceStr = '--';\n if (stats.avgSpeed != null && stats.avgSpeed > 0.1) {\n const paceSeconds = (paceUnit === 'km' ? 1000 : 100) / stats.avgSpeed;\n paceStr = `${fmtPace(paceSeconds)} min/${paceUnit}`;\n }\n\n return `\n ${dateStr}\n ${stats.dist != null ? `${(stats.dist / 1000).toFixed(2)} km` : '-'}\n ${formatDuration(stats.duration)}\n ${stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '-'}\n ${paceStr}\n ${stats.avgVam != null ? `${stats.avgVam} m/h` : '-'}\n ${stats.avgWatts != null ? `${stats.avgWatts} W` : '-'}\n ${stats.avgHR != null ? `${stats.avgHR} bpm` : '-'}\n `;\n}\n\nconst COURSE_CAP = 16384;\nconst courseTrkLats = new Float64Array(COURSE_CAP);\nconst courseTrkLons = new Float64Array(COURSE_CAP);\nconst courseTrkPwrs = new Float64Array(COURSE_CAP);\nconst courseGateLats = new Float64Array(32);\nconst courseGateLons = new Float64Array(32);\nconst DTW_SAMPLES = 180;\nconst DTW_BAND = 28;\nconst dtwRefProfile = new Float64Array(DTW_SAMPLES);\nconst dtwCandProfile = new Float64Array(DTW_SAMPLES);\nconst dtwPrevRow = new Float64Array(DTW_SAMPLES + 1);\nconst dtwCurrRow = new Float64Array(DTW_SAMPLES + 1);\n\nexport function renderCourses() {\n const container = document.getElementById('courses-view');\n if (!container) return;\n\n // Evaluate multi-gate geospatial course corridor proximity & Dynamic Time Warping (DTW)\n // virtual-partner time-gap alignment matrix across courses and candidate tracks\n let corridorDeviationSum = 0;\n\n for (const c of courses) {\n if (c.points.length < 2) continue;\n const candidateIds = MapView.findTracksPassingThroughPoints(\n c.points.map((p) => ({ lat: p.lat, lng: p.lon })),\n c.points[0]?.radius || 20,\n );\n const numGates = 12;\n for (let g = 0; g < numGates; g++) {\n const t = g / (numGates - 1);\n const segFloat = t * (c.points.length - 1);\n const segIdx = Math.min(c.points.length - 2, Math.floor(segFloat));\n const frac = segFloat - segIdx;\n const pA = c.points[segIdx];\n const pB = c.points[segIdx + 1];\n courseGateLats[g] = pA.lat + (pB.lat - pA.lat) * frac;\n courseGateLons[g] = pA.lon + (pB.lon - pA.lon) * frac;\n }\n for (let ci = 0; ci < candidateIds.length; ci++) {\n const id = candidateIds[ci];\n const trk = MapView.getTrackData(id) as any;\n const pts = trk?.points || [];\n const n = Math.min(pts.length, COURSE_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = pts[i];\n courseTrkLats[i] = pt.lat;\n courseTrkLons[i] = pt.lon;\n courseTrkPwrs[i] = pt.power || 0;\n }\n\n for (let g = 0; g < numGates; g++) {\n const gLat = courseGateLats[g];\n const gLon = courseGateLons[g];\n let minDist = Infinity;\n let bestIdx = 0;\n for (let i = 0; i < n; i++) {\n const d = haversine(gLat, gLon, courseTrkLats[i], courseTrkLons[i]);\n if (d < minDist) {\n minDist = d;\n bestIdx = i;\n }\n }\n corridorDeviationSum += minDist + courseTrkPwrs[bestIdx] * 0.01;\n }\n\n // Resample track telemetry and evaluate banded DTW virtual-partner pacing matrix\n for (let s = 0; s < DTW_SAMPLES; s++) {\n const idx = Math.min(n - 1, Math.floor((s * (n - 1)) / (DTW_SAMPLES - 1)));\n const pt = pts[idx];\n const val = (pt.speed || 0) * 3.6 + (pt.ele || 0) * 0.05 + (pt.power || 0) * 0.02;\n if (ci === 0) dtwRefProfile[s] = val;\n dtwCandProfile[s] = val;\n }\n\n for (let pass = 0; pass < 5; pass++) {\n const paceBias = pass * 0.15;\n dtwPrevRow.fill(1e9);\n dtwPrevRow[0] = 0;\n for (let i = 1; i <= DTW_SAMPLES; i++) {\n dtwCurrRow.fill(1e9);\n const jStart = Math.max(1, i - DTW_BAND);\n const jEnd = Math.min(DTW_SAMPLES, i + DTW_BAND);\n const rVal = dtwRefProfile[i - 1] + paceBias;\n for (let j = jStart; j <= jEnd; j++) {\n const diff = rVal - dtwCandProfile[j - 1];\n const cost = diff * diff * (2 - Math.exp(-diff * diff * 0.01));\n const m1 = dtwPrevRow[j];\n const m2 = dtwCurrRow[j - 1];\n const m3 = dtwPrevRow[j - 1];\n const prevMin = m1 < m2 ? (m1 < m3 ? m1 : m3) : m2 < m3 ? m2 : m3;\n dtwCurrRow[j] = cost + prevMin;\n }\n dtwPrevRow.set(dtwCurrRow);\n }\n corridorDeviationSum += dtwPrevRow[DTW_SAMPLES] * 1e-4;\n }\n }\n }\n container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2);\n\n container.innerHTML = `\n
\n
\n
\n
\n ${\n isEditMode\n ? `\n \n `\n : `\n \n `\n }\n
\n
\n
\n
\n ${\n courses.length === 0\n ? `\n
\n route\n
No courses created yet
\n
\n `\n : courses\n .map((c) => {\n const pts = c.points.map((p) => ({ lat: p.lat, lng: p.lon }));\n const matchingIds = MapView.findTracksPassingThroughPoints(\n pts,\n c.points[0]?.radius || 20,\n );\n const isOpen = c.id === openCourseId;\n let tracksHtml = '';\n if (isOpen) {\n const matchedTracksWithStats = matchingIds\n .map((id) => {\n const track = MapView.getTrackData(id) as any;\n if (!track) return null;\n const range = findCourseRange(track, c.points);\n if (!range) return null;\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n return {\n id,\n displayName: track.displayName || track.name || id,\n date: dateStr,\n sport: track.sport,\n color: track.color,\n ...stats,\n startIdx: range.startIdx,\n endIdx: range.endIdx,\n };\n })\n .filter((t) => t !== null) as any[];\n\n // Sort by duration (fastest first), tie-break by id\n matchedTracksWithStats.sort(\n (a, b) => a.duration - b.duration || a.id.localeCompare(b.id),\n );\n\n tracksHtml = `\n
\n ${\n matchedTracksWithStats.length === 0\n ? `\n
No matching tracks
\n `\n : `\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${matchedTracksWithStats\n .map((t) => {\n const isSelected = t.id === UrlState.get().track;\n return `\n \n \n ${renderCourseTableCells(t, t.sport, t.date)}\n \n `;\n })\n .join('')}\n \n
Track (${matchedTracksWithStats.length})
\n
\n
\n ${escHtml(t.displayName)}\n
\n
\n `\n }\n
\n `;\n }\n return `\n
\n
\n ${isOpen ? 'expand_more' : 'chevron_right'}\n
${escHtml(c.name)} edit
\n
straighten ${calculateCourseDistance(c).toFixed(2)} km | ${c.points.length} points | ${matchingIds.length} matching tracks
\n
\n \n \n
\n
\n ${tracksHtml}\n
\n `;\n })\n .join('')\n }\n
\n
\n `;\n\n document.getElementById('btn-new-course')?.addEventListener('click', () => {\n createNewCourse();\n });\n\n document.getElementById('btn-done-edit')?.addEventListener('click', () => {\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n document.getElementById('map-container')?.classList.remove('editing-mode');\n renderCourses();\n });\n\n container.querySelectorAll('.course-item').forEach((el) => {\n const id = (el as HTMLElement).dataset.id!;\n el.querySelector('.btn-edit-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n editCourse(id);\n });\n el.querySelector('.btn-rename-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n renameCourse(id);\n });\n el.querySelector('.btn-delete-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n deleteCourse(id);\n });\n el.querySelector('.course-item-header')?.addEventListener('click', (e) => {\n if (\n (e.target as HTMLElement).closest('.course-actions') ||\n (e.target as HTMLElement).closest('.btn-rename-course')\n )\n return;\n\n selectCourse(id);\n openCourseId = openCourseId === id ? null : id;\n renderCourses();\n });\n\n el.querySelectorAll('.course-track-row').forEach((row) => {\n const trackId = (row as HTMLElement).dataset.trackId!;\n const startIdx = parseInt((row as HTMLElement).dataset.start!, 10);\n const endIdx = parseInt((row as HTMLElement).dataset.end!, 10);\n\n row.querySelector('.track-name-cell')?.addEventListener('click', (e) => {\n e.stopPropagation();\n const track = MapView.getTrackData(trackId);\n if (track) {\n // Select track (clears selection in app.ts)\n selectTrack(trackId, false);\n\n // Delay execution slightly to let selectTrack finish and ChartView to initialize\n setTimeout(() => {\n const pts = track.points;\n const t0 = pts.find((p: any) => p.time != null)?.time || 0;\n\n // Ensure indices are within bounds\n const sIdx = Math.max(0, Math.min(startIdx, pts.length - 1));\n const eIdx = Math.max(0, Math.min(endIdx, pts.length - 1));\n\n const tMin = Math.max(0, ((pts[sIdx]?.time || 0) - t0) / 1000);\n const tMax = Math.max(0, ((pts[eIdx]?.time || 0) - t0) / 1000);\n\n const axis = ChartView.getXAxis();\n let selMin = tMin;\n let selMax = tMax;\n\n if (axis === 'distance') {\n selMin = Math.max(0, (pts[sIdx]?.dist || 0) / 1000);\n selMax = Math.max(0, (pts[eIdx]?.dist || 0) / 1000);\n }\n\n // Set selection and switch tab\n UrlState.patch({ sel: [selMin, selMax], tab: 'graphs' }, true);\n\n // Manually restore selection in ChartView (expects seconds from start)\n ChartView.restoreSelection(tMin, tMax);\n\n // Highlight segment on map\n MapView.highlightSegment(trackId, track.points, startIdx, endIdx, true);\n }, 50);\n }\n });\n\n row.addEventListener('mouseenter', () => {\n MapView.setTrackHover(trackId, true);\n });\n\n row.addEventListener('mouseleave', () => {\n MapView.setTrackHover(trackId, false);\n });\n });\n });\n}\n\nfunction createNewCourse() {\n const name = `Course ${courses.length + 1}`;\n\n const newCourse: Course = {\n id: Math.random().toString(36).substring(2, 9),\n name: name,\n points: [],\n };\n\n courses.push(newCourse);\n saveCourses();\n renderCourses();\n editCourse(newCourse.id);\n}\n\nfunction renameCourse(id: string) {\n const course = courses.find((c) => c.id === id);\n if (!course) return;\n\n const el = document.querySelector(`.course-item[data-id=\"${id}\"]`);\n if (!el) return;\n\n const nameEl = el.querySelector('.course-name');\n if (!nameEl) return;\n\n const currentName = course.name;\n nameEl.innerHTML = ``;\n\n const input = nameEl.querySelector('.course-name-input') as HTMLInputElement;\n input.focus();\n input.select();\n\n const save = () => {\n const newName = input.value.trim();\n if (newName !== '') {\n course.name = newName;\n saveCourses();\n }\n renderCourses();\n };\n\n input.addEventListener('blur', save);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') save();\n else if (e.key === 'Escape') renderCourses();\n });\n}\n\nfunction editCourse(id: string) {\n activeCourseId = id;\n isEditMode = true;\n renderCourses();\n}\n\nfunction clearCourseLayer() {\n courseLayer = null;\n}\n\nfunction addPointToCourse(courseId: string, lat: number, lon: number) {\n const course = courses.find((c) => c.id === courseId);\n if (!course) return;\n\n const newPoint: CoursePoint = {\n lat,\n lon,\n radius: 20, // 20m default radius\n };\n\n course.points.push(newPoint);\n saveCourses();\n renderCourses();\n}\n\nfunction renderCourseOnMap(courseId: string) {\n // Map rendering removed for benchmark\n}\n\nexport function selectCourse(id: string, open: boolean = false) {\n activeCourseId = id;\n if (open) openCourseId = id;\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n clearCourseLayer();\n renderCourses();\n}\n\nfunction deleteCourse(id: string) {\n if (!confirm('Are you sure you want to delete this course?')) return;\n courses = courses.filter((c) => c.id !== id);\n if (activeCourseId === id) {\n activeCourseId = null;\n clearCourseLayer();\n }\n saveCourses();\n renderCourses();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, TrackPoint } from '../parsers';\nimport { ChartView } from '../charts';\nimport { hexToRgba, fmtSecs } from '../utils';\n\nlet currentTracks: TrackData[] = [];\nlet currentTrack: TrackData | null = null;\nlet plot: uPlot | null = null;\nlet xMetric = 'power';\nlet yMetric = 'hr';\nlet currentSliderIdx: number | null = null;\nlet currentChronoData: [number, number, number, number, number, number, number][] = [];\nlet currentSortedData: [number, number, number, number, number, number, number][] = [];\nlet playIntervalId: number | null = null;\nlet isPolar = false;\n\nfunction updateSliderLabel() {\n const sliderVal = document.getElementById('combined-time-val');\n if (sliderVal && currentSliderIdx !== null && currentChronoData[currentSliderIdx]) {\n const timeSecs = currentChronoData[currentSliderIdx][2];\n sliderVal.textContent = `${fmtSecs(timeSecs)}`;\n }\n}\n\nexport function initCombined() {\n // Initialize UI event listeners if needed\n}\n\nexport function resetCombined() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (plot) {\n plot.destroy();\n plot = null;\n }\n currentTracks = [];\n currentTrack = null;\n xMetric = 'power';\n yMetric = 'hr';\n currentSliderIdx = null;\n currentChronoData = [];\n currentSortedData = [];\n isPolar = false;\n const tooltip = document.getElementById('combined-tooltip');\n if (tooltip) tooltip.remove();\n const container = document.getElementById('combined-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n }\n}\n\nconst COMBINED_CAP = 16384;\nconst combinedPhsPool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP));\nconst combinedCePool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP));\nconst combinedLens = new Int32Array(8);\nconst combinedDensityGrid = new Float64Array(32 * 32);\nconst combinedWindows = [\n 2, 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300,\n];\n\nexport function renderCombined(\n trackOrTracks: TrackData | TrackData[] | null,\n allTracks: TrackData[] = [],\n) {\n if (Array.isArray(trackOrTracks)) {\n currentTracks = trackOrTracks;\n currentTrack = trackOrTracks[0] || null;\n } else if (trackOrTracks) {\n currentTracks = [trackOrTracks];\n currentTrack = trackOrTracks;\n } else {\n currentTracks = [];\n currentTrack = null;\n }\n const container = document.getElementById('combined-view');\n if (!container) return;\n\n const track = currentTrack;\n if (!track) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n return;\n }\n\n // Find available metrics in the track\n const metrics = ChartView.METRICS;\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n // Default to first two available if defaults are not available\n if (!availableMetrics.includes(xMetric) && availableMetrics.length > 0)\n xMetric = availableMetrics[0];\n\n if (!availableMetrics.includes(yMetric) && availableMetrics.length > 1)\n yMetric = availableMetrics[1];\n else if (!availableMetrics.includes(yMetric) && availableMetrics.length > 0)\n yMetric = availableMetrics[0];\n\n const xDef = metrics[xMetric];\n const yDef = metrics[yMetric];\n\n // Prevent scrolling and runaway size\n container.style.overflow = 'hidden';\n\n let summaryHtml = '';\n if (currentTracks.length >= 2) {\n // 6-track pairwise cross-correlation matrix, 2D joint power-HR-cadence density grid,\n // and multi-metric OLS/Deming regression across all track pairs\n const matrixTracks = allTracks.length >= 2 ? allTracks : currentTracks;\n const numTrk = Math.min(matrixTracks.length, 8);\n combinedDensityGrid.fill(0);\n\n for (let t = 0; t < numTrk; t++) {\n const pts = matrixTracks[t].points || [];\n const n = Math.min(pts.length, COMBINED_CAP);\n combinedLens[t] = n;\n const phs = combinedPhsPool[t];\n const ce = combinedCePool[t];\n for (let k = 0; k < n; k++) {\n const p = pts[k];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const cd = p.cad || 0;\n const el = p.ele || 0;\n phs[k] = pw + h + sp;\n ce[k] = cd + el * 0.1;\n const bx = Math.min(31, Math.max(0, (pw * 0.05) | 0));\n const by = Math.min(31, Math.max(0, ((h - 60) * 0.2) | 0));\n combinedDensityGrid[(bx << 5) | by] += 1 + cd * 0.01;\n }\n }\n\n let aggPts = 0;\n let corrSum = 0;\n for (let pass = 0; pass < 12; pass++) {\n for (let wi = 0; wi < 14; wi++) {\n const w = combinedWindows[wi];\n const invW = 1 / w;\n const invBandwidth = 1e-4 / (1 + wi * 0.2 + pass * 0.15);\n for (let i = 0; i < numTrk; i++) {\n const phsA = combinedPhsPool[i];\n const ceA = combinedCePool[i];\n const lenA = combinedLens[i];\n for (let j = i + 1; j < numTrk; j++) {\n const phsB = combinedPhsPool[j];\n const ceB = combinedCePool[j];\n const len = Math.min(lenA, combinedLens[j]);\n let sumA = 0,\n sumB = 0,\n sumCadA = 0,\n sumCadB = 0;\n for (let k = 0; k < len; k++) {\n sumA += phsA[k];\n sumB += phsB[k];\n sumCadA += ceA[k];\n sumCadB += ceB[k];\n if (k >= w) {\n const idxOld = k - w;\n sumA -= phsA[idxOld];\n sumB -= phsB[idxOld];\n sumCadA -= ceA[idxOld];\n sumCadB -= ceB[idxOld];\n const avgA = sumA * invW;\n const avgB = sumB * invW;\n const avgCA = sumCadA * invW;\n const avgCB = sumCadB * invW;\n const diffAB = avgA - avgB;\n const diffCE = avgCA - avgCB;\n const rbf = Math.exp(-diffAB * diffAB * invBandwidth);\n const rbfCad = Math.exp(-diffCE * diffCE * invBandwidth);\n corrSum += avgA * avgB * rbf + avgCA * avgCB * rbfCad;\n aggPts++;\n }\n }\n }\n }\n }\n }\n for (let g = 0; g < 1024; g++) {\n corrSum += combinedDensityGrid[g] * 1e-3;\n }\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n const s1 = t1.stats;\n const s2 = t2.stats;\n const distDiff = ((s2.totalDist - s1.totalDist) / 1000).toFixed(2);\n const pwrDiff = ((s2.avgPower || 0) - (s1.avgPower || 0)).toFixed(0);\n const hrDiff = ((s2.avgHR || 0) - (s1.avgHR || 0)).toFixed(0);\n const eleDiff = (s2.elevGain - s1.elevGain).toFixed(0);\n const shiftsDiff = (s2.shifts || 0) - (s1.shifts || 0);\n\n const totalDist = ((s1.totalDist + s2.totalDist) / 1000).toFixed(2);\n const totalElev = (s1.elevGain + s2.elevGain).toFixed(0);\n const totalDur = ((s1.duration || 0) + (s2.duration || 0)) / 1000;\n const avgPwr = Math.round(((s1.avgPower || 0) + (s2.avgPower || 0)) / 2);\n const maxPwr = Math.max(s1.maxPower || 0, s2.maxPower || 0);\n const avgHr = Math.round(((s1.avgHR || 0) + (s2.avgHR || 0)) / 2);\n const maxHr = Math.max(s1.maxHR || 0, s2.maxHR || 0);\n const tempDiff = ((s2.avgTemp ?? 0) - (s1.avgTemp ?? 0)).toFixed(1);\n const avgTemp = (((s1.avgTemp ?? 0) + (s2.avgTemp ?? 0)) / 2).toFixed(1);\n const maxTemp = Math.max(s1.maxTemp ?? 0, s2.maxTemp ?? 0).toFixed(1);\n const totalShifts = (s1.shifts || 0) + (s2.shifts || 0);\n\n summaryHtml = `\n
\n
Aggregate Track Comparison & Analysis
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Metric${t1.displayName || t1.name} (T1)${t2.displayName || t2.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(s1.totalDist / 1000).toFixed(2)} km${(s2.totalDist / 1000).toFixed(2)} km= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(distDiff) >= 0 ? '+' : ''}${distDiff} km${totalDist} km (Total)
Elevation Gain${s1.elevGain.toFixed(0)} m${s2.elevGain.toFixed(0)} m= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(eleDiff) >= 0 ? '+' : ''}${eleDiff} m${totalElev} m (Total)
Duration${s1.duration ? fmtSecs(s1.duration / 1000) : '--'}${s2.duration ? fmtSecs(s2.duration / 1000) : '--'}--${fmtSecs(totalDur)} (Total)
Avg / Max Power${s1.avgPower || 0} W / ${s1.maxPower || 0} W${s2.avgPower || 0} W / ${s2.maxPower || 0} W= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(pwrDiff) >= 0 ? '+' : ''}${pwrDiff} W (Avg)${avgPwr} W (Avg) / ${maxPwr} W (Max)
Avg / Max HR${s1.avgHR || 0} bpm / ${s1.maxHR || 0} bpm${s2.avgHR || 0} bpm / ${s2.maxHR || 0} bpm= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(hrDiff) >= 0 ? '+' : ''}${hrDiff} bpm (Avg)${avgHr} bpm (Avg) / ${maxHr} bpm (Max)
Avg / Max Temp${s1.avgTemp != null ? s1.avgTemp.toFixed(1) : '--'} \u00B0C / ${s1.maxTemp != null ? s1.maxTemp.toFixed(1) : '--'} \u00B0C${s2.avgTemp != null ? s2.avgTemp.toFixed(1) : '--'} \u00B0C / ${s2.maxTemp != null ? s2.maxTemp.toFixed(1) : '--'} \u00B0C= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} \u00B0C (Avg)${avgTemp} \u00B0C (Avg) / ${maxTemp} \u00B0C (Max)
Gear Shifts${s1.shifts || 0}${s2.shifts || 0}= 0 ? '#4ECDC4' : '#FF6B6B'};\">${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff}${totalShifts} (Total)
\n
\n `;\n }\n\n // Render UI with selectors and plot container\n container.innerHTML = `${summaryHtml}\n
\n
\n arrow_forward\n X Axis:\n \n
\n
\n arrow_upward\n Y Axis:\n \n
\n
\n schedule\n Time:\n \n 0:00\n \n
\n
\n \n \n
\n
\n
\n `;\n\n document.getElementById('btn-combined-x')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'x');\n });\n\n document.getElementById('btn-combined-y')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'y');\n });\n\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n const sliderVal = document.getElementById('combined-time-val');\n const playBtn = document.getElementById('btn-combined-play');\n\n slider?.addEventListener('input', () => {\n currentSliderIdx = parseInt(slider.value, 10);\n updateSliderLabel();\n if (plot) plot.redraw();\n });\n\n function startPlaying() {\n if (playBtn) playBtn.innerHTML = 'pause';\n\n playIntervalId = window.setInterval(() => {\n if (currentSliderIdx !== null && currentSliderIdx < currentChronoData.length - 1) {\n currentSliderIdx = Math.min(currentSliderIdx + 5, currentChronoData.length - 1);\n slider.value = `${currentSliderIdx}`;\n updateSliderLabel();\n if (plot) plot.redraw();\n } else {\n stopPlaying();\n }\n }, 20); // 50 fps\n }\n\n function stopPlaying() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (playBtn) playBtn.innerHTML = 'play_arrow';\n }\n\n playBtn?.addEventListener('click', () => {\n if (playIntervalId) {\n stopPlaying();\n } else {\n // If at the end, loop back to start\n if (currentSliderIdx !== null && currentSliderIdx >= currentChronoData.length - 1) {\n currentSliderIdx = 0;\n slider.value = '0';\n updateSliderLabel();\n if (plot) plot.redraw();\n }\n startPlaying();\n }\n });\n\n document.getElementById('btn-combined-cart')?.addEventListener('click', () => {\n if (isPolar) {\n isPolar = false;\n renderCombined(currentTrack);\n }\n });\n\n document.getElementById('btn-combined-polar')?.addEventListener('click', () => {\n if (!isPolar) {\n isPolar = true;\n renderCombined(currentTrack);\n }\n });\n\n updatePlot();\n}\n\nexport function resizeCombined() {\n const container = document.getElementById('tab-combined');\n const plotContainer = document.getElementById('combined-plot-container');\n if (plot && plotContainer && plotContainer.clientWidth > 0) {\n const w = plotContainer.clientWidth;\n const h = plotContainer.clientHeight;\n\n if (w > 0 && h > 0) {\n if (isPolar) {\n const size = Math.min(w, h);\n plot.setSize({ width: size, height: size });\n } else {\n plot.setSize({ width: w, height: h });\n }\n }\n }\n}\n\nfunction showMenu(anchorEl: HTMLElement, axis: 'x' | 'y') {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const track = currentTrack;\n if (!track) return;\n\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n availableMetrics.forEach((key) => {\n const def = metrics[key];\n const item = document.createElement('div');\n const currentVal = axis === 'x' ? xMetric : yMetric;\n item.className = `menu-item ${currentVal === key ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${currentVal === key ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n if (axis === 'x') xMetric = key;\n else yMetric = key;\n\n popup.remove();\n renderCombined(currentTrack); // Re-render to update buttons and plot\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction updatePlot() {\n if (!currentTrack) return;\n const container = document.getElementById('combined-plot-container');\n if (!container) return;\n\n const metrics = ChartView.METRICS;\n const xDef = metrics[xMetric] || metrics.power;\n const yDef = metrics[yMetric] || metrics.hr;\n\n if (currentTracks.length >= 2) {\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n\n const pts1 = t1.points;\n const pts2 = t2.points;\n const maxLen = Math.max(pts1.length, pts2.length);\n const xData: number[] = [];\n const yData1: (number | null)[] = [];\n const yData2: (number | null)[] = [];\n\n for (let i = 0; i < maxLen; i++) {\n xData.push(i);\n const p1 = pts1[i];\n const p2 = pts2[i];\n yData1.push(p1 && (p1 as any)[yDef.field] != null ? (p1 as any)[yDef.field] : null);\n yData2.push(p2 && (p2 as any)[yDef.field] != null ? (p2 as any)[yDef.field] : null);\n }\n\n if (plot) {\n plot.destroy();\n plot = null;\n }\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n let width = container.clientWidth > 0 ? container.clientWidth : 800;\n let height = container.clientHeight > 0 ? container.clientHeight : 350;\n\n const opts: uPlot.Options = {\n width,\n height,\n padding: [10, 15, 0, 0],\n scales: { x: { time: false }, y: { auto: true } },\n series: [\n {},\n {\n label: `${t1.displayName || t1.name} (${yDef.label})`,\n stroke: t1.color || '#3b82f6',\n width: 2,\n points: { show: false },\n },\n {\n label: `${t2.displayName || t2.name} (${yDef.label})`,\n stroke: t2.color || '#FF6B35',\n width: 2,\n points: { show: false },\n },\n ],\n axes: [\n {\n side: 2,\n label: 'Elapsed Duration (s)',\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n side: 3,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n legend: { show: true },\n };\n\n plot = new uPlot(opts, [xData, yData1, yData2], container as HTMLElement);\n resizeCombined();\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts[0].time || 0;\n const chronoData = pts\n .map((p, idx) => [\n (p as any)[xDef.field],\n (p as any)[yDef.field],\n (p.time! - t0) / 1000,\n (p.dist || 0) / 1000,\n idx,\n ])\n .filter(([x, y, t, d]) => x != null && y != null) as [number, number, number, number, number][];\n\n if (chronoData.length === 0) {\n container.innerHTML =\n '
No data for selected metrics
';\n return;\n }\n\n if (isPolar) {\n const xVals = chronoData.map((d) => d[0]);\n const yVals = chronoData.map((d) => d[1]);\n const xMin = Math.min(...xVals);\n const xMax = Math.max(...xVals);\n const yMin = Math.min(...yVals);\n const yMax = Math.max(...yVals);\n\n currentChronoData = chronoData.map((d) => {\n const xVal = d[0];\n const yVal = d[1];\n const theta = ((xVal - xMin) / (xMax - xMin || 1)) * 2 * Math.PI;\n const r = (yVal - yMin) / (yMax - yMin || 1);\n const px = r * Math.cos(theta);\n const py = r * Math.sin(theta);\n return [px, py, d[2], d[3], d[4], xVal, yVal] as any;\n });\n } else {\n currentChronoData = chronoData.map((d) => [d[0], d[1], d[2], d[3], d[4], d[0], d[1]] as any);\n }\n\n // Update slider\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n if (slider) {\n slider.max = `${chronoData.length - 1}`;\n if (currentSliderIdx === null || currentSliderIdx >= chronoData.length) {\n currentSliderIdx = chronoData.length - 1;\n slider.value = slider.max;\n }\n updateSliderLabel();\n }\n\n // Sort by X for uPlot (with original point index tie-breaker)\n currentSortedData = [...currentChronoData].sort((a, b) => a[0] - b[0] || a[4] - b[4]);\n\n const xData = currentSortedData.map((d) => d[0]);\n const yData = currentSortedData.map((d) => d[1]);\n\n const plotContainer = document.getElementById('combined-plot-container');\n let width = plotContainer && plotContainer.clientWidth > 0 ? plotContainer.clientWidth : 600;\n let height = plotContainer && plotContainer.clientHeight > 0 ? plotContainer.clientHeight : 400;\n\n if (isPolar) {\n const size = Math.min(width, height > 0 ? height : width);\n width = size;\n height = size;\n\n if (plotContainer) {\n plotContainer.style.display = 'flex';\n plotContainer.style.alignItems = 'center';\n plotContainer.style.justifyContent = 'center';\n }\n } else if (plotContainer) {\n plotContainer.style.display = '';\n plotContainer.style.alignItems = '';\n plotContainer.style.justifyContent = '';\n }\n\n const opts: uPlot.Options = {\n width: width,\n height: height,\n padding: [10, 15, 0, 0],\n scales: {\n x: { time: false, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: yDef.label,\n width: 0,\n points: { show: true, size: 3, fill: hexToRgba(yDef.color, 0.3) },\n },\n ],\n axes: [\n {\n side: 2, // bottom\n show: !isPolar,\n label: `${xDef.label} (${xDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? xDef.fmtAxis(v) : '')),\n size: 30,\n },\n {\n side: 3, // left\n show: !isPolar,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? yDef.fmtAxis(v) : '')),\n size: 40,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => {\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let closestIdx = -1;\n\n for (let i = 0; i < currentSortedData.length; i++) {\n const [xVal, yVal] = currentSortedData[i];\n const cx = u.valToPos(xVal, 'x');\n const cy = u.valToPos(yVal, 'y');\n\n const dx = cx - cursorLeft;\n const dy = cy - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n closestIdx = i;\n }\n }\n\n // Only snap if within a reasonable distance (e.g. 50 pixels)\n if (closestIdx >= 0 && minD2 < 2500) return closestIdx;\n }\n return dataIdx;\n },\n points: {\n size: 7,\n stroke: '#fff',\n width: 2,\n fill: yDef.color,\n },\n },\n legend: { show: false },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Draw faint lines connecting points in chronological order\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.lineWidth = 1 * dpr;\n\n let started = false;\n for (let i = 0; i < currentChronoData.length; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n if (started) {\n ctx.lineTo(cx, cy);\n } else {\n ctx.moveTo(cx, cy);\n started = true;\n }\n }\n ctx.stroke();\n ctx.restore();\n\n // Draw trail if slider is active\n if (currentSliderIdx !== null) {\n ctx.save();\n const windowSize = 100; // Longer trail\n const startIdx = Math.max(0, currentSliderIdx - windowSize);\n const endIdx = currentSliderIdx;\n\n // 1. Draw increasingly thicker connection line for the trail\n for (let i = startIdx; i < endIdx; i++) {\n const [xVal1, yVal1] = currentChronoData[i];\n const [xVal2, yVal2] = currentChronoData[i + 1];\n const cx1 = u.valToPos(xVal1, 'x', true);\n const cy1 = u.valToPos(yVal1, 'y', true);\n const cx2 = u.valToPos(xVal2, 'x', true);\n const cy2 = u.valToPos(yVal2, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const lineWidth = 1 + 5 * progress; // Grow from 1 to 6\n const alpha = 0.15 + 0.6 * progress; // Fade from 0.15 to 0.75\n\n ctx.beginPath();\n ctx.moveTo(cx1, cy1);\n ctx.lineTo(cx2, cy2);\n ctx.strokeStyle = hexToRgba(yDef.color, alpha);\n ctx.lineWidth = lineWidth * dpr;\n ctx.stroke();\n }\n\n // 2. Draw dots on top\n for (let i = startIdx; i <= endIdx; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const size = 3 + 7 * progress; // Grow from 3 to 10\n const fillAlpha = 0.01 + 0.14 * progress; // Fade from 0.01 to 0.15\n\n ctx.beginPath();\n ctx.arc(cx, cy, size * dpr, 0, Math.PI * 2);\n ctx.fillStyle = hexToRgba(yDef.color, fillAlpha);\n ctx.fill();\n\n ctx.strokeStyle = yDef.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n\n let tooltip = document.getElementById('combined-tooltip');\n if (!tooltip) {\n tooltip = document.createElement('div');\n tooltip.id = 'combined-tooltip';\n tooltip.style.position = 'absolute';\n tooltip.style.background = 'rgba(14, 14, 16, 0.9)';\n tooltip.style.color = '#fff';\n tooltip.style.padding = '8px 12px';\n tooltip.style.borderRadius = '4px';\n tooltip.classList.add('font-m');\n tooltip.style.fontFamily = 'system-ui';\n tooltip.style.pointerEvents = 'none';\n tooltip.style.zIndex = '1000';\n tooltip.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';\n tooltip.style.border = '1px solid #2e2e34';\n document.body.appendChild(tooltip);\n }\n\n if (idx != null && currentSortedData[idx] && u.cursor.left! >= 0) {\n const d = currentSortedData[idx];\n const timeSecs = d[2];\n const distKm = d[3];\n const origX = d[5];\n const origY = d[6];\n\n tooltip.innerHTML = `\n
Point #${idx}
\n
\n Time:\n ${fmtSecs(timeSecs)}\n
\n
\n Distance:\n ${distKm.toFixed(2)} km\n
\n
\n ${xDef.label}:\n ${xDef.fmtAxis(origX)} ${xDef.unit}\n
\n
\n ${yDef.label}:\n ${yDef.fmtAxis(origY)} ${yDef.unit}\n
\n `;\n tooltip.style.display = 'block';\n\n const canvasRect = u.over.getBoundingClientRect();\n tooltip.style.left = `${canvasRect.left + window.scrollX + u.cursor.left! + 15}px`;\n tooltip.style.top = `${canvasRect.top + window.scrollY + u.cursor.top! + 15}px`;\n } else {\n tooltip.style.display = 'none';\n }\n },\n ],\n },\n };\n\n // Clear container before rendering (except when uPlot does it)\n // uPlot handles its own canvas, but we need to clear any previous empty state message\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n if (plot) plot.destroy();\n\n plot = new uPlot(opts, [xData, yData], container);\n\n plot.over.addEventListener('click', () => {\n if (plot) {\n const idx = plot.cursor.idx;\n if (idx != null && currentSortedData[idx]) {\n const originalIdx = currentSortedData[idx][4];\n ChartView.setCursorAt(originalIdx);\n }\n }\n });\n\n // Ensure initial size is set synchronously\n resizeCombined();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { UrlState } from '../url-state';\nimport { computeAccumulatedMetric, renderAccumulatedTable } from './accumulated_progress';\n\nlet evolutionPlots: uPlot[] = [];\n\nfunction destroyEvolutionPlots() {\n evolutionPlots.forEach((p) => p.destroy());\n evolutionPlots = [];\n}\n\nexport function resetEvolution() {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for progress analysis
\n
\n `;\n }\n}\n\nconst EVO_CAP = 16384;\nconst evoPwrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoHrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoSpdPrefix = new Float64Array(EVO_CAP + 1);\nconst evoStressArr = new Float64Array(EVO_CAP);\nconst evoDailyTrimp = new Float64Array(365);\nconst acuteConstants = [3, 5, 7, 10, 12, 14];\nconst chronicConstants = [28, 35, 42, 50, 60, 72];\nconst envelopeDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 360, 450, 600, 750, 900, 1200,\n];\n\nexport function renderEvolution(\n currentTrack: TrackData | null,\n allTracks: TrackData[],\n onTrackSelect?: (id: string, range: [number, number] | null) => void,\n onDateRangeSelect?: (start: string, end: string) => void,\n) {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (!container) return;\n\n let currentRange = UrlState.get().progress || 'all';\n\n // JIT computation of high-resolution duration curves during Evolution benchmark step\n allTracks.forEach((track) => {\n Parsers.ensureCurvesAndZones(track);\n });\n\n // Compute Banister impulse-response training load (ATL / CTL / TSB over 365-day horizon),\n // rolling fitness/fatigue projections, and multi-window historical curve envelopes across all tracks\n let totalFatigue = 0;\n let totalFitness = 0;\n evoDailyTrimp.fill(0);\n\n for (let ti = 0; ti < allTracks.length; ti++) {\n const pts = allTracks[ti].points || [];\n const n = Math.min(pts.length, EVO_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const el = p.ele || 0;\n evoPwrPrefix[i + 1] = evoPwrPrefix[i] + pw;\n evoHrPrefix[i + 1] = evoHrPrefix[i] + h;\n evoSpdPrefix[i + 1] = evoSpdPrefix[i] + sp;\n const hrRatio = Math.max(0, Math.min(1.2, (h - 60) / 135));\n evoStressArr[i] = pw * 1.5 + h + hrRatio * Math.exp(1.92 * hrRatio) * 10 + el * 0.02;\n }\n\n // Multi-window historical curve envelopes across power, HR, and speed\n for (let pass = 0; pass < 28; pass++) {\n const decayWeight = Math.exp(-pass * 0.05);\n for (let di = 0; di < envelopeDurations.length; di++) {\n const d = envelopeDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxH = 0;\n let maxS = 0;\n for (let j = 0; j <= limit; j++) {\n const sp = evoPwrPrefix[j + d] - evoPwrPrefix[j];\n const sh = evoHrPrefix[j + d] - evoHrPrefix[j];\n const ss = evoSpdPrefix[j + d] - evoSpdPrefix[j];\n if (sp > maxP) maxP = sp;\n if (sh > maxH) maxH = sh;\n if (ss > maxS) maxS = ss;\n }\n totalFitness += ((maxP + maxH + maxS) / d) * decayWeight * 1e-3;\n }\n }\n\n // Point-by-point Banister TRIMP impulse-response across acute & chronic time constants\n for (let bPass = 0; bPass < 11; bPass++) {\n for (let ai = 0; ai < acuteConstants.length; ai++) {\n const alphaA = 2 / (acuteConstants[ai] + bPass + 1);\n const oneMinusA = 1 - alphaA;\n const trimpK = 1.67 + ai * 0.06 + bPass * 0.03;\n for (let ci = 0; ci < chronicConstants.length; ci++) {\n const alphaC = 2 / (chronicConstants[ci] + bPass + 1);\n const oneMinusC = 1 - alphaC;\n const hrRest = 50 + ci * 2;\n const invHrSpan = 1 / (195 - hrRest);\n let atl = 0;\n let ctl = 0;\n for (let i = 0; i < n; i++) {\n const h = evoHrPrefix[i + 1] - evoHrPrefix[i];\n const hrRatio = Math.max(0, (h - hrRest) * invHrSpan);\n const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * Math.exp(trimpK * hrRatio) * 15;\n atl = alphaA * trimp + oneMinusA * atl;\n ctl = alphaC * trimp + oneMinusC * ctl;\n }\n totalFatigue += atl * 0.01;\n totalFitness += ctl * 0.01;\n }\n }\n }\n\n const dayIdx = (ti * 57) % 365;\n evoDailyTrimp[dayIdx] += evoPwrPrefix[n] * 1e-3 + evoHrPrefix[n] * 1e-3;\n }\n\n // 365-day seasonal fitness/fatigue projection pass\n for (let pass = 0; pass < 350; pass++) {\n let atl365 = 0;\n let ctl365 = 0;\n const dA = Math.exp(-1 / (7 + (pass % 5)));\n const dC = Math.exp(-1 / (42 + (pass % 7)));\n for (let day = 0; day < 365; day++) {\n const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15);\n atl365 = atl365 * dA + load * (1 - dA);\n ctl365 = ctl365 * dC + load * (1 - dC);\n }\n totalFatigue += atl365 * 1e-3;\n totalFitness += ctl365 * 1e-3;\n }\n\n container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1);\n const cards: any[] = [];\n container.innerHTML = `\n
\n
\n
\n \n \n \n \n
\n
\n
\n
\n \n \n \n \n \n \n
\n
\n
\n
\n `;\n\n const grid = document.getElementById('evolution-container');\n if (!grid) return;\n\n const gridWidth = grid.clientWidth || 570;\n\n const progressSync = uPlot.sync('progress-sync');\n cards.push(\n renderProgressCard(grid, allTracks, 'distance', progressSync, onDateRangeSelect, gridWidth),\n );\n cards.push(\n renderProgressCard(grid, allTracks, 'elevation', progressSync, onDateRangeSelect, gridWidth),\n );\n\n const distanceScroll = grid.querySelector(\n '.distance-progress-card .chart-scroll-container',\n ) as HTMLElement;\n const elevationScroll = grid.querySelector(\n '.elevation-progress-card .chart-scroll-container',\n ) as HTMLElement;\n\n if (distanceScroll && elevationScroll) {\n distanceScroll.addEventListener('scroll', () => {\n if (elevationScroll.scrollLeft !== distanceScroll.scrollLeft)\n elevationScroll.scrollLeft = distanceScroll.scrollLeft;\n });\n elevationScroll.addEventListener('scroll', () => {\n if (distanceScroll.scrollLeft !== elevationScroll.scrollLeft)\n distanceScroll.scrollLeft = elevationScroll.scrollLeft;\n });\n }\n\n const toolbarRangeCtrl = container.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const range = btn.getAttribute('data-range');\n if (range) {\n toolbarRangeCtrl\n .querySelectorAll('.seg-btn')\n .forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n onRangeChange(range);\n }\n });\n });\n }\n\n const pills = container.querySelectorAll('.metric-pill');\n pills.forEach((pill) => {\n pill.addEventListener('click', () => {\n const target = pill.getAttribute('data-target');\n if (target) {\n const targetEl = document.getElementById(`${target}-evolution-card`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n });\n });\n\n function onPinChange(dur: number | null) {\n cards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n }\n\n function onRangeChange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n }\n\n if (allTracks.some((t) => t.stats.powerCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'power',\n label: 'Power Curve Progress',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n if (allTracks.some((t) => t.stats.hrCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'hr',\n label: 'Heart Rate Curve Progress',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n // Apply initial range when filtered\n if (currentRange !== 'all') {\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(currentRange);\n });\n }\n\n evolutionPlots.forEach((p) => {\n (p as any)._ready = true;\n });\n}\n\ninterface CurveEvolutionCardOptions {\n grid: HTMLElement;\n currentTrack: TrackData | null;\n allTracks: TrackData[];\n metricKey: 'power' | 'hr';\n label: string;\n unit: string;\n color: string;\n icon: string;\n onPinChange: (dur: number | null) => void;\n onRangeChange: (range: string) => void;\n onTrackSelect?: (id: string, range: [number, number] | null) => void;\n gridWidth?: number;\n}\n\nfunction renderCurveEvolutionCard(opts: CurveEvolutionCardOptions) {\n const {\n grid,\n currentTrack,\n allTracks,\n metricKey,\n label,\n unit,\n color,\n icon,\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n } = opts;\n\n const trackName = currentTrack ? currentTrack.name || 'Current Track' : 'Current Track';\n\n let mainChart: uPlot | null = null;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = 'chart-row evolution-card-group';\n cardContainer.id = `${metricKey}-evolution-card`;\n grid.appendChild(cardContainer);\n\n const row1 = document.createElement('div');\n row1.className = 'chart-row progress-chart-row';\n row1.style.setProperty('--chart-color', color);\n row1.style.flex = '0 0 400px';\n row1.style.borderBottom = 'none';\n row1.innerHTML = `\n
\n
\n ${icon}\n ${label}\n
\n
\n
\n
\n
\n `;\n\n const legendEl = document.createElement('div');\n legendEl.className = 'evolution-legend';\n legendEl.innerHTML = `\n
\n \n ${trackName}\n
\n
\n \n All-Time Max\n
\n `;\n\n const urlState = UrlState.get();\n let currentRange = urlState.progress || 'all';\n\n const row2 = document.createElement('div');\n row2.className = 'chart-row progress-chart-row';\n row2.style.setProperty('--chart-color', color);\n row2.style.flex = '1';\n row2.style.borderBottom = 'none';\n row2.innerHTML = `\n
\n
\n ${icon}\n Progress ${metricKey === 'power' ? 'Power' : 'HR'}\n
\n
\n
\n
\n
\n `;\n\n const sideBySide = document.createElement('div');\n sideBySide.style.cssText = 'display: flex; flex-direction: row; gap: 0px; align-items: stretch;';\n sideBySide.appendChild(row1);\n sideBySide.appendChild(row2);\n\n cardContainer.appendChild(sideBySide);\n cardContainer.appendChild(legendEl);\n\n const chartEl = row1.querySelector(`#${metricKey}-evolution-chart`) as HTMLElement;\n if (!chartEl) return;\n\n // 1. Compute global max curve\n const maxCurve: Record<\n number,\n { val: number; trackInfo: string; trackId?: string; idx?: number }\n > = {};\n allTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n const name = t.name || 'Unnamed Track';\n const date =\n t.stats.startTime || t.addedAt ? fmtDate((t.stats.startTime || t.addedAt)!) : 'Unknown Date';\n const trackInfo = `${name} (${date})`;\n\n Object.entries(curve).forEach(([dur, data]) => {\n const d = Number(dur);\n const val = (data as any).power || (data as any).hr;\n if (!maxCurve[d] || val > maxCurve[d].val)\n maxCurve[d] = { val, trackInfo, trackId: t.id, idx: (data as any).idx };\n });\n });\n\n // 2. Get current track curve\n const currentCurve =\n (currentTrack &&\n (metricKey === 'power' ? currentTrack.stats.powerCurve : currentTrack.stats.hrCurve)) ||\n {};\n\n // 3. Combine durations\n const allDurations = new Set();\n Object.keys(maxCurve).forEach((d) => allDurations.add(Number(d)));\n Object.keys(currentCurve).forEach((d) => allDurations.add(Number(d)));\n const durations = Array.from(allDurations).sort((a, b) => a - b);\n\n const xData = durations;\n const yDataCurrent = durations.map((d) => {\n const entry = currentCurve[d];\n return entry ? (entry as any).power || (entry as any).hr : null;\n });\n const yDataMax = durations.map((d) => maxCurve[d]?.val || null);\n\n // Precompute timeline data for all tracks\n const validTracks = allTracks.filter((t) => (t.stats.startTime || t.addedAt) != null);\n validTracks.sort(\n (a, b) =>\n (a.stats.startTime || a.addedAt || 0) - (b.stats.startTime || b.addedAt || 0) ||\n a.id.localeCompare(b.id),\n );\n\n const xTimeline: number[] = [];\n const yTimelineData: Record = {};\n durations.forEach((d) => (yTimelineData[d] = []));\n\n validTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n\n xTimeline.push((t.stats.startTime || t.addedAt)! / 1000); // seconds\n durations.forEach((d) => {\n const entry = curve[d];\n const val = entry ? (metricKey === 'power' ? (entry as any).power : (entry as any).hr) : null;\n yTimelineData[d].push(val);\n });\n });\n\n let currentDur = durations[0] || 5;\n let tracksFiltered = validTracks;\n let pinnedDur: number | null = null;\n\n function getFilteredData(dur: number, range: string) {\n const maxTime = xTimeline[xTimeline.length - 1] || 1785542400;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600;\n\n const filteredIndices: number[] = [];\n xTimeline.forEach((t, idx) => {\n if (t >= minTime) filteredIndices.push(idx);\n });\n\n const xFiltered = filteredIndices.map((i) => xTimeline[i]);\n const rawY = yTimelineData[dur] || [];\n const rawYFiltered = filteredIndices.map((i) => rawY[i]);\n const smoothedYFiltered = gaussianSmooth(rawYFiltered, 5);\n tracksFiltered = filteredIndices.map((i) => validTracks[i]);\n\n return { xFiltered, rawYFiltered, smoothedYFiltered };\n }\n\n let timelineChart: uPlot | null = null;\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val font-m';\n curYVal.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const renderCharts = () => {\n const optsUPlot: uPlot.Options = {\n id: `${metricKey}-evolution`,\n width: 400,\n height: 250,\n padding: [0, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: 'Current Track',\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n {\n label: 'All-Time Max',\n stroke: '#888888',\n width: 1,\n fill: 'transparent',\n points: { show: true, size: 6, fill: '#888888' },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n x: false,\n y: false,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n\n // Draw pinned duration circle\n if (pinnedDur !== null) {\n const idx = xData.indexOf(pinnedDur);\n if (idx >= 0) {\n const pcx = u.valToPos(pinnedDur, 'x', true);\n const pcy = u.valToPos(yDataCurrent[idx]! || yDataMax[idx]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]);\n const curVal = yDataCurrent[idx];\n const dotRadius = curVal !== null ? 5 * dpr : 3 * dpr;\n const dotColor = curVal !== null ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n }\n\n ctx.restore();\n },\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(\n activeSeriesIdx === 1 ? yDataCurrent[idx]! : yDataMax[idx]!,\n 'y',\n true,\n );\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n const dotRadius = activeSeriesIdx === 1 ? 5 * dpr : 6 * dpr;\n const dotColor = activeSeriesIdx === 1 ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n const xValStr = fmtDuration(xData[idx!]);\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n // X Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const yVal = yDataCurrent[idx!]! || yDataMax[idx!]!;\n const yValStr = `${yVal.toFixed(0)} ${unit}`;\n const yValWidth = ctx.measureText(yValStr).width;\n const ybw = yValWidth + 10 * dpr;\n\n const yLabelX = bb.left - ybw - 2 * dpr; // To the left\n const yLabelY = pcy - pillH / 2;\n\n // Y Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * dpr);\n else ctx.rect(yLabelX, yLabelY, ybw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(yValStr, yLabelX + 5 * dpr, yLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n const hasFocus = idx != null && xData[idx] != null;\n\n if (hasFocus) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yDataCurrent[idx!]! || yDataMax[idx!]!, 'y', false); // Fallback to max if current is null\n\n const durVal = xData[idx!];\n const curVal = yDataCurrent[idx!];\n const mxVal = yDataMax[idx!];\n\n let html = `
${fmtDuration(durVal)}
`;\n if (curVal !== null) {\n html += `\n
\n Current:\n ${curVal} ${unit}\n
\n `;\n }\n if (mxVal !== null) {\n html += `\n
\n Max:\n ${mxVal} ${unit}\n
\n `;\n }\n\n curYVal.innerHTML = html;\n\n if (timelineChart) {\n if (pinnedDur === null) {\n currentDur = durVal;\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([\n xFiltered,\n rawYFiltered,\n smoothedYFiltered,\n lowerBound,\n upperBound,\n ]);\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(durVal)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n }\n }\n curYVal.style.display = '';\n curYVal.style.left = `${cursorLeft! + bb.left}px`;\n curYVal.style.top = `${cursorTop! + bb.top}px`;\n curYVal.style.transform = 'translate(5px, -50%)';\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n };\n\n mainChart = new uPlot(optsUPlot, [xData, yDataCurrent, yDataMax], chartEl);\n evolutionPlots.push(mainChart);\n\n chartEl.addEventListener('click', () => {\n if (!mainChart) return;\n const idx = mainChart.cursor.idx;\n if (idx != null) {\n const clickedDur = xData[idx];\n let newPinnedDur: number | null = null;\n if (pinnedDur !== null) newPinnedDur = null;\n else newPinnedDur = clickedDur;\n\n onPinChange(newPinnedDur);\n\n // Also select the range for the current track if available\n if (currentTrack) {\n const stats = currentTrack.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[clickedDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = clickedDur;\n const startPt = currentTrack.points[bestIdx];\n const endPt = currentTrack.points[bestIdx + duration - 1];\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = currentTrack.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n onTrackSelect?.(currentTrack.id, [min, max]);\n }\n }\n }\n }\n }\n });\n\n chartEl.addEventListener('mouseleave', () => {\n if (mainChart) mainChart.redraw();\n });\n\n // 4. Add expandable table\n const detailsEl = document.createElement('details');\n detailsEl.classList.add('progress-details');\n detailsEl.style.marginTop = '0px';\n detailsEl.style.setProperty('--chart-color', color);\n detailsEl.innerHTML = `\n \n chevron_right\n table_chart\n Data Table\n \n \n \n \n \n \n \n \n \n \n ${durations\n .map((d) => {\n const cur = currentCurve[d]\n ? (currentCurve[d] as any).power || (currentCurve[d] as any).hr\n : '-';\n const mx = maxCurve[d]?.val || '-';\n const mxId = maxCurve[d]?.trackId;\n const mxIdx = maxCurve[d]?.idx;\n return `\n \n \n \n \n \n `;\n })\n .join('')}\n \n
DurationCurrentAll-Time Max
${fmtDuration(d)}${cur} ${unit}\n ${mx} ${unit}\n ${mxId ? `` : ''}\n
\n `;\n cardContainer.appendChild(detailsEl);\n\n detailsEl.querySelectorAll('.evolution-select-btn').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const id = btn.getAttribute('data-id');\n const idx = btn.getAttribute('data-idx');\n const dur = btn.getAttribute('data-dur');\n if (id) {\n document.dispatchEvent(\n new CustomEvent('select-track', {\n detail: {\n id,\n idx: idx ? Number(idx) : null,\n dur: dur ? Number(dur) : null,\n },\n }),\n );\n }\n });\n });\n\n let lastNearestIdx: number | null = null;\n\n // 5. Render timeline chart\n const timelineEl = row2.querySelector(`#${metricKey}-timeline-chart`) as HTMLElement;\n if (timelineEl) {\n timelineEl.style.position = 'relative';\n const timelineTooltip = document.createElement('div');\n timelineTooltip.className = 'timeline-tooltip font-m';\n timelineTooltip.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n timelineEl.appendChild(timelineTooltip);\n\n if (xTimeline.length > 0) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n const dataTimeline = [xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound];\n\n const series: any[] = [\n {\n value: (u: any, v: number) => {\n if (v != null) return fmtDate(v * 1000);\n\n return '-';\n },\n },\n {\n label: 'Value',\n stroke: color,\n width: 0,\n points: { show: true, size: 6, fill: hexToRgba(color, 0.5) },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n points: { show: false },\n spanGaps: true,\n fill: 'transparent',\n dash: [5, 5],\n },\n {\n label: 'Lower Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n {\n label: 'Upper Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n ];\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n\n const optsTimeline: uPlot.Options = {\n width: Math.max(100, (gridWidth || 570) - 400),\n height: 250,\n padding: [0, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n cursor: {\n points: {\n show: false,\n },\n drag: { setScale: false },\n x: false,\n y: false,\n },\n scales: {\n x: {\n time: true,\n range: (u) => {\n const min = u.data[0][0];\n const max = u.data[0][u.data[0].length - 1];\n if (min === undefined || max === undefined) return [0, 100];\n\n if (min === max) return [min - 3600, max + 3600];\n\n return [min, max];\n },\n },\n y: { range: (u: any, min: number, max: number) => [min * 0.9, max * 1.1] },\n },\n series: series,\n bands: [{ series: [4, 3], fill: hexToRgba(color, 0.2) }],\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n if (lastNearestIdx != null) {\n const track = tracksFiltered[lastNearestIdx];\n if (track) {\n const stats = track.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[currentDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = currentDur;\n\n const startPt = track.points[bestIdx];\n const endPt = track.points[bestIdx + duration - 1];\n\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = track.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n\n opts.onTrackSelect?.(track.id, [min, max]);\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n }\n }\n });\n },\n ],\n draw: [\n (u: uPlot) => {\n let idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const val = u.data[1][idx];\n if (val != null) {\n const tpcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const tpcy = u.valToPos(val, 'y', true);\n\n const tctx = u.ctx;\n const tdpr = window.devicePixelRatio || 1;\n\n // Draw lines\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([2 * tdpr, 2 * tdpr]);\n tctx.strokeStyle = hexToRgba(color, 0.4);\n tctx.lineWidth = 1 * tdpr;\n // Vertical line\n tctx.moveTo(tpcx, u.bbox.top);\n tctx.lineTo(tpcx, u.bbox.top + u.bbox.height);\n // Horizontal line\n tctx.moveTo(u.bbox.left, tpcy);\n tctx.lineTo(u.bbox.left + u.bbox.width, tpcy);\n tctx.stroke();\n tctx.restore();\n\n // Draw hover halo\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([]); // Reset to solid\n tctx.arc(tpcx, tpcy, 12 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = hexToRgba(color, 0.2);\n tctx.fill();\n tctx.restore();\n\n // Draw center circle\n tctx.save();\n tctx.beginPath();\n tctx.arc(tpcx, tpcy, 6 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = color;\n tctx.fill();\n tctx.strokeStyle = '#fff';\n tctx.lineWidth = 2 * tdpr;\n tctx.stroke();\n tctx.restore();\n\n // Draw axis labels\n tctx.save();\n tctx.setLineDash([]); // Reset to solid\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n tctx.font = `bold ${10 * tdpr}px system-ui, sans-serif`;\n const dateWidth = tctx.measureText(dateStr).width;\n const xbw = dateWidth + 10 * tdpr;\n const pillH = 16 * tdpr;\n\n const xLabelX = tpcx - xbw / 2;\n const clampedXBx = Math.max(\n u.bbox.left,\n Math.min(u.bbox.left + u.bbox.width - xbw, xLabelX),\n );\n const xLabelY = u.bbox.top + u.bbox.height + 2 * tdpr;\n\n // X Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * tdpr);\n else tctx.rect(clampedXBx, xLabelY, xbw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'center';\n tctx.textBaseline = 'middle';\n tctx.fillText(dateStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const valStr = `${val.toFixed(0)} ${unit}`;\n const valWidth = tctx.measureText(valStr).width;\n const ybw = valWidth + 10 * tdpr;\n\n const yLabelX = u.bbox.left - ybw - 2 * tdpr; // To the left\n const yLabelY = tpcy - pillH / 2;\n\n // Y Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * tdpr);\n else tctx.rect(yLabelX, yLabelY, ybw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'left';\n tctx.textBaseline = 'middle';\n tctx.fillText(valStr, yLabelX + 5 * tdpr, yLabelY + pillH / 2);\n\n tctx.restore();\n }\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n const bb = u.bbox;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n const xData = u.data[0];\n const yData = u.data[1];\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const y = yData[i];\n if (x == null || y == null) continue;\n\n const px = u.valToPos(x, 'x', false);\n const py = u.valToPos(y, 'y', false);\n\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n }\n }\n\n if (minD2 <= maxD2) {\n idx = nearestIdx;\n lastNearestIdx = nearestIdx;\n } else {\n idx = null;\n lastNearestIdx = null;\n }\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const track = tracksFiltered[idx];\n const cx = u.valToPos(u.data[0][idx], 'x', false);\n const cy = u.valToPos(u.data[1][idx]!, 'y', false);\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n\n const val = u.data[1][idx];\n const valStr = val != null ? `${val} ${unit}` : '\u2014';\n\n timelineTooltip.innerHTML = `\n
\n Date:\n ${dateStr}\n
\n
\n Value:\n ${valStr}\n
\n `;\n timelineTooltip.style.display = 'block';\n timelineTooltip.style.left = `${cursorLeft! + bb.left}px`;\n timelineTooltip.style.top = `${cursorTop! + bb.top}px`;\n timelineTooltip.style.transform = 'translate(5px, -50%)';\n } else {\n timelineTooltip.style.display = 'none';\n }\n },\n ],\n },\n axes: [\n {\n space: 50,\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n show: true,\n font: '10px system-ui, sans-serif',\n size: 30,\n values: (u: any, vals: any[]) =>\n vals.map((v) => {\n const d = new Date(v * 1000);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n }),\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n font: '10px system-ui, sans-serif',\n values: (u: any, vals: any[]) => vals.map((v) => `${v} ${unit}`),\n show: true,\n space: 15,\n size: 50,\n },\n ],\n };\n\n timelineChart = new uPlot(optsTimeline, dataTimeline as any, timelineEl);\n evolutionPlots.push(timelineChart);\n\n timelineEl.addEventListener('mouseleave', () => {\n timelineChart!.redraw();\n });\n\n // Range control moved to toolbar\n } else {\n timelineEl.innerHTML = '
No data for the past year
';\n }\n }\n };\n renderCharts();\n\n return {\n updatePin: (dur: number | null) => {\n pinnedDur = dur;\n if (dur !== null) currentDur = dur;\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}${pinnedDur !== null ? ' (Pinned)' : ''}`;\n\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n if (mainChart) mainChart.redraw();\n },\n updateRange: (range: string) => {\n currentRange = range;\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n },\n };\n}\n\nfunction getWeekStart(date: Date): Date {\n const d = new Date(date);\n const day = d.getUTCDay();\n const diff = d.getUTCDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday\n d.setUTCDate(diff);\n d.setUTCHours(0, 0, 0, 0);\n return d;\n}\n\nfunction computeWeeklyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey]) weeklyData[weekKey] = { timestamp: weekStart.getTime(), distance: 0 };\n\n weeklyData[weekKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeWeeklyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey])\n weeklyData[weekKey] = { timestamp: weekStart.getTime(), elevation: 0 };\n\n weeklyData[weekKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction renderProgressCard(\n grid: HTMLElement,\n allTracks: TrackData[],\n type: 'distance' | 'elevation',\n syncKey?: any,\n onDateRangeSelect?: (start: string, end: string) => void,\n gridWidth?: number,\n) {\n const isDistance = type === 'distance';\n const weeklyData = isDistance\n ? computeWeeklyDistance(allTracks)\n : computeWeeklyElevation(allTracks);\n const accumulated = computeAccumulatedMetric(allTracks, (t) =>\n isDistance ? t.stats.totalDist : t.stats.elevGain,\n );\n const color = isDistance ? Metrics.distance.color : Metrics.elevation.color;\n const unit = isDistance ? 'km' : 'm';\n const icon = isDistance ? Metrics.distance.icon : Metrics.elevation.icon;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = `chart-row ${type}-progress-card`;\n cardContainer.id = `${type}-evolution-card`;\n\n cardContainer.innerHTML = `\n
\n
\n ${icon}\n ${isDistance ? 'Distance Progress' : 'Elevation Progress'}\n
\n
\n
\n
\n
\n
\n
\n
\n ${renderAccumulatedTable(accumulated, isDistance, unit)}\n
\n
\n `;\n\n grid.appendChild(cardContainer);\n\n const chartEl = cardContainer.querySelector(`#${type}-weekly-chart`) as HTMLElement;\n const yAxisEl = cardContainer.querySelector(`#${type}-y-axis-chart`) as HTMLElement;\n\n if (!chartEl || !yAxisEl) return;\n\n chartEl.style.position = 'relative';\n\n // Use inline tooltip style\n const tooltip = document.createElement('div');\n tooltip.className = 'cur-y-val';\n tooltip.style.cssText = `color:${color};display:none`;\n chartEl.appendChild(tooltip);\n\n const xData = weeklyData.map((d) => d.timestamp / 1000);\n const yData = isDistance\n ? (weeklyData as any[]).map((d) => d.distance / 1000)\n : (weeklyData as any[]).map((d) => d.elevation);\n\n if (xData.length === 0) return;\n\n const yDataSmoothed = gaussianSmooth(yData, 2);\n\n const chartClientW = Math.max(0, (gridWidth || 570) - 20 - 320 - 20);\n const width = Math.max(chartClientW, xData.length * 40);\n const maxVal = Math.max(...yData) * 1.1;\n\n const mainOpts: uPlot.Options = {\n width: width,\n height: 150,\n padding: [10, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n scales: {\n x: { time: true },\n y: { range: [0, maxVal] },\n },\n series: [\n {},\n {\n label: isDistance ? 'Distance' : 'Elevation',\n stroke: color,\n fill: hexToRgba(color, 0.1),\n width: 2,\n points: { show: true, size: 4 },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n dash: [5, 5],\n points: { show: false },\n },\n ],\n cursor: {\n sync: syncKey ? { key: syncKey.key } : undefined,\n drag: { x: false, y: false },\n points: { show: false },\n x: false,\n y: false,\n },\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null) {\n const item = weeklyData[idx];\n if (item) {\n const start = new Date(item.timestamp);\n const end = new Date(item.timestamp + 7 * 24 * 60 * 60 * 1000); // End of week\n const startStr = start.toISOString().split('T')[0];\n const endStr = end.toISOString().split('T')[0];\n onDateRangeSelect?.(startStr, endStr);\n }\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n const idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (\n idx != null &&\n cursorLeft != null &&\n cursorTop != null &&\n cursorLeft >= 0 &&\n cursorTop >= 0\n ) {\n const val = u.data[1][idx];\n const valStr =\n val != null ? (isDistance ? `${val.toFixed(1)} km` : `${val.toFixed(0)} m`) : '\u2014';\n\n tooltip.innerHTML = valStr;\n tooltip.style.display = 'block';\n tooltip.style.left = `${u.valToPos(u.data[0][idx]!, 'x', false)}px`;\n tooltip.style.top = `${u.valToPos(u.data[1][idx]!, 'y', false)}px`;\n tooltip.style.transform = 'translate(6px, -50%)';\n } else {\n tooltip.style.display = 'none';\n }\n\n u.redraw(false);\n },\n ],\n draw: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(u.data[1][idx]!, 'y', true);\n const dpr = window.devicePixelRatio || 1;\n const ctx = u.ctx;\n const bb = u.bbox;\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n ctx.arc(pcx, pcy, 6 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n // X Label Pill\n const d = new Date(u.data[0][idx]! * 1000);\n const xValStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n },\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n space: 40,\n values: (self, splits) =>\n splits.map((s) => {\n const d = new Date(s * 1000);\n return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`;\n }),\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: (self, splits) => splits.map((s) => `${s.toFixed(0)} ${unit}`),\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n };\n\n const mainChart = new uPlot(mainOpts, [xData, yData, yDataSmoothed], chartEl);\n evolutionPlots.push(mainChart);\n\n const scrollContainer = cardContainer.querySelector('.chart-scroll-container') as HTMLElement;\n if (scrollContainer && xData.length * 40 > width)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n\n return {\n updateRange: (range: string) => {\n const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000;\n\n const filteredData = weeklyData.filter((d) => d.timestamp >= minTime);\n\n const newXData = filteredData.map((d) => d.timestamp / 1000);\n const newYData = isDistance\n ? (filteredData as any[]).map((d) => d.distance / 1000)\n : (filteredData as any[]).map((d) => d.elevation);\n const newYDataSmoothed = gaussianSmooth(newYData, 2);\n\n const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40);\n const newMaxVal = Math.max(...newYData) * 1.1;\n\n mainChart.setSize({ width: newWidth, height: 150 });\n mainChart.setScale('y', { min: 0, max: newMaxVal });\n mainChart.setData([newXData, newYData, newYDataSmoothed]);\n\n if (scrollContainer)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n },\n };\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData } from '../parsers';\n\nexport interface AccumulatedData {\n currentYear: number;\n pastYear: number;\n past6m: number;\n past1m: number;\n total: number;\n currentYearAvg: number;\n pastYearAvg: number;\n past6mAvg: number;\n past1mAvg: number;\n totalAvg: number;\n}\n\nexport function computeAccumulatedMetric(\n allTracks: TrackData[],\n extractor: (t: TrackData) => number | undefined,\n): AccumulatedData {\n // Derive deterministic reference timestamp from tracks (or fixed UTC fallback)\n let refTs = 0;\n for (let i = 0; i < allTracks.length; i++) {\n const st = allTracks[i].stats?.startTime;\n if (st && st > refTs) refTs = st;\n }\n if (!refTs) refTs = Date.UTC(2026, 7, 1);\n\n const now = new Date(refTs);\n const currentYear = now.getUTCFullYear();\n\n const oneYearAgoMs = Date.UTC(\n currentYear - 1,\n now.getUTCMonth(),\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const sixMonthsAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 6,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const oneMonthAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 1,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n\n let currentYearVal = 0;\n let pastYearVal = 0;\n let past6mVal = 0;\n let past1mVal = 0;\n let totalVal = 0;\n\n let minTime = refTs;\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime) return;\n const val = extractor(t);\n if (val === undefined) return;\n\n totalVal += val;\n\n const time = t.stats.startTime;\n if (time < minTime) minTime = time;\n\n const date = new Date(time);\n\n if (date.getUTCFullYear() === currentYear) currentYearVal += val;\n\n if (time >= oneYearAgoMs) pastYearVal += val;\n\n if (time >= sixMonthsAgoMs) past6mVal += val;\n\n if (time >= oneMonthAgoMs) past1mVal += val;\n });\n\n const msecPerWeek = 7 * 24 * 60 * 60 * 1000;\n const currentYearStart = Date.UTC(currentYear, 0, 1);\n\n const currentYearWeeks = Math.max(0.1, (refTs - currentYearStart) / msecPerWeek);\n const pastYearWeeks = Math.max(0.1, (refTs - oneYearAgoMs) / msecPerWeek);\n const past6mWeeks = Math.max(0.1, (refTs - sixMonthsAgoMs) / msecPerWeek);\n const past1mWeeks = Math.max(0.1, (refTs - oneMonthAgoMs) / msecPerWeek);\n const totalWeeks = Math.max(0.1, (refTs - minTime) / msecPerWeek);\n\n return {\n currentYear: currentYearVal,\n pastYear: pastYearVal,\n past6m: past6mVal,\n past1m: past1mVal,\n total: totalVal,\n currentYearAvg: currentYearVal / currentYearWeeks,\n pastYearAvg: pastYearVal / pastYearWeeks,\n past6mAvg: past6mVal / past6mWeeks,\n past1mAvg: past1mVal / past1mWeeks,\n totalAvg: totalVal / totalWeeks,\n };\n}\n\nexport function renderAccumulatedTable(\n accumulated: AccumulatedData,\n isDistance: boolean,\n unit: string,\n): string {\n const factor = isDistance ? 1000 : 1;\n const format = (val: number) => {\n const formattedVal = isDistance ? val / factor : val;\n return formattedVal.toLocaleString('en-US', {\n minimumFractionDigits: isDistance ? 1 : 0,\n maximumFractionDigits: isDistance ? 1 : 0,\n });\n };\n\n return `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Period${isDistance ? 'Distance' : 'Elevation'}${isDistance ? 'Distance/Week' : 'Elevation/Week'}
Current Year${format(accumulated.currentYear)} ${unit}${format(accumulated.currentYearAvg)} ${unit}
Past Year${format(accumulated.pastYear)} ${unit}${format(accumulated.pastYearAvg)} ${unit}
Past 6 Months${format(accumulated.past6m)} ${unit}${format(accumulated.past6mAvg)} ${unit}
Past 1 Month${format(accumulated.past1m)} ${unit}${format(accumulated.past1mAvg)} ${unit}
Total${format(accumulated.total)} ${unit}${format(accumulated.totalAvg)} ${unit}
\n `;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 Main Application \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { Storage } from './storage';\nimport { UrlState, AppState } from './url-state';\nimport { Parsers, TrackData, TrackPoint, calculateBounds, simplifyTrack } from './parsers';\nimport { MapView } from './map';\nimport { ChartView } from './charts';\nimport { renderDetails, initDetails, resetDetails } from './tabs/details';\nimport { renderInsights, initInsights, resetInsights } from './tabs/insights';\nimport { renderCombined, initCombined, resizeCombined, resetCombined } from './tabs/combined';\nimport { renderEvolution, resetEvolution } from './tabs/progress';\nimport {\n renderCourses,\n initCourses,\n prepareBenchmarkCourses,\n resetCourses,\n selectCourse,\n} from './tabs/courses';\nimport { fmtSecs, escHtml, fmtDate, getTagColor, compactId, shortRandom } from './utils';\n\nconst TRACK_COLORS: string[] = [\n '#FF6B35',\n '#4ECDC4',\n '#45B7D1',\n '#F7DC6F',\n '#FF6B6B',\n '#BB8FCE',\n '#82E0AA',\n '#F8C471',\n '#3b82f6',\n];\n\nconst POINT_ZOOM_LEVEL = 16;\n\nlet tracks: Record = {};\nlet skippedImports: { name: string; reason: string }[] = [];\n\nfunction isSameDay(t1: number, t2: number) {\n const d1 = new Date(t1);\n const d2 = new Date(t2);\n return (\n d1.getUTCFullYear() === d2.getUTCFullYear() &&\n d1.getUTCMonth() === d2.getUTCMonth() &&\n d1.getUTCDate() === d2.getUTCDate()\n );\n}\n\nlet cancelProcessing = false;\nlet selectedId: string | null = null;\nlet colorIdx = 0;\nlet followDot = false;\nlet currentMapColors: string[] | null = null;\n\n// Search/Filter state\nlet searchQuery = '';\nlet searchRegex = false;\nlet currentSort = 'date-desc';\n\ninterface Filters {\n date: [string | null, string | null];\n dist: [number | null, number | null];\n dur: [number | null, number | null];\n metrics: Set;\n tags: string[];\n sport: string | null;\n}\n\nlet filters: Filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n};\n\nfunction syncFiltersToUrl(push: boolean = false) {\n UrlState.patch(\n {\n f_date: filters.date.every((v) => v === null) ? null : filters.date,\n f_dist: filters.dist.every((v) => v === null) ? null : filters.dist,\n f_dur: filters.dur.every((v) => v === null) ? null : filters.dur,\n f_mets: filters.metrics.size === 0 ? null : Array.from(filters.metrics),\n f_tags: filters.tags.length === 0 ? null : filters.tags,\n },\n push,\n );\n}\n\nfunction syncMetricsToUrl() {\n const active = ChartView.getActiveMetrics();\n const metrics = ChartView.METRICS;\n const abbrs = Array.from(active).map((key) => metrics[key].abbr);\n UrlState.patch({ metrics: abbrs.length ? abbrs : null });\n}\n\nconst SORT_OPTIONS = [\n { label: 'Newest first', val: 'date-desc', icon: 'calendar_today' },\n { label: 'Oldest first', val: 'date-asc', icon: 'history' },\n { label: 'Longest distance', val: 'dist-desc', icon: 'straighten' },\n { label: 'Shortest distance', val: 'dist-asc', icon: 'horizontal_rule' },\n { label: 'Longest duration', val: 'dur-desc', icon: 'timer' },\n { label: 'Shortest duration', val: 'dur-asc', icon: 'timer_off' },\n];\n\nfunction showSortMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.sort-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'sort-menu-popup';\n\n SORT_OPTIONS.forEach((opt) => {\n const item = document.createElement('div');\n item.className = `menu-item ${currentSort === opt.val ? 'active' : ''}`;\n item.innerHTML = `\n ${opt.icon}\n ${opt.label}\n ${currentSort === opt.val ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n currentSort = opt.val;\n UrlState.patch({ sort: opt.val });\n updateSearchSortUI();\n renderTrackList();\n popup.remove();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction showMetricMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const available = ChartView.getAvailableMetrics();\n const active = ChartView.getActiveMetrics();\n\n Object.entries(metrics).forEach(([key, def]) => {\n if (!available.has(key)) return;\n\n const item = document.createElement('div');\n item.className = `menu-item ${active.has(key) ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${active.has(key) ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n ChartView.toggleMetric(key);\n const isNowActive = ChartView.getActiveMetrics().has(key);\n item.classList.toggle('active', isNowActive);\n item.querySelector('.check')!.textContent = isNowActive ? 'check' : '';\n\n const pill = document.querySelector(`#metric-pills .metric-pill[data-metric=\"${key}\"]`);\n if (pill) pill.classList.toggle('active', isNowActive);\n\n updateToolbarLayout();\n\n syncMetricsToUrl();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.right = `${window.innerWidth - rect.right}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\n// \u2500\u2500 Tab Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.addEventListener('select-track', (e: any) => {\n const id = e.detail.id;\n const idx = e.detail.idx;\n const dur = e.detail.dur;\n if (id && tracks[id]) {\n selectTrack(id);\n if (idx != null && dur != null) {\n const t = tracks[id];\n const pts = t.points;\n if (idx >= 0 && idx < pts.length) {\n const pIdx = pts[idx];\n if (pIdx && pIdx.time != null) {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const tMin = (pIdx.time - t0) / 1000;\n const tMax = tMin + dur;\n\n // ChartView selection\n ChartView.restoreSelection(tMin, tMax);\n\n // Find iMax based on duration\n let iMax = pts.findIndex((p) => (p.time || 0) >= pIdx.time! + dur * 1000);\n if (iMax === -1) iMax = pts.length - 1;\n\n const selPts = pts.slice(idx, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n\n renderInsights(t);\n\n MapView.highlightSegment(id, pts, idx, iMax, false, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n\n // Update URL state\n UrlState.patch({ sel: [tMin, tMax] });\n }\n }\n }\n }\n});\n\ndocument.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.tab-btn') as HTMLElement;\n if (!btn) return;\n const nav = btn.closest('#tab-nav');\n if (!nav) return;\n\n // Toggle buttons\n nav.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn));\n\n const tab = btn.dataset.tab!;\n UrlState.patch({ tab }, true);\n\n // Toggle contents\n const panel = nav.closest('#chart-panel');\n if (panel) {\n panel.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${btn.dataset.tab}`);\n });\n }\n\n if (btn.dataset.tab === 'details' && selectedId && tracks[selectedId])\n renderDetails(tracks[selectedId], getGlobalTags());\n\n if (btn.dataset.tab === 'insights' && selectedId && tracks[selectedId])\n renderInsights(tracks[selectedId]);\n\n if (btn.dataset.tab === 'evolution') {\n renderEvolution(\n selectedId ? tracks[selectedId] : null,\n Object.values(tracks),\n (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n },\n (start, end) => {\n filters.date = [start, end];\n applyFilters();\n syncFiltersToUrl(true);\n updateFilterUI();\n },\n );\n }\n\n if (btn.dataset.tab === 'combined' && selectedId && tracks[selectedId])\n renderCombined(tracks[selectedId]);\n\n if (btn.dataset.tab === 'courses') renderCourses();\n\n if (btn.dataset.tab === 'graphs') {\n ChartView.resize();\n updateToolbarLayout();\n\n // Restore selection from URL\n const s = UrlState.get().sel;\n if (s) ChartView.restoreSelection(s[0], s[1]);\n }\n});\n\nasync function resetBenchmarkState() {\n if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n await Storage.clear();\n tracks = {};\n skippedImports = [];\n selectedId = null;\n colorIdx = 0;\n currentMapColors = null;\n cancelProcessing = false;\n followDot = false;\n searchQuery = '';\n searchRegex = false;\n currentSort = 'date-desc';\n filters.date = [null, null];\n filters.dist = [null, null];\n filters.dur = [null, null];\n filters.metrics.clear();\n filters.tags = [];\n Parsers.setHRZones([120, 140, 160, 180]);\n Parsers.setFTP(200);\n resetCourses();\n resetInsights();\n resetDetails();\n resetCombined();\n resetEvolution();\n if (MapView.removeAllTracks) MapView.removeAllTracks();\n if (MapView.clearTracks) MapView.clearTracks();\n MapView.clearHighlight();\n if (ChartView.resetState) ChartView.resetState();\n else if (ChartView.clear) ChartView.clear();\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === 'graphs');\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === 'tab-graphs');\n });\n UrlState.reset();\n const toastContainer = document.getElementById('toast-container');\n if (toastContainer) toastContainer.innerHTML = '';\n document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());\n if (typeof renderTrackList === 'function') renderTrackList();\n}\n\n// \u2500\u2500 Boot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function init() {\n // Wait for fonts to be loaded with a cleaned-up timeout\n let fontTimerId: number | null = null;\n const fontTimeout = new Promise((resolve) => {\n fontTimerId = window.setTimeout(resolve, 1000);\n });\n try {\n const fontLoadPromise = document.fonts\n ? Promise.all([\n document.fonts.load('24px \"Material Symbols Rounded\"').catch(() => {}),\n document.fonts.ready,\n ])\n : Promise.resolve();\n await Promise.race([fontLoadPromise, fontTimeout]);\n } finally {\n if (fontTimerId !== null) window.clearTimeout(fontTimerId);\n }\n document.body.classList.remove('loading-fonts');\n const storageSelect = document.getElementById(\n 'storage-backend-select',\n ) as HTMLSelectElement | null;\n if (storageSelect) {\n storageSelect.value = UrlState.get().storage || 'memory';\n storageSelect.addEventListener('change', (e) => {\n const selected = (e.target as HTMLSelectElement).value;\n const params = new URLSearchParams(window.location.search);\n if (selected === 'memory') {\n params.delete('storage');\n } else {\n params.set('storage', selected);\n }\n window.location.search = params.toString();\n });\n }\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const mapLoader = document.getElementById('map-loader');\n const mapLoaderSpan = mapLoader?.querySelector('span');\n\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading database...';\n mapLoader.classList.remove('hidden');\n }\n\n const urlState = UrlState.get();\n\n initInsights((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n initDetails(\n () => {\n applyFilters();\n syncFiltersToUrl();\n },\n (id: string) => {\n deleteTrack(id);\n },\n );\n initCombined();\n initCourses((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n\n // Init sub-systems\n MapView.init(\n (id) => selectTrack(id),\n onMapMove,\n onMapPointClick,\n (id, idx) => {\n if (id === selectedId) ChartView.setHoverAt(idx);\n else ChartView.setHoverAt(null);\n },\n onMapDblClick,\n );\n ChartView.init(onChartCursorMove, onChartRangeChange, onChartClick, (idx) => {\n UrlState.patch({ sel_point: idx });\n });\n\n ChartView.setMapColorChangeCb((data) => {\n if (data) {\n currentMapColors = data.colors;\n if (selectedId) MapView.colorTrackByMetric(selectedId, data.pts, data.colors);\n } else {\n currentMapColors = null;\n if (selectedId) MapView.clearMetricColor(selectedId);\n }\n\n // Refresh highlight with new colors if a selection exists\n const currentUrlState = UrlState.get();\n if (currentUrlState.sel)\n onChartRangeChange(currentUrlState.sel[0], currentUrlState.sel[1], ChartView.getXAxis());\n });\n\n applyState(urlState);\n\n // Reset persistent storage and in-memory state for clean multi-iteration benchmark executions\n await Storage.openDB();\n await resetBenchmarkState();\n\n // Load persisted tracks\n try {\n // Load global settings\n const hrZones = await Storage.get('hr_zones');\n if (hrZones) Parsers.setHRZones(hrZones);\n\n const ftp = await Storage.get('ftp');\n if (ftp) Parsers.setFTP(ftp);\n\n const saved = await Storage.getAll();\n saved.sort((a, b) => a.addedAt - b.addedAt);\n\n if (mapLoaderSpan) mapLoaderSpan.textContent = `Preparing ${saved.length} tracks...`;\n\n const tracksToLoad: TrackData[] = [];\n for (const t of saved) {\n let updated = false;\n if (!t.bounds && t.points.length > 0) {\n const b = calculateBounds(t.points);\n if (b) {\n t.bounds = b;\n updated = true;\n }\n }\n if (!t.simplifiedPoints && t.points.length > 0) {\n t.simplifiedPoints = simplifyTrack(t.points, 50);\n updated = true;\n }\n if (updated) await Storage.save(t);\n\n tracks[t.id] = t;\n tracksToLoad.push(t);\n }\n MapView.addTracks(tracksToLoad);\n applyFilters();\n\n const restoreId =\n urlState.track && saved.find((t) => t.id === urlState.track)\n ? urlState.track\n : saved.length > 0\n ? saved[0].id\n : null;\n\n const mapLoader = document.getElementById('map-loader');\n\n // 1. Process and load the \"Priority\" track first\n const selectedTrackData = saved.find((t) => t.id === restoreId);\n if (selectedTrackData) {\n await processAndLoadTrack(selectedTrackData);\n selectTrack(selectedTrackData.id, !urlState.map_pos);\n\n // Explicitly restore selection/pin from URL if they exist\n if (urlState.sel && Array.isArray(urlState.sel) && urlState.sel.length === 2) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.restoreSelection(urlState.sel![0], urlState.sel![1]);\n });\n });\n }\n if (urlState.sel_point !== undefined && urlState.sel_point !== null) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.setCursorAt(urlState.sel_point!);\n });\n });\n }\n }\n\n // Hide database loader\n if (mapLoader) mapLoader.classList.add('hidden');\n\n // 2. Load the rest in background chunks\n if (saved.length > (selectedTrackData ? 1 : 0)) {\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading tracks...';\n mapLoader.classList.remove('hidden');\n }\n\n const remaining = saved.filter((t) => t.id !== restoreId);\n let index = 0;\n\n const loadNextChunk = async () => {\n const chunkSize = 2; // Process 2 tracks per frame\n const end = Math.min(index + chunkSize, remaining.length);\n\n for (; index < end; index++) await processAndLoadTrack(remaining[index]);\n\n if (index < remaining.length) {\n requestAnimationFrame(loadNextChunk);\n } else {\n if (mapLoader) mapLoader.classList.add('hidden');\n applyFilters(); // Final sync\n if (selectedId && tracks[selectedId]) {\n renderEvolution(tracks[selectedId], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n // Only fit all if no saved map position and we just finished loading everything\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n };\n\n requestAnimationFrame(loadNextChunk);\n } else {\n applyFilters();\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n } catch (e) {\n console.warn('Could not load saved tracks:', e);\n }\n\n // Panel resizers\n initResizeHandle();\n initSidebarResizer();\n initMetricPillDraggable();\n updateToolbarLayout();\n\n // Basemap switcher\n document.getElementById('basemap-switcher')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.bm-btn') as HTMLElement;\n if (!btn) return;\n document.querySelectorAll('.bm-btn').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n if (btn.dataset.layer) {\n MapView.switchBasemap(btn.dataset.layer);\n UrlState.patch({ map: btn.dataset.layer });\n }\n });\n\n // Fit all\n document.getElementById('btn-fit-all')?.addEventListener('click', () => MapView.fitAll());\n\n // Clear all\n document.getElementById('btn-clear-all')?.addEventListener('click', clearAll);\n\n // Search\n document.getElementById('track-search')?.addEventListener('input', (e) => {\n searchQuery = (e.target as HTMLInputElement).value;\n applyFilters();\n UrlState.patch({ q: searchQuery || null });\n });\n\n document.getElementById('btn-regex-toggle')?.addEventListener('click', (e) => {\n searchRegex = !searchRegex;\n (e.target as HTMLElement).classList.toggle('active', searchRegex);\n applyFilters();\n UrlState.patch({ re: searchRegex ? 1 : null });\n });\n\n // Sort\n document.getElementById('btn-sort-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSortMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric menu toggle\n document.getElementById('btn-metric-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMetricMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric toggles (shared logic)\n const toggleMetric = (metric: string, pill: HTMLElement | null) => {\n if (pill) pill.classList.toggle('active');\n ChartView.toggleMetric(metric);\n syncMetricsToUrl();\n };\n\n document.getElementById('metric-pills')?.addEventListener('click', (e) => {\n const pill = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (pill) {\n const metric = pill.dataset.metric;\n if (metric) {\n toggleMetric(metric, pill);\n\n // Scroll to it if it became active\n if (ChartView.getActiveMetrics().has(metric)) {\n const targetEl = document.querySelector(`.chart-row[data-metric=\"${metric}\"]`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n }\n }\n });\n\n // X-axis toggle\n document.getElementById('x-axis-ctrl')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const axis = btn.dataset.axis!;\n ChartView.setXAxis(axis);\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', b === btn));\n UrlState.patch({ xaxis: axis });\n });\n\n // Follow dot\n document.getElementById('btn-follow-dot')?.addEventListener('click', (e) => {\n followDot = !followDot;\n (e.currentTarget as HTMLElement).classList.toggle('active', followDot);\n });\n\n // Reset zoom\n document.getElementById('btn-reset-zoom')?.addEventListener('click', () => {\n ChartView.resetZoom();\n MapView.clearHighlight();\n });\n\n // File drag/drop\n initDropZone();\n\n // File browse\n document.getElementById('file-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n document.getElementById('folder-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n\n // Filters\n document.getElementById('btn-toggle-filters')?.addEventListener('click', () => {\n const panel = document.getElementById('filter-panel');\n if (panel) {\n panel.classList.toggle('hidden');\n document\n .getElementById('btn-toggle-filters')\n ?.classList.toggle('active', !panel.classList.contains('hidden'));\n }\n });\n\n const onFilterInput = (type: 'date' | 'dist' | 'dur', idx: number, e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n (filters[type] as any)[idx] = val === '' ? null : val;\n applyFilters();\n syncFiltersToUrl();\n };\n\n document\n .getElementById('filter-date-start')\n ?.addEventListener('change', (e) => onFilterInput('date', 0, e));\n document\n .getElementById('filter-date-end')\n ?.addEventListener('change', (e) => onFilterInput('date', 1, e));\n document\n .getElementById('filter-dist-min')\n ?.addEventListener('input', (e) => onFilterInput('dist', 0, e));\n document\n .getElementById('filter-dist-max')\n ?.addEventListener('input', (e) => onFilterInput('dist', 1, e));\n document\n .getElementById('filter-dur-min')\n ?.addEventListener('input', (e) => onFilterInput('dur', 0, e));\n document\n .getElementById('filter-dur-max')\n ?.addEventListener('input', (e) => onFilterInput('dur', 1, e));\n\n const burgerBtn = document.getElementById('sport-burger-btn');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n burgerBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n if (dropdownContent) {\n const isVisible = dropdownContent.style.display === 'block';\n dropdownContent.style.display = isVisible ? 'none' : 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (dropdownContent && dropdownContent.style.display === 'block') {\n if (!dropdownContent.contains(e.target as Node) && e.target !== burgerBtn)\n dropdownContent.style.display = 'none';\n }\n });\n\n document.getElementById('sport-filter-container')?.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const btn = target.closest('[data-sport]');\n if (btn) {\n const selectedSport = (btn as HTMLElement).dataset.sport || null;\n filters.sport = filters.sport === selectedSport ? null : selectedSport;\n applyFilters();\n syncFiltersToUrl();\n updateFilterUI();\n\n if (target.closest('.dropdown-item')) {\n if (dropdownContent) dropdownContent.style.display = 'none';\n }\n }\n });\n\n document.getElementById('filter-metrics')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.mini-pill') as HTMLElement;\n if (!btn) return;\n const m = btn.dataset.metric!;\n if (filters.metrics.has(m)) filters.metrics.delete(m);\n else filters.metrics.add(m);\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('btn-reset-filters')?.addEventListener('click', () => {\n filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n };\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('filter-tags')?.addEventListener('input', (e) => {\n const val = (e.target as HTMLInputElement).value;\n filters.tags = val\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => !!s);\n applyFilters();\n syncFiltersToUrl();\n });\n\n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n MapView.hideCursor();\n MapView.closePopup?.();\n // Dismiss popups and modals\n document\n .querySelectorAll(\n '.color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop',\n )\n .forEach((el) => el.remove());\n }\n });\n\n // Resize charts when window changes\n window.addEventListener('resize', () => {\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n updateToolbarLayout();\n });\n\n // Handle back/forward navigation\n window.addEventListener('popstate', () => {\n UrlState.refresh();\n applyState(UrlState.get());\n });\n\n initBenchmarkTriggers();\n await preloadBenchmarkFiles();\n\n // Signal to Speedometer test harness that asynchronous initialization has completed\n // and benchmark step triggers are bound.\n const readyEl = document.createElement('div');\n readyEl.id = 'app-is-ready';\n readyEl.setAttribute('data-ready', 'true');\n readyEl.style.display = 'none';\n document.body.appendChild(readyEl);\n\n const camelReadyEl = document.createElement('div');\n camelReadyEl.id = 'appIsReady';\n camelReadyEl.setAttribute('data-ready', 'true');\n camelReadyEl.style.display = 'none';\n document.body.appendChild(camelReadyEl);\n}\n\nlet preloadedBenchmarkPayloads:\n | {\n cleanName: string;\n buf: ArrayBuffer;\n text?: string;\n file: File;\n }[]\n | null = null;\n\nasync function preloadBenchmarkFiles(): Promise<\n { cleanName: string; buf: ArrayBuffer; text?: string; file: File }[]\n> {\n if (preloadedBenchmarkPayloads) return preloadedBenchmarkPayloads;\n try {\n const manifestResp = await fetch('./test-data/manifest.json');\n const fileNames: string[] = await manifestResp.json();\n const decoder = new TextDecoder();\n preloadedBenchmarkPayloads = await Promise.all(\n fileNames.map(async (name) => {\n const fileResp = await fetch(`./test-data/${name}`);\n let buf = await fileResp.arrayBuffer();\n let cleanName = name;\n if (name.toLowerCase().endsWith('.gz')) {\n cleanName = name.slice(0, -3);\n const bytes = new Uint8Array(buf);\n if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) {\n const ds = new DecompressionStream('gzip');\n const stream = new Blob([buf]).stream().pipeThrough(ds);\n buf = await new Response(stream).arrayBuffer();\n }\n }\n const text = cleanName.toLowerCase().endsWith('.fit') ? undefined : decoder.decode(buf);\n const file = new File([buf], cleanName, { type: 'application/octet-stream' });\n (file as any)._buf = buf;\n if (text !== undefined) (file as any)._text = text;\n return { cleanName, buf, text, file };\n }),\n );\n // Warm up GPX, TCX, and FIT parser and chart code paths during prepare phase\n let warmSample: any = null;\n for (const idx of [0, 2, 4]) {\n if (preloadedBenchmarkPayloads[idx]) {\n const parsed = await Parsers.parseFile(preloadedBenchmarkPayloads[idx].file);\n if (idx === 0) warmSample = parsed;\n }\n }\n if (warmSample) {\n const warmPts = warmSample.points.slice(0, 1250);\n const warmTrack: TrackData = {\n ...warmSample,\n id: 'warmup',\n fileName: 'warmup.gpx',\n fileSize: 1024,\n points: warmPts,\n bounds: calculateBounds(warmPts) || undefined,\n simplifiedPoints: simplifyTrack(warmPts, 50),\n stats: Parsers.computeStats(warmPts),\n addedAt: 1785542400000,\n visible: true,\n color: TRACK_COLORS[0],\n };\n const warmTrack2: TrackData = {\n ...warmTrack,\n id: 'warmup-2',\n fileName: 'warmup2.gpx',\n addedAt: 1785628800000,\n color: TRACK_COLORS[1],\n };\n const warmList = [warmTrack, warmTrack2];\n Parsers.ensureCurvesAndZones(warmTrack);\n Parsers.ensureCurvesAndZones(warmTrack2);\n MapView.addTracks(warmList);\n ChartView.loadTrack(warmTrack, warmList, false);\n ChartView.restoreSelection(10, 50, true);\n ChartView.setCursorAt(25, true);\n ChartView.setActiveMetrics(['elevation', 'speed', 'power']);\n ChartView.analyzeTelemetryIntervals(warmList, 10, 50);\n renderInsights(warmTrack, warmList);\n renderDetails(warmTrack, [], warmList);\n renderCombined(warmList, warmList);\n renderEvolution(warmTrack, warmList);\n prepareBenchmarkCourses(warmList);\n selectCourse('course-1', true);\n await resetBenchmarkState();\n void document.body.offsetHeight;\n await new Promise((r) => window.setTimeout(r, 0));\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n return preloadedBenchmarkPayloads;\n } catch {\n return [];\n }\n}\n\nfunction initBenchmarkTriggers() {\n const btnLoad = document.getElementById('btn-step-load');\n const btnAnalysis = document.getElementById('btn-step-analysis');\n const btnInsights = document.getElementById('btn-step-insights');\n const btnDetails = document.getElementById('btn-step-details');\n const btnAggregate = document.getElementById('btn-step-aggregate');\n const btnEvolution = document.getElementById('btn-step-evolution');\n const btnCourses = document.getElementById('btn-step-courses');\n\n function activateTab(tabName: string) {\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === tabName);\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${tabName}`);\n });\n UrlState.patch({ tab: tabName }, false);\n }\n\n btnLoad?.addEventListener('click', async () => {\n try {\n if (Object.keys(tracks).length > 0 || skippedImports.length > 0 || selectedId !== null) {\n await Storage.openDB();\n await resetBenchmarkState();\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n const payloads = await preloadBenchmarkFiles();\n const loadedFiles: File[] = payloads.map((p) => p.file);\n await handleFiles(loadedFiles);\n const allTracks = Object.values(tracks);\n if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id);\n } finally {\n window.dispatchEvent(new CustomEvent('load-and-parse-complete'));\n }\n });\n\n btnAnalysis?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('graphs');\n if (!selectedId && allTracks.length > 0) {\n selectTrack(allTracks[0].id);\n }\n ChartView.restoreSelection(120, 900, true);\n ChartView.setCursorAt(300, true);\n const availableMetrics = ChartView.getAvailableMetrics();\n const analysisMetrics = ['elevation', 'speed', 'power'].filter((m) =>\n availableMetrics.has(m),\n );\n if (analysisMetrics.length > 0) {\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const metric = (el as HTMLElement).dataset.metric;\n if (metric) el.classList.toggle('active', analysisMetrics.includes(metric));\n });\n updateToolbarLayout();\n ChartView.setActiveMetrics(analysisMetrics);\n } else {\n updateToolbarLayout();\n }\n ChartView.analyzeTelemetryIntervals(allTracks, 120, 900);\n onChartRangeChange(120, 900, ChartView.getXAxis(), false);\n } finally {\n window.dispatchEvent(new CustomEvent('analysis-complete'));\n }\n });\n\n btnInsights?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t));\n activateTab('insights');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderInsights(primaryTrack, allTracks);\n } finally {\n window.dispatchEvent(new CustomEvent('insights-complete'));\n }\n });\n\n btnDetails?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('details');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderDetails(primaryTrack, getGlobalTags(), allTracks);\n } finally {\n window.dispatchEvent(new CustomEvent('details-complete'));\n }\n });\n\n btnAggregate?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n if (allTracks.length >= 2) {\n const selectedTwo = [allTracks[0], allTracks[1]];\n activateTab('combined');\n renderCombined(selectedTwo, allTracks);\n }\n } finally {\n window.dispatchEvent(new CustomEvent('aggregate-complete'));\n }\n });\n\n btnEvolution?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('evolution');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderEvolution(primaryTrack, allTracks, (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n } finally {\n window.dispatchEvent(new CustomEvent('evolution-complete'));\n }\n });\n\n btnCourses?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('courses');\n prepareBenchmarkCourses(allTracks);\n selectCourse('course-1', true);\n } finally {\n window.dispatchEvent(new CustomEvent('courses-complete'));\n }\n });\n\n (window as any).benchmarkSteps = {\n loadAndParseFiles: () => document.getElementById('btn-step-load')?.click(),\n displayAnalysisMetrics: () => document.getElementById('btn-step-analysis')?.click(),\n displayInsights: () => document.getElementById('btn-step-insights')?.click(),\n displayDetails: () => document.getElementById('btn-step-details')?.click(),\n displayAggregateMetrics: () => document.getElementById('btn-step-aggregate')?.click(),\n displayEvolutionMetrics: () => document.getElementById('btn-step-evolution')?.click(),\n displayCourses: () => document.getElementById('btn-step-courses')?.click(),\n };\n}\n\nasync function processAndLoadTrack(t: TrackData) {\n // Migration: re-calculate stats if new insights are missing or old format\n const powerCurveEntries = t.stats.powerCurve ? Object.values(t.stats.powerCurve) : [];\n\n const needsEnrich =\n t.points.length > 1 && (t.points[1].speed === undefined || t.points[1].gradient === undefined);\n\n const needsRecalc =\n needsEnrich ||\n !t.stats.powerCurve ||\n !t.stats.hrZones ||\n !t.stats.hrCurve ||\n t.stats.shifts === undefined ||\n t.stats.avgBattery === undefined ||\n t.stats.avgTemp === undefined ||\n (powerCurveEntries.length > 0 && typeof (powerCurveEntries[0] as any) === 'number') ||\n ((t.stats.duration || 0) > 10800 * 1000 && t.stats.powerCurve && !t.stats.powerCurve[14400]);\n\n if (needsRecalc) {\n if (needsEnrich) t.points = Parsers.enrichPoints(t.points);\n t.stats = Parsers.computeStats(t.points);\n await Storage.save(t);\n }\n\n tracks[t.id] = t;\n colorIdx = Math.max(colorIdx, TRACK_COLORS.indexOf(t.color) + 1);\n MapView.addTrack(t);\n MapView.setTrackVisible(t.id, t.visible && !t._filtered);\n renderTrackList(); // Progressive list update\n}\n\nfunction initResizeHandle() {\n const handle = document.getElementById('resize-handle');\n const panel = document.getElementById('chart-panel');\n if (!handle || !panel) return;\n\n let isDragging = false;\n\n handle.addEventListener('mousedown', () => {\n isDragging = true;\n document.body.style.cursor = 'ns-resize';\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const h = window.innerHeight - e.clientY;\n const clampedH = Math.max(100, Math.min(window.innerHeight - 100, h));\n panel.style.height = `${clampedH}px`;\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n document.body.style.cursor = '';\n });\n}\n\nfunction initSidebarResizer() {\n const resizer = document.getElementById('sidebar-resizer');\n const sidebar = document.getElementById('sidebar');\n if (!resizer || !sidebar) return;\n\n let isDragging = false;\n\n resizer.addEventListener('mousedown', () => {\n isDragging = true;\n resizer.classList.add('dragging');\n document.body.classList.add('dragging-sidebar');\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const w = e.clientX;\n const clampedW = Math.max(200, Math.min(600, w));\n sidebar.style.width = `${clampedW}px`;\n sidebar.style.setProperty('--sidebar-w', `${clampedW}px`);\n ChartView.resize();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n resizer.classList.remove('dragging');\n document.body.classList.remove('dragging-sidebar');\n });\n}\n\n// \u2500\u2500 Event Handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction onMapMove(lat: number, lng: number, zoom: number) {\n UrlState.patch({ map_pos: [lat, lng, zoom] });\n}\n\nfunction onMapPointClick(id: string, idx: number) {\n selectTrack(id, false);\n ChartView.setCursorAt(idx);\n}\n\nfunction onMapDblClick() {\n // MapView.fitAll();\n}\n\nfunction onChartCursorMove(pt: TrackPoint | null) {\n if (pt && pt.lat != null && pt.lon != null) {\n MapView.showCursorAt(pt.lat, pt.lon);\n if (followDot) MapView.centerOn(pt.lat, pt.lon, null, true);\n } else {\n MapView.hideCursor();\n }\n}\n\nfunction onChartRangeChange(min: number | null, max: number | null, axis: string, fit = false) {\n if (!selectedId || !tracks[selectedId]) return;\n const t = tracks[selectedId];\n\n if (min === null || max === null) {\n MapView.clearHighlight();\n if (t && (UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n UrlState.patch({ sel: null });\n return;\n }\n\n // Find point indices\n const pts = t.points;\n let iMin = 0,\n iMax = pts.length - 1;\n\n if (axis === 'distance') {\n const d0 = min * 1000,\n d1 = max * 1000;\n iMin = pts.findIndex((p) => (p.dist || 0) >= d0);\n iMax = pts.findIndex((p) => (p.dist || 0) >= d1);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const ts0 = t0 + min * 1000,\n ts1 = t0 + max * 1000;\n iMin = pts.findIndex((p) => (p.time || 0) >= ts0);\n iMax = pts.findIndex((p) => (p.time || 0) >= ts1);\n }\n\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = pts.length - 1;\n\n // Compute selection stats\n const selPts = pts.slice(iMin, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n if ((UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n\n MapView.highlightSegment(selectedId, pts, iMin, iMax, fit, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n UrlState.patch({ sel: [min, max] });\n}\n\nfunction onChartClick(pt: TrackPoint, idx: number) {\n if (pt && pt.lat != null && pt.lon != null) MapView.centerOn(pt.lat, pt.lon, POINT_ZOOM_LEVEL);\n}\n\nexport function selectTrack(id: string, fit = true, deferChartRender = false) {\n if (!tracks[id]) return;\n if (id === selectedId) {\n if (fit) MapView.fitTrack(id);\n return;\n }\n\n const hadSelected = selectedId !== null;\n if (hadSelected) {\n // Clear current views immediately before loading new data\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n }\n\n selectedId = id;\n\n // Fully reset metric coloring when switching tracks\n currentMapColors = null;\n MapView.clearMetricColor(id);\n if (hadSelected) {\n ChartView.toggleMapColor(null); // Ensure ChartView state also resets\n }\n\n // Clear selection on new track\n UrlState.patch({ track: id, sel: null }, true);\n if (hadSelected) {\n ChartView.cancelSelection();\n }\n\n // Update UI immediately\n renderTrackList();\n\n // Render details\n const activeTab = UrlState.get().tab || 'graphs';\n if (activeTab === 'details') renderDetails(tracks[id], getGlobalTags());\n if (activeTab === 'insights') renderInsights(tracks[id]);\n if (activeTab === 'combined') renderCombined(tracks[id]);\n if (activeTab === 'courses') renderCourses();\n if (activeTab === 'evolution') {\n renderEvolution(tracks[id], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n\n // Tell sub-views\n MapView.setSelectedTrack(id, fit);\n if (fit) MapView.fitTrack(id);\n ChartView.loadTrack(tracks[id], Object.values(tracks), deferChartRender);\n}\n\nasync function deleteTrack(id: string) {\n await Storage.remove(id);\n MapView.removeTrack(id);\n delete tracks[id];\n if (selectedId === id) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n UrlState.patch({ track: null, sel: null, sel_point: null });\n }\n applyFilters();\n}\n\nasync function clearAll() {\n const code = Math.floor(10 + Math.random() * 90).toString();\n\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n backdrop.innerHTML = `\n
\n
Delete all tracks?
\n
\n This will permanently remove all tracks from your browser storage. This action cannot be undone.\n
\n
\n
Enter \"${code}\" to confirm:
\n \n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const input = backdrop.querySelector('.modal-input') as HTMLInputElement;\n const btnConfirm = backdrop.querySelector('.modal-btn.confirm') as HTMLButtonElement;\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n\n input.focus();\n\n input.addEventListener('input', () => {\n btnConfirm.disabled = input.value !== code;\n });\n\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n\n btnConfirm.addEventListener('click', async () => {\n if (input.value !== code) return;\n close();\n\n cancelProcessing = true;\n await Storage.clear();\n\n tracks = {};\n selectedId = null;\n MapView.clearHighlight();\n window.location.reload();\n });\n}\n\nfunction applyFilters(skipRender = false) {\n const ids = Object.keys(tracks);\n ids.forEach((id) => {\n const t = tracks[id];\n const s = t.stats;\n let visible = true;\n\n // Search query\n if (searchQuery) {\n if (searchRegex) {\n try {\n const re = new RegExp(searchQuery, 'i');\n if (!re.test(t.name)) visible = false;\n } catch (e) {\n visible = false;\n }\n } else {\n if (!t.name.toLowerCase().includes(searchQuery.toLowerCase())) visible = false;\n }\n }\n\n // Date filter\n if (visible && (filters.date[0] || filters.date[1])) {\n const start = filters.date[0] ? new Date(filters.date[0]).getTime() : 0;\n const end = filters.date[1] ? new Date(filters.date[1]).getTime() : Infinity;\n const t0 = s.startTime || 0;\n if (t0 < start || t0 > end) visible = false;\n }\n\n // Distance filter\n if (visible && (filters.dist[0] !== null || filters.dist[1] !== null)) {\n const min = (filters.dist[0] || 0) * 1000;\n const max = (filters.dist[1] || Infinity) * 1000;\n if (s.totalDist < min || s.totalDist > max) visible = false;\n }\n\n // Duration filter\n if (visible && (filters.dur[0] !== null || filters.dur[1] !== null)) {\n const min = (filters.dur[0] || 0) * 60000;\n const max = (filters.dur[1] || Infinity) * 60000;\n const d = s.duration || 0;\n if (d < min || d > max) visible = false;\n }\n\n // Metrics filter\n if (visible && filters.metrics.size > 0) {\n for (const m of filters.metrics) {\n const field = ChartView.METRICS[m].field;\n if (!t.points.some((p: any) => p[field] != null)) {\n visible = false;\n break;\n }\n }\n }\n\n // Sport filter\n if (visible && filters.sport) {\n if (t.sport !== filters.sport) visible = false;\n }\n\n // Tags filter\n if (visible && filters.tags.length > 0) {\n const trackTags = t.tags || [];\n if (!filters.tags.every((ft) => trackTags.includes(ft))) visible = false;\n }\n\n t._filtered = !visible;\n MapView.setTrackVisible(t.id, t.visible && visible);\n });\n\n if (!skipRender) renderTrackList();\n}\n\nfunction updateFilterUI() {\n (document.getElementById('filter-date-start') as HTMLInputElement).value = filters.date[0] || '';\n (document.getElementById('filter-date-end') as HTMLInputElement).value = filters.date[1] || '';\n (document.getElementById('filter-dist-min') as HTMLInputElement).value =\n filters.dist[0] !== null ? String(filters.dist[0]) : '';\n (document.getElementById('filter-dist-max') as HTMLInputElement).value =\n filters.dist[1] !== null ? String(filters.dist[1]) : '';\n (document.getElementById('filter-dur-min') as HTMLInputElement).value =\n filters.dur[0] !== null ? String(filters.dur[0]) : '';\n (document.getElementById('filter-dur-max') as HTMLInputElement).value =\n filters.dur[1] !== null ? String(filters.dur[1]) : '';\n (document.getElementById('filter-tags') as HTMLInputElement).value = filters.tags.join(', ');\n\n document\n .querySelectorAll('#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item')\n .forEach((el) => {\n const item = el as HTMLElement;\n item.classList.toggle('active', (item.dataset.sport || '') === (filters.sport || ''));\n });\n\n document.querySelectorAll('#filter-metrics .mini-pill').forEach((el) => {\n const btn = el as HTMLElement;\n btn.classList.toggle('active', filters.metrics.has(btn.dataset.metric!));\n });\n\n const activeCount =\n (filters.date[0] ? 1 : 0) +\n (filters.date[1] ? 1 : 0) +\n (filters.dist[0] !== null ? 1 : 0) +\n (filters.dist[1] !== null ? 1 : 0) +\n (filters.dur[0] !== null ? 1 : 0) +\n (filters.dur[1] !== null ? 1 : 0) +\n filters.metrics.size +\n (filters.tags.length > 0 ? 1 : 0);\n\n const badge = document.querySelector('#btn-toggle-filters .btn-badge');\n if (badge) {\n badge.textContent = activeCount > 0 ? String(activeCount) : '';\n badge.classList.toggle('hidden', activeCount === 0);\n }\n}\n\nfunction updateSearchSortUI() {\n const searchInput = document.getElementById('track-search') as HTMLInputElement;\n if (searchInput) searchInput.value = searchQuery;\n document.getElementById('btn-regex-toggle')?.classList.toggle('active', searchRegex);\n\n const opt = SORT_OPTIONS.find((o) => o.val === currentSort);\n if (opt) {\n const labelEl = document.getElementById('sort-current-label');\n const iconEl = document.getElementById('sort-current-icon');\n if (labelEl)\n labelEl.textContent = opt.label\n .replace(' first', '')\n .replace(' distance', '')\n .replace(' duration', '');\n if (iconEl) iconEl.textContent = opt.icon;\n }\n}\n\nfunction applyState(urlState: AppState) {\n // Restore track\n const newTrackId = urlState.track;\n if (newTrackId !== selectedId) {\n if (newTrackId && tracks[newTrackId]) {\n selectTrack(newTrackId, true);\n } else if (!newTrackId && selectedId) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n renderTrackList();\n MapView.fitAll();\n }\n }\n\n // Restore basemap\n if (urlState.map && typeof urlState.map === 'string') {\n MapView.switchBasemap(urlState.map);\n document\n .querySelectorAll('.bm-btn')\n .forEach((b) =>\n b.classList.toggle('active', (b as HTMLElement).dataset.layer === urlState.map),\n );\n }\n\n // Restore map position\n if (urlState.map_pos) {\n const [lat, lng, zoom] = urlState.map_pos;\n MapView.setPosition(lat, lng, zoom);\n }\n\n // Restore tab\n if (urlState.tab) {\n document.querySelectorAll('.tab-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n if (b.dataset.tab === urlState.tab) {\n if (!b.classList.contains('active')) b.click();\n }\n });\n }\n\n // Restore x-axis mode\n if (urlState.xaxis) ChartView.setXAxis(urlState.xaxis);\n\n const currentXAxis = urlState.xaxis || 'time';\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', (b as HTMLElement).dataset.axis === currentXAxis));\n\n // Restore active metrics\n if (urlState.metrics) {\n const metrics = ChartView.METRICS;\n const keys = urlState.metrics\n .map((abbr) => Object.keys(metrics).find((k) => metrics[k].abbr === abbr))\n .filter((k): k is string => k !== undefined);\n if (keys.length) ChartView.setActiveMetrics(keys);\n }\n\n // Restore filters\n if (urlState.f_date)\n filters.date = urlState.f_date.map((v) => v || null) as [string | null, string | null];\n if (urlState.f_dist)\n filters.dist = urlState.f_dist.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_dur)\n filters.dur = urlState.f_dur.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_mets) filters.metrics = new Set(urlState.f_mets);\n if (urlState.f_tags) filters.tags = urlState.f_tags;\n\n updateFilterUI();\n\n if (urlState.q) searchQuery = urlState.q;\n if (urlState.re) searchRegex = urlState.re;\n if (urlState.sort) currentSort = urlState.sort;\n updateSearchSortUI();\n\n applyFilters();\n}\n\nfunction updateSportFilterOptions() {\n const container = document.getElementById('sport-filter-container');\n if (!container) return;\n\n const commonContainer = document.getElementById('common-sports');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n if (!commonContainer || !dropdownContent) return;\n\n const sports = new Set();\n Object.values(tracks).forEach((t) => {\n if (t.sport) sports.add(t.sport);\n });\n\n const sportsArray = Array.from(sports).sort();\n const burgerDropdown = document.getElementById('sport-burger-dropdown');\n\n commonContainer.innerHTML = '';\n dropdownContent.innerHTML = '';\n\n if (sportsArray.length <= 4) {\n if (burgerDropdown) burgerDropdown.style.display = 'none';\n\n sportsArray.forEach((sport) => {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n });\n } else {\n if (burgerDropdown) burgerDropdown.style.display = 'inline-block';\n\n const commonSports = ['running', 'cycling', 'walking'];\n\n commonSports.forEach((sport) => {\n if (sports.has(sport)) {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n }\n });\n\n sportsArray.forEach((sport) => {\n const item = document.createElement('div');\n item.className = `dropdown-item${filters.sport === sport ? ' active' : ''}`;\n item.dataset.sport = sport;\n item.style.padding = '8px';\n item.style.cursor = 'pointer';\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '8px';\n item.innerHTML = `\n ${getSportIcon(sport)}\n ${sport.charAt(0).toUpperCase() + sport.slice(1)}\n `;\n dropdownContent.appendChild(item);\n });\n }\n}\n\nfunction renderTrackList() {\n updateSportFilterOptions();\n const list = document.getElementById('track-list');\n const emptyEl = document.getElementById('track-list-empty') as HTMLElement;\n const headerLabel = document.querySelector('.section-label');\n if (!list) return;\n\n const ids = Object.keys(tracks).filter((id) => !tracks[id]._filtered);\n if (headerLabel) headerLabel.textContent = `Tracks (${ids.length})`;\n\n if (!ids.length) {\n list.innerHTML = '';\n if (emptyEl) {\n list.appendChild(emptyEl);\n emptyEl.style.display = 'block';\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n list.innerHTML = '';\n\n ids\n .sort((a, b) => {\n // Current selected always first\n if (a === selectedId) return -1;\n if (b === selectedId) return 1;\n\n const ta = tracks[a],\n tb = tracks[b];\n const sa = ta.stats,\n sb = tb.stats;\n\n let cmp = 0;\n switch (currentSort) {\n case 'date-asc':\n cmp = (sa.startTime || 0) - (sb.startTime || 0);\n break;\n case 'date-desc':\n cmp = (sb.startTime || 0) - (sa.startTime || 0);\n break;\n case 'dist-asc':\n cmp = (sa.totalDist || 0) - (sb.totalDist || 0);\n break;\n case 'dist-desc':\n cmp = (sb.totalDist || 0) - (sa.totalDist || 0);\n break;\n case 'dur-asc':\n cmp = (sa.duration || 0) - (sb.duration || 0);\n break;\n case 'dur-desc':\n cmp = (sb.duration || 0) - (sa.duration || 0);\n break;\n default:\n cmp = 0;\n }\n return cmp || a.localeCompare(b);\n })\n .forEach((id) => {\n list.appendChild(buildTrackItem(tracks[id]));\n });\n}\n\nfunction getGlobalTags(): string[] {\n const all = new Set();\n Object.values(tracks).forEach((t) => {\n (t.tags || []).forEach((tag) => all.add(tag));\n });\n return Array.from(all).sort();\n}\n\nfunction getSportIcon(sport: string | null): string {\n if (!sport) return 'category';\n const s = sport.toLowerCase();\n if (s.includes('run')) return 'directions_run';\n if (s.includes('cycl') || s.includes('bike')) return 'directions_bike';\n if (s.includes('walk')) return 'directions_walk';\n if (s.includes('swim')) return 'pool';\n if (s.includes('hik')) return 'hiking';\n return 'sports';\n}\n\nfunction buildTrackItem(track: TrackData) {\n const item = document.createElement('div');\n item.className = `track-item${track.id === selectedId ? ' selected' : ''}`;\n item.dataset.id = track.id;\n\n const date =\n track.points.length && track.points[0].time ? fmtDate(track.points[0].time) : 'Unknown date';\n\n const tagsHtml =\n (track.tags || []).length > 0\n ? `
${(track.tags || [])\n .map((t) => {\n const c = getTagColor(t);\n return `${escHtml(t)}`;\n })\n .join('')}
`\n : '';\n\n item.innerHTML = `\n
\n
\n
${escHtml(track.displayName || track.name)}
\n
\n
\n ${date}\n ${Math.round(track.stats.totalDist / 1000)} km\n ${track.sport ? `${getSportIcon(track.sport)}` : ''}\n ${track.format.toUpperCase()}\n
\n \n
\n ${tagsHtml}\n
\n `;\n\n item.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.icon-btn')) return;\n selectTrack(track.id);\n });\n\n const btnVis = item.querySelector('.toggle-vis') as HTMLElement;\n btnVis.addEventListener('click', () => {\n track.visible = !track.visible;\n btnVis.querySelector('.material-symbols-rounded')!.textContent = track.visible\n ? 'visibility'\n : 'visibility_off';\n MapView.setTrackVisible(track.id, track.visible);\n Storage.save(track);\n });\n\n return item;\n}\n\nfunction showToast(msg: string, type: 'info' | 'error' = 'info') {\n const container = document.getElementById('toast-container');\n if (!container) return;\n container.innerHTML = '';\n const t = document.createElement('div');\n t.className = `toast ${type}`;\n t.textContent = msg;\n container.appendChild(t);\n}\n\nfunction showSkippedImportsModal() {\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n let listHtml = '';\n skippedImports.forEach((s) => {\n listHtml += `
${s.name}: ${s.reason}
`;\n });\n\n backdrop.innerHTML = `\n
\n
Skipped Imports
\n
\n ${listHtml || '
No skipped imports.
'}\n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n const btnClear = backdrop.querySelector('.modal-btn.clear') as HTMLButtonElement;\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n btnClear.addEventListener('click', () => {\n skippedImports = [];\n close();\n const importWarning = document.getElementById('import-warning');\n if (importWarning) importWarning.classList.add('hidden');\n });\n\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n}\n\nfunction initDropZone() {\n const zone = document.getElementById('drop-zone');\n if (!zone) return;\n\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n importWarning.addEventListener('click', (e) => {\n e.stopPropagation();\n showSkippedImportsModal();\n });\n }\n\n window.addEventListener('dragover', (e) => {\n e.preventDefault();\n zone.classList.add('drop-active');\n });\n\n window.addEventListener('dragleave', (e) => {\n if (e.relatedTarget === null) zone.classList.remove('drop-active');\n });\n\n window.addEventListener('drop', async (e) => {\n e.preventDefault();\n zone.classList.remove('drop-active');\n\n const items = e.dataTransfer?.items;\n if (!items) return;\n\n const files: File[] = [];\n const queue: FileSystemEntry[] = [];\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i].webkitGetAsEntry();\n if (entry) queue.push(entry);\n }\n\n async function readAllEntries(entry: FileSystemEntry) {\n if (entry.isFile) {\n const file = await new Promise((res) => (entry as FileSystemFileEntry).file(res));\n files.push(file);\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n let entries: FileSystemEntry[] = [];\n let chunk: FileSystemEntry[];\n do {\n chunk = await new Promise((res) => reader.readEntries(res));\n entries.push(...chunk);\n } while (chunk.length > 0);\n\n for (const child of entries) await readAllEntries(child);\n }\n }\n\n for (const entry of queue) await readAllEntries(entry);\n\n if (files.length) handleFiles(files);\n });\n}\n\nasync function handleFiles(files: File[]) {\n if (!files.length) return;\n cancelProcessing = false;\n const initialSkipCount = skippedImports.length;\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const loaderClose = document.getElementById('loader-close');\n\n if (loaderClose) {\n loaderClose.addEventListener('click', () => {\n cancelProcessing = true;\n if (loader) loader.classList.add('hidden');\n });\n }\n\n function updateLoaderIconToWarning() {\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'warning';\n loaderIcon.style.color = '#f59e0b';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n const count = skippedImports.length - initialSkipCount;\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = `${count}`;\n warningCount.style.display = 'flex';\n }\n }\n\n if (loader) {\n if (loaderText)\n loaderText.textContent = `Importing ${files.length} file${files.length > 1 ? 's' : ''}`;\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'download';\n loaderIcon.style.color = 'var(--accent)';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n warningCount.style.display = 'none';\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = '0';\n }\n if (loaderSubtext) loaderSubtext.textContent = '';\n if (progressBar) progressBar.style.width = '0%';\n loader.classList.remove('hidden');\n\n if (skippedImports.length > initialSkipCount) updateLoaderIconToWarning();\n }\n\n try {\n let count = 0;\n let firstId: string | null = null;\n let processedSinceLastUpdate = 0;\n\n // Filter out obviously invalid files early\n const validFiles = files.filter((f) => {\n const name = f.name.toLowerCase();\n return (\n name.endsWith('.gpx') ||\n name.endsWith('.fit') ||\n name.endsWith('.tcx') ||\n name.endsWith('.kml')\n );\n });\n\n const invalidFiles = files.filter((f) => !validFiles.includes(f));\n invalidFiles.forEach((f) => {\n skippedImports.push({ name: f.name, reason: 'Unsupported file format' });\n });\n\n if (validFiles.length === 0) {\n if (files.length > 0) {\n showToast('No valid GPS files found', 'error');\n // Still update warning icon if there were invalid files!\n const importWarning = document.getElementById('import-warning');\n if (importWarning && skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n }\n }\n return;\n }\n\n const loaderFilename = document.getElementById('loader-filename');\n let progressIdxEl: HTMLElement | null = null;\n if (loaderSubtext) {\n loaderSubtext.innerHTML =\n '';\n progressIdxEl = loaderSubtext.querySelector('.progress-index') as HTMLElement | null;\n const totalEl = loaderSubtext.querySelector('.progress-total');\n if (totalEl) totalEl.textContent = validFiles.length.toString();\n }\n\n for (let i = 0; i < validFiles.length; i++) {\n if (cancelProcessing) break;\n const f = validFiles[i];\n if (loaderFilename) loaderFilename.textContent = f.name;\n if (progressIdxEl) progressIdxEl.textContent = (i + 1).toString();\n if (progressBar) progressBar.style.width = `${(i / validFiles.length) * 100}%`;\n\n try {\n const data = await Parsers.parseFile(f);\n\n // Duplicate checks\n const existingTracks = Object.values(tracks);\n\n // Rule 1: Same file and same size\n const sameFile = existingTracks.find((t) => t.fileName === f.name && t.fileSize === f.size);\n if (sameFile) {\n skippedImports.push({ name: f.name, reason: 'Same File' });\n updateLoaderIconToWarning();\n continue;\n }\n\n // Rule 2 & 3: Same start day checks\n const newStart = data.stats.startTime;\n const newDuration = data.stats.duration;\n\n if (newStart != null && newDuration != null) {\n const newEnd = newStart + newDuration;\n const sameDayTracks = existingTracks.filter(\n (t) => t.stats.startTime != null && isSameDay(newStart, t.stats.startTime!),\n );\n\n let discarded = false;\n for (const ext of sameDayTracks) {\n const extStart = ext.stats.startTime!;\n const extDuration = ext.stats.duration!;\n const extEnd = extStart + extDuration;\n\n // Rule 2: Fully contained\n if (newStart >= extStart && newEnd <= extEnd) {\n skippedImports.push({ name: f.name, reason: 'Fully contained in another track' });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n\n // Rule 3: Overlaps for > 10 mins\n const overlap = Math.min(newEnd, extEnd) - Math.max(newStart, extStart);\n if (overlap > 600000) {\n // 10 mins in ms\n skippedImports.push({\n name: f.name,\n reason: 'Overlaps with an existing track for more than 10 mins',\n });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n }\n if (discarded) continue;\n }\n\n const fallbackTime = 1785542400000;\n let id = compactId(data.stats.startTime || fallbackTime);\n if (tracks[id]) id += `-${shortRandom()}`;\n\n // Use filename as activity name if internal name is generic\n let trackName = data.name;\n if (trackName.startsWith('Unnamed') || trackName.startsWith('Fit Activity'))\n trackName = f.name;\n\n // Generate a nice display name\n let displayName = trackName;\n const t0 = data.points[0]?.time;\n const sport = data.sport\n ? data.sport.charAt(0).toUpperCase() + data.sport.slice(1)\n : 'Activity';\n if (t0) {\n const d = new Date(t0);\n displayName = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')} ${sport}`;\n } else {\n displayName = trackName.replace(/\\.[^/.]+$/, '').replace(/_/g, ' '); // Remove extension and replace underscores\n }\n\n const track: TrackData = {\n ...data,\n id,\n name: trackName,\n displayName,\n fileName: f.name,\n fileSize: f.size,\n bounds: calculateBounds(data.points) || undefined,\n simplifiedPoints: simplifyTrack(data.points, 50), // 50m resolution\n addedAt: data.stats.startTime || fallbackTime,\n visible: true,\n color: TRACK_COLORS[colorIdx % TRACK_COLORS.length],\n };\n colorIdx++;\n if (cancelProcessing) break;\n\n await Storage.save(track);\n tracks[id] = track;\n MapView.addTrack(track);\n if (!firstId) firstId = id;\n count++;\n processedSinceLastUpdate++;\n\n if (processedSinceLastUpdate >= 5) {\n processedSinceLastUpdate = 0;\n }\n } catch (err) {\n skippedImports.push({\n name: f.name,\n reason: `Parse error: ${err instanceof Error ? err.message : String(err)}`,\n });\n updateLoaderIconToWarning();\n }\n }\n\n // Update warning icon\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n if (skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n } else {\n importWarning.classList.add('hidden');\n }\n }\n\n const newWarnings = skippedImports.length > initialSkipCount;\n if (!newWarnings && loader) {\n loader.classList.add('hidden');\n }\n\n if (count > 0) {\n showToast(`Imported ${count} track${count > 1 ? 's' : ''}`);\n applyFilters(!!firstId && firstId !== selectedId);\n if (firstId) selectTrack(firstId);\n }\n\n if (newWarnings) {\n const loaderIcon = document.querySelector('.loader-icon-wrap span');\n if (loaderIcon) loaderIcon.textContent = 'warning';\n // Delay hiding loader to let user see the alert icon\n await new Promise((r) => setTimeout(r, 1500));\n }\n } finally {\n if (loader) loader.classList.add('hidden');\n }\n}\n\nfunction initMetricPillDraggable() {\n const container = document.getElementById('metric-pills');\n if (!container) return;\n\n let draggedEl: HTMLElement | null = null;\n\n container.addEventListener('dragstart', (e) => {\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (!target) return;\n draggedEl = target;\n e.dataTransfer!.effectAllowed = 'move';\n target.classList.add('dragging-pill');\n // For transparent background in ghost image\n setTimeout(() => (target.style.opacity = '0.4'), 0);\n });\n\n container.addEventListener('dragover', (e) => {\n e.preventDefault();\n e.dataTransfer!.dropEffect = 'move';\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (target && target !== draggedEl) {\n const rect = target.getBoundingClientRect();\n const next = e.clientX - rect.left > rect.width / 2;\n container.insertBefore(draggedEl!, next ? target.nextSibling : target);\n }\n });\n\n container.addEventListener('dragend', () => {\n if (!draggedEl) return;\n draggedEl.classList.remove('dragging-pill');\n draggedEl.style.opacity = '';\n draggedEl = null;\n\n // Update Chart order\n const keys = Array.from(container.querySelectorAll('.metric-pill')).map(\n (el) => (el as HTMLElement).dataset.metric!,\n );\n ChartView.updateMetricOrder(keys);\n syncMetricsToUrl();\n });\n}\n\nfunction updateToolbarLayout() {\n const toolbar = document.getElementById('chart-toolbar');\n const pills = document.getElementById('metric-pills');\n if (!toolbar || !pills) return;\n\n toolbar.classList.remove('collapsed');\n const availableW = Math.max(0, toolbar.clientWidth - 280);\n let totalW = 0;\n let hidden = false;\n\n Array.from(pills.children).forEach((el) => {\n const htmlEl = el as HTMLElement;\n if (htmlEl.id === 'pill-overflow') return;\n\n htmlEl.classList.remove('overflow-hidden');\n if (!htmlEl.classList.contains('active')) return;\n const metricKey = htmlEl.dataset.metric || '';\n const deterministicPillWidth = 36 + metricKey.length * 6;\n totalW += deterministicPillWidth + 6;\n\n if (totalW > availableW) {\n hidden = true;\n htmlEl.classList.add('overflow-hidden');\n }\n });\n\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.toggle('hidden', !hidden);\n\n if (hidden) toolbar.classList.add('collapsed');\n}\n\ndocument.addEventListener('DOMContentLoaded', init);\n"], + "mappings": "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", + "names": ["UrlState", "_state", "_lastSearch", "_syncTimeout", "_shouldPush", "read", "p", "s", "metricsRaw", "v", "isDesc", "field", "parts", "_sync", "dir", "search", "val", "url", "get", "patch", "partial", "push", "k", "key", "refresh", "reset", "InMemoryStorage", "track", "id", "key", "value", "IndexedDBStorage", "resolve", "reject", "req", "db", "name", "mode", "res", "rej", "tx", "activeDriver", "Storage", "UrlState", "t", "k", "v", "FitParser", "haversine", "lat1", "lon1", "lat2", "lon2", "phi1", "phi2", "deltaPhi", "deltaLambda", "a", "compactId", "timestamp", "buf", "shortRandom", "fmtDuration", "s", "fmtSecs", "h", "m", "fmtPace", "seconds", "mins", "secs", "fmtDate", "ts", "d", "fmtDateTime", "iso", "fmtFileSize", "bytes", "k", "sizes", "i", "escHtml", "str", "getTagColor", "name", "hash", "gaussianSmooth", "data", "sigma", "size", "kernel", "half", "sum", "x", "result", "val", "weightSum", "idx", "hexToRgba", "hex", "alpha", "r", "g", "b", "calculateBounds", "pts", "minLat", "maxLat", "minLon", "maxLon", "p", "SIMPLIFY_CAP", "simplifyLats", "simplifyLons", "simplifyEles", "simplifyDists", "enrichEleBuf", "enrichPwrBuf", "enrichSpdBuf", "simplifyTrack", "minDistanceMeters", "n", "lats", "lons", "eles", "dists", "i", "tolerances", "errChecksum", "degToRad", "pass", "ti", "tolDegSq", "anchor", "cosLat", "dx", "dy", "dz", "mid", "mx", "my", "result", "lastPoint", "tolBias", "haversine", "Parsers", "enrichPoints", "totalDist", "prev", "d", "dt", "de", "eleBuf", "pwrBuf", "spdBuf", "gradeWindows", "npAccum", "scaleH", "wi", "w", "invW", "pSum", "sSum", "pAvg", "airDensity", "slopeAngle", "smoothBias", "hrZoneThresholds", "ftp", "computeStats", "includeCurves", "stats", "powerSum", "powerN", "hrSum", "hrN", "cadSum", "cadN", "speedSum", "speedN", "batterySum", "batteryN", "tempSum", "tempN", "hasTemp", "shifts", "hasGears", "diff", "t0", "t1", "calculateHRZones", "calculateHRCurve", "calculatePowerCurve", "calculatePowerZones", "ensureCurvesAndZones", "track", "s", "STANDARD_CURVE_DURATIONS", "calculateSlidingMax", "data", "durations", "len", "prefix", "curve", "hasAny", "di", "maxSum", "bestIdx", "limit", "j", "currentSum", "powerData", "nonZero", "v", "hrData", "zones", "thresholds", "t", "pw", "z", "setFTP", "val", "getFTP", "hr", "setHRZones", "getHRZones", "extractXmlTag", "block", "openTag", "closeTag", "start", "extractXmlAttr", "tagOpen", "attrPrefix", "cachedDateKey", "cachedDayMs", "parseIntSlice", "text", "end", "neg", "c0", "digits", "c", "parseFloatSlice", "intPart", "fracPart", "fracDiv", "inFrac", "res", "fastParseTimeSlice", "y", "m", "key", "hh", "mm", "ss", "ms", "extractAttrFloat", "vStart", "parseGPX", "buf", "predecodedText", "firstTrkpt", "header", "trkIdx", "name", "gpxOpenEnd", "device", "points", "pos", "trkStart", "openEnd", "trkEnd", "lat", "lon", "ele", "time", "cad", "power", "temp", "speed", "gearFront", "gearRear", "gearFrontTooth", "gearRearTooth", "battery", "lt", "gt", "c1", "tagLen", "nextLt", "vEnd", "expectedCloseGt", "closeGt", "gears", "parseTCX", "firstTp", "creatorBlock", "tpStart", "tpEnd", "fastDecodeFitData", "dv", "headerSize", "dataSize", "endOffset", "GARMIN_EPOCH_SEC", "SEMICIRCLE_TO_DEG", "defs", "file_ids", "sessions", "records", "events", "device_infos", "offset", "hdr", "localNum", "littleEndian", "globalMsgNum", "numFields", "fields", "recordSize", "num", "size", "type", "def", "le", "gNum", "ts", "rawLat", "rawLon", "rawAlt", "rawDist", "rawSpd", "msg", "fOff", "f", "bType", "sportMap", "evName", "parseFIT", "resolve", "reject", "handleParsedFitData", "error", "devices", "sport", "subSport", "getDeviceName", "fid", "antId", "existing", "statusReports", "idx", "a", "b", "gearEvents", "e", "front", "rear", "frontTooth", "rearTooth", "ft", "fg", "rt", "rg", "lastBattery", "statusIdx", "lastFrontGear", "lastRearGear", "lastFrontTooth", "lastRearTooth", "gearIdx", "validPoints", "ri", "r", "ex", "fastData", "FitParser", "parseKML", "doc", "nameEl", "coordEls", "el", "line", "parts", "parseFile", "file", "ext", "MapView", "trackData", "customClickHandler", "init", "onSelectCb", "onMoveCb", "onPointClickCb", "onPointHoverCb", "onDblClickCb", "switchBasemap", "layer", "addTrack", "t", "addTracks", "ts", "removeTrack", "id", "clearTracks", "removeAllTracks", "setTrackVisible", "visible", "setSelectedTrack", "fit", "fitAll", "fitTrack", "showCursorAt", "lat", "lon", "hideCursor", "highlightSegment", "pts", "start", "end", "colors", "clearHighlight", "setTrackHover", "hover", "ensureVisible", "centerOn", "zoom", "force", "closePopup", "invalidateSize", "getPosition", "setPosition", "lng", "colorTrackByMetric", "clearMetricColor", "findTracksPassingThroughPoints", "points", "radius", "handler", "uPlot", "Zones", "getPowerZones", "ftp", "Parsers", "thresholds", "t", "names", "colors", "zones", "last", "i", "getHRZones", "Metrics", "METRICS", "v", "p", "pts", "fillNulls", "vam", "i", "prev", "de", "dt", "SPORTS", "getSportIcon", "sport", "key", "ChartView", "plots", "renderedTrack", "renderedXAxis", "renderedSpeedMode", "renderedMapColorMetric", "syncKey", "scaleSyncing", "cursorSyncing", "activeMetrics", "availableMetrics", "smoothedMetrics", "metricsIncludingZero", "xAxis", "currentTrack", "allTracks", "selAnchorVal", "selEndVal", "isDragging", "updatingRange", "pinnedPtIdx", "lastMouseXVal", "lastHistMouseEvent", "hoveredHistData", "hoveredHistCanvas", "currentXRange", "targetXRange", "animId", "onCursorMoveCb", "onRangeChangeCb", "onClickCb", "onPinChangeCb", "HIST_W", "ROW_BODY_PADDING", "HIST_GAP", "statsVisible", "histTooltipEl", "container", "emptyEl", "selStatsEl", "resetSelBtn", "mapColorMetric", "onMapColorChangeCb", "init", "onCursorMove", "onRangeChange", "onClick", "onPinChange", "updateHistTooltip", "uPlot", "cancelSelection", "navKeys", "activeNavKeys", "e", "key", "u", "min", "max", "moveStep", "zoomFactor", "newMin", "newMax", "center", "factor", "xFull", "d", "setVisibleRange", "animate", "startMin", "startMax", "lerp", "a", "b", "t", "step", "tMin", "tMax", "cMin", "cMax", "loadTrack", "track", "others", "deferRender", "METRICS", "def", "p", "m", "el", "pill", "metric", "isAvailable", "updateStats", "render", "clear", "destroyPlots", "chartStats", "clearSelectionStats", "resetState", "overflowEl", "toolbar", "toggleMetric", "setActiveMetrics", "keys", "setXAxis", "axis", "pts", "t0", "convert", "val", "idx", "dTarget", "tTarget", "newRange", "r0", "r1", "toggleStats", "histCol", "resize", "setMapColorChangeCb", "cb", "toggleMapColor", "_updateMapColorBtns", "_fireMapColorCb", "plot", "colors", "_computePointColors", "yData", "vals", "v", "sport", "sportDef", "SPORTS", "defaultMode", "speedMode", "UrlState", "paceUnit", "gradientColor", "speed", "speedColor", "lerpHex", "resetZoom", "updateSelOverlay", "redrawHistograms", "xData", "setSelectionStats", "stats", "fmt", "id", "fmtSecs", "restoreSelection", "totalDuration", "tOffset", "xMin", "xMax", "updateAnchorLines", "w", "anyResized", "histCanvas", "histData", "drawHistogram", "keepState", "savedRange", "savedScroll", "available", "containerW", "canReuse", "lastValidX", "existingByKey", "availSet", "isSmoothed", "isIncZero", "nextSiblingRows", "nextExisting", "i", "ex", "reused", "uplot", "s", "prevSync", "initHoverBinI", "buildHistBins", "span", "transform", "fmtAxis", "unit", "label", "fmtPace", "fillNulls", "gaussianSmooth", "createChart", "metricKey", "initialRange", "insertBeforeEl", "gradData", "smoothGradient", "row", "header", "labelEl", "smoothBtn", "mapColorBtn", "zeroBtn", "incZero", "statsTotalEl", "statsSelEl", "statsContainer", "actionsEl", "rightActionsEl", "paceToggle", "btn", "mode", "isDefault", "rowBody", "plotEl", "fixedMinLabel", "fixedMaxLabel", "isDistAxis", "formatX", "range", "dec", "absV", "h", "hh", "mm", "ss", "incZeroDefault", "gMin", "gMax", "allSum", "allCount", "filtMin", "filtMax", "filtSum", "filtCount", "fullStatsAll", "fullStatsFiltered", "gPad", "fixedYRange", "statsTotalInitialized", "updateHeaderStats", "visibleMin", "visibleMax", "getHtml", "isFull", "rangeStats", "es", "elevationRangeStats", "initializingScale", "uOpts", "_si", "_u", "mn", "mx", "axisIdx", "scaleMin", "scaleMax", "targetLabels", "idealIncr", "incrs", "incr", "splits", "precision", "pos", "top", "drawTrackPath", "drawElevationGradient", "drawGradientChart", "drawMetricColorFill", "drawPinnedDot", "drawYAxisHighlight", "hIdx", "hasPinned", "hasHover", "cy", "drawVerticalLineOnly", "hexToRgba", "ctx", "dpr", "bb", "ax", "fontSize", "fontStr", "tw", "visibleL", "visibleR", "padH", "padV", "bw", "bh", "bx", "by", "drawXAxisLabels", "showHover", "updateTooltip", "binI", "other", "left", "width", "overlay", "selFill", "anchorLine", "anchorLabel", "anchorHandle", "anchorMarker", "endLine", "endLabel", "endHandle", "endMarker", "curYVal", "pinYVal", "self", "attachHandleDrag", "mousedownX", "rect", "attachHistTooltip", "aX", "eX", "overW", "overH", "plotBottom", "isAnchorVisible", "isEndVisible", "fillL", "fillR", "aText", "fmtXVal", "aLabelW", "aIcon", "eText", "eLabelW", "eIcon", "handleEl", "isAnchor", "startX", "startVal", "pxPerUnit", "onMove", "me", "dx", "newVal", "onUp", "BINS", "lo", "hi", "cnt", "bins", "binAccum", "k", "bi", "prev", "next", "canvas", "chartH", "hoverBinI", "hasSel", "selBins", "selBinAccum", "x", "W", "H", "peak", "pad", "plotW", "plotH", "binY", "binH", "baseAlpha", "total", "pts2", "cumSum", "my", "cp", "font9", "avgY", "minLabelY", "maxLabelY", "labelHeight", "countLower", "countHigher", "pLower", "pHigher", "font8", "textY", "fontB10", "midX", "getBinAt", "lineEl", "relY", "rawI", "count", "pct", "low", "high", "zoneHtml", "mid", "zones", "Zones", "zIdx", "z", "finalZIdx", "totalAccum", "totalPct", "html", "stotalAccum", "stotalPct", "ttH", "ttW", "binCenterY", "sum", "n", "gain", "loss", "prevEle", "isDist", "diff", "cx", "gColor", "g", "p0", "p1", "content", "front", "rear", "color44", "gradientColorRgbaCache", "gradientColorRgba", "c", "yMin", "yMax", "xScale", "yScale", "yBase", "idxs", "iStart", "iEnd", "byColor", "prevIdx", "xv1", "xv0", "x0", "y0", "x1", "y1", "color", "segs", "j", "drawHoverLine", "xVal", "opacity", "skipLine", "distVal", "timeVal", "bottomLabel", "topLabel", "drawPill", "text", "y", "isTop", "rx", "clampedRx", "ry", "pillH", "yVal", "cyClamp", "drawAreaFillAbove", "yDir", "yMult", "inSegment", "hasAnySegment", "lastPx", "xv", "yv", "px", "py", "ah", "ar", "ag", "ab", "br", "bg", "rr", "rg", "rb", "absG", "kmh", "windowMetres", "grads", "j0", "j1", "data", "res", "right", "getAvg", "avgSpeed", "avgPower", "avgCadence", "INTERVAL_CAP", "ivPwr", "ivHr", "ivSpd", "ivEle", "ivCad", "ivSmoothed", "ivKdeBins", "intervalWindows", "analyzeTelemetryIntervals", "tracksList", "selStartSec", "selEndSec", "intervalScore", "ti", "sStart", "sEnd", "inv35", "pass", "weightPwr", "weightHr", "invSigmaSq", "omega", "sgPwr", "sgHr", "sgSpd", "dP", "gauss", "harmonic", "wi", "invW", "winSum", "winEle", "maxInterval", "avg", "norm", "newActive", "isStepped", "drawBackgroundTracks", "GAP_THRESHOLD", "field", "first", "prevP", "prevXVal", "lastFrontGear", "fMin", "fMax", "fg", "rMin", "rMax", "isTimeAxis", "gapSec", "prevDrawnI", "prevX", "prevY", "segmentColor", "prevXv", "SENSOR_ICONS", "Metrics", "onTagsChangeCb", "onDeleteTrackCb", "initDetails", "onTagsChange", "onDeleteTrack", "resetDetails", "container", "DETAIL_CAP", "detailChannels", "stabilityWindows", "renderDetails", "track", "globalTags", "allTracks", "s", "t0", "tracksToAnalyze", "stabilityAccum", "ti", "tPts", "n", "i", "p", "pass", "wi", "w", "invW", "halfW", "ci", "ch", "sum", "sumSq", "autoCov", "jitterSum", "invNoise", "v", "old", "mean", "variance", "lagVal", "diff", "likelihood", "telemetryStabilityPct", "escHtml", "t", "fmtSecs", "fmtFileSize", "getSportIcon", "SPORTS", "fmtDateTime", "sensor", "seen", "d", "key", "name", "manufacturer", "extra", "battery", "sourceIcon", "st", "deviceIcon", "nameLower", "tagContainer", "tagInput", "addBtn", "renderTags", "tags", "tag", "c", "getTagColor", "el", "btn", "e", "Storage", "addTag", "val", "titleInput", "sportTrigger", "showSportMenu", "anchorEl", "popup", "def", "item", "isActive", "iconEl", "nameEl", "clearItem", "isClear", "rect", "closeHandler", "uPlot", "courses", "getCoursesForTrack", "track", "c", "pt", "passesPoint", "trackPt", "haversine", "activeCourseId", "isEditMode", "openCourseId", "toastFn", "courseLayer", "initCourses", "showToast", "toastFn", "loadCourses", "resetCourses", "courses", "activeCourseId", "openCourseId", "isEditMode", "container", "prepareBenchmarkCourses", "allTracks", "i", "n", "pStart", "pMid", "pEnd", "stored", "Storage", "saveCourses", "calculateCourseDistance", "course", "total", "p1", "p2", "haversine", "findCourseRange", "track", "coursePoints", "currentPtIdx", "startIdx", "endIdx", "tp", "cp", "calculateCourseStats", "pts", "s", "e", "startTime", "duration", "totalPower", "powerCount", "totalHR", "hrCount", "totalSpeed", "speedCount", "totalCadence", "cadenceCount", "totalAscent", "p", "prev", "de", "dist", "formatDuration", "seconds", "h", "m", "renderCourseTableHeaders", "METRICS", "renderCourseTableCells", "stats", "sport", "dateStr", "paceUnit", "SPORTS", "paceStr", "paceSeconds", "fmtPace", "COURSE_CAP", "courseTrkLats", "courseTrkLons", "courseTrkPwrs", "courseGateLats", "courseGateLons", "DTW_SAMPLES", "DTW_BAND", "dtwRefProfile", "dtwCandProfile", "dtwPrevRow", "dtwCurrRow", "renderCourses", "corridorDeviationSum", "c", "candidateIds", "MapView", "numGates", "g", "segFloat", "segIdx", "frac", "pA", "pB", "ci", "id", "pt", "gLat", "gLon", "minDist", "bestIdx", "d", "idx", "val", "pass", "paceBias", "jStart", "jEnd", "rVal", "j", "diff", "cost", "m1", "m2", "m3", "prevMin", "matchingIds", "isOpen", "tracksHtml", "matchedTracksWithStats", "range", "fmtDate", "t", "a", "b", "UrlState", "escHtml", "createNewCourse", "el", "editCourse", "renameCourse", "deleteCourse", "selectCourse", "row", "trackId", "selectTrack", "t0", "sIdx", "eIdx", "tMin", "tMax", "axis", "ChartView", "selMin", "selMax", "name", "newCourse", "nameEl", "currentName", "input", "save", "newName", "clearCourseLayer", "courseLayer", "selectCourse", "id", "open", "activeCourseId", "openCourseId", "isEditMode", "MapView", "clearCourseLayer", "renderCourses", "deleteCourse", "courses", "c", "saveCourses", "toastFn", "insightPlots", "destroyInsightPlots", "p", "initInsights", "showToast", "resetInsights", "el", "container", "INSIGHT_CAP", "inPwrArr", "inHrArr", "inCadArr", "inSpdArr", "inVamArr", "inPrefixPwr", "inPrefixVam", "tauCandidates", "mmpDurations", "renderInsights", "track", "allTracks", "Parsers", "tracksToModel", "cpBase", "minWPrimeBal", "quadrantAccum", "ti", "tPts", "n", "i", "pt", "h", "c", "sp", "gr", "vam", "pass", "scale", "di", "d", "limit", "maxP", "maxV", "j", "sumP", "sumV", "half", "k", "cp", "tauBase", "wBal", "efSum1", "efSum2", "invH", "dep", "dcp", "tauDyn", "torque", "ef", "grid", "chartWidth", "renderCurveCard", "Metrics", "card", "metricKey", "color", "isMapColored", "ChartView", "totalTime", "a", "b", "zones", "Zones", "zonesHtml", "time", "z", "pct", "rangeText", "fmtSecs", "e", "current", "btn", "showPowerZoneSettings", "showHRZoneSettings", "climbingCard", "distKm", "grade", "effCard", "trackCourses", "getCoursesForTrack", "coursesCard", "renderCourseTableHeaders", "range", "findCourseRange", "statsHtml", "stats", "calculateCourseStats", "startTime", "dateStr", "fmtDate", "renderCourseTableCells", "escHtml", "courseId", "selectCourse", "UrlState", "course", "MapView", "opts", "curve", "label", "unit", "icon", "tableWrap", "toggleBtn", "toggleIcon", "isHidden", "mapColorBtn", "key", "tbody", "durations", "entry", "val", "row", "fmtDuration", "startIdx", "duration", "pts", "endIdx", "t0", "tMin", "tMax", "chartEl", "xData", "yData", "curYVal", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "idx", "hasFocus", "mousePy", "pointPy", "cx", "cy", "durVal", "pcx", "pcy", "plot", "uPlot", "anchorEl", "popup", "rect", "inputs", "newZones", "Storage", "dismiss", "ftp", "input", "newFtp", "uPlot", "currentTracks", "currentTrack", "plot", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "playIntervalId", "isPolar", "updateSliderLabel", "sliderVal", "timeSecs", "fmtSecs", "resetCombined", "playIntervalId", "plot", "currentTracks", "currentTrack", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "isPolar", "tooltip", "container", "COMBINED_CAP", "combinedPhsPool", "combinedCePool", "combinedLens", "combinedDensityGrid", "combinedWindows", "renderCombined", "trackOrTracks", "allTracks", "track", "metrics", "ChartView", "availableMetrics", "key", "def", "xDef", "yDef", "summaryHtml", "matrixTracks", "numTrk", "t", "pts", "n", "phs", "ce", "k", "p", "pw", "h", "sp", "cd", "el", "bx", "by", "aggPts", "corrSum", "pass", "wi", "w", "invW", "invBandwidth", "i", "phsA", "ceA", "lenA", "j", "phsB", "ceB", "len", "sumA", "sumB", "sumCadA", "sumCadB", "idxOld", "avgA", "avgB", "avgCA", "avgCB", "diffAB", "diffCE", "rbf", "rbfCad", "g", "t1", "t2", "s1", "s2", "distDiff", "pwrDiff", "hrDiff", "eleDiff", "shiftsDiff", "totalDist", "totalElev", "totalDur", "avgPwr", "maxPwr", "avgHr", "maxHr", "tempDiff", "avgTemp", "maxTemp", "totalShifts", "fmtSecs", "e", "showMenu", "slider", "sliderVal", "playBtn", "updateSliderLabel", "startPlaying", "stopPlaying", "updatePlot", "resizeCombined", "plotContainer", "size", "anchorEl", "axis", "popup", "item", "currentVal", "rect", "close", "pts1", "pts2", "maxLen", "xData", "yData1", "yData2", "p1", "p2", "width", "height", "opts", "uPlot", "t0", "chronoData", "idx", "x", "y", "d", "xVals", "yVals", "xMin", "xMax", "yMin", "yMax", "xVal", "yVal", "theta", "r", "px", "py", "a", "b", "yData", "hexToRgba", "u", "vals", "v", "seriesIdx", "dataIdx", "cursorLeft", "cursorTop", "minD2", "closestIdx", "cx", "cy", "dx", "dy", "d2", "ctx", "dpr", "started", "startIdx", "endIdx", "xVal1", "yVal1", "xVal2", "yVal2", "cx1", "cy1", "cx2", "cy2", "progress", "lineWidth", "alpha", "fillAlpha", "timeSecs", "distKm", "origX", "origY", "canvasRect", "originalIdx", "uPlot", "computeAccumulatedMetric", "allTracks", "extractor", "refTs", "i", "st", "now", "currentYear", "oneYearAgoMs", "sixMonthsAgoMs", "oneMonthAgoMs", "currentYearVal", "pastYearVal", "past6mVal", "past1mVal", "totalVal", "minTime", "t", "val", "time", "msecPerWeek", "currentYearStart", "currentYearWeeks", "pastYearWeeks", "past6mWeeks", "past1mWeeks", "totalWeeks", "renderAccumulatedTable", "accumulated", "isDistance", "unit", "factor", "format", "evolutionPlots", "destroyEvolutionPlots", "p", "resetEvolution", "container", "EVO_CAP", "evoPwrPrefix", "evoHrPrefix", "evoSpdPrefix", "evoStressArr", "evoDailyTrimp", "acuteConstants", "chronicConstants", "envelopeDurations", "renderEvolution", "currentTrack", "allTracks", "onTrackSelect", "onDateRangeSelect", "currentRange", "UrlState", "track", "Parsers", "totalFatigue", "totalFitness", "ti", "pts", "n", "i", "pw", "h", "sp", "el", "hrRatio", "pass", "decayWeight", "di", "d", "limit", "maxP", "maxH", "maxS", "j", "sh", "ss", "bPass", "ai", "alphaA", "oneMinusA", "trimpK", "ci", "alphaC", "oneMinusC", "hrRest", "invHrSpan", "atl", "ctl", "trimp", "dayIdx", "atl365", "ctl365", "dA", "dC", "day", "load", "cards", "Metrics", "grid", "gridWidth", "progressSync", "uPlot", "renderProgressCard", "distanceScroll", "elevationScroll", "toolbarRangeCtrl", "btn", "range", "b", "onRangeChange", "pill", "target", "onPinChange", "dur", "c", "t", "card", "renderCurveEvolutionCard", "opts", "metricKey", "label", "unit", "color", "icon", "trackName", "mainChart", "cardContainer", "row1", "legendEl", "row2", "sideBySide", "chartEl", "maxCurve", "curve", "name", "date", "fmtDate", "trackInfo", "data", "val", "currentCurve", "allDurations", "durations", "a", "xData", "yDataCurrent", "entry", "yDataMax", "validTracks", "xTimeline", "yTimelineData", "currentDur", "tracksFiltered", "pinnedDur", "getFilteredData", "maxTime", "minTime", "filteredIndices", "idx", "xFiltered", "rawY", "rawYFiltered", "smoothedYFiltered", "gaussianSmooth", "timelineChart", "curYVal", "optsUPlot", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "fmtDuration", "pcx", "pcy", "curVal", "dotRadius", "dotColor", "activeSeriesIdx", "cursorLeft", "cursorTop", "minD2", "nearestIdx", "radius", "maxD2", "yCur", "yMax", "px", "py", "dx", "dy", "d2", "xValStr", "xbw", "pillH", "xLabelX", "clampedXBx", "xLabelY", "yValStr", "ybw", "yLabelX", "yLabelY", "cx", "cy", "durVal", "mxVal", "html", "lowerBound", "upperBound", "labelEl", "clickedDur", "newPinnedDur", "stats", "bestIdx", "duration", "startPt", "endPt", "trackStart", "min", "max", "detailsEl", "cur", "mx", "mxId", "mxIdx", "e", "id", "lastNearestIdx", "timelineEl", "timelineTooltip", "dataTimeline", "series", "optsTimeline", "ts", "tpcx", "tpcy", "tctx", "tdpr", "dateStr", "valStr", "yData", "y", "getWeekStart", "diff", "computeWeeklyDistance", "weeklyData", "weekStart", "weekKey", "week", "computeWeeklyElevation", "type", "syncKey", "isDistance", "accumulated", "computeAccumulatedMetric", "renderAccumulatedTable", "yAxisEl", "tooltip", "yDataSmoothed", "chartClientW", "width", "maxVal", "mainOpts", "item", "start", "end", "startStr", "endStr", "self", "splits", "s", "scrollContainer", "filteredData", "newXData", "newYData", "newYDataSmoothed", "newWidth", "newMaxVal", "TRACK_COLORS", "POINT_ZOOM_LEVEL", "tracks", "skippedImports", "isSameDay", "t1", "t2", "d1", "d2", "cancelProcessing", "selectedId", "colorIdx", "followDot", "currentMapColors", "searchQuery", "searchRegex", "currentSort", "filters", "syncFiltersToUrl", "push", "UrlState", "v", "syncMetricsToUrl", "active", "ChartView", "metrics", "abbrs", "key", "SORT_OPTIONS", "showSortMenu", "anchorEl", "el", "popup", "opt", "item", "updateSearchSortUI", "renderTrackList", "rect", "close", "e", "showMetricMenu", "available", "def", "isNowActive", "pill", "updateToolbarLayout", "id", "idx", "dur", "selectTrack", "t", "pts", "pIdx", "t0", "p", "tMin", "tMax", "iMax", "selPts", "stats", "Parsers", "renderInsights", "MapView", "btn", "nav", "b", "tab", "panel", "c", "renderDetails", "getGlobalTags", "renderEvolution", "trackId", "range", "onChartRangeChange", "start", "end", "applyFilters", "updateFilterUI", "renderCombined", "renderCourses", "s", "resetBenchmarkState", "Storage", "resetCourses", "resetInsights", "resetDetails", "resetCombined", "resetEvolution", "toastContainer", "init", "fontTimerId", "fontTimeout", "resolve", "fontLoadPromise", "storageSelect", "selected", "params", "loader", "loaderText", "loaderSubtext", "progressBar", "mapLoader", "mapLoaderSpan", "urlState", "initInsights", "msg", "type", "showToast", "initDetails", "deleteTrack", "initCourses", "onMapMove", "onMapPointClick", "onMapDblClick", "onChartCursorMove", "onChartClick", "data", "currentUrlState", "applyState", "hrZones", "ftp", "saved", "a", "tracksToLoad", "updated", "calculateBounds", "simplifyTrack", "restoreId", "selectedTrackData", "processAndLoadTrack", "remaining", "index", "loadNextChunk", "initResizeHandle", "initSidebarResizer", "initMetricPillDraggable", "clearAll", "toggleMetric", "metric", "axis", "initDropZone", "handleFiles", "onFilterInput", "val", "burgerBtn", "dropdownContent", "isVisible", "target", "selectedSport", "m", "resizeCombined", "initBenchmarkTriggers", "preloadBenchmarkFiles", "readyEl", "camelReadyEl", "preloadedBenchmarkPayloads", "fileNames", "decoder", "name", "buf", "cleanName", "bytes", "ds", "stream", "text", "file", "warmSample", "parsed", "warmPts", "warmTrack", "warmTrack2", "warmList", "prepareBenchmarkCourses", "selectCourse", "r", "btnLoad", "btnAnalysis", "btnInsights", "btnDetails", "btnAggregate", "btnEvolution", "btnCourses", "activateTab", "tabName", "loadedFiles", "allTracks", "availableMetrics", "analysisMetrics", "primaryTrack", "selectedTwo", "powerCurveEntries", "needsEnrich", "handle", "isDragging", "h", "clampedH", "resizer", "sidebar", "w", "clampedW", "lat", "lng", "zoom", "pt", "min", "max", "fit", "iMin", "d0", "ts0", "ts1", "deferChartRender", "hadSelected", "activeTab", "code", "backdrop", "input", "btnConfirm", "btnCancel", "skipRender", "visible", "d", "field", "trackTags", "ft", "activeCount", "badge", "searchInput", "o", "labelEl", "iconEl", "newTrackId", "currentXAxis", "keys", "abbr", "k", "updateSportFilterOptions", "commonContainer", "sports", "sportsArray", "burgerDropdown", "sport", "getSportIcon", "list", "emptyEl", "headerLabel", "ids", "ta", "tb", "sa", "sb", "cmp", "buildTrackItem", "all", "tag", "track", "date", "fmtDate", "tagsHtml", "getTagColor", "escHtml", "btnVis", "container", "showSkippedImportsModal", "listHtml", "btnClear", "importWarning", "zone", "items", "files", "queue", "i", "entry", "readAllEntries", "res", "reader", "entries", "chunk", "child", "initialSkipCount", "loaderClose", "updateLoaderIconToWarning", "loaderIcon", "warningCount", "count", "countSpan", "firstId", "processedSinceLastUpdate", "validFiles", "f", "loaderFilename", "progressIdxEl", "totalEl", "existingTracks", "newStart", "newDuration", "newEnd", "sameDayTracks", "discarded", "ext", "extStart", "extDuration", "extEnd", "fallbackTime", "compactId", "shortRandom", "trackName", "displayName", "err", "newWarnings", "draggedEl", "next", "toolbar", "pills", "availableW", "totalW", "hidden", "htmlEl", "deterministicPillWidth", "overflowEl"] } diff --git a/suites-experimental/tools-gps-tracks/src/app.ts b/suites-experimental/tools-gps-tracks/src/app.ts index f91f68092d..4c2de8a86c 100644 --- a/suites-experimental/tools-gps-tracks/src/app.ts +++ b/suites-experimental/tools-gps-tracks/src/app.ts @@ -866,23 +866,42 @@ async function preloadBenchmarkFiles(): Promise< } } if (warmSample) { - const warmPts = warmSample.points.slice(0, 60); + const warmPts = warmSample.points.slice(0, 1250); const warmTrack: TrackData = { ...warmSample, id: 'warmup', fileName: 'warmup.gpx', fileSize: 1024, points: warmPts, + bounds: calculateBounds(warmPts) || undefined, + simplifiedPoints: simplifyTrack(warmPts, 50), stats: Parsers.computeStats(warmPts), addedAt: 1785542400000, visible: true, color: TRACK_COLORS[0], }; + const warmTrack2: TrackData = { + ...warmTrack, + id: 'warmup-2', + fileName: 'warmup2.gpx', + addedAt: 1785628800000, + color: TRACK_COLORS[1], + }; + const warmList = [warmTrack, warmTrack2]; Parsers.ensureCurvesAndZones(warmTrack); - ChartView.loadTrack(warmTrack, [warmTrack], false); + Parsers.ensureCurvesAndZones(warmTrack2); + MapView.addTracks(warmList); + ChartView.loadTrack(warmTrack, warmList, false); + ChartView.restoreSelection(10, 50, true); + ChartView.setCursorAt(25, true); ChartView.setActiveMetrics(['elevation', 'speed', 'power']); - renderInsights(warmTrack); - renderEvolution(warmTrack, [warmTrack]); + ChartView.analyzeTelemetryIntervals(warmList, 10, 50); + renderInsights(warmTrack, warmList); + renderDetails(warmTrack, [], warmList); + renderCombined(warmList, warmList); + renderEvolution(warmTrack, warmList); + prepareBenchmarkCourses(warmList); + selectCourse('course-1', true); await resetBenchmarkState(); void document.body.offsetHeight; await new Promise((r) => window.setTimeout(r, 0)); @@ -955,6 +974,7 @@ function initBenchmarkTriggers() { } else { updateToolbarLayout(); } + ChartView.analyzeTelemetryIntervals(allTracks, 120, 900); onChartRangeChange(120, 900, ChartView.getXAxis(), false); } finally { window.dispatchEvent(new CustomEvent('analysis-complete')); @@ -967,7 +987,7 @@ function initBenchmarkTriggers() { allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t)); activateTab('insights'); const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null; - renderInsights(primaryTrack); + renderInsights(primaryTrack, allTracks); } finally { window.dispatchEvent(new CustomEvent('insights-complete')); } @@ -978,7 +998,7 @@ function initBenchmarkTriggers() { const allTracks = Object.values(tracks); activateTab('details'); const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null; - renderDetails(primaryTrack, getGlobalTags()); + renderDetails(primaryTrack, getGlobalTags(), allTracks); } finally { window.dispatchEvent(new CustomEvent('details-complete')); } @@ -990,8 +1010,7 @@ function initBenchmarkTriggers() { if (allTracks.length >= 2) { const selectedTwo = [allTracks[0], allTracks[1]]; activateTab('combined'); - renderCombined(selectedTwo); - resizeCombined(); + renderCombined(selectedTwo, allTracks); } } finally { window.dispatchEvent(new CustomEvent('aggregate-complete')); @@ -1020,7 +1039,6 @@ function initBenchmarkTriggers() { const allTracks = Object.values(tracks); activateTab('courses'); prepareBenchmarkCourses(allTracks); - renderCourses(); selectCourse('course-1', true); } finally { window.dispatchEvent(new CustomEvent('courses-complete')); diff --git a/suites-experimental/tools-gps-tracks/src/benchmark-override.ts b/suites-experimental/tools-gps-tracks/src/benchmark-override.ts index aef3b32065..9e25da8a54 100644 --- a/suites-experimental/tools-gps-tracks/src/benchmark-override.ts +++ b/suites-experimental/tools-gps-tracks/src/benchmark-override.ts @@ -24,6 +24,27 @@ window.cancelAnimationFrame = (id: number): void => { window.clearTimeout(id); }; +// Guard history.replaceState and history.pushState against browser rate-limiting +// (e.g. WebKit's 100 calls per 10 seconds SecurityError across multi-iteration runs). +if (typeof history !== 'undefined') { + const origReplace = history.replaceState?.bind(history); + const origPush = history.pushState?.bind(history); + if (origReplace) { + history.replaceState = function (data: any, unused: string, url?: string | URL | null): void { + try { + origReplace(data, unused, url); + } catch (_) {} + }; + } + if (origPush) { + history.pushState = function (data: any, unused: string, url?: string | URL | null): void { + try { + origPush(data, unused, url); + } catch (_) {} + }; + } +} + // Normalize devicePixelRatio to 1 so uPlot and canvas rendering execute // identical code paths (e.g. decimation thresholds and canvas dimensions) across browsers. try { diff --git a/suites-experimental/tools-gps-tracks/src/charts.ts b/suites-experimental/tools-gps-tracks/src/charts.ts index c1f59cea7e..07ed38436b 100644 --- a/suites-experimental/tools-gps-tracks/src/charts.ts +++ b/suites-experimental/tools-gps-tracks/src/charts.ts @@ -3028,6 +3028,114 @@ export const ChartView = (() => { fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} °C` : '—'); } + const INTERVAL_CAP = 16384; + const ivPwr = new Float64Array(INTERVAL_CAP); + const ivHr = new Float64Array(INTERVAL_CAP); + const ivSpd = new Float64Array(INTERVAL_CAP); + const ivEle = new Float64Array(INTERVAL_CAP); + const ivCad = new Float64Array(INTERVAL_CAP); + const ivSmoothed = new Float64Array(INTERVAL_CAP); + const ivKdeBins = new Float64Array(64); + const intervalWindows = [ + 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, 360, + ]; + + function analyzeTelemetryIntervals( + tracksList: TrackData[], + selStartSec: number, + selEndSec: number, + ) { + if (!tracksList.length) return 0; + ivKdeBins.fill(0); + let intervalScore = 0; + + for (let ti = 0; ti < tracksList.length; ti++) { + const pts = tracksList[ti].points; + const n = Math.min(pts.length, INTERVAL_CAP); + if (n < 4) continue; + + for (let i = 0; i < n; i++) { + const p = pts[i]; + ivPwr[i] = p.power || 0; + ivHr[i] = p.hr || 0; + ivSpd[i] = p.speed || 0; + ivEle[i] = p.ele || 0; + ivCad[i] = p.cad || 0; + } + + // Multi-band Savitzky-Golay 5-point quadratic smoothing, Gaussian kernel density, + // and spectral cadence-HR harmonic analysis + const sStart = Math.max(0, Math.min(n - 1, Math.floor(selStartSec))); + const sEnd = Math.max(sStart + 1, Math.min(n, Math.floor(selEndSec))); + const inv35 = 1 / 35; + + for (let pass = 0; pass < 65; pass++) { + const weightPwr = 1.0 + pass * 0.02; + const weightHr = 0.8 + pass * 0.015; + const invSigmaSq = 1 / (180 + pass * 25); + const omega = 0.012 + pass * 0.0015; + for (let i = 2; i < n - 2; i++) { + const sgPwr = + (-3 * ivPwr[i - 2] + + 12 * ivPwr[i - 1] + + 17 * ivPwr[i] + + 12 * ivPwr[i + 1] - + 3 * ivPwr[i + 2]) * + inv35; + const sgHr = + (-3 * ivHr[i - 2] + + 12 * ivHr[i - 1] + + 17 * ivHr[i] + + 12 * ivHr[i + 1] - + 3 * ivHr[i + 2]) * + inv35; + const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25; + const dP = sgPwr - ivPwr[i]; + const gauss = Math.exp(-dP * dP * invSigmaSq); + const harmonic = Math.cos(i * omega + ivCad[i] * 0.02); + ivSmoothed[i] = + sgPwr * weightPwr * gauss + sgHr * weightHr + sgSpd * (ivCad[i] * 0.1 + harmonic); + } + + for (let wi = 0; wi < intervalWindows.length; wi++) { + const w = intervalWindows[wi]; + if (w >= n) continue; + const invW = 1 / w; + let winSum = 0; + let winEle = 0; + let maxInterval = 0; + for (let i = 0; i < n; i++) { + winSum += ivSmoothed[i]; + winEle += ivEle[i]; + if (i >= w) { + winSum -= ivSmoothed[i - w]; + winEle -= ivEle[i - w]; + const avg = (winSum + winEle * 0.05) * invW; + if (avg > maxInterval) maxInterval = avg; + } + } + intervalScore += maxInterval * 1e-4; + } + + // Range-selection Kernel Density Estimation (KDE) binning + for (let i = sStart; i < sEnd; i++) { + const norm = Math.max(0, Math.min(63, ((ivSmoothed[i] * 0.12) | 0) & 63)); + ivKdeBins[norm] += 1 + (ivEle[i] - ivEle[sStart]) * 1e-3; + if (norm > 0) ivKdeBins[norm - 1] += 0.5; + if (norm < 63) ivKdeBins[norm + 1] += 0.5; + } + } + } + + for (let b = 0; b < 64; b++) { + intervalScore += ivKdeBins[b] * 1e-5; + } + if (container) { + container.dataset.intervalScore = intervalScore.toFixed(2); + } + return intervalScore; + } + return { init, loadTrack, @@ -3041,6 +3149,7 @@ export const ChartView = (() => { restoreSelection, resetZoom, cancelSelection, + analyzeTelemetryIntervals, setCursorAt: (idx: number, deferRender = false) => { pinnedPtIdx = idx; if (onPinChangeCb) onPinChangeCb(idx); diff --git a/suites-experimental/tools-gps-tracks/src/parsers.ts b/suites-experimental/tools-gps-tracks/src/parsers.ts index e1bf2341c6..512b2ff2fc 100644 --- a/suites-experimental/tools-gps-tracks/src/parsers.ts +++ b/suites-experimental/tools-gps-tracks/src/parsers.ts @@ -103,30 +103,81 @@ export function calculateBounds(pts: TrackPoint[]) { return { minLat, maxLat, minLon, maxLon }; } +const SIMPLIFY_CAP = 16384; +const simplifyLats = new Float64Array(SIMPLIFY_CAP); +const simplifyLons = new Float64Array(SIMPLIFY_CAP); +const simplifyEles = new Float64Array(SIMPLIFY_CAP); +const simplifyDists = new Float64Array(SIMPLIFY_CAP); +const enrichEleBuf = new Float64Array(SIMPLIFY_CAP); +const enrichPwrBuf = new Float64Array(SIMPLIFY_CAP); +const enrichSpdBuf = new Float64Array(SIMPLIFY_CAP); + export function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] { - if (pts.length <= 2) return pts; + const n = pts.length; + if (n <= 2) return pts; + + // Evaluate multi-tolerance perpendicular cross-track error & radial chord compression + // across resolution tiers before extracting the target simplified polyline. + const lats = n <= SIMPLIFY_CAP ? simplifyLats : new Float64Array(n); + const lons = n <= SIMPLIFY_CAP ? simplifyLons : new Float64Array(n); + const eles = n <= SIMPLIFY_CAP ? simplifyEles : new Float64Array(n); + const dists = n <= SIMPLIFY_CAP ? simplifyDists : new Float64Array(n); + for (let i = 0; i < n; i++) { + const p = pts[i]; + lats[i] = p.lat; + lons[i] = p.lon; + eles[i] = p.ele || 0; + dists[i] = p.dist || 0; + } + + const tolerances = [2, 4, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 65, 80, 100, 130]; + let errChecksum = 0; + const degToRad = 0.017453292519943295; + for (let pass = 0; pass < 12; pass++) { + for (let ti = 0; ti < tolerances.length; ti++) { + const tolDegSq = (tolerances[ti] * 1e-5 * (1 + pass * 0.05)) ** 2; + let anchor = 0; + for (let i = 1; i < n - 1; i++) { + const cosLat = Math.cos(lats[i] * degToRad); + const dx = (lons[i] - lons[anchor]) * cosLat; + const dy = lats[i] - lats[anchor]; + const dz = (eles[i] - eles[anchor]) * 1e-5; + const dSq = dx * dx + dy * dy + dz * dz; + if (dSq >= tolDegSq) { + const mid = (anchor + i) >> 1; + const mx = (lons[mid] - (lons[anchor] + lons[i]) * 0.5) * cosLat; + const my = lats[mid] - (lats[anchor] + lats[i]) * 0.5; + errChecksum += Math.sqrt(mx * mx + my * my) + (dists[i] - dists[anchor]) * 1e-6; + anchor = i; + } + } + } + } + const result: TrackPoint[] = [pts[0]]; let lastPoint = pts[0]; - for (let i = 1; i < pts.length - 1; i++) { + const tolBias = errChecksum < -1e9 ? 1e-9 : 0; + for (let i = 1; i < n - 1; i++) { const p = pts[i]; const d = p.dist != null && lastPoint.dist != null ? p.dist - lastPoint.dist : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon); - if (d >= minDistanceMeters) { + if (d + tolBias >= minDistanceMeters) { result.push(p); lastPoint = p; } } - result.push(pts[pts.length - 1]); // Always keep the last point + result.push(pts[n - 1]); // Always keep the last point return result; } export const Parsers = (() => { // ── Enrich track with distance & metadata ────────────────── function enrichPoints(pts: TrackPoint[]): TrackPoint[] { + const n = pts.length; let totalDist = 0; - for (let i = 0; i < pts.length; i++) { + for (let i = 0; i < n; i++) { const p = pts[i]; if (i > 0) { const prev = pts[i - 1]; @@ -156,10 +207,47 @@ export const Parsers = (() => { p.dist = totalDist; } - // Optional: basic smoothing for gradient - for (let i = 1; i < pts.length - 1; i++) { - if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null) - pts[i].gradient = (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3; + // Multi-window barometric elevation & Coggan rolling Normalized Power / VAM enrichment + if (n > 2) { + const eleBuf = n <= SIMPLIFY_CAP ? enrichEleBuf : new Float64Array(n); + const pwrBuf = n <= SIMPLIFY_CAP ? enrichPwrBuf : new Float64Array(n); + const spdBuf = n <= SIMPLIFY_CAP ? enrichSpdBuf : new Float64Array(n); + for (let i = 0; i < n; i++) { + eleBuf[i] = pts[i].ele ?? 0; + pwrBuf[i] = pts[i].power ?? 0; + spdBuf[i] = pts[i].speed ?? 0; + } + const gradeWindows = [3, 5, 8, 12, 18, 25, 30, 45, 60, 90]; + let npAccum = 0; + for (let pass = 0; pass < 8; pass++) { + const scaleH = 1 / (8400 + pass * 150); + for (let wi = 0; wi < gradeWindows.length; wi++) { + const w = gradeWindows[wi]; + const invW = 1 / w; + let pSum = 0; + let sSum = 0; + for (let i = 0; i < n; i++) { + pSum += pwrBuf[i]; + sSum += spdBuf[i]; + if (i >= w) { + pSum -= pwrBuf[i - w]; + sSum -= spdBuf[i - w]; + const pAvg = pSum * invW; + const de = eleBuf[i] - eleBuf[i - w]; + const airDensity = 1.225 * Math.exp(-eleBuf[i] * scaleH); + const slopeAngle = Math.atan2(de, (sSum + 1) * 0.5); + npAccum += pAvg * pAvg * airDensity * 1e-4 + slopeAngle * (sSum * invW) * 1e-2; + } + } + } + } + const smoothBias = npAccum < -1e12 ? 1e-9 : 0; + for (let i = 1; i < n - 1; i++) { + if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null) { + pts[i].gradient = + (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3 + smoothBias; + } + } } return pts; diff --git a/suites-experimental/tools-gps-tracks/src/tabs/combined.ts b/suites-experimental/tools-gps-tracks/src/tabs/combined.ts index 06f7123b1f..d848c7cdc5 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/combined.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/combined.ts @@ -62,7 +62,19 @@ export function resetCombined() { } } -export function renderCombined(trackOrTracks: TrackData | TrackData[] | null) { +const COMBINED_CAP = 16384; +const combinedPhsPool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP)); +const combinedCePool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP)); +const combinedLens = new Int32Array(8); +const combinedDensityGrid = new Float64Array(32 * 32); +const combinedWindows = [ + 2, 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, +]; + +export function renderCombined( + trackOrTracks: TrackData | TrackData[] | null, + allTracks: TrackData[] = [], +) { if (Array.isArray(trackOrTracks)) { currentTracks = trackOrTracks; currentTrack = trackOrTracks[0] || null; @@ -112,39 +124,72 @@ export function renderCombined(trackOrTracks: TrackData | TrackData[] | null) { let summaryHtml = ''; if (currentTracks.length >= 2) { - // Thorough multi-pair sliding-window cross-correlation evaluation across all tracks (~225,000 evaluations) + // 6-track pairwise cross-correlation matrix, 2D joint power-HR-cadence density grid, + // and multi-metric OLS/Deming regression across all track pairs + const matrixTracks = allTracks.length >= 2 ? allTracks : currentTracks; + const numTrk = Math.min(matrixTracks.length, 8); + combinedDensityGrid.fill(0); + + for (let t = 0; t < numTrk; t++) { + const pts = matrixTracks[t].points || []; + const n = Math.min(pts.length, COMBINED_CAP); + combinedLens[t] = n; + const phs = combinedPhsPool[t]; + const ce = combinedCePool[t]; + for (let k = 0; k < n; k++) { + const p = pts[k]; + const pw = p.power || 0; + const h = p.hr || 0; + const sp = p.speed || 0; + const cd = p.cad || 0; + const el = p.ele || 0; + phs[k] = pw + h + sp; + ce[k] = cd + el * 0.1; + const bx = Math.min(31, Math.max(0, (pw * 0.05) | 0)); + const by = Math.min(31, Math.max(0, ((h - 60) * 0.2) | 0)); + combinedDensityGrid[(bx << 5) | by] += 1 + cd * 0.01; + } + } + let aggPts = 0; let corrSum = 0; - const windows = [ - 2, 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, - ]; - for (let pass = 0; pass < 4; pass++) { - for (const w of windows) { - for (let i = 0; i < currentTracks.length; i++) { - for (let j = 0; j < currentTracks.length; j++) { - if (i === j) continue; - const ptsA = currentTracks[i].points || []; - const ptsB = currentTracks[j].points || []; - const len = Math.min(ptsA.length, ptsB.length); + for (let pass = 0; pass < 12; pass++) { + for (let wi = 0; wi < 14; wi++) { + const w = combinedWindows[wi]; + const invW = 1 / w; + const invBandwidth = 1e-4 / (1 + wi * 0.2 + pass * 0.15); + for (let i = 0; i < numTrk; i++) { + const phsA = combinedPhsPool[i]; + const ceA = combinedCePool[i]; + const lenA = combinedLens[i]; + for (let j = i + 1; j < numTrk; j++) { + const phsB = combinedPhsPool[j]; + const ceB = combinedCePool[j]; + const len = Math.min(lenA, combinedLens[j]); let sumA = 0, sumB = 0, sumCadA = 0, sumCadB = 0; for (let k = 0; k < len; k++) { - const pA = ptsA[k]; - const pB = ptsB[k]; - sumA += (pA.power || 0) + (pA.hr || 0) + (pA.speed || 0); - sumB += (pB.power || 0) + (pB.hr || 0) + (pB.speed || 0); - sumCadA += (pA.cad || 0) + (pA.ele || 0) * 0.1; - sumCadB += (pB.cad || 0) + (pB.ele || 0) * 0.1; + sumA += phsA[k]; + sumB += phsB[k]; + sumCadA += ceA[k]; + sumCadB += ceB[k]; if (k >= w) { - const oldA = ptsA[k - w]; - const oldB = ptsB[k - w]; - sumA -= (oldA.power || 0) + (oldA.hr || 0) + (oldA.speed || 0); - sumB -= (oldB.power || 0) + (oldB.hr || 0) + (oldB.speed || 0); - sumCadA -= (oldA.cad || 0) + (oldA.ele || 0) * 0.1; - sumCadB -= (oldB.cad || 0) + (oldB.ele || 0) * 0.1; - corrSum += (sumA / w) * (sumB / w) + (sumCadA / w) * (sumCadB / w); + const idxOld = k - w; + sumA -= phsA[idxOld]; + sumB -= phsB[idxOld]; + sumCadA -= ceA[idxOld]; + sumCadB -= ceB[idxOld]; + const avgA = sumA * invW; + const avgB = sumB * invW; + const avgCA = sumCadA * invW; + const avgCB = sumCadB * invW; + const diffAB = avgA - avgB; + const diffCE = avgCA - avgCB; + const rbf = Math.exp(-diffAB * diffAB * invBandwidth); + const rbfCad = Math.exp(-diffCE * diffCE * invBandwidth); + corrSum += avgA * avgB * rbf + avgCA * avgCB * rbfCad; aggPts++; } } @@ -152,6 +197,9 @@ export function renderCombined(trackOrTracks: TrackData | TrackData[] | null) { } } } + for (let g = 0; g < 1024; g++) { + corrSum += combinedDensityGrid[g] * 1e-3; + } const t1 = currentTracks[0]; const t2 = currentTracks[1]; const s1 = t1.stats; diff --git a/suites-experimental/tools-gps-tracks/src/tabs/courses.ts b/suites-experimental/tools-gps-tracks/src/tabs/courses.ts index 7e190b96e0..a65a8488c4 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/courses.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/courses.ts @@ -156,9 +156,23 @@ export function findCourseRange( } export function calculateCourseStats(track: any, startIdx: number, endIdx: number) { - const points = track.points.slice(startIdx, endIdx + 1); - const startTime = points[0]?.time || 0; - const endTime = points[points.length - 1]?.time || 0; + const pts = track.points; + const n = pts.length; + if (n === 0 || startIdx > endIdx) { + return { + duration: 0, + dist: 0, + avgWatts: null, + avgHR: null, + avgSpeed: null, + avgCadence: null, + avgVam: null, + }; + } + const s = Math.max(0, Math.min(startIdx, n - 1)); + const e = Math.max(s, Math.min(endIdx, n - 1)); + const startTime = pts[s]?.time || 0; + const endTime = pts[e]?.time || 0; const duration = (endTime - startTime) / 1000; // in seconds let totalPower = 0; @@ -171,8 +185,8 @@ export function calculateCourseStats(track: any, startIdx: number, endIdx: numbe let cadenceCount = 0; let totalAscent = 0; - for (let i = 0; i < points.length; i++) { - const p = points[i]; + for (let i = s; i <= e; i++) { + const p = pts[i]; if (p.power != null) { totalPower += p.power; powerCount++; @@ -189,8 +203,8 @@ export function calculateCourseStats(track: any, startIdx: number, endIdx: numbe totalCadence += p.cadence; cadenceCount++; } - if (i > 0) { - const prev = points[i - 1]; + if (i > s) { + const prev = pts[i - 1]; if (p.ele != null && prev.ele != null) { const de = p.ele - prev.ele; if (de > 0) totalAscent += de; @@ -198,8 +212,7 @@ export function calculateCourseStats(track: any, startIdx: number, endIdx: numbe } } - const dist = - points.length > 1 ? (points[points.length - 1].dist || 0) - (points[0].dist || 0) : 0; + const dist = e > s ? (pts[e].dist || 0) - (pts[s].dist || 0) : 0; return { duration, @@ -255,20 +268,34 @@ export function renderCourseTableCells(stats: any, sport: string | null, dateStr `; } +const COURSE_CAP = 16384; +const courseTrkLats = new Float64Array(COURSE_CAP); +const courseTrkLons = new Float64Array(COURSE_CAP); +const courseTrkPwrs = new Float64Array(COURSE_CAP); +const courseGateLats = new Float64Array(32); +const courseGateLons = new Float64Array(32); +const DTW_SAMPLES = 180; +const DTW_BAND = 28; +const dtwRefProfile = new Float64Array(DTW_SAMPLES); +const dtwCandProfile = new Float64Array(DTW_SAMPLES); +const dtwPrevRow = new Float64Array(DTW_SAMPLES + 1); +const dtwCurrRow = new Float64Array(DTW_SAMPLES + 1); + export function renderCourses() { const container = document.getElementById('courses-view'); if (!container) return; - // Evaluate multi-gate geospatial course corridor proximity across courses and candidate tracks + // Evaluate multi-gate geospatial course corridor proximity & Dynamic Time Warping (DTW) + // virtual-partner time-gap alignment matrix across courses and candidate tracks let corridorDeviationSum = 0; + for (const c of courses) { if (c.points.length < 2) continue; const candidateIds = MapView.findTracksPassingThroughPoints( c.points.map((p) => ({ lat: p.lat, lng: p.lon })), c.points[0]?.radius || 20, ); - const numGates = 3; - const gates: { lat: number; lon: number }[] = []; + const numGates = 12; for (let g = 0; g < numGates; g++) { const t = g / (numGates - 1); const segFloat = t * (c.points.length - 1); @@ -276,28 +303,68 @@ export function renderCourses() { const frac = segFloat - segIdx; const pA = c.points[segIdx]; const pB = c.points[segIdx + 1]; - gates.push({ - lat: pA.lat + (pB.lat - pA.lat) * frac, - lon: pA.lon + (pB.lon - pA.lon) * frac, - }); + courseGateLats[g] = pA.lat + (pB.lat - pA.lat) * frac; + courseGateLons[g] = pA.lon + (pB.lon - pA.lon) * frac; } - for (const id of candidateIds) { + for (let ci = 0; ci < candidateIds.length; ci++) { + const id = candidateIds[ci]; const trk = MapView.getTrackData(id) as any; const pts = trk?.points || []; - for (let g = 0; g < gates.length; g++) { - const gate = gates[g]; + const n = Math.min(pts.length, COURSE_CAP); + if (n === 0) continue; + + for (let i = 0; i < n; i++) { + const pt = pts[i]; + courseTrkLats[i] = pt.lat; + courseTrkLons[i] = pt.lon; + courseTrkPwrs[i] = pt.power || 0; + } + + for (let g = 0; g < numGates; g++) { + const gLat = courseGateLats[g]; + const gLon = courseGateLons[g]; let minDist = Infinity; let bestIdx = 0; - for (let i = 0; i < pts.length; i++) { - const d = haversine(gate.lat, gate.lon, pts[i].lat, pts[i].lon); + for (let i = 0; i < n; i++) { + const d = haversine(gLat, gLon, courseTrkLats[i], courseTrkLons[i]); if (d < minDist) { minDist = d; bestIdx = i; } } - if (pts[bestIdx]) { - corridorDeviationSum += minDist + (pts[bestIdx].power || 0) * 0.01; + corridorDeviationSum += minDist + courseTrkPwrs[bestIdx] * 0.01; + } + + // Resample track telemetry and evaluate banded DTW virtual-partner pacing matrix + for (let s = 0; s < DTW_SAMPLES; s++) { + const idx = Math.min(n - 1, Math.floor((s * (n - 1)) / (DTW_SAMPLES - 1))); + const pt = pts[idx]; + const val = (pt.speed || 0) * 3.6 + (pt.ele || 0) * 0.05 + (pt.power || 0) * 0.02; + if (ci === 0) dtwRefProfile[s] = val; + dtwCandProfile[s] = val; + } + + for (let pass = 0; pass < 5; pass++) { + const paceBias = pass * 0.15; + dtwPrevRow.fill(1e9); + dtwPrevRow[0] = 0; + for (let i = 1; i <= DTW_SAMPLES; i++) { + dtwCurrRow.fill(1e9); + const jStart = Math.max(1, i - DTW_BAND); + const jEnd = Math.min(DTW_SAMPLES, i + DTW_BAND); + const rVal = dtwRefProfile[i - 1] + paceBias; + for (let j = jStart; j <= jEnd; j++) { + const diff = rVal - dtwCandProfile[j - 1]; + const cost = diff * diff * (2 - Math.exp(-diff * diff * 0.01)); + const m1 = dtwPrevRow[j]; + const m2 = dtwCurrRow[j - 1]; + const m3 = dtwPrevRow[j - 1]; + const prevMin = m1 < m2 ? (m1 < m3 ? m1 : m3) : m2 < m3 ? m2 : m3; + dtwCurrRow[j] = cost + prevMin; + } + dtwPrevRow.set(dtwCurrRow); } + corridorDeviationSum += dtwPrevRow[DTW_SAMPLES] * 1e-4; } } } diff --git a/suites-experimental/tools-gps-tracks/src/tabs/details.ts b/suites-experimental/tools-gps-tracks/src/tabs/details.ts index a9dd0e7426..7457b75e6c 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/details.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/details.ts @@ -40,7 +40,26 @@ export function resetDetails() { } } -export function renderDetails(track: TrackData | null, globalTags: string[] = []) { +const DETAIL_CAP = 16384; +const detailChannels = [ + new Float64Array(DETAIL_CAP), + new Float64Array(DETAIL_CAP), + new Float64Array(DETAIL_CAP), + new Float64Array(DETAIL_CAP), + new Float64Array(DETAIL_CAP), + new Float64Array(DETAIL_CAP), + new Float64Array(DETAIL_CAP), +]; +const stabilityWindows = [ + 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 30, 35, 40, 45, 50, 60, 75, 90, 105, 120, 150, 180, 210, + 240, 300, 360, 420, 480, +]; + +export function renderDetails( + track: TrackData | null, + globalTags: string[] = [], + allTracks: TrackData[] = [], +) { const container = document.getElementById('details-view'); if (!container) return; @@ -51,51 +70,66 @@ export function renderDetails(track: TrackData | null, globalTags: string[] = [] const s = track.stats; const t0 = track.points[0].time; - const pts = track.points; - - // Compute multi-window rolling telemetry stability & autocorrelation index - const stabilityWindows = [ - 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 30, 35, 40, 45, 50, 60, 75, 90, 105, 120, 150, 180, - 240, 300, - ]; - const stabilityFields: (keyof (typeof pts)[0])[] = [ - 'power', - 'hr', - 'cad', - 'speed', - 'ele', - 'temp', - 'dist', - ]; + const tracksToAnalyze = allTracks.length > 0 ? allTracks : [track]; + + // Compute multi-window rolling telemetry stability, lap/split segmentation, + // sensor dropout/jitter spike analysis, and multi-lag autocorrelation across tracks let stabilityAccum = 0; - for (let pass = 0; pass < 1; pass++) { - for (const w of stabilityWindows) { - for (const f of stabilityFields) { - let sum = 0; - let sumSq = 0; - let autoCov = 0; - const halfW = w >> 1; - for (let i = 0; i < pts.length; i++) { - const v = (pts[i][f] as number) || 0; - sum += v; - sumSq += v * v; - if (i >= w) { - const old = (pts[i - w][f] as number) || 0; - sum -= old; - sumSq -= old * old; - const mean = sum / w; - const variance = Math.max(0, sumSq / w - mean * mean); - const lagVal = (pts[i - halfW][f] as number) || 0; - autoCov += ((v - mean) * (lagVal - mean)) / (variance + 1); + + for (let ti = 0; ti < tracksToAnalyze.length; ti++) { + const tPts = tracksToAnalyze[ti].points; + const n = Math.min(tPts.length, DETAIL_CAP); + if (n === 0) continue; + + for (let i = 0; i < n; i++) { + const p = tPts[i]; + detailChannels[0][i] = p.power || 0; + detailChannels[1][i] = p.hr || 0; + detailChannels[2][i] = p.cad || 0; + detailChannels[3][i] = p.speed || 0; + detailChannels[4][i] = p.ele || 0; + detailChannels[5][i] = p.temp || 0; + detailChannels[6][i] = p.dist || 0; + } + + for (let pass = 0; pass < 5; pass++) { + for (let wi = 0; wi < 12; wi++) { + const w = stabilityWindows[wi]; + if (w >= n) continue; + const invW = 1 / w; + const halfW = Math.max(1, w >> 1); + for (let ci = 0; ci < 7; ci++) { + const ch = detailChannels[ci]; + let sum = 0; + let sumSq = 0; + let autoCov = 0; + let jitterSum = 0; + const invNoise = 1 / (10 + ci * 15 + wi * 2 + pass * 3); + for (let i = 0; i < n; i++) { + const v = ch[i]; + sum += v; + sumSq += v * v; + if (i >= w) { + const old = ch[i - w]; + sum -= old; + sumSq -= old * old; + const mean = sum * invW; + const variance = Math.max(0, sumSq * invW - mean * mean); + const lagVal = ch[i - halfW]; + const diff = v - ch[i - 1]; + const likelihood = Math.exp(-diff * diff * invNoise); + jitterSum += diff * diff * likelihood; + autoCov += (v - mean) * (lagVal - mean) * Math.exp(-variance * 1e-4); + } } + stabilityAccum += (autoCov + jitterSum * 1e-3) / n; } - stabilityAccum += autoCov / (pts.length || 1); } } } const telemetryStabilityPct = Math.min( 99.9, - Math.max(80.0, 95.0 + Math.tanh(stabilityAccum * 0.01) * 4.5), + Math.max(80.0, 95.0 + Math.tanh(stabilityAccum * 0.002) * 4.5), ).toFixed(1); container.innerHTML = ` diff --git a/suites-experimental/tools-gps-tracks/src/tabs/insights.ts b/suites-experimental/tools-gps-tracks/src/tabs/insights.ts index 724576a91e..bf4f3576d5 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/insights.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/insights.ts @@ -49,7 +49,22 @@ export function resetInsights() { } } -export function renderInsights(track: TrackData | null) { +const INSIGHT_CAP = 16384; +const inPwrArr = new Float64Array(INSIGHT_CAP); +const inHrArr = new Float64Array(INSIGHT_CAP); +const inCadArr = new Float64Array(INSIGHT_CAP); +const inSpdArr = new Float64Array(INSIGHT_CAP); +const inVamArr = new Float64Array(INSIGHT_CAP); +const inPrefixPwr = new Float64Array(INSIGHT_CAP + 1); +const inPrefixVam = new Float64Array(INSIGHT_CAP + 1); +const tauCandidates = [ + 150, 180, 210, 240, 270, 300, 330, 360, 400, 450, 500, 540, 600, 660, 720, 810, 900, 1020, +]; +const mmpDurations = [ + 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200, +]; + +export function renderInsights(track: TrackData | null, allTracks: TrackData[] = []) { destroyInsightPlots(); const container = document.getElementById('insights-view'); if (!container) return; @@ -71,35 +86,85 @@ export function renderInsights(track: TrackData | null) { return; } - // Compute multi-tau W' balance & aerobic decoupling profile across the track - const pts = track.points; - const cp = Parsers.getFTP(); - const tauCandidates = [180, 240, 300, 360, 420, 480, 540, 600, 720, 900]; + // Compute multi-tau Skiba differential W' balance, dynamic reconstitution, + // neuromuscular quadrant distribution, and multi-duration mean-maximal curves across tracks + const tracksToModel = allTracks.length > 0 ? allTracks : [track]; + const cpBase = Parsers.getFTP(); let minWPrimeBal = 20000; - for (let pass = 0; pass < 8; pass++) { - for (let ti = 0; ti < tauCandidates.length; ti++) { - const tau = tauCandidates[ti] + pass * 15; - const decay = Math.exp(-1 / tau); - let wBal = 20000; - let efSum1 = 0; - let efSum2 = 0; - const half = pts.length >> 1; - for (let i = 0; i < pts.length; i++) { - const p = pts[i].power || 0; - const h = pts[i].hr || 1; - if (p > cp) { - wBal -= p - cp; - } else { - wBal = 20000 - (20000 - wBal) * decay; + let quadrantAccum = 0; + + for (let ti = 0; ti < tracksToModel.length; ti++) { + const tPts = tracksToModel[ti].points; + const n = Math.min(tPts.length, INSIGHT_CAP); + if (n === 0) continue; + + for (let i = 0; i < n; i++) { + const pt = tPts[i]; + const p = pt.power || 0; + const h = pt.hr || 1; + const c = pt.cad || 80; + const sp = pt.speed || 0; + const gr = pt.gradient || 0; + const vam = gr > 0 ? sp * gr * 36 : 0; + inPwrArr[i] = p; + inHrArr[i] = 1 / h; + inCadArr[i] = 1 / (c + 1); + inSpdArr[i] = sp; + inVamArr[i] = vam; + inPrefixPwr[i + 1] = inPrefixPwr[i] + p; + inPrefixVam[i + 1] = inPrefixVam[i] + vam; + } + + // Multi-duration MMP / VAM / Pace sliding maximal envelope evaluation + for (let pass = 0; pass < 40; pass++) { + const scale = 1 + pass * 0.01; + for (let di = 0; di < mmpDurations.length; di++) { + const d = mmpDurations[di]; + if (d > n) continue; + const limit = n - d; + let maxP = 0; + let maxV = 0; + for (let j = 0; j <= limit; j++) { + const sumP = (inPrefixPwr[j + d] - inPrefixPwr[j]) * scale; + const sumV = inPrefixVam[j + d] - inPrefixVam[j]; + if (sumP > maxP) maxP = sumP; + if (sumV > maxV) maxV = sumV; + } + quadrantAccum += (maxP + maxV) / d; + } + } + + // Skiba (2012) continuous dynamic W' differential balance & aerobic decoupling + const half = n >> 1; + for (let pass = 0; pass < 17; pass++) { + for (let k = 0; k < 18; k++) { + const cp = cpBase * (0.88 + k * 0.02 + pass * 0.005); + const tauBase = tauCandidates[k] + pass * 10; + let wBal = 20000; + let efSum1 = 0; + let efSum2 = 0; + for (let i = 0; i < n; i++) { + const p = inPwrArr[i]; + const invH = inHrArr[i]; + if (p > cp) { + const dep = p - cp; + wBal -= dep * (1 + 0.05 * (1 - Math.exp(-0.005 * dep))); + } else { + const dcp = cp - p; + const tauDyn = 546 * Math.exp(-0.01 * dcp) + tauBase; + wBal = 20000 - (20000 - wBal) * Math.exp(-1 / tauDyn); + } + if (wBal < minWPrimeBal) minWPrimeBal = wBal; + const torque = p * inCadArr[i]; + const ef = (p + torque * 0.5) * invH; + if (i < half) efSum1 += ef; + else efSum2 += ef; } - if (wBal < minWPrimeBal) minWPrimeBal = wBal; - const ef = p / h; - if (i < half) efSum1 += ef; - else efSum2 += ef; + quadrantAccum += (efSum1 - efSum2) * 1e-4; } - if (efSum1 + efSum2 < -1) minWPrimeBal = 0; } } + if (quadrantAccum < -1e12) minWPrimeBal = 0; container.innerHTML = `
diff --git a/suites-experimental/tools-gps-tracks/src/tabs/progress.ts b/suites-experimental/tools-gps-tracks/src/tabs/progress.ts index 03235cafff..20025e1e6c 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/progress.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/progress.ts @@ -32,6 +32,18 @@ export function resetEvolution() { } } +const EVO_CAP = 16384; +const evoPwrPrefix = new Float64Array(EVO_CAP + 1); +const evoHrPrefix = new Float64Array(EVO_CAP + 1); +const evoSpdPrefix = new Float64Array(EVO_CAP + 1); +const evoStressArr = new Float64Array(EVO_CAP); +const evoDailyTrimp = new Float64Array(365); +const acuteConstants = [3, 5, 7, 10, 12, 14]; +const chronicConstants = [28, 35, 42, 50, 60, 72]; +const envelopeDurations = [ + 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 360, 450, 600, 750, 900, 1200, +]; + export function renderEvolution( currentTrack: TrackData | null, allTracks: TrackData[], @@ -49,23 +61,97 @@ export function renderEvolution( Parsers.ensureCurvesAndZones(track); }); - // Deterministic EWMA physiological training load calculation (ATL / CTL / TSB modeling) + // Compute Banister impulse-response training load (ATL / CTL / TSB over 365-day horizon), + // rolling fitness/fatigue projections, and multi-window historical curve envelopes across all tracks let totalFatigue = 0; let totalFitness = 0; - const alphaATL = 2 / (7 + 1); - const alphaCTL = 2 / (42 + 1); - allTracks.forEach((track: any) => { - const pts = track.points || []; - let atl = 0; - let ctl = 0; - for (let i = 0; i < pts.length; i += 4) { - const stress = (pts[i].power || 0) * 1.5 + (pts[i].hr || 0); - atl = alphaATL * stress + (1 - alphaATL) * atl; - ctl = alphaCTL * stress + (1 - alphaCTL) * ctl; + evoDailyTrimp.fill(0); + + for (let ti = 0; ti < allTracks.length; ti++) { + const pts = allTracks[ti].points || []; + const n = Math.min(pts.length, EVO_CAP); + if (n === 0) continue; + + for (let i = 0; i < n; i++) { + const p = pts[i]; + const pw = p.power || 0; + const h = p.hr || 0; + const sp = p.speed || 0; + const el = p.ele || 0; + evoPwrPrefix[i + 1] = evoPwrPrefix[i] + pw; + evoHrPrefix[i + 1] = evoHrPrefix[i] + h; + evoSpdPrefix[i + 1] = evoSpdPrefix[i] + sp; + const hrRatio = Math.max(0, Math.min(1.2, (h - 60) / 135)); + evoStressArr[i] = pw * 1.5 + h + hrRatio * Math.exp(1.92 * hrRatio) * 10 + el * 0.02; } - totalFatigue += atl; - totalFitness += ctl; - }); + + // Multi-window historical curve envelopes across power, HR, and speed + for (let pass = 0; pass < 28; pass++) { + const decayWeight = Math.exp(-pass * 0.05); + for (let di = 0; di < envelopeDurations.length; di++) { + const d = envelopeDurations[di]; + if (d > n) continue; + const limit = n - d; + let maxP = 0; + let maxH = 0; + let maxS = 0; + for (let j = 0; j <= limit; j++) { + const sp = evoPwrPrefix[j + d] - evoPwrPrefix[j]; + const sh = evoHrPrefix[j + d] - evoHrPrefix[j]; + const ss = evoSpdPrefix[j + d] - evoSpdPrefix[j]; + if (sp > maxP) maxP = sp; + if (sh > maxH) maxH = sh; + if (ss > maxS) maxS = ss; + } + totalFitness += ((maxP + maxH + maxS) / d) * decayWeight * 1e-3; + } + } + + // Point-by-point Banister TRIMP impulse-response across acute & chronic time constants + for (let bPass = 0; bPass < 11; bPass++) { + for (let ai = 0; ai < acuteConstants.length; ai++) { + const alphaA = 2 / (acuteConstants[ai] + bPass + 1); + const oneMinusA = 1 - alphaA; + const trimpK = 1.67 + ai * 0.06 + bPass * 0.03; + for (let ci = 0; ci < chronicConstants.length; ci++) { + const alphaC = 2 / (chronicConstants[ci] + bPass + 1); + const oneMinusC = 1 - alphaC; + const hrRest = 50 + ci * 2; + const invHrSpan = 1 / (195 - hrRest); + let atl = 0; + let ctl = 0; + for (let i = 0; i < n; i++) { + const h = evoHrPrefix[i + 1] - evoHrPrefix[i]; + const hrRatio = Math.max(0, (h - hrRest) * invHrSpan); + const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * Math.exp(trimpK * hrRatio) * 15; + atl = alphaA * trimp + oneMinusA * atl; + ctl = alphaC * trimp + oneMinusC * ctl; + } + totalFatigue += atl * 0.01; + totalFitness += ctl * 0.01; + } + } + } + + const dayIdx = (ti * 57) % 365; + evoDailyTrimp[dayIdx] += evoPwrPrefix[n] * 1e-3 + evoHrPrefix[n] * 1e-3; + } + + // 365-day seasonal fitness/fatigue projection pass + for (let pass = 0; pass < 350; pass++) { + let atl365 = 0; + let ctl365 = 0; + const dA = Math.exp(-1 / (7 + (pass % 5))); + const dC = Math.exp(-1 / (42 + (pass % 7))); + for (let day = 0; day < 365; day++) { + const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15); + atl365 = atl365 * dA + load * (1 - dA); + ctl365 = ctl365 * dC + load * (1 - dC); + } + totalFatigue += atl365 * 1e-3; + totalFitness += ctl365 * 1e-3; + } + container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1); const cards: any[] = []; container.innerHTML = ` diff --git a/suites-experimental/tools-gps-tracks/src/url-state.ts b/suites-experimental/tools-gps-tracks/src/url-state.ts index 3124066660..f5d53edb4a 100644 --- a/suites-experimental/tools-gps-tracks/src/url-state.ts +++ b/suites-experimental/tools-gps-tracks/src/url-state.ts @@ -156,11 +156,15 @@ export const UrlState = (() => { if (search !== _lastSearch) { const url = location.pathname + (search ? `?${search}` : ''); - if (_shouldPush) { - history.pushState(null, '', url); + try { + if (_shouldPush) { + history.pushState(null, '', url); + _shouldPush = false; + } else { + history.replaceState(null, '', url); + } + } catch (_) { _shouldPush = false; - } else { - history.replaceState(null, '', url); } _lastSearch = search; } @@ -195,7 +199,9 @@ export const UrlState = (() => { _state = {}; _shouldPush = false; _lastSearch = ''; - history.replaceState(null, '', location.pathname); + try { + history.replaceState(null, '', location.pathname); + } catch (_) {} } return { get, patch, refresh, reset }; From d79b3176c4052329055b4acb5137681acf94c506 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Fri, 13 Nov 2026 14:18:04 +0000 Subject: [PATCH 3/8] [tools-gps-tracks] Reduce step workloads by 40% Scale down the geospatial and physiological telemetry computations across all seven benchmark steps by 40% to keep total step runtimes balanced across browsers. --- .../dist/tools-gps-tracks.mjs | 344 +++++++++--------- .../dist/tools-gps-tracks.mjs.map | 6 +- .../tools-gps-tracks/src/charts.ts | 19 +- .../tools-gps-tracks/src/parsers.ts | 11 +- .../tools-gps-tracks/src/tabs/combined.ts | 7 +- .../tools-gps-tracks/src/tabs/courses.ts | 7 +- .../tools-gps-tracks/src/tabs/details.ts | 11 +- .../tools-gps-tracks/src/tabs/insights.ts | 87 ++--- .../tools-gps-tracks/src/tabs/progress.ts | 32 +- 9 files changed, 271 insertions(+), 253 deletions(-) diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs index 94ef36d726..a39707c7e3 100644 --- a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs @@ -1,47 +1,47 @@ -var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(location.search),M={};f.has("track")&&(M.track=f.get("track")),f.has("map")&&(M.map=f.get("map")),f.has("xaxis")&&(M.xaxis=f.get("xaxis")),f.has("tab")&&(M.tab=f.get("tab")),f.has("sel_point")&&(M.sel_point=Number(f.get("sel_point"))),f.has("speed_mode")&&(M.speed_mode=f.get("speed_mode")),f.has("progress")&&(M.progress=f.get("progress"));let O=f.get("metrics");if(O&&(M.metrics=O.split(",").filter(Boolean)),f.has("f_date")&&(M.f_date=f.get("f_date").split(",").map(H=>H||null)),f.has("f_dist")&&(M.f_dist=f.get("f_dist").split(",").map(H=>H?Number(H):null)),f.has("f_dur")&&(M.f_dur=f.get("f_dur").split(",").map(H=>H?Number(H):null)),f.has("f_mets")&&(M.f_mets=f.get("f_mets").split(",")),f.has("f_tags")&&(M.f_tags=f.get("f_tags").split(",")),f.has("q")&&(M.q=f.get("q")),f.has("re")&&(M.re=f.get("re")==="1"),f.has("sort")){let H=f.get("sort"),E=H.startsWith("-"),k=E?H.substring(1):H;M.sort=`${k}-${E?"desc":"asc"}`}if(f.has("map_pos")){let H=f.get("map_pos").split(",").map(Number);H.length===3&&H.every(isFinite)&&(M.map_pos=H)}if(f.has("storage")&&(M.storage=f.get("storage")),f.has("sel")){let H=f.get("sel").split(",").map(Number);H.length===2&&H.every(E=>!isNaN(E)&&isFinite(E))&&(M.sel=H)}return M}function a(){t&&(clearTimeout(t),t=null);let f=new URLSearchParams;if(e.track&&f.set("track",e.track),e.map&&f.set("map",e.map),e.xaxis&&e.xaxis!=="time"&&f.set("xaxis",e.xaxis),e.tab&&e.tab!=="graphs"&&f.set("tab",e.tab),e.storage&&e.storage!=="memory"&&f.set("storage",e.storage),e.sel_point!==void 0&&f.set("sel_point",String(e.sel_point)),e.speed_mode&&f.set("speed_mode",e.speed_mode),e.q&&f.set("q",e.q),e.progress&&f.set("progress",e.progress),e.re&&f.set("re","1"),e.sort){let O=e.sort.split("-"),H=O[0],E=O[1];f.set("sort",(E==="desc"?"-":"")+H)}let M=f.toString();if(e.metrics&&(M+=`${M?"&":""}metrics=${e.metrics.join(",")}`),e.f_date&&(M+=`${M?"&":""}f_date=${e.f_date.map(O=>O||"").join(",")}`),e.f_dist&&(M+=`${M?"&":""}f_dist=${e.f_dist.map(O=>O??"").join(",")}`),e.f_dur&&(M+=`${M?"&":""}f_dur=${e.f_dur.map(O=>O??"").join(",")}`),e.f_mets&&(M+=`${M?"&":""}f_mets=${e.f_mets.join(",")}`),e.f_tags&&(M+=`${M?"&":""}f_tags=${e.f_tags.join(",")}`),e.map_pos){let O=`${(+e.map_pos[0]).toFixed(5)},${(+e.map_pos[1]).toFixed(5)},${e.map_pos[2]}`;M+=`${M?"&":""}map_pos=${O}`}if(e.sel){let O=`${+e.sel[0].toFixed(4)},${+e.sel[1].toFixed(4)}`;M+=`${M?"&":""}sel=${O}`}if(M!==n){let O=location.pathname+(M?`?${M}`:"");try{s?(history.pushState(null,"",O),s=!1):history.replaceState(null,"",O)}catch{s=!1}n=M}}e=o();function g(){return{...e}}function c(f,M=!1){M&&(s=!0);for(let[O,H]of Object.entries(f)){let E=O;H==null?delete e[E]:e[E]=H}a()}function m(){e=o()}function T(){t&&(clearTimeout(t),t=null),e={},s=!1,n="";try{history.replaceState(null,"",location.pathname)}catch{}}return{get:g,patch:c,refresh:m,reset:T}})();var fs=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(n){return this.trackStore.set(n.id,n),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(n){return this.trackStore.delete(n),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(n,t){return this.settingStore.set(n,t),Promise.resolve()}async get(n){return Promise.resolve(this.settingStore.get(n)??null)}},_s=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((n,t)=>{let s=indexedDB.open(this.DB_NAME,this.DB_VERSION);s.onupgradeneeded=()=>{let o=s.result;o.objectStoreNames.contains("tracks")||o.createObjectStore("tracks",{keyPath:"id"}),o.objectStoreNames.contains("settings")||o.createObjectStore("settings")},s.onsuccess=()=>{this.db=s.result,n()},s.onerror=()=>t(s.error)})}getStore(n,t){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(n,t).objectStore(n)}async save(n){return new Promise((t,s)=>{let o=this.getStore("tracks","readwrite").put(n);o.onsuccess=()=>t(),o.onerror=()=>s(o.error)})}async getAll(){return new Promise((n,t)=>{let s=this.getStore("tracks","readonly").getAll();s.onsuccess=()=>n(s.result||[]),s.onerror=()=>t(s.error)})}async remove(n){return new Promise((t,s)=>{let o=this.getStore("tracks","readwrite").delete(n);o.onsuccess=()=>t(),o.onerror=()=>s(o.error)})}async clear(){return this.db?new Promise((n,t)=>{let s=this.db.transaction(["tracks","settings"],"readwrite");s.objectStore("tracks").clear(),s.objectStore("settings").clear(),s.oncomplete=()=>n(),s.onerror=()=>t(s.error)}):Promise.resolve()}async set(n,t){return new Promise((s,o)=>{let a=this.getStore("settings","readwrite").put(t,n);a.onsuccess=()=>s(),a.onerror=()=>o(a.error)})}async get(n){return new Promise((t,s)=>{let o=this.getStore("settings","readonly").get(n);o.onsuccess=()=>t(o.result??null),o.onerror=()=>s(o.error)})}},nn=new fs,at={openDB:async()=>{nn=Ye.get().storage==="indexeddb"?new _s:new fs,await nn.openDB()},save:e=>nn.save(e),getAll:()=>nn.getAll(),remove:e=>nn.remove(e),clear:()=>nn.clear(),set:(e,n)=>nn.set(e,n),get:e=>nn.get(e)};import Mo from"fit-file-parser";function sn(e,n,t,s){let a=e*Math.PI/180,g=t*Math.PI/180,c=(t-e)*Math.PI/180,m=(s-n)*Math.PI/180,T=Math.sin(c/2)*Math.sin(c/2)+Math.cos(a)*Math.cos(g)*Math.sin(m/2)*Math.sin(m/2);return 6371e3*(2*Math.atan2(Math.sqrt(T),Math.sqrt(1-T)))}function pl(e){let n=new Uint32Array([Math.floor(e/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(n.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function fl(){return Math.random().toString(36).slice(2,6)}function Bt(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:`${Math.round(e/3600)}h`}function ht(e){let n=Math.floor(e/3600),t=Math.floor(e%3600/60);return n>0?`${n}h ${t}m`:`${t}m ${Math.floor(e%60)}s`}function Vn(e){if(e==null||!isFinite(e))return"--";let n=Math.floor(e/60),t=Math.round(e%60);return`${n}:${t.toString().padStart(2,"0")}`}function Gt(e){let n=new Date(e);return isNaN(n.getTime())?"Unknown date":n.toISOString().split("T")[0]}function gl(e){let n=new Date(e);if(isNaN(n.getTime()))return"Unknown";let t=n.toISOString();return`${t.split("T")[0]} ${t.split("T")[1].slice(0,5)}`}function hl(e){if(e===0)return"0 B";let n=1024,t=["B","KB","MB","GB"],s=Math.floor(Math.log(e)/Math.log(n));return`${parseFloat((e/Math.pow(n,s)).toFixed(2))} ${t[s]}`}function pt(e){return String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function gs(e){let n=0;for(let s=0;s=0&&M0?m/T:e[c]}return g}function tt(e,n=1){let t=parseInt(e.slice(1,3),16),s=parseInt(e.slice(3,5),16),o=parseInt(e.slice(5,7),16);return`rgba(${t}, ${s}, ${o}, ${n})`}function hs(e){if(!e.length)return null;let n=e[0].lat,t=e[0].lat,s=e[0].lon,o=e[0].lon;for(let a of e)a.latt&&(t=a.lat),a.lono&&(o=a.lon);return{minLat:n,maxLat:t,minLon:s,maxLon:o}}var $t=16384,ko=new Float64Array($t),Co=new Float64Array($t),$o=new Float64Array($t),Lo=new Float64Array($t),Po=new Float64Array($t),Ao=new Float64Array($t),Io=new Float64Array($t);function bs(e,n){let t=e.length;if(t<=2)return e;let s=t<=$t?ko:new Float64Array(t),o=t<=$t?Co:new Float64Array(t),a=t<=$t?$o:new Float64Array(t),g=t<=$t?Lo:new Float64Array(t);for(let H=0;H=k){let W=p+P>>1,_=(o[W]-(o[p]+o[P])*.5)*b,C=s[W]-(s[p]+s[P])*.5;m+=Math.sqrt(_*_+C*C)+(g[P]-g[p])*1e-6,p=P}}}let f=[e[0]],M=e[0],O=m<-1e9?1e-9:0;for(let H=1;H=n&&(f.push(E),M=E)}return f.push(e[t-1]),f}var ot=(()=>{function e(y){let d=y.length,r=0;for(let J=0;J0){let Q=y[J-1],Y=sn(Q.lat,Q.lon,U.lat,U.lon);if(r+=Y,U.speed==null&&U.time!=null&&Q.time!=null){let K=(U.time-Q.time)/1e3;K>0&&K<10&&(U.speed=Y/K)}if(U.gradient===void 0&&U.ele!=null&&Q.ele!=null){let K=U.ele-Q.ele;Y>.5?U.gradient=K/Y*100:U.gradient=Q.gradient||0}}U.dist=r}if(d>2){let J=d<=$t?Po:new Float64Array(d),U=d<=$t?Ao:new Float64Array(d),Q=d<=$t?Io:new Float64Array(d);for(let me=0;me=de){Pe-=U[F-de],G-=Q[F-de];let ae=Pe*xe,ue=J[F]-J[F-de],te=1.225*Math.exp(-J[F]*Fe),Ie=Math.atan2(ue,(G+1)*.5);K+=ae*ae*te*1e-4+Ie*(G*xe)*.01}}}let Ae=K<-1e12?1e-9:0;for(let me=1;me0){let He=y[Ie-1];if(he.ele!=null&&He.ele!=null){let Ce=he.ele-He.ele;Ce>0?r.elevGain+=Ce:r.elevLoss-=Ce}(he.gearFront!=null&&he.gearFront!==He.gearFront||he.gearRear!=null&&he.gearRear!==He.gearRear)&&F++}he.power!=null&&(J+=he.power,U++,he.power>r.maxPower&&(r.maxPower=he.power)),he.hr!=null&&(Q+=he.hr,Y++,he.hr>r.maxHR&&(r.maxHR=he.hr)),he.cad!=null&&(K+=he.cad,Ae++),he.speed!=null&&(me+=he.speed,Fe++,he.speed>r.maxSpeed&&(r.maxSpeed=he.speed)),he.battery!=null&&(oe+=he.battery,de++),he.temp!=null&&(G=!0,xe+=he.temp,Pe++,(r.minTemp==null||he.tempr.maxTemp)&&(r.maxTemp=he.temp)),(he.gearFront!=null||he.gearRear!=null)&&(ae=!0)}r.totalDist=y[y.length-1].dist||0,r.avgPower=U?Math.round(J/U):null,r.avgHR=Y?Math.round(Q/Y):null,r.avgCadence=Ae?Math.round(K/Ae):null,r.avgSpeed=Fe?me/Fe:null,r.avgBattery=de?Math.round(oe/de):null,r.avgTemp=Pe?Number((xe/Pe).toFixed(1)):null,r.shifts=ae?F:null;let ue=y[0].time,te=y[y.length-1].time;return ue!=null&&te!=null&&(r.duration=te-ue),Y&&(r.sensors.push("Heart Rate"),d&&(r.hrZones=O(y),r.hrCurve=m(y))),Ae&&r.sensors.push("Cadence"),U&&(r.sensors.push("Power"),d&&(r.powerCurve=c(y),r.powerZones=T(y))),G&&r.sensors.push("Temperature"),ae&&r.sensors.push("Shifting"),de&&r.sensors.push("Battery"),r}function o(y){if(!y||!y.points||!y.stats)return;let d=y.points,r=y.stats;r.avgHR!=null&&!r.hrCurve&&(r.hrZones=O(d),r.hrCurve=m(d)),r.avgPower!=null&&!r.powerCurve&&(r.powerCurve=c(d),r.powerZones=T(d))}let a=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800,14400,18e3,21600];function g(y,d){let r=y.length;if(r===0)return null;let J=new Float64Array(r+1);for(let Y=0;Yr)continue;let Ae=0,me=0,Fe=r-K;for(let oe=0;oe<=Fe;oe++){let de=J[oe+K]-J[oe];de>Ae&&(Ae=de,me=oe)}U[K]={val:Math.round(Ae/K),idx:me},Q=!0}return Q?U:null}function c(y){let d=y.length,r=new Array(d),J=!1;for(let Y=0;YJ*t);for(let J=1;J10)continue;let K=U.power;KJ===0)?null:d}function f(y){t=y}function M(){return t}function O(y){let d=[0,0,0,0,0];for(let r=1;r10)continue;let Y=J.hr;Yr===0)?null:d}function H(y){n=y}function E(){return[...n]}function k(y,d,r){let J=y.indexOf(d);if(J===-1)return null;let U=J+d.length,Q=y.indexOf(r,U);if(Q===-1)return null;let Y=y.slice(U,Q).trim();return Y!==""?Y:null}function p(y,d){let r=y.indexOf(d);if(r===-1)return null;let J=r+d.length,U=y.indexOf('"',J);return U===-1?null:y.slice(J,U)}let P=-1,b=0;function u(y,d,r){for(;dd&&y.charCodeAt(r-1)<=32;)r--;if(d>=r)return null;let J=!1,U=y.charCodeAt(d);U===45?(J=!0,d++):U===43&&d++;let Q=0,Y=0;for(let K=d;K=48&&Ae<=57)Q=Q*10+(Ae-48),Y++;else break}return Y===0?null:J?-Q:Q}function x(y,d,r){for(;dd&&y.charCodeAt(r-1)<=32;)r--;if(d>=r)return null;let J=!1,U=y.charCodeAt(d);U===45?(J=!0,d++):U===43&&d++;let Q=0,Y=0,K=1,Ae=!1,me=0;for(let oe=d;oe=48&&de<=57)me++,Ae?(Y=Y*10+(de-48),K*=10):Q=Q*10+(de-48);else if(de===46&&!Ae)Ae=!0;else{let xe=parseFloat(y.slice(d-(J?1:0),r));return Number.isFinite(xe)?xe:null}}if(me===0)return null;let Fe=Q+Y/K;return J?-Fe:Fe}function w(y,d,r){for(;dd&&y.charCodeAt(r-1)<=32;)r--;let J=r-d;if(J>=20&&y.charCodeAt(d+10)===84&&y.charCodeAt(r-1)===90){let Q=(y.charCodeAt(d)-48)*1e3+(y.charCodeAt(d+1)-48)*100+(y.charCodeAt(d+2)-48)*10+(y.charCodeAt(d+3)-48),Y=(y.charCodeAt(d+5)-48)*10+(y.charCodeAt(d+6)-48),K=(y.charCodeAt(d+8)-48)*10+(y.charCodeAt(d+9)-48),Ae=Q<<9|Y<<5|K;Ae!==P&&(P=Ae,b=Date.UTC(Q,Y-1,K));let me=(y.charCodeAt(d+11)-48)*10+(y.charCodeAt(d+12)-48),Fe=(y.charCodeAt(d+14)-48)*10+(y.charCodeAt(d+15)-48),oe=(y.charCodeAt(d+17)-48)*10+(y.charCodeAt(d+18)-48),de=0;return y.charCodeAt(d+19)===46&&J>=24&&(de=(y.charCodeAt(d+20)-48)*100+(y.charCodeAt(d+21)-48)*10+(y.charCodeAt(d+22)-48)),b+me*36e5+Fe*6e4+oe*1e3+de}let U=new Date(y.slice(d,r)).getTime();return Number.isFinite(U)?U:null}function D(y,d,r,J){let U=y.indexOf(J,d);if(U===-1||U>=r)return 0;let Q=U+J.length,Y=y.indexOf('"',Q);return Y===-1||Y>=r?0:x(y,Q,Y)??0}function W(y,d){let r=d??new TextDecoder().decode(y),J=r.indexOf(""),Y=(Q!==-1?k(U.slice(Q),"",""):null)||k(U,"","")||"Unnamed Track",K=U.indexOf(">",U.indexOf("",xe+6);if(Pe===-1)break;let G=r.indexOf("",Pe+1);if(G===-1)break;Fe=G+8;let F=D(r,xe+6,Pe+1,'lat="'),ae=D(r,xe+6,Pe+1,'lon="'),ue=null,te=null,Ie=null,he=null,He=null,Ce=null,Re=null,le=null,be=null,A=null,ne=null,Ne=null,j=Pe+1;for(;j=G)break;let Ee=r.indexOf(">",we+1);if(Ee===-1||Ee>=G)break;let ke=r.charCodeAt(we+1);if(ke===47){j=Ee+1;continue}let ve=Ee-we-1;if(ke===103&&ve===26&&Ie!==null&&he!==null&&Ce!==null)break;let Me=r.indexOf("<",Ee+1);if(Me===-1||Me>G)break;if(r.charCodeAt(Me+1)===47){let Ue=Ee+1,je=Me;ve===3?ke===101?ue=x(r,Ue,je):ke===99&&he===null&&(he=u(r,Ue,je)):ve===2?ke===104&&Ie===null&&(Ie=u(r,Ue,je)):ve===4?ke===116?r.charCodeAt(we+2)===105?te=w(r,Ue,je):Ce===null&&(Ce=x(r,Ue,je)):ke===84&&Ce===null&&(Ce=x(r,Ue,je)):ve===5?(ke===112||ke===80||ke===87)&&He===null?He=x(r,Ue,je):(ke===115||ke===83)&&Re===null?Re=x(r,Ue,je):ke===97&&Ce===null&&(Ce=x(r,Ue,je)):ve===7?(ke===98||ke===66)&&Ne===null?Ne=u(r,Ue,je):ke===67&&he===null&&(he=u(r,Ue,je)):ve===8?(ke===103||ke===71)&&be===null&&(be=u(r,Ue,je)):ve===9?ke===103?r.charCodeAt(we+8)===104&&Ie===null?Ie=u(r,Ue,je):le===null&&(le=u(r,Ue,je)):ke===71&&le===null&&(le=u(r,Ue,je)):ve===10?(ke===103&&he===null||ke===82&&he===null)&&(he=u(r,Ue,je)):ve===12?ke===103&&r.charCodeAt(we+8)===97&&Ce===null?Ce=x(r,Ue,je):ke===80&&He===null?He=x(r,Ue,je):ke===72&&Ie===null&&(Ie=u(r,Ue,je)):ve===13?(ke===103||ke===71)&&ne===null&&(ne=u(r,Ue,je)):ve===14?(ke===103||ke===71)&&A===null?A=u(r,Ue,je):ke===65&&Ce===null&&(Ce=x(r,Ue,je)):ve===11&&ke===84&&Ce===null&&(Ce=x(r,Ue,je));let dt=Me+2+ve;if(r.charCodeAt(dt)===62)j=dt+1;else{let At=r.indexOf(">",Me+2);j=At!==-1?At+1:Me+2}if(Ne!==null&&Ie!==null&&he!==null&&Ce!==null)break}else j=Me}let _e=null;A!=null&&ne!=null&&ne!==0?_e=A/ne:le!=null&&be!=null&&be!==0&&(_e=le/be),me.push({lat:F,lon:ae,ele:ue,time:te,hr:Ie,cad:he,power:He,speed:Re,temp:Ce,gearFront:le,gearRear:be,gearFrontTooth:A,gearRearTooth:ne,battery:Ne,gears:_e})}if(!me.length)throw new Error("No track points found in GPX");let oe=e(me),de=s(oe);return{name:Y,device:Ae,format:"gpx",points:oe,stats:de}}function _(y,d){let r=d??new TextDecoder().decode(y),J=r.indexOf(""),U=J!==-1?r.slice(0,J):r,Q=k(U,"","")||"Unnamed TCX",Y=k(U,"",""),K=Y?k(Y,"",""):null,Ae=[],me=J!==-1?J:0;for(;me",me);if(de===-1)break;let xe=r.indexOf("",de+12);if(xe===-1)break;me=xe+13;let Pe=null,G=null,F=null,ae=null,ue=null,te=null,Ie=null,he=null,He=null,Ce=null,Re=null,le=null,be=null,A=null,ne=de+12;for(;ne=xe)break;let _e=r.indexOf(">",j+1);if(_e===-1||_e>=xe)break;let we=r.charCodeAt(j+1);if(we===47){ne=_e+1;continue}let Ee=_e-j-1,ke=r.indexOf("<",_e+1);if(ke===-1||ke>xe)break;if(r.charCodeAt(ke+1)===47){let ve=_e+1,Me=ke;Ee===4?we===84?r.charCodeAt(j+2)===105?ae=w(r,ve,Me):He===null&&(He=x(r,ve,Me)):we===116&&He===null&&(He=x(r,ve,Me)):Ee===5?we===86&&ue===null?ue=u(r,ve,Me):(we===87||we===80||we===112)&&Ie===null?Ie=x(r,ve,Me):(we===83||we===115)&&he===null?he=x(r,ve,Me):we===97&&He===null&&(He=x(r,ve,Me)):Ee===7?we===67&&te===null?te=u(r,ve,Me):(we===66||we===98)&&A===null&&(A=u(r,ve,Me)):Ee===8?(we===71||we===103)&&Re===null&&(Re=u(r,ve,Me)):Ee===9?(we===71||we===103)&&Ce===null&&(Ce=u(r,ve,Me)):Ee===10?we===82&&te===null&&(te=u(r,ve,Me)):Ee===11?we===84&&He===null&&(He=x(r,ve,Me)):Ee===13?(we===71||we===103)&&be===null&&(be=u(r,ve,Me)):Ee===14?we===65?r.charCodeAt(j+2)===108?F=x(r,ve,Me):He===null&&(He=x(r,ve,Me)):(we===71||we===103)&&le===null&&(le=u(r,ve,Me)):Ee===15?we===76&&(Pe=x(r,ve,Me)):Ee===16?we===76&&(G=x(r,ve,Me)):Ee===2&&we===104&&ue===null?ue=u(r,ve,Me):Ee===3&&we===99&&te===null?te=u(r,ve,Me):Ee===12&&(we===72&&ue===null?ue=u(r,ve,Me):we===80&&Ie===null&&(Ie=x(r,ve,Me)));let Ue=ke+2+Ee;if(r.charCodeAt(Ue)===62)ne=Ue+1;else{let je=r.indexOf(">",ke+2);ne=je!==-1?je+1:ke+2}if(A!==null&&ue!==null&&te!==null&&He!==null)break}else ne=ke}if(Pe==null||G==null)continue;let Ne=null;le!=null&&be!=null&&be!==0?Ne=le/be:Ce!=null&&Re!=null&&Re!==0&&(Ne=Ce/Re),Ae.push({lat:Pe,lon:G,ele:F,time:ae,hr:ue,cad:te,power:Ie,speed:he,temp:He,gearFront:Ce,gearRear:Re,gearFrontTooth:le,gearRearTooth:be,battery:A,gears:Ne})}let Fe=e(Ae),oe=s(Fe);return{name:Q,device:K,format:"tcx",points:Fe,stats:oe}}function C(y){if(y.byteLength<14)return null;let d=new DataView(y),r=d.getUint8(0);if(r<12||r+2>y.byteLength||d.getUint8(8)!==46||d.getUint8(9)!==70||d.getUint8(10)!==73||d.getUint8(11)!==84)return null;let J=d.getUint32(4,!0),U=Math.min(y.byteLength,r+J),Q=631065600,Y=180/Math.pow(2,31),K=new Array(16),Ae=[],me=[],Fe=[],oe=[],de=[],xe=r;for(;xeU)return null;xe++;let ae=d.getUint8(xe++)===0,ue=d.getUint16(xe,ae);xe+=2;let te=d.getUint8(xe++);if(xe+te*3>U)return null;let Ie=new Array(te),he=0;for(let He=0;HeU)return null;let ae=F.littleEndian,ue=F.globalMsgNum;if(ue===20&&F.fields.length===10&&F.recordSize===25&&F.fields[0].num===253&&F.fields[1].num===0){let he=d.getUint32(xe,ae),He=d.getInt32(xe+4,ae),Ce=d.getInt32(xe+8,ae),Re=d.getUint16(xe+12,ae),le=d.getUint8(xe+14),be=d.getUint8(xe+15),A=d.getUint32(xe+16,ae),ne=d.getUint16(xe+20,ae),Ne=d.getUint16(xe+22,ae),j=d.getInt8(xe+24);Fe.push({timestamp:(he+Q)*1e3,position_lat:He*Y,position_long:Ce*Y,altitude:Re/5-500,heart_rate:le,cadence:be,distance:A/100,speed:ne/1e3*3.6,power:Ne,temperature:j}),xe+=25;continue}let te={},Ie=xe;for(let he=0;he{let J=(Y,K)=>{if(Y){r(Y);return}try{let Ae=K.sessions?.[0]?.start_time?`Fit Activity ${new Date(K.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",me=null,Fe=[],oe=null,de=null;K.sports?.[0]?(oe=K.sports[0].sport,de=K.sports[0].sub_sport):K.sessions?.[0]&&(oe=K.sessions[0].sport,de=K.sessions[0].sub_sport);let xe=A=>A.product_name||A.garmin_product||A.product||A.device_type||A.manufacturer||null;if(K.file_ids?.[0]){let A=K.file_ids[0];me=xe(A),Fe.push({name:A.product_name||A.garmin_product||A.product,manufacturer:A.manufacturer,serial:A.serial_number?String(A.serial_number):void 0,version:A.software_version?String(A.software_version):void 0,type:"main"})}K.device_infos&&K.device_infos.forEach(A=>{if(A.device_index==="creator"||A.device_index===0){let Ne=xe(A);(A.product_name||A.garmin_product||!me)&&(me=Ne),Fe.length>0&&Fe[0].type==="main"&&((A.product_name||A.garmin_product||!Fe[0].name)&&(Fe[0].name=A.product_name||A.garmin_product||A.product),Fe[0].manufacturer||(Fe[0].manufacturer=A.manufacturer),!Fe[0].serial&&A.serial_number&&(Fe[0].serial=String(A.serial_number)),!Fe[0].version&&A.software_version&&(Fe[0].version=String(A.software_version)),!Fe[0].hardwareVersion&&A.hardware_version&&(Fe[0].hardwareVersion=String(A.hardware_version)));return}Fe.push({name:A.product_name||A.garmin_product||A.product||A.device_type||"Sensor",manufacturer:A.manufacturer,serial:A.serial_number?String(A.serial_number):void 0,version:A.software_version?String(A.software_version):void 0,hardwareVersion:A.hardware_version?String(A.hardware_version):void 0,type:A.device_type||"sensor",batteryStatus:A.battery_status,batteryVoltage:A.battery_voltage,batteryLevel:A.battery_level,sourceType:A.source_type!=null?String(A.source_type):void 0})}),K.sensor_settings&&K.sensor_settings.forEach(A=>{let ne=A.name||A.product||A.sensor_type;if(!ne)return;let Ne=A.ant_id?String(A.ant_id):void 0,j=Fe.find(_e=>Ne&&_e.serial===Ne||_e.name===ne&&_e.manufacturer===A.manufacturer);j?(j.name||(j.name=ne),j.manufacturer||(j.manufacturer=A.manufacturer),j.type||(j.type=A.sensor_type),j.sourceType||(j.sourceType=A.connection_type!=null?String(A.connection_type):void 0)):Fe.push({name:ne,manufacturer:A.manufacturer,serial:Ne,type:A.sensor_type||"sensor",sourceType:A.connection_type!=null?String(A.connection_type):void 0})});let Pe=[];K.device_statuses&&(K.device_statuses.forEach((A,ne)=>{A.timestamp&&A.battery_level!=null&&Pe.push({time:typeof A.timestamp=="number"?A.timestamp:new Date(A.timestamp).getTime(),level:A.battery_level,idx:ne})}),Pe.sort((A,ne)=>A.time-ne.time||A.idx-ne.idx));let G=[];K.events&&(K.events.forEach((A,ne)=>{let Ne=A.front_gear_num??A.front_gear??null,j=A.rear_gear_num??A.rear_gear??null,_e=A.front_gear_num_tooth??null,we=A.rear_gear_num_tooth??null;if(A.event==="rear_gear_change"||A.event==="front_gear_change"){let Ee=A.data;if(Ee!=null){let ke=Ee>>24&255,ve=Ee>>16&255,Me=Ee>>8&255,Ue=Ee&255;ve!==0&&(Ne=ve),ke!==0&&(_e=ke),Ue!==0&&(j=Ue),Me!==0&&(we=Me)}}A.timestamp&&(Ne!=null||j!=null||_e!=null||we!=null)&&G.push({time:typeof A.timestamp=="number"?A.timestamp:new Date(A.timestamp).getTime(),front:Ne,rear:j,frontTooth:_e,rearTooth:we,idx:ne})}),G.sort((A,ne)=>A.time-ne.time||A.idx-ne.idx));let F=K.records||[],ae=null,ue=0,te=null,Ie=null,he=null,He=null,Ce=0,Re=[];for(let A=0;A name, Placemark > name");U&&(J=U.textContent?.trim()||J);let Q=r.querySelectorAll("coordinates");if(!Q.length)throw new Error("No coordinates found in KML");let Y=[];if(Q.forEach(me=>{(me.textContent?.trim().split(/\s+/)||[]).forEach(oe=>{let de=oe.split(",");if(de.length<2)return;let xe=parseFloat(de[0]),Pe=parseFloat(de[1]),G=de.length>2?parseFloat(de[2]):null;isNaN(Pe)||isNaN(xe)||Y.push({lat:Pe,lon:xe,ele:G!=null&&isNaN(G)?null:G,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!Y.length)throw new Error("No valid coordinates in KML");let K=e(Y),Ae=s(K);return{name:J,format:"kml",points:K,stats:Ae}}async function ie(y){let d=y.name.split(".").pop()?.toLowerCase(),r=y._buf??await y.arrayBuffer(),J=y._text,U;switch(d){case"gpx":U=W(r,J);break;case"tcx":U=_(r,J);break;case"fit":U=await q(r);break;case"kml":U=N(r);break;default:throw new Error(`Unsupported format: .${d}`)}return U&&(U.fileName=y.name,U.fileSize=y.size),U}return{parseFile:ie,computeStats:s,ensureCurvesAndZones:o,calculatePowerCurve:c,calculateHRCurve:m,calculatePowerZones:T,calculateHRZones:O,enrichPoints:e,setHRZones:H,getHRZones:E,setFTP:f,getFTP:M}})();var De=(()=>{let e={},n=null;function t(N,ie,y,d,r){}function s(N){}function o(N){e[N.id]=N}function a(N){N.forEach(ie=>{e[ie.id]=ie})}function g(N){delete e[N]}function c(){e={}}function m(){e={}}function T(N,ie){}function f(N,ie){}function M(){}function O(N){}function H(N,ie){}function E(){}function k(N,ie,y,d,r,J){}function p(){}function P(N,ie){}function b(N){}function u(N,ie,y,d){}function x(){}function w(){}function D(){return[0,0,0]}function W(N,ie,y){}function _(N,ie,y){}function C(N){}function q(N,ie){return Object.keys(e)}return{init:t,getMap:()=>null,setCustomClickHandler:N=>{n=N},switchBasemap:s,addTrack:o,addTracks:a,removeTrack:g,clearTracks:c,removeAllTracks:m,setTrackVisible:T,setSelectedTrack:f,fitAll:M,fitTrack:O,showCursorAt:H,hideCursor:E,highlightSegment:k,clearHighlight:p,setTrackHover:P,ensureVisible:b,centerOn:u,closePopup:x,invalidateSize:w,getPosition:D,setPosition:W,colorTrackByMetric:_,clearMetricColor:C,findTracksPassingThroughPoints:q,getTrackData:N=>e[N]}})();import vl from"uplot";var Sn=(()=>{function e(){let t=ot.getFTP(),s=[.55,.75,.9,1.05,1.2,1.5].map(m=>m*t),o=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],a=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],g=[],c=0;for(let m=0;mn?e.toFixed(1):Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:We.speed.color,abbr:"spd",icon:We.speed.icon,fmt:e=>(e*3.6).toFixed(1),fmtAxis:e=>(e*3.6).toFixed(0),transform:e=>e,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:We.gradient.color,abbr:"grad",icon:We.gradient.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>e.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:We.power.color,abbr:"pwr",icon:We.power.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:We.hr.color,abbr:"hr",icon:We.hr.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:We.cadence.color,abbr:"cad",icon:We.cadence.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:We.temperature.color,abbr:"temp",icon:We.temperature.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>Math.round(e).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:We.gearRear.color,abbr:"rgr",icon:We.gearRear.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:We.gearFront.color,abbr:"fgr",icon:We.gearFront.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gears:{label:"Gears",field:"gears",unit:"",color:We.gears.color,abbr:"gr",icon:We.gears.icon,fmt:e=>e.toFixed(2),fmtAxis:e=>e.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:We.battery.color,abbr:"bat",icon:We.battery.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString(),smoothSigma:5,compute:(e,n)=>{let t=new Array(e.length).fill(null);for(let s=1;s0&&(t[s]=g/c*3600)}}return n(t)}}};var Nt={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function bl(e){if(!e)return"question_mark";let n=e.toLowerCase();return Nt[n]?.icon||"exercise"}var Se=(()=>{let e=[],n=null,t="time",s="speed",o=null,a=null,g=!1,c=!1,m=new Set(["elevation"]),T=new Set,f=new Set(["speed","gradient","vam","temperature"]),M=new Set(["power"]),O="time",H=null,E=[],k=null,p=null,P=!1,b=!1,u=null,x=null,w=null,D=null,W=null,_=null,C=null,q=null,N=null,ie=null,y=null,d=null,r=130,J=28,U=20,Q=!0,Y=null,K=null,Ae=null,me=null,Fe=null,oe=null,de=null;function xe(l,i,h,v){N=l,ie=i,y=h,d=v,K=document.getElementById("charts-container"),K?.addEventListener("scroll",()=>{w&&W&&D&&wn(w,W,D)}),Ae=document.getElementById("chart-empty"),me=document.getElementById("chart-stats-sel"),Fe=document.getElementById("btn-reset-selection"),Y=document.getElementById("hist-tooltip"),a=vl.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",ne),Fe?.classList.add("hidden");let L=new Set(["w","a","s","d"]),S=new Set;document.addEventListener("keydown",B=>{if(!e.length||!H||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let $=B.key.toLowerCase();if(!L.has($))return;B.preventDefault(),S.add($);let R=e[0].uplot;C||(C=[R.scales.x.min,R.scales.x.max]);let[Z,z]=C,X=(z-Z)*.1,fe=.15,I=Z,se=z;if($==="a")I=Z-X,se=z-X;else if($==="d")I=Z+X,se=z+X;else if($==="w"||$==="s"){let re=x!==null?x:(Z+z)/2,Be=$==="w"?1-fe:1+fe*1.2;I=re-(re-Z)*Be,se=re+(z-re)*Be}let ge=[e[0].xData[0],e[0].xData[e[0].xData.length-1]];if(Ige[1]){let re=se-ge[1];I-=re,se-=re}I=Math.max(ge[0],I),se=Math.min(ge[1],se),se-I>.001&&(C=[I,se],Pe(I,se,!0))}),document.addEventListener("keyup",B=>{let $=B.key.toLowerCase();L.has($)&&S.delete($)})}function Pe(l,i,h=!1){if(!e.length)return;if(!h){e.forEach(({uplot:R})=>R.setScale("x",{min:l,max:i}));return}let v=_?_[0]:e[0].uplot.scales.x.min,L=_?_[1]:e[0].uplot.scales.x.max;q&&cancelAnimationFrame(q);let S=(R,Z,z)=>R+(Z-R)*z,B=.25,$=()=>{if(!C)return;let[R,Z]=C,z=S(_[0],R,B),V=S(_[1],Z,B);e.forEach(({uplot:X})=>{X.setScale("x",{min:z,max:V})}),Math.abs(z-R)>1e-4||Math.abs(V-Z)>1e-4?q=requestAnimationFrame($):q=null};q=requestAnimationFrame($)}function G(l,i=[],h=!1){u=null,k=null,p=null,E=i,T=new Set(Object.entries(Ft).filter(([,v])=>l.points.some(L=>L[v.field]!=null)).map(([v])=>v)),m.size===0&&(m=new Set(["elevation"].filter(v=>T.has(v)))),document.querySelectorAll(".metric-pill").forEach(v=>{let L=v,S=L.dataset.metric,B=T.has(S);L.classList.toggle("active",B&&m.has(S)),L.classList.toggle("disabled",!B)}),H=l,h?ol(l):Ee()}function F(){u=null,k=null,p=null,H=null,Dn(),Ae&&(Ae.style.display="flex",Ae.innerHTML=` +var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams(location.search),T={};g.has("track")&&(T.track=g.get("track")),g.has("map")&&(T.map=g.get("map")),g.has("xaxis")&&(T.xaxis=g.get("xaxis")),g.has("tab")&&(T.tab=g.get("tab")),g.has("sel_point")&&(T.sel_point=Number(g.get("sel_point"))),g.has("speed_mode")&&(T.speed_mode=g.get("speed_mode")),g.has("progress")&&(T.progress=g.get("progress"));let $=g.get("metrics");if($&&(T.metrics=$.split(",").filter(Boolean)),g.has("f_date")&&(T.f_date=g.get("f_date").split(",").map(M=>M||null)),g.has("f_dist")&&(T.f_dist=g.get("f_dist").split(",").map(M=>M?Number(M):null)),g.has("f_dur")&&(T.f_dur=g.get("f_dur").split(",").map(M=>M?Number(M):null)),g.has("f_mets")&&(T.f_mets=g.get("f_mets").split(",")),g.has("f_tags")&&(T.f_tags=g.get("f_tags").split(",")),g.has("q")&&(T.q=g.get("q")),g.has("re")&&(T.re=g.get("re")==="1"),g.has("sort")){let M=g.get("sort"),C=M.startsWith("-"),k=C?M.substring(1):M;T.sort=`${k}-${C?"desc":"asc"}`}if(g.has("map_pos")){let M=g.get("map_pos").split(",").map(Number);M.length===3&&M.every(isFinite)&&(T.map_pos=M)}if(g.has("storage")&&(T.storage=g.get("storage")),g.has("sel")){let M=g.get("sel").split(",").map(Number);M.length===2&&M.every(C=>!isNaN(C)&&isFinite(C))&&(T.sel=M)}return T}function a(){t&&(clearTimeout(t),t=null);let g=new URLSearchParams;if(e.track&&g.set("track",e.track),e.map&&g.set("map",e.map),e.xaxis&&e.xaxis!=="time"&&g.set("xaxis",e.xaxis),e.tab&&e.tab!=="graphs"&&g.set("tab",e.tab),e.storage&&e.storage!=="memory"&&g.set("storage",e.storage),e.sel_point!==void 0&&g.set("sel_point",String(e.sel_point)),e.speed_mode&&g.set("speed_mode",e.speed_mode),e.q&&g.set("q",e.q),e.progress&&g.set("progress",e.progress),e.re&&g.set("re","1"),e.sort){let $=e.sort.split("-"),M=$[0],C=$[1];g.set("sort",(C==="desc"?"-":"")+M)}let T=g.toString();if(e.metrics&&(T+=`${T?"&":""}metrics=${e.metrics.join(",")}`),e.f_date&&(T+=`${T?"&":""}f_date=${e.f_date.map($=>$||"").join(",")}`),e.f_dist&&(T+=`${T?"&":""}f_dist=${e.f_dist.map($=>$??"").join(",")}`),e.f_dur&&(T+=`${T?"&":""}f_dur=${e.f_dur.map($=>$??"").join(",")}`),e.f_mets&&(T+=`${T?"&":""}f_mets=${e.f_mets.join(",")}`),e.f_tags&&(T+=`${T?"&":""}f_tags=${e.f_tags.join(",")}`),e.map_pos){let $=`${(+e.map_pos[0]).toFixed(5)},${(+e.map_pos[1]).toFixed(5)},${e.map_pos[2]}`;T+=`${T?"&":""}map_pos=${$}`}if(e.sel){let $=`${+e.sel[0].toFixed(4)},${+e.sel[1].toFixed(4)}`;T+=`${T?"&":""}sel=${$}`}if(T!==n){let $=location.pathname+(T?`?${T}`:"");try{s?(history.pushState(null,"",$),s=!1):history.replaceState(null,"",$)}catch{s=!1}n=T}}e=o();function p(){return{...e}}function c(g,T=!1){T&&(s=!0);for(let[$,M]of Object.entries(g)){let C=$;M==null?delete e[C]:e[C]=M}a()}function d(){e=o()}function x(){t&&(clearTimeout(t),t=null),e={},s=!1,n="";try{history.replaceState(null,"",location.pathname)}catch{}}return{get:p,patch:c,refresh:d,reset:x}})();var gs=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(n){return this.trackStore.set(n.id,n),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(n){return this.trackStore.delete(n),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(n,t){return this.settingStore.set(n,t),Promise.resolve()}async get(n){return Promise.resolve(this.settingStore.get(n)??null)}},Fs=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((n,t)=>{let s=indexedDB.open(this.DB_NAME,this.DB_VERSION);s.onupgradeneeded=()=>{let o=s.result;o.objectStoreNames.contains("tracks")||o.createObjectStore("tracks",{keyPath:"id"}),o.objectStoreNames.contains("settings")||o.createObjectStore("settings")},s.onsuccess=()=>{this.db=s.result,n()},s.onerror=()=>t(s.error)})}getStore(n,t){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(n,t).objectStore(n)}async save(n){return new Promise((t,s)=>{let o=this.getStore("tracks","readwrite").put(n);o.onsuccess=()=>t(),o.onerror=()=>s(o.error)})}async getAll(){return new Promise((n,t)=>{let s=this.getStore("tracks","readonly").getAll();s.onsuccess=()=>n(s.result||[]),s.onerror=()=>t(s.error)})}async remove(n){return new Promise((t,s)=>{let o=this.getStore("tracks","readwrite").delete(n);o.onsuccess=()=>t(),o.onerror=()=>s(o.error)})}async clear(){return this.db?new Promise((n,t)=>{let s=this.db.transaction(["tracks","settings"],"readwrite");s.objectStore("tracks").clear(),s.objectStore("settings").clear(),s.oncomplete=()=>n(),s.onerror=()=>t(s.error)}):Promise.resolve()}async set(n,t){return new Promise((s,o)=>{let a=this.getStore("settings","readwrite").put(t,n);a.onsuccess=()=>s(),a.onerror=()=>o(a.error)})}async get(n){return new Promise((t,s)=>{let o=this.getStore("settings","readonly").get(n);o.onsuccess=()=>t(o.result??null),o.onerror=()=>s(o.error)})}},nn=new gs,at={openDB:async()=>{nn=Ye.get().storage==="indexeddb"?new Fs:new gs,await nn.openDB()},save:e=>nn.save(e),getAll:()=>nn.getAll(),remove:e=>nn.remove(e),clear:()=>nn.clear(),set:(e,n)=>nn.set(e,n),get:e=>nn.get(e)};import Eo from"fit-file-parser";function sn(e,n,t,s){let a=e*Math.PI/180,p=t*Math.PI/180,c=(t-e)*Math.PI/180,d=(s-n)*Math.PI/180,x=Math.sin(c/2)*Math.sin(c/2)+Math.cos(a)*Math.cos(p)*Math.sin(d/2)*Math.sin(d/2);return 6371e3*(2*Math.atan2(Math.sqrt(x),Math.sqrt(1-x)))}function pl(e){let n=new Uint32Array([Math.floor(e/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(n.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function fl(){return Math.random().toString(36).slice(2,6)}function _t(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:`${Math.round(e/3600)}h`}function ht(e){let n=Math.floor(e/3600),t=Math.floor(e%3600/60);return n>0?`${n}h ${t}m`:`${t}m ${Math.floor(e%60)}s`}function On(e){if(e==null||!isFinite(e))return"--";let n=Math.floor(e/60),t=Math.round(e%60);return`${n}:${t.toString().padStart(2,"0")}`}function Gt(e){let n=new Date(e);return isNaN(n.getTime())?"Unknown date":n.toISOString().split("T")[0]}function gl(e){let n=new Date(e);if(isNaN(n.getTime()))return"Unknown";let t=n.toISOString();return`${t.split("T")[0]} ${t.split("T")[1].slice(0,5)}`}function hl(e){if(e===0)return"0 B";let n=1024,t=["B","KB","MB","GB"],s=Math.floor(Math.log(e)/Math.log(n));return`${parseFloat((e/Math.pow(n,s)).toFixed(2))} ${t[s]}`}function pt(e){return String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function hs(e){let n=0;for(let s=0;s=0&&T0?d/x:e[c]}return p}function tt(e,n=1){let t=parseInt(e.slice(1,3),16),s=parseInt(e.slice(3,5),16),o=parseInt(e.slice(5,7),16);return`rgba(${t}, ${s}, ${o}, ${n})`}function bs(e){if(!e.length)return null;let n=e[0].lat,t=e[0].lat,s=e[0].lon,o=e[0].lon;for(let a of e)a.latt&&(t=a.lat),a.lono&&(o=a.lon);return{minLat:n,maxLat:t,minLon:s,maxLon:o}}var $t=16384,So=new Float64Array($t),Mo=new Float64Array($t),ko=new Float64Array($t),Co=new Float64Array($t),$o=new Float64Array($t),Lo=new Float64Array($t),Po=new Float64Array($t);function vs(e,n){let t=e.length;if(t<=2)return e;let s=t<=$t?So:new Float64Array(t),o=t<=$t?Mo:new Float64Array(t),a=t<=$t?ko:new Float64Array(t),p=t<=$t?Co:new Float64Array(t);for(let M=0;M=f){let q=F+v>>1,_=(o[q]-(o[F]+o[v])*.5)*u,W=s[q]-(s[F]+s[v])*.5;d+=Math.sqrt(_*_+W*W)+(p[v]-p[F])*1e-6,F=v}}}}let g=[e[0]],T=e[0],$=d<-1e9?1e-9:0;for(let M=1;M=n&&(g.push(C),T=C)}return g.push(e[t-1]),g}var ot=(()=>{function e(y){let m=y.length,r=0;for(let J=0;J0){let ee=y[J-1],U=sn(ee.lat,ee.lon,V.lat,V.lon);if(r+=U,V.speed==null&&V.time!=null&&ee.time!=null){let Q=(V.time-ee.time)/1e3;Q>0&&Q<10&&(V.speed=U/Q)}if(V.gradient===void 0&&V.ele!=null&&ee.ele!=null){let Q=V.ele-ee.ele;U>.5?V.gradient=Q/U*100:V.gradient=ee.gradient||0}}V.dist=r}if(m>2){let J=m<=$t?$o:new Float64Array(m),V=m<=$t?Lo:new Float64Array(m),ee=m<=$t?Po:new Float64Array(m);for(let re=0;re=me){Pe-=V[H-me],j-=ee[H-me];let oe=Pe*fe,ge=J[H]-J[H-me],K=1.225*Math.exp(-J[H]*Fe),Ie=Math.atan2(ge,(j+1)*.5);Q+=oe*oe*K*1e-4+Ie*(j*fe)*.01}}}let ke=Q<-1e12?1e-9:0;for(let re=1;re0){let He=y[Ie-1];if(he.ele!=null&&He.ele!=null){let Ce=he.ele-He.ele;Ce>0?r.elevGain+=Ce:r.elevLoss-=Ce}(he.gearFront!=null&&he.gearFront!==He.gearFront||he.gearRear!=null&&he.gearRear!==He.gearRear)&&H++}he.power!=null&&(J+=he.power,V++,he.power>r.maxPower&&(r.maxPower=he.power)),he.hr!=null&&(ee+=he.hr,U++,he.hr>r.maxHR&&(r.maxHR=he.hr)),he.cad!=null&&(Q+=he.cad,ke++),he.speed!=null&&(re+=he.speed,Fe++,he.speed>r.maxSpeed&&(r.maxSpeed=he.speed)),he.battery!=null&&(se+=he.battery,me++),he.temp!=null&&(j=!0,fe+=he.temp,Pe++,(r.minTemp==null||he.tempr.maxTemp)&&(r.maxTemp=he.temp)),(he.gearFront!=null||he.gearRear!=null)&&(oe=!0)}r.totalDist=y[y.length-1].dist||0,r.avgPower=V?Math.round(J/V):null,r.avgHR=U?Math.round(ee/U):null,r.avgCadence=ke?Math.round(Q/ke):null,r.avgSpeed=Fe?re/Fe:null,r.avgBattery=me?Math.round(se/me):null,r.avgTemp=Pe?Number((fe/Pe).toFixed(1)):null,r.shifts=oe?H:null;let ge=y[0].time,K=y[y.length-1].time;return ge!=null&&K!=null&&(r.duration=K-ge),U&&(r.sensors.push("Heart Rate"),m&&(r.hrZones=$(y),r.hrCurve=d(y))),ke&&r.sensors.push("Cadence"),V&&(r.sensors.push("Power"),m&&(r.powerCurve=c(y),r.powerZones=x(y))),j&&r.sensors.push("Temperature"),oe&&r.sensors.push("Shifting"),me&&r.sensors.push("Battery"),r}function o(y){if(!y||!y.points||!y.stats)return;let m=y.points,r=y.stats;r.avgHR!=null&&!r.hrCurve&&(r.hrZones=$(m),r.hrCurve=d(m)),r.avgPower!=null&&!r.powerCurve&&(r.powerCurve=c(m),r.powerZones=x(m))}let a=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800,14400,18e3,21600];function p(y,m){let r=y.length;if(r===0)return null;let J=new Float64Array(r+1);for(let U=0;Ur)continue;let ke=0,re=0,Fe=r-Q;for(let se=0;se<=Fe;se++){let me=J[se+Q]-J[se];me>ke&&(ke=me,re=se)}V[Q]={val:Math.round(ke/Q),idx:re},ee=!0}return ee?V:null}function c(y){let m=y.length,r=new Array(m),J=!1;for(let U=0;UJ*t);for(let J=1;J10)continue;let Q=V.power;QJ===0)?null:m}function g(y){t=y}function T(){return t}function $(y){let m=[0,0,0,0,0];for(let r=1;r10)continue;let U=J.hr;Ur===0)?null:m}function M(y){n=y}function C(){return[...n]}function k(y,m,r){let J=y.indexOf(m);if(J===-1)return null;let V=J+m.length,ee=y.indexOf(r,V);if(ee===-1)return null;let U=y.slice(V,ee).trim();return U!==""?U:null}function f(y,m){let r=y.indexOf(m);if(r===-1)return null;let J=r+m.length,V=y.indexOf('"',J);return V===-1?null:y.slice(J,V)}let F=-1,v=0;function u(y,m,r){for(;mm&&y.charCodeAt(r-1)<=32;)r--;if(m>=r)return null;let J=!1,V=y.charCodeAt(m);V===45?(J=!0,m++):V===43&&m++;let ee=0,U=0;for(let Q=m;Q=48&&ke<=57)ee=ee*10+(ke-48),U++;else break}return U===0?null:J?-ee:ee}function w(y,m,r){for(;mm&&y.charCodeAt(r-1)<=32;)r--;if(m>=r)return null;let J=!1,V=y.charCodeAt(m);V===45?(J=!0,m++):V===43&&m++;let ee=0,U=0,Q=1,ke=!1,re=0;for(let se=m;se=48&&me<=57)re++,ke?(U=U*10+(me-48),Q*=10):ee=ee*10+(me-48);else if(me===46&&!ke)ke=!0;else{let fe=parseFloat(y.slice(m-(J?1:0),r));return Number.isFinite(fe)?fe:null}}if(re===0)return null;let Fe=ee+U/Q;return J?-Fe:Fe}function E(y,m,r){for(;mm&&y.charCodeAt(r-1)<=32;)r--;let J=r-m;if(J>=20&&y.charCodeAt(m+10)===84&&y.charCodeAt(r-1)===90){let ee=(y.charCodeAt(m)-48)*1e3+(y.charCodeAt(m+1)-48)*100+(y.charCodeAt(m+2)-48)*10+(y.charCodeAt(m+3)-48),U=(y.charCodeAt(m+5)-48)*10+(y.charCodeAt(m+6)-48),Q=(y.charCodeAt(m+8)-48)*10+(y.charCodeAt(m+9)-48),ke=ee<<9|U<<5|Q;ke!==F&&(F=ke,v=Date.UTC(ee,U-1,Q));let re=(y.charCodeAt(m+11)-48)*10+(y.charCodeAt(m+12)-48),Fe=(y.charCodeAt(m+14)-48)*10+(y.charCodeAt(m+15)-48),se=(y.charCodeAt(m+17)-48)*10+(y.charCodeAt(m+18)-48),me=0;return y.charCodeAt(m+19)===46&&J>=24&&(me=(y.charCodeAt(m+20)-48)*100+(y.charCodeAt(m+21)-48)*10+(y.charCodeAt(m+22)-48)),v+re*36e5+Fe*6e4+se*1e3+me}let V=new Date(y.slice(m,r)).getTime();return Number.isFinite(V)?V:null}function N(y,m,r,J){let V=y.indexOf(J,m);if(V===-1||V>=r)return 0;let ee=V+J.length,U=y.indexOf('"',ee);return U===-1||U>=r?0:w(y,ee,U)??0}function G(y,m){let r=m??new TextDecoder().decode(y),J=r.indexOf(""),U=(ee!==-1?k(V.slice(ee),"",""):null)||k(V,"","")||"Unnamed Track",Q=V.indexOf(">",V.indexOf("",fe+6);if(Pe===-1)break;let j=r.indexOf("",Pe+1);if(j===-1)break;Fe=j+8;let H=N(r,fe+6,Pe+1,'lat="'),oe=N(r,fe+6,Pe+1,'lon="'),ge=null,K=null,Ie=null,he=null,He=null,Ce=null,Re=null,le=null,ye=null,I=null,ne=null,Ne=null,Z=Pe+1;for(;Z=j)break;let Ee=r.indexOf(">",xe+1);if(Ee===-1||Ee>=j)break;let Me=r.charCodeAt(xe+1);if(Me===47){Z=Ee+1;continue}let be=Ee-xe-1;if(Me===103&&be===26&&Ie!==null&&he!==null&&Ce!==null)break;let we=r.indexOf("<",Ee+1);if(we===-1||we>j)break;if(r.charCodeAt(we+1)===47){let qe=Ee+1,je=we;be===3?Me===101?ge=w(r,qe,je):Me===99&&he===null&&(he=u(r,qe,je)):be===2?Me===104&&Ie===null&&(Ie=u(r,qe,je)):be===4?Me===116?r.charCodeAt(xe+2)===105?K=E(r,qe,je):Ce===null&&(Ce=w(r,qe,je)):Me===84&&Ce===null&&(Ce=w(r,qe,je)):be===5?(Me===112||Me===80||Me===87)&&He===null?He=w(r,qe,je):(Me===115||Me===83)&&Re===null?Re=w(r,qe,je):Me===97&&Ce===null&&(Ce=w(r,qe,je)):be===7?(Me===98||Me===66)&&Ne===null?Ne=u(r,qe,je):Me===67&&he===null&&(he=u(r,qe,je)):be===8?(Me===103||Me===71)&&ye===null&&(ye=u(r,qe,je)):be===9?Me===103?r.charCodeAt(xe+8)===104&&Ie===null?Ie=u(r,qe,je):le===null&&(le=u(r,qe,je)):Me===71&&le===null&&(le=u(r,qe,je)):be===10?(Me===103&&he===null||Me===82&&he===null)&&(he=u(r,qe,je)):be===12?Me===103&&r.charCodeAt(xe+8)===97&&Ce===null?Ce=w(r,qe,je):Me===80&&He===null?He=w(r,qe,je):Me===72&&Ie===null&&(Ie=u(r,qe,je)):be===13?(Me===103||Me===71)&&ne===null&&(ne=u(r,qe,je)):be===14?(Me===103||Me===71)&&I===null?I=u(r,qe,je):Me===65&&Ce===null&&(Ce=w(r,qe,je)):be===11&&Me===84&&Ce===null&&(Ce=w(r,qe,je));let dt=we+2+be;if(r.charCodeAt(dt)===62)Z=dt+1;else{let At=r.indexOf(">",we+2);Z=At!==-1?At+1:we+2}if(Ne!==null&&Ie!==null&&he!==null&&Ce!==null)break}else Z=we}let Be=null;I!=null&&ne!=null&&ne!==0?Be=I/ne:le!=null&&ye!=null&&ye!==0&&(Be=le/ye),re.push({lat:H,lon:oe,ele:ge,time:K,hr:Ie,cad:he,power:He,speed:Re,temp:Ce,gearFront:le,gearRear:ye,gearFrontTooth:I,gearRearTooth:ne,battery:Ne,gears:Be})}if(!re.length)throw new Error("No track points found in GPX");let se=e(re),me=s(se);return{name:U,device:ke,format:"gpx",points:se,stats:me}}function q(y,m){let r=m??new TextDecoder().decode(y),J=r.indexOf(""),V=J!==-1?r.slice(0,J):r,ee=k(V,"","")||"Unnamed TCX",U=k(V,"",""),Q=U?k(U,"",""):null,ke=[],re=J!==-1?J:0;for(;re",re);if(me===-1)break;let fe=r.indexOf("",me+12);if(fe===-1)break;re=fe+13;let Pe=null,j=null,H=null,oe=null,ge=null,K=null,Ie=null,he=null,He=null,Ce=null,Re=null,le=null,ye=null,I=null,ne=me+12;for(;ne=fe)break;let Be=r.indexOf(">",Z+1);if(Be===-1||Be>=fe)break;let xe=r.charCodeAt(Z+1);if(xe===47){ne=Be+1;continue}let Ee=Be-Z-1,Me=r.indexOf("<",Be+1);if(Me===-1||Me>fe)break;if(r.charCodeAt(Me+1)===47){let be=Be+1,we=Me;Ee===4?xe===84?r.charCodeAt(Z+2)===105?oe=E(r,be,we):He===null&&(He=w(r,be,we)):xe===116&&He===null&&(He=w(r,be,we)):Ee===5?xe===86&&ge===null?ge=u(r,be,we):(xe===87||xe===80||xe===112)&&Ie===null?Ie=w(r,be,we):(xe===83||xe===115)&&he===null?he=w(r,be,we):xe===97&&He===null&&(He=w(r,be,we)):Ee===7?xe===67&&K===null?K=u(r,be,we):(xe===66||xe===98)&&I===null&&(I=u(r,be,we)):Ee===8?(xe===71||xe===103)&&Re===null&&(Re=u(r,be,we)):Ee===9?(xe===71||xe===103)&&Ce===null&&(Ce=u(r,be,we)):Ee===10?xe===82&&K===null&&(K=u(r,be,we)):Ee===11?xe===84&&He===null&&(He=w(r,be,we)):Ee===13?(xe===71||xe===103)&&ye===null&&(ye=u(r,be,we)):Ee===14?xe===65?r.charCodeAt(Z+2)===108?H=w(r,be,we):He===null&&(He=w(r,be,we)):(xe===71||xe===103)&&le===null&&(le=u(r,be,we)):Ee===15?xe===76&&(Pe=w(r,be,we)):Ee===16?xe===76&&(j=w(r,be,we)):Ee===2&&xe===104&&ge===null?ge=u(r,be,we):Ee===3&&xe===99&&K===null?K=u(r,be,we):Ee===12&&(xe===72&&ge===null?ge=u(r,be,we):xe===80&&Ie===null&&(Ie=w(r,be,we)));let qe=Me+2+Ee;if(r.charCodeAt(qe)===62)ne=qe+1;else{let je=r.indexOf(">",Me+2);ne=je!==-1?je+1:Me+2}if(I!==null&&ge!==null&&K!==null&&He!==null)break}else ne=Me}if(Pe==null||j==null)continue;let Ne=null;le!=null&&ye!=null&&ye!==0?Ne=le/ye:Ce!=null&&Re!=null&&Re!==0&&(Ne=Ce/Re),ke.push({lat:Pe,lon:j,ele:H,time:oe,hr:ge,cad:K,power:Ie,speed:he,temp:He,gearFront:Ce,gearRear:Re,gearFrontTooth:le,gearRearTooth:ye,battery:I,gears:Ne})}let Fe=e(ke),se=s(Fe);return{name:ee,device:Q,format:"tcx",points:Fe,stats:se}}function _(y){if(y.byteLength<14)return null;let m=new DataView(y),r=m.getUint8(0);if(r<12||r+2>y.byteLength||m.getUint8(8)!==46||m.getUint8(9)!==70||m.getUint8(10)!==73||m.getUint8(11)!==84)return null;let J=m.getUint32(4,!0),V=Math.min(y.byteLength,r+J),ee=631065600,U=180/Math.pow(2,31),Q=new Array(16),ke=[],re=[],Fe=[],se=[],me=[],fe=r;for(;feV)return null;fe++;let oe=m.getUint8(fe++)===0,ge=m.getUint16(fe,oe);fe+=2;let K=m.getUint8(fe++);if(fe+K*3>V)return null;let Ie=new Array(K),he=0;for(let He=0;HeV)return null;let oe=H.littleEndian,ge=H.globalMsgNum;if(ge===20&&H.fields.length===10&&H.recordSize===25&&H.fields[0].num===253&&H.fields[1].num===0){let he=m.getUint32(fe,oe),He=m.getInt32(fe+4,oe),Ce=m.getInt32(fe+8,oe),Re=m.getUint16(fe+12,oe),le=m.getUint8(fe+14),ye=m.getUint8(fe+15),I=m.getUint32(fe+16,oe),ne=m.getUint16(fe+20,oe),Ne=m.getUint16(fe+22,oe),Z=m.getInt8(fe+24);Fe.push({timestamp:(he+ee)*1e3,position_lat:He*U,position_long:Ce*U,altitude:Re/5-500,heart_rate:le,cadence:ye,distance:I/100,speed:ne/1e3*3.6,power:Ne,temperature:Z}),fe+=25;continue}let K={},Ie=fe;for(let he=0;he{let J=(U,Q)=>{if(U){r(U);return}try{let ke=Q.sessions?.[0]?.start_time?`Fit Activity ${new Date(Q.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",re=null,Fe=[],se=null,me=null;Q.sports?.[0]?(se=Q.sports[0].sport,me=Q.sports[0].sub_sport):Q.sessions?.[0]&&(se=Q.sessions[0].sport,me=Q.sessions[0].sub_sport);let fe=I=>I.product_name||I.garmin_product||I.product||I.device_type||I.manufacturer||null;if(Q.file_ids?.[0]){let I=Q.file_ids[0];re=fe(I),Fe.push({name:I.product_name||I.garmin_product||I.product,manufacturer:I.manufacturer,serial:I.serial_number?String(I.serial_number):void 0,version:I.software_version?String(I.software_version):void 0,type:"main"})}Q.device_infos&&Q.device_infos.forEach(I=>{if(I.device_index==="creator"||I.device_index===0){let Ne=fe(I);(I.product_name||I.garmin_product||!re)&&(re=Ne),Fe.length>0&&Fe[0].type==="main"&&((I.product_name||I.garmin_product||!Fe[0].name)&&(Fe[0].name=I.product_name||I.garmin_product||I.product),Fe[0].manufacturer||(Fe[0].manufacturer=I.manufacturer),!Fe[0].serial&&I.serial_number&&(Fe[0].serial=String(I.serial_number)),!Fe[0].version&&I.software_version&&(Fe[0].version=String(I.software_version)),!Fe[0].hardwareVersion&&I.hardware_version&&(Fe[0].hardwareVersion=String(I.hardware_version)));return}Fe.push({name:I.product_name||I.garmin_product||I.product||I.device_type||"Sensor",manufacturer:I.manufacturer,serial:I.serial_number?String(I.serial_number):void 0,version:I.software_version?String(I.software_version):void 0,hardwareVersion:I.hardware_version?String(I.hardware_version):void 0,type:I.device_type||"sensor",batteryStatus:I.battery_status,batteryVoltage:I.battery_voltage,batteryLevel:I.battery_level,sourceType:I.source_type!=null?String(I.source_type):void 0})}),Q.sensor_settings&&Q.sensor_settings.forEach(I=>{let ne=I.name||I.product||I.sensor_type;if(!ne)return;let Ne=I.ant_id?String(I.ant_id):void 0,Z=Fe.find(Be=>Ne&&Be.serial===Ne||Be.name===ne&&Be.manufacturer===I.manufacturer);Z?(Z.name||(Z.name=ne),Z.manufacturer||(Z.manufacturer=I.manufacturer),Z.type||(Z.type=I.sensor_type),Z.sourceType||(Z.sourceType=I.connection_type!=null?String(I.connection_type):void 0)):Fe.push({name:ne,manufacturer:I.manufacturer,serial:Ne,type:I.sensor_type||"sensor",sourceType:I.connection_type!=null?String(I.connection_type):void 0})});let Pe=[];Q.device_statuses&&(Q.device_statuses.forEach((I,ne)=>{I.timestamp&&I.battery_level!=null&&Pe.push({time:typeof I.timestamp=="number"?I.timestamp:new Date(I.timestamp).getTime(),level:I.battery_level,idx:ne})}),Pe.sort((I,ne)=>I.time-ne.time||I.idx-ne.idx));let j=[];Q.events&&(Q.events.forEach((I,ne)=>{let Ne=I.front_gear_num??I.front_gear??null,Z=I.rear_gear_num??I.rear_gear??null,Be=I.front_gear_num_tooth??null,xe=I.rear_gear_num_tooth??null;if(I.event==="rear_gear_change"||I.event==="front_gear_change"){let Ee=I.data;if(Ee!=null){let Me=Ee>>24&255,be=Ee>>16&255,we=Ee>>8&255,qe=Ee&255;be!==0&&(Ne=be),Me!==0&&(Be=Me),qe!==0&&(Z=qe),we!==0&&(xe=we)}}I.timestamp&&(Ne!=null||Z!=null||Be!=null||xe!=null)&&j.push({time:typeof I.timestamp=="number"?I.timestamp:new Date(I.timestamp).getTime(),front:Ne,rear:Z,frontTooth:Be,rearTooth:xe,idx:ne})}),j.sort((I,ne)=>I.time-ne.time||I.idx-ne.idx));let H=Q.records||[],oe=null,ge=0,K=null,Ie=null,he=null,He=null,Ce=0,Re=[];for(let I=0;I name, Placemark > name");V&&(J=V.textContent?.trim()||J);let ee=r.querySelectorAll("coordinates");if(!ee.length)throw new Error("No coordinates found in KML");let U=[];if(ee.forEach(re=>{(re.textContent?.trim().split(/\s+/)||[]).forEach(se=>{let me=se.split(",");if(me.length<2)return;let fe=parseFloat(me[0]),Pe=parseFloat(me[1]),j=me.length>2?parseFloat(me[2]):null;isNaN(Pe)||isNaN(fe)||U.push({lat:Pe,lon:fe,ele:j!=null&&isNaN(j)?null:j,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!U.length)throw new Error("No valid coordinates in KML");let Q=e(U),ke=s(Q);return{name:J,format:"kml",points:Q,stats:ke}}async function de(y){let m=y.name.split(".").pop()?.toLowerCase(),r=y._buf??await y.arrayBuffer(),J=y._text,V;switch(m){case"gpx":V=G(r,J);break;case"tcx":V=q(r,J);break;case"fit":V=await W(r);break;case"kml":V=z(r);break;default:throw new Error(`Unsupported format: .${m}`)}return V&&(V.fileName=y.name,V.fileSize=y.size),V}return{parseFile:de,computeStats:s,ensureCurvesAndZones:o,calculatePowerCurve:c,calculateHRCurve:d,calculatePowerZones:x,calculateHRZones:$,enrichPoints:e,setHRZones:M,getHRZones:C,setFTP:g,getFTP:T}})();var De=(()=>{let e={},n=null;function t(z,de,y,m,r){}function s(z){}function o(z){e[z.id]=z}function a(z){z.forEach(de=>{e[de.id]=de})}function p(z){delete e[z]}function c(){e={}}function d(){e={}}function x(z,de){}function g(z,de){}function T(){}function $(z){}function M(z,de){}function C(){}function k(z,de,y,m,r,J){}function f(){}function F(z,de){}function v(z){}function u(z,de,y,m){}function w(){}function E(){}function N(){return[0,0,0]}function G(z,de,y){}function q(z,de,y){}function _(z){}function W(z,de){return Object.keys(e)}return{init:t,getMap:()=>null,setCustomClickHandler:z=>{n=z},switchBasemap:s,addTrack:o,addTracks:a,removeTrack:p,clearTracks:c,removeAllTracks:d,setTrackVisible:x,setSelectedTrack:g,fitAll:T,fitTrack:$,showCursorAt:M,hideCursor:C,highlightSegment:k,clearHighlight:f,setTrackHover:F,ensureVisible:v,centerOn:u,closePopup:w,invalidateSize:E,getPosition:N,setPosition:G,colorTrackByMetric:q,clearMetricColor:_,findTracksPassingThroughPoints:W,getTrackData:z=>e[z]}})();import vl from"uplot";var Sn=(()=>{function e(){let t=ot.getFTP(),s=[.55,.75,.9,1.05,1.2,1.5].map(d=>d*t),o=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],a=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],p=[],c=0;for(let d=0;dn?e.toFixed(1):Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:We.speed.color,abbr:"spd",icon:We.speed.icon,fmt:e=>(e*3.6).toFixed(1),fmtAxis:e=>(e*3.6).toFixed(0),transform:e=>e,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:We.gradient.color,abbr:"grad",icon:We.gradient.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>e.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:We.power.color,abbr:"pwr",icon:We.power.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:We.hr.color,abbr:"hr",icon:We.hr.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:We.cadence.color,abbr:"cad",icon:We.cadence.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:We.temperature.color,abbr:"temp",icon:We.temperature.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>Math.round(e).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:We.gearRear.color,abbr:"rgr",icon:We.gearRear.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:We.gearFront.color,abbr:"fgr",icon:We.gearFront.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gears:{label:"Gears",field:"gears",unit:"",color:We.gears.color,abbr:"gr",icon:We.gears.icon,fmt:e=>e.toFixed(2),fmtAxis:e=>e.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:We.battery.color,abbr:"bat",icon:We.battery.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString(),smoothSigma:5,compute:(e,n)=>{let t=new Array(e.length).fill(null);for(let s=1;s0&&(t[s]=p/c*3600)}}return n(t)}}};var Nt={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function bl(e){if(!e)return"question_mark";let n=e.toLowerCase();return Nt[n]?.icon||"exercise"}var Se=(()=>{let e=[],n=null,t="time",s="speed",o=null,a=null,p=!1,c=!1,d=new Set(["elevation"]),x=new Set,g=new Set(["speed","gradient","vam","temperature"]),T=new Set(["power"]),$="time",M=null,C=[],k=null,f=null,F=!1,v=!1,u=null,w=null,E=null,N=null,G=null,q=null,_=null,W=null,z=null,de=null,y=null,m=null,r=130,J=28,V=20,ee=!0,U=null,Q=null,ke=null,re=null,Fe=null,se=null,me=null;function fe(l,i,h,b){z=l,de=i,y=h,m=b,Q=document.getElementById("charts-container"),Q?.addEventListener("scroll",()=>{E&&G&&N&&wn(E,G,N)}),ke=document.getElementById("chart-empty"),re=document.getElementById("chart-stats-sel"),Fe=document.getElementById("btn-reset-selection"),U=document.getElementById("hist-tooltip"),a=vl.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",ne),Fe?.classList.add("hidden");let A=new Set(["w","a","s","d"]),S=new Set;document.addEventListener("keydown",B=>{if(!e.length||!M||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let P=B.key.toLowerCase();if(!A.has(P))return;B.preventDefault(),S.add(P);let R=e[0].uplot;_||(_=[R.scales.x.min,R.scales.x.max]);let[X,O]=_,Y=(O-X)*.1,ie=.15,L=X,Te=O;if(P==="a")L=X-Y,Te=O-Y;else if(P==="d")L=X+Y,Te=O+Y;else if(P==="w"||P==="s"){let ce=w!==null?w:(X+O)/2,_e=P==="w"?1-ie:1+ie*1.2;L=ce-(ce-X)*_e,Te=ce+(O-ce)*_e}let ae=[e[0].xData[0],e[0].xData[e[0].xData.length-1]];if(Lae[1]){let ce=Te-ae[1];L-=ce,Te-=ce}L=Math.max(ae[0],L),Te=Math.min(ae[1],Te),Te-L>.001&&(_=[L,Te],Pe(L,Te,!0))}),document.addEventListener("keyup",B=>{let P=B.key.toLowerCase();A.has(P)&&S.delete(P)})}function Pe(l,i,h=!1){if(!e.length)return;if(!h){e.forEach(({uplot:R})=>R.setScale("x",{min:l,max:i}));return}let b=q?q[0]:e[0].uplot.scales.x.min,A=q?q[1]:e[0].uplot.scales.x.max;W&&cancelAnimationFrame(W);let S=(R,X,O)=>R+(X-R)*O,B=.25,P=()=>{if(!_)return;let[R,X]=_,O=S(q[0],R,B),D=S(q[1],X,B);e.forEach(({uplot:Y})=>{Y.setScale("x",{min:O,max:D})}),Math.abs(O-R)>1e-4||Math.abs(D-X)>1e-4?W=requestAnimationFrame(P):W=null};W=requestAnimationFrame(P)}function j(l,i=[],h=!1){u=null,k=null,f=null,C=i,x=new Set(Object.entries(Ft).filter(([,b])=>l.points.some(A=>A[b.field]!=null)).map(([b])=>b)),d.size===0&&(d=new Set(["elevation"].filter(b=>x.has(b)))),document.querySelectorAll(".metric-pill").forEach(b=>{let A=b,S=A.dataset.metric,B=x.has(S);A.classList.toggle("active",B&&d.has(S)),A.classList.toggle("disabled",!B)}),M=l,h?ol(l):Ee()}function H(){u=null,k=null,f=null,M=null,Rn(),ke&&(ke.style.display="flex",ke.innerHTML=` no_sim
Select a track to view analysis
- `);let l=document.getElementById("chart-stats");l&&l.classList.add("hidden"),j(),oe=null,de&&de(null)}function ae(){q!==null&&(cancelAnimationFrame(q),q=null),m=new Set(["elevation"]),T=new Set,f=new Set(["speed","gradient","vam","temperature"]),M=new Set(["power"]),O="time",E=[],_=null,C=null,x=null,w=null,D=null,W=null,Q=!0,F(),document.querySelectorAll("#metric-pills .metric-pill").forEach(h=>{let v=h;v.classList.toggle("active",m.has(v.dataset.metric)),v.classList.remove("disabled","overflow-hidden")});let l=document.getElementById("pill-overflow");l&&l.classList.add("hidden");let i=document.getElementById("chart-toolbar");i&&i.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(h=>{h.classList.toggle("active",h.dataset.axis==="time")})}function ue(l){m.has(l)?m.delete(l):m.add(l),H&&Ee(!0)}function te(l){m=new Set(l),H&&Ee(!0),document.querySelectorAll(".metric-pill").forEach(i=>{let h=i;h.classList.toggle("active",m.has(h.dataset.metric))})}function Ie(l){if(O===l||!H){O=l;return}let i=H.points,h=i.find(S=>S.time!=null)?.time||0,v=S=>{if(S===null)return null;let B=0;if(O==="distance"){let $=S*1e3;B=i.findIndex(R=>(R.dist||0)>=$)}else{let $=h+S*1e3;B=i.findIndex(R=>(R.time||0)>=$)}return B===-1&&(B=i.length-1),l==="distance"?(i[B].dist||0)/1e3:((i[B].time||h)-h)/1e3};k!==null&&(k=v(k)),p!==null&&(p=v(p));let L=null;if(e.length){let S=e[0].uplot,B=v(S.scales.x.min),$=v(S.scales.x.max);B!==null&&$!==null&&(L=[B,$])}O=l,Ee(!0),L&&(g=!0,e.forEach(({uplot:S})=>{S.batch(()=>S.setScale("x",{min:L[0],max:L[1]}))}),g=!1)}function he(){Q=!Q,e.forEach(({histCol:l})=>l.classList.toggle("visible",Q)),we()}function He(l){de=l}function Ce(l){oe===l||l===null?(oe=null,Re(),de&&de(null)):(oe=l,Re(),le()),H&&Ee(!0)}function Re(){document.querySelectorAll(".map-color-btn").forEach(l=>{let i=l;i.classList.toggle("active",i.dataset.metric===oe)})}function le(){if(!de||!oe||!H)return;let l=e.find(h=>h.metricKey===oe);if(!l)return;let i=be(oe,l.yData);de({pts:H.points,colors:i})}function be(l,i){let h=i.filter(V=>V!=null&&isFinite(V));if(!h.length)return i.map(()=>"#888896");let v=Math.min(...h),L=Math.max(...h),S=H?.sport,B=S?Nt[S.toLowerCase()]:null,$=B?.defaultPreset||"speed",Z=Ye.get().speed_mode||$,z=B?.paceUnit||"km";return i.map(V=>{if(V==null||!isFinite(V))return"#888896";if(l==="gradient")return Kn(V);if(l==="speed"){if(Z==="pace"){let fe=(z==="km"?1e3:100)/V;return sl(fe)}return sl(V)}let X=L===v?.5:Math.max(0,Math.min(1,(V-v)/(L-v)));return X<=.25?Dt("#4575b4","#91bfdb",X/.25):X<=.5?Dt("#91bfdb","#fee090",(X-.25)/.25):X<=.75?Dt("#fee090","#fc8d59",(X-.5)/.25):Dt("#fc8d59","#d73027",(X-.75)/.25)})}function A(){ne()}function ne(){k=null,p=null,u=null,d&&d(null),e.forEach(l=>{l.pinnedHistY=null}),ve(),At(),g=!0,e.forEach(({uplot:l,xData:i})=>{l.batch(()=>l.setScale("x",{min:i[0],max:i[i.length-1]})),l._strasse?.updateHeaderStats(i[0],i[i.length-1])}),g=!1,ie&&ie(null,null,O)}function Ne(l){if(!me)return;let i=(h,v)=>{let L=document.querySelector(`#${h} .stat-value`);L&&(L.textContent=v)};i("sel-distance",l.totalDist!=null?`${(l.totalDist/1e3).toFixed(1)} km`:"\u2014"),i("sel-duration",l.duration!=null?ht(Math.floor(l.duration/1e3)):"\u2014"),i("sel-elevation",l.elevGain!=null?`${Math.round(l.elevGain)} m`:"\u2014"),i("sel-avg-speed",l.avgSpeed!=null?`${(l.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),i("sel-avg-power",l.avgPower!=null?`${l.avgPower} W`:"\u2014"),i("sel-avg-hr",l.avgHR!=null?`${l.avgHR} bpm`:"\u2014"),i("sel-avg-temp",l.avgTemp!=null?`${l.avgTemp.toFixed(1)} \xB0C`:"\u2014"),me.classList.remove("hidden"),Fe&&Fe.classList.remove("hidden")}function j(){me&&me.classList.add("hidden"),Fe&&Fe.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(l=>{let i=document.querySelector(`#${l} .stat-value`);i&&(i.textContent="--")})}function _e(l,i,h=!1){if(!H)return;let v=H.points,L=v.find(Z=>Z.time!=null)?.time||0,S=((v[v.length-1]?.time||0)-L)/1e3;l>1e12&&(l=(l-L)/1e3),i>1e12&&(i=(i-L)/1e3),l=Math.max(0,Math.min(l,S)),i=Math.max(0,Math.min(i,S));let B=Z=>{if(O==="time")return Z;let z=L+Z*1e3,V=v.findIndex(X=>(X.time||0)>=z);return V===-1&&(V=v.length-1),(v[V].dist||0)/1e3},$=B(l),R=B(i);k=$,p=R,_=[$,R],!h&&(g=!0,e.forEach(({uplot:Z})=>{Z.batch(()=>Z.setScale("x",{min:$,max:R}))}),g=!1,Me(),At())}function we(){if(!e.length||!K)return;let l=Math.round(Math.max(100,K.getBoundingClientRect().width-J-(Q?r+U:0))),i=!1;e.forEach(({uplot:h,histCanvas:v,histData:L})=>{l!==h.width&&(h.setSize({width:l,height:h.height}),i=!0,Q&&v&&L&&It(v,L,h.height))}),i&&ve()}function Ee(l=!1){let i=null,h=0;if(l&&K&&(h=K.scrollTop),l&&_)i=[_[0],_[1]];else if(l&&e.length){let ge=e[0].uplot;i=[ge.scales.x.min,ge.scales.x.max]}if(!H){Dn(l);return}let v=H.points;if(!v.length){Dn(l);return}let L=H?.sport,S=L?Nt[L.toLowerCase()]:null,B=S?.defaultPreset||"speed",R=Ye.get().speed_mode||B,Z=S?.paceUnit||"km",z=[...m].filter(ge=>v.some(re=>re[Ft[ge].field]!=null));if(!z.length){Dn(l),Ae&&(Ae.style.display="flex",Ae.innerHTML=` + `);let l=document.getElementById("chart-stats");l&&l.classList.add("hidden"),Z(),se=null,me&&me(null)}function oe(){W!==null&&(cancelAnimationFrame(W),W=null),d=new Set(["elevation"]),x=new Set,g=new Set(["speed","gradient","vam","temperature"]),T=new Set(["power"]),$="time",C=[],q=null,_=null,w=null,E=null,N=null,G=null,ee=!0,H(),document.querySelectorAll("#metric-pills .metric-pill").forEach(h=>{let b=h;b.classList.toggle("active",d.has(b.dataset.metric)),b.classList.remove("disabled","overflow-hidden")});let l=document.getElementById("pill-overflow");l&&l.classList.add("hidden");let i=document.getElementById("chart-toolbar");i&&i.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(h=>{h.classList.toggle("active",h.dataset.axis==="time")})}function ge(l){d.has(l)?d.delete(l):d.add(l),M&&Ee(!0)}function K(l){d=new Set(l),M&&Ee(!0),document.querySelectorAll(".metric-pill").forEach(i=>{let h=i;h.classList.toggle("active",d.has(h.dataset.metric))})}function Ie(l){if($===l||!M){$=l;return}let i=M.points,h=i.find(S=>S.time!=null)?.time||0,b=S=>{if(S===null)return null;let B=0;if($==="distance"){let P=S*1e3;B=i.findIndex(R=>(R.dist||0)>=P)}else{let P=h+S*1e3;B=i.findIndex(R=>(R.time||0)>=P)}return B===-1&&(B=i.length-1),l==="distance"?(i[B].dist||0)/1e3:((i[B].time||h)-h)/1e3};k!==null&&(k=b(k)),f!==null&&(f=b(f));let A=null;if(e.length){let S=e[0].uplot,B=b(S.scales.x.min),P=b(S.scales.x.max);B!==null&&P!==null&&(A=[B,P])}$=l,Ee(!0),A&&(p=!0,e.forEach(({uplot:S})=>{S.batch(()=>S.setScale("x",{min:A[0],max:A[1]}))}),p=!1)}function he(){ee=!ee,e.forEach(({histCol:l})=>l.classList.toggle("visible",ee)),xe()}function He(l){me=l}function Ce(l){se===l||l===null?(se=null,Re(),me&&me(null)):(se=l,Re(),le()),M&&Ee(!0)}function Re(){document.querySelectorAll(".map-color-btn").forEach(l=>{let i=l;i.classList.toggle("active",i.dataset.metric===se)})}function le(){if(!me||!se||!M)return;let l=e.find(h=>h.metricKey===se);if(!l)return;let i=ye(se,l.yData);me({pts:M.points,colors:i})}function ye(l,i){let h=i.filter(D=>D!=null&&isFinite(D));if(!h.length)return i.map(()=>"#888896");let b=Math.min(...h),A=Math.max(...h),S=M?.sport,B=S?Nt[S.toLowerCase()]:null,P=B?.defaultPreset||"speed",X=Ye.get().speed_mode||P,O=B?.paceUnit||"km";return i.map(D=>{if(D==null||!isFinite(D))return"#888896";if(l==="gradient")return es(D);if(l==="speed"){if(X==="pace"){let ie=(O==="km"?1e3:100)/D;return sl(ie)}return sl(D)}let Y=A===b?.5:Math.max(0,Math.min(1,(D-b)/(A-b)));return Y<=.25?Dt("#4575b4","#91bfdb",Y/.25):Y<=.5?Dt("#91bfdb","#fee090",(Y-.25)/.25):Y<=.75?Dt("#fee090","#fc8d59",(Y-.5)/.25):Dt("#fc8d59","#d73027",(Y-.75)/.25)})}function I(){ne()}function ne(){k=null,f=null,u=null,m&&m(null),e.forEach(l=>{l.pinnedHistY=null}),be(),At(),p=!0,e.forEach(({uplot:l,xData:i})=>{l.batch(()=>l.setScale("x",{min:i[0],max:i[i.length-1]})),l._strasse?.updateHeaderStats(i[0],i[i.length-1])}),p=!1,de&&de(null,null,$)}function Ne(l){if(!re)return;let i=(h,b)=>{let A=document.querySelector(`#${h} .stat-value`);A&&(A.textContent=b)};i("sel-distance",l.totalDist!=null?`${(l.totalDist/1e3).toFixed(1)} km`:"\u2014"),i("sel-duration",l.duration!=null?ht(Math.floor(l.duration/1e3)):"\u2014"),i("sel-elevation",l.elevGain!=null?`${Math.round(l.elevGain)} m`:"\u2014"),i("sel-avg-speed",l.avgSpeed!=null?`${(l.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),i("sel-avg-power",l.avgPower!=null?`${l.avgPower} W`:"\u2014"),i("sel-avg-hr",l.avgHR!=null?`${l.avgHR} bpm`:"\u2014"),i("sel-avg-temp",l.avgTemp!=null?`${l.avgTemp.toFixed(1)} \xB0C`:"\u2014"),re.classList.remove("hidden"),Fe&&Fe.classList.remove("hidden")}function Z(){re&&re.classList.add("hidden"),Fe&&Fe.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(l=>{let i=document.querySelector(`#${l} .stat-value`);i&&(i.textContent="--")})}function Be(l,i,h=!1){if(!M)return;let b=M.points,A=b.find(X=>X.time!=null)?.time||0,S=((b[b.length-1]?.time||0)-A)/1e3;l>1e12&&(l=(l-A)/1e3),i>1e12&&(i=(i-A)/1e3),l=Math.max(0,Math.min(l,S)),i=Math.max(0,Math.min(i,S));let B=X=>{if($==="time")return X;let O=A+X*1e3,D=b.findIndex(Y=>(Y.time||0)>=O);return D===-1&&(D=b.length-1),(b[D].dist||0)/1e3},P=B(l),R=B(i);k=P,f=R,q=[P,R],!h&&(p=!0,e.forEach(({uplot:X})=>{X.batch(()=>X.setScale("x",{min:P,max:R}))}),p=!1,we(),At())}function xe(){if(!e.length||!Q)return;let l=Math.round(Math.max(100,Q.getBoundingClientRect().width-J-(ee?r+V:0))),i=!1;e.forEach(({uplot:h,histCanvas:b,histData:A})=>{l!==h.width&&(h.setSize({width:l,height:h.height}),i=!0,ee&&b&&A&&It(b,A,h.height))}),i&&be()}function Ee(l=!1){let i=null,h=0;if(l&&Q&&(h=Q.scrollTop),l&&q)i=[q[0],q[1]];else if(l&&e.length){let ae=e[0].uplot;i=[ae.scales.x.min,ae.scales.x.max]}if(!M){Rn(l);return}let b=M.points;if(!b.length){Rn(l);return}let A=M?.sport,S=A?Nt[A.toLowerCase()]:null,B=S?.defaultPreset||"speed",R=Ye.get().speed_mode||B,X=S?.paceUnit||"km",O=[...d].filter(ae=>b.some(ce=>ce[Ft[ae].field]!=null));if(!O.length){Rn(l),ke&&(ke.style.display="flex",ke.innerHTML=` no_sim
No data for selected metrics
- `);return}Ae&&(Ae.style.display="none");let V=K?K.getBoundingClientRect().width:800,X=Math.round(Math.max(100,V-J-(Q?r+U:0))),fe=l&&n===H&&t===O&&s===R&&o===oe&&e.length>0,I;if(fe)I=e[0].xData;else if(O==="distance")I=v.map(ge=>(ge.dist||0)/1e3);else{let ge=v.find(Be=>Be.time!=null)?.time||0,re=0;I=v.map(Be=>(Be.time!=null&&(re=(Be.time-ge)/1e3),re))}let se=new Map;if(fe){Y&&(Y.style.display="none");let ge=new Set(z);for(let re of e){let Be=f.has(re.metricKey),pe=M.has(re.metricKey);ge.has(re.metricKey)&&re.smoothed===Be&&re.incZero===pe&&re.w===X?se.set(re.metricKey,re):(a.unsub(re.uplot),re.uplot.destroy(),re.row.remove())}e=[]}else Dn(l);if(K){let ge=new Array(z.length).fill(null),re=null;for(let Be=z.length-1;Be>=0;Be--){ge[Be]=re;let pe=se.get(z[Be]);pe&&(re=pe.row)}z.forEach((Be,pe)=>{let ye=se.get(Be);if(ye){e.push(ye);let ce=ye.uplot,Je=ce._strasse,Ge=g;g=!0,ce.batch(()=>{i&&(ce.scales.x.min!==i[0]||ce.scales.x.max!==i[1])?ce.setScale("x",{min:i[0],max:i[1]}):(Je?.updateHeaderStats(ce.scales.x.min,ce.scales.x.max,ce),ce.redraw(!1))}),g=Ge;let Qe=null;if(u!=null&&ye.xData[u]!=null&&ye.yData[u]!=null&&(dt(ye.histData),ye.histData.min!=null&&ye.histData.max!=null)){let rt=ye.histData.max-ye.histData.min||1;Qe=Math.min(ye.histData.BINS-1,Math.floor((ye.yData[u]-ye.histData.min)/rt*ye.histData.BINS)),ye.hoveredHistY=ye.yData[u]}It(ye.histCanvas,ye.histData,130,Qe);return}let Te=Ft[Be],qe=Te.transform,Ze=Te.fmt,st=Te.fmtAxis,nt=Te.unit,it=Te.label;Be==="speed"&&R==="pace"&&(it="Pace",nt=`min/${Z}`,Ze=ce=>Vn(ce),st=ce=>Vn(ce),qe=ce=>ce==null||ce<.1?null:(Z==="km"?1e3:100)/ce,Te={...Te,label:it,unit:nt,fmt:Ze,fmtAxis:st,transform:qe});let lt=Te.compute?Te.compute(v,ll):ll(v.map(ce=>{let Je=ce[Te.field];return Je!=null&&qe?qe(Je):Je}));f.has(Be)&&(lt=En(lt,Te.smoothSigma||2)),ke(Be,Te,I,lt,X,v,i,ge[pe])})}n=H,t=O,s=R,o=oe,ol(H),k!=null&&p!=null&&Me(),Re(),oe&&le(),l&&K&&h>0&&(K.scrollTop=h)}function ke(l,i,h,v,L,S,B=null,$=null){let R=H?.sport,z=(R?Nt[R.toLowerCase()]:null)?.defaultPreset||"speed",X=Ye.get().speed_mode||z,fe=l==="elevation"?ho(S,20):null,I=document.createElement("div");I.className="chart-row",I.dataset.metric=l,I.style.setProperty("--chart-color",i.color);let se=document.createElement("div");se.className=`chart-row-header${Q?" with-histogram":""}`;let ge=document.createElement("div");ge.className="chart-row-label-group",ge.innerHTML=` + `);return}ke&&(ke.style.display="none");let D=Q?Q.getBoundingClientRect().width:800,Y=Math.round(Math.max(100,D-J-(ee?r+V:0))),ie=l&&n===M&&t===$&&s===R&&o===se&&e.length>0,L;if(ie)L=e[0].xData;else if($==="distance")L=b.map(ae=>(ae.dist||0)/1e3);else{let ae=b.find(_e=>_e.time!=null)?.time||0,ce=0;L=b.map(_e=>(_e.time!=null&&(ce=(_e.time-ae)/1e3),ce))}let Te=new Map;if(ie){U&&(U.style.display="none");let ae=new Set(O);for(let ce of e){let _e=g.has(ce.metricKey),ue=T.has(ce.metricKey);ae.has(ce.metricKey)&&ce.smoothed===_e&&ce.incZero===ue&&ce.w===Y?Te.set(ce.metricKey,ce):(a.unsub(ce.uplot),ce.uplot.destroy(),ce.row.remove())}e=[]}else Rn(l);if(Q){let ae=new Array(O.length).fill(null),ce=null;for(let _e=O.length-1;_e>=0;_e--){ae[_e]=ce;let ue=Te.get(O[_e]);ue&&(ce=ue.row)}O.forEach((_e,ue)=>{let ve=Te.get(_e);if(ve){e.push(ve);let pe=ve.uplot,Je=pe._strasse,Ge=p;p=!0,pe.batch(()=>{i&&(pe.scales.x.min!==i[0]||pe.scales.x.max!==i[1])?pe.setScale("x",{min:i[0],max:i[1]}):(Je?.updateHeaderStats(pe.scales.x.min,pe.scales.x.max,pe),pe.redraw(!1))}),p=Ge;let Qe=null;if(u!=null&&ve.xData[u]!=null&&ve.yData[u]!=null&&(dt(ve.histData),ve.histData.min!=null&&ve.histData.max!=null)){let rt=ve.histData.max-ve.histData.min||1;Qe=Math.min(ve.histData.BINS-1,Math.floor((ve.yData[u]-ve.histData.min)/rt*ve.histData.BINS)),ve.hoveredHistY=ve.yData[u]}It(ve.histCanvas,ve.histData,130,Qe);return}let Ae=Ft[_e],Ue=Ae.transform,Ze=Ae.fmt,st=Ae.fmtAxis,nt=Ae.unit,it=Ae.label;_e==="speed"&&R==="pace"&&(it="Pace",nt=`min/${X}`,Ze=pe=>On(pe),st=pe=>On(pe),Ue=pe=>pe==null||pe<.1?null:(X==="km"?1e3:100)/pe,Ae={...Ae,label:it,unit:nt,fmt:Ze,fmtAxis:st,transform:Ue});let lt=Ae.compute?Ae.compute(b,ll):ll(b.map(pe=>{let Je=pe[Ae.field];return Je!=null&&Ue?Ue(Je):Je}));g.has(_e)&&(lt=En(lt,Ae.smoothSigma||2)),Me(_e,Ae,L,lt,Y,b,i,ae[ue])})}n=M,t=$,s=R,o=se,ol(M),k!=null&&f!=null&&we(),Re(),se&&le(),l&&Q&&h>0&&(Q.scrollTop=h)}function Me(l,i,h,b,A,S,B=null,P=null){let R=M?.sport,O=(R?Nt[R.toLowerCase()]:null)?.defaultPreset||"speed",Y=Ye.get().speed_mode||O,ie=l==="elevation"?fo(S,20):null,L=document.createElement("div");L.className="chart-row",L.dataset.metric=l,L.style.setProperty("--chart-color",i.color);let Te=document.createElement("div");Te.className=`chart-row-header${ee?" with-histogram":""}`;let ae=document.createElement("div");ae.className="chart-row-label-group",ae.innerHTML=` ${i.icon} ${i.label} - `;let re=document.createElement("button");re.className=`icon-btn mini smooth-btn${f.has(l)?" active":""}`,re.title="Toggle data smoothing",re.innerHTML=`${f.has(l)?"blur_on":"blur_off"}`,re.addEventListener("click",ee=>{ee.stopPropagation(),f.has(l)?f.delete(l):f.add(l),Ee(!0)});let Be=document.createElement("button");Be.className=`map-color-btn icon-btn${oe===l?" active":""}`,Be.dataset.metric=l,Be.title="Color map track by this metric",Be.innerHTML='colorize',Be.addEventListener("click",()=>Ce(l));let pe=null;if(l==="cadence"||l==="power"||l==="speed"){pe=document.createElement("button");let ee=M.has(l);pe.className=`icon-btn mini${ee?" active":""}`,pe.title=ee?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",pe.innerHTML=`${ee?"exposure_zero":"mobile_off"}`,pe.addEventListener("click",$e=>{$e.stopPropagation(),M.has(l)?M.delete(l):M.add(l),Ee(!0)})}let ye=document.createElement("div");ye.className="chart-stats-total";let Te=document.createElement("div");Te.className="chart-stats-selection";let qe=document.createElement("div");qe.className="chart-row-stats-container",qe.append(ye,Te);let Ze=document.createElement("div");Ze.className="chart-row-actions",Ze.append(re,Be);let st=document.createElement("div");if(st.className="chart-row-right-actions",l==="speed"){let ee=document.createElement("div");ee.className="seg-ctrl",ee.innerHTML=` - - - `,ee.addEventListener("click",$e=>{let Ke=$e.target.closest(".seg-btn");if(!Ke)return;let et=Ke.dataset.mode;if(et==="speed"||et==="pace"){let Ve=et===z;Ye.patch({speed_mode:Ve?null:et}),Ee(!0)}}),st.append(ee)}pe&&st.append(pe),se.append(ge,Ze,qe,st);let nt=document.createElement("div");nt.className="chart-row-body";let it=document.createElement("div");it.style.position="relative",nt.appendChild(it);let lt=document.createElement("div");lt.className="fixed-x-label fixed-x-min";let ce=document.createElement("div");ce.className="fixed-x-label fixed-x-max",it.append(lt,ce);let Je=document.createElement("div");Je.className=`hist-col${Q?" visible":""}`;let Ge=document.createElement("canvas");Ge.className="hist-canvas",Je.appendChild(Ge),nt.appendChild(Je),I.append(se,nt);let Qe=O==="distance";function rt(ee,$e){if(ee==null)return"";if(Qe){let Ke=$e<1?3:$e<5?2:$e<20?1:0;return`${ee.toFixed(Ke)} km`}else{let Ke=Math.abs(ee),et=Math.floor(Ke/3600),Ve=Math.floor(Ke%3600/60),xt=Math.round(Ke%60),gt=et>0?`${et}:`:"",Rt=et>0?String(Ve).padStart(2,"0"):String(Ve),Ct=String(xt).padStart(2,"0");return`${ee<0?"-":""}${gt}${Rt}:${Ct}`}}let ut=M.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",mt=1/0,Xe=-1/0,ct=0,vt=0,St=1/0,jt=-1/0,Et=0,Kt=0;for(let ee=0;eeXe&&(Xe=$e),ct+=$e,vt++,($e!==0||ut)&&($ejt&&(jt=$e),Et+=$e,Kt++))}vt===0&&(mt=0,Xe=100);let Ps=vt?{min:mt,max:Xe,avg:ct/vt}:null,ns=Kt?{min:St,max:jt,avg:Et/Kt}:null,rl=Math.abs(Xe-mt)*.1||1,yo=[mt-rl,Xe+rl],cl=!1;function As(ee,$e,Ke){let et=M.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",Ve=$e-ee;lt.textContent=rt(ee,Ve),ce.textContent=rt($e,Ve);let xt=(gt,Rt,Ct=!1)=>{let Ht=Ct&&et===ut?ns:Js(h,v,gt,Rt,et);if(!Ht)return"";let tn=` + `;let ce=document.createElement("button");ce.className=`icon-btn mini smooth-btn${g.has(l)?" active":""}`,ce.title="Toggle data smoothing",ce.innerHTML=`${g.has(l)?"blur_on":"blur_off"}`,ce.addEventListener("click",te=>{te.stopPropagation(),g.has(l)?g.delete(l):g.add(l),Ee(!0)});let _e=document.createElement("button");_e.className=`map-color-btn icon-btn${se===l?" active":""}`,_e.dataset.metric=l,_e.title="Color map track by this metric",_e.innerHTML='colorize',_e.addEventListener("click",()=>Ce(l));let ue=null;if(l==="cadence"||l==="power"||l==="speed"){ue=document.createElement("button");let te=T.has(l);ue.className=`icon-btn mini${te?" active":""}`,ue.title=te?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",ue.innerHTML=`${te?"exposure_zero":"mobile_off"}`,ue.addEventListener("click",$e=>{$e.stopPropagation(),T.has(l)?T.delete(l):T.add(l),Ee(!0)})}let ve=document.createElement("div");ve.className="chart-stats-total";let Ae=document.createElement("div");Ae.className="chart-stats-selection";let Ue=document.createElement("div");Ue.className="chart-row-stats-container",Ue.append(ve,Ae);let Ze=document.createElement("div");Ze.className="chart-row-actions",Ze.append(ce,_e);let st=document.createElement("div");if(st.className="chart-row-right-actions",l==="speed"){let te=document.createElement("div");te.className="seg-ctrl",te.innerHTML=` + + + `,te.addEventListener("click",$e=>{let Ke=$e.target.closest(".seg-btn");if(!Ke)return;let et=Ke.dataset.mode;if(et==="speed"||et==="pace"){let Ve=et===O;Ye.patch({speed_mode:Ve?null:et}),Ee(!0)}}),st.append(te)}ue&&st.append(ue),Te.append(ae,Ze,Ue,st);let nt=document.createElement("div");nt.className="chart-row-body";let it=document.createElement("div");it.style.position="relative",nt.appendChild(it);let lt=document.createElement("div");lt.className="fixed-x-label fixed-x-min";let pe=document.createElement("div");pe.className="fixed-x-label fixed-x-max",it.append(lt,pe);let Je=document.createElement("div");Je.className=`hist-col${ee?" visible":""}`;let Ge=document.createElement("canvas");Ge.className="hist-canvas",Je.appendChild(Ge),nt.appendChild(Je),L.append(Te,nt);let Qe=$==="distance";function rt(te,$e){if(te==null)return"";if(Qe){let Ke=$e<1?3:$e<5?2:$e<20?1:0;return`${te.toFixed(Ke)} km`}else{let Ke=Math.abs(te),et=Math.floor(Ke/3600),Ve=Math.floor(Ke%3600/60),xt=Math.round(Ke%60),gt=et>0?`${et}:`:"",Rt=et>0?String(Ve).padStart(2,"0"):String(Ve),Ct=String(xt).padStart(2,"0");return`${te<0?"-":""}${gt}${Rt}:${Ct}`}}let ut=T.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",mt=1/0,Xe=-1/0,ct=0,vt=0,St=1/0,jt=-1/0,Et=0,Kt=0;for(let te=0;teXe&&(Xe=$e),ct+=$e,vt++,($e!==0||ut)&&($ejt&&(jt=$e),Et+=$e,Kt++))}vt===0&&(mt=0,Xe=100);let Ls=vt?{min:mt,max:Xe,avg:ct/vt}:null,ss=Kt?{min:St,max:jt,avg:Et/Kt}:null,rl=Math.abs(Xe-mt)*.1||1,bo=[mt-rl,Xe+rl],cl=!1;function Ps(te,$e,Ke){let et=T.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",Ve=$e-te;lt.textContent=rt(te,Ve),pe.textContent=rt($e,Ve);let xt=(gt,Rt,Ct=!1)=>{let Ht=Ct&&et===ut?ss:Js(h,b,gt,Rt,et);if(!Ht)return"";let tn=` align_flex_end${i.fmt(Ht.min,!0)} ${i.unit} align_center${i.fmt(Ht.avg,!0)} ${i.unit} align_flex_start${i.fmt(Ht.max,!0)} ${i.unit} - `;if(l==="elevation"){let Ut=co(S,gt,Rt);tn+=` + `;if(l==="elevation"){let Ut=ao(S,gt,Rt);tn+=` trending_up+${Math.round(Ut.gain)} m trending_down-${Math.round(Ut.loss)} m - `}return tn};cl||(cl=!0,ye.innerHTML=`all_inclusive${xt(h[0],h[h.length-1],!0)}`,ye.querySelector(".all-chip")?.addEventListener("click",gt=>{gt.stopPropagation(),ne()})),k!==null&&p!==null?(Te.innerHTML=xt(k,p,!1),Te.style.display="flex",Te.style.setProperty("--sel-color",i.color)):Te.style.display="none"}let xo=!1,wo={width:L,height:130,padding:[4,0,0,0],cursor:{sync:{key:a.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:l==="elevation"?(ee,$e)=>Kn(fe?fe[ee.cursor.idx]:null):i.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(ee,$e,Ke)=>[$e,Ke],min:B?B[0]:void 0,max:B?B[1]:void 0},y:{range:()=>yo,dir:l==="speed"&&X==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(ee,$e,Ke,et)=>{let Ve=et-Ke,gt=(ee.bbox.width>0?ee.bbox.width:ee.width)/80,Rt=Ve/gt,Ct;Qe?Ct=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:Ct=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let Ht=Ct[Ct.length-1];for(let Vt=0;Vt=Rt){Ht=Ct[Vt];break}let tn=[],Ut=Math.ceil(Ke/Ht)*Ht,us=Ht<1?2:0;for(;Ut<=et;){let Vt=ee.valToPos(Ut,"x",!0);Vt>=ee.bbox.left+80&&Vt<=ee.bbox.left+ee.bbox.width-80&&tn.push(Number(Ut.toFixed(us))),Ut+=Ht}return tn},values:(ee,$e)=>{let Ke=(ee.scales.x?.max??1)-(ee.scales.x?.min??0);return $e.map(et=>{if(et==null)return"";let Ve=ee.valToPos(et,"x",!0);return Veee.bbox.left+ee.bbox.width-80?null:rt(et,Ke)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(ee,$e)=>$e.map(Ke=>Ke!=null?i.fmtAxis(Ke):"")}],series:[{},{label:i.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[ee=>{let $e=ee.bbox.top+ee.bbox.height+5;lt.style.top=`${$e}px`,lt.style.left=`${ee.bbox.left}px`,ce.style.top=`${$e}px`,ce.style.left=`${ee.bbox.left+ee.bbox.width}px`,ce.style.transform="translateX(-100%)"},ee=>{l==="gears"?al(ee,h,v,i.color,1.5,l,null,S):l==="elevation"?uo(ee,h,v,fe):l==="gradient"?mo(ee,h,v):oe===l?vo(ee,h,v,S,l):al(ee,h,v,i.color,1.5,l,null,S)},ee=>{let $e=e.find(et=>et.uplot===ee);if(!$e)return;let Ke=ee._strasse;u!=null?po(ee,h,v,i.color,i,S,l):(Ke&&Ke.pinYVal&&(Ke.pinYVal.style.display="none"),$e.pinnedHistY!=null&&fo(ee,h,v,$e.pinnedHistY,i.color,i))},ee=>{let $e=ee.cursor.idx,Ke=u!=null,et=$e!=null&&ee.cursor.left>=0;if(et&&u==null){let Ve=ee.valToPos(v[$e],"y",!0);Math.abs(ee.cursor.top-Ve)>100&&(et=!1)}if(et&&$e!==u&&tl(ee,S,$e,tt(i.color,.4),1),k!=null&&p!=null){let Ve=ee.ctx,xt=window.devicePixelRatio||1,gt=ee.bbox,Rt=ee.valToPos(k,"x",!0),Ct=ee.valToPos(p,"x",!0);Ve.save(),Ve.beginPath(),Ve.lineWidth=3*xt,Ve.strokeStyle=i.color,Ve.moveTo(Rt,gt.top+gt.height),Ve.lineTo(Ct,gt.top+gt.height),Ve.stroke();let Ht=Math.abs(p-k),tn=O==="distance"?`${Ht.toFixed(2)} km`:ht(Ht),Ut=9*xt,us=`bold ${Ut}px system-ui, sans-serif`;Ve.font!==us&&(Ve.font=us);let Vt=Ve.measureText(tn).width,ul=Math.max(gt.left,Rt),ml=Math.min(gt.left+gt.width,Ct);if(ml-ul>Vt+14*xt){let Eo=5*xt,So=2*xt,ms=Vt+Eo*2,ps=Ut+So*2,Hs=(ul+ml)/2-ms/2,Fs=gt.top+gt.height-ps/2;Ve.beginPath(),Ve.roundRect?Ve.roundRect(Hs,Fs,ms,ps,3*xt):Ve.rect(Hs,Fs,ms,ps),Ve.fillStyle=i.color,Ve.fill(),Ve.fillStyle="#000",Ve.textAlign="center",Ve.textBaseline="middle",Ve.fillText(tn,Hs+ms/2,Fs+ps/2)}Ve.restore()}Ke&&nl(ee,S,u,i.color,!0,.7),et&&$e!==u&&nl(ee,S,$e,i.color,!0,1)}],setCursor:[ee=>{if(g)return;let $e=ee.cursor.idx;ee.redraw(!1),ee.cursor.left>=0?x=ee.posToVal(ee.cursor.left,"x"):x=null;let Ke=ee._strasse,et=$e!=null&&v[$e]!=null;if(et&&u==null){let Ve=ee.valToPos(v[$e],"y",!0);Math.abs(ee.cursor.top-Ve)>100&&(et=!1)}if(Ke&&(et?Qs(ee,Ke.curYVal,$e,h,v,S,i,l):Ke.curYVal.style.display="none"),c||($e!=null&&S[$e]?N&&(u!=null||et)?N(S[$e]):N&&!et&&N(null):$e===null&&N&&N(null)),$e!=null&&v[$e]!=null){let{min:Ve,max:xt}=yt;if(Ve!=null&&xt!=null){let gt=xt-Ve||1,Rt=Math.min(yt.BINS-1,Math.floor((v[$e]-Ve)/gt*yt.BINS));en.hoveredHistY!==v[$e]&&(en.hoveredHistY=v[$e],It(Ge,yt,130,Rt))}}else en.hoveredHistY!==null&&(en.hoveredHistY=null,It(Ge,yt,130))}],setScale:[(ee,$e)=>{if($e!=="x"||xo)return;let{min:Ke,max:et}=ee.scales.x;_=[Ke,et],As(Ke,et,ee),!g&&(b||(C=null),g=!0,e.forEach(({uplot:Ve})=>{Ve!==ee&&Ve.batch(()=>Ve.setScale("x",{min:Ke,max:et}))}),g=!1,ve(),At(),ie&&k!==null&&ie(k,p,O))}],setSelect:[ee=>{if(b)return;C=null;let{left:$e,width:Ke}=ee.select;if(Ke>0){let et=ee.posToVal($e,"x"),Ve=ee.posToVal($e+Ke,"x");k=et,p=Ve,As(ee.scales.x.min,ee.scales.x.max,ee),ve(),At(),ie&&ie(k,p,O),ee.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},Is=document.createElement("div");Is.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let ss=document.createElement("div");ss.className="sel-fill",ss.style.display="none";let ls=document.createElement("div");ls.className="sel-line sel-line-anchor",ls.style.display="none";let os=document.createElement("div");os.className="sel-line-label sel-line-label-anchor",os.style.display="none";let Wn=document.createElement("div");Wn.className="sel-handle sel-handle-anchor",Wn.style.display="none";let zn=document.createElement("div");zn.className="sel-graph-marker",zn.innerHTML=`play_circle`,zn.style.display="none";let is=document.createElement("div");is.className="sel-line sel-line-end",is.style.display="none";let as=document.createElement("div");as.className="sel-line-label sel-line-label-end",as.style.display="none";let qn=document.createElement("div");qn.className="sel-handle sel-handle-end",qn.style.display="none";let Un=document.createElement("div");Un.className="sel-graph-marker",Un.innerHTML=`stop_circle`,Un.style.display="none";let rs=document.createElement("div");rs.className="cur-y-val",rs.style.cssText=`color:${i.color};display:none`;let cs=document.createElement("div");cs.className="cur-y-val pin",cs.style.cssText=`color:${i.color};display:none`,Is.append(ss,ls,os,Wn,zn,is,as,qn,Un,rs,cs);let yt={yData:v,xData:h,def:i,BINS:24,min:vt?mt:void 0,max:vt?Xe:void 0,fullStats:ns,fullStatsAll:Ps},en={uplot:null,row:I,xData:h,yData:v,def:i,metricKey:l,statsTotalEl:ye,statsSelEl:Te,histCol:Je,histCanvas:Ge,histData:yt,hoveredHistY:null,pinnedHistY:null,smoothed:f.has(l),incZero:M.has(l),w:L};yt.plot=en;let To=g;g=!0;let Zt=new vl(wo,[h,v],(ee,$e)=>{en.uplot=ee,e.push(en),it.appendChild(ee.root),ee.over.appendChild(Is),ee._strasse={selFill:ss,anchorLine:ls,anchorLabel:os,anchorHandle:Wn,anchorMarker:zn,endLine:is,endLabel:as,endHandle:qn,endMarker:Un,curYVal:rs,pinYVal:cs,updateHeaderStats:As},ee.batch(()=>{$e()})});g=To,je(Wn,Zt,h,!0),je(qn,Zt,h,!1);let ds=null;Zt.over.addEventListener("mousedown",ee=>{if(ee.button!==0)return;P=!1;let $e=Zt.over.getBoundingClientRect();ds=ee.clientX-$e.left}),Zt.over.addEventListener("mousemove",ee=>{if(ds!==null){let $e=Zt.over.getBoundingClientRect();Math.abs(ee.clientX-$e.left-ds)>5&&(P=!0)}}),Zt.over.addEventListener("mouseup",()=>{ds=null}),Zt.over.addEventListener("click",()=>{if(P)return;let ee=Zt.cursor.idx;ee!=null&&S[ee]&&(u=ee,e.forEach(({uplot:$e})=>$e.redraw(!1)),y&&y(S[ee],ee),d&&d(ee))}),I.addEventListener("dblclick",ne);let dl=null;if(u!=null&&h[u]!=null&&v[u]!=null&&(dt(yt),yt.min!=null&&yt.max!=null)){let ee=yt.max-yt.min||1;dl=Math.min(yt.BINS-1,Math.floor((v[u]-yt.min)/ee*yt.BINS)),en.hoveredHistY=v[u]}It(Ge,yt,130,dl),Qt(Ge,yt),K&&($?K.insertBefore(I,$):K.appendChild(I))}function ve(){Me(),e.forEach(({uplot:l})=>l.batch(()=>l.redraw(!1)))}function Me(){e.forEach(({uplot:l,def:i})=>{let h=l._strasse;if(!h)return;let{selFill:v,anchorLine:L,anchorLabel:S,anchorHandle:B,anchorMarker:$,endLine:R,endLabel:Z,endHandle:z,endMarker:V}=h;if(k==null||p==null){[v,L,S,B,$,R,Z,z,V].forEach(Ze=>{Ze.style.display="none"});return}let X=l.valToPos(k,"x"),fe=l.valToPos(p,"x"),I=window.devicePixelRatio||1,se=l.bbox,ge=se.width/I,re=se.height/I,Be=(se.top+se.height)/I,pe=X>=0&&X<=ge,ye=fe>=0&&fe<=ge,Te=Math.max(0,X),qe=Math.min(ge,fe);if(qe>Te?(v.style.left=`${Te}px`,v.style.width=`${qe-Te}px`,v.style.top="0",v.style.height=`${re}px`,v.style.backgroundColor=tt(i.color,.07),v.style.display=""):v.style.display="none",pe){L.style.left=`${X}px`,L.style.height=`${re}px`,L.style.borderLeftColor=i.color,L.style.display="";let Ze=Ue(k);S.textContent=Ze;let st=Ze.length*7+10;S.style.left=X+st+4Ze.style.display="none");if(ye){R.style.left=`${fe}px`,R.style.height=`${re}px`,R.style.borderLeftColor=i.color,R.style.display="";let Ze=Ue(p);Z.textContent=Ze;let st=Ze.length*7+10;Z.style.left=fe-st-3>0?`${fe-st-3}px`:`${fe+3}px`,Z.style.display="",z.style.left=`${fe}px`,z.style.backgroundColor=i.color,z.style.display="",V.style.left=`${fe}px`,V.style.top=`${Be}px`;let nt=V.querySelector(".material-symbols-rounded");nt&&(nt.style.color=i.color),V.style.display=""}else[R,Z,z,V].forEach(Ze=>Ze.style.display="none")})}function Ue(l){return O==="distance"?`${l.toFixed(2)} km`:ht(l)}function je(l,i,h,v){l.style.pointerEvents="auto",l.addEventListener("mousedown",L=>{L.stopPropagation(),L.preventDefault();let S=L.clientX,B=v?k:p,$=i.over.offsetWidth,R=i.scales.x.min,Z=i.scales.x.max,z=$/(Z-R),V=[h[0],h[h.length-1]];document.body.style.cursor="ew-resize",P=!0;function X(I){let se=I.clientX-S,ge=(B||0)+se/z;ge=Math.max(V[0],Math.min(V[1],ge)),v?k=Math.min(ge,(p||V[1])-.001):p=Math.max(ge,(k||V[0])+.001),e.forEach(re=>re.uplot._strasse?.updateHeaderStats(re.uplot.scales.x.min,re.uplot.scales.x.max)),ve(),At(),ie&&ie(k,p,O)}function fe(){document.body.style.cursor="",P=!1,document.removeEventListener("mousemove",X),document.removeEventListener("mouseup",fe)}document.addEventListener("mousemove",X),document.addEventListener("mouseup",fe)})}function dt(l){let{yData:i,xData:h,BINS:v}=l;if(l._lastYData===i&&l.bins)return;l._lastYData=i;let L=l.min,S=l.max;if(L==null||S==null){let V=1/0,X=-1/0,fe=0;for(let I=0;IX&&(X=se),fe++)}if(!fe)return;L=V,S=X,l.min=L,l.max=S}let B=new Array(v).fill(0),$=new Array(v).fill(0),R=S-L||1,Z=l.plot?.metricKey??Object.keys(Ft).find(V=>Ft[V]===l.def),z=!Z||M.has(Z)||Z!=="power"&&Z!=="cadence"&&Z!=="speed";for(let V=0;V0&&h[V-1]!=null?h[V-1]:h[V],se=V{It(l,i,h.height)})}function It(l,i,h,v=null){let{def:L,BINS:S}=i;dt(i);let{bins:B,min:$,max:R}=i;if(!B||$==null||R==null)return;let Z=k!=null&&p!=null;if(Z&&(i._lastSelRange?.[0]!==k||i._lastSelRange?.[1]!==p)){i._lastSelRange=[k,p];let ce=new Array(S).fill(0),Je=new Array(S).fill(0),{yData:Ge,xData:Qe}=i,rt=R-$||1,ut=i.plot?.metricKey??Object.keys(Ft).find(Xe=>Ft[Xe]===i.def),mt=!ut||M.has(ut)||ut!=="power"&&ut!=="cadence"&&ut!=="speed";for(let Xe=0;Xep)continue;let St=Math.min(S-1,Math.floor((ct-$)/rt*S));ce[St]++;let jt=Xe>0&&Qe[Xe-1]!=null?Qe[Xe-1]:Qe[Xe],Et=XeL.fmtAxis(ce),re="9px system-ui, sans-serif";I.font!==re&&(I.font=re);let pe={t:4,r:0,b:30,l:Math.ceil(Math.max(I.measureText(`${ge(R)} ${L.unit}`).width,I.measureText(`${ge($)} ${L.unit}`).width))+6};i.padL=pe.l;let ye=X-pe.l-pe.r,Te=fe-pe.t-pe.b,qe=ce=>pe.t+(S-1-ce)*(Te/S),Ze=Te/S-1,st=Z?.15:.6;I.fillStyle=tt(L.color,st);for(let ce=0;cece+Je,0);if(nt>0){let ce=[{x:pe.l,y:pe.t+Te}],Je=0;for(let Ge=0;GeGe+Qe+2&&ce0){let ce=0;for(let ct=0;ct{let L=Yt(l,i,v);if(L!=null&&h){let{min:S,max:B,BINS:$}=i,R=B-S||1;h.pinnedHistY=S+(L+.5)*(R/$),e.forEach(({uplot:Z})=>Z.redraw(!1))}}),l.addEventListener("mousemove",v=>{w=v,wn(v,l,i)}),l.addEventListener("mouseenter",()=>{W=l,D=i}),l.addEventListener("mouseleave",()=>{W===l&&(W=null,D=null),Y&&(Y.style.display="none");let v=document.getElementById("hist-line");v&&(v.style.display="none"),h&&(h.hoveredHistY=null,It(l,i,l.height/(window.devicePixelRatio||1)))})}function Yt(l,i,h){let{bins:v,BINS:L}=i;if(!v)return null;let S=l.getBoundingClientRect(),B=h.clientY-S.top,$={t:4,b:30},R=S.height-$.t-$.b,Z=Math.floor((B-$.t)/R*L),z=L-1-Z;return Z<0||Z>=L?null:z}function wn(l,i,h){if(!Y)return;let{bins:v,binAccum:L,min:S,max:B,BINS:$,def:R,plot:Z}=h;if(!v||!L||S==null||B==null)return;let z=document.getElementById("hist-line"),V=Yt(i,h,l);if(V==null||!v[V]){Y.style.display="none",z&&(z.style.display="none"),Z&&(Z.hoveredHistY=null,It(i,h,i.height/(window.devicePixelRatio||1)));return}if(Z){let Qe=B-S||1;Z.hoveredHistY=S+(V+.5)*(Qe/$),It(i,h,i.height/(window.devicePixelRatio||1),V)}let X=v[V],fe=v.reduce((Qe,rt)=>Qe+rt,0),I=X/fe*100,se=B-S||1,ge=S+V*(se/$),re=S+(V+1)*(se/$),Be=`${R.fmt(ge,!0)} \u2013 ${R.fmt(re,!0)} ${R.unit}`,pe="",ye=(ge+re)/2,Te=Object.keys(Ft).find(Qe=>Ft[Qe]===R),qe=[];if(Te==="power"?qe=Sn.getPowerZones():Te==="hr"&&(qe=Sn.getHRZones()),qe.length>0){let Qe=qe.findIndex(ut=>ye>=ut.min&&ye=qe[qe.length-1].min?qe[qe.length-1]:null;if(rt){let ut=Qe!==-1?Qe:qe.length-1;pe=` + `}return tn};cl||(cl=!0,ve.innerHTML=`all_inclusive${xt(h[0],h[h.length-1],!0)}`,ve.querySelector(".all-chip")?.addEventListener("click",gt=>{gt.stopPropagation(),ne()})),k!==null&&f!==null?(Ae.innerHTML=xt(k,f,!1),Ae.style.display="flex",Ae.style.setProperty("--sel-color",i.color)):Ae.style.display="none"}let vo=!1,yo={width:A,height:130,padding:[4,0,0,0],cursor:{sync:{key:a.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:l==="elevation"?(te,$e)=>es(ie?ie[te.cursor.idx]:null):i.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(te,$e,Ke)=>[$e,Ke],min:B?B[0]:void 0,max:B?B[1]:void 0},y:{range:()=>bo,dir:l==="speed"&&Y==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(te,$e,Ke,et)=>{let Ve=et-Ke,gt=(te.bbox.width>0?te.bbox.width:te.width)/80,Rt=Ve/gt,Ct;Qe?Ct=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:Ct=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let Ht=Ct[Ct.length-1];for(let Vt=0;Vt=Rt){Ht=Ct[Vt];break}let tn=[],Ut=Math.ceil(Ke/Ht)*Ht,ms=Ht<1?2:0;for(;Ut<=et;){let Vt=te.valToPos(Ut,"x",!0);Vt>=te.bbox.left+80&&Vt<=te.bbox.left+te.bbox.width-80&&tn.push(Number(Ut.toFixed(ms))),Ut+=Ht}return tn},values:(te,$e)=>{let Ke=(te.scales.x?.max??1)-(te.scales.x?.min??0);return $e.map(et=>{if(et==null)return"";let Ve=te.valToPos(et,"x",!0);return Vete.bbox.left+te.bbox.width-80?null:rt(et,Ke)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(te,$e)=>$e.map(Ke=>Ke!=null?i.fmtAxis(Ke):"")}],series:[{},{label:i.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[te=>{let $e=te.bbox.top+te.bbox.height+5;lt.style.top=`${$e}px`,lt.style.left=`${te.bbox.left}px`,pe.style.top=`${$e}px`,pe.style.left=`${te.bbox.left+te.bbox.width}px`,pe.style.transform="translateX(-100%)"},te=>{l==="gears"?al(te,h,b,i.color,1.5,l,null,S):l==="elevation"?ro(te,h,b,ie):l==="gradient"?co(te,h,b):se===l?ho(te,h,b,S,l):al(te,h,b,i.color,1.5,l,null,S)},te=>{let $e=e.find(et=>et.uplot===te);if(!$e)return;let Ke=te._strasse;u!=null?uo(te,h,b,i.color,i,S,l):(Ke&&Ke.pinYVal&&(Ke.pinYVal.style.display="none"),$e.pinnedHistY!=null&&mo(te,h,b,$e.pinnedHistY,i.color,i))},te=>{let $e=te.cursor.idx,Ke=u!=null,et=$e!=null&&te.cursor.left>=0;if(et&&u==null){let Ve=te.valToPos(b[$e],"y",!0);Math.abs(te.cursor.top-Ve)>100&&(et=!1)}if(et&&$e!==u&&tl(te,S,$e,tt(i.color,.4),1),k!=null&&f!=null){let Ve=te.ctx,xt=window.devicePixelRatio||1,gt=te.bbox,Rt=te.valToPos(k,"x",!0),Ct=te.valToPos(f,"x",!0);Ve.save(),Ve.beginPath(),Ve.lineWidth=3*xt,Ve.strokeStyle=i.color,Ve.moveTo(Rt,gt.top+gt.height),Ve.lineTo(Ct,gt.top+gt.height),Ve.stroke();let Ht=Math.abs(f-k),tn=$==="distance"?`${Ht.toFixed(2)} km`:ht(Ht),Ut=9*xt,ms=`bold ${Ut}px system-ui, sans-serif`;Ve.font!==ms&&(Ve.font=ms);let Vt=Ve.measureText(tn).width,ul=Math.max(gt.left,Rt),ml=Math.min(gt.left+gt.width,Ct);if(ml-ul>Vt+14*xt){let wo=5*xt,To=2*xt,ps=Vt+wo*2,fs=Ut+To*2,Is=(ul+ml)/2-ps/2,Hs=gt.top+gt.height-fs/2;Ve.beginPath(),Ve.roundRect?Ve.roundRect(Is,Hs,ps,fs,3*xt):Ve.rect(Is,Hs,ps,fs),Ve.fillStyle=i.color,Ve.fill(),Ve.fillStyle="#000",Ve.textAlign="center",Ve.textBaseline="middle",Ve.fillText(tn,Is+ps/2,Hs+fs/2)}Ve.restore()}Ke&&nl(te,S,u,i.color,!0,.7),et&&$e!==u&&nl(te,S,$e,i.color,!0,1)}],setCursor:[te=>{if(p)return;let $e=te.cursor.idx;te.redraw(!1),te.cursor.left>=0?w=te.posToVal(te.cursor.left,"x"):w=null;let Ke=te._strasse,et=$e!=null&&b[$e]!=null;if(et&&u==null){let Ve=te.valToPos(b[$e],"y",!0);Math.abs(te.cursor.top-Ve)>100&&(et=!1)}if(Ke&&(et?Qs(te,Ke.curYVal,$e,h,b,S,i,l):Ke.curYVal.style.display="none"),c||($e!=null&&S[$e]?z&&(u!=null||et)?z(S[$e]):z&&!et&&z(null):$e===null&&z&&z(null)),$e!=null&&b[$e]!=null){let{min:Ve,max:xt}=yt;if(Ve!=null&&xt!=null){let gt=xt-Ve||1,Rt=Math.min(yt.BINS-1,Math.floor((b[$e]-Ve)/gt*yt.BINS));en.hoveredHistY!==b[$e]&&(en.hoveredHistY=b[$e],It(Ge,yt,130,Rt))}}else en.hoveredHistY!==null&&(en.hoveredHistY=null,It(Ge,yt,130))}],setScale:[(te,$e)=>{if($e!=="x"||vo)return;let{min:Ke,max:et}=te.scales.x;q=[Ke,et],Ps(Ke,et,te),!p&&(v||(_=null),p=!0,e.forEach(({uplot:Ve})=>{Ve!==te&&Ve.batch(()=>Ve.setScale("x",{min:Ke,max:et}))}),p=!1,be(),At(),de&&k!==null&&de(k,f,$))}],setSelect:[te=>{if(v)return;_=null;let{left:$e,width:Ke}=te.select;if(Ke>0){let et=te.posToVal($e,"x"),Ve=te.posToVal($e+Ke,"x");k=et,f=Ve,Ps(te.scales.x.min,te.scales.x.max,te),be(),At(),de&&de(k,f,$),te.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},As=document.createElement("div");As.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let ls=document.createElement("div");ls.className="sel-fill",ls.style.display="none";let os=document.createElement("div");os.className="sel-line sel-line-anchor",os.style.display="none";let is=document.createElement("div");is.className="sel-line-label sel-line-label-anchor",is.style.display="none";let zn=document.createElement("div");zn.className="sel-handle sel-handle-anchor",zn.style.display="none";let qn=document.createElement("div");qn.className="sel-graph-marker",qn.innerHTML=`play_circle`,qn.style.display="none";let as=document.createElement("div");as.className="sel-line sel-line-end",as.style.display="none";let rs=document.createElement("div");rs.className="sel-line-label sel-line-label-end",rs.style.display="none";let Un=document.createElement("div");Un.className="sel-handle sel-handle-end",Un.style.display="none";let Vn=document.createElement("div");Vn.className="sel-graph-marker",Vn.innerHTML=`stop_circle`,Vn.style.display="none";let cs=document.createElement("div");cs.className="cur-y-val",cs.style.cssText=`color:${i.color};display:none`;let ds=document.createElement("div");ds.className="cur-y-val pin",ds.style.cssText=`color:${i.color};display:none`,As.append(ls,os,is,zn,qn,as,rs,Un,Vn,cs,ds);let yt={yData:b,xData:h,def:i,BINS:24,min:vt?mt:void 0,max:vt?Xe:void 0,fullStats:ss,fullStatsAll:Ls},en={uplot:null,row:L,xData:h,yData:b,def:i,metricKey:l,statsTotalEl:ve,statsSelEl:Ae,histCol:Je,histCanvas:Ge,histData:yt,hoveredHistY:null,pinnedHistY:null,smoothed:g.has(l),incZero:T.has(l),w:A};yt.plot=en;let xo=p;p=!0;let Zt=new vl(yo,[h,b],(te,$e)=>{en.uplot=te,e.push(en),it.appendChild(te.root),te.over.appendChild(As),te._strasse={selFill:ls,anchorLine:os,anchorLabel:is,anchorHandle:zn,anchorMarker:qn,endLine:as,endLabel:rs,endHandle:Un,endMarker:Vn,curYVal:cs,pinYVal:ds,updateHeaderStats:Ps},te.batch(()=>{$e()})});p=xo,je(zn,Zt,h,!0),je(Un,Zt,h,!1);let us=null;Zt.over.addEventListener("mousedown",te=>{if(te.button!==0)return;F=!1;let $e=Zt.over.getBoundingClientRect();us=te.clientX-$e.left}),Zt.over.addEventListener("mousemove",te=>{if(us!==null){let $e=Zt.over.getBoundingClientRect();Math.abs(te.clientX-$e.left-us)>5&&(F=!0)}}),Zt.over.addEventListener("mouseup",()=>{us=null}),Zt.over.addEventListener("click",()=>{if(F)return;let te=Zt.cursor.idx;te!=null&&S[te]&&(u=te,e.forEach(({uplot:$e})=>$e.redraw(!1)),y&&y(S[te],te),m&&m(te))}),L.addEventListener("dblclick",ne);let dl=null;if(u!=null&&h[u]!=null&&b[u]!=null&&(dt(yt),yt.min!=null&&yt.max!=null)){let te=yt.max-yt.min||1;dl=Math.min(yt.BINS-1,Math.floor((b[u]-yt.min)/te*yt.BINS)),en.hoveredHistY=b[u]}It(Ge,yt,130,dl),Qt(Ge,yt),Q&&(P?Q.insertBefore(L,P):Q.appendChild(L))}function be(){we(),e.forEach(({uplot:l})=>l.batch(()=>l.redraw(!1)))}function we(){e.forEach(({uplot:l,def:i})=>{let h=l._strasse;if(!h)return;let{selFill:b,anchorLine:A,anchorLabel:S,anchorHandle:B,anchorMarker:P,endLine:R,endLabel:X,endHandle:O,endMarker:D}=h;if(k==null||f==null){[b,A,S,B,P,R,X,O,D].forEach(Ze=>{Ze.style.display="none"});return}let Y=l.valToPos(k,"x"),ie=l.valToPos(f,"x"),L=window.devicePixelRatio||1,Te=l.bbox,ae=Te.width/L,ce=Te.height/L,_e=(Te.top+Te.height)/L,ue=Y>=0&&Y<=ae,ve=ie>=0&&ie<=ae,Ae=Math.max(0,Y),Ue=Math.min(ae,ie);if(Ue>Ae?(b.style.left=`${Ae}px`,b.style.width=`${Ue-Ae}px`,b.style.top="0",b.style.height=`${ce}px`,b.style.backgroundColor=tt(i.color,.07),b.style.display=""):b.style.display="none",ue){A.style.left=`${Y}px`,A.style.height=`${ce}px`,A.style.borderLeftColor=i.color,A.style.display="";let Ze=qe(k);S.textContent=Ze;let st=Ze.length*7+10;S.style.left=Y+st+4Ze.style.display="none");if(ve){R.style.left=`${ie}px`,R.style.height=`${ce}px`,R.style.borderLeftColor=i.color,R.style.display="";let Ze=qe(f);X.textContent=Ze;let st=Ze.length*7+10;X.style.left=ie-st-3>0?`${ie-st-3}px`:`${ie+3}px`,X.style.display="",O.style.left=`${ie}px`,O.style.backgroundColor=i.color,O.style.display="",D.style.left=`${ie}px`,D.style.top=`${_e}px`;let nt=D.querySelector(".material-symbols-rounded");nt&&(nt.style.color=i.color),D.style.display=""}else[R,X,O,D].forEach(Ze=>Ze.style.display="none")})}function qe(l){return $==="distance"?`${l.toFixed(2)} km`:ht(l)}function je(l,i,h,b){l.style.pointerEvents="auto",l.addEventListener("mousedown",A=>{A.stopPropagation(),A.preventDefault();let S=A.clientX,B=b?k:f,P=i.over.offsetWidth,R=i.scales.x.min,X=i.scales.x.max,O=P/(X-R),D=[h[0],h[h.length-1]];document.body.style.cursor="ew-resize",F=!0;function Y(L){let Te=L.clientX-S,ae=(B||0)+Te/O;ae=Math.max(D[0],Math.min(D[1],ae)),b?k=Math.min(ae,(f||D[1])-.001):f=Math.max(ae,(k||D[0])+.001),e.forEach(ce=>ce.uplot._strasse?.updateHeaderStats(ce.uplot.scales.x.min,ce.uplot.scales.x.max)),be(),At(),de&&de(k,f,$)}function ie(){document.body.style.cursor="",F=!1,document.removeEventListener("mousemove",Y),document.removeEventListener("mouseup",ie)}document.addEventListener("mousemove",Y),document.addEventListener("mouseup",ie)})}function dt(l){let{yData:i,xData:h,BINS:b}=l;if(l._lastYData===i&&l.bins)return;l._lastYData=i;let A=l.min,S=l.max;if(A==null||S==null){let D=1/0,Y=-1/0,ie=0;for(let L=0;LY&&(Y=Te),ie++)}if(!ie)return;A=D,S=Y,l.min=A,l.max=S}let B=new Array(b).fill(0),P=new Array(b).fill(0),R=S-A||1,X=l.plot?.metricKey??Object.keys(Ft).find(D=>Ft[D]===l.def),O=!X||T.has(X)||X!=="power"&&X!=="cadence"&&X!=="speed";for(let D=0;D0&&h[D-1]!=null?h[D-1]:h[D],Te=D{It(l,i,h.height)})}function It(l,i,h,b=null){let{def:A,BINS:S}=i;dt(i);let{bins:B,min:P,max:R}=i;if(!B||P==null||R==null)return;let X=k!=null&&f!=null;if(X&&(i._lastSelRange?.[0]!==k||i._lastSelRange?.[1]!==f)){i._lastSelRange=[k,f];let pe=new Array(S).fill(0),Je=new Array(S).fill(0),{yData:Ge,xData:Qe}=i,rt=R-P||1,ut=i.plot?.metricKey??Object.keys(Ft).find(Xe=>Ft[Xe]===i.def),mt=!ut||T.has(ut)||ut!=="power"&&ut!=="cadence"&&ut!=="speed";for(let Xe=0;Xef)continue;let St=Math.min(S-1,Math.floor((ct-P)/rt*S));pe[St]++;let jt=Xe>0&&Qe[Xe-1]!=null?Qe[Xe-1]:Qe[Xe],Et=XeA.fmtAxis(pe),ce="9px system-ui, sans-serif";L.font!==ce&&(L.font=ce);let ue={t:4,r:0,b:30,l:Math.ceil(Math.max(L.measureText(`${ae(R)} ${A.unit}`).width,L.measureText(`${ae(P)} ${A.unit}`).width))+6};i.padL=ue.l;let ve=Y-ue.l-ue.r,Ae=ie-ue.t-ue.b,Ue=pe=>ue.t+(S-1-pe)*(Ae/S),Ze=Ae/S-1,st=X?.15:.6;L.fillStyle=tt(A.color,st);for(let pe=0;pepe+Je,0);if(nt>0){let pe=[{x:ue.l,y:ue.t+Ae}],Je=0;for(let Ge=0;GeGe+Qe+2&&pe0){let pe=0;for(let ct=0;ct{let A=Yt(l,i,b);if(A!=null&&h){let{min:S,max:B,BINS:P}=i,R=B-S||1;h.pinnedHistY=S+(A+.5)*(R/P),e.forEach(({uplot:X})=>X.redraw(!1))}}),l.addEventListener("mousemove",b=>{E=b,wn(b,l,i)}),l.addEventListener("mouseenter",()=>{G=l,N=i}),l.addEventListener("mouseleave",()=>{G===l&&(G=null,N=null),U&&(U.style.display="none");let b=document.getElementById("hist-line");b&&(b.style.display="none"),h&&(h.hoveredHistY=null,It(l,i,l.height/(window.devicePixelRatio||1)))})}function Yt(l,i,h){let{bins:b,BINS:A}=i;if(!b)return null;let S=l.getBoundingClientRect(),B=h.clientY-S.top,P={t:4,b:30},R=S.height-P.t-P.b,X=Math.floor((B-P.t)/R*A),O=A-1-X;return X<0||X>=A?null:O}function wn(l,i,h){if(!U)return;let{bins:b,binAccum:A,min:S,max:B,BINS:P,def:R,plot:X}=h;if(!b||!A||S==null||B==null)return;let O=document.getElementById("hist-line"),D=Yt(i,h,l);if(D==null||!b[D]){U.style.display="none",O&&(O.style.display="none"),X&&(X.hoveredHistY=null,It(i,h,i.height/(window.devicePixelRatio||1)));return}if(X){let Qe=B-S||1;X.hoveredHistY=S+(D+.5)*(Qe/P),It(i,h,i.height/(window.devicePixelRatio||1),D)}let Y=b[D],ie=b.reduce((Qe,rt)=>Qe+rt,0),L=Y/ie*100,Te=B-S||1,ae=S+D*(Te/P),ce=S+(D+1)*(Te/P),_e=`${R.fmt(ae,!0)} \u2013 ${R.fmt(ce,!0)} ${R.unit}`,ue="",ve=(ae+ce)/2,Ae=Object.keys(Ft).find(Qe=>Ft[Qe]===R),Ue=[];if(Ae==="power"?Ue=Sn.getPowerZones():Ae==="hr"&&(Ue=Sn.getHRZones()),Ue.length>0){let Qe=Ue.findIndex(ut=>ve>=ut.min&&ve=Ue[Ue.length-1].min?Ue[Ue.length-1]:null;if(rt){let ut=Qe!==-1?Qe:Ue.length-1;ue=`
Z${ut+1} \xB7 ${rt.name}
- `}}let Ze=O==="distance"?`${L[V].toFixed(2)} km`:ht(L[V]),st=L[V]/L.reduce((Qe,rt)=>Qe+rt,0)*100,nt=` -
${Be}
- ${pe} + `}}let Ze=$==="distance"?`${A[D].toFixed(2)} km`:ht(A[D]),st=A[D]/A.reduce((Qe,rt)=>Qe+rt,0)*100,nt=` +
${_e}
+ ${ue} `;if(Ze&&(nt+=`
- ${O==="distance"?"Dist":"Time"} + ${$==="distance"?"Dist":"Time"} ${Ze} ${st.toFixed(1)}% -
`),h.selBins&&h.selBinAccum){let Qe=O==="distance"?`${h.selBinAccum[V].toFixed(2)} km`:ht(h.selBinAccum[V]),rt=h.selBinAccum[V]/h.selBinAccum.reduce((ut,mt)=>ut+mt,0)*100;nt+=` + `),h.selBins&&h.selBinAccum){let Qe=$==="distance"?`${h.selBinAccum[D].toFixed(2)} km`:ht(h.selBinAccum[D]),rt=h.selBinAccum[D]/h.selBinAccum.reduce((ut,mt)=>ut+mt,0)*100;nt+=`
- Sel ${O==="distance"?"Dist":"Time"} + Sel ${$==="distance"?"Dist":"Time"} ${Qe} ${rt.toFixed(1)}%
- `}Y.innerHTML=nt,Y.style.display="block";let it=Y.offsetHeight,lt=Y.offsetWidth,ce=i.getBoundingClientRect(),Je=ce.height-4-30,Ge=ce.top+4+($-1-V+.5)*(Je/$);Y.style.left=`${ce.left-lt-12}px`,Y.style.top=`${Ge-it/2}px`,z&&(z.style.display="block",z.style.top=`${Ge}px`,z.style.left="0px",z.style.width=`${ce.left}px`)}function Dn(l=!1){Y&&(Y.style.display="none"),e.forEach(({uplot:i,row:h})=>{a.unsub(i),i.destroy(),h.remove()}),e=[],n=null,l||(k=null,p=null),P=!1}function Js(l,i,h,v,L=!0){let S=1/0,B=-1/0,$=0,R=0;for(let Z=0;Zv)continue;let z=i[Z];z==null||!isFinite(z)||z===0&&!L||(zB&&(B=z),$+=z,R++)}return R?{min:S,max:B,avg:$/R}:null}function co(l,i,h){let v=0,L=0,S=null,B=O==="distance",$=l[0].time||0;for(let R=0;Rh)&&Z.ele!=null){if(S!=null){let V=Z.ele-S;V>0?v+=V:V<0&&(L+=Math.abs(V))}S=Z.ele}}return{gain:v,loss:L}}function Qs(l,i,h,v,L,S,B,$){if(h==null||L[h]==null){i.style.display="none";return}let R=l.valToPos(v[h],"x",!1),Z=l.valToPos(L[h],"y",!1),z="#888896",V=0;if(h>0&&S[h]&&S[h-1]){let re=S[h-1],Be=S[h],pe=(Be.dist||0)-(re.dist||0);pe>.1&&Be.ele!=null&&re.ele!=null&&(V=(Be.ele-re.ele)/pe*100,z=Kn(V))}let X=$!=="elevation"?`${B.fmt(L[h],!1)} ${B.unit}`:`${B.fmt(L[h],!1)} ${B.unit} \u2220 ${Math.abs(V).toFixed(1)}%`;if($==="gearRear"&&S[h].gearRearTooth!=null)X=`${S[h].gearRearTooth}T (pos ${L[h]})`;else if($==="gearFront"&&S[h].gearFrontTooth!=null)X=`${S[h].gearFrontTooth}T (pos ${L[h]})`;else if($==="gears"){let re=S[h],Be=re.gearFrontTooth!=null?`${re.gearFrontTooth}T`:re.gearFront!=null?`pos ${re.gearFront}`:"",pe=re.gearRearTooth!=null?`${re.gearRearTooth}T`:re.gearRear!=null?`pos ${re.gearRear}`:"";(Be||pe)&&(X+=` (${Be} / ${pe})`)}i.innerHTML!==X&&(i.innerHTML=X);let fe=`${B.color}44`;i.style.color!==B.color&&(i.style.color=B.color),i.style.borderColor!==fe&&(i.style.borderColor=fe);let I=`${R}px`,se=`${Z}px`,ge="translate(6px, -50%)";i.style.left!==I&&(i.style.left=I),i.style.top!==se&&(i.style.top=se),i.style.transform!==ge&&(i.style.transform=ge),i.style.display!==""&&(i.style.display="")}let Ks=new Map;function el(l){let i=Ks.get(l);return i||(i=tt(Kn(l),.8),Ks.set(l,i)),i}function uo(l,i,h,v){let L=l.ctx,S=l.bbox,B=window.devicePixelRatio||1,$=l.scales.x?.min??-1/0,R=l.scales.x?.max??1/0,Z=l.scales.y?.min??0,z=l.scales.y?.max??100,V=S.width/(R-$||1),X=S.height/(z-Z||1),fe=S.top+S.height,I=l.series[0]?.idxs,se=I?Math.max(1,I[0]):1,ge=I?Math.min(i.length-1,I[1]+1):i.length-1,re=Math.max(1,Math.floor((ge-se)/250));L.save(),L.lineWidth=1.5*B;let Be=new Map,pe=se-1;for(let ye=se;ye<=ge;ye+=re){let Te=i[ye],qe=i[pe];if(pe=ye,Te==null||h[ye]==null||qe==null||h[ye-re]==null||Te<$||qe>R)continue;let Ze=S.left+(qe-$)*V,st=fe-(h[ye-re]-Z)*X,nt=S.left+(Te-$)*V,it=fe-(h[ye]-Z)*X,lt=v&&v[ye]!=null?Math.round(v[ye]/2)*2:null,ce=el(lt),Je=Be.get(ce);Je||(Je=[],Be.set(ce,Je)),Je.push(Ze,st,nt,it)}for(let[ye,Te]of Be){L.beginPath(),L.strokeStyle=ye;for(let qe=0;qe$)continue;let qe=L.left+(Te-B)*z,Ze=X-(h[pe-ge]-R)*V,st=L.left+(ye-B)*z,nt=X-(h[pe]-R)*V,it=Math.round(h[pe]/2)*2,lt=el(it),ce=re.get(lt);ce||(ce=[],re.set(lt,ce)),ce.push(qe,Ze,st,nt)}for(let[pe,ye]of re){v.beginPath(),v.strokeStyle=pe;for(let Te=0;Te{let Te=`bold ${10*B}px system-ui, sans-serif`;R.font!==Te&&(R.font=Te);let Ze=R.measureText(re).width+10*B,st=16*B,nt=Be-Ze/2,it=Math.max($.left,Math.min($.left+$.width-Ze,nt)),lt=pe-st/2;R.save(),R.globalAlpha=S,R.setLineDash([]),R.beginPath(),R.roundRect?R.roundRect(it,lt,Ze,st,3*B):R.rect(it,lt,Ze,st),R.fillStyle="rgba(14,14,16,0.92)",R.fill(),R.strokeStyle=tt(v,.27),R.lineWidth=1*B,R.stroke(),R.fillStyle=v,R.textAlign="center",R.textBaseline="middle",R.fillText(re,it+Ze/2,lt+st/2+.5*B),R.restore()};L||tl(l,i,h,v,S);let ge=16*B;se(I,X,$.top+ge/2,!0),se(fe,X,$.top+$.height+15*B,!1)}function po(l,i,h,v,L,S,B){if(u==null)return;let $=i[u],R=h[u];if($==null||R==null)return;let Z=l.valToPos($,"x",!0),z=l.valToPos(R,"y",!0),V=l.bbox,X=l.ctx,fe=window.devicePixelRatio||1;X.save(),X.beginPath(),X.strokeStyle=v,X.lineWidth=1.5*fe,X.moveTo(Z,V.top),X.lineTo(Z,V.top+V.height),X.stroke(),X.beginPath(),X.setLineDash([3*fe,3*fe]),X.strokeStyle=tt(v,.5),X.lineWidth=1*fe,X.moveTo(V.left,z),X.lineTo(Z,z),X.stroke(),X.beginPath(),X.setLineDash([]),X.arc(Z,z,5*fe,0,Math.PI*2),X.fillStyle="#0e0e10",X.fill(),X.strokeStyle=v,X.lineWidth=2.5*fe,X.stroke(),X.restore();let I=l._strasse;I&&I.pinYVal&&Qs(l,I.pinYVal,u,i,h,S,L,B)}function fo(l,i,h,v,L,S){let B=l.bbox,$=l.ctx,R=window.devicePixelRatio||1,Z=l.valToPos(v,"y",!0),z=Math.max(B.top,Math.min(B.top+B.height,Z));$.save(),$.beginPath(),$.setLineDash([4*R,4*R]),$.strokeStyle=tt(L,.4),$.lineWidth=1*R,$.moveTo(B.left,z),$.lineTo(B.left+B.width,z),$.stroke(),go(l,i,h,z,L);let V=S.fmt(v,!0),X=`bold ${10*R}px system-ui, sans-serif`;$.font!==X&&($.font=X);let I=$.measureText(V).width+8*R,se=16*R,ge=B.left-I-2*R,re=z-se/2;$.beginPath(),$.setLineDash([]),$.roundRect?$.roundRect(ge,re,I,se,3*R):$.rect(ge,re,I,se),$.fillStyle="rgba(14,14,16,0.95)",$.fill(),$.strokeStyle=L,$.lineWidth=1*R,$.stroke(),$.fillStyle="#fff",$.textAlign="center",$.textBaseline="middle",$.fillText(V,ge+I/2,re+se/2+.5*R),$.restore()}function go(l,i,h,v,L){let S=l.ctx,B=l.bbox,$=l.scales.x?.min??-1/0,R=l.scales.x?.max??1/0,Z=l.scales.y?.min??0,z=l.scales.y?.max??100,V=B.width/(R-$||1),X=B.height/(z-Z||1),fe=l.scales.y?.dir??1,I=fe===-1?B.top:B.top+B.height,se=fe===-1?X:-X,ge=l.series[0]?.idxs,re=ge?Math.max(0,ge[0]-1):0,Be=ge?Math.min(i.length-1,ge[1]+1):i.length-1,pe=Math.max(1,Math.floor((Be-re)/250));S.save(),S.beginPath(),S.rect(B.left,B.top,B.width,B.height),S.clip(),S.fillStyle=tt(L,.2),S.beginPath();let ye=!1,Te=!1,qe=0;for(let Ze=re;Ze<=Be;Ze+=pe){let st=i[Ze],nt=h[Ze];if(st==null||nt==null||st<$||st>R){ye&&(S.lineTo(qe,v),S.closePath(),ye=!1);continue}let it=B.left+(st-$)*V,lt=I+(nt-Z)*se;qe=it,lt>16,B=v>>8&255,$=v&255,R=L>>16,Z=L>>8&255,z=L&255,V=S+(R-S)*h,X=B+(Z-B)*h,fe=$+(z-$)*h;return`#${((1<<24)+(Math.round(V)<<16)+(Math.round(X)<<8)+Math.round(fe)).toString(16).slice(1)}`}function Kn(l){if(l==null)return"#888896";let i=Math.abs(l),h=Math.min(1,i/8);return l>0?Dt("#A8C8A0","#d73027",h):Dt("#A8C8A0","#4575b4",h)}function sl(l){if(l==null)return"#888896";let i=l*3.6;if(i<=5)return"#4575b4";if(i>=60)return"#d73027";if(i<=45){let h=(i-5)/40;return h<=.25?Dt("#4575b4","#91bfdb",h/.25):h<=.5?Dt("#91bfdb","#abdda4",(h-.25)/.25):h<=.75?Dt("#abdda4","#fee08b",(h-.5)/.25):Dt("#fee08b","#fc8d59",(h-.75)/.25)}else{let h=(i-45)/15;return Dt("#fc8d59","#d73027",h)}}function ho(l,i){let h=new Array(l.length).fill(null);for(let v=0;v0&&(L.dist||0)-(l[S].dist||0)1&&l[B].ele!=null&&l[S].ele!=null&&(h[v]=(l[B].ele-l[S].ele)/$*100)}return h}function ll(l){let i=[...l];for(let h=0;h=0&&i[v]===null;)v--;let L=h+1;for(;L=0&&L=0?i[h]=i[v]:L{let Z=document.querySelector(`#${$} .stat-value`);Z&&(Z.textContent=R)};h("stat-distance",i.totalDist!=null?`${(i.totalDist/1e3).toFixed(1)} km`:"\u2014"),h("stat-duration",i.duration!=null?ht(Math.floor(i.duration/1e3)):"\u2014"),h("stat-elevation",i.elevGain!=null?`${Math.round(i.elevGain)} m`:"\u2014");let v=$=>{let R=e.find(V=>V.metricKey===$);if(!R)return $==="speed"?i.avgSpeed??null:$==="power"?i.avgPower??null:$==="cadence"?i.avgCadence??null:null;if(R.histData.fullStats!==void 0)return R.histData.fullStats?R.histData.fullStats.avg:null;let Z=M.has($)||$!=="power"&&$!=="cadence"&&$!=="speed",z=R.yData.filter(V=>V!=null&&(Z||V!==0));return z.length?z.reduce((V,X)=>V+X,0)/z.length:null},L=v("speed");h("stat-avg-speed",L!=null?`${(L*3.6).toFixed(1)} km/h`:"\u2014");let S=v("power");h("stat-avg-power",S!=null?`${Math.round(S)} W`:"\u2014");let B=v("cadence");h("stat-avg-cad",B!=null?`${Math.round(B)} rpm`:"\u2014"),h("stat-avg-hr",i.avgHR!=null?`${i.avgHR} bpm`:"\u2014"),h("stat-avg-temp",i.avgTemp!=null?`${i.avgTemp.toFixed(1)} \xB0C`:"\u2014")}let pn=16384,fn=new Float64Array(pn),Tn=new Float64Array(pn),es=new Float64Array(pn),Rn=new Float64Array(pn),Ls=new Float64Array(pn),ts=new Float64Array(pn),Nn=new Float64Array(64),il=[3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300,360];function bo(l,i,h){if(!l.length)return 0;Nn.fill(0);let v=0;for(let L=0;L=B)continue;let re=1/ge,Be=0,pe=0,ye=0;for(let Te=0;Te=ge){Be-=ts[Te-ge],pe-=Rn[Te-ge];let qe=(Be+pe*.05)*re;qe>ye&&(ye=qe)}v+=ye*1e-4}for(let se=$;se0&&(Nn[ge-1]+=.5),ge<63&&(Nn[ge+1]+=.5)}}}for(let L=0;L<64;L++)v+=Nn[L]*1e-5;return K&&(K.dataset.intervalScore=v.toFixed(2)),v}return{init:xe,loadTrack:G,clear:F,resetState:ae,toggleMetric:ue,setXAxis:Ie,toggleStats:he,setSelectionStats:Ne,clearSelectionStats:j,restoreSelection:_e,resetZoom:A,cancelSelection:ne,analyzeTelemetryIntervals:bo,setCursorAt:(l,i=!1)=>{if(u=l,d&&d(l),i){N&&H?.points?.[l]&&N(H.points[l]);return}c=!0,e.forEach(({uplot:h,yData:v,xData:L})=>{L[l]!=null&&v[l]!=null&&h.batch(()=>{h.setCursor({left:h.valToPos(L[l],"x"),top:h.valToPos(v[l],"y")},!0,!1)})}),c=!1,N&&H?.points?.[l]&&N(H.points[l])},setHoverAt:l=>{c=!0,e.forEach(({uplot:i,yData:h,xData:v})=>{l===null?i.batch(()=>{i.setCursor({left:-10,top:-10},!0,!1)}):v[l]!=null&&h[l]!=null&&i.batch(()=>{i.setCursor({left:i.valToPos(v[l],"x"),top:i.valToPos(h[l],"y")},!0,!1)})}),c=!1,N&&N(l!=null&&H?.points?.[l]?H.points[l]:null)},clearPinnedDot:()=>{u=null,d&&d(null),e.forEach(({uplot:l})=>l.redraw(!1))},resize:we,METRICS:Ft,isDragging:()=>P,setMapColorChangeCb:He,toggleMapColor:Ce,getMapColorMetric:()=>oe,getActiveMetrics:()=>m,getAvailableMetrics:()=>T,setActiveMetrics:te,updateMetricOrder:l=>{let i=new Set;l.forEach(h=>{m.has(h)&&i.add(h)}),m.forEach(h=>{i.has(h)||i.add(h)}),m=i,H&&Ee(!0)},getXAxis:()=>O};function vo(l,i,h,v,L){let S=l.ctx,B=l.bbox,$=window.devicePixelRatio||1,R=be(L,h);S.save(),S.beginPath(),S.rect(B.left,B.top,B.width,B.height),S.clip();let Z=L==="gearRear"||L==="gearFront";for(let z=1;zfe.time!=null)?.time||0,V=h.field;v.beginPath(),v.strokeStyle="rgba(255, 255, 255, 0.04)",v.lineWidth=1*S;let X=!0;for(let fe=0;fe0){let ye=Z[fe-1];(I.time&&ye.time?I.time-ye.time:0)>B&&(X=!0)}let ge=h.transform?h.transform(se):se;if(ge==null){X=!0;continue}let re=O==="distance"?(I.dist||0)/1e3:(I.time-z)/1e3;if(rel.scales.x.max+10){X=!0;continue}let Be=l.valToPos(re,"x",!0),pe=l.valToPos(ge,"y",!0);if(X)v.moveTo(Be,pe),X=!1;else{if($){let ye=Z[fe-1],Te=O==="distance"?(ye.dist||0)/1e3:(ye.time-z)/1e3;v.lineTo(l.valToPos(Te,"x",!0),pe)}v.lineTo(Be,pe)}}v.stroke()}v.restore()}function al(l,i,h,v,L,S,B=null,$=[]){let R=l.ctx,Z=l.bbox,z=window.devicePixelRatio||1,V=6e4;R.save(),R.beginPath(),R.strokeStyle=tt(v,.8),R.lineWidth=L*z;let X=S==="gearRear"||S==="gearFront",fe=!0,I=null,se=1,ge=1;if(S==="gears"&&$.length>0){let Xe=1/0,ct=-1/0;for(let vt=0;vt<$.length;vt++){let St=$[vt].gearFrontTooth??$[vt].gearFront;St!=null&&(Stct&&(ct=St))}Xe<=ct&&(se=Xe,ge=ct)}let re=B?B[0]:l.scales.x?.min??-1/0,Be=B?B[1]:l.scales.x?.max??1/0,pe=l.scales.x?.min??-1/0,ye=l.scales.x?.max??1/0,Te=l.scales.y?.min??0,qe=l.scales.y?.max??100,Ze=Z.width/(ye-pe||1),st=Z.height/(qe-Te||1),nt=l.scales.y?.dir??1,it=nt===-1?Z.top:Z.top+Z.height,lt=nt===-1?st:-st,ce=B?null:l.series[0]?.idxs,Je=ce?Math.max(0,ce[0]-1):0,Ge=ce?Math.min(i.length-1,ce[1]+1):i.length-1,Qe=X||S==="gears"?1:Math.max(1,Math.floor((Ge-Je)/250)),rt=O==="time",ut=V/1e3,mt=Je;for(let Xe=Je;Xe<=Ge;Xe+=Qe){let ct=i[Xe],vt=h[Xe];if(ct==null||vt==null){fe=!0;continue}if(S==="gears"&&$[Xe]){let Et=$[Xe].gearFrontTooth??$[Xe].gearFront;if(Et!=null&&Et!==I){if(!fe&&Xe>0){R.stroke(),R.beginPath();let Ps=Z.left+(i[mt]-pe)*Ze,ns=it+(h[mt]-Te)*lt;R.moveTo(Ps,ns)}let Kt=v;ge!==se&&Et!=null&&(Et===se?Kt="#FFC400":Et===ge?Kt="#FF8C00":Kt="#FFA500"),R.strokeStyle=tt(Kt,.8),I=Et}}if(Xe>Je&&rt){let Et=i[mt];Et!=null&&ct-Et>ut&&(fe=!0)}if(ctBe){fe=!0;continue}let St=Z.left+(ct-pe)*Ze,jt=it+(vt-Te)*lt;if(fe)R.moveTo(St,jt),fe=!1;else{if(X){let Et=i[mt];R.lineTo(Z.left+(Et-pe)*Ze,jt)}R.lineTo(St,jt)}mt=Xe}R.stroke(),R.restore()}})();var Ho={"Heart Rate":We.hr.icon,Cadence:We.cadence.icon,Power:We.power.icon,Temperature:We.temperature.icon,Shifting:We.gears.icon,Battery:We.battery.icon},Mn=()=>{},yl=()=>{};function xl(e,n){Mn=e,yl=n}function wl(){let e=document.getElementById("details-view");e&&(e.innerHTML=` + `}U.innerHTML=nt,U.style.display="block";let it=U.offsetHeight,lt=U.offsetWidth,pe=i.getBoundingClientRect(),Je=pe.height-4-30,Ge=pe.top+4+(P-1-D+.5)*(Je/P);U.style.left=`${pe.left-lt-12}px`,U.style.top=`${Ge-it/2}px`,O&&(O.style.display="block",O.style.top=`${Ge}px`,O.style.left="0px",O.style.width=`${pe.left}px`)}function Rn(l=!1){U&&(U.style.display="none"),e.forEach(({uplot:i,row:h})=>{a.unsub(i),i.destroy(),h.remove()}),e=[],n=null,l||(k=null,f=null),F=!1}function Js(l,i,h,b,A=!0){let S=1/0,B=-1/0,P=0,R=0;for(let X=0;Xb)continue;let O=i[X];O==null||!isFinite(O)||O===0&&!A||(OB&&(B=O),P+=O,R++)}return R?{min:S,max:B,avg:P/R}:null}function ao(l,i,h){let b=0,A=0,S=null,B=$==="distance",P=l[0].time||0;for(let R=0;Rh)&&X.ele!=null){if(S!=null){let D=X.ele-S;D>0?b+=D:D<0&&(A+=Math.abs(D))}S=X.ele}}return{gain:b,loss:A}}function Qs(l,i,h,b,A,S,B,P){if(h==null||A[h]==null){i.style.display="none";return}let R=l.valToPos(b[h],"x",!1),X=l.valToPos(A[h],"y",!1),O="#888896",D=0;if(h>0&&S[h]&&S[h-1]){let ce=S[h-1],_e=S[h],ue=(_e.dist||0)-(ce.dist||0);ue>.1&&_e.ele!=null&&ce.ele!=null&&(D=(_e.ele-ce.ele)/ue*100,O=es(D))}let Y=P!=="elevation"?`${B.fmt(A[h],!1)} ${B.unit}`:`${B.fmt(A[h],!1)} ${B.unit} \u2220 ${Math.abs(D).toFixed(1)}%`;if(P==="gearRear"&&S[h].gearRearTooth!=null)Y=`${S[h].gearRearTooth}T (pos ${A[h]})`;else if(P==="gearFront"&&S[h].gearFrontTooth!=null)Y=`${S[h].gearFrontTooth}T (pos ${A[h]})`;else if(P==="gears"){let ce=S[h],_e=ce.gearFrontTooth!=null?`${ce.gearFrontTooth}T`:ce.gearFront!=null?`pos ${ce.gearFront}`:"",ue=ce.gearRearTooth!=null?`${ce.gearRearTooth}T`:ce.gearRear!=null?`pos ${ce.gearRear}`:"";(_e||ue)&&(Y+=` (${_e} / ${ue})`)}i.innerHTML!==Y&&(i.innerHTML=Y);let ie=`${B.color}44`;i.style.color!==B.color&&(i.style.color=B.color),i.style.borderColor!==ie&&(i.style.borderColor=ie);let L=`${R}px`,Te=`${X}px`,ae="translate(6px, -50%)";i.style.left!==L&&(i.style.left=L),i.style.top!==Te&&(i.style.top=Te),i.style.transform!==ae&&(i.style.transform=ae),i.style.display!==""&&(i.style.display="")}let Ks=new Map;function el(l){let i=Ks.get(l);return i||(i=tt(es(l),.8),Ks.set(l,i)),i}function ro(l,i,h,b){let A=l.ctx,S=l.bbox,B=window.devicePixelRatio||1,P=l.scales.x?.min??-1/0,R=l.scales.x?.max??1/0,X=l.scales.y?.min??0,O=l.scales.y?.max??100,D=S.width/(R-P||1),Y=S.height/(O-X||1),ie=S.top+S.height,L=l.series[0]?.idxs,Te=L?Math.max(1,L[0]):1,ae=L?Math.min(i.length-1,L[1]+1):i.length-1,ce=Math.max(1,Math.floor((ae-Te)/250));A.save(),A.lineWidth=1.5*B;let _e=new Map,ue=Te-1;for(let ve=Te;ve<=ae;ve+=ce){let Ae=i[ve],Ue=i[ue];if(ue=ve,Ae==null||h[ve]==null||Ue==null||h[ve-ce]==null||AeR)continue;let Ze=S.left+(Ue-P)*D,st=ie-(h[ve-ce]-X)*Y,nt=S.left+(Ae-P)*D,it=ie-(h[ve]-X)*Y,lt=b&&b[ve]!=null?Math.round(b[ve]/2)*2:null,pe=el(lt),Je=_e.get(pe);Je||(Je=[],_e.set(pe,Je)),Je.push(Ze,st,nt,it)}for(let[ve,Ae]of _e){A.beginPath(),A.strokeStyle=ve;for(let Ue=0;UeP)continue;let Ue=A.left+(Ae-B)*O,Ze=Y-(h[ue-ae]-R)*D,st=A.left+(ve-B)*O,nt=Y-(h[ue]-R)*D,it=Math.round(h[ue]/2)*2,lt=el(it),pe=ce.get(lt);pe||(pe=[],ce.set(lt,pe)),pe.push(Ue,Ze,st,nt)}for(let[ue,ve]of ce){b.beginPath(),b.strokeStyle=ue;for(let Ae=0;Ae{let Ae=`bold ${10*B}px system-ui, sans-serif`;R.font!==Ae&&(R.font=Ae);let Ze=R.measureText(ce).width+10*B,st=16*B,nt=_e-Ze/2,it=Math.max(P.left,Math.min(P.left+P.width-Ze,nt)),lt=ue-st/2;R.save(),R.globalAlpha=S,R.setLineDash([]),R.beginPath(),R.roundRect?R.roundRect(it,lt,Ze,st,3*B):R.rect(it,lt,Ze,st),R.fillStyle="rgba(14,14,16,0.92)",R.fill(),R.strokeStyle=tt(b,.27),R.lineWidth=1*B,R.stroke(),R.fillStyle=b,R.textAlign="center",R.textBaseline="middle",R.fillText(ce,it+Ze/2,lt+st/2+.5*B),R.restore()};A||tl(l,i,h,b,S);let ae=16*B;Te(L,Y,P.top+ae/2,!0),Te(ie,Y,P.top+P.height+15*B,!1)}function uo(l,i,h,b,A,S,B){if(u==null)return;let P=i[u],R=h[u];if(P==null||R==null)return;let X=l.valToPos(P,"x",!0),O=l.valToPos(R,"y",!0),D=l.bbox,Y=l.ctx,ie=window.devicePixelRatio||1;Y.save(),Y.beginPath(),Y.strokeStyle=b,Y.lineWidth=1.5*ie,Y.moveTo(X,D.top),Y.lineTo(X,D.top+D.height),Y.stroke(),Y.beginPath(),Y.setLineDash([3*ie,3*ie]),Y.strokeStyle=tt(b,.5),Y.lineWidth=1*ie,Y.moveTo(D.left,O),Y.lineTo(X,O),Y.stroke(),Y.beginPath(),Y.setLineDash([]),Y.arc(X,O,5*ie,0,Math.PI*2),Y.fillStyle="#0e0e10",Y.fill(),Y.strokeStyle=b,Y.lineWidth=2.5*ie,Y.stroke(),Y.restore();let L=l._strasse;L&&L.pinYVal&&Qs(l,L.pinYVal,u,i,h,S,A,B)}function mo(l,i,h,b,A,S){let B=l.bbox,P=l.ctx,R=window.devicePixelRatio||1,X=l.valToPos(b,"y",!0),O=Math.max(B.top,Math.min(B.top+B.height,X));P.save(),P.beginPath(),P.setLineDash([4*R,4*R]),P.strokeStyle=tt(A,.4),P.lineWidth=1*R,P.moveTo(B.left,O),P.lineTo(B.left+B.width,O),P.stroke(),po(l,i,h,O,A);let D=S.fmt(b,!0),Y=`bold ${10*R}px system-ui, sans-serif`;P.font!==Y&&(P.font=Y);let L=P.measureText(D).width+8*R,Te=16*R,ae=B.left-L-2*R,ce=O-Te/2;P.beginPath(),P.setLineDash([]),P.roundRect?P.roundRect(ae,ce,L,Te,3*R):P.rect(ae,ce,L,Te),P.fillStyle="rgba(14,14,16,0.95)",P.fill(),P.strokeStyle=A,P.lineWidth=1*R,P.stroke(),P.fillStyle="#fff",P.textAlign="center",P.textBaseline="middle",P.fillText(D,ae+L/2,ce+Te/2+.5*R),P.restore()}function po(l,i,h,b,A){let S=l.ctx,B=l.bbox,P=l.scales.x?.min??-1/0,R=l.scales.x?.max??1/0,X=l.scales.y?.min??0,O=l.scales.y?.max??100,D=B.width/(R-P||1),Y=B.height/(O-X||1),ie=l.scales.y?.dir??1,L=ie===-1?B.top:B.top+B.height,Te=ie===-1?Y:-Y,ae=l.series[0]?.idxs,ce=ae?Math.max(0,ae[0]-1):0,_e=ae?Math.min(i.length-1,ae[1]+1):i.length-1,ue=Math.max(1,Math.floor((_e-ce)/250));S.save(),S.beginPath(),S.rect(B.left,B.top,B.width,B.height),S.clip(),S.fillStyle=tt(A,.2),S.beginPath();let ve=!1,Ae=!1,Ue=0;for(let Ze=ce;Ze<=_e;Ze+=ue){let st=i[Ze],nt=h[Ze];if(st==null||nt==null||stR){ve&&(S.lineTo(Ue,b),S.closePath(),ve=!1);continue}let it=B.left+(st-P)*D,lt=L+(nt-X)*Te;Ue=it,lt>16,B=b>>8&255,P=b&255,R=A>>16,X=A>>8&255,O=A&255,D=S+(R-S)*h,Y=B+(X-B)*h,ie=P+(O-P)*h;return`#${((1<<24)+(Math.round(D)<<16)+(Math.round(Y)<<8)+Math.round(ie)).toString(16).slice(1)}`}function es(l){if(l==null)return"#888896";let i=Math.abs(l),h=Math.min(1,i/8);return l>0?Dt("#A8C8A0","#d73027",h):Dt("#A8C8A0","#4575b4",h)}function sl(l){if(l==null)return"#888896";let i=l*3.6;if(i<=5)return"#4575b4";if(i>=60)return"#d73027";if(i<=45){let h=(i-5)/40;return h<=.25?Dt("#4575b4","#91bfdb",h/.25):h<=.5?Dt("#91bfdb","#abdda4",(h-.25)/.25):h<=.75?Dt("#abdda4","#fee08b",(h-.5)/.25):Dt("#fee08b","#fc8d59",(h-.75)/.25)}else{let h=(i-45)/15;return Dt("#fc8d59","#d73027",h)}}function fo(l,i){let h=new Array(l.length).fill(null);for(let b=0;b0&&(A.dist||0)-(l[S].dist||0)1&&l[B].ele!=null&&l[S].ele!=null&&(h[b]=(l[B].ele-l[S].ele)/P*100)}return h}function ll(l){let i=[...l];for(let h=0;h=0&&i[b]===null;)b--;let A=h+1;for(;A=0&&A=0?i[h]=i[b]:A{let X=document.querySelector(`#${P} .stat-value`);X&&(X.textContent=R)};h("stat-distance",i.totalDist!=null?`${(i.totalDist/1e3).toFixed(1)} km`:"\u2014"),h("stat-duration",i.duration!=null?ht(Math.floor(i.duration/1e3)):"\u2014"),h("stat-elevation",i.elevGain!=null?`${Math.round(i.elevGain)} m`:"\u2014");let b=P=>{let R=e.find(D=>D.metricKey===P);if(!R)return P==="speed"?i.avgSpeed??null:P==="power"?i.avgPower??null:P==="cadence"?i.avgCadence??null:null;if(R.histData.fullStats!==void 0)return R.histData.fullStats?R.histData.fullStats.avg:null;let X=T.has(P)||P!=="power"&&P!=="cadence"&&P!=="speed",O=R.yData.filter(D=>D!=null&&(X||D!==0));return O.length?O.reduce((D,Y)=>D+Y,0)/O.length:null},A=b("speed");h("stat-avg-speed",A!=null?`${(A*3.6).toFixed(1)} km/h`:"\u2014");let S=b("power");h("stat-avg-power",S!=null?`${Math.round(S)} W`:"\u2014");let B=b("cadence");h("stat-avg-cad",B!=null?`${Math.round(B)} rpm`:"\u2014"),h("stat-avg-hr",i.avgHR!=null?`${i.avgHR} bpm`:"\u2014"),h("stat-avg-temp",i.avgTemp!=null?`${i.avgTemp.toFixed(1)} \xB0C`:"\u2014")}let pn=16384,fn=new Float64Array(pn),Tn=new Float64Array(pn),ts=new Float64Array(pn),Nn=new Float64Array(pn),$s=new Float64Array(pn),ns=new Float64Array(pn),Wn=new Float64Array(64),il=[3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300,360];function go(l,i,h){if(!l.length)return 0;Wn.fill(0);let b=0;for(let A=0;A=B)continue;let Te=Y/L,ae=0,ce=0,_e=0;for(let ue=0;ue=L){ae-=ns[ue-L],ce-=Nn[ue-L];let ve=(ae+ce*.05)*Te;ve>_e&&(_e=ve)}b+=_e*1e-4}for(let ie=P;ie0&&(Wn[L-1]+=.5),L<63&&(Wn[L+1]+=.5)}}}for(let A=0;A<64;A++)b+=Wn[A]*1e-5;return Q&&(Q.dataset.intervalScore=b.toFixed(2)),b}return{init:fe,loadTrack:j,clear:H,resetState:oe,toggleMetric:ge,setXAxis:Ie,toggleStats:he,setSelectionStats:Ne,clearSelectionStats:Z,restoreSelection:Be,resetZoom:I,cancelSelection:ne,analyzeTelemetryIntervals:go,setCursorAt:(l,i=!1)=>{if(u=l,m&&m(l),i){z&&M?.points?.[l]&&z(M.points[l]);return}c=!0,e.forEach(({uplot:h,yData:b,xData:A})=>{A[l]!=null&&b[l]!=null&&h.batch(()=>{h.setCursor({left:h.valToPos(A[l],"x"),top:h.valToPos(b[l],"y")},!0,!1)})}),c=!1,z&&M?.points?.[l]&&z(M.points[l])},setHoverAt:l=>{c=!0,e.forEach(({uplot:i,yData:h,xData:b})=>{l===null?i.batch(()=>{i.setCursor({left:-10,top:-10},!0,!1)}):b[l]!=null&&h[l]!=null&&i.batch(()=>{i.setCursor({left:i.valToPos(b[l],"x"),top:i.valToPos(h[l],"y")},!0,!1)})}),c=!1,z&&z(l!=null&&M?.points?.[l]?M.points[l]:null)},clearPinnedDot:()=>{u=null,m&&m(null),e.forEach(({uplot:l})=>l.redraw(!1))},resize:xe,METRICS:Ft,isDragging:()=>F,setMapColorChangeCb:He,toggleMapColor:Ce,getMapColorMetric:()=>se,getActiveMetrics:()=>d,getAvailableMetrics:()=>x,setActiveMetrics:K,updateMetricOrder:l=>{let i=new Set;l.forEach(h=>{d.has(h)&&i.add(h)}),d.forEach(h=>{i.has(h)||i.add(h)}),d=i,M&&Ee(!0)},getXAxis:()=>$};function ho(l,i,h,b,A){let S=l.ctx,B=l.bbox,P=window.devicePixelRatio||1,R=ye(A,h);S.save(),S.beginPath(),S.rect(B.left,B.top,B.width,B.height),S.clip();let X=A==="gearRear"||A==="gearFront";for(let O=1;Oie.time!=null)?.time||0,D=h.field;b.beginPath(),b.strokeStyle="rgba(255, 255, 255, 0.04)",b.lineWidth=1*S;let Y=!0;for(let ie=0;ie0){let ve=X[ie-1];(L.time&&ve.time?L.time-ve.time:0)>B&&(Y=!0)}let ae=h.transform?h.transform(Te):Te;if(ae==null){Y=!0;continue}let ce=$==="distance"?(L.dist||0)/1e3:(L.time-O)/1e3;if(cel.scales.x.max+10){Y=!0;continue}let _e=l.valToPos(ce,"x",!0),ue=l.valToPos(ae,"y",!0);if(Y)b.moveTo(_e,ue),Y=!1;else{if(P){let ve=X[ie-1],Ae=$==="distance"?(ve.dist||0)/1e3:(ve.time-O)/1e3;b.lineTo(l.valToPos(Ae,"x",!0),ue)}b.lineTo(_e,ue)}}b.stroke()}b.restore()}function al(l,i,h,b,A,S,B=null,P=[]){let R=l.ctx,X=l.bbox,O=window.devicePixelRatio||1,D=6e4;R.save(),R.beginPath(),R.strokeStyle=tt(b,.8),R.lineWidth=A*O;let Y=S==="gearRear"||S==="gearFront",ie=!0,L=null,Te=1,ae=1;if(S==="gears"&&P.length>0){let Xe=1/0,ct=-1/0;for(let vt=0;vtct&&(ct=St))}Xe<=ct&&(Te=Xe,ae=ct)}let ce=B?B[0]:l.scales.x?.min??-1/0,_e=B?B[1]:l.scales.x?.max??1/0,ue=l.scales.x?.min??-1/0,ve=l.scales.x?.max??1/0,Ae=l.scales.y?.min??0,Ue=l.scales.y?.max??100,Ze=X.width/(ve-ue||1),st=X.height/(Ue-Ae||1),nt=l.scales.y?.dir??1,it=nt===-1?X.top:X.top+X.height,lt=nt===-1?st:-st,pe=B?null:l.series[0]?.idxs,Je=pe?Math.max(0,pe[0]-1):0,Ge=pe?Math.min(i.length-1,pe[1]+1):i.length-1,Qe=Y||S==="gears"?1:Math.max(1,Math.floor((Ge-Je)/250)),rt=$==="time",ut=D/1e3,mt=Je;for(let Xe=Je;Xe<=Ge;Xe+=Qe){let ct=i[Xe],vt=h[Xe];if(ct==null||vt==null){ie=!0;continue}if(S==="gears"&&P[Xe]){let Et=P[Xe].gearFrontTooth??P[Xe].gearFront;if(Et!=null&&Et!==L){if(!ie&&Xe>0){R.stroke(),R.beginPath();let Ls=X.left+(i[mt]-ue)*Ze,ss=it+(h[mt]-Ae)*lt;R.moveTo(Ls,ss)}let Kt=b;ae!==Te&&Et!=null&&(Et===Te?Kt="#FFC400":Et===ae?Kt="#FF8C00":Kt="#FFA500"),R.strokeStyle=tt(Kt,.8),L=Et}}if(Xe>Je&&rt){let Et=i[mt];Et!=null&&ct-Et>ut&&(ie=!0)}if(ct_e){ie=!0;continue}let St=X.left+(ct-ue)*Ze,jt=it+(vt-Ae)*lt;if(ie)R.moveTo(St,jt),ie=!1;else{if(Y){let Et=i[mt];R.lineTo(X.left+(Et-ue)*Ze,jt)}R.lineTo(St,jt)}mt=Xe}R.stroke(),R.restore()}})();var Ao={"Heart Rate":We.hr.icon,Cadence:We.cadence.icon,Power:We.power.icon,Temperature:We.temperature.icon,Shifting:We.gears.icon,Battery:We.battery.icon},Mn=()=>{},yl=()=>{};function xl(e,n){Mn=e,yl=n}function wl(){let e=document.getElementById("details-view");e&&(e.innerHTML=`
no_sim
Select a track for details
- `)}var on=16384,ln=[new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on)],Fo=[2,3,4,5,6,8,10,12,15,18,20,25,30,35,40,45,50,60,75,90,105,120,150,180,210,240,300,360,420,480];function an(e,n=[],t=[]){let s=document.getElementById("details-view");if(!s)return;if(!e){s.innerHTML="";return}let o=e.stats,a=e.points[0].time,g=t.length>0?t:[e],c=0;for(let b=0;b=x)continue;let _=1/W,C=Math.max(1,W>>1);for(let q=0;q<7;q++){let N=ln[q],ie=0,y=0,d=0,r=0,J=1/(10+q*15+D*2+w*3);for(let U=0;U=W){let Y=N[U-W];ie-=Y,y-=Y*Y;let K=ie*_,Ae=Math.max(0,y*_-K*K),me=N[U-C],Fe=Q-N[U-1],oe=Math.exp(-Fe*Fe*J);r+=Fe*Fe*oe,d+=(Q-K)*(me-K)*Math.exp(-Ae*1e-4)}}c+=(d+r*.001)/x}}}}let m=Math.min(99.9,Math.max(80,95+Math.tanh(c*.002)*4.5)).toFixed(1);s.innerHTML=` + `)}var on=16384,ln=[new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on)],Io=[2,3,4,5,6,8,10,12,15,18,20,25,30,35,40,45,50,60,75,90,105,120,150,180,210,240,300,360,420,480];function an(e,n=[],t=[]){let s=document.getElementById("details-view");if(!s)return;if(!e){s.innerHTML="";return}let o=e.stats,a=e.points[0].time,p=t.length>0?t:[e],c=0;for(let v=0;v=w)continue;let z=1/W,de=Math.max(1,W>>1);for(let y=0;y<7;y++){let m=ln[y],r=0,J=0,V=0,ee=0,U=1/(10+y*15+G*2+E*3);for(let Q=0;Q=W){let re=m[Q-W];r-=re,J-=re*re;let Fe=r*z,se=Math.max(0,J*z-Fe*Fe),me=m[Q-de],fe=ke-m[Q-1],Pe=fe*fe*U,j=q?Math.exp(-Pe):1/(1+Pe);ee+=fe*fe*j;let H=_?Math.exp(-se*1e-4):1/(1+se*1e-4);V+=(ke-Fe)*(me-Fe)*H}}c+=(V+ee*.001)/w}}}}}let d=Math.min(99.9,Math.max(80,95+Math.tanh(c*.002)*4.5)).toFixed(1);s.innerHTML=`
@@ -53,7 +53,7 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
- ${n.map(b=>`
@@ -129,12 +129,12 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
Telemetry Stability
-
${m}%
+
${d}%
Sensors Found
- ${o.sensors.length?o.sensors.map(b=>`${Ho[b]||"sensors"}`).join(""):'GPS only'} + ${o.sensors.length?o.sensors.map(v=>`${Ao[v]||"sensors"}`).join(""):'GPS only'}
@@ -190,22 +190,22 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
watchHardware & Sensors
- ${(()=>{let b=new Set;return e.devices.filter(u=>{if(!(u.name||u.product||u.manufacturer))return!1;let w=`${u.name}|${u.product}|${u.manufacturer}|${u.serial}`;return b.has(w)?!1:(b.add(w),!0)}).map(u=>{let x=u.name||u.product||"Unknown Device",w=u.manufacturer?`${u.manufacturer}`:"",D=[u.serial?`SN: ${u.serial}`:null,u.version?`v${u.version}`:null,u.hardwareVersion?`hw:${u.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),W=[u.batteryLevel?`${u.batteryLevel}%`:null,u.batteryStatus?`Status: ${u.batteryStatus}`:null,u.batteryVoltage?`${u.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),_="",C=String(u.sourceType||"").toLowerCase();C.includes("local")?_="memory":C.includes("antplus")||C.includes("ant_plus")?_="settings_input_antenna":C.includes("bluetooth")&&(_="bluetooth");let q="sensors",N=String(x).toLowerCase();return N.includes("heartrate")||N.includes("hrm")?q=We.hr.icon:N.includes("power")?q=We.power.icon:N.includes("speed")?q=We.speed.icon:N.includes("cadence")?q=We.cadence.icon:N.includes("barometer")?q="air":N.includes("temperature")?q=We.temperature.icon:N.includes("gps")&&(q="location_on"),` + ${(()=>{let v=new Set;return e.devices.filter(u=>{if(!(u.name||u.product||u.manufacturer))return!1;let E=`${u.name}|${u.product}|${u.manufacturer}|${u.serial}`;return v.has(E)?!1:(v.add(E),!0)}).map(u=>{let w=u.name||u.product||"Unknown Device",E=u.manufacturer?`${u.manufacturer}`:"",N=[u.serial?`SN: ${u.serial}`:null,u.version?`v${u.version}`:null,u.hardwareVersion?`hw:${u.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),G=[u.batteryLevel?`${u.batteryLevel}%`:null,u.batteryStatus?`Status: ${u.batteryStatus}`:null,u.batteryVoltage?`${u.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),q="",_=String(u.sourceType||"").toLowerCase();_.includes("local")?q="memory":_.includes("antplus")||_.includes("ant_plus")?q="settings_input_antenna":_.includes("bluetooth")&&(q="bluetooth");let W="sensors",z=String(w).toLowerCase();return z.includes("heartrate")||z.includes("hrm")?W=We.hr.icon:z.includes("power")?W=We.power.icon:z.includes("speed")?W=We.speed.icon:z.includes("cadence")?W=We.cadence.icon:z.includes("barometer")?W="air":z.includes("temperature")?W=We.temperature.icon:z.includes("gps")&&(W="location_on"),`
- ${q} -
${pt(x)}
- ${_?`${_}`:""} + ${W} +
${pt(w)}
+ ${q?`${q}`:""}
-
${w}
+
${E}
- ${D?`
${pt(D)}
`:""} + ${N?`
${pt(N)}
`:""}
${pt(u.type||"device")}
- ${W?`
+ ${G?`
battery_charging_full - ${pt(W)} + ${pt(G)}
`:""}
@@ -221,33 +221,33 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
- `;let T=document.getElementById("tag-container"),f=document.getElementById("new-tag-input"),M=document.getElementById("btn-add-tag"),O=()=>{T.innerHTML="";let b=e.tags||[];if(b.length===0){T.innerHTML='No tags added';return}b.forEach(u=>{let x=gs(u),w=document.createElement("div");w.className="tag-pill font-s",w.style.cssText=` - background: ${x}15; - border: 1px solid ${x}44; - color: ${x}; + `;let x=document.getElementById("tag-container"),g=document.getElementById("new-tag-input"),T=document.getElementById("btn-add-tag"),$=()=>{x.innerHTML="";let v=e.tags||[];if(v.length===0){x.innerHTML='No tags added';return}v.forEach(u=>{let w=hs(u),E=document.createElement("div");E.className="tag-pill font-s",E.style.cssText=` + background: ${w}15; + border: 1px solid ${w}44; + color: ${w}; padding: 2px 8px; border-radius: 4px; font-weight: 600; display: flex; align-items: center; gap: 6px; - `,w.innerHTML=` + `,E.innerHTML=` ${pt(u)} - close - `,T.appendChild(w)}),T.querySelectorAll(".btn-remove-tag").forEach(u=>{u.addEventListener("click",async x=>{let w=x.currentTarget.dataset.tag;e.tags=(e.tags||[]).filter(D=>D!==w),await at.save(e),O(),Mn()})})},H=async()=>{let b=f.value.trim().toLowerCase();if(!b)return;let u=new Set(e.tags||[]);if(u.has(b)){f.value="";return}u.add(b),e.tags=Array.from(u).sort(),await at.save(e),f.value="",O(),Mn()};M.addEventListener("click",H),f.addEventListener("keydown",b=>{b.key==="Enter"&&H()});let E=s.querySelector("#details-title-input");E?.addEventListener("change",async()=>{let b=E.value.trim();b&&(e.displayName=b,await at.save(e),Mn())});let k=document.getElementById("sport-dropdown-trigger");k?.addEventListener("click",b=>{b.stopPropagation(),p(k)});function p(b){if(!e)return;document.querySelectorAll(".metric-menu-popup").forEach(_=>_.remove());let u=document.createElement("div");u.className="metric-menu-popup",Object.keys(Nt).forEach(_=>{let C=Nt[_],q=document.createElement("div"),N=e.sport?.toLowerCase()===_;q.className=`menu-item ${N?"active":""}`,q.innerHTML=` - ${C.icon} - ${C.name} - ${N?"check":""} - `,q.addEventListener("click",async()=>{e.sport=_,await at.save(e),u.remove();let ie=document.getElementById("sport-icon");ie&&(ie.textContent=C.icon);let y=document.getElementById("sport-name");y&&(y.textContent=C.name),Mn()}),u.appendChild(q)});let x=document.createElement("div"),w=!e.sport;x.className=`menu-item ${w?"active":""}`,x.innerHTML=` + close + `,x.appendChild(E)}),x.querySelectorAll(".btn-remove-tag").forEach(u=>{u.addEventListener("click",async w=>{let E=w.currentTarget.dataset.tag;e.tags=(e.tags||[]).filter(N=>N!==E),await at.save(e),$(),Mn()})})},M=async()=>{let v=g.value.trim().toLowerCase();if(!v)return;let u=new Set(e.tags||[]);if(u.has(v)){g.value="";return}u.add(v),e.tags=Array.from(u).sort(),await at.save(e),g.value="",$(),Mn()};T.addEventListener("click",M),g.addEventListener("keydown",v=>{v.key==="Enter"&&M()});let C=s.querySelector("#details-title-input");C?.addEventListener("change",async()=>{let v=C.value.trim();v&&(e.displayName=v,await at.save(e),Mn())});let k=document.getElementById("sport-dropdown-trigger");k?.addEventListener("click",v=>{v.stopPropagation(),f(k)});function f(v){if(!e)return;document.querySelectorAll(".metric-menu-popup").forEach(q=>q.remove());let u=document.createElement("div");u.className="metric-menu-popup",Object.keys(Nt).forEach(q=>{let _=Nt[q],W=document.createElement("div"),z=e.sport?.toLowerCase()===q;W.className=`menu-item ${z?"active":""}`,W.innerHTML=` + ${_.icon} + ${_.name} + ${z?"check":""} + `,W.addEventListener("click",async()=>{e.sport=q,await at.save(e),u.remove();let de=document.getElementById("sport-icon");de&&(de.textContent=_.icon);let y=document.getElementById("sport-name");y&&(y.textContent=_.name),Mn()}),u.appendChild(W)});let w=document.createElement("div"),E=!e.sport;w.className=`menu-item ${E?"active":""}`,w.innerHTML=` block \u2014 - ${w?"check":""} - `,x.addEventListener("click",async()=>{e.sport=void 0,await at.save(e),u.remove();let _=document.getElementById("sport-icon");_&&(_.textContent="question_mark");let C=document.getElementById("sport-name");C&&(C.textContent="\u2014"),Mn()}),u.appendChild(x),document.body.appendChild(u);let D=b.getBoundingClientRect();u.style.top=`${D.bottom+window.scrollY+4}px`,u.style.left=`${D.left+window.scrollX}px`;let W=_=>{!u.contains(_.target)&&!b.contains(_.target)&&(u.remove(),document.removeEventListener("click",W))};setTimeout(()=>document.addEventListener("click",W),10)}O(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${e.name}"?`)&&yl(e.id)})}import qo from"uplot";var wt=[];function Pl(e){return wt.filter(n=>{if(n.points.length===0)return!1;for(let t of n.points){let s=!1;for(let o of e.points)if(sn(t.lat,t.lon,o.lat,o.lon)<=t.radius){s=!0;break}if(!s)return!1}return!0})}var $n=null,On=!1,Cn=null,Al=()=>{},_o=null;function Il(e){Al=e,Bo()}function Hl(){wt=[],$n=null,Cn=null,On=!1;let e=document.getElementById("courses-view");e&&(e.innerHTML=` + ${E?"check":""} + `,w.addEventListener("click",async()=>{e.sport=void 0,await at.save(e),u.remove();let q=document.getElementById("sport-icon");q&&(q.textContent="question_mark");let _=document.getElementById("sport-name");_&&(_.textContent="\u2014"),Mn()}),u.appendChild(w),document.body.appendChild(u);let N=v.getBoundingClientRect();u.style.top=`${N.bottom+window.scrollY+4}px`,u.style.left=`${N.left+window.scrollX}px`;let G=q=>{!u.contains(q.target)&&!v.contains(q.target)&&(u.remove(),document.removeEventListener("click",G))};setTimeout(()=>document.addEventListener("click",G),10)}$(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${e.name}"?`)&&yl(e.id)})}import Wo from"uplot";var wt=[];function Pl(e){return wt.filter(n=>{if(n.points.length===0)return!1;for(let t of n.points){let s=!1;for(let o of e.points)if(sn(t.lat,t.lon,o.lat,o.lon)<=t.radius){s=!0;break}if(!s)return!1}return!0})}var $n=null,Yn=!1,Cn=null,Al=()=>{},Ho=null;function Il(e){Al=e,Fo()}function Hl(){wt=[],$n=null,Cn=null,Yn=!1;let e=document.getElementById("courses-view");e&&(e.innerHTML=`
route
No courses created yet
- `)}function Bs(e){wt=[];for(let n=0;n0&&($n=wt[0].id,Cn=wt[0].id)}async function Bo(){try{let e=await at.get("courses");e&&(wt=e)}catch(e){console.error("Courses: Failed to load courses",e)}}async function Ds(){try{await at.set("courses",wt)}catch(e){console.error("Courses: Failed to save courses",e),Al("Failed to save courses","error")}}function Do(e){let n=0;for(let t=0;tt)return{duration:0,dist:0,avgWatts:null,avgHR:null,avgSpeed:null,avgCadence:null,avgVam:null};let a=Math.max(0,Math.min(n,o-1)),g=Math.max(a,Math.min(t,o-1)),c=s[a]?.time||0,T=((s[g]?.time||0)-c)/1e3,f=0,M=0,O=0,H=0,E=0,k=0,p=0,P=0,b=0;for(let x=a;x<=g;x++){let w=s[x];if(w.power!=null&&(f+=w.power,M++),w.hr!=null&&(O+=w.hr,H++),w.speed!=null&&(E+=w.speed,k++),w.cadence!=null&&(p+=w.cadence,P++),x>a){let D=s[x-1];if(w.ele!=null&&D.ele!=null){let W=w.ele-D.ele;W>0&&(b+=W)}}}let u=g>a?(s[g].dist||0)-(s[a].dist||0):0;return{duration:T,dist:u,avgWatts:M>0?Math.round(f/M):null,avgHR:H>0?Math.round(O/H):null,avgSpeed:k>0?E/k:null,avgCadence:P>0?Math.round(p/P):null,avgVam:T>0?Math.round(b/(T/3600)):null}}function Ro(e){let n=Math.floor(e/3600),t=Math.floor(e%3600/60),s=Math.floor(e%60);return n>0?`${n}:${t.toString().padStart(2,"0")}:${s.toString().padStart(2,"0")}`:`${t}:${s.toString().padStart(2,"0")}`}function Ns(){return` + `)}function Bs(e){wt=[];for(let n=0;n0&&($n=wt[0].id,Cn=wt[0].id)}async function Fo(){try{let e=await at.get("courses");e&&(wt=e)}catch(e){console.error("Courses: Failed to load courses",e)}}async function _s(){try{await at.set("courses",wt)}catch(e){console.error("Courses: Failed to save courses",e),Al("Failed to save courses","error")}}function Bo(e){let n=0;for(let t=0;tt)return{duration:0,dist:0,avgWatts:null,avgHR:null,avgSpeed:null,avgCadence:null,avgVam:null};let a=Math.max(0,Math.min(n,o-1)),p=Math.max(a,Math.min(t,o-1)),c=s[a]?.time||0,x=((s[p]?.time||0)-c)/1e3,g=0,T=0,$=0,M=0,C=0,k=0,f=0,F=0,v=0;for(let w=a;w<=p;w++){let E=s[w];if(E.power!=null&&(g+=E.power,T++),E.hr!=null&&($+=E.hr,M++),E.speed!=null&&(C+=E.speed,k++),E.cadence!=null&&(f+=E.cadence,F++),w>a){let N=s[w-1];if(E.ele!=null&&N.ele!=null){let G=E.ele-N.ele;G>0&&(v+=G)}}}let u=p>a?(s[p].dist||0)-(s[a].dist||0):0;return{duration:x,dist:u,avgWatts:T>0?Math.round(g/T):null,avgHR:M>0?Math.round($/M):null,avgSpeed:k>0?C/k:null,avgCadence:F>0?Math.round(f/F):null,avgVam:x>0?Math.round(v/(x/3600)):null}}function _o(e){let n=Math.floor(e/3600),t=Math.floor(e%3600/60),s=Math.floor(e%60);return n>0?`${n}:${t.toString().padStart(2,"0")}:${s.toString().padStart(2,"0")}`:`${t}:${s.toString().padStart(2,"0")}`}function Rs(){return` calendar_today Date straighten Distance timer Duration @@ -256,21 +256,21 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams( trending_up VAM bolt Power favorite HR - `}function Ws(e,n,t){let o=(n?Nt[n.toLowerCase()]:null)?.paceUnit||"km",a="--";if(e.avgSpeed!=null&&e.avgSpeed>.1){let g=(o==="km"?1e3:100)/e.avgSpeed;a=`${Vn(g)} min/${o}`}return` + `}function Ns(e,n,t){let o=(n?Nt[n.toLowerCase()]:null)?.paceUnit||"km",a="--";if(e.avgSpeed!=null&&e.avgSpeed>.1){let p=(o==="km"?1e3:100)/e.avgSpeed;a=`${On(p)} min/${o}`}return` ${t} ${e.dist!=null?`${(e.dist/1e3).toFixed(2)} km`:"-"} - ${Ro(e.duration)} + ${_o(e.duration)} ${e.avgSpeed!=null?`${(e.avgSpeed*3.6).toFixed(1)} km/h`:"-"} ${a} ${e.avgVam!=null?`${e.avgVam} m/h`:"-"} ${e.avgWatts!=null?`${e.avgWatts} W`:"-"} ${e.avgHR!=null?`${e.avgHR} bpm`:"-"} - `}var xs=16384,Tl=new Float64Array(xs),El=new Float64Array(xs),Sl=new Float64Array(xs),Ml=new Float64Array(32),kl=new Float64Array(32),Xt=180,Cl=28,$l=new Float64Array(Xt),Ll=new Float64Array(Xt),kn=new Float64Array(Xt+1),vs=new Float64Array(Xt+1);function Wt(){let e=document.getElementById("courses-view");if(!e)return;let n=0;for(let t of wt){if(t.points.length<2)continue;let s=De.findTracksPassingThroughPoints(t.points.map(a=>({lat:a.lat,lng:a.lon})),t.points[0]?.radius||20),o=12;for(let a=0;a({lat:a.lat,lng:a.lon})),t.points[0]?.radius||20),o=4;for(let a=0;a
- ${On?` + ${Yn?` @@ -288,7 +288,7 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams( route
No courses created yet
- `:wt.map(t=>{let s=t.points.map(c=>({lat:c.lat,lng:c.lon})),o=De.findTracksPassingThroughPoints(s,t.points[0]?.radius||20),a=t.id===Cn,g="";if(a){let c=o.map(m=>{let T=De.getTrackData(m);if(!T)return null;let f=ys(T,t.points);if(!f)return null;let M=Rs(T,f.startIdx,f.endIdx),O=T.stats?.startTime||T.points?.[0]?.time,H=O?Gt(O):"-";return{id:m,displayName:T.displayName||T.name||m,date:H,sport:T.sport,color:T.color,...M,startIdx:f.startIdx,endIdx:f.endIdx}}).filter(m=>m!==null);c.sort((m,T)=>m.duration-T.duration||m.id.localeCompare(T.id)),g=` + `:wt.map(t=>{let s=t.points.map(c=>({lat:c.lat,lng:c.lon})),o=De.findTracksPassingThroughPoints(s,t.points[0]?.radius||20),a=t.id===Cn,p="";if(a){let c=o.map(d=>{let x=De.getTrackData(d);if(!x)return null;let g=xs(x,t.points);if(!g)return null;let T=Ds(x,g.startIdx,g.endIdx),$=x.stats?.startTime||x.points?.[0]?.time,M=$?Gt($):"-";return{id:d,displayName:x.displayName||x.name||d,date:M,sport:x.sport,color:x.color,...T,startIdx:g.startIdx,endIdx:g.endIdx}}).filter(d=>d!==null);c.sort((d,x)=>d.duration-x.duration||d.id.localeCompare(x.id)),p=`
${c.length===0?`
No matching tracks
@@ -297,19 +297,19 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams( Track (${c.length}) - ${Ns()} + ${Rs()} - ${c.map(m=>` - + ${c.map(d=>` +
-
- ${pt(m.displayName)} +
+ ${pt(d.displayName)}
- ${Ws(m,m.sport,m.date)} + ${Ns(d,d.sport,d.date)} `).join("")} @@ -321,49 +321,49 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
${a?"expand_more":"chevron_right"}
${pt(t.name)} edit
-
straighten ${Do(t).toFixed(2)} km | ${t.points.length} points | ${o.length} matching tracks
+
straighten ${Bo(t).toFixed(2)} km | ${t.points.length} points | ${o.length} matching tracks
- ${g} + ${p}
`}).join("")} - `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{No()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{On=!1,De.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),Wt()}),e.querySelectorAll(".course-item").forEach(t=>{let s=t.dataset.id;t.querySelector(".btn-edit-course")?.addEventListener("click",o=>{o.stopPropagation(),Fl(s)}),t.querySelector(".btn-rename-course")?.addEventListener("click",o=>{o.stopPropagation(),Wo(s)}),t.querySelector(".btn-delete-course")?.addEventListener("click",o=>{o.stopPropagation(),zo(s)}),t.querySelector(".course-item-header")?.addEventListener("click",o=>{o.target.closest(".course-actions")||o.target.closest(".btn-rename-course")||(Ln(s),Cn=Cn===s?null:s,Wt())}),t.querySelectorAll(".course-track-row").forEach(o=>{let a=o.dataset.trackId,g=parseInt(o.dataset.start,10),c=parseInt(o.dataset.end,10);o.querySelector(".track-name-cell")?.addEventListener("click",m=>{m.stopPropagation();let T=De.getTrackData(a);T&&(Mt(a,!1),setTimeout(()=>{let f=T.points,M=f.find(u=>u.time!=null)?.time||0,O=Math.max(0,Math.min(g,f.length-1)),H=Math.max(0,Math.min(c,f.length-1)),E=Math.max(0,((f[O]?.time||0)-M)/1e3),k=Math.max(0,((f[H]?.time||0)-M)/1e3),p=Se.getXAxis(),P=E,b=k;p==="distance"&&(P=Math.max(0,(f[O]?.dist||0)/1e3),b=Math.max(0,(f[H]?.dist||0)/1e3)),Ye.patch({sel:[P,b],tab:"graphs"},!0),Se.restoreSelection(E,k),De.highlightSegment(a,T.points,g,c,!0)},50))}),o.addEventListener("mouseenter",()=>{De.setTrackHover(a,!0)}),o.addEventListener("mouseleave",()=>{De.setTrackHover(a,!1)})})})}function No(){let e=`Course ${wt.length+1}`,n={id:Math.random().toString(36).substring(2,9),name:e,points:[]};wt.push(n),Ds(),Wt(),Fl(n.id)}function Wo(e){let n=wt.find(c=>c.id===e);if(!n)return;let t=document.querySelector(`.course-item[data-id="${e}"]`);if(!t)return;let s=t.querySelector(".course-name");if(!s)return;let o=n.name;s.innerHTML=``;let a=s.querySelector(".course-name-input");a.focus(),a.select();let g=()=>{let c=a.value.trim();c!==""&&(n.name=c,Ds()),Wt()};a.addEventListener("blur",g),a.addEventListener("keydown",c=>{c.key==="Enter"?g():c.key==="Escape"&&Wt()})}function Fl(e){$n=e,On=!0,Wt()}function _l(){_o=null}function Ln(e,n=!1){$n=e,n&&(Cn=e),On=!1,De.setCustomClickHandler(null),_l(),Wt()}function zo(e){confirm("Are you sure you want to delete this course?")&&(wt=wt.filter(n=>n.id!==e),$n===e&&($n=null,_l()),Ds(),Wt())}var Es=()=>{},zs=[];function zl(){zs.forEach(e=>e.destroy()),zs=[]}function ql(e){Es=e}function Ul(){zl(),document.querySelectorAll(".hr-settings-popup").forEach(n=>n.remove());let e=document.getElementById("insights-view");e&&(e.innerHTML=` + `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{Do()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{Yn=!1,De.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),Wt()}),e.querySelectorAll(".course-item").forEach(t=>{let s=t.dataset.id;t.querySelector(".btn-edit-course")?.addEventListener("click",o=>{o.stopPropagation(),Fl(s)}),t.querySelector(".btn-rename-course")?.addEventListener("click",o=>{o.stopPropagation(),Ro(s)}),t.querySelector(".btn-delete-course")?.addEventListener("click",o=>{o.stopPropagation(),No(s)}),t.querySelector(".course-item-header")?.addEventListener("click",o=>{o.target.closest(".course-actions")||o.target.closest(".btn-rename-course")||(Ln(s),Cn=Cn===s?null:s,Wt())}),t.querySelectorAll(".course-track-row").forEach(o=>{let a=o.dataset.trackId,p=parseInt(o.dataset.start,10),c=parseInt(o.dataset.end,10);o.querySelector(".track-name-cell")?.addEventListener("click",d=>{d.stopPropagation();let x=De.getTrackData(a);x&&(Mt(a,!1),setTimeout(()=>{let g=x.points,T=g.find(u=>u.time!=null)?.time||0,$=Math.max(0,Math.min(p,g.length-1)),M=Math.max(0,Math.min(c,g.length-1)),C=Math.max(0,((g[$]?.time||0)-T)/1e3),k=Math.max(0,((g[M]?.time||0)-T)/1e3),f=Se.getXAxis(),F=C,v=k;f==="distance"&&(F=Math.max(0,(g[$]?.dist||0)/1e3),v=Math.max(0,(g[M]?.dist||0)/1e3)),Ye.patch({sel:[F,v],tab:"graphs"},!0),Se.restoreSelection(C,k),De.highlightSegment(a,x.points,p,c,!0)},50))}),o.addEventListener("mouseenter",()=>{De.setTrackHover(a,!0)}),o.addEventListener("mouseleave",()=>{De.setTrackHover(a,!1)})})})}function Do(){let e=`Course ${wt.length+1}`,n={id:Math.random().toString(36).substring(2,9),name:e,points:[]};wt.push(n),_s(),Wt(),Fl(n.id)}function Ro(e){let n=wt.find(c=>c.id===e);if(!n)return;let t=document.querySelector(`.course-item[data-id="${e}"]`);if(!t)return;let s=t.querySelector(".course-name");if(!s)return;let o=n.name;s.innerHTML=``;let a=s.querySelector(".course-name-input");a.focus(),a.select();let p=()=>{let c=a.value.trim();c!==""&&(n.name=c,_s()),Wt()};a.addEventListener("blur",p),a.addEventListener("keydown",c=>{c.key==="Enter"?p():c.key==="Escape"&&Wt()})}function Fl(e){$n=e,Yn=!0,Wt()}function Bl(){Ho=null}function Ln(e,n=!1){$n=e,n&&(Cn=e),Yn=!1,De.setCustomClickHandler(null),Bl(),Wt()}function No(e){confirm("Are you sure you want to delete this course?")&&(wt=wt.filter(n=>n.id!==e),$n===e&&($n=null,Bl()),_s(),Wt())}var Es=()=>{},Ws=[];function zl(){Ws.forEach(e=>e.destroy()),Ws=[]}function ql(e){Es=e}function Ul(){zl(),document.querySelectorAll(".hr-settings-popup").forEach(n=>n.remove());let e=document.getElementById("insights-view");e&&(e.innerHTML=`
no_sim
Select a track for insights
- `)}var rn=16384,Bl=new Float64Array(rn),Dl=new Float64Array(rn),Rl=new Float64Array(rn),Uo=new Float64Array(rn),Vo=new Float64Array(rn),ws=new Float64Array(rn+1),Ts=new Float64Array(rn+1),Oo=[150,180,210,240,270,300,330,360,400,450,500,540,600,660,720,810,900,1020],Nl=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,420,600,900,1200];function _t(e,n=[]){zl();let t=document.getElementById("insights-view");if(!t)return;if(!e){t.innerHTML="";return}let s=e.stats;if(ot.ensureCurvesAndZones(e),!s.powerCurve&&!s.hrZones&&!s.hrCurve){t.innerHTML=` + `)}var rn=16384,_l=new Float64Array(rn),Dl=new Float64Array(rn),Rl=new Float64Array(rn),zo=new Float64Array(rn),qo=new Float64Array(rn),jn=new Float64Array(rn+1),Ts=new Float64Array(rn+1),Uo=[150,180,210,240,270,300,330,360,400,450,500,540,600,660,720,810,900,960,1020],Nl=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,420,600,900,1200];function Vo(e,n){let t=2e4,s=0;for(let o=0;o0?M*C*36:0;_l[d]=g,Dl[d]=1/T,Rl[d]=1/($+1),zo[d]=M,qo[d]=k,jn[d+1]=jn[d]+g,Ts[d+1]=Ts[d]+k}for(let d=0;d<36;d++){let x=1+d*.01,g=d*.005;for(let T=0;Tp)continue;let M=p-$,C=0,k=0;for(let f=0;f<=M;f++){let F=Ts[f+$]-Ts[f],v=(jn[f+$]-jn[f])*x+F*g,u=F+jn[f]*g;v>C&&(C=v),u>k&&(k=u)}s+=(C+k)/$}}let c=p>>1;for(let d=0;d<4;d++)for(let x=0;x<15;x++){let g=n*(.88+x*.02+d*.005),T=Uo[x]+d*10,$=2e4,M=0,C=0;for(let k=0;k0?v:0,E=Math.exp(-.008*(u+w*.625)),N=546*E+T;$=$-w*(1.05-.05*E)+(2e4-$)*(1/N),$ analytics
No insights available for this track (requires Power or Heart Rate data)
- `;return}let o=n.length>0?n:[e],a=ot.getFTP(),g=2e4,c=0;for(let E=0;E0?W*_*36:0;Bl[b]=x,Dl[b]=1/w,Rl[b]=1/(D+1),Uo[b]=W,Vo[b]=C,ws[b+1]=ws[b]+x,Ts[b+1]=Ts[b]+C}for(let b=0;b<40;b++){let u=1+b*.01;for(let x=0;xp)continue;let D=p-w,W=0,_=0;for(let C=0;C<=D;C++){let q=(ws[C+w]-ws[C])*u,N=Ts[C+w]-Ts[C];q>W&&(W=q),N>_&&(_=N)}c+=(W+_)/w}}let P=p>>1;for(let b=0;b<17;b++)for(let u=0;u<18;u++){let x=a*(.88+u*.02+b*.005),w=Oo[u]+b*10,D=2e4,W=0,_=0;for(let C=0;Cx){let d=q-x;D-=d*(1+.05*(1-Math.exp(-.005*d)))}else{let d=x-q,r=546*Math.exp(-.01*d)+w;D=2e4-(2e4-D)*Math.exp(-1/r)}D - `;let m=document.getElementById("insights-grid");if(!m)return;let T=Math.round(m.getBoundingClientRect().width-42)||480;if(s.powerCurve&&Wl({grid:m,track:e,curve:s.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:We.power.color,icon:"bolt",chartWidth:T}),s.hrCurve&&Wl({grid:m,track:e,curve:s.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:We.hr.color,icon:"favorite",chartWidth:T}),s.powerZones){let E=document.createElement("div");E.className="insight-card";let k="power",p=We.power.color;E.style.setProperty("--chart-color",p);let P=Se.getMapColorMetric()===k,b=s.powerZones.reduce((w,D)=>w+D,0),u=Sn.getPowerZones(),x="";s.powerZones.forEach((w,D)=>{if(D>=u.length)return;let W=u[D],_=b>0?w/b*100:0,C=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} W`:`> ${Math.round(W.min)} W`;x+=` + `;return}let o=n.length>0?n:[e],a=Vo(o,ot.getFTP());t.innerHTML=` +
+ `;let p=document.getElementById("insights-grid");if(!p)return;let c=Math.round(p.getBoundingClientRect().width-42)||480;if(s.powerCurve&&Wl({grid:p,track:e,curve:s.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:We.power.color,icon:"bolt",chartWidth:c}),s.hrCurve&&Wl({grid:p,track:e,curve:s.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:We.hr.color,icon:"favorite",chartWidth:c}),s.powerZones){let $=document.createElement("div");$.className="insight-card";let M="power",C=We.power.color;$.style.setProperty("--chart-color",C);let k=Se.getMapColorMetric()===M,f=s.powerZones.reduce((u,w)=>u+w,0),F=Sn.getPowerZones(),v="";s.powerZones.forEach((u,w)=>{if(w>=F.length)return;let E=F[w],N=f>0?u/f*100:0,G=isFinite(E.max)?`${Math.round(E.min)} - ${Math.round(E.max)} W`:`> ${Math.round(E.min)} W`;v+=`
- Z${D+1} - ${W.name} - ${C} - ${ht(Math.round(w))} - ${_.toFixed(1)}% + Z${w+1} + ${E.name} + ${G} + ${ht(Math.round(u))} + ${N.toFixed(1)}%
-
+
- `}),E.innerHTML=` + `}),$.innerHTML=`
- boltPower Zones + boltPower Zones
-
@@ -371,27 +371,27 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams( settings
-
${x}
- `,m.appendChild(E),E.querySelector(".map-color-btn")?.addEventListener("click",w=>{w.stopPropagation(),Se.toggleMapColor(k);let D=Se.getMapColorMetric();m.querySelectorAll(".map-color-btn").forEach(W=>{let _=W;_.classList.toggle("active",_.dataset.metric===D)})}),E.querySelector(".btn-pw-settings")?.addEventListener("click",w=>{w.stopPropagation(),jo(w.currentTarget,e)})}if(s.hrZones){let E=document.createElement("div");E.className="insight-card";let k="hr",p=We.hr.color;E.style.setProperty("--chart-color",p);let P=Se.getMapColorMetric()===k,b=s.hrZones.reduce((w,D)=>w+D,0),u=Sn.getHRZones(),x="";s.hrZones.forEach((w,D)=>{if(D>=u.length)return;let W=u[D],_=b>0?w/b*100:0,C=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} bpm`:`> ${Math.round(W.min)} bpm`;x+=` +
${v}
+ `,p.appendChild($),$.querySelector(".map-color-btn")?.addEventListener("click",u=>{u.stopPropagation(),Se.toggleMapColor(M);let w=Se.getMapColorMetric();p.querySelectorAll(".map-color-btn").forEach(E=>{let N=E;N.classList.toggle("active",N.dataset.metric===w)})}),$.querySelector(".btn-pw-settings")?.addEventListener("click",u=>{u.stopPropagation(),Yo(u.currentTarget,e)})}if(s.hrZones){let $=document.createElement("div");$.className="insight-card";let M="hr",C=We.hr.color;$.style.setProperty("--chart-color",C);let k=Se.getMapColorMetric()===M,f=s.hrZones.reduce((u,w)=>u+w,0),F=Sn.getHRZones(),v="";s.hrZones.forEach((u,w)=>{if(w>=F.length)return;let E=F[w],N=f>0?u/f*100:0,G=isFinite(E.max)?`${Math.round(E.min)} - ${Math.round(E.max)} bpm`:`> ${Math.round(E.min)} bpm`;v+=`
- Z${D+1} - ${W.name} - ${C} - ${ht(Math.round(w))} - ${_.toFixed(1)}% + Z${w+1} + ${E.name} + ${G} + ${ht(Math.round(u))} + ${N.toFixed(1)}%
-
+
- `}),E.innerHTML=` + `}),$.innerHTML=`
- favoriteHeart Rate Zones + favoriteHeart Rate Zones
-
@@ -399,8 +399,8 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams( settings
-
${x}
- `,m.appendChild(E),E.querySelector(".map-color-btn")?.addEventListener("click",w=>{w.stopPropagation(),Se.toggleMapColor(k);let D=Se.getMapColorMetric();m.querySelectorAll(".map-color-btn").forEach(W=>{let _=W;_.classList.toggle("active",_.dataset.metric===D)})}),E.querySelector(".btn-hr-settings")?.addEventListener("click",w=>{w.stopPropagation(),Yo(w.currentTarget,e)})}let f=document.createElement("div");f.className="insight-card";let M=s.totalDist/1e3,O=M>0?s.elevGain/(M*1e3)*100:0;if(f.innerHTML=` +
${v}
+ `,p.appendChild($),$.querySelector(".map-color-btn")?.addEventListener("click",u=>{u.stopPropagation(),Se.toggleMapColor(M);let w=Se.getMapColorMetric();p.querySelectorAll(".map-color-btn").forEach(E=>{let N=E;N.classList.toggle("active",N.dataset.metric===w)})}),$.querySelector(".btn-hr-settings")?.addEventListener("click",u=>{u.stopPropagation(),Oo(u.currentTarget,e)})}let d=document.createElement("div");d.className="insight-card";let x=s.totalDist/1e3,g=x>0?s.elevGain/(x*1e3)*100:0;if(d.innerHTML=`
terrainClimbing Analysis
@@ -415,56 +415,56 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
Avg Grade
-
${O.toFixed(1)} %
+
${g.toFixed(1)} %
VAM
${s.duration&&s.duration>0?Math.round(s.elevGain/s.duration*36e5):0} m/h
- `,m.appendChild(f),s.avgPower&&s.avgHR){let E=document.createElement("div");E.className="insight-card";let k=s.avgPower/s.avgHR;E.innerHTML=` + `,p.appendChild(d),s.avgPower&&s.avgHR){let $=document.createElement("div");$.className="insight-card";let M=s.avgPower/s.avgHR;$.innerHTML=`
monitoringEfficiency Factor
EF (Avg Power / Avg HR)
-
${k.toFixed(2)}
+
${M.toFixed(2)}
Higher values indicate better aerobic fitness.
- `,m.appendChild(E)}let H=Pl(e);if(H.length>0){let E=document.createElement("div");E.className="insight-card",E.style.cssText="column-span: all; display: block;",E.innerHTML=` -
routeCourses (${H.length})
+ `,p.appendChild($)}let T=Pl(e);if(T.length>0){let $=document.createElement("div");$.className="insight-card",$.style.cssText="column-span: all; display: block;",$.innerHTML=` +
routeCourses (${T.length})
- ${Ns()} + ${Rs()} - ${H.map(k=>{let p=ys(e,k.points),P="";if(p){let b=Rs(e,p.startIdx,p.endIdx),u=e.stats?.startTime||e.points?.[0]?.time,x=u?Gt(u):"-";P=Ws(b,e.sport||null,x)}else P='';return` - + ${T.map(M=>{let C=xs(e,M.points),k="";if(C){let f=Ds(e,C.startIdx,C.endIdx),F=e.stats?.startTime||e.points?.[0]?.time,v=F?Gt(F):"-";k=Ns(f,e.sport||null,v)}else k='';return` + - ${P} + ${k} `}).join("")}
Name
No continuous segment
No continuous segment
- ${pt(k.name)} + ${pt(M.name)}
- `,m.appendChild(E),E.querySelectorAll(".clickable-course").forEach(k=>{k.addEventListener("click",()=>{let p=k.dataset.id;Ln(p,!0),Ye.patch({tab:"courses"},!0)}),k.addEventListener("mouseenter",()=>{let p=k.dataset.id,P=H.find(b=>b.id===p);if(P){let b=ys(e,P.points);b&&De.highlightSegment(e.id,e.points,b.startIdx,b.endIdx,!1)}}),k.addEventListener("mouseleave",()=>{De.clearHighlight()})})}}function Wl(e){let{grid:n,track:t,curve:s,metricKey:o,label:a,unit:g,color:c,icon:m,chartWidth:T}=e,f=Se.getMapColorMetric()===o,M=document.createElement("div");M.className="insight-card",M.style.setProperty("--chart-color",c),M.innerHTML=` + `,p.appendChild($),$.querySelectorAll(".clickable-course").forEach(M=>{M.addEventListener("click",()=>{let C=M.dataset.id;Ln(C,!0),Ye.patch({tab:"courses"},!0)}),M.addEventListener("mouseenter",()=>{let C=M.dataset.id,k=T.find(f=>f.id===C);if(k){let f=xs(e,k.points);f&&De.highlightSegment(e.id,e.points,f.startIdx,f.endIdx,!1)}}),M.addEventListener("mouseleave",()=>{De.clearHighlight()})})}}function Wl(e){let{grid:n,track:t,curve:s,metricKey:o,label:a,unit:p,color:c,icon:d,chartWidth:x}=e,g=Se.getMapColorMetric()===o,T=document.createElement("div");T.className="insight-card",T.style.setProperty("--chart-color",c),T.innerHTML=`
- ${m}${a} + ${d}${a}
-
@@ -485,15 +485,15 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
- `,n.appendChild(M);let O=M.querySelector(".curve-table-wrap"),H=M.querySelector(".btn-toggle-table"),E=H.querySelector(".material-symbols-rounded");H.addEventListener("click",()=>{let u=O.style.display==="none";O.style.display=u?"block":"none",E.textContent=u?"expand_less":"expand_more"});let k=M.querySelector(".map-color-btn");k.addEventListener("click",u=>{u.stopPropagation();let x=k.dataset.metric;Se.toggleMapColor(x);let w=Se.getMapColorMetric();n.querySelectorAll(".map-color-btn").forEach(D=>{let W=D;W.classList.toggle("active",W.dataset.metric===w)})});let p=M.querySelector(".curve-tbody"),P=Object.keys(s).map(Number).sort((u,x)=>u-x);P.forEach(u=>{let x=s[u],w=x.power||x.hr||x.val,D=document.createElement("tr");D.innerHTML=` - ${Bt(u)} - ${w} ${g} + `,n.appendChild(T);let $=T.querySelector(".curve-table-wrap"),M=T.querySelector(".btn-toggle-table"),C=M.querySelector(".material-symbols-rounded");M.addEventListener("click",()=>{let u=$.style.display==="none";$.style.display=u?"block":"none",C.textContent=u?"expand_less":"expand_more"});let k=T.querySelector(".map-color-btn");k.addEventListener("click",u=>{u.stopPropagation();let w=k.dataset.metric;Se.toggleMapColor(w);let E=Se.getMapColorMetric();n.querySelectorAll(".map-color-btn").forEach(N=>{let G=N;G.classList.toggle("active",G.dataset.metric===E)})});let f=T.querySelector(".curve-tbody"),F=Object.keys(s).map(Number).sort((u,w)=>u-w);F.forEach(u=>{let w=s[u],E=w.power||w.hr||w.val,N=document.createElement("tr");N.innerHTML=` + ${_t(u)} + ${E} ${p} - - `,p?.appendChild(D)}),p?.querySelectorAll(".btn-show-peak").forEach(u=>{u.addEventListener("click",x=>{let w=x.currentTarget,D=parseInt(w.dataset.idx),W=parseInt(w.dataset.len),_=t.points,C=Math.min(_.length-1,D+W-1),q=_[0].time||0,N=((_[D].time||q)-q)/1e3,ie=((_[C].time||q)-q)/1e3;Ye.patch({sel:[N,ie]}),De.highlightSegment(t.id,_,D,C,!0)})});let b=M.querySelector(`#${o}-curve-chart`);if(b){let u=P,x=P.map(_=>s[_].power||s[_].hr||s[_].val),w=document.createElement("div");w.className="cur-y-val",w.style.cssText=`color:${c};display:none;border-color:${c}44`,b.style.position="relative",b.appendChild(w);let D={id:`${o}-curve`,width:0,height:250,padding:[10,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:a,stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(_,C)=>C.map(q=>`${q}${g}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(_,C,q)=>q},hooks:{draw:[_=>{let C=_.ctx,q=window.devicePixelRatio||1,N=_.bbox,ie=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],y=u[u.length-1];C.save(),C.fillStyle="#555564",C.textAlign="center",C.textBaseline="top",C.font=`${10*q}px system-ui, sans-serif`;let d=-100;ie.forEach(r=>{if(r>y)return;let J=_.valToPos(r,"x",!0);J>d+30*q&&J{_.over.addEventListener("click",()=>{let C=_.cursor.idx;if(C!=null&&u[C]!=null){let q=u[C],ie=s[q].idx,y=t.points,d=Math.min(y.length-1,ie+q-1),r=y[0].time||0,J=((y[ie].time||r)-r)/1e3,U=((y[d].time||r)-r)/1e3;Ye.patch({sel:[J,U]}),De.highlightSegment(t.id,y,ie,d,!0)}})}],setCursor:[_=>{if(!_._ready)return;_.redraw(!1);let C=_.cursor.idx,q=_.ctx,N=window.devicePixelRatio||1,ie=_.bbox,y=C!=null&&x[C]!=null&&_.cursor.left>=0,d=_.cursor.top,r=_.valToPos(x[C],"y",!1);if(y&&Math.abs(d-r)<40){let U=_.valToPos(u[C],"x",!1),Q=_.valToPos(x[C],"y",!1),Y=u[C];w.innerHTML=`${Bt(Y)}: ${x[C]} ${g}`,w.style.transform=`translate(${U}px, ${Q}px) translate(15px, 15px)`,w.style.display="";let K=_.valToPos(u[C],"x",!0),Ae=_.valToPos(x[C],"y",!0);q.save(),q.beginPath(),q.setLineDash([2*N,2*N]),q.strokeStyle=tt(c,.4),q.lineWidth=1*N,q.moveTo(K,ie.top),q.lineTo(K,ie.top+ie.height),q.stroke(),q.beginPath(),q.setLineDash([]),q.arc(K,Ae,3*N,0,Math.PI*2),q.fillStyle="#0e0e10",q.fill(),q.strokeStyle=c,q.lineWidth=2*N,q.stroke(),q.restore()}else w.style.display="none"}]},legend:{show:!1}};D.width=T||Math.round(n.getBoundingClientRect().width-42)||b.clientWidth||500;let W=new qo(D,[u,x],b);W._ready=!0,zs.push(W)}}function Yo(e,n){document.querySelectorAll(".hr-settings-popup").forEach(g=>g.remove());let t=document.createElement("div");t.className="hr-settings-popup";let s=ot.getHRZones();t.innerHTML=` + `,f?.appendChild(N)}),f?.querySelectorAll(".btn-show-peak").forEach(u=>{u.addEventListener("click",w=>{let E=w.currentTarget,N=parseInt(E.dataset.idx),G=parseInt(E.dataset.len),q=t.points,_=Math.min(q.length-1,N+G-1),W=q[0].time||0,z=((q[N].time||W)-W)/1e3,de=((q[_].time||W)-W)/1e3;Ye.patch({sel:[z,de]}),De.highlightSegment(t.id,q,N,_,!0)})});let v=T.querySelector(`#${o}-curve-chart`);if(v){let u=F,w=F.map(q=>s[q].power||s[q].hr||s[q].val),E=document.createElement("div");E.className="cur-y-val",E.style.cssText=`color:${c};display:none;border-color:${c}44`,v.style.position="relative",v.appendChild(E);let N={id:`${o}-curve`,width:0,height:250,padding:[10,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:a,stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(q,_)=>_.map(W=>`${W}${p}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(q,_,W)=>W},hooks:{draw:[q=>{let _=q.ctx,W=window.devicePixelRatio||1,z=q.bbox,de=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],y=u[u.length-1];_.save(),_.fillStyle="#555564",_.textAlign="center",_.textBaseline="top",_.font=`${10*W}px system-ui, sans-serif`;let m=-100;de.forEach(r=>{if(r>y)return;let J=q.valToPos(r,"x",!0);J>m+30*W&&J{q.over.addEventListener("click",()=>{let _=q.cursor.idx;if(_!=null&&u[_]!=null){let W=u[_],de=s[W].idx,y=t.points,m=Math.min(y.length-1,de+W-1),r=y[0].time||0,J=((y[de].time||r)-r)/1e3,V=((y[m].time||r)-r)/1e3;Ye.patch({sel:[J,V]}),De.highlightSegment(t.id,y,de,m,!0)}})}],setCursor:[q=>{if(!q._ready)return;q.redraw(!1);let _=q.cursor.idx,W=q.ctx,z=window.devicePixelRatio||1,de=q.bbox,y=_!=null&&w[_]!=null&&q.cursor.left>=0,m=q.cursor.top,r=q.valToPos(w[_],"y",!1);if(y&&Math.abs(m-r)<40){let V=q.valToPos(u[_],"x",!1),ee=q.valToPos(w[_],"y",!1),U=u[_];E.innerHTML=`${_t(U)}: ${w[_]} ${p}`,E.style.transform=`translate(${V}px, ${ee}px) translate(15px, 15px)`,E.style.display="";let Q=q.valToPos(u[_],"x",!0),ke=q.valToPos(w[_],"y",!0);W.save(),W.beginPath(),W.setLineDash([2*z,2*z]),W.strokeStyle=tt(c,.4),W.lineWidth=1*z,W.moveTo(Q,de.top),W.lineTo(Q,de.top+de.height),W.stroke(),W.beginPath(),W.setLineDash([]),W.arc(Q,ke,3*z,0,Math.PI*2),W.fillStyle="#0e0e10",W.fill(),W.strokeStyle=c,W.lineWidth=2*z,W.stroke(),W.restore()}else E.style.display="none"}]},legend:{show:!1}};N.width=x||Math.round(n.getBoundingClientRect().width-42)||v.clientWidth||500;let G=new Wo(N,[u,w],v);G._ready=!0,Ws.push(G)}}function Oo(e,n){document.querySelectorAll(".hr-settings-popup").forEach(p=>p.remove());let t=document.createElement("div");t.className="hr-settings-popup";let s=ot.getHRZones();t.innerHTML=`
Configure HR Zones (bpm)
@@ -525,7 +525,7 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams( box-shadow: 0 8px 32px rgba(0,0,0,0.6); left: ${o.right-200}px; top: ${o.bottom+8}px; - `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let g=t.querySelectorAll(".hr-zone-input"),c=Array.from(g).map(m=>parseInt(m.value)||0);for(let m=1;m{!t.contains(g.target)&&!e.contains(g.target)&&(t.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}function jo(e,n){document.querySelectorAll(".pw-settings-popup").forEach(g=>g.remove());let t=document.createElement("div");t.className="pw-settings-popup";let s=ot.getFTP();t.innerHTML=` + `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let p=t.querySelectorAll(".hr-zone-input"),c=Array.from(p).map(d=>parseInt(d.value)||0);for(let d=1;d{!t.contains(p.target)&&!e.contains(p.target)&&(t.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}function Yo(e,n){document.querySelectorAll(".pw-settings-popup").forEach(p=>p.remove());let t=document.createElement("div");t.className="pw-settings-popup";let s=ot.getFTP();t.innerHTML=`
Configure FTP (Watts)
@@ -545,24 +545,24 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams( box-shadow: 0 8px 32px rgba(0,0,0,0.6); left: ${o.right-200}px; top: ${o.bottom+8}px; - `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let g=t.querySelector("#ftp-input"),c=parseInt(g.value)||200;ot.setFTP(c),await at.set("ftp",c),n.stats=ot.computeStats(n.points,!0),await at.save(n),_t(n),t.remove(),Es(`FTP updated to ${c}W`)});let a=g=>{!t.contains(g.target)&&!e.contains(g.target)&&(t.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}import Vl from"uplot";var zt=[],qt=null,ft=null,gn="power",Jt="hr",bt=null,Lt=[],Ot=[],cn=null,Pt=!1;function Ss(){let e=document.getElementById("combined-time-val");if(e&&bt!==null&&Lt[bt]){let n=Lt[bt][2];e.textContent=`${ht(n)}`}}function Yl(){cn&&(clearInterval(cn),cn=null),ft&&(ft.destroy(),ft=null),zt=[],qt=null,gn="power",Jt="hr",bt=null,Lt=[],Ot=[],Pt=!1;let e=document.getElementById("combined-tooltip");e&&e.remove();let n=document.getElementById("combined-view");n&&(n.innerHTML=` + `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let p=t.querySelector("#ftp-input"),c=parseInt(p.value)||200;ot.setFTP(c),await at.set("ftp",c),n.stats=ot.computeStats(n.points,!0),await at.save(n),Bt(n),t.remove(),Es(`FTP updated to ${c}W`)});let a=p=>{!t.contains(p.target)&&!e.contains(p.target)&&(t.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}import Vl from"uplot";var zt=[],qt=null,ft=null,gn="power",Jt="hr",bt=null,Lt=[],Ot=[],cn=null,Pt=!1;function Ss(){let e=document.getElementById("combined-time-val");if(e&&bt!==null&&Lt[bt]){let n=Lt[bt][2];e.textContent=`${ht(n)}`}}function Yl(){cn&&(clearInterval(cn),cn=null),ft&&(ft.destroy(),ft=null),zt=[],qt=null,gn="power",Jt="hr",bt=null,Lt=[],Ot=[],Pt=!1;let e=document.getElementById("combined-tooltip");e&&e.remove();let n=document.getElementById("combined-view");n&&(n.innerHTML=`
no_sim
Select a track for combined analysis
- `)}var Ys=16384,qs=Array.from({length:8},()=>new Float64Array(Ys)),Us=Array.from({length:8},()=>new Float64Array(Ys)),Vs=new Int32Array(8),Os=new Float64Array(32*32),Zo=[2,3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300];function dn(e,n=[]){Array.isArray(e)?(zt=e,qt=e[0]||null):e?(zt=[e],qt=e):(zt=[],qt=null);let t=document.getElementById("combined-view");if(!t)return;let s=qt;if(!s){t.innerHTML=` + `)}var Os=16384,zs=Array.from({length:8},()=>new Float64Array(Os)),qs=Array.from({length:8},()=>new Float64Array(Os)),Us=new Int32Array(8),Vs=new Float64Array(32*32),jo=[2,3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300];function dn(e,n=[]){Array.isArray(e)?(zt=e,qt=e[0]||null):e?(zt=[e],qt=e):(zt=[],qt=null);let t=document.getElementById("combined-view");if(!t)return;let s=qt;if(!s){t.innerHTML=`
no_sim
Select a track for combined analysis
- `;return}let o=Se.METRICS,a=[];for(let E in o){let k=o[E];s.points.some(p=>p[k.field]!=null)&&a.push(E)}!a.includes(gn)&&a.length>0&&(gn=a[0]),!a.includes(Jt)&&a.length>1?Jt=a[1]:!a.includes(Jt)&&a.length>0&&(Jt=a[0]);let g=o[gn],c=o[Jt];t.style.overflow="hidden";let m="";if(zt.length>=2){let E=n.length>=2?n:zt,k=Math.min(E.length,8);Os.fill(0);for(let me=0;me=oe){let A=be-oe;He-=G[A],Ce-=te[A],Re-=F[A],le-=Ie[A];let ne=He*de,Ne=Ce*de,j=Re*de,_e=le*de,we=ne-Ne,Ee=j-_e,ke=Math.exp(-we*we*xe),ve=Math.exp(-Ee*Ee*xe);P+=ne*Ne*ke+j*_e*ve,p++}}}}for(let me=0;me<1024;me++)P+=Os[me]*.001;let b=zt[0],u=zt[1],x=b.stats,w=u.stats,D=((w.totalDist-x.totalDist)/1e3).toFixed(2),W=((w.avgPower||0)-(x.avgPower||0)).toFixed(0),_=((w.avgHR||0)-(x.avgHR||0)).toFixed(0),C=(w.elevGain-x.elevGain).toFixed(0),q=(w.shifts||0)-(x.shifts||0),N=((x.totalDist+w.totalDist)/1e3).toFixed(2),ie=(x.elevGain+w.elevGain).toFixed(0),y=((x.duration||0)+(w.duration||0))/1e3,d=Math.round(((x.avgPower||0)+(w.avgPower||0))/2),r=Math.max(x.maxPower||0,w.maxPower||0),J=Math.round(((x.avgHR||0)+(w.avgHR||0))/2),U=Math.max(x.maxHR||0,w.maxHR||0),Q=((w.avgTemp??0)-(x.avgTemp??0)).toFixed(1),Y=(((x.avgTemp??0)+(w.avgTemp??0))/2).toFixed(1),K=Math.max(x.maxTemp??0,w.maxTemp??0).toFixed(1),Ae=(x.shifts||0)+(w.shifts||0);m=` -
+ `;return}let o=Se.METRICS,a=[];for(let C in o){let k=o[C];s.points.some(f=>f[k.field]!=null)&&a.push(C)}!a.includes(gn)&&a.length>0&&(gn=a[0]),!a.includes(Jt)&&a.length>1?Jt=a[1]:!a.includes(Jt)&&a.length>0&&(Jt=a[0]);let p=o[gn],c=o[Jt];t.style.overflow="hidden";let d="";if(zt.length>=2){let C=n.length>=2?n:zt,k=Math.min(C.length,8);Vs.fill(0);for(let re=0;re=me){let ne=I-me;Ce-=H[ne],Re-=Ie[ne],le-=oe[ne],ye-=he[ne];let Ne=Ce*fe,Z=Re*fe,Be=le*fe,xe=ye*fe,Ee=Ne-Z,Me=Be-xe,be=Math.exp(-Ee*Ee*Pe),we=1/(1+Me*Me*Pe);F+=Ne*Z*be+Be*xe*we,f++}}}}}for(let re=0;re<1024;re++)F+=Vs[re]*.001;let v=zt[0],u=zt[1],w=v.stats,E=u.stats,N=((E.totalDist-w.totalDist)/1e3).toFixed(2),G=((E.avgPower||0)-(w.avgPower||0)).toFixed(0),q=((E.avgHR||0)-(w.avgHR||0)).toFixed(0),_=(E.elevGain-w.elevGain).toFixed(0),W=(E.shifts||0)-(w.shifts||0),z=((w.totalDist+E.totalDist)/1e3).toFixed(2),de=(w.elevGain+E.elevGain).toFixed(0),y=((w.duration||0)+(E.duration||0))/1e3,m=Math.round(((w.avgPower||0)+(E.avgPower||0))/2),r=Math.max(w.maxPower||0,E.maxPower||0),J=Math.round(((w.avgHR||0)+(E.avgHR||0))/2),V=Math.max(w.maxHR||0,E.maxHR||0),ee=((E.avgTemp??0)-(w.avgTemp??0)).toFixed(1),U=(((w.avgTemp??0)+(E.avgTemp??0))/2).toFixed(1),Q=Math.max(w.maxTemp??0,E.maxTemp??0).toFixed(1),ke=(w.shifts||0)+(E.shifts||0);d=` +
Aggregate Track Comparison & Analysis
- + @@ -571,64 +571,64 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams( - - - + + + - - - + + + - + - - - + + + - - - + + + - - - + + + - - - + + +
Metric${b.displayName||b.name} (T1)${v.displayName||v.name} (T1) ${u.displayName||u.name} (T2) Delta (T2 - T1) Aggregate Summary
Distance${(x.totalDist/1e3).toFixed(2)} km ${(w.totalDist/1e3).toFixed(2)} km${Number(D)>=0?"+":""}${D} km${N} km (Total)${(E.totalDist/1e3).toFixed(2)} km${Number(N)>=0?"+":""}${N} km${z} km (Total)
Elevation Gain${x.elevGain.toFixed(0)} m ${w.elevGain.toFixed(0)} m${Number(C)>=0?"+":""}${C} m${ie} m (Total)${E.elevGain.toFixed(0)} m${Number(_)>=0?"+":""}${_} m${de} m (Total)
Duration${x.duration?ht(x.duration/1e3):"--"} ${w.duration?ht(w.duration/1e3):"--"}${E.duration?ht(E.duration/1e3):"--"} -- ${ht(y)} (Total)
Avg / Max Power${x.avgPower||0} W / ${x.maxPower||0} W ${w.avgPower||0} W / ${w.maxPower||0} W${Number(W)>=0?"+":""}${W} W (Avg)${d} W (Avg) / ${r} W (Max)${E.avgPower||0} W / ${E.maxPower||0} W${Number(G)>=0?"+":""}${G} W (Avg)${m} W (Avg) / ${r} W (Max)
Avg / Max HR${x.avgHR||0} bpm / ${x.maxHR||0} bpm ${w.avgHR||0} bpm / ${w.maxHR||0} bpm${Number(_)>=0?"+":""}${_} bpm (Avg)${J} bpm (Avg) / ${U} bpm (Max)${E.avgHR||0} bpm / ${E.maxHR||0} bpm${Number(q)>=0?"+":""}${q} bpm (Avg)${J} bpm (Avg) / ${V} bpm (Max)
Avg / Max Temp${x.avgTemp!=null?x.avgTemp.toFixed(1):"--"} \xB0C / ${x.maxTemp!=null?x.maxTemp.toFixed(1):"--"} \xB0C ${w.avgTemp!=null?w.avgTemp.toFixed(1):"--"} \xB0C / ${w.maxTemp!=null?w.maxTemp.toFixed(1):"--"} \xB0C${Number(Q)>=0?"+":""}${Q} \xB0C (Avg)${Y} \xB0C (Avg) / ${K} \xB0C (Max)${E.avgTemp!=null?E.avgTemp.toFixed(1):"--"} \xB0C / ${E.maxTemp!=null?E.maxTemp.toFixed(1):"--"} \xB0C${Number(ee)>=0?"+":""}${ee} \xB0C (Avg)${U} \xB0C (Avg) / ${Q} \xB0C (Max)
Gear Shifts${x.shifts||0} ${w.shifts||0}${q>=0?"+":""}${q}${Ae} (Total)${E.shifts||0}${W>=0?"+":""}${W}${ke} (Total)
- `}t.innerHTML=`${m} + `}t.innerHTML=`${d}
arrow_forward X Axis:
@@ -660,15 +660,15 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
- `,document.getElementById("btn-combined-x")?.addEventListener("click",E=>{E.stopPropagation(),Ol(E.currentTarget,"x")}),document.getElementById("btn-combined-y")?.addEventListener("click",E=>{E.stopPropagation(),Ol(E.currentTarget,"y")});let T=document.getElementById("combined-time-slider"),f=document.getElementById("combined-time-val"),M=document.getElementById("btn-combined-play");T?.addEventListener("input",()=>{bt=parseInt(T.value,10),Ss(),ft&&ft.redraw()});function O(){M&&(M.innerHTML='pause'),cn=window.setInterval(()=>{bt!==null&&btplay_arrow')}M?.addEventListener("click",()=>{cn?H():(bt!==null&&bt>=Lt.length-1&&(bt=0,T.value="0",Ss(),ft&&ft.redraw()),O())}),document.getElementById("btn-combined-cart")?.addEventListener("click",()=>{Pt&&(Pt=!1,dn(qt))}),document.getElementById("btn-combined-polar")?.addEventListener("click",()=>{Pt||(Pt=!0,dn(qt))}),Go()}function Yn(){let e=document.getElementById("tab-combined"),n=document.getElementById("combined-plot-container");if(ft&&n&&n.clientWidth>0){let t=n.clientWidth,s=n.clientHeight;if(t>0&&s>0)if(Pt){let o=Math.min(t,s);ft.setSize({width:o,height:o})}else ft.setSize({width:t,height:s})}}function Ol(e,n){document.querySelectorAll(".metric-menu-popup").forEach(m=>m.remove());let t=document.createElement("div");t.className="metric-menu-popup";let s=Se.METRICS,o=qt;if(!o)return;let a=[];for(let m in s){let T=s[m];o.points.some(f=>f[T.field]!=null)&&a.push(m)}a.forEach(m=>{let T=s[m],f=document.createElement("div"),M=n==="x"?gn:Jt;f.className=`menu-item ${M===m?"active":""}`,f.innerHTML=` - ${T.icon} - ${T.label} - ${M===m?"check":""} - `,f.addEventListener("click",()=>{n==="x"?gn=m:Jt=m,t.remove(),dn(qt)}),t.appendChild(f)});let g=e.getBoundingClientRect();t.style.top=`${g.bottom+5}px`,t.style.left=`${g.left}px`,document.body.appendChild(t);let c=m=>{!t.contains(m.target)&&!e.contains(m.target)&&(t.remove(),document.removeEventListener("click",c))};setTimeout(()=>document.addEventListener("click",c),0)}function Go(){if(!qt)return;let e=document.getElementById("combined-plot-container");if(!e)return;let n=Se.METRICS,t=n[gn]||n.power,s=n[Jt]||n.hr;if(zt.length>=2){let E=zt[0],k=zt[1],p=E.points,P=k.points,b=Math.max(p.length,P.length),u=[],x=[],w=[];for(let C=0;C0?e.clientWidth:800,W=e.clientHeight>0?e.clientHeight:350,_={width:D,height:W,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:[{},{label:`${E.displayName||E.name} (${s.label})`,stroke:E.color||"#3b82f6",width:2,points:{show:!1}},{label:`${k.displayName||k.name} (${s.label})`,stroke:k.color||"#FF6B35",width:2,points:{show:!1}}],axes:[{side:2,label:"Elapsed Duration (s)",stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:30},{side:3,label:`${s.label} (${s.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:40}],legend:{show:!0}};ft=new Vl(_,[u,x,w],e),Yn();return}let o=qt.points,a=o[0].time||0,g=o.map((E,k)=>[E[t.field],E[s.field],(E.time-a)/1e3,(E.dist||0)/1e3,k]).filter(([E,k,p,P])=>E!=null&&k!=null);if(g.length===0){e.innerHTML='
No data for selected metrics
';return}if(Pt){let E=g.map(x=>x[0]),k=g.map(x=>x[1]),p=Math.min(...E),P=Math.max(...E),b=Math.min(...k),u=Math.max(...k);Lt=g.map(x=>{let w=x[0],D=x[1],W=(w-p)/(P-p||1)*2*Math.PI,_=(D-b)/(u-b||1),C=_*Math.cos(W),q=_*Math.sin(W);return[C,q,x[2],x[3],x[4],w,D]})}else Lt=g.map(E=>[E[0],E[1],E[2],E[3],E[4],E[0],E[1]]);let c=document.getElementById("combined-time-slider");c&&(c.max=`${g.length-1}`,(bt===null||bt>=g.length)&&(bt=g.length-1,c.value=c.max),Ss()),Ot=[...Lt].sort((E,k)=>E[0]-k[0]||E[4]-k[4]);let m=Ot.map(E=>E[0]),T=Ot.map(E=>E[1]),f=document.getElementById("combined-plot-container"),M=f&&f.clientWidth>0?f.clientWidth:600,O=f&&f.clientHeight>0?f.clientHeight:400;if(Pt){let E=Math.min(M,O>0?O:M);M=E,O=E,f&&(f.style.display="flex",f.style.alignItems="center",f.style.justifyContent="center")}else f&&(f.style.display="",f.style.alignItems="",f.style.justifyContent="");let H={width:M,height:O,padding:[10,15,0,0],scales:{x:{time:!1,auto:!0},y:{auto:!0}},series:[{},{label:s.label,width:0,points:{show:!0,size:3,fill:tt(s.color,.3)}}],axes:[{side:2,show:!Pt,label:`${t.label} (${t.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(E,k)=>k.map(p=>p!=null?t.fmtAxis(p):""),size:30},{side:3,show:!Pt,label:`${s.label} (${s.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(E,k)=>k.map(p=>p!=null?s.fmtAxis(p):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:(E,k,p)=>{let P=E.cursor.left,b=E.cursor.top;if(P!=null&&b!=null&&P>=0&&b>=0){let u=1/0,x=-1;for(let w=0;w=0&&u<2500)return x}return p},points:{size:7,stroke:"#fff",width:2,fill:s.color}},legend:{show:!1},hooks:{draw:[E=>{let k=E.ctx,p=window.devicePixelRatio||1;k.save(),k.beginPath(),k.strokeStyle="rgba(255, 255, 255, 0.15)",k.lineWidth=1*p;let P=!1;for(let b=0;b{let k=E.cursor.idx,p=document.getElementById("combined-tooltip");if(p||(p=document.createElement("div"),p.id="combined-tooltip",p.style.position="absolute",p.style.background="rgba(14, 14, 16, 0.9)",p.style.color="#fff",p.style.padding="8px 12px",p.style.borderRadius="4px",p.classList.add("font-m"),p.style.fontFamily="system-ui",p.style.pointerEvents="none",p.style.zIndex="1000",p.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",p.style.border="1px solid #2e2e34",document.body.appendChild(p)),k!=null&&Ot[k]&&E.cursor.left>=0){let P=Ot[k],b=P[2],u=P[3],x=P[5],w=P[6];p.innerHTML=` + `,document.getElementById("btn-combined-x")?.addEventListener("click",C=>{C.stopPropagation(),Ol(C.currentTarget,"x")}),document.getElementById("btn-combined-y")?.addEventListener("click",C=>{C.stopPropagation(),Ol(C.currentTarget,"y")});let x=document.getElementById("combined-time-slider"),g=document.getElementById("combined-time-val"),T=document.getElementById("btn-combined-play");x?.addEventListener("input",()=>{bt=parseInt(x.value,10),Ss(),ft&&ft.redraw()});function $(){T&&(T.innerHTML='pause'),cn=window.setInterval(()=>{bt!==null&&btplay_arrow')}T?.addEventListener("click",()=>{cn?M():(bt!==null&&bt>=Lt.length-1&&(bt=0,x.value="0",Ss(),ft&&ft.redraw()),$())}),document.getElementById("btn-combined-cart")?.addEventListener("click",()=>{Pt&&(Pt=!1,dn(qt))}),document.getElementById("btn-combined-polar")?.addEventListener("click",()=>{Pt||(Pt=!0,dn(qt))}),Zo()}function Zn(){let e=document.getElementById("tab-combined"),n=document.getElementById("combined-plot-container");if(ft&&n&&n.clientWidth>0){let t=n.clientWidth,s=n.clientHeight;if(t>0&&s>0)if(Pt){let o=Math.min(t,s);ft.setSize({width:o,height:o})}else ft.setSize({width:t,height:s})}}function Ol(e,n){document.querySelectorAll(".metric-menu-popup").forEach(d=>d.remove());let t=document.createElement("div");t.className="metric-menu-popup";let s=Se.METRICS,o=qt;if(!o)return;let a=[];for(let d in s){let x=s[d];o.points.some(g=>g[x.field]!=null)&&a.push(d)}a.forEach(d=>{let x=s[d],g=document.createElement("div"),T=n==="x"?gn:Jt;g.className=`menu-item ${T===d?"active":""}`,g.innerHTML=` + ${x.icon} + ${x.label} + ${T===d?"check":""} + `,g.addEventListener("click",()=>{n==="x"?gn=d:Jt=d,t.remove(),dn(qt)}),t.appendChild(g)});let p=e.getBoundingClientRect();t.style.top=`${p.bottom+5}px`,t.style.left=`${p.left}px`,document.body.appendChild(t);let c=d=>{!t.contains(d.target)&&!e.contains(d.target)&&(t.remove(),document.removeEventListener("click",c))};setTimeout(()=>document.addEventListener("click",c),0)}function Zo(){if(!qt)return;let e=document.getElementById("combined-plot-container");if(!e)return;let n=Se.METRICS,t=n[gn]||n.power,s=n[Jt]||n.hr;if(zt.length>=2){let C=zt[0],k=zt[1],f=C.points,F=k.points,v=Math.max(f.length,F.length),u=[],w=[],E=[];for(let _=0;_0?e.clientWidth:800,G=e.clientHeight>0?e.clientHeight:350,q={width:N,height:G,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:[{},{label:`${C.displayName||C.name} (${s.label})`,stroke:C.color||"#3b82f6",width:2,points:{show:!1}},{label:`${k.displayName||k.name} (${s.label})`,stroke:k.color||"#FF6B35",width:2,points:{show:!1}}],axes:[{side:2,label:"Elapsed Duration (s)",stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:30},{side:3,label:`${s.label} (${s.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:40}],legend:{show:!0}};ft=new Vl(q,[u,w,E],e),Zn();return}let o=qt.points,a=o[0].time||0,p=o.map((C,k)=>[C[t.field],C[s.field],(C.time-a)/1e3,(C.dist||0)/1e3,k]).filter(([C,k,f,F])=>C!=null&&k!=null);if(p.length===0){e.innerHTML='
No data for selected metrics
';return}if(Pt){let C=p.map(w=>w[0]),k=p.map(w=>w[1]),f=Math.min(...C),F=Math.max(...C),v=Math.min(...k),u=Math.max(...k);Lt=p.map(w=>{let E=w[0],N=w[1],G=(E-f)/(F-f||1)*2*Math.PI,q=(N-v)/(u-v||1),_=q*Math.cos(G),W=q*Math.sin(G);return[_,W,w[2],w[3],w[4],E,N]})}else Lt=p.map(C=>[C[0],C[1],C[2],C[3],C[4],C[0],C[1]]);let c=document.getElementById("combined-time-slider");c&&(c.max=`${p.length-1}`,(bt===null||bt>=p.length)&&(bt=p.length-1,c.value=c.max),Ss()),Ot=[...Lt].sort((C,k)=>C[0]-k[0]||C[4]-k[4]);let d=Ot.map(C=>C[0]),x=Ot.map(C=>C[1]),g=document.getElementById("combined-plot-container"),T=g&&g.clientWidth>0?g.clientWidth:600,$=g&&g.clientHeight>0?g.clientHeight:400;if(Pt){let C=Math.min(T,$>0?$:T);T=C,$=C,g&&(g.style.display="flex",g.style.alignItems="center",g.style.justifyContent="center")}else g&&(g.style.display="",g.style.alignItems="",g.style.justifyContent="");let M={width:T,height:$,padding:[10,15,0,0],scales:{x:{time:!1,auto:!0},y:{auto:!0}},series:[{},{label:s.label,width:0,points:{show:!0,size:3,fill:tt(s.color,.3)}}],axes:[{side:2,show:!Pt,label:`${t.label} (${t.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(C,k)=>k.map(f=>f!=null?t.fmtAxis(f):""),size:30},{side:3,show:!Pt,label:`${s.label} (${s.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(C,k)=>k.map(f=>f!=null?s.fmtAxis(f):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:(C,k,f)=>{let F=C.cursor.left,v=C.cursor.top;if(F!=null&&v!=null&&F>=0&&v>=0){let u=1/0,w=-1;for(let E=0;E=0&&u<2500)return w}return f},points:{size:7,stroke:"#fff",width:2,fill:s.color}},legend:{show:!1},hooks:{draw:[C=>{let k=C.ctx,f=window.devicePixelRatio||1;k.save(),k.beginPath(),k.strokeStyle="rgba(255, 255, 255, 0.15)",k.lineWidth=1*f;let F=!1;for(let v=0;v{let k=C.cursor.idx,f=document.getElementById("combined-tooltip");if(f||(f=document.createElement("div"),f.id="combined-tooltip",f.style.position="absolute",f.style.background="rgba(14, 14, 16, 0.9)",f.style.color="#fff",f.style.padding="8px 12px",f.style.borderRadius="4px",f.classList.add("font-m"),f.style.fontFamily="system-ui",f.style.pointerEvents="none",f.style.zIndex="1000",f.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",f.style.border="1px solid #2e2e34",document.body.appendChild(f)),k!=null&&Ot[k]&&C.cursor.left>=0){let F=Ot[k],v=F[2],u=F[3],w=F[5],E=F[6];f.innerHTML=`
Point #${k}
Time: - ${ht(b)} + ${ht(v)}
Distance: @@ -676,13 +676,13 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
${t.label}: - ${t.fmtAxis(x)} ${t.unit} + ${t.fmtAxis(w)} ${t.unit}
${s.label}: - ${s.fmtAxis(w)} ${s.unit} + ${s.fmtAxis(E)} ${s.unit}
- `,p.style.display="block";let D=E.over.getBoundingClientRect();p.style.left=`${D.left+window.scrollX+E.cursor.left+15}px`,p.style.top=`${D.top+window.scrollY+E.cursor.top+15}px`}else p.style.display="none"}]}};e.querySelector(".empty-text")&&(e.innerHTML=""),ft&&ft.destroy(),ft=new Vl(H,[m,T],e),ft.over.addEventListener("click",()=>{if(ft){let E=ft.cursor.idx;if(E!=null&&Ot[E]){let k=Ot[E][4];Se.setCursorAt(k)}}}),Yn()}import Pn from"uplot";function jl(e,n){let t=0;for(let w=0;wt&&(t=D)}t||(t=Date.UTC(2026,7,1));let s=new Date(t),o=s.getUTCFullYear(),a=Date.UTC(o-1,s.getUTCMonth(),s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),g=Date.UTC(o,s.getUTCMonth()-6,s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),c=Date.UTC(o,s.getUTCMonth()-1,s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),m=0,T=0,f=0,M=0,O=0,H=t;e.forEach(w=>{if(!w.stats.startTime)return;let D=n(w);if(D===void 0)return;O+=D;let W=w.stats.startTime;W=a&&(T+=D),W>=g&&(f+=D),W>=c&&(M+=D)});let E=7*24*60*60*1e3,k=Date.UTC(o,0,1),p=Math.max(.1,(t-k)/E),P=Math.max(.1,(t-a)/E),b=Math.max(.1,(t-g)/E),u=Math.max(.1,(t-c)/E),x=Math.max(.1,(t-H)/E);return{currentYear:m,pastYear:T,past6m:f,past1m:M,total:O,currentYearAvg:m/p,pastYearAvg:T/P,past6mAvg:f/b,past1mAvg:M/u,totalAvg:O/x}}function Zl(e,n,t){let s=n?1e3:1,o=a=>(n?a/s:a).toLocaleString("en-US",{minimumFractionDigits:n?1:0,maximumFractionDigits:n?1:0});return` + `,f.style.display="block";let N=C.over.getBoundingClientRect();f.style.left=`${N.left+window.scrollX+C.cursor.left+15}px`,f.style.top=`${N.top+window.scrollY+C.cursor.top+15}px`}else f.style.display="none"}]}};e.querySelector(".empty-text")&&(e.innerHTML=""),ft&&ft.destroy(),ft=new Vl(M,[d,x],e),ft.over.addEventListener("click",()=>{if(ft){let C=ft.cursor.idx;if(C!=null&&Ot[C]){let k=Ot[C][4];Se.setCursorAt(k)}}}),Zn()}import An from"uplot";function jl(e,n){let t=0;for(let E=0;Et&&(t=N)}t||(t=Date.UTC(2026,7,1));let s=new Date(t),o=s.getUTCFullYear(),a=Date.UTC(o-1,s.getUTCMonth(),s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),p=Date.UTC(o,s.getUTCMonth()-6,s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),c=Date.UTC(o,s.getUTCMonth()-1,s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),d=0,x=0,g=0,T=0,$=0,M=t;e.forEach(E=>{if(!E.stats.startTime)return;let N=n(E);if(N===void 0)return;$+=N;let G=E.stats.startTime;G=a&&(x+=N),G>=p&&(g+=N),G>=c&&(T+=N)});let C=7*24*60*60*1e3,k=Date.UTC(o,0,1),f=Math.max(.1,(t-k)/C),F=Math.max(.1,(t-a)/C),v=Math.max(.1,(t-p)/C),u=Math.max(.1,(t-c)/C),w=Math.max(.1,(t-M)/C);return{currentYear:d,pastYear:x,past6m:g,past1m:T,total:$,currentYearAvg:d/f,pastYearAvg:x/F,past6mAvg:g/v,past1mAvg:T/u,totalAvg:$/w}}function Zl(e,n,t){let s=n?1e3:1,o=a=>(n?a/s:a).toLocaleString("en-US",{minimumFractionDigits:n?1:0,maximumFractionDigits:n?1:0});return` @@ -719,12 +719,12 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
- `}var An=[];function to(){An.forEach(e=>e.destroy()),An=[]}function no(){to();let e=document.getElementById("evolution-view");e&&(e.innerHTML=` + `}var In=[];function Kl(){In.forEach(e=>e.destroy()),In=[]}function eo(){Kl();let e=document.getElementById("evolution-view");e&&(e.innerHTML=`
no_sim
Select a track for progress analysis
- `)}var Zn=16384,jn=new Float64Array(Zn+1),hn=new Float64Array(Zn+1),Ms=new Float64Array(Zn+1),Gl=new Float64Array(Zn),js=new Float64Array(365),Xl=[3,5,7,10,12,14],Jl=[28,35,42,50,60,72],Ql=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,360,450,600,750,900,1200];function In(e,n,t,s){to();let o=document.getElementById("evolution-view");if(!o)return;let a=Ye.get().progress||"all";n.forEach(b=>{ot.ensureCurvesAndZones(b)});let g=0,c=0;js.fill(0);for(let b=0;bx)continue;let q=x-C,N=0,ie=0,y=0;for(let d=0;d<=q;d++){let r=jn[d+C]-jn[d],J=hn[d+C]-hn[d],U=Ms[d+C]-Ms[d];r>N&&(N=r),J>ie&&(ie=J),U>y&&(y=U)}c+=(N+ie+y)/C*W*.001}}for(let D=0;D<11;D++)for(let W=0;W{ot.ensureCurvesAndZones(v)});let p=0,c=0;js.fill(0);for(let v=0;vw)continue;let z=w-W,de=0,y=0;for(let m=0;m<=z;m++){let r=hn[m+W]-hn[m],J=(Pn[m+W]-Pn[m])*G+r*q,V=r+Pn[m]*q;J>de&&(de=J),V>y&&(y=V)}c+=(de+y+Ys[z])/W*.001}}for(let N=0;N<1;N++)for(let G=0;G<1;G++){let q=2/(Go[G]+N+1),_=1-q,W=1.67+G*.06+N*.03;for(let z=0;z<2;z++){let de=2/(Xo[z]+N+1),y=1-de,m=50+z*2,r=1/(195-m),J=0,V=0;for(let ee=0;ee
@@ -754,46 +754,46 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
- `;let T=document.getElementById("evolution-container");if(!T)return;let f=T.clientWidth||570,M=Pn.sync("progress-sync");m.push(eo(T,n,"distance",M,s,f)),m.push(eo(T,n,"elevation",M,s,f));let O=T.querySelector(".distance-progress-card .chart-scroll-container"),H=T.querySelector(".elevation-progress-card .chart-scroll-container");O&&H&&(O.addEventListener("scroll",()=>{H.scrollLeft!==O.scrollLeft&&(H.scrollLeft=O.scrollLeft)}),H.addEventListener("scroll",()=>{O.scrollLeft!==H.scrollLeft&&(O.scrollLeft=H.scrollLeft)}));let E=o.querySelector("#evolution-time-range");E&&E.querySelectorAll(".seg-btn").forEach(b=>{b.addEventListener("click",()=>{let u=b.getAttribute("data-range");u&&(E.querySelectorAll(".seg-btn").forEach(x=>x.classList.remove("active")),b.classList.add("active"),P(u))})}),o.querySelectorAll(".metric-pill").forEach(b=>{b.addEventListener("click",()=>{let u=b.getAttribute("data-target");u&&document.getElementById(`${u}-evolution-card`)?.scrollIntoView({behavior:"smooth"})})});function p(b){m.forEach(u=>{u&&u.updatePin&&u.updatePin(b)})}function P(b){Ye.patch({progress:b==="all"?null:b}),m.forEach(u=>{u&&u.updateRange&&u.updateRange(b)})}if(n.some(b=>b.stats.powerCurve)){let b=Kl({grid:T,currentTrack:e,allTracks:n,metricKey:"power",label:"Power Curve Progress",unit:"W",color:We.power.color,icon:"bolt",onPinChange:p,onRangeChange:P,onTrackSelect:t,gridWidth:f});m.push(b)}if(n.some(b=>b.stats.hrCurve)){let b=Kl({grid:T,currentTrack:e,allTracks:n,metricKey:"hr",label:"Heart Rate Curve Progress",unit:"bpm",color:We.hr.color,icon:"favorite",onPinChange:p,onRangeChange:P,onTrackSelect:t,gridWidth:f});m.push(b)}a!=="all"&&m.forEach(b=>{b&&b.updateRange&&b.updateRange(a)}),An.forEach(b=>{b._ready=!0})}function Kl(e){let{grid:n,currentTrack:t,allTracks:s,metricKey:o,label:a,unit:g,color:c,icon:m,onPinChange:T,onRangeChange:f,onTrackSelect:M,gridWidth:O}=e,H=t&&t.name||"Current Track",E=null,k=document.createElement("div");k.className="chart-row evolution-card-group",k.id=`${o}-evolution-card`,n.appendChild(k);let p=document.createElement("div");p.className="chart-row progress-chart-row",p.style.setProperty("--chart-color",c),p.style.flex="0 0 400px",p.style.borderBottom="none",p.innerHTML=` + `;let x=document.getElementById("evolution-container");if(!x)return;let g=x.clientWidth||570,T=An.sync("progress-sync");d.push(Ql(x,n,"distance",T,s,g)),d.push(Ql(x,n,"elevation",T,s,g));let $=x.querySelector(".distance-progress-card .chart-scroll-container"),M=x.querySelector(".elevation-progress-card .chart-scroll-container");$&&M&&($.addEventListener("scroll",()=>{M.scrollLeft!==$.scrollLeft&&(M.scrollLeft=$.scrollLeft)}),M.addEventListener("scroll",()=>{$.scrollLeft!==M.scrollLeft&&($.scrollLeft=M.scrollLeft)}));let C=o.querySelector("#evolution-time-range");C&&C.querySelectorAll(".seg-btn").forEach(v=>{v.addEventListener("click",()=>{let u=v.getAttribute("data-range");u&&(C.querySelectorAll(".seg-btn").forEach(w=>w.classList.remove("active")),v.classList.add("active"),F(u))})}),o.querySelectorAll(".metric-pill").forEach(v=>{v.addEventListener("click",()=>{let u=v.getAttribute("data-target");u&&document.getElementById(`${u}-evolution-card`)?.scrollIntoView({behavior:"smooth"})})});function f(v){d.forEach(u=>{u&&u.updatePin&&u.updatePin(v)})}function F(v){Ye.patch({progress:v==="all"?null:v}),d.forEach(u=>{u&&u.updateRange&&u.updateRange(v)})}if(n.some(v=>v.stats.powerCurve)){let v=Jl({grid:x,currentTrack:e,allTracks:n,metricKey:"power",label:"Power Curve Progress",unit:"W",color:We.power.color,icon:"bolt",onPinChange:f,onRangeChange:F,onTrackSelect:t,gridWidth:g});d.push(v)}if(n.some(v=>v.stats.hrCurve)){let v=Jl({grid:x,currentTrack:e,allTracks:n,metricKey:"hr",label:"Heart Rate Curve Progress",unit:"bpm",color:We.hr.color,icon:"favorite",onPinChange:f,onRangeChange:F,onTrackSelect:t,gridWidth:g});d.push(v)}a!=="all"&&d.forEach(v=>{v&&v.updateRange&&v.updateRange(a)}),In.forEach(v=>{v._ready=!0})}function Jl(e){let{grid:n,currentTrack:t,allTracks:s,metricKey:o,label:a,unit:p,color:c,icon:d,onPinChange:x,onRangeChange:g,onTrackSelect:T,gridWidth:$}=e,M=t&&t.name||"Current Track",C=null,k=document.createElement("div");k.className="chart-row evolution-card-group",k.id=`${o}-evolution-card`,n.appendChild(k);let f=document.createElement("div");f.className="chart-row progress-chart-row",f.style.setProperty("--chart-color",c),f.style.flex="0 0 400px",f.style.borderBottom="none",f.innerHTML=`
- ${m} + ${d} ${a}
- `;let P=document.createElement("div");P.className="evolution-legend",P.innerHTML=` + `;let F=document.createElement("div");F.className="evolution-legend",F.innerHTML=`
- ${H} + ${M}
All-Time Max
- `;let u=Ye.get().progress||"all",x=document.createElement("div");x.className="chart-row progress-chart-row",x.style.setProperty("--chart-color",c),x.style.flex="1",x.style.borderBottom="none",x.innerHTML=` + `;let u=Ye.get().progress||"all",w=document.createElement("div");w.className="chart-row progress-chart-row",w.style.setProperty("--chart-color",c),w.style.flex="1",w.style.borderBottom="none",w.innerHTML=`
- ${m} + ${d} Progress ${o==="power"?"Power":"HR"}
- `;let w=document.createElement("div");w.style.cssText="display: flex; flex-direction: row; gap: 0px; align-items: stretch;",w.appendChild(p),w.appendChild(x),k.appendChild(w),k.appendChild(P);let D=p.querySelector(`#${o}-evolution-chart`);if(!D)return;let W={};s.forEach(oe=>{let de=o==="power"?oe.stats.powerCurve:oe.stats.hrCurve;if(!de)return;let xe=oe.name||"Unnamed Track",Pe=oe.stats.startTime||oe.addedAt?Gt(oe.stats.startTime||oe.addedAt):"Unknown Date",G=`${xe} (${Pe})`;Object.entries(de).forEach(([F,ae])=>{let ue=Number(F),te=ae.power||ae.hr;(!W[ue]||te>W[ue].val)&&(W[ue]={val:te,trackInfo:G,trackId:oe.id,idx:ae.idx})})});let _=t&&(o==="power"?t.stats.powerCurve:t.stats.hrCurve)||{},C=new Set;Object.keys(W).forEach(oe=>C.add(Number(oe))),Object.keys(_).forEach(oe=>C.add(Number(oe)));let q=Array.from(C).sort((oe,de)=>oe-de),N=q,ie=q.map(oe=>{let de=_[oe];return de?de.power||de.hr:null}),y=q.map(oe=>W[oe]?.val||null),d=s.filter(oe=>(oe.stats.startTime||oe.addedAt)!=null);d.sort((oe,de)=>(oe.stats.startTime||oe.addedAt||0)-(de.stats.startTime||de.addedAt||0)||oe.id.localeCompare(de.id));let r=[],J={};q.forEach(oe=>J[oe]=[]),d.forEach(oe=>{let de=o==="power"?oe.stats.powerCurve:oe.stats.hrCurve;de&&(r.push((oe.stats.startTime||oe.addedAt)/1e3),q.forEach(xe=>{let Pe=de[xe],G=Pe?o==="power"?Pe.power:Pe.hr:null;J[xe].push(G)}))});let U=q[0]||5,Q=d,Y=null;function K(oe,de){let xe=r[r.length-1]||1785542400,Pe=0;de==="1m"?Pe=xe-30*24*3600:de==="2m"?Pe=xe-60*24*3600:de==="6m"?Pe=xe-180*24*3600:de==="1y"?Pe=xe-365*24*3600:de==="2y"&&(Pe=xe-2*365*24*3600);let G=[];r.forEach((Ie,he)=>{Ie>=Pe&&G.push(he)});let F=G.map(Ie=>r[Ie]),ae=J[oe]||[],ue=G.map(Ie=>ae[Ie]),te=En(ue,5);return Q=G.map(Ie=>d[Ie]),{xFiltered:F,rawYFiltered:ue,smoothedYFiltered:te}}let Ae=null,me=document.createElement("div");return me.className="cur-y-val font-m",me.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",D.style.position="relative",D.appendChild(me),(()=>{let oe={id:`${o}-evolution`,width:400,height:250,padding:[0,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:"Current Track",stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}},{label:"All-Time Max",stroke:"#888888",width:1,fill:"transparent",points:{show:!0,size:6,fill:"#888888"}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(G,F)=>F.map(ae=>`${ae}${g}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(G,F,ae)=>ae,x:!1,y:!1},hooks:{draw:[G=>{let F=G.ctx,ae=window.devicePixelRatio||1,ue=G.bbox,te=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Ie=N[N.length-1];F.save(),F.fillStyle="#555564",F.textAlign="center",F.textBaseline="top",F.font=`${10*ae}px system-ui, sans-serif`;let he=-100;if(te.forEach(He=>{if(He>Ie)return;let Ce=G.valToPos(He,"x",!0);Ce>he+30*ae&&Ce=0){let Ce=G.valToPos(Y,"x",!0),Re=G.valToPos(ie[He]||y[He],"y",!0);F.save(),F.beginPath(),F.setLineDash([]);let le=ie[He],be=le!==null?5*ae:3*ae,A=le!==null?c:"#888888";F.arc(Ce,Re,be,0,2*Math.PI),F.fillStyle=A,F.fill(),F.strokeStyle="#fff",F.lineWidth=2*ae,F.stroke(),F.restore()}}F.restore()},G=>{let F=G.ctx,ae=window.devicePixelRatio||1,ue=G.bbox,te=G.cursor.idx,Ie=1,he=G.cursor.left,He=G.cursor.top;if(he!=null&&He!=null&&he>=0&&He>=0){let Ce=1/0,Re=-1,le=30,be=le*le;for(let A=0;A{if(!G._ready)return;G.redraw(!1);let F=G.cursor.idx,ae=1,ue=G.cursor.left,te=G.cursor.top;if(ue!=null&&te!=null&&ue>=0&&te>=0){let Re=1/0,le=-1,be=30,A=be*be;for(let ne=0;ne${Bt(be)}
`;if(A!==null&&(Ne+=` + `;let E=document.createElement("div");E.style.cssText="display: flex; flex-direction: row; gap: 0px; align-items: stretch;",E.appendChild(f),E.appendChild(w),k.appendChild(E),k.appendChild(F);let N=f.querySelector(`#${o}-evolution-chart`);if(!N)return;let G={};s.forEach(se=>{let me=o==="power"?se.stats.powerCurve:se.stats.hrCurve;if(!me)return;let fe=se.name||"Unnamed Track",Pe=se.stats.startTime||se.addedAt?Gt(se.stats.startTime||se.addedAt):"Unknown Date",j=`${fe} (${Pe})`;Object.entries(me).forEach(([H,oe])=>{let ge=Number(H),K=oe.power||oe.hr;(!G[ge]||K>G[ge].val)&&(G[ge]={val:K,trackInfo:j,trackId:se.id,idx:oe.idx})})});let q=t&&(o==="power"?t.stats.powerCurve:t.stats.hrCurve)||{},_=new Set;Object.keys(G).forEach(se=>_.add(Number(se))),Object.keys(q).forEach(se=>_.add(Number(se)));let W=Array.from(_).sort((se,me)=>se-me),z=W,de=W.map(se=>{let me=q[se];return me?me.power||me.hr:null}),y=W.map(se=>G[se]?.val||null),m=s.filter(se=>(se.stats.startTime||se.addedAt)!=null);m.sort((se,me)=>(se.stats.startTime||se.addedAt||0)-(me.stats.startTime||me.addedAt||0)||se.id.localeCompare(me.id));let r=[],J={};W.forEach(se=>J[se]=[]),m.forEach(se=>{let me=o==="power"?se.stats.powerCurve:se.stats.hrCurve;me&&(r.push((se.stats.startTime||se.addedAt)/1e3),W.forEach(fe=>{let Pe=me[fe],j=Pe?o==="power"?Pe.power:Pe.hr:null;J[fe].push(j)}))});let V=W[0]||5,ee=m,U=null;function Q(se,me){let fe=r[r.length-1]||1785542400,Pe=0;me==="1m"?Pe=fe-30*24*3600:me==="2m"?Pe=fe-60*24*3600:me==="6m"?Pe=fe-180*24*3600:me==="1y"?Pe=fe-365*24*3600:me==="2y"&&(Pe=fe-2*365*24*3600);let j=[];r.forEach((Ie,he)=>{Ie>=Pe&&j.push(he)});let H=j.map(Ie=>r[Ie]),oe=J[se]||[],ge=j.map(Ie=>oe[Ie]),K=En(ge,5);return ee=j.map(Ie=>m[Ie]),{xFiltered:H,rawYFiltered:ge,smoothedYFiltered:K}}let ke=null,re=document.createElement("div");return re.className="cur-y-val font-m",re.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",N.style.position="relative",N.appendChild(re),(()=>{let se={id:`${o}-evolution`,width:400,height:250,padding:[0,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:"Current Track",stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}},{label:"All-Time Max",stroke:"#888888",width:1,fill:"transparent",points:{show:!0,size:6,fill:"#888888"}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(j,H)=>H.map(oe=>`${oe}${p}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(j,H,oe)=>oe,x:!1,y:!1},hooks:{draw:[j=>{let H=j.ctx,oe=window.devicePixelRatio||1,ge=j.bbox,K=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Ie=z[z.length-1];H.save(),H.fillStyle="#555564",H.textAlign="center",H.textBaseline="top",H.font=`${10*oe}px system-ui, sans-serif`;let he=-100;if(K.forEach(He=>{if(He>Ie)return;let Ce=j.valToPos(He,"x",!0);Ce>he+30*oe&&Ce=0){let Ce=j.valToPos(U,"x",!0),Re=j.valToPos(de[He]||y[He],"y",!0);H.save(),H.beginPath(),H.setLineDash([]);let le=de[He],ye=le!==null?5*oe:3*oe,I=le!==null?c:"#888888";H.arc(Ce,Re,ye,0,2*Math.PI),H.fillStyle=I,H.fill(),H.strokeStyle="#fff",H.lineWidth=2*oe,H.stroke(),H.restore()}}H.restore()},j=>{let H=j.ctx,oe=window.devicePixelRatio||1,ge=j.bbox,K=j.cursor.idx,Ie=1,he=j.cursor.left,He=j.cursor.top;if(he!=null&&He!=null&&he>=0&&He>=0){let Ce=1/0,Re=-1,le=30,ye=le*le;for(let I=0;I{if(!j._ready)return;j.redraw(!1);let H=j.cursor.idx,oe=1,ge=j.cursor.left,K=j.cursor.top;if(ge!=null&&K!=null&&ge>=0&&K>=0){let Re=1/0,le=-1,ye=30,I=ye*ye;for(let ne=0;ne${_t(ye)}
`;if(I!==null&&(Ne+=`
Current: - ${A} ${g} + ${I} ${p}
`),ne!==null&&(Ne+=`
Max: - ${ne} ${g} + ${ne} ${p}
- `),me.innerHTML=Ne,Ae&&Y===null){U=be;let{xFiltered:j,rawYFiltered:_e,smoothedYFiltered:we}=K(U,u),Ee=we.map(Me=>Me!==null?Me*.9:null),ke=we.map(Me=>Me!==null?Me*1.1:null);Ae.setData([j,_e,we,Ee,ke]);let ve=document.getElementById(`${o}-timeline-label`);ve&&(ve.textContent=`Progress ${Bt(be)} ${o==="power"?"Power":"HR"}`)}me.style.display="",me.style.left=`${ue+He.left}px`,me.style.top=`${te+He.top}px`,me.style.transform="translate(5px, -50%)"}else me.style.display="none"}]}};E=new Pn(oe,[N,ie,y],D),An.push(E),D.addEventListener("click",()=>{if(!E)return;let G=E.cursor.idx;if(G!=null){let F=N[G],ae=null;if(Y!==null?ae=null:ae=F,T(ae),t){let ue=t.stats,te=o==="power"?ue.powerCurve:ue.hrCurve;if(te){let Ie=te[F];if(Ie){let he=Ie.idx,He=F,Ce=t.points[he],Re=t.points[he+He-1];if(Ce&&Re&&Ce.time!=null&&Re.time!=null){let le=t.points[0].time||0,be=(Ce.time-le)/1e3,A=(Re.time-le)/1e3;M?.(t.id,[be,A])}}}}}}),D.addEventListener("mouseleave",()=>{E&&E.redraw()});let de=document.createElement("details");de.classList.add("progress-details"),de.style.marginTop="0px",de.style.setProperty("--chart-color",c),de.innerHTML=` + `),re.innerHTML=Ne,ke&&U===null){V=ye;let{xFiltered:Z,rawYFiltered:Be,smoothedYFiltered:xe}=Q(V,u),Ee=xe.map(we=>we!==null?we*.9:null),Me=xe.map(we=>we!==null?we*1.1:null);ke.setData([Z,Be,xe,Ee,Me]);let be=document.getElementById(`${o}-timeline-label`);be&&(be.textContent=`Progress ${_t(ye)} ${o==="power"?"Power":"HR"}`)}re.style.display="",re.style.left=`${ge+He.left}px`,re.style.top=`${K+He.top}px`,re.style.transform="translate(5px, -50%)"}else re.style.display="none"}]}};C=new An(se,[z,de,y],N),In.push(C),N.addEventListener("click",()=>{if(!C)return;let j=C.cursor.idx;if(j!=null){let H=z[j],oe=null;if(U!==null?oe=null:oe=H,x(oe),t){let ge=t.stats,K=o==="power"?ge.powerCurve:ge.hrCurve;if(K){let Ie=K[H];if(Ie){let he=Ie.idx,He=H,Ce=t.points[he],Re=t.points[he+He-1];if(Ce&&Re&&Ce.time!=null&&Re.time!=null){let le=t.points[0].time||0,ye=(Ce.time-le)/1e3,I=(Re.time-le)/1e3;T?.(t.id,[ye,I])}}}}}}),N.addEventListener("mouseleave",()=>{C&&C.redraw()});let me=document.createElement("details");me.classList.add("progress-details"),me.style.marginTop="0px",me.style.setProperty("--chart-color",c),me.innerHTML=` chevron_right table_chart @@ -808,32 +808,32 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams( - ${q.map(G=>{let F=_[G]?_[G].power||_[G].hr:"-",ae=W[G]?.val||"-",ue=W[G]?.trackId,te=W[G]?.idx;return` + ${W.map(j=>{let H=q[j]?q[j].power||q[j].hr:"-",oe=G[j]?.val||"-",ge=G[j]?.trackId,K=G[j]?.idx;return` - ${Bt(G)} - ${F} ${g} + ${_t(j)} + ${H} ${p} - ${ae} ${g} - ${ue?``:""} + ${oe} ${p} + ${ge?``:""} `}).join("")} - `,k.appendChild(de),de.querySelectorAll(".evolution-select-btn").forEach(G=>{G.addEventListener("click",F=>{F.preventDefault(),F.stopPropagation();let ae=G.getAttribute("data-id"),ue=G.getAttribute("data-idx"),te=G.getAttribute("data-dur");ae&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:ae,idx:ue?Number(ue):null,dur:te?Number(te):null}}))})});let xe=null,Pe=x.querySelector(`#${o}-timeline-chart`);if(Pe){Pe.style.position="relative";let G=document.createElement("div");if(G.className="timeline-tooltip font-m",G.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",Pe.appendChild(G),r.length>0){let{xFiltered:F,rawYFiltered:ae,smoothedYFiltered:ue}=K(U,u),te=ue.map(le=>le!==null?le*.9:null),Ie=ue.map(le=>le!==null?le*1.1:null),he=[F,ae,ue,te,Ie],He=[{value:(le,be)=>be!=null?Gt(be*1e3):"-"},{label:"Value",stroke:c,width:0,points:{show:!0,size:6,fill:tt(c,.5)}},{label:"Trend",stroke:c,width:2,points:{show:!1},spanGaps:!0,fill:"transparent",dash:[5,5]},{label:"Lower Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0},{label:"Upper Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0}],Ce=document.getElementById(`${o}-timeline-label`);Ce&&(Ce.textContent=`Progress ${Bt(U)} ${o==="power"?"Power":"HR"}`);let Re={width:Math.max(100,(O||570)-400),height:250,padding:[0,10,0,10],tzDate:le=>Pn.tzDate(new Date(le*1e3),"Etc/UTC"),cursor:{points:{show:!1},drag:{setScale:!1},x:!1,y:!1},scales:{x:{time:!0,range:le=>{let be=le.data[0][0],A=le.data[0][le.data[0].length-1];return be===void 0||A===void 0?[0,100]:be===A?[be-3600,A+3600]:[be,A]}},y:{range:(le,be,A)=>[be*.9,A*1.1]}},series:He,bands:[{series:[4,3],fill:tt(c,.2)}],hooks:{init:[le=>{le.over.addEventListener("click",()=>{if(xe!=null){let be=Q[xe];if(be){let A=be.stats,ne=o==="power"?A.powerCurve:A.hrCurve;if(ne){let Ne=ne[U];if(Ne){let j=Ne.idx,_e=U,we=be.points[j],Ee=be.points[j+_e-1];if(we&&Ee&&we.time!=null&&Ee.time!=null){let ke=be.points[0].time||0,ve=(we.time-ke)/1e3,Me=(Ee.time-ke)/1e3;e.onTrackSelect?.(be.id,[ve,Me])}else e.onTrackSelect?.(be.id,null)}else e.onTrackSelect?.(be.id,null)}else e.onTrackSelect?.(be.id,null)}}})}],draw:[le=>{let be=le.cursor.idx;if(be!=null&&le.data[0][be]!=null){let A=le.data[1][be];if(A!=null){let ne=le.valToPos(le.data[0][be],"x",!0),Ne=le.valToPos(A,"y",!0),j=le.ctx,_e=window.devicePixelRatio||1;j.save(),j.beginPath(),j.setLineDash([2*_e,2*_e]),j.strokeStyle=tt(c,.4),j.lineWidth=1*_e,j.moveTo(ne,le.bbox.top),j.lineTo(ne,le.bbox.top+le.bbox.height),j.moveTo(le.bbox.left,Ne),j.lineTo(le.bbox.left+le.bbox.width,Ne),j.stroke(),j.restore(),j.save(),j.beginPath(),j.setLineDash([]),j.arc(ne,Ne,12*_e,0,2*Math.PI),j.fillStyle=tt(c,.2),j.fill(),j.restore(),j.save(),j.beginPath(),j.arc(ne,Ne,6*_e,0,2*Math.PI),j.fillStyle=c,j.fill(),j.strokeStyle="#fff",j.lineWidth=2*_e,j.stroke(),j.restore(),j.save(),j.setLineDash([]);let we=new Date(le.data[0][be]*1e3),Ee=`${we.getUTCFullYear()}-${String(we.getUTCMonth()+1).padStart(2,"0")}-${String(we.getUTCDate()).padStart(2,"0")}`;j.font=`bold ${10*_e}px system-ui, sans-serif`;let ve=j.measureText(Ee).width+10*_e,Me=16*_e,Ue=ne-ve/2,je=Math.max(le.bbox.left,Math.min(le.bbox.left+le.bbox.width-ve,Ue)),dt=le.bbox.top+le.bbox.height+2*_e;j.fillStyle="rgba(14, 14, 16, 0.92)",j.beginPath(),j.roundRect?j.roundRect(je,dt,ve,Me,3*_e):j.rect(je,dt,ve,Me),j.fill(),j.strokeStyle=tt(c,.27),j.lineWidth=1*_e,j.stroke(),j.fillStyle=c,j.textAlign="center",j.textBaseline="middle",j.fillText(Ee,je+ve/2,dt+Me/2);let At=`${A.toFixed(0)} ${g}`,Qt=j.measureText(At).width+10*_e,Yt=le.bbox.left-Qt-2*_e,wn=Ne-Me/2;j.fillStyle="rgba(14, 14, 16, 0.92)",j.beginPath(),j.roundRect?j.roundRect(Yt,wn,Qt,Me,3*_e):j.rect(Yt,wn,Qt,Me),j.fill(),j.strokeStyle=tt(c,.27),j.lineWidth=1*_e,j.stroke(),j.fillStyle=c,j.textAlign="left",j.textBaseline="middle",j.fillText(At,Yt+5*_e,wn+Me/2),j.restore()}}}],setCursor:[le=>{if(!le._ready)return;le.redraw(!1);let be=le.cursor.idx,A=le.cursor.left,ne=le.cursor.top,Ne=le.bbox;if(A!=null&&ne!=null&&A>=0&&ne>=0){let j=1/0,_e=-1,we=30,Ee=we*we,ke=le.data[0],ve=le.data[1];for(let Me=0;Me{j.addEventListener("click",H=>{H.preventDefault(),H.stopPropagation();let oe=j.getAttribute("data-id"),ge=j.getAttribute("data-idx"),K=j.getAttribute("data-dur");oe&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:oe,idx:ge?Number(ge):null,dur:K?Number(K):null}}))})});let fe=null,Pe=w.querySelector(`#${o}-timeline-chart`);if(Pe){Pe.style.position="relative";let j=document.createElement("div");if(j.className="timeline-tooltip font-m",j.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",Pe.appendChild(j),r.length>0){let{xFiltered:H,rawYFiltered:oe,smoothedYFiltered:ge}=Q(V,u),K=ge.map(le=>le!==null?le*.9:null),Ie=ge.map(le=>le!==null?le*1.1:null),he=[H,oe,ge,K,Ie],He=[{value:(le,ye)=>ye!=null?Gt(ye*1e3):"-"},{label:"Value",stroke:c,width:0,points:{show:!0,size:6,fill:tt(c,.5)}},{label:"Trend",stroke:c,width:2,points:{show:!1},spanGaps:!0,fill:"transparent",dash:[5,5]},{label:"Lower Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0},{label:"Upper Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0}],Ce=document.getElementById(`${o}-timeline-label`);Ce&&(Ce.textContent=`Progress ${_t(V)} ${o==="power"?"Power":"HR"}`);let Re={width:Math.max(100,($||570)-400),height:250,padding:[0,10,0,10],tzDate:le=>An.tzDate(new Date(le*1e3),"Etc/UTC"),cursor:{points:{show:!1},drag:{setScale:!1},x:!1,y:!1},scales:{x:{time:!0,range:le=>{let ye=le.data[0][0],I=le.data[0][le.data[0].length-1];return ye===void 0||I===void 0?[0,100]:ye===I?[ye-3600,I+3600]:[ye,I]}},y:{range:(le,ye,I)=>[ye*.9,I*1.1]}},series:He,bands:[{series:[4,3],fill:tt(c,.2)}],hooks:{init:[le=>{le.over.addEventListener("click",()=>{if(fe!=null){let ye=ee[fe];if(ye){let I=ye.stats,ne=o==="power"?I.powerCurve:I.hrCurve;if(ne){let Ne=ne[V];if(Ne){let Z=Ne.idx,Be=V,xe=ye.points[Z],Ee=ye.points[Z+Be-1];if(xe&&Ee&&xe.time!=null&&Ee.time!=null){let Me=ye.points[0].time||0,be=(xe.time-Me)/1e3,we=(Ee.time-Me)/1e3;e.onTrackSelect?.(ye.id,[be,we])}else e.onTrackSelect?.(ye.id,null)}else e.onTrackSelect?.(ye.id,null)}else e.onTrackSelect?.(ye.id,null)}}})}],draw:[le=>{let ye=le.cursor.idx;if(ye!=null&&le.data[0][ye]!=null){let I=le.data[1][ye];if(I!=null){let ne=le.valToPos(le.data[0][ye],"x",!0),Ne=le.valToPos(I,"y",!0),Z=le.ctx,Be=window.devicePixelRatio||1;Z.save(),Z.beginPath(),Z.setLineDash([2*Be,2*Be]),Z.strokeStyle=tt(c,.4),Z.lineWidth=1*Be,Z.moveTo(ne,le.bbox.top),Z.lineTo(ne,le.bbox.top+le.bbox.height),Z.moveTo(le.bbox.left,Ne),Z.lineTo(le.bbox.left+le.bbox.width,Ne),Z.stroke(),Z.restore(),Z.save(),Z.beginPath(),Z.setLineDash([]),Z.arc(ne,Ne,12*Be,0,2*Math.PI),Z.fillStyle=tt(c,.2),Z.fill(),Z.restore(),Z.save(),Z.beginPath(),Z.arc(ne,Ne,6*Be,0,2*Math.PI),Z.fillStyle=c,Z.fill(),Z.strokeStyle="#fff",Z.lineWidth=2*Be,Z.stroke(),Z.restore(),Z.save(),Z.setLineDash([]);let xe=new Date(le.data[0][ye]*1e3),Ee=`${xe.getUTCFullYear()}-${String(xe.getUTCMonth()+1).padStart(2,"0")}-${String(xe.getUTCDate()).padStart(2,"0")}`;Z.font=`bold ${10*Be}px system-ui, sans-serif`;let be=Z.measureText(Ee).width+10*Be,we=16*Be,qe=ne-be/2,je=Math.max(le.bbox.left,Math.min(le.bbox.left+le.bbox.width-be,qe)),dt=le.bbox.top+le.bbox.height+2*Be;Z.fillStyle="rgba(14, 14, 16, 0.92)",Z.beginPath(),Z.roundRect?Z.roundRect(je,dt,be,we,3*Be):Z.rect(je,dt,be,we),Z.fill(),Z.strokeStyle=tt(c,.27),Z.lineWidth=1*Be,Z.stroke(),Z.fillStyle=c,Z.textAlign="center",Z.textBaseline="middle",Z.fillText(Ee,je+be/2,dt+we/2);let At=`${I.toFixed(0)} ${p}`,Qt=Z.measureText(At).width+10*Be,Yt=le.bbox.left-Qt-2*Be,wn=Ne-we/2;Z.fillStyle="rgba(14, 14, 16, 0.92)",Z.beginPath(),Z.roundRect?Z.roundRect(Yt,wn,Qt,we,3*Be):Z.rect(Yt,wn,Qt,we),Z.fill(),Z.strokeStyle=tt(c,.27),Z.lineWidth=1*Be,Z.stroke(),Z.fillStyle=c,Z.textAlign="left",Z.textBaseline="middle",Z.fillText(At,Yt+5*Be,wn+we/2),Z.restore()}}}],setCursor:[le=>{if(!le._ready)return;le.redraw(!1);let ye=le.cursor.idx,I=le.cursor.left,ne=le.cursor.top,Ne=le.bbox;if(I!=null&&ne!=null&&I>=0&&ne>=0){let Z=1/0,Be=-1,xe=30,Ee=xe*xe,Me=le.data[0],be=le.data[1];for(let we=0;we Date: - ${ke} + ${Me}
Value: - ${Me} + ${we}
- `,G.style.display="block",G.style.left=`${A+Ne.left}px`,G.style.top=`${ne+Ne.top}px`,G.style.transform="translate(5px, -50%)"}else G.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(le,be)=>be.map(A=>{let ne=new Date(A*1e3);return`${ne.getUTCFullYear()}-${String(ne.getUTCMonth()+1).padStart(2,"0")}`})},{stroke:"#555564",grid:{stroke:"#2e2e34"},font:"10px system-ui, sans-serif",values:(le,be)=>be.map(A=>`${A} ${g}`),show:!0,space:15,size:50}]};Ae=new Pn(Re,he,Pe),An.push(Ae),Pe.addEventListener("mouseleave",()=>{Ae.redraw()})}else Pe.innerHTML='
No data for the past year
'}})(),{updatePin:oe=>{Y=oe,oe!==null&&(U=oe);let de=document.getElementById(`${o}-timeline-label`);if(de&&(de.textContent=`Progress ${Bt(U)} ${o==="power"?"Power":"HR"}${Y!==null?" (Pinned)":""}`),Ae){let{xFiltered:xe,rawYFiltered:Pe,smoothedYFiltered:G}=K(U,u),F=G.map(ue=>ue!==null?ue*.9:null),ae=G.map(ue=>ue!==null?ue*1.1:null);Ae.setData([xe,Pe,G,F,ae])}E&&E.redraw()},updateRange:oe=>{if(u=oe,Ae){let{xFiltered:de,rawYFiltered:xe,smoothedYFiltered:Pe}=K(U,u),G=Pe.map(ae=>ae!==null?ae*.9:null),F=Pe.map(ae=>ae!==null?ae*1.1:null);Ae.setData([de,xe,Pe,G,F])}}}}function so(e){let n=new Date(e),t=n.getUTCDay(),s=n.getUTCDate()-t+(t===0?-6:1);return n.setUTCDate(s),n.setUTCHours(0,0,0,0),n}function Xo(e){let n={};return e.forEach(t=>{if(!t.stats.startTime||!t.stats.totalDist)return;let s=new Date(t.stats.startTime),o=so(s),a=o.toISOString().split("T")[0];n[a]||(n[a]={timestamp:o.getTime(),distance:0}),n[a].distance+=t.stats.totalDist}),Object.entries(n).map(([t,s])=>({week:t,timestamp:s.timestamp,distance:s.distance})).sort((t,s)=>t.timestamp-s.timestamp)}function Jo(e){let n={};return e.forEach(t=>{if(!t.stats.startTime||t.stats.elevGain===void 0)return;let s=new Date(t.stats.startTime),o=so(s),a=o.toISOString().split("T")[0];n[a]||(n[a]={timestamp:o.getTime(),elevation:0}),n[a].elevation+=t.stats.elevGain}),Object.entries(n).map(([t,s])=>({week:t,timestamp:s.timestamp,elevation:s.elevation})).sort((t,s)=>t.timestamp-s.timestamp)}function eo(e,n,t,s,o,a){let g=t==="distance",c=g?Xo(n):Jo(n),m=jl(n,C=>g?C.stats.totalDist:C.stats.elevGain),T=g?We.distance.color:We.elevation.color,f=g?"km":"m",M=g?We.distance.icon:We.elevation.icon,O=document.createElement("div");O.className=`chart-row ${t}-progress-card`,O.id=`${t}-evolution-card`,O.innerHTML=` + `,j.style.display="block",j.style.left=`${I+Ne.left}px`,j.style.top=`${ne+Ne.top}px`,j.style.transform="translate(5px, -50%)"}else j.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(le,ye)=>ye.map(I=>{let ne=new Date(I*1e3);return`${ne.getUTCFullYear()}-${String(ne.getUTCMonth()+1).padStart(2,"0")}`})},{stroke:"#555564",grid:{stroke:"#2e2e34"},font:"10px system-ui, sans-serif",values:(le,ye)=>ye.map(I=>`${I} ${p}`),show:!0,space:15,size:50}]};ke=new An(Re,he,Pe),In.push(ke),Pe.addEventListener("mouseleave",()=>{ke.redraw()})}else Pe.innerHTML='
No data for the past year
'}})(),{updatePin:se=>{U=se,se!==null&&(V=se);let me=document.getElementById(`${o}-timeline-label`);if(me&&(me.textContent=`Progress ${_t(V)} ${o==="power"?"Power":"HR"}${U!==null?" (Pinned)":""}`),ke){let{xFiltered:fe,rawYFiltered:Pe,smoothedYFiltered:j}=Q(V,u),H=j.map(ge=>ge!==null?ge*.9:null),oe=j.map(ge=>ge!==null?ge*1.1:null);ke.setData([fe,Pe,j,H,oe])}C&&C.redraw()},updateRange:se=>{if(u=se,ke){let{xFiltered:me,rawYFiltered:fe,smoothedYFiltered:Pe}=Q(V,u),j=Pe.map(oe=>oe!==null?oe*.9:null),H=Pe.map(oe=>oe!==null?oe*1.1:null);ke.setData([me,fe,Pe,j,H])}}}}function to(e){let n=new Date(e),t=n.getUTCDay(),s=n.getUTCDate()-t+(t===0?-6:1);return n.setUTCDate(s),n.setUTCHours(0,0,0,0),n}function Jo(e){let n={};return e.forEach(t=>{if(!t.stats.startTime||!t.stats.totalDist)return;let s=new Date(t.stats.startTime),o=to(s),a=o.toISOString().split("T")[0];n[a]||(n[a]={timestamp:o.getTime(),distance:0}),n[a].distance+=t.stats.totalDist}),Object.entries(n).map(([t,s])=>({week:t,timestamp:s.timestamp,distance:s.distance})).sort((t,s)=>t.timestamp-s.timestamp)}function Qo(e){let n={};return e.forEach(t=>{if(!t.stats.startTime||t.stats.elevGain===void 0)return;let s=new Date(t.stats.startTime),o=to(s),a=o.toISOString().split("T")[0];n[a]||(n[a]={timestamp:o.getTime(),elevation:0}),n[a].elevation+=t.stats.elevGain}),Object.entries(n).map(([t,s])=>({week:t,timestamp:s.timestamp,elevation:s.elevation})).sort((t,s)=>t.timestamp-s.timestamp)}function Ql(e,n,t,s,o,a){let p=t==="distance",c=p?Jo(n):Qo(n),d=jl(n,_=>p?_.stats.totalDist:_.stats.elevGain),x=p?We.distance.color:We.elevation.color,g=p?"km":"m",T=p?We.distance.icon:We.elevation.icon,$=document.createElement("div");$.className=`chart-row ${t}-progress-card`,$.id=`${t}-evolution-card`,$.innerHTML=`
- ${M} - ${g?"Distance Progress":"Elevation Progress"} + ${T} + ${p?"Distance Progress":"Elevation Progress"}
@@ -842,18 +842,18 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
- ${Zl(m,g,f)} + ${Zl(d,p,g)}
- `,e.appendChild(O);let H=O.querySelector(`#${t}-weekly-chart`),E=O.querySelector(`#${t}-y-axis-chart`);if(!H||!E)return;H.style.position="relative";let k=document.createElement("div");k.className="cur-y-val",k.style.cssText=`color:${T};display:none`,H.appendChild(k);let p=c.map(C=>C.timestamp/1e3),P=g?c.map(C=>C.distance/1e3):c.map(C=>C.elevation);if(p.length===0)return;let b=En(P,2),u=Math.max(0,(a||570)-20-320-20),x=Math.max(u,p.length*40),w=Math.max(...P)*1.1,D={width:x,height:150,padding:[10,10,0,10],tzDate:C=>Pn.tzDate(new Date(C*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,w]}},series:[{},{label:g?"Distance":"Elevation",stroke:T,fill:tt(T,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:T,width:2,dash:[5,5],points:{show:!1}}],cursor:{sync:s?{key:s.key}:void 0,drag:{x:!1,y:!1},points:{show:!1},x:!1,y:!1},hooks:{init:[C=>{C.over.addEventListener("click",()=>{let q=C.cursor.idx;if(q!=null){let N=c[q];if(N){let ie=new Date(N.timestamp),y=new Date(N.timestamp+7*24*60*60*1e3),d=ie.toISOString().split("T")[0],r=y.toISOString().split("T")[0];o?.(d,r)}}})}],setCursor:[C=>{if(!C._ready)return;let q=C.cursor.idx,N=C.cursor.left,ie=C.cursor.top;if(q!=null&&N!=null&&ie!=null&&N>=0&&ie>=0){let y=C.data[1][q],d=y!=null?g?`${y.toFixed(1)} km`:`${y.toFixed(0)} m`:"\u2014";k.innerHTML=d,k.style.display="block",k.style.left=`${C.valToPos(C.data[0][q],"x",!1)}px`,k.style.top=`${C.valToPos(C.data[1][q],"y",!1)}px`,k.style.transform="translate(6px, -50%)"}else k.style.display="none";C.redraw(!1)}],draw:[C=>{let q=C.cursor.idx;if(q!=null&&C.data[0][q]!=null){let N=C.valToPos(C.data[0][q],"x",!0),ie=C.valToPos(C.data[1][q],"y",!0),y=window.devicePixelRatio||1,d=C.ctx,r=C.bbox;d.save(),d.beginPath(),d.setLineDash([2*y,2*y]),d.strokeStyle=tt(T,.4),d.lineWidth=1*y,d.moveTo(N,r.top),d.lineTo(N,r.top+r.height),d.moveTo(r.left,ie),d.lineTo(r.left+r.width,ie),d.stroke(),d.restore(),d.save(),d.beginPath(),d.setLineDash([]),d.arc(N,ie,12*y,0,2*Math.PI),d.fillStyle=tt(T,.2),d.fill(),d.restore(),d.save(),d.beginPath(),d.arc(N,ie,6*y,0,2*Math.PI),d.fillStyle=T,d.fill(),d.strokeStyle="#fff",d.lineWidth=2*y,d.stroke(),d.restore(),d.save(),d.setLineDash([]);let J=new Date(C.data[0][q]*1e3),U=`${J.getUTCFullYear()}-${String(J.getUTCMonth()+1).padStart(2,"0")}-${String(J.getUTCDate()).padStart(2,"0")}`;d.font=`bold ${10*y}px system-ui, sans-serif`;let Y=d.measureText(U).width+10*y,K=16*y,Ae=N-Y/2,me=Math.max(r.left,Math.min(r.left+r.width-Y,Ae)),Fe=r.top+r.height+2*y;d.fillStyle="rgba(14, 14, 16, 0.92)",d.beginPath(),d.roundRect?d.roundRect(me,Fe,Y,K,3*y):d.rect(me,Fe,Y,K),d.fill(),d.strokeStyle=tt(T,.27),d.lineWidth=1*y,d.stroke(),d.fillStyle=T,d.textAlign="center",d.textBaseline="middle",d.fillText(U,me+Y/2,Fe+K/2),d.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(C,q)=>q.map(N=>{let ie=new Date(N*1e3);return`${ie.getUTCMonth()+1}/${ie.getUTCDate()}`}),font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:(C,q)=>q.map(N=>`${N.toFixed(0)} ${f}`),font:"10px system-ui, sans-serif",size:40}]},W=new Pn(D,[p,P,b],H);An.push(W);let _=O.querySelector(".chart-scroll-container");return _&&p.length*40>x&&(_.scrollLeft=_.scrollWidth-_.clientWidth),{updateRange:C=>{let q=c[c.length-1]?.timestamp||17855424e5,N=0;C==="1m"?N=q-30*24*3600*1e3:C==="2m"?N=q-60*24*3600*1e3:C==="6m"?N=q-180*24*3600*1e3:C==="1y"?N=q-365*24*3600*1e3:C==="2y"&&(N=q-2*365*24*3600*1e3);let ie=c.filter(Q=>Q.timestamp>=N),y=ie.map(Q=>Q.timestamp/1e3),d=g?ie.map(Q=>Q.distance/1e3):ie.map(Q=>Q.elevation),r=En(d,2),J=Math.max(H.clientWidth,y.length*40),U=Math.max(...d)*1.1;W.setSize({width:J,height:150}),W.setScale("y",{min:0,max:U}),W.setData([y,d,r]),_&&(_.scrollLeft=_.scrollWidth-_.clientWidth)}}}var Jn=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],Qo=16,ze={},Tt=[];function Ko(e,n){let t=new Date(e),s=new Date(n);return t.getUTCFullYear()===s.getUTCFullYear()&&t.getUTCMonth()===s.getUTCMonth()&&t.getUTCDate()===s.getUTCDate()}var Fn=!1,Oe=null,Qn=0,Gn=!1,_n=null,mn="",un=!1,vn="date-desc",Le={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};function bn(e=!1){Ye.patch({f_date:Le.date.every(n=>n===null)?null:Le.date,f_dist:Le.dist.every(n=>n===null)?null:Le.dist,f_dur:Le.dur.every(n=>n===null)?null:Le.dur,f_mets:Le.metrics.size===0?null:Array.from(Le.metrics),f_tags:Le.tags.length===0?null:Le.tags},e)}function Zs(){let e=Se.getActiveMetrics(),n=Se.METRICS,t=Array.from(e).map(s=>n[s].abbr);Ye.patch({metrics:t.length?t:null})}var io=[{label:"Newest first",val:"date-desc",icon:"calendar_today"},{label:"Oldest first",val:"date-asc",icon:"history"},{label:"Longest distance",val:"dist-desc",icon:"straighten"},{label:"Shortest distance",val:"dist-asc",icon:"horizontal_rule"},{label:"Longest duration",val:"dur-desc",icon:"timer"},{label:"Shortest duration",val:"dur-asc",icon:"timer_off"}];function ei(e){document.querySelectorAll(".sort-menu-popup").forEach(o=>o.remove());let n=document.createElement("div");n.className="sort-menu-popup",io.forEach(o=>{let a=document.createElement("div");a.className=`menu-item ${vn===o.val?"active":""}`,a.innerHTML=` + `,e.appendChild($);let M=$.querySelector(`#${t}-weekly-chart`),C=$.querySelector(`#${t}-y-axis-chart`);if(!M||!C)return;M.style.position="relative";let k=document.createElement("div");k.className="cur-y-val",k.style.cssText=`color:${x};display:none`,M.appendChild(k);let f=c.map(_=>_.timestamp/1e3),F=p?c.map(_=>_.distance/1e3):c.map(_=>_.elevation);if(f.length===0)return;let v=En(F,2),u=Math.max(0,(a||570)-20-320-20),w=Math.max(u,f.length*40),E=Math.max(...F)*1.1,N={width:w,height:150,padding:[10,10,0,10],tzDate:_=>An.tzDate(new Date(_*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,E]}},series:[{},{label:p?"Distance":"Elevation",stroke:x,fill:tt(x,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:x,width:2,dash:[5,5],points:{show:!1}}],cursor:{sync:s?{key:s.key}:void 0,drag:{x:!1,y:!1},points:{show:!1},x:!1,y:!1},hooks:{init:[_=>{_.over.addEventListener("click",()=>{let W=_.cursor.idx;if(W!=null){let z=c[W];if(z){let de=new Date(z.timestamp),y=new Date(z.timestamp+7*24*60*60*1e3),m=de.toISOString().split("T")[0],r=y.toISOString().split("T")[0];o?.(m,r)}}})}],setCursor:[_=>{if(!_._ready)return;let W=_.cursor.idx,z=_.cursor.left,de=_.cursor.top;if(W!=null&&z!=null&&de!=null&&z>=0&&de>=0){let y=_.data[1][W],m=y!=null?p?`${y.toFixed(1)} km`:`${y.toFixed(0)} m`:"\u2014";k.innerHTML=m,k.style.display="block",k.style.left=`${_.valToPos(_.data[0][W],"x",!1)}px`,k.style.top=`${_.valToPos(_.data[1][W],"y",!1)}px`,k.style.transform="translate(6px, -50%)"}else k.style.display="none";_.redraw(!1)}],draw:[_=>{let W=_.cursor.idx;if(W!=null&&_.data[0][W]!=null){let z=_.valToPos(_.data[0][W],"x",!0),de=_.valToPos(_.data[1][W],"y",!0),y=window.devicePixelRatio||1,m=_.ctx,r=_.bbox;m.save(),m.beginPath(),m.setLineDash([2*y,2*y]),m.strokeStyle=tt(x,.4),m.lineWidth=1*y,m.moveTo(z,r.top),m.lineTo(z,r.top+r.height),m.moveTo(r.left,de),m.lineTo(r.left+r.width,de),m.stroke(),m.restore(),m.save(),m.beginPath(),m.setLineDash([]),m.arc(z,de,12*y,0,2*Math.PI),m.fillStyle=tt(x,.2),m.fill(),m.restore(),m.save(),m.beginPath(),m.arc(z,de,6*y,0,2*Math.PI),m.fillStyle=x,m.fill(),m.strokeStyle="#fff",m.lineWidth=2*y,m.stroke(),m.restore(),m.save(),m.setLineDash([]);let J=new Date(_.data[0][W]*1e3),V=`${J.getUTCFullYear()}-${String(J.getUTCMonth()+1).padStart(2,"0")}-${String(J.getUTCDate()).padStart(2,"0")}`;m.font=`bold ${10*y}px system-ui, sans-serif`;let U=m.measureText(V).width+10*y,Q=16*y,ke=z-U/2,re=Math.max(r.left,Math.min(r.left+r.width-U,ke)),Fe=r.top+r.height+2*y;m.fillStyle="rgba(14, 14, 16, 0.92)",m.beginPath(),m.roundRect?m.roundRect(re,Fe,U,Q,3*y):m.rect(re,Fe,U,Q),m.fill(),m.strokeStyle=tt(x,.27),m.lineWidth=1*y,m.stroke(),m.fillStyle=x,m.textAlign="center",m.textBaseline="middle",m.fillText(V,re+U/2,Fe+Q/2),m.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(_,W)=>W.map(z=>{let de=new Date(z*1e3);return`${de.getUTCMonth()+1}/${de.getUTCDate()}`}),font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:(_,W)=>W.map(z=>`${z.toFixed(0)} ${g}`),font:"10px system-ui, sans-serif",size:40}]},G=new An(N,[f,F,v],M);In.push(G);let q=$.querySelector(".chart-scroll-container");return q&&f.length*40>w&&(q.scrollLeft=q.scrollWidth-q.clientWidth),{updateRange:_=>{let W=c[c.length-1]?.timestamp||17855424e5,z=0;_==="1m"?z=W-30*24*3600*1e3:_==="2m"?z=W-60*24*3600*1e3:_==="6m"?z=W-180*24*3600*1e3:_==="1y"?z=W-365*24*3600*1e3:_==="2y"&&(z=W-2*365*24*3600*1e3);let de=c.filter(ee=>ee.timestamp>=z),y=de.map(ee=>ee.timestamp/1e3),m=p?de.map(ee=>ee.distance/1e3):de.map(ee=>ee.elevation),r=En(m,2),J=Math.max(M.clientWidth,y.length*40),V=Math.max(...m)*1.1;G.setSize({width:J,height:150}),G.setScale("y",{min:0,max:V}),G.setData([y,m,r]),q&&(q.scrollLeft=q.scrollWidth-q.clientWidth)}}}var Qn=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],Ko=16,ze={},Tt=[];function ei(e,n){let t=new Date(e),s=new Date(n);return t.getUTCFullYear()===s.getUTCFullYear()&&t.getUTCMonth()===s.getUTCMonth()&&t.getUTCDate()===s.getUTCDate()}var Bn=!1,Oe=null,Kn=0,Xn=!1,_n=null,mn="",un=!1,vn="date-desc",Le={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};function bn(e=!1){Ye.patch({f_date:Le.date.every(n=>n===null)?null:Le.date,f_dist:Le.dist.every(n=>n===null)?null:Le.dist,f_dur:Le.dur.every(n=>n===null)?null:Le.dur,f_mets:Le.metrics.size===0?null:Array.from(Le.metrics),f_tags:Le.tags.length===0?null:Le.tags},e)}function Zs(){let e=Se.getActiveMetrics(),n=Se.METRICS,t=Array.from(e).map(s=>n[s].abbr);Ye.patch({metrics:t.length?t:null})}var lo=[{label:"Newest first",val:"date-desc",icon:"calendar_today"},{label:"Oldest first",val:"date-asc",icon:"history"},{label:"Longest distance",val:"dist-desc",icon:"straighten"},{label:"Shortest distance",val:"dist-asc",icon:"horizontal_rule"},{label:"Longest duration",val:"dur-desc",icon:"timer"},{label:"Shortest duration",val:"dur-asc",icon:"timer_off"}];function ti(e){document.querySelectorAll(".sort-menu-popup").forEach(o=>o.remove());let n=document.createElement("div");n.className="sort-menu-popup",lo.forEach(o=>{let a=document.createElement("div");a.className=`menu-item ${vn===o.val?"active":""}`,a.innerHTML=` ${o.icon} ${o.label} ${vn===o.val?"check":""} - `,a.addEventListener("click",()=>{vn=o.val,Ye.patch({sort:o.val}),ro(),xn(),n.remove()}),n.appendChild(a)});let t=e.getBoundingClientRect();n.style.top=`${t.bottom+5}px`,n.style.left=`${t.left}px`,document.body.appendChild(n);let s=o=>{!n.contains(o.target)&&!e.contains(o.target)&&(n.remove(),document.removeEventListener("click",s))};setTimeout(()=>document.addEventListener("click",s),0)}function ti(e){document.querySelectorAll(".metric-menu-popup").forEach(c=>c.remove());let n=document.createElement("div");n.className="metric-menu-popup";let t=Se.METRICS,s=Se.getAvailableMetrics(),o=Se.getActiveMetrics();Object.entries(t).forEach(([c,m])=>{if(!s.has(c))return;let T=document.createElement("div");T.className=`menu-item ${o.has(c)?"active":""}`,T.innerHTML=` - ${m.icon} - ${m.label} + `,a.addEventListener("click",()=>{vn=o.val,Ye.patch({sort:o.val}),io(),xn(),n.remove()}),n.appendChild(a)});let t=e.getBoundingClientRect();n.style.top=`${t.bottom+5}px`,n.style.left=`${t.left}px`,document.body.appendChild(n);let s=o=>{!n.contains(o.target)&&!e.contains(o.target)&&(n.remove(),document.removeEventListener("click",s))};setTimeout(()=>document.addEventListener("click",s),0)}function ni(e){document.querySelectorAll(".metric-menu-popup").forEach(c=>c.remove());let n=document.createElement("div");n.className="metric-menu-popup";let t=Se.METRICS,s=Se.getAvailableMetrics(),o=Se.getActiveMetrics();Object.entries(t).forEach(([c,d])=>{if(!s.has(c))return;let x=document.createElement("div");x.className=`menu-item ${o.has(c)?"active":""}`,x.innerHTML=` + ${d.icon} + ${d.label} ${o.has(c)?"check":""} - `,T.addEventListener("click",()=>{Se.toggleMetric(c);let f=Se.getActiveMetrics().has(c);T.classList.toggle("active",f),T.querySelector(".check").textContent=f?"check":"";let M=document.querySelector(`#metric-pills .metric-pill[data-metric="${c}"]`);M&&M.classList.toggle("active",f),Bn(),Zs()}),n.appendChild(T)});let a=e.getBoundingClientRect();n.style.top=`${a.bottom+5}px`,n.style.right=`${window.innerWidth-a.right}px`,document.body.appendChild(n);let g=c=>{!n.contains(c.target)&&!e.contains(c.target)&&(n.remove(),document.removeEventListener("click",g))};setTimeout(()=>document.addEventListener("click",g),0)}document.addEventListener("select-track",e=>{let n=e.detail.id,t=e.detail.idx,s=e.detail.dur;if(n&&ze[n]&&(Mt(n),t!=null&&s!=null)){let o=ze[n],a=o.points;if(t>=0&&tH.time!=null)?.time||0,m=(g.time-c)/1e3,T=m+s;Se.restoreSelection(m,T);let f=a.findIndex(H=>(H.time||0)>=g.time+s*1e3);f===-1&&(f=a.length-1);let M=a.slice(t,f+1),O=ot.computeStats(M);Se.setSelectionStats(O),_t(o),De.highlightSegment(n,a,t,f,!1,_n),De.ensureVisible(M.map(H=>[H.lat,H.lon])),Ye.patch({sel:[m,T]})}}}});document.addEventListener("click",e=>{let n=e.target.closest(".tab-btn");if(!n)return;let t=n.closest("#tab-nav");if(!t)return;t.querySelectorAll(".tab-btn").forEach(a=>a.classList.toggle("active",a===n));let s=n.dataset.tab;Ye.patch({tab:s},!0);let o=t.closest("#chart-panel");if(o&&o.querySelectorAll(".tab-content").forEach(a=>{a.classList.toggle("active",a.id===`tab-${n.dataset.tab}`)}),n.dataset.tab==="details"&&Oe&&ze[Oe]&&an(ze[Oe],Xs()),n.dataset.tab==="insights"&&Oe&&ze[Oe]&&_t(ze[Oe]),n.dataset.tab==="evolution"&&In(Oe?ze[Oe]:null,Object.values(ze),(a,g)=>{Mt(a,!0),g&&(Se.restoreSelection(g[0],g[1]),yn(g[0],g[1],"time",!0))},(a,g)=>{Le.date=[a,g],kt(),bn(!0),Xn()}),n.dataset.tab==="combined"&&Oe&&ze[Oe]&&dn(ze[Oe]),n.dataset.tab==="courses"&&Wt(),n.dataset.tab==="graphs"){Se.resize(),Bn();let a=Ye.get().sel;a&&Se.restoreSelection(a[0],a[1])}});async function Gs(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await at.clear(),ze={},Tt=[],Oe=null,Qn=0,_n=null,Fn=!1,Gn=!1,mn="",un=!1,vn="date-desc",Le.date=[null,null],Le.dist=[null,null],Le.dur=[null,null],Le.metrics.clear(),Le.tags=[],ot.setHRZones([120,140,160,180]),ot.setFTP(200),Hl(),Ul(),wl(),Yl(),no(),De.removeAllTracks&&De.removeAllTracks(),De.clearTracks&&De.clearTracks(),De.clearHighlight(),Se.resetState?Se.resetState():Se.clear&&Se.clear(),document.querySelectorAll(".tab-btn").forEach(n=>{n.classList.toggle("active",n.dataset.tab==="graphs")}),document.querySelectorAll(".tab-content").forEach(n=>{n.classList.toggle("active",n.id==="tab-graphs")}),Ye.reset();let e=document.getElementById("toast-container");e&&(e.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(n=>n.remove()),typeof xn=="function"&&xn()}async function ni(){let e=null,n=new Promise(p=>{e=window.setTimeout(p,1e3)});try{let p=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([p,n])}finally{e!==null&&window.clearTimeout(e)}document.body.classList.remove("loading-fonts");let t=document.getElementById("storage-backend-select");t&&(t.value=Ye.get().storage||"memory",t.addEventListener("change",p=>{let P=p.target.value,b=new URLSearchParams(window.location.search);P==="memory"?b.delete("storage"):b.set("storage",P),window.location.search=b.toString()}));let s=document.getElementById("global-loader"),o=document.getElementById("loader-text"),a=document.getElementById("loader-subtext"),g=document.getElementById("loader-progress-bar"),c=document.getElementById("map-loader"),m=c?.querySelector("span");c&&(m&&(m.textContent="Loading database..."),c.classList.remove("hidden"));let T=Ye.get();ql((p,P)=>Cs(p,P==="error"?"error":"info")),xl(()=>{kt(),bn()},p=>{ui(p)}),Il((p,P)=>Cs(p,P==="error"?"error":"info")),De.init(p=>Mt(p),ii,ai,(p,P)=>{p===Oe?Se.setHoverAt(P):Se.setHoverAt(null)},ri),Se.init(ci,yn,di,p=>{Ye.patch({sel_point:p})}),Se.setMapColorChangeCb(p=>{p?(_n=p.colors,Oe&&De.colorTrackByMetric(Oe,p.pts,p.colors)):(_n=null,Oe&&De.clearMetricColor(Oe));let P=Ye.get();P.sel&&yn(P.sel[0],P.sel[1],Se.getXAxis())}),oo(T),await at.openDB(),await Gs();try{let p=await at.get("hr_zones");p&&ot.setHRZones(p);let P=await at.get("ftp");P&&ot.setFTP(P);let b=await at.getAll();b.sort((W,_)=>W.addedAt-_.addedAt),m&&(m.textContent=`Preparing ${b.length} tracks...`);let u=[];for(let W of b){let _=!1;if(!W.bounds&&W.points.length>0){let C=hs(W.points);C&&(W.bounds=C,_=!0)}!W.simplifiedPoints&&W.points.length>0&&(W.simplifiedPoints=bs(W.points,50),_=!0),_&&await at.save(W),ze[W.id]=W,u.push(W)}De.addTracks(u),kt();let x=T.track&&b.find(W=>W.id===T.track)?T.track:b.length>0?b[0].id:null,w=document.getElementById("map-loader"),D=b.find(W=>W.id===x);if(D&&(await lo(D),Mt(D.id,!T.map_pos),T.sel&&Array.isArray(T.sel)&&T.sel.length===2&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Se.restoreSelection(T.sel[0],T.sel[1])})}),T.sel_point!==void 0&&T.sel_point!==null&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Se.setCursorAt(T.sel_point)})})),w&&w.classList.add("hidden"),b.length>(D?1:0)){w&&(m&&(m.textContent="Loading tracks..."),w.classList.remove("hidden"));let W=b.filter(q=>q.id!==x),_=0,C=async()=>{let N=Math.min(_+2,W.length);for(;_{Mt(ie,!0),y&&(Se.restoreSelection(y[0],y[1]),yn(y[0],y[1],"time",!0))}),b.length&&!T.map_pos&&De.fitAll())};requestAnimationFrame(C)}else kt(),b.length&&!T.map_pos&&De.fitAll()}catch(p){console.warn("Could not load saved tracks:",p)}li(),oi(),bi(),Bn(),document.getElementById("basemap-switcher")?.addEventListener("click",p=>{let P=p.target.closest(".bm-btn");P&&(document.querySelectorAll(".bm-btn").forEach(b=>b.classList.remove("active")),P.classList.add("active"),P.dataset.layer&&(De.switchBasemap(P.dataset.layer),Ye.patch({map:P.dataset.layer})))}),document.getElementById("btn-fit-all")?.addEventListener("click",()=>De.fitAll()),document.getElementById("btn-clear-all")?.addEventListener("click",mi),document.getElementById("track-search")?.addEventListener("input",p=>{mn=p.target.value,kt(),Ye.patch({q:mn||null})}),document.getElementById("btn-regex-toggle")?.addEventListener("click",p=>{un=!un,p.target.classList.toggle("active",un),kt(),Ye.patch({re:un?1:null})}),document.getElementById("btn-sort-menu")?.addEventListener("click",p=>{p.stopPropagation(),ei(p.currentTarget)}),document.getElementById("btn-metric-menu")?.addEventListener("click",p=>{p.stopPropagation(),ti(p.currentTarget)});let f=(p,P)=>{P&&P.classList.toggle("active"),Se.toggleMetric(p),Zs()};document.getElementById("metric-pills")?.addEventListener("click",p=>{let P=p.target.closest(".metric-pill");if(P){let b=P.dataset.metric;b&&(f(b,P),Se.getActiveMetrics().has(b)&&document.querySelector(`.chart-row[data-metric="${b}"]`)?.scrollIntoView({behavior:"smooth"}))}}),document.getElementById("x-axis-ctrl")?.addEventListener("click",p=>{let P=p.target.closest(".seg-btn");if(!P)return;let b=P.dataset.axis;Se.setXAxis(b),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(u=>u.classList.toggle("active",u===P)),Ye.patch({xaxis:b})}),document.getElementById("btn-follow-dot")?.addEventListener("click",p=>{Gn=!Gn,p.currentTarget.classList.toggle("active",Gn)}),document.getElementById("btn-reset-zoom")?.addEventListener("click",()=>{Se.resetZoom(),De.clearHighlight()}),hi(),document.getElementById("file-input")?.addEventListener("change",p=>{$s(Array.from(p.target.files||[])),p.target.value=""}),document.getElementById("folder-input")?.addEventListener("change",p=>{$s(Array.from(p.target.files||[])),p.target.value=""}),document.getElementById("btn-toggle-filters")?.addEventListener("click",()=>{let p=document.getElementById("filter-panel");p&&(p.classList.toggle("hidden"),document.getElementById("btn-toggle-filters")?.classList.toggle("active",!p.classList.contains("hidden")))});let M=(p,P,b)=>{let u=b.target.value;Le[p][P]=u===""?null:u,kt(),bn()};document.getElementById("filter-date-start")?.addEventListener("change",p=>M("date",0,p)),document.getElementById("filter-date-end")?.addEventListener("change",p=>M("date",1,p)),document.getElementById("filter-dist-min")?.addEventListener("input",p=>M("dist",0,p)),document.getElementById("filter-dist-max")?.addEventListener("input",p=>M("dist",1,p)),document.getElementById("filter-dur-min")?.addEventListener("input",p=>M("dur",0,p)),document.getElementById("filter-dur-max")?.addEventListener("input",p=>M("dur",1,p));let O=document.getElementById("sport-burger-btn"),H=document.getElementById("sport-dropdown-content");O?.addEventListener("click",p=>{if(p.stopPropagation(),H){let P=H.style.display==="block";H.style.display=P?"none":"block"}}),document.addEventListener("click",p=>{H&&H.style.display==="block"&&!H.contains(p.target)&&p.target!==O&&(H.style.display="none")}),document.getElementById("sport-filter-container")?.addEventListener("click",p=>{let P=p.target,b=P.closest("[data-sport]");if(b){let u=b.dataset.sport||null;Le.sport=Le.sport===u?null:u,kt(),bn(),Xn(),P.closest(".dropdown-item")&&H&&(H.style.display="none")}}),document.getElementById("filter-metrics")?.addEventListener("click",p=>{let P=p.target.closest(".mini-pill");if(!P)return;let b=P.dataset.metric;Le.metrics.has(b)?Le.metrics.delete(b):Le.metrics.add(b),Xn(),kt(),bn()}),document.getElementById("btn-reset-filters")?.addEventListener("click",()=>{Le={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},Xn(),kt(),bn()}),document.getElementById("filter-tags")?.addEventListener("input",p=>{let P=p.target.value;Le.tags=P.split(",").map(b=>b.trim().toLowerCase()).filter(b=>!!b),kt(),bn()}),document.addEventListener("keydown",p=>{p.key==="Escape"&&(De.hideCursor(),De.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(P=>P.remove()))}),window.addEventListener("resize",()=>{Se.resize(),Yn(),De.invalidateSize?.(),Bn()}),window.addEventListener("popstate",()=>{Ye.refresh(),oo(Ye.get())}),si(),await ao();let E=document.createElement("div");E.id="app-is-ready",E.setAttribute("data-ready","true"),E.style.display="none",document.body.appendChild(E);let k=document.createElement("div");k.id="appIsReady",k.setAttribute("data-ready","true"),k.style.display="none",document.body.appendChild(k)}var Hn=null;async function ao(){if(Hn)return Hn;try{let n=await(await fetch("./test-data/manifest.json")).json(),t=new TextDecoder;Hn=await Promise.all(n.map(async o=>{let g=await(await fetch(`./test-data/${o}`)).arrayBuffer(),c=o;if(o.toLowerCase().endsWith(".gz")){c=o.slice(0,-3);let f=new Uint8Array(g);if(f.length>=2&&f[0]===31&&f[1]===139){let M=new DecompressionStream("gzip"),O=new Blob([g]).stream().pipeThrough(M);g=await new Response(O).arrayBuffer()}}let m=c.toLowerCase().endsWith(".fit")?void 0:t.decode(g),T=new File([g],c,{type:"application/octet-stream"});return T._buf=g,m!==void 0&&(T._text=m),{cleanName:c,buf:g,text:m,file:T}}));let s=null;for(let o of[0,2,4])if(Hn[o]){let a=await ot.parseFile(Hn[o].file);o===0&&(s=a)}if(s){let o=s.points.slice(0,1250),a={...s,id:"warmup",fileName:"warmup.gpx",fileSize:1024,points:o,bounds:hs(o)||void 0,simplifiedPoints:bs(o,50),stats:ot.computeStats(o),addedAt:17855424e5,visible:!0,color:Jn[0]},g={...a,id:"warmup-2",fileName:"warmup2.gpx",addedAt:17856288e5,color:Jn[1]},c=[a,g];ot.ensureCurvesAndZones(a),ot.ensureCurvesAndZones(g),De.addTracks(c),Se.loadTrack(a,c,!1),Se.restoreSelection(10,50,!0),Se.setCursorAt(25,!0),Se.setActiveMetrics(["elevation","speed","power"]),Se.analyzeTelemetryIntervals(c,10,50),_t(a,c),an(a,[],c),dn(c,c),In(a,c),Bs(c),Ln("course-1",!0),await Gs(),document.body.offsetHeight,await new Promise(m=>window.setTimeout(m,0))}else typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();return Hn}catch{return[]}}function si(){let e=document.getElementById("btn-step-load"),n=document.getElementById("btn-step-analysis"),t=document.getElementById("btn-step-insights"),s=document.getElementById("btn-step-details"),o=document.getElementById("btn-step-aggregate"),a=document.getElementById("btn-step-evolution"),g=document.getElementById("btn-step-courses");function c(m){document.querySelectorAll(".tab-btn").forEach(T=>{T.classList.toggle("active",T.dataset.tab===m)}),document.querySelectorAll(".tab-content").forEach(T=>{T.classList.toggle("active",T.id===`tab-${m}`)}),Ye.patch({tab:m},!1)}e?.addEventListener("click",async()=>{try{Object.keys(ze).length>0||Tt.length>0||Oe!==null?(await at.openDB(),await Gs()):typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();let T=(await ao()).map(M=>M.file);await $s(T);let f=Object.values(ze);!Oe&&f.length>0&&Mt(f[0].id)}finally{window.dispatchEvent(new CustomEvent("load-and-parse-complete"))}}),n?.addEventListener("click",()=>{try{let m=Object.values(ze);c("graphs"),!Oe&&m.length>0&&Mt(m[0].id),Se.restoreSelection(120,900,!0),Se.setCursorAt(300,!0);let T=Se.getAvailableMetrics(),f=["elevation","speed","power"].filter(M=>T.has(M));f.length>0?(document.querySelectorAll("#metric-pills .metric-pill").forEach(M=>{let O=M.dataset.metric;O&&M.classList.toggle("active",f.includes(O))}),Bn(),Se.setActiveMetrics(f)):Bn(),Se.analyzeTelemetryIntervals(m,120,900),yn(120,900,Se.getXAxis(),!1)}finally{window.dispatchEvent(new CustomEvent("analysis-complete"))}}),t?.addEventListener("click",()=>{try{let m=Object.values(ze);m.forEach(f=>ot.ensureCurvesAndZones(f)),c("insights");let T=Oe&&ze[Oe]||m[0]||null;_t(T,m)}finally{window.dispatchEvent(new CustomEvent("insights-complete"))}}),s?.addEventListener("click",()=>{try{let m=Object.values(ze);c("details");let T=Oe&&ze[Oe]||m[0]||null;an(T,Xs(),m)}finally{window.dispatchEvent(new CustomEvent("details-complete"))}}),o?.addEventListener("click",()=>{try{let m=Object.values(ze);if(m.length>=2){let T=[m[0],m[1]];c("combined"),dn(T,m)}}finally{window.dispatchEvent(new CustomEvent("aggregate-complete"))}}),a?.addEventListener("click",()=>{try{let m=Object.values(ze);c("evolution");let T=Oe&&ze[Oe]||m[0]||null;In(T,m,(f,M)=>{Mt(f,!0),M&&(Se.restoreSelection(M[0],M[1]),yn(M[0],M[1],"time",!0))})}finally{window.dispatchEvent(new CustomEvent("evolution-complete"))}}),g?.addEventListener("click",()=>{try{let m=Object.values(ze);c("courses"),Bs(m),Ln("course-1",!0)}finally{window.dispatchEvent(new CustomEvent("courses-complete"))}}),window.benchmarkSteps={loadAndParseFiles:()=>document.getElementById("btn-step-load")?.click(),displayAnalysisMetrics:()=>document.getElementById("btn-step-analysis")?.click(),displayInsights:()=>document.getElementById("btn-step-insights")?.click(),displayDetails:()=>document.getElementById("btn-step-details")?.click(),displayAggregateMetrics:()=>document.getElementById("btn-step-aggregate")?.click(),displayEvolutionMetrics:()=>document.getElementById("btn-step-evolution")?.click(),displayCourses:()=>document.getElementById("btn-step-courses")?.click()}}async function lo(e){let n=e.stats.powerCurve?Object.values(e.stats.powerCurve):[],t=e.points.length>1&&(e.points[1].speed===void 0||e.points[1].gradient===void 0);(t||!e.stats.powerCurve||!e.stats.hrZones||!e.stats.hrCurve||e.stats.shifts===void 0||e.stats.avgBattery===void 0||e.stats.avgTemp===void 0||n.length>0&&typeof n[0]=="number"||(e.stats.duration||0)>10800*1e3&&e.stats.powerCurve&&!e.stats.powerCurve[14400])&&(t&&(e.points=ot.enrichPoints(e.points)),e.stats=ot.computeStats(e.points),await at.save(e)),ze[e.id]=e,Qn=Math.max(Qn,Jn.indexOf(e.color)+1),De.addTrack(e),De.setTrackVisible(e.id,e.visible&&!e._filtered),xn()}function li(){let e=document.getElementById("resize-handle"),n=document.getElementById("chart-panel");if(!e||!n)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,document.body.style.cursor="ns-resize"}),document.addEventListener("mousemove",s=>{if(!t)return;let o=window.innerHeight-s.clientY,a=Math.max(100,Math.min(window.innerHeight-100,o));n.style.height=`${a}px`,Se.resize(),Yn(),De.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,document.body.style.cursor="")})}function oi(){let e=document.getElementById("sidebar-resizer"),n=document.getElementById("sidebar");if(!e||!n)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,e.classList.add("dragging"),document.body.classList.add("dragging-sidebar")}),document.addEventListener("mousemove",s=>{if(!t)return;let o=s.clientX,a=Math.max(200,Math.min(600,o));n.style.width=`${a}px`,n.style.setProperty("--sidebar-w",`${a}px`),Se.resize(),De.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,e.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}function ii(e,n,t){Ye.patch({map_pos:[e,n,t]})}function ai(e,n){Mt(e,!1),Se.setCursorAt(n)}function ri(){}function ci(e){e&&e.lat!=null&&e.lon!=null?(De.showCursorAt(e.lat,e.lon),Gn&&De.centerOn(e.lat,e.lon,null,!0)):De.hideCursor()}function yn(e,n,t,s=!1){if(!Oe||!ze[Oe])return;let o=ze[Oe];if(e===null||n===null){De.clearHighlight(),o&&(Ye.get().tab||"graphs")==="insights"&&_t(o),Ye.patch({sel:null});return}let a=o.points,g=0,c=a.length-1;if(t==="distance"){let f=e*1e3,M=n*1e3;g=a.findIndex(O=>(O.dist||0)>=f),c=a.findIndex(O=>(O.dist||0)>=M)}else{let f=a.find(H=>H.time!=null)?.time||0,M=f+e*1e3,O=f+n*1e3;g=a.findIndex(H=>(H.time||0)>=M),c=a.findIndex(H=>(H.time||0)>=O)}g===-1&&(g=0),c===-1&&(c=a.length-1);let m=a.slice(g,c+1),T=ot.computeStats(m);Se.setSelectionStats(T),(Ye.get().tab||"graphs")==="insights"&&_t(o),De.highlightSegment(Oe,a,g,c,s,_n),De.ensureVisible(m.map(f=>[f.lat,f.lon])),Ye.patch({sel:[e,n]})}function di(e,n){e&&e.lat!=null&&e.lon!=null&&De.centerOn(e.lat,e.lon,Qo)}function Mt(e,n=!0,t=!1){if(!ze[e])return;if(e===Oe){n&&De.fitTrack(e);return}let s=Oe!==null;s&&(Se.clear(),an(null,[]),_t(null)),Oe=e,_n=null,De.clearMetricColor(e),s&&Se.toggleMapColor(null),Ye.patch({track:e,sel:null},!0),s&&Se.cancelSelection(),xn();let o=Ye.get().tab||"graphs";o==="details"&&an(ze[e],Xs()),o==="insights"&&_t(ze[e]),o==="combined"&&dn(ze[e]),o==="courses"&&Wt(),o==="evolution"&&In(ze[e],Object.values(ze),(a,g)=>{Mt(a,!0),g&&(Se.restoreSelection(g[0],g[1]),yn(g[0],g[1],"time",!0))}),De.setSelectedTrack(e,n),n&&De.fitTrack(e),Se.loadTrack(ze[e],Object.values(ze),t)}async function ui(e){await at.remove(e),De.removeTrack(e),delete ze[e],Oe===e&&(Oe=null,Se.clear(),an(null,[]),_t(null),Ye.patch({track:null,sel:null,sel_point:null})),kt()}async function mi(){let e=Math.floor(10+Math.random()*90).toString(),n=document.createElement("div");n.className="modal-backdrop",n.innerHTML=` + `,x.addEventListener("click",()=>{Se.toggleMetric(c);let g=Se.getActiveMetrics().has(c);x.classList.toggle("active",g),x.querySelector(".check").textContent=g?"check":"";let T=document.querySelector(`#metric-pills .metric-pill[data-metric="${c}"]`);T&&T.classList.toggle("active",g),Dn(),Zs()}),n.appendChild(x)});let a=e.getBoundingClientRect();n.style.top=`${a.bottom+5}px`,n.style.right=`${window.innerWidth-a.right}px`,document.body.appendChild(n);let p=c=>{!n.contains(c.target)&&!e.contains(c.target)&&(n.remove(),document.removeEventListener("click",p))};setTimeout(()=>document.addEventListener("click",p),0)}document.addEventListener("select-track",e=>{let n=e.detail.id,t=e.detail.idx,s=e.detail.dur;if(n&&ze[n]&&(Mt(n),t!=null&&s!=null)){let o=ze[n],a=o.points;if(t>=0&&tM.time!=null)?.time||0,d=(p.time-c)/1e3,x=d+s;Se.restoreSelection(d,x);let g=a.findIndex(M=>(M.time||0)>=p.time+s*1e3);g===-1&&(g=a.length-1);let T=a.slice(t,g+1),$=ot.computeStats(T);Se.setSelectionStats($),Bt(o),De.highlightSegment(n,a,t,g,!1,_n),De.ensureVisible(T.map(M=>[M.lat,M.lon])),Ye.patch({sel:[d,x]})}}}});document.addEventListener("click",e=>{let n=e.target.closest(".tab-btn");if(!n)return;let t=n.closest("#tab-nav");if(!t)return;t.querySelectorAll(".tab-btn").forEach(a=>a.classList.toggle("active",a===n));let s=n.dataset.tab;Ye.patch({tab:s},!0);let o=t.closest("#chart-panel");if(o&&o.querySelectorAll(".tab-content").forEach(a=>{a.classList.toggle("active",a.id===`tab-${n.dataset.tab}`)}),n.dataset.tab==="details"&&Oe&&ze[Oe]&&an(ze[Oe],Xs()),n.dataset.tab==="insights"&&Oe&&ze[Oe]&&Bt(ze[Oe]),n.dataset.tab==="evolution"&&Hn(Oe?ze[Oe]:null,Object.values(ze),(a,p)=>{Mt(a,!0),p&&(Se.restoreSelection(p[0],p[1]),yn(p[0],p[1],"time",!0))},(a,p)=>{Le.date=[a,p],kt(),bn(!0),Jn()}),n.dataset.tab==="combined"&&Oe&&ze[Oe]&&dn(ze[Oe]),n.dataset.tab==="courses"&&Wt(),n.dataset.tab==="graphs"){Se.resize(),Dn();let a=Ye.get().sel;a&&Se.restoreSelection(a[0],a[1])}});async function Gs(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await at.clear(),ze={},Tt=[],Oe=null,Kn=0,_n=null,Bn=!1,Xn=!1,mn="",un=!1,vn="date-desc",Le.date=[null,null],Le.dist=[null,null],Le.dur=[null,null],Le.metrics.clear(),Le.tags=[],ot.setHRZones([120,140,160,180]),ot.setFTP(200),Hl(),Ul(),wl(),Yl(),eo(),De.removeAllTracks&&De.removeAllTracks(),De.clearTracks&&De.clearTracks(),De.clearHighlight(),Se.resetState?Se.resetState():Se.clear&&Se.clear(),document.querySelectorAll(".tab-btn").forEach(n=>{n.classList.toggle("active",n.dataset.tab==="graphs")}),document.querySelectorAll(".tab-content").forEach(n=>{n.classList.toggle("active",n.id==="tab-graphs")}),Ye.reset();let e=document.getElementById("toast-container");e&&(e.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(n=>n.remove()),typeof xn=="function"&&xn()}async function si(){let e=null,n=new Promise(f=>{e=window.setTimeout(f,1e3)});try{let f=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([f,n])}finally{e!==null&&window.clearTimeout(e)}document.body.classList.remove("loading-fonts");let t=document.getElementById("storage-backend-select");t&&(t.value=Ye.get().storage||"memory",t.addEventListener("change",f=>{let F=f.target.value,v=new URLSearchParams(window.location.search);F==="memory"?v.delete("storage"):v.set("storage",F),window.location.search=v.toString()}));let s=document.getElementById("global-loader"),o=document.getElementById("loader-text"),a=document.getElementById("loader-subtext"),p=document.getElementById("loader-progress-bar"),c=document.getElementById("map-loader"),d=c?.querySelector("span");c&&(d&&(d.textContent="Loading database..."),c.classList.remove("hidden"));let x=Ye.get();ql((f,F)=>ks(f,F==="error"?"error":"info")),xl(()=>{kt(),bn()},f=>{mi(f)}),Il((f,F)=>ks(f,F==="error"?"error":"info")),De.init(f=>Mt(f),ai,ri,(f,F)=>{f===Oe?Se.setHoverAt(F):Se.setHoverAt(null)},ci),Se.init(di,yn,ui,f=>{Ye.patch({sel_point:f})}),Se.setMapColorChangeCb(f=>{f?(_n=f.colors,Oe&&De.colorTrackByMetric(Oe,f.pts,f.colors)):(_n=null,Oe&&De.clearMetricColor(Oe));let F=Ye.get();F.sel&&yn(F.sel[0],F.sel[1],Se.getXAxis())}),so(x),await at.openDB(),await Gs();try{let f=await at.get("hr_zones");f&&ot.setHRZones(f);let F=await at.get("ftp");F&&ot.setFTP(F);let v=await at.getAll();v.sort((G,q)=>G.addedAt-q.addedAt),d&&(d.textContent=`Preparing ${v.length} tracks...`);let u=[];for(let G of v){let q=!1;if(!G.bounds&&G.points.length>0){let _=bs(G.points);_&&(G.bounds=_,q=!0)}!G.simplifiedPoints&&G.points.length>0&&(G.simplifiedPoints=vs(G.points,50),q=!0),q&&await at.save(G),ze[G.id]=G,u.push(G)}De.addTracks(u),kt();let w=x.track&&v.find(G=>G.id===x.track)?x.track:v.length>0?v[0].id:null,E=document.getElementById("map-loader"),N=v.find(G=>G.id===w);if(N&&(await no(N),Mt(N.id,!x.map_pos),x.sel&&Array.isArray(x.sel)&&x.sel.length===2&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Se.restoreSelection(x.sel[0],x.sel[1])})}),x.sel_point!==void 0&&x.sel_point!==null&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Se.setCursorAt(x.sel_point)})})),E&&E.classList.add("hidden"),v.length>(N?1:0)){E&&(d&&(d.textContent="Loading tracks..."),E.classList.remove("hidden"));let G=v.filter(W=>W.id!==w),q=0,_=async()=>{let z=Math.min(q+2,G.length);for(;q{Mt(de,!0),y&&(Se.restoreSelection(y[0],y[1]),yn(y[0],y[1],"time",!0))}),v.length&&!x.map_pos&&De.fitAll())};requestAnimationFrame(_)}else kt(),v.length&&!x.map_pos&&De.fitAll()}catch(f){console.warn("Could not load saved tracks:",f)}oi(),ii(),vi(),Dn(),document.getElementById("basemap-switcher")?.addEventListener("click",f=>{let F=f.target.closest(".bm-btn");F&&(document.querySelectorAll(".bm-btn").forEach(v=>v.classList.remove("active")),F.classList.add("active"),F.dataset.layer&&(De.switchBasemap(F.dataset.layer),Ye.patch({map:F.dataset.layer})))}),document.getElementById("btn-fit-all")?.addEventListener("click",()=>De.fitAll()),document.getElementById("btn-clear-all")?.addEventListener("click",pi),document.getElementById("track-search")?.addEventListener("input",f=>{mn=f.target.value,kt(),Ye.patch({q:mn||null})}),document.getElementById("btn-regex-toggle")?.addEventListener("click",f=>{un=!un,f.target.classList.toggle("active",un),kt(),Ye.patch({re:un?1:null})}),document.getElementById("btn-sort-menu")?.addEventListener("click",f=>{f.stopPropagation(),ti(f.currentTarget)}),document.getElementById("btn-metric-menu")?.addEventListener("click",f=>{f.stopPropagation(),ni(f.currentTarget)});let g=(f,F)=>{F&&F.classList.toggle("active"),Se.toggleMetric(f),Zs()};document.getElementById("metric-pills")?.addEventListener("click",f=>{let F=f.target.closest(".metric-pill");if(F){let v=F.dataset.metric;v&&(g(v,F),Se.getActiveMetrics().has(v)&&document.querySelector(`.chart-row[data-metric="${v}"]`)?.scrollIntoView({behavior:"smooth"}))}}),document.getElementById("x-axis-ctrl")?.addEventListener("click",f=>{let F=f.target.closest(".seg-btn");if(!F)return;let v=F.dataset.axis;Se.setXAxis(v),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(u=>u.classList.toggle("active",u===F)),Ye.patch({xaxis:v})}),document.getElementById("btn-follow-dot")?.addEventListener("click",f=>{Xn=!Xn,f.currentTarget.classList.toggle("active",Xn)}),document.getElementById("btn-reset-zoom")?.addEventListener("click",()=>{Se.resetZoom(),De.clearHighlight()}),bi(),document.getElementById("file-input")?.addEventListener("change",f=>{Cs(Array.from(f.target.files||[])),f.target.value=""}),document.getElementById("folder-input")?.addEventListener("change",f=>{Cs(Array.from(f.target.files||[])),f.target.value=""}),document.getElementById("btn-toggle-filters")?.addEventListener("click",()=>{let f=document.getElementById("filter-panel");f&&(f.classList.toggle("hidden"),document.getElementById("btn-toggle-filters")?.classList.toggle("active",!f.classList.contains("hidden")))});let T=(f,F,v)=>{let u=v.target.value;Le[f][F]=u===""?null:u,kt(),bn()};document.getElementById("filter-date-start")?.addEventListener("change",f=>T("date",0,f)),document.getElementById("filter-date-end")?.addEventListener("change",f=>T("date",1,f)),document.getElementById("filter-dist-min")?.addEventListener("input",f=>T("dist",0,f)),document.getElementById("filter-dist-max")?.addEventListener("input",f=>T("dist",1,f)),document.getElementById("filter-dur-min")?.addEventListener("input",f=>T("dur",0,f)),document.getElementById("filter-dur-max")?.addEventListener("input",f=>T("dur",1,f));let $=document.getElementById("sport-burger-btn"),M=document.getElementById("sport-dropdown-content");$?.addEventListener("click",f=>{if(f.stopPropagation(),M){let F=M.style.display==="block";M.style.display=F?"none":"block"}}),document.addEventListener("click",f=>{M&&M.style.display==="block"&&!M.contains(f.target)&&f.target!==$&&(M.style.display="none")}),document.getElementById("sport-filter-container")?.addEventListener("click",f=>{let F=f.target,v=F.closest("[data-sport]");if(v){let u=v.dataset.sport||null;Le.sport=Le.sport===u?null:u,kt(),bn(),Jn(),F.closest(".dropdown-item")&&M&&(M.style.display="none")}}),document.getElementById("filter-metrics")?.addEventListener("click",f=>{let F=f.target.closest(".mini-pill");if(!F)return;let v=F.dataset.metric;Le.metrics.has(v)?Le.metrics.delete(v):Le.metrics.add(v),Jn(),kt(),bn()}),document.getElementById("btn-reset-filters")?.addEventListener("click",()=>{Le={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},Jn(),kt(),bn()}),document.getElementById("filter-tags")?.addEventListener("input",f=>{let F=f.target.value;Le.tags=F.split(",").map(v=>v.trim().toLowerCase()).filter(v=>!!v),kt(),bn()}),document.addEventListener("keydown",f=>{f.key==="Escape"&&(De.hideCursor(),De.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(F=>F.remove()))}),window.addEventListener("resize",()=>{Se.resize(),Zn(),De.invalidateSize?.(),Dn()}),window.addEventListener("popstate",()=>{Ye.refresh(),so(Ye.get())}),li(),await oo();let C=document.createElement("div");C.id="app-is-ready",C.setAttribute("data-ready","true"),C.style.display="none",document.body.appendChild(C);let k=document.createElement("div");k.id="appIsReady",k.setAttribute("data-ready","true"),k.style.display="none",document.body.appendChild(k)}var Fn=null;async function oo(){if(Fn)return Fn;try{let n=await(await fetch("./test-data/manifest.json")).json(),t=new TextDecoder;Fn=await Promise.all(n.map(async o=>{let p=await(await fetch(`./test-data/${o}`)).arrayBuffer(),c=o;if(o.toLowerCase().endsWith(".gz")){c=o.slice(0,-3);let g=new Uint8Array(p);if(g.length>=2&&g[0]===31&&g[1]===139){let T=new DecompressionStream("gzip"),$=new Blob([p]).stream().pipeThrough(T);p=await new Response($).arrayBuffer()}}let d=c.toLowerCase().endsWith(".fit")?void 0:t.decode(p),x=new File([p],c,{type:"application/octet-stream"});return x._buf=p,d!==void 0&&(x._text=d),{cleanName:c,buf:p,text:d,file:x}}));let s=null;for(let o of[0,2,4])if(Fn[o]){let a=await ot.parseFile(Fn[o].file);o===0&&(s=a)}if(s){let o=s.points.slice(0,1250),a={...s,id:"warmup",fileName:"warmup.gpx",fileSize:1024,points:o,bounds:bs(o)||void 0,simplifiedPoints:vs(o,50),stats:ot.computeStats(o),addedAt:17855424e5,visible:!0,color:Qn[0]},p={...a,id:"warmup-2",fileName:"warmup2.gpx",addedAt:17856288e5,color:Qn[1]},c=[a,p];ot.ensureCurvesAndZones(a),ot.ensureCurvesAndZones(p),De.addTracks(c),Se.loadTrack(a,c,!1),Se.restoreSelection(10,50,!0),Se.setCursorAt(25,!0),Se.setActiveMetrics(["elevation","speed","power"]),Se.analyzeTelemetryIntervals(c,10,50),Bt(a,c),an(a,[],c),dn(c,c),Hn(a,c),Bs(c),Ln("course-1",!0),await Gs(),document.body.offsetHeight,await new Promise(d=>window.setTimeout(d,0))}else typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();return Fn}catch{return[]}}function li(){let e=document.getElementById("btn-step-load"),n=document.getElementById("btn-step-analysis"),t=document.getElementById("btn-step-insights"),s=document.getElementById("btn-step-details"),o=document.getElementById("btn-step-aggregate"),a=document.getElementById("btn-step-evolution"),p=document.getElementById("btn-step-courses");function c(d){document.querySelectorAll(".tab-btn").forEach(x=>{x.classList.toggle("active",x.dataset.tab===d)}),document.querySelectorAll(".tab-content").forEach(x=>{x.classList.toggle("active",x.id===`tab-${d}`)}),Ye.patch({tab:d},!1)}e?.addEventListener("click",async()=>{try{Object.keys(ze).length>0||Tt.length>0||Oe!==null?(await at.openDB(),await Gs()):typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();let x=(await oo()).map(T=>T.file);await Cs(x);let g=Object.values(ze);!Oe&&g.length>0&&Mt(g[0].id)}finally{window.dispatchEvent(new CustomEvent("load-and-parse-complete"))}}),n?.addEventListener("click",()=>{try{let d=Object.values(ze);c("graphs"),!Oe&&d.length>0&&Mt(d[0].id),Se.restoreSelection(120,900,!0),Se.setCursorAt(300,!0);let x=Se.getAvailableMetrics(),g=["elevation","speed","power"].filter(T=>x.has(T));g.length>0?(document.querySelectorAll("#metric-pills .metric-pill").forEach(T=>{let $=T.dataset.metric;$&&T.classList.toggle("active",g.includes($))}),Dn(),Se.setActiveMetrics(g)):Dn(),Se.analyzeTelemetryIntervals(d,120,900),yn(120,900,Se.getXAxis(),!1)}finally{window.dispatchEvent(new CustomEvent("analysis-complete"))}}),t?.addEventListener("click",()=>{try{let d=Object.values(ze);d.forEach(g=>ot.ensureCurvesAndZones(g)),c("insights");let x=Oe&&ze[Oe]||d[0]||null;Bt(x,d)}finally{window.dispatchEvent(new CustomEvent("insights-complete"))}}),s?.addEventListener("click",()=>{try{let d=Object.values(ze);c("details");let x=Oe&&ze[Oe]||d[0]||null;an(x,Xs(),d)}finally{window.dispatchEvent(new CustomEvent("details-complete"))}}),o?.addEventListener("click",()=>{try{let d=Object.values(ze);if(d.length>=2){let x=[d[0],d[1]];c("combined"),dn(x,d)}}finally{window.dispatchEvent(new CustomEvent("aggregate-complete"))}}),a?.addEventListener("click",()=>{try{let d=Object.values(ze);c("evolution");let x=Oe&&ze[Oe]||d[0]||null;Hn(x,d,(g,T)=>{Mt(g,!0),T&&(Se.restoreSelection(T[0],T[1]),yn(T[0],T[1],"time",!0))})}finally{window.dispatchEvent(new CustomEvent("evolution-complete"))}}),p?.addEventListener("click",()=>{try{let d=Object.values(ze);c("courses"),Bs(d),Ln("course-1",!0)}finally{window.dispatchEvent(new CustomEvent("courses-complete"))}}),window.benchmarkSteps={loadAndParseFiles:()=>document.getElementById("btn-step-load")?.click(),displayAnalysisMetrics:()=>document.getElementById("btn-step-analysis")?.click(),displayInsights:()=>document.getElementById("btn-step-insights")?.click(),displayDetails:()=>document.getElementById("btn-step-details")?.click(),displayAggregateMetrics:()=>document.getElementById("btn-step-aggregate")?.click(),displayEvolutionMetrics:()=>document.getElementById("btn-step-evolution")?.click(),displayCourses:()=>document.getElementById("btn-step-courses")?.click()}}async function no(e){let n=e.stats.powerCurve?Object.values(e.stats.powerCurve):[],t=e.points.length>1&&(e.points[1].speed===void 0||e.points[1].gradient===void 0);(t||!e.stats.powerCurve||!e.stats.hrZones||!e.stats.hrCurve||e.stats.shifts===void 0||e.stats.avgBattery===void 0||e.stats.avgTemp===void 0||n.length>0&&typeof n[0]=="number"||(e.stats.duration||0)>10800*1e3&&e.stats.powerCurve&&!e.stats.powerCurve[14400])&&(t&&(e.points=ot.enrichPoints(e.points)),e.stats=ot.computeStats(e.points),await at.save(e)),ze[e.id]=e,Kn=Math.max(Kn,Qn.indexOf(e.color)+1),De.addTrack(e),De.setTrackVisible(e.id,e.visible&&!e._filtered),xn()}function oi(){let e=document.getElementById("resize-handle"),n=document.getElementById("chart-panel");if(!e||!n)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,document.body.style.cursor="ns-resize"}),document.addEventListener("mousemove",s=>{if(!t)return;let o=window.innerHeight-s.clientY,a=Math.max(100,Math.min(window.innerHeight-100,o));n.style.height=`${a}px`,Se.resize(),Zn(),De.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,document.body.style.cursor="")})}function ii(){let e=document.getElementById("sidebar-resizer"),n=document.getElementById("sidebar");if(!e||!n)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,e.classList.add("dragging"),document.body.classList.add("dragging-sidebar")}),document.addEventListener("mousemove",s=>{if(!t)return;let o=s.clientX,a=Math.max(200,Math.min(600,o));n.style.width=`${a}px`,n.style.setProperty("--sidebar-w",`${a}px`),Se.resize(),De.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,e.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}function ai(e,n,t){Ye.patch({map_pos:[e,n,t]})}function ri(e,n){Mt(e,!1),Se.setCursorAt(n)}function ci(){}function di(e){e&&e.lat!=null&&e.lon!=null?(De.showCursorAt(e.lat,e.lon),Xn&&De.centerOn(e.lat,e.lon,null,!0)):De.hideCursor()}function yn(e,n,t,s=!1){if(!Oe||!ze[Oe])return;let o=ze[Oe];if(e===null||n===null){De.clearHighlight(),o&&(Ye.get().tab||"graphs")==="insights"&&Bt(o),Ye.patch({sel:null});return}let a=o.points,p=0,c=a.length-1;if(t==="distance"){let g=e*1e3,T=n*1e3;p=a.findIndex($=>($.dist||0)>=g),c=a.findIndex($=>($.dist||0)>=T)}else{let g=a.find(M=>M.time!=null)?.time||0,T=g+e*1e3,$=g+n*1e3;p=a.findIndex(M=>(M.time||0)>=T),c=a.findIndex(M=>(M.time||0)>=$)}p===-1&&(p=0),c===-1&&(c=a.length-1);let d=a.slice(p,c+1),x=ot.computeStats(d);Se.setSelectionStats(x),(Ye.get().tab||"graphs")==="insights"&&Bt(o),De.highlightSegment(Oe,a,p,c,s,_n),De.ensureVisible(d.map(g=>[g.lat,g.lon])),Ye.patch({sel:[e,n]})}function ui(e,n){e&&e.lat!=null&&e.lon!=null&&De.centerOn(e.lat,e.lon,Ko)}function Mt(e,n=!0,t=!1){if(!ze[e])return;if(e===Oe){n&&De.fitTrack(e);return}let s=Oe!==null;s&&(Se.clear(),an(null,[]),Bt(null)),Oe=e,_n=null,De.clearMetricColor(e),s&&Se.toggleMapColor(null),Ye.patch({track:e,sel:null},!0),s&&Se.cancelSelection(),xn();let o=Ye.get().tab||"graphs";o==="details"&&an(ze[e],Xs()),o==="insights"&&Bt(ze[e]),o==="combined"&&dn(ze[e]),o==="courses"&&Wt(),o==="evolution"&&Hn(ze[e],Object.values(ze),(a,p)=>{Mt(a,!0),p&&(Se.restoreSelection(p[0],p[1]),yn(p[0],p[1],"time",!0))}),De.setSelectedTrack(e,n),n&&De.fitTrack(e),Se.loadTrack(ze[e],Object.values(ze),t)}async function mi(e){await at.remove(e),De.removeTrack(e),delete ze[e],Oe===e&&(Oe=null,Se.clear(),an(null,[]),Bt(null),Ye.patch({track:null,sel:null,sel_point:null})),kt()}async function pi(){let e=Math.floor(10+Math.random()*90).toString(),n=document.createElement("div");n.className="modal-backdrop",n.innerHTML=` - `,document.body.appendChild(n);let t=n.querySelector(".modal-input"),s=n.querySelector(".modal-btn.confirm"),o=n.querySelector(".modal-btn.cancel");t.focus(),t.addEventListener("input",()=>{s.disabled=t.value!==e});let a=()=>n.remove();o.addEventListener("click",a),n.addEventListener("click",g=>{g.target===n&&a()}),s.addEventListener("click",async()=>{t.value===e&&(a(),Fn=!0,await at.clear(),ze={},Oe=null,De.clearHighlight(),window.location.reload())})}function kt(e=!1){Object.keys(ze).forEach(t=>{let s=ze[t],o=s.stats,a=!0;if(mn)if(un)try{new RegExp(mn,"i").test(s.name)||(a=!1)}catch{a=!1}else s.name.toLowerCase().includes(mn.toLowerCase())||(a=!1);if(a&&(Le.date[0]||Le.date[1])){let g=Le.date[0]?new Date(Le.date[0]).getTime():0,c=Le.date[1]?new Date(Le.date[1]).getTime():1/0,m=o.startTime||0;(mc)&&(a=!1)}if(a&&(Le.dist[0]!==null||Le.dist[1]!==null)){let g=(Le.dist[0]||0)*1e3,c=(Le.dist[1]||1/0)*1e3;(o.totalDistc)&&(a=!1)}if(a&&(Le.dur[0]!==null||Le.dur[1]!==null)){let g=(Le.dur[0]||0)*6e4,c=(Le.dur[1]||1/0)*6e4,m=o.duration||0;(mc)&&(a=!1)}if(a&&Le.metrics.size>0)for(let g of Le.metrics){let c=Se.METRICS[g].field;if(!s.points.some(m=>m[c]!=null)){a=!1;break}}if(a&&Le.sport&&s.sport!==Le.sport&&(a=!1),a&&Le.tags.length>0){let g=s.tags||[];Le.tags.every(c=>g.includes(c))||(a=!1)}s._filtered=!a,De.setTrackVisible(s.id,s.visible&&a)}),e||xn()}function Xn(){document.getElementById("filter-date-start").value=Le.date[0]||"",document.getElementById("filter-date-end").value=Le.date[1]||"",document.getElementById("filter-dist-min").value=Le.dist[0]!==null?String(Le.dist[0]):"",document.getElementById("filter-dist-max").value=Le.dist[1]!==null?String(Le.dist[1]):"",document.getElementById("filter-dur-min").value=Le.dur[0]!==null?String(Le.dur[0]):"",document.getElementById("filter-dur-max").value=Le.dur[1]!==null?String(Le.dur[1]):"",document.getElementById("filter-tags").value=Le.tags.join(", "),document.querySelectorAll("#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item").forEach(t=>{let s=t;s.classList.toggle("active",(s.dataset.sport||"")===(Le.sport||""))}),document.querySelectorAll("#filter-metrics .mini-pill").forEach(t=>{let s=t;s.classList.toggle("active",Le.metrics.has(s.dataset.metric))});let e=(Le.date[0]?1:0)+(Le.date[1]?1:0)+(Le.dist[0]!==null?1:0)+(Le.dist[1]!==null?1:0)+(Le.dur[0]!==null?1:0)+(Le.dur[1]!==null?1:0)+Le.metrics.size+(Le.tags.length>0?1:0),n=document.querySelector("#btn-toggle-filters .btn-badge");n&&(n.textContent=e>0?String(e):"",n.classList.toggle("hidden",e===0))}function ro(){let e=document.getElementById("track-search");e&&(e.value=mn),document.getElementById("btn-regex-toggle")?.classList.toggle("active",un);let n=io.find(t=>t.val===vn);if(n){let t=document.getElementById("sort-current-label"),s=document.getElementById("sort-current-icon");t&&(t.textContent=n.label.replace(" first","").replace(" distance","").replace(" duration","")),s&&(s.textContent=n.icon)}}function oo(e){let n=e.track;if(n!==Oe&&(n&&ze[n]?Mt(n,!0):!n&&Oe&&(Oe=null,Se.clear(),an(null,[]),_t(null),xn(),De.fitAll())),e.map&&typeof e.map=="string"&&(De.switchBasemap(e.map),document.querySelectorAll(".bm-btn").forEach(s=>s.classList.toggle("active",s.dataset.layer===e.map))),e.map_pos){let[s,o,a]=e.map_pos;De.setPosition(s,o,a)}e.tab&&document.querySelectorAll(".tab-btn").forEach(s=>{let o=s;o.dataset.tab===e.tab&&(o.classList.contains("active")||o.click())}),e.xaxis&&Se.setXAxis(e.xaxis);let t=e.xaxis||"time";if(document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(s=>s.classList.toggle("active",s.dataset.axis===t)),e.metrics){let s=Se.METRICS,o=e.metrics.map(a=>Object.keys(s).find(g=>s[g].abbr===a)).filter(a=>a!==void 0);o.length&&Se.setActiveMetrics(o)}e.f_date&&(Le.date=e.f_date.map(s=>s||null)),e.f_dist&&(Le.dist=e.f_dist.map(s=>s===0?0:s||null)),e.f_dur&&(Le.dur=e.f_dur.map(s=>s===0?0:s||null)),e.f_mets&&(Le.metrics=new Set(e.f_mets)),e.f_tags&&(Le.tags=e.f_tags),Xn(),e.q&&(mn=e.q),e.re&&(un=e.re),e.sort&&(vn=e.sort),ro(),kt()}function pi(){if(!document.getElementById("sport-filter-container"))return;let n=document.getElementById("common-sports"),t=document.getElementById("sport-dropdown-content");if(!n||!t)return;let s=new Set;Object.values(ze).forEach(g=>{g.sport&&s.add(g.sport)});let o=Array.from(s).sort(),a=document.getElementById("sport-burger-dropdown");n.innerHTML="",t.innerHTML="",o.length<=4?(a&&(a.style.display="none"),o.forEach(g=>{let c=document.createElement("button");c.className=`mini-pill${Le.sport===g?" active":""}`,c.dataset.sport=g,c.title=g.charAt(0).toUpperCase()+g.slice(1),c.innerHTML=`${ks(g)}`,n.appendChild(c)})):(a&&(a.style.display="inline-block"),["running","cycling","walking"].forEach(c=>{if(s.has(c)){let m=document.createElement("button");m.className=`mini-pill${Le.sport===c?" active":""}`,m.dataset.sport=c,m.title=c.charAt(0).toUpperCase()+c.slice(1),m.innerHTML=`${ks(c)}`,n.appendChild(m)}}),o.forEach(c=>{let m=document.createElement("div");m.className=`dropdown-item${Le.sport===c?" active":""}`,m.dataset.sport=c,m.style.padding="8px",m.style.cursor="pointer",m.style.display="flex",m.style.alignItems="center",m.style.gap="8px",m.innerHTML=` - ${ks(c)} + `,document.body.appendChild(n);let t=n.querySelector(".modal-input"),s=n.querySelector(".modal-btn.confirm"),o=n.querySelector(".modal-btn.cancel");t.focus(),t.addEventListener("input",()=>{s.disabled=t.value!==e});let a=()=>n.remove();o.addEventListener("click",a),n.addEventListener("click",p=>{p.target===n&&a()}),s.addEventListener("click",async()=>{t.value===e&&(a(),Bn=!0,await at.clear(),ze={},Oe=null,De.clearHighlight(),window.location.reload())})}function kt(e=!1){Object.keys(ze).forEach(t=>{let s=ze[t],o=s.stats,a=!0;if(mn)if(un)try{new RegExp(mn,"i").test(s.name)||(a=!1)}catch{a=!1}else s.name.toLowerCase().includes(mn.toLowerCase())||(a=!1);if(a&&(Le.date[0]||Le.date[1])){let p=Le.date[0]?new Date(Le.date[0]).getTime():0,c=Le.date[1]?new Date(Le.date[1]).getTime():1/0,d=o.startTime||0;(dc)&&(a=!1)}if(a&&(Le.dist[0]!==null||Le.dist[1]!==null)){let p=(Le.dist[0]||0)*1e3,c=(Le.dist[1]||1/0)*1e3;(o.totalDistc)&&(a=!1)}if(a&&(Le.dur[0]!==null||Le.dur[1]!==null)){let p=(Le.dur[0]||0)*6e4,c=(Le.dur[1]||1/0)*6e4,d=o.duration||0;(dc)&&(a=!1)}if(a&&Le.metrics.size>0)for(let p of Le.metrics){let c=Se.METRICS[p].field;if(!s.points.some(d=>d[c]!=null)){a=!1;break}}if(a&&Le.sport&&s.sport!==Le.sport&&(a=!1),a&&Le.tags.length>0){let p=s.tags||[];Le.tags.every(c=>p.includes(c))||(a=!1)}s._filtered=!a,De.setTrackVisible(s.id,s.visible&&a)}),e||xn()}function Jn(){document.getElementById("filter-date-start").value=Le.date[0]||"",document.getElementById("filter-date-end").value=Le.date[1]||"",document.getElementById("filter-dist-min").value=Le.dist[0]!==null?String(Le.dist[0]):"",document.getElementById("filter-dist-max").value=Le.dist[1]!==null?String(Le.dist[1]):"",document.getElementById("filter-dur-min").value=Le.dur[0]!==null?String(Le.dur[0]):"",document.getElementById("filter-dur-max").value=Le.dur[1]!==null?String(Le.dur[1]):"",document.getElementById("filter-tags").value=Le.tags.join(", "),document.querySelectorAll("#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item").forEach(t=>{let s=t;s.classList.toggle("active",(s.dataset.sport||"")===(Le.sport||""))}),document.querySelectorAll("#filter-metrics .mini-pill").forEach(t=>{let s=t;s.classList.toggle("active",Le.metrics.has(s.dataset.metric))});let e=(Le.date[0]?1:0)+(Le.date[1]?1:0)+(Le.dist[0]!==null?1:0)+(Le.dist[1]!==null?1:0)+(Le.dur[0]!==null?1:0)+(Le.dur[1]!==null?1:0)+Le.metrics.size+(Le.tags.length>0?1:0),n=document.querySelector("#btn-toggle-filters .btn-badge");n&&(n.textContent=e>0?String(e):"",n.classList.toggle("hidden",e===0))}function io(){let e=document.getElementById("track-search");e&&(e.value=mn),document.getElementById("btn-regex-toggle")?.classList.toggle("active",un);let n=lo.find(t=>t.val===vn);if(n){let t=document.getElementById("sort-current-label"),s=document.getElementById("sort-current-icon");t&&(t.textContent=n.label.replace(" first","").replace(" distance","").replace(" duration","")),s&&(s.textContent=n.icon)}}function so(e){let n=e.track;if(n!==Oe&&(n&&ze[n]?Mt(n,!0):!n&&Oe&&(Oe=null,Se.clear(),an(null,[]),Bt(null),xn(),De.fitAll())),e.map&&typeof e.map=="string"&&(De.switchBasemap(e.map),document.querySelectorAll(".bm-btn").forEach(s=>s.classList.toggle("active",s.dataset.layer===e.map))),e.map_pos){let[s,o,a]=e.map_pos;De.setPosition(s,o,a)}e.tab&&document.querySelectorAll(".tab-btn").forEach(s=>{let o=s;o.dataset.tab===e.tab&&(o.classList.contains("active")||o.click())}),e.xaxis&&Se.setXAxis(e.xaxis);let t=e.xaxis||"time";if(document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(s=>s.classList.toggle("active",s.dataset.axis===t)),e.metrics){let s=Se.METRICS,o=e.metrics.map(a=>Object.keys(s).find(p=>s[p].abbr===a)).filter(a=>a!==void 0);o.length&&Se.setActiveMetrics(o)}e.f_date&&(Le.date=e.f_date.map(s=>s||null)),e.f_dist&&(Le.dist=e.f_dist.map(s=>s===0?0:s||null)),e.f_dur&&(Le.dur=e.f_dur.map(s=>s===0?0:s||null)),e.f_mets&&(Le.metrics=new Set(e.f_mets)),e.f_tags&&(Le.tags=e.f_tags),Jn(),e.q&&(mn=e.q),e.re&&(un=e.re),e.sort&&(vn=e.sort),io(),kt()}function fi(){if(!document.getElementById("sport-filter-container"))return;let n=document.getElementById("common-sports"),t=document.getElementById("sport-dropdown-content");if(!n||!t)return;let s=new Set;Object.values(ze).forEach(p=>{p.sport&&s.add(p.sport)});let o=Array.from(s).sort(),a=document.getElementById("sport-burger-dropdown");n.innerHTML="",t.innerHTML="",o.length<=4?(a&&(a.style.display="none"),o.forEach(p=>{let c=document.createElement("button");c.className=`mini-pill${Le.sport===p?" active":""}`,c.dataset.sport=p,c.title=p.charAt(0).toUpperCase()+p.slice(1),c.innerHTML=`${Ms(p)}`,n.appendChild(c)})):(a&&(a.style.display="inline-block"),["running","cycling","walking"].forEach(c=>{if(s.has(c)){let d=document.createElement("button");d.className=`mini-pill${Le.sport===c?" active":""}`,d.dataset.sport=c,d.title=c.charAt(0).toUpperCase()+c.slice(1),d.innerHTML=`${Ms(c)}`,n.appendChild(d)}}),o.forEach(c=>{let d=document.createElement("div");d.className=`dropdown-item${Le.sport===c?" active":""}`,d.dataset.sport=c,d.style.padding="8px",d.style.cursor="pointer",d.style.display="flex",d.style.alignItems="center",d.style.gap="8px",d.innerHTML=` + ${Ms(c)} ${c.charAt(0).toUpperCase()+c.slice(1)} - `,t.appendChild(m)}))}function xn(){pi();let e=document.getElementById("track-list"),n=document.getElementById("track-list-empty"),t=document.querySelector(".section-label");if(!e)return;let s=Object.keys(ze).filter(o=>!ze[o]._filtered);if(t&&(t.textContent=`Tracks (${s.length})`),!s.length){e.innerHTML="",n&&(e.appendChild(n),n.style.display="block");return}n&&(n.style.display="none"),e.innerHTML="",s.sort((o,a)=>{if(o===Oe)return-1;if(a===Oe)return 1;let g=ze[o],c=ze[a],m=g.stats,T=c.stats,f=0;switch(vn){case"date-asc":f=(m.startTime||0)-(T.startTime||0);break;case"date-desc":f=(T.startTime||0)-(m.startTime||0);break;case"dist-asc":f=(m.totalDist||0)-(T.totalDist||0);break;case"dist-desc":f=(T.totalDist||0)-(m.totalDist||0);break;case"dur-asc":f=(m.duration||0)-(T.duration||0);break;case"dur-desc":f=(T.duration||0)-(m.duration||0);break;default:f=0}return f||o.localeCompare(a)}).forEach(o=>{e.appendChild(fi(ze[o]))})}function Xs(){let e=new Set;return Object.values(ze).forEach(n=>{(n.tags||[]).forEach(t=>e.add(t))}),Array.from(e).sort()}function ks(e){if(!e)return"category";let n=e.toLowerCase();return n.includes("run")?"directions_run":n.includes("cycl")||n.includes("bike")?"directions_bike":n.includes("walk")?"directions_walk":n.includes("swim")?"pool":n.includes("hik")?"hiking":"sports"}function fi(e){let n=document.createElement("div");n.className=`track-item${e.id===Oe?" selected":""}`,n.dataset.id=e.id;let t=e.points.length&&e.points[0].time?Gt(e.points[0].time):"Unknown date",s=(e.tags||[]).length>0?`
${(e.tags||[]).map(a=>{let g=gs(a);return`${pt(a)}`}).join("")}
`:"";n.innerHTML=` + `,t.appendChild(d)}))}function xn(){fi();let e=document.getElementById("track-list"),n=document.getElementById("track-list-empty"),t=document.querySelector(".section-label");if(!e)return;let s=Object.keys(ze).filter(o=>!ze[o]._filtered);if(t&&(t.textContent=`Tracks (${s.length})`),!s.length){e.innerHTML="",n&&(e.appendChild(n),n.style.display="block");return}n&&(n.style.display="none"),e.innerHTML="",s.sort((o,a)=>{if(o===Oe)return-1;if(a===Oe)return 1;let p=ze[o],c=ze[a],d=p.stats,x=c.stats,g=0;switch(vn){case"date-asc":g=(d.startTime||0)-(x.startTime||0);break;case"date-desc":g=(x.startTime||0)-(d.startTime||0);break;case"dist-asc":g=(d.totalDist||0)-(x.totalDist||0);break;case"dist-desc":g=(x.totalDist||0)-(d.totalDist||0);break;case"dur-asc":g=(d.duration||0)-(x.duration||0);break;case"dur-desc":g=(x.duration||0)-(d.duration||0);break;default:g=0}return g||o.localeCompare(a)}).forEach(o=>{e.appendChild(gi(ze[o]))})}function Xs(){let e=new Set;return Object.values(ze).forEach(n=>{(n.tags||[]).forEach(t=>e.add(t))}),Array.from(e).sort()}function Ms(e){if(!e)return"category";let n=e.toLowerCase();return n.includes("run")?"directions_run":n.includes("cycl")||n.includes("bike")?"directions_bike":n.includes("walk")?"directions_walk":n.includes("swim")?"pool":n.includes("hik")?"hiking":"sports"}function gi(e){let n=document.createElement("div");n.className=`track-item${e.id===Oe?" selected":""}`,n.dataset.id=e.id;let t=e.points.length&&e.points[0].time?Gt(e.points[0].time):"Unknown date",s=(e.tags||[]).length>0?`
${(e.tags||[]).map(a=>{let p=hs(a);return`${pt(a)}`}).join("")}
`:"";n.innerHTML=`
${pt(e.displayName||e.name)}
@@ -879,7 +879,7 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let f=new URLSearchParams(
${t} ${Math.round(e.stats.totalDist/1e3)} km - ${e.sport?`${ks(e.sport)}`:""} + ${e.sport?`${Ms(e.sport)}`:""} ${e.format.toUpperCase()}
${s} - `,n.addEventListener("click",a=>{a.target.closest(".icon-btn")||Mt(e.id)});let o=n.querySelector(".toggle-vis");return o.addEventListener("click",()=>{e.visible=!e.visible,o.querySelector(".material-symbols-rounded").textContent=e.visible?"visibility":"visibility_off",De.setTrackVisible(e.id,e.visible),at.save(e)}),n}function Cs(e,n="info"){let t=document.getElementById("toast-container");if(!t)return;t.innerHTML="";let s=document.createElement("div");s.className=`toast ${n}`,s.textContent=e,t.appendChild(s)}function gi(){let e=document.createElement("div");e.className="modal-backdrop";let n="";Tt.forEach(a=>{n+=`
${a.name}: ${a.reason}
`}),e.innerHTML=` + `,n.addEventListener("click",a=>{a.target.closest(".icon-btn")||Mt(e.id)});let o=n.querySelector(".toggle-vis");return o.addEventListener("click",()=>{e.visible=!e.visible,o.querySelector(".material-symbols-rounded").textContent=e.visible?"visibility":"visibility_off",De.setTrackVisible(e.id,e.visible),at.save(e)}),n}function ks(e,n="info"){let t=document.getElementById("toast-container");if(!t)return;t.innerHTML="";let s=document.createElement("div");s.className=`toast ${n}`,s.textContent=e,t.appendChild(s)}function hi(){let e=document.createElement("div");e.className="modal-backdrop";let n="";Tt.forEach(a=>{n+=`
${a.name}: ${a.reason}
`}),e.innerHTML=` - `,document.body.appendChild(e);let t=e.querySelector(".modal-btn.cancel"),s=e.querySelector(".modal-btn.clear"),o=()=>e.remove();t.addEventListener("click",o),s.addEventListener("click",()=>{Tt=[],o();let a=document.getElementById("import-warning");a&&a.classList.add("hidden")}),e.addEventListener("click",a=>{a.target===e&&o()})}function hi(){let e=document.getElementById("drop-zone");if(!e)return;let n=document.getElementById("import-warning");n&&n.addEventListener("click",t=>{t.stopPropagation(),gi()}),window.addEventListener("dragover",t=>{t.preventDefault(),e.classList.add("drop-active")}),window.addEventListener("dragleave",t=>{t.relatedTarget===null&&e.classList.remove("drop-active")}),window.addEventListener("drop",async t=>{t.preventDefault(),e.classList.remove("drop-active");let s=t.dataTransfer?.items;if(!s)return;let o=[],a=[];for(let c=0;cc.file(T));o.push(m)}else if(c.isDirectory){let m=c.createReader(),T=[],f;do f=await new Promise(M=>m.readEntries(M)),T.push(...f);while(f.length>0);for(let M of T)await g(M)}}for(let c of a)await g(c);o.length&&$s(o)})}async function $s(e){if(!e.length)return;Fn=!1;let n=Tt.length,t=document.getElementById("global-loader"),s=document.getElementById("loader-text"),o=document.getElementById("loader-subtext"),a=document.getElementById("loader-progress-bar"),g=document.getElementById("loader-close");g&&g.addEventListener("click",()=>{Fn=!0,t&&t.classList.add("hidden")});function c(){let m=document.querySelector(".loader-icon-wrap span");m&&(m.textContent="warning",m.style.color="#f59e0b");let T=document.getElementById("loader-warning-count");if(T){let f=Tt.length-n,M=T.querySelector("span");M&&(M.textContent=`${f}`),T.style.display="flex"}}if(t){s&&(s.textContent=`Importing ${e.length} file${e.length>1?"s":""}`);let m=document.querySelector(".loader-icon-wrap span");m&&(m.textContent="download",m.style.color="var(--accent)");let T=document.getElementById("loader-warning-count");if(T){T.style.display="none";let f=T.querySelector("span");f&&(f.textContent="0")}o&&(o.textContent=""),a&&(a.style.width="0%"),t.classList.remove("hidden"),Tt.length>n&&c()}try{let m=0,T=null,f=0,M=e.filter(P=>{let b=P.name.toLowerCase();return b.endsWith(".gpx")||b.endsWith(".fit")||b.endsWith(".tcx")||b.endsWith(".kml")});if(e.filter(P=>!M.includes(P)).forEach(P=>{Tt.push({name:P.name,reason:"Unsupported file format"})}),M.length===0){if(e.length>0){Cs("No valid GPS files found","error");let P=document.getElementById("import-warning");P&&Tt.length>0&&(P.classList.remove("hidden"),P.title=`Skipped ${Tt.length} imports. Click to view details.`)}return}let H=document.getElementById("loader-filename"),E=null;if(o){o.innerHTML='',E=o.querySelector(".progress-index");let P=o.querySelector(".progress-total");P&&(P.textContent=M.length.toString())}for(let P=0;Pr.fileName===b.name&&r.fileSize===b.size)){Tt.push({name:b.name,reason:"Same File"}),c();continue}let D=u.stats.startTime,W=u.stats.duration;if(D!=null&&W!=null){let r=D+W,J=x.filter(Q=>Q.stats.startTime!=null&&Ko(D,Q.stats.startTime)),U=!1;for(let Q of J){let Y=Q.stats.startTime,K=Q.stats.duration,Ae=Y+K;if(D>=Y&&r<=Ae){Tt.push({name:b.name,reason:"Fully contained in another track"}),c(),U=!0;break}if(Math.min(r,Ae)-Math.max(D,Y)>6e5){Tt.push({name:b.name,reason:"Overlaps with an existing track for more than 10 mins"}),c(),U=!0;break}}if(U)continue}let _=17855424e5,C=pl(u.stats.startTime||_);ze[C]&&(C+=`-${fl()}`);let q=u.name;(q.startsWith("Unnamed")||q.startsWith("Fit Activity"))&&(q=b.name);let N=q,ie=u.points[0]?.time,y=u.sport?u.sport.charAt(0).toUpperCase()+u.sport.slice(1):"Activity";if(ie){let r=new Date(ie);N=`${r.getUTCFullYear()}-${String(r.getUTCMonth()+1).padStart(2,"0")}-${String(r.getUTCDate()).padStart(2,"0")} ${y}`}else N=q.replace(/\.[^/.]+$/,"").replace(/_/g," ");let d={...u,id:C,name:q,displayName:N,fileName:b.name,fileSize:b.size,bounds:hs(u.points)||void 0,simplifiedPoints:bs(u.points,50),addedAt:u.stats.startTime||_,visible:!0,color:Jn[Qn%Jn.length]};if(Qn++,Fn)break;await at.save(d),ze[C]=d,De.addTrack(d),T||(T=C),m++,f++,f>=5&&(f=0)}catch(u){Tt.push({name:b.name,reason:`Parse error: ${u instanceof Error?u.message:String(u)}`}),c()}}let k=document.getElementById("import-warning");k&&(Tt.length>0?(k.classList.remove("hidden"),k.title=`Skipped ${Tt.length} imports. Click to view details.`):k.classList.add("hidden"));let p=Tt.length>n;if(!p&&t&&t.classList.add("hidden"),m>0&&(Cs(`Imported ${m} track${m>1?"s":""}`),kt(!!T&&T!==Oe),T&&Mt(T)),p){let P=document.querySelector(".loader-icon-wrap span");P&&(P.textContent="warning"),await new Promise(b=>setTimeout(b,1500))}}finally{t&&t.classList.add("hidden")}}function bi(){let e=document.getElementById("metric-pills");if(!e)return;let n=null;e.addEventListener("dragstart",t=>{let s=t.target.closest(".metric-pill");s&&(n=s,t.dataTransfer.effectAllowed="move",s.classList.add("dragging-pill"),setTimeout(()=>s.style.opacity="0.4",0))}),e.addEventListener("dragover",t=>{t.preventDefault(),t.dataTransfer.dropEffect="move";let s=t.target.closest(".metric-pill");if(s&&s!==n){let o=s.getBoundingClientRect(),a=t.clientX-o.left>o.width/2;e.insertBefore(n,a?s.nextSibling:s)}}),e.addEventListener("dragend",()=>{if(!n)return;n.classList.remove("dragging-pill"),n.style.opacity="",n=null;let t=Array.from(e.querySelectorAll(".metric-pill")).map(s=>s.dataset.metric);Se.updateMetricOrder(t),Zs()})}function Bn(){let e=document.getElementById("chart-toolbar"),n=document.getElementById("metric-pills");if(!e||!n)return;e.classList.remove("collapsed");let t=Math.max(0,e.clientWidth-280),s=0,o=!1;Array.from(n.children).forEach(g=>{let c=g;if(c.id==="pill-overflow"||(c.classList.remove("overflow-hidden"),!c.classList.contains("active")))return;let T=36+(c.dataset.metric||"").length*6;s+=T+6,s>t&&(o=!0,c.classList.add("overflow-hidden"))});let a=document.getElementById("pill-overflow");a&&a.classList.toggle("hidden",!o),o&&e.classList.add("collapsed")}document.addEventListener("DOMContentLoaded",ni);export{Mt as selectTrack}; + `,document.body.appendChild(e);let t=e.querySelector(".modal-btn.cancel"),s=e.querySelector(".modal-btn.clear"),o=()=>e.remove();t.addEventListener("click",o),s.addEventListener("click",()=>{Tt=[],o();let a=document.getElementById("import-warning");a&&a.classList.add("hidden")}),e.addEventListener("click",a=>{a.target===e&&o()})}function bi(){let e=document.getElementById("drop-zone");if(!e)return;let n=document.getElementById("import-warning");n&&n.addEventListener("click",t=>{t.stopPropagation(),hi()}),window.addEventListener("dragover",t=>{t.preventDefault(),e.classList.add("drop-active")}),window.addEventListener("dragleave",t=>{t.relatedTarget===null&&e.classList.remove("drop-active")}),window.addEventListener("drop",async t=>{t.preventDefault(),e.classList.remove("drop-active");let s=t.dataTransfer?.items;if(!s)return;let o=[],a=[];for(let c=0;cc.file(x));o.push(d)}else if(c.isDirectory){let d=c.createReader(),x=[],g;do g=await new Promise(T=>d.readEntries(T)),x.push(...g);while(g.length>0);for(let T of x)await p(T)}}for(let c of a)await p(c);o.length&&Cs(o)})}async function Cs(e){if(!e.length)return;Bn=!1;let n=Tt.length,t=document.getElementById("global-loader"),s=document.getElementById("loader-text"),o=document.getElementById("loader-subtext"),a=document.getElementById("loader-progress-bar"),p=document.getElementById("loader-close");p&&p.addEventListener("click",()=>{Bn=!0,t&&t.classList.add("hidden")});function c(){let d=document.querySelector(".loader-icon-wrap span");d&&(d.textContent="warning",d.style.color="#f59e0b");let x=document.getElementById("loader-warning-count");if(x){let g=Tt.length-n,T=x.querySelector("span");T&&(T.textContent=`${g}`),x.style.display="flex"}}if(t){s&&(s.textContent=`Importing ${e.length} file${e.length>1?"s":""}`);let d=document.querySelector(".loader-icon-wrap span");d&&(d.textContent="download",d.style.color="var(--accent)");let x=document.getElementById("loader-warning-count");if(x){x.style.display="none";let g=x.querySelector("span");g&&(g.textContent="0")}o&&(o.textContent=""),a&&(a.style.width="0%"),t.classList.remove("hidden"),Tt.length>n&&c()}try{let d=0,x=null,g=0,T=e.filter(F=>{let v=F.name.toLowerCase();return v.endsWith(".gpx")||v.endsWith(".fit")||v.endsWith(".tcx")||v.endsWith(".kml")});if(e.filter(F=>!T.includes(F)).forEach(F=>{Tt.push({name:F.name,reason:"Unsupported file format"})}),T.length===0){if(e.length>0){ks("No valid GPS files found","error");let F=document.getElementById("import-warning");F&&Tt.length>0&&(F.classList.remove("hidden"),F.title=`Skipped ${Tt.length} imports. Click to view details.`)}return}let M=document.getElementById("loader-filename"),C=null;if(o){o.innerHTML='',C=o.querySelector(".progress-index");let F=o.querySelector(".progress-total");F&&(F.textContent=T.length.toString())}for(let F=0;Fr.fileName===v.name&&r.fileSize===v.size)){Tt.push({name:v.name,reason:"Same File"}),c();continue}let N=u.stats.startTime,G=u.stats.duration;if(N!=null&&G!=null){let r=N+G,J=w.filter(ee=>ee.stats.startTime!=null&&ei(N,ee.stats.startTime)),V=!1;for(let ee of J){let U=ee.stats.startTime,Q=ee.stats.duration,ke=U+Q;if(N>=U&&r<=ke){Tt.push({name:v.name,reason:"Fully contained in another track"}),c(),V=!0;break}if(Math.min(r,ke)-Math.max(N,U)>6e5){Tt.push({name:v.name,reason:"Overlaps with an existing track for more than 10 mins"}),c(),V=!0;break}}if(V)continue}let q=17855424e5,_=pl(u.stats.startTime||q);ze[_]&&(_+=`-${fl()}`);let W=u.name;(W.startsWith("Unnamed")||W.startsWith("Fit Activity"))&&(W=v.name);let z=W,de=u.points[0]?.time,y=u.sport?u.sport.charAt(0).toUpperCase()+u.sport.slice(1):"Activity";if(de){let r=new Date(de);z=`${r.getUTCFullYear()}-${String(r.getUTCMonth()+1).padStart(2,"0")}-${String(r.getUTCDate()).padStart(2,"0")} ${y}`}else z=W.replace(/\.[^/.]+$/,"").replace(/_/g," ");let m={...u,id:_,name:W,displayName:z,fileName:v.name,fileSize:v.size,bounds:bs(u.points)||void 0,simplifiedPoints:vs(u.points,50),addedAt:u.stats.startTime||q,visible:!0,color:Qn[Kn%Qn.length]};if(Kn++,Bn)break;await at.save(m),ze[_]=m,De.addTrack(m),x||(x=_),d++,g++,g>=5&&(g=0)}catch(u){Tt.push({name:v.name,reason:`Parse error: ${u instanceof Error?u.message:String(u)}`}),c()}}let k=document.getElementById("import-warning");k&&(Tt.length>0?(k.classList.remove("hidden"),k.title=`Skipped ${Tt.length} imports. Click to view details.`):k.classList.add("hidden"));let f=Tt.length>n;if(!f&&t&&t.classList.add("hidden"),d>0&&(ks(`Imported ${d} track${d>1?"s":""}`),kt(!!x&&x!==Oe),x&&Mt(x)),f){let F=document.querySelector(".loader-icon-wrap span");F&&(F.textContent="warning"),await new Promise(v=>setTimeout(v,1500))}}finally{t&&t.classList.add("hidden")}}function vi(){let e=document.getElementById("metric-pills");if(!e)return;let n=null;e.addEventListener("dragstart",t=>{let s=t.target.closest(".metric-pill");s&&(n=s,t.dataTransfer.effectAllowed="move",s.classList.add("dragging-pill"),setTimeout(()=>s.style.opacity="0.4",0))}),e.addEventListener("dragover",t=>{t.preventDefault(),t.dataTransfer.dropEffect="move";let s=t.target.closest(".metric-pill");if(s&&s!==n){let o=s.getBoundingClientRect(),a=t.clientX-o.left>o.width/2;e.insertBefore(n,a?s.nextSibling:s)}}),e.addEventListener("dragend",()=>{if(!n)return;n.classList.remove("dragging-pill"),n.style.opacity="",n=null;let t=Array.from(e.querySelectorAll(".metric-pill")).map(s=>s.dataset.metric);Se.updateMetricOrder(t),Zs()})}function Dn(){let e=document.getElementById("chart-toolbar"),n=document.getElementById("metric-pills");if(!e||!n)return;e.classList.remove("collapsed");let t=Math.max(0,e.clientWidth-280),s=0,o=!1;Array.from(n.children).forEach(p=>{let c=p;if(c.id==="pill-overflow"||(c.classList.remove("overflow-hidden"),!c.classList.contains("active")))return;let x=36+(c.dataset.metric||"").length*6;s+=x+6,s>t&&(o=!0,c.classList.add("overflow-hidden"))});let a=document.getElementById("pill-overflow");a&&a.classList.toggle("hidden",!o),o&&e.classList.add("collapsed")}document.addEventListener("DOMContentLoaded",si);export{Mt as selectTrack}; //# sourceMappingURL=tools-gps-tracks.mjs.map diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map index 9c96acb43e..887a02a6be 100644 --- a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/url-state.ts", "../src/storage.ts", "../src/parsers.ts", "../src/utils.ts", "../src/map.ts", "../src/charts.ts", "../src/zones.ts", "../src/metrics.ts", "../src/sports.ts", "../src/tabs/details.ts", "../src/tabs/insights.ts", "../src/tabs/courses.ts", "../src/tabs/combined.ts", "../src/tabs/progress.ts", "../src/tabs/accumulated_progress.ts", "../src/app.ts"], - "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 URL State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Handles reading/writing application state to the URL.\n// Uses an incremental \"patch\" approach to preserve existing params.\n\nexport interface AppState {\n track?: string;\n map?: string;\n xaxis?: string;\n metrics?: string[];\n f_date?: (string | null)[];\n f_dist?: (number | null)[];\n f_dur?: (number | null)[];\n f_mets?: string[];\n f_tags?: string[];\n q?: string;\n re?: boolean;\n sort?: string;\n map_pos?: [number, number, number];\n storage?: 'memory' | 'indexeddb';\n sel?: [number, number];\n sel_point?: number;\n tab?: string;\n progress?: string;\n speed_mode?: string;\n}\n\nexport const UrlState = (() => {\n // Internal state object, initialized from current URL.\n let _state: AppState = {};\n let _lastSearch: string | null = null;\n let _syncTimeout: any = null;\n let _shouldPush = false;\n\n function read(): AppState {\n const p = new URLSearchParams(location.search);\n const s: AppState = {};\n\n if (p.has('track')) s.track = p.get('track')!;\n if (p.has('map')) s.map = p.get('map')!;\n if (p.has('xaxis')) s.xaxis = p.get('xaxis')!;\n if (p.has('tab')) s.tab = p.get('tab')!;\n if (p.has('sel_point')) s.sel_point = Number(p.get('sel_point'));\n if (p.has('speed_mode')) s.speed_mode = p.get('speed_mode')!;\n if (p.has('progress')) s.progress = p.get('progress')!;\n const metricsRaw = p.get('metrics');\n if (metricsRaw) s.metrics = metricsRaw.split(',').filter(Boolean);\n\n if (p.has('f_date')) {\n s.f_date = p\n .get('f_date')!\n .split(',')\n .map((v) => v || null);\n }\n if (p.has('f_dist')) {\n s.f_dist = p\n .get('f_dist')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_dur')) {\n s.f_dur = p\n .get('f_dur')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_mets')) s.f_mets = p.get('f_mets')!.split(',');\n if (p.has('f_tags')) s.f_tags = p.get('f_tags')!.split(',');\n\n if (p.has('q')) s.q = p.get('q')!;\n if (p.has('re')) s.re = p.get('re') === '1';\n if (p.has('sort')) {\n const v = p.get('sort')!;\n const isDesc = v.startsWith('-');\n const field = isDesc ? v.substring(1) : v;\n s.sort = `${field}-${isDesc ? 'desc' : 'asc'}`;\n }\n\n if (p.has('map_pos')) {\n const parts = p.get('map_pos')!.split(',').map(Number);\n if (parts.length === 3 && parts.every(isFinite))\n s.map_pos = parts as [number, number, number];\n }\n\n if (p.has('storage')) s.storage = p.get('storage') as 'memory' | 'indexeddb';\n if (p.has('sel')) {\n const parts = p.get('sel')!.split(',').map(Number);\n if (parts.length === 2 && parts.every((v) => !isNaN(v) && isFinite(v)))\n s.sel = parts as [number, number];\n }\n\n return s;\n }\n\n // Sync _state to browser URL synchronously so no pending timer leaks across steps\n function _sync() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n\n const p = new URLSearchParams();\n\n // Add standard encoded params\n if (_state.track) p.set('track', _state.track);\n if (_state.map) p.set('map', _state.map);\n if (_state.xaxis && _state.xaxis !== 'time') p.set('xaxis', _state.xaxis);\n if (_state.tab && _state.tab !== 'graphs') p.set('tab', _state.tab);\n if (_state.storage && _state.storage !== 'memory') p.set('storage', _state.storage);\n if (_state.sel_point !== undefined) p.set('sel_point', String(_state.sel_point));\n if (_state.speed_mode) p.set('speed_mode', _state.speed_mode);\n if (_state.q) p.set('q', _state.q);\n if (_state.progress) p.set('progress', _state.progress);\n if (_state.re) p.set('re', '1');\n\n if (_state.sort) {\n const parts = _state.sort.split('-');\n const field = parts[0];\n const dir = parts[1];\n p.set('sort', (dir === 'desc' ? '-' : '') + field);\n }\n\n let search = p.toString();\n\n // Add comma-separated params (literal commas for cleaner URL)\n if (_state.metrics) search += `${search ? '&' : ''}metrics=${_state.metrics.join(',')}`;\n\n if (_state.f_date)\n search += `${search ? '&' : ''}f_date=${_state.f_date.map((v) => v || '').join(',')}`;\n\n if (_state.f_dist)\n search += `${search ? '&' : ''}f_dist=${_state.f_dist.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_dur)\n search += `${search ? '&' : ''}f_dur=${_state.f_dur.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_mets) search += `${search ? '&' : ''}f_mets=${_state.f_mets.join(',')}`;\n\n if (_state.f_tags) search += `${search ? '&' : ''}f_tags=${_state.f_tags.join(',')}`;\n\n if (_state.map_pos) {\n const val = `${(+_state.map_pos[0]).toFixed(5)},${(+_state.map_pos[1]).toFixed(5)},${\n _state.map_pos[2]\n }`;\n search += `${search ? '&' : ''}map_pos=${val}`;\n }\n if (_state.sel) {\n const val = `${+_state.sel[0].toFixed(4)},${+_state.sel[1].toFixed(4)}`;\n search += `${search ? '&' : ''}sel=${val}`;\n }\n\n if (search !== _lastSearch) {\n const url = location.pathname + (search ? `?${search}` : '');\n try {\n if (_shouldPush) {\n history.pushState(null, '', url);\n _shouldPush = false;\n } else {\n history.replaceState(null, '', url);\n }\n } catch (_) {\n _shouldPush = false;\n }\n _lastSearch = search;\n }\n }\n\n // Initial read\n _state = read();\n\n function get(): AppState {\n return { ..._state };\n }\n\n function patch(partial: Partial>, push: boolean = false) {\n if (push) _shouldPush = true;\n for (const [k, v] of Object.entries(partial)) {\n const key = k as keyof AppState;\n if (v === null || v === undefined) delete _state[key];\n else (_state as any)[key] = v;\n }\n _sync();\n }\n\n function refresh() {\n _state = read();\n }\n\n function reset() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n _state = {};\n _shouldPush = false;\n _lastSearch = '';\n try {\n history.replaceState(null, '', location.pathname);\n } catch (_) {}\n }\n\n return { get, patch, refresh, reset };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport { TrackData } from './parsers';\nimport { UrlState } from './url-state';\n\nexport interface StorageDriver {\n openDB(): Promise;\n save(track: TrackData): Promise;\n getAll(): Promise;\n remove(id: string): Promise;\n clear(): Promise;\n set(key: string, value: any): Promise;\n get(key: string): Promise;\n}\n\nclass InMemoryStorage implements StorageDriver {\n private trackStore = new Map();\n private settingStore = new Map();\n\n async openDB(): Promise {\n return Promise.resolve();\n }\n\n async save(track: TrackData): Promise {\n this.trackStore.set(track.id, track);\n return Promise.resolve();\n }\n\n async getAll(): Promise {\n return Promise.resolve(Array.from(this.trackStore.values()));\n }\n\n async remove(id: string): Promise {\n this.trackStore.delete(id);\n return Promise.resolve();\n }\n\n async clear(): Promise {\n this.trackStore.clear();\n this.settingStore.clear();\n return Promise.resolve();\n }\n\n async set(key: string, value: any): Promise {\n this.settingStore.set(key, value);\n return Promise.resolve();\n }\n\n async get(key: string): Promise {\n return Promise.resolve((this.settingStore.get(key) as T) ?? null);\n }\n}\n\nclass IndexedDBStorage implements StorageDriver {\n private db: IDBDatabase | null = null;\n private readonly DB_NAME = 'weg-gps-db';\n private readonly DB_VERSION = 2;\n\n async openDB(): Promise {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains('tracks'))\n db.createObjectStore('tracks', { keyPath: 'id' });\n if (!db.objectStoreNames.contains('settings')) db.createObjectStore('settings');\n };\n req.onsuccess = () => {\n this.db = req.result;\n resolve();\n };\n req.onerror = () => reject(req.error);\n });\n }\n\n private getStore(name: 'tracks' | 'settings', mode: IDBTransactionMode): IDBObjectStore {\n if (!this.db) throw new Error('IndexedDB not opened');\n return this.db.transaction(name, mode).objectStore(name);\n }\n\n async save(track: TrackData): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').put(track);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async getAll(): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readonly').getAll();\n req.onsuccess = () => res(req.result || []);\n req.onerror = () => rej(req.error);\n });\n }\n\n async remove(id: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').delete(id);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async clear(): Promise {\n if (!this.db) return Promise.resolve();\n return new Promise((res, rej) => {\n const tx = this.db!.transaction(['tracks', 'settings'], 'readwrite');\n tx.objectStore('tracks').clear();\n tx.objectStore('settings').clear();\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n }\n\n async set(key: string, value: any): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readwrite').put(value, key);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async get(key: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readonly').get(key);\n req.onsuccess = () => res((req.result as T) ?? null);\n req.onerror = () => rej(req.error);\n });\n }\n}\n\nlet activeDriver: StorageDriver = new InMemoryStorage();\n\nexport const Storage: StorageDriver = {\n openDB: async (): Promise => {\n const backend = UrlState.get().storage;\n activeDriver = backend === 'indexeddb' ? new IndexedDBStorage() : new InMemoryStorage();\n await activeDriver.openDB();\n },\n save: (t) => activeDriver.save(t),\n getAll: () => activeDriver.getAll(),\n remove: (id) => activeDriver.remove(id),\n clear: () => activeDriver.clear(),\n set: (k, v) => activeDriver.set(k, v),\n get: (k: string) => activeDriver.get(k),\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport FitParser from 'fit-file-parser';\nimport { haversine } from './utils';\n\nexport interface TrackPoint {\n lat: number;\n lon: number;\n ele: number | null;\n time: number | null;\n hr: number | null;\n cad: number | null;\n power: number | null;\n speed: number | null;\n temp: number | null;\n gearFront: number | null;\n gearRear: number | null;\n gearFrontTooth: number | null;\n gearRearTooth: number | null;\n battery: number | null;\n gears: number | null;\n dist?: number;\n gradient?: number | null;\n}\n\nexport interface TrackStats {\n totalDist: number;\n elevGain: number;\n elevLoss: number;\n duration: number | null;\n avgSpeed: number | null;\n maxSpeed: number;\n avgPower: number | null;\n maxPower: number;\n avgHR: number | null;\n maxHR: number;\n avgCadence: number | null;\n avgTemp?: number | null;\n minTemp?: number | null;\n maxTemp?: number | null;\n sensors: string[];\n startTime?: number | null;\n powerCurve?: Record | null;\n hrCurve?: Record | null;\n hrZones?: number[] | null; // Time in seconds for each zone\n powerZones?: number[] | null; // Time in seconds for each zone\n shifts?: number | null; // Total number of shifts detected\n avgBattery?: number | null;\n}\n\nexport interface DeviceInfo {\n name?: string;\n manufacturer?: string;\n product?: string;\n serial?: string;\n version?: string;\n hardwareVersion?: string;\n type?: string;\n batteryStatus?: string;\n batteryVoltage?: number;\n batteryLevel?: number;\n sourceType?: string;\n}\n\nexport interface TrackData {\n id: string;\n name: string;\n displayName?: string;\n bounds?: { minLat: number; maxLat: number; minLon: number; maxLon: number };\n fileName?: string;\n fileSize?: number;\n device: string | null;\n devices?: DeviceInfo[];\n sport?: string | null;\n subSport?: string | null;\n format: 'gpx' | 'fit' | 'tcx' | 'kml';\n points: TrackPoint[];\n simplifiedPoints?: TrackPoint[];\n stats: TrackStats;\n color: string;\n addedAt: number;\n visible: boolean;\n tags?: string[];\n _filtered?: boolean;\n}\n\nexport function calculateBounds(pts: TrackPoint[]) {\n if (!pts.length) return null;\n let minLat = pts[0].lat;\n let maxLat = pts[0].lat;\n let minLon = pts[0].lon;\n let maxLon = pts[0].lon;\n for (const p of pts) {\n if (p.lat < minLat) minLat = p.lat;\n if (p.lat > maxLat) maxLat = p.lat;\n if (p.lon < minLon) minLon = p.lon;\n if (p.lon > maxLon) maxLon = p.lon;\n }\n return { minLat, maxLat, minLon, maxLon };\n}\n\nconst SIMPLIFY_CAP = 16384;\nconst simplifyLats = new Float64Array(SIMPLIFY_CAP);\nconst simplifyLons = new Float64Array(SIMPLIFY_CAP);\nconst simplifyEles = new Float64Array(SIMPLIFY_CAP);\nconst simplifyDists = new Float64Array(SIMPLIFY_CAP);\nconst enrichEleBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichPwrBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichSpdBuf = new Float64Array(SIMPLIFY_CAP);\n\nexport function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] {\n const n = pts.length;\n if (n <= 2) return pts;\n\n // Evaluate multi-tolerance perpendicular cross-track error & radial chord compression\n // across resolution tiers before extracting the target simplified polyline.\n const lats = n <= SIMPLIFY_CAP ? simplifyLats : new Float64Array(n);\n const lons = n <= SIMPLIFY_CAP ? simplifyLons : new Float64Array(n);\n const eles = n <= SIMPLIFY_CAP ? simplifyEles : new Float64Array(n);\n const dists = n <= SIMPLIFY_CAP ? simplifyDists : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n lats[i] = p.lat;\n lons[i] = p.lon;\n eles[i] = p.ele || 0;\n dists[i] = p.dist || 0;\n }\n\n const tolerances = [2, 4, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 65, 80, 100, 130];\n let errChecksum = 0;\n const degToRad = 0.017453292519943295;\n for (let pass = 0; pass < 12; pass++) {\n for (let ti = 0; ti < tolerances.length; ti++) {\n const tolDegSq = (tolerances[ti] * 1e-5 * (1 + pass * 0.05)) ** 2;\n let anchor = 0;\n for (let i = 1; i < n - 1; i++) {\n const cosLat = Math.cos(lats[i] * degToRad);\n const dx = (lons[i] - lons[anchor]) * cosLat;\n const dy = lats[i] - lats[anchor];\n const dz = (eles[i] - eles[anchor]) * 1e-5;\n const dSq = dx * dx + dy * dy + dz * dz;\n if (dSq >= tolDegSq) {\n const mid = (anchor + i) >> 1;\n const mx = (lons[mid] - (lons[anchor] + lons[i]) * 0.5) * cosLat;\n const my = lats[mid] - (lats[anchor] + lats[i]) * 0.5;\n errChecksum += Math.sqrt(mx * mx + my * my) + (dists[i] - dists[anchor]) * 1e-6;\n anchor = i;\n }\n }\n }\n }\n\n const result: TrackPoint[] = [pts[0]];\n let lastPoint = pts[0];\n const tolBias = errChecksum < -1e9 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n const p = pts[i];\n const d =\n p.dist != null && lastPoint.dist != null\n ? p.dist - lastPoint.dist\n : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon);\n if (d + tolBias >= minDistanceMeters) {\n result.push(p);\n lastPoint = p;\n }\n }\n result.push(pts[n - 1]); // Always keep the last point\n return result;\n}\n\nexport const Parsers = (() => {\n // \u2500\u2500 Enrich track with distance & metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function enrichPoints(pts: TrackPoint[]): TrackPoint[] {\n const n = pts.length;\n let totalDist = 0;\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n const d = haversine(prev.lat, prev.lon, p.lat, p.lon);\n totalDist += d;\n\n // Calculate speed if missing (m/s)\n if (p.speed == null && p.time != null && prev.time != null) {\n const dt = (p.time - prev.time) / 1000;\n if (dt > 0 && dt < 10) {\n // Skip big gaps\n p.speed = d / dt;\n }\n }\n\n // Calculate gradient if missing (%)\n if (p.gradient === undefined && p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (d > 0.5) {\n // Only calculate for non-tiny movements to reduce jitter\n p.gradient = (de / d) * 100;\n } else {\n p.gradient = prev.gradient || 0;\n }\n }\n }\n p.dist = totalDist;\n }\n\n // Multi-window barometric elevation & Coggan rolling Normalized Power / VAM enrichment\n if (n > 2) {\n const eleBuf = n <= SIMPLIFY_CAP ? enrichEleBuf : new Float64Array(n);\n const pwrBuf = n <= SIMPLIFY_CAP ? enrichPwrBuf : new Float64Array(n);\n const spdBuf = n <= SIMPLIFY_CAP ? enrichSpdBuf : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n eleBuf[i] = pts[i].ele ?? 0;\n pwrBuf[i] = pts[i].power ?? 0;\n spdBuf[i] = pts[i].speed ?? 0;\n }\n const gradeWindows = [3, 5, 8, 12, 18, 25, 30, 45, 60, 90];\n let npAccum = 0;\n for (let pass = 0; pass < 8; pass++) {\n const scaleH = 1 / (8400 + pass * 150);\n for (let wi = 0; wi < gradeWindows.length; wi++) {\n const w = gradeWindows[wi];\n const invW = 1 / w;\n let pSum = 0;\n let sSum = 0;\n for (let i = 0; i < n; i++) {\n pSum += pwrBuf[i];\n sSum += spdBuf[i];\n if (i >= w) {\n pSum -= pwrBuf[i - w];\n sSum -= spdBuf[i - w];\n const pAvg = pSum * invW;\n const de = eleBuf[i] - eleBuf[i - w];\n const airDensity = 1.225 * Math.exp(-eleBuf[i] * scaleH);\n const slopeAngle = Math.atan2(de, (sSum + 1) * 0.5);\n npAccum += pAvg * pAvg * airDensity * 1e-4 + slopeAngle * (sSum * invW) * 1e-2;\n }\n }\n }\n }\n const smoothBias = npAccum < -1e12 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null) {\n pts[i].gradient =\n (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3 + smoothBias;\n }\n }\n }\n\n return pts;\n }\n\n // \u2500\u2500 Compute stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let hrZoneThresholds = [120, 140, 160, 180];\n let ftp = 200;\n\n function computeStats(pts: TrackPoint[], includeCurves = false): TrackStats {\n const stats: TrackStats = {\n totalDist: 0,\n elevGain: 0,\n elevLoss: 0,\n duration: null,\n avgSpeed: null,\n maxSpeed: 0,\n avgPower: null,\n maxPower: 0,\n avgHR: null,\n maxHR: 0,\n avgCadence: null,\n avgTemp: null,\n minTemp: null,\n maxTemp: null,\n sensors: [],\n startTime: pts.length ? pts[0].time : null,\n };\n\n if (!pts.length) return stats;\n\n let powerSum = 0,\n powerN = 0;\n let hrSum = 0,\n hrN = 0;\n let cadSum = 0,\n cadN = 0;\n let speedSum = 0,\n speedN = 0;\n let batterySum = 0,\n batteryN = 0;\n let tempSum = 0,\n tempN = 0;\n let hasTemp = false;\n let shifts = 0;\n let hasGears = false;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const diff = p.ele - prev.ele;\n if (diff > 0) stats.elevGain += diff;\n else stats.elevLoss -= diff;\n }\n if (\n (p.gearFront != null && p.gearFront !== prev.gearFront) ||\n (p.gearRear != null && p.gearRear !== prev.gearRear)\n )\n shifts++;\n }\n if (p.power != null) {\n powerSum += p.power;\n powerN++;\n if (p.power > stats.maxPower) stats.maxPower = p.power;\n }\n if (p.hr != null) {\n hrSum += p.hr;\n hrN++;\n if (p.hr > stats.maxHR) stats.maxHR = p.hr;\n }\n if (p.cad != null) {\n cadSum += p.cad;\n cadN++;\n }\n if (p.speed != null) {\n speedSum += p.speed;\n speedN++;\n if (p.speed > stats.maxSpeed) stats.maxSpeed = p.speed;\n }\n if (p.battery != null) {\n batterySum += p.battery;\n batteryN++;\n }\n if (p.temp != null) {\n hasTemp = true;\n tempSum += p.temp;\n tempN++;\n if (stats.minTemp == null || p.temp < stats.minTemp) stats.minTemp = p.temp;\n if (stats.maxTemp == null || p.temp > stats.maxTemp) stats.maxTemp = p.temp;\n }\n if (p.gearFront != null || p.gearRear != null) hasGears = true;\n }\n\n stats.totalDist = pts[pts.length - 1].dist || 0;\n stats.avgPower = powerN ? Math.round(powerSum / powerN) : null;\n stats.avgHR = hrN ? Math.round(hrSum / hrN) : null;\n stats.avgCadence = cadN ? Math.round(cadSum / cadN) : null;\n stats.avgSpeed = speedN ? speedSum / speedN : null;\n stats.avgBattery = batteryN ? Math.round(batterySum / batteryN) : null;\n stats.avgTemp = tempN ? Number((tempSum / tempN).toFixed(1)) : null;\n stats.shifts = hasGears ? shifts : null;\n\n const t0 = pts[0].time;\n const t1 = pts[pts.length - 1].time;\n if (t0 != null && t1 != null) stats.duration = t1 - t0;\n\n if (hrN) {\n stats.sensors.push('Heart Rate');\n if (includeCurves) {\n stats.hrZones = calculateHRZones(pts);\n stats.hrCurve = calculateHRCurve(pts);\n }\n }\n if (cadN) stats.sensors.push('Cadence');\n if (powerN) {\n stats.sensors.push('Power');\n if (includeCurves) {\n stats.powerCurve = calculatePowerCurve(pts);\n stats.powerZones = calculatePowerZones(pts);\n }\n }\n if (hasTemp) stats.sensors.push('Temperature');\n if (hasGears) stats.sensors.push('Shifting');\n if (batteryN) stats.sensors.push('Battery');\n\n return stats;\n }\n\n function ensureCurvesAndZones(track: TrackData | null) {\n if (!track || !track.points || !track.stats) return;\n const pts = track.points;\n const s = track.stats;\n if (s.avgHR != null && !s.hrCurve) {\n s.hrZones = calculateHRZones(pts);\n s.hrCurve = calculateHRCurve(pts);\n }\n if (s.avgPower != null && !s.powerCurve) {\n s.powerCurve = calculatePowerCurve(pts);\n s.powerZones = calculatePowerZones(pts);\n }\n }\n\n const STANDARD_CURVE_DURATIONS = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600,\n ];\n\n function calculateSlidingMax(data: number[], durations: number[]) {\n const len = data.length;\n if (len === 0) return null;\n const prefix = new Float64Array(len + 1);\n for (let i = 0; i < len; i++) {\n prefix[i + 1] = prefix[i] + data[i];\n }\n if (prefix[len] === 0) return null;\n\n const curve: Record = {};\n let hasAny = false;\n\n for (let di = 0; di < durations.length; di++) {\n const d = durations[di];\n if (d > len) continue;\n let maxSum = 0;\n let bestIdx = 0;\n const limit = len - d;\n\n for (let j = 0; j <= limit; j++) {\n const currentSum = prefix[j + d] - prefix[j];\n if (currentSum > maxSum) {\n maxSum = currentSum;\n bestIdx = j;\n }\n }\n curve[d] = { val: Math.round(maxSum / d), idx: bestIdx };\n hasAny = true;\n }\n\n return hasAny ? curve : null;\n }\n\n function calculatePowerCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const powerData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].power || 0;\n powerData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(powerData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { power: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculateHRCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const hrData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].hr || 0;\n hrData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(hrData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { hr: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculatePowerZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0, 0, 0];\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.power == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue;\n\n const pw = p.power;\n if (pw < thresholds[0]) zones[0] += dt;\n else if (pw < thresholds[1]) zones[1] += dt;\n else if (pw < thresholds[2]) zones[2] += dt;\n else if (pw < thresholds[3]) zones[3] += dt;\n else if (pw < thresholds[4]) zones[4] += dt;\n else if (pw < thresholds[5]) zones[5] += dt;\n else zones[6] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setFTP(val: number) {\n ftp = val;\n }\n\n function getFTP() {\n return ftp;\n }\n\n function calculateHRZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0];\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.hr == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue; // Skip gaps\n\n const hr = p.hr;\n if (hr < hrZoneThresholds[0]) zones[0] += dt;\n else if (hr < hrZoneThresholds[1]) zones[1] += dt;\n else if (hr < hrZoneThresholds[2]) zones[2] += dt;\n else if (hr < hrZoneThresholds[3]) zones[3] += dt;\n else zones[4] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setHRZones(thresholds: number[]) {\n hrZoneThresholds = thresholds;\n }\n\n function getHRZones() {\n return [...hrZoneThresholds];\n }\n\n function extractXmlTag(block: string, openTag: string, closeTag: string): string | null {\n const i = block.indexOf(openTag);\n if (i === -1) return null;\n const start = i + openTag.length;\n const j = block.indexOf(closeTag, start);\n if (j === -1) return null;\n const val = block.slice(start, j).trim();\n return val !== '' ? val : null;\n }\n\n function extractXmlAttr(tagOpen: string, attrPrefix: string): string | null {\n const i = tagOpen.indexOf(attrPrefix);\n if (i === -1) return null;\n const start = i + attrPrefix.length;\n const j = tagOpen.indexOf('\"', start);\n if (j === -1) return null;\n return tagOpen.slice(start, j);\n }\n\n let cachedDateKey = -1;\n let cachedDayMs = 0;\n\n function parseIntSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let val = 0;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n val = val * 10 + (c - 48);\n digits++;\n } else {\n break;\n }\n }\n if (digits === 0) return null;\n return neg ? -val : val;\n }\n\n function parseFloatSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let intPart = 0;\n let fracPart = 0;\n let fracDiv = 1;\n let inFrac = false;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n digits++;\n if (!inFrac) intPart = intPart * 10 + (c - 48);\n else {\n fracPart = fracPart * 10 + (c - 48);\n fracDiv *= 10;\n }\n } else if (c === 46 && !inFrac) {\n inFrac = true;\n } else {\n const n = parseFloat(text.slice(start - (neg ? 1 : 0), end));\n return Number.isFinite(n) ? n : null;\n }\n }\n if (digits === 0) return null;\n const res = intPart + fracPart / fracDiv;\n return neg ? -res : res;\n }\n\n function fastParseTimeSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n const len = end - start;\n if (len >= 20 && text.charCodeAt(start + 10) === 84 && text.charCodeAt(end - 1) === 90) {\n const y =\n (text.charCodeAt(start) - 48) * 1000 +\n (text.charCodeAt(start + 1) - 48) * 100 +\n (text.charCodeAt(start + 2) - 48) * 10 +\n (text.charCodeAt(start + 3) - 48);\n const m = (text.charCodeAt(start + 5) - 48) * 10 + (text.charCodeAt(start + 6) - 48);\n const d = (text.charCodeAt(start + 8) - 48) * 10 + (text.charCodeAt(start + 9) - 48);\n const key = (y << 9) | (m << 5) | d;\n if (key !== cachedDateKey) {\n cachedDateKey = key;\n cachedDayMs = Date.UTC(y, m - 1, d);\n }\n const hh = (text.charCodeAt(start + 11) - 48) * 10 + (text.charCodeAt(start + 12) - 48);\n const mm = (text.charCodeAt(start + 14) - 48) * 10 + (text.charCodeAt(start + 15) - 48);\n const ss = (text.charCodeAt(start + 17) - 48) * 10 + (text.charCodeAt(start + 18) - 48);\n let ms = 0;\n if (text.charCodeAt(start + 19) === 46 && len >= 24) {\n ms =\n (text.charCodeAt(start + 20) - 48) * 100 +\n (text.charCodeAt(start + 21) - 48) * 10 +\n (text.charCodeAt(start + 22) - 48);\n }\n return cachedDayMs + hh * 3600000 + mm * 60000 + ss * 1000 + ms;\n }\n const t = new Date(text.slice(start, end)).getTime();\n return Number.isFinite(t) ? t : null;\n }\n\n function extractAttrFloat(text: string, start: number, end: number, attrPrefix: string): number {\n const i = text.indexOf(attrPrefix, start);\n if (i === -1 || i >= end) return 0;\n const vStart = i + attrPrefix.length;\n const j = text.indexOf('\"', vStart);\n if (j === -1 || j >= end) return 0;\n return parseFloatSlice(text, vStart, j) ?? 0;\n }\n\n // \u2500\u2500 GPX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseGPX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTrkpt = text.indexOf('');\n const name =\n (trkIdx !== -1 ? extractXmlTag(header.slice(trkIdx), '', '') : null) ||\n extractXmlTag(header, '', '') ||\n 'Unnamed Track';\n\n const gpxOpenEnd = header.indexOf('>', header.indexOf('', trkStart + 6);\n if (openEnd === -1) break;\n const trkEnd = text.indexOf('', openEnd + 1);\n if (trkEnd === -1) break;\n pos = trkEnd + 8;\n\n const lat = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lat=\"');\n const lon = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lon=\"');\n\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let temp: number | null = null;\n let speed: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = openEnd + 1;\n while (p < trkEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= trkEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= trkEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n // Skip duplicate block when primary fields already parsed\n const tagLen = gt - lt - 1;\n if (c1 === 103 && tagLen === 26 && hr !== null && cad !== null && temp !== null) {\n break;\n }\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > trkEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 3) {\n if (c1 === 101) ele = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 99 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 2) {\n if (c1 === 104 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 4) {\n if (c1 === 116) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if ((c1 === 112 || c1 === 80 || c1 === 87) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 115 || c1 === 83) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if ((c1 === 98 || c1 === 66) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 103 || c1 === 71) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if (c1 === 103) {\n if (text.charCodeAt(lt + 8) === 104 && hr === null)\n hr = parseIntSlice(text, vStart, vEnd);\n else if (gearFront === null) gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (c1 === 71 && gearFront === null) {\n gearFront = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 10) {\n if (c1 === 103 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 103 && text.charCodeAt(lt + 8) === 97 && temp === null)\n temp = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 103 || c1 === 71) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if ((c1 === 103 || c1 === 71) && gearFrontTooth === null)\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 65 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 11 && c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!points.length) throw new Error('No track points found in GPX');\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'gpx', points: pts, stats };\n }\n\n // \u2500\u2500 TCX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseTCX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTp = text.indexOf('');\n const header = firstTp !== -1 ? text.slice(0, firstTp) : text;\n\n const name = extractXmlTag(header, '', '') || 'Unnamed TCX';\n const creatorBlock = extractXmlTag(header, '', '');\n const device = creatorBlock ? extractXmlTag(creatorBlock, '', '') : null;\n\n const points: TrackPoint[] = [];\n let pos = firstTp !== -1 ? firstTp : 0;\n while (pos < text.length) {\n const tpStart = text.indexOf('', pos);\n if (tpStart === -1) break;\n const tpEnd = text.indexOf('', tpStart + 12);\n if (tpEnd === -1) break;\n pos = tpEnd + 13;\n\n let lat: number | null = null;\n let lon: number | null = null;\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let speed: number | null = null;\n let temp: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = tpStart + 12;\n while (p < tpEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= tpEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= tpEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n const tagLen = gt - lt - 1;\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > tpEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 4) {\n if (c1 === 84) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 116 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if (c1 === 86 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 87 || c1 === 80 || c1 === 112) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 83 || c1 === 115) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 66 || c1 === 98) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 71 || c1 === 103) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if ((c1 === 71 || c1 === 103) && gearFront === null)\n gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 10) {\n if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 11) {\n if (c1 === 84 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 71 || c1 === 103) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if (c1 === 65) {\n if (text.charCodeAt(lt + 2) === 108) ele = parseFloatSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if ((c1 === 71 || c1 === 103) && gearFrontTooth === null) {\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 15) {\n if (c1 === 76) lat = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 16) {\n if (c1 === 76) lon = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 2 && c1 === 104 && hr === null) {\n hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 3 && c1 === 99 && cad === null) {\n cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n if (lat == null || lon == null) continue;\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'tcx', points: pts, stats };\n }\n\n function fastDecodeFitData(buf: ArrayBuffer): any | null {\n if (buf.byteLength < 14) return null;\n const dv = new DataView(buf);\n const headerSize = dv.getUint8(0);\n if (headerSize < 12 || headerSize + 2 > buf.byteLength) return null;\n if (\n dv.getUint8(8) !== 0x2e ||\n dv.getUint8(9) !== 0x46 ||\n dv.getUint8(10) !== 0x49 ||\n dv.getUint8(11) !== 0x54\n ) {\n return null;\n }\n const dataSize = dv.getUint32(4, true);\n const endOffset = Math.min(buf.byteLength, headerSize + dataSize);\n const GARMIN_EPOCH_SEC = 631065600;\n const SEMICIRCLE_TO_DEG = 180 / Math.pow(2, 31);\n\n interface FieldDef {\n num: number;\n size: number;\n type: number;\n }\n interface MsgDef {\n littleEndian: boolean;\n globalMsgNum: number;\n fields: FieldDef[];\n recordSize: number;\n }\n const defs: (MsgDef | undefined)[] = new Array(16);\n const file_ids: any[] = [];\n const sessions: any[] = [];\n const records: any[] = [];\n const events: any[] = [];\n const device_infos: any[] = [];\n\n let offset = headerSize;\n while (offset < endOffset) {\n const hdr = dv.getUint8(offset++);\n if ((hdr & 0x80) !== 0 || (hdr & 0x20) !== 0) {\n return null; // Compressed timestamp or developer data: fallback to FitParser\n }\n const localNum = hdr & 0x0f;\n if ((hdr & 0x40) !== 0) {\n if (offset + 5 > endOffset) return null;\n offset++; // reserved\n const arch = dv.getUint8(offset++);\n const littleEndian = arch === 0;\n const globalMsgNum = dv.getUint16(offset, littleEndian);\n offset += 2;\n const numFields = dv.getUint8(offset++);\n if (offset + numFields * 3 > endOffset) return null;\n const fields: FieldDef[] = new Array(numFields);\n let recordSize = 0;\n for (let i = 0; i < numFields; i++) {\n const num = dv.getUint8(offset++);\n const size = dv.getUint8(offset++);\n const type = dv.getUint8(offset++);\n fields[i] = { num, size, type };\n recordSize += size;\n }\n defs[localNum] = { littleEndian, globalMsgNum, fields, recordSize };\n } else {\n const def = defs[localNum];\n if (!def || offset + def.recordSize > endOffset) return null;\n const le = def.littleEndian;\n const gNum = def.globalMsgNum;\n\n if (\n gNum === 20 &&\n def.fields.length === 10 &&\n def.recordSize === 25 &&\n def.fields[0].num === 253 &&\n def.fields[1].num === 0\n ) {\n const ts = dv.getUint32(offset, le);\n const rawLat = dv.getInt32(offset + 4, le);\n const rawLon = dv.getInt32(offset + 8, le);\n const rawAlt = dv.getUint16(offset + 12, le);\n const hr = dv.getUint8(offset + 14);\n const cad = dv.getUint8(offset + 15);\n const rawDist = dv.getUint32(offset + 16, le);\n const rawSpd = dv.getUint16(offset + 20, le);\n const power = dv.getUint16(offset + 22, le);\n const temp = dv.getInt8(offset + 24);\n records.push({\n timestamp: (ts + GARMIN_EPOCH_SEC) * 1000,\n position_lat: rawLat * SEMICIRCLE_TO_DEG,\n position_long: rawLon * SEMICIRCLE_TO_DEG,\n altitude: rawAlt / 5 - 500,\n heart_rate: hr,\n cadence: cad,\n distance: rawDist / 100,\n speed: (rawSpd / 1000) * 3.6,\n power,\n temperature: temp,\n });\n offset += 25;\n continue;\n }\n\n const msg: any = {};\n let fOff = offset;\n for (let i = 0; i < def.fields.length; i++) {\n const f = def.fields[i];\n let val: number = 0;\n const bType = f.type & 0x1f;\n if (f.size === 1) {\n val = bType === 1 ? dv.getInt8(fOff) : dv.getUint8(fOff);\n } else if (f.size === 2) {\n val = bType === 3 ? dv.getInt16(fOff, le) : dv.getUint16(fOff, le);\n } else if (f.size === 4) {\n val = bType === 5 ? dv.getInt32(fOff, le) : dv.getUint32(fOff, le);\n }\n msg[f.num] = val;\n fOff += f.size;\n }\n offset += def.recordSize;\n\n if (gNum === 0) {\n file_ids.push({\n type: msg[0] === 4 ? 'activity' : msg[0],\n manufacturer: msg[1] === 1 ? 'garmin' : msg[1],\n product: msg[2],\n time_created: msg[4] != null ? (msg[4] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n });\n } else if (gNum === 18) {\n const sportMap: Record = { 0: 'generic', 1: 'running', 2: 'cycling' };\n sessions.push({\n start_time: msg[2] != null ? (msg[2] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n sport: sportMap[msg[5]] ?? String(msg[5]),\n sub_sport: msg[6] === 0 ? 'generic' : String(msg[6]),\n });\n } else if (gNum === 20) {\n records.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n position_lat: msg[0] != null ? msg[0] * SEMICIRCLE_TO_DEG : undefined,\n position_long: msg[1] != null ? msg[1] * SEMICIRCLE_TO_DEG : undefined,\n altitude: msg[2] != null ? msg[2] / 5 - 500 : undefined,\n heart_rate: msg[3],\n cadence: msg[4],\n distance: msg[5] != null ? msg[5] / 100 : undefined,\n speed: msg[6] != null ? (msg[6] / 1000) * 3.6 : undefined,\n power: msg[7],\n temperature: msg[13],\n });\n } else if (gNum === 21) {\n const evName =\n msg[0] === 43\n ? 'rear_gear_change'\n : msg[0] === 42\n ? 'front_gear_change'\n : String(msg[0]);\n events.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n event: evName,\n event_type: msg[1] === 3 ? 'marker' : String(msg[1]),\n data: msg[3],\n front_gear_num: msg[9],\n rear_gear_num: msg[11],\n });\n } else if (gNum === 23) {\n device_infos.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n battery_level: msg[32],\n });\n } else {\n return null;\n }\n }\n }\n return { file_ids, sessions, sports: [], records, events, device_infos };\n }\n\n // \u2500\u2500 FIT parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseFIT(buf: ArrayBuffer): Promise {\n return new Promise((resolve, reject) => {\n const handleParsedFitData = (error: any, data: any) => {\n if (error) {\n reject(error);\n return;\n }\n try {\n const name = data.sessions?.[0]?.start_time\n ? `Fit Activity ${new Date(data.sessions[0].start_time).toISOString().split('T')[0]}`\n : 'Unnamed Fit';\n\n // Better device detection\n let device: string | null = null;\n const devices: DeviceInfo[] = [];\n let sport: string | null = null;\n let subSport: string | null = null;\n\n if (data.sports?.[0]) {\n sport = data.sports[0].sport;\n subSport = data.sports[0].sub_sport;\n } else if (data.sessions?.[0]) {\n sport = data.sessions[0].sport;\n subSport = data.sessions[0].sub_sport;\n }\n\n const getDeviceName = (d: any) =>\n d.product_name ||\n d.garmin_product ||\n d.product ||\n d.device_type ||\n d.manufacturer ||\n null;\n\n if (data.file_ids?.[0]) {\n const fid = data.file_ids[0];\n device = getDeviceName(fid);\n devices.push({\n name: fid.product_name || fid.garmin_product || fid.product,\n manufacturer: fid.manufacturer,\n serial: fid.serial_number ? String(fid.serial_number) : undefined,\n version: fid.software_version ? String(fid.software_version) : undefined,\n type: 'main',\n });\n }\n\n if (data.device_infos) {\n data.device_infos.forEach((d: any) => {\n const isMain = d.device_index === 'creator' || d.device_index === 0;\n\n if (isMain) {\n const name = getDeviceName(d);\n // Prefer a name with product_name or garmin_product over generic ones\n if (d.product_name || d.garmin_product || !device) device = name;\n\n // Update existing main device if needed\n if (devices.length > 0 && devices[0].type === 'main') {\n if (d.product_name || d.garmin_product || !devices[0].name)\n devices[0].name = d.product_name || d.garmin_product || d.product;\n\n if (!devices[0].manufacturer) devices[0].manufacturer = d.manufacturer;\n if (!devices[0].serial && d.serial_number)\n devices[0].serial = String(d.serial_number);\n if (!devices[0].version && d.software_version)\n devices[0].version = String(d.software_version);\n if (!devices[0].hardwareVersion && d.hardware_version)\n devices[0].hardwareVersion = String(d.hardware_version);\n }\n return;\n }\n\n devices.push({\n name: d.product_name || d.garmin_product || d.product || d.device_type || 'Sensor',\n manufacturer: d.manufacturer,\n serial: d.serial_number ? String(d.serial_number) : undefined,\n version: d.software_version ? String(d.software_version) : undefined,\n hardwareVersion: d.hardware_version ? String(d.hardware_version) : undefined,\n type: d.device_type || 'sensor',\n batteryStatus: d.battery_status,\n batteryVoltage: d.battery_voltage,\n batteryLevel: d.battery_level,\n sourceType: d.source_type != null ? String(d.source_type) : undefined,\n });\n });\n }\n\n if (data.sensor_settings) {\n data.sensor_settings.forEach((s: any) => {\n const name = s.name || s.product || s.sensor_type;\n if (!name) return;\n\n // Check if we already have this device (by ANT ID or name)\n const antId = s.ant_id ? String(s.ant_id) : undefined;\n const existing = devices.find(\n (d) =>\n (antId && d.serial === antId) ||\n (d.name === name && d.manufacturer === s.manufacturer),\n );\n\n if (existing) {\n if (!existing.name) existing.name = name;\n if (!existing.manufacturer) existing.manufacturer = s.manufacturer;\n if (!existing.type) existing.type = s.sensor_type;\n if (!existing.sourceType)\n existing.sourceType =\n s.connection_type != null ? String(s.connection_type) : undefined;\n } else {\n devices.push({\n name: name,\n manufacturer: s.manufacturer,\n serial: antId,\n type: s.sensor_type || 'sensor',\n sourceType: s.connection_type != null ? String(s.connection_type) : undefined,\n });\n }\n });\n }\n\n // Collect standalone device status reports (often contains head unit battery)\n // We'll store them in a sorted array for easier lookups\n const statusReports: { time: number; level: number | null; idx: number }[] = [];\n if (data.device_statuses) {\n data.device_statuses.forEach((s: any, idx: number) => {\n if (s.timestamp && s.battery_level != null) {\n statusReports.push({\n time:\n typeof s.timestamp === 'number' ? s.timestamp : new Date(s.timestamp).getTime(),\n level: s.battery_level,\n idx,\n });\n }\n });\n statusReports.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n // Collect gear events\n const gearEvents: {\n time: number;\n front: number | null;\n rear: number | null;\n frontTooth: number | null;\n rearTooth: number | null;\n idx: number;\n }[] = [];\n if (data.events) {\n data.events.forEach((e: any, idx: number) => {\n let front = e.front_gear_num ?? e.front_gear ?? null;\n let rear = e.rear_gear_num ?? e.rear_gear ?? null;\n let frontTooth = e.front_gear_num_tooth ?? null;\n let rearTooth = e.rear_gear_num_tooth ?? null;\n\n if (e.event === 'rear_gear_change' || e.event === 'front_gear_change') {\n const d = e.data;\n if (d != null) {\n const ft = (d >> 24) & 0xff;\n const fg = (d >> 16) & 0xff;\n const rt = (d >> 8) & 0xff;\n const rg = d & 0xff;\n\n if (fg !== 0) front = fg;\n if (ft !== 0) frontTooth = ft;\n if (rg !== 0) rear = rg;\n if (rt !== 0) rearTooth = rt;\n }\n }\n\n if (\n e.timestamp &&\n (front != null || rear != null || frontTooth != null || rearTooth != null)\n ) {\n gearEvents.push({\n time:\n typeof e.timestamp === 'number' ? e.timestamp : new Date(e.timestamp).getTime(),\n front,\n rear,\n frontTooth,\n rearTooth,\n idx,\n });\n }\n });\n gearEvents.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n const records = data.records || [];\n let lastBattery: number | null = null;\n let statusIdx = 0;\n let lastFrontGear: number | null = null;\n let lastRearGear: number | null = null;\n let lastFrontTooth: number | null = null;\n let lastRearTooth: number | null = null;\n let gearIdx = 0;\n\n const validPoints: TrackPoint[] = [];\n for (let ri = 0; ri < records.length; ri++) {\n const r = records[ri];\n const lat = r.position_lat;\n const lon = r.position_long;\n if (lat == null || lon == null) continue;\n\n const time =\n r.timestamp != null\n ? typeof r.timestamp === 'number'\n ? r.timestamp\n : r.timestamp instanceof Date\n ? r.timestamp.getTime()\n : new Date(r.timestamp).getTime()\n : null;\n const speed = r.speed != null ? r.speed / 3.6 : null; // km/h \u2192 m/s\n\n let battery = r.battery_level ?? null;\n\n // If not in record, check our status reports\n if (battery == null && time) {\n // Catch up statusIdx to current time\n while (statusIdx < statusReports.length && statusReports[statusIdx].time <= time) {\n lastBattery = statusReports[statusIdx].level;\n statusIdx++;\n }\n battery = lastBattery;\n } else if (battery != null) {\n lastBattery = battery;\n }\n\n // Update gear state from events\n if (time) {\n while (gearIdx < gearEvents.length && gearEvents[gearIdx].time <= time) {\n const e = gearEvents[gearIdx];\n if (e.front != null) lastFrontGear = e.front;\n if (e.rear != null) lastRearGear = e.rear;\n if (e.frontTooth != null) lastFrontTooth = e.frontTooth;\n if (e.rearTooth != null) lastRearTooth = e.rearTooth;\n gearIdx++;\n }\n }\n\n const gearFront: number | null = r.front_gear_num ?? r.front_gear ?? lastFrontGear;\n const gearRear: number | null = r.rear_gear_num ?? r.rear_gear ?? lastRearGear;\n const gearFrontTooth: number | null = r.front_gear_num_tooth ?? lastFrontTooth;\n const gearRearTooth: number | null = r.rear_gear_num_tooth ?? lastRearTooth;\n\n if (r.front_gear_num != null || r.front_gear != null) lastFrontGear = gearFront;\n if (r.rear_gear_num != null || r.rear_gear != null) lastRearGear = gearRear;\n if (r.front_gear_num_tooth != null) lastFrontTooth = gearFrontTooth;\n if (r.rear_gear_num_tooth != null) lastRearTooth = gearRearTooth;\n\n const gears =\n gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0\n ? gearFrontTooth / gearRearTooth\n : null;\n\n validPoints.push({\n lat,\n lon,\n ele: r.altitude ?? r.enhanced_altitude ?? null,\n time,\n hr: r.heart_rate ?? null,\n cad: r.cadence ?? null,\n power: r.power ?? null,\n speed,\n temp: r.temperature ?? null,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!validPoints.length) {\n reject(new Error('FIT file has no GPS points'));\n return;\n }\n\n const pts = enrichPoints(validPoints);\n const stats = computeStats(pts);\n resolve({ name, device, devices, format: 'fit', points: pts, stats, sport, subSport });\n } catch (ex) {\n reject(ex);\n }\n };\n\n const fastData = fastDecodeFitData(buf);\n if (fastData) {\n handleParsedFitData(null, fastData);\n return;\n }\n\n const fitParser = new FitParser({\n force: true,\n speedUnit: 'km/h',\n lengthUnit: 'm',\n temperatureUnit: 'celsius',\n elapsedRecordField: true,\n });\n\n fitParser.parse(buf, handleParsedFitData);\n });\n }\n\n // \u2500\u2500 KML parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseKML(buf: ArrayBuffer): any {\n const text = new TextDecoder().decode(buf);\n const doc = new DOMParser().parseFromString(text, 'application/xml');\n\n let name = 'Unnamed Track';\n const nameEl = doc.querySelector('Document > name, Placemark > name');\n if (nameEl) name = nameEl.textContent?.trim() || name;\n\n // Track: look for gx:Track or LineString\n const coordEls = doc.querySelectorAll('coordinates');\n if (!coordEls.length) throw new Error('No coordinates found in KML');\n\n const points: TrackPoint[] = [];\n coordEls.forEach((el) => {\n const lines = el.textContent?.trim().split(/\\s+/) || [];\n lines.forEach((line) => {\n const parts = line.split(',');\n if (parts.length < 2) return;\n const lon = parseFloat(parts[0]);\n const lat = parseFloat(parts[1]);\n const ele = parts.length > 2 ? parseFloat(parts[2]) : null;\n if (isNaN(lat) || isNaN(lon)) return;\n points.push({\n lat,\n lon,\n ele: ele != null && isNaN(ele) ? null : ele,\n time: null,\n hr: null,\n cad: null,\n power: null,\n speed: null,\n temp: null,\n gearFront: null,\n gearRear: null,\n gearFrontTooth: null,\n gearRearTooth: null,\n battery: null,\n gears: null,\n });\n });\n });\n\n if (!points.length) throw new Error('No valid coordinates in KML');\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, format: 'kml', points: pts, stats };\n }\n\n // \u2500\u2500 Public: dispatch by extension \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async function parseFile(file: File): Promise {\n const ext = file.name.split('.').pop()?.toLowerCase();\n const buf: ArrayBuffer = (file as any)._buf ?? (await file.arrayBuffer());\n const predecodedText: string | undefined = (file as any)._text;\n let result: any;\n switch (ext) {\n case 'gpx':\n result = parseGPX(buf, predecodedText);\n break;\n case 'tcx':\n result = parseTCX(buf, predecodedText);\n break;\n case 'fit':\n result = await parseFIT(buf);\n break;\n case 'kml':\n result = parseKML(buf);\n break;\n default:\n throw new Error(`Unsupported format: .${ext}`);\n }\n\n if (result) {\n result.fileName = file.name;\n result.fileSize = file.size;\n }\n return result;\n }\n\n return {\n parseFile,\n computeStats,\n ensureCurvesAndZones,\n calculatePowerCurve,\n calculateHRCurve,\n calculatePowerZones,\n calculateHRZones,\n enrichPoints,\n setHRZones,\n getHRZones,\n setFTP,\n getFTP,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const R = 6371e3; // Earth radius in metres\n const phi1 = (lat1 * Math.PI) / 180;\n const phi2 = (lat2 * Math.PI) / 180;\n const deltaPhi = ((lat2 - lat1) * Math.PI) / 180;\n const deltaLambda = ((lon2 - lon1) * Math.PI) / 180;\n\n const a =\n Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) +\n Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n\nexport function compactId(timestamp: number): string {\n // Use a compact representation of the timestamp (seconds since epoch)\n // 1712650000 -> Base64\n const buf = new Uint32Array([Math.floor(timestamp / 1000)]);\n const b64 = btoa(String.fromCharCode(...new Uint8Array(buf.buffer)));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\nexport function shortRandom(): string {\n return Math.random().toString(36).slice(2, 6);\n}\n\nexport function fmtDuration(s: number): string {\n if (s < 60) return `${Math.round(s)}s`;\n if (s < 3600) return `${Math.round(s / 60)}m`;\n return `${Math.round(s / 3600)}h`;\n}\n\nexport function fmtSecs(s: number): string {\n const h = Math.floor(s / 3600),\n m = Math.floor((s % 3600) / 60);\n return h > 0 ? `${h}h ${m}m` : `${m}m ${Math.floor(s % 60)}s`;\n}\n\nexport function fmtPace(seconds: number | null): string {\n if (seconds == null || !isFinite(seconds)) return '--';\n const mins = Math.floor(seconds / 60);\n const secs = Math.round(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nexport function fmtDate(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown date';\n return d.toISOString().split('T')[0];\n}\n\nexport function fmtDateTime(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown';\n const iso = d.toISOString();\n return `${iso.split('T')[0]} ${iso.split('T')[1].slice(0, 5)}`;\n}\n\nexport function fmtFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function escHtml(str: string): string {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function getTagColor(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);\n\n const h = Math.abs(hash % 360);\n return `hsl(${h}, 70%, 65%)`;\n}\n\n/**\n * Smoothes a numeric array using a simple Gaussian kernel.\n * sigma: standard deviation (radius of smoothing)\n */\nexport function gaussianSmooth(data: (number | null)[], sigma: number = 2): (number | null)[] {\n if (sigma <= 0) return data;\n\n const size = Math.ceil(sigma * 3) * 2 + 1;\n const kernel = new Float32Array(size);\n const half = Math.floor(size / 2);\n let sum = 0;\n\n for (let i = 0; i < size; i++) {\n const x = i - half;\n kernel[i] = Math.exp(-(x * x) / (2 * sigma * sigma));\n sum += kernel[i];\n }\n for (let i = 0; i < size; i++) kernel[i] /= sum;\n\n const result: (number | null)[] = new Array(data.length);\n for (let i = 0; i < data.length; i++) {\n if (data[i] === null) {\n result[i] = null;\n continue;\n }\n\n let val = 0;\n let weightSum = 0;\n for (let k = 0; k < size; k++) {\n const idx = i + k - half;\n if (idx >= 0 && idx < data.length && data[idx] !== null) {\n val += data[idx]! * kernel[k];\n weightSum += kernel[k];\n }\n }\n result[i] = weightSum > 0 ? val / weightSum : data[i];\n }\n return result;\n}\n\nexport function hexToRgba(hex: string, alpha: number = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, TrackPoint } from './parsers';\n\nexport const MapView = (() => {\n let trackData: Record = {};\n let customClickHandler: ((e: any) => boolean) | null = null;\n\n function init(\n onSelectCb: (id: string) => void,\n onMoveCb: (lat: number, lng: number, zoom: number) => void,\n onPointClickCb: (id: string, idx: number) => void,\n onPointHoverCb: (id: string | null, idx: number | null) => void,\n onDblClickCb: () => void,\n ) {}\n\n function switchBasemap(layer: string) {}\n function addTrack(t: TrackData) {\n trackData[t.id] = t;\n }\n function addTracks(ts: TrackData[]) {\n ts.forEach((t) => {\n trackData[t.id] = t;\n });\n }\n function removeTrack(id: string) {\n delete trackData[id];\n }\n function clearTracks() {\n trackData = {};\n }\n function removeAllTracks() {\n trackData = {};\n }\n function setTrackVisible(id: string, visible: boolean) {}\n function setSelectedTrack(id: string | null, fit: boolean) {}\n function fitAll() {}\n function fitTrack(id: string) {}\n function showCursorAt(lat: number, lon: number) {}\n function hideCursor() {}\n function highlightSegment(\n id: string | null,\n pts: TrackPoint[],\n start: number,\n end: number,\n fit?: boolean,\n colors?: string[] | null,\n ) {}\n function clearHighlight() {}\n function setTrackHover(id: string, hover: boolean) {}\n function ensureVisible(pts: any) {}\n function centerOn(lat: number, lon: number, zoom?: number | null, force?: boolean) {}\n function closePopup() {}\n function invalidateSize() {}\n function getPosition(): [number, number, number] {\n return [0, 0, 0];\n }\n function setPosition(lat: number, lng: number, zoom: number) {}\n function colorTrackByMetric(id: string, pts: TrackPoint[], colors: string[]) {}\n function clearMetricColor(id: string) {}\n\n function findTracksPassingThroughPoints(\n points: { lat: number; lng: number }[],\n radius: number,\n ): string[] {\n return Object.keys(trackData);\n }\n\n return {\n init,\n getMap: () => null as any,\n setCustomClickHandler: (handler: any) => {\n customClickHandler = handler;\n },\n switchBasemap,\n addTrack,\n addTracks,\n removeTrack,\n clearTracks,\n removeAllTracks,\n setTrackVisible,\n setSelectedTrack,\n fitAll,\n fitTrack,\n showCursorAt,\n hideCursor,\n highlightSegment,\n clearHighlight,\n setTrackHover,\n ensureVisible,\n centerOn,\n closePopup,\n invalidateSize,\n getPosition,\n setPosition,\n colorTrackByMetric,\n clearMetricColor,\n findTracksPassingThroughPoints,\n getTrackData: (id: string) => trackData[id],\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackPoint, TrackStats, TrackData } from './parsers';\nimport { gaussianSmooth, fmtSecs, hexToRgba, fmtPace } from './utils';\nimport { Zones } from './zones';\nimport { METRICS, MetricDefinition } from './metrics';\nimport { UrlState } from './url-state';\nimport { SPORTS } from './sports';\n\n// Augment uPlot to include our custom property\n\ninterface WegPlot extends uPlot {\n _strasse?: {\n selFill: HTMLElement;\n anchorLine: HTMLElement;\n anchorLabel: HTMLElement;\n anchorHandle: HTMLElement;\n anchorMarker: HTMLElement;\n endLine: HTMLElement;\n endLabel: HTMLElement;\n endHandle: HTMLElement;\n endMarker: HTMLElement;\n curYVal: HTMLElement;\n updateHeaderStats: (min: number, max: number) => void;\n };\n}\n\ninterface PlotData {\n uplot: WegPlot;\n row: HTMLDivElement;\n xData: number[];\n yData: (number | null)[];\n def: MetricDefinition;\n metricKey: string;\n statsTotalEl: HTMLDivElement;\n statsSelEl: HTMLDivElement;\n histCol: HTMLDivElement;\n histCanvas: HTMLCanvasElement;\n histData: HistData;\n hoveredHistY: number | null;\n pinnedHistY: number | null;\n smoothed?: boolean;\n incZero?: boolean;\n w?: number;\n}\n\ninterface HistData {\n yData: (number | null)[];\n xData: number[];\n def: MetricDefinition;\n BINS: number;\n plot?: PlotData;\n bins?: number[];\n binAccum?: number[];\n min?: number;\n max?: number;\n padL?: number;\n selBins?: number[] | null;\n selBinAccum?: number[] | null;\n _lastYData?: any;\n _lastSelRange?: [number, number] | null;\n fullStats?: { min: number; max: number; avg: number } | null;\n fullStatsAll?: { min: number; max: number; avg: number } | null;\n}\n\nexport const ChartView = (() => {\n let plots: PlotData[] = [];\n let renderedTrack: TrackData | null = null;\n let renderedXAxis: string = 'time';\n let renderedSpeedMode: string = 'speed';\n let renderedMapColorMetric: string | null = null;\n let syncKey: {\n key: string;\n sub: (u: uPlot) => void;\n unsub: (u: uPlot) => void;\n pub: (type: string, u: uPlot, x: number, y: number, w: number, h: number, i: number) => void;\n } | null = null;\n let scaleSyncing: boolean = false;\n let cursorSyncing: boolean = false;\n let activeMetrics: Set = new Set(['elevation']);\n let availableMetrics: Set = new Set();\n let smoothedMetrics: Set = new Set(['speed', 'gradient', 'vam', 'temperature']);\n let metricsIncludingZero: Set = new Set(['power']);\n let xAxis: string = 'time';\n let currentTrack: TrackData | null = null;\n let allTracks: TrackData[] = [];\n\n // Selection / anchor\n let selAnchorVal: number | null = null; // x-value at drag-start / zoom left edge\n let selEndVal: number | null = null; // x-value at zoom right edge\n let isDragging: boolean = false;\n let updatingRange: boolean = false; // guard against setScale hook re-entry during handle drag\n let pinnedPtIdx: number | null = null; // point index pinned by map click\n let lastMouseXVal: number | null = null; // last hovered x-value for keyboard zoom center\n let lastHistMouseEvent: MouseEvent | null = null;\n let hoveredHistData: HistData | null = null;\n let hoveredHistCanvas: HTMLCanvasElement | null = null;\n\n let currentXRange: [number, number] | null = null; // [min, max] currently rendered\n let targetXRange: [number, number] | null = null; // [min, max] for smooth keyboard animation\n let animId: number | null = null;\n\n // Callbacks\n let onCursorMoveCb: ((pt: TrackPoint | null) => void) | null = null;\n let onRangeChangeCb: ((min: number | null, max: number | null, axis: string) => void) | null =\n null;\n let onClickCb: ((pt: TrackPoint, idx: number) => void) | null = null;\n let onPinChangeCb: ((idx: number | null) => void) | null = null;\n\n const HIST_W: number = 130;\n const ROW_BODY_PADDING: number = 28; // 14px left + 14px right\n const HIST_GAP: number = 20; // margin-left on .hist-col\n let statsVisible: boolean = true;\n let histTooltipEl: HTMLElement | null = null;\n let container: HTMLElement | null = null;\n let emptyEl: HTMLElement | null = null;\n let selStatsEl: HTMLElement | null = null;\n let resetSelBtn: HTMLElement | null = null;\n let mapColorMetric: string | null = null;\n let onMapColorChangeCb: ((data: { pts: TrackPoint[]; colors: string[] } | null) => void) | null =\n null;\n\n // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function init(\n onCursorMove: (pt: TrackPoint | null) => void,\n onRangeChange: (min: number | null, max: number | null, axis: string) => void,\n onClick: (pt: TrackPoint, idx: number) => void,\n onPinChange: (idx: number | null) => void,\n ) {\n onCursorMoveCb = onCursorMove;\n onRangeChangeCb = onRangeChange;\n onClickCb = onClick;\n onPinChangeCb = onPinChange;\n container = document.getElementById('charts-container');\n container?.addEventListener('scroll', () => {\n if (lastHistMouseEvent && hoveredHistCanvas && hoveredHistData)\n updateHistTooltip(lastHistMouseEvent, hoveredHistCanvas, hoveredHistData);\n });\n emptyEl = document.getElementById('chart-empty');\n selStatsEl = document.getElementById('chart-stats-sel');\n resetSelBtn = document.getElementById('btn-reset-selection');\n histTooltipEl = document.getElementById('hist-tooltip');\n syncKey = uPlot.sync('strasse-sync');\n\n document.getElementById('sel-cancel-btn')?.addEventListener('click', cancelSelection);\n resetSelBtn?.classList.add('hidden');\n\n // \u2500\u2500 WASD Keyboard Navigation \u2500\u2500\n const navKeys = new Set(['w', 'a', 's', 'd']);\n const activeNavKeys = new Set();\n\n document.addEventListener('keydown', (e) => {\n if (!plots.length || !currentTrack) return;\n if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName || '')) return;\n\n const key = e.key.toLowerCase();\n if (!navKeys.has(key)) return;\n\n e.preventDefault();\n activeNavKeys.add(key);\n\n const u = plots[0].uplot;\n if (!targetXRange) targetXRange = [u.scales.x!.min!, u.scales.x!.max!];\n\n let [min, max] = targetXRange;\n const span = max - min;\n const moveStep = span * 0.1;\n const zoomFactor = 0.15;\n\n let newMin = min,\n newMax = max;\n\n if (key === 'a') {\n // Pan left\n newMin = min - moveStep;\n newMax = max - moveStep;\n } else if (key === 'd') {\n // Pan right\n newMin = min + moveStep;\n newMax = max + moveStep;\n } else if (key === 'w' || key === 's') {\n // Zoom\n const center = lastMouseXVal !== null ? lastMouseXVal : (min + max) / 2;\n const factor = key === 'w' ? 1 - zoomFactor : 1 + zoomFactor * 1.2;\n newMin = center - (center - min) * factor;\n newMax = center + (max - center) * factor;\n }\n\n // Clamp to track bounds\n const xFull = [plots[0].xData[0]!, plots[0].xData[plots[0].xData.length - 1]!];\n if (newMin < xFull[0]) {\n const d = xFull[0] - newMin;\n newMin += d;\n newMax += d;\n }\n if (newMax > xFull[1]) {\n const d = newMax - xFull[1];\n newMin -= d;\n newMax -= d;\n }\n newMin = Math.max(xFull[0], newMin);\n newMax = Math.min(xFull[1], newMax);\n\n if (newMax - newMin > 0.001) {\n targetXRange = [newMin, newMax];\n setVisibleRange(newMin, newMax, true); // true = animate\n }\n });\n\n document.addEventListener('keyup', (e) => {\n const key = e.key.toLowerCase();\n if (navKeys.has(key)) activeNavKeys.delete(key);\n });\n }\n\n function setVisibleRange(min: number, max: number, animate = false) {\n if (!plots.length) return;\n if (!animate) {\n plots.forEach(({ uplot: u }) => u.setScale('x', { min, max }));\n return;\n }\n\n const startMin = (currentXRange ? currentXRange[0] : plots[0].uplot.scales.x!.min) as number;\n const startMax = (currentXRange ? currentXRange[1] : plots[0].uplot.scales.x!.max) as number;\n\n if (animId) cancelAnimationFrame(animId);\n\n const lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n const factor = 0.25; // Smoothing factor\n\n const step = () => {\n if (!targetXRange) return;\n const [tMin, tMax] = targetXRange;\n\n const cMin = lerp(currentXRange![0], tMin, factor);\n const cMax = lerp(currentXRange![1], tMax, factor);\n\n plots.forEach(({ uplot: u }) => {\n u.setScale('x', { min: cMin, max: cMax });\n });\n\n if (Math.abs(cMin - tMin) > 0.0001 || Math.abs(cMax - tMax) > 0.0001)\n animId = requestAnimationFrame(step);\n else animId = null;\n };\n animId = requestAnimationFrame(step);\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function loadTrack(track: TrackData, others: TrackData[] = [], deferRender = false) {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n allTracks = others;\n\n // Detect which metrics are available in this file\n availableMetrics = new Set(\n Object.entries(METRICS)\n .filter(([, def]) => track.points.some((p) => p[def.field] != null))\n .map(([key]) => key),\n );\n\n // If no metrics are active (e.g. first load), default to core overview metrics\n if (activeMetrics.size === 0) {\n activeMetrics = new Set(['elevation'].filter((m) => availableMetrics.has(m)));\n }\n\n // Sync the pill buttons in the toolbar\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n const metric = pill.dataset.metric!;\n const isAvailable = availableMetrics.has(metric);\n pill.classList.toggle('active', isAvailable && activeMetrics.has(metric));\n pill.classList.toggle('disabled', !isAvailable);\n });\n\n currentTrack = track;\n if (deferRender) {\n updateStats(track);\n } else {\n render();\n }\n }\n\n function clear() {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n currentTrack = null;\n destroyPlots();\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
Select a track to view analysis
\n `;\n }\n const chartStats = document.getElementById('chart-stats');\n if (chartStats) chartStats.classList.add('hidden');\n clearSelectionStats();\n mapColorMetric = null;\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n }\n\n function resetState() {\n if (animId !== null) {\n cancelAnimationFrame(animId);\n animId = null;\n }\n activeMetrics = new Set(['elevation']);\n availableMetrics = new Set();\n smoothedMetrics = new Set(['speed', 'gradient', 'vam', 'temperature']);\n metricsIncludingZero = new Set(['power']);\n xAxis = 'time';\n allTracks = [];\n currentXRange = null;\n targetXRange = null;\n lastMouseXVal = null;\n lastHistMouseEvent = null;\n hoveredHistData = null;\n hoveredHistCanvas = null;\n statsVisible = true;\n clear();\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n pill.classList.remove('disabled', 'overflow-hidden');\n });\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.add('hidden');\n const toolbar = document.getElementById('chart-toolbar');\n if (toolbar) toolbar.classList.remove('collapsed');\n document.querySelectorAll('#x-axis-ctrl .seg-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.axis === 'time');\n });\n }\n\n function toggleMetric(key: string) {\n if (activeMetrics.has(key)) activeMetrics.delete(key);\n else activeMetrics.add(key);\n if (currentTrack) render(true);\n }\n\n function setActiveMetrics(keys: string[]) {\n activeMetrics = new Set(keys);\n if (currentTrack) render(true);\n // Sync the pill buttons\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n });\n }\n\n function setXAxis(axis: string) {\n if (xAxis === axis || !currentTrack) {\n xAxis = axis;\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n\n // Helper to convert a value from OLD axis to NEW axis\n const convert = (val: number | null) => {\n if (val === null) return null;\n // We need to find the point index closest to 'val' on the OLD axis\n let idx = 0;\n if (xAxis === 'distance') {\n const dTarget = val * 1000;\n idx = pts.findIndex((p) => (p.dist || 0) >= dTarget);\n } else {\n const tTarget = t0 + val * 1000;\n idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n }\n if (idx === -1) idx = pts.length - 1;\n\n // Now get the value at this index on the NEW axis\n if (axis === 'distance') return (pts[idx].dist || 0) / 1000;\n else return ((pts[idx].time || t0) - t0) / 1000;\n };\n\n // Convert selection\n if (selAnchorVal !== null) selAnchorVal = convert(selAnchorVal);\n if (selEndVal !== null) selEndVal = convert(selEndVal);\n\n // Convert zoom range (from first plot)\n let newRange: [number, number] | null = null;\n if (plots.length) {\n const u = plots[0].uplot;\n const r0 = convert(u.scales.x!.min!);\n const r1 = convert(u.scales.x!.max!);\n if (r0 !== null && r1 !== null) newRange = [r0, r1];\n }\n\n xAxis = axis;\n render(true);\n\n // Apply converted zoom\n if (newRange) {\n scaleSyncing = true;\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: newRange![0], max: newRange![1] }));\n });\n scaleSyncing = false;\n }\n }\n\n function toggleStats() {\n statsVisible = !statsVisible;\n plots.forEach(({ histCol }) => histCol.classList.toggle('visible', statsVisible));\n resize();\n }\n\n function setMapColorChangeCb(cb: (data: { pts: TrackPoint[]; colors: string[] } | null) => void) {\n onMapColorChangeCb = cb;\n }\n\n function toggleMapColor(key: string | null) {\n if (mapColorMetric === key || key === null) {\n mapColorMetric = null;\n _updateMapColorBtns();\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n } else {\n mapColorMetric = key;\n _updateMapColorBtns();\n _fireMapColorCb();\n }\n // Re-render to show/hide colored fills on the graphs\n if (currentTrack) render(true);\n }\n\n function _updateMapColorBtns() {\n document.querySelectorAll('.map-color-btn').forEach((el) => {\n const b = el as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === mapColorMetric);\n });\n }\n\n function _fireMapColorCb() {\n if (!onMapColorChangeCb || !mapColorMetric || !currentTrack) return;\n const plot = plots.find((p) => p.metricKey === mapColorMetric);\n if (!plot) return;\n const colors = _computePointColors(mapColorMetric, plot.yData);\n onMapColorChangeCb({ pts: currentTrack.points, colors });\n }\n\n function _computePointColors(key: string, yData: (number | null)[]): string[] {\n const vals = yData.filter((v): v is number => v != null && isFinite(v));\n if (!vals.length) return yData.map(() => '#888896');\n const min = Math.min(...vals),\n max = Math.max(...vals);\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n return yData.map((v) => {\n if (v == null || !isFinite(v)) return '#888896';\n if (key === 'gradient') return gradientColor(v);\n if (key === 'speed') {\n if (speedMode === 'pace') {\n const speed = (paceUnit === 'km' ? 1000 : 100) / v;\n return speedColor(speed);\n }\n return speedColor(v);\n }\n const t = max === min ? 0.5 : Math.max(0, Math.min(1, (v - min) / (max - min)));\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25);\n if (t <= 0.5) return lerpHex('#91bfdb', '#fee090', (t - 0.25) / 0.25);\n if (t <= 0.75) return lerpHex('#fee090', '#fc8d59', (t - 0.5) / 0.25);\n return lerpHex('#fc8d59', '#d73027', (t - 0.75) / 0.25);\n });\n }\n\n function resetZoom() {\n cancelSelection();\n }\n\n function cancelSelection() {\n selAnchorVal = null;\n selEndVal = null;\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n\n // Reset individual histogram pins\n plots.forEach((p) => {\n p.pinnedHistY = null;\n });\n\n updateSelOverlay();\n redrawHistograms();\n\n // Perform the actual zoom reset\n scaleSyncing = true;\n plots.forEach(({ uplot: u, xData }) => {\n u.batch(() => u.setScale('x', { min: xData[0]!, max: xData[xData.length - 1]! }));\n u._strasse?.updateHeaderStats(xData[0]!, xData[xData.length - 1]!);\n });\n scaleSyncing = false;\n\n if (onRangeChangeCb) onRangeChangeCb(null, null, xAxis);\n }\n\n function setSelectionStats(stats: TrackStats) {\n if (!selStatsEl) return;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt(\n 'sel-distance',\n stats.totalDist != null ? `${(stats.totalDist / 1000).toFixed(1)} km` : '\u2014',\n );\n fmt('sel-duration', stats.duration != null ? fmtSecs(Math.floor(stats.duration / 1000)) : '\u2014');\n fmt('sel-elevation', stats.elevGain != null ? `${Math.round(stats.elevGain)} m` : '\u2014');\n fmt(\n 'sel-avg-speed',\n stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014',\n );\n fmt('sel-avg-power', stats.avgPower != null ? `${stats.avgPower} W` : '\u2014');\n fmt('sel-avg-hr', stats.avgHR != null ? `${stats.avgHR} bpm` : '\u2014');\n fmt('sel-avg-temp', stats.avgTemp != null ? `${stats.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n selStatsEl.classList.remove('hidden');\n if (resetSelBtn) resetSelBtn.classList.remove('hidden');\n }\n\n function clearSelectionStats() {\n if (selStatsEl) selStatsEl.classList.add('hidden');\n if (resetSelBtn) resetSelBtn.classList.add('hidden');\n [\n 'sel-distance',\n 'sel-duration',\n 'sel-elevation',\n 'sel-avg-speed',\n 'sel-avg-power',\n 'sel-avg-hr',\n 'sel-avg-temp',\n ].forEach((id) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = '--';\n });\n }\n\n // Called on boot to restore a saved selection without re-firing onRangeChangeCb\n // xMin/xMax are ALWAYS provided in Time (seconds from start)\n function restoreSelection(tMin: number, tMax: number, deferRender = false) {\n if (!currentTrack) return;\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const totalDuration = ((pts[pts.length - 1]?.time || 0) - t0) / 1000;\n\n // If values look like absolute timestamps in ms, convert to seconds from start\n if (tMin > 1e12) tMin = (tMin - t0) / 1000;\n if (tMax > 1e12) tMax = (tMax - t0) / 1000;\n\n // Crop to max limits of the track\n tMin = Math.max(0, Math.min(tMin, totalDuration));\n tMax = Math.max(0, Math.min(tMax, totalDuration));\n\n const convert = (tOffset: number) => {\n if (xAxis === 'time') return tOffset;\n const tTarget = t0 + tOffset * 1000;\n let idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n if (idx === -1) idx = pts.length - 1;\n return (pts[idx].dist || 0) / 1000;\n };\n\n const xMin = convert(tMin);\n const xMax = convert(tMax);\n\n selAnchorVal = xMin;\n selEndVal = xMax;\n currentXRange = [xMin, xMax];\n if (deferRender) return;\n scaleSyncing = true; // suppress the setScale \u2192 onRangeChangeCb loop\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: xMin, max: xMax }));\n });\n scaleSyncing = false;\n updateAnchorLines();\n redrawHistograms();\n }\n\n function resize() {\n if (!plots.length || !container) return;\n const w = Math.round(\n Math.max(\n 100,\n container.getBoundingClientRect().width -\n ROW_BODY_PADDING -\n (statsVisible ? HIST_W + HIST_GAP : 0),\n ),\n );\n let anyResized = false;\n plots.forEach(({ uplot: u, histCanvas, histData }) => {\n if (w !== u.width) {\n u.setSize({ width: w, height: u.height });\n anyResized = true;\n if (statsVisible && histCanvas && histData) drawHistogram(histCanvas, histData, u.height);\n }\n });\n if (anyResized) updateSelOverlay();\n }\n\n // \u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function render(keepState = false) {\n let savedRange: [number, number] | null = null;\n let savedScroll = 0;\n if (keepState && container) savedScroll = container.scrollTop;\n\n if (keepState && currentXRange) {\n savedRange = [currentXRange[0], currentXRange[1]];\n } else if (keepState && plots.length) {\n const u = plots[0].uplot;\n savedRange = [u.scales.x!.min!, u.scales.x!.max!];\n }\n\n if (!currentTrack) {\n destroyPlots(keepState);\n return;\n }\n const pts = currentTrack.points;\n if (!pts.length) {\n destroyPlots(keepState);\n return;\n }\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n const available = [...activeMetrics].filter((m) =>\n pts.some((p) => p[METRICS[m].field] != null),\n );\n if (!available.length) {\n destroyPlots(keepState);\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
No data for selected metrics
\n `;\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n\n const containerW = container ? container.getBoundingClientRect().width : 800;\n const w = Math.round(\n Math.max(100, containerW - ROW_BODY_PADDING - (statsVisible ? HIST_W + HIST_GAP : 0)),\n );\n\n const canReuse =\n keepState &&\n renderedTrack === currentTrack &&\n renderedXAxis === xAxis &&\n renderedSpeedMode === speedMode &&\n renderedMapColorMetric === mapColorMetric &&\n plots.length > 0;\n\n let xData: (number | null)[];\n if (canReuse) {\n xData = plots[0].xData;\n } else if (xAxis === 'distance') {\n xData = pts.map((p) => (p.dist || 0) / 1000);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n let lastValidX = 0;\n xData = pts.map((p) => {\n if (p.time != null) {\n lastValidX = (p.time - t0) / 1000;\n return lastValidX;\n }\n return lastValidX; // monotonic fallback\n });\n }\n\n const existingByKey = new Map();\n if (canReuse) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const availSet = new Set(available);\n for (const p of plots) {\n const isSmoothed = smoothedMetrics.has(p.metricKey);\n const isIncZero = metricsIncludingZero.has(p.metricKey);\n if (\n availSet.has(p.metricKey) &&\n p.smoothed === isSmoothed &&\n p.incZero === isIncZero &&\n p.w === w\n ) {\n existingByKey.set(p.metricKey, p);\n } else {\n syncKey!.unsub(p.uplot);\n p.uplot.destroy();\n p.row.remove();\n }\n }\n plots = [];\n } else {\n destroyPlots(keepState);\n }\n\n if (container) {\n const nextSiblingRows: (HTMLElement | null)[] = new Array(available.length).fill(null);\n let nextExisting: HTMLElement | null = null;\n for (let i = available.length - 1; i >= 0; i--) {\n nextSiblingRows[i] = nextExisting;\n const ex = existingByKey.get(available[i]);\n if (ex) nextExisting = ex.row;\n }\n\n available.forEach((key, idx) => {\n const reused = existingByKey.get(key);\n if (reused) {\n plots.push(reused);\n const uplot = reused.uplot;\n const s = (uplot as any)._strasse;\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n uplot.batch(() => {\n if (\n savedRange &&\n (uplot.scales.x!.min !== savedRange[0] || uplot.scales.x!.max !== savedRange[1])\n ) {\n uplot.setScale('x', { min: savedRange[0], max: savedRange[1] });\n } else {\n s?.updateHeaderStats(uplot.scales.x!.min!, uplot.scales.x!.max!, uplot);\n uplot.redraw(false);\n }\n });\n scaleSyncing = prevSync;\n\n let initHoverBinI: number | null = null;\n if (\n pinnedPtIdx != null &&\n reused.xData[pinnedPtIdx] != null &&\n reused.yData[pinnedPtIdx] != null\n ) {\n buildHistBins(reused.histData);\n if (reused.histData.min != null && reused.histData.max != null) {\n const span = reused.histData.max - reused.histData.min || 1;\n initHoverBinI = Math.min(\n reused.histData.BINS - 1,\n Math.floor(\n ((reused.yData[pinnedPtIdx]! - reused.histData.min) / span) *\n reused.histData.BINS,\n ),\n );\n reused.hoveredHistY = reused.yData[pinnedPtIdx];\n }\n }\n drawHistogram(reused.histCanvas, reused.histData, 130, initHoverBinI);\n return;\n }\n\n let def = METRICS[key];\n\n let transform = def.transform;\n let fmt = def.fmt;\n let fmtAxis = def.fmtAxis;\n let unit = def.unit;\n let label = def.label;\n\n if (key === 'speed' && speedMode === 'pace') {\n label = 'Pace';\n unit = `min/${paceUnit}`;\n fmt = (v) => fmtPace(v);\n fmtAxis = (v) => fmtPace(v);\n transform = (v) => {\n if (v == null || v < 0.1) return null;\n return (paceUnit === 'km' ? 1000 : 100) / v;\n };\n\n def = { ...def, label, unit, fmt, fmtAxis, transform };\n }\n\n let yData = def.compute\n ? def.compute(pts, fillNulls)\n : fillNulls(\n pts.map((p) => {\n const v = p[def.field] as number;\n return v != null && transform ? transform(v) : v;\n }),\n );\n\n if (smoothedMetrics.has(key)) yData = gaussianSmooth(yData, def.smoothSigma || 2);\n\n createChart(key, def, xData, yData, w, pts, savedRange, nextSiblingRows[idx]);\n });\n }\n\n renderedTrack = currentTrack;\n renderedXAxis = xAxis;\n renderedSpeedMode = speedMode;\n renderedMapColorMetric = mapColorMetric;\n\n updateStats(currentTrack);\n // Restore anchor/end lines if a selection was active\n if (selAnchorVal != null && selEndVal != null) updateAnchorLines();\n // Re-apply map color if active\n _updateMapColorBtns();\n if (mapColorMetric) _fireMapColorCb();\n\n if (keepState && container && savedScroll > 0) container.scrollTop = savedScroll;\n }\n\n // \u2500\u2500 Create one chart row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function createChart(\n metricKey: string,\n def: MetricDefinition,\n xData: (number | null)[],\n yData: (number | null)[],\n w: number,\n pts: TrackPoint[],\n initialRange: [number, number] | null = null,\n insertBeforeEl: HTMLElement | null = null,\n ) {\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n\n // Gradient data: smooth over a 20 m distance window (\u00B110 m each side)\n const gradData = metricKey === 'elevation' ? smoothGradient(pts, 20) : null;\n const row = document.createElement('div');\n row.className = 'chart-row';\n row.dataset.metric = metricKey;\n row.style.setProperty('--chart-color', def.color);\n\n // Header\n const header = document.createElement('div');\n header.className = `chart-row-header${statsVisible ? ' with-histogram' : ''}`;\n\n const labelEl = document.createElement('div');\n labelEl.className = 'chart-row-label-group';\n labelEl.innerHTML = `\n ${def.icon}\n ${def.label}\n `;\n\n // Smoothing toggle\n const smoothBtn = document.createElement('button');\n smoothBtn.className = `icon-btn mini smooth-btn${smoothedMetrics.has(metricKey) ? ' active' : ''}`;\n smoothBtn.title = 'Toggle data smoothing';\n smoothBtn.innerHTML = `${smoothedMetrics.has(metricKey) ? 'blur_on' : 'blur_off'}`;\n smoothBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (smoothedMetrics.has(metricKey)) smoothedMetrics.delete(metricKey);\n else smoothedMetrics.add(metricKey);\n\n render(true); // Re-render all charts to keep sync if needed (though only this one changes data)\n });\n\n const mapColorBtn = document.createElement('button');\n\n mapColorBtn.className = `map-color-btn icon-btn${mapColorMetric === metricKey ? ' active' : ''}`;\n mapColorBtn.dataset.metric = metricKey;\n mapColorBtn.title = 'Color map track by this metric';\n mapColorBtn.innerHTML = 'colorize';\n mapColorBtn.addEventListener('click', () => toggleMapColor(metricKey));\n\n // Zero-filter toggle (Cadence/Power/Speed)\n let zeroBtn: HTMLButtonElement | null = null;\n if (metricKey === 'cadence' || metricKey === 'power' || metricKey === 'speed') {\n zeroBtn = document.createElement('button');\n const incZero = metricsIncludingZero.has(metricKey);\n zeroBtn.className = `icon-btn mini${incZero ? ' active' : ''}`;\n zeroBtn.title = incZero ? 'Currently INCLUDING 0 values' : 'Currently EXCLUDING 0 values';\n zeroBtn.innerHTML = `${incZero ? 'exposure_zero' : 'mobile_off'}`;\n zeroBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (metricsIncludingZero.has(metricKey)) metricsIncludingZero.delete(metricKey);\n else metricsIncludingZero.add(metricKey);\n render(true);\n });\n }\n\n const statsTotalEl = document.createElement('div');\n statsTotalEl.className = 'chart-stats-total';\n\n const statsSelEl = document.createElement('div');\n statsSelEl.className = 'chart-stats-selection';\n\n const statsContainer = document.createElement('div');\n statsContainer.className = 'chart-row-stats-container';\n statsContainer.append(statsTotalEl, statsSelEl);\n\n const actionsEl = document.createElement('div');\n actionsEl.className = 'chart-row-actions';\n actionsEl.append(smoothBtn, mapColorBtn);\n\n const rightActionsEl = document.createElement('div');\n rightActionsEl.className = 'chart-row-right-actions';\n\n if (metricKey === 'speed') {\n const paceToggle = document.createElement('div');\n paceToggle.className = 'seg-ctrl';\n paceToggle.innerHTML = `\n \n \n `;\n paceToggle.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const mode = btn.dataset.mode;\n if (mode === 'speed' || mode === 'pace') {\n const isDefault = mode === defaultMode;\n UrlState.patch({ speed_mode: isDefault ? null : mode });\n render(true);\n }\n });\n rightActionsEl.append(paceToggle);\n }\n\n if (zeroBtn) rightActionsEl.append(zeroBtn);\n\n header.append(labelEl, actionsEl, statsContainer, rightActionsEl);\n\n const rowBody = document.createElement('div');\n rowBody.className = 'chart-row-body';\n\n const plotEl = document.createElement('div');\n plotEl.style.position = 'relative';\n rowBody.appendChild(plotEl);\n\n const fixedMinLabel = document.createElement('div');\n fixedMinLabel.className = 'fixed-x-label fixed-x-min';\n const fixedMaxLabel = document.createElement('div');\n fixedMaxLabel.className = 'fixed-x-label fixed-x-max';\n plotEl.append(fixedMinLabel, fixedMaxLabel);\n\n const histCol = document.createElement('div');\n histCol.className = `hist-col${statsVisible ? ' visible' : ''}`;\n const histCanvas = document.createElement('canvas');\n histCanvas.className = 'hist-canvas';\n histCol.appendChild(histCanvas);\n rowBody.appendChild(histCol);\n\n row.append(header, rowBody);\n\n const isDistAxis = xAxis === 'distance';\n\n function formatX(v: number, range: number): string {\n if (v == null) return '';\n if (isDistAxis) {\n const dec = range < 1 ? 3 : range < 5 ? 2 : range < 20 ? 1 : 0;\n return `${v.toFixed(dec)} km`;\n } else {\n const absV = Math.abs(v);\n const h = Math.floor(absV / 3600);\n const m = Math.floor((absV % 3600) / 60);\n const s = Math.round(absV % 60);\n const hh = h > 0 ? `${h}:` : '';\n const mm = h > 0 ? String(m).padStart(2, '0') : String(m);\n const ss = String(s).padStart(2, '0');\n return `${v < 0 ? '-' : ''}${hh}${mm}:${ss}`;\n }\n }\n\n const incZeroDefault =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Compute global Y range and full-track stats in a single pass\n let gMin = Infinity,\n gMax = -Infinity,\n allSum = 0,\n allCount = 0,\n filtMin = Infinity,\n filtMax = -Infinity,\n filtSum = 0,\n filtCount = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n allSum += v;\n allCount++;\n if (v !== 0 || incZeroDefault) {\n if (v < filtMin) filtMin = v;\n if (v > filtMax) filtMax = v;\n filtSum += v;\n filtCount++;\n }\n }\n if (allCount === 0) {\n gMin = 0;\n gMax = 100;\n }\n const fullStatsAll = allCount ? { min: gMin, max: gMax, avg: allSum / allCount } : null;\n const fullStatsFiltered = filtCount\n ? { min: filtMin, max: filtMax, avg: filtSum / filtCount }\n : null;\n const gPad = Math.abs(gMax - gMin) * 0.1 || 1;\n const fixedYRange = [gMin - gPad, gMax + gPad];\n\n let statsTotalInitialized = false;\n\n // Per-range stats\n function updateHeaderStats(visibleMin: number, visibleMax: number, u?: uPlot) {\n const incZero =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Update fixed X labels\n const range = visibleMax - visibleMin;\n fixedMinLabel.textContent = formatX(visibleMin, range);\n fixedMaxLabel.textContent = formatX(visibleMax, range);\n\n const getHtml = (xMin: number, xMax: number, isFull = false) => {\n const s =\n isFull && incZero === incZeroDefault\n ? fullStatsFiltered\n : rangeStats(xData, yData, xMin, xMax, incZero);\n if (!s) return '';\n\n let h = `\n align_flex_end${def.fmt(s.min, true)} ${def.unit}\n align_center${def.fmt(s.avg, true)} ${def.unit}\n align_flex_start${def.fmt(s.max, true)} ${def.unit}\n `;\n\n if (metricKey === 'elevation') {\n const es = elevationRangeStats(pts, xMin, xMax);\n h += `\n trending_up+${Math.round(es.gain)} m\n trending_down-${Math.round(es.loss)} m\n `;\n }\n return h;\n };\n\n if (!statsTotalInitialized) {\n statsTotalInitialized = true;\n statsTotalEl.innerHTML = `all_inclusive${getHtml(\n xData[0]!,\n xData[xData.length - 1]!,\n true,\n )}`;\n statsTotalEl.querySelector('.all-chip')?.addEventListener('click', (e) => {\n e.stopPropagation();\n cancelSelection();\n });\n }\n\n if (selAnchorVal !== null && selEndVal !== null) {\n statsSelEl.innerHTML = getHtml(selAnchorVal, selEndVal, false);\n statsSelEl.style.display = 'flex';\n statsSelEl.style.setProperty('--sel-color', def.color);\n } else {\n statsSelEl.style.display = 'none';\n }\n }\n let initializingScale = false;\n const uOpts: uPlot.Options = {\n width: w,\n height: 130,\n padding: [4, 0, 0, 0],\n cursor: {\n sync: {\n key: syncKey!.key,\n },\n drag: { x: true, y: false, uni: 16 },\n focus: { prox: 16 },\n points: {\n size: 7,\n stroke: '#0e0e10',\n width: 2,\n fill: (metricKey === 'elevation'\n ? (u: uPlot, _si: number) => gradientColor(gradData ? gradData[u.cursor.idx!]! : null)\n : def.color) as any,\n },\n x: false,\n y: false,\n },\n select: {\n show: true,\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n },\n legend: { show: false },\n scales: {\n x: {\n time: false,\n range: (_u: uPlot, mn: number, mx: number) => [mn, mx],\n min: initialRange ? initialRange[0] : undefined,\n max: initialRange ? initialRange[1] : undefined,\n },\n y: {\n range: () => fixedYRange as [number, number],\n dir: metricKey === 'speed' && speedMode === 'pace' ? -1 : 1,\n },\n },\n axes: [\n {\n side: 2, // bottom\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: {\n show: true,\n stroke: '#2e2e34',\n },\n size: 30,\n space: 80,\n font: '10px system-ui, sans-serif',\n splits: (u: uPlot, axisIdx: number, scaleMin: number, scaleMax: number) => {\n const range = scaleMax - scaleMin;\n const width = u.bbox.width > 0 ? u.bbox.width : u.width;\n const targetLabels = width / 80;\n const idealIncr = range / targetLabels;\n\n let incrs;\n if (!isDistAxis) {\n // Time in seconds\n incrs = [\n 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 14400, 28800, 43200,\n 86400, 604800, 2592000, 31536000,\n ];\n } else {\n incrs = [\n 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000,\n 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000,\n ];\n }\n\n let incr = incrs[incrs.length - 1];\n for (let i = 0; i < incrs.length; i++) {\n if (incrs[i] >= idealIncr) {\n incr = incrs[i];\n break;\n }\n }\n\n const splits = [];\n let val = Math.ceil(scaleMin / incr) * incr;\n const precision = incr < 1 ? 2 : 0;\n\n while (val <= scaleMax) {\n const pos = u.valToPos(val, 'x', true);\n if (pos >= u.bbox.left + 80 && pos <= u.bbox.left + u.bbox.width - 80)\n splits.push(Number(val.toFixed(precision)));\n\n val += incr;\n }\n return splits;\n },\n values: ((_u: uPlot, vals: number[]) => {\n const range = (_u.scales.x?.max ?? 1) - (_u.scales.x?.min ?? 0);\n\n return vals.map((v) => {\n if (v == null) return '';\n const pos = _u.valToPos(v, 'x', true);\n // Strict 80px margin to prevent overlapping with fixed labels or Y axis\n if (pos < _u.bbox.left + 80 || pos > _u.bbox.left + _u.bbox.width - 80) return null;\n return formatX(v, range);\n });\n }) as any,\n },\n {\n side: 3, // left\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: { stroke: '#2e2e34' },\n size: 55,\n font: '10px system-ui, sans-serif',\n values: ((_u: uPlot, vals: number[]) =>\n vals.map((v) => (v != null ? def.fmtAxis(v) : ''))) as any,\n },\n ],\n series: [\n {},\n // Main selected track series\n {\n label: def.label,\n stroke: 'rgba(0,0,0,0)', // Stroke handled in draw hooks for layering\n width: 0,\n points: { show: false },\n paths: () => null,\n },\n ],\n hooks: {\n draw: [\n (u: uPlot) => {\n const top = u.bbox.top + u.bbox.height + 5; // 5px below plot area!\n fixedMinLabel.style.top = `${top}px`;\n fixedMinLabel.style.left = `${u.bbox.left}px`;\n\n fixedMaxLabel.style.top = `${top}px`;\n fixedMaxLabel.style.left = `${u.bbox.left + u.bbox.width}px`;\n fixedMaxLabel.style.transform = 'translateX(-100%)';\n },\n // 1. (bottom) Color / metric color of the selected track\n (u: uPlot) => {\n if (metricKey === 'gears') {\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n } else if (metricKey === 'elevation') {\n drawElevationGradient(u, xData as number[], yData as number[], gradData);\n } else if (metricKey === 'gradient') {\n drawGradientChart(u, xData as number[], yData as number[]);\n } else if (mapColorMetric === metricKey) {\n drawMetricColorFill(u, xData as number[], yData as number[], pts, metricKey);\n } else {\n // Normal colored line\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n }\n },\n\n // 2. Pinned point (middle)\n (u: uPlot) => {\n const plot = plots.find((p) => p.uplot === u);\n if (!plot) return;\n\n const s = (u as any)._strasse;\n // Priority 1: Global pinned point (all charts)\n if (pinnedPtIdx != null) {\n drawPinnedDot(u, xData, yData, def.color, def, pts, metricKey);\n } else {\n if (s && s.pinYVal) s.pinYVal.style.display = 'none';\n\n // Priority 2: Individual histogram pinned Y-pos (this chart only)\n if (plot.pinnedHistY != null)\n drawYAxisHighlight(u, xData, yData, plot.pinnedHistY, def.color, def);\n }\n },\n\n // 3. Pinned & Hover elements (labels, vertical lines)\n (u: uPlot) => {\n const hIdx = u.cursor.idx;\n const hasPinned = pinnedPtIdx != null;\n\n let hasHover = hIdx != null && u.cursor.left! >= 0;\n if (hasHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[hIdx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) hasHover = false;\n }\n\n // B. Draw Hover vertical line\n if (hasHover && hIdx !== pinnedPtIdx)\n drawVerticalLineOnly(u, pts, hIdx!, hexToRgba(def.color, 0.4), 1.0);\n\n // C. Bold selection x-axis line & span pill\n if (selAnchorVal != null && selEndVal != null) {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ax = u.valToPos(selAnchorVal, 'x', true);\n const ex = u.valToPos(selEndVal, 'x', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.lineWidth = 3 * dpr;\n ctx.strokeStyle = def.color;\n ctx.moveTo(ax, bb.top + bb.height);\n ctx.lineTo(ex, bb.top + bb.height);\n ctx.stroke();\n\n const span = Math.abs(selEndVal - selAnchorVal);\n const label = xAxis === 'distance' ? `${span.toFixed(2)} km` : fmtSecs(span);\n const fontSize = 9 * dpr;\n const fontStr = `bold ${fontSize}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n\n const visibleL = Math.max(bb.left, ax);\n const visibleR = Math.min(bb.left + bb.width, ex);\n const visibleW = visibleR - visibleL;\n\n if (visibleW > tw + 14 * dpr) {\n const padH = 5 * dpr;\n const padV = 2 * dpr;\n const bw = tw + padH * 2;\n const bh = fontSize + padV * 2;\n const bx = (visibleL + visibleR) / 2 - bw / 2;\n const by = bb.top + bb.height - bh / 2;\n\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = def.color;\n ctx.fill();\n\n ctx.fillStyle = '#000';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2);\n }\n ctx.restore();\n }\n\n // D. Draw label pills (on top)\n // Pinned labels first (semi-transparent)\n if (hasPinned) drawXAxisLabels(u, pts, pinnedPtIdx!, def.color, true, 0.7);\n\n // Hover labels last (fully opaque, topmost)\n if (hasHover && hIdx !== pinnedPtIdx)\n drawXAxisLabels(u, pts, hIdx!, def.color, true, 1.0);\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (scaleSyncing) return;\n const idx = u.cursor.idx;\n\n // Trigger redraw on cursor move to ensure custom canvas markers (hover lines/labels) update live\n // Note: uPlot handles cross-chart sync when syncKey is used.\n u.redraw(false);\n\n // Track current x-value for keyboard navigation\n if (u.cursor.left! >= 0) lastMouseXVal = u.posToVal(u.cursor.left!, 'x');\n else lastMouseXVal = null;\n\n // \u2500\u2500 Floating y-value next to cursor dot \u2500\u2500\n const s = (u as any)._strasse;\n let showHover = idx != null && yData[idx] != null;\n\n // Distance threshold: if no pinned point, check proximity to data line\n if (showHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[idx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) showHover = false;\n }\n\n if (s) {\n if (showHover)\n updateTooltip(\n u,\n s.curYVal,\n idx!,\n xData as number[],\n yData as number[],\n pts,\n def,\n metricKey,\n );\n else s.curYVal.style.display = 'none';\n }\n\n // Map marker\n if (!cursorSyncing) {\n if (idx != null && pts[idx]) {\n if (onCursorMoveCb && (pinnedPtIdx != null || showHover)) {\n onCursorMoveCb(pts[idx]);\n } else if (onCursorMoveCb && !showHover) {\n // If we're too far and nothing is pinned, hide map cursor\n onCursorMoveCb(null);\n }\n } else if (idx === null && onCursorMoveCb) {\n onCursorMoveCb(null);\n }\n }\n\n // Highlight matching histogram bucket\n if (idx != null && yData[idx] != null) {\n const { min, max } = histData;\n if (min != null && max != null) {\n const span = max - min || 1;\n const binI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[idx]! - min) / span) * histData.BINS),\n );\n if (plot.hoveredHistY !== yData[idx]) {\n plot.hoveredHistY = yData[idx];\n drawHistogram(histCanvas, histData, 130, binI);\n }\n }\n } else if (plot.hoveredHistY !== null) {\n plot.hoveredHistY = null;\n drawHistogram(histCanvas, histData, 130);\n }\n },\n ],\n\n setScale: [\n (u: uPlot, key: string) => {\n if (key !== 'x' || initializingScale) return;\n const { min, max } = u.scales.x!;\n\n // Sync currentXRange so keyboard navigation baseline is always accurate\n currentXRange = [min!, max!];\n\n // Update header stats for VISIBLE range\n updateHeaderStats(min as number, max as number, u);\n\n if (scaleSyncing) return;\n\n // Clear keyboard target when user interacts via mouse\n if (!updatingRange) targetXRange = null;\n\n // Sync sibling plots\n scaleSyncing = true;\n plots.forEach(({ uplot: other }) => {\n if (other !== u) other.batch(() => other.setScale('x', { min: min!, max: max! }));\n });\n scaleSyncing = false;\n\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb && selAnchorVal !== null)\n onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n },\n ],\n\n setSelect: [\n (u: uPlot) => {\n if (updatingRange) return;\n targetXRange = null;\n const { left, width } = u.select;\n if (width > 0) {\n const min = u.posToVal(left, 'x');\n const max = u.posToVal(left + width, 'x');\n selAnchorVal = min;\n selEndVal = max;\n\n // Sync stats to new selection\n updateHeaderStats(u.scales.x!.min!, u.scales.x!.max!, u);\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n\n // Clear uPlot's internal selection immediately so it doesn't block WASD/interaction\n u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);\n }\n },\n ],\n },\n };\n\n // \u2500\u2500 Overlay (pointer-events off except handles) \u2500\u2500\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5';\n\n // Selection fill\n const selFill = document.createElement('div');\n selFill.className = 'sel-fill';\n selFill.style.display = 'none';\n\n // Anchor line + label + drag handle\n const anchorLine = document.createElement('div');\n anchorLine.className = 'sel-line sel-line-anchor';\n anchorLine.style.display = 'none';\n\n const anchorLabel = document.createElement('div');\n anchorLabel.className = 'sel-line-label sel-line-label-anchor';\n anchorLabel.style.display = 'none';\n\n const anchorHandle = document.createElement('div');\n anchorHandle.className = 'sel-handle sel-handle-anchor';\n anchorHandle.style.display = 'none';\n\n const anchorMarker = document.createElement('div');\n anchorMarker.className = 'sel-graph-marker';\n anchorMarker.innerHTML =\n 'play_circle';\n anchorMarker.style.display = 'none';\n\n // End line + label + drag handle\n const endLine = document.createElement('div');\n endLine.className = 'sel-line sel-line-end';\n endLine.style.display = 'none';\n\n const endLabel = document.createElement('div');\n endLabel.className = 'sel-line-label sel-line-label-end';\n endLabel.style.display = 'none';\n\n const endHandle = document.createElement('div');\n endHandle.className = 'sel-handle sel-handle-end';\n endHandle.style.display = 'none';\n\n const endMarker = document.createElement('div');\n endMarker.className = 'sel-graph-marker';\n endMarker.innerHTML =\n 'stop_circle';\n endMarker.style.display = 'none';\n\n // Floating cursor y-value\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${def.color};display:none`;\n\n // Floating pinned y-value\n const pinYVal = document.createElement('div');\n pinYVal.className = 'cur-y-val pin';\n pinYVal.style.cssText = `color:${def.color};display:none`;\n\n overlay.append(\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n );\n\n const histData: HistData = {\n yData,\n xData: xData as number[],\n def,\n BINS: 24,\n min: allCount ? gMin : undefined,\n max: allCount ? gMax : undefined,\n fullStats: fullStatsFiltered,\n fullStatsAll,\n };\n const plot: PlotData = {\n uplot: null as any,\n row,\n xData: xData as number[],\n yData,\n def,\n metricKey,\n statsTotalEl,\n statsSelEl,\n histCol,\n histCanvas,\n histData,\n hoveredHistY: null,\n pinnedHistY: null,\n smoothed: smoothedMetrics.has(metricKey),\n incZero: metricsIncludingZero.has(metricKey),\n w,\n };\n histData.plot = plot; // Back-reference for tooltip to trigger redraws\n\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n const uplot = new uPlot(uOpts, [xData, yData] as any, (self, init) => {\n plot.uplot = self as WegPlot;\n plots.push(plot);\n plotEl.appendChild(self.root);\n self.over.appendChild(overlay);\n (self as any)._strasse = {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n updateHeaderStats,\n };\n self.batch(() => {\n init();\n });\n }) as WegPlot;\n scaleSyncing = prevSync;\n\n // \u2500\u2500 Handle drag \u2500\u2500\n attachHandleDrag(anchorHandle, uplot, xData, true);\n attachHandleDrag(endHandle, uplot, xData, false);\n\n // \u2500\u2500 Mouse listeners \u2500\u2500\n let mousedownX: number | null = null;\n uplot.over.addEventListener('mousedown', (e) => {\n if (e.button !== 0) return;\n isDragging = false;\n const rect = uplot.over.getBoundingClientRect();\n const xPx = e.clientX - rect.left;\n mousedownX = xPx;\n });\n uplot.over.addEventListener('mousemove', (e) => {\n if (mousedownX !== null) {\n const rect = uplot.over.getBoundingClientRect();\n if (Math.abs(e.clientX - rect.left - mousedownX) > 5) isDragging = true;\n }\n });\n uplot.over.addEventListener('mouseup', () => {\n mousedownX = null;\n });\n\n // Click to pin point (sticky selection)\n uplot.over.addEventListener('click', () => {\n if (isDragging) return;\n const idx = uplot.cursor.idx;\n if (idx != null && pts[idx]) {\n pinnedPtIdx = idx;\n plots.forEach(({ uplot: u }) => u.redraw(false));\n if (onClickCb) onClickCb(pts[idx], idx);\n if (onPinChangeCb) onPinChangeCb(idx);\n }\n });\n\n row.addEventListener('dblclick', cancelSelection);\n\n let initHoverBinI: number | null = null;\n if (pinnedPtIdx != null && xData[pinnedPtIdx] != null && yData[pinnedPtIdx] != null) {\n buildHistBins(histData);\n if (histData.min != null && histData.max != null) {\n const span = histData.max - histData.min || 1;\n initHoverBinI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[pinnedPtIdx]! - histData.min) / span) * histData.BINS),\n );\n plot.hoveredHistY = yData[pinnedPtIdx];\n }\n }\n\n drawHistogram(histCanvas, histData, 130, initHoverBinI);\n attachHistTooltip(histCanvas, histData);\n if (container) {\n if (insertBeforeEl) container.insertBefore(row, insertBeforeEl);\n else container.appendChild(row);\n }\n }\n\n // \u2500\u2500 Selection overlay (fill + lines + handles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateSelOverlay() {\n updateAnchorLines();\n // Redraw canvas markers (bold selection line + span pill)\n plots.forEach(({ uplot: u }) => u.batch(() => u.redraw(false)));\n }\n\n function updateAnchorLines() {\n plots.forEach(({ uplot: u, def }) => {\n const s = (u as any)._strasse;\n if (!s) return;\n const {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n } = s;\n if (selAnchorVal == null || selEndVal == null) {\n [\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n ].forEach((el: HTMLElement) => {\n el.style.display = 'none';\n });\n return;\n }\n const aX = u.valToPos(selAnchorVal, 'x');\n const eX = u.valToPos(selEndVal, 'x');\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const overW = bb.width / dpr;\n const overH = bb.height / dpr;\n const plotBottom = (bb.top + bb.height) / dpr;\n\n const isAnchorVisible = aX >= 0 && aX <= overW;\n const isEndVisible = eX >= 0 && eX <= overW;\n\n // Fill: clamp left/right to visible area\n const fillL = Math.max(0, aX);\n const fillR = Math.min(overW, eX);\n if (fillR > fillL) {\n selFill.style.left = `${fillL}px`;\n selFill.style.width = `${fillR - fillL}px`;\n selFill.style.top = '0';\n selFill.style.height = `${overH}px`;\n selFill.style.backgroundColor = hexToRgba(def.color, 0.07);\n selFill.style.display = '';\n } else {\n selFill.style.display = 'none';\n }\n\n // Anchor line\n if (isAnchorVisible) {\n anchorLine.style.left = `${aX}px`;\n anchorLine.style.height = `${overH}px`;\n anchorLine.style.borderLeftColor = def.color;\n anchorLine.style.display = '';\n // Anchor label\n const aText = fmtXVal(selAnchorVal);\n anchorLabel.textContent = aText;\n const aLabelW = aText.length * 7 + 10;\n anchorLabel.style.left = aX + aLabelW + 4 < overW ? `${aX + 3}px` : `${aX - aLabelW - 3}px`;\n anchorLabel.style.display = '';\n // Anchor handle\n anchorHandle.style.left = `${aX}px`;\n anchorHandle.style.backgroundColor = def.color;\n anchorHandle.style.display = '';\n // Anchor marker: centered on the bold line\n anchorMarker.style.left = `${aX}px`;\n anchorMarker.style.top = `${plotBottom}px`;\n const aIcon = anchorMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (aIcon) aIcon.style.color = def.color;\n anchorMarker.style.display = '';\n } else {\n [anchorLine, anchorLabel, anchorHandle, anchorMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n\n // End line\n if (isEndVisible) {\n endLine.style.left = `${eX}px`;\n endLine.style.height = `${overH}px`;\n endLine.style.borderLeftColor = def.color;\n endLine.style.display = '';\n // End label\n const eText = fmtXVal(selEndVal);\n endLabel.textContent = eText;\n const eLabelW = eText.length * 7 + 10;\n endLabel.style.left = eX - eLabelW - 3 > 0 ? `${eX - eLabelW - 3}px` : `${eX + 3}px`;\n endLabel.style.display = '';\n // End handle\n endHandle.style.left = `${eX}px`;\n endHandle.style.backgroundColor = def.color;\n endHandle.style.display = '';\n // End marker: centered on the bold line\n endMarker.style.left = `${eX}px`;\n endMarker.style.top = `${plotBottom}px`;\n const eIcon = endMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (eIcon) eIcon.style.color = def.color;\n endMarker.style.display = '';\n } else {\n [endLine, endLabel, endHandle, endMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n });\n }\n\n function fmtXVal(v: number) {\n return xAxis === 'distance' ? `${v.toFixed(2)} km` : fmtSecs(v);\n }\n\n // \u2500\u2500 Handle drag logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function attachHandleDrag(\n handleEl: HTMLElement,\n uplot: uPlot,\n xData: (number | null)[],\n isAnchor: boolean,\n ) {\n // pointer-events enabled on the handle itself\n handleEl.style.pointerEvents = 'auto';\n\n handleEl.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n const startX = e.clientX;\n const startVal = isAnchor ? selAnchorVal : selEndVal;\n const overW = uplot.over.offsetWidth;\n // px-per-data-unit at current zoom\n const xMin = uplot.scales.x!.min!,\n xMax = uplot.scales.x!.max!;\n const pxPerUnit = overW / (xMax - xMin);\n const xFull = [xData[0]!, xData[xData.length - 1]!];\n\n document.body.style.cursor = 'ew-resize';\n isDragging = true;\n\n function onMove(me: MouseEvent) {\n const dx = me.clientX - startX;\n let newVal = (startVal || 0) + dx / pxPerUnit;\n newVal = Math.max(xFull[0], Math.min(xFull[1], newVal));\n\n if (isAnchor) selAnchorVal = Math.min(newVal, (selEndVal || xFull[1]) - 0.001);\n else selEndVal = Math.max(newVal, (selAnchorVal || xFull[0]) + 0.001);\n\n // When dragging handles, we typically want to stay zoomed to the selection?\n // Actually, let's keep the zoom as is, and just update the selection overlay and stats.\n plots.forEach((p) =>\n (p.uplot as any)._strasse?.updateHeaderStats(\n p.uplot.scales.x!.min!,\n p.uplot.scales.x!.max!,\n ),\n );\n updateSelOverlay();\n redrawHistograms();\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n }\n\n function onUp() {\n document.body.style.cursor = '';\n isDragging = false;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n }\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n }\n\n // \u2500\u2500 Histogram logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function buildHistBins(histData: HistData) {\n const { yData, xData, BINS } = histData;\n\n // Cache to avoid re-binning every frame during hover\n if (histData._lastYData === yData && histData.bins) return;\n histData._lastYData = yData;\n\n let min = histData.min;\n let max = histData.max;\n if (min == null || max == null) {\n let lo = Infinity,\n hi = -Infinity,\n cnt = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < lo) lo = v;\n if (v > hi) hi = v;\n cnt++;\n }\n if (!cnt) return;\n min = lo;\n max = hi;\n histData.min = min;\n histData.max = max;\n }\n\n const bins = new Array(BINS).fill(0);\n const binAccum = new Array(BINS).fill(0); // accumulated x-weight per bin (time in s or dist in km)\n\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n bins[bi]++;\n\n // weight by x-delta\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n binAccum[bi] += (next - prev) / 2;\n }\n histData.bins = bins;\n histData.binAccum = binAccum;\n }\n\n function redrawHistograms() {\n plots.forEach(({ histCanvas, histData, uplot: u }) => {\n drawHistogram(histCanvas, histData, u.height);\n });\n }\n\n function drawHistogram(\n canvas: HTMLCanvasElement,\n histData: HistData,\n chartH: number,\n hoverBinI: number | null = null,\n ) {\n const { def, BINS } = histData;\n buildHistBins(histData);\n const { bins, min, max } = histData;\n if (!bins || min == null || max == null) return;\n\n const hasSel = selAnchorVal != null && selEndVal != null;\n\n // Compute selection bins if a range is active and changed\n if (\n hasSel &&\n (histData._lastSelRange?.[0] !== selAnchorVal || histData._lastSelRange?.[1] !== selEndVal)\n ) {\n histData._lastSelRange = [selAnchorVal!, selEndVal!];\n const selBins = new Array(BINS).fill(0);\n const selBinAccum = new Array(BINS).fill(0);\n const { yData, xData } = histData;\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const x = xData[i];\n if (x == null || x < selAnchorVal! || x > selEndVal!) continue;\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n selBins[bi]++;\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n selBinAccum[bi] += (next - prev) / 2;\n }\n histData.selBins = selBins;\n histData.selBinAccum = selBinAccum;\n } else if (!hasSel) {\n histData.selBins = null;\n histData.selBinAccum = null;\n histData._lastSelRange = null;\n }\n const selBins = histData.selBins;\n\n const dpr = window.devicePixelRatio || 1;\n const W = HIST_W;\n const H = chartH;\n\n // Performance: only set dimensions if they changed (resets canvas)\n if (canvas.width !== W * dpr || canvas.height !== H * dpr) {\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n }\n\n const ctx = canvas.getContext('2d')!;\n ctx.resetTransform();\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, W, H);\n\n const peak = Math.max(...bins);\n\n // Measure label width so bars start right after them\n const fmt = (v: number) => def.fmtAxis(v);\n const fontStr = '9px system-ui, sans-serif';\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const labelW = Math.ceil(\n Math.max(\n ctx.measureText(`${fmt(max)} ${def.unit}`).width,\n ctx.measureText(`${fmt(min)} ${def.unit}`).width,\n ),\n );\n\n // Vertical alignment with main graph:\n // uPlot padding: [4, 0, 0, 0]\n // Axis size: 30\n const pad = { t: 4, r: 0, b: 30, l: labelW + 6 };\n histData.padL = pad.l;\n const plotW = W - pad.l - pad.r;\n const plotH = H - pad.t - pad.b;\n\n // bin 0 = lowest values \u2192 drawn at bottom; bin BINS-1 = highest \u2192 drawn at top\n const binY = (i: number) => pad.t + (BINS - 1 - i) * (plotH / BINS);\n const binH = plotH / BINS - 1;\n\n // Full distribution (dimmed when selection active)\n const baseAlpha = hasSel ? 0.15 : 0.6;\n ctx.fillStyle = hexToRgba(def.color, baseAlpha);\n for (let i = 0; i < BINS; i++) {\n if (!bins[i]) continue;\n const bw = (bins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n\n // Selection overlay (bright)\n if (selBins) {\n ctx.fillStyle = hexToRgba(def.color, 0.85);\n for (let i = 0; i < BINS; i++) {\n if (!selBins[i]) continue;\n const bw = (selBins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n ctx.fillStyle = def.color;\n ctx.fillRect(pad.l, pad.t, 2, plotH);\n }\n\n // CDF overlay \u2014 smooth curve from bottom (0%) to top (100%)\n const total = bins.reduce((s, v) => s + v, 0);\n if (total > 0) {\n // Build CDF points: one per bin boundary, bottom\u2192top\n const pts2 = [{ x: pad.l, y: pad.t + plotH }];\n let cumSum = 0;\n for (let i = 0; i < BINS; i++) {\n cumSum += bins[i];\n pts2.push({ x: pad.l + (cumSum / total) * plotW, y: binY(i) });\n }\n\n ctx.beginPath();\n // CDF line is now solid\n ctx.setLineDash([]);\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 0.75 * dpr;\n ctx.lineJoin = 'round';\n ctx.moveTo(pts2[0].x, pts2[0].y);\n for (let i = 1; i < pts2.length - 1; i++) {\n const mx = (pts2[i].x + pts2[i + 1].x) / 2;\n const my = (pts2[i].y + pts2[i + 1].y) / 2;\n ctx.quadraticCurveTo(pts2[i].x, pts2[i].y, mx, my);\n }\n ctx.lineTo(pts2[pts2.length - 1].x, pts2[pts2.length - 1].y);\n ctx.stroke();\n\n // \u2500\u2500 Hover highlight on CDF \u2500\u2500\n if (hoverBinI != null && pts2[hoverBinI + 1]) {\n const cp = pts2[hoverBinI + 1];\n // Vertical line down\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(def.color, 0.6);\n ctx.moveTo(cp.x, cp.y);\n ctx.lineTo(cp.x, pad.t + plotH);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Dot: tiny precision point\n ctx.beginPath();\n ctx.arc(cp.x, cp.y, 1.2 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n }\n\n // Axis labels: max at top, min at bottom\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n const font9 = '9px system-ui, sans-serif';\n if (ctx.font !== font9) ctx.font = font9;\n ctx.textAlign = 'right';\n\n // Draw Max\n ctx.textBaseline = 'top';\n ctx.fillText(`${fmt(max)} ${def.unit}`, pad.l - 4, pad.t);\n\n // Draw Min\n ctx.textBaseline = 'bottom';\n ctx.fillText(`${fmt(min)} ${def.unit}`, pad.l - 4, H - pad.b);\n\n // Draw Avg (only if it doesn't overlap min/max)\n const stats =\n !hasSel && histData.fullStatsAll !== undefined\n ? histData.fullStatsAll\n : rangeStats(\n histData.xData,\n histData.yData,\n selAnchorVal || -Infinity,\n selEndVal || Infinity,\n );\n if (stats) {\n const avgY =\n pad.t +\n (BINS - 1 - Math.min(BINS - 1, Math.floor(((stats.avg - min) / (max - min || 1)) * BINS))) *\n (plotH / BINS);\n const minLabelY = H - pad.b;\n const maxLabelY = pad.t;\n const labelHeight = 10; // Approx 10px height for 9px font\n\n if (avgY > maxLabelY + labelHeight + 2 && avgY < minLabelY - labelHeight - 2) {\n ctx.textBaseline = 'middle';\n if (ctx.fillStyle !== '#aaa') ctx.fillStyle = '#aaa';\n ctx.fillText(`${fmt(stats.avg)} ${def.unit}`, pad.l - 4, avgY);\n // Draw small indicator tick\n ctx.beginPath();\n ctx.moveTo(pad.l - 3, avgY);\n ctx.lineTo(pad.l, avgY);\n if (ctx.strokeStyle !== '#aaa') ctx.strokeStyle = '#aaa';\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n }\n\n // \u2500\u2500 Higher/Lower percentages below histogram \u2500\u2500\n if (hoverBinI != null && total > 0) {\n let countLower = 0;\n for (let i = 0; i < hoverBinI; i++) countLower += bins[i];\n let countHigher = 0;\n for (let i = hoverBinI + 1; i < BINS; i++) countHigher += bins[i];\n\n const pLower = Math.round((countLower / total) * 100);\n const pHigher = Math.round((countHigher / total) * 100);\n\n ctx.save();\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const font8 = '8px system-ui, sans-serif';\n if (ctx.font !== font8) ctx.font = font8;\n\n const textY = H - pad.b + 6;\n\n // Draw \"Lower\" stat\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('LOWER', pad.l, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n const fontB10 = 'bold 10px system-ui, sans-serif';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pLower}%`, pad.l, textY + 10);\n\n // Draw \"Higher\" stat\n const midX = pad.l + plotW / 2;\n if (ctx.font !== font8) ctx.font = font8;\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('HIGHER', midX, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pHigher}%`, midX, textY + 10);\n\n ctx.restore();\n }\n }\n\n function attachHistTooltip(canvas: HTMLCanvasElement, histData: HistData) {\n const { plot } = histData;\n\n canvas.addEventListener('click', (e) => {\n const binI = getBinAt(canvas, histData, e);\n if (binI != null && plot) {\n const { min, max, BINS } = histData;\n const span = max! - min! || 1;\n plot.pinnedHistY = min! + (binI + 0.5) * (span / BINS!);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n }\n });\n\n canvas.addEventListener('mousemove', (e) => {\n lastHistMouseEvent = e;\n updateHistTooltip(e, canvas, histData);\n });\n\n canvas.addEventListener('mouseenter', () => {\n hoveredHistCanvas = canvas;\n hoveredHistData = histData;\n });\n\n canvas.addEventListener('mouseleave', () => {\n if (hoveredHistCanvas === canvas) {\n hoveredHistCanvas = null;\n hoveredHistData = null;\n }\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const lineEl = document.getElementById('hist-line');\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n });\n }\n\n function getBinAt(canvas: HTMLCanvasElement, histData: HistData, e: MouseEvent) {\n const { bins, BINS } = histData;\n if (!bins) return null;\n const rect = canvas.getBoundingClientRect();\n const relY = e.clientY - rect.top;\n // Use exact padding from drawHistogram: t: 4, b: 30\n const pad = { t: 4, b: 30 };\n const plotH = rect.height - pad.t - pad.b;\n const rawI = Math.floor(((relY - pad.t) / plotH) * BINS!);\n const binI = BINS! - 1 - rawI;\n if (rawI < 0 || rawI >= BINS!) return null;\n return binI;\n }\n\n function updateHistTooltip(e: MouseEvent, canvas: HTMLCanvasElement, histData: HistData) {\n if (!histTooltipEl) return;\n const { bins, binAccum, min, max, BINS, def, plot } = histData;\n if (!bins || !binAccum || min == null || max == null) return;\n\n const lineEl = document.getElementById('hist-line');\n const binI = getBinAt(canvas, histData, e);\n\n if (binI == null || !bins[binI]) {\n histTooltipEl.style.display = 'none';\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n return;\n }\n\n if (plot) {\n const span = max - min || 1;\n plot.hoveredHistY = min + (binI + 0.5) * (span / BINS!);\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1), binI);\n }\n\n const count = bins[binI];\n const total = bins.reduce((s, v) => s + v, 0);\n const pct = (count / total) * 100;\n\n const span = max - min || 1;\n const low = min + binI * (span / BINS!);\n const high = min + (binI + 1) * (span / BINS!);\n const label = `${def.fmt(low, true)} \u2013 ${def.fmt(high, true)} ${def.unit}`;\n\n // Zone info\n let zoneHtml = '';\n const mid = (low + high) / 2;\n const metricKey = Object.keys(METRICS).find((k) => METRICS[k] === def);\n let zones: any[] = [];\n if (metricKey === 'power') zones = Zones.getPowerZones();\n else if (metricKey === 'hr') zones = Zones.getHRZones();\n\n if (zones.length > 0) {\n const zIdx = zones.findIndex((z) => mid >= z.min && mid < z.max);\n const z =\n zIdx !== -1\n ? zones[zIdx]\n : mid >= zones[zones.length - 1].min\n ? zones[zones.length - 1]\n : null;\n if (z) {\n const finalZIdx = zIdx !== -1 ? zIdx : zones.length - 1;\n zoneHtml = `\n
\n Z${finalZIdx + 1}\n \u00B7\n ${z.name}\n
\n `;\n }\n }\n\n const totalAccum =\n xAxis === 'distance' ? `${binAccum[binI].toFixed(2)} km` : fmtSecs(binAccum[binI]);\n const totalPct = (binAccum[binI] / binAccum.reduce((s, v) => s + v, 0)) * 100;\n\n let html = `\n
${label}
\n ${zoneHtml}\n `;\n\n if (totalAccum) {\n html += `
\n ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${totalAccum}\n ${totalPct.toFixed(1)}%\n
`;\n }\n\n // Selection context\n if (histData.selBins && histData.selBinAccum) {\n const stotalAccum =\n xAxis === 'distance'\n ? `${histData.selBinAccum[binI].toFixed(2)} km`\n : fmtSecs(histData.selBinAccum[binI]);\n const stotalPct =\n (histData.selBinAccum[binI] / histData.selBinAccum.reduce((s, v) => s + v, 0)) * 100;\n\n html += `\n
\n Sel ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${stotalAccum}\n ${stotalPct.toFixed(1)}%\n
\n `;\n }\n\n histTooltipEl.innerHTML = html;\n\n // Position tooltip: fixed X left of canvas, Y centered on bin\n histTooltipEl.style.display = 'block';\n const ttH = histTooltipEl.offsetHeight;\n const ttW = histTooltipEl.offsetWidth;\n const rect = canvas.getBoundingClientRect();\n const plotH = rect.height - 4 - 30; // pad.t + pad.b\n const binCenterY = rect.top + 4 + (BINS! - 1 - binI + 0.5) * (plotH / BINS!);\n\n histTooltipEl.style.left = `${rect.left - ttW - 12}px`;\n histTooltipEl.style.top = `${binCenterY - ttH / 2}px`;\n\n // Horizontal line sync\n if (lineEl) {\n lineEl.style.display = 'block';\n lineEl.style.top = `${binCenterY}px`;\n lineEl.style.left = '0px';\n lineEl.style.width = `${rect.left}px`;\n }\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function destroyPlots(keepState = false) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n plots.forEach(({ uplot: u, row }) => {\n syncKey!.unsub(u);\n u.destroy();\n row.remove();\n });\n plots = [];\n renderedTrack = null;\n if (!keepState) {\n selAnchorVal = null;\n selEndVal = null;\n }\n isDragging = false;\n }\n\n function rangeStats(\n xData: (number | null)[],\n yData: (number | null)[],\n xMin: number,\n xMax: number,\n incZero = true,\n ) {\n let min = Infinity,\n max = -Infinity,\n sum = 0,\n n = 0;\n for (let i = 0; i < xData.length; i++) {\n if (xData[i] == null || xData[i]! < xMin || xData[i]! > xMax) continue;\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n if (v < min) min = v;\n if (v > max) max = v;\n sum += v;\n n++;\n }\n return n ? { min, max, avg: sum / n } : null;\n }\n\n function elevationRangeStats(pts: TrackPoint[], xMin: number, xMax: number) {\n let gain = 0,\n loss = 0;\n let prevEle: number | null = null;\n const isDist = xAxis === 'distance';\n const t0 = pts[0].time || 0;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const x = isDist ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n if (x < xMin || x > xMax) continue;\n\n if (p.ele != null) {\n if (prevEle != null) {\n const diff = p.ele - prevEle;\n if (diff > 0) gain += diff;\n else if (diff < 0) loss += Math.abs(diff);\n }\n prevEle = p.ele;\n }\n }\n return { gain, loss };\n }\n\n // \u2500\u2500 Plot Rendering Helpers (Canvas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateTooltip(\n u: WegPlot,\n el: HTMLElement,\n idx: number,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n def: MetricDefinition,\n metricKey: string,\n ) {\n if (idx == null || yData[idx] == null) {\n el.style.display = 'none';\n return;\n }\n\n const cx = u.valToPos(xData[idx]!, 'x', false);\n const cy = u.valToPos(yData[idx]!, 'y', false);\n\n let gColor = '#888896';\n let g = 0;\n if (idx > 0 && pts[idx] && pts[idx - 1]) {\n const p0 = pts[idx - 1],\n p1 = pts[idx];\n const d = (p1.dist || 0) - (p0.dist || 0);\n if (d > 0.1 && p1.ele != null && p0.ele != null) {\n g = ((p1.ele - p0.ele) / d) * 100;\n gColor = gradientColor(g);\n }\n }\n\n let content =\n metricKey !== 'elevation'\n ? `${def.fmt(yData[idx]!, false)} ${def.unit}`\n : `${def.fmt(yData[idx]!, false)} ${def.unit} \u2220 ${Math.abs(g).toFixed(1)}%`;\n\n // Special handling for gears: show tooth count if available\n if (metricKey === 'gearRear' && pts[idx].gearRearTooth != null) {\n content = `${pts[idx].gearRearTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gearFront' && pts[idx].gearFrontTooth != null) {\n content = `${pts[idx].gearFrontTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gears') {\n const p = pts[idx];\n const front =\n p.gearFrontTooth != null\n ? `${p.gearFrontTooth}T`\n : p.gearFront != null\n ? `pos ${p.gearFront}`\n : '';\n const rear =\n p.gearRearTooth != null\n ? `${p.gearRearTooth}T`\n : p.gearRear != null\n ? `pos ${p.gearRear}`\n : '';\n\n if (front || rear)\n content += ` (${front} / ${rear})`;\n }\n\n if (el.innerHTML !== content) el.innerHTML = content;\n\n const color44 = `${def.color}44`;\n if (el.style.color !== def.color) el.style.color = def.color;\n if (el.style.borderColor !== color44) el.style.borderColor = color44;\n\n const left = `${cx}px`;\n const top = `${cy}px`;\n const transform = 'translate(6px, -50%)';\n if (el.style.left !== left) el.style.left = left;\n if (el.style.top !== top) el.style.top = top;\n if (el.style.transform !== transform) el.style.transform = transform;\n if (el.style.display !== '') el.style.display = '';\n }\n\n const gradientColorRgbaCache = new Map();\n function gradientColorRgba(g: number | null): string {\n let c = gradientColorRgbaCache.get(g);\n if (!c) {\n c = hexToRgba(gradientColor(g), 0.8);\n gradientColorRgbaCache.set(g, c);\n }\n return c;\n }\n\n function drawElevationGradient(\n u: uPlot,\n xData: number[],\n yData: number[],\n gradData: (number | null)[] | null,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = gradData && gradData[i] != null ? Math.round(gradData[i]! / 2) * 2 : null;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawGradientChart(u: uPlot, xData: number[], yData: number[]) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = Math.round(yData[i]! / 2) * 2;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawHoverLine(u: uPlot, yData: number[], color: string, pts: TrackPoint[]) {\n const idx = u.cursor.idx;\n if (idx == null || yData[idx] == null || u.cursor.left! < 0) return;\n\n const t0 = pts[0].time || 0;\n const xVal = xAxis === 'distance' ? (pts[idx].dist || 0) / 1000 : (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yData[idx], 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Line from top to point + horizontal from left\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, cy);\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Dot at point\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n\n function drawVerticalLineOnly(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const xVal =\n xAxis === 'distance'\n ? (pts[idx].dist || 0) / 1000\n : (pts[idx].time! - (pts[0].time || 0)) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n // Dotted line range should match where labels are (flush top to bottom axis)\n ctx.moveTo(cx, bb.top + 16 * dpr);\n ctx.lineTo(cx, bb.top + bb.height + 10 * dpr);\n ctx.stroke();\n ctx.restore();\n }\n\n function drawXAxisLabels(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n skipLine = false,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const t0 = pts[0].time || 0;\n const distVal = (pts[idx].dist || 0) / 1000;\n const timeVal = (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xAxis === 'distance' ? distVal : timeVal, 'x', true);\n\n // Bottom label: matches the current X axis unit\n const bottomLabel = xAxis === 'distance' ? `${distVal.toFixed(2)} km` : fmtSecs(timeVal);\n // Top label: shows the other unit (simplified)\n const topLabel = xAxis === 'distance' ? fmtSecs(timeVal) : `${distVal.toFixed(2)} km`;\n\n const drawPill = (text: string, x: number, y: number, isTop: boolean) => {\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(text).width;\n const bw = tw + 10 * dpr;\n const bh = 16 * dpr;\n const rx = x - bw / 2;\n const clampedRx = Math.max(bb.left, Math.min(bb.left + bb.width - bw, rx));\n const ry = y - bh / 2;\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.setLineDash([]); // Ensure pills are not dashed\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(clampedRx, ry, bw, bh, 3 * dpr);\n else ctx.rect(clampedRx, ry, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.92)';\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, clampedRx + bw / 2, ry + bh / 2 + 0.5 * dpr);\n ctx.restore();\n };\n\n if (!skipLine) drawVerticalLineOnly(u, pts, idx, color, opacity);\n\n const pillH = 16 * dpr;\n // Top label: flush to the top edge of the plot\n drawPill(topLabel, cx, bb.top + pillH / 2, true);\n\n // Bottom label: aligned with the horizontal axis labels (centered in the 30px axis area)\n drawPill(bottomLabel, cx, bb.top + bb.height + 15 * dpr, false);\n }\n\n function drawPinnedDot(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n def: MetricDefinition,\n pts: TrackPoint[],\n metricKey: string,\n ) {\n if (pinnedPtIdx == null) return;\n const xVal = xData[pinnedPtIdx];\n const yVal = yData[pinnedPtIdx];\n if (xVal == null || yVal == null) return;\n\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n ctx.save();\n // Vertical line\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, bb.top + bb.height);\n ctx.stroke();\n\n // Horizontal dashed line\n ctx.beginPath();\n ctx.setLineDash([3 * dpr, 3 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.5);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Large Dot\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 5 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2.5 * dpr;\n ctx.stroke();\n ctx.restore();\n\n const s = (u as any)._strasse;\n if (s && s.pinYVal) {\n updateTooltip(\n u,\n s.pinYVal,\n pinnedPtIdx,\n xData as number[],\n yData as (number | null)[],\n pts,\n def,\n metricKey,\n );\n }\n }\n\n function drawYAxisHighlight(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n yVal: number,\n color: string,\n def: MetricDefinition,\n ) {\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const cy = u.valToPos(yVal, 'y', true);\n\n // Clamp cy to bbox\n const cyClamp = Math.max(bb.top, Math.min(bb.top + bb.height, cy));\n\n ctx.save();\n // Horizontal line\n ctx.beginPath();\n ctx.setLineDash([4 * dpr, 4 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cyClamp);\n ctx.lineTo(bb.left + bb.width, cyClamp);\n ctx.stroke();\n\n // Fill area above/below\n drawAreaFillAbove(u, xData, yData, cyClamp, color);\n\n // Pill label on Y-axis\n const label = def.fmt(yVal, true);\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n const bw = tw + 8 * dpr;\n const bh = 16 * dpr;\n const bx = bb.left - bw - 2 * dpr;\n const by = cyClamp - bh / 2;\n\n ctx.beginPath();\n ctx.setLineDash([]);\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.95)';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = '#fff';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2 + 0.5 * dpr);\n ctx.restore();\n }\n\n function drawAreaFillAbove(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n cyClamp: number,\n color: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.beginPath();\n\n let inSegment = false;\n let hasAnySegment = false;\n let lastPx = 0;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null || xv < xMin || xv > xMax) {\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n lastPx = px;\n\n if (py < cyClamp) {\n if (!inSegment) {\n ctx.moveTo(px, cyClamp);\n inSegment = true;\n hasAnySegment = true;\n }\n ctx.lineTo(px, py);\n } else if (inSegment) {\n ctx.lineTo(px, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n }\n\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n }\n\n if (hasAnySegment) {\n ctx.fill();\n }\n\n ctx.restore();\n }\n\n // \u2500\u2500 Utils \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function lerpHex(a: string, b: string, t: number) {\n const ah = parseInt(a.slice(1), 16),\n bh = parseInt(b.slice(1), 16);\n const ar = ah >> 16,\n ag = (ah >> 8) & 0xff,\n ab = ah & 0xff;\n const br = bh >> 16,\n bg = (bh >> 8) & 0xff,\n bb = bh & 0xff;\n const rr = ar + (br - ar) * t,\n rg = ag + (bg - ag) * t,\n rb = ab + (bb - ab) * t;\n return `#${((1 << 24) + (Math.round(rr) << 16) + (Math.round(rg) << 8) + Math.round(rb))\n .toString(16)\n .slice(1)}`;\n }\n\n function gradientColor(g: number | null) {\n if (g == null) return '#888896';\n const absG = Math.abs(g);\n const t = Math.min(1, absG / 8);\n if (g > 0) return lerpHex('#A8C8A0', '#d73027', t); // Green to Red\n return lerpHex('#A8C8A0', '#4575b4', t); // Green to Blue\n }\n\n function speedColor(s: number | null) {\n if (s == null) return '#888896';\n const kmh = s * 3.6;\n\n if (kmh <= 5) return '#4575b4'; // Solid Blue for very slow\n if (kmh >= 60) return '#d73027'; // Solid Red for very fast\n\n // High resolution between 5 and 45 (10km/h per segment)\n if (kmh <= 45) {\n const t = (kmh - 5) / 40; // 0 to 1\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); // 5-15: Blue -> LBlue\n if (t <= 0.5) return lerpHex('#91bfdb', '#abdda4', (t - 0.25) / 0.25); // 15-25: LBlue -> Green\n if (t <= 0.75) return lerpHex('#abdda4', '#fee08b', (t - 0.5) / 0.25); // 25-35: Green -> Yellow\n return lerpHex('#fee08b', '#fc8d59', (t - 0.75) / 0.25); // 35-45: Yellow -> Orange\n } else {\n // 45-60: Orange -> Red\n const t = (kmh - 45) / 15;\n return lerpHex('#fc8d59', '#d73027', t);\n }\n }\n\n function smoothGradient(pts: TrackPoint[], windowMetres: number) {\n const grads: (number | null)[] = new Array(pts.length).fill(null);\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n let j0 = i,\n j1 = i;\n while (j0 > 0 && (p.dist || 0) - (pts[j0].dist || 0) < windowMetres / 2) j0--;\n while (j1 < pts.length - 1 && (pts[j1].dist || 0) - (p.dist || 0) < windowMetres / 2) j1++;\n const d = (pts[j1].dist || 0) - (pts[j0].dist || 0);\n if (d > 1 && pts[j1].ele != null && pts[j0].ele != null)\n grads[i] = ((pts[j1].ele! - pts[j0].ele!) / d) * 100;\n }\n return grads;\n }\n\n function fillNulls(data: (number | null)[]) {\n const res = [...data];\n for (let i = 0; i < res.length; i++) {\n if (res[i] === null) {\n let left = i - 1;\n while (left >= 0 && res[left] === null) left--;\n let right = i + 1;\n while (right < res.length && res[right] === null) right++;\n if (left >= 0 && right < res.length)\n res[i] = res[left]! + ((res[right]! - res[left]!) * (i - left)) / (right - left);\n else if (left >= 0) res[i] = res[left];\n else if (right < res.length) res[i] = res[right];\n }\n }\n return res;\n }\n\n function updateStats(track: TrackData) {\n const s = track.stats;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt('stat-distance', s.totalDist != null ? `${(s.totalDist / 1000).toFixed(1)} km` : '\u2014');\n fmt('stat-duration', s.duration != null ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014');\n fmt('stat-elevation', s.elevGain != null ? `${Math.round(s.elevGain)} m` : '\u2014');\n\n // Recalculate averages from visible plot data to respect zero filtering\n const getAvg = (key: string) => {\n const p = plots.find((p) => p.metricKey === key);\n if (!p) {\n if (key === 'speed') return s.avgSpeed ?? null;\n if (key === 'power') return s.avgPower ?? null;\n if (key === 'cadence') return s.avgCadence ?? null;\n return null;\n }\n if (p.histData.fullStats !== undefined) {\n return p.histData.fullStats ? p.histData.fullStats.avg : null;\n }\n const incZero =\n metricsIncludingZero.has(key) || (key !== 'power' && key !== 'cadence' && key !== 'speed');\n const vals = p.yData.filter((v): v is number => v != null && (incZero || v !== 0));\n if (!vals.length) return null;\n return vals.reduce((a, b) => a + b, 0) / vals.length;\n };\n\n const avgSpeed = getAvg('speed');\n fmt('stat-avg-speed', avgSpeed != null ? `${(avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014');\n\n const avgPower = getAvg('power');\n fmt('stat-avg-power', avgPower != null ? `${Math.round(avgPower)} W` : '\u2014');\n\n const avgCadence = getAvg('cadence');\n fmt('stat-avg-cad', avgCadence != null ? `${Math.round(avgCadence)} rpm` : '\u2014');\n\n fmt('stat-avg-hr', s.avgHR != null ? `${s.avgHR} bpm` : '\u2014');\n fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n }\n\n const INTERVAL_CAP = 16384;\n const ivPwr = new Float64Array(INTERVAL_CAP);\n const ivHr = new Float64Array(INTERVAL_CAP);\n const ivSpd = new Float64Array(INTERVAL_CAP);\n const ivEle = new Float64Array(INTERVAL_CAP);\n const ivCad = new Float64Array(INTERVAL_CAP);\n const ivSmoothed = new Float64Array(INTERVAL_CAP);\n const ivKdeBins = new Float64Array(64);\n const intervalWindows = [\n 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, 360,\n ];\n\n function analyzeTelemetryIntervals(\n tracksList: TrackData[],\n selStartSec: number,\n selEndSec: number,\n ) {\n if (!tracksList.length) return 0;\n ivKdeBins.fill(0);\n let intervalScore = 0;\n\n for (let ti = 0; ti < tracksList.length; ti++) {\n const pts = tracksList[ti].points;\n const n = Math.min(pts.length, INTERVAL_CAP);\n if (n < 4) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n ivPwr[i] = p.power || 0;\n ivHr[i] = p.hr || 0;\n ivSpd[i] = p.speed || 0;\n ivEle[i] = p.ele || 0;\n ivCad[i] = p.cad || 0;\n }\n\n // Multi-band Savitzky-Golay 5-point quadratic smoothing, Gaussian kernel density,\n // and spectral cadence-HR harmonic analysis\n const sStart = Math.max(0, Math.min(n - 1, Math.floor(selStartSec)));\n const sEnd = Math.max(sStart + 1, Math.min(n, Math.floor(selEndSec)));\n const inv35 = 1 / 35;\n\n for (let pass = 0; pass < 65; pass++) {\n const weightPwr = 1.0 + pass * 0.02;\n const weightHr = 0.8 + pass * 0.015;\n const invSigmaSq = 1 / (180 + pass * 25);\n const omega = 0.012 + pass * 0.0015;\n for (let i = 2; i < n - 2; i++) {\n const sgPwr =\n (-3 * ivPwr[i - 2] +\n 12 * ivPwr[i - 1] +\n 17 * ivPwr[i] +\n 12 * ivPwr[i + 1] -\n 3 * ivPwr[i + 2]) *\n inv35;\n const sgHr =\n (-3 * ivHr[i - 2] +\n 12 * ivHr[i - 1] +\n 17 * ivHr[i] +\n 12 * ivHr[i + 1] -\n 3 * ivHr[i + 2]) *\n inv35;\n const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25;\n const dP = sgPwr - ivPwr[i];\n const gauss = Math.exp(-dP * dP * invSigmaSq);\n const harmonic = Math.cos(i * omega + ivCad[i] * 0.02);\n ivSmoothed[i] =\n sgPwr * weightPwr * gauss + sgHr * weightHr + sgSpd * (ivCad[i] * 0.1 + harmonic);\n }\n\n for (let wi = 0; wi < intervalWindows.length; wi++) {\n const w = intervalWindows[wi];\n if (w >= n) continue;\n const invW = 1 / w;\n let winSum = 0;\n let winEle = 0;\n let maxInterval = 0;\n for (let i = 0; i < n; i++) {\n winSum += ivSmoothed[i];\n winEle += ivEle[i];\n if (i >= w) {\n winSum -= ivSmoothed[i - w];\n winEle -= ivEle[i - w];\n const avg = (winSum + winEle * 0.05) * invW;\n if (avg > maxInterval) maxInterval = avg;\n }\n }\n intervalScore += maxInterval * 1e-4;\n }\n\n // Range-selection Kernel Density Estimation (KDE) binning\n for (let i = sStart; i < sEnd; i++) {\n const norm = Math.max(0, Math.min(63, ((ivSmoothed[i] * 0.12) | 0) & 63));\n ivKdeBins[norm] += 1 + (ivEle[i] - ivEle[sStart]) * 1e-3;\n if (norm > 0) ivKdeBins[norm - 1] += 0.5;\n if (norm < 63) ivKdeBins[norm + 1] += 0.5;\n }\n }\n }\n\n for (let b = 0; b < 64; b++) {\n intervalScore += ivKdeBins[b] * 1e-5;\n }\n if (container) {\n container.dataset.intervalScore = intervalScore.toFixed(2);\n }\n return intervalScore;\n }\n\n return {\n init,\n loadTrack,\n clear,\n resetState,\n toggleMetric,\n setXAxis,\n toggleStats,\n setSelectionStats,\n clearSelectionStats,\n restoreSelection,\n resetZoom,\n cancelSelection,\n analyzeTelemetryIntervals,\n setCursorAt: (idx: number, deferRender = false) => {\n pinnedPtIdx = idx;\n if (onPinChangeCb) onPinChangeCb(idx);\n if (deferRender) {\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n return;\n }\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n },\n setHoverAt: (idx: number | null) => {\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (idx === null) {\n u.batch(() => {\n (u as any).setCursor({ left: -10, top: -10 }, true, false);\n });\n } else if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb) {\n onCursorMoveCb(\n idx != null && currentTrack?.points?.[idx] ? currentTrack.points[idx] : null,\n );\n }\n },\n clearPinnedDot: () => {\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n },\n resize,\n METRICS,\n isDragging: () => isDragging,\n setMapColorChangeCb,\n toggleMapColor,\n getMapColorMetric: () => mapColorMetric,\n getActiveMetrics: () => activeMetrics,\n getAvailableMetrics: () => availableMetrics,\n setActiveMetrics,\n updateMetricOrder: (keys: string[]) => {\n // Keys might only contain current active ones, or more.\n // We want to re-order activeMetrics to match the order in 'keys'\n const newActive = new Set();\n keys.forEach((k) => {\n if (activeMetrics.has(k)) newActive.add(k);\n });\n // Add any remaining ones that were active but not in the keys list (shouldn't happen with our DND)\n activeMetrics.forEach((k) => {\n if (!newActive.has(k)) newActive.add(k);\n });\n activeMetrics = newActive;\n if (currentTrack) render(true);\n },\n getXAxis: () => xAxis,\n };\n\n function drawMetricColorFill(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n metricKey: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const colors = _computePointColors(metricKey, yData);\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (let i = 1; i < xData.length; i++) {\n if (xData[i] == null || yData[i] == null || xData[i - 1] == null || yData[i - 1] == null)\n continue;\n const x0 = u.valToPos(xData[i - 1]!, 'x', true);\n const y0 = u.valToPos(yData[i - 1]!, 'y', true);\n const x1 = u.valToPos(xData[i]!, 'x', true);\n const y1 = u.valToPos(yData[i]!, 'y', true);\n\n const c = colors[i];\n\n // Top line segment\n ctx.beginPath();\n ctx.moveTo(x0, y0);\n if (isStepped) ctx.lineTo(x1, y0);\n\n ctx.lineTo(x1, y1);\n ctx.strokeStyle = c;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawBackgroundTracks(u: uPlot, metricKey: string, def: MetricDefinition) {\n if (!allTracks.length) return;\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (const track of allTracks) {\n if (currentTrack && track.id === currentTrack.id) continue;\n\n const pts = track.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const field = def.field;\n\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)'; // Extremely faint\n ctx.lineWidth = 1 * dpr;\n\n let first = true;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const v = p[field] as number;\n\n if (v == null) {\n first = true;\n continue;\n }\n\n if (i > 0) {\n const prev = pts[i - 1];\n const dt = p.time && prev.time ? p.time - prev.time : 0;\n if (dt > GAP_THRESHOLD) first = true;\n }\n\n const val = def.transform ? def.transform(v) : v;\n if (val == null) {\n first = true;\n continue;\n }\n const xVal = xAxis === 'distance' ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n\n // Skip if way outside horizontal range\n if (xVal < u.scales.x!.min! - 10 || xVal > u.scales.x!.max! + 10) {\n first = true;\n continue;\n }\n\n const px = u.valToPos(xVal, 'x', true);\n const py = u.valToPos(val, 'y', true);\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevP = pts[i - 1];\n const prevXVal =\n xAxis === 'distance' ? (prevP.dist || 0) / 1000 : (prevP.time! - t0) / 1000;\n ctx.lineTo(u.valToPos(prevXVal, 'x', true), py);\n }\n ctx.lineTo(px, py);\n }\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawTrackPath(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n width: number,\n metricKey: string,\n range: [number, number] | null = null,\n pts: TrackPoint[] = [],\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = hexToRgba(color, 0.8);\n ctx.lineWidth = width * dpr;\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n let first = true;\n let lastFrontGear: number | null = null;\n let fMin = 1;\n let fMax = 1;\n\n if (metricKey === 'gears' && pts.length > 0) {\n let lo = Infinity,\n hi = -Infinity;\n for (let i = 0; i < pts.length; i++) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null) {\n if (fg < lo) lo = fg;\n if (fg > hi) hi = fg;\n }\n }\n if (lo <= hi) {\n fMin = lo;\n fMax = hi;\n }\n }\n\n const rMin = range ? range[0] : (u.scales.x?.min ?? -Infinity);\n const rMax = range ? range[1] : (u.scales.x?.max ?? Infinity);\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = !range ? u.series[0]?.idxs : null;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step =\n isStepped || metricKey === 'gears' ? 1 : Math.max(1, Math.floor((iEnd - iStart) / 250));\n const isTimeAxis = xAxis === 'time';\n const gapSec = GAP_THRESHOLD / 1000;\n let prevDrawnI = iStart;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null) {\n first = true;\n continue;\n }\n\n if (metricKey === 'gears' && pts[i]) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null && fg !== lastFrontGear) {\n if (!first && i > 0) {\n ctx.stroke();\n ctx.beginPath();\n const prevX = bb.left + (xData[prevDrawnI]! - xMin) * xScale;\n const prevY = yBase + (yData[prevDrawnI]! - yMin) * yMult;\n ctx.moveTo(prevX, prevY);\n }\n\n // Compute color\n let segmentColor = color;\n if (fMax !== fMin && fg != null) {\n if (fg === fMin)\n segmentColor = '#FFC400'; // Small ring: Yellow-Orange\n else if (fg === fMax)\n segmentColor = '#FF8C00'; // Big ring: Dark Orange\n else segmentColor = '#FFA500'; // Middle ring: Orange\n }\n ctx.strokeStyle = hexToRgba(segmentColor, 0.8);\n lastFrontGear = fg;\n }\n }\n\n // Check gap\n if (i > iStart && isTimeAxis) {\n const prevXv = xData[prevDrawnI];\n if (prevXv != null && xv - prevXv > gapSec) first = true;\n }\n\n // Check range (or visible x-scale bounds)\n if (xv < rMin || xv > rMax) {\n first = true;\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevXv = xData[prevDrawnI]!;\n ctx.lineTo(bb.left + (prevXv - xMin) * xScale, py);\n }\n ctx.lineTo(px, py);\n }\n prevDrawnI = i;\n }\n ctx.stroke();\n ctx.restore();\n }\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { Parsers } from './parsers';\n\nexport interface ZoneRange {\n name: string;\n min: number;\n max: number;\n color: string;\n}\n\nexport const Zones = (() => {\n function getPowerZones(): ZoneRange[] {\n const ftp = Parsers.getFTP();\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n const names = [\n 'Active Recovery',\n 'Endurance',\n 'Tempo',\n 'Threshold',\n 'VO2 Max',\n 'Anaerobic',\n 'Neuromuscular',\n ];\n const colors = ['#82E0AA', '#A8C8A0', '#F7DC6F', '#F8C471', '#F39C12', '#E67E22', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[6], min: last, max: Infinity, color: colors[6] });\n return zones;\n }\n\n function getHRZones(): ZoneRange[] {\n const thresholds = Parsers.getHRZones();\n const names = ['Recovery', 'Aerobic', 'Tempo', 'Threshold', 'Anaerobic'];\n const colors = ['#82E0AA', '#F7DC6F', '#F8C471', '#FF6B6B', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[4], min: last, max: Infinity, color: colors[4] });\n return zones;\n }\n\n return {\n getPowerZones,\n getHRZones,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackPoint } from './parsers';\n\nexport interface MetricDefinition {\n label: string;\n field: keyof TrackPoint;\n unit: string;\n color: string;\n abbr: string;\n icon: string;\n fmt: (v: number, precise?: boolean) => string;\n fmtAxis: (v: number) => string;\n compute?: (\n pts: TrackPoint[],\n fillNulls: (data: (number | null)[]) => (number | null)[],\n ) => (number | null)[];\n transform?: (v: number) => number | null;\n smoothSigma?: number;\n}\n\nexport const Metrics = {\n speed: { name: 'Speed', color: '#45B7D1', icon: 'speed' },\n gradient: { name: 'Gradient', color: '#A8C8A0', icon: 'trending_up' },\n power: { name: 'Power', color: '#F7DC6F', icon: 'bolt' },\n hr: { name: 'Heart Rate', color: '#FF6B6B', icon: 'favorite' },\n cadence: { name: 'Cadence', color: '#BB8FCE', icon: 'directions_run' },\n temperature: { name: 'Temperature', color: '#F8C471', icon: 'thermostat' },\n elevation: { name: 'Elevation', color: '#4ECDC4', icon: 'terrain' },\n distance: { name: 'Distance', color: '#9f1bfdff', icon: 'arrow_range' },\n gearRear: { name: 'Rear Gear', color: '#82E0AA', icon: 'settings' },\n gearFront: { name: 'Front Gear', color: '#A8C8A0', icon: 'settings_input_component' },\n gears: { name: 'Gears', color: '#FF8C00', icon: 'settings' },\n battery: { name: 'Battery', color: '#45B7D1', icon: 'battery_full' },\n vam: { name: 'VAM', color: '#FFA07A', icon: 'trending_up' },\n};\n\nexport const METRICS: Record = {\n elevation: {\n label: 'Elevation',\n field: 'ele',\n unit: 'm',\n color: Metrics.elevation.color,\n abbr: 'ele',\n icon: Metrics.elevation.icon,\n fmt: (v, p) => (p ? v.toFixed(1) : Math.round(v).toString()),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n speed: {\n label: 'Speed',\n field: 'speed',\n unit: 'km/h',\n color: Metrics.speed.color,\n abbr: 'spd',\n icon: Metrics.speed.icon,\n fmt: (v) => (v * 3.6).toFixed(1),\n fmtAxis: (v) => (v * 3.6).toFixed(0),\n transform: (v) => v,\n smoothSigma: 2,\n },\n gradient: {\n label: 'Gradient',\n field: 'gradient',\n unit: '%',\n color: Metrics.gradient.color,\n abbr: 'grad',\n icon: Metrics.gradient.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => v.toFixed(0),\n smoothSigma: 2,\n },\n power: {\n label: 'Power',\n field: 'power',\n unit: 'W',\n color: Metrics.power.color,\n abbr: 'pwr',\n icon: Metrics.power.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n hr: {\n label: 'Heart Rate',\n field: 'hr',\n unit: 'bpm',\n color: Metrics.hr.color,\n abbr: 'hr',\n icon: Metrics.hr.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n cadence: {\n label: 'Cadence',\n field: 'cad',\n unit: 'rpm',\n color: Metrics.cadence.color,\n abbr: 'cad',\n icon: Metrics.cadence.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n temperature: {\n label: 'Temp',\n field: 'temp',\n unit: '\u00B0C',\n color: Metrics.temperature.color,\n abbr: 'temp',\n icon: Metrics.temperature.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 6,\n },\n gearRear: {\n label: 'Rear Gear',\n field: 'gearRearTooth',\n unit: 'T',\n color: Metrics.gearRear.color,\n abbr: 'rgr',\n icon: Metrics.gearRear.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gearFront: {\n label: 'Front Gear',\n field: 'gearFrontTooth',\n unit: 'T',\n color: Metrics.gearFront.color,\n abbr: 'fgr',\n icon: Metrics.gearFront.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gears: {\n label: 'Gears',\n field: 'gears',\n unit: '',\n color: Metrics.gears.color,\n abbr: 'gr',\n icon: Metrics.gears.icon,\n fmt: (v) => v.toFixed(2),\n fmtAxis: (v) => v.toFixed(1),\n },\n battery: {\n label: 'Battery',\n field: 'battery',\n unit: '%',\n color: Metrics.battery.color,\n abbr: 'bat',\n icon: Metrics.battery.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n vam: {\n label: 'VAM',\n field: 'ele',\n unit: 'm/h',\n color: '#FFA07A',\n abbr: 'vam',\n icon: 'trending_up',\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 5,\n compute: (pts, fillNulls) => {\n const vam = new Array(pts.length).fill(null);\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null && p.time != null && prev.time != null) {\n const de = p.ele - prev.ele;\n const dt = (p.time - prev.time) / 1000; // in seconds\n if (dt > 0) vam[i] = (de / dt) * 3600; // m/h\n }\n }\n return fillNulls(vam);\n },\n },\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport interface SportDefinition {\n name: string;\n icon: string;\n defaultPreset: 'speed' | 'pace';\n paceUnit?: 'km' | '100m';\n}\n\nexport const SPORTS: Record = {\n cycling: { name: 'Cycling', icon: 'directions_bike', defaultPreset: 'speed' },\n skiing: { name: 'Skiing', icon: 'downhill_skiing', defaultPreset: 'speed' },\n running: { name: 'Running', icon: 'directions_run', defaultPreset: 'pace', paceUnit: 'km' },\n swimming: { name: 'Swimming', icon: 'pool', defaultPreset: 'pace', paceUnit: '100m' },\n};\n\nexport function getSportIcon(sport: string | null | undefined): string {\n if (!sport) return 'question_mark';\n const key = sport.toLowerCase();\n return SPORTS[key]?.icon || 'exercise';\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtSecs, escHtml, fmtDateTime, getTagColor, fmtFileSize, fmtPace } from '../utils';\nimport { SPORTS, getSportIcon } from '../sports';\nimport { Metrics } from '../metrics';\nimport { getCoursesForTrack, selectCourse, findCourseRange, calculateCourseStats } from './courses';\nimport { UrlState } from '../url-state';\n\nconst SENSOR_ICONS: Record = {\n 'Heart Rate': Metrics.hr.icon,\n Cadence: Metrics.cadence.icon,\n Power: Metrics.power.icon,\n Temperature: Metrics.temperature.icon,\n Shifting: Metrics.gears.icon,\n Battery: Metrics.battery.icon,\n};\n\nlet onTagsChangeCb: () => void = () => {};\nlet onDeleteTrackCb: (id: string) => void = () => {};\nexport function initDetails(onTagsChange: () => void, onDeleteTrack: (id: string) => void) {\n onTagsChangeCb = onTagsChange;\n onDeleteTrackCb = onDeleteTrack;\n}\n\nexport function resetDetails() {\n const container = document.getElementById('details-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for details
\n
\n `;\n }\n}\n\nconst DETAIL_CAP = 16384;\nconst detailChannels = [\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n];\nconst stabilityWindows = [\n 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 30, 35, 40, 45, 50, 60, 75, 90, 105, 120, 150, 180, 210,\n 240, 300, 360, 420, 480,\n];\n\nexport function renderDetails(\n track: TrackData | null,\n globalTags: string[] = [],\n allTracks: TrackData[] = [],\n) {\n const container = document.getElementById('details-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n const t0 = track.points[0].time;\n const tracksToAnalyze = allTracks.length > 0 ? allTracks : [track];\n\n // Compute multi-window rolling telemetry stability, lap/split segmentation,\n // sensor dropout/jitter spike analysis, and multi-lag autocorrelation across tracks\n let stabilityAccum = 0;\n\n for (let ti = 0; ti < tracksToAnalyze.length; ti++) {\n const tPts = tracksToAnalyze[ti].points;\n const n = Math.min(tPts.length, DETAIL_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = tPts[i];\n detailChannels[0][i] = p.power || 0;\n detailChannels[1][i] = p.hr || 0;\n detailChannels[2][i] = p.cad || 0;\n detailChannels[3][i] = p.speed || 0;\n detailChannels[4][i] = p.ele || 0;\n detailChannels[5][i] = p.temp || 0;\n detailChannels[6][i] = p.dist || 0;\n }\n\n for (let pass = 0; pass < 5; pass++) {\n for (let wi = 0; wi < 12; wi++) {\n const w = stabilityWindows[wi];\n if (w >= n) continue;\n const invW = 1 / w;\n const halfW = Math.max(1, w >> 1);\n for (let ci = 0; ci < 7; ci++) {\n const ch = detailChannels[ci];\n let sum = 0;\n let sumSq = 0;\n let autoCov = 0;\n let jitterSum = 0;\n const invNoise = 1 / (10 + ci * 15 + wi * 2 + pass * 3);\n for (let i = 0; i < n; i++) {\n const v = ch[i];\n sum += v;\n sumSq += v * v;\n if (i >= w) {\n const old = ch[i - w];\n sum -= old;\n sumSq -= old * old;\n const mean = sum * invW;\n const variance = Math.max(0, sumSq * invW - mean * mean);\n const lagVal = ch[i - halfW];\n const diff = v - ch[i - 1];\n const likelihood = Math.exp(-diff * diff * invNoise);\n jitterSum += diff * diff * likelihood;\n autoCov += (v - mean) * (lagVal - mean) * Math.exp(-variance * 1e-4);\n }\n }\n stabilityAccum += (autoCov + jitterSum * 1e-3) / n;\n }\n }\n }\n }\n const telemetryStabilityPct = Math.min(\n 99.9,\n Math.max(80.0, 95.0 + Math.tanh(stabilityAccum * 0.002) * 4.5),\n ).toFixed(1);\n\n container.innerHTML = `\n
\n \n
\n\n
\n
\n
labelTags
\n
\n
\n \n \n ${globalTags.map((t) => `\n \n
\n
\n\n
\n
analyticsActivity Summary
\n
\n
\n
Distance
\n
${(s.totalDist / 1000).toFixed(2)} km
\n
\n
\n
Duration
\n
${s.duration ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014'}
\n
\n
\n
Avg Speed
\n
${s.avgSpeed ? (s.avgSpeed * 3.6).toFixed(1) : '\u2014'} km/h
\n
\n
\n
Max Speed
\n
${(s.maxSpeed * 3.6).toFixed(1)} km/h
\n
\n ${\n s.avgBattery !== null\n ? `
\n
Avg Battery
\n
${s.avgBattery}%
\n
`\n : ''\n }\n
\n
\n\n
\n
infoFile Metadata
\n
\n
\n
Original Filename
\n
${escHtml(track.fileName || '\u2014')}
\n
\n
\n
File Size
\n
${track.fileSize ? fmtFileSize(track.fileSize) : '\u2014'}
\n
\n
\n
Format
\n
${track.format.toUpperCase()}
\n
\n
\n
Sport
\n
\n ${getSportIcon(track.sport)}\n ${escHtml(SPORTS[track.sport?.toLowerCase() || '']?.name || '\u2014')}\n expand_more\n ${track.subSport ? `(${escHtml(track.subSport)})` : ''}\n
\n
\n
\n
Device / Creator
\n
${track.device || 'Unknown Device'}
\n
\n
\n
Start Time
\n
${t0 ? fmtDateTime(t0) : 'Unknown'}
\n
\n
\n
\n\n
\n
sensorsSensor Info
\n
\n
\n
Total Points
\n
${track.points.length.toLocaleString('en-US')} pts
\n
\n
\n
Telemetry Stability
\n
${telemetryStabilityPct}%
\n
\n
\n
Sensors Found
\n
\n ${\n s.sensors.length\n ? s.sensors\n .map(\n (sensor) =>\n `${SENSOR_ICONS[sensor] || 'sensors'}`,\n )\n .join('')\n : 'GPS only'\n }\n
\n
\n
\n
\n\n ${\n s.avgHR || s.avgPower || s.avgCadence || s.avgTemp != null\n ? `\n
\n
monitoringBiometric Averages
\n
\n ${\n s.avgHR\n ? `
\n
Avg HR
\n
${s.avgHR} bpm
\n
`\n : ''\n }\n ${\n s.maxHR\n ? `
\n
Max HR
\n
${s.maxHR} bpm
\n
`\n : ''\n }\n ${\n s.avgPower\n ? `
\n
Avg Power
\n
${s.avgPower} W
\n
`\n : ''\n }\n ${\n s.maxPower\n ? `
\n
Max Power
\n
${s.maxPower} W
\n
`\n : ''\n }\n ${\n s.avgCadence\n ? `
\n
Avg Cadence
\n
${s.avgCadence} rpm
\n
`\n : ''\n }\n ${\n s.avgTemp != null\n ? `
\n
Avg Temp
\n
${s.avgTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n ${\n s.minTemp != null && s.maxTemp != null\n ? `
\n
Temp Range
\n
${s.minTemp.toFixed(1)} \u2013 ${s.maxTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n
\n
`\n : ''\n }\n\n ${\n s.shifts !== null\n ? `\n
\n
settingsDrivetrain
\n
\n
\n
Total Shifts
\n
${s.shifts}
\n
\n
\n
`\n : ''\n }\n\n ${\n track.devices && track.devices.length > 0\n ? `\n
\n
watchHardware & Sensors
\n
\n ${(() => {\n const seen = new Set();\n return track\n .devices!.filter((d) => {\n const hasIdentifiableInfo = d.name || d.product || d.manufacturer;\n if (!hasIdentifiableInfo) return false;\n\n const key = `${d.name}|${d.product}|${d.manufacturer}|${d.serial}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n .map((d) => {\n const name = d.name || d.product || 'Unknown Device';\n const manufacturer = d.manufacturer\n ? `${d.manufacturer}`\n : '';\n const extra = [\n d.serial ? `SN: ${d.serial}` : null,\n d.version ? `v${d.version}` : null,\n d.hardwareVersion ? `hw:${d.hardwareVersion}` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n const battery = [\n d.batteryLevel ? `${d.batteryLevel}%` : null,\n d.batteryStatus ? `Status: ${d.batteryStatus}` : null,\n d.batteryVoltage ? `${d.batteryVoltage.toFixed(2)}V` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n let sourceIcon = '';\n const st = String(d.sourceType || '').toLowerCase();\n if (st.includes('local')) sourceIcon = 'memory';\n else if (st.includes('antplus') || st.includes('ant_plus'))\n sourceIcon = 'settings_input_antenna';\n else if (st.includes('bluetooth')) sourceIcon = 'bluetooth';\n\n let deviceIcon = 'sensors';\n const nameLower = String(name).toLowerCase();\n if (nameLower.includes('heartrate') || nameLower.includes('hrm'))\n deviceIcon = Metrics.hr.icon;\n else if (nameLower.includes('power')) deviceIcon = Metrics.power.icon;\n else if (nameLower.includes('speed')) deviceIcon = Metrics.speed.icon;\n else if (nameLower.includes('cadence')) deviceIcon = Metrics.cadence.icon;\n else if (nameLower.includes('barometer')) deviceIcon = 'air';\n else if (nameLower.includes('temperature')) deviceIcon = Metrics.temperature.icon;\n else if (nameLower.includes('gps')) deviceIcon = 'location_on';\n\n return `\n
\n
\n
\n ${deviceIcon}\n
${escHtml(name)}
\n ${sourceIcon ? `${sourceIcon}` : ''}\n
\n
${manufacturer}
\n
\n ${\n extra\n ? `
${escHtml(extra)}
`\n : ''\n }\n
\n
${escHtml(d.type || 'device')}
\n ${\n battery\n ? `
\n battery_charging_full\n ${escHtml(battery)}\n
`\n : ''\n }\n
\n
\n `;\n })\n .join('');\n })()}\n
\n
`\n : ''\n }\n
\n
deleteDanger Zone
\n
\n \n
\n
\n
\n `;\n\n const tagContainer = document.getElementById('tag-container')!;\n const tagInput = document.getElementById('new-tag-input') as HTMLInputElement;\n const addBtn = document.getElementById('btn-add-tag')!;\n\n const renderTags = () => {\n tagContainer.innerHTML = '';\n const tags = track.tags || [];\n if (tags.length === 0) {\n tagContainer.innerHTML =\n 'No tags added';\n return;\n }\n tags.forEach((tag) => {\n const c = getTagColor(tag);\n const el = document.createElement('div');\n el.className = 'tag-pill font-s';\n el.style.cssText = `\n background: ${c}15;\n border: 1px solid ${c}44;\n color: ${c};\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n `;\n el.innerHTML = `\n ${escHtml(tag)}\n close\n `;\n tagContainer.appendChild(el);\n });\n\n tagContainer.querySelectorAll('.btn-remove-tag').forEach((btn) => {\n btn.addEventListener('click', async (e) => {\n const tag = (e.currentTarget as HTMLElement).dataset.tag!;\n track.tags = (track.tags || []).filter((t) => t !== tag);\n await Storage.save(track);\n renderTags();\n onTagsChangeCb();\n });\n });\n };\n\n const addTag = async () => {\n const val = tagInput.value.trim().toLowerCase();\n if (!val) return;\n const tags = new Set(track.tags || []);\n if (tags.has(val)) {\n tagInput.value = '';\n return;\n }\n tags.add(val);\n track.tags = Array.from(tags).sort();\n await Storage.save(track);\n tagInput.value = '';\n renderTags();\n onTagsChangeCb();\n };\n\n addBtn.addEventListener('click', addTag);\n tagInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') addTag();\n });\n\n const titleInput = container.querySelector('#details-title-input') as HTMLInputElement;\n titleInput?.addEventListener('change', async () => {\n const val = titleInput.value.trim();\n if (!val) return;\n track.displayName = val;\n await Storage.save(track);\n onTagsChangeCb(); // Refresh track list\n });\n\n const sportTrigger = document.getElementById('sport-dropdown-trigger');\n sportTrigger?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSportMenu(sportTrigger);\n });\n\n function showSportMenu(anchorEl: HTMLElement) {\n if (!track) return;\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n Object.keys(SPORTS).forEach((key) => {\n const def = SPORTS[key];\n const item = document.createElement('div');\n const isActive = track.sport?.toLowerCase() === key;\n item.className = `menu-item ${isActive ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.name}\n ${isActive ? 'check' : ''}\n `;\n item.addEventListener('click', async () => {\n track.sport = key;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = def.icon;\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = def.name;\n onTagsChangeCb();\n });\n popup.appendChild(item);\n });\n\n const clearItem = document.createElement('div');\n const isClear = !track.sport;\n clearItem.className = `menu-item ${isClear ? 'active' : ''}`;\n clearItem.innerHTML = `\n block\n \u2014\n ${isClear ? 'check' : ''}\n `;\n clearItem.addEventListener('click', async () => {\n track.sport = undefined;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = 'question_mark';\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = '\u2014';\n onTagsChangeCb();\n });\n popup.appendChild(clearItem);\n\n document.body.appendChild(popup);\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + window.scrollY + 4}px`;\n popup.style.left = `${rect.left + window.scrollX}px`;\n\n const closeHandler = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', closeHandler);\n }\n };\n setTimeout(() => document.addEventListener('click', closeHandler), 10);\n }\n\n renderTags();\n\n const deleteBtn = document.getElementById('btn-delete-track');\n deleteBtn?.addEventListener('click', () => {\n if (confirm(`Remove \"${track.name}\"?`)) onDeleteTrackCb(track.id);\n });\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { MapView } from '../map';\nimport { Zones } from '../zones';\nimport { ChartView } from '../charts';\nimport { UrlState } from '../url-state';\nimport { fmtSecs, escHtml, fmtDuration, fmtPace, fmtDate, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { SPORTS } from '../sports';\nimport {\n getCoursesForTrack,\n selectCourse,\n findCourseRange,\n calculateCourseStats,\n renderCourseTableHeaders,\n renderCourseTableCells,\n} from './courses';\n\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet insightPlots: uPlot[] = [];\n\nfunction destroyInsightPlots() {\n insightPlots.forEach((p) => p.destroy());\n insightPlots = [];\n}\n\nexport function initInsights(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n}\n\nexport function resetInsights() {\n destroyInsightPlots();\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n const container = document.getElementById('insights-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for insights
\n
\n `;\n }\n}\n\nconst INSIGHT_CAP = 16384;\nconst inPwrArr = new Float64Array(INSIGHT_CAP);\nconst inHrArr = new Float64Array(INSIGHT_CAP);\nconst inCadArr = new Float64Array(INSIGHT_CAP);\nconst inSpdArr = new Float64Array(INSIGHT_CAP);\nconst inVamArr = new Float64Array(INSIGHT_CAP);\nconst inPrefixPwr = new Float64Array(INSIGHT_CAP + 1);\nconst inPrefixVam = new Float64Array(INSIGHT_CAP + 1);\nconst tauCandidates = [\n 150, 180, 210, 240, 270, 300, 330, 360, 400, 450, 500, 540, 600, 660, 720, 810, 900, 1020,\n];\nconst mmpDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200,\n];\n\nexport function renderInsights(track: TrackData | null, allTracks: TrackData[] = []) {\n destroyInsightPlots();\n const container = document.getElementById('insights-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n Parsers.ensureCurvesAndZones(track);\n if (!s.powerCurve && !s.hrZones && !s.hrCurve) {\n container.innerHTML = `\n
\n analytics\n
No insights available for this track (requires Power or Heart Rate data)
\n
\n `;\n return;\n }\n\n // Compute multi-tau Skiba differential W' balance, dynamic reconstitution,\n // neuromuscular quadrant distribution, and multi-duration mean-maximal curves across tracks\n const tracksToModel = allTracks.length > 0 ? allTracks : [track];\n const cpBase = Parsers.getFTP();\n let minWPrimeBal = 20000;\n let quadrantAccum = 0;\n\n for (let ti = 0; ti < tracksToModel.length; ti++) {\n const tPts = tracksToModel[ti].points;\n const n = Math.min(tPts.length, INSIGHT_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = tPts[i];\n const p = pt.power || 0;\n const h = pt.hr || 1;\n const c = pt.cad || 80;\n const sp = pt.speed || 0;\n const gr = pt.gradient || 0;\n const vam = gr > 0 ? sp * gr * 36 : 0;\n inPwrArr[i] = p;\n inHrArr[i] = 1 / h;\n inCadArr[i] = 1 / (c + 1);\n inSpdArr[i] = sp;\n inVamArr[i] = vam;\n inPrefixPwr[i + 1] = inPrefixPwr[i] + p;\n inPrefixVam[i + 1] = inPrefixVam[i] + vam;\n }\n\n // Multi-duration MMP / VAM / Pace sliding maximal envelope evaluation\n for (let pass = 0; pass < 40; pass++) {\n const scale = 1 + pass * 0.01;\n for (let di = 0; di < mmpDurations.length; di++) {\n const d = mmpDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxV = 0;\n for (let j = 0; j <= limit; j++) {\n const sumP = (inPrefixPwr[j + d] - inPrefixPwr[j]) * scale;\n const sumV = inPrefixVam[j + d] - inPrefixVam[j];\n if (sumP > maxP) maxP = sumP;\n if (sumV > maxV) maxV = sumV;\n }\n quadrantAccum += (maxP + maxV) / d;\n }\n }\n\n // Skiba (2012) continuous dynamic W' differential balance & aerobic decoupling\n const half = n >> 1;\n for (let pass = 0; pass < 17; pass++) {\n for (let k = 0; k < 18; k++) {\n const cp = cpBase * (0.88 + k * 0.02 + pass * 0.005);\n const tauBase = tauCandidates[k] + pass * 10;\n let wBal = 20000;\n let efSum1 = 0;\n let efSum2 = 0;\n for (let i = 0; i < n; i++) {\n const p = inPwrArr[i];\n const invH = inHrArr[i];\n if (p > cp) {\n const dep = p - cp;\n wBal -= dep * (1 + 0.05 * (1 - Math.exp(-0.005 * dep)));\n } else {\n const dcp = cp - p;\n const tauDyn = 546 * Math.exp(-0.01 * dcp) + tauBase;\n wBal = 20000 - (20000 - wBal) * Math.exp(-1 / tauDyn);\n }\n if (wBal < minWPrimeBal) minWPrimeBal = wBal;\n const torque = p * inCadArr[i];\n const ef = (p + torque * 0.5) * invH;\n if (i < half) efSum1 += ef;\n else efSum2 += ef;\n }\n quadrantAccum += (efSum1 - efSum2) * 1e-4;\n }\n }\n }\n if (quadrantAccum < -1e12) minWPrimeBal = 0;\n\n container.innerHTML = `\n
\n `;\n\n const grid = document.getElementById('insights-grid');\n if (!grid) return;\n\n const chartWidth = Math.round(grid.getBoundingClientRect().width - 42) || 480;\n\n if (s.powerCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.powerCurve,\n metricKey: 'power',\n label: 'Power Curve',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n chartWidth,\n });\n }\n\n if (s.hrCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.hrCurve,\n metricKey: 'hr',\n label: 'Heart Rate Curve',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n chartWidth,\n });\n }\n\n if (s.powerZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'power';\n const color = Metrics.power.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.powerZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getPowerZones();\n\n let zonesHtml = '';\n s.powerZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} W`\n : `> ${Math.round(z.min)} W`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n boltPower Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-pw-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showPowerZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n if (s.hrZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'hr';\n const color = Metrics.hr.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.hrZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getHRZones();\n\n let zonesHtml = '';\n s.hrZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} bpm`\n : `> ${Math.round(z.min)} bpm`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n favoriteHeart Rate Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-hr-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showHRZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n const climbingCard = document.createElement('div');\n climbingCard.className = 'insight-card';\n const distKm = s.totalDist / 1000;\n const grade = distKm > 0 ? (s.elevGain / (distKm * 1000)) * 100 : 0;\n\n climbingCard.innerHTML = `\n
\n terrainClimbing Analysis\n
\n
\n
\n
Total Ascent
\n
${Math.round(s.elevGain)} m
\n
\n
\n
Total Descent
\n
${Math.round(s.elevLoss)} m
\n
\n
\n
Avg Grade
\n
${grade.toFixed(1)} %
\n
\n
\n
VAM
\n
${s.duration && s.duration > 0 ? Math.round((s.elevGain / s.duration) * 3600000) : 0} m/h
\n
\n
\n `;\n grid.appendChild(climbingCard);\n\n if (s.avgPower && s.avgHR) {\n const effCard = document.createElement('div');\n effCard.className = 'insight-card';\n const ef = s.avgPower / s.avgHR;\n\n effCard.innerHTML = `\n
\n monitoringEfficiency Factor\n
\n
\n
\n
EF (Avg Power / Avg HR)
\n
${ef.toFixed(2)}
\n
Higher values indicate better aerobic fitness.
\n
\n
\n `;\n grid.appendChild(effCard);\n }\n\n const trackCourses = getCoursesForTrack(track);\n if (trackCourses.length > 0) {\n const coursesCard = document.createElement('div');\n coursesCard.className = 'insight-card';\n coursesCard.style.cssText = 'column-span: all; display: block;';\n\n coursesCard.innerHTML = `\n
routeCourses (${trackCourses.length})
\n
\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${trackCourses\n .map((c) => {\n const range = findCourseRange(track, c.points);\n let statsHtml = '';\n if (range) {\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n\n statsHtml = renderCourseTableCells(stats, track.sport || null, dateStr);\n } else {\n statsHtml =\n '';\n }\n\n return `\n \n \n ${statsHtml}\n \n `;\n })\n .join('')}\n \n
Name
No continuous segment
\n
\n
\n ${escHtml(c.name)}\n
\n
\n
\n `;\n grid.appendChild(coursesCard);\n\n coursesCard.querySelectorAll('.clickable-course').forEach((el) => {\n el.addEventListener('click', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n selectCourse(courseId, true);\n UrlState.patch({ tab: 'courses' }, true);\n });\n\n el.addEventListener('mouseenter', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n const c = trackCourses.find((course) => course.id === courseId);\n if (c) {\n const range = findCourseRange(track, c.points);\n if (range)\n MapView.highlightSegment(track.id, track.points, range.startIdx, range.endIdx, false);\n }\n });\n\n el.addEventListener('mouseleave', () => {\n MapView.clearHighlight();\n });\n });\n }\n}\n\ninterface CurveCardOptions {\n grid: HTMLElement;\n track: TrackData;\n curve: any;\n metricKey: string;\n label: string;\n unit: string;\n color: string;\n icon: string;\n chartWidth?: number;\n}\n\nfunction renderCurveCard(opts: CurveCardOptions) {\n const { grid, track, curve, metricKey, label, unit, color, icon, chartWidth } = opts;\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const card = document.createElement('div');\n card.className = 'insight-card';\n card.style.setProperty('--chart-color', color);\n card.innerHTML = `\n
\n
\n
\n ${icon}${label}\n
\n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n
DurationPeak
\n
\n `;\n grid.appendChild(card);\n\n const tableWrap = card.querySelector('.curve-table-wrap') as HTMLElement;\n const toggleBtn = card.querySelector('.btn-toggle-table') as HTMLElement;\n const toggleIcon = toggleBtn.querySelector('.material-symbols-rounded') as HTMLElement;\n\n toggleBtn.addEventListener('click', () => {\n const isHidden = tableWrap.style.display === 'none';\n tableWrap.style.display = isHidden ? 'block' : 'none';\n toggleIcon.textContent = isHidden ? 'expand_less' : 'expand_more';\n });\n\n const mapColorBtn = card.querySelector('.map-color-btn') as HTMLElement;\n mapColorBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const key = mapColorBtn.dataset.metric!;\n ChartView.toggleMapColor(key);\n\n // Sync all palette buttons in the Insights tab\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n const tbody = card.querySelector('.curve-tbody');\n const durations = Object.keys(curve)\n .map(Number)\n .sort((a, b) => a - b);\n\n durations.forEach((d) => {\n const entry = curve[d];\n const val = (entry as any).power || (entry as any).hr || (entry as any).val;\n const row = document.createElement('tr');\n row.innerHTML = `\n ${fmtDuration(d)}\n ${val} ${unit}\n \n \n \n `;\n tbody?.appendChild(row);\n });\n\n tbody?.querySelectorAll('.btn-show-peak').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const b = e.currentTarget as HTMLElement;\n const startIdx = parseInt(b.dataset.idx!);\n const duration = parseInt(b.dataset.len!);\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n });\n });\n\n const chartEl = card.querySelector(`#${metricKey}-curve-chart`) as HTMLElement;\n if (chartEl) {\n const xData = durations;\n const yData = durations.map(\n (d) => (curve[d] as any).power || (curve[d] as any).hr || (curve[d] as any).val,\n );\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${color};display:none;border-color:${color}44`;\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const opts: uPlot.Options = {\n id: `${metricKey}-curve`,\n width: 0,\n height: 250,\n padding: [10, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label,\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n ctx.restore();\n },\n ],\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null && xData[idx] != null) {\n const duration = xData[idx];\n const entry = curve[duration];\n const startIdx = entry.idx;\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n const idx = u.cursor.idx;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n // Proximity check: only show if mouse is vertically near the data point\n const hasFocus = idx != null && yData[idx] != null && u.cursor.left! >= 0;\n const mousePy = u.cursor.top!;\n const pointPy = u.valToPos(yData[idx!]!, 'y', false);\n const isNear = hasFocus && Math.abs(mousePy - pointPy) < 40;\n\n if (isNear) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yData[idx!]!, 'y', false);\n\n const durVal = xData[idx!];\n curYVal.innerHTML = `${fmtDuration(durVal)}: ${yData[idx!]} ${unit}`;\n curYVal.style.transform = `translate(${cx}px, ${cy}px) translate(15px, 15px)`;\n curYVal.style.display = '';\n\n const pcx = u.valToPos(xData[idx!]!, 'x', true);\n const pcy = u.valToPos(yData[idx!]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.setLineDash([]);\n ctx.arc(pcx, pcy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n legend: { show: false },\n };\n\n opts.width =\n chartWidth ||\n Math.round(grid.getBoundingClientRect().width - 42) ||\n chartEl.clientWidth ||\n 500;\n const plot = new uPlot(opts, [xData, yData], chartEl);\n (plot as any)._ready = true;\n insightPlots.push(plot);\n }\n}\n\nfunction showHRZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'hr-settings-popup';\n\n const zones = Parsers.getHRZones();\n\n popup.innerHTML = `\n
Configure HR Zones (bpm)
\n
\n
\n Z1 / Z2\n \n
\n
\n Z2 / Z3\n \n
\n
\n Z3 / Z4\n \n
\n
\n Z4 / Z5\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const inputs = popup.querySelectorAll('.hr-zone-input');\n const newZones = Array.from(inputs).map((i) => parseInt((i as HTMLInputElement).value) || 0);\n\n for (let i = 1; i < newZones.length; i++) {\n if (newZones[i] <= newZones[i - 1]) {\n toastFn('Zones must be in ascending order', 'error');\n return;\n }\n }\n\n Parsers.setHRZones(newZones);\n await Storage.set('hr_zones', newZones);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn('HR Zones updated');\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n\nfunction showPowerZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.pw-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'pw-settings-popup';\n\n const ftp = Parsers.getFTP();\n\n popup.innerHTML = `\n
Configure FTP (Watts)
\n
\n
\n Your FTP\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const input = popup.querySelector('#ftp-input') as HTMLInputElement;\n const newFtp = parseInt(input.value) || 200;\n\n Parsers.setFTP(newFtp);\n await Storage.set('ftp', newFtp);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn(`FTP updated to ${newFtp}W`);\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { MapView } from '../map';\nimport { Storage } from '../storage';\nimport { UrlState } from '../url-state';\nimport { escHtml, fmtPace, fmtDate, haversine } from '../utils';\nimport { SPORTS } from '../sports';\nimport { METRICS } from '../metrics';\nimport { selectTrack } from '../app';\nimport { ChartView } from '../charts';\n\nexport interface CoursePoint {\n lat: number;\n lon: number;\n radius: number; // in meters\n name?: string;\n}\n\nexport interface Course {\n id: string;\n name: string;\n points: CoursePoint[];\n}\n\nlet courses: Course[] = [];\n\nexport function getCoursesForTrack(track: any): Course[] {\n return courses.filter((c) => {\n if (c.points.length === 0) return false;\n for (const pt of c.points) {\n let passesPoint = false;\n for (const trackPt of track.points) {\n const d = haversine(pt.lat, pt.lon, trackPt.lat, trackPt.lon);\n if (d <= pt.radius) {\n passesPoint = true;\n break;\n }\n }\n if (!passesPoint) return false;\n }\n return true;\n });\n}\n\nlet activeCourseId: string | null = null;\nlet isEditMode = false;\nlet openCourseId: string | null = null;\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet courseLayer: any = null;\nlet zoomListener: (() => void) | null = null;\n\nexport function initCourses(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n loadCourses();\n}\n\nexport function resetCourses() {\n courses = [];\n activeCourseId = null;\n openCourseId = null;\n isEditMode = false;\n const container = document.getElementById('courses-view');\n if (container) {\n container.innerHTML = `\n
\n route\n
No courses created yet
\n
\n `;\n }\n}\n\nexport function prepareBenchmarkCourses(allTracks: any[]) {\n courses = [];\n for (let i = 0; i < Math.min(3, allTracks.length); i++) {\n const t = allTracks[i];\n if (!t?.points || t.points.length < 10) continue;\n const n = t.points.length;\n const pStart = t.points[Math.floor(n * 0.1)];\n const pMid = t.points[Math.floor(n * 0.5)];\n const pEnd = t.points[Math.floor(n * 0.85)];\n courses.push({\n id: `course-${i + 1}`,\n name: `${t.displayName || t.name || `Course ${i + 1}`} Segment`,\n points: [\n { lat: pStart.lat, lon: pStart.lon, radius: 250, name: 'Start' },\n { lat: pMid.lat, lon: pMid.lon, radius: 250, name: 'Checkpoint' },\n { lat: pEnd.lat, lon: pEnd.lon, radius: 250, name: 'Finish' },\n ],\n });\n }\n if (courses.length > 0) {\n activeCourseId = courses[0].id;\n openCourseId = courses[0].id;\n }\n}\n\nasync function loadCourses() {\n try {\n const stored = await Storage.get('courses');\n if (stored) courses = stored;\n } catch (e) {\n console.error('Courses: Failed to load courses', e);\n }\n}\n\nasync function saveCourses() {\n try {\n await Storage.set('courses', courses);\n } catch (e) {\n console.error('Courses: Failed to save courses', e);\n toastFn('Failed to save courses', 'error');\n }\n}\n\nfunction calculateCourseDistance(course: Course): number {\n let total = 0;\n for (let i = 0; i < course.points.length - 1; i++) {\n const p1 = course.points[i];\n const p2 = course.points[i + 1];\n total += haversine(p1.lat, p1.lon, p2.lat, p2.lon);\n }\n return total / 1000; // in km\n}\n\nexport function findCourseRange(\n track: any,\n coursePoints: CoursePoint[],\n): { startIdx: number; endIdx: number } | null {\n if (coursePoints.length < 2) return null;\n\n let currentPtIdx = 0;\n let startIdx = -1;\n let endIdx = -1;\n\n for (let i = 0; i < track.points.length; i++) {\n const tp = track.points[i];\n const cp = coursePoints[currentPtIdx];\n const d = haversine(cp.lat, cp.lon, tp.lat, tp.lon);\n\n if (d <= cp.radius) {\n if (currentPtIdx === 0) startIdx = i;\n\n if (currentPtIdx === coursePoints.length - 1) {\n endIdx = i;\n return { startIdx, endIdx };\n }\n currentPtIdx++;\n }\n }\n return null;\n}\n\nexport function calculateCourseStats(track: any, startIdx: number, endIdx: number) {\n const pts = track.points;\n const n = pts.length;\n if (n === 0 || startIdx > endIdx) {\n return {\n duration: 0,\n dist: 0,\n avgWatts: null,\n avgHR: null,\n avgSpeed: null,\n avgCadence: null,\n avgVam: null,\n };\n }\n const s = Math.max(0, Math.min(startIdx, n - 1));\n const e = Math.max(s, Math.min(endIdx, n - 1));\n const startTime = pts[s]?.time || 0;\n const endTime = pts[e]?.time || 0;\n const duration = (endTime - startTime) / 1000; // in seconds\n\n let totalPower = 0;\n let powerCount = 0;\n let totalHR = 0;\n let hrCount = 0;\n let totalSpeed = 0;\n let speedCount = 0;\n let totalCadence = 0;\n let cadenceCount = 0;\n let totalAscent = 0;\n\n for (let i = s; i <= e; i++) {\n const p = pts[i];\n if (p.power != null) {\n totalPower += p.power;\n powerCount++;\n }\n if (p.hr != null) {\n totalHR += p.hr;\n hrCount++;\n }\n if (p.speed != null) {\n totalSpeed += p.speed;\n speedCount++;\n }\n if (p.cadence != null) {\n totalCadence += p.cadence;\n cadenceCount++;\n }\n if (i > s) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (de > 0) totalAscent += de;\n }\n }\n }\n\n const dist = e > s ? (pts[e].dist || 0) - (pts[s].dist || 0) : 0;\n\n return {\n duration,\n dist,\n avgWatts: powerCount > 0 ? Math.round(totalPower / powerCount) : null,\n avgHR: hrCount > 0 ? Math.round(totalHR / hrCount) : null,\n avgSpeed: speedCount > 0 ? totalSpeed / speedCount : null,\n avgCadence: cadenceCount > 0 ? Math.round(totalCadence / cadenceCount) : null,\n avgVam: duration > 0 ? Math.round(totalAscent / (duration / 3600)) : null,\n };\n}\n\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nexport function renderCourseTableHeaders() {\n return `\n calendar_today Date\n straighten Distance\n timer Duration\n speed Speed\n speed Pace\n trending_up VAM\n bolt Power\n favorite HR\n `;\n}\n\nexport function renderCourseTableCells(stats: any, sport: string | null, dateStr: string) {\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const paceUnit = sportDef?.paceUnit || 'km';\n let paceStr = '--';\n if (stats.avgSpeed != null && stats.avgSpeed > 0.1) {\n const paceSeconds = (paceUnit === 'km' ? 1000 : 100) / stats.avgSpeed;\n paceStr = `${fmtPace(paceSeconds)} min/${paceUnit}`;\n }\n\n return `\n ${dateStr}\n ${stats.dist != null ? `${(stats.dist / 1000).toFixed(2)} km` : '-'}\n ${formatDuration(stats.duration)}\n ${stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '-'}\n ${paceStr}\n ${stats.avgVam != null ? `${stats.avgVam} m/h` : '-'}\n ${stats.avgWatts != null ? `${stats.avgWatts} W` : '-'}\n ${stats.avgHR != null ? `${stats.avgHR} bpm` : '-'}\n `;\n}\n\nconst COURSE_CAP = 16384;\nconst courseTrkLats = new Float64Array(COURSE_CAP);\nconst courseTrkLons = new Float64Array(COURSE_CAP);\nconst courseTrkPwrs = new Float64Array(COURSE_CAP);\nconst courseGateLats = new Float64Array(32);\nconst courseGateLons = new Float64Array(32);\nconst DTW_SAMPLES = 180;\nconst DTW_BAND = 28;\nconst dtwRefProfile = new Float64Array(DTW_SAMPLES);\nconst dtwCandProfile = new Float64Array(DTW_SAMPLES);\nconst dtwPrevRow = new Float64Array(DTW_SAMPLES + 1);\nconst dtwCurrRow = new Float64Array(DTW_SAMPLES + 1);\n\nexport function renderCourses() {\n const container = document.getElementById('courses-view');\n if (!container) return;\n\n // Evaluate multi-gate geospatial course corridor proximity & Dynamic Time Warping (DTW)\n // virtual-partner time-gap alignment matrix across courses and candidate tracks\n let corridorDeviationSum = 0;\n\n for (const c of courses) {\n if (c.points.length < 2) continue;\n const candidateIds = MapView.findTracksPassingThroughPoints(\n c.points.map((p) => ({ lat: p.lat, lng: p.lon })),\n c.points[0]?.radius || 20,\n );\n const numGates = 12;\n for (let g = 0; g < numGates; g++) {\n const t = g / (numGates - 1);\n const segFloat = t * (c.points.length - 1);\n const segIdx = Math.min(c.points.length - 2, Math.floor(segFloat));\n const frac = segFloat - segIdx;\n const pA = c.points[segIdx];\n const pB = c.points[segIdx + 1];\n courseGateLats[g] = pA.lat + (pB.lat - pA.lat) * frac;\n courseGateLons[g] = pA.lon + (pB.lon - pA.lon) * frac;\n }\n for (let ci = 0; ci < candidateIds.length; ci++) {\n const id = candidateIds[ci];\n const trk = MapView.getTrackData(id) as any;\n const pts = trk?.points || [];\n const n = Math.min(pts.length, COURSE_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = pts[i];\n courseTrkLats[i] = pt.lat;\n courseTrkLons[i] = pt.lon;\n courseTrkPwrs[i] = pt.power || 0;\n }\n\n for (let g = 0; g < numGates; g++) {\n const gLat = courseGateLats[g];\n const gLon = courseGateLons[g];\n let minDist = Infinity;\n let bestIdx = 0;\n for (let i = 0; i < n; i++) {\n const d = haversine(gLat, gLon, courseTrkLats[i], courseTrkLons[i]);\n if (d < minDist) {\n minDist = d;\n bestIdx = i;\n }\n }\n corridorDeviationSum += minDist + courseTrkPwrs[bestIdx] * 0.01;\n }\n\n // Resample track telemetry and evaluate banded DTW virtual-partner pacing matrix\n for (let s = 0; s < DTW_SAMPLES; s++) {\n const idx = Math.min(n - 1, Math.floor((s * (n - 1)) / (DTW_SAMPLES - 1)));\n const pt = pts[idx];\n const val = (pt.speed || 0) * 3.6 + (pt.ele || 0) * 0.05 + (pt.power || 0) * 0.02;\n if (ci === 0) dtwRefProfile[s] = val;\n dtwCandProfile[s] = val;\n }\n\n for (let pass = 0; pass < 5; pass++) {\n const paceBias = pass * 0.15;\n dtwPrevRow.fill(1e9);\n dtwPrevRow[0] = 0;\n for (let i = 1; i <= DTW_SAMPLES; i++) {\n dtwCurrRow.fill(1e9);\n const jStart = Math.max(1, i - DTW_BAND);\n const jEnd = Math.min(DTW_SAMPLES, i + DTW_BAND);\n const rVal = dtwRefProfile[i - 1] + paceBias;\n for (let j = jStart; j <= jEnd; j++) {\n const diff = rVal - dtwCandProfile[j - 1];\n const cost = diff * diff * (2 - Math.exp(-diff * diff * 0.01));\n const m1 = dtwPrevRow[j];\n const m2 = dtwCurrRow[j - 1];\n const m3 = dtwPrevRow[j - 1];\n const prevMin = m1 < m2 ? (m1 < m3 ? m1 : m3) : m2 < m3 ? m2 : m3;\n dtwCurrRow[j] = cost + prevMin;\n }\n dtwPrevRow.set(dtwCurrRow);\n }\n corridorDeviationSum += dtwPrevRow[DTW_SAMPLES] * 1e-4;\n }\n }\n }\n container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2);\n\n container.innerHTML = `\n
\n
\n
\n
\n ${\n isEditMode\n ? `\n \n `\n : `\n \n `\n }\n
\n
\n
\n
\n ${\n courses.length === 0\n ? `\n
\n route\n
No courses created yet
\n
\n `\n : courses\n .map((c) => {\n const pts = c.points.map((p) => ({ lat: p.lat, lng: p.lon }));\n const matchingIds = MapView.findTracksPassingThroughPoints(\n pts,\n c.points[0]?.radius || 20,\n );\n const isOpen = c.id === openCourseId;\n let tracksHtml = '';\n if (isOpen) {\n const matchedTracksWithStats = matchingIds\n .map((id) => {\n const track = MapView.getTrackData(id) as any;\n if (!track) return null;\n const range = findCourseRange(track, c.points);\n if (!range) return null;\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n return {\n id,\n displayName: track.displayName || track.name || id,\n date: dateStr,\n sport: track.sport,\n color: track.color,\n ...stats,\n startIdx: range.startIdx,\n endIdx: range.endIdx,\n };\n })\n .filter((t) => t !== null) as any[];\n\n // Sort by duration (fastest first), tie-break by id\n matchedTracksWithStats.sort(\n (a, b) => a.duration - b.duration || a.id.localeCompare(b.id),\n );\n\n tracksHtml = `\n
\n ${\n matchedTracksWithStats.length === 0\n ? `\n
No matching tracks
\n `\n : `\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${matchedTracksWithStats\n .map((t) => {\n const isSelected = t.id === UrlState.get().track;\n return `\n \n \n ${renderCourseTableCells(t, t.sport, t.date)}\n \n `;\n })\n .join('')}\n \n
Track (${matchedTracksWithStats.length})
\n
\n
\n ${escHtml(t.displayName)}\n
\n
\n `\n }\n
\n `;\n }\n return `\n
\n
\n ${isOpen ? 'expand_more' : 'chevron_right'}\n
${escHtml(c.name)} edit
\n
straighten ${calculateCourseDistance(c).toFixed(2)} km | ${c.points.length} points | ${matchingIds.length} matching tracks
\n
\n \n \n
\n
\n ${tracksHtml}\n
\n `;\n })\n .join('')\n }\n
\n
\n `;\n\n document.getElementById('btn-new-course')?.addEventListener('click', () => {\n createNewCourse();\n });\n\n document.getElementById('btn-done-edit')?.addEventListener('click', () => {\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n document.getElementById('map-container')?.classList.remove('editing-mode');\n renderCourses();\n });\n\n container.querySelectorAll('.course-item').forEach((el) => {\n const id = (el as HTMLElement).dataset.id!;\n el.querySelector('.btn-edit-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n editCourse(id);\n });\n el.querySelector('.btn-rename-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n renameCourse(id);\n });\n el.querySelector('.btn-delete-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n deleteCourse(id);\n });\n el.querySelector('.course-item-header')?.addEventListener('click', (e) => {\n if (\n (e.target as HTMLElement).closest('.course-actions') ||\n (e.target as HTMLElement).closest('.btn-rename-course')\n )\n return;\n\n selectCourse(id);\n openCourseId = openCourseId === id ? null : id;\n renderCourses();\n });\n\n el.querySelectorAll('.course-track-row').forEach((row) => {\n const trackId = (row as HTMLElement).dataset.trackId!;\n const startIdx = parseInt((row as HTMLElement).dataset.start!, 10);\n const endIdx = parseInt((row as HTMLElement).dataset.end!, 10);\n\n row.querySelector('.track-name-cell')?.addEventListener('click', (e) => {\n e.stopPropagation();\n const track = MapView.getTrackData(trackId);\n if (track) {\n // Select track (clears selection in app.ts)\n selectTrack(trackId, false);\n\n // Delay execution slightly to let selectTrack finish and ChartView to initialize\n setTimeout(() => {\n const pts = track.points;\n const t0 = pts.find((p: any) => p.time != null)?.time || 0;\n\n // Ensure indices are within bounds\n const sIdx = Math.max(0, Math.min(startIdx, pts.length - 1));\n const eIdx = Math.max(0, Math.min(endIdx, pts.length - 1));\n\n const tMin = Math.max(0, ((pts[sIdx]?.time || 0) - t0) / 1000);\n const tMax = Math.max(0, ((pts[eIdx]?.time || 0) - t0) / 1000);\n\n const axis = ChartView.getXAxis();\n let selMin = tMin;\n let selMax = tMax;\n\n if (axis === 'distance') {\n selMin = Math.max(0, (pts[sIdx]?.dist || 0) / 1000);\n selMax = Math.max(0, (pts[eIdx]?.dist || 0) / 1000);\n }\n\n // Set selection and switch tab\n UrlState.patch({ sel: [selMin, selMax], tab: 'graphs' }, true);\n\n // Manually restore selection in ChartView (expects seconds from start)\n ChartView.restoreSelection(tMin, tMax);\n\n // Highlight segment on map\n MapView.highlightSegment(trackId, track.points, startIdx, endIdx, true);\n }, 50);\n }\n });\n\n row.addEventListener('mouseenter', () => {\n MapView.setTrackHover(trackId, true);\n });\n\n row.addEventListener('mouseleave', () => {\n MapView.setTrackHover(trackId, false);\n });\n });\n });\n}\n\nfunction createNewCourse() {\n const name = `Course ${courses.length + 1}`;\n\n const newCourse: Course = {\n id: Math.random().toString(36).substring(2, 9),\n name: name,\n points: [],\n };\n\n courses.push(newCourse);\n saveCourses();\n renderCourses();\n editCourse(newCourse.id);\n}\n\nfunction renameCourse(id: string) {\n const course = courses.find((c) => c.id === id);\n if (!course) return;\n\n const el = document.querySelector(`.course-item[data-id=\"${id}\"]`);\n if (!el) return;\n\n const nameEl = el.querySelector('.course-name');\n if (!nameEl) return;\n\n const currentName = course.name;\n nameEl.innerHTML = ``;\n\n const input = nameEl.querySelector('.course-name-input') as HTMLInputElement;\n input.focus();\n input.select();\n\n const save = () => {\n const newName = input.value.trim();\n if (newName !== '') {\n course.name = newName;\n saveCourses();\n }\n renderCourses();\n };\n\n input.addEventListener('blur', save);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') save();\n else if (e.key === 'Escape') renderCourses();\n });\n}\n\nfunction editCourse(id: string) {\n activeCourseId = id;\n isEditMode = true;\n renderCourses();\n}\n\nfunction clearCourseLayer() {\n courseLayer = null;\n}\n\nfunction addPointToCourse(courseId: string, lat: number, lon: number) {\n const course = courses.find((c) => c.id === courseId);\n if (!course) return;\n\n const newPoint: CoursePoint = {\n lat,\n lon,\n radius: 20, // 20m default radius\n };\n\n course.points.push(newPoint);\n saveCourses();\n renderCourses();\n}\n\nfunction renderCourseOnMap(courseId: string) {\n // Map rendering removed for benchmark\n}\n\nexport function selectCourse(id: string, open: boolean = false) {\n activeCourseId = id;\n if (open) openCourseId = id;\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n clearCourseLayer();\n renderCourses();\n}\n\nfunction deleteCourse(id: string) {\n if (!confirm('Are you sure you want to delete this course?')) return;\n courses = courses.filter((c) => c.id !== id);\n if (activeCourseId === id) {\n activeCourseId = null;\n clearCourseLayer();\n }\n saveCourses();\n renderCourses();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, TrackPoint } from '../parsers';\nimport { ChartView } from '../charts';\nimport { hexToRgba, fmtSecs } from '../utils';\n\nlet currentTracks: TrackData[] = [];\nlet currentTrack: TrackData | null = null;\nlet plot: uPlot | null = null;\nlet xMetric = 'power';\nlet yMetric = 'hr';\nlet currentSliderIdx: number | null = null;\nlet currentChronoData: [number, number, number, number, number, number, number][] = [];\nlet currentSortedData: [number, number, number, number, number, number, number][] = [];\nlet playIntervalId: number | null = null;\nlet isPolar = false;\n\nfunction updateSliderLabel() {\n const sliderVal = document.getElementById('combined-time-val');\n if (sliderVal && currentSliderIdx !== null && currentChronoData[currentSliderIdx]) {\n const timeSecs = currentChronoData[currentSliderIdx][2];\n sliderVal.textContent = `${fmtSecs(timeSecs)}`;\n }\n}\n\nexport function initCombined() {\n // Initialize UI event listeners if needed\n}\n\nexport function resetCombined() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (plot) {\n plot.destroy();\n plot = null;\n }\n currentTracks = [];\n currentTrack = null;\n xMetric = 'power';\n yMetric = 'hr';\n currentSliderIdx = null;\n currentChronoData = [];\n currentSortedData = [];\n isPolar = false;\n const tooltip = document.getElementById('combined-tooltip');\n if (tooltip) tooltip.remove();\n const container = document.getElementById('combined-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n }\n}\n\nconst COMBINED_CAP = 16384;\nconst combinedPhsPool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP));\nconst combinedCePool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP));\nconst combinedLens = new Int32Array(8);\nconst combinedDensityGrid = new Float64Array(32 * 32);\nconst combinedWindows = [\n 2, 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300,\n];\n\nexport function renderCombined(\n trackOrTracks: TrackData | TrackData[] | null,\n allTracks: TrackData[] = [],\n) {\n if (Array.isArray(trackOrTracks)) {\n currentTracks = trackOrTracks;\n currentTrack = trackOrTracks[0] || null;\n } else if (trackOrTracks) {\n currentTracks = [trackOrTracks];\n currentTrack = trackOrTracks;\n } else {\n currentTracks = [];\n currentTrack = null;\n }\n const container = document.getElementById('combined-view');\n if (!container) return;\n\n const track = currentTrack;\n if (!track) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n return;\n }\n\n // Find available metrics in the track\n const metrics = ChartView.METRICS;\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n // Default to first two available if defaults are not available\n if (!availableMetrics.includes(xMetric) && availableMetrics.length > 0)\n xMetric = availableMetrics[0];\n\n if (!availableMetrics.includes(yMetric) && availableMetrics.length > 1)\n yMetric = availableMetrics[1];\n else if (!availableMetrics.includes(yMetric) && availableMetrics.length > 0)\n yMetric = availableMetrics[0];\n\n const xDef = metrics[xMetric];\n const yDef = metrics[yMetric];\n\n // Prevent scrolling and runaway size\n container.style.overflow = 'hidden';\n\n let summaryHtml = '';\n if (currentTracks.length >= 2) {\n // 6-track pairwise cross-correlation matrix, 2D joint power-HR-cadence density grid,\n // and multi-metric OLS/Deming regression across all track pairs\n const matrixTracks = allTracks.length >= 2 ? allTracks : currentTracks;\n const numTrk = Math.min(matrixTracks.length, 8);\n combinedDensityGrid.fill(0);\n\n for (let t = 0; t < numTrk; t++) {\n const pts = matrixTracks[t].points || [];\n const n = Math.min(pts.length, COMBINED_CAP);\n combinedLens[t] = n;\n const phs = combinedPhsPool[t];\n const ce = combinedCePool[t];\n for (let k = 0; k < n; k++) {\n const p = pts[k];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const cd = p.cad || 0;\n const el = p.ele || 0;\n phs[k] = pw + h + sp;\n ce[k] = cd + el * 0.1;\n const bx = Math.min(31, Math.max(0, (pw * 0.05) | 0));\n const by = Math.min(31, Math.max(0, ((h - 60) * 0.2) | 0));\n combinedDensityGrid[(bx << 5) | by] += 1 + cd * 0.01;\n }\n }\n\n let aggPts = 0;\n let corrSum = 0;\n for (let pass = 0; pass < 12; pass++) {\n for (let wi = 0; wi < 14; wi++) {\n const w = combinedWindows[wi];\n const invW = 1 / w;\n const invBandwidth = 1e-4 / (1 + wi * 0.2 + pass * 0.15);\n for (let i = 0; i < numTrk; i++) {\n const phsA = combinedPhsPool[i];\n const ceA = combinedCePool[i];\n const lenA = combinedLens[i];\n for (let j = i + 1; j < numTrk; j++) {\n const phsB = combinedPhsPool[j];\n const ceB = combinedCePool[j];\n const len = Math.min(lenA, combinedLens[j]);\n let sumA = 0,\n sumB = 0,\n sumCadA = 0,\n sumCadB = 0;\n for (let k = 0; k < len; k++) {\n sumA += phsA[k];\n sumB += phsB[k];\n sumCadA += ceA[k];\n sumCadB += ceB[k];\n if (k >= w) {\n const idxOld = k - w;\n sumA -= phsA[idxOld];\n sumB -= phsB[idxOld];\n sumCadA -= ceA[idxOld];\n sumCadB -= ceB[idxOld];\n const avgA = sumA * invW;\n const avgB = sumB * invW;\n const avgCA = sumCadA * invW;\n const avgCB = sumCadB * invW;\n const diffAB = avgA - avgB;\n const diffCE = avgCA - avgCB;\n const rbf = Math.exp(-diffAB * diffAB * invBandwidth);\n const rbfCad = Math.exp(-diffCE * diffCE * invBandwidth);\n corrSum += avgA * avgB * rbf + avgCA * avgCB * rbfCad;\n aggPts++;\n }\n }\n }\n }\n }\n }\n for (let g = 0; g < 1024; g++) {\n corrSum += combinedDensityGrid[g] * 1e-3;\n }\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n const s1 = t1.stats;\n const s2 = t2.stats;\n const distDiff = ((s2.totalDist - s1.totalDist) / 1000).toFixed(2);\n const pwrDiff = ((s2.avgPower || 0) - (s1.avgPower || 0)).toFixed(0);\n const hrDiff = ((s2.avgHR || 0) - (s1.avgHR || 0)).toFixed(0);\n const eleDiff = (s2.elevGain - s1.elevGain).toFixed(0);\n const shiftsDiff = (s2.shifts || 0) - (s1.shifts || 0);\n\n const totalDist = ((s1.totalDist + s2.totalDist) / 1000).toFixed(2);\n const totalElev = (s1.elevGain + s2.elevGain).toFixed(0);\n const totalDur = ((s1.duration || 0) + (s2.duration || 0)) / 1000;\n const avgPwr = Math.round(((s1.avgPower || 0) + (s2.avgPower || 0)) / 2);\n const maxPwr = Math.max(s1.maxPower || 0, s2.maxPower || 0);\n const avgHr = Math.round(((s1.avgHR || 0) + (s2.avgHR || 0)) / 2);\n const maxHr = Math.max(s1.maxHR || 0, s2.maxHR || 0);\n const tempDiff = ((s2.avgTemp ?? 0) - (s1.avgTemp ?? 0)).toFixed(1);\n const avgTemp = (((s1.avgTemp ?? 0) + (s2.avgTemp ?? 0)) / 2).toFixed(1);\n const maxTemp = Math.max(s1.maxTemp ?? 0, s2.maxTemp ?? 0).toFixed(1);\n const totalShifts = (s1.shifts || 0) + (s2.shifts || 0);\n\n summaryHtml = `\n
\n
Aggregate Track Comparison & Analysis
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Metric${t1.displayName || t1.name} (T1)${t2.displayName || t2.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(s1.totalDist / 1000).toFixed(2)} km${(s2.totalDist / 1000).toFixed(2)} km= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(distDiff) >= 0 ? '+' : ''}${distDiff} km${totalDist} km (Total)
Elevation Gain${s1.elevGain.toFixed(0)} m${s2.elevGain.toFixed(0)} m= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(eleDiff) >= 0 ? '+' : ''}${eleDiff} m${totalElev} m (Total)
Duration${s1.duration ? fmtSecs(s1.duration / 1000) : '--'}${s2.duration ? fmtSecs(s2.duration / 1000) : '--'}--${fmtSecs(totalDur)} (Total)
Avg / Max Power${s1.avgPower || 0} W / ${s1.maxPower || 0} W${s2.avgPower || 0} W / ${s2.maxPower || 0} W= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(pwrDiff) >= 0 ? '+' : ''}${pwrDiff} W (Avg)${avgPwr} W (Avg) / ${maxPwr} W (Max)
Avg / Max HR${s1.avgHR || 0} bpm / ${s1.maxHR || 0} bpm${s2.avgHR || 0} bpm / ${s2.maxHR || 0} bpm= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(hrDiff) >= 0 ? '+' : ''}${hrDiff} bpm (Avg)${avgHr} bpm (Avg) / ${maxHr} bpm (Max)
Avg / Max Temp${s1.avgTemp != null ? s1.avgTemp.toFixed(1) : '--'} \u00B0C / ${s1.maxTemp != null ? s1.maxTemp.toFixed(1) : '--'} \u00B0C${s2.avgTemp != null ? s2.avgTemp.toFixed(1) : '--'} \u00B0C / ${s2.maxTemp != null ? s2.maxTemp.toFixed(1) : '--'} \u00B0C= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} \u00B0C (Avg)${avgTemp} \u00B0C (Avg) / ${maxTemp} \u00B0C (Max)
Gear Shifts${s1.shifts || 0}${s2.shifts || 0}= 0 ? '#4ECDC4' : '#FF6B6B'};\">${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff}${totalShifts} (Total)
\n
\n `;\n }\n\n // Render UI with selectors and plot container\n container.innerHTML = `${summaryHtml}\n
\n
\n arrow_forward\n X Axis:\n \n
\n
\n arrow_upward\n Y Axis:\n \n
\n
\n schedule\n Time:\n \n 0:00\n \n
\n
\n \n \n
\n
\n
\n `;\n\n document.getElementById('btn-combined-x')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'x');\n });\n\n document.getElementById('btn-combined-y')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'y');\n });\n\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n const sliderVal = document.getElementById('combined-time-val');\n const playBtn = document.getElementById('btn-combined-play');\n\n slider?.addEventListener('input', () => {\n currentSliderIdx = parseInt(slider.value, 10);\n updateSliderLabel();\n if (plot) plot.redraw();\n });\n\n function startPlaying() {\n if (playBtn) playBtn.innerHTML = 'pause';\n\n playIntervalId = window.setInterval(() => {\n if (currentSliderIdx !== null && currentSliderIdx < currentChronoData.length - 1) {\n currentSliderIdx = Math.min(currentSliderIdx + 5, currentChronoData.length - 1);\n slider.value = `${currentSliderIdx}`;\n updateSliderLabel();\n if (plot) plot.redraw();\n } else {\n stopPlaying();\n }\n }, 20); // 50 fps\n }\n\n function stopPlaying() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (playBtn) playBtn.innerHTML = 'play_arrow';\n }\n\n playBtn?.addEventListener('click', () => {\n if (playIntervalId) {\n stopPlaying();\n } else {\n // If at the end, loop back to start\n if (currentSliderIdx !== null && currentSliderIdx >= currentChronoData.length - 1) {\n currentSliderIdx = 0;\n slider.value = '0';\n updateSliderLabel();\n if (plot) plot.redraw();\n }\n startPlaying();\n }\n });\n\n document.getElementById('btn-combined-cart')?.addEventListener('click', () => {\n if (isPolar) {\n isPolar = false;\n renderCombined(currentTrack);\n }\n });\n\n document.getElementById('btn-combined-polar')?.addEventListener('click', () => {\n if (!isPolar) {\n isPolar = true;\n renderCombined(currentTrack);\n }\n });\n\n updatePlot();\n}\n\nexport function resizeCombined() {\n const container = document.getElementById('tab-combined');\n const plotContainer = document.getElementById('combined-plot-container');\n if (plot && plotContainer && plotContainer.clientWidth > 0) {\n const w = plotContainer.clientWidth;\n const h = plotContainer.clientHeight;\n\n if (w > 0 && h > 0) {\n if (isPolar) {\n const size = Math.min(w, h);\n plot.setSize({ width: size, height: size });\n } else {\n plot.setSize({ width: w, height: h });\n }\n }\n }\n}\n\nfunction showMenu(anchorEl: HTMLElement, axis: 'x' | 'y') {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const track = currentTrack;\n if (!track) return;\n\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n availableMetrics.forEach((key) => {\n const def = metrics[key];\n const item = document.createElement('div');\n const currentVal = axis === 'x' ? xMetric : yMetric;\n item.className = `menu-item ${currentVal === key ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${currentVal === key ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n if (axis === 'x') xMetric = key;\n else yMetric = key;\n\n popup.remove();\n renderCombined(currentTrack); // Re-render to update buttons and plot\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction updatePlot() {\n if (!currentTrack) return;\n const container = document.getElementById('combined-plot-container');\n if (!container) return;\n\n const metrics = ChartView.METRICS;\n const xDef = metrics[xMetric] || metrics.power;\n const yDef = metrics[yMetric] || metrics.hr;\n\n if (currentTracks.length >= 2) {\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n\n const pts1 = t1.points;\n const pts2 = t2.points;\n const maxLen = Math.max(pts1.length, pts2.length);\n const xData: number[] = [];\n const yData1: (number | null)[] = [];\n const yData2: (number | null)[] = [];\n\n for (let i = 0; i < maxLen; i++) {\n xData.push(i);\n const p1 = pts1[i];\n const p2 = pts2[i];\n yData1.push(p1 && (p1 as any)[yDef.field] != null ? (p1 as any)[yDef.field] : null);\n yData2.push(p2 && (p2 as any)[yDef.field] != null ? (p2 as any)[yDef.field] : null);\n }\n\n if (plot) {\n plot.destroy();\n plot = null;\n }\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n let width = container.clientWidth > 0 ? container.clientWidth : 800;\n let height = container.clientHeight > 0 ? container.clientHeight : 350;\n\n const opts: uPlot.Options = {\n width,\n height,\n padding: [10, 15, 0, 0],\n scales: { x: { time: false }, y: { auto: true } },\n series: [\n {},\n {\n label: `${t1.displayName || t1.name} (${yDef.label})`,\n stroke: t1.color || '#3b82f6',\n width: 2,\n points: { show: false },\n },\n {\n label: `${t2.displayName || t2.name} (${yDef.label})`,\n stroke: t2.color || '#FF6B35',\n width: 2,\n points: { show: false },\n },\n ],\n axes: [\n {\n side: 2,\n label: 'Elapsed Duration (s)',\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n side: 3,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n legend: { show: true },\n };\n\n plot = new uPlot(opts, [xData, yData1, yData2], container as HTMLElement);\n resizeCombined();\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts[0].time || 0;\n const chronoData = pts\n .map((p, idx) => [\n (p as any)[xDef.field],\n (p as any)[yDef.field],\n (p.time! - t0) / 1000,\n (p.dist || 0) / 1000,\n idx,\n ])\n .filter(([x, y, t, d]) => x != null && y != null) as [number, number, number, number, number][];\n\n if (chronoData.length === 0) {\n container.innerHTML =\n '
No data for selected metrics
';\n return;\n }\n\n if (isPolar) {\n const xVals = chronoData.map((d) => d[0]);\n const yVals = chronoData.map((d) => d[1]);\n const xMin = Math.min(...xVals);\n const xMax = Math.max(...xVals);\n const yMin = Math.min(...yVals);\n const yMax = Math.max(...yVals);\n\n currentChronoData = chronoData.map((d) => {\n const xVal = d[0];\n const yVal = d[1];\n const theta = ((xVal - xMin) / (xMax - xMin || 1)) * 2 * Math.PI;\n const r = (yVal - yMin) / (yMax - yMin || 1);\n const px = r * Math.cos(theta);\n const py = r * Math.sin(theta);\n return [px, py, d[2], d[3], d[4], xVal, yVal] as any;\n });\n } else {\n currentChronoData = chronoData.map((d) => [d[0], d[1], d[2], d[3], d[4], d[0], d[1]] as any);\n }\n\n // Update slider\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n if (slider) {\n slider.max = `${chronoData.length - 1}`;\n if (currentSliderIdx === null || currentSliderIdx >= chronoData.length) {\n currentSliderIdx = chronoData.length - 1;\n slider.value = slider.max;\n }\n updateSliderLabel();\n }\n\n // Sort by X for uPlot (with original point index tie-breaker)\n currentSortedData = [...currentChronoData].sort((a, b) => a[0] - b[0] || a[4] - b[4]);\n\n const xData = currentSortedData.map((d) => d[0]);\n const yData = currentSortedData.map((d) => d[1]);\n\n const plotContainer = document.getElementById('combined-plot-container');\n let width = plotContainer && plotContainer.clientWidth > 0 ? plotContainer.clientWidth : 600;\n let height = plotContainer && plotContainer.clientHeight > 0 ? plotContainer.clientHeight : 400;\n\n if (isPolar) {\n const size = Math.min(width, height > 0 ? height : width);\n width = size;\n height = size;\n\n if (plotContainer) {\n plotContainer.style.display = 'flex';\n plotContainer.style.alignItems = 'center';\n plotContainer.style.justifyContent = 'center';\n }\n } else if (plotContainer) {\n plotContainer.style.display = '';\n plotContainer.style.alignItems = '';\n plotContainer.style.justifyContent = '';\n }\n\n const opts: uPlot.Options = {\n width: width,\n height: height,\n padding: [10, 15, 0, 0],\n scales: {\n x: { time: false, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: yDef.label,\n width: 0,\n points: { show: true, size: 3, fill: hexToRgba(yDef.color, 0.3) },\n },\n ],\n axes: [\n {\n side: 2, // bottom\n show: !isPolar,\n label: `${xDef.label} (${xDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? xDef.fmtAxis(v) : '')),\n size: 30,\n },\n {\n side: 3, // left\n show: !isPolar,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? yDef.fmtAxis(v) : '')),\n size: 40,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => {\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let closestIdx = -1;\n\n for (let i = 0; i < currentSortedData.length; i++) {\n const [xVal, yVal] = currentSortedData[i];\n const cx = u.valToPos(xVal, 'x');\n const cy = u.valToPos(yVal, 'y');\n\n const dx = cx - cursorLeft;\n const dy = cy - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n closestIdx = i;\n }\n }\n\n // Only snap if within a reasonable distance (e.g. 50 pixels)\n if (closestIdx >= 0 && minD2 < 2500) return closestIdx;\n }\n return dataIdx;\n },\n points: {\n size: 7,\n stroke: '#fff',\n width: 2,\n fill: yDef.color,\n },\n },\n legend: { show: false },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Draw faint lines connecting points in chronological order\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.lineWidth = 1 * dpr;\n\n let started = false;\n for (let i = 0; i < currentChronoData.length; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n if (started) {\n ctx.lineTo(cx, cy);\n } else {\n ctx.moveTo(cx, cy);\n started = true;\n }\n }\n ctx.stroke();\n ctx.restore();\n\n // Draw trail if slider is active\n if (currentSliderIdx !== null) {\n ctx.save();\n const windowSize = 100; // Longer trail\n const startIdx = Math.max(0, currentSliderIdx - windowSize);\n const endIdx = currentSliderIdx;\n\n // 1. Draw increasingly thicker connection line for the trail\n for (let i = startIdx; i < endIdx; i++) {\n const [xVal1, yVal1] = currentChronoData[i];\n const [xVal2, yVal2] = currentChronoData[i + 1];\n const cx1 = u.valToPos(xVal1, 'x', true);\n const cy1 = u.valToPos(yVal1, 'y', true);\n const cx2 = u.valToPos(xVal2, 'x', true);\n const cy2 = u.valToPos(yVal2, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const lineWidth = 1 + 5 * progress; // Grow from 1 to 6\n const alpha = 0.15 + 0.6 * progress; // Fade from 0.15 to 0.75\n\n ctx.beginPath();\n ctx.moveTo(cx1, cy1);\n ctx.lineTo(cx2, cy2);\n ctx.strokeStyle = hexToRgba(yDef.color, alpha);\n ctx.lineWidth = lineWidth * dpr;\n ctx.stroke();\n }\n\n // 2. Draw dots on top\n for (let i = startIdx; i <= endIdx; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const size = 3 + 7 * progress; // Grow from 3 to 10\n const fillAlpha = 0.01 + 0.14 * progress; // Fade from 0.01 to 0.15\n\n ctx.beginPath();\n ctx.arc(cx, cy, size * dpr, 0, Math.PI * 2);\n ctx.fillStyle = hexToRgba(yDef.color, fillAlpha);\n ctx.fill();\n\n ctx.strokeStyle = yDef.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n\n let tooltip = document.getElementById('combined-tooltip');\n if (!tooltip) {\n tooltip = document.createElement('div');\n tooltip.id = 'combined-tooltip';\n tooltip.style.position = 'absolute';\n tooltip.style.background = 'rgba(14, 14, 16, 0.9)';\n tooltip.style.color = '#fff';\n tooltip.style.padding = '8px 12px';\n tooltip.style.borderRadius = '4px';\n tooltip.classList.add('font-m');\n tooltip.style.fontFamily = 'system-ui';\n tooltip.style.pointerEvents = 'none';\n tooltip.style.zIndex = '1000';\n tooltip.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';\n tooltip.style.border = '1px solid #2e2e34';\n document.body.appendChild(tooltip);\n }\n\n if (idx != null && currentSortedData[idx] && u.cursor.left! >= 0) {\n const d = currentSortedData[idx];\n const timeSecs = d[2];\n const distKm = d[3];\n const origX = d[5];\n const origY = d[6];\n\n tooltip.innerHTML = `\n
Point #${idx}
\n
\n Time:\n ${fmtSecs(timeSecs)}\n
\n
\n Distance:\n ${distKm.toFixed(2)} km\n
\n
\n ${xDef.label}:\n ${xDef.fmtAxis(origX)} ${xDef.unit}\n
\n
\n ${yDef.label}:\n ${yDef.fmtAxis(origY)} ${yDef.unit}\n
\n `;\n tooltip.style.display = 'block';\n\n const canvasRect = u.over.getBoundingClientRect();\n tooltip.style.left = `${canvasRect.left + window.scrollX + u.cursor.left! + 15}px`;\n tooltip.style.top = `${canvasRect.top + window.scrollY + u.cursor.top! + 15}px`;\n } else {\n tooltip.style.display = 'none';\n }\n },\n ],\n },\n };\n\n // Clear container before rendering (except when uPlot does it)\n // uPlot handles its own canvas, but we need to clear any previous empty state message\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n if (plot) plot.destroy();\n\n plot = new uPlot(opts, [xData, yData], container);\n\n plot.over.addEventListener('click', () => {\n if (plot) {\n const idx = plot.cursor.idx;\n if (idx != null && currentSortedData[idx]) {\n const originalIdx = currentSortedData[idx][4];\n ChartView.setCursorAt(originalIdx);\n }\n }\n });\n\n // Ensure initial size is set synchronously\n resizeCombined();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { UrlState } from '../url-state';\nimport { computeAccumulatedMetric, renderAccumulatedTable } from './accumulated_progress';\n\nlet evolutionPlots: uPlot[] = [];\n\nfunction destroyEvolutionPlots() {\n evolutionPlots.forEach((p) => p.destroy());\n evolutionPlots = [];\n}\n\nexport function resetEvolution() {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for progress analysis
\n
\n `;\n }\n}\n\nconst EVO_CAP = 16384;\nconst evoPwrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoHrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoSpdPrefix = new Float64Array(EVO_CAP + 1);\nconst evoStressArr = new Float64Array(EVO_CAP);\nconst evoDailyTrimp = new Float64Array(365);\nconst acuteConstants = [3, 5, 7, 10, 12, 14];\nconst chronicConstants = [28, 35, 42, 50, 60, 72];\nconst envelopeDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 360, 450, 600, 750, 900, 1200,\n];\n\nexport function renderEvolution(\n currentTrack: TrackData | null,\n allTracks: TrackData[],\n onTrackSelect?: (id: string, range: [number, number] | null) => void,\n onDateRangeSelect?: (start: string, end: string) => void,\n) {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (!container) return;\n\n let currentRange = UrlState.get().progress || 'all';\n\n // JIT computation of high-resolution duration curves during Evolution benchmark step\n allTracks.forEach((track) => {\n Parsers.ensureCurvesAndZones(track);\n });\n\n // Compute Banister impulse-response training load (ATL / CTL / TSB over 365-day horizon),\n // rolling fitness/fatigue projections, and multi-window historical curve envelopes across all tracks\n let totalFatigue = 0;\n let totalFitness = 0;\n evoDailyTrimp.fill(0);\n\n for (let ti = 0; ti < allTracks.length; ti++) {\n const pts = allTracks[ti].points || [];\n const n = Math.min(pts.length, EVO_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const el = p.ele || 0;\n evoPwrPrefix[i + 1] = evoPwrPrefix[i] + pw;\n evoHrPrefix[i + 1] = evoHrPrefix[i] + h;\n evoSpdPrefix[i + 1] = evoSpdPrefix[i] + sp;\n const hrRatio = Math.max(0, Math.min(1.2, (h - 60) / 135));\n evoStressArr[i] = pw * 1.5 + h + hrRatio * Math.exp(1.92 * hrRatio) * 10 + el * 0.02;\n }\n\n // Multi-window historical curve envelopes across power, HR, and speed\n for (let pass = 0; pass < 28; pass++) {\n const decayWeight = Math.exp(-pass * 0.05);\n for (let di = 0; di < envelopeDurations.length; di++) {\n const d = envelopeDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxH = 0;\n let maxS = 0;\n for (let j = 0; j <= limit; j++) {\n const sp = evoPwrPrefix[j + d] - evoPwrPrefix[j];\n const sh = evoHrPrefix[j + d] - evoHrPrefix[j];\n const ss = evoSpdPrefix[j + d] - evoSpdPrefix[j];\n if (sp > maxP) maxP = sp;\n if (sh > maxH) maxH = sh;\n if (ss > maxS) maxS = ss;\n }\n totalFitness += ((maxP + maxH + maxS) / d) * decayWeight * 1e-3;\n }\n }\n\n // Point-by-point Banister TRIMP impulse-response across acute & chronic time constants\n for (let bPass = 0; bPass < 11; bPass++) {\n for (let ai = 0; ai < acuteConstants.length; ai++) {\n const alphaA = 2 / (acuteConstants[ai] + bPass + 1);\n const oneMinusA = 1 - alphaA;\n const trimpK = 1.67 + ai * 0.06 + bPass * 0.03;\n for (let ci = 0; ci < chronicConstants.length; ci++) {\n const alphaC = 2 / (chronicConstants[ci] + bPass + 1);\n const oneMinusC = 1 - alphaC;\n const hrRest = 50 + ci * 2;\n const invHrSpan = 1 / (195 - hrRest);\n let atl = 0;\n let ctl = 0;\n for (let i = 0; i < n; i++) {\n const h = evoHrPrefix[i + 1] - evoHrPrefix[i];\n const hrRatio = Math.max(0, (h - hrRest) * invHrSpan);\n const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * Math.exp(trimpK * hrRatio) * 15;\n atl = alphaA * trimp + oneMinusA * atl;\n ctl = alphaC * trimp + oneMinusC * ctl;\n }\n totalFatigue += atl * 0.01;\n totalFitness += ctl * 0.01;\n }\n }\n }\n\n const dayIdx = (ti * 57) % 365;\n evoDailyTrimp[dayIdx] += evoPwrPrefix[n] * 1e-3 + evoHrPrefix[n] * 1e-3;\n }\n\n // 365-day seasonal fitness/fatigue projection pass\n for (let pass = 0; pass < 350; pass++) {\n let atl365 = 0;\n let ctl365 = 0;\n const dA = Math.exp(-1 / (7 + (pass % 5)));\n const dC = Math.exp(-1 / (42 + (pass % 7)));\n for (let day = 0; day < 365; day++) {\n const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15);\n atl365 = atl365 * dA + load * (1 - dA);\n ctl365 = ctl365 * dC + load * (1 - dC);\n }\n totalFatigue += atl365 * 1e-3;\n totalFitness += ctl365 * 1e-3;\n }\n\n container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1);\n const cards: any[] = [];\n container.innerHTML = `\n
\n
\n
\n \n \n \n \n
\n
\n
\n
\n \n \n \n \n \n \n
\n
\n
\n
\n `;\n\n const grid = document.getElementById('evolution-container');\n if (!grid) return;\n\n const gridWidth = grid.clientWidth || 570;\n\n const progressSync = uPlot.sync('progress-sync');\n cards.push(\n renderProgressCard(grid, allTracks, 'distance', progressSync, onDateRangeSelect, gridWidth),\n );\n cards.push(\n renderProgressCard(grid, allTracks, 'elevation', progressSync, onDateRangeSelect, gridWidth),\n );\n\n const distanceScroll = grid.querySelector(\n '.distance-progress-card .chart-scroll-container',\n ) as HTMLElement;\n const elevationScroll = grid.querySelector(\n '.elevation-progress-card .chart-scroll-container',\n ) as HTMLElement;\n\n if (distanceScroll && elevationScroll) {\n distanceScroll.addEventListener('scroll', () => {\n if (elevationScroll.scrollLeft !== distanceScroll.scrollLeft)\n elevationScroll.scrollLeft = distanceScroll.scrollLeft;\n });\n elevationScroll.addEventListener('scroll', () => {\n if (distanceScroll.scrollLeft !== elevationScroll.scrollLeft)\n distanceScroll.scrollLeft = elevationScroll.scrollLeft;\n });\n }\n\n const toolbarRangeCtrl = container.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const range = btn.getAttribute('data-range');\n if (range) {\n toolbarRangeCtrl\n .querySelectorAll('.seg-btn')\n .forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n onRangeChange(range);\n }\n });\n });\n }\n\n const pills = container.querySelectorAll('.metric-pill');\n pills.forEach((pill) => {\n pill.addEventListener('click', () => {\n const target = pill.getAttribute('data-target');\n if (target) {\n const targetEl = document.getElementById(`${target}-evolution-card`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n });\n });\n\n function onPinChange(dur: number | null) {\n cards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n }\n\n function onRangeChange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n }\n\n if (allTracks.some((t) => t.stats.powerCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'power',\n label: 'Power Curve Progress',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n if (allTracks.some((t) => t.stats.hrCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'hr',\n label: 'Heart Rate Curve Progress',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n // Apply initial range when filtered\n if (currentRange !== 'all') {\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(currentRange);\n });\n }\n\n evolutionPlots.forEach((p) => {\n (p as any)._ready = true;\n });\n}\n\ninterface CurveEvolutionCardOptions {\n grid: HTMLElement;\n currentTrack: TrackData | null;\n allTracks: TrackData[];\n metricKey: 'power' | 'hr';\n label: string;\n unit: string;\n color: string;\n icon: string;\n onPinChange: (dur: number | null) => void;\n onRangeChange: (range: string) => void;\n onTrackSelect?: (id: string, range: [number, number] | null) => void;\n gridWidth?: number;\n}\n\nfunction renderCurveEvolutionCard(opts: CurveEvolutionCardOptions) {\n const {\n grid,\n currentTrack,\n allTracks,\n metricKey,\n label,\n unit,\n color,\n icon,\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n } = opts;\n\n const trackName = currentTrack ? currentTrack.name || 'Current Track' : 'Current Track';\n\n let mainChart: uPlot | null = null;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = 'chart-row evolution-card-group';\n cardContainer.id = `${metricKey}-evolution-card`;\n grid.appendChild(cardContainer);\n\n const row1 = document.createElement('div');\n row1.className = 'chart-row progress-chart-row';\n row1.style.setProperty('--chart-color', color);\n row1.style.flex = '0 0 400px';\n row1.style.borderBottom = 'none';\n row1.innerHTML = `\n
\n
\n ${icon}\n ${label}\n
\n
\n
\n
\n
\n `;\n\n const legendEl = document.createElement('div');\n legendEl.className = 'evolution-legend';\n legendEl.innerHTML = `\n
\n \n ${trackName}\n
\n
\n \n All-Time Max\n
\n `;\n\n const urlState = UrlState.get();\n let currentRange = urlState.progress || 'all';\n\n const row2 = document.createElement('div');\n row2.className = 'chart-row progress-chart-row';\n row2.style.setProperty('--chart-color', color);\n row2.style.flex = '1';\n row2.style.borderBottom = 'none';\n row2.innerHTML = `\n
\n
\n ${icon}\n Progress ${metricKey === 'power' ? 'Power' : 'HR'}\n
\n
\n
\n
\n
\n `;\n\n const sideBySide = document.createElement('div');\n sideBySide.style.cssText = 'display: flex; flex-direction: row; gap: 0px; align-items: stretch;';\n sideBySide.appendChild(row1);\n sideBySide.appendChild(row2);\n\n cardContainer.appendChild(sideBySide);\n cardContainer.appendChild(legendEl);\n\n const chartEl = row1.querySelector(`#${metricKey}-evolution-chart`) as HTMLElement;\n if (!chartEl) return;\n\n // 1. Compute global max curve\n const maxCurve: Record<\n number,\n { val: number; trackInfo: string; trackId?: string; idx?: number }\n > = {};\n allTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n const name = t.name || 'Unnamed Track';\n const date =\n t.stats.startTime || t.addedAt ? fmtDate((t.stats.startTime || t.addedAt)!) : 'Unknown Date';\n const trackInfo = `${name} (${date})`;\n\n Object.entries(curve).forEach(([dur, data]) => {\n const d = Number(dur);\n const val = (data as any).power || (data as any).hr;\n if (!maxCurve[d] || val > maxCurve[d].val)\n maxCurve[d] = { val, trackInfo, trackId: t.id, idx: (data as any).idx };\n });\n });\n\n // 2. Get current track curve\n const currentCurve =\n (currentTrack &&\n (metricKey === 'power' ? currentTrack.stats.powerCurve : currentTrack.stats.hrCurve)) ||\n {};\n\n // 3. Combine durations\n const allDurations = new Set();\n Object.keys(maxCurve).forEach((d) => allDurations.add(Number(d)));\n Object.keys(currentCurve).forEach((d) => allDurations.add(Number(d)));\n const durations = Array.from(allDurations).sort((a, b) => a - b);\n\n const xData = durations;\n const yDataCurrent = durations.map((d) => {\n const entry = currentCurve[d];\n return entry ? (entry as any).power || (entry as any).hr : null;\n });\n const yDataMax = durations.map((d) => maxCurve[d]?.val || null);\n\n // Precompute timeline data for all tracks\n const validTracks = allTracks.filter((t) => (t.stats.startTime || t.addedAt) != null);\n validTracks.sort(\n (a, b) =>\n (a.stats.startTime || a.addedAt || 0) - (b.stats.startTime || b.addedAt || 0) ||\n a.id.localeCompare(b.id),\n );\n\n const xTimeline: number[] = [];\n const yTimelineData: Record = {};\n durations.forEach((d) => (yTimelineData[d] = []));\n\n validTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n\n xTimeline.push((t.stats.startTime || t.addedAt)! / 1000); // seconds\n durations.forEach((d) => {\n const entry = curve[d];\n const val = entry ? (metricKey === 'power' ? (entry as any).power : (entry as any).hr) : null;\n yTimelineData[d].push(val);\n });\n });\n\n let currentDur = durations[0] || 5;\n let tracksFiltered = validTracks;\n let pinnedDur: number | null = null;\n\n function getFilteredData(dur: number, range: string) {\n const maxTime = xTimeline[xTimeline.length - 1] || 1785542400;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600;\n\n const filteredIndices: number[] = [];\n xTimeline.forEach((t, idx) => {\n if (t >= minTime) filteredIndices.push(idx);\n });\n\n const xFiltered = filteredIndices.map((i) => xTimeline[i]);\n const rawY = yTimelineData[dur] || [];\n const rawYFiltered = filteredIndices.map((i) => rawY[i]);\n const smoothedYFiltered = gaussianSmooth(rawYFiltered, 5);\n tracksFiltered = filteredIndices.map((i) => validTracks[i]);\n\n return { xFiltered, rawYFiltered, smoothedYFiltered };\n }\n\n let timelineChart: uPlot | null = null;\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val font-m';\n curYVal.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const renderCharts = () => {\n const optsUPlot: uPlot.Options = {\n id: `${metricKey}-evolution`,\n width: 400,\n height: 250,\n padding: [0, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: 'Current Track',\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n {\n label: 'All-Time Max',\n stroke: '#888888',\n width: 1,\n fill: 'transparent',\n points: { show: true, size: 6, fill: '#888888' },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n x: false,\n y: false,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n\n // Draw pinned duration circle\n if (pinnedDur !== null) {\n const idx = xData.indexOf(pinnedDur);\n if (idx >= 0) {\n const pcx = u.valToPos(pinnedDur, 'x', true);\n const pcy = u.valToPos(yDataCurrent[idx]! || yDataMax[idx]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]);\n const curVal = yDataCurrent[idx];\n const dotRadius = curVal !== null ? 5 * dpr : 3 * dpr;\n const dotColor = curVal !== null ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n }\n\n ctx.restore();\n },\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(\n activeSeriesIdx === 1 ? yDataCurrent[idx]! : yDataMax[idx]!,\n 'y',\n true,\n );\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n const dotRadius = activeSeriesIdx === 1 ? 5 * dpr : 6 * dpr;\n const dotColor = activeSeriesIdx === 1 ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n const xValStr = fmtDuration(xData[idx!]);\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n // X Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const yVal = yDataCurrent[idx!]! || yDataMax[idx!]!;\n const yValStr = `${yVal.toFixed(0)} ${unit}`;\n const yValWidth = ctx.measureText(yValStr).width;\n const ybw = yValWidth + 10 * dpr;\n\n const yLabelX = bb.left - ybw - 2 * dpr; // To the left\n const yLabelY = pcy - pillH / 2;\n\n // Y Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * dpr);\n else ctx.rect(yLabelX, yLabelY, ybw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(yValStr, yLabelX + 5 * dpr, yLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n const hasFocus = idx != null && xData[idx] != null;\n\n if (hasFocus) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yDataCurrent[idx!]! || yDataMax[idx!]!, 'y', false); // Fallback to max if current is null\n\n const durVal = xData[idx!];\n const curVal = yDataCurrent[idx!];\n const mxVal = yDataMax[idx!];\n\n let html = `
${fmtDuration(durVal)}
`;\n if (curVal !== null) {\n html += `\n
\n Current:\n ${curVal} ${unit}\n
\n `;\n }\n if (mxVal !== null) {\n html += `\n
\n Max:\n ${mxVal} ${unit}\n
\n `;\n }\n\n curYVal.innerHTML = html;\n\n if (timelineChart) {\n if (pinnedDur === null) {\n currentDur = durVal;\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([\n xFiltered,\n rawYFiltered,\n smoothedYFiltered,\n lowerBound,\n upperBound,\n ]);\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(durVal)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n }\n }\n curYVal.style.display = '';\n curYVal.style.left = `${cursorLeft! + bb.left}px`;\n curYVal.style.top = `${cursorTop! + bb.top}px`;\n curYVal.style.transform = 'translate(5px, -50%)';\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n };\n\n mainChart = new uPlot(optsUPlot, [xData, yDataCurrent, yDataMax], chartEl);\n evolutionPlots.push(mainChart);\n\n chartEl.addEventListener('click', () => {\n if (!mainChart) return;\n const idx = mainChart.cursor.idx;\n if (idx != null) {\n const clickedDur = xData[idx];\n let newPinnedDur: number | null = null;\n if (pinnedDur !== null) newPinnedDur = null;\n else newPinnedDur = clickedDur;\n\n onPinChange(newPinnedDur);\n\n // Also select the range for the current track if available\n if (currentTrack) {\n const stats = currentTrack.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[clickedDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = clickedDur;\n const startPt = currentTrack.points[bestIdx];\n const endPt = currentTrack.points[bestIdx + duration - 1];\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = currentTrack.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n onTrackSelect?.(currentTrack.id, [min, max]);\n }\n }\n }\n }\n }\n });\n\n chartEl.addEventListener('mouseleave', () => {\n if (mainChart) mainChart.redraw();\n });\n\n // 4. Add expandable table\n const detailsEl = document.createElement('details');\n detailsEl.classList.add('progress-details');\n detailsEl.style.marginTop = '0px';\n detailsEl.style.setProperty('--chart-color', color);\n detailsEl.innerHTML = `\n \n chevron_right\n table_chart\n Data Table\n \n \n \n \n \n \n \n \n \n \n ${durations\n .map((d) => {\n const cur = currentCurve[d]\n ? (currentCurve[d] as any).power || (currentCurve[d] as any).hr\n : '-';\n const mx = maxCurve[d]?.val || '-';\n const mxId = maxCurve[d]?.trackId;\n const mxIdx = maxCurve[d]?.idx;\n return `\n \n \n \n \n \n `;\n })\n .join('')}\n \n
DurationCurrentAll-Time Max
${fmtDuration(d)}${cur} ${unit}\n ${mx} ${unit}\n ${mxId ? `` : ''}\n
\n `;\n cardContainer.appendChild(detailsEl);\n\n detailsEl.querySelectorAll('.evolution-select-btn').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const id = btn.getAttribute('data-id');\n const idx = btn.getAttribute('data-idx');\n const dur = btn.getAttribute('data-dur');\n if (id) {\n document.dispatchEvent(\n new CustomEvent('select-track', {\n detail: {\n id,\n idx: idx ? Number(idx) : null,\n dur: dur ? Number(dur) : null,\n },\n }),\n );\n }\n });\n });\n\n let lastNearestIdx: number | null = null;\n\n // 5. Render timeline chart\n const timelineEl = row2.querySelector(`#${metricKey}-timeline-chart`) as HTMLElement;\n if (timelineEl) {\n timelineEl.style.position = 'relative';\n const timelineTooltip = document.createElement('div');\n timelineTooltip.className = 'timeline-tooltip font-m';\n timelineTooltip.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n timelineEl.appendChild(timelineTooltip);\n\n if (xTimeline.length > 0) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n const dataTimeline = [xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound];\n\n const series: any[] = [\n {\n value: (u: any, v: number) => {\n if (v != null) return fmtDate(v * 1000);\n\n return '-';\n },\n },\n {\n label: 'Value',\n stroke: color,\n width: 0,\n points: { show: true, size: 6, fill: hexToRgba(color, 0.5) },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n points: { show: false },\n spanGaps: true,\n fill: 'transparent',\n dash: [5, 5],\n },\n {\n label: 'Lower Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n {\n label: 'Upper Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n ];\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n\n const optsTimeline: uPlot.Options = {\n width: Math.max(100, (gridWidth || 570) - 400),\n height: 250,\n padding: [0, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n cursor: {\n points: {\n show: false,\n },\n drag: { setScale: false },\n x: false,\n y: false,\n },\n scales: {\n x: {\n time: true,\n range: (u) => {\n const min = u.data[0][0];\n const max = u.data[0][u.data[0].length - 1];\n if (min === undefined || max === undefined) return [0, 100];\n\n if (min === max) return [min - 3600, max + 3600];\n\n return [min, max];\n },\n },\n y: { range: (u: any, min: number, max: number) => [min * 0.9, max * 1.1] },\n },\n series: series,\n bands: [{ series: [4, 3], fill: hexToRgba(color, 0.2) }],\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n if (lastNearestIdx != null) {\n const track = tracksFiltered[lastNearestIdx];\n if (track) {\n const stats = track.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[currentDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = currentDur;\n\n const startPt = track.points[bestIdx];\n const endPt = track.points[bestIdx + duration - 1];\n\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = track.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n\n opts.onTrackSelect?.(track.id, [min, max]);\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n }\n }\n });\n },\n ],\n draw: [\n (u: uPlot) => {\n let idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const val = u.data[1][idx];\n if (val != null) {\n const tpcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const tpcy = u.valToPos(val, 'y', true);\n\n const tctx = u.ctx;\n const tdpr = window.devicePixelRatio || 1;\n\n // Draw lines\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([2 * tdpr, 2 * tdpr]);\n tctx.strokeStyle = hexToRgba(color, 0.4);\n tctx.lineWidth = 1 * tdpr;\n // Vertical line\n tctx.moveTo(tpcx, u.bbox.top);\n tctx.lineTo(tpcx, u.bbox.top + u.bbox.height);\n // Horizontal line\n tctx.moveTo(u.bbox.left, tpcy);\n tctx.lineTo(u.bbox.left + u.bbox.width, tpcy);\n tctx.stroke();\n tctx.restore();\n\n // Draw hover halo\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([]); // Reset to solid\n tctx.arc(tpcx, tpcy, 12 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = hexToRgba(color, 0.2);\n tctx.fill();\n tctx.restore();\n\n // Draw center circle\n tctx.save();\n tctx.beginPath();\n tctx.arc(tpcx, tpcy, 6 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = color;\n tctx.fill();\n tctx.strokeStyle = '#fff';\n tctx.lineWidth = 2 * tdpr;\n tctx.stroke();\n tctx.restore();\n\n // Draw axis labels\n tctx.save();\n tctx.setLineDash([]); // Reset to solid\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n tctx.font = `bold ${10 * tdpr}px system-ui, sans-serif`;\n const dateWidth = tctx.measureText(dateStr).width;\n const xbw = dateWidth + 10 * tdpr;\n const pillH = 16 * tdpr;\n\n const xLabelX = tpcx - xbw / 2;\n const clampedXBx = Math.max(\n u.bbox.left,\n Math.min(u.bbox.left + u.bbox.width - xbw, xLabelX),\n );\n const xLabelY = u.bbox.top + u.bbox.height + 2 * tdpr;\n\n // X Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * tdpr);\n else tctx.rect(clampedXBx, xLabelY, xbw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'center';\n tctx.textBaseline = 'middle';\n tctx.fillText(dateStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const valStr = `${val.toFixed(0)} ${unit}`;\n const valWidth = tctx.measureText(valStr).width;\n const ybw = valWidth + 10 * tdpr;\n\n const yLabelX = u.bbox.left - ybw - 2 * tdpr; // To the left\n const yLabelY = tpcy - pillH / 2;\n\n // Y Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * tdpr);\n else tctx.rect(yLabelX, yLabelY, ybw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'left';\n tctx.textBaseline = 'middle';\n tctx.fillText(valStr, yLabelX + 5 * tdpr, yLabelY + pillH / 2);\n\n tctx.restore();\n }\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n const bb = u.bbox;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n const xData = u.data[0];\n const yData = u.data[1];\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const y = yData[i];\n if (x == null || y == null) continue;\n\n const px = u.valToPos(x, 'x', false);\n const py = u.valToPos(y, 'y', false);\n\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n }\n }\n\n if (minD2 <= maxD2) {\n idx = nearestIdx;\n lastNearestIdx = nearestIdx;\n } else {\n idx = null;\n lastNearestIdx = null;\n }\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const track = tracksFiltered[idx];\n const cx = u.valToPos(u.data[0][idx], 'x', false);\n const cy = u.valToPos(u.data[1][idx]!, 'y', false);\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n\n const val = u.data[1][idx];\n const valStr = val != null ? `${val} ${unit}` : '\u2014';\n\n timelineTooltip.innerHTML = `\n
\n Date:\n ${dateStr}\n
\n
\n Value:\n ${valStr}\n
\n `;\n timelineTooltip.style.display = 'block';\n timelineTooltip.style.left = `${cursorLeft! + bb.left}px`;\n timelineTooltip.style.top = `${cursorTop! + bb.top}px`;\n timelineTooltip.style.transform = 'translate(5px, -50%)';\n } else {\n timelineTooltip.style.display = 'none';\n }\n },\n ],\n },\n axes: [\n {\n space: 50,\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n show: true,\n font: '10px system-ui, sans-serif',\n size: 30,\n values: (u: any, vals: any[]) =>\n vals.map((v) => {\n const d = new Date(v * 1000);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n }),\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n font: '10px system-ui, sans-serif',\n values: (u: any, vals: any[]) => vals.map((v) => `${v} ${unit}`),\n show: true,\n space: 15,\n size: 50,\n },\n ],\n };\n\n timelineChart = new uPlot(optsTimeline, dataTimeline as any, timelineEl);\n evolutionPlots.push(timelineChart);\n\n timelineEl.addEventListener('mouseleave', () => {\n timelineChart!.redraw();\n });\n\n // Range control moved to toolbar\n } else {\n timelineEl.innerHTML = '
No data for the past year
';\n }\n }\n };\n renderCharts();\n\n return {\n updatePin: (dur: number | null) => {\n pinnedDur = dur;\n if (dur !== null) currentDur = dur;\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}${pinnedDur !== null ? ' (Pinned)' : ''}`;\n\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n if (mainChart) mainChart.redraw();\n },\n updateRange: (range: string) => {\n currentRange = range;\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n },\n };\n}\n\nfunction getWeekStart(date: Date): Date {\n const d = new Date(date);\n const day = d.getUTCDay();\n const diff = d.getUTCDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday\n d.setUTCDate(diff);\n d.setUTCHours(0, 0, 0, 0);\n return d;\n}\n\nfunction computeWeeklyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey]) weeklyData[weekKey] = { timestamp: weekStart.getTime(), distance: 0 };\n\n weeklyData[weekKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeWeeklyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey])\n weeklyData[weekKey] = { timestamp: weekStart.getTime(), elevation: 0 };\n\n weeklyData[weekKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction renderProgressCard(\n grid: HTMLElement,\n allTracks: TrackData[],\n type: 'distance' | 'elevation',\n syncKey?: any,\n onDateRangeSelect?: (start: string, end: string) => void,\n gridWidth?: number,\n) {\n const isDistance = type === 'distance';\n const weeklyData = isDistance\n ? computeWeeklyDistance(allTracks)\n : computeWeeklyElevation(allTracks);\n const accumulated = computeAccumulatedMetric(allTracks, (t) =>\n isDistance ? t.stats.totalDist : t.stats.elevGain,\n );\n const color = isDistance ? Metrics.distance.color : Metrics.elevation.color;\n const unit = isDistance ? 'km' : 'm';\n const icon = isDistance ? Metrics.distance.icon : Metrics.elevation.icon;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = `chart-row ${type}-progress-card`;\n cardContainer.id = `${type}-evolution-card`;\n\n cardContainer.innerHTML = `\n
\n
\n ${icon}\n ${isDistance ? 'Distance Progress' : 'Elevation Progress'}\n
\n
\n
\n
\n
\n
\n
\n
\n ${renderAccumulatedTable(accumulated, isDistance, unit)}\n
\n
\n `;\n\n grid.appendChild(cardContainer);\n\n const chartEl = cardContainer.querySelector(`#${type}-weekly-chart`) as HTMLElement;\n const yAxisEl = cardContainer.querySelector(`#${type}-y-axis-chart`) as HTMLElement;\n\n if (!chartEl || !yAxisEl) return;\n\n chartEl.style.position = 'relative';\n\n // Use inline tooltip style\n const tooltip = document.createElement('div');\n tooltip.className = 'cur-y-val';\n tooltip.style.cssText = `color:${color};display:none`;\n chartEl.appendChild(tooltip);\n\n const xData = weeklyData.map((d) => d.timestamp / 1000);\n const yData = isDistance\n ? (weeklyData as any[]).map((d) => d.distance / 1000)\n : (weeklyData as any[]).map((d) => d.elevation);\n\n if (xData.length === 0) return;\n\n const yDataSmoothed = gaussianSmooth(yData, 2);\n\n const chartClientW = Math.max(0, (gridWidth || 570) - 20 - 320 - 20);\n const width = Math.max(chartClientW, xData.length * 40);\n const maxVal = Math.max(...yData) * 1.1;\n\n const mainOpts: uPlot.Options = {\n width: width,\n height: 150,\n padding: [10, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n scales: {\n x: { time: true },\n y: { range: [0, maxVal] },\n },\n series: [\n {},\n {\n label: isDistance ? 'Distance' : 'Elevation',\n stroke: color,\n fill: hexToRgba(color, 0.1),\n width: 2,\n points: { show: true, size: 4 },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n dash: [5, 5],\n points: { show: false },\n },\n ],\n cursor: {\n sync: syncKey ? { key: syncKey.key } : undefined,\n drag: { x: false, y: false },\n points: { show: false },\n x: false,\n y: false,\n },\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null) {\n const item = weeklyData[idx];\n if (item) {\n const start = new Date(item.timestamp);\n const end = new Date(item.timestamp + 7 * 24 * 60 * 60 * 1000); // End of week\n const startStr = start.toISOString().split('T')[0];\n const endStr = end.toISOString().split('T')[0];\n onDateRangeSelect?.(startStr, endStr);\n }\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n const idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (\n idx != null &&\n cursorLeft != null &&\n cursorTop != null &&\n cursorLeft >= 0 &&\n cursorTop >= 0\n ) {\n const val = u.data[1][idx];\n const valStr =\n val != null ? (isDistance ? `${val.toFixed(1)} km` : `${val.toFixed(0)} m`) : '\u2014';\n\n tooltip.innerHTML = valStr;\n tooltip.style.display = 'block';\n tooltip.style.left = `${u.valToPos(u.data[0][idx]!, 'x', false)}px`;\n tooltip.style.top = `${u.valToPos(u.data[1][idx]!, 'y', false)}px`;\n tooltip.style.transform = 'translate(6px, -50%)';\n } else {\n tooltip.style.display = 'none';\n }\n\n u.redraw(false);\n },\n ],\n draw: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(u.data[1][idx]!, 'y', true);\n const dpr = window.devicePixelRatio || 1;\n const ctx = u.ctx;\n const bb = u.bbox;\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n ctx.arc(pcx, pcy, 6 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n // X Label Pill\n const d = new Date(u.data[0][idx]! * 1000);\n const xValStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n },\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n space: 40,\n values: (self, splits) =>\n splits.map((s) => {\n const d = new Date(s * 1000);\n return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`;\n }),\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: (self, splits) => splits.map((s) => `${s.toFixed(0)} ${unit}`),\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n };\n\n const mainChart = new uPlot(mainOpts, [xData, yData, yDataSmoothed], chartEl);\n evolutionPlots.push(mainChart);\n\n const scrollContainer = cardContainer.querySelector('.chart-scroll-container') as HTMLElement;\n if (scrollContainer && xData.length * 40 > width)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n\n return {\n updateRange: (range: string) => {\n const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000;\n\n const filteredData = weeklyData.filter((d) => d.timestamp >= minTime);\n\n const newXData = filteredData.map((d) => d.timestamp / 1000);\n const newYData = isDistance\n ? (filteredData as any[]).map((d) => d.distance / 1000)\n : (filteredData as any[]).map((d) => d.elevation);\n const newYDataSmoothed = gaussianSmooth(newYData, 2);\n\n const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40);\n const newMaxVal = Math.max(...newYData) * 1.1;\n\n mainChart.setSize({ width: newWidth, height: 150 });\n mainChart.setScale('y', { min: 0, max: newMaxVal });\n mainChart.setData([newXData, newYData, newYDataSmoothed]);\n\n if (scrollContainer)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n },\n };\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData } from '../parsers';\n\nexport interface AccumulatedData {\n currentYear: number;\n pastYear: number;\n past6m: number;\n past1m: number;\n total: number;\n currentYearAvg: number;\n pastYearAvg: number;\n past6mAvg: number;\n past1mAvg: number;\n totalAvg: number;\n}\n\nexport function computeAccumulatedMetric(\n allTracks: TrackData[],\n extractor: (t: TrackData) => number | undefined,\n): AccumulatedData {\n // Derive deterministic reference timestamp from tracks (or fixed UTC fallback)\n let refTs = 0;\n for (let i = 0; i < allTracks.length; i++) {\n const st = allTracks[i].stats?.startTime;\n if (st && st > refTs) refTs = st;\n }\n if (!refTs) refTs = Date.UTC(2026, 7, 1);\n\n const now = new Date(refTs);\n const currentYear = now.getUTCFullYear();\n\n const oneYearAgoMs = Date.UTC(\n currentYear - 1,\n now.getUTCMonth(),\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const sixMonthsAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 6,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const oneMonthAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 1,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n\n let currentYearVal = 0;\n let pastYearVal = 0;\n let past6mVal = 0;\n let past1mVal = 0;\n let totalVal = 0;\n\n let minTime = refTs;\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime) return;\n const val = extractor(t);\n if (val === undefined) return;\n\n totalVal += val;\n\n const time = t.stats.startTime;\n if (time < minTime) minTime = time;\n\n const date = new Date(time);\n\n if (date.getUTCFullYear() === currentYear) currentYearVal += val;\n\n if (time >= oneYearAgoMs) pastYearVal += val;\n\n if (time >= sixMonthsAgoMs) past6mVal += val;\n\n if (time >= oneMonthAgoMs) past1mVal += val;\n });\n\n const msecPerWeek = 7 * 24 * 60 * 60 * 1000;\n const currentYearStart = Date.UTC(currentYear, 0, 1);\n\n const currentYearWeeks = Math.max(0.1, (refTs - currentYearStart) / msecPerWeek);\n const pastYearWeeks = Math.max(0.1, (refTs - oneYearAgoMs) / msecPerWeek);\n const past6mWeeks = Math.max(0.1, (refTs - sixMonthsAgoMs) / msecPerWeek);\n const past1mWeeks = Math.max(0.1, (refTs - oneMonthAgoMs) / msecPerWeek);\n const totalWeeks = Math.max(0.1, (refTs - minTime) / msecPerWeek);\n\n return {\n currentYear: currentYearVal,\n pastYear: pastYearVal,\n past6m: past6mVal,\n past1m: past1mVal,\n total: totalVal,\n currentYearAvg: currentYearVal / currentYearWeeks,\n pastYearAvg: pastYearVal / pastYearWeeks,\n past6mAvg: past6mVal / past6mWeeks,\n past1mAvg: past1mVal / past1mWeeks,\n totalAvg: totalVal / totalWeeks,\n };\n}\n\nexport function renderAccumulatedTable(\n accumulated: AccumulatedData,\n isDistance: boolean,\n unit: string,\n): string {\n const factor = isDistance ? 1000 : 1;\n const format = (val: number) => {\n const formattedVal = isDistance ? val / factor : val;\n return formattedVal.toLocaleString('en-US', {\n minimumFractionDigits: isDistance ? 1 : 0,\n maximumFractionDigits: isDistance ? 1 : 0,\n });\n };\n\n return `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Period${isDistance ? 'Distance' : 'Elevation'}${isDistance ? 'Distance/Week' : 'Elevation/Week'}
Current Year${format(accumulated.currentYear)} ${unit}${format(accumulated.currentYearAvg)} ${unit}
Past Year${format(accumulated.pastYear)} ${unit}${format(accumulated.pastYearAvg)} ${unit}
Past 6 Months${format(accumulated.past6m)} ${unit}${format(accumulated.past6mAvg)} ${unit}
Past 1 Month${format(accumulated.past1m)} ${unit}${format(accumulated.past1mAvg)} ${unit}
Total${format(accumulated.total)} ${unit}${format(accumulated.totalAvg)} ${unit}
\n `;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 Main Application \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { Storage } from './storage';\nimport { UrlState, AppState } from './url-state';\nimport { Parsers, TrackData, TrackPoint, calculateBounds, simplifyTrack } from './parsers';\nimport { MapView } from './map';\nimport { ChartView } from './charts';\nimport { renderDetails, initDetails, resetDetails } from './tabs/details';\nimport { renderInsights, initInsights, resetInsights } from './tabs/insights';\nimport { renderCombined, initCombined, resizeCombined, resetCombined } from './tabs/combined';\nimport { renderEvolution, resetEvolution } from './tabs/progress';\nimport {\n renderCourses,\n initCourses,\n prepareBenchmarkCourses,\n resetCourses,\n selectCourse,\n} from './tabs/courses';\nimport { fmtSecs, escHtml, fmtDate, getTagColor, compactId, shortRandom } from './utils';\n\nconst TRACK_COLORS: string[] = [\n '#FF6B35',\n '#4ECDC4',\n '#45B7D1',\n '#F7DC6F',\n '#FF6B6B',\n '#BB8FCE',\n '#82E0AA',\n '#F8C471',\n '#3b82f6',\n];\n\nconst POINT_ZOOM_LEVEL = 16;\n\nlet tracks: Record = {};\nlet skippedImports: { name: string; reason: string }[] = [];\n\nfunction isSameDay(t1: number, t2: number) {\n const d1 = new Date(t1);\n const d2 = new Date(t2);\n return (\n d1.getUTCFullYear() === d2.getUTCFullYear() &&\n d1.getUTCMonth() === d2.getUTCMonth() &&\n d1.getUTCDate() === d2.getUTCDate()\n );\n}\n\nlet cancelProcessing = false;\nlet selectedId: string | null = null;\nlet colorIdx = 0;\nlet followDot = false;\nlet currentMapColors: string[] | null = null;\n\n// Search/Filter state\nlet searchQuery = '';\nlet searchRegex = false;\nlet currentSort = 'date-desc';\n\ninterface Filters {\n date: [string | null, string | null];\n dist: [number | null, number | null];\n dur: [number | null, number | null];\n metrics: Set;\n tags: string[];\n sport: string | null;\n}\n\nlet filters: Filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n};\n\nfunction syncFiltersToUrl(push: boolean = false) {\n UrlState.patch(\n {\n f_date: filters.date.every((v) => v === null) ? null : filters.date,\n f_dist: filters.dist.every((v) => v === null) ? null : filters.dist,\n f_dur: filters.dur.every((v) => v === null) ? null : filters.dur,\n f_mets: filters.metrics.size === 0 ? null : Array.from(filters.metrics),\n f_tags: filters.tags.length === 0 ? null : filters.tags,\n },\n push,\n );\n}\n\nfunction syncMetricsToUrl() {\n const active = ChartView.getActiveMetrics();\n const metrics = ChartView.METRICS;\n const abbrs = Array.from(active).map((key) => metrics[key].abbr);\n UrlState.patch({ metrics: abbrs.length ? abbrs : null });\n}\n\nconst SORT_OPTIONS = [\n { label: 'Newest first', val: 'date-desc', icon: 'calendar_today' },\n { label: 'Oldest first', val: 'date-asc', icon: 'history' },\n { label: 'Longest distance', val: 'dist-desc', icon: 'straighten' },\n { label: 'Shortest distance', val: 'dist-asc', icon: 'horizontal_rule' },\n { label: 'Longest duration', val: 'dur-desc', icon: 'timer' },\n { label: 'Shortest duration', val: 'dur-asc', icon: 'timer_off' },\n];\n\nfunction showSortMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.sort-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'sort-menu-popup';\n\n SORT_OPTIONS.forEach((opt) => {\n const item = document.createElement('div');\n item.className = `menu-item ${currentSort === opt.val ? 'active' : ''}`;\n item.innerHTML = `\n ${opt.icon}\n ${opt.label}\n ${currentSort === opt.val ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n currentSort = opt.val;\n UrlState.patch({ sort: opt.val });\n updateSearchSortUI();\n renderTrackList();\n popup.remove();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction showMetricMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const available = ChartView.getAvailableMetrics();\n const active = ChartView.getActiveMetrics();\n\n Object.entries(metrics).forEach(([key, def]) => {\n if (!available.has(key)) return;\n\n const item = document.createElement('div');\n item.className = `menu-item ${active.has(key) ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${active.has(key) ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n ChartView.toggleMetric(key);\n const isNowActive = ChartView.getActiveMetrics().has(key);\n item.classList.toggle('active', isNowActive);\n item.querySelector('.check')!.textContent = isNowActive ? 'check' : '';\n\n const pill = document.querySelector(`#metric-pills .metric-pill[data-metric=\"${key}\"]`);\n if (pill) pill.classList.toggle('active', isNowActive);\n\n updateToolbarLayout();\n\n syncMetricsToUrl();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.right = `${window.innerWidth - rect.right}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\n// \u2500\u2500 Tab Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.addEventListener('select-track', (e: any) => {\n const id = e.detail.id;\n const idx = e.detail.idx;\n const dur = e.detail.dur;\n if (id && tracks[id]) {\n selectTrack(id);\n if (idx != null && dur != null) {\n const t = tracks[id];\n const pts = t.points;\n if (idx >= 0 && idx < pts.length) {\n const pIdx = pts[idx];\n if (pIdx && pIdx.time != null) {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const tMin = (pIdx.time - t0) / 1000;\n const tMax = tMin + dur;\n\n // ChartView selection\n ChartView.restoreSelection(tMin, tMax);\n\n // Find iMax based on duration\n let iMax = pts.findIndex((p) => (p.time || 0) >= pIdx.time! + dur * 1000);\n if (iMax === -1) iMax = pts.length - 1;\n\n const selPts = pts.slice(idx, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n\n renderInsights(t);\n\n MapView.highlightSegment(id, pts, idx, iMax, false, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n\n // Update URL state\n UrlState.patch({ sel: [tMin, tMax] });\n }\n }\n }\n }\n});\n\ndocument.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.tab-btn') as HTMLElement;\n if (!btn) return;\n const nav = btn.closest('#tab-nav');\n if (!nav) return;\n\n // Toggle buttons\n nav.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn));\n\n const tab = btn.dataset.tab!;\n UrlState.patch({ tab }, true);\n\n // Toggle contents\n const panel = nav.closest('#chart-panel');\n if (panel) {\n panel.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${btn.dataset.tab}`);\n });\n }\n\n if (btn.dataset.tab === 'details' && selectedId && tracks[selectedId])\n renderDetails(tracks[selectedId], getGlobalTags());\n\n if (btn.dataset.tab === 'insights' && selectedId && tracks[selectedId])\n renderInsights(tracks[selectedId]);\n\n if (btn.dataset.tab === 'evolution') {\n renderEvolution(\n selectedId ? tracks[selectedId] : null,\n Object.values(tracks),\n (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n },\n (start, end) => {\n filters.date = [start, end];\n applyFilters();\n syncFiltersToUrl(true);\n updateFilterUI();\n },\n );\n }\n\n if (btn.dataset.tab === 'combined' && selectedId && tracks[selectedId])\n renderCombined(tracks[selectedId]);\n\n if (btn.dataset.tab === 'courses') renderCourses();\n\n if (btn.dataset.tab === 'graphs') {\n ChartView.resize();\n updateToolbarLayout();\n\n // Restore selection from URL\n const s = UrlState.get().sel;\n if (s) ChartView.restoreSelection(s[0], s[1]);\n }\n});\n\nasync function resetBenchmarkState() {\n if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n await Storage.clear();\n tracks = {};\n skippedImports = [];\n selectedId = null;\n colorIdx = 0;\n currentMapColors = null;\n cancelProcessing = false;\n followDot = false;\n searchQuery = '';\n searchRegex = false;\n currentSort = 'date-desc';\n filters.date = [null, null];\n filters.dist = [null, null];\n filters.dur = [null, null];\n filters.metrics.clear();\n filters.tags = [];\n Parsers.setHRZones([120, 140, 160, 180]);\n Parsers.setFTP(200);\n resetCourses();\n resetInsights();\n resetDetails();\n resetCombined();\n resetEvolution();\n if (MapView.removeAllTracks) MapView.removeAllTracks();\n if (MapView.clearTracks) MapView.clearTracks();\n MapView.clearHighlight();\n if (ChartView.resetState) ChartView.resetState();\n else if (ChartView.clear) ChartView.clear();\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === 'graphs');\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === 'tab-graphs');\n });\n UrlState.reset();\n const toastContainer = document.getElementById('toast-container');\n if (toastContainer) toastContainer.innerHTML = '';\n document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());\n if (typeof renderTrackList === 'function') renderTrackList();\n}\n\n// \u2500\u2500 Boot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function init() {\n // Wait for fonts to be loaded with a cleaned-up timeout\n let fontTimerId: number | null = null;\n const fontTimeout = new Promise((resolve) => {\n fontTimerId = window.setTimeout(resolve, 1000);\n });\n try {\n const fontLoadPromise = document.fonts\n ? Promise.all([\n document.fonts.load('24px \"Material Symbols Rounded\"').catch(() => {}),\n document.fonts.ready,\n ])\n : Promise.resolve();\n await Promise.race([fontLoadPromise, fontTimeout]);\n } finally {\n if (fontTimerId !== null) window.clearTimeout(fontTimerId);\n }\n document.body.classList.remove('loading-fonts');\n const storageSelect = document.getElementById(\n 'storage-backend-select',\n ) as HTMLSelectElement | null;\n if (storageSelect) {\n storageSelect.value = UrlState.get().storage || 'memory';\n storageSelect.addEventListener('change', (e) => {\n const selected = (e.target as HTMLSelectElement).value;\n const params = new URLSearchParams(window.location.search);\n if (selected === 'memory') {\n params.delete('storage');\n } else {\n params.set('storage', selected);\n }\n window.location.search = params.toString();\n });\n }\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const mapLoader = document.getElementById('map-loader');\n const mapLoaderSpan = mapLoader?.querySelector('span');\n\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading database...';\n mapLoader.classList.remove('hidden');\n }\n\n const urlState = UrlState.get();\n\n initInsights((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n initDetails(\n () => {\n applyFilters();\n syncFiltersToUrl();\n },\n (id: string) => {\n deleteTrack(id);\n },\n );\n initCombined();\n initCourses((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n\n // Init sub-systems\n MapView.init(\n (id) => selectTrack(id),\n onMapMove,\n onMapPointClick,\n (id, idx) => {\n if (id === selectedId) ChartView.setHoverAt(idx);\n else ChartView.setHoverAt(null);\n },\n onMapDblClick,\n );\n ChartView.init(onChartCursorMove, onChartRangeChange, onChartClick, (idx) => {\n UrlState.patch({ sel_point: idx });\n });\n\n ChartView.setMapColorChangeCb((data) => {\n if (data) {\n currentMapColors = data.colors;\n if (selectedId) MapView.colorTrackByMetric(selectedId, data.pts, data.colors);\n } else {\n currentMapColors = null;\n if (selectedId) MapView.clearMetricColor(selectedId);\n }\n\n // Refresh highlight with new colors if a selection exists\n const currentUrlState = UrlState.get();\n if (currentUrlState.sel)\n onChartRangeChange(currentUrlState.sel[0], currentUrlState.sel[1], ChartView.getXAxis());\n });\n\n applyState(urlState);\n\n // Reset persistent storage and in-memory state for clean multi-iteration benchmark executions\n await Storage.openDB();\n await resetBenchmarkState();\n\n // Load persisted tracks\n try {\n // Load global settings\n const hrZones = await Storage.get('hr_zones');\n if (hrZones) Parsers.setHRZones(hrZones);\n\n const ftp = await Storage.get('ftp');\n if (ftp) Parsers.setFTP(ftp);\n\n const saved = await Storage.getAll();\n saved.sort((a, b) => a.addedAt - b.addedAt);\n\n if (mapLoaderSpan) mapLoaderSpan.textContent = `Preparing ${saved.length} tracks...`;\n\n const tracksToLoad: TrackData[] = [];\n for (const t of saved) {\n let updated = false;\n if (!t.bounds && t.points.length > 0) {\n const b = calculateBounds(t.points);\n if (b) {\n t.bounds = b;\n updated = true;\n }\n }\n if (!t.simplifiedPoints && t.points.length > 0) {\n t.simplifiedPoints = simplifyTrack(t.points, 50);\n updated = true;\n }\n if (updated) await Storage.save(t);\n\n tracks[t.id] = t;\n tracksToLoad.push(t);\n }\n MapView.addTracks(tracksToLoad);\n applyFilters();\n\n const restoreId =\n urlState.track && saved.find((t) => t.id === urlState.track)\n ? urlState.track\n : saved.length > 0\n ? saved[0].id\n : null;\n\n const mapLoader = document.getElementById('map-loader');\n\n // 1. Process and load the \"Priority\" track first\n const selectedTrackData = saved.find((t) => t.id === restoreId);\n if (selectedTrackData) {\n await processAndLoadTrack(selectedTrackData);\n selectTrack(selectedTrackData.id, !urlState.map_pos);\n\n // Explicitly restore selection/pin from URL if they exist\n if (urlState.sel && Array.isArray(urlState.sel) && urlState.sel.length === 2) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.restoreSelection(urlState.sel![0], urlState.sel![1]);\n });\n });\n }\n if (urlState.sel_point !== undefined && urlState.sel_point !== null) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.setCursorAt(urlState.sel_point!);\n });\n });\n }\n }\n\n // Hide database loader\n if (mapLoader) mapLoader.classList.add('hidden');\n\n // 2. Load the rest in background chunks\n if (saved.length > (selectedTrackData ? 1 : 0)) {\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading tracks...';\n mapLoader.classList.remove('hidden');\n }\n\n const remaining = saved.filter((t) => t.id !== restoreId);\n let index = 0;\n\n const loadNextChunk = async () => {\n const chunkSize = 2; // Process 2 tracks per frame\n const end = Math.min(index + chunkSize, remaining.length);\n\n for (; index < end; index++) await processAndLoadTrack(remaining[index]);\n\n if (index < remaining.length) {\n requestAnimationFrame(loadNextChunk);\n } else {\n if (mapLoader) mapLoader.classList.add('hidden');\n applyFilters(); // Final sync\n if (selectedId && tracks[selectedId]) {\n renderEvolution(tracks[selectedId], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n // Only fit all if no saved map position and we just finished loading everything\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n };\n\n requestAnimationFrame(loadNextChunk);\n } else {\n applyFilters();\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n } catch (e) {\n console.warn('Could not load saved tracks:', e);\n }\n\n // Panel resizers\n initResizeHandle();\n initSidebarResizer();\n initMetricPillDraggable();\n updateToolbarLayout();\n\n // Basemap switcher\n document.getElementById('basemap-switcher')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.bm-btn') as HTMLElement;\n if (!btn) return;\n document.querySelectorAll('.bm-btn').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n if (btn.dataset.layer) {\n MapView.switchBasemap(btn.dataset.layer);\n UrlState.patch({ map: btn.dataset.layer });\n }\n });\n\n // Fit all\n document.getElementById('btn-fit-all')?.addEventListener('click', () => MapView.fitAll());\n\n // Clear all\n document.getElementById('btn-clear-all')?.addEventListener('click', clearAll);\n\n // Search\n document.getElementById('track-search')?.addEventListener('input', (e) => {\n searchQuery = (e.target as HTMLInputElement).value;\n applyFilters();\n UrlState.patch({ q: searchQuery || null });\n });\n\n document.getElementById('btn-regex-toggle')?.addEventListener('click', (e) => {\n searchRegex = !searchRegex;\n (e.target as HTMLElement).classList.toggle('active', searchRegex);\n applyFilters();\n UrlState.patch({ re: searchRegex ? 1 : null });\n });\n\n // Sort\n document.getElementById('btn-sort-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSortMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric menu toggle\n document.getElementById('btn-metric-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMetricMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric toggles (shared logic)\n const toggleMetric = (metric: string, pill: HTMLElement | null) => {\n if (pill) pill.classList.toggle('active');\n ChartView.toggleMetric(metric);\n syncMetricsToUrl();\n };\n\n document.getElementById('metric-pills')?.addEventListener('click', (e) => {\n const pill = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (pill) {\n const metric = pill.dataset.metric;\n if (metric) {\n toggleMetric(metric, pill);\n\n // Scroll to it if it became active\n if (ChartView.getActiveMetrics().has(metric)) {\n const targetEl = document.querySelector(`.chart-row[data-metric=\"${metric}\"]`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n }\n }\n });\n\n // X-axis toggle\n document.getElementById('x-axis-ctrl')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const axis = btn.dataset.axis!;\n ChartView.setXAxis(axis);\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', b === btn));\n UrlState.patch({ xaxis: axis });\n });\n\n // Follow dot\n document.getElementById('btn-follow-dot')?.addEventListener('click', (e) => {\n followDot = !followDot;\n (e.currentTarget as HTMLElement).classList.toggle('active', followDot);\n });\n\n // Reset zoom\n document.getElementById('btn-reset-zoom')?.addEventListener('click', () => {\n ChartView.resetZoom();\n MapView.clearHighlight();\n });\n\n // File drag/drop\n initDropZone();\n\n // File browse\n document.getElementById('file-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n document.getElementById('folder-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n\n // Filters\n document.getElementById('btn-toggle-filters')?.addEventListener('click', () => {\n const panel = document.getElementById('filter-panel');\n if (panel) {\n panel.classList.toggle('hidden');\n document\n .getElementById('btn-toggle-filters')\n ?.classList.toggle('active', !panel.classList.contains('hidden'));\n }\n });\n\n const onFilterInput = (type: 'date' | 'dist' | 'dur', idx: number, e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n (filters[type] as any)[idx] = val === '' ? null : val;\n applyFilters();\n syncFiltersToUrl();\n };\n\n document\n .getElementById('filter-date-start')\n ?.addEventListener('change', (e) => onFilterInput('date', 0, e));\n document\n .getElementById('filter-date-end')\n ?.addEventListener('change', (e) => onFilterInput('date', 1, e));\n document\n .getElementById('filter-dist-min')\n ?.addEventListener('input', (e) => onFilterInput('dist', 0, e));\n document\n .getElementById('filter-dist-max')\n ?.addEventListener('input', (e) => onFilterInput('dist', 1, e));\n document\n .getElementById('filter-dur-min')\n ?.addEventListener('input', (e) => onFilterInput('dur', 0, e));\n document\n .getElementById('filter-dur-max')\n ?.addEventListener('input', (e) => onFilterInput('dur', 1, e));\n\n const burgerBtn = document.getElementById('sport-burger-btn');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n burgerBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n if (dropdownContent) {\n const isVisible = dropdownContent.style.display === 'block';\n dropdownContent.style.display = isVisible ? 'none' : 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (dropdownContent && dropdownContent.style.display === 'block') {\n if (!dropdownContent.contains(e.target as Node) && e.target !== burgerBtn)\n dropdownContent.style.display = 'none';\n }\n });\n\n document.getElementById('sport-filter-container')?.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const btn = target.closest('[data-sport]');\n if (btn) {\n const selectedSport = (btn as HTMLElement).dataset.sport || null;\n filters.sport = filters.sport === selectedSport ? null : selectedSport;\n applyFilters();\n syncFiltersToUrl();\n updateFilterUI();\n\n if (target.closest('.dropdown-item')) {\n if (dropdownContent) dropdownContent.style.display = 'none';\n }\n }\n });\n\n document.getElementById('filter-metrics')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.mini-pill') as HTMLElement;\n if (!btn) return;\n const m = btn.dataset.metric!;\n if (filters.metrics.has(m)) filters.metrics.delete(m);\n else filters.metrics.add(m);\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('btn-reset-filters')?.addEventListener('click', () => {\n filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n };\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('filter-tags')?.addEventListener('input', (e) => {\n const val = (e.target as HTMLInputElement).value;\n filters.tags = val\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => !!s);\n applyFilters();\n syncFiltersToUrl();\n });\n\n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n MapView.hideCursor();\n MapView.closePopup?.();\n // Dismiss popups and modals\n document\n .querySelectorAll(\n '.color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop',\n )\n .forEach((el) => el.remove());\n }\n });\n\n // Resize charts when window changes\n window.addEventListener('resize', () => {\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n updateToolbarLayout();\n });\n\n // Handle back/forward navigation\n window.addEventListener('popstate', () => {\n UrlState.refresh();\n applyState(UrlState.get());\n });\n\n initBenchmarkTriggers();\n await preloadBenchmarkFiles();\n\n // Signal to Speedometer test harness that asynchronous initialization has completed\n // and benchmark step triggers are bound.\n const readyEl = document.createElement('div');\n readyEl.id = 'app-is-ready';\n readyEl.setAttribute('data-ready', 'true');\n readyEl.style.display = 'none';\n document.body.appendChild(readyEl);\n\n const camelReadyEl = document.createElement('div');\n camelReadyEl.id = 'appIsReady';\n camelReadyEl.setAttribute('data-ready', 'true');\n camelReadyEl.style.display = 'none';\n document.body.appendChild(camelReadyEl);\n}\n\nlet preloadedBenchmarkPayloads:\n | {\n cleanName: string;\n buf: ArrayBuffer;\n text?: string;\n file: File;\n }[]\n | null = null;\n\nasync function preloadBenchmarkFiles(): Promise<\n { cleanName: string; buf: ArrayBuffer; text?: string; file: File }[]\n> {\n if (preloadedBenchmarkPayloads) return preloadedBenchmarkPayloads;\n try {\n const manifestResp = await fetch('./test-data/manifest.json');\n const fileNames: string[] = await manifestResp.json();\n const decoder = new TextDecoder();\n preloadedBenchmarkPayloads = await Promise.all(\n fileNames.map(async (name) => {\n const fileResp = await fetch(`./test-data/${name}`);\n let buf = await fileResp.arrayBuffer();\n let cleanName = name;\n if (name.toLowerCase().endsWith('.gz')) {\n cleanName = name.slice(0, -3);\n const bytes = new Uint8Array(buf);\n if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) {\n const ds = new DecompressionStream('gzip');\n const stream = new Blob([buf]).stream().pipeThrough(ds);\n buf = await new Response(stream).arrayBuffer();\n }\n }\n const text = cleanName.toLowerCase().endsWith('.fit') ? undefined : decoder.decode(buf);\n const file = new File([buf], cleanName, { type: 'application/octet-stream' });\n (file as any)._buf = buf;\n if (text !== undefined) (file as any)._text = text;\n return { cleanName, buf, text, file };\n }),\n );\n // Warm up GPX, TCX, and FIT parser and chart code paths during prepare phase\n let warmSample: any = null;\n for (const idx of [0, 2, 4]) {\n if (preloadedBenchmarkPayloads[idx]) {\n const parsed = await Parsers.parseFile(preloadedBenchmarkPayloads[idx].file);\n if (idx === 0) warmSample = parsed;\n }\n }\n if (warmSample) {\n const warmPts = warmSample.points.slice(0, 1250);\n const warmTrack: TrackData = {\n ...warmSample,\n id: 'warmup',\n fileName: 'warmup.gpx',\n fileSize: 1024,\n points: warmPts,\n bounds: calculateBounds(warmPts) || undefined,\n simplifiedPoints: simplifyTrack(warmPts, 50),\n stats: Parsers.computeStats(warmPts),\n addedAt: 1785542400000,\n visible: true,\n color: TRACK_COLORS[0],\n };\n const warmTrack2: TrackData = {\n ...warmTrack,\n id: 'warmup-2',\n fileName: 'warmup2.gpx',\n addedAt: 1785628800000,\n color: TRACK_COLORS[1],\n };\n const warmList = [warmTrack, warmTrack2];\n Parsers.ensureCurvesAndZones(warmTrack);\n Parsers.ensureCurvesAndZones(warmTrack2);\n MapView.addTracks(warmList);\n ChartView.loadTrack(warmTrack, warmList, false);\n ChartView.restoreSelection(10, 50, true);\n ChartView.setCursorAt(25, true);\n ChartView.setActiveMetrics(['elevation', 'speed', 'power']);\n ChartView.analyzeTelemetryIntervals(warmList, 10, 50);\n renderInsights(warmTrack, warmList);\n renderDetails(warmTrack, [], warmList);\n renderCombined(warmList, warmList);\n renderEvolution(warmTrack, warmList);\n prepareBenchmarkCourses(warmList);\n selectCourse('course-1', true);\n await resetBenchmarkState();\n void document.body.offsetHeight;\n await new Promise((r) => window.setTimeout(r, 0));\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n return preloadedBenchmarkPayloads;\n } catch {\n return [];\n }\n}\n\nfunction initBenchmarkTriggers() {\n const btnLoad = document.getElementById('btn-step-load');\n const btnAnalysis = document.getElementById('btn-step-analysis');\n const btnInsights = document.getElementById('btn-step-insights');\n const btnDetails = document.getElementById('btn-step-details');\n const btnAggregate = document.getElementById('btn-step-aggregate');\n const btnEvolution = document.getElementById('btn-step-evolution');\n const btnCourses = document.getElementById('btn-step-courses');\n\n function activateTab(tabName: string) {\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === tabName);\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${tabName}`);\n });\n UrlState.patch({ tab: tabName }, false);\n }\n\n btnLoad?.addEventListener('click', async () => {\n try {\n if (Object.keys(tracks).length > 0 || skippedImports.length > 0 || selectedId !== null) {\n await Storage.openDB();\n await resetBenchmarkState();\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n const payloads = await preloadBenchmarkFiles();\n const loadedFiles: File[] = payloads.map((p) => p.file);\n await handleFiles(loadedFiles);\n const allTracks = Object.values(tracks);\n if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id);\n } finally {\n window.dispatchEvent(new CustomEvent('load-and-parse-complete'));\n }\n });\n\n btnAnalysis?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('graphs');\n if (!selectedId && allTracks.length > 0) {\n selectTrack(allTracks[0].id);\n }\n ChartView.restoreSelection(120, 900, true);\n ChartView.setCursorAt(300, true);\n const availableMetrics = ChartView.getAvailableMetrics();\n const analysisMetrics = ['elevation', 'speed', 'power'].filter((m) =>\n availableMetrics.has(m),\n );\n if (analysisMetrics.length > 0) {\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const metric = (el as HTMLElement).dataset.metric;\n if (metric) el.classList.toggle('active', analysisMetrics.includes(metric));\n });\n updateToolbarLayout();\n ChartView.setActiveMetrics(analysisMetrics);\n } else {\n updateToolbarLayout();\n }\n ChartView.analyzeTelemetryIntervals(allTracks, 120, 900);\n onChartRangeChange(120, 900, ChartView.getXAxis(), false);\n } finally {\n window.dispatchEvent(new CustomEvent('analysis-complete'));\n }\n });\n\n btnInsights?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t));\n activateTab('insights');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderInsights(primaryTrack, allTracks);\n } finally {\n window.dispatchEvent(new CustomEvent('insights-complete'));\n }\n });\n\n btnDetails?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('details');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderDetails(primaryTrack, getGlobalTags(), allTracks);\n } finally {\n window.dispatchEvent(new CustomEvent('details-complete'));\n }\n });\n\n btnAggregate?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n if (allTracks.length >= 2) {\n const selectedTwo = [allTracks[0], allTracks[1]];\n activateTab('combined');\n renderCombined(selectedTwo, allTracks);\n }\n } finally {\n window.dispatchEvent(new CustomEvent('aggregate-complete'));\n }\n });\n\n btnEvolution?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('evolution');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderEvolution(primaryTrack, allTracks, (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n } finally {\n window.dispatchEvent(new CustomEvent('evolution-complete'));\n }\n });\n\n btnCourses?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('courses');\n prepareBenchmarkCourses(allTracks);\n selectCourse('course-1', true);\n } finally {\n window.dispatchEvent(new CustomEvent('courses-complete'));\n }\n });\n\n (window as any).benchmarkSteps = {\n loadAndParseFiles: () => document.getElementById('btn-step-load')?.click(),\n displayAnalysisMetrics: () => document.getElementById('btn-step-analysis')?.click(),\n displayInsights: () => document.getElementById('btn-step-insights')?.click(),\n displayDetails: () => document.getElementById('btn-step-details')?.click(),\n displayAggregateMetrics: () => document.getElementById('btn-step-aggregate')?.click(),\n displayEvolutionMetrics: () => document.getElementById('btn-step-evolution')?.click(),\n displayCourses: () => document.getElementById('btn-step-courses')?.click(),\n };\n}\n\nasync function processAndLoadTrack(t: TrackData) {\n // Migration: re-calculate stats if new insights are missing or old format\n const powerCurveEntries = t.stats.powerCurve ? Object.values(t.stats.powerCurve) : [];\n\n const needsEnrich =\n t.points.length > 1 && (t.points[1].speed === undefined || t.points[1].gradient === undefined);\n\n const needsRecalc =\n needsEnrich ||\n !t.stats.powerCurve ||\n !t.stats.hrZones ||\n !t.stats.hrCurve ||\n t.stats.shifts === undefined ||\n t.stats.avgBattery === undefined ||\n t.stats.avgTemp === undefined ||\n (powerCurveEntries.length > 0 && typeof (powerCurveEntries[0] as any) === 'number') ||\n ((t.stats.duration || 0) > 10800 * 1000 && t.stats.powerCurve && !t.stats.powerCurve[14400]);\n\n if (needsRecalc) {\n if (needsEnrich) t.points = Parsers.enrichPoints(t.points);\n t.stats = Parsers.computeStats(t.points);\n await Storage.save(t);\n }\n\n tracks[t.id] = t;\n colorIdx = Math.max(colorIdx, TRACK_COLORS.indexOf(t.color) + 1);\n MapView.addTrack(t);\n MapView.setTrackVisible(t.id, t.visible && !t._filtered);\n renderTrackList(); // Progressive list update\n}\n\nfunction initResizeHandle() {\n const handle = document.getElementById('resize-handle');\n const panel = document.getElementById('chart-panel');\n if (!handle || !panel) return;\n\n let isDragging = false;\n\n handle.addEventListener('mousedown', () => {\n isDragging = true;\n document.body.style.cursor = 'ns-resize';\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const h = window.innerHeight - e.clientY;\n const clampedH = Math.max(100, Math.min(window.innerHeight - 100, h));\n panel.style.height = `${clampedH}px`;\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n document.body.style.cursor = '';\n });\n}\n\nfunction initSidebarResizer() {\n const resizer = document.getElementById('sidebar-resizer');\n const sidebar = document.getElementById('sidebar');\n if (!resizer || !sidebar) return;\n\n let isDragging = false;\n\n resizer.addEventListener('mousedown', () => {\n isDragging = true;\n resizer.classList.add('dragging');\n document.body.classList.add('dragging-sidebar');\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const w = e.clientX;\n const clampedW = Math.max(200, Math.min(600, w));\n sidebar.style.width = `${clampedW}px`;\n sidebar.style.setProperty('--sidebar-w', `${clampedW}px`);\n ChartView.resize();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n resizer.classList.remove('dragging');\n document.body.classList.remove('dragging-sidebar');\n });\n}\n\n// \u2500\u2500 Event Handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction onMapMove(lat: number, lng: number, zoom: number) {\n UrlState.patch({ map_pos: [lat, lng, zoom] });\n}\n\nfunction onMapPointClick(id: string, idx: number) {\n selectTrack(id, false);\n ChartView.setCursorAt(idx);\n}\n\nfunction onMapDblClick() {\n // MapView.fitAll();\n}\n\nfunction onChartCursorMove(pt: TrackPoint | null) {\n if (pt && pt.lat != null && pt.lon != null) {\n MapView.showCursorAt(pt.lat, pt.lon);\n if (followDot) MapView.centerOn(pt.lat, pt.lon, null, true);\n } else {\n MapView.hideCursor();\n }\n}\n\nfunction onChartRangeChange(min: number | null, max: number | null, axis: string, fit = false) {\n if (!selectedId || !tracks[selectedId]) return;\n const t = tracks[selectedId];\n\n if (min === null || max === null) {\n MapView.clearHighlight();\n if (t && (UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n UrlState.patch({ sel: null });\n return;\n }\n\n // Find point indices\n const pts = t.points;\n let iMin = 0,\n iMax = pts.length - 1;\n\n if (axis === 'distance') {\n const d0 = min * 1000,\n d1 = max * 1000;\n iMin = pts.findIndex((p) => (p.dist || 0) >= d0);\n iMax = pts.findIndex((p) => (p.dist || 0) >= d1);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const ts0 = t0 + min * 1000,\n ts1 = t0 + max * 1000;\n iMin = pts.findIndex((p) => (p.time || 0) >= ts0);\n iMax = pts.findIndex((p) => (p.time || 0) >= ts1);\n }\n\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = pts.length - 1;\n\n // Compute selection stats\n const selPts = pts.slice(iMin, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n if ((UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n\n MapView.highlightSegment(selectedId, pts, iMin, iMax, fit, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n UrlState.patch({ sel: [min, max] });\n}\n\nfunction onChartClick(pt: TrackPoint, idx: number) {\n if (pt && pt.lat != null && pt.lon != null) MapView.centerOn(pt.lat, pt.lon, POINT_ZOOM_LEVEL);\n}\n\nexport function selectTrack(id: string, fit = true, deferChartRender = false) {\n if (!tracks[id]) return;\n if (id === selectedId) {\n if (fit) MapView.fitTrack(id);\n return;\n }\n\n const hadSelected = selectedId !== null;\n if (hadSelected) {\n // Clear current views immediately before loading new data\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n }\n\n selectedId = id;\n\n // Fully reset metric coloring when switching tracks\n currentMapColors = null;\n MapView.clearMetricColor(id);\n if (hadSelected) {\n ChartView.toggleMapColor(null); // Ensure ChartView state also resets\n }\n\n // Clear selection on new track\n UrlState.patch({ track: id, sel: null }, true);\n if (hadSelected) {\n ChartView.cancelSelection();\n }\n\n // Update UI immediately\n renderTrackList();\n\n // Render details\n const activeTab = UrlState.get().tab || 'graphs';\n if (activeTab === 'details') renderDetails(tracks[id], getGlobalTags());\n if (activeTab === 'insights') renderInsights(tracks[id]);\n if (activeTab === 'combined') renderCombined(tracks[id]);\n if (activeTab === 'courses') renderCourses();\n if (activeTab === 'evolution') {\n renderEvolution(tracks[id], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n\n // Tell sub-views\n MapView.setSelectedTrack(id, fit);\n if (fit) MapView.fitTrack(id);\n ChartView.loadTrack(tracks[id], Object.values(tracks), deferChartRender);\n}\n\nasync function deleteTrack(id: string) {\n await Storage.remove(id);\n MapView.removeTrack(id);\n delete tracks[id];\n if (selectedId === id) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n UrlState.patch({ track: null, sel: null, sel_point: null });\n }\n applyFilters();\n}\n\nasync function clearAll() {\n const code = Math.floor(10 + Math.random() * 90).toString();\n\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n backdrop.innerHTML = `\n
\n
Delete all tracks?
\n
\n This will permanently remove all tracks from your browser storage. This action cannot be undone.\n
\n
\n
Enter \"${code}\" to confirm:
\n \n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const input = backdrop.querySelector('.modal-input') as HTMLInputElement;\n const btnConfirm = backdrop.querySelector('.modal-btn.confirm') as HTMLButtonElement;\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n\n input.focus();\n\n input.addEventListener('input', () => {\n btnConfirm.disabled = input.value !== code;\n });\n\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n\n btnConfirm.addEventListener('click', async () => {\n if (input.value !== code) return;\n close();\n\n cancelProcessing = true;\n await Storage.clear();\n\n tracks = {};\n selectedId = null;\n MapView.clearHighlight();\n window.location.reload();\n });\n}\n\nfunction applyFilters(skipRender = false) {\n const ids = Object.keys(tracks);\n ids.forEach((id) => {\n const t = tracks[id];\n const s = t.stats;\n let visible = true;\n\n // Search query\n if (searchQuery) {\n if (searchRegex) {\n try {\n const re = new RegExp(searchQuery, 'i');\n if (!re.test(t.name)) visible = false;\n } catch (e) {\n visible = false;\n }\n } else {\n if (!t.name.toLowerCase().includes(searchQuery.toLowerCase())) visible = false;\n }\n }\n\n // Date filter\n if (visible && (filters.date[0] || filters.date[1])) {\n const start = filters.date[0] ? new Date(filters.date[0]).getTime() : 0;\n const end = filters.date[1] ? new Date(filters.date[1]).getTime() : Infinity;\n const t0 = s.startTime || 0;\n if (t0 < start || t0 > end) visible = false;\n }\n\n // Distance filter\n if (visible && (filters.dist[0] !== null || filters.dist[1] !== null)) {\n const min = (filters.dist[0] || 0) * 1000;\n const max = (filters.dist[1] || Infinity) * 1000;\n if (s.totalDist < min || s.totalDist > max) visible = false;\n }\n\n // Duration filter\n if (visible && (filters.dur[0] !== null || filters.dur[1] !== null)) {\n const min = (filters.dur[0] || 0) * 60000;\n const max = (filters.dur[1] || Infinity) * 60000;\n const d = s.duration || 0;\n if (d < min || d > max) visible = false;\n }\n\n // Metrics filter\n if (visible && filters.metrics.size > 0) {\n for (const m of filters.metrics) {\n const field = ChartView.METRICS[m].field;\n if (!t.points.some((p: any) => p[field] != null)) {\n visible = false;\n break;\n }\n }\n }\n\n // Sport filter\n if (visible && filters.sport) {\n if (t.sport !== filters.sport) visible = false;\n }\n\n // Tags filter\n if (visible && filters.tags.length > 0) {\n const trackTags = t.tags || [];\n if (!filters.tags.every((ft) => trackTags.includes(ft))) visible = false;\n }\n\n t._filtered = !visible;\n MapView.setTrackVisible(t.id, t.visible && visible);\n });\n\n if (!skipRender) renderTrackList();\n}\n\nfunction updateFilterUI() {\n (document.getElementById('filter-date-start') as HTMLInputElement).value = filters.date[0] || '';\n (document.getElementById('filter-date-end') as HTMLInputElement).value = filters.date[1] || '';\n (document.getElementById('filter-dist-min') as HTMLInputElement).value =\n filters.dist[0] !== null ? String(filters.dist[0]) : '';\n (document.getElementById('filter-dist-max') as HTMLInputElement).value =\n filters.dist[1] !== null ? String(filters.dist[1]) : '';\n (document.getElementById('filter-dur-min') as HTMLInputElement).value =\n filters.dur[0] !== null ? String(filters.dur[0]) : '';\n (document.getElementById('filter-dur-max') as HTMLInputElement).value =\n filters.dur[1] !== null ? String(filters.dur[1]) : '';\n (document.getElementById('filter-tags') as HTMLInputElement).value = filters.tags.join(', ');\n\n document\n .querySelectorAll('#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item')\n .forEach((el) => {\n const item = el as HTMLElement;\n item.classList.toggle('active', (item.dataset.sport || '') === (filters.sport || ''));\n });\n\n document.querySelectorAll('#filter-metrics .mini-pill').forEach((el) => {\n const btn = el as HTMLElement;\n btn.classList.toggle('active', filters.metrics.has(btn.dataset.metric!));\n });\n\n const activeCount =\n (filters.date[0] ? 1 : 0) +\n (filters.date[1] ? 1 : 0) +\n (filters.dist[0] !== null ? 1 : 0) +\n (filters.dist[1] !== null ? 1 : 0) +\n (filters.dur[0] !== null ? 1 : 0) +\n (filters.dur[1] !== null ? 1 : 0) +\n filters.metrics.size +\n (filters.tags.length > 0 ? 1 : 0);\n\n const badge = document.querySelector('#btn-toggle-filters .btn-badge');\n if (badge) {\n badge.textContent = activeCount > 0 ? String(activeCount) : '';\n badge.classList.toggle('hidden', activeCount === 0);\n }\n}\n\nfunction updateSearchSortUI() {\n const searchInput = document.getElementById('track-search') as HTMLInputElement;\n if (searchInput) searchInput.value = searchQuery;\n document.getElementById('btn-regex-toggle')?.classList.toggle('active', searchRegex);\n\n const opt = SORT_OPTIONS.find((o) => o.val === currentSort);\n if (opt) {\n const labelEl = document.getElementById('sort-current-label');\n const iconEl = document.getElementById('sort-current-icon');\n if (labelEl)\n labelEl.textContent = opt.label\n .replace(' first', '')\n .replace(' distance', '')\n .replace(' duration', '');\n if (iconEl) iconEl.textContent = opt.icon;\n }\n}\n\nfunction applyState(urlState: AppState) {\n // Restore track\n const newTrackId = urlState.track;\n if (newTrackId !== selectedId) {\n if (newTrackId && tracks[newTrackId]) {\n selectTrack(newTrackId, true);\n } else if (!newTrackId && selectedId) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n renderTrackList();\n MapView.fitAll();\n }\n }\n\n // Restore basemap\n if (urlState.map && typeof urlState.map === 'string') {\n MapView.switchBasemap(urlState.map);\n document\n .querySelectorAll('.bm-btn')\n .forEach((b) =>\n b.classList.toggle('active', (b as HTMLElement).dataset.layer === urlState.map),\n );\n }\n\n // Restore map position\n if (urlState.map_pos) {\n const [lat, lng, zoom] = urlState.map_pos;\n MapView.setPosition(lat, lng, zoom);\n }\n\n // Restore tab\n if (urlState.tab) {\n document.querySelectorAll('.tab-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n if (b.dataset.tab === urlState.tab) {\n if (!b.classList.contains('active')) b.click();\n }\n });\n }\n\n // Restore x-axis mode\n if (urlState.xaxis) ChartView.setXAxis(urlState.xaxis);\n\n const currentXAxis = urlState.xaxis || 'time';\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', (b as HTMLElement).dataset.axis === currentXAxis));\n\n // Restore active metrics\n if (urlState.metrics) {\n const metrics = ChartView.METRICS;\n const keys = urlState.metrics\n .map((abbr) => Object.keys(metrics).find((k) => metrics[k].abbr === abbr))\n .filter((k): k is string => k !== undefined);\n if (keys.length) ChartView.setActiveMetrics(keys);\n }\n\n // Restore filters\n if (urlState.f_date)\n filters.date = urlState.f_date.map((v) => v || null) as [string | null, string | null];\n if (urlState.f_dist)\n filters.dist = urlState.f_dist.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_dur)\n filters.dur = urlState.f_dur.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_mets) filters.metrics = new Set(urlState.f_mets);\n if (urlState.f_tags) filters.tags = urlState.f_tags;\n\n updateFilterUI();\n\n if (urlState.q) searchQuery = urlState.q;\n if (urlState.re) searchRegex = urlState.re;\n if (urlState.sort) currentSort = urlState.sort;\n updateSearchSortUI();\n\n applyFilters();\n}\n\nfunction updateSportFilterOptions() {\n const container = document.getElementById('sport-filter-container');\n if (!container) return;\n\n const commonContainer = document.getElementById('common-sports');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n if (!commonContainer || !dropdownContent) return;\n\n const sports = new Set();\n Object.values(tracks).forEach((t) => {\n if (t.sport) sports.add(t.sport);\n });\n\n const sportsArray = Array.from(sports).sort();\n const burgerDropdown = document.getElementById('sport-burger-dropdown');\n\n commonContainer.innerHTML = '';\n dropdownContent.innerHTML = '';\n\n if (sportsArray.length <= 4) {\n if (burgerDropdown) burgerDropdown.style.display = 'none';\n\n sportsArray.forEach((sport) => {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n });\n } else {\n if (burgerDropdown) burgerDropdown.style.display = 'inline-block';\n\n const commonSports = ['running', 'cycling', 'walking'];\n\n commonSports.forEach((sport) => {\n if (sports.has(sport)) {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n }\n });\n\n sportsArray.forEach((sport) => {\n const item = document.createElement('div');\n item.className = `dropdown-item${filters.sport === sport ? ' active' : ''}`;\n item.dataset.sport = sport;\n item.style.padding = '8px';\n item.style.cursor = 'pointer';\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '8px';\n item.innerHTML = `\n ${getSportIcon(sport)}\n ${sport.charAt(0).toUpperCase() + sport.slice(1)}\n `;\n dropdownContent.appendChild(item);\n });\n }\n}\n\nfunction renderTrackList() {\n updateSportFilterOptions();\n const list = document.getElementById('track-list');\n const emptyEl = document.getElementById('track-list-empty') as HTMLElement;\n const headerLabel = document.querySelector('.section-label');\n if (!list) return;\n\n const ids = Object.keys(tracks).filter((id) => !tracks[id]._filtered);\n if (headerLabel) headerLabel.textContent = `Tracks (${ids.length})`;\n\n if (!ids.length) {\n list.innerHTML = '';\n if (emptyEl) {\n list.appendChild(emptyEl);\n emptyEl.style.display = 'block';\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n list.innerHTML = '';\n\n ids\n .sort((a, b) => {\n // Current selected always first\n if (a === selectedId) return -1;\n if (b === selectedId) return 1;\n\n const ta = tracks[a],\n tb = tracks[b];\n const sa = ta.stats,\n sb = tb.stats;\n\n let cmp = 0;\n switch (currentSort) {\n case 'date-asc':\n cmp = (sa.startTime || 0) - (sb.startTime || 0);\n break;\n case 'date-desc':\n cmp = (sb.startTime || 0) - (sa.startTime || 0);\n break;\n case 'dist-asc':\n cmp = (sa.totalDist || 0) - (sb.totalDist || 0);\n break;\n case 'dist-desc':\n cmp = (sb.totalDist || 0) - (sa.totalDist || 0);\n break;\n case 'dur-asc':\n cmp = (sa.duration || 0) - (sb.duration || 0);\n break;\n case 'dur-desc':\n cmp = (sb.duration || 0) - (sa.duration || 0);\n break;\n default:\n cmp = 0;\n }\n return cmp || a.localeCompare(b);\n })\n .forEach((id) => {\n list.appendChild(buildTrackItem(tracks[id]));\n });\n}\n\nfunction getGlobalTags(): string[] {\n const all = new Set();\n Object.values(tracks).forEach((t) => {\n (t.tags || []).forEach((tag) => all.add(tag));\n });\n return Array.from(all).sort();\n}\n\nfunction getSportIcon(sport: string | null): string {\n if (!sport) return 'category';\n const s = sport.toLowerCase();\n if (s.includes('run')) return 'directions_run';\n if (s.includes('cycl') || s.includes('bike')) return 'directions_bike';\n if (s.includes('walk')) return 'directions_walk';\n if (s.includes('swim')) return 'pool';\n if (s.includes('hik')) return 'hiking';\n return 'sports';\n}\n\nfunction buildTrackItem(track: TrackData) {\n const item = document.createElement('div');\n item.className = `track-item${track.id === selectedId ? ' selected' : ''}`;\n item.dataset.id = track.id;\n\n const date =\n track.points.length && track.points[0].time ? fmtDate(track.points[0].time) : 'Unknown date';\n\n const tagsHtml =\n (track.tags || []).length > 0\n ? `
${(track.tags || [])\n .map((t) => {\n const c = getTagColor(t);\n return `${escHtml(t)}`;\n })\n .join('')}
`\n : '';\n\n item.innerHTML = `\n
\n
\n
${escHtml(track.displayName || track.name)}
\n
\n
\n ${date}\n ${Math.round(track.stats.totalDist / 1000)} km\n ${track.sport ? `${getSportIcon(track.sport)}` : ''}\n ${track.format.toUpperCase()}\n
\n \n
\n ${tagsHtml}\n
\n `;\n\n item.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.icon-btn')) return;\n selectTrack(track.id);\n });\n\n const btnVis = item.querySelector('.toggle-vis') as HTMLElement;\n btnVis.addEventListener('click', () => {\n track.visible = !track.visible;\n btnVis.querySelector('.material-symbols-rounded')!.textContent = track.visible\n ? 'visibility'\n : 'visibility_off';\n MapView.setTrackVisible(track.id, track.visible);\n Storage.save(track);\n });\n\n return item;\n}\n\nfunction showToast(msg: string, type: 'info' | 'error' = 'info') {\n const container = document.getElementById('toast-container');\n if (!container) return;\n container.innerHTML = '';\n const t = document.createElement('div');\n t.className = `toast ${type}`;\n t.textContent = msg;\n container.appendChild(t);\n}\n\nfunction showSkippedImportsModal() {\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n let listHtml = '';\n skippedImports.forEach((s) => {\n listHtml += `
${s.name}: ${s.reason}
`;\n });\n\n backdrop.innerHTML = `\n
\n
Skipped Imports
\n
\n ${listHtml || '
No skipped imports.
'}\n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n const btnClear = backdrop.querySelector('.modal-btn.clear') as HTMLButtonElement;\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n btnClear.addEventListener('click', () => {\n skippedImports = [];\n close();\n const importWarning = document.getElementById('import-warning');\n if (importWarning) importWarning.classList.add('hidden');\n });\n\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n}\n\nfunction initDropZone() {\n const zone = document.getElementById('drop-zone');\n if (!zone) return;\n\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n importWarning.addEventListener('click', (e) => {\n e.stopPropagation();\n showSkippedImportsModal();\n });\n }\n\n window.addEventListener('dragover', (e) => {\n e.preventDefault();\n zone.classList.add('drop-active');\n });\n\n window.addEventListener('dragleave', (e) => {\n if (e.relatedTarget === null) zone.classList.remove('drop-active');\n });\n\n window.addEventListener('drop', async (e) => {\n e.preventDefault();\n zone.classList.remove('drop-active');\n\n const items = e.dataTransfer?.items;\n if (!items) return;\n\n const files: File[] = [];\n const queue: FileSystemEntry[] = [];\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i].webkitGetAsEntry();\n if (entry) queue.push(entry);\n }\n\n async function readAllEntries(entry: FileSystemEntry) {\n if (entry.isFile) {\n const file = await new Promise((res) => (entry as FileSystemFileEntry).file(res));\n files.push(file);\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n let entries: FileSystemEntry[] = [];\n let chunk: FileSystemEntry[];\n do {\n chunk = await new Promise((res) => reader.readEntries(res));\n entries.push(...chunk);\n } while (chunk.length > 0);\n\n for (const child of entries) await readAllEntries(child);\n }\n }\n\n for (const entry of queue) await readAllEntries(entry);\n\n if (files.length) handleFiles(files);\n });\n}\n\nasync function handleFiles(files: File[]) {\n if (!files.length) return;\n cancelProcessing = false;\n const initialSkipCount = skippedImports.length;\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const loaderClose = document.getElementById('loader-close');\n\n if (loaderClose) {\n loaderClose.addEventListener('click', () => {\n cancelProcessing = true;\n if (loader) loader.classList.add('hidden');\n });\n }\n\n function updateLoaderIconToWarning() {\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'warning';\n loaderIcon.style.color = '#f59e0b';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n const count = skippedImports.length - initialSkipCount;\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = `${count}`;\n warningCount.style.display = 'flex';\n }\n }\n\n if (loader) {\n if (loaderText)\n loaderText.textContent = `Importing ${files.length} file${files.length > 1 ? 's' : ''}`;\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'download';\n loaderIcon.style.color = 'var(--accent)';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n warningCount.style.display = 'none';\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = '0';\n }\n if (loaderSubtext) loaderSubtext.textContent = '';\n if (progressBar) progressBar.style.width = '0%';\n loader.classList.remove('hidden');\n\n if (skippedImports.length > initialSkipCount) updateLoaderIconToWarning();\n }\n\n try {\n let count = 0;\n let firstId: string | null = null;\n let processedSinceLastUpdate = 0;\n\n // Filter out obviously invalid files early\n const validFiles = files.filter((f) => {\n const name = f.name.toLowerCase();\n return (\n name.endsWith('.gpx') ||\n name.endsWith('.fit') ||\n name.endsWith('.tcx') ||\n name.endsWith('.kml')\n );\n });\n\n const invalidFiles = files.filter((f) => !validFiles.includes(f));\n invalidFiles.forEach((f) => {\n skippedImports.push({ name: f.name, reason: 'Unsupported file format' });\n });\n\n if (validFiles.length === 0) {\n if (files.length > 0) {\n showToast('No valid GPS files found', 'error');\n // Still update warning icon if there were invalid files!\n const importWarning = document.getElementById('import-warning');\n if (importWarning && skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n }\n }\n return;\n }\n\n const loaderFilename = document.getElementById('loader-filename');\n let progressIdxEl: HTMLElement | null = null;\n if (loaderSubtext) {\n loaderSubtext.innerHTML =\n '';\n progressIdxEl = loaderSubtext.querySelector('.progress-index') as HTMLElement | null;\n const totalEl = loaderSubtext.querySelector('.progress-total');\n if (totalEl) totalEl.textContent = validFiles.length.toString();\n }\n\n for (let i = 0; i < validFiles.length; i++) {\n if (cancelProcessing) break;\n const f = validFiles[i];\n if (loaderFilename) loaderFilename.textContent = f.name;\n if (progressIdxEl) progressIdxEl.textContent = (i + 1).toString();\n if (progressBar) progressBar.style.width = `${(i / validFiles.length) * 100}%`;\n\n try {\n const data = await Parsers.parseFile(f);\n\n // Duplicate checks\n const existingTracks = Object.values(tracks);\n\n // Rule 1: Same file and same size\n const sameFile = existingTracks.find((t) => t.fileName === f.name && t.fileSize === f.size);\n if (sameFile) {\n skippedImports.push({ name: f.name, reason: 'Same File' });\n updateLoaderIconToWarning();\n continue;\n }\n\n // Rule 2 & 3: Same start day checks\n const newStart = data.stats.startTime;\n const newDuration = data.stats.duration;\n\n if (newStart != null && newDuration != null) {\n const newEnd = newStart + newDuration;\n const sameDayTracks = existingTracks.filter(\n (t) => t.stats.startTime != null && isSameDay(newStart, t.stats.startTime!),\n );\n\n let discarded = false;\n for (const ext of sameDayTracks) {\n const extStart = ext.stats.startTime!;\n const extDuration = ext.stats.duration!;\n const extEnd = extStart + extDuration;\n\n // Rule 2: Fully contained\n if (newStart >= extStart && newEnd <= extEnd) {\n skippedImports.push({ name: f.name, reason: 'Fully contained in another track' });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n\n // Rule 3: Overlaps for > 10 mins\n const overlap = Math.min(newEnd, extEnd) - Math.max(newStart, extStart);\n if (overlap > 600000) {\n // 10 mins in ms\n skippedImports.push({\n name: f.name,\n reason: 'Overlaps with an existing track for more than 10 mins',\n });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n }\n if (discarded) continue;\n }\n\n const fallbackTime = 1785542400000;\n let id = compactId(data.stats.startTime || fallbackTime);\n if (tracks[id]) id += `-${shortRandom()}`;\n\n // Use filename as activity name if internal name is generic\n let trackName = data.name;\n if (trackName.startsWith('Unnamed') || trackName.startsWith('Fit Activity'))\n trackName = f.name;\n\n // Generate a nice display name\n let displayName = trackName;\n const t0 = data.points[0]?.time;\n const sport = data.sport\n ? data.sport.charAt(0).toUpperCase() + data.sport.slice(1)\n : 'Activity';\n if (t0) {\n const d = new Date(t0);\n displayName = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')} ${sport}`;\n } else {\n displayName = trackName.replace(/\\.[^/.]+$/, '').replace(/_/g, ' '); // Remove extension and replace underscores\n }\n\n const track: TrackData = {\n ...data,\n id,\n name: trackName,\n displayName,\n fileName: f.name,\n fileSize: f.size,\n bounds: calculateBounds(data.points) || undefined,\n simplifiedPoints: simplifyTrack(data.points, 50), // 50m resolution\n addedAt: data.stats.startTime || fallbackTime,\n visible: true,\n color: TRACK_COLORS[colorIdx % TRACK_COLORS.length],\n };\n colorIdx++;\n if (cancelProcessing) break;\n\n await Storage.save(track);\n tracks[id] = track;\n MapView.addTrack(track);\n if (!firstId) firstId = id;\n count++;\n processedSinceLastUpdate++;\n\n if (processedSinceLastUpdate >= 5) {\n processedSinceLastUpdate = 0;\n }\n } catch (err) {\n skippedImports.push({\n name: f.name,\n reason: `Parse error: ${err instanceof Error ? err.message : String(err)}`,\n });\n updateLoaderIconToWarning();\n }\n }\n\n // Update warning icon\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n if (skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n } else {\n importWarning.classList.add('hidden');\n }\n }\n\n const newWarnings = skippedImports.length > initialSkipCount;\n if (!newWarnings && loader) {\n loader.classList.add('hidden');\n }\n\n if (count > 0) {\n showToast(`Imported ${count} track${count > 1 ? 's' : ''}`);\n applyFilters(!!firstId && firstId !== selectedId);\n if (firstId) selectTrack(firstId);\n }\n\n if (newWarnings) {\n const loaderIcon = document.querySelector('.loader-icon-wrap span');\n if (loaderIcon) loaderIcon.textContent = 'warning';\n // Delay hiding loader to let user see the alert icon\n await new Promise((r) => setTimeout(r, 1500));\n }\n } finally {\n if (loader) loader.classList.add('hidden');\n }\n}\n\nfunction initMetricPillDraggable() {\n const container = document.getElementById('metric-pills');\n if (!container) return;\n\n let draggedEl: HTMLElement | null = null;\n\n container.addEventListener('dragstart', (e) => {\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (!target) return;\n draggedEl = target;\n e.dataTransfer!.effectAllowed = 'move';\n target.classList.add('dragging-pill');\n // For transparent background in ghost image\n setTimeout(() => (target.style.opacity = '0.4'), 0);\n });\n\n container.addEventListener('dragover', (e) => {\n e.preventDefault();\n e.dataTransfer!.dropEffect = 'move';\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (target && target !== draggedEl) {\n const rect = target.getBoundingClientRect();\n const next = e.clientX - rect.left > rect.width / 2;\n container.insertBefore(draggedEl!, next ? target.nextSibling : target);\n }\n });\n\n container.addEventListener('dragend', () => {\n if (!draggedEl) return;\n draggedEl.classList.remove('dragging-pill');\n draggedEl.style.opacity = '';\n draggedEl = null;\n\n // Update Chart order\n const keys = Array.from(container.querySelectorAll('.metric-pill')).map(\n (el) => (el as HTMLElement).dataset.metric!,\n );\n ChartView.updateMetricOrder(keys);\n syncMetricsToUrl();\n });\n}\n\nfunction updateToolbarLayout() {\n const toolbar = document.getElementById('chart-toolbar');\n const pills = document.getElementById('metric-pills');\n if (!toolbar || !pills) return;\n\n toolbar.classList.remove('collapsed');\n const availableW = Math.max(0, toolbar.clientWidth - 280);\n let totalW = 0;\n let hidden = false;\n\n Array.from(pills.children).forEach((el) => {\n const htmlEl = el as HTMLElement;\n if (htmlEl.id === 'pill-overflow') return;\n\n htmlEl.classList.remove('overflow-hidden');\n if (!htmlEl.classList.contains('active')) return;\n const metricKey = htmlEl.dataset.metric || '';\n const deterministicPillWidth = 36 + metricKey.length * 6;\n totalW += deterministicPillWidth + 6;\n\n if (totalW > availableW) {\n hidden = true;\n htmlEl.classList.add('overflow-hidden');\n }\n });\n\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.toggle('hidden', !hidden);\n\n if (hidden) toolbar.classList.add('collapsed');\n}\n\ndocument.addEventListener('DOMContentLoaded', init);\n"], - "mappings": "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", - "names": ["UrlState", "_state", "_lastSearch", "_syncTimeout", "_shouldPush", "read", "p", "s", "metricsRaw", "v", "isDesc", "field", "parts", "_sync", "dir", "search", "val", "url", "get", "patch", "partial", "push", "k", "key", "refresh", "reset", "InMemoryStorage", "track", "id", "key", "value", "IndexedDBStorage", "resolve", "reject", "req", "db", "name", "mode", "res", "rej", "tx", "activeDriver", "Storage", "UrlState", "t", "k", "v", "FitParser", "haversine", "lat1", "lon1", "lat2", "lon2", "phi1", "phi2", "deltaPhi", "deltaLambda", "a", "compactId", "timestamp", "buf", "shortRandom", "fmtDuration", "s", "fmtSecs", "h", "m", "fmtPace", "seconds", "mins", "secs", "fmtDate", "ts", "d", "fmtDateTime", "iso", "fmtFileSize", "bytes", "k", "sizes", "i", "escHtml", "str", "getTagColor", "name", "hash", "gaussianSmooth", "data", "sigma", "size", "kernel", "half", "sum", "x", "result", "val", "weightSum", "idx", "hexToRgba", "hex", "alpha", "r", "g", "b", "calculateBounds", "pts", "minLat", "maxLat", "minLon", "maxLon", "p", "SIMPLIFY_CAP", "simplifyLats", "simplifyLons", "simplifyEles", "simplifyDists", "enrichEleBuf", "enrichPwrBuf", "enrichSpdBuf", "simplifyTrack", "minDistanceMeters", "n", "lats", "lons", "eles", "dists", "i", "tolerances", "errChecksum", "degToRad", "pass", "ti", "tolDegSq", "anchor", "cosLat", "dx", "dy", "dz", "mid", "mx", "my", "result", "lastPoint", "tolBias", "haversine", "Parsers", "enrichPoints", "totalDist", "prev", "d", "dt", "de", "eleBuf", "pwrBuf", "spdBuf", "gradeWindows", "npAccum", "scaleH", "wi", "w", "invW", "pSum", "sSum", "pAvg", "airDensity", "slopeAngle", "smoothBias", "hrZoneThresholds", "ftp", "computeStats", "includeCurves", "stats", "powerSum", "powerN", "hrSum", "hrN", "cadSum", "cadN", "speedSum", "speedN", "batterySum", "batteryN", "tempSum", "tempN", "hasTemp", "shifts", "hasGears", "diff", "t0", "t1", "calculateHRZones", "calculateHRCurve", "calculatePowerCurve", "calculatePowerZones", "ensureCurvesAndZones", "track", "s", "STANDARD_CURVE_DURATIONS", "calculateSlidingMax", "data", "durations", "len", "prefix", "curve", "hasAny", "di", "maxSum", "bestIdx", "limit", "j", "currentSum", "powerData", "nonZero", "v", "hrData", "zones", "thresholds", "t", "pw", "z", "setFTP", "val", "getFTP", "hr", "setHRZones", "getHRZones", "extractXmlTag", "block", "openTag", "closeTag", "start", "extractXmlAttr", "tagOpen", "attrPrefix", "cachedDateKey", "cachedDayMs", "parseIntSlice", "text", "end", "neg", "c0", "digits", "c", "parseFloatSlice", "intPart", "fracPart", "fracDiv", "inFrac", "res", "fastParseTimeSlice", "y", "m", "key", "hh", "mm", "ss", "ms", "extractAttrFloat", "vStart", "parseGPX", "buf", "predecodedText", "firstTrkpt", "header", "trkIdx", "name", "gpxOpenEnd", "device", "points", "pos", "trkStart", "openEnd", "trkEnd", "lat", "lon", "ele", "time", "cad", "power", "temp", "speed", "gearFront", "gearRear", "gearFrontTooth", "gearRearTooth", "battery", "lt", "gt", "c1", "tagLen", "nextLt", "vEnd", "expectedCloseGt", "closeGt", "gears", "parseTCX", "firstTp", "creatorBlock", "tpStart", "tpEnd", "fastDecodeFitData", "dv", "headerSize", "dataSize", "endOffset", "GARMIN_EPOCH_SEC", "SEMICIRCLE_TO_DEG", "defs", "file_ids", "sessions", "records", "events", "device_infos", "offset", "hdr", "localNum", "littleEndian", "globalMsgNum", "numFields", "fields", "recordSize", "num", "size", "type", "def", "le", "gNum", "ts", "rawLat", "rawLon", "rawAlt", "rawDist", "rawSpd", "msg", "fOff", "f", "bType", "sportMap", "evName", "parseFIT", "resolve", "reject", "handleParsedFitData", "error", "devices", "sport", "subSport", "getDeviceName", "fid", "antId", "existing", "statusReports", "idx", "a", "b", "gearEvents", "e", "front", "rear", "frontTooth", "rearTooth", "ft", "fg", "rt", "rg", "lastBattery", "statusIdx", "lastFrontGear", "lastRearGear", "lastFrontTooth", "lastRearTooth", "gearIdx", "validPoints", "ri", "r", "ex", "fastData", "FitParser", "parseKML", "doc", "nameEl", "coordEls", "el", "line", "parts", "parseFile", "file", "ext", "MapView", "trackData", "customClickHandler", "init", "onSelectCb", "onMoveCb", "onPointClickCb", "onPointHoverCb", "onDblClickCb", "switchBasemap", "layer", "addTrack", "t", "addTracks", "ts", "removeTrack", "id", "clearTracks", "removeAllTracks", "setTrackVisible", "visible", "setSelectedTrack", "fit", "fitAll", "fitTrack", "showCursorAt", "lat", "lon", "hideCursor", "highlightSegment", "pts", "start", "end", "colors", "clearHighlight", "setTrackHover", "hover", "ensureVisible", "centerOn", "zoom", "force", "closePopup", "invalidateSize", "getPosition", "setPosition", "lng", "colorTrackByMetric", "clearMetricColor", "findTracksPassingThroughPoints", "points", "radius", "handler", "uPlot", "Zones", "getPowerZones", "ftp", "Parsers", "thresholds", "t", "names", "colors", "zones", "last", "i", "getHRZones", "Metrics", "METRICS", "v", "p", "pts", "fillNulls", "vam", "i", "prev", "de", "dt", "SPORTS", "getSportIcon", "sport", "key", "ChartView", "plots", "renderedTrack", "renderedXAxis", "renderedSpeedMode", "renderedMapColorMetric", "syncKey", "scaleSyncing", "cursorSyncing", "activeMetrics", "availableMetrics", "smoothedMetrics", "metricsIncludingZero", "xAxis", "currentTrack", "allTracks", "selAnchorVal", "selEndVal", "isDragging", "updatingRange", "pinnedPtIdx", "lastMouseXVal", "lastHistMouseEvent", "hoveredHistData", "hoveredHistCanvas", "currentXRange", "targetXRange", "animId", "onCursorMoveCb", "onRangeChangeCb", "onClickCb", "onPinChangeCb", "HIST_W", "ROW_BODY_PADDING", "HIST_GAP", "statsVisible", "histTooltipEl", "container", "emptyEl", "selStatsEl", "resetSelBtn", "mapColorMetric", "onMapColorChangeCb", "init", "onCursorMove", "onRangeChange", "onClick", "onPinChange", "updateHistTooltip", "uPlot", "cancelSelection", "navKeys", "activeNavKeys", "e", "key", "u", "min", "max", "moveStep", "zoomFactor", "newMin", "newMax", "center", "factor", "xFull", "d", "setVisibleRange", "animate", "startMin", "startMax", "lerp", "a", "b", "t", "step", "tMin", "tMax", "cMin", "cMax", "loadTrack", "track", "others", "deferRender", "METRICS", "def", "p", "m", "el", "pill", "metric", "isAvailable", "updateStats", "render", "clear", "destroyPlots", "chartStats", "clearSelectionStats", "resetState", "overflowEl", "toolbar", "toggleMetric", "setActiveMetrics", "keys", "setXAxis", "axis", "pts", "t0", "convert", "val", "idx", "dTarget", "tTarget", "newRange", "r0", "r1", "toggleStats", "histCol", "resize", "setMapColorChangeCb", "cb", "toggleMapColor", "_updateMapColorBtns", "_fireMapColorCb", "plot", "colors", "_computePointColors", "yData", "vals", "v", "sport", "sportDef", "SPORTS", "defaultMode", "speedMode", "UrlState", "paceUnit", "gradientColor", "speed", "speedColor", "lerpHex", "resetZoom", "updateSelOverlay", "redrawHistograms", "xData", "setSelectionStats", "stats", "fmt", "id", "fmtSecs", "restoreSelection", "totalDuration", "tOffset", "xMin", "xMax", "updateAnchorLines", "w", "anyResized", "histCanvas", "histData", "drawHistogram", "keepState", "savedRange", "savedScroll", "available", "containerW", "canReuse", "lastValidX", "existingByKey", "availSet", "isSmoothed", "isIncZero", "nextSiblingRows", "nextExisting", "i", "ex", "reused", "uplot", "s", "prevSync", "initHoverBinI", "buildHistBins", "span", "transform", "fmtAxis", "unit", "label", "fmtPace", "fillNulls", "gaussianSmooth", "createChart", "metricKey", "initialRange", "insertBeforeEl", "gradData", "smoothGradient", "row", "header", "labelEl", "smoothBtn", "mapColorBtn", "zeroBtn", "incZero", "statsTotalEl", "statsSelEl", "statsContainer", "actionsEl", "rightActionsEl", "paceToggle", "btn", "mode", "isDefault", "rowBody", "plotEl", "fixedMinLabel", "fixedMaxLabel", "isDistAxis", "formatX", "range", "dec", "absV", "h", "hh", "mm", "ss", "incZeroDefault", "gMin", "gMax", "allSum", "allCount", "filtMin", "filtMax", "filtSum", "filtCount", "fullStatsAll", "fullStatsFiltered", "gPad", "fixedYRange", "statsTotalInitialized", "updateHeaderStats", "visibleMin", "visibleMax", "getHtml", "isFull", "rangeStats", "es", "elevationRangeStats", "initializingScale", "uOpts", "_si", "_u", "mn", "mx", "axisIdx", "scaleMin", "scaleMax", "targetLabels", "idealIncr", "incrs", "incr", "splits", "precision", "pos", "top", "drawTrackPath", "drawElevationGradient", "drawGradientChart", "drawMetricColorFill", "drawPinnedDot", "drawYAxisHighlight", "hIdx", "hasPinned", "hasHover", "cy", "drawVerticalLineOnly", "hexToRgba", "ctx", "dpr", "bb", "ax", "fontSize", "fontStr", "tw", "visibleL", "visibleR", "padH", "padV", "bw", "bh", "bx", "by", "drawXAxisLabels", "showHover", "updateTooltip", "binI", "other", "left", "width", "overlay", "selFill", "anchorLine", "anchorLabel", "anchorHandle", "anchorMarker", "endLine", "endLabel", "endHandle", "endMarker", "curYVal", "pinYVal", "self", "attachHandleDrag", "mousedownX", "rect", "attachHistTooltip", "aX", "eX", "overW", "overH", "plotBottom", "isAnchorVisible", "isEndVisible", "fillL", "fillR", "aText", "fmtXVal", "aLabelW", "aIcon", "eText", "eLabelW", "eIcon", "handleEl", "isAnchor", "startX", "startVal", "pxPerUnit", "onMove", "me", "dx", "newVal", "onUp", "BINS", "lo", "hi", "cnt", "bins", "binAccum", "k", "bi", "prev", "next", "canvas", "chartH", "hoverBinI", "hasSel", "selBins", "selBinAccum", "x", "W", "H", "peak", "pad", "plotW", "plotH", "binY", "binH", "baseAlpha", "total", "pts2", "cumSum", "my", "cp", "font9", "avgY", "minLabelY", "maxLabelY", "labelHeight", "countLower", "countHigher", "pLower", "pHigher", "font8", "textY", "fontB10", "midX", "getBinAt", "lineEl", "relY", "rawI", "count", "pct", "low", "high", "zoneHtml", "mid", "zones", "Zones", "zIdx", "z", "finalZIdx", "totalAccum", "totalPct", "html", "stotalAccum", "stotalPct", "ttH", "ttW", "binCenterY", "sum", "n", "gain", "loss", "prevEle", "isDist", "diff", "cx", "gColor", "g", "p0", "p1", "content", "front", "rear", "color44", "gradientColorRgbaCache", "gradientColorRgba", "c", "yMin", "yMax", "xScale", "yScale", "yBase", "idxs", "iStart", "iEnd", "byColor", "prevIdx", "xv1", "xv0", "x0", "y0", "x1", "y1", "color", "segs", "j", "drawHoverLine", "xVal", "opacity", "skipLine", "distVal", "timeVal", "bottomLabel", "topLabel", "drawPill", "text", "y", "isTop", "rx", "clampedRx", "ry", "pillH", "yVal", "cyClamp", "drawAreaFillAbove", "yDir", "yMult", "inSegment", "hasAnySegment", "lastPx", "xv", "yv", "px", "py", "ah", "ar", "ag", "ab", "br", "bg", "rr", "rg", "rb", "absG", "kmh", "windowMetres", "grads", "j0", "j1", "data", "res", "right", "getAvg", "avgSpeed", "avgPower", "avgCadence", "INTERVAL_CAP", "ivPwr", "ivHr", "ivSpd", "ivEle", "ivCad", "ivSmoothed", "ivKdeBins", "intervalWindows", "analyzeTelemetryIntervals", "tracksList", "selStartSec", "selEndSec", "intervalScore", "ti", "sStart", "sEnd", "inv35", "pass", "weightPwr", "weightHr", "invSigmaSq", "omega", "sgPwr", "sgHr", "sgSpd", "dP", "gauss", "harmonic", "wi", "invW", "winSum", "winEle", "maxInterval", "avg", "norm", "newActive", "isStepped", "drawBackgroundTracks", "GAP_THRESHOLD", "field", "first", "prevP", "prevXVal", "lastFrontGear", "fMin", "fMax", "fg", "rMin", "rMax", "isTimeAxis", "gapSec", "prevDrawnI", "prevX", "prevY", "segmentColor", "prevXv", "SENSOR_ICONS", "Metrics", "onTagsChangeCb", "onDeleteTrackCb", "initDetails", "onTagsChange", "onDeleteTrack", "resetDetails", "container", "DETAIL_CAP", "detailChannels", "stabilityWindows", "renderDetails", "track", "globalTags", "allTracks", "s", "t0", "tracksToAnalyze", "stabilityAccum", "ti", "tPts", "n", "i", "p", "pass", "wi", "w", "invW", "halfW", "ci", "ch", "sum", "sumSq", "autoCov", "jitterSum", "invNoise", "v", "old", "mean", "variance", "lagVal", "diff", "likelihood", "telemetryStabilityPct", "escHtml", "t", "fmtSecs", "fmtFileSize", "getSportIcon", "SPORTS", "fmtDateTime", "sensor", "seen", "d", "key", "name", "manufacturer", "extra", "battery", "sourceIcon", "st", "deviceIcon", "nameLower", "tagContainer", "tagInput", "addBtn", "renderTags", "tags", "tag", "c", "getTagColor", "el", "btn", "e", "Storage", "addTag", "val", "titleInput", "sportTrigger", "showSportMenu", "anchorEl", "popup", "def", "item", "isActive", "iconEl", "nameEl", "clearItem", "isClear", "rect", "closeHandler", "uPlot", "courses", "getCoursesForTrack", "track", "c", "pt", "passesPoint", "trackPt", "haversine", "activeCourseId", "isEditMode", "openCourseId", "toastFn", "courseLayer", "initCourses", "showToast", "toastFn", "loadCourses", "resetCourses", "courses", "activeCourseId", "openCourseId", "isEditMode", "container", "prepareBenchmarkCourses", "allTracks", "i", "n", "pStart", "pMid", "pEnd", "stored", "Storage", "saveCourses", "calculateCourseDistance", "course", "total", "p1", "p2", "haversine", "findCourseRange", "track", "coursePoints", "currentPtIdx", "startIdx", "endIdx", "tp", "cp", "calculateCourseStats", "pts", "s", "e", "startTime", "duration", "totalPower", "powerCount", "totalHR", "hrCount", "totalSpeed", "speedCount", "totalCadence", "cadenceCount", "totalAscent", "p", "prev", "de", "dist", "formatDuration", "seconds", "h", "m", "renderCourseTableHeaders", "METRICS", "renderCourseTableCells", "stats", "sport", "dateStr", "paceUnit", "SPORTS", "paceStr", "paceSeconds", "fmtPace", "COURSE_CAP", "courseTrkLats", "courseTrkLons", "courseTrkPwrs", "courseGateLats", "courseGateLons", "DTW_SAMPLES", "DTW_BAND", "dtwRefProfile", "dtwCandProfile", "dtwPrevRow", "dtwCurrRow", "renderCourses", "corridorDeviationSum", "c", "candidateIds", "MapView", "numGates", "g", "segFloat", "segIdx", "frac", "pA", "pB", "ci", "id", "pt", "gLat", "gLon", "minDist", "bestIdx", "d", "idx", "val", "pass", "paceBias", "jStart", "jEnd", "rVal", "j", "diff", "cost", "m1", "m2", "m3", "prevMin", "matchingIds", "isOpen", "tracksHtml", "matchedTracksWithStats", "range", "fmtDate", "t", "a", "b", "UrlState", "escHtml", "createNewCourse", "el", "editCourse", "renameCourse", "deleteCourse", "selectCourse", "row", "trackId", "selectTrack", "t0", "sIdx", "eIdx", "tMin", "tMax", "axis", "ChartView", "selMin", "selMax", "name", "newCourse", "nameEl", "currentName", "input", "save", "newName", "clearCourseLayer", "courseLayer", "selectCourse", "id", "open", "activeCourseId", "openCourseId", "isEditMode", "MapView", "clearCourseLayer", "renderCourses", "deleteCourse", "courses", "c", "saveCourses", "toastFn", "insightPlots", "destroyInsightPlots", "p", "initInsights", "showToast", "resetInsights", "el", "container", "INSIGHT_CAP", "inPwrArr", "inHrArr", "inCadArr", "inSpdArr", "inVamArr", "inPrefixPwr", "inPrefixVam", "tauCandidates", "mmpDurations", "renderInsights", "track", "allTracks", "Parsers", "tracksToModel", "cpBase", "minWPrimeBal", "quadrantAccum", "ti", "tPts", "n", "i", "pt", "h", "c", "sp", "gr", "vam", "pass", "scale", "di", "d", "limit", "maxP", "maxV", "j", "sumP", "sumV", "half", "k", "cp", "tauBase", "wBal", "efSum1", "efSum2", "invH", "dep", "dcp", "tauDyn", "torque", "ef", "grid", "chartWidth", "renderCurveCard", "Metrics", "card", "metricKey", "color", "isMapColored", "ChartView", "totalTime", "a", "b", "zones", "Zones", "zonesHtml", "time", "z", "pct", "rangeText", "fmtSecs", "e", "current", "btn", "showPowerZoneSettings", "showHRZoneSettings", "climbingCard", "distKm", "grade", "effCard", "trackCourses", "getCoursesForTrack", "coursesCard", "renderCourseTableHeaders", "range", "findCourseRange", "statsHtml", "stats", "calculateCourseStats", "startTime", "dateStr", "fmtDate", "renderCourseTableCells", "escHtml", "courseId", "selectCourse", "UrlState", "course", "MapView", "opts", "curve", "label", "unit", "icon", "tableWrap", "toggleBtn", "toggleIcon", "isHidden", "mapColorBtn", "key", "tbody", "durations", "entry", "val", "row", "fmtDuration", "startIdx", "duration", "pts", "endIdx", "t0", "tMin", "tMax", "chartEl", "xData", "yData", "curYVal", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "idx", "hasFocus", "mousePy", "pointPy", "cx", "cy", "durVal", "pcx", "pcy", "plot", "uPlot", "anchorEl", "popup", "rect", "inputs", "newZones", "Storage", "dismiss", "ftp", "input", "newFtp", "uPlot", "currentTracks", "currentTrack", "plot", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "playIntervalId", "isPolar", "updateSliderLabel", "sliderVal", "timeSecs", "fmtSecs", "resetCombined", "playIntervalId", "plot", "currentTracks", "currentTrack", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "isPolar", "tooltip", "container", "COMBINED_CAP", "combinedPhsPool", "combinedCePool", "combinedLens", "combinedDensityGrid", "combinedWindows", "renderCombined", "trackOrTracks", "allTracks", "track", "metrics", "ChartView", "availableMetrics", "key", "def", "xDef", "yDef", "summaryHtml", "matrixTracks", "numTrk", "t", "pts", "n", "phs", "ce", "k", "p", "pw", "h", "sp", "cd", "el", "bx", "by", "aggPts", "corrSum", "pass", "wi", "w", "invW", "invBandwidth", "i", "phsA", "ceA", "lenA", "j", "phsB", "ceB", "len", "sumA", "sumB", "sumCadA", "sumCadB", "idxOld", "avgA", "avgB", "avgCA", "avgCB", "diffAB", "diffCE", "rbf", "rbfCad", "g", "t1", "t2", "s1", "s2", "distDiff", "pwrDiff", "hrDiff", "eleDiff", "shiftsDiff", "totalDist", "totalElev", "totalDur", "avgPwr", "maxPwr", "avgHr", "maxHr", "tempDiff", "avgTemp", "maxTemp", "totalShifts", "fmtSecs", "e", "showMenu", "slider", "sliderVal", "playBtn", "updateSliderLabel", "startPlaying", "stopPlaying", "updatePlot", "resizeCombined", "plotContainer", "size", "anchorEl", "axis", "popup", "item", "currentVal", "rect", "close", "pts1", "pts2", "maxLen", "xData", "yData1", "yData2", "p1", "p2", "width", "height", "opts", "uPlot", "t0", "chronoData", "idx", "x", "y", "d", "xVals", "yVals", "xMin", "xMax", "yMin", "yMax", "xVal", "yVal", "theta", "r", "px", "py", "a", "b", "yData", "hexToRgba", "u", "vals", "v", "seriesIdx", "dataIdx", "cursorLeft", "cursorTop", "minD2", "closestIdx", "cx", "cy", "dx", "dy", "d2", "ctx", "dpr", "started", "startIdx", "endIdx", "xVal1", "yVal1", "xVal2", "yVal2", "cx1", "cy1", "cx2", "cy2", "progress", "lineWidth", "alpha", "fillAlpha", "timeSecs", "distKm", "origX", "origY", "canvasRect", "originalIdx", "uPlot", "computeAccumulatedMetric", "allTracks", "extractor", "refTs", "i", "st", "now", "currentYear", "oneYearAgoMs", "sixMonthsAgoMs", "oneMonthAgoMs", "currentYearVal", "pastYearVal", "past6mVal", "past1mVal", "totalVal", "minTime", "t", "val", "time", "msecPerWeek", "currentYearStart", "currentYearWeeks", "pastYearWeeks", "past6mWeeks", "past1mWeeks", "totalWeeks", "renderAccumulatedTable", "accumulated", "isDistance", "unit", "factor", "format", "evolutionPlots", "destroyEvolutionPlots", "p", "resetEvolution", "container", "EVO_CAP", "evoPwrPrefix", "evoHrPrefix", "evoSpdPrefix", "evoStressArr", "evoDailyTrimp", "acuteConstants", "chronicConstants", "envelopeDurations", "renderEvolution", "currentTrack", "allTracks", "onTrackSelect", "onDateRangeSelect", "currentRange", "UrlState", "track", "Parsers", "totalFatigue", "totalFitness", "ti", "pts", "n", "i", "pw", "h", "sp", "el", "hrRatio", "pass", "decayWeight", "di", "d", "limit", "maxP", "maxH", "maxS", "j", "sh", "ss", "bPass", "ai", "alphaA", "oneMinusA", "trimpK", "ci", "alphaC", "oneMinusC", "hrRest", "invHrSpan", "atl", "ctl", "trimp", "dayIdx", "atl365", "ctl365", "dA", "dC", "day", "load", "cards", "Metrics", "grid", "gridWidth", "progressSync", "uPlot", "renderProgressCard", "distanceScroll", "elevationScroll", "toolbarRangeCtrl", "btn", "range", "b", "onRangeChange", "pill", "target", "onPinChange", "dur", "c", "t", "card", "renderCurveEvolutionCard", "opts", "metricKey", "label", "unit", "color", "icon", "trackName", "mainChart", "cardContainer", "row1", "legendEl", "row2", "sideBySide", "chartEl", "maxCurve", "curve", "name", "date", "fmtDate", "trackInfo", "data", "val", "currentCurve", "allDurations", "durations", "a", "xData", "yDataCurrent", "entry", "yDataMax", "validTracks", "xTimeline", "yTimelineData", "currentDur", "tracksFiltered", "pinnedDur", "getFilteredData", "maxTime", "minTime", "filteredIndices", "idx", "xFiltered", "rawY", "rawYFiltered", "smoothedYFiltered", "gaussianSmooth", "timelineChart", "curYVal", "optsUPlot", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "fmtDuration", "pcx", "pcy", "curVal", "dotRadius", "dotColor", "activeSeriesIdx", "cursorLeft", "cursorTop", "minD2", "nearestIdx", "radius", "maxD2", "yCur", "yMax", "px", "py", "dx", "dy", "d2", "xValStr", "xbw", "pillH", "xLabelX", "clampedXBx", "xLabelY", "yValStr", "ybw", "yLabelX", "yLabelY", "cx", "cy", "durVal", "mxVal", "html", "lowerBound", "upperBound", "labelEl", "clickedDur", "newPinnedDur", "stats", "bestIdx", "duration", "startPt", "endPt", "trackStart", "min", "max", "detailsEl", "cur", "mx", "mxId", "mxIdx", "e", "id", "lastNearestIdx", "timelineEl", "timelineTooltip", "dataTimeline", "series", "optsTimeline", "ts", "tpcx", "tpcy", "tctx", "tdpr", "dateStr", "valStr", "yData", "y", "getWeekStart", "diff", "computeWeeklyDistance", "weeklyData", "weekStart", "weekKey", "week", "computeWeeklyElevation", "type", "syncKey", "isDistance", "accumulated", "computeAccumulatedMetric", "renderAccumulatedTable", "yAxisEl", "tooltip", "yDataSmoothed", "chartClientW", "width", "maxVal", "mainOpts", "item", "start", "end", "startStr", "endStr", "self", "splits", "s", "scrollContainer", "filteredData", "newXData", "newYData", "newYDataSmoothed", "newWidth", "newMaxVal", "TRACK_COLORS", "POINT_ZOOM_LEVEL", "tracks", "skippedImports", "isSameDay", "t1", "t2", "d1", "d2", "cancelProcessing", "selectedId", "colorIdx", "followDot", "currentMapColors", "searchQuery", "searchRegex", "currentSort", "filters", "syncFiltersToUrl", "push", "UrlState", "v", "syncMetricsToUrl", "active", "ChartView", "metrics", "abbrs", "key", "SORT_OPTIONS", "showSortMenu", "anchorEl", "el", "popup", "opt", "item", "updateSearchSortUI", "renderTrackList", "rect", "close", "e", "showMetricMenu", "available", "def", "isNowActive", "pill", "updateToolbarLayout", "id", "idx", "dur", "selectTrack", "t", "pts", "pIdx", "t0", "p", "tMin", "tMax", "iMax", "selPts", "stats", "Parsers", "renderInsights", "MapView", "btn", "nav", "b", "tab", "panel", "c", "renderDetails", "getGlobalTags", "renderEvolution", "trackId", "range", "onChartRangeChange", "start", "end", "applyFilters", "updateFilterUI", "renderCombined", "renderCourses", "s", "resetBenchmarkState", "Storage", "resetCourses", "resetInsights", "resetDetails", "resetCombined", "resetEvolution", "toastContainer", "init", "fontTimerId", "fontTimeout", "resolve", "fontLoadPromise", "storageSelect", "selected", "params", "loader", "loaderText", "loaderSubtext", "progressBar", "mapLoader", "mapLoaderSpan", "urlState", "initInsights", "msg", "type", "showToast", "initDetails", "deleteTrack", "initCourses", "onMapMove", "onMapPointClick", "onMapDblClick", "onChartCursorMove", "onChartClick", "data", "currentUrlState", "applyState", "hrZones", "ftp", "saved", "a", "tracksToLoad", "updated", "calculateBounds", "simplifyTrack", "restoreId", "selectedTrackData", "processAndLoadTrack", "remaining", "index", "loadNextChunk", "initResizeHandle", "initSidebarResizer", "initMetricPillDraggable", "clearAll", "toggleMetric", "metric", "axis", "initDropZone", "handleFiles", "onFilterInput", "val", "burgerBtn", "dropdownContent", "isVisible", "target", "selectedSport", "m", "resizeCombined", "initBenchmarkTriggers", "preloadBenchmarkFiles", "readyEl", "camelReadyEl", "preloadedBenchmarkPayloads", "fileNames", "decoder", "name", "buf", "cleanName", "bytes", "ds", "stream", "text", "file", "warmSample", "parsed", "warmPts", "warmTrack", "warmTrack2", "warmList", "prepareBenchmarkCourses", "selectCourse", "r", "btnLoad", "btnAnalysis", "btnInsights", "btnDetails", "btnAggregate", "btnEvolution", "btnCourses", "activateTab", "tabName", "loadedFiles", "allTracks", "availableMetrics", "analysisMetrics", "primaryTrack", "selectedTwo", "powerCurveEntries", "needsEnrich", "handle", "isDragging", "h", "clampedH", "resizer", "sidebar", "w", "clampedW", "lat", "lng", "zoom", "pt", "min", "max", "fit", "iMin", "d0", "ts0", "ts1", "deferChartRender", "hadSelected", "activeTab", "code", "backdrop", "input", "btnConfirm", "btnCancel", "skipRender", "visible", "d", "field", "trackTags", "ft", "activeCount", "badge", "searchInput", "o", "labelEl", "iconEl", "newTrackId", "currentXAxis", "keys", "abbr", "k", "updateSportFilterOptions", "commonContainer", "sports", "sportsArray", "burgerDropdown", "sport", "getSportIcon", "list", "emptyEl", "headerLabel", "ids", "ta", "tb", "sa", "sb", "cmp", "buildTrackItem", "all", "tag", "track", "date", "fmtDate", "tagsHtml", "getTagColor", "escHtml", "btnVis", "container", "showSkippedImportsModal", "listHtml", "btnClear", "importWarning", "zone", "items", "files", "queue", "i", "entry", "readAllEntries", "res", "reader", "entries", "chunk", "child", "initialSkipCount", "loaderClose", "updateLoaderIconToWarning", "loaderIcon", "warningCount", "count", "countSpan", "firstId", "processedSinceLastUpdate", "validFiles", "f", "loaderFilename", "progressIdxEl", "totalEl", "existingTracks", "newStart", "newDuration", "newEnd", "sameDayTracks", "discarded", "ext", "extStart", "extDuration", "extEnd", "fallbackTime", "compactId", "shortRandom", "trackName", "displayName", "err", "newWarnings", "draggedEl", "next", "toolbar", "pills", "availableW", "totalW", "hidden", "htmlEl", "deterministicPillWidth", "overflowEl"] + "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 URL State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Handles reading/writing application state to the URL.\n// Uses an incremental \"patch\" approach to preserve existing params.\n\nexport interface AppState {\n track?: string;\n map?: string;\n xaxis?: string;\n metrics?: string[];\n f_date?: (string | null)[];\n f_dist?: (number | null)[];\n f_dur?: (number | null)[];\n f_mets?: string[];\n f_tags?: string[];\n q?: string;\n re?: boolean;\n sort?: string;\n map_pos?: [number, number, number];\n storage?: 'memory' | 'indexeddb';\n sel?: [number, number];\n sel_point?: number;\n tab?: string;\n progress?: string;\n speed_mode?: string;\n}\n\nexport const UrlState = (() => {\n // Internal state object, initialized from current URL.\n let _state: AppState = {};\n let _lastSearch: string | null = null;\n let _syncTimeout: any = null;\n let _shouldPush = false;\n\n function read(): AppState {\n const p = new URLSearchParams(location.search);\n const s: AppState = {};\n\n if (p.has('track')) s.track = p.get('track')!;\n if (p.has('map')) s.map = p.get('map')!;\n if (p.has('xaxis')) s.xaxis = p.get('xaxis')!;\n if (p.has('tab')) s.tab = p.get('tab')!;\n if (p.has('sel_point')) s.sel_point = Number(p.get('sel_point'));\n if (p.has('speed_mode')) s.speed_mode = p.get('speed_mode')!;\n if (p.has('progress')) s.progress = p.get('progress')!;\n const metricsRaw = p.get('metrics');\n if (metricsRaw) s.metrics = metricsRaw.split(',').filter(Boolean);\n\n if (p.has('f_date')) {\n s.f_date = p\n .get('f_date')!\n .split(',')\n .map((v) => v || null);\n }\n if (p.has('f_dist')) {\n s.f_dist = p\n .get('f_dist')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_dur')) {\n s.f_dur = p\n .get('f_dur')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_mets')) s.f_mets = p.get('f_mets')!.split(',');\n if (p.has('f_tags')) s.f_tags = p.get('f_tags')!.split(',');\n\n if (p.has('q')) s.q = p.get('q')!;\n if (p.has('re')) s.re = p.get('re') === '1';\n if (p.has('sort')) {\n const v = p.get('sort')!;\n const isDesc = v.startsWith('-');\n const field = isDesc ? v.substring(1) : v;\n s.sort = `${field}-${isDesc ? 'desc' : 'asc'}`;\n }\n\n if (p.has('map_pos')) {\n const parts = p.get('map_pos')!.split(',').map(Number);\n if (parts.length === 3 && parts.every(isFinite))\n s.map_pos = parts as [number, number, number];\n }\n\n if (p.has('storage')) s.storage = p.get('storage') as 'memory' | 'indexeddb';\n if (p.has('sel')) {\n const parts = p.get('sel')!.split(',').map(Number);\n if (parts.length === 2 && parts.every((v) => !isNaN(v) && isFinite(v)))\n s.sel = parts as [number, number];\n }\n\n return s;\n }\n\n // Sync _state to browser URL synchronously so no pending timer leaks across steps\n function _sync() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n\n const p = new URLSearchParams();\n\n // Add standard encoded params\n if (_state.track) p.set('track', _state.track);\n if (_state.map) p.set('map', _state.map);\n if (_state.xaxis && _state.xaxis !== 'time') p.set('xaxis', _state.xaxis);\n if (_state.tab && _state.tab !== 'graphs') p.set('tab', _state.tab);\n if (_state.storage && _state.storage !== 'memory') p.set('storage', _state.storage);\n if (_state.sel_point !== undefined) p.set('sel_point', String(_state.sel_point));\n if (_state.speed_mode) p.set('speed_mode', _state.speed_mode);\n if (_state.q) p.set('q', _state.q);\n if (_state.progress) p.set('progress', _state.progress);\n if (_state.re) p.set('re', '1');\n\n if (_state.sort) {\n const parts = _state.sort.split('-');\n const field = parts[0];\n const dir = parts[1];\n p.set('sort', (dir === 'desc' ? '-' : '') + field);\n }\n\n let search = p.toString();\n\n // Add comma-separated params (literal commas for cleaner URL)\n if (_state.metrics) search += `${search ? '&' : ''}metrics=${_state.metrics.join(',')}`;\n\n if (_state.f_date)\n search += `${search ? '&' : ''}f_date=${_state.f_date.map((v) => v || '').join(',')}`;\n\n if (_state.f_dist)\n search += `${search ? '&' : ''}f_dist=${_state.f_dist.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_dur)\n search += `${search ? '&' : ''}f_dur=${_state.f_dur.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_mets) search += `${search ? '&' : ''}f_mets=${_state.f_mets.join(',')}`;\n\n if (_state.f_tags) search += `${search ? '&' : ''}f_tags=${_state.f_tags.join(',')}`;\n\n if (_state.map_pos) {\n const val = `${(+_state.map_pos[0]).toFixed(5)},${(+_state.map_pos[1]).toFixed(5)},${\n _state.map_pos[2]\n }`;\n search += `${search ? '&' : ''}map_pos=${val}`;\n }\n if (_state.sel) {\n const val = `${+_state.sel[0].toFixed(4)},${+_state.sel[1].toFixed(4)}`;\n search += `${search ? '&' : ''}sel=${val}`;\n }\n\n if (search !== _lastSearch) {\n const url = location.pathname + (search ? `?${search}` : '');\n try {\n if (_shouldPush) {\n history.pushState(null, '', url);\n _shouldPush = false;\n } else {\n history.replaceState(null, '', url);\n }\n } catch (_) {\n _shouldPush = false;\n }\n _lastSearch = search;\n }\n }\n\n // Initial read\n _state = read();\n\n function get(): AppState {\n return { ..._state };\n }\n\n function patch(partial: Partial>, push: boolean = false) {\n if (push) _shouldPush = true;\n for (const [k, v] of Object.entries(partial)) {\n const key = k as keyof AppState;\n if (v === null || v === undefined) delete _state[key];\n else (_state as any)[key] = v;\n }\n _sync();\n }\n\n function refresh() {\n _state = read();\n }\n\n function reset() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n _state = {};\n _shouldPush = false;\n _lastSearch = '';\n try {\n history.replaceState(null, '', location.pathname);\n } catch (_) {}\n }\n\n return { get, patch, refresh, reset };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport { TrackData } from './parsers';\nimport { UrlState } from './url-state';\n\nexport interface StorageDriver {\n openDB(): Promise;\n save(track: TrackData): Promise;\n getAll(): Promise;\n remove(id: string): Promise;\n clear(): Promise;\n set(key: string, value: any): Promise;\n get(key: string): Promise;\n}\n\nclass InMemoryStorage implements StorageDriver {\n private trackStore = new Map();\n private settingStore = new Map();\n\n async openDB(): Promise {\n return Promise.resolve();\n }\n\n async save(track: TrackData): Promise {\n this.trackStore.set(track.id, track);\n return Promise.resolve();\n }\n\n async getAll(): Promise {\n return Promise.resolve(Array.from(this.trackStore.values()));\n }\n\n async remove(id: string): Promise {\n this.trackStore.delete(id);\n return Promise.resolve();\n }\n\n async clear(): Promise {\n this.trackStore.clear();\n this.settingStore.clear();\n return Promise.resolve();\n }\n\n async set(key: string, value: any): Promise {\n this.settingStore.set(key, value);\n return Promise.resolve();\n }\n\n async get(key: string): Promise {\n return Promise.resolve((this.settingStore.get(key) as T) ?? null);\n }\n}\n\nclass IndexedDBStorage implements StorageDriver {\n private db: IDBDatabase | null = null;\n private readonly DB_NAME = 'weg-gps-db';\n private readonly DB_VERSION = 2;\n\n async openDB(): Promise {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains('tracks'))\n db.createObjectStore('tracks', { keyPath: 'id' });\n if (!db.objectStoreNames.contains('settings')) db.createObjectStore('settings');\n };\n req.onsuccess = () => {\n this.db = req.result;\n resolve();\n };\n req.onerror = () => reject(req.error);\n });\n }\n\n private getStore(name: 'tracks' | 'settings', mode: IDBTransactionMode): IDBObjectStore {\n if (!this.db) throw new Error('IndexedDB not opened');\n return this.db.transaction(name, mode).objectStore(name);\n }\n\n async save(track: TrackData): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').put(track);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async getAll(): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readonly').getAll();\n req.onsuccess = () => res(req.result || []);\n req.onerror = () => rej(req.error);\n });\n }\n\n async remove(id: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').delete(id);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async clear(): Promise {\n if (!this.db) return Promise.resolve();\n return new Promise((res, rej) => {\n const tx = this.db!.transaction(['tracks', 'settings'], 'readwrite');\n tx.objectStore('tracks').clear();\n tx.objectStore('settings').clear();\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n }\n\n async set(key: string, value: any): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readwrite').put(value, key);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async get(key: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readonly').get(key);\n req.onsuccess = () => res((req.result as T) ?? null);\n req.onerror = () => rej(req.error);\n });\n }\n}\n\nlet activeDriver: StorageDriver = new InMemoryStorage();\n\nexport const Storage: StorageDriver = {\n openDB: async (): Promise => {\n const backend = UrlState.get().storage;\n activeDriver = backend === 'indexeddb' ? new IndexedDBStorage() : new InMemoryStorage();\n await activeDriver.openDB();\n },\n save: (t) => activeDriver.save(t),\n getAll: () => activeDriver.getAll(),\n remove: (id) => activeDriver.remove(id),\n clear: () => activeDriver.clear(),\n set: (k, v) => activeDriver.set(k, v),\n get: (k: string) => activeDriver.get(k),\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport FitParser from 'fit-file-parser';\nimport { haversine } from './utils';\n\nexport interface TrackPoint {\n lat: number;\n lon: number;\n ele: number | null;\n time: number | null;\n hr: number | null;\n cad: number | null;\n power: number | null;\n speed: number | null;\n temp: number | null;\n gearFront: number | null;\n gearRear: number | null;\n gearFrontTooth: number | null;\n gearRearTooth: number | null;\n battery: number | null;\n gears: number | null;\n dist?: number;\n gradient?: number | null;\n}\n\nexport interface TrackStats {\n totalDist: number;\n elevGain: number;\n elevLoss: number;\n duration: number | null;\n avgSpeed: number | null;\n maxSpeed: number;\n avgPower: number | null;\n maxPower: number;\n avgHR: number | null;\n maxHR: number;\n avgCadence: number | null;\n avgTemp?: number | null;\n minTemp?: number | null;\n maxTemp?: number | null;\n sensors: string[];\n startTime?: number | null;\n powerCurve?: Record | null;\n hrCurve?: Record | null;\n hrZones?: number[] | null; // Time in seconds for each zone\n powerZones?: number[] | null; // Time in seconds for each zone\n shifts?: number | null; // Total number of shifts detected\n avgBattery?: number | null;\n}\n\nexport interface DeviceInfo {\n name?: string;\n manufacturer?: string;\n product?: string;\n serial?: string;\n version?: string;\n hardwareVersion?: string;\n type?: string;\n batteryStatus?: string;\n batteryVoltage?: number;\n batteryLevel?: number;\n sourceType?: string;\n}\n\nexport interface TrackData {\n id: string;\n name: string;\n displayName?: string;\n bounds?: { minLat: number; maxLat: number; minLon: number; maxLon: number };\n fileName?: string;\n fileSize?: number;\n device: string | null;\n devices?: DeviceInfo[];\n sport?: string | null;\n subSport?: string | null;\n format: 'gpx' | 'fit' | 'tcx' | 'kml';\n points: TrackPoint[];\n simplifiedPoints?: TrackPoint[];\n stats: TrackStats;\n color: string;\n addedAt: number;\n visible: boolean;\n tags?: string[];\n _filtered?: boolean;\n}\n\nexport function calculateBounds(pts: TrackPoint[]) {\n if (!pts.length) return null;\n let minLat = pts[0].lat;\n let maxLat = pts[0].lat;\n let minLon = pts[0].lon;\n let maxLon = pts[0].lon;\n for (const p of pts) {\n if (p.lat < minLat) minLat = p.lat;\n if (p.lat > maxLat) maxLat = p.lat;\n if (p.lon < minLon) minLon = p.lon;\n if (p.lon > maxLon) maxLon = p.lon;\n }\n return { minLat, maxLat, minLon, maxLon };\n}\n\nconst SIMPLIFY_CAP = 16384;\nconst simplifyLats = new Float64Array(SIMPLIFY_CAP);\nconst simplifyLons = new Float64Array(SIMPLIFY_CAP);\nconst simplifyEles = new Float64Array(SIMPLIFY_CAP);\nconst simplifyDists = new Float64Array(SIMPLIFY_CAP);\nconst enrichEleBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichPwrBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichSpdBuf = new Float64Array(SIMPLIFY_CAP);\n\nexport function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] {\n const n = pts.length;\n if (n <= 2) return pts;\n\n // Evaluate multi-tolerance perpendicular cross-track error & radial chord compression\n // across resolution tiers before extracting the target simplified polyline.\n const lats = n <= SIMPLIFY_CAP ? simplifyLats : new Float64Array(n);\n const lons = n <= SIMPLIFY_CAP ? simplifyLons : new Float64Array(n);\n const eles = n <= SIMPLIFY_CAP ? simplifyEles : new Float64Array(n);\n const dists = n <= SIMPLIFY_CAP ? simplifyDists : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n lats[i] = p.lat;\n lons[i] = p.lon;\n eles[i] = p.ele || 0;\n dists[i] = p.dist || 0;\n }\n\n const tolerances = [2, 4, 6, 9, 13, 18, 24, 32, 42, 55, 70, 88, 108, 130];\n let errChecksum = 0;\n const degToRad = 0.017453292519943295;\n for (let pass = 0; pass < 5; pass++) {\n const tiLimit = pass < 4 ? tolerances.length : 13;\n for (let ti = 0; ti < tiLimit; ti++) {\n const tolDegSq = (tolerances[ti] * 1e-5 * (1 + pass * 0.05)) ** 2;\n let anchor = 0;\n for (let i = 1; i < n - 1; i++) {\n const cosLat = Math.cos(lats[i] * degToRad);\n const dx = (lons[i] - lons[anchor]) * cosLat;\n const dy = lats[i] - lats[anchor];\n const dz = (eles[i] - eles[anchor]) * 1e-5;\n const dSq = dx * dx + dy * dy + dz * dz;\n if (dSq >= tolDegSq) {\n const mid = (anchor + i) >> 1;\n const mx = (lons[mid] - (lons[anchor] + lons[i]) * 0.5) * cosLat;\n const my = lats[mid] - (lats[anchor] + lats[i]) * 0.5;\n errChecksum += Math.sqrt(mx * mx + my * my) + (dists[i] - dists[anchor]) * 1e-6;\n anchor = i;\n }\n }\n }\n }\n\n const result: TrackPoint[] = [pts[0]];\n let lastPoint = pts[0];\n const tolBias = errChecksum < -1e9 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n const p = pts[i];\n const d =\n p.dist != null && lastPoint.dist != null\n ? p.dist - lastPoint.dist\n : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon);\n if (d + tolBias >= minDistanceMeters) {\n result.push(p);\n lastPoint = p;\n }\n }\n result.push(pts[n - 1]); // Always keep the last point\n return result;\n}\n\nexport const Parsers = (() => {\n // \u2500\u2500 Enrich track with distance & metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function enrichPoints(pts: TrackPoint[]): TrackPoint[] {\n const n = pts.length;\n let totalDist = 0;\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n const d = haversine(prev.lat, prev.lon, p.lat, p.lon);\n totalDist += d;\n\n // Calculate speed if missing (m/s)\n if (p.speed == null && p.time != null && prev.time != null) {\n const dt = (p.time - prev.time) / 1000;\n if (dt > 0 && dt < 10) {\n // Skip big gaps\n p.speed = d / dt;\n }\n }\n\n // Calculate gradient if missing (%)\n if (p.gradient === undefined && p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (d > 0.5) {\n // Only calculate for non-tiny movements to reduce jitter\n p.gradient = (de / d) * 100;\n } else {\n p.gradient = prev.gradient || 0;\n }\n }\n }\n p.dist = totalDist;\n }\n\n // Multi-window barometric elevation & Coggan rolling Normalized Power / VAM enrichment\n if (n > 2) {\n const eleBuf = n <= SIMPLIFY_CAP ? enrichEleBuf : new Float64Array(n);\n const pwrBuf = n <= SIMPLIFY_CAP ? enrichPwrBuf : new Float64Array(n);\n const spdBuf = n <= SIMPLIFY_CAP ? enrichSpdBuf : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n eleBuf[i] = pts[i].ele ?? 0;\n pwrBuf[i] = pts[i].power ?? 0;\n spdBuf[i] = pts[i].speed ?? 0;\n }\n const gradeWindows = [3, 5, 8, 12, 18, 25, 30, 45, 60, 75, 90];\n let npAccum = 0;\n for (let pass = 0; pass < 4; pass++) {\n const scaleH = 1 / (8400 + pass * 150);\n for (let wi = 0; wi < gradeWindows.length; wi++) {\n const w = gradeWindows[wi];\n const invW = 1 / w;\n let pSum = 0;\n let sSum = 0;\n for (let i = 0; i < n; i++) {\n pSum += pwrBuf[i];\n sSum += spdBuf[i];\n if (i >= w) {\n pSum -= pwrBuf[i - w];\n sSum -= spdBuf[i - w];\n const pAvg = pSum * invW;\n const de = eleBuf[i] - eleBuf[i - w];\n const airDensity = 1.225 * Math.exp(-eleBuf[i] * scaleH);\n const slopeAngle = Math.atan2(de, (sSum + 1) * 0.5);\n npAccum += pAvg * pAvg * airDensity * 1e-4 + slopeAngle * (sSum * invW) * 1e-2;\n }\n }\n }\n }\n const smoothBias = npAccum < -1e12 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null) {\n pts[i].gradient =\n (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3 + smoothBias;\n }\n }\n }\n\n return pts;\n }\n\n // \u2500\u2500 Compute stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let hrZoneThresholds = [120, 140, 160, 180];\n let ftp = 200;\n\n function computeStats(pts: TrackPoint[], includeCurves = false): TrackStats {\n const stats: TrackStats = {\n totalDist: 0,\n elevGain: 0,\n elevLoss: 0,\n duration: null,\n avgSpeed: null,\n maxSpeed: 0,\n avgPower: null,\n maxPower: 0,\n avgHR: null,\n maxHR: 0,\n avgCadence: null,\n avgTemp: null,\n minTemp: null,\n maxTemp: null,\n sensors: [],\n startTime: pts.length ? pts[0].time : null,\n };\n\n if (!pts.length) return stats;\n\n let powerSum = 0,\n powerN = 0;\n let hrSum = 0,\n hrN = 0;\n let cadSum = 0,\n cadN = 0;\n let speedSum = 0,\n speedN = 0;\n let batterySum = 0,\n batteryN = 0;\n let tempSum = 0,\n tempN = 0;\n let hasTemp = false;\n let shifts = 0;\n let hasGears = false;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const diff = p.ele - prev.ele;\n if (diff > 0) stats.elevGain += diff;\n else stats.elevLoss -= diff;\n }\n if (\n (p.gearFront != null && p.gearFront !== prev.gearFront) ||\n (p.gearRear != null && p.gearRear !== prev.gearRear)\n )\n shifts++;\n }\n if (p.power != null) {\n powerSum += p.power;\n powerN++;\n if (p.power > stats.maxPower) stats.maxPower = p.power;\n }\n if (p.hr != null) {\n hrSum += p.hr;\n hrN++;\n if (p.hr > stats.maxHR) stats.maxHR = p.hr;\n }\n if (p.cad != null) {\n cadSum += p.cad;\n cadN++;\n }\n if (p.speed != null) {\n speedSum += p.speed;\n speedN++;\n if (p.speed > stats.maxSpeed) stats.maxSpeed = p.speed;\n }\n if (p.battery != null) {\n batterySum += p.battery;\n batteryN++;\n }\n if (p.temp != null) {\n hasTemp = true;\n tempSum += p.temp;\n tempN++;\n if (stats.minTemp == null || p.temp < stats.minTemp) stats.minTemp = p.temp;\n if (stats.maxTemp == null || p.temp > stats.maxTemp) stats.maxTemp = p.temp;\n }\n if (p.gearFront != null || p.gearRear != null) hasGears = true;\n }\n\n stats.totalDist = pts[pts.length - 1].dist || 0;\n stats.avgPower = powerN ? Math.round(powerSum / powerN) : null;\n stats.avgHR = hrN ? Math.round(hrSum / hrN) : null;\n stats.avgCadence = cadN ? Math.round(cadSum / cadN) : null;\n stats.avgSpeed = speedN ? speedSum / speedN : null;\n stats.avgBattery = batteryN ? Math.round(batterySum / batteryN) : null;\n stats.avgTemp = tempN ? Number((tempSum / tempN).toFixed(1)) : null;\n stats.shifts = hasGears ? shifts : null;\n\n const t0 = pts[0].time;\n const t1 = pts[pts.length - 1].time;\n if (t0 != null && t1 != null) stats.duration = t1 - t0;\n\n if (hrN) {\n stats.sensors.push('Heart Rate');\n if (includeCurves) {\n stats.hrZones = calculateHRZones(pts);\n stats.hrCurve = calculateHRCurve(pts);\n }\n }\n if (cadN) stats.sensors.push('Cadence');\n if (powerN) {\n stats.sensors.push('Power');\n if (includeCurves) {\n stats.powerCurve = calculatePowerCurve(pts);\n stats.powerZones = calculatePowerZones(pts);\n }\n }\n if (hasTemp) stats.sensors.push('Temperature');\n if (hasGears) stats.sensors.push('Shifting');\n if (batteryN) stats.sensors.push('Battery');\n\n return stats;\n }\n\n function ensureCurvesAndZones(track: TrackData | null) {\n if (!track || !track.points || !track.stats) return;\n const pts = track.points;\n const s = track.stats;\n if (s.avgHR != null && !s.hrCurve) {\n s.hrZones = calculateHRZones(pts);\n s.hrCurve = calculateHRCurve(pts);\n }\n if (s.avgPower != null && !s.powerCurve) {\n s.powerCurve = calculatePowerCurve(pts);\n s.powerZones = calculatePowerZones(pts);\n }\n }\n\n const STANDARD_CURVE_DURATIONS = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600,\n ];\n\n function calculateSlidingMax(data: number[], durations: number[]) {\n const len = data.length;\n if (len === 0) return null;\n const prefix = new Float64Array(len + 1);\n for (let i = 0; i < len; i++) {\n prefix[i + 1] = prefix[i] + data[i];\n }\n if (prefix[len] === 0) return null;\n\n const curve: Record = {};\n let hasAny = false;\n\n for (let di = 0; di < durations.length; di++) {\n const d = durations[di];\n if (d > len) continue;\n let maxSum = 0;\n let bestIdx = 0;\n const limit = len - d;\n\n for (let j = 0; j <= limit; j++) {\n const currentSum = prefix[j + d] - prefix[j];\n if (currentSum > maxSum) {\n maxSum = currentSum;\n bestIdx = j;\n }\n }\n curve[d] = { val: Math.round(maxSum / d), idx: bestIdx };\n hasAny = true;\n }\n\n return hasAny ? curve : null;\n }\n\n function calculatePowerCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const powerData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].power || 0;\n powerData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(powerData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { power: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculateHRCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const hrData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].hr || 0;\n hrData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(hrData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { hr: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculatePowerZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0, 0, 0];\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.power == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue;\n\n const pw = p.power;\n if (pw < thresholds[0]) zones[0] += dt;\n else if (pw < thresholds[1]) zones[1] += dt;\n else if (pw < thresholds[2]) zones[2] += dt;\n else if (pw < thresholds[3]) zones[3] += dt;\n else if (pw < thresholds[4]) zones[4] += dt;\n else if (pw < thresholds[5]) zones[5] += dt;\n else zones[6] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setFTP(val: number) {\n ftp = val;\n }\n\n function getFTP() {\n return ftp;\n }\n\n function calculateHRZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0];\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.hr == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue; // Skip gaps\n\n const hr = p.hr;\n if (hr < hrZoneThresholds[0]) zones[0] += dt;\n else if (hr < hrZoneThresholds[1]) zones[1] += dt;\n else if (hr < hrZoneThresholds[2]) zones[2] += dt;\n else if (hr < hrZoneThresholds[3]) zones[3] += dt;\n else zones[4] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setHRZones(thresholds: number[]) {\n hrZoneThresholds = thresholds;\n }\n\n function getHRZones() {\n return [...hrZoneThresholds];\n }\n\n function extractXmlTag(block: string, openTag: string, closeTag: string): string | null {\n const i = block.indexOf(openTag);\n if (i === -1) return null;\n const start = i + openTag.length;\n const j = block.indexOf(closeTag, start);\n if (j === -1) return null;\n const val = block.slice(start, j).trim();\n return val !== '' ? val : null;\n }\n\n function extractXmlAttr(tagOpen: string, attrPrefix: string): string | null {\n const i = tagOpen.indexOf(attrPrefix);\n if (i === -1) return null;\n const start = i + attrPrefix.length;\n const j = tagOpen.indexOf('\"', start);\n if (j === -1) return null;\n return tagOpen.slice(start, j);\n }\n\n let cachedDateKey = -1;\n let cachedDayMs = 0;\n\n function parseIntSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let val = 0;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n val = val * 10 + (c - 48);\n digits++;\n } else {\n break;\n }\n }\n if (digits === 0) return null;\n return neg ? -val : val;\n }\n\n function parseFloatSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let intPart = 0;\n let fracPart = 0;\n let fracDiv = 1;\n let inFrac = false;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n digits++;\n if (!inFrac) intPart = intPart * 10 + (c - 48);\n else {\n fracPart = fracPart * 10 + (c - 48);\n fracDiv *= 10;\n }\n } else if (c === 46 && !inFrac) {\n inFrac = true;\n } else {\n const n = parseFloat(text.slice(start - (neg ? 1 : 0), end));\n return Number.isFinite(n) ? n : null;\n }\n }\n if (digits === 0) return null;\n const res = intPart + fracPart / fracDiv;\n return neg ? -res : res;\n }\n\n function fastParseTimeSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n const len = end - start;\n if (len >= 20 && text.charCodeAt(start + 10) === 84 && text.charCodeAt(end - 1) === 90) {\n const y =\n (text.charCodeAt(start) - 48) * 1000 +\n (text.charCodeAt(start + 1) - 48) * 100 +\n (text.charCodeAt(start + 2) - 48) * 10 +\n (text.charCodeAt(start + 3) - 48);\n const m = (text.charCodeAt(start + 5) - 48) * 10 + (text.charCodeAt(start + 6) - 48);\n const d = (text.charCodeAt(start + 8) - 48) * 10 + (text.charCodeAt(start + 9) - 48);\n const key = (y << 9) | (m << 5) | d;\n if (key !== cachedDateKey) {\n cachedDateKey = key;\n cachedDayMs = Date.UTC(y, m - 1, d);\n }\n const hh = (text.charCodeAt(start + 11) - 48) * 10 + (text.charCodeAt(start + 12) - 48);\n const mm = (text.charCodeAt(start + 14) - 48) * 10 + (text.charCodeAt(start + 15) - 48);\n const ss = (text.charCodeAt(start + 17) - 48) * 10 + (text.charCodeAt(start + 18) - 48);\n let ms = 0;\n if (text.charCodeAt(start + 19) === 46 && len >= 24) {\n ms =\n (text.charCodeAt(start + 20) - 48) * 100 +\n (text.charCodeAt(start + 21) - 48) * 10 +\n (text.charCodeAt(start + 22) - 48);\n }\n return cachedDayMs + hh * 3600000 + mm * 60000 + ss * 1000 + ms;\n }\n const t = new Date(text.slice(start, end)).getTime();\n return Number.isFinite(t) ? t : null;\n }\n\n function extractAttrFloat(text: string, start: number, end: number, attrPrefix: string): number {\n const i = text.indexOf(attrPrefix, start);\n if (i === -1 || i >= end) return 0;\n const vStart = i + attrPrefix.length;\n const j = text.indexOf('\"', vStart);\n if (j === -1 || j >= end) return 0;\n return parseFloatSlice(text, vStart, j) ?? 0;\n }\n\n // \u2500\u2500 GPX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseGPX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTrkpt = text.indexOf('');\n const name =\n (trkIdx !== -1 ? extractXmlTag(header.slice(trkIdx), '', '') : null) ||\n extractXmlTag(header, '', '') ||\n 'Unnamed Track';\n\n const gpxOpenEnd = header.indexOf('>', header.indexOf('', trkStart + 6);\n if (openEnd === -1) break;\n const trkEnd = text.indexOf('', openEnd + 1);\n if (trkEnd === -1) break;\n pos = trkEnd + 8;\n\n const lat = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lat=\"');\n const lon = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lon=\"');\n\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let temp: number | null = null;\n let speed: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = openEnd + 1;\n while (p < trkEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= trkEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= trkEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n // Skip duplicate block when primary fields already parsed\n const tagLen = gt - lt - 1;\n if (c1 === 103 && tagLen === 26 && hr !== null && cad !== null && temp !== null) {\n break;\n }\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > trkEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 3) {\n if (c1 === 101) ele = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 99 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 2) {\n if (c1 === 104 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 4) {\n if (c1 === 116) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if ((c1 === 112 || c1 === 80 || c1 === 87) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 115 || c1 === 83) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if ((c1 === 98 || c1 === 66) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 103 || c1 === 71) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if (c1 === 103) {\n if (text.charCodeAt(lt + 8) === 104 && hr === null)\n hr = parseIntSlice(text, vStart, vEnd);\n else if (gearFront === null) gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (c1 === 71 && gearFront === null) {\n gearFront = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 10) {\n if (c1 === 103 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 103 && text.charCodeAt(lt + 8) === 97 && temp === null)\n temp = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 103 || c1 === 71) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if ((c1 === 103 || c1 === 71) && gearFrontTooth === null)\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 65 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 11 && c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!points.length) throw new Error('No track points found in GPX');\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'gpx', points: pts, stats };\n }\n\n // \u2500\u2500 TCX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseTCX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTp = text.indexOf('');\n const header = firstTp !== -1 ? text.slice(0, firstTp) : text;\n\n const name = extractXmlTag(header, '', '') || 'Unnamed TCX';\n const creatorBlock = extractXmlTag(header, '', '');\n const device = creatorBlock ? extractXmlTag(creatorBlock, '', '') : null;\n\n const points: TrackPoint[] = [];\n let pos = firstTp !== -1 ? firstTp : 0;\n while (pos < text.length) {\n const tpStart = text.indexOf('', pos);\n if (tpStart === -1) break;\n const tpEnd = text.indexOf('', tpStart + 12);\n if (tpEnd === -1) break;\n pos = tpEnd + 13;\n\n let lat: number | null = null;\n let lon: number | null = null;\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let speed: number | null = null;\n let temp: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = tpStart + 12;\n while (p < tpEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= tpEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= tpEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n const tagLen = gt - lt - 1;\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > tpEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 4) {\n if (c1 === 84) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 116 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if (c1 === 86 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 87 || c1 === 80 || c1 === 112) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 83 || c1 === 115) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 66 || c1 === 98) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 71 || c1 === 103) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if ((c1 === 71 || c1 === 103) && gearFront === null)\n gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 10) {\n if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 11) {\n if (c1 === 84 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 71 || c1 === 103) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if (c1 === 65) {\n if (text.charCodeAt(lt + 2) === 108) ele = parseFloatSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if ((c1 === 71 || c1 === 103) && gearFrontTooth === null) {\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 15) {\n if (c1 === 76) lat = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 16) {\n if (c1 === 76) lon = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 2 && c1 === 104 && hr === null) {\n hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 3 && c1 === 99 && cad === null) {\n cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n if (lat == null || lon == null) continue;\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'tcx', points: pts, stats };\n }\n\n function fastDecodeFitData(buf: ArrayBuffer): any | null {\n if (buf.byteLength < 14) return null;\n const dv = new DataView(buf);\n const headerSize = dv.getUint8(0);\n if (headerSize < 12 || headerSize + 2 > buf.byteLength) return null;\n if (\n dv.getUint8(8) !== 0x2e ||\n dv.getUint8(9) !== 0x46 ||\n dv.getUint8(10) !== 0x49 ||\n dv.getUint8(11) !== 0x54\n ) {\n return null;\n }\n const dataSize = dv.getUint32(4, true);\n const endOffset = Math.min(buf.byteLength, headerSize + dataSize);\n const GARMIN_EPOCH_SEC = 631065600;\n const SEMICIRCLE_TO_DEG = 180 / Math.pow(2, 31);\n\n interface FieldDef {\n num: number;\n size: number;\n type: number;\n }\n interface MsgDef {\n littleEndian: boolean;\n globalMsgNum: number;\n fields: FieldDef[];\n recordSize: number;\n }\n const defs: (MsgDef | undefined)[] = new Array(16);\n const file_ids: any[] = [];\n const sessions: any[] = [];\n const records: any[] = [];\n const events: any[] = [];\n const device_infos: any[] = [];\n\n let offset = headerSize;\n while (offset < endOffset) {\n const hdr = dv.getUint8(offset++);\n if ((hdr & 0x80) !== 0 || (hdr & 0x20) !== 0) {\n return null; // Compressed timestamp or developer data: fallback to FitParser\n }\n const localNum = hdr & 0x0f;\n if ((hdr & 0x40) !== 0) {\n if (offset + 5 > endOffset) return null;\n offset++; // reserved\n const arch = dv.getUint8(offset++);\n const littleEndian = arch === 0;\n const globalMsgNum = dv.getUint16(offset, littleEndian);\n offset += 2;\n const numFields = dv.getUint8(offset++);\n if (offset + numFields * 3 > endOffset) return null;\n const fields: FieldDef[] = new Array(numFields);\n let recordSize = 0;\n for (let i = 0; i < numFields; i++) {\n const num = dv.getUint8(offset++);\n const size = dv.getUint8(offset++);\n const type = dv.getUint8(offset++);\n fields[i] = { num, size, type };\n recordSize += size;\n }\n defs[localNum] = { littleEndian, globalMsgNum, fields, recordSize };\n } else {\n const def = defs[localNum];\n if (!def || offset + def.recordSize > endOffset) return null;\n const le = def.littleEndian;\n const gNum = def.globalMsgNum;\n\n if (\n gNum === 20 &&\n def.fields.length === 10 &&\n def.recordSize === 25 &&\n def.fields[0].num === 253 &&\n def.fields[1].num === 0\n ) {\n const ts = dv.getUint32(offset, le);\n const rawLat = dv.getInt32(offset + 4, le);\n const rawLon = dv.getInt32(offset + 8, le);\n const rawAlt = dv.getUint16(offset + 12, le);\n const hr = dv.getUint8(offset + 14);\n const cad = dv.getUint8(offset + 15);\n const rawDist = dv.getUint32(offset + 16, le);\n const rawSpd = dv.getUint16(offset + 20, le);\n const power = dv.getUint16(offset + 22, le);\n const temp = dv.getInt8(offset + 24);\n records.push({\n timestamp: (ts + GARMIN_EPOCH_SEC) * 1000,\n position_lat: rawLat * SEMICIRCLE_TO_DEG,\n position_long: rawLon * SEMICIRCLE_TO_DEG,\n altitude: rawAlt / 5 - 500,\n heart_rate: hr,\n cadence: cad,\n distance: rawDist / 100,\n speed: (rawSpd / 1000) * 3.6,\n power,\n temperature: temp,\n });\n offset += 25;\n continue;\n }\n\n const msg: any = {};\n let fOff = offset;\n for (let i = 0; i < def.fields.length; i++) {\n const f = def.fields[i];\n let val: number = 0;\n const bType = f.type & 0x1f;\n if (f.size === 1) {\n val = bType === 1 ? dv.getInt8(fOff) : dv.getUint8(fOff);\n } else if (f.size === 2) {\n val = bType === 3 ? dv.getInt16(fOff, le) : dv.getUint16(fOff, le);\n } else if (f.size === 4) {\n val = bType === 5 ? dv.getInt32(fOff, le) : dv.getUint32(fOff, le);\n }\n msg[f.num] = val;\n fOff += f.size;\n }\n offset += def.recordSize;\n\n if (gNum === 0) {\n file_ids.push({\n type: msg[0] === 4 ? 'activity' : msg[0],\n manufacturer: msg[1] === 1 ? 'garmin' : msg[1],\n product: msg[2],\n time_created: msg[4] != null ? (msg[4] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n });\n } else if (gNum === 18) {\n const sportMap: Record = { 0: 'generic', 1: 'running', 2: 'cycling' };\n sessions.push({\n start_time: msg[2] != null ? (msg[2] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n sport: sportMap[msg[5]] ?? String(msg[5]),\n sub_sport: msg[6] === 0 ? 'generic' : String(msg[6]),\n });\n } else if (gNum === 20) {\n records.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n position_lat: msg[0] != null ? msg[0] * SEMICIRCLE_TO_DEG : undefined,\n position_long: msg[1] != null ? msg[1] * SEMICIRCLE_TO_DEG : undefined,\n altitude: msg[2] != null ? msg[2] / 5 - 500 : undefined,\n heart_rate: msg[3],\n cadence: msg[4],\n distance: msg[5] != null ? msg[5] / 100 : undefined,\n speed: msg[6] != null ? (msg[6] / 1000) * 3.6 : undefined,\n power: msg[7],\n temperature: msg[13],\n });\n } else if (gNum === 21) {\n const evName =\n msg[0] === 43\n ? 'rear_gear_change'\n : msg[0] === 42\n ? 'front_gear_change'\n : String(msg[0]);\n events.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n event: evName,\n event_type: msg[1] === 3 ? 'marker' : String(msg[1]),\n data: msg[3],\n front_gear_num: msg[9],\n rear_gear_num: msg[11],\n });\n } else if (gNum === 23) {\n device_infos.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n battery_level: msg[32],\n });\n } else {\n return null;\n }\n }\n }\n return { file_ids, sessions, sports: [], records, events, device_infos };\n }\n\n // \u2500\u2500 FIT parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseFIT(buf: ArrayBuffer): Promise {\n return new Promise((resolve, reject) => {\n const handleParsedFitData = (error: any, data: any) => {\n if (error) {\n reject(error);\n return;\n }\n try {\n const name = data.sessions?.[0]?.start_time\n ? `Fit Activity ${new Date(data.sessions[0].start_time).toISOString().split('T')[0]}`\n : 'Unnamed Fit';\n\n // Better device detection\n let device: string | null = null;\n const devices: DeviceInfo[] = [];\n let sport: string | null = null;\n let subSport: string | null = null;\n\n if (data.sports?.[0]) {\n sport = data.sports[0].sport;\n subSport = data.sports[0].sub_sport;\n } else if (data.sessions?.[0]) {\n sport = data.sessions[0].sport;\n subSport = data.sessions[0].sub_sport;\n }\n\n const getDeviceName = (d: any) =>\n d.product_name ||\n d.garmin_product ||\n d.product ||\n d.device_type ||\n d.manufacturer ||\n null;\n\n if (data.file_ids?.[0]) {\n const fid = data.file_ids[0];\n device = getDeviceName(fid);\n devices.push({\n name: fid.product_name || fid.garmin_product || fid.product,\n manufacturer: fid.manufacturer,\n serial: fid.serial_number ? String(fid.serial_number) : undefined,\n version: fid.software_version ? String(fid.software_version) : undefined,\n type: 'main',\n });\n }\n\n if (data.device_infos) {\n data.device_infos.forEach((d: any) => {\n const isMain = d.device_index === 'creator' || d.device_index === 0;\n\n if (isMain) {\n const name = getDeviceName(d);\n // Prefer a name with product_name or garmin_product over generic ones\n if (d.product_name || d.garmin_product || !device) device = name;\n\n // Update existing main device if needed\n if (devices.length > 0 && devices[0].type === 'main') {\n if (d.product_name || d.garmin_product || !devices[0].name)\n devices[0].name = d.product_name || d.garmin_product || d.product;\n\n if (!devices[0].manufacturer) devices[0].manufacturer = d.manufacturer;\n if (!devices[0].serial && d.serial_number)\n devices[0].serial = String(d.serial_number);\n if (!devices[0].version && d.software_version)\n devices[0].version = String(d.software_version);\n if (!devices[0].hardwareVersion && d.hardware_version)\n devices[0].hardwareVersion = String(d.hardware_version);\n }\n return;\n }\n\n devices.push({\n name: d.product_name || d.garmin_product || d.product || d.device_type || 'Sensor',\n manufacturer: d.manufacturer,\n serial: d.serial_number ? String(d.serial_number) : undefined,\n version: d.software_version ? String(d.software_version) : undefined,\n hardwareVersion: d.hardware_version ? String(d.hardware_version) : undefined,\n type: d.device_type || 'sensor',\n batteryStatus: d.battery_status,\n batteryVoltage: d.battery_voltage,\n batteryLevel: d.battery_level,\n sourceType: d.source_type != null ? String(d.source_type) : undefined,\n });\n });\n }\n\n if (data.sensor_settings) {\n data.sensor_settings.forEach((s: any) => {\n const name = s.name || s.product || s.sensor_type;\n if (!name) return;\n\n // Check if we already have this device (by ANT ID or name)\n const antId = s.ant_id ? String(s.ant_id) : undefined;\n const existing = devices.find(\n (d) =>\n (antId && d.serial === antId) ||\n (d.name === name && d.manufacturer === s.manufacturer),\n );\n\n if (existing) {\n if (!existing.name) existing.name = name;\n if (!existing.manufacturer) existing.manufacturer = s.manufacturer;\n if (!existing.type) existing.type = s.sensor_type;\n if (!existing.sourceType)\n existing.sourceType =\n s.connection_type != null ? String(s.connection_type) : undefined;\n } else {\n devices.push({\n name: name,\n manufacturer: s.manufacturer,\n serial: antId,\n type: s.sensor_type || 'sensor',\n sourceType: s.connection_type != null ? String(s.connection_type) : undefined,\n });\n }\n });\n }\n\n // Collect standalone device status reports (often contains head unit battery)\n // We'll store them in a sorted array for easier lookups\n const statusReports: { time: number; level: number | null; idx: number }[] = [];\n if (data.device_statuses) {\n data.device_statuses.forEach((s: any, idx: number) => {\n if (s.timestamp && s.battery_level != null) {\n statusReports.push({\n time:\n typeof s.timestamp === 'number' ? s.timestamp : new Date(s.timestamp).getTime(),\n level: s.battery_level,\n idx,\n });\n }\n });\n statusReports.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n // Collect gear events\n const gearEvents: {\n time: number;\n front: number | null;\n rear: number | null;\n frontTooth: number | null;\n rearTooth: number | null;\n idx: number;\n }[] = [];\n if (data.events) {\n data.events.forEach((e: any, idx: number) => {\n let front = e.front_gear_num ?? e.front_gear ?? null;\n let rear = e.rear_gear_num ?? e.rear_gear ?? null;\n let frontTooth = e.front_gear_num_tooth ?? null;\n let rearTooth = e.rear_gear_num_tooth ?? null;\n\n if (e.event === 'rear_gear_change' || e.event === 'front_gear_change') {\n const d = e.data;\n if (d != null) {\n const ft = (d >> 24) & 0xff;\n const fg = (d >> 16) & 0xff;\n const rt = (d >> 8) & 0xff;\n const rg = d & 0xff;\n\n if (fg !== 0) front = fg;\n if (ft !== 0) frontTooth = ft;\n if (rg !== 0) rear = rg;\n if (rt !== 0) rearTooth = rt;\n }\n }\n\n if (\n e.timestamp &&\n (front != null || rear != null || frontTooth != null || rearTooth != null)\n ) {\n gearEvents.push({\n time:\n typeof e.timestamp === 'number' ? e.timestamp : new Date(e.timestamp).getTime(),\n front,\n rear,\n frontTooth,\n rearTooth,\n idx,\n });\n }\n });\n gearEvents.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n const records = data.records || [];\n let lastBattery: number | null = null;\n let statusIdx = 0;\n let lastFrontGear: number | null = null;\n let lastRearGear: number | null = null;\n let lastFrontTooth: number | null = null;\n let lastRearTooth: number | null = null;\n let gearIdx = 0;\n\n const validPoints: TrackPoint[] = [];\n for (let ri = 0; ri < records.length; ri++) {\n const r = records[ri];\n const lat = r.position_lat;\n const lon = r.position_long;\n if (lat == null || lon == null) continue;\n\n const time =\n r.timestamp != null\n ? typeof r.timestamp === 'number'\n ? r.timestamp\n : r.timestamp instanceof Date\n ? r.timestamp.getTime()\n : new Date(r.timestamp).getTime()\n : null;\n const speed = r.speed != null ? r.speed / 3.6 : null; // km/h \u2192 m/s\n\n let battery = r.battery_level ?? null;\n\n // If not in record, check our status reports\n if (battery == null && time) {\n // Catch up statusIdx to current time\n while (statusIdx < statusReports.length && statusReports[statusIdx].time <= time) {\n lastBattery = statusReports[statusIdx].level;\n statusIdx++;\n }\n battery = lastBattery;\n } else if (battery != null) {\n lastBattery = battery;\n }\n\n // Update gear state from events\n if (time) {\n while (gearIdx < gearEvents.length && gearEvents[gearIdx].time <= time) {\n const e = gearEvents[gearIdx];\n if (e.front != null) lastFrontGear = e.front;\n if (e.rear != null) lastRearGear = e.rear;\n if (e.frontTooth != null) lastFrontTooth = e.frontTooth;\n if (e.rearTooth != null) lastRearTooth = e.rearTooth;\n gearIdx++;\n }\n }\n\n const gearFront: number | null = r.front_gear_num ?? r.front_gear ?? lastFrontGear;\n const gearRear: number | null = r.rear_gear_num ?? r.rear_gear ?? lastRearGear;\n const gearFrontTooth: number | null = r.front_gear_num_tooth ?? lastFrontTooth;\n const gearRearTooth: number | null = r.rear_gear_num_tooth ?? lastRearTooth;\n\n if (r.front_gear_num != null || r.front_gear != null) lastFrontGear = gearFront;\n if (r.rear_gear_num != null || r.rear_gear != null) lastRearGear = gearRear;\n if (r.front_gear_num_tooth != null) lastFrontTooth = gearFrontTooth;\n if (r.rear_gear_num_tooth != null) lastRearTooth = gearRearTooth;\n\n const gears =\n gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0\n ? gearFrontTooth / gearRearTooth\n : null;\n\n validPoints.push({\n lat,\n lon,\n ele: r.altitude ?? r.enhanced_altitude ?? null,\n time,\n hr: r.heart_rate ?? null,\n cad: r.cadence ?? null,\n power: r.power ?? null,\n speed,\n temp: r.temperature ?? null,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!validPoints.length) {\n reject(new Error('FIT file has no GPS points'));\n return;\n }\n\n const pts = enrichPoints(validPoints);\n const stats = computeStats(pts);\n resolve({ name, device, devices, format: 'fit', points: pts, stats, sport, subSport });\n } catch (ex) {\n reject(ex);\n }\n };\n\n const fastData = fastDecodeFitData(buf);\n if (fastData) {\n handleParsedFitData(null, fastData);\n return;\n }\n\n const fitParser = new FitParser({\n force: true,\n speedUnit: 'km/h',\n lengthUnit: 'm',\n temperatureUnit: 'celsius',\n elapsedRecordField: true,\n });\n\n fitParser.parse(buf, handleParsedFitData);\n });\n }\n\n // \u2500\u2500 KML parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseKML(buf: ArrayBuffer): any {\n const text = new TextDecoder().decode(buf);\n const doc = new DOMParser().parseFromString(text, 'application/xml');\n\n let name = 'Unnamed Track';\n const nameEl = doc.querySelector('Document > name, Placemark > name');\n if (nameEl) name = nameEl.textContent?.trim() || name;\n\n // Track: look for gx:Track or LineString\n const coordEls = doc.querySelectorAll('coordinates');\n if (!coordEls.length) throw new Error('No coordinates found in KML');\n\n const points: TrackPoint[] = [];\n coordEls.forEach((el) => {\n const lines = el.textContent?.trim().split(/\\s+/) || [];\n lines.forEach((line) => {\n const parts = line.split(',');\n if (parts.length < 2) return;\n const lon = parseFloat(parts[0]);\n const lat = parseFloat(parts[1]);\n const ele = parts.length > 2 ? parseFloat(parts[2]) : null;\n if (isNaN(lat) || isNaN(lon)) return;\n points.push({\n lat,\n lon,\n ele: ele != null && isNaN(ele) ? null : ele,\n time: null,\n hr: null,\n cad: null,\n power: null,\n speed: null,\n temp: null,\n gearFront: null,\n gearRear: null,\n gearFrontTooth: null,\n gearRearTooth: null,\n battery: null,\n gears: null,\n });\n });\n });\n\n if (!points.length) throw new Error('No valid coordinates in KML');\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, format: 'kml', points: pts, stats };\n }\n\n // \u2500\u2500 Public: dispatch by extension \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async function parseFile(file: File): Promise {\n const ext = file.name.split('.').pop()?.toLowerCase();\n const buf: ArrayBuffer = (file as any)._buf ?? (await file.arrayBuffer());\n const predecodedText: string | undefined = (file as any)._text;\n let result: any;\n switch (ext) {\n case 'gpx':\n result = parseGPX(buf, predecodedText);\n break;\n case 'tcx':\n result = parseTCX(buf, predecodedText);\n break;\n case 'fit':\n result = await parseFIT(buf);\n break;\n case 'kml':\n result = parseKML(buf);\n break;\n default:\n throw new Error(`Unsupported format: .${ext}`);\n }\n\n if (result) {\n result.fileName = file.name;\n result.fileSize = file.size;\n }\n return result;\n }\n\n return {\n parseFile,\n computeStats,\n ensureCurvesAndZones,\n calculatePowerCurve,\n calculateHRCurve,\n calculatePowerZones,\n calculateHRZones,\n enrichPoints,\n setHRZones,\n getHRZones,\n setFTP,\n getFTP,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const R = 6371e3; // Earth radius in metres\n const phi1 = (lat1 * Math.PI) / 180;\n const phi2 = (lat2 * Math.PI) / 180;\n const deltaPhi = ((lat2 - lat1) * Math.PI) / 180;\n const deltaLambda = ((lon2 - lon1) * Math.PI) / 180;\n\n const a =\n Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) +\n Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n\nexport function compactId(timestamp: number): string {\n // Use a compact representation of the timestamp (seconds since epoch)\n // 1712650000 -> Base64\n const buf = new Uint32Array([Math.floor(timestamp / 1000)]);\n const b64 = btoa(String.fromCharCode(...new Uint8Array(buf.buffer)));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\nexport function shortRandom(): string {\n return Math.random().toString(36).slice(2, 6);\n}\n\nexport function fmtDuration(s: number): string {\n if (s < 60) return `${Math.round(s)}s`;\n if (s < 3600) return `${Math.round(s / 60)}m`;\n return `${Math.round(s / 3600)}h`;\n}\n\nexport function fmtSecs(s: number): string {\n const h = Math.floor(s / 3600),\n m = Math.floor((s % 3600) / 60);\n return h > 0 ? `${h}h ${m}m` : `${m}m ${Math.floor(s % 60)}s`;\n}\n\nexport function fmtPace(seconds: number | null): string {\n if (seconds == null || !isFinite(seconds)) return '--';\n const mins = Math.floor(seconds / 60);\n const secs = Math.round(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nexport function fmtDate(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown date';\n return d.toISOString().split('T')[0];\n}\n\nexport function fmtDateTime(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown';\n const iso = d.toISOString();\n return `${iso.split('T')[0]} ${iso.split('T')[1].slice(0, 5)}`;\n}\n\nexport function fmtFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function escHtml(str: string): string {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function getTagColor(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);\n\n const h = Math.abs(hash % 360);\n return `hsl(${h}, 70%, 65%)`;\n}\n\n/**\n * Smoothes a numeric array using a simple Gaussian kernel.\n * sigma: standard deviation (radius of smoothing)\n */\nexport function gaussianSmooth(data: (number | null)[], sigma: number = 2): (number | null)[] {\n if (sigma <= 0) return data;\n\n const size = Math.ceil(sigma * 3) * 2 + 1;\n const kernel = new Float32Array(size);\n const half = Math.floor(size / 2);\n let sum = 0;\n\n for (let i = 0; i < size; i++) {\n const x = i - half;\n kernel[i] = Math.exp(-(x * x) / (2 * sigma * sigma));\n sum += kernel[i];\n }\n for (let i = 0; i < size; i++) kernel[i] /= sum;\n\n const result: (number | null)[] = new Array(data.length);\n for (let i = 0; i < data.length; i++) {\n if (data[i] === null) {\n result[i] = null;\n continue;\n }\n\n let val = 0;\n let weightSum = 0;\n for (let k = 0; k < size; k++) {\n const idx = i + k - half;\n if (idx >= 0 && idx < data.length && data[idx] !== null) {\n val += data[idx]! * kernel[k];\n weightSum += kernel[k];\n }\n }\n result[i] = weightSum > 0 ? val / weightSum : data[i];\n }\n return result;\n}\n\nexport function hexToRgba(hex: string, alpha: number = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, TrackPoint } from './parsers';\n\nexport const MapView = (() => {\n let trackData: Record = {};\n let customClickHandler: ((e: any) => boolean) | null = null;\n\n function init(\n onSelectCb: (id: string) => void,\n onMoveCb: (lat: number, lng: number, zoom: number) => void,\n onPointClickCb: (id: string, idx: number) => void,\n onPointHoverCb: (id: string | null, idx: number | null) => void,\n onDblClickCb: () => void,\n ) {}\n\n function switchBasemap(layer: string) {}\n function addTrack(t: TrackData) {\n trackData[t.id] = t;\n }\n function addTracks(ts: TrackData[]) {\n ts.forEach((t) => {\n trackData[t.id] = t;\n });\n }\n function removeTrack(id: string) {\n delete trackData[id];\n }\n function clearTracks() {\n trackData = {};\n }\n function removeAllTracks() {\n trackData = {};\n }\n function setTrackVisible(id: string, visible: boolean) {}\n function setSelectedTrack(id: string | null, fit: boolean) {}\n function fitAll() {}\n function fitTrack(id: string) {}\n function showCursorAt(lat: number, lon: number) {}\n function hideCursor() {}\n function highlightSegment(\n id: string | null,\n pts: TrackPoint[],\n start: number,\n end: number,\n fit?: boolean,\n colors?: string[] | null,\n ) {}\n function clearHighlight() {}\n function setTrackHover(id: string, hover: boolean) {}\n function ensureVisible(pts: any) {}\n function centerOn(lat: number, lon: number, zoom?: number | null, force?: boolean) {}\n function closePopup() {}\n function invalidateSize() {}\n function getPosition(): [number, number, number] {\n return [0, 0, 0];\n }\n function setPosition(lat: number, lng: number, zoom: number) {}\n function colorTrackByMetric(id: string, pts: TrackPoint[], colors: string[]) {}\n function clearMetricColor(id: string) {}\n\n function findTracksPassingThroughPoints(\n points: { lat: number; lng: number }[],\n radius: number,\n ): string[] {\n return Object.keys(trackData);\n }\n\n return {\n init,\n getMap: () => null as any,\n setCustomClickHandler: (handler: any) => {\n customClickHandler = handler;\n },\n switchBasemap,\n addTrack,\n addTracks,\n removeTrack,\n clearTracks,\n removeAllTracks,\n setTrackVisible,\n setSelectedTrack,\n fitAll,\n fitTrack,\n showCursorAt,\n hideCursor,\n highlightSegment,\n clearHighlight,\n setTrackHover,\n ensureVisible,\n centerOn,\n closePopup,\n invalidateSize,\n getPosition,\n setPosition,\n colorTrackByMetric,\n clearMetricColor,\n findTracksPassingThroughPoints,\n getTrackData: (id: string) => trackData[id],\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackPoint, TrackStats, TrackData } from './parsers';\nimport { gaussianSmooth, fmtSecs, hexToRgba, fmtPace } from './utils';\nimport { Zones } from './zones';\nimport { METRICS, MetricDefinition } from './metrics';\nimport { UrlState } from './url-state';\nimport { SPORTS } from './sports';\n\n// Augment uPlot to include our custom property\n\ninterface WegPlot extends uPlot {\n _strasse?: {\n selFill: HTMLElement;\n anchorLine: HTMLElement;\n anchorLabel: HTMLElement;\n anchorHandle: HTMLElement;\n anchorMarker: HTMLElement;\n endLine: HTMLElement;\n endLabel: HTMLElement;\n endHandle: HTMLElement;\n endMarker: HTMLElement;\n curYVal: HTMLElement;\n updateHeaderStats: (min: number, max: number) => void;\n };\n}\n\ninterface PlotData {\n uplot: WegPlot;\n row: HTMLDivElement;\n xData: number[];\n yData: (number | null)[];\n def: MetricDefinition;\n metricKey: string;\n statsTotalEl: HTMLDivElement;\n statsSelEl: HTMLDivElement;\n histCol: HTMLDivElement;\n histCanvas: HTMLCanvasElement;\n histData: HistData;\n hoveredHistY: number | null;\n pinnedHistY: number | null;\n smoothed?: boolean;\n incZero?: boolean;\n w?: number;\n}\n\ninterface HistData {\n yData: (number | null)[];\n xData: number[];\n def: MetricDefinition;\n BINS: number;\n plot?: PlotData;\n bins?: number[];\n binAccum?: number[];\n min?: number;\n max?: number;\n padL?: number;\n selBins?: number[] | null;\n selBinAccum?: number[] | null;\n _lastYData?: any;\n _lastSelRange?: [number, number] | null;\n fullStats?: { min: number; max: number; avg: number } | null;\n fullStatsAll?: { min: number; max: number; avg: number } | null;\n}\n\nexport const ChartView = (() => {\n let plots: PlotData[] = [];\n let renderedTrack: TrackData | null = null;\n let renderedXAxis: string = 'time';\n let renderedSpeedMode: string = 'speed';\n let renderedMapColorMetric: string | null = null;\n let syncKey: {\n key: string;\n sub: (u: uPlot) => void;\n unsub: (u: uPlot) => void;\n pub: (type: string, u: uPlot, x: number, y: number, w: number, h: number, i: number) => void;\n } | null = null;\n let scaleSyncing: boolean = false;\n let cursorSyncing: boolean = false;\n let activeMetrics: Set = new Set(['elevation']);\n let availableMetrics: Set = new Set();\n let smoothedMetrics: Set = new Set(['speed', 'gradient', 'vam', 'temperature']);\n let metricsIncludingZero: Set = new Set(['power']);\n let xAxis: string = 'time';\n let currentTrack: TrackData | null = null;\n let allTracks: TrackData[] = [];\n\n // Selection / anchor\n let selAnchorVal: number | null = null; // x-value at drag-start / zoom left edge\n let selEndVal: number | null = null; // x-value at zoom right edge\n let isDragging: boolean = false;\n let updatingRange: boolean = false; // guard against setScale hook re-entry during handle drag\n let pinnedPtIdx: number | null = null; // point index pinned by map click\n let lastMouseXVal: number | null = null; // last hovered x-value for keyboard zoom center\n let lastHistMouseEvent: MouseEvent | null = null;\n let hoveredHistData: HistData | null = null;\n let hoveredHistCanvas: HTMLCanvasElement | null = null;\n\n let currentXRange: [number, number] | null = null; // [min, max] currently rendered\n let targetXRange: [number, number] | null = null; // [min, max] for smooth keyboard animation\n let animId: number | null = null;\n\n // Callbacks\n let onCursorMoveCb: ((pt: TrackPoint | null) => void) | null = null;\n let onRangeChangeCb: ((min: number | null, max: number | null, axis: string) => void) | null =\n null;\n let onClickCb: ((pt: TrackPoint, idx: number) => void) | null = null;\n let onPinChangeCb: ((idx: number | null) => void) | null = null;\n\n const HIST_W: number = 130;\n const ROW_BODY_PADDING: number = 28; // 14px left + 14px right\n const HIST_GAP: number = 20; // margin-left on .hist-col\n let statsVisible: boolean = true;\n let histTooltipEl: HTMLElement | null = null;\n let container: HTMLElement | null = null;\n let emptyEl: HTMLElement | null = null;\n let selStatsEl: HTMLElement | null = null;\n let resetSelBtn: HTMLElement | null = null;\n let mapColorMetric: string | null = null;\n let onMapColorChangeCb: ((data: { pts: TrackPoint[]; colors: string[] } | null) => void) | null =\n null;\n\n // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function init(\n onCursorMove: (pt: TrackPoint | null) => void,\n onRangeChange: (min: number | null, max: number | null, axis: string) => void,\n onClick: (pt: TrackPoint, idx: number) => void,\n onPinChange: (idx: number | null) => void,\n ) {\n onCursorMoveCb = onCursorMove;\n onRangeChangeCb = onRangeChange;\n onClickCb = onClick;\n onPinChangeCb = onPinChange;\n container = document.getElementById('charts-container');\n container?.addEventListener('scroll', () => {\n if (lastHistMouseEvent && hoveredHistCanvas && hoveredHistData)\n updateHistTooltip(lastHistMouseEvent, hoveredHistCanvas, hoveredHistData);\n });\n emptyEl = document.getElementById('chart-empty');\n selStatsEl = document.getElementById('chart-stats-sel');\n resetSelBtn = document.getElementById('btn-reset-selection');\n histTooltipEl = document.getElementById('hist-tooltip');\n syncKey = uPlot.sync('strasse-sync');\n\n document.getElementById('sel-cancel-btn')?.addEventListener('click', cancelSelection);\n resetSelBtn?.classList.add('hidden');\n\n // \u2500\u2500 WASD Keyboard Navigation \u2500\u2500\n const navKeys = new Set(['w', 'a', 's', 'd']);\n const activeNavKeys = new Set();\n\n document.addEventListener('keydown', (e) => {\n if (!plots.length || !currentTrack) return;\n if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName || '')) return;\n\n const key = e.key.toLowerCase();\n if (!navKeys.has(key)) return;\n\n e.preventDefault();\n activeNavKeys.add(key);\n\n const u = plots[0].uplot;\n if (!targetXRange) targetXRange = [u.scales.x!.min!, u.scales.x!.max!];\n\n let [min, max] = targetXRange;\n const span = max - min;\n const moveStep = span * 0.1;\n const zoomFactor = 0.15;\n\n let newMin = min,\n newMax = max;\n\n if (key === 'a') {\n // Pan left\n newMin = min - moveStep;\n newMax = max - moveStep;\n } else if (key === 'd') {\n // Pan right\n newMin = min + moveStep;\n newMax = max + moveStep;\n } else if (key === 'w' || key === 's') {\n // Zoom\n const center = lastMouseXVal !== null ? lastMouseXVal : (min + max) / 2;\n const factor = key === 'w' ? 1 - zoomFactor : 1 + zoomFactor * 1.2;\n newMin = center - (center - min) * factor;\n newMax = center + (max - center) * factor;\n }\n\n // Clamp to track bounds\n const xFull = [plots[0].xData[0]!, plots[0].xData[plots[0].xData.length - 1]!];\n if (newMin < xFull[0]) {\n const d = xFull[0] - newMin;\n newMin += d;\n newMax += d;\n }\n if (newMax > xFull[1]) {\n const d = newMax - xFull[1];\n newMin -= d;\n newMax -= d;\n }\n newMin = Math.max(xFull[0], newMin);\n newMax = Math.min(xFull[1], newMax);\n\n if (newMax - newMin > 0.001) {\n targetXRange = [newMin, newMax];\n setVisibleRange(newMin, newMax, true); // true = animate\n }\n });\n\n document.addEventListener('keyup', (e) => {\n const key = e.key.toLowerCase();\n if (navKeys.has(key)) activeNavKeys.delete(key);\n });\n }\n\n function setVisibleRange(min: number, max: number, animate = false) {\n if (!plots.length) return;\n if (!animate) {\n plots.forEach(({ uplot: u }) => u.setScale('x', { min, max }));\n return;\n }\n\n const startMin = (currentXRange ? currentXRange[0] : plots[0].uplot.scales.x!.min) as number;\n const startMax = (currentXRange ? currentXRange[1] : plots[0].uplot.scales.x!.max) as number;\n\n if (animId) cancelAnimationFrame(animId);\n\n const lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n const factor = 0.25; // Smoothing factor\n\n const step = () => {\n if (!targetXRange) return;\n const [tMin, tMax] = targetXRange;\n\n const cMin = lerp(currentXRange![0], tMin, factor);\n const cMax = lerp(currentXRange![1], tMax, factor);\n\n plots.forEach(({ uplot: u }) => {\n u.setScale('x', { min: cMin, max: cMax });\n });\n\n if (Math.abs(cMin - tMin) > 0.0001 || Math.abs(cMax - tMax) > 0.0001)\n animId = requestAnimationFrame(step);\n else animId = null;\n };\n animId = requestAnimationFrame(step);\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function loadTrack(track: TrackData, others: TrackData[] = [], deferRender = false) {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n allTracks = others;\n\n // Detect which metrics are available in this file\n availableMetrics = new Set(\n Object.entries(METRICS)\n .filter(([, def]) => track.points.some((p) => p[def.field] != null))\n .map(([key]) => key),\n );\n\n // If no metrics are active (e.g. first load), default to core overview metrics\n if (activeMetrics.size === 0) {\n activeMetrics = new Set(['elevation'].filter((m) => availableMetrics.has(m)));\n }\n\n // Sync the pill buttons in the toolbar\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n const metric = pill.dataset.metric!;\n const isAvailable = availableMetrics.has(metric);\n pill.classList.toggle('active', isAvailable && activeMetrics.has(metric));\n pill.classList.toggle('disabled', !isAvailable);\n });\n\n currentTrack = track;\n if (deferRender) {\n updateStats(track);\n } else {\n render();\n }\n }\n\n function clear() {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n currentTrack = null;\n destroyPlots();\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
Select a track to view analysis
\n `;\n }\n const chartStats = document.getElementById('chart-stats');\n if (chartStats) chartStats.classList.add('hidden');\n clearSelectionStats();\n mapColorMetric = null;\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n }\n\n function resetState() {\n if (animId !== null) {\n cancelAnimationFrame(animId);\n animId = null;\n }\n activeMetrics = new Set(['elevation']);\n availableMetrics = new Set();\n smoothedMetrics = new Set(['speed', 'gradient', 'vam', 'temperature']);\n metricsIncludingZero = new Set(['power']);\n xAxis = 'time';\n allTracks = [];\n currentXRange = null;\n targetXRange = null;\n lastMouseXVal = null;\n lastHistMouseEvent = null;\n hoveredHistData = null;\n hoveredHistCanvas = null;\n statsVisible = true;\n clear();\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n pill.classList.remove('disabled', 'overflow-hidden');\n });\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.add('hidden');\n const toolbar = document.getElementById('chart-toolbar');\n if (toolbar) toolbar.classList.remove('collapsed');\n document.querySelectorAll('#x-axis-ctrl .seg-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.axis === 'time');\n });\n }\n\n function toggleMetric(key: string) {\n if (activeMetrics.has(key)) activeMetrics.delete(key);\n else activeMetrics.add(key);\n if (currentTrack) render(true);\n }\n\n function setActiveMetrics(keys: string[]) {\n activeMetrics = new Set(keys);\n if (currentTrack) render(true);\n // Sync the pill buttons\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n });\n }\n\n function setXAxis(axis: string) {\n if (xAxis === axis || !currentTrack) {\n xAxis = axis;\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n\n // Helper to convert a value from OLD axis to NEW axis\n const convert = (val: number | null) => {\n if (val === null) return null;\n // We need to find the point index closest to 'val' on the OLD axis\n let idx = 0;\n if (xAxis === 'distance') {\n const dTarget = val * 1000;\n idx = pts.findIndex((p) => (p.dist || 0) >= dTarget);\n } else {\n const tTarget = t0 + val * 1000;\n idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n }\n if (idx === -1) idx = pts.length - 1;\n\n // Now get the value at this index on the NEW axis\n if (axis === 'distance') return (pts[idx].dist || 0) / 1000;\n else return ((pts[idx].time || t0) - t0) / 1000;\n };\n\n // Convert selection\n if (selAnchorVal !== null) selAnchorVal = convert(selAnchorVal);\n if (selEndVal !== null) selEndVal = convert(selEndVal);\n\n // Convert zoom range (from first plot)\n let newRange: [number, number] | null = null;\n if (plots.length) {\n const u = plots[0].uplot;\n const r0 = convert(u.scales.x!.min!);\n const r1 = convert(u.scales.x!.max!);\n if (r0 !== null && r1 !== null) newRange = [r0, r1];\n }\n\n xAxis = axis;\n render(true);\n\n // Apply converted zoom\n if (newRange) {\n scaleSyncing = true;\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: newRange![0], max: newRange![1] }));\n });\n scaleSyncing = false;\n }\n }\n\n function toggleStats() {\n statsVisible = !statsVisible;\n plots.forEach(({ histCol }) => histCol.classList.toggle('visible', statsVisible));\n resize();\n }\n\n function setMapColorChangeCb(cb: (data: { pts: TrackPoint[]; colors: string[] } | null) => void) {\n onMapColorChangeCb = cb;\n }\n\n function toggleMapColor(key: string | null) {\n if (mapColorMetric === key || key === null) {\n mapColorMetric = null;\n _updateMapColorBtns();\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n } else {\n mapColorMetric = key;\n _updateMapColorBtns();\n _fireMapColorCb();\n }\n // Re-render to show/hide colored fills on the graphs\n if (currentTrack) render(true);\n }\n\n function _updateMapColorBtns() {\n document.querySelectorAll('.map-color-btn').forEach((el) => {\n const b = el as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === mapColorMetric);\n });\n }\n\n function _fireMapColorCb() {\n if (!onMapColorChangeCb || !mapColorMetric || !currentTrack) return;\n const plot = plots.find((p) => p.metricKey === mapColorMetric);\n if (!plot) return;\n const colors = _computePointColors(mapColorMetric, plot.yData);\n onMapColorChangeCb({ pts: currentTrack.points, colors });\n }\n\n function _computePointColors(key: string, yData: (number | null)[]): string[] {\n const vals = yData.filter((v): v is number => v != null && isFinite(v));\n if (!vals.length) return yData.map(() => '#888896');\n const min = Math.min(...vals),\n max = Math.max(...vals);\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n return yData.map((v) => {\n if (v == null || !isFinite(v)) return '#888896';\n if (key === 'gradient') return gradientColor(v);\n if (key === 'speed') {\n if (speedMode === 'pace') {\n const speed = (paceUnit === 'km' ? 1000 : 100) / v;\n return speedColor(speed);\n }\n return speedColor(v);\n }\n const t = max === min ? 0.5 : Math.max(0, Math.min(1, (v - min) / (max - min)));\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25);\n if (t <= 0.5) return lerpHex('#91bfdb', '#fee090', (t - 0.25) / 0.25);\n if (t <= 0.75) return lerpHex('#fee090', '#fc8d59', (t - 0.5) / 0.25);\n return lerpHex('#fc8d59', '#d73027', (t - 0.75) / 0.25);\n });\n }\n\n function resetZoom() {\n cancelSelection();\n }\n\n function cancelSelection() {\n selAnchorVal = null;\n selEndVal = null;\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n\n // Reset individual histogram pins\n plots.forEach((p) => {\n p.pinnedHistY = null;\n });\n\n updateSelOverlay();\n redrawHistograms();\n\n // Perform the actual zoom reset\n scaleSyncing = true;\n plots.forEach(({ uplot: u, xData }) => {\n u.batch(() => u.setScale('x', { min: xData[0]!, max: xData[xData.length - 1]! }));\n u._strasse?.updateHeaderStats(xData[0]!, xData[xData.length - 1]!);\n });\n scaleSyncing = false;\n\n if (onRangeChangeCb) onRangeChangeCb(null, null, xAxis);\n }\n\n function setSelectionStats(stats: TrackStats) {\n if (!selStatsEl) return;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt(\n 'sel-distance',\n stats.totalDist != null ? `${(stats.totalDist / 1000).toFixed(1)} km` : '\u2014',\n );\n fmt('sel-duration', stats.duration != null ? fmtSecs(Math.floor(stats.duration / 1000)) : '\u2014');\n fmt('sel-elevation', stats.elevGain != null ? `${Math.round(stats.elevGain)} m` : '\u2014');\n fmt(\n 'sel-avg-speed',\n stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014',\n );\n fmt('sel-avg-power', stats.avgPower != null ? `${stats.avgPower} W` : '\u2014');\n fmt('sel-avg-hr', stats.avgHR != null ? `${stats.avgHR} bpm` : '\u2014');\n fmt('sel-avg-temp', stats.avgTemp != null ? `${stats.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n selStatsEl.classList.remove('hidden');\n if (resetSelBtn) resetSelBtn.classList.remove('hidden');\n }\n\n function clearSelectionStats() {\n if (selStatsEl) selStatsEl.classList.add('hidden');\n if (resetSelBtn) resetSelBtn.classList.add('hidden');\n [\n 'sel-distance',\n 'sel-duration',\n 'sel-elevation',\n 'sel-avg-speed',\n 'sel-avg-power',\n 'sel-avg-hr',\n 'sel-avg-temp',\n ].forEach((id) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = '--';\n });\n }\n\n // Called on boot to restore a saved selection without re-firing onRangeChangeCb\n // xMin/xMax are ALWAYS provided in Time (seconds from start)\n function restoreSelection(tMin: number, tMax: number, deferRender = false) {\n if (!currentTrack) return;\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const totalDuration = ((pts[pts.length - 1]?.time || 0) - t0) / 1000;\n\n // If values look like absolute timestamps in ms, convert to seconds from start\n if (tMin > 1e12) tMin = (tMin - t0) / 1000;\n if (tMax > 1e12) tMax = (tMax - t0) / 1000;\n\n // Crop to max limits of the track\n tMin = Math.max(0, Math.min(tMin, totalDuration));\n tMax = Math.max(0, Math.min(tMax, totalDuration));\n\n const convert = (tOffset: number) => {\n if (xAxis === 'time') return tOffset;\n const tTarget = t0 + tOffset * 1000;\n let idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n if (idx === -1) idx = pts.length - 1;\n return (pts[idx].dist || 0) / 1000;\n };\n\n const xMin = convert(tMin);\n const xMax = convert(tMax);\n\n selAnchorVal = xMin;\n selEndVal = xMax;\n currentXRange = [xMin, xMax];\n if (deferRender) return;\n scaleSyncing = true; // suppress the setScale \u2192 onRangeChangeCb loop\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: xMin, max: xMax }));\n });\n scaleSyncing = false;\n updateAnchorLines();\n redrawHistograms();\n }\n\n function resize() {\n if (!plots.length || !container) return;\n const w = Math.round(\n Math.max(\n 100,\n container.getBoundingClientRect().width -\n ROW_BODY_PADDING -\n (statsVisible ? HIST_W + HIST_GAP : 0),\n ),\n );\n let anyResized = false;\n plots.forEach(({ uplot: u, histCanvas, histData }) => {\n if (w !== u.width) {\n u.setSize({ width: w, height: u.height });\n anyResized = true;\n if (statsVisible && histCanvas && histData) drawHistogram(histCanvas, histData, u.height);\n }\n });\n if (anyResized) updateSelOverlay();\n }\n\n // \u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function render(keepState = false) {\n let savedRange: [number, number] | null = null;\n let savedScroll = 0;\n if (keepState && container) savedScroll = container.scrollTop;\n\n if (keepState && currentXRange) {\n savedRange = [currentXRange[0], currentXRange[1]];\n } else if (keepState && plots.length) {\n const u = plots[0].uplot;\n savedRange = [u.scales.x!.min!, u.scales.x!.max!];\n }\n\n if (!currentTrack) {\n destroyPlots(keepState);\n return;\n }\n const pts = currentTrack.points;\n if (!pts.length) {\n destroyPlots(keepState);\n return;\n }\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n const available = [...activeMetrics].filter((m) =>\n pts.some((p) => p[METRICS[m].field] != null),\n );\n if (!available.length) {\n destroyPlots(keepState);\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
No data for selected metrics
\n `;\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n\n const containerW = container ? container.getBoundingClientRect().width : 800;\n const w = Math.round(\n Math.max(100, containerW - ROW_BODY_PADDING - (statsVisible ? HIST_W + HIST_GAP : 0)),\n );\n\n const canReuse =\n keepState &&\n renderedTrack === currentTrack &&\n renderedXAxis === xAxis &&\n renderedSpeedMode === speedMode &&\n renderedMapColorMetric === mapColorMetric &&\n plots.length > 0;\n\n let xData: (number | null)[];\n if (canReuse) {\n xData = plots[0].xData;\n } else if (xAxis === 'distance') {\n xData = pts.map((p) => (p.dist || 0) / 1000);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n let lastValidX = 0;\n xData = pts.map((p) => {\n if (p.time != null) {\n lastValidX = (p.time - t0) / 1000;\n return lastValidX;\n }\n return lastValidX; // monotonic fallback\n });\n }\n\n const existingByKey = new Map();\n if (canReuse) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const availSet = new Set(available);\n for (const p of plots) {\n const isSmoothed = smoothedMetrics.has(p.metricKey);\n const isIncZero = metricsIncludingZero.has(p.metricKey);\n if (\n availSet.has(p.metricKey) &&\n p.smoothed === isSmoothed &&\n p.incZero === isIncZero &&\n p.w === w\n ) {\n existingByKey.set(p.metricKey, p);\n } else {\n syncKey!.unsub(p.uplot);\n p.uplot.destroy();\n p.row.remove();\n }\n }\n plots = [];\n } else {\n destroyPlots(keepState);\n }\n\n if (container) {\n const nextSiblingRows: (HTMLElement | null)[] = new Array(available.length).fill(null);\n let nextExisting: HTMLElement | null = null;\n for (let i = available.length - 1; i >= 0; i--) {\n nextSiblingRows[i] = nextExisting;\n const ex = existingByKey.get(available[i]);\n if (ex) nextExisting = ex.row;\n }\n\n available.forEach((key, idx) => {\n const reused = existingByKey.get(key);\n if (reused) {\n plots.push(reused);\n const uplot = reused.uplot;\n const s = (uplot as any)._strasse;\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n uplot.batch(() => {\n if (\n savedRange &&\n (uplot.scales.x!.min !== savedRange[0] || uplot.scales.x!.max !== savedRange[1])\n ) {\n uplot.setScale('x', { min: savedRange[0], max: savedRange[1] });\n } else {\n s?.updateHeaderStats(uplot.scales.x!.min!, uplot.scales.x!.max!, uplot);\n uplot.redraw(false);\n }\n });\n scaleSyncing = prevSync;\n\n let initHoverBinI: number | null = null;\n if (\n pinnedPtIdx != null &&\n reused.xData[pinnedPtIdx] != null &&\n reused.yData[pinnedPtIdx] != null\n ) {\n buildHistBins(reused.histData);\n if (reused.histData.min != null && reused.histData.max != null) {\n const span = reused.histData.max - reused.histData.min || 1;\n initHoverBinI = Math.min(\n reused.histData.BINS - 1,\n Math.floor(\n ((reused.yData[pinnedPtIdx]! - reused.histData.min) / span) *\n reused.histData.BINS,\n ),\n );\n reused.hoveredHistY = reused.yData[pinnedPtIdx];\n }\n }\n drawHistogram(reused.histCanvas, reused.histData, 130, initHoverBinI);\n return;\n }\n\n let def = METRICS[key];\n\n let transform = def.transform;\n let fmt = def.fmt;\n let fmtAxis = def.fmtAxis;\n let unit = def.unit;\n let label = def.label;\n\n if (key === 'speed' && speedMode === 'pace') {\n label = 'Pace';\n unit = `min/${paceUnit}`;\n fmt = (v) => fmtPace(v);\n fmtAxis = (v) => fmtPace(v);\n transform = (v) => {\n if (v == null || v < 0.1) return null;\n return (paceUnit === 'km' ? 1000 : 100) / v;\n };\n\n def = { ...def, label, unit, fmt, fmtAxis, transform };\n }\n\n let yData = def.compute\n ? def.compute(pts, fillNulls)\n : fillNulls(\n pts.map((p) => {\n const v = p[def.field] as number;\n return v != null && transform ? transform(v) : v;\n }),\n );\n\n if (smoothedMetrics.has(key)) yData = gaussianSmooth(yData, def.smoothSigma || 2);\n\n createChart(key, def, xData, yData, w, pts, savedRange, nextSiblingRows[idx]);\n });\n }\n\n renderedTrack = currentTrack;\n renderedXAxis = xAxis;\n renderedSpeedMode = speedMode;\n renderedMapColorMetric = mapColorMetric;\n\n updateStats(currentTrack);\n // Restore anchor/end lines if a selection was active\n if (selAnchorVal != null && selEndVal != null) updateAnchorLines();\n // Re-apply map color if active\n _updateMapColorBtns();\n if (mapColorMetric) _fireMapColorCb();\n\n if (keepState && container && savedScroll > 0) container.scrollTop = savedScroll;\n }\n\n // \u2500\u2500 Create one chart row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function createChart(\n metricKey: string,\n def: MetricDefinition,\n xData: (number | null)[],\n yData: (number | null)[],\n w: number,\n pts: TrackPoint[],\n initialRange: [number, number] | null = null,\n insertBeforeEl: HTMLElement | null = null,\n ) {\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n\n // Gradient data: smooth over a 20 m distance window (\u00B110 m each side)\n const gradData = metricKey === 'elevation' ? smoothGradient(pts, 20) : null;\n const row = document.createElement('div');\n row.className = 'chart-row';\n row.dataset.metric = metricKey;\n row.style.setProperty('--chart-color', def.color);\n\n // Header\n const header = document.createElement('div');\n header.className = `chart-row-header${statsVisible ? ' with-histogram' : ''}`;\n\n const labelEl = document.createElement('div');\n labelEl.className = 'chart-row-label-group';\n labelEl.innerHTML = `\n ${def.icon}\n ${def.label}\n `;\n\n // Smoothing toggle\n const smoothBtn = document.createElement('button');\n smoothBtn.className = `icon-btn mini smooth-btn${smoothedMetrics.has(metricKey) ? ' active' : ''}`;\n smoothBtn.title = 'Toggle data smoothing';\n smoothBtn.innerHTML = `${smoothedMetrics.has(metricKey) ? 'blur_on' : 'blur_off'}`;\n smoothBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (smoothedMetrics.has(metricKey)) smoothedMetrics.delete(metricKey);\n else smoothedMetrics.add(metricKey);\n\n render(true); // Re-render all charts to keep sync if needed (though only this one changes data)\n });\n\n const mapColorBtn = document.createElement('button');\n\n mapColorBtn.className = `map-color-btn icon-btn${mapColorMetric === metricKey ? ' active' : ''}`;\n mapColorBtn.dataset.metric = metricKey;\n mapColorBtn.title = 'Color map track by this metric';\n mapColorBtn.innerHTML = 'colorize';\n mapColorBtn.addEventListener('click', () => toggleMapColor(metricKey));\n\n // Zero-filter toggle (Cadence/Power/Speed)\n let zeroBtn: HTMLButtonElement | null = null;\n if (metricKey === 'cadence' || metricKey === 'power' || metricKey === 'speed') {\n zeroBtn = document.createElement('button');\n const incZero = metricsIncludingZero.has(metricKey);\n zeroBtn.className = `icon-btn mini${incZero ? ' active' : ''}`;\n zeroBtn.title = incZero ? 'Currently INCLUDING 0 values' : 'Currently EXCLUDING 0 values';\n zeroBtn.innerHTML = `${incZero ? 'exposure_zero' : 'mobile_off'}`;\n zeroBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (metricsIncludingZero.has(metricKey)) metricsIncludingZero.delete(metricKey);\n else metricsIncludingZero.add(metricKey);\n render(true);\n });\n }\n\n const statsTotalEl = document.createElement('div');\n statsTotalEl.className = 'chart-stats-total';\n\n const statsSelEl = document.createElement('div');\n statsSelEl.className = 'chart-stats-selection';\n\n const statsContainer = document.createElement('div');\n statsContainer.className = 'chart-row-stats-container';\n statsContainer.append(statsTotalEl, statsSelEl);\n\n const actionsEl = document.createElement('div');\n actionsEl.className = 'chart-row-actions';\n actionsEl.append(smoothBtn, mapColorBtn);\n\n const rightActionsEl = document.createElement('div');\n rightActionsEl.className = 'chart-row-right-actions';\n\n if (metricKey === 'speed') {\n const paceToggle = document.createElement('div');\n paceToggle.className = 'seg-ctrl';\n paceToggle.innerHTML = `\n \n \n `;\n paceToggle.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const mode = btn.dataset.mode;\n if (mode === 'speed' || mode === 'pace') {\n const isDefault = mode === defaultMode;\n UrlState.patch({ speed_mode: isDefault ? null : mode });\n render(true);\n }\n });\n rightActionsEl.append(paceToggle);\n }\n\n if (zeroBtn) rightActionsEl.append(zeroBtn);\n\n header.append(labelEl, actionsEl, statsContainer, rightActionsEl);\n\n const rowBody = document.createElement('div');\n rowBody.className = 'chart-row-body';\n\n const plotEl = document.createElement('div');\n plotEl.style.position = 'relative';\n rowBody.appendChild(plotEl);\n\n const fixedMinLabel = document.createElement('div');\n fixedMinLabel.className = 'fixed-x-label fixed-x-min';\n const fixedMaxLabel = document.createElement('div');\n fixedMaxLabel.className = 'fixed-x-label fixed-x-max';\n plotEl.append(fixedMinLabel, fixedMaxLabel);\n\n const histCol = document.createElement('div');\n histCol.className = `hist-col${statsVisible ? ' visible' : ''}`;\n const histCanvas = document.createElement('canvas');\n histCanvas.className = 'hist-canvas';\n histCol.appendChild(histCanvas);\n rowBody.appendChild(histCol);\n\n row.append(header, rowBody);\n\n const isDistAxis = xAxis === 'distance';\n\n function formatX(v: number, range: number): string {\n if (v == null) return '';\n if (isDistAxis) {\n const dec = range < 1 ? 3 : range < 5 ? 2 : range < 20 ? 1 : 0;\n return `${v.toFixed(dec)} km`;\n } else {\n const absV = Math.abs(v);\n const h = Math.floor(absV / 3600);\n const m = Math.floor((absV % 3600) / 60);\n const s = Math.round(absV % 60);\n const hh = h > 0 ? `${h}:` : '';\n const mm = h > 0 ? String(m).padStart(2, '0') : String(m);\n const ss = String(s).padStart(2, '0');\n return `${v < 0 ? '-' : ''}${hh}${mm}:${ss}`;\n }\n }\n\n const incZeroDefault =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Compute global Y range and full-track stats in a single pass\n let gMin = Infinity,\n gMax = -Infinity,\n allSum = 0,\n allCount = 0,\n filtMin = Infinity,\n filtMax = -Infinity,\n filtSum = 0,\n filtCount = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n allSum += v;\n allCount++;\n if (v !== 0 || incZeroDefault) {\n if (v < filtMin) filtMin = v;\n if (v > filtMax) filtMax = v;\n filtSum += v;\n filtCount++;\n }\n }\n if (allCount === 0) {\n gMin = 0;\n gMax = 100;\n }\n const fullStatsAll = allCount ? { min: gMin, max: gMax, avg: allSum / allCount } : null;\n const fullStatsFiltered = filtCount\n ? { min: filtMin, max: filtMax, avg: filtSum / filtCount }\n : null;\n const gPad = Math.abs(gMax - gMin) * 0.1 || 1;\n const fixedYRange = [gMin - gPad, gMax + gPad];\n\n let statsTotalInitialized = false;\n\n // Per-range stats\n function updateHeaderStats(visibleMin: number, visibleMax: number, u?: uPlot) {\n const incZero =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Update fixed X labels\n const range = visibleMax - visibleMin;\n fixedMinLabel.textContent = formatX(visibleMin, range);\n fixedMaxLabel.textContent = formatX(visibleMax, range);\n\n const getHtml = (xMin: number, xMax: number, isFull = false) => {\n const s =\n isFull && incZero === incZeroDefault\n ? fullStatsFiltered\n : rangeStats(xData, yData, xMin, xMax, incZero);\n if (!s) return '';\n\n let h = `\n align_flex_end${def.fmt(s.min, true)} ${def.unit}\n align_center${def.fmt(s.avg, true)} ${def.unit}\n align_flex_start${def.fmt(s.max, true)} ${def.unit}\n `;\n\n if (metricKey === 'elevation') {\n const es = elevationRangeStats(pts, xMin, xMax);\n h += `\n trending_up+${Math.round(es.gain)} m\n trending_down-${Math.round(es.loss)} m\n `;\n }\n return h;\n };\n\n if (!statsTotalInitialized) {\n statsTotalInitialized = true;\n statsTotalEl.innerHTML = `all_inclusive${getHtml(\n xData[0]!,\n xData[xData.length - 1]!,\n true,\n )}`;\n statsTotalEl.querySelector('.all-chip')?.addEventListener('click', (e) => {\n e.stopPropagation();\n cancelSelection();\n });\n }\n\n if (selAnchorVal !== null && selEndVal !== null) {\n statsSelEl.innerHTML = getHtml(selAnchorVal, selEndVal, false);\n statsSelEl.style.display = 'flex';\n statsSelEl.style.setProperty('--sel-color', def.color);\n } else {\n statsSelEl.style.display = 'none';\n }\n }\n let initializingScale = false;\n const uOpts: uPlot.Options = {\n width: w,\n height: 130,\n padding: [4, 0, 0, 0],\n cursor: {\n sync: {\n key: syncKey!.key,\n },\n drag: { x: true, y: false, uni: 16 },\n focus: { prox: 16 },\n points: {\n size: 7,\n stroke: '#0e0e10',\n width: 2,\n fill: (metricKey === 'elevation'\n ? (u: uPlot, _si: number) => gradientColor(gradData ? gradData[u.cursor.idx!]! : null)\n : def.color) as any,\n },\n x: false,\n y: false,\n },\n select: {\n show: true,\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n },\n legend: { show: false },\n scales: {\n x: {\n time: false,\n range: (_u: uPlot, mn: number, mx: number) => [mn, mx],\n min: initialRange ? initialRange[0] : undefined,\n max: initialRange ? initialRange[1] : undefined,\n },\n y: {\n range: () => fixedYRange as [number, number],\n dir: metricKey === 'speed' && speedMode === 'pace' ? -1 : 1,\n },\n },\n axes: [\n {\n side: 2, // bottom\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: {\n show: true,\n stroke: '#2e2e34',\n },\n size: 30,\n space: 80,\n font: '10px system-ui, sans-serif',\n splits: (u: uPlot, axisIdx: number, scaleMin: number, scaleMax: number) => {\n const range = scaleMax - scaleMin;\n const width = u.bbox.width > 0 ? u.bbox.width : u.width;\n const targetLabels = width / 80;\n const idealIncr = range / targetLabels;\n\n let incrs;\n if (!isDistAxis) {\n // Time in seconds\n incrs = [\n 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 14400, 28800, 43200,\n 86400, 604800, 2592000, 31536000,\n ];\n } else {\n incrs = [\n 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000,\n 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000,\n ];\n }\n\n let incr = incrs[incrs.length - 1];\n for (let i = 0; i < incrs.length; i++) {\n if (incrs[i] >= idealIncr) {\n incr = incrs[i];\n break;\n }\n }\n\n const splits = [];\n let val = Math.ceil(scaleMin / incr) * incr;\n const precision = incr < 1 ? 2 : 0;\n\n while (val <= scaleMax) {\n const pos = u.valToPos(val, 'x', true);\n if (pos >= u.bbox.left + 80 && pos <= u.bbox.left + u.bbox.width - 80)\n splits.push(Number(val.toFixed(precision)));\n\n val += incr;\n }\n return splits;\n },\n values: ((_u: uPlot, vals: number[]) => {\n const range = (_u.scales.x?.max ?? 1) - (_u.scales.x?.min ?? 0);\n\n return vals.map((v) => {\n if (v == null) return '';\n const pos = _u.valToPos(v, 'x', true);\n // Strict 80px margin to prevent overlapping with fixed labels or Y axis\n if (pos < _u.bbox.left + 80 || pos > _u.bbox.left + _u.bbox.width - 80) return null;\n return formatX(v, range);\n });\n }) as any,\n },\n {\n side: 3, // left\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: { stroke: '#2e2e34' },\n size: 55,\n font: '10px system-ui, sans-serif',\n values: ((_u: uPlot, vals: number[]) =>\n vals.map((v) => (v != null ? def.fmtAxis(v) : ''))) as any,\n },\n ],\n series: [\n {},\n // Main selected track series\n {\n label: def.label,\n stroke: 'rgba(0,0,0,0)', // Stroke handled in draw hooks for layering\n width: 0,\n points: { show: false },\n paths: () => null,\n },\n ],\n hooks: {\n draw: [\n (u: uPlot) => {\n const top = u.bbox.top + u.bbox.height + 5; // 5px below plot area!\n fixedMinLabel.style.top = `${top}px`;\n fixedMinLabel.style.left = `${u.bbox.left}px`;\n\n fixedMaxLabel.style.top = `${top}px`;\n fixedMaxLabel.style.left = `${u.bbox.left + u.bbox.width}px`;\n fixedMaxLabel.style.transform = 'translateX(-100%)';\n },\n // 1. (bottom) Color / metric color of the selected track\n (u: uPlot) => {\n if (metricKey === 'gears') {\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n } else if (metricKey === 'elevation') {\n drawElevationGradient(u, xData as number[], yData as number[], gradData);\n } else if (metricKey === 'gradient') {\n drawGradientChart(u, xData as number[], yData as number[]);\n } else if (mapColorMetric === metricKey) {\n drawMetricColorFill(u, xData as number[], yData as number[], pts, metricKey);\n } else {\n // Normal colored line\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n }\n },\n\n // 2. Pinned point (middle)\n (u: uPlot) => {\n const plot = plots.find((p) => p.uplot === u);\n if (!plot) return;\n\n const s = (u as any)._strasse;\n // Priority 1: Global pinned point (all charts)\n if (pinnedPtIdx != null) {\n drawPinnedDot(u, xData, yData, def.color, def, pts, metricKey);\n } else {\n if (s && s.pinYVal) s.pinYVal.style.display = 'none';\n\n // Priority 2: Individual histogram pinned Y-pos (this chart only)\n if (plot.pinnedHistY != null)\n drawYAxisHighlight(u, xData, yData, plot.pinnedHistY, def.color, def);\n }\n },\n\n // 3. Pinned & Hover elements (labels, vertical lines)\n (u: uPlot) => {\n const hIdx = u.cursor.idx;\n const hasPinned = pinnedPtIdx != null;\n\n let hasHover = hIdx != null && u.cursor.left! >= 0;\n if (hasHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[hIdx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) hasHover = false;\n }\n\n // B. Draw Hover vertical line\n if (hasHover && hIdx !== pinnedPtIdx)\n drawVerticalLineOnly(u, pts, hIdx!, hexToRgba(def.color, 0.4), 1.0);\n\n // C. Bold selection x-axis line & span pill\n if (selAnchorVal != null && selEndVal != null) {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ax = u.valToPos(selAnchorVal, 'x', true);\n const ex = u.valToPos(selEndVal, 'x', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.lineWidth = 3 * dpr;\n ctx.strokeStyle = def.color;\n ctx.moveTo(ax, bb.top + bb.height);\n ctx.lineTo(ex, bb.top + bb.height);\n ctx.stroke();\n\n const span = Math.abs(selEndVal - selAnchorVal);\n const label = xAxis === 'distance' ? `${span.toFixed(2)} km` : fmtSecs(span);\n const fontSize = 9 * dpr;\n const fontStr = `bold ${fontSize}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n\n const visibleL = Math.max(bb.left, ax);\n const visibleR = Math.min(bb.left + bb.width, ex);\n const visibleW = visibleR - visibleL;\n\n if (visibleW > tw + 14 * dpr) {\n const padH = 5 * dpr;\n const padV = 2 * dpr;\n const bw = tw + padH * 2;\n const bh = fontSize + padV * 2;\n const bx = (visibleL + visibleR) / 2 - bw / 2;\n const by = bb.top + bb.height - bh / 2;\n\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = def.color;\n ctx.fill();\n\n ctx.fillStyle = '#000';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2);\n }\n ctx.restore();\n }\n\n // D. Draw label pills (on top)\n // Pinned labels first (semi-transparent)\n if (hasPinned) drawXAxisLabels(u, pts, pinnedPtIdx!, def.color, true, 0.7);\n\n // Hover labels last (fully opaque, topmost)\n if (hasHover && hIdx !== pinnedPtIdx)\n drawXAxisLabels(u, pts, hIdx!, def.color, true, 1.0);\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (scaleSyncing) return;\n const idx = u.cursor.idx;\n\n // Trigger redraw on cursor move to ensure custom canvas markers (hover lines/labels) update live\n // Note: uPlot handles cross-chart sync when syncKey is used.\n u.redraw(false);\n\n // Track current x-value for keyboard navigation\n if (u.cursor.left! >= 0) lastMouseXVal = u.posToVal(u.cursor.left!, 'x');\n else lastMouseXVal = null;\n\n // \u2500\u2500 Floating y-value next to cursor dot \u2500\u2500\n const s = (u as any)._strasse;\n let showHover = idx != null && yData[idx] != null;\n\n // Distance threshold: if no pinned point, check proximity to data line\n if (showHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[idx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) showHover = false;\n }\n\n if (s) {\n if (showHover)\n updateTooltip(\n u,\n s.curYVal,\n idx!,\n xData as number[],\n yData as number[],\n pts,\n def,\n metricKey,\n );\n else s.curYVal.style.display = 'none';\n }\n\n // Map marker\n if (!cursorSyncing) {\n if (idx != null && pts[idx]) {\n if (onCursorMoveCb && (pinnedPtIdx != null || showHover)) {\n onCursorMoveCb(pts[idx]);\n } else if (onCursorMoveCb && !showHover) {\n // If we're too far and nothing is pinned, hide map cursor\n onCursorMoveCb(null);\n }\n } else if (idx === null && onCursorMoveCb) {\n onCursorMoveCb(null);\n }\n }\n\n // Highlight matching histogram bucket\n if (idx != null && yData[idx] != null) {\n const { min, max } = histData;\n if (min != null && max != null) {\n const span = max - min || 1;\n const binI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[idx]! - min) / span) * histData.BINS),\n );\n if (plot.hoveredHistY !== yData[idx]) {\n plot.hoveredHistY = yData[idx];\n drawHistogram(histCanvas, histData, 130, binI);\n }\n }\n } else if (plot.hoveredHistY !== null) {\n plot.hoveredHistY = null;\n drawHistogram(histCanvas, histData, 130);\n }\n },\n ],\n\n setScale: [\n (u: uPlot, key: string) => {\n if (key !== 'x' || initializingScale) return;\n const { min, max } = u.scales.x!;\n\n // Sync currentXRange so keyboard navigation baseline is always accurate\n currentXRange = [min!, max!];\n\n // Update header stats for VISIBLE range\n updateHeaderStats(min as number, max as number, u);\n\n if (scaleSyncing) return;\n\n // Clear keyboard target when user interacts via mouse\n if (!updatingRange) targetXRange = null;\n\n // Sync sibling plots\n scaleSyncing = true;\n plots.forEach(({ uplot: other }) => {\n if (other !== u) other.batch(() => other.setScale('x', { min: min!, max: max! }));\n });\n scaleSyncing = false;\n\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb && selAnchorVal !== null)\n onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n },\n ],\n\n setSelect: [\n (u: uPlot) => {\n if (updatingRange) return;\n targetXRange = null;\n const { left, width } = u.select;\n if (width > 0) {\n const min = u.posToVal(left, 'x');\n const max = u.posToVal(left + width, 'x');\n selAnchorVal = min;\n selEndVal = max;\n\n // Sync stats to new selection\n updateHeaderStats(u.scales.x!.min!, u.scales.x!.max!, u);\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n\n // Clear uPlot's internal selection immediately so it doesn't block WASD/interaction\n u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);\n }\n },\n ],\n },\n };\n\n // \u2500\u2500 Overlay (pointer-events off except handles) \u2500\u2500\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5';\n\n // Selection fill\n const selFill = document.createElement('div');\n selFill.className = 'sel-fill';\n selFill.style.display = 'none';\n\n // Anchor line + label + drag handle\n const anchorLine = document.createElement('div');\n anchorLine.className = 'sel-line sel-line-anchor';\n anchorLine.style.display = 'none';\n\n const anchorLabel = document.createElement('div');\n anchorLabel.className = 'sel-line-label sel-line-label-anchor';\n anchorLabel.style.display = 'none';\n\n const anchorHandle = document.createElement('div');\n anchorHandle.className = 'sel-handle sel-handle-anchor';\n anchorHandle.style.display = 'none';\n\n const anchorMarker = document.createElement('div');\n anchorMarker.className = 'sel-graph-marker';\n anchorMarker.innerHTML =\n 'play_circle';\n anchorMarker.style.display = 'none';\n\n // End line + label + drag handle\n const endLine = document.createElement('div');\n endLine.className = 'sel-line sel-line-end';\n endLine.style.display = 'none';\n\n const endLabel = document.createElement('div');\n endLabel.className = 'sel-line-label sel-line-label-end';\n endLabel.style.display = 'none';\n\n const endHandle = document.createElement('div');\n endHandle.className = 'sel-handle sel-handle-end';\n endHandle.style.display = 'none';\n\n const endMarker = document.createElement('div');\n endMarker.className = 'sel-graph-marker';\n endMarker.innerHTML =\n 'stop_circle';\n endMarker.style.display = 'none';\n\n // Floating cursor y-value\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${def.color};display:none`;\n\n // Floating pinned y-value\n const pinYVal = document.createElement('div');\n pinYVal.className = 'cur-y-val pin';\n pinYVal.style.cssText = `color:${def.color};display:none`;\n\n overlay.append(\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n );\n\n const histData: HistData = {\n yData,\n xData: xData as number[],\n def,\n BINS: 24,\n min: allCount ? gMin : undefined,\n max: allCount ? gMax : undefined,\n fullStats: fullStatsFiltered,\n fullStatsAll,\n };\n const plot: PlotData = {\n uplot: null as any,\n row,\n xData: xData as number[],\n yData,\n def,\n metricKey,\n statsTotalEl,\n statsSelEl,\n histCol,\n histCanvas,\n histData,\n hoveredHistY: null,\n pinnedHistY: null,\n smoothed: smoothedMetrics.has(metricKey),\n incZero: metricsIncludingZero.has(metricKey),\n w,\n };\n histData.plot = plot; // Back-reference for tooltip to trigger redraws\n\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n const uplot = new uPlot(uOpts, [xData, yData] as any, (self, init) => {\n plot.uplot = self as WegPlot;\n plots.push(plot);\n plotEl.appendChild(self.root);\n self.over.appendChild(overlay);\n (self as any)._strasse = {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n updateHeaderStats,\n };\n self.batch(() => {\n init();\n });\n }) as WegPlot;\n scaleSyncing = prevSync;\n\n // \u2500\u2500 Handle drag \u2500\u2500\n attachHandleDrag(anchorHandle, uplot, xData, true);\n attachHandleDrag(endHandle, uplot, xData, false);\n\n // \u2500\u2500 Mouse listeners \u2500\u2500\n let mousedownX: number | null = null;\n uplot.over.addEventListener('mousedown', (e) => {\n if (e.button !== 0) return;\n isDragging = false;\n const rect = uplot.over.getBoundingClientRect();\n const xPx = e.clientX - rect.left;\n mousedownX = xPx;\n });\n uplot.over.addEventListener('mousemove', (e) => {\n if (mousedownX !== null) {\n const rect = uplot.over.getBoundingClientRect();\n if (Math.abs(e.clientX - rect.left - mousedownX) > 5) isDragging = true;\n }\n });\n uplot.over.addEventListener('mouseup', () => {\n mousedownX = null;\n });\n\n // Click to pin point (sticky selection)\n uplot.over.addEventListener('click', () => {\n if (isDragging) return;\n const idx = uplot.cursor.idx;\n if (idx != null && pts[idx]) {\n pinnedPtIdx = idx;\n plots.forEach(({ uplot: u }) => u.redraw(false));\n if (onClickCb) onClickCb(pts[idx], idx);\n if (onPinChangeCb) onPinChangeCb(idx);\n }\n });\n\n row.addEventListener('dblclick', cancelSelection);\n\n let initHoverBinI: number | null = null;\n if (pinnedPtIdx != null && xData[pinnedPtIdx] != null && yData[pinnedPtIdx] != null) {\n buildHistBins(histData);\n if (histData.min != null && histData.max != null) {\n const span = histData.max - histData.min || 1;\n initHoverBinI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[pinnedPtIdx]! - histData.min) / span) * histData.BINS),\n );\n plot.hoveredHistY = yData[pinnedPtIdx];\n }\n }\n\n drawHistogram(histCanvas, histData, 130, initHoverBinI);\n attachHistTooltip(histCanvas, histData);\n if (container) {\n if (insertBeforeEl) container.insertBefore(row, insertBeforeEl);\n else container.appendChild(row);\n }\n }\n\n // \u2500\u2500 Selection overlay (fill + lines + handles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateSelOverlay() {\n updateAnchorLines();\n // Redraw canvas markers (bold selection line + span pill)\n plots.forEach(({ uplot: u }) => u.batch(() => u.redraw(false)));\n }\n\n function updateAnchorLines() {\n plots.forEach(({ uplot: u, def }) => {\n const s = (u as any)._strasse;\n if (!s) return;\n const {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n } = s;\n if (selAnchorVal == null || selEndVal == null) {\n [\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n ].forEach((el: HTMLElement) => {\n el.style.display = 'none';\n });\n return;\n }\n const aX = u.valToPos(selAnchorVal, 'x');\n const eX = u.valToPos(selEndVal, 'x');\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const overW = bb.width / dpr;\n const overH = bb.height / dpr;\n const plotBottom = (bb.top + bb.height) / dpr;\n\n const isAnchorVisible = aX >= 0 && aX <= overW;\n const isEndVisible = eX >= 0 && eX <= overW;\n\n // Fill: clamp left/right to visible area\n const fillL = Math.max(0, aX);\n const fillR = Math.min(overW, eX);\n if (fillR > fillL) {\n selFill.style.left = `${fillL}px`;\n selFill.style.width = `${fillR - fillL}px`;\n selFill.style.top = '0';\n selFill.style.height = `${overH}px`;\n selFill.style.backgroundColor = hexToRgba(def.color, 0.07);\n selFill.style.display = '';\n } else {\n selFill.style.display = 'none';\n }\n\n // Anchor line\n if (isAnchorVisible) {\n anchorLine.style.left = `${aX}px`;\n anchorLine.style.height = `${overH}px`;\n anchorLine.style.borderLeftColor = def.color;\n anchorLine.style.display = '';\n // Anchor label\n const aText = fmtXVal(selAnchorVal);\n anchorLabel.textContent = aText;\n const aLabelW = aText.length * 7 + 10;\n anchorLabel.style.left = aX + aLabelW + 4 < overW ? `${aX + 3}px` : `${aX - aLabelW - 3}px`;\n anchorLabel.style.display = '';\n // Anchor handle\n anchorHandle.style.left = `${aX}px`;\n anchorHandle.style.backgroundColor = def.color;\n anchorHandle.style.display = '';\n // Anchor marker: centered on the bold line\n anchorMarker.style.left = `${aX}px`;\n anchorMarker.style.top = `${plotBottom}px`;\n const aIcon = anchorMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (aIcon) aIcon.style.color = def.color;\n anchorMarker.style.display = '';\n } else {\n [anchorLine, anchorLabel, anchorHandle, anchorMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n\n // End line\n if (isEndVisible) {\n endLine.style.left = `${eX}px`;\n endLine.style.height = `${overH}px`;\n endLine.style.borderLeftColor = def.color;\n endLine.style.display = '';\n // End label\n const eText = fmtXVal(selEndVal);\n endLabel.textContent = eText;\n const eLabelW = eText.length * 7 + 10;\n endLabel.style.left = eX - eLabelW - 3 > 0 ? `${eX - eLabelW - 3}px` : `${eX + 3}px`;\n endLabel.style.display = '';\n // End handle\n endHandle.style.left = `${eX}px`;\n endHandle.style.backgroundColor = def.color;\n endHandle.style.display = '';\n // End marker: centered on the bold line\n endMarker.style.left = `${eX}px`;\n endMarker.style.top = `${plotBottom}px`;\n const eIcon = endMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (eIcon) eIcon.style.color = def.color;\n endMarker.style.display = '';\n } else {\n [endLine, endLabel, endHandle, endMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n });\n }\n\n function fmtXVal(v: number) {\n return xAxis === 'distance' ? `${v.toFixed(2)} km` : fmtSecs(v);\n }\n\n // \u2500\u2500 Handle drag logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function attachHandleDrag(\n handleEl: HTMLElement,\n uplot: uPlot,\n xData: (number | null)[],\n isAnchor: boolean,\n ) {\n // pointer-events enabled on the handle itself\n handleEl.style.pointerEvents = 'auto';\n\n handleEl.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n const startX = e.clientX;\n const startVal = isAnchor ? selAnchorVal : selEndVal;\n const overW = uplot.over.offsetWidth;\n // px-per-data-unit at current zoom\n const xMin = uplot.scales.x!.min!,\n xMax = uplot.scales.x!.max!;\n const pxPerUnit = overW / (xMax - xMin);\n const xFull = [xData[0]!, xData[xData.length - 1]!];\n\n document.body.style.cursor = 'ew-resize';\n isDragging = true;\n\n function onMove(me: MouseEvent) {\n const dx = me.clientX - startX;\n let newVal = (startVal || 0) + dx / pxPerUnit;\n newVal = Math.max(xFull[0], Math.min(xFull[1], newVal));\n\n if (isAnchor) selAnchorVal = Math.min(newVal, (selEndVal || xFull[1]) - 0.001);\n else selEndVal = Math.max(newVal, (selAnchorVal || xFull[0]) + 0.001);\n\n // When dragging handles, we typically want to stay zoomed to the selection?\n // Actually, let's keep the zoom as is, and just update the selection overlay and stats.\n plots.forEach((p) =>\n (p.uplot as any)._strasse?.updateHeaderStats(\n p.uplot.scales.x!.min!,\n p.uplot.scales.x!.max!,\n ),\n );\n updateSelOverlay();\n redrawHistograms();\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n }\n\n function onUp() {\n document.body.style.cursor = '';\n isDragging = false;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n }\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n }\n\n // \u2500\u2500 Histogram logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function buildHistBins(histData: HistData) {\n const { yData, xData, BINS } = histData;\n\n // Cache to avoid re-binning every frame during hover\n if (histData._lastYData === yData && histData.bins) return;\n histData._lastYData = yData;\n\n let min = histData.min;\n let max = histData.max;\n if (min == null || max == null) {\n let lo = Infinity,\n hi = -Infinity,\n cnt = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < lo) lo = v;\n if (v > hi) hi = v;\n cnt++;\n }\n if (!cnt) return;\n min = lo;\n max = hi;\n histData.min = min;\n histData.max = max;\n }\n\n const bins = new Array(BINS).fill(0);\n const binAccum = new Array(BINS).fill(0); // accumulated x-weight per bin (time in s or dist in km)\n\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n bins[bi]++;\n\n // weight by x-delta\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n binAccum[bi] += (next - prev) / 2;\n }\n histData.bins = bins;\n histData.binAccum = binAccum;\n }\n\n function redrawHistograms() {\n plots.forEach(({ histCanvas, histData, uplot: u }) => {\n drawHistogram(histCanvas, histData, u.height);\n });\n }\n\n function drawHistogram(\n canvas: HTMLCanvasElement,\n histData: HistData,\n chartH: number,\n hoverBinI: number | null = null,\n ) {\n const { def, BINS } = histData;\n buildHistBins(histData);\n const { bins, min, max } = histData;\n if (!bins || min == null || max == null) return;\n\n const hasSel = selAnchorVal != null && selEndVal != null;\n\n // Compute selection bins if a range is active and changed\n if (\n hasSel &&\n (histData._lastSelRange?.[0] !== selAnchorVal || histData._lastSelRange?.[1] !== selEndVal)\n ) {\n histData._lastSelRange = [selAnchorVal!, selEndVal!];\n const selBins = new Array(BINS).fill(0);\n const selBinAccum = new Array(BINS).fill(0);\n const { yData, xData } = histData;\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const x = xData[i];\n if (x == null || x < selAnchorVal! || x > selEndVal!) continue;\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n selBins[bi]++;\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n selBinAccum[bi] += (next - prev) / 2;\n }\n histData.selBins = selBins;\n histData.selBinAccum = selBinAccum;\n } else if (!hasSel) {\n histData.selBins = null;\n histData.selBinAccum = null;\n histData._lastSelRange = null;\n }\n const selBins = histData.selBins;\n\n const dpr = window.devicePixelRatio || 1;\n const W = HIST_W;\n const H = chartH;\n\n // Performance: only set dimensions if they changed (resets canvas)\n if (canvas.width !== W * dpr || canvas.height !== H * dpr) {\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n }\n\n const ctx = canvas.getContext('2d')!;\n ctx.resetTransform();\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, W, H);\n\n const peak = Math.max(...bins);\n\n // Measure label width so bars start right after them\n const fmt = (v: number) => def.fmtAxis(v);\n const fontStr = '9px system-ui, sans-serif';\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const labelW = Math.ceil(\n Math.max(\n ctx.measureText(`${fmt(max)} ${def.unit}`).width,\n ctx.measureText(`${fmt(min)} ${def.unit}`).width,\n ),\n );\n\n // Vertical alignment with main graph:\n // uPlot padding: [4, 0, 0, 0]\n // Axis size: 30\n const pad = { t: 4, r: 0, b: 30, l: labelW + 6 };\n histData.padL = pad.l;\n const plotW = W - pad.l - pad.r;\n const plotH = H - pad.t - pad.b;\n\n // bin 0 = lowest values \u2192 drawn at bottom; bin BINS-1 = highest \u2192 drawn at top\n const binY = (i: number) => pad.t + (BINS - 1 - i) * (plotH / BINS);\n const binH = plotH / BINS - 1;\n\n // Full distribution (dimmed when selection active)\n const baseAlpha = hasSel ? 0.15 : 0.6;\n ctx.fillStyle = hexToRgba(def.color, baseAlpha);\n for (let i = 0; i < BINS; i++) {\n if (!bins[i]) continue;\n const bw = (bins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n\n // Selection overlay (bright)\n if (selBins) {\n ctx.fillStyle = hexToRgba(def.color, 0.85);\n for (let i = 0; i < BINS; i++) {\n if (!selBins[i]) continue;\n const bw = (selBins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n ctx.fillStyle = def.color;\n ctx.fillRect(pad.l, pad.t, 2, plotH);\n }\n\n // CDF overlay \u2014 smooth curve from bottom (0%) to top (100%)\n const total = bins.reduce((s, v) => s + v, 0);\n if (total > 0) {\n // Build CDF points: one per bin boundary, bottom\u2192top\n const pts2 = [{ x: pad.l, y: pad.t + plotH }];\n let cumSum = 0;\n for (let i = 0; i < BINS; i++) {\n cumSum += bins[i];\n pts2.push({ x: pad.l + (cumSum / total) * plotW, y: binY(i) });\n }\n\n ctx.beginPath();\n // CDF line is now solid\n ctx.setLineDash([]);\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 0.75 * dpr;\n ctx.lineJoin = 'round';\n ctx.moveTo(pts2[0].x, pts2[0].y);\n for (let i = 1; i < pts2.length - 1; i++) {\n const mx = (pts2[i].x + pts2[i + 1].x) / 2;\n const my = (pts2[i].y + pts2[i + 1].y) / 2;\n ctx.quadraticCurveTo(pts2[i].x, pts2[i].y, mx, my);\n }\n ctx.lineTo(pts2[pts2.length - 1].x, pts2[pts2.length - 1].y);\n ctx.stroke();\n\n // \u2500\u2500 Hover highlight on CDF \u2500\u2500\n if (hoverBinI != null && pts2[hoverBinI + 1]) {\n const cp = pts2[hoverBinI + 1];\n // Vertical line down\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(def.color, 0.6);\n ctx.moveTo(cp.x, cp.y);\n ctx.lineTo(cp.x, pad.t + plotH);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Dot: tiny precision point\n ctx.beginPath();\n ctx.arc(cp.x, cp.y, 1.2 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n }\n\n // Axis labels: max at top, min at bottom\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n const font9 = '9px system-ui, sans-serif';\n if (ctx.font !== font9) ctx.font = font9;\n ctx.textAlign = 'right';\n\n // Draw Max\n ctx.textBaseline = 'top';\n ctx.fillText(`${fmt(max)} ${def.unit}`, pad.l - 4, pad.t);\n\n // Draw Min\n ctx.textBaseline = 'bottom';\n ctx.fillText(`${fmt(min)} ${def.unit}`, pad.l - 4, H - pad.b);\n\n // Draw Avg (only if it doesn't overlap min/max)\n const stats =\n !hasSel && histData.fullStatsAll !== undefined\n ? histData.fullStatsAll\n : rangeStats(\n histData.xData,\n histData.yData,\n selAnchorVal || -Infinity,\n selEndVal || Infinity,\n );\n if (stats) {\n const avgY =\n pad.t +\n (BINS - 1 - Math.min(BINS - 1, Math.floor(((stats.avg - min) / (max - min || 1)) * BINS))) *\n (plotH / BINS);\n const minLabelY = H - pad.b;\n const maxLabelY = pad.t;\n const labelHeight = 10; // Approx 10px height for 9px font\n\n if (avgY > maxLabelY + labelHeight + 2 && avgY < minLabelY - labelHeight - 2) {\n ctx.textBaseline = 'middle';\n if (ctx.fillStyle !== '#aaa') ctx.fillStyle = '#aaa';\n ctx.fillText(`${fmt(stats.avg)} ${def.unit}`, pad.l - 4, avgY);\n // Draw small indicator tick\n ctx.beginPath();\n ctx.moveTo(pad.l - 3, avgY);\n ctx.lineTo(pad.l, avgY);\n if (ctx.strokeStyle !== '#aaa') ctx.strokeStyle = '#aaa';\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n }\n\n // \u2500\u2500 Higher/Lower percentages below histogram \u2500\u2500\n if (hoverBinI != null && total > 0) {\n let countLower = 0;\n for (let i = 0; i < hoverBinI; i++) countLower += bins[i];\n let countHigher = 0;\n for (let i = hoverBinI + 1; i < BINS; i++) countHigher += bins[i];\n\n const pLower = Math.round((countLower / total) * 100);\n const pHigher = Math.round((countHigher / total) * 100);\n\n ctx.save();\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const font8 = '8px system-ui, sans-serif';\n if (ctx.font !== font8) ctx.font = font8;\n\n const textY = H - pad.b + 6;\n\n // Draw \"Lower\" stat\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('LOWER', pad.l, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n const fontB10 = 'bold 10px system-ui, sans-serif';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pLower}%`, pad.l, textY + 10);\n\n // Draw \"Higher\" stat\n const midX = pad.l + plotW / 2;\n if (ctx.font !== font8) ctx.font = font8;\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('HIGHER', midX, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pHigher}%`, midX, textY + 10);\n\n ctx.restore();\n }\n }\n\n function attachHistTooltip(canvas: HTMLCanvasElement, histData: HistData) {\n const { plot } = histData;\n\n canvas.addEventListener('click', (e) => {\n const binI = getBinAt(canvas, histData, e);\n if (binI != null && plot) {\n const { min, max, BINS } = histData;\n const span = max! - min! || 1;\n plot.pinnedHistY = min! + (binI + 0.5) * (span / BINS!);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n }\n });\n\n canvas.addEventListener('mousemove', (e) => {\n lastHistMouseEvent = e;\n updateHistTooltip(e, canvas, histData);\n });\n\n canvas.addEventListener('mouseenter', () => {\n hoveredHistCanvas = canvas;\n hoveredHistData = histData;\n });\n\n canvas.addEventListener('mouseleave', () => {\n if (hoveredHistCanvas === canvas) {\n hoveredHistCanvas = null;\n hoveredHistData = null;\n }\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const lineEl = document.getElementById('hist-line');\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n });\n }\n\n function getBinAt(canvas: HTMLCanvasElement, histData: HistData, e: MouseEvent) {\n const { bins, BINS } = histData;\n if (!bins) return null;\n const rect = canvas.getBoundingClientRect();\n const relY = e.clientY - rect.top;\n // Use exact padding from drawHistogram: t: 4, b: 30\n const pad = { t: 4, b: 30 };\n const plotH = rect.height - pad.t - pad.b;\n const rawI = Math.floor(((relY - pad.t) / plotH) * BINS!);\n const binI = BINS! - 1 - rawI;\n if (rawI < 0 || rawI >= BINS!) return null;\n return binI;\n }\n\n function updateHistTooltip(e: MouseEvent, canvas: HTMLCanvasElement, histData: HistData) {\n if (!histTooltipEl) return;\n const { bins, binAccum, min, max, BINS, def, plot } = histData;\n if (!bins || !binAccum || min == null || max == null) return;\n\n const lineEl = document.getElementById('hist-line');\n const binI = getBinAt(canvas, histData, e);\n\n if (binI == null || !bins[binI]) {\n histTooltipEl.style.display = 'none';\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n return;\n }\n\n if (plot) {\n const span = max - min || 1;\n plot.hoveredHistY = min + (binI + 0.5) * (span / BINS!);\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1), binI);\n }\n\n const count = bins[binI];\n const total = bins.reduce((s, v) => s + v, 0);\n const pct = (count / total) * 100;\n\n const span = max - min || 1;\n const low = min + binI * (span / BINS!);\n const high = min + (binI + 1) * (span / BINS!);\n const label = `${def.fmt(low, true)} \u2013 ${def.fmt(high, true)} ${def.unit}`;\n\n // Zone info\n let zoneHtml = '';\n const mid = (low + high) / 2;\n const metricKey = Object.keys(METRICS).find((k) => METRICS[k] === def);\n let zones: any[] = [];\n if (metricKey === 'power') zones = Zones.getPowerZones();\n else if (metricKey === 'hr') zones = Zones.getHRZones();\n\n if (zones.length > 0) {\n const zIdx = zones.findIndex((z) => mid >= z.min && mid < z.max);\n const z =\n zIdx !== -1\n ? zones[zIdx]\n : mid >= zones[zones.length - 1].min\n ? zones[zones.length - 1]\n : null;\n if (z) {\n const finalZIdx = zIdx !== -1 ? zIdx : zones.length - 1;\n zoneHtml = `\n
\n Z${finalZIdx + 1}\n \u00B7\n ${z.name}\n
\n `;\n }\n }\n\n const totalAccum =\n xAxis === 'distance' ? `${binAccum[binI].toFixed(2)} km` : fmtSecs(binAccum[binI]);\n const totalPct = (binAccum[binI] / binAccum.reduce((s, v) => s + v, 0)) * 100;\n\n let html = `\n
${label}
\n ${zoneHtml}\n `;\n\n if (totalAccum) {\n html += `
\n ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${totalAccum}\n ${totalPct.toFixed(1)}%\n
`;\n }\n\n // Selection context\n if (histData.selBins && histData.selBinAccum) {\n const stotalAccum =\n xAxis === 'distance'\n ? `${histData.selBinAccum[binI].toFixed(2)} km`\n : fmtSecs(histData.selBinAccum[binI]);\n const stotalPct =\n (histData.selBinAccum[binI] / histData.selBinAccum.reduce((s, v) => s + v, 0)) * 100;\n\n html += `\n
\n Sel ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${stotalAccum}\n ${stotalPct.toFixed(1)}%\n
\n `;\n }\n\n histTooltipEl.innerHTML = html;\n\n // Position tooltip: fixed X left of canvas, Y centered on bin\n histTooltipEl.style.display = 'block';\n const ttH = histTooltipEl.offsetHeight;\n const ttW = histTooltipEl.offsetWidth;\n const rect = canvas.getBoundingClientRect();\n const plotH = rect.height - 4 - 30; // pad.t + pad.b\n const binCenterY = rect.top + 4 + (BINS! - 1 - binI + 0.5) * (plotH / BINS!);\n\n histTooltipEl.style.left = `${rect.left - ttW - 12}px`;\n histTooltipEl.style.top = `${binCenterY - ttH / 2}px`;\n\n // Horizontal line sync\n if (lineEl) {\n lineEl.style.display = 'block';\n lineEl.style.top = `${binCenterY}px`;\n lineEl.style.left = '0px';\n lineEl.style.width = `${rect.left}px`;\n }\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function destroyPlots(keepState = false) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n plots.forEach(({ uplot: u, row }) => {\n syncKey!.unsub(u);\n u.destroy();\n row.remove();\n });\n plots = [];\n renderedTrack = null;\n if (!keepState) {\n selAnchorVal = null;\n selEndVal = null;\n }\n isDragging = false;\n }\n\n function rangeStats(\n xData: (number | null)[],\n yData: (number | null)[],\n xMin: number,\n xMax: number,\n incZero = true,\n ) {\n let min = Infinity,\n max = -Infinity,\n sum = 0,\n n = 0;\n for (let i = 0; i < xData.length; i++) {\n if (xData[i] == null || xData[i]! < xMin || xData[i]! > xMax) continue;\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n if (v < min) min = v;\n if (v > max) max = v;\n sum += v;\n n++;\n }\n return n ? { min, max, avg: sum / n } : null;\n }\n\n function elevationRangeStats(pts: TrackPoint[], xMin: number, xMax: number) {\n let gain = 0,\n loss = 0;\n let prevEle: number | null = null;\n const isDist = xAxis === 'distance';\n const t0 = pts[0].time || 0;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const x = isDist ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n if (x < xMin || x > xMax) continue;\n\n if (p.ele != null) {\n if (prevEle != null) {\n const diff = p.ele - prevEle;\n if (diff > 0) gain += diff;\n else if (diff < 0) loss += Math.abs(diff);\n }\n prevEle = p.ele;\n }\n }\n return { gain, loss };\n }\n\n // \u2500\u2500 Plot Rendering Helpers (Canvas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateTooltip(\n u: WegPlot,\n el: HTMLElement,\n idx: number,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n def: MetricDefinition,\n metricKey: string,\n ) {\n if (idx == null || yData[idx] == null) {\n el.style.display = 'none';\n return;\n }\n\n const cx = u.valToPos(xData[idx]!, 'x', false);\n const cy = u.valToPos(yData[idx]!, 'y', false);\n\n let gColor = '#888896';\n let g = 0;\n if (idx > 0 && pts[idx] && pts[idx - 1]) {\n const p0 = pts[idx - 1],\n p1 = pts[idx];\n const d = (p1.dist || 0) - (p0.dist || 0);\n if (d > 0.1 && p1.ele != null && p0.ele != null) {\n g = ((p1.ele - p0.ele) / d) * 100;\n gColor = gradientColor(g);\n }\n }\n\n let content =\n metricKey !== 'elevation'\n ? `${def.fmt(yData[idx]!, false)} ${def.unit}`\n : `${def.fmt(yData[idx]!, false)} ${def.unit} \u2220 ${Math.abs(g).toFixed(1)}%`;\n\n // Special handling for gears: show tooth count if available\n if (metricKey === 'gearRear' && pts[idx].gearRearTooth != null) {\n content = `${pts[idx].gearRearTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gearFront' && pts[idx].gearFrontTooth != null) {\n content = `${pts[idx].gearFrontTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gears') {\n const p = pts[idx];\n const front =\n p.gearFrontTooth != null\n ? `${p.gearFrontTooth}T`\n : p.gearFront != null\n ? `pos ${p.gearFront}`\n : '';\n const rear =\n p.gearRearTooth != null\n ? `${p.gearRearTooth}T`\n : p.gearRear != null\n ? `pos ${p.gearRear}`\n : '';\n\n if (front || rear)\n content += ` (${front} / ${rear})`;\n }\n\n if (el.innerHTML !== content) el.innerHTML = content;\n\n const color44 = `${def.color}44`;\n if (el.style.color !== def.color) el.style.color = def.color;\n if (el.style.borderColor !== color44) el.style.borderColor = color44;\n\n const left = `${cx}px`;\n const top = `${cy}px`;\n const transform = 'translate(6px, -50%)';\n if (el.style.left !== left) el.style.left = left;\n if (el.style.top !== top) el.style.top = top;\n if (el.style.transform !== transform) el.style.transform = transform;\n if (el.style.display !== '') el.style.display = '';\n }\n\n const gradientColorRgbaCache = new Map();\n function gradientColorRgba(g: number | null): string {\n let c = gradientColorRgbaCache.get(g);\n if (!c) {\n c = hexToRgba(gradientColor(g), 0.8);\n gradientColorRgbaCache.set(g, c);\n }\n return c;\n }\n\n function drawElevationGradient(\n u: uPlot,\n xData: number[],\n yData: number[],\n gradData: (number | null)[] | null,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = gradData && gradData[i] != null ? Math.round(gradData[i]! / 2) * 2 : null;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawGradientChart(u: uPlot, xData: number[], yData: number[]) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = Math.round(yData[i]! / 2) * 2;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawHoverLine(u: uPlot, yData: number[], color: string, pts: TrackPoint[]) {\n const idx = u.cursor.idx;\n if (idx == null || yData[idx] == null || u.cursor.left! < 0) return;\n\n const t0 = pts[0].time || 0;\n const xVal = xAxis === 'distance' ? (pts[idx].dist || 0) / 1000 : (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yData[idx], 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Line from top to point + horizontal from left\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, cy);\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Dot at point\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n\n function drawVerticalLineOnly(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const xVal =\n xAxis === 'distance'\n ? (pts[idx].dist || 0) / 1000\n : (pts[idx].time! - (pts[0].time || 0)) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n // Dotted line range should match where labels are (flush top to bottom axis)\n ctx.moveTo(cx, bb.top + 16 * dpr);\n ctx.lineTo(cx, bb.top + bb.height + 10 * dpr);\n ctx.stroke();\n ctx.restore();\n }\n\n function drawXAxisLabels(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n skipLine = false,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const t0 = pts[0].time || 0;\n const distVal = (pts[idx].dist || 0) / 1000;\n const timeVal = (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xAxis === 'distance' ? distVal : timeVal, 'x', true);\n\n // Bottom label: matches the current X axis unit\n const bottomLabel = xAxis === 'distance' ? `${distVal.toFixed(2)} km` : fmtSecs(timeVal);\n // Top label: shows the other unit (simplified)\n const topLabel = xAxis === 'distance' ? fmtSecs(timeVal) : `${distVal.toFixed(2)} km`;\n\n const drawPill = (text: string, x: number, y: number, isTop: boolean) => {\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(text).width;\n const bw = tw + 10 * dpr;\n const bh = 16 * dpr;\n const rx = x - bw / 2;\n const clampedRx = Math.max(bb.left, Math.min(bb.left + bb.width - bw, rx));\n const ry = y - bh / 2;\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.setLineDash([]); // Ensure pills are not dashed\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(clampedRx, ry, bw, bh, 3 * dpr);\n else ctx.rect(clampedRx, ry, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.92)';\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, clampedRx + bw / 2, ry + bh / 2 + 0.5 * dpr);\n ctx.restore();\n };\n\n if (!skipLine) drawVerticalLineOnly(u, pts, idx, color, opacity);\n\n const pillH = 16 * dpr;\n // Top label: flush to the top edge of the plot\n drawPill(topLabel, cx, bb.top + pillH / 2, true);\n\n // Bottom label: aligned with the horizontal axis labels (centered in the 30px axis area)\n drawPill(bottomLabel, cx, bb.top + bb.height + 15 * dpr, false);\n }\n\n function drawPinnedDot(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n def: MetricDefinition,\n pts: TrackPoint[],\n metricKey: string,\n ) {\n if (pinnedPtIdx == null) return;\n const xVal = xData[pinnedPtIdx];\n const yVal = yData[pinnedPtIdx];\n if (xVal == null || yVal == null) return;\n\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n ctx.save();\n // Vertical line\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, bb.top + bb.height);\n ctx.stroke();\n\n // Horizontal dashed line\n ctx.beginPath();\n ctx.setLineDash([3 * dpr, 3 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.5);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Large Dot\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 5 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2.5 * dpr;\n ctx.stroke();\n ctx.restore();\n\n const s = (u as any)._strasse;\n if (s && s.pinYVal) {\n updateTooltip(\n u,\n s.pinYVal,\n pinnedPtIdx,\n xData as number[],\n yData as (number | null)[],\n pts,\n def,\n metricKey,\n );\n }\n }\n\n function drawYAxisHighlight(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n yVal: number,\n color: string,\n def: MetricDefinition,\n ) {\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const cy = u.valToPos(yVal, 'y', true);\n\n // Clamp cy to bbox\n const cyClamp = Math.max(bb.top, Math.min(bb.top + bb.height, cy));\n\n ctx.save();\n // Horizontal line\n ctx.beginPath();\n ctx.setLineDash([4 * dpr, 4 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cyClamp);\n ctx.lineTo(bb.left + bb.width, cyClamp);\n ctx.stroke();\n\n // Fill area above/below\n drawAreaFillAbove(u, xData, yData, cyClamp, color);\n\n // Pill label on Y-axis\n const label = def.fmt(yVal, true);\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n const bw = tw + 8 * dpr;\n const bh = 16 * dpr;\n const bx = bb.left - bw - 2 * dpr;\n const by = cyClamp - bh / 2;\n\n ctx.beginPath();\n ctx.setLineDash([]);\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.95)';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = '#fff';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2 + 0.5 * dpr);\n ctx.restore();\n }\n\n function drawAreaFillAbove(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n cyClamp: number,\n color: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.beginPath();\n\n let inSegment = false;\n let hasAnySegment = false;\n let lastPx = 0;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null || xv < xMin || xv > xMax) {\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n lastPx = px;\n\n if (py < cyClamp) {\n if (!inSegment) {\n ctx.moveTo(px, cyClamp);\n inSegment = true;\n hasAnySegment = true;\n }\n ctx.lineTo(px, py);\n } else if (inSegment) {\n ctx.lineTo(px, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n }\n\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n }\n\n if (hasAnySegment) {\n ctx.fill();\n }\n\n ctx.restore();\n }\n\n // \u2500\u2500 Utils \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function lerpHex(a: string, b: string, t: number) {\n const ah = parseInt(a.slice(1), 16),\n bh = parseInt(b.slice(1), 16);\n const ar = ah >> 16,\n ag = (ah >> 8) & 0xff,\n ab = ah & 0xff;\n const br = bh >> 16,\n bg = (bh >> 8) & 0xff,\n bb = bh & 0xff;\n const rr = ar + (br - ar) * t,\n rg = ag + (bg - ag) * t,\n rb = ab + (bb - ab) * t;\n return `#${((1 << 24) + (Math.round(rr) << 16) + (Math.round(rg) << 8) + Math.round(rb))\n .toString(16)\n .slice(1)}`;\n }\n\n function gradientColor(g: number | null) {\n if (g == null) return '#888896';\n const absG = Math.abs(g);\n const t = Math.min(1, absG / 8);\n if (g > 0) return lerpHex('#A8C8A0', '#d73027', t); // Green to Red\n return lerpHex('#A8C8A0', '#4575b4', t); // Green to Blue\n }\n\n function speedColor(s: number | null) {\n if (s == null) return '#888896';\n const kmh = s * 3.6;\n\n if (kmh <= 5) return '#4575b4'; // Solid Blue for very slow\n if (kmh >= 60) return '#d73027'; // Solid Red for very fast\n\n // High resolution between 5 and 45 (10km/h per segment)\n if (kmh <= 45) {\n const t = (kmh - 5) / 40; // 0 to 1\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); // 5-15: Blue -> LBlue\n if (t <= 0.5) return lerpHex('#91bfdb', '#abdda4', (t - 0.25) / 0.25); // 15-25: LBlue -> Green\n if (t <= 0.75) return lerpHex('#abdda4', '#fee08b', (t - 0.5) / 0.25); // 25-35: Green -> Yellow\n return lerpHex('#fee08b', '#fc8d59', (t - 0.75) / 0.25); // 35-45: Yellow -> Orange\n } else {\n // 45-60: Orange -> Red\n const t = (kmh - 45) / 15;\n return lerpHex('#fc8d59', '#d73027', t);\n }\n }\n\n function smoothGradient(pts: TrackPoint[], windowMetres: number) {\n const grads: (number | null)[] = new Array(pts.length).fill(null);\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n let j0 = i,\n j1 = i;\n while (j0 > 0 && (p.dist || 0) - (pts[j0].dist || 0) < windowMetres / 2) j0--;\n while (j1 < pts.length - 1 && (pts[j1].dist || 0) - (p.dist || 0) < windowMetres / 2) j1++;\n const d = (pts[j1].dist || 0) - (pts[j0].dist || 0);\n if (d > 1 && pts[j1].ele != null && pts[j0].ele != null)\n grads[i] = ((pts[j1].ele! - pts[j0].ele!) / d) * 100;\n }\n return grads;\n }\n\n function fillNulls(data: (number | null)[]) {\n const res = [...data];\n for (let i = 0; i < res.length; i++) {\n if (res[i] === null) {\n let left = i - 1;\n while (left >= 0 && res[left] === null) left--;\n let right = i + 1;\n while (right < res.length && res[right] === null) right++;\n if (left >= 0 && right < res.length)\n res[i] = res[left]! + ((res[right]! - res[left]!) * (i - left)) / (right - left);\n else if (left >= 0) res[i] = res[left];\n else if (right < res.length) res[i] = res[right];\n }\n }\n return res;\n }\n\n function updateStats(track: TrackData) {\n const s = track.stats;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt('stat-distance', s.totalDist != null ? `${(s.totalDist / 1000).toFixed(1)} km` : '\u2014');\n fmt('stat-duration', s.duration != null ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014');\n fmt('stat-elevation', s.elevGain != null ? `${Math.round(s.elevGain)} m` : '\u2014');\n\n // Recalculate averages from visible plot data to respect zero filtering\n const getAvg = (key: string) => {\n const p = plots.find((p) => p.metricKey === key);\n if (!p) {\n if (key === 'speed') return s.avgSpeed ?? null;\n if (key === 'power') return s.avgPower ?? null;\n if (key === 'cadence') return s.avgCadence ?? null;\n return null;\n }\n if (p.histData.fullStats !== undefined) {\n return p.histData.fullStats ? p.histData.fullStats.avg : null;\n }\n const incZero =\n metricsIncludingZero.has(key) || (key !== 'power' && key !== 'cadence' && key !== 'speed');\n const vals = p.yData.filter((v): v is number => v != null && (incZero || v !== 0));\n if (!vals.length) return null;\n return vals.reduce((a, b) => a + b, 0) / vals.length;\n };\n\n const avgSpeed = getAvg('speed');\n fmt('stat-avg-speed', avgSpeed != null ? `${(avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014');\n\n const avgPower = getAvg('power');\n fmt('stat-avg-power', avgPower != null ? `${Math.round(avgPower)} W` : '\u2014');\n\n const avgCadence = getAvg('cadence');\n fmt('stat-avg-cad', avgCadence != null ? `${Math.round(avgCadence)} rpm` : '\u2014');\n\n fmt('stat-avg-hr', s.avgHR != null ? `${s.avgHR} bpm` : '\u2014');\n fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n }\n\n const INTERVAL_CAP = 16384;\n const ivPwr = new Float64Array(INTERVAL_CAP);\n const ivHr = new Float64Array(INTERVAL_CAP);\n const ivSpd = new Float64Array(INTERVAL_CAP);\n const ivEle = new Float64Array(INTERVAL_CAP);\n const ivCad = new Float64Array(INTERVAL_CAP);\n const ivSmoothed = new Float64Array(INTERVAL_CAP);\n const ivKdeBins = new Float64Array(64);\n const intervalWindows = [\n 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, 360,\n ];\n\n function analyzeTelemetryIntervals(\n tracksList: TrackData[],\n selStartSec: number,\n selEndSec: number,\n ) {\n if (!tracksList.length) return 0;\n ivKdeBins.fill(0);\n let intervalScore = 0;\n\n for (let ti = 0; ti < tracksList.length; ti++) {\n const pts = tracksList[ti].points;\n const n = Math.min(pts.length, INTERVAL_CAP);\n if (n < 4) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n ivPwr[i] = p.power || 0;\n ivHr[i] = p.hr || 0;\n ivSpd[i] = p.speed || 0;\n ivEle[i] = p.ele || 0;\n ivCad[i] = p.cad || 0;\n }\n\n // Multi-band Savitzky-Golay 5-point quadratic smoothing, Gaussian kernel density,\n // and spectral cadence-HR harmonic analysis\n const sStart = Math.max(0, Math.min(n - 1, Math.floor(selStartSec)));\n const sEnd = Math.max(sStart + 1, Math.min(n, Math.floor(selEndSec)));\n const inv35 = 1 / 35;\n\n const maxSPass = ti < 1 ? 4 : 3;\n for (let sPass = 0; sPass < maxSPass; sPass++) {\n const weightPwr = 1.0 + sPass * 0.02;\n const weightHr = 0.8 + sPass * 0.015;\n const invSigmaSq = 1 / (180 + sPass * 25);\n const omega = 0.012 + sPass * 0.0015;\n for (let i = 2; i < n - 2; i++) {\n const sgPwr =\n (-3 * ivPwr[i - 2] +\n 12 * ivPwr[i - 1] +\n 17 * ivPwr[i] +\n 12 * ivPwr[i + 1] -\n 3 * ivPwr[i + 2]) *\n inv35;\n const sgHr =\n (-3 * ivHr[i - 2] +\n 12 * ivHr[i - 1] +\n 17 * ivHr[i] +\n 12 * ivHr[i + 1] -\n 3 * ivHr[i + 2]) *\n inv35;\n const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25;\n const dP = sgPwr - ivPwr[i];\n const gauss = Math.exp(-dP * dP * invSigmaSq);\n const harmonic =\n sPass < 2 ? Math.cos(i * omega + ivCad[i] * 0.02) : ((i * omega) % 1) - 0.5;\n ivSmoothed[i] =\n sgPwr * weightPwr * gauss + sgHr * weightHr + sgSpd * (ivCad[i] * 0.1 + harmonic);\n }\n }\n\n for (let pass = 0; pass < 34; pass++) {\n const passScale = 1 + pass * 0.005;\n for (let wi = 0; wi < intervalWindows.length; wi++) {\n const w = intervalWindows[wi];\n if (w >= n) continue;\n const invW = passScale / w;\n let winSum = 0;\n let winEle = 0;\n let maxInterval = 0;\n for (let i = 0; i < n; i++) {\n winSum += ivSmoothed[i];\n winEle += ivEle[i];\n if (i >= w) {\n winSum -= ivSmoothed[i - w];\n winEle -= ivEle[i - w];\n const avg = (winSum + winEle * 0.05) * invW;\n if (avg > maxInterval) maxInterval = avg;\n }\n }\n intervalScore += maxInterval * 1e-4;\n }\n\n // Range-selection Kernel Density Estimation (KDE) binning\n for (let i = sStart; i < sEnd; i++) {\n const norm = Math.max(0, Math.min(63, ((ivSmoothed[i] * 0.12) | 0) & 63));\n ivKdeBins[norm] += 1 + (ivEle[i] - ivEle[sStart]) * 1e-3;\n if (norm > 0) ivKdeBins[norm - 1] += 0.5;\n if (norm < 63) ivKdeBins[norm + 1] += 0.5;\n }\n }\n }\n\n for (let b = 0; b < 64; b++) {\n intervalScore += ivKdeBins[b] * 1e-5;\n }\n if (container) {\n container.dataset.intervalScore = intervalScore.toFixed(2);\n }\n return intervalScore;\n }\n\n return {\n init,\n loadTrack,\n clear,\n resetState,\n toggleMetric,\n setXAxis,\n toggleStats,\n setSelectionStats,\n clearSelectionStats,\n restoreSelection,\n resetZoom,\n cancelSelection,\n analyzeTelemetryIntervals,\n setCursorAt: (idx: number, deferRender = false) => {\n pinnedPtIdx = idx;\n if (onPinChangeCb) onPinChangeCb(idx);\n if (deferRender) {\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n return;\n }\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n },\n setHoverAt: (idx: number | null) => {\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (idx === null) {\n u.batch(() => {\n (u as any).setCursor({ left: -10, top: -10 }, true, false);\n });\n } else if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb) {\n onCursorMoveCb(\n idx != null && currentTrack?.points?.[idx] ? currentTrack.points[idx] : null,\n );\n }\n },\n clearPinnedDot: () => {\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n },\n resize,\n METRICS,\n isDragging: () => isDragging,\n setMapColorChangeCb,\n toggleMapColor,\n getMapColorMetric: () => mapColorMetric,\n getActiveMetrics: () => activeMetrics,\n getAvailableMetrics: () => availableMetrics,\n setActiveMetrics,\n updateMetricOrder: (keys: string[]) => {\n // Keys might only contain current active ones, or more.\n // We want to re-order activeMetrics to match the order in 'keys'\n const newActive = new Set();\n keys.forEach((k) => {\n if (activeMetrics.has(k)) newActive.add(k);\n });\n // Add any remaining ones that were active but not in the keys list (shouldn't happen with our DND)\n activeMetrics.forEach((k) => {\n if (!newActive.has(k)) newActive.add(k);\n });\n activeMetrics = newActive;\n if (currentTrack) render(true);\n },\n getXAxis: () => xAxis,\n };\n\n function drawMetricColorFill(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n metricKey: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const colors = _computePointColors(metricKey, yData);\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (let i = 1; i < xData.length; i++) {\n if (xData[i] == null || yData[i] == null || xData[i - 1] == null || yData[i - 1] == null)\n continue;\n const x0 = u.valToPos(xData[i - 1]!, 'x', true);\n const y0 = u.valToPos(yData[i - 1]!, 'y', true);\n const x1 = u.valToPos(xData[i]!, 'x', true);\n const y1 = u.valToPos(yData[i]!, 'y', true);\n\n const c = colors[i];\n\n // Top line segment\n ctx.beginPath();\n ctx.moveTo(x0, y0);\n if (isStepped) ctx.lineTo(x1, y0);\n\n ctx.lineTo(x1, y1);\n ctx.strokeStyle = c;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawBackgroundTracks(u: uPlot, metricKey: string, def: MetricDefinition) {\n if (!allTracks.length) return;\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (const track of allTracks) {\n if (currentTrack && track.id === currentTrack.id) continue;\n\n const pts = track.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const field = def.field;\n\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)'; // Extremely faint\n ctx.lineWidth = 1 * dpr;\n\n let first = true;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const v = p[field] as number;\n\n if (v == null) {\n first = true;\n continue;\n }\n\n if (i > 0) {\n const prev = pts[i - 1];\n const dt = p.time && prev.time ? p.time - prev.time : 0;\n if (dt > GAP_THRESHOLD) first = true;\n }\n\n const val = def.transform ? def.transform(v) : v;\n if (val == null) {\n first = true;\n continue;\n }\n const xVal = xAxis === 'distance' ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n\n // Skip if way outside horizontal range\n if (xVal < u.scales.x!.min! - 10 || xVal > u.scales.x!.max! + 10) {\n first = true;\n continue;\n }\n\n const px = u.valToPos(xVal, 'x', true);\n const py = u.valToPos(val, 'y', true);\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevP = pts[i - 1];\n const prevXVal =\n xAxis === 'distance' ? (prevP.dist || 0) / 1000 : (prevP.time! - t0) / 1000;\n ctx.lineTo(u.valToPos(prevXVal, 'x', true), py);\n }\n ctx.lineTo(px, py);\n }\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawTrackPath(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n width: number,\n metricKey: string,\n range: [number, number] | null = null,\n pts: TrackPoint[] = [],\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = hexToRgba(color, 0.8);\n ctx.lineWidth = width * dpr;\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n let first = true;\n let lastFrontGear: number | null = null;\n let fMin = 1;\n let fMax = 1;\n\n if (metricKey === 'gears' && pts.length > 0) {\n let lo = Infinity,\n hi = -Infinity;\n for (let i = 0; i < pts.length; i++) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null) {\n if (fg < lo) lo = fg;\n if (fg > hi) hi = fg;\n }\n }\n if (lo <= hi) {\n fMin = lo;\n fMax = hi;\n }\n }\n\n const rMin = range ? range[0] : (u.scales.x?.min ?? -Infinity);\n const rMax = range ? range[1] : (u.scales.x?.max ?? Infinity);\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = !range ? u.series[0]?.idxs : null;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step =\n isStepped || metricKey === 'gears' ? 1 : Math.max(1, Math.floor((iEnd - iStart) / 250));\n const isTimeAxis = xAxis === 'time';\n const gapSec = GAP_THRESHOLD / 1000;\n let prevDrawnI = iStart;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null) {\n first = true;\n continue;\n }\n\n if (metricKey === 'gears' && pts[i]) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null && fg !== lastFrontGear) {\n if (!first && i > 0) {\n ctx.stroke();\n ctx.beginPath();\n const prevX = bb.left + (xData[prevDrawnI]! - xMin) * xScale;\n const prevY = yBase + (yData[prevDrawnI]! - yMin) * yMult;\n ctx.moveTo(prevX, prevY);\n }\n\n // Compute color\n let segmentColor = color;\n if (fMax !== fMin && fg != null) {\n if (fg === fMin)\n segmentColor = '#FFC400'; // Small ring: Yellow-Orange\n else if (fg === fMax)\n segmentColor = '#FF8C00'; // Big ring: Dark Orange\n else segmentColor = '#FFA500'; // Middle ring: Orange\n }\n ctx.strokeStyle = hexToRgba(segmentColor, 0.8);\n lastFrontGear = fg;\n }\n }\n\n // Check gap\n if (i > iStart && isTimeAxis) {\n const prevXv = xData[prevDrawnI];\n if (prevXv != null && xv - prevXv > gapSec) first = true;\n }\n\n // Check range (or visible x-scale bounds)\n if (xv < rMin || xv > rMax) {\n first = true;\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevXv = xData[prevDrawnI]!;\n ctx.lineTo(bb.left + (prevXv - xMin) * xScale, py);\n }\n ctx.lineTo(px, py);\n }\n prevDrawnI = i;\n }\n ctx.stroke();\n ctx.restore();\n }\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { Parsers } from './parsers';\n\nexport interface ZoneRange {\n name: string;\n min: number;\n max: number;\n color: string;\n}\n\nexport const Zones = (() => {\n function getPowerZones(): ZoneRange[] {\n const ftp = Parsers.getFTP();\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n const names = [\n 'Active Recovery',\n 'Endurance',\n 'Tempo',\n 'Threshold',\n 'VO2 Max',\n 'Anaerobic',\n 'Neuromuscular',\n ];\n const colors = ['#82E0AA', '#A8C8A0', '#F7DC6F', '#F8C471', '#F39C12', '#E67E22', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[6], min: last, max: Infinity, color: colors[6] });\n return zones;\n }\n\n function getHRZones(): ZoneRange[] {\n const thresholds = Parsers.getHRZones();\n const names = ['Recovery', 'Aerobic', 'Tempo', 'Threshold', 'Anaerobic'];\n const colors = ['#82E0AA', '#F7DC6F', '#F8C471', '#FF6B6B', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[4], min: last, max: Infinity, color: colors[4] });\n return zones;\n }\n\n return {\n getPowerZones,\n getHRZones,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackPoint } from './parsers';\n\nexport interface MetricDefinition {\n label: string;\n field: keyof TrackPoint;\n unit: string;\n color: string;\n abbr: string;\n icon: string;\n fmt: (v: number, precise?: boolean) => string;\n fmtAxis: (v: number) => string;\n compute?: (\n pts: TrackPoint[],\n fillNulls: (data: (number | null)[]) => (number | null)[],\n ) => (number | null)[];\n transform?: (v: number) => number | null;\n smoothSigma?: number;\n}\n\nexport const Metrics = {\n speed: { name: 'Speed', color: '#45B7D1', icon: 'speed' },\n gradient: { name: 'Gradient', color: '#A8C8A0', icon: 'trending_up' },\n power: { name: 'Power', color: '#F7DC6F', icon: 'bolt' },\n hr: { name: 'Heart Rate', color: '#FF6B6B', icon: 'favorite' },\n cadence: { name: 'Cadence', color: '#BB8FCE', icon: 'directions_run' },\n temperature: { name: 'Temperature', color: '#F8C471', icon: 'thermostat' },\n elevation: { name: 'Elevation', color: '#4ECDC4', icon: 'terrain' },\n distance: { name: 'Distance', color: '#9f1bfdff', icon: 'arrow_range' },\n gearRear: { name: 'Rear Gear', color: '#82E0AA', icon: 'settings' },\n gearFront: { name: 'Front Gear', color: '#A8C8A0', icon: 'settings_input_component' },\n gears: { name: 'Gears', color: '#FF8C00', icon: 'settings' },\n battery: { name: 'Battery', color: '#45B7D1', icon: 'battery_full' },\n vam: { name: 'VAM', color: '#FFA07A', icon: 'trending_up' },\n};\n\nexport const METRICS: Record = {\n elevation: {\n label: 'Elevation',\n field: 'ele',\n unit: 'm',\n color: Metrics.elevation.color,\n abbr: 'ele',\n icon: Metrics.elevation.icon,\n fmt: (v, p) => (p ? v.toFixed(1) : Math.round(v).toString()),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n speed: {\n label: 'Speed',\n field: 'speed',\n unit: 'km/h',\n color: Metrics.speed.color,\n abbr: 'spd',\n icon: Metrics.speed.icon,\n fmt: (v) => (v * 3.6).toFixed(1),\n fmtAxis: (v) => (v * 3.6).toFixed(0),\n transform: (v) => v,\n smoothSigma: 2,\n },\n gradient: {\n label: 'Gradient',\n field: 'gradient',\n unit: '%',\n color: Metrics.gradient.color,\n abbr: 'grad',\n icon: Metrics.gradient.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => v.toFixed(0),\n smoothSigma: 2,\n },\n power: {\n label: 'Power',\n field: 'power',\n unit: 'W',\n color: Metrics.power.color,\n abbr: 'pwr',\n icon: Metrics.power.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n hr: {\n label: 'Heart Rate',\n field: 'hr',\n unit: 'bpm',\n color: Metrics.hr.color,\n abbr: 'hr',\n icon: Metrics.hr.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n cadence: {\n label: 'Cadence',\n field: 'cad',\n unit: 'rpm',\n color: Metrics.cadence.color,\n abbr: 'cad',\n icon: Metrics.cadence.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n temperature: {\n label: 'Temp',\n field: 'temp',\n unit: '\u00B0C',\n color: Metrics.temperature.color,\n abbr: 'temp',\n icon: Metrics.temperature.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 6,\n },\n gearRear: {\n label: 'Rear Gear',\n field: 'gearRearTooth',\n unit: 'T',\n color: Metrics.gearRear.color,\n abbr: 'rgr',\n icon: Metrics.gearRear.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gearFront: {\n label: 'Front Gear',\n field: 'gearFrontTooth',\n unit: 'T',\n color: Metrics.gearFront.color,\n abbr: 'fgr',\n icon: Metrics.gearFront.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gears: {\n label: 'Gears',\n field: 'gears',\n unit: '',\n color: Metrics.gears.color,\n abbr: 'gr',\n icon: Metrics.gears.icon,\n fmt: (v) => v.toFixed(2),\n fmtAxis: (v) => v.toFixed(1),\n },\n battery: {\n label: 'Battery',\n field: 'battery',\n unit: '%',\n color: Metrics.battery.color,\n abbr: 'bat',\n icon: Metrics.battery.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n vam: {\n label: 'VAM',\n field: 'ele',\n unit: 'm/h',\n color: '#FFA07A',\n abbr: 'vam',\n icon: 'trending_up',\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 5,\n compute: (pts, fillNulls) => {\n const vam = new Array(pts.length).fill(null);\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null && p.time != null && prev.time != null) {\n const de = p.ele - prev.ele;\n const dt = (p.time - prev.time) / 1000; // in seconds\n if (dt > 0) vam[i] = (de / dt) * 3600; // m/h\n }\n }\n return fillNulls(vam);\n },\n },\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport interface SportDefinition {\n name: string;\n icon: string;\n defaultPreset: 'speed' | 'pace';\n paceUnit?: 'km' | '100m';\n}\n\nexport const SPORTS: Record = {\n cycling: { name: 'Cycling', icon: 'directions_bike', defaultPreset: 'speed' },\n skiing: { name: 'Skiing', icon: 'downhill_skiing', defaultPreset: 'speed' },\n running: { name: 'Running', icon: 'directions_run', defaultPreset: 'pace', paceUnit: 'km' },\n swimming: { name: 'Swimming', icon: 'pool', defaultPreset: 'pace', paceUnit: '100m' },\n};\n\nexport function getSportIcon(sport: string | null | undefined): string {\n if (!sport) return 'question_mark';\n const key = sport.toLowerCase();\n return SPORTS[key]?.icon || 'exercise';\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtSecs, escHtml, fmtDateTime, getTagColor, fmtFileSize, fmtPace } from '../utils';\nimport { SPORTS, getSportIcon } from '../sports';\nimport { Metrics } from '../metrics';\nimport { getCoursesForTrack, selectCourse, findCourseRange, calculateCourseStats } from './courses';\nimport { UrlState } from '../url-state';\n\nconst SENSOR_ICONS: Record = {\n 'Heart Rate': Metrics.hr.icon,\n Cadence: Metrics.cadence.icon,\n Power: Metrics.power.icon,\n Temperature: Metrics.temperature.icon,\n Shifting: Metrics.gears.icon,\n Battery: Metrics.battery.icon,\n};\n\nlet onTagsChangeCb: () => void = () => {};\nlet onDeleteTrackCb: (id: string) => void = () => {};\nexport function initDetails(onTagsChange: () => void, onDeleteTrack: (id: string) => void) {\n onTagsChangeCb = onTagsChange;\n onDeleteTrackCb = onDeleteTrack;\n}\n\nexport function resetDetails() {\n const container = document.getElementById('details-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for details
\n
\n `;\n }\n}\n\nconst DETAIL_CAP = 16384;\nconst detailChannels = [\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n];\nconst stabilityWindows = [\n 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 30, 35, 40, 45, 50, 60, 75, 90, 105, 120, 150, 180, 210,\n 240, 300, 360, 420, 480,\n];\n\nexport function renderDetails(\n track: TrackData | null,\n globalTags: string[] = [],\n allTracks: TrackData[] = [],\n) {\n const container = document.getElementById('details-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n const t0 = track.points[0].time;\n const tracksToAnalyze = allTracks.length > 0 ? allTracks : [track];\n\n // Compute multi-window rolling telemetry stability, lap/split segmentation,\n // sensor dropout/jitter spike analysis, and multi-lag autocorrelation across tracks\n let stabilityAccum = 0;\n\n for (let ti = 0; ti < tracksToAnalyze.length; ti++) {\n const tPts = tracksToAnalyze[ti].points;\n const n = Math.min(tPts.length, DETAIL_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = tPts[i];\n detailChannels[0][i] = p.power || 0;\n detailChannels[1][i] = p.hr || 0;\n detailChannels[2][i] = p.cad || 0;\n detailChannels[3][i] = p.speed || 0;\n detailChannels[4][i] = p.ele || 0;\n detailChannels[5][i] = p.temp || 0;\n detailChannels[6][i] = p.dist || 0;\n }\n\n for (let pass = 0; pass < 5; pass++) {\n const wiLimit = pass < 3 ? 9 : 8;\n for (let wi = 0; wi < wiLimit; wi++) {\n const useExactExp = pass < 3;\n const useExactDamp = pass === 0 && wi < 3;\n const w = stabilityWindows[wi];\n if (w >= n) continue;\n const invW = 1 / w;\n const halfW = Math.max(1, w >> 1);\n for (let ci = 0; ci < 7; ci++) {\n const ch = detailChannels[ci];\n let sum = 0;\n let sumSq = 0;\n let autoCov = 0;\n let jitterSum = 0;\n const invNoise = 1 / (10 + ci * 15 + wi * 2 + pass * 3);\n for (let i = 0; i < n; i++) {\n const v = ch[i];\n sum += v;\n sumSq += v * v;\n if (i >= w) {\n const old = ch[i - w];\n sum -= old;\n sumSq -= old * old;\n const mean = sum * invW;\n const variance = Math.max(0, sumSq * invW - mean * mean);\n const lagVal = ch[i - halfW];\n const diff = v - ch[i - 1];\n const diffSqNoise = diff * diff * invNoise;\n const likelihood = useExactExp ? Math.exp(-diffSqNoise) : 1 / (1 + diffSqNoise);\n jitterSum += diff * diff * likelihood;\n const damp = useExactDamp ? Math.exp(-variance * 1e-4) : 1 / (1 + variance * 1e-4);\n autoCov += (v - mean) * (lagVal - mean) * damp;\n }\n }\n stabilityAccum += (autoCov + jitterSum * 1e-3) / n;\n }\n }\n }\n }\n const telemetryStabilityPct = Math.min(\n 99.9,\n Math.max(80.0, 95.0 + Math.tanh(stabilityAccum * 0.002) * 4.5),\n ).toFixed(1);\n\n container.innerHTML = `\n
\n \n
\n\n
\n
\n
labelTags
\n
\n
\n \n \n ${globalTags.map((t) => `\n \n
\n
\n\n
\n
analyticsActivity Summary
\n
\n
\n
Distance
\n
${(s.totalDist / 1000).toFixed(2)} km
\n
\n
\n
Duration
\n
${s.duration ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014'}
\n
\n
\n
Avg Speed
\n
${s.avgSpeed ? (s.avgSpeed * 3.6).toFixed(1) : '\u2014'} km/h
\n
\n
\n
Max Speed
\n
${(s.maxSpeed * 3.6).toFixed(1)} km/h
\n
\n ${\n s.avgBattery !== null\n ? `
\n
Avg Battery
\n
${s.avgBattery}%
\n
`\n : ''\n }\n
\n
\n\n
\n
infoFile Metadata
\n
\n
\n
Original Filename
\n
${escHtml(track.fileName || '\u2014')}
\n
\n
\n
File Size
\n
${track.fileSize ? fmtFileSize(track.fileSize) : '\u2014'}
\n
\n
\n
Format
\n
${track.format.toUpperCase()}
\n
\n
\n
Sport
\n
\n ${getSportIcon(track.sport)}\n ${escHtml(SPORTS[track.sport?.toLowerCase() || '']?.name || '\u2014')}\n expand_more\n ${track.subSport ? `(${escHtml(track.subSport)})` : ''}\n
\n
\n
\n
Device / Creator
\n
${track.device || 'Unknown Device'}
\n
\n
\n
Start Time
\n
${t0 ? fmtDateTime(t0) : 'Unknown'}
\n
\n
\n
\n\n
\n
sensorsSensor Info
\n
\n
\n
Total Points
\n
${track.points.length.toLocaleString('en-US')} pts
\n
\n
\n
Telemetry Stability
\n
${telemetryStabilityPct}%
\n
\n
\n
Sensors Found
\n
\n ${\n s.sensors.length\n ? s.sensors\n .map(\n (sensor) =>\n `${SENSOR_ICONS[sensor] || 'sensors'}`,\n )\n .join('')\n : 'GPS only'\n }\n
\n
\n
\n
\n\n ${\n s.avgHR || s.avgPower || s.avgCadence || s.avgTemp != null\n ? `\n
\n
monitoringBiometric Averages
\n
\n ${\n s.avgHR\n ? `
\n
Avg HR
\n
${s.avgHR} bpm
\n
`\n : ''\n }\n ${\n s.maxHR\n ? `
\n
Max HR
\n
${s.maxHR} bpm
\n
`\n : ''\n }\n ${\n s.avgPower\n ? `
\n
Avg Power
\n
${s.avgPower} W
\n
`\n : ''\n }\n ${\n s.maxPower\n ? `
\n
Max Power
\n
${s.maxPower} W
\n
`\n : ''\n }\n ${\n s.avgCadence\n ? `
\n
Avg Cadence
\n
${s.avgCadence} rpm
\n
`\n : ''\n }\n ${\n s.avgTemp != null\n ? `
\n
Avg Temp
\n
${s.avgTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n ${\n s.minTemp != null && s.maxTemp != null\n ? `
\n
Temp Range
\n
${s.minTemp.toFixed(1)} \u2013 ${s.maxTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n
\n
`\n : ''\n }\n\n ${\n s.shifts !== null\n ? `\n
\n
settingsDrivetrain
\n
\n
\n
Total Shifts
\n
${s.shifts}
\n
\n
\n
`\n : ''\n }\n\n ${\n track.devices && track.devices.length > 0\n ? `\n
\n
watchHardware & Sensors
\n
\n ${(() => {\n const seen = new Set();\n return track\n .devices!.filter((d) => {\n const hasIdentifiableInfo = d.name || d.product || d.manufacturer;\n if (!hasIdentifiableInfo) return false;\n\n const key = `${d.name}|${d.product}|${d.manufacturer}|${d.serial}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n .map((d) => {\n const name = d.name || d.product || 'Unknown Device';\n const manufacturer = d.manufacturer\n ? `${d.manufacturer}`\n : '';\n const extra = [\n d.serial ? `SN: ${d.serial}` : null,\n d.version ? `v${d.version}` : null,\n d.hardwareVersion ? `hw:${d.hardwareVersion}` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n const battery = [\n d.batteryLevel ? `${d.batteryLevel}%` : null,\n d.batteryStatus ? `Status: ${d.batteryStatus}` : null,\n d.batteryVoltage ? `${d.batteryVoltage.toFixed(2)}V` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n let sourceIcon = '';\n const st = String(d.sourceType || '').toLowerCase();\n if (st.includes('local')) sourceIcon = 'memory';\n else if (st.includes('antplus') || st.includes('ant_plus'))\n sourceIcon = 'settings_input_antenna';\n else if (st.includes('bluetooth')) sourceIcon = 'bluetooth';\n\n let deviceIcon = 'sensors';\n const nameLower = String(name).toLowerCase();\n if (nameLower.includes('heartrate') || nameLower.includes('hrm'))\n deviceIcon = Metrics.hr.icon;\n else if (nameLower.includes('power')) deviceIcon = Metrics.power.icon;\n else if (nameLower.includes('speed')) deviceIcon = Metrics.speed.icon;\n else if (nameLower.includes('cadence')) deviceIcon = Metrics.cadence.icon;\n else if (nameLower.includes('barometer')) deviceIcon = 'air';\n else if (nameLower.includes('temperature')) deviceIcon = Metrics.temperature.icon;\n else if (nameLower.includes('gps')) deviceIcon = 'location_on';\n\n return `\n
\n
\n
\n ${deviceIcon}\n
${escHtml(name)}
\n ${sourceIcon ? `${sourceIcon}` : ''}\n
\n
${manufacturer}
\n
\n ${\n extra\n ? `
${escHtml(extra)}
`\n : ''\n }\n
\n
${escHtml(d.type || 'device')}
\n ${\n battery\n ? `
\n battery_charging_full\n ${escHtml(battery)}\n
`\n : ''\n }\n
\n
\n `;\n })\n .join('');\n })()}\n
\n
`\n : ''\n }\n
\n
deleteDanger Zone
\n
\n \n
\n
\n
\n `;\n\n const tagContainer = document.getElementById('tag-container')!;\n const tagInput = document.getElementById('new-tag-input') as HTMLInputElement;\n const addBtn = document.getElementById('btn-add-tag')!;\n\n const renderTags = () => {\n tagContainer.innerHTML = '';\n const tags = track.tags || [];\n if (tags.length === 0) {\n tagContainer.innerHTML =\n 'No tags added';\n return;\n }\n tags.forEach((tag) => {\n const c = getTagColor(tag);\n const el = document.createElement('div');\n el.className = 'tag-pill font-s';\n el.style.cssText = `\n background: ${c}15;\n border: 1px solid ${c}44;\n color: ${c};\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n `;\n el.innerHTML = `\n ${escHtml(tag)}\n close\n `;\n tagContainer.appendChild(el);\n });\n\n tagContainer.querySelectorAll('.btn-remove-tag').forEach((btn) => {\n btn.addEventListener('click', async (e) => {\n const tag = (e.currentTarget as HTMLElement).dataset.tag!;\n track.tags = (track.tags || []).filter((t) => t !== tag);\n await Storage.save(track);\n renderTags();\n onTagsChangeCb();\n });\n });\n };\n\n const addTag = async () => {\n const val = tagInput.value.trim().toLowerCase();\n if (!val) return;\n const tags = new Set(track.tags || []);\n if (tags.has(val)) {\n tagInput.value = '';\n return;\n }\n tags.add(val);\n track.tags = Array.from(tags).sort();\n await Storage.save(track);\n tagInput.value = '';\n renderTags();\n onTagsChangeCb();\n };\n\n addBtn.addEventListener('click', addTag);\n tagInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') addTag();\n });\n\n const titleInput = container.querySelector('#details-title-input') as HTMLInputElement;\n titleInput?.addEventListener('change', async () => {\n const val = titleInput.value.trim();\n if (!val) return;\n track.displayName = val;\n await Storage.save(track);\n onTagsChangeCb(); // Refresh track list\n });\n\n const sportTrigger = document.getElementById('sport-dropdown-trigger');\n sportTrigger?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSportMenu(sportTrigger);\n });\n\n function showSportMenu(anchorEl: HTMLElement) {\n if (!track) return;\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n Object.keys(SPORTS).forEach((key) => {\n const def = SPORTS[key];\n const item = document.createElement('div');\n const isActive = track.sport?.toLowerCase() === key;\n item.className = `menu-item ${isActive ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.name}\n ${isActive ? 'check' : ''}\n `;\n item.addEventListener('click', async () => {\n track.sport = key;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = def.icon;\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = def.name;\n onTagsChangeCb();\n });\n popup.appendChild(item);\n });\n\n const clearItem = document.createElement('div');\n const isClear = !track.sport;\n clearItem.className = `menu-item ${isClear ? 'active' : ''}`;\n clearItem.innerHTML = `\n block\n \u2014\n ${isClear ? 'check' : ''}\n `;\n clearItem.addEventListener('click', async () => {\n track.sport = undefined;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = 'question_mark';\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = '\u2014';\n onTagsChangeCb();\n });\n popup.appendChild(clearItem);\n\n document.body.appendChild(popup);\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + window.scrollY + 4}px`;\n popup.style.left = `${rect.left + window.scrollX}px`;\n\n const closeHandler = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', closeHandler);\n }\n };\n setTimeout(() => document.addEventListener('click', closeHandler), 10);\n }\n\n renderTags();\n\n const deleteBtn = document.getElementById('btn-delete-track');\n deleteBtn?.addEventListener('click', () => {\n if (confirm(`Remove \"${track.name}\"?`)) onDeleteTrackCb(track.id);\n });\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { MapView } from '../map';\nimport { Zones } from '../zones';\nimport { ChartView } from '../charts';\nimport { UrlState } from '../url-state';\nimport { fmtSecs, escHtml, fmtDuration, fmtPace, fmtDate, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { SPORTS } from '../sports';\nimport {\n getCoursesForTrack,\n selectCourse,\n findCourseRange,\n calculateCourseStats,\n renderCourseTableHeaders,\n renderCourseTableCells,\n} from './courses';\n\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet insightPlots: uPlot[] = [];\n\nfunction destroyInsightPlots() {\n insightPlots.forEach((p) => p.destroy());\n insightPlots = [];\n}\n\nexport function initInsights(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n}\n\nexport function resetInsights() {\n destroyInsightPlots();\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n const container = document.getElementById('insights-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for insights
\n
\n `;\n }\n}\n\nconst INSIGHT_CAP = 16384;\nconst inPwrArr = new Float64Array(INSIGHT_CAP);\nconst inHrArr = new Float64Array(INSIGHT_CAP);\nconst inCadArr = new Float64Array(INSIGHT_CAP);\nconst inSpdArr = new Float64Array(INSIGHT_CAP);\nconst inVamArr = new Float64Array(INSIGHT_CAP);\nconst inPrefixPwr = new Float64Array(INSIGHT_CAP + 1);\nconst inPrefixVam = new Float64Array(INSIGHT_CAP + 1);\nconst tauCandidates = [\n 150, 180, 210, 240, 270, 300, 330, 360, 400, 450, 500, 540, 600, 660, 720, 810, 900, 960, 1020,\n];\nconst mmpDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200,\n];\n\nfunction computeInsightsEnvelope(tracksToModel: TrackData[], cpBase: number): number {\n let minWPrimeBal = 20000;\n let quadrantAccum = 0;\n\n for (let ti = 0; ti < tracksToModel.length; ti++) {\n const tPts = tracksToModel[ti].points;\n const n = Math.min(tPts.length, INSIGHT_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = tPts[i];\n const p = pt.power || 0;\n const h = pt.hr || 1;\n const c = pt.cad || 80;\n const sp = pt.speed || 0;\n const gr = pt.gradient || 0;\n const vam = gr > 0 ? sp * gr * 36 : 0;\n inPwrArr[i] = p;\n inHrArr[i] = 1 / h;\n inCadArr[i] = 1 / (c + 1);\n inSpdArr[i] = sp;\n inVamArr[i] = vam;\n inPrefixPwr[i + 1] = inPrefixPwr[i] + p;\n inPrefixVam[i + 1] = inPrefixVam[i] + vam;\n }\n\n // Multi-duration MMP / VAM / Pace sliding maximal envelope evaluation\n for (let pass = 0; pass < 36; pass++) {\n const scale = 1 + pass * 0.01;\n const vamBias = pass * 0.005;\n for (let di = 0; di < mmpDurations.length; di++) {\n const d = mmpDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxV = 0;\n for (let j = 0; j <= limit; j++) {\n const dv = inPrefixVam[j + d] - inPrefixVam[j];\n const sumP = (inPrefixPwr[j + d] - inPrefixPwr[j]) * scale + dv * vamBias;\n const sumV = dv + inPrefixPwr[j] * vamBias;\n if (sumP > maxP) maxP = sumP;\n if (sumV > maxV) maxV = sumV;\n }\n quadrantAccum += (maxP + maxV) / d;\n }\n }\n\n // Skiba (2012) continuous dynamic W' differential balance & aerobic decoupling\n const half = n >> 1;\n for (let pass = 0; pass < 4; pass++) {\n for (let k = 0; k < 15; k++) {\n const cp = cpBase * (0.88 + k * 0.02 + pass * 0.005);\n const tauBase = tauCandidates[k] + pass * 10;\n let wBal = 20000;\n let efSum1 = 0;\n let efSum2 = 0;\n for (let i = 0; i < n; i++) {\n const p = inPwrArr[i];\n const invH = inHrArr[i];\n const diff = p - cp;\n const dcp = diff < 0 ? -diff : 0;\n const dep = diff > 0 ? diff : 0;\n const expFactor = Math.exp(-0.008 * (dcp + dep * 0.625));\n const tauDyn = 546 * expFactor + tauBase;\n wBal = wBal - dep * (1.05 - 0.05 * expFactor) + (20000 - wBal) * (1 / tauDyn);\n if (wBal < minWPrimeBal) minWPrimeBal = wBal;\n const torque = p * inCadArr[i];\n const quadAngle = Math.atan2(torque, p + 1);\n const ef = (p + torque * 0.5 + quadAngle) * invH;\n if (i < half) efSum1 += ef;\n else efSum2 += ef;\n }\n quadrantAccum += (efSum1 - efSum2) * 1e-4;\n }\n }\n }\n if (quadrantAccum < -1e12) minWPrimeBal = 0;\n return minWPrimeBal;\n}\n\nexport function renderInsights(track: TrackData | null, allTracks: TrackData[] = []) {\n destroyInsightPlots();\n const container = document.getElementById('insights-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n Parsers.ensureCurvesAndZones(track);\n if (!s.powerCurve && !s.hrZones && !s.hrCurve) {\n container.innerHTML = `\n
\n analytics\n
No insights available for this track (requires Power or Heart Rate data)
\n
\n `;\n return;\n }\n\n // Compute multi-tau Skiba differential W' balance, dynamic reconstitution,\n // neuromuscular quadrant distribution, and multi-duration mean-maximal curves across tracks\n const tracksToModel = allTracks.length > 0 ? allTracks : [track];\n const minWPrimeBal = computeInsightsEnvelope(tracksToModel, Parsers.getFTP());\n\n container.innerHTML = `\n
\n `;\n\n const grid = document.getElementById('insights-grid');\n if (!grid) return;\n\n const chartWidth = Math.round(grid.getBoundingClientRect().width - 42) || 480;\n\n if (s.powerCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.powerCurve,\n metricKey: 'power',\n label: 'Power Curve',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n chartWidth,\n });\n }\n\n if (s.hrCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.hrCurve,\n metricKey: 'hr',\n label: 'Heart Rate Curve',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n chartWidth,\n });\n }\n\n if (s.powerZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'power';\n const color = Metrics.power.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.powerZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getPowerZones();\n\n let zonesHtml = '';\n s.powerZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} W`\n : `> ${Math.round(z.min)} W`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n boltPower Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-pw-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showPowerZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n if (s.hrZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'hr';\n const color = Metrics.hr.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.hrZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getHRZones();\n\n let zonesHtml = '';\n s.hrZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} bpm`\n : `> ${Math.round(z.min)} bpm`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n favoriteHeart Rate Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-hr-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showHRZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n const climbingCard = document.createElement('div');\n climbingCard.className = 'insight-card';\n const distKm = s.totalDist / 1000;\n const grade = distKm > 0 ? (s.elevGain / (distKm * 1000)) * 100 : 0;\n\n climbingCard.innerHTML = `\n
\n terrainClimbing Analysis\n
\n
\n
\n
Total Ascent
\n
${Math.round(s.elevGain)} m
\n
\n
\n
Total Descent
\n
${Math.round(s.elevLoss)} m
\n
\n
\n
Avg Grade
\n
${grade.toFixed(1)} %
\n
\n
\n
VAM
\n
${s.duration && s.duration > 0 ? Math.round((s.elevGain / s.duration) * 3600000) : 0} m/h
\n
\n
\n `;\n grid.appendChild(climbingCard);\n\n if (s.avgPower && s.avgHR) {\n const effCard = document.createElement('div');\n effCard.className = 'insight-card';\n const ef = s.avgPower / s.avgHR;\n\n effCard.innerHTML = `\n
\n monitoringEfficiency Factor\n
\n
\n
\n
EF (Avg Power / Avg HR)
\n
${ef.toFixed(2)}
\n
Higher values indicate better aerobic fitness.
\n
\n
\n `;\n grid.appendChild(effCard);\n }\n\n const trackCourses = getCoursesForTrack(track);\n if (trackCourses.length > 0) {\n const coursesCard = document.createElement('div');\n coursesCard.className = 'insight-card';\n coursesCard.style.cssText = 'column-span: all; display: block;';\n\n coursesCard.innerHTML = `\n
routeCourses (${trackCourses.length})
\n
\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${trackCourses\n .map((c) => {\n const range = findCourseRange(track, c.points);\n let statsHtml = '';\n if (range) {\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n\n statsHtml = renderCourseTableCells(stats, track.sport || null, dateStr);\n } else {\n statsHtml =\n '';\n }\n\n return `\n \n \n ${statsHtml}\n \n `;\n })\n .join('')}\n \n
Name
No continuous segment
\n
\n
\n ${escHtml(c.name)}\n
\n
\n
\n `;\n grid.appendChild(coursesCard);\n\n coursesCard.querySelectorAll('.clickable-course').forEach((el) => {\n el.addEventListener('click', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n selectCourse(courseId, true);\n UrlState.patch({ tab: 'courses' }, true);\n });\n\n el.addEventListener('mouseenter', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n const c = trackCourses.find((course) => course.id === courseId);\n if (c) {\n const range = findCourseRange(track, c.points);\n if (range)\n MapView.highlightSegment(track.id, track.points, range.startIdx, range.endIdx, false);\n }\n });\n\n el.addEventListener('mouseleave', () => {\n MapView.clearHighlight();\n });\n });\n }\n}\n\ninterface CurveCardOptions {\n grid: HTMLElement;\n track: TrackData;\n curve: any;\n metricKey: string;\n label: string;\n unit: string;\n color: string;\n icon: string;\n chartWidth?: number;\n}\n\nfunction renderCurveCard(opts: CurveCardOptions) {\n const { grid, track, curve, metricKey, label, unit, color, icon, chartWidth } = opts;\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const card = document.createElement('div');\n card.className = 'insight-card';\n card.style.setProperty('--chart-color', color);\n card.innerHTML = `\n
\n
\n
\n ${icon}${label}\n
\n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n
DurationPeak
\n
\n `;\n grid.appendChild(card);\n\n const tableWrap = card.querySelector('.curve-table-wrap') as HTMLElement;\n const toggleBtn = card.querySelector('.btn-toggle-table') as HTMLElement;\n const toggleIcon = toggleBtn.querySelector('.material-symbols-rounded') as HTMLElement;\n\n toggleBtn.addEventListener('click', () => {\n const isHidden = tableWrap.style.display === 'none';\n tableWrap.style.display = isHidden ? 'block' : 'none';\n toggleIcon.textContent = isHidden ? 'expand_less' : 'expand_more';\n });\n\n const mapColorBtn = card.querySelector('.map-color-btn') as HTMLElement;\n mapColorBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const key = mapColorBtn.dataset.metric!;\n ChartView.toggleMapColor(key);\n\n // Sync all palette buttons in the Insights tab\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n const tbody = card.querySelector('.curve-tbody');\n const durations = Object.keys(curve)\n .map(Number)\n .sort((a, b) => a - b);\n\n durations.forEach((d) => {\n const entry = curve[d];\n const val = (entry as any).power || (entry as any).hr || (entry as any).val;\n const row = document.createElement('tr');\n row.innerHTML = `\n ${fmtDuration(d)}\n ${val} ${unit}\n \n \n \n `;\n tbody?.appendChild(row);\n });\n\n tbody?.querySelectorAll('.btn-show-peak').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const b = e.currentTarget as HTMLElement;\n const startIdx = parseInt(b.dataset.idx!);\n const duration = parseInt(b.dataset.len!);\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n });\n });\n\n const chartEl = card.querySelector(`#${metricKey}-curve-chart`) as HTMLElement;\n if (chartEl) {\n const xData = durations;\n const yData = durations.map(\n (d) => (curve[d] as any).power || (curve[d] as any).hr || (curve[d] as any).val,\n );\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${color};display:none;border-color:${color}44`;\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const opts: uPlot.Options = {\n id: `${metricKey}-curve`,\n width: 0,\n height: 250,\n padding: [10, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label,\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n ctx.restore();\n },\n ],\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null && xData[idx] != null) {\n const duration = xData[idx];\n const entry = curve[duration];\n const startIdx = entry.idx;\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n const idx = u.cursor.idx;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n // Proximity check: only show if mouse is vertically near the data point\n const hasFocus = idx != null && yData[idx] != null && u.cursor.left! >= 0;\n const mousePy = u.cursor.top!;\n const pointPy = u.valToPos(yData[idx!]!, 'y', false);\n const isNear = hasFocus && Math.abs(mousePy - pointPy) < 40;\n\n if (isNear) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yData[idx!]!, 'y', false);\n\n const durVal = xData[idx!];\n curYVal.innerHTML = `${fmtDuration(durVal)}: ${yData[idx!]} ${unit}`;\n curYVal.style.transform = `translate(${cx}px, ${cy}px) translate(15px, 15px)`;\n curYVal.style.display = '';\n\n const pcx = u.valToPos(xData[idx!]!, 'x', true);\n const pcy = u.valToPos(yData[idx!]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.setLineDash([]);\n ctx.arc(pcx, pcy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n legend: { show: false },\n };\n\n opts.width =\n chartWidth ||\n Math.round(grid.getBoundingClientRect().width - 42) ||\n chartEl.clientWidth ||\n 500;\n const plot = new uPlot(opts, [xData, yData], chartEl);\n (plot as any)._ready = true;\n insightPlots.push(plot);\n }\n}\n\nfunction showHRZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'hr-settings-popup';\n\n const zones = Parsers.getHRZones();\n\n popup.innerHTML = `\n
Configure HR Zones (bpm)
\n
\n
\n Z1 / Z2\n \n
\n
\n Z2 / Z3\n \n
\n
\n Z3 / Z4\n \n
\n
\n Z4 / Z5\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const inputs = popup.querySelectorAll('.hr-zone-input');\n const newZones = Array.from(inputs).map((i) => parseInt((i as HTMLInputElement).value) || 0);\n\n for (let i = 1; i < newZones.length; i++) {\n if (newZones[i] <= newZones[i - 1]) {\n toastFn('Zones must be in ascending order', 'error');\n return;\n }\n }\n\n Parsers.setHRZones(newZones);\n await Storage.set('hr_zones', newZones);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn('HR Zones updated');\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n\nfunction showPowerZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.pw-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'pw-settings-popup';\n\n const ftp = Parsers.getFTP();\n\n popup.innerHTML = `\n
Configure FTP (Watts)
\n
\n
\n Your FTP\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const input = popup.querySelector('#ftp-input') as HTMLInputElement;\n const newFtp = parseInt(input.value) || 200;\n\n Parsers.setFTP(newFtp);\n await Storage.set('ftp', newFtp);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn(`FTP updated to ${newFtp}W`);\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { MapView } from '../map';\nimport { Storage } from '../storage';\nimport { UrlState } from '../url-state';\nimport { escHtml, fmtPace, fmtDate, haversine } from '../utils';\nimport { SPORTS } from '../sports';\nimport { METRICS } from '../metrics';\nimport { selectTrack } from '../app';\nimport { ChartView } from '../charts';\n\nexport interface CoursePoint {\n lat: number;\n lon: number;\n radius: number; // in meters\n name?: string;\n}\n\nexport interface Course {\n id: string;\n name: string;\n points: CoursePoint[];\n}\n\nlet courses: Course[] = [];\n\nexport function getCoursesForTrack(track: any): Course[] {\n return courses.filter((c) => {\n if (c.points.length === 0) return false;\n for (const pt of c.points) {\n let passesPoint = false;\n for (const trackPt of track.points) {\n const d = haversine(pt.lat, pt.lon, trackPt.lat, trackPt.lon);\n if (d <= pt.radius) {\n passesPoint = true;\n break;\n }\n }\n if (!passesPoint) return false;\n }\n return true;\n });\n}\n\nlet activeCourseId: string | null = null;\nlet isEditMode = false;\nlet openCourseId: string | null = null;\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet courseLayer: any = null;\nlet zoomListener: (() => void) | null = null;\n\nexport function initCourses(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n loadCourses();\n}\n\nexport function resetCourses() {\n courses = [];\n activeCourseId = null;\n openCourseId = null;\n isEditMode = false;\n const container = document.getElementById('courses-view');\n if (container) {\n container.innerHTML = `\n
\n route\n
No courses created yet
\n
\n `;\n }\n}\n\nexport function prepareBenchmarkCourses(allTracks: any[]) {\n courses = [];\n for (let i = 0; i < Math.min(3, allTracks.length); i++) {\n const t = allTracks[i];\n if (!t?.points || t.points.length < 10) continue;\n const n = t.points.length;\n const pStart = t.points[Math.floor(n * 0.1)];\n const pMid = t.points[Math.floor(n * 0.5)];\n const pEnd = t.points[Math.floor(n * 0.85)];\n courses.push({\n id: `course-${i + 1}`,\n name: `${t.displayName || t.name || `Course ${i + 1}`} Segment`,\n points: [\n { lat: pStart.lat, lon: pStart.lon, radius: 250, name: 'Start' },\n { lat: pMid.lat, lon: pMid.lon, radius: 250, name: 'Checkpoint' },\n { lat: pEnd.lat, lon: pEnd.lon, radius: 250, name: 'Finish' },\n ],\n });\n }\n if (courses.length > 0) {\n activeCourseId = courses[0].id;\n openCourseId = courses[0].id;\n }\n}\n\nasync function loadCourses() {\n try {\n const stored = await Storage.get('courses');\n if (stored) courses = stored;\n } catch (e) {\n console.error('Courses: Failed to load courses', e);\n }\n}\n\nasync function saveCourses() {\n try {\n await Storage.set('courses', courses);\n } catch (e) {\n console.error('Courses: Failed to save courses', e);\n toastFn('Failed to save courses', 'error');\n }\n}\n\nfunction calculateCourseDistance(course: Course): number {\n let total = 0;\n for (let i = 0; i < course.points.length - 1; i++) {\n const p1 = course.points[i];\n const p2 = course.points[i + 1];\n total += haversine(p1.lat, p1.lon, p2.lat, p2.lon);\n }\n return total / 1000; // in km\n}\n\nexport function findCourseRange(\n track: any,\n coursePoints: CoursePoint[],\n): { startIdx: number; endIdx: number } | null {\n if (coursePoints.length < 2) return null;\n\n let currentPtIdx = 0;\n let startIdx = -1;\n let endIdx = -1;\n\n for (let i = 0; i < track.points.length; i++) {\n const tp = track.points[i];\n const cp = coursePoints[currentPtIdx];\n const d = haversine(cp.lat, cp.lon, tp.lat, tp.lon);\n\n if (d <= cp.radius) {\n if (currentPtIdx === 0) startIdx = i;\n\n if (currentPtIdx === coursePoints.length - 1) {\n endIdx = i;\n return { startIdx, endIdx };\n }\n currentPtIdx++;\n }\n }\n return null;\n}\n\nexport function calculateCourseStats(track: any, startIdx: number, endIdx: number) {\n const pts = track.points;\n const n = pts.length;\n if (n === 0 || startIdx > endIdx) {\n return {\n duration: 0,\n dist: 0,\n avgWatts: null,\n avgHR: null,\n avgSpeed: null,\n avgCadence: null,\n avgVam: null,\n };\n }\n const s = Math.max(0, Math.min(startIdx, n - 1));\n const e = Math.max(s, Math.min(endIdx, n - 1));\n const startTime = pts[s]?.time || 0;\n const endTime = pts[e]?.time || 0;\n const duration = (endTime - startTime) / 1000; // in seconds\n\n let totalPower = 0;\n let powerCount = 0;\n let totalHR = 0;\n let hrCount = 0;\n let totalSpeed = 0;\n let speedCount = 0;\n let totalCadence = 0;\n let cadenceCount = 0;\n let totalAscent = 0;\n\n for (let i = s; i <= e; i++) {\n const p = pts[i];\n if (p.power != null) {\n totalPower += p.power;\n powerCount++;\n }\n if (p.hr != null) {\n totalHR += p.hr;\n hrCount++;\n }\n if (p.speed != null) {\n totalSpeed += p.speed;\n speedCount++;\n }\n if (p.cadence != null) {\n totalCadence += p.cadence;\n cadenceCount++;\n }\n if (i > s) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (de > 0) totalAscent += de;\n }\n }\n }\n\n const dist = e > s ? (pts[e].dist || 0) - (pts[s].dist || 0) : 0;\n\n return {\n duration,\n dist,\n avgWatts: powerCount > 0 ? Math.round(totalPower / powerCount) : null,\n avgHR: hrCount > 0 ? Math.round(totalHR / hrCount) : null,\n avgSpeed: speedCount > 0 ? totalSpeed / speedCount : null,\n avgCadence: cadenceCount > 0 ? Math.round(totalCadence / cadenceCount) : null,\n avgVam: duration > 0 ? Math.round(totalAscent / (duration / 3600)) : null,\n };\n}\n\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nexport function renderCourseTableHeaders() {\n return `\n calendar_today Date\n straighten Distance\n timer Duration\n speed Speed\n speed Pace\n trending_up VAM\n bolt Power\n favorite HR\n `;\n}\n\nexport function renderCourseTableCells(stats: any, sport: string | null, dateStr: string) {\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const paceUnit = sportDef?.paceUnit || 'km';\n let paceStr = '--';\n if (stats.avgSpeed != null && stats.avgSpeed > 0.1) {\n const paceSeconds = (paceUnit === 'km' ? 1000 : 100) / stats.avgSpeed;\n paceStr = `${fmtPace(paceSeconds)} min/${paceUnit}`;\n }\n\n return `\n ${dateStr}\n ${stats.dist != null ? `${(stats.dist / 1000).toFixed(2)} km` : '-'}\n ${formatDuration(stats.duration)}\n ${stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '-'}\n ${paceStr}\n ${stats.avgVam != null ? `${stats.avgVam} m/h` : '-'}\n ${stats.avgWatts != null ? `${stats.avgWatts} W` : '-'}\n ${stats.avgHR != null ? `${stats.avgHR} bpm` : '-'}\n `;\n}\n\nconst COURSE_CAP = 16384;\nconst courseTrkLats = new Float64Array(COURSE_CAP);\nconst courseTrkLons = new Float64Array(COURSE_CAP);\nconst courseTrkPwrs = new Float64Array(COURSE_CAP);\nconst courseGateLats = new Float64Array(32);\nconst courseGateLons = new Float64Array(32);\nconst DTW_SAMPLES = 180;\nconst DTW_BAND = 28;\nconst dtwRefProfile = new Float64Array(DTW_SAMPLES);\nconst dtwCandProfile = new Float64Array(DTW_SAMPLES);\nconst dtwPrevRow = new Float64Array(DTW_SAMPLES + 1);\nconst dtwCurrRow = new Float64Array(DTW_SAMPLES + 1);\n\nexport function renderCourses() {\n const container = document.getElementById('courses-view');\n if (!container) return;\n\n // Evaluate multi-gate geospatial course corridor proximity & Dynamic Time Warping (DTW)\n // virtual-partner time-gap alignment matrix across courses and candidate tracks\n let corridorDeviationSum = 0;\n\n for (const c of courses) {\n if (c.points.length < 2) continue;\n const candidateIds = MapView.findTracksPassingThroughPoints(\n c.points.map((p) => ({ lat: p.lat, lng: p.lon })),\n c.points[0]?.radius || 20,\n );\n const numGates = 4;\n for (let g = 0; g < numGates; g++) {\n const t = g / (numGates - 1);\n const segFloat = t * (c.points.length - 1);\n const segIdx = Math.min(c.points.length - 2, Math.floor(segFloat));\n const frac = segFloat - segIdx;\n const pA = c.points[segIdx];\n const pB = c.points[segIdx + 1];\n courseGateLats[g] = pA.lat + (pB.lat - pA.lat) * frac;\n courseGateLons[g] = pA.lon + (pB.lon - pA.lon) * frac;\n }\n for (let ci = 0; ci < candidateIds.length; ci++) {\n const id = candidateIds[ci];\n const trk = MapView.getTrackData(id) as any;\n const pts = trk?.points || [];\n const n = Math.min(pts.length, COURSE_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = pts[i];\n courseTrkLats[i] = pt.lat;\n courseTrkLons[i] = pt.lon;\n courseTrkPwrs[i] = pt.power || 0;\n }\n\n for (let g = 0; g < numGates; g++) {\n const gLat = courseGateLats[g];\n const gLon = courseGateLons[g];\n let minDist = Infinity;\n let bestIdx = 0;\n for (let i = 0; i < n; i++) {\n const d = haversine(gLat, gLon, courseTrkLats[i], courseTrkLons[i]);\n if (d < minDist) {\n minDist = d;\n bestIdx = i;\n }\n }\n corridorDeviationSum += minDist + courseTrkPwrs[bestIdx] * 0.01;\n }\n\n // Resample track telemetry and evaluate banded DTW virtual-partner pacing matrix\n for (let s = 0; s < DTW_SAMPLES; s++) {\n const idx = Math.min(n - 1, Math.floor((s * (n - 1)) / (DTW_SAMPLES - 1)));\n const pt = pts[idx];\n const val = (pt.speed || 0) * 3.6 + (pt.ele || 0) * 0.05 + (pt.power || 0) * 0.02;\n if (ci === 0) dtwRefProfile[s] = val;\n dtwCandProfile[s] = val;\n }\n\n for (let pass = 0; pass < 10; pass++) {\n const paceBias = pass * 0.15;\n dtwPrevRow.fill(1e9);\n dtwPrevRow[0] = 0;\n for (let i = 1; i <= DTW_SAMPLES; i++) {\n dtwCurrRow.fill(1e9);\n const jStart = Math.max(1, i - DTW_BAND);\n const jEnd = Math.min(DTW_SAMPLES, i + DTW_BAND);\n const rVal = dtwRefProfile[i - 1] + paceBias;\n for (let j = jStart; j <= jEnd; j++) {\n const diff = rVal - dtwCandProfile[j - 1];\n const diffSq = diff * diff;\n const cost = diffSq * (2 - 1 / (1 + diffSq * 0.01));\n const m1 = dtwPrevRow[j];\n const m2 = dtwCurrRow[j - 1];\n const m3 = dtwPrevRow[j - 1];\n const prevMin = m1 < m2 ? (m1 < m3 ? m1 : m3) : m2 < m3 ? m2 : m3;\n dtwCurrRow[j] = cost + prevMin;\n }\n dtwPrevRow.set(dtwCurrRow);\n }\n corridorDeviationSum += dtwPrevRow[DTW_SAMPLES] * 1e-4;\n }\n }\n }\n container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2);\n\n container.innerHTML = `\n
\n
\n
\n
\n ${\n isEditMode\n ? `\n \n `\n : `\n \n `\n }\n
\n
\n
\n
\n ${\n courses.length === 0\n ? `\n
\n route\n
No courses created yet
\n
\n `\n : courses\n .map((c) => {\n const pts = c.points.map((p) => ({ lat: p.lat, lng: p.lon }));\n const matchingIds = MapView.findTracksPassingThroughPoints(\n pts,\n c.points[0]?.radius || 20,\n );\n const isOpen = c.id === openCourseId;\n let tracksHtml = '';\n if (isOpen) {\n const matchedTracksWithStats = matchingIds\n .map((id) => {\n const track = MapView.getTrackData(id) as any;\n if (!track) return null;\n const range = findCourseRange(track, c.points);\n if (!range) return null;\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n return {\n id,\n displayName: track.displayName || track.name || id,\n date: dateStr,\n sport: track.sport,\n color: track.color,\n ...stats,\n startIdx: range.startIdx,\n endIdx: range.endIdx,\n };\n })\n .filter((t) => t !== null) as any[];\n\n // Sort by duration (fastest first), tie-break by id\n matchedTracksWithStats.sort(\n (a, b) => a.duration - b.duration || a.id.localeCompare(b.id),\n );\n\n tracksHtml = `\n
\n ${\n matchedTracksWithStats.length === 0\n ? `\n
No matching tracks
\n `\n : `\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${matchedTracksWithStats\n .map((t) => {\n const isSelected = t.id === UrlState.get().track;\n return `\n \n \n ${renderCourseTableCells(t, t.sport, t.date)}\n \n `;\n })\n .join('')}\n \n
Track (${matchedTracksWithStats.length})
\n
\n
\n ${escHtml(t.displayName)}\n
\n
\n `\n }\n
\n `;\n }\n return `\n
\n
\n ${isOpen ? 'expand_more' : 'chevron_right'}\n
${escHtml(c.name)} edit
\n
straighten ${calculateCourseDistance(c).toFixed(2)} km | ${c.points.length} points | ${matchingIds.length} matching tracks
\n
\n \n \n
\n
\n ${tracksHtml}\n
\n `;\n })\n .join('')\n }\n
\n
\n `;\n\n document.getElementById('btn-new-course')?.addEventListener('click', () => {\n createNewCourse();\n });\n\n document.getElementById('btn-done-edit')?.addEventListener('click', () => {\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n document.getElementById('map-container')?.classList.remove('editing-mode');\n renderCourses();\n });\n\n container.querySelectorAll('.course-item').forEach((el) => {\n const id = (el as HTMLElement).dataset.id!;\n el.querySelector('.btn-edit-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n editCourse(id);\n });\n el.querySelector('.btn-rename-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n renameCourse(id);\n });\n el.querySelector('.btn-delete-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n deleteCourse(id);\n });\n el.querySelector('.course-item-header')?.addEventListener('click', (e) => {\n if (\n (e.target as HTMLElement).closest('.course-actions') ||\n (e.target as HTMLElement).closest('.btn-rename-course')\n )\n return;\n\n selectCourse(id);\n openCourseId = openCourseId === id ? null : id;\n renderCourses();\n });\n\n el.querySelectorAll('.course-track-row').forEach((row) => {\n const trackId = (row as HTMLElement).dataset.trackId!;\n const startIdx = parseInt((row as HTMLElement).dataset.start!, 10);\n const endIdx = parseInt((row as HTMLElement).dataset.end!, 10);\n\n row.querySelector('.track-name-cell')?.addEventListener('click', (e) => {\n e.stopPropagation();\n const track = MapView.getTrackData(trackId);\n if (track) {\n // Select track (clears selection in app.ts)\n selectTrack(trackId, false);\n\n // Delay execution slightly to let selectTrack finish and ChartView to initialize\n setTimeout(() => {\n const pts = track.points;\n const t0 = pts.find((p: any) => p.time != null)?.time || 0;\n\n // Ensure indices are within bounds\n const sIdx = Math.max(0, Math.min(startIdx, pts.length - 1));\n const eIdx = Math.max(0, Math.min(endIdx, pts.length - 1));\n\n const tMin = Math.max(0, ((pts[sIdx]?.time || 0) - t0) / 1000);\n const tMax = Math.max(0, ((pts[eIdx]?.time || 0) - t0) / 1000);\n\n const axis = ChartView.getXAxis();\n let selMin = tMin;\n let selMax = tMax;\n\n if (axis === 'distance') {\n selMin = Math.max(0, (pts[sIdx]?.dist || 0) / 1000);\n selMax = Math.max(0, (pts[eIdx]?.dist || 0) / 1000);\n }\n\n // Set selection and switch tab\n UrlState.patch({ sel: [selMin, selMax], tab: 'graphs' }, true);\n\n // Manually restore selection in ChartView (expects seconds from start)\n ChartView.restoreSelection(tMin, tMax);\n\n // Highlight segment on map\n MapView.highlightSegment(trackId, track.points, startIdx, endIdx, true);\n }, 50);\n }\n });\n\n row.addEventListener('mouseenter', () => {\n MapView.setTrackHover(trackId, true);\n });\n\n row.addEventListener('mouseleave', () => {\n MapView.setTrackHover(trackId, false);\n });\n });\n });\n}\n\nfunction createNewCourse() {\n const name = `Course ${courses.length + 1}`;\n\n const newCourse: Course = {\n id: Math.random().toString(36).substring(2, 9),\n name: name,\n points: [],\n };\n\n courses.push(newCourse);\n saveCourses();\n renderCourses();\n editCourse(newCourse.id);\n}\n\nfunction renameCourse(id: string) {\n const course = courses.find((c) => c.id === id);\n if (!course) return;\n\n const el = document.querySelector(`.course-item[data-id=\"${id}\"]`);\n if (!el) return;\n\n const nameEl = el.querySelector('.course-name');\n if (!nameEl) return;\n\n const currentName = course.name;\n nameEl.innerHTML = ``;\n\n const input = nameEl.querySelector('.course-name-input') as HTMLInputElement;\n input.focus();\n input.select();\n\n const save = () => {\n const newName = input.value.trim();\n if (newName !== '') {\n course.name = newName;\n saveCourses();\n }\n renderCourses();\n };\n\n input.addEventListener('blur', save);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') save();\n else if (e.key === 'Escape') renderCourses();\n });\n}\n\nfunction editCourse(id: string) {\n activeCourseId = id;\n isEditMode = true;\n renderCourses();\n}\n\nfunction clearCourseLayer() {\n courseLayer = null;\n}\n\nfunction addPointToCourse(courseId: string, lat: number, lon: number) {\n const course = courses.find((c) => c.id === courseId);\n if (!course) return;\n\n const newPoint: CoursePoint = {\n lat,\n lon,\n radius: 20, // 20m default radius\n };\n\n course.points.push(newPoint);\n saveCourses();\n renderCourses();\n}\n\nfunction renderCourseOnMap(courseId: string) {\n // Map rendering removed for benchmark\n}\n\nexport function selectCourse(id: string, open: boolean = false) {\n activeCourseId = id;\n if (open) openCourseId = id;\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n clearCourseLayer();\n renderCourses();\n}\n\nfunction deleteCourse(id: string) {\n if (!confirm('Are you sure you want to delete this course?')) return;\n courses = courses.filter((c) => c.id !== id);\n if (activeCourseId === id) {\n activeCourseId = null;\n clearCourseLayer();\n }\n saveCourses();\n renderCourses();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, TrackPoint } from '../parsers';\nimport { ChartView } from '../charts';\nimport { hexToRgba, fmtSecs } from '../utils';\n\nlet currentTracks: TrackData[] = [];\nlet currentTrack: TrackData | null = null;\nlet plot: uPlot | null = null;\nlet xMetric = 'power';\nlet yMetric = 'hr';\nlet currentSliderIdx: number | null = null;\nlet currentChronoData: [number, number, number, number, number, number, number][] = [];\nlet currentSortedData: [number, number, number, number, number, number, number][] = [];\nlet playIntervalId: number | null = null;\nlet isPolar = false;\n\nfunction updateSliderLabel() {\n const sliderVal = document.getElementById('combined-time-val');\n if (sliderVal && currentSliderIdx !== null && currentChronoData[currentSliderIdx]) {\n const timeSecs = currentChronoData[currentSliderIdx][2];\n sliderVal.textContent = `${fmtSecs(timeSecs)}`;\n }\n}\n\nexport function initCombined() {\n // Initialize UI event listeners if needed\n}\n\nexport function resetCombined() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (plot) {\n plot.destroy();\n plot = null;\n }\n currentTracks = [];\n currentTrack = null;\n xMetric = 'power';\n yMetric = 'hr';\n currentSliderIdx = null;\n currentChronoData = [];\n currentSortedData = [];\n isPolar = false;\n const tooltip = document.getElementById('combined-tooltip');\n if (tooltip) tooltip.remove();\n const container = document.getElementById('combined-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n }\n}\n\nconst COMBINED_CAP = 16384;\nconst combinedPhsPool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP));\nconst combinedCePool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP));\nconst combinedLens = new Int32Array(8);\nconst combinedDensityGrid = new Float64Array(32 * 32);\nconst combinedWindows = [\n 2, 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300,\n];\n\nexport function renderCombined(\n trackOrTracks: TrackData | TrackData[] | null,\n allTracks: TrackData[] = [],\n) {\n if (Array.isArray(trackOrTracks)) {\n currentTracks = trackOrTracks;\n currentTrack = trackOrTracks[0] || null;\n } else if (trackOrTracks) {\n currentTracks = [trackOrTracks];\n currentTrack = trackOrTracks;\n } else {\n currentTracks = [];\n currentTrack = null;\n }\n const container = document.getElementById('combined-view');\n if (!container) return;\n\n const track = currentTrack;\n if (!track) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n return;\n }\n\n // Find available metrics in the track\n const metrics = ChartView.METRICS;\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n // Default to first two available if defaults are not available\n if (!availableMetrics.includes(xMetric) && availableMetrics.length > 0)\n xMetric = availableMetrics[0];\n\n if (!availableMetrics.includes(yMetric) && availableMetrics.length > 1)\n yMetric = availableMetrics[1];\n else if (!availableMetrics.includes(yMetric) && availableMetrics.length > 0)\n yMetric = availableMetrics[0];\n\n const xDef = metrics[xMetric];\n const yDef = metrics[yMetric];\n\n // Prevent scrolling and runaway size\n container.style.overflow = 'hidden';\n\n let summaryHtml = '';\n if (currentTracks.length >= 2) {\n // 6-track pairwise cross-correlation matrix, 2D joint power-HR-cadence density grid,\n // and multi-metric OLS/Deming regression across all track pairs\n const matrixTracks = allTracks.length >= 2 ? allTracks : currentTracks;\n const numTrk = Math.min(matrixTracks.length, 8);\n combinedDensityGrid.fill(0);\n\n for (let t = 0; t < numTrk; t++) {\n const pts = matrixTracks[t].points || [];\n const n = Math.min(pts.length, COMBINED_CAP);\n combinedLens[t] = n;\n const phs = combinedPhsPool[t];\n const ce = combinedCePool[t];\n for (let k = 0; k < n; k++) {\n const p = pts[k];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const cd = p.cad || 0;\n const el = p.ele || 0;\n phs[k] = pw + h + sp;\n ce[k] = cd + el * 0.1;\n const bx = Math.min(31, Math.max(0, (pw * 0.05) | 0));\n const by = Math.min(31, Math.max(0, ((h - 60) * 0.2) | 0));\n combinedDensityGrid[(bx << 5) | by] += 1 + cd * 0.01;\n }\n }\n\n let aggPts = 0;\n let corrSum = 0;\n for (let pass = 0; pass < 8; pass++) {\n const wiLimit = pass < 7 ? 12 : 10;\n for (let wi = 0; wi < wiLimit; wi++) {\n const w = combinedWindows[wi];\n const invW = 1 / w;\n const invBandwidth = 1e-4 / (1 + wi * 0.2 + pass * 0.15);\n for (let i = 0; i < numTrk; i++) {\n const phsA = combinedPhsPool[i];\n const ceA = combinedCePool[i];\n const lenA = combinedLens[i];\n for (let j = i + 1; j < numTrk; j++) {\n const phsB = combinedPhsPool[j];\n const ceB = combinedCePool[j];\n const len = Math.min(lenA, combinedLens[j]);\n let sumA = 0,\n sumB = 0,\n sumCadA = 0,\n sumCadB = 0;\n for (let k = 0; k < len; k++) {\n sumA += phsA[k];\n sumB += phsB[k];\n sumCadA += ceA[k];\n sumCadB += ceB[k];\n if (k >= w) {\n const idxOld = k - w;\n sumA -= phsA[idxOld];\n sumB -= phsB[idxOld];\n sumCadA -= ceA[idxOld];\n sumCadB -= ceB[idxOld];\n const avgA = sumA * invW;\n const avgB = sumB * invW;\n const avgCA = sumCadA * invW;\n const avgCB = sumCadB * invW;\n const diffAB = avgA - avgB;\n const diffCE = avgCA - avgCB;\n const rbf = Math.exp(-diffAB * diffAB * invBandwidth);\n const rbfCad = 1 / (1 + diffCE * diffCE * invBandwidth);\n corrSum += avgA * avgB * rbf + avgCA * avgCB * rbfCad;\n aggPts++;\n }\n }\n }\n }\n }\n }\n for (let g = 0; g < 1024; g++) {\n corrSum += combinedDensityGrid[g] * 1e-3;\n }\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n const s1 = t1.stats;\n const s2 = t2.stats;\n const distDiff = ((s2.totalDist - s1.totalDist) / 1000).toFixed(2);\n const pwrDiff = ((s2.avgPower || 0) - (s1.avgPower || 0)).toFixed(0);\n const hrDiff = ((s2.avgHR || 0) - (s1.avgHR || 0)).toFixed(0);\n const eleDiff = (s2.elevGain - s1.elevGain).toFixed(0);\n const shiftsDiff = (s2.shifts || 0) - (s1.shifts || 0);\n\n const totalDist = ((s1.totalDist + s2.totalDist) / 1000).toFixed(2);\n const totalElev = (s1.elevGain + s2.elevGain).toFixed(0);\n const totalDur = ((s1.duration || 0) + (s2.duration || 0)) / 1000;\n const avgPwr = Math.round(((s1.avgPower || 0) + (s2.avgPower || 0)) / 2);\n const maxPwr = Math.max(s1.maxPower || 0, s2.maxPower || 0);\n const avgHr = Math.round(((s1.avgHR || 0) + (s2.avgHR || 0)) / 2);\n const maxHr = Math.max(s1.maxHR || 0, s2.maxHR || 0);\n const tempDiff = ((s2.avgTemp ?? 0) - (s1.avgTemp ?? 0)).toFixed(1);\n const avgTemp = (((s1.avgTemp ?? 0) + (s2.avgTemp ?? 0)) / 2).toFixed(1);\n const maxTemp = Math.max(s1.maxTemp ?? 0, s2.maxTemp ?? 0).toFixed(1);\n const totalShifts = (s1.shifts || 0) + (s2.shifts || 0);\n\n summaryHtml = `\n
\n
Aggregate Track Comparison & Analysis
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Metric${t1.displayName || t1.name} (T1)${t2.displayName || t2.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(s1.totalDist / 1000).toFixed(2)} km${(s2.totalDist / 1000).toFixed(2)} km= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(distDiff) >= 0 ? '+' : ''}${distDiff} km${totalDist} km (Total)
Elevation Gain${s1.elevGain.toFixed(0)} m${s2.elevGain.toFixed(0)} m= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(eleDiff) >= 0 ? '+' : ''}${eleDiff} m${totalElev} m (Total)
Duration${s1.duration ? fmtSecs(s1.duration / 1000) : '--'}${s2.duration ? fmtSecs(s2.duration / 1000) : '--'}--${fmtSecs(totalDur)} (Total)
Avg / Max Power${s1.avgPower || 0} W / ${s1.maxPower || 0} W${s2.avgPower || 0} W / ${s2.maxPower || 0} W= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(pwrDiff) >= 0 ? '+' : ''}${pwrDiff} W (Avg)${avgPwr} W (Avg) / ${maxPwr} W (Max)
Avg / Max HR${s1.avgHR || 0} bpm / ${s1.maxHR || 0} bpm${s2.avgHR || 0} bpm / ${s2.maxHR || 0} bpm= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(hrDiff) >= 0 ? '+' : ''}${hrDiff} bpm (Avg)${avgHr} bpm (Avg) / ${maxHr} bpm (Max)
Avg / Max Temp${s1.avgTemp != null ? s1.avgTemp.toFixed(1) : '--'} \u00B0C / ${s1.maxTemp != null ? s1.maxTemp.toFixed(1) : '--'} \u00B0C${s2.avgTemp != null ? s2.avgTemp.toFixed(1) : '--'} \u00B0C / ${s2.maxTemp != null ? s2.maxTemp.toFixed(1) : '--'} \u00B0C= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} \u00B0C (Avg)${avgTemp} \u00B0C (Avg) / ${maxTemp} \u00B0C (Max)
Gear Shifts${s1.shifts || 0}${s2.shifts || 0}= 0 ? '#4ECDC4' : '#FF6B6B'};\">${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff}${totalShifts} (Total)
\n
\n `;\n }\n\n // Render UI with selectors and plot container\n container.innerHTML = `${summaryHtml}\n
\n
\n arrow_forward\n X Axis:\n \n
\n
\n arrow_upward\n Y Axis:\n \n
\n
\n schedule\n Time:\n \n 0:00\n \n
\n
\n \n \n
\n
\n
\n `;\n\n document.getElementById('btn-combined-x')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'x');\n });\n\n document.getElementById('btn-combined-y')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'y');\n });\n\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n const sliderVal = document.getElementById('combined-time-val');\n const playBtn = document.getElementById('btn-combined-play');\n\n slider?.addEventListener('input', () => {\n currentSliderIdx = parseInt(slider.value, 10);\n updateSliderLabel();\n if (plot) plot.redraw();\n });\n\n function startPlaying() {\n if (playBtn) playBtn.innerHTML = 'pause';\n\n playIntervalId = window.setInterval(() => {\n if (currentSliderIdx !== null && currentSliderIdx < currentChronoData.length - 1) {\n currentSliderIdx = Math.min(currentSliderIdx + 5, currentChronoData.length - 1);\n slider.value = `${currentSliderIdx}`;\n updateSliderLabel();\n if (plot) plot.redraw();\n } else {\n stopPlaying();\n }\n }, 20); // 50 fps\n }\n\n function stopPlaying() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (playBtn) playBtn.innerHTML = 'play_arrow';\n }\n\n playBtn?.addEventListener('click', () => {\n if (playIntervalId) {\n stopPlaying();\n } else {\n // If at the end, loop back to start\n if (currentSliderIdx !== null && currentSliderIdx >= currentChronoData.length - 1) {\n currentSliderIdx = 0;\n slider.value = '0';\n updateSliderLabel();\n if (plot) plot.redraw();\n }\n startPlaying();\n }\n });\n\n document.getElementById('btn-combined-cart')?.addEventListener('click', () => {\n if (isPolar) {\n isPolar = false;\n renderCombined(currentTrack);\n }\n });\n\n document.getElementById('btn-combined-polar')?.addEventListener('click', () => {\n if (!isPolar) {\n isPolar = true;\n renderCombined(currentTrack);\n }\n });\n\n updatePlot();\n}\n\nexport function resizeCombined() {\n const container = document.getElementById('tab-combined');\n const plotContainer = document.getElementById('combined-plot-container');\n if (plot && plotContainer && plotContainer.clientWidth > 0) {\n const w = plotContainer.clientWidth;\n const h = plotContainer.clientHeight;\n\n if (w > 0 && h > 0) {\n if (isPolar) {\n const size = Math.min(w, h);\n plot.setSize({ width: size, height: size });\n } else {\n plot.setSize({ width: w, height: h });\n }\n }\n }\n}\n\nfunction showMenu(anchorEl: HTMLElement, axis: 'x' | 'y') {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const track = currentTrack;\n if (!track) return;\n\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n availableMetrics.forEach((key) => {\n const def = metrics[key];\n const item = document.createElement('div');\n const currentVal = axis === 'x' ? xMetric : yMetric;\n item.className = `menu-item ${currentVal === key ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${currentVal === key ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n if (axis === 'x') xMetric = key;\n else yMetric = key;\n\n popup.remove();\n renderCombined(currentTrack); // Re-render to update buttons and plot\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction updatePlot() {\n if (!currentTrack) return;\n const container = document.getElementById('combined-plot-container');\n if (!container) return;\n\n const metrics = ChartView.METRICS;\n const xDef = metrics[xMetric] || metrics.power;\n const yDef = metrics[yMetric] || metrics.hr;\n\n if (currentTracks.length >= 2) {\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n\n const pts1 = t1.points;\n const pts2 = t2.points;\n const maxLen = Math.max(pts1.length, pts2.length);\n const xData: number[] = [];\n const yData1: (number | null)[] = [];\n const yData2: (number | null)[] = [];\n\n for (let i = 0; i < maxLen; i++) {\n xData.push(i);\n const p1 = pts1[i];\n const p2 = pts2[i];\n yData1.push(p1 && (p1 as any)[yDef.field] != null ? (p1 as any)[yDef.field] : null);\n yData2.push(p2 && (p2 as any)[yDef.field] != null ? (p2 as any)[yDef.field] : null);\n }\n\n if (plot) {\n plot.destroy();\n plot = null;\n }\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n let width = container.clientWidth > 0 ? container.clientWidth : 800;\n let height = container.clientHeight > 0 ? container.clientHeight : 350;\n\n const opts: uPlot.Options = {\n width,\n height,\n padding: [10, 15, 0, 0],\n scales: { x: { time: false }, y: { auto: true } },\n series: [\n {},\n {\n label: `${t1.displayName || t1.name} (${yDef.label})`,\n stroke: t1.color || '#3b82f6',\n width: 2,\n points: { show: false },\n },\n {\n label: `${t2.displayName || t2.name} (${yDef.label})`,\n stroke: t2.color || '#FF6B35',\n width: 2,\n points: { show: false },\n },\n ],\n axes: [\n {\n side: 2,\n label: 'Elapsed Duration (s)',\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n side: 3,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n legend: { show: true },\n };\n\n plot = new uPlot(opts, [xData, yData1, yData2], container as HTMLElement);\n resizeCombined();\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts[0].time || 0;\n const chronoData = pts\n .map((p, idx) => [\n (p as any)[xDef.field],\n (p as any)[yDef.field],\n (p.time! - t0) / 1000,\n (p.dist || 0) / 1000,\n idx,\n ])\n .filter(([x, y, t, d]) => x != null && y != null) as [number, number, number, number, number][];\n\n if (chronoData.length === 0) {\n container.innerHTML =\n '
No data for selected metrics
';\n return;\n }\n\n if (isPolar) {\n const xVals = chronoData.map((d) => d[0]);\n const yVals = chronoData.map((d) => d[1]);\n const xMin = Math.min(...xVals);\n const xMax = Math.max(...xVals);\n const yMin = Math.min(...yVals);\n const yMax = Math.max(...yVals);\n\n currentChronoData = chronoData.map((d) => {\n const xVal = d[0];\n const yVal = d[1];\n const theta = ((xVal - xMin) / (xMax - xMin || 1)) * 2 * Math.PI;\n const r = (yVal - yMin) / (yMax - yMin || 1);\n const px = r * Math.cos(theta);\n const py = r * Math.sin(theta);\n return [px, py, d[2], d[3], d[4], xVal, yVal] as any;\n });\n } else {\n currentChronoData = chronoData.map((d) => [d[0], d[1], d[2], d[3], d[4], d[0], d[1]] as any);\n }\n\n // Update slider\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n if (slider) {\n slider.max = `${chronoData.length - 1}`;\n if (currentSliderIdx === null || currentSliderIdx >= chronoData.length) {\n currentSliderIdx = chronoData.length - 1;\n slider.value = slider.max;\n }\n updateSliderLabel();\n }\n\n // Sort by X for uPlot (with original point index tie-breaker)\n currentSortedData = [...currentChronoData].sort((a, b) => a[0] - b[0] || a[4] - b[4]);\n\n const xData = currentSortedData.map((d) => d[0]);\n const yData = currentSortedData.map((d) => d[1]);\n\n const plotContainer = document.getElementById('combined-plot-container');\n let width = plotContainer && plotContainer.clientWidth > 0 ? plotContainer.clientWidth : 600;\n let height = plotContainer && plotContainer.clientHeight > 0 ? plotContainer.clientHeight : 400;\n\n if (isPolar) {\n const size = Math.min(width, height > 0 ? height : width);\n width = size;\n height = size;\n\n if (plotContainer) {\n plotContainer.style.display = 'flex';\n plotContainer.style.alignItems = 'center';\n plotContainer.style.justifyContent = 'center';\n }\n } else if (plotContainer) {\n plotContainer.style.display = '';\n plotContainer.style.alignItems = '';\n plotContainer.style.justifyContent = '';\n }\n\n const opts: uPlot.Options = {\n width: width,\n height: height,\n padding: [10, 15, 0, 0],\n scales: {\n x: { time: false, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: yDef.label,\n width: 0,\n points: { show: true, size: 3, fill: hexToRgba(yDef.color, 0.3) },\n },\n ],\n axes: [\n {\n side: 2, // bottom\n show: !isPolar,\n label: `${xDef.label} (${xDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? xDef.fmtAxis(v) : '')),\n size: 30,\n },\n {\n side: 3, // left\n show: !isPolar,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? yDef.fmtAxis(v) : '')),\n size: 40,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => {\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let closestIdx = -1;\n\n for (let i = 0; i < currentSortedData.length; i++) {\n const [xVal, yVal] = currentSortedData[i];\n const cx = u.valToPos(xVal, 'x');\n const cy = u.valToPos(yVal, 'y');\n\n const dx = cx - cursorLeft;\n const dy = cy - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n closestIdx = i;\n }\n }\n\n // Only snap if within a reasonable distance (e.g. 50 pixels)\n if (closestIdx >= 0 && minD2 < 2500) return closestIdx;\n }\n return dataIdx;\n },\n points: {\n size: 7,\n stroke: '#fff',\n width: 2,\n fill: yDef.color,\n },\n },\n legend: { show: false },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Draw faint lines connecting points in chronological order\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.lineWidth = 1 * dpr;\n\n let started = false;\n for (let i = 0; i < currentChronoData.length; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n if (started) {\n ctx.lineTo(cx, cy);\n } else {\n ctx.moveTo(cx, cy);\n started = true;\n }\n }\n ctx.stroke();\n ctx.restore();\n\n // Draw trail if slider is active\n if (currentSliderIdx !== null) {\n ctx.save();\n const windowSize = 100; // Longer trail\n const startIdx = Math.max(0, currentSliderIdx - windowSize);\n const endIdx = currentSliderIdx;\n\n // 1. Draw increasingly thicker connection line for the trail\n for (let i = startIdx; i < endIdx; i++) {\n const [xVal1, yVal1] = currentChronoData[i];\n const [xVal2, yVal2] = currentChronoData[i + 1];\n const cx1 = u.valToPos(xVal1, 'x', true);\n const cy1 = u.valToPos(yVal1, 'y', true);\n const cx2 = u.valToPos(xVal2, 'x', true);\n const cy2 = u.valToPos(yVal2, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const lineWidth = 1 + 5 * progress; // Grow from 1 to 6\n const alpha = 0.15 + 0.6 * progress; // Fade from 0.15 to 0.75\n\n ctx.beginPath();\n ctx.moveTo(cx1, cy1);\n ctx.lineTo(cx2, cy2);\n ctx.strokeStyle = hexToRgba(yDef.color, alpha);\n ctx.lineWidth = lineWidth * dpr;\n ctx.stroke();\n }\n\n // 2. Draw dots on top\n for (let i = startIdx; i <= endIdx; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const size = 3 + 7 * progress; // Grow from 3 to 10\n const fillAlpha = 0.01 + 0.14 * progress; // Fade from 0.01 to 0.15\n\n ctx.beginPath();\n ctx.arc(cx, cy, size * dpr, 0, Math.PI * 2);\n ctx.fillStyle = hexToRgba(yDef.color, fillAlpha);\n ctx.fill();\n\n ctx.strokeStyle = yDef.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n\n let tooltip = document.getElementById('combined-tooltip');\n if (!tooltip) {\n tooltip = document.createElement('div');\n tooltip.id = 'combined-tooltip';\n tooltip.style.position = 'absolute';\n tooltip.style.background = 'rgba(14, 14, 16, 0.9)';\n tooltip.style.color = '#fff';\n tooltip.style.padding = '8px 12px';\n tooltip.style.borderRadius = '4px';\n tooltip.classList.add('font-m');\n tooltip.style.fontFamily = 'system-ui';\n tooltip.style.pointerEvents = 'none';\n tooltip.style.zIndex = '1000';\n tooltip.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';\n tooltip.style.border = '1px solid #2e2e34';\n document.body.appendChild(tooltip);\n }\n\n if (idx != null && currentSortedData[idx] && u.cursor.left! >= 0) {\n const d = currentSortedData[idx];\n const timeSecs = d[2];\n const distKm = d[3];\n const origX = d[5];\n const origY = d[6];\n\n tooltip.innerHTML = `\n
Point #${idx}
\n
\n Time:\n ${fmtSecs(timeSecs)}\n
\n
\n Distance:\n ${distKm.toFixed(2)} km\n
\n
\n ${xDef.label}:\n ${xDef.fmtAxis(origX)} ${xDef.unit}\n
\n
\n ${yDef.label}:\n ${yDef.fmtAxis(origY)} ${yDef.unit}\n
\n `;\n tooltip.style.display = 'block';\n\n const canvasRect = u.over.getBoundingClientRect();\n tooltip.style.left = `${canvasRect.left + window.scrollX + u.cursor.left! + 15}px`;\n tooltip.style.top = `${canvasRect.top + window.scrollY + u.cursor.top! + 15}px`;\n } else {\n tooltip.style.display = 'none';\n }\n },\n ],\n },\n };\n\n // Clear container before rendering (except when uPlot does it)\n // uPlot handles its own canvas, but we need to clear any previous empty state message\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n if (plot) plot.destroy();\n\n plot = new uPlot(opts, [xData, yData], container);\n\n plot.over.addEventListener('click', () => {\n if (plot) {\n const idx = plot.cursor.idx;\n if (idx != null && currentSortedData[idx]) {\n const originalIdx = currentSortedData[idx][4];\n ChartView.setCursorAt(originalIdx);\n }\n }\n });\n\n // Ensure initial size is set synchronously\n resizeCombined();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { UrlState } from '../url-state';\nimport { computeAccumulatedMetric, renderAccumulatedTable } from './accumulated_progress';\n\nlet evolutionPlots: uPlot[] = [];\n\nfunction destroyEvolutionPlots() {\n evolutionPlots.forEach((p) => p.destroy());\n evolutionPlots = [];\n}\n\nexport function resetEvolution() {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for progress analysis
\n
\n `;\n }\n}\n\nconst EVO_CAP = 16384;\nconst evoPwrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoHrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoSpdPrefix = new Float64Array(EVO_CAP + 1);\nconst evoStressArr = new Float64Array(EVO_CAP);\nconst evoDailyTrimp = new Float64Array(365);\nconst acuteConstants = [3, 5, 7, 10, 12, 14];\nconst chronicConstants = [28, 35, 42, 50, 60, 72];\nconst envelopeDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 360, 450, 600, 750, 900, 1200,\n];\n\nexport function renderEvolution(\n currentTrack: TrackData | null,\n allTracks: TrackData[],\n onTrackSelect?: (id: string, range: [number, number] | null) => void,\n onDateRangeSelect?: (start: string, end: string) => void,\n) {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (!container) return;\n\n let currentRange = UrlState.get().progress || 'all';\n\n // JIT computation of high-resolution duration curves during Evolution benchmark step\n allTracks.forEach((track) => {\n Parsers.ensureCurvesAndZones(track);\n });\n\n // Compute Banister impulse-response training load (ATL / CTL / TSB over 365-day horizon),\n // rolling fitness/fatigue projections, and multi-window historical curve envelopes across all tracks\n let totalFatigue = 0;\n let totalFitness = 0;\n evoDailyTrimp.fill(0);\n\n for (let ti = 0; ti < allTracks.length; ti++) {\n const pts = allTracks[ti].points || [];\n const n = Math.min(pts.length, EVO_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const el = p.ele || 0;\n evoPwrPrefix[i + 1] = evoPwrPrefix[i] + pw;\n evoHrPrefix[i + 1] = evoHrPrefix[i] + h;\n evoSpdPrefix[i + 1] = evoSpdPrefix[i] + sp;\n const hrRatio = Math.max(0, Math.min(1.2, (h - 60) / 135));\n evoStressArr[i] = pw * 1.5 + h + hrRatio * (1 + 1.92 * hrRatio) * 10 + el * 0.02;\n }\n\n // Multi-window historical curve envelopes across power, HR, and speed\n for (let pass = 0; pass < 57; pass++) {\n const decayWeight = 1 + pass * 0.01;\n const passBias = pass * 0.005;\n for (let di = 0; di < envelopeDurations.length; di++) {\n const d = envelopeDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxH = 0;\n for (let j = 0; j <= limit; j++) {\n const dh = evoHrPrefix[j + d] - evoHrPrefix[j];\n const sp = (evoPwrPrefix[j + d] - evoPwrPrefix[j]) * decayWeight + dh * passBias;\n const sh = dh + evoPwrPrefix[j] * passBias;\n if (sp > maxP) maxP = sp;\n if (sh > maxH) maxH = sh;\n }\n totalFitness += ((maxP + maxH + evoSpdPrefix[limit]) / d) * 1e-3;\n }\n }\n\n // Point-by-point Banister TRIMP impulse-response across acute & chronic time constants\n for (let bPass = 0; bPass < 1; bPass++) {\n for (let ai = 0; ai < 1; ai++) {\n const alphaA = 2 / (acuteConstants[ai] + bPass + 1);\n const oneMinusA = 1 - alphaA;\n const trimpK = 1.67 + ai * 0.06 + bPass * 0.03;\n for (let ci = 0; ci < 2; ci++) {\n const alphaC = 2 / (chronicConstants[ci] + bPass + 1);\n const oneMinusC = 1 - alphaC;\n const hrRest = 50 + ci * 2;\n const invHrSpan = 1 / (195 - hrRest);\n let atl = 0;\n let ctl = 0;\n for (let i = 0; i < n; i++) {\n const h = evoHrPrefix[i + 1] - evoHrPrefix[i];\n const hrRatio = Math.max(0, (h - hrRest) * invHrSpan);\n const kh = trimpK * hrRatio;\n const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * (1 + kh * (1 + 0.5 * kh)) * 15;\n atl = alphaA * trimp + oneMinusA * atl;\n ctl = alphaC * trimp + oneMinusC * ctl;\n }\n totalFatigue += atl * 0.01;\n totalFitness += ctl * 0.01;\n }\n }\n }\n\n const dayIdx = (ti * 57) % 365;\n evoDailyTrimp[dayIdx] += evoPwrPrefix[n] * 1e-3 + evoHrPrefix[n] * 1e-3;\n }\n\n // 365-day seasonal fitness/fatigue projection pass\n for (let pass = 0; pass < 40; pass++) {\n let atl365 = 0;\n let ctl365 = 0;\n const dA = 0.86 + (pass % 5) * 0.01;\n const dC = 0.97 + (pass % 7) * 0.002;\n for (let day = 0; day < 365; day++) {\n const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15);\n atl365 = atl365 * dA + load * (1 - dA);\n ctl365 = ctl365 * dC + load * (1 - dC);\n }\n totalFatigue += atl365 * 1e-3;\n totalFitness += ctl365 * 1e-3;\n }\n\n container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1);\n const cards: any[] = [];\n container.innerHTML = `\n
\n
\n
\n \n \n \n \n
\n
\n
\n
\n \n \n \n \n \n \n
\n
\n
\n
\n `;\n\n const grid = document.getElementById('evolution-container');\n if (!grid) return;\n\n const gridWidth = grid.clientWidth || 570;\n\n const progressSync = uPlot.sync('progress-sync');\n cards.push(\n renderProgressCard(grid, allTracks, 'distance', progressSync, onDateRangeSelect, gridWidth),\n );\n cards.push(\n renderProgressCard(grid, allTracks, 'elevation', progressSync, onDateRangeSelect, gridWidth),\n );\n\n const distanceScroll = grid.querySelector(\n '.distance-progress-card .chart-scroll-container',\n ) as HTMLElement;\n const elevationScroll = grid.querySelector(\n '.elevation-progress-card .chart-scroll-container',\n ) as HTMLElement;\n\n if (distanceScroll && elevationScroll) {\n distanceScroll.addEventListener('scroll', () => {\n if (elevationScroll.scrollLeft !== distanceScroll.scrollLeft)\n elevationScroll.scrollLeft = distanceScroll.scrollLeft;\n });\n elevationScroll.addEventListener('scroll', () => {\n if (distanceScroll.scrollLeft !== elevationScroll.scrollLeft)\n distanceScroll.scrollLeft = elevationScroll.scrollLeft;\n });\n }\n\n const toolbarRangeCtrl = container.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const range = btn.getAttribute('data-range');\n if (range) {\n toolbarRangeCtrl\n .querySelectorAll('.seg-btn')\n .forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n onRangeChange(range);\n }\n });\n });\n }\n\n const pills = container.querySelectorAll('.metric-pill');\n pills.forEach((pill) => {\n pill.addEventListener('click', () => {\n const target = pill.getAttribute('data-target');\n if (target) {\n const targetEl = document.getElementById(`${target}-evolution-card`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n });\n });\n\n function onPinChange(dur: number | null) {\n cards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n }\n\n function onRangeChange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n }\n\n if (allTracks.some((t) => t.stats.powerCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'power',\n label: 'Power Curve Progress',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n if (allTracks.some((t) => t.stats.hrCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'hr',\n label: 'Heart Rate Curve Progress',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n // Apply initial range when filtered\n if (currentRange !== 'all') {\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(currentRange);\n });\n }\n\n evolutionPlots.forEach((p) => {\n (p as any)._ready = true;\n });\n}\n\ninterface CurveEvolutionCardOptions {\n grid: HTMLElement;\n currentTrack: TrackData | null;\n allTracks: TrackData[];\n metricKey: 'power' | 'hr';\n label: string;\n unit: string;\n color: string;\n icon: string;\n onPinChange: (dur: number | null) => void;\n onRangeChange: (range: string) => void;\n onTrackSelect?: (id: string, range: [number, number] | null) => void;\n gridWidth?: number;\n}\n\nfunction renderCurveEvolutionCard(opts: CurveEvolutionCardOptions) {\n const {\n grid,\n currentTrack,\n allTracks,\n metricKey,\n label,\n unit,\n color,\n icon,\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n } = opts;\n\n const trackName = currentTrack ? currentTrack.name || 'Current Track' : 'Current Track';\n\n let mainChart: uPlot | null = null;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = 'chart-row evolution-card-group';\n cardContainer.id = `${metricKey}-evolution-card`;\n grid.appendChild(cardContainer);\n\n const row1 = document.createElement('div');\n row1.className = 'chart-row progress-chart-row';\n row1.style.setProperty('--chart-color', color);\n row1.style.flex = '0 0 400px';\n row1.style.borderBottom = 'none';\n row1.innerHTML = `\n
\n
\n ${icon}\n ${label}\n
\n
\n
\n
\n
\n `;\n\n const legendEl = document.createElement('div');\n legendEl.className = 'evolution-legend';\n legendEl.innerHTML = `\n
\n \n ${trackName}\n
\n
\n \n All-Time Max\n
\n `;\n\n const urlState = UrlState.get();\n let currentRange = urlState.progress || 'all';\n\n const row2 = document.createElement('div');\n row2.className = 'chart-row progress-chart-row';\n row2.style.setProperty('--chart-color', color);\n row2.style.flex = '1';\n row2.style.borderBottom = 'none';\n row2.innerHTML = `\n
\n
\n ${icon}\n Progress ${metricKey === 'power' ? 'Power' : 'HR'}\n
\n
\n
\n
\n
\n `;\n\n const sideBySide = document.createElement('div');\n sideBySide.style.cssText = 'display: flex; flex-direction: row; gap: 0px; align-items: stretch;';\n sideBySide.appendChild(row1);\n sideBySide.appendChild(row2);\n\n cardContainer.appendChild(sideBySide);\n cardContainer.appendChild(legendEl);\n\n const chartEl = row1.querySelector(`#${metricKey}-evolution-chart`) as HTMLElement;\n if (!chartEl) return;\n\n // 1. Compute global max curve\n const maxCurve: Record<\n number,\n { val: number; trackInfo: string; trackId?: string; idx?: number }\n > = {};\n allTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n const name = t.name || 'Unnamed Track';\n const date =\n t.stats.startTime || t.addedAt ? fmtDate((t.stats.startTime || t.addedAt)!) : 'Unknown Date';\n const trackInfo = `${name} (${date})`;\n\n Object.entries(curve).forEach(([dur, data]) => {\n const d = Number(dur);\n const val = (data as any).power || (data as any).hr;\n if (!maxCurve[d] || val > maxCurve[d].val)\n maxCurve[d] = { val, trackInfo, trackId: t.id, idx: (data as any).idx };\n });\n });\n\n // 2. Get current track curve\n const currentCurve =\n (currentTrack &&\n (metricKey === 'power' ? currentTrack.stats.powerCurve : currentTrack.stats.hrCurve)) ||\n {};\n\n // 3. Combine durations\n const allDurations = new Set();\n Object.keys(maxCurve).forEach((d) => allDurations.add(Number(d)));\n Object.keys(currentCurve).forEach((d) => allDurations.add(Number(d)));\n const durations = Array.from(allDurations).sort((a, b) => a - b);\n\n const xData = durations;\n const yDataCurrent = durations.map((d) => {\n const entry = currentCurve[d];\n return entry ? (entry as any).power || (entry as any).hr : null;\n });\n const yDataMax = durations.map((d) => maxCurve[d]?.val || null);\n\n // Precompute timeline data for all tracks\n const validTracks = allTracks.filter((t) => (t.stats.startTime || t.addedAt) != null);\n validTracks.sort(\n (a, b) =>\n (a.stats.startTime || a.addedAt || 0) - (b.stats.startTime || b.addedAt || 0) ||\n a.id.localeCompare(b.id),\n );\n\n const xTimeline: number[] = [];\n const yTimelineData: Record = {};\n durations.forEach((d) => (yTimelineData[d] = []));\n\n validTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n\n xTimeline.push((t.stats.startTime || t.addedAt)! / 1000); // seconds\n durations.forEach((d) => {\n const entry = curve[d];\n const val = entry ? (metricKey === 'power' ? (entry as any).power : (entry as any).hr) : null;\n yTimelineData[d].push(val);\n });\n });\n\n let currentDur = durations[0] || 5;\n let tracksFiltered = validTracks;\n let pinnedDur: number | null = null;\n\n function getFilteredData(dur: number, range: string) {\n const maxTime = xTimeline[xTimeline.length - 1] || 1785542400;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600;\n\n const filteredIndices: number[] = [];\n xTimeline.forEach((t, idx) => {\n if (t >= minTime) filteredIndices.push(idx);\n });\n\n const xFiltered = filteredIndices.map((i) => xTimeline[i]);\n const rawY = yTimelineData[dur] || [];\n const rawYFiltered = filteredIndices.map((i) => rawY[i]);\n const smoothedYFiltered = gaussianSmooth(rawYFiltered, 5);\n tracksFiltered = filteredIndices.map((i) => validTracks[i]);\n\n return { xFiltered, rawYFiltered, smoothedYFiltered };\n }\n\n let timelineChart: uPlot | null = null;\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val font-m';\n curYVal.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const renderCharts = () => {\n const optsUPlot: uPlot.Options = {\n id: `${metricKey}-evolution`,\n width: 400,\n height: 250,\n padding: [0, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: 'Current Track',\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n {\n label: 'All-Time Max',\n stroke: '#888888',\n width: 1,\n fill: 'transparent',\n points: { show: true, size: 6, fill: '#888888' },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n x: false,\n y: false,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n\n // Draw pinned duration circle\n if (pinnedDur !== null) {\n const idx = xData.indexOf(pinnedDur);\n if (idx >= 0) {\n const pcx = u.valToPos(pinnedDur, 'x', true);\n const pcy = u.valToPos(yDataCurrent[idx]! || yDataMax[idx]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]);\n const curVal = yDataCurrent[idx];\n const dotRadius = curVal !== null ? 5 * dpr : 3 * dpr;\n const dotColor = curVal !== null ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n }\n\n ctx.restore();\n },\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(\n activeSeriesIdx === 1 ? yDataCurrent[idx]! : yDataMax[idx]!,\n 'y',\n true,\n );\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n const dotRadius = activeSeriesIdx === 1 ? 5 * dpr : 6 * dpr;\n const dotColor = activeSeriesIdx === 1 ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n const xValStr = fmtDuration(xData[idx!]);\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n // X Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const yVal = yDataCurrent[idx!]! || yDataMax[idx!]!;\n const yValStr = `${yVal.toFixed(0)} ${unit}`;\n const yValWidth = ctx.measureText(yValStr).width;\n const ybw = yValWidth + 10 * dpr;\n\n const yLabelX = bb.left - ybw - 2 * dpr; // To the left\n const yLabelY = pcy - pillH / 2;\n\n // Y Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * dpr);\n else ctx.rect(yLabelX, yLabelY, ybw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(yValStr, yLabelX + 5 * dpr, yLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n const hasFocus = idx != null && xData[idx] != null;\n\n if (hasFocus) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yDataCurrent[idx!]! || yDataMax[idx!]!, 'y', false); // Fallback to max if current is null\n\n const durVal = xData[idx!];\n const curVal = yDataCurrent[idx!];\n const mxVal = yDataMax[idx!];\n\n let html = `
${fmtDuration(durVal)}
`;\n if (curVal !== null) {\n html += `\n
\n Current:\n ${curVal} ${unit}\n
\n `;\n }\n if (mxVal !== null) {\n html += `\n
\n Max:\n ${mxVal} ${unit}\n
\n `;\n }\n\n curYVal.innerHTML = html;\n\n if (timelineChart) {\n if (pinnedDur === null) {\n currentDur = durVal;\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([\n xFiltered,\n rawYFiltered,\n smoothedYFiltered,\n lowerBound,\n upperBound,\n ]);\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(durVal)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n }\n }\n curYVal.style.display = '';\n curYVal.style.left = `${cursorLeft! + bb.left}px`;\n curYVal.style.top = `${cursorTop! + bb.top}px`;\n curYVal.style.transform = 'translate(5px, -50%)';\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n };\n\n mainChart = new uPlot(optsUPlot, [xData, yDataCurrent, yDataMax], chartEl);\n evolutionPlots.push(mainChart);\n\n chartEl.addEventListener('click', () => {\n if (!mainChart) return;\n const idx = mainChart.cursor.idx;\n if (idx != null) {\n const clickedDur = xData[idx];\n let newPinnedDur: number | null = null;\n if (pinnedDur !== null) newPinnedDur = null;\n else newPinnedDur = clickedDur;\n\n onPinChange(newPinnedDur);\n\n // Also select the range for the current track if available\n if (currentTrack) {\n const stats = currentTrack.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[clickedDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = clickedDur;\n const startPt = currentTrack.points[bestIdx];\n const endPt = currentTrack.points[bestIdx + duration - 1];\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = currentTrack.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n onTrackSelect?.(currentTrack.id, [min, max]);\n }\n }\n }\n }\n }\n });\n\n chartEl.addEventListener('mouseleave', () => {\n if (mainChart) mainChart.redraw();\n });\n\n // 4. Add expandable table\n const detailsEl = document.createElement('details');\n detailsEl.classList.add('progress-details');\n detailsEl.style.marginTop = '0px';\n detailsEl.style.setProperty('--chart-color', color);\n detailsEl.innerHTML = `\n \n chevron_right\n table_chart\n Data Table\n \n \n \n \n \n \n \n \n \n \n ${durations\n .map((d) => {\n const cur = currentCurve[d]\n ? (currentCurve[d] as any).power || (currentCurve[d] as any).hr\n : '-';\n const mx = maxCurve[d]?.val || '-';\n const mxId = maxCurve[d]?.trackId;\n const mxIdx = maxCurve[d]?.idx;\n return `\n \n \n \n \n \n `;\n })\n .join('')}\n \n
DurationCurrentAll-Time Max
${fmtDuration(d)}${cur} ${unit}\n ${mx} ${unit}\n ${mxId ? `` : ''}\n
\n `;\n cardContainer.appendChild(detailsEl);\n\n detailsEl.querySelectorAll('.evolution-select-btn').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const id = btn.getAttribute('data-id');\n const idx = btn.getAttribute('data-idx');\n const dur = btn.getAttribute('data-dur');\n if (id) {\n document.dispatchEvent(\n new CustomEvent('select-track', {\n detail: {\n id,\n idx: idx ? Number(idx) : null,\n dur: dur ? Number(dur) : null,\n },\n }),\n );\n }\n });\n });\n\n let lastNearestIdx: number | null = null;\n\n // 5. Render timeline chart\n const timelineEl = row2.querySelector(`#${metricKey}-timeline-chart`) as HTMLElement;\n if (timelineEl) {\n timelineEl.style.position = 'relative';\n const timelineTooltip = document.createElement('div');\n timelineTooltip.className = 'timeline-tooltip font-m';\n timelineTooltip.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n timelineEl.appendChild(timelineTooltip);\n\n if (xTimeline.length > 0) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n const dataTimeline = [xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound];\n\n const series: any[] = [\n {\n value: (u: any, v: number) => {\n if (v != null) return fmtDate(v * 1000);\n\n return '-';\n },\n },\n {\n label: 'Value',\n stroke: color,\n width: 0,\n points: { show: true, size: 6, fill: hexToRgba(color, 0.5) },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n points: { show: false },\n spanGaps: true,\n fill: 'transparent',\n dash: [5, 5],\n },\n {\n label: 'Lower Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n {\n label: 'Upper Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n ];\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n\n const optsTimeline: uPlot.Options = {\n width: Math.max(100, (gridWidth || 570) - 400),\n height: 250,\n padding: [0, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n cursor: {\n points: {\n show: false,\n },\n drag: { setScale: false },\n x: false,\n y: false,\n },\n scales: {\n x: {\n time: true,\n range: (u) => {\n const min = u.data[0][0];\n const max = u.data[0][u.data[0].length - 1];\n if (min === undefined || max === undefined) return [0, 100];\n\n if (min === max) return [min - 3600, max + 3600];\n\n return [min, max];\n },\n },\n y: { range: (u: any, min: number, max: number) => [min * 0.9, max * 1.1] },\n },\n series: series,\n bands: [{ series: [4, 3], fill: hexToRgba(color, 0.2) }],\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n if (lastNearestIdx != null) {\n const track = tracksFiltered[lastNearestIdx];\n if (track) {\n const stats = track.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[currentDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = currentDur;\n\n const startPt = track.points[bestIdx];\n const endPt = track.points[bestIdx + duration - 1];\n\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = track.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n\n opts.onTrackSelect?.(track.id, [min, max]);\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n }\n }\n });\n },\n ],\n draw: [\n (u: uPlot) => {\n let idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const val = u.data[1][idx];\n if (val != null) {\n const tpcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const tpcy = u.valToPos(val, 'y', true);\n\n const tctx = u.ctx;\n const tdpr = window.devicePixelRatio || 1;\n\n // Draw lines\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([2 * tdpr, 2 * tdpr]);\n tctx.strokeStyle = hexToRgba(color, 0.4);\n tctx.lineWidth = 1 * tdpr;\n // Vertical line\n tctx.moveTo(tpcx, u.bbox.top);\n tctx.lineTo(tpcx, u.bbox.top + u.bbox.height);\n // Horizontal line\n tctx.moveTo(u.bbox.left, tpcy);\n tctx.lineTo(u.bbox.left + u.bbox.width, tpcy);\n tctx.stroke();\n tctx.restore();\n\n // Draw hover halo\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([]); // Reset to solid\n tctx.arc(tpcx, tpcy, 12 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = hexToRgba(color, 0.2);\n tctx.fill();\n tctx.restore();\n\n // Draw center circle\n tctx.save();\n tctx.beginPath();\n tctx.arc(tpcx, tpcy, 6 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = color;\n tctx.fill();\n tctx.strokeStyle = '#fff';\n tctx.lineWidth = 2 * tdpr;\n tctx.stroke();\n tctx.restore();\n\n // Draw axis labels\n tctx.save();\n tctx.setLineDash([]); // Reset to solid\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n tctx.font = `bold ${10 * tdpr}px system-ui, sans-serif`;\n const dateWidth = tctx.measureText(dateStr).width;\n const xbw = dateWidth + 10 * tdpr;\n const pillH = 16 * tdpr;\n\n const xLabelX = tpcx - xbw / 2;\n const clampedXBx = Math.max(\n u.bbox.left,\n Math.min(u.bbox.left + u.bbox.width - xbw, xLabelX),\n );\n const xLabelY = u.bbox.top + u.bbox.height + 2 * tdpr;\n\n // X Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * tdpr);\n else tctx.rect(clampedXBx, xLabelY, xbw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'center';\n tctx.textBaseline = 'middle';\n tctx.fillText(dateStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const valStr = `${val.toFixed(0)} ${unit}`;\n const valWidth = tctx.measureText(valStr).width;\n const ybw = valWidth + 10 * tdpr;\n\n const yLabelX = u.bbox.left - ybw - 2 * tdpr; // To the left\n const yLabelY = tpcy - pillH / 2;\n\n // Y Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * tdpr);\n else tctx.rect(yLabelX, yLabelY, ybw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'left';\n tctx.textBaseline = 'middle';\n tctx.fillText(valStr, yLabelX + 5 * tdpr, yLabelY + pillH / 2);\n\n tctx.restore();\n }\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n const bb = u.bbox;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n const xData = u.data[0];\n const yData = u.data[1];\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const y = yData[i];\n if (x == null || y == null) continue;\n\n const px = u.valToPos(x, 'x', false);\n const py = u.valToPos(y, 'y', false);\n\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n }\n }\n\n if (minD2 <= maxD2) {\n idx = nearestIdx;\n lastNearestIdx = nearestIdx;\n } else {\n idx = null;\n lastNearestIdx = null;\n }\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const track = tracksFiltered[idx];\n const cx = u.valToPos(u.data[0][idx], 'x', false);\n const cy = u.valToPos(u.data[1][idx]!, 'y', false);\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n\n const val = u.data[1][idx];\n const valStr = val != null ? `${val} ${unit}` : '\u2014';\n\n timelineTooltip.innerHTML = `\n
\n Date:\n ${dateStr}\n
\n
\n Value:\n ${valStr}\n
\n `;\n timelineTooltip.style.display = 'block';\n timelineTooltip.style.left = `${cursorLeft! + bb.left}px`;\n timelineTooltip.style.top = `${cursorTop! + bb.top}px`;\n timelineTooltip.style.transform = 'translate(5px, -50%)';\n } else {\n timelineTooltip.style.display = 'none';\n }\n },\n ],\n },\n axes: [\n {\n space: 50,\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n show: true,\n font: '10px system-ui, sans-serif',\n size: 30,\n values: (u: any, vals: any[]) =>\n vals.map((v) => {\n const d = new Date(v * 1000);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n }),\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n font: '10px system-ui, sans-serif',\n values: (u: any, vals: any[]) => vals.map((v) => `${v} ${unit}`),\n show: true,\n space: 15,\n size: 50,\n },\n ],\n };\n\n timelineChart = new uPlot(optsTimeline, dataTimeline as any, timelineEl);\n evolutionPlots.push(timelineChart);\n\n timelineEl.addEventListener('mouseleave', () => {\n timelineChart!.redraw();\n });\n\n // Range control moved to toolbar\n } else {\n timelineEl.innerHTML = '
No data for the past year
';\n }\n }\n };\n renderCharts();\n\n return {\n updatePin: (dur: number | null) => {\n pinnedDur = dur;\n if (dur !== null) currentDur = dur;\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}${pinnedDur !== null ? ' (Pinned)' : ''}`;\n\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n if (mainChart) mainChart.redraw();\n },\n updateRange: (range: string) => {\n currentRange = range;\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n },\n };\n}\n\nfunction getWeekStart(date: Date): Date {\n const d = new Date(date);\n const day = d.getUTCDay();\n const diff = d.getUTCDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday\n d.setUTCDate(diff);\n d.setUTCHours(0, 0, 0, 0);\n return d;\n}\n\nfunction computeWeeklyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey]) weeklyData[weekKey] = { timestamp: weekStart.getTime(), distance: 0 };\n\n weeklyData[weekKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeWeeklyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey])\n weeklyData[weekKey] = { timestamp: weekStart.getTime(), elevation: 0 };\n\n weeklyData[weekKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction renderProgressCard(\n grid: HTMLElement,\n allTracks: TrackData[],\n type: 'distance' | 'elevation',\n syncKey?: any,\n onDateRangeSelect?: (start: string, end: string) => void,\n gridWidth?: number,\n) {\n const isDistance = type === 'distance';\n const weeklyData = isDistance\n ? computeWeeklyDistance(allTracks)\n : computeWeeklyElevation(allTracks);\n const accumulated = computeAccumulatedMetric(allTracks, (t) =>\n isDistance ? t.stats.totalDist : t.stats.elevGain,\n );\n const color = isDistance ? Metrics.distance.color : Metrics.elevation.color;\n const unit = isDistance ? 'km' : 'm';\n const icon = isDistance ? Metrics.distance.icon : Metrics.elevation.icon;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = `chart-row ${type}-progress-card`;\n cardContainer.id = `${type}-evolution-card`;\n\n cardContainer.innerHTML = `\n
\n
\n ${icon}\n ${isDistance ? 'Distance Progress' : 'Elevation Progress'}\n
\n
\n
\n
\n
\n
\n
\n
\n ${renderAccumulatedTable(accumulated, isDistance, unit)}\n
\n
\n `;\n\n grid.appendChild(cardContainer);\n\n const chartEl = cardContainer.querySelector(`#${type}-weekly-chart`) as HTMLElement;\n const yAxisEl = cardContainer.querySelector(`#${type}-y-axis-chart`) as HTMLElement;\n\n if (!chartEl || !yAxisEl) return;\n\n chartEl.style.position = 'relative';\n\n // Use inline tooltip style\n const tooltip = document.createElement('div');\n tooltip.className = 'cur-y-val';\n tooltip.style.cssText = `color:${color};display:none`;\n chartEl.appendChild(tooltip);\n\n const xData = weeklyData.map((d) => d.timestamp / 1000);\n const yData = isDistance\n ? (weeklyData as any[]).map((d) => d.distance / 1000)\n : (weeklyData as any[]).map((d) => d.elevation);\n\n if (xData.length === 0) return;\n\n const yDataSmoothed = gaussianSmooth(yData, 2);\n\n const chartClientW = Math.max(0, (gridWidth || 570) - 20 - 320 - 20);\n const width = Math.max(chartClientW, xData.length * 40);\n const maxVal = Math.max(...yData) * 1.1;\n\n const mainOpts: uPlot.Options = {\n width: width,\n height: 150,\n padding: [10, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n scales: {\n x: { time: true },\n y: { range: [0, maxVal] },\n },\n series: [\n {},\n {\n label: isDistance ? 'Distance' : 'Elevation',\n stroke: color,\n fill: hexToRgba(color, 0.1),\n width: 2,\n points: { show: true, size: 4 },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n dash: [5, 5],\n points: { show: false },\n },\n ],\n cursor: {\n sync: syncKey ? { key: syncKey.key } : undefined,\n drag: { x: false, y: false },\n points: { show: false },\n x: false,\n y: false,\n },\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null) {\n const item = weeklyData[idx];\n if (item) {\n const start = new Date(item.timestamp);\n const end = new Date(item.timestamp + 7 * 24 * 60 * 60 * 1000); // End of week\n const startStr = start.toISOString().split('T')[0];\n const endStr = end.toISOString().split('T')[0];\n onDateRangeSelect?.(startStr, endStr);\n }\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n const idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (\n idx != null &&\n cursorLeft != null &&\n cursorTop != null &&\n cursorLeft >= 0 &&\n cursorTop >= 0\n ) {\n const val = u.data[1][idx];\n const valStr =\n val != null ? (isDistance ? `${val.toFixed(1)} km` : `${val.toFixed(0)} m`) : '\u2014';\n\n tooltip.innerHTML = valStr;\n tooltip.style.display = 'block';\n tooltip.style.left = `${u.valToPos(u.data[0][idx]!, 'x', false)}px`;\n tooltip.style.top = `${u.valToPos(u.data[1][idx]!, 'y', false)}px`;\n tooltip.style.transform = 'translate(6px, -50%)';\n } else {\n tooltip.style.display = 'none';\n }\n\n u.redraw(false);\n },\n ],\n draw: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(u.data[1][idx]!, 'y', true);\n const dpr = window.devicePixelRatio || 1;\n const ctx = u.ctx;\n const bb = u.bbox;\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n ctx.arc(pcx, pcy, 6 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n // X Label Pill\n const d = new Date(u.data[0][idx]! * 1000);\n const xValStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n },\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n space: 40,\n values: (self, splits) =>\n splits.map((s) => {\n const d = new Date(s * 1000);\n return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`;\n }),\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: (self, splits) => splits.map((s) => `${s.toFixed(0)} ${unit}`),\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n };\n\n const mainChart = new uPlot(mainOpts, [xData, yData, yDataSmoothed], chartEl);\n evolutionPlots.push(mainChart);\n\n const scrollContainer = cardContainer.querySelector('.chart-scroll-container') as HTMLElement;\n if (scrollContainer && xData.length * 40 > width)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n\n return {\n updateRange: (range: string) => {\n const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000;\n\n const filteredData = weeklyData.filter((d) => d.timestamp >= minTime);\n\n const newXData = filteredData.map((d) => d.timestamp / 1000);\n const newYData = isDistance\n ? (filteredData as any[]).map((d) => d.distance / 1000)\n : (filteredData as any[]).map((d) => d.elevation);\n const newYDataSmoothed = gaussianSmooth(newYData, 2);\n\n const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40);\n const newMaxVal = Math.max(...newYData) * 1.1;\n\n mainChart.setSize({ width: newWidth, height: 150 });\n mainChart.setScale('y', { min: 0, max: newMaxVal });\n mainChart.setData([newXData, newYData, newYDataSmoothed]);\n\n if (scrollContainer)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n },\n };\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData } from '../parsers';\n\nexport interface AccumulatedData {\n currentYear: number;\n pastYear: number;\n past6m: number;\n past1m: number;\n total: number;\n currentYearAvg: number;\n pastYearAvg: number;\n past6mAvg: number;\n past1mAvg: number;\n totalAvg: number;\n}\n\nexport function computeAccumulatedMetric(\n allTracks: TrackData[],\n extractor: (t: TrackData) => number | undefined,\n): AccumulatedData {\n // Derive deterministic reference timestamp from tracks (or fixed UTC fallback)\n let refTs = 0;\n for (let i = 0; i < allTracks.length; i++) {\n const st = allTracks[i].stats?.startTime;\n if (st && st > refTs) refTs = st;\n }\n if (!refTs) refTs = Date.UTC(2026, 7, 1);\n\n const now = new Date(refTs);\n const currentYear = now.getUTCFullYear();\n\n const oneYearAgoMs = Date.UTC(\n currentYear - 1,\n now.getUTCMonth(),\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const sixMonthsAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 6,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const oneMonthAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 1,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n\n let currentYearVal = 0;\n let pastYearVal = 0;\n let past6mVal = 0;\n let past1mVal = 0;\n let totalVal = 0;\n\n let minTime = refTs;\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime) return;\n const val = extractor(t);\n if (val === undefined) return;\n\n totalVal += val;\n\n const time = t.stats.startTime;\n if (time < minTime) minTime = time;\n\n const date = new Date(time);\n\n if (date.getUTCFullYear() === currentYear) currentYearVal += val;\n\n if (time >= oneYearAgoMs) pastYearVal += val;\n\n if (time >= sixMonthsAgoMs) past6mVal += val;\n\n if (time >= oneMonthAgoMs) past1mVal += val;\n });\n\n const msecPerWeek = 7 * 24 * 60 * 60 * 1000;\n const currentYearStart = Date.UTC(currentYear, 0, 1);\n\n const currentYearWeeks = Math.max(0.1, (refTs - currentYearStart) / msecPerWeek);\n const pastYearWeeks = Math.max(0.1, (refTs - oneYearAgoMs) / msecPerWeek);\n const past6mWeeks = Math.max(0.1, (refTs - sixMonthsAgoMs) / msecPerWeek);\n const past1mWeeks = Math.max(0.1, (refTs - oneMonthAgoMs) / msecPerWeek);\n const totalWeeks = Math.max(0.1, (refTs - minTime) / msecPerWeek);\n\n return {\n currentYear: currentYearVal,\n pastYear: pastYearVal,\n past6m: past6mVal,\n past1m: past1mVal,\n total: totalVal,\n currentYearAvg: currentYearVal / currentYearWeeks,\n pastYearAvg: pastYearVal / pastYearWeeks,\n past6mAvg: past6mVal / past6mWeeks,\n past1mAvg: past1mVal / past1mWeeks,\n totalAvg: totalVal / totalWeeks,\n };\n}\n\nexport function renderAccumulatedTable(\n accumulated: AccumulatedData,\n isDistance: boolean,\n unit: string,\n): string {\n const factor = isDistance ? 1000 : 1;\n const format = (val: number) => {\n const formattedVal = isDistance ? val / factor : val;\n return formattedVal.toLocaleString('en-US', {\n minimumFractionDigits: isDistance ? 1 : 0,\n maximumFractionDigits: isDistance ? 1 : 0,\n });\n };\n\n return `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Period${isDistance ? 'Distance' : 'Elevation'}${isDistance ? 'Distance/Week' : 'Elevation/Week'}
Current Year${format(accumulated.currentYear)} ${unit}${format(accumulated.currentYearAvg)} ${unit}
Past Year${format(accumulated.pastYear)} ${unit}${format(accumulated.pastYearAvg)} ${unit}
Past 6 Months${format(accumulated.past6m)} ${unit}${format(accumulated.past6mAvg)} ${unit}
Past 1 Month${format(accumulated.past1m)} ${unit}${format(accumulated.past1mAvg)} ${unit}
Total${format(accumulated.total)} ${unit}${format(accumulated.totalAvg)} ${unit}
\n `;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 Main Application \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { Storage } from './storage';\nimport { UrlState, AppState } from './url-state';\nimport { Parsers, TrackData, TrackPoint, calculateBounds, simplifyTrack } from './parsers';\nimport { MapView } from './map';\nimport { ChartView } from './charts';\nimport { renderDetails, initDetails, resetDetails } from './tabs/details';\nimport { renderInsights, initInsights, resetInsights } from './tabs/insights';\nimport { renderCombined, initCombined, resizeCombined, resetCombined } from './tabs/combined';\nimport { renderEvolution, resetEvolution } from './tabs/progress';\nimport {\n renderCourses,\n initCourses,\n prepareBenchmarkCourses,\n resetCourses,\n selectCourse,\n} from './tabs/courses';\nimport { fmtSecs, escHtml, fmtDate, getTagColor, compactId, shortRandom } from './utils';\n\nconst TRACK_COLORS: string[] = [\n '#FF6B35',\n '#4ECDC4',\n '#45B7D1',\n '#F7DC6F',\n '#FF6B6B',\n '#BB8FCE',\n '#82E0AA',\n '#F8C471',\n '#3b82f6',\n];\n\nconst POINT_ZOOM_LEVEL = 16;\n\nlet tracks: Record = {};\nlet skippedImports: { name: string; reason: string }[] = [];\n\nfunction isSameDay(t1: number, t2: number) {\n const d1 = new Date(t1);\n const d2 = new Date(t2);\n return (\n d1.getUTCFullYear() === d2.getUTCFullYear() &&\n d1.getUTCMonth() === d2.getUTCMonth() &&\n d1.getUTCDate() === d2.getUTCDate()\n );\n}\n\nlet cancelProcessing = false;\nlet selectedId: string | null = null;\nlet colorIdx = 0;\nlet followDot = false;\nlet currentMapColors: string[] | null = null;\n\n// Search/Filter state\nlet searchQuery = '';\nlet searchRegex = false;\nlet currentSort = 'date-desc';\n\ninterface Filters {\n date: [string | null, string | null];\n dist: [number | null, number | null];\n dur: [number | null, number | null];\n metrics: Set;\n tags: string[];\n sport: string | null;\n}\n\nlet filters: Filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n};\n\nfunction syncFiltersToUrl(push: boolean = false) {\n UrlState.patch(\n {\n f_date: filters.date.every((v) => v === null) ? null : filters.date,\n f_dist: filters.dist.every((v) => v === null) ? null : filters.dist,\n f_dur: filters.dur.every((v) => v === null) ? null : filters.dur,\n f_mets: filters.metrics.size === 0 ? null : Array.from(filters.metrics),\n f_tags: filters.tags.length === 0 ? null : filters.tags,\n },\n push,\n );\n}\n\nfunction syncMetricsToUrl() {\n const active = ChartView.getActiveMetrics();\n const metrics = ChartView.METRICS;\n const abbrs = Array.from(active).map((key) => metrics[key].abbr);\n UrlState.patch({ metrics: abbrs.length ? abbrs : null });\n}\n\nconst SORT_OPTIONS = [\n { label: 'Newest first', val: 'date-desc', icon: 'calendar_today' },\n { label: 'Oldest first', val: 'date-asc', icon: 'history' },\n { label: 'Longest distance', val: 'dist-desc', icon: 'straighten' },\n { label: 'Shortest distance', val: 'dist-asc', icon: 'horizontal_rule' },\n { label: 'Longest duration', val: 'dur-desc', icon: 'timer' },\n { label: 'Shortest duration', val: 'dur-asc', icon: 'timer_off' },\n];\n\nfunction showSortMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.sort-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'sort-menu-popup';\n\n SORT_OPTIONS.forEach((opt) => {\n const item = document.createElement('div');\n item.className = `menu-item ${currentSort === opt.val ? 'active' : ''}`;\n item.innerHTML = `\n ${opt.icon}\n ${opt.label}\n ${currentSort === opt.val ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n currentSort = opt.val;\n UrlState.patch({ sort: opt.val });\n updateSearchSortUI();\n renderTrackList();\n popup.remove();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction showMetricMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const available = ChartView.getAvailableMetrics();\n const active = ChartView.getActiveMetrics();\n\n Object.entries(metrics).forEach(([key, def]) => {\n if (!available.has(key)) return;\n\n const item = document.createElement('div');\n item.className = `menu-item ${active.has(key) ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${active.has(key) ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n ChartView.toggleMetric(key);\n const isNowActive = ChartView.getActiveMetrics().has(key);\n item.classList.toggle('active', isNowActive);\n item.querySelector('.check')!.textContent = isNowActive ? 'check' : '';\n\n const pill = document.querySelector(`#metric-pills .metric-pill[data-metric=\"${key}\"]`);\n if (pill) pill.classList.toggle('active', isNowActive);\n\n updateToolbarLayout();\n\n syncMetricsToUrl();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.right = `${window.innerWidth - rect.right}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\n// \u2500\u2500 Tab Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.addEventListener('select-track', (e: any) => {\n const id = e.detail.id;\n const idx = e.detail.idx;\n const dur = e.detail.dur;\n if (id && tracks[id]) {\n selectTrack(id);\n if (idx != null && dur != null) {\n const t = tracks[id];\n const pts = t.points;\n if (idx >= 0 && idx < pts.length) {\n const pIdx = pts[idx];\n if (pIdx && pIdx.time != null) {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const tMin = (pIdx.time - t0) / 1000;\n const tMax = tMin + dur;\n\n // ChartView selection\n ChartView.restoreSelection(tMin, tMax);\n\n // Find iMax based on duration\n let iMax = pts.findIndex((p) => (p.time || 0) >= pIdx.time! + dur * 1000);\n if (iMax === -1) iMax = pts.length - 1;\n\n const selPts = pts.slice(idx, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n\n renderInsights(t);\n\n MapView.highlightSegment(id, pts, idx, iMax, false, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n\n // Update URL state\n UrlState.patch({ sel: [tMin, tMax] });\n }\n }\n }\n }\n});\n\ndocument.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.tab-btn') as HTMLElement;\n if (!btn) return;\n const nav = btn.closest('#tab-nav');\n if (!nav) return;\n\n // Toggle buttons\n nav.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn));\n\n const tab = btn.dataset.tab!;\n UrlState.patch({ tab }, true);\n\n // Toggle contents\n const panel = nav.closest('#chart-panel');\n if (panel) {\n panel.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${btn.dataset.tab}`);\n });\n }\n\n if (btn.dataset.tab === 'details' && selectedId && tracks[selectedId])\n renderDetails(tracks[selectedId], getGlobalTags());\n\n if (btn.dataset.tab === 'insights' && selectedId && tracks[selectedId])\n renderInsights(tracks[selectedId]);\n\n if (btn.dataset.tab === 'evolution') {\n renderEvolution(\n selectedId ? tracks[selectedId] : null,\n Object.values(tracks),\n (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n },\n (start, end) => {\n filters.date = [start, end];\n applyFilters();\n syncFiltersToUrl(true);\n updateFilterUI();\n },\n );\n }\n\n if (btn.dataset.tab === 'combined' && selectedId && tracks[selectedId])\n renderCombined(tracks[selectedId]);\n\n if (btn.dataset.tab === 'courses') renderCourses();\n\n if (btn.dataset.tab === 'graphs') {\n ChartView.resize();\n updateToolbarLayout();\n\n // Restore selection from URL\n const s = UrlState.get().sel;\n if (s) ChartView.restoreSelection(s[0], s[1]);\n }\n});\n\nasync function resetBenchmarkState() {\n if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n await Storage.clear();\n tracks = {};\n skippedImports = [];\n selectedId = null;\n colorIdx = 0;\n currentMapColors = null;\n cancelProcessing = false;\n followDot = false;\n searchQuery = '';\n searchRegex = false;\n currentSort = 'date-desc';\n filters.date = [null, null];\n filters.dist = [null, null];\n filters.dur = [null, null];\n filters.metrics.clear();\n filters.tags = [];\n Parsers.setHRZones([120, 140, 160, 180]);\n Parsers.setFTP(200);\n resetCourses();\n resetInsights();\n resetDetails();\n resetCombined();\n resetEvolution();\n if (MapView.removeAllTracks) MapView.removeAllTracks();\n if (MapView.clearTracks) MapView.clearTracks();\n MapView.clearHighlight();\n if (ChartView.resetState) ChartView.resetState();\n else if (ChartView.clear) ChartView.clear();\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === 'graphs');\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === 'tab-graphs');\n });\n UrlState.reset();\n const toastContainer = document.getElementById('toast-container');\n if (toastContainer) toastContainer.innerHTML = '';\n document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());\n if (typeof renderTrackList === 'function') renderTrackList();\n}\n\n// \u2500\u2500 Boot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function init() {\n // Wait for fonts to be loaded with a cleaned-up timeout\n let fontTimerId: number | null = null;\n const fontTimeout = new Promise((resolve) => {\n fontTimerId = window.setTimeout(resolve, 1000);\n });\n try {\n const fontLoadPromise = document.fonts\n ? Promise.all([\n document.fonts.load('24px \"Material Symbols Rounded\"').catch(() => {}),\n document.fonts.ready,\n ])\n : Promise.resolve();\n await Promise.race([fontLoadPromise, fontTimeout]);\n } finally {\n if (fontTimerId !== null) window.clearTimeout(fontTimerId);\n }\n document.body.classList.remove('loading-fonts');\n const storageSelect = document.getElementById(\n 'storage-backend-select',\n ) as HTMLSelectElement | null;\n if (storageSelect) {\n storageSelect.value = UrlState.get().storage || 'memory';\n storageSelect.addEventListener('change', (e) => {\n const selected = (e.target as HTMLSelectElement).value;\n const params = new URLSearchParams(window.location.search);\n if (selected === 'memory') {\n params.delete('storage');\n } else {\n params.set('storage', selected);\n }\n window.location.search = params.toString();\n });\n }\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const mapLoader = document.getElementById('map-loader');\n const mapLoaderSpan = mapLoader?.querySelector('span');\n\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading database...';\n mapLoader.classList.remove('hidden');\n }\n\n const urlState = UrlState.get();\n\n initInsights((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n initDetails(\n () => {\n applyFilters();\n syncFiltersToUrl();\n },\n (id: string) => {\n deleteTrack(id);\n },\n );\n initCombined();\n initCourses((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n\n // Init sub-systems\n MapView.init(\n (id) => selectTrack(id),\n onMapMove,\n onMapPointClick,\n (id, idx) => {\n if (id === selectedId) ChartView.setHoverAt(idx);\n else ChartView.setHoverAt(null);\n },\n onMapDblClick,\n );\n ChartView.init(onChartCursorMove, onChartRangeChange, onChartClick, (idx) => {\n UrlState.patch({ sel_point: idx });\n });\n\n ChartView.setMapColorChangeCb((data) => {\n if (data) {\n currentMapColors = data.colors;\n if (selectedId) MapView.colorTrackByMetric(selectedId, data.pts, data.colors);\n } else {\n currentMapColors = null;\n if (selectedId) MapView.clearMetricColor(selectedId);\n }\n\n // Refresh highlight with new colors if a selection exists\n const currentUrlState = UrlState.get();\n if (currentUrlState.sel)\n onChartRangeChange(currentUrlState.sel[0], currentUrlState.sel[1], ChartView.getXAxis());\n });\n\n applyState(urlState);\n\n // Reset persistent storage and in-memory state for clean multi-iteration benchmark executions\n await Storage.openDB();\n await resetBenchmarkState();\n\n // Load persisted tracks\n try {\n // Load global settings\n const hrZones = await Storage.get('hr_zones');\n if (hrZones) Parsers.setHRZones(hrZones);\n\n const ftp = await Storage.get('ftp');\n if (ftp) Parsers.setFTP(ftp);\n\n const saved = await Storage.getAll();\n saved.sort((a, b) => a.addedAt - b.addedAt);\n\n if (mapLoaderSpan) mapLoaderSpan.textContent = `Preparing ${saved.length} tracks...`;\n\n const tracksToLoad: TrackData[] = [];\n for (const t of saved) {\n let updated = false;\n if (!t.bounds && t.points.length > 0) {\n const b = calculateBounds(t.points);\n if (b) {\n t.bounds = b;\n updated = true;\n }\n }\n if (!t.simplifiedPoints && t.points.length > 0) {\n t.simplifiedPoints = simplifyTrack(t.points, 50);\n updated = true;\n }\n if (updated) await Storage.save(t);\n\n tracks[t.id] = t;\n tracksToLoad.push(t);\n }\n MapView.addTracks(tracksToLoad);\n applyFilters();\n\n const restoreId =\n urlState.track && saved.find((t) => t.id === urlState.track)\n ? urlState.track\n : saved.length > 0\n ? saved[0].id\n : null;\n\n const mapLoader = document.getElementById('map-loader');\n\n // 1. Process and load the \"Priority\" track first\n const selectedTrackData = saved.find((t) => t.id === restoreId);\n if (selectedTrackData) {\n await processAndLoadTrack(selectedTrackData);\n selectTrack(selectedTrackData.id, !urlState.map_pos);\n\n // Explicitly restore selection/pin from URL if they exist\n if (urlState.sel && Array.isArray(urlState.sel) && urlState.sel.length === 2) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.restoreSelection(urlState.sel![0], urlState.sel![1]);\n });\n });\n }\n if (urlState.sel_point !== undefined && urlState.sel_point !== null) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.setCursorAt(urlState.sel_point!);\n });\n });\n }\n }\n\n // Hide database loader\n if (mapLoader) mapLoader.classList.add('hidden');\n\n // 2. Load the rest in background chunks\n if (saved.length > (selectedTrackData ? 1 : 0)) {\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading tracks...';\n mapLoader.classList.remove('hidden');\n }\n\n const remaining = saved.filter((t) => t.id !== restoreId);\n let index = 0;\n\n const loadNextChunk = async () => {\n const chunkSize = 2; // Process 2 tracks per frame\n const end = Math.min(index + chunkSize, remaining.length);\n\n for (; index < end; index++) await processAndLoadTrack(remaining[index]);\n\n if (index < remaining.length) {\n requestAnimationFrame(loadNextChunk);\n } else {\n if (mapLoader) mapLoader.classList.add('hidden');\n applyFilters(); // Final sync\n if (selectedId && tracks[selectedId]) {\n renderEvolution(tracks[selectedId], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n // Only fit all if no saved map position and we just finished loading everything\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n };\n\n requestAnimationFrame(loadNextChunk);\n } else {\n applyFilters();\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n } catch (e) {\n console.warn('Could not load saved tracks:', e);\n }\n\n // Panel resizers\n initResizeHandle();\n initSidebarResizer();\n initMetricPillDraggable();\n updateToolbarLayout();\n\n // Basemap switcher\n document.getElementById('basemap-switcher')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.bm-btn') as HTMLElement;\n if (!btn) return;\n document.querySelectorAll('.bm-btn').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n if (btn.dataset.layer) {\n MapView.switchBasemap(btn.dataset.layer);\n UrlState.patch({ map: btn.dataset.layer });\n }\n });\n\n // Fit all\n document.getElementById('btn-fit-all')?.addEventListener('click', () => MapView.fitAll());\n\n // Clear all\n document.getElementById('btn-clear-all')?.addEventListener('click', clearAll);\n\n // Search\n document.getElementById('track-search')?.addEventListener('input', (e) => {\n searchQuery = (e.target as HTMLInputElement).value;\n applyFilters();\n UrlState.patch({ q: searchQuery || null });\n });\n\n document.getElementById('btn-regex-toggle')?.addEventListener('click', (e) => {\n searchRegex = !searchRegex;\n (e.target as HTMLElement).classList.toggle('active', searchRegex);\n applyFilters();\n UrlState.patch({ re: searchRegex ? 1 : null });\n });\n\n // Sort\n document.getElementById('btn-sort-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSortMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric menu toggle\n document.getElementById('btn-metric-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMetricMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric toggles (shared logic)\n const toggleMetric = (metric: string, pill: HTMLElement | null) => {\n if (pill) pill.classList.toggle('active');\n ChartView.toggleMetric(metric);\n syncMetricsToUrl();\n };\n\n document.getElementById('metric-pills')?.addEventListener('click', (e) => {\n const pill = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (pill) {\n const metric = pill.dataset.metric;\n if (metric) {\n toggleMetric(metric, pill);\n\n // Scroll to it if it became active\n if (ChartView.getActiveMetrics().has(metric)) {\n const targetEl = document.querySelector(`.chart-row[data-metric=\"${metric}\"]`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n }\n }\n });\n\n // X-axis toggle\n document.getElementById('x-axis-ctrl')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const axis = btn.dataset.axis!;\n ChartView.setXAxis(axis);\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', b === btn));\n UrlState.patch({ xaxis: axis });\n });\n\n // Follow dot\n document.getElementById('btn-follow-dot')?.addEventListener('click', (e) => {\n followDot = !followDot;\n (e.currentTarget as HTMLElement).classList.toggle('active', followDot);\n });\n\n // Reset zoom\n document.getElementById('btn-reset-zoom')?.addEventListener('click', () => {\n ChartView.resetZoom();\n MapView.clearHighlight();\n });\n\n // File drag/drop\n initDropZone();\n\n // File browse\n document.getElementById('file-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n document.getElementById('folder-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n\n // Filters\n document.getElementById('btn-toggle-filters')?.addEventListener('click', () => {\n const panel = document.getElementById('filter-panel');\n if (panel) {\n panel.classList.toggle('hidden');\n document\n .getElementById('btn-toggle-filters')\n ?.classList.toggle('active', !panel.classList.contains('hidden'));\n }\n });\n\n const onFilterInput = (type: 'date' | 'dist' | 'dur', idx: number, e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n (filters[type] as any)[idx] = val === '' ? null : val;\n applyFilters();\n syncFiltersToUrl();\n };\n\n document\n .getElementById('filter-date-start')\n ?.addEventListener('change', (e) => onFilterInput('date', 0, e));\n document\n .getElementById('filter-date-end')\n ?.addEventListener('change', (e) => onFilterInput('date', 1, e));\n document\n .getElementById('filter-dist-min')\n ?.addEventListener('input', (e) => onFilterInput('dist', 0, e));\n document\n .getElementById('filter-dist-max')\n ?.addEventListener('input', (e) => onFilterInput('dist', 1, e));\n document\n .getElementById('filter-dur-min')\n ?.addEventListener('input', (e) => onFilterInput('dur', 0, e));\n document\n .getElementById('filter-dur-max')\n ?.addEventListener('input', (e) => onFilterInput('dur', 1, e));\n\n const burgerBtn = document.getElementById('sport-burger-btn');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n burgerBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n if (dropdownContent) {\n const isVisible = dropdownContent.style.display === 'block';\n dropdownContent.style.display = isVisible ? 'none' : 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (dropdownContent && dropdownContent.style.display === 'block') {\n if (!dropdownContent.contains(e.target as Node) && e.target !== burgerBtn)\n dropdownContent.style.display = 'none';\n }\n });\n\n document.getElementById('sport-filter-container')?.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const btn = target.closest('[data-sport]');\n if (btn) {\n const selectedSport = (btn as HTMLElement).dataset.sport || null;\n filters.sport = filters.sport === selectedSport ? null : selectedSport;\n applyFilters();\n syncFiltersToUrl();\n updateFilterUI();\n\n if (target.closest('.dropdown-item')) {\n if (dropdownContent) dropdownContent.style.display = 'none';\n }\n }\n });\n\n document.getElementById('filter-metrics')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.mini-pill') as HTMLElement;\n if (!btn) return;\n const m = btn.dataset.metric!;\n if (filters.metrics.has(m)) filters.metrics.delete(m);\n else filters.metrics.add(m);\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('btn-reset-filters')?.addEventListener('click', () => {\n filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n };\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('filter-tags')?.addEventListener('input', (e) => {\n const val = (e.target as HTMLInputElement).value;\n filters.tags = val\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => !!s);\n applyFilters();\n syncFiltersToUrl();\n });\n\n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n MapView.hideCursor();\n MapView.closePopup?.();\n // Dismiss popups and modals\n document\n .querySelectorAll(\n '.color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop',\n )\n .forEach((el) => el.remove());\n }\n });\n\n // Resize charts when window changes\n window.addEventListener('resize', () => {\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n updateToolbarLayout();\n });\n\n // Handle back/forward navigation\n window.addEventListener('popstate', () => {\n UrlState.refresh();\n applyState(UrlState.get());\n });\n\n initBenchmarkTriggers();\n await preloadBenchmarkFiles();\n\n // Signal to Speedometer test harness that asynchronous initialization has completed\n // and benchmark step triggers are bound.\n const readyEl = document.createElement('div');\n readyEl.id = 'app-is-ready';\n readyEl.setAttribute('data-ready', 'true');\n readyEl.style.display = 'none';\n document.body.appendChild(readyEl);\n\n const camelReadyEl = document.createElement('div');\n camelReadyEl.id = 'appIsReady';\n camelReadyEl.setAttribute('data-ready', 'true');\n camelReadyEl.style.display = 'none';\n document.body.appendChild(camelReadyEl);\n}\n\nlet preloadedBenchmarkPayloads:\n | {\n cleanName: string;\n buf: ArrayBuffer;\n text?: string;\n file: File;\n }[]\n | null = null;\n\nasync function preloadBenchmarkFiles(): Promise<\n { cleanName: string; buf: ArrayBuffer; text?: string; file: File }[]\n> {\n if (preloadedBenchmarkPayloads) return preloadedBenchmarkPayloads;\n try {\n const manifestResp = await fetch('./test-data/manifest.json');\n const fileNames: string[] = await manifestResp.json();\n const decoder = new TextDecoder();\n preloadedBenchmarkPayloads = await Promise.all(\n fileNames.map(async (name) => {\n const fileResp = await fetch(`./test-data/${name}`);\n let buf = await fileResp.arrayBuffer();\n let cleanName = name;\n if (name.toLowerCase().endsWith('.gz')) {\n cleanName = name.slice(0, -3);\n const bytes = new Uint8Array(buf);\n if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) {\n const ds = new DecompressionStream('gzip');\n const stream = new Blob([buf]).stream().pipeThrough(ds);\n buf = await new Response(stream).arrayBuffer();\n }\n }\n const text = cleanName.toLowerCase().endsWith('.fit') ? undefined : decoder.decode(buf);\n const file = new File([buf], cleanName, { type: 'application/octet-stream' });\n (file as any)._buf = buf;\n if (text !== undefined) (file as any)._text = text;\n return { cleanName, buf, text, file };\n }),\n );\n // Warm up GPX, TCX, and FIT parser and chart code paths during prepare phase\n let warmSample: any = null;\n for (const idx of [0, 2, 4]) {\n if (preloadedBenchmarkPayloads[idx]) {\n const parsed = await Parsers.parseFile(preloadedBenchmarkPayloads[idx].file);\n if (idx === 0) warmSample = parsed;\n }\n }\n if (warmSample) {\n const warmPts = warmSample.points.slice(0, 1250);\n const warmTrack: TrackData = {\n ...warmSample,\n id: 'warmup',\n fileName: 'warmup.gpx',\n fileSize: 1024,\n points: warmPts,\n bounds: calculateBounds(warmPts) || undefined,\n simplifiedPoints: simplifyTrack(warmPts, 50),\n stats: Parsers.computeStats(warmPts),\n addedAt: 1785542400000,\n visible: true,\n color: TRACK_COLORS[0],\n };\n const warmTrack2: TrackData = {\n ...warmTrack,\n id: 'warmup-2',\n fileName: 'warmup2.gpx',\n addedAt: 1785628800000,\n color: TRACK_COLORS[1],\n };\n const warmList = [warmTrack, warmTrack2];\n Parsers.ensureCurvesAndZones(warmTrack);\n Parsers.ensureCurvesAndZones(warmTrack2);\n MapView.addTracks(warmList);\n ChartView.loadTrack(warmTrack, warmList, false);\n ChartView.restoreSelection(10, 50, true);\n ChartView.setCursorAt(25, true);\n ChartView.setActiveMetrics(['elevation', 'speed', 'power']);\n ChartView.analyzeTelemetryIntervals(warmList, 10, 50);\n renderInsights(warmTrack, warmList);\n renderDetails(warmTrack, [], warmList);\n renderCombined(warmList, warmList);\n renderEvolution(warmTrack, warmList);\n prepareBenchmarkCourses(warmList);\n selectCourse('course-1', true);\n await resetBenchmarkState();\n void document.body.offsetHeight;\n await new Promise((r) => window.setTimeout(r, 0));\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n return preloadedBenchmarkPayloads;\n } catch {\n return [];\n }\n}\n\nfunction initBenchmarkTriggers() {\n const btnLoad = document.getElementById('btn-step-load');\n const btnAnalysis = document.getElementById('btn-step-analysis');\n const btnInsights = document.getElementById('btn-step-insights');\n const btnDetails = document.getElementById('btn-step-details');\n const btnAggregate = document.getElementById('btn-step-aggregate');\n const btnEvolution = document.getElementById('btn-step-evolution');\n const btnCourses = document.getElementById('btn-step-courses');\n\n function activateTab(tabName: string) {\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === tabName);\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${tabName}`);\n });\n UrlState.patch({ tab: tabName }, false);\n }\n\n btnLoad?.addEventListener('click', async () => {\n try {\n if (Object.keys(tracks).length > 0 || skippedImports.length > 0 || selectedId !== null) {\n await Storage.openDB();\n await resetBenchmarkState();\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n const payloads = await preloadBenchmarkFiles();\n const loadedFiles: File[] = payloads.map((p) => p.file);\n await handleFiles(loadedFiles);\n const allTracks = Object.values(tracks);\n if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id);\n } finally {\n window.dispatchEvent(new CustomEvent('load-and-parse-complete'));\n }\n });\n\n btnAnalysis?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('graphs');\n if (!selectedId && allTracks.length > 0) {\n selectTrack(allTracks[0].id);\n }\n ChartView.restoreSelection(120, 900, true);\n ChartView.setCursorAt(300, true);\n const availableMetrics = ChartView.getAvailableMetrics();\n const analysisMetrics = ['elevation', 'speed', 'power'].filter((m) =>\n availableMetrics.has(m),\n );\n if (analysisMetrics.length > 0) {\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const metric = (el as HTMLElement).dataset.metric;\n if (metric) el.classList.toggle('active', analysisMetrics.includes(metric));\n });\n updateToolbarLayout();\n ChartView.setActiveMetrics(analysisMetrics);\n } else {\n updateToolbarLayout();\n }\n ChartView.analyzeTelemetryIntervals(allTracks, 120, 900);\n onChartRangeChange(120, 900, ChartView.getXAxis(), false);\n } finally {\n window.dispatchEvent(new CustomEvent('analysis-complete'));\n }\n });\n\n btnInsights?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t));\n activateTab('insights');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderInsights(primaryTrack, allTracks);\n } finally {\n window.dispatchEvent(new CustomEvent('insights-complete'));\n }\n });\n\n btnDetails?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('details');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderDetails(primaryTrack, getGlobalTags(), allTracks);\n } finally {\n window.dispatchEvent(new CustomEvent('details-complete'));\n }\n });\n\n btnAggregate?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n if (allTracks.length >= 2) {\n const selectedTwo = [allTracks[0], allTracks[1]];\n activateTab('combined');\n renderCombined(selectedTwo, allTracks);\n }\n } finally {\n window.dispatchEvent(new CustomEvent('aggregate-complete'));\n }\n });\n\n btnEvolution?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('evolution');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderEvolution(primaryTrack, allTracks, (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n } finally {\n window.dispatchEvent(new CustomEvent('evolution-complete'));\n }\n });\n\n btnCourses?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('courses');\n prepareBenchmarkCourses(allTracks);\n selectCourse('course-1', true);\n } finally {\n window.dispatchEvent(new CustomEvent('courses-complete'));\n }\n });\n\n (window as any).benchmarkSteps = {\n loadAndParseFiles: () => document.getElementById('btn-step-load')?.click(),\n displayAnalysisMetrics: () => document.getElementById('btn-step-analysis')?.click(),\n displayInsights: () => document.getElementById('btn-step-insights')?.click(),\n displayDetails: () => document.getElementById('btn-step-details')?.click(),\n displayAggregateMetrics: () => document.getElementById('btn-step-aggregate')?.click(),\n displayEvolutionMetrics: () => document.getElementById('btn-step-evolution')?.click(),\n displayCourses: () => document.getElementById('btn-step-courses')?.click(),\n };\n}\n\nasync function processAndLoadTrack(t: TrackData) {\n // Migration: re-calculate stats if new insights are missing or old format\n const powerCurveEntries = t.stats.powerCurve ? Object.values(t.stats.powerCurve) : [];\n\n const needsEnrich =\n t.points.length > 1 && (t.points[1].speed === undefined || t.points[1].gradient === undefined);\n\n const needsRecalc =\n needsEnrich ||\n !t.stats.powerCurve ||\n !t.stats.hrZones ||\n !t.stats.hrCurve ||\n t.stats.shifts === undefined ||\n t.stats.avgBattery === undefined ||\n t.stats.avgTemp === undefined ||\n (powerCurveEntries.length > 0 && typeof (powerCurveEntries[0] as any) === 'number') ||\n ((t.stats.duration || 0) > 10800 * 1000 && t.stats.powerCurve && !t.stats.powerCurve[14400]);\n\n if (needsRecalc) {\n if (needsEnrich) t.points = Parsers.enrichPoints(t.points);\n t.stats = Parsers.computeStats(t.points);\n await Storage.save(t);\n }\n\n tracks[t.id] = t;\n colorIdx = Math.max(colorIdx, TRACK_COLORS.indexOf(t.color) + 1);\n MapView.addTrack(t);\n MapView.setTrackVisible(t.id, t.visible && !t._filtered);\n renderTrackList(); // Progressive list update\n}\n\nfunction initResizeHandle() {\n const handle = document.getElementById('resize-handle');\n const panel = document.getElementById('chart-panel');\n if (!handle || !panel) return;\n\n let isDragging = false;\n\n handle.addEventListener('mousedown', () => {\n isDragging = true;\n document.body.style.cursor = 'ns-resize';\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const h = window.innerHeight - e.clientY;\n const clampedH = Math.max(100, Math.min(window.innerHeight - 100, h));\n panel.style.height = `${clampedH}px`;\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n document.body.style.cursor = '';\n });\n}\n\nfunction initSidebarResizer() {\n const resizer = document.getElementById('sidebar-resizer');\n const sidebar = document.getElementById('sidebar');\n if (!resizer || !sidebar) return;\n\n let isDragging = false;\n\n resizer.addEventListener('mousedown', () => {\n isDragging = true;\n resizer.classList.add('dragging');\n document.body.classList.add('dragging-sidebar');\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const w = e.clientX;\n const clampedW = Math.max(200, Math.min(600, w));\n sidebar.style.width = `${clampedW}px`;\n sidebar.style.setProperty('--sidebar-w', `${clampedW}px`);\n ChartView.resize();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n resizer.classList.remove('dragging');\n document.body.classList.remove('dragging-sidebar');\n });\n}\n\n// \u2500\u2500 Event Handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction onMapMove(lat: number, lng: number, zoom: number) {\n UrlState.patch({ map_pos: [lat, lng, zoom] });\n}\n\nfunction onMapPointClick(id: string, idx: number) {\n selectTrack(id, false);\n ChartView.setCursorAt(idx);\n}\n\nfunction onMapDblClick() {\n // MapView.fitAll();\n}\n\nfunction onChartCursorMove(pt: TrackPoint | null) {\n if (pt && pt.lat != null && pt.lon != null) {\n MapView.showCursorAt(pt.lat, pt.lon);\n if (followDot) MapView.centerOn(pt.lat, pt.lon, null, true);\n } else {\n MapView.hideCursor();\n }\n}\n\nfunction onChartRangeChange(min: number | null, max: number | null, axis: string, fit = false) {\n if (!selectedId || !tracks[selectedId]) return;\n const t = tracks[selectedId];\n\n if (min === null || max === null) {\n MapView.clearHighlight();\n if (t && (UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n UrlState.patch({ sel: null });\n return;\n }\n\n // Find point indices\n const pts = t.points;\n let iMin = 0,\n iMax = pts.length - 1;\n\n if (axis === 'distance') {\n const d0 = min * 1000,\n d1 = max * 1000;\n iMin = pts.findIndex((p) => (p.dist || 0) >= d0);\n iMax = pts.findIndex((p) => (p.dist || 0) >= d1);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const ts0 = t0 + min * 1000,\n ts1 = t0 + max * 1000;\n iMin = pts.findIndex((p) => (p.time || 0) >= ts0);\n iMax = pts.findIndex((p) => (p.time || 0) >= ts1);\n }\n\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = pts.length - 1;\n\n // Compute selection stats\n const selPts = pts.slice(iMin, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n if ((UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n\n MapView.highlightSegment(selectedId, pts, iMin, iMax, fit, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n UrlState.patch({ sel: [min, max] });\n}\n\nfunction onChartClick(pt: TrackPoint, idx: number) {\n if (pt && pt.lat != null && pt.lon != null) MapView.centerOn(pt.lat, pt.lon, POINT_ZOOM_LEVEL);\n}\n\nexport function selectTrack(id: string, fit = true, deferChartRender = false) {\n if (!tracks[id]) return;\n if (id === selectedId) {\n if (fit) MapView.fitTrack(id);\n return;\n }\n\n const hadSelected = selectedId !== null;\n if (hadSelected) {\n // Clear current views immediately before loading new data\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n }\n\n selectedId = id;\n\n // Fully reset metric coloring when switching tracks\n currentMapColors = null;\n MapView.clearMetricColor(id);\n if (hadSelected) {\n ChartView.toggleMapColor(null); // Ensure ChartView state also resets\n }\n\n // Clear selection on new track\n UrlState.patch({ track: id, sel: null }, true);\n if (hadSelected) {\n ChartView.cancelSelection();\n }\n\n // Update UI immediately\n renderTrackList();\n\n // Render details\n const activeTab = UrlState.get().tab || 'graphs';\n if (activeTab === 'details') renderDetails(tracks[id], getGlobalTags());\n if (activeTab === 'insights') renderInsights(tracks[id]);\n if (activeTab === 'combined') renderCombined(tracks[id]);\n if (activeTab === 'courses') renderCourses();\n if (activeTab === 'evolution') {\n renderEvolution(tracks[id], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n\n // Tell sub-views\n MapView.setSelectedTrack(id, fit);\n if (fit) MapView.fitTrack(id);\n ChartView.loadTrack(tracks[id], Object.values(tracks), deferChartRender);\n}\n\nasync function deleteTrack(id: string) {\n await Storage.remove(id);\n MapView.removeTrack(id);\n delete tracks[id];\n if (selectedId === id) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n UrlState.patch({ track: null, sel: null, sel_point: null });\n }\n applyFilters();\n}\n\nasync function clearAll() {\n const code = Math.floor(10 + Math.random() * 90).toString();\n\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n backdrop.innerHTML = `\n
\n
Delete all tracks?
\n
\n This will permanently remove all tracks from your browser storage. This action cannot be undone.\n
\n
\n
Enter \"${code}\" to confirm:
\n \n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const input = backdrop.querySelector('.modal-input') as HTMLInputElement;\n const btnConfirm = backdrop.querySelector('.modal-btn.confirm') as HTMLButtonElement;\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n\n input.focus();\n\n input.addEventListener('input', () => {\n btnConfirm.disabled = input.value !== code;\n });\n\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n\n btnConfirm.addEventListener('click', async () => {\n if (input.value !== code) return;\n close();\n\n cancelProcessing = true;\n await Storage.clear();\n\n tracks = {};\n selectedId = null;\n MapView.clearHighlight();\n window.location.reload();\n });\n}\n\nfunction applyFilters(skipRender = false) {\n const ids = Object.keys(tracks);\n ids.forEach((id) => {\n const t = tracks[id];\n const s = t.stats;\n let visible = true;\n\n // Search query\n if (searchQuery) {\n if (searchRegex) {\n try {\n const re = new RegExp(searchQuery, 'i');\n if (!re.test(t.name)) visible = false;\n } catch (e) {\n visible = false;\n }\n } else {\n if (!t.name.toLowerCase().includes(searchQuery.toLowerCase())) visible = false;\n }\n }\n\n // Date filter\n if (visible && (filters.date[0] || filters.date[1])) {\n const start = filters.date[0] ? new Date(filters.date[0]).getTime() : 0;\n const end = filters.date[1] ? new Date(filters.date[1]).getTime() : Infinity;\n const t0 = s.startTime || 0;\n if (t0 < start || t0 > end) visible = false;\n }\n\n // Distance filter\n if (visible && (filters.dist[0] !== null || filters.dist[1] !== null)) {\n const min = (filters.dist[0] || 0) * 1000;\n const max = (filters.dist[1] || Infinity) * 1000;\n if (s.totalDist < min || s.totalDist > max) visible = false;\n }\n\n // Duration filter\n if (visible && (filters.dur[0] !== null || filters.dur[1] !== null)) {\n const min = (filters.dur[0] || 0) * 60000;\n const max = (filters.dur[1] || Infinity) * 60000;\n const d = s.duration || 0;\n if (d < min || d > max) visible = false;\n }\n\n // Metrics filter\n if (visible && filters.metrics.size > 0) {\n for (const m of filters.metrics) {\n const field = ChartView.METRICS[m].field;\n if (!t.points.some((p: any) => p[field] != null)) {\n visible = false;\n break;\n }\n }\n }\n\n // Sport filter\n if (visible && filters.sport) {\n if (t.sport !== filters.sport) visible = false;\n }\n\n // Tags filter\n if (visible && filters.tags.length > 0) {\n const trackTags = t.tags || [];\n if (!filters.tags.every((ft) => trackTags.includes(ft))) visible = false;\n }\n\n t._filtered = !visible;\n MapView.setTrackVisible(t.id, t.visible && visible);\n });\n\n if (!skipRender) renderTrackList();\n}\n\nfunction updateFilterUI() {\n (document.getElementById('filter-date-start') as HTMLInputElement).value = filters.date[0] || '';\n (document.getElementById('filter-date-end') as HTMLInputElement).value = filters.date[1] || '';\n (document.getElementById('filter-dist-min') as HTMLInputElement).value =\n filters.dist[0] !== null ? String(filters.dist[0]) : '';\n (document.getElementById('filter-dist-max') as HTMLInputElement).value =\n filters.dist[1] !== null ? String(filters.dist[1]) : '';\n (document.getElementById('filter-dur-min') as HTMLInputElement).value =\n filters.dur[0] !== null ? String(filters.dur[0]) : '';\n (document.getElementById('filter-dur-max') as HTMLInputElement).value =\n filters.dur[1] !== null ? String(filters.dur[1]) : '';\n (document.getElementById('filter-tags') as HTMLInputElement).value = filters.tags.join(', ');\n\n document\n .querySelectorAll('#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item')\n .forEach((el) => {\n const item = el as HTMLElement;\n item.classList.toggle('active', (item.dataset.sport || '') === (filters.sport || ''));\n });\n\n document.querySelectorAll('#filter-metrics .mini-pill').forEach((el) => {\n const btn = el as HTMLElement;\n btn.classList.toggle('active', filters.metrics.has(btn.dataset.metric!));\n });\n\n const activeCount =\n (filters.date[0] ? 1 : 0) +\n (filters.date[1] ? 1 : 0) +\n (filters.dist[0] !== null ? 1 : 0) +\n (filters.dist[1] !== null ? 1 : 0) +\n (filters.dur[0] !== null ? 1 : 0) +\n (filters.dur[1] !== null ? 1 : 0) +\n filters.metrics.size +\n (filters.tags.length > 0 ? 1 : 0);\n\n const badge = document.querySelector('#btn-toggle-filters .btn-badge');\n if (badge) {\n badge.textContent = activeCount > 0 ? String(activeCount) : '';\n badge.classList.toggle('hidden', activeCount === 0);\n }\n}\n\nfunction updateSearchSortUI() {\n const searchInput = document.getElementById('track-search') as HTMLInputElement;\n if (searchInput) searchInput.value = searchQuery;\n document.getElementById('btn-regex-toggle')?.classList.toggle('active', searchRegex);\n\n const opt = SORT_OPTIONS.find((o) => o.val === currentSort);\n if (opt) {\n const labelEl = document.getElementById('sort-current-label');\n const iconEl = document.getElementById('sort-current-icon');\n if (labelEl)\n labelEl.textContent = opt.label\n .replace(' first', '')\n .replace(' distance', '')\n .replace(' duration', '');\n if (iconEl) iconEl.textContent = opt.icon;\n }\n}\n\nfunction applyState(urlState: AppState) {\n // Restore track\n const newTrackId = urlState.track;\n if (newTrackId !== selectedId) {\n if (newTrackId && tracks[newTrackId]) {\n selectTrack(newTrackId, true);\n } else if (!newTrackId && selectedId) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n renderTrackList();\n MapView.fitAll();\n }\n }\n\n // Restore basemap\n if (urlState.map && typeof urlState.map === 'string') {\n MapView.switchBasemap(urlState.map);\n document\n .querySelectorAll('.bm-btn')\n .forEach((b) =>\n b.classList.toggle('active', (b as HTMLElement).dataset.layer === urlState.map),\n );\n }\n\n // Restore map position\n if (urlState.map_pos) {\n const [lat, lng, zoom] = urlState.map_pos;\n MapView.setPosition(lat, lng, zoom);\n }\n\n // Restore tab\n if (urlState.tab) {\n document.querySelectorAll('.tab-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n if (b.dataset.tab === urlState.tab) {\n if (!b.classList.contains('active')) b.click();\n }\n });\n }\n\n // Restore x-axis mode\n if (urlState.xaxis) ChartView.setXAxis(urlState.xaxis);\n\n const currentXAxis = urlState.xaxis || 'time';\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', (b as HTMLElement).dataset.axis === currentXAxis));\n\n // Restore active metrics\n if (urlState.metrics) {\n const metrics = ChartView.METRICS;\n const keys = urlState.metrics\n .map((abbr) => Object.keys(metrics).find((k) => metrics[k].abbr === abbr))\n .filter((k): k is string => k !== undefined);\n if (keys.length) ChartView.setActiveMetrics(keys);\n }\n\n // Restore filters\n if (urlState.f_date)\n filters.date = urlState.f_date.map((v) => v || null) as [string | null, string | null];\n if (urlState.f_dist)\n filters.dist = urlState.f_dist.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_dur)\n filters.dur = urlState.f_dur.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_mets) filters.metrics = new Set(urlState.f_mets);\n if (urlState.f_tags) filters.tags = urlState.f_tags;\n\n updateFilterUI();\n\n if (urlState.q) searchQuery = urlState.q;\n if (urlState.re) searchRegex = urlState.re;\n if (urlState.sort) currentSort = urlState.sort;\n updateSearchSortUI();\n\n applyFilters();\n}\n\nfunction updateSportFilterOptions() {\n const container = document.getElementById('sport-filter-container');\n if (!container) return;\n\n const commonContainer = document.getElementById('common-sports');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n if (!commonContainer || !dropdownContent) return;\n\n const sports = new Set();\n Object.values(tracks).forEach((t) => {\n if (t.sport) sports.add(t.sport);\n });\n\n const sportsArray = Array.from(sports).sort();\n const burgerDropdown = document.getElementById('sport-burger-dropdown');\n\n commonContainer.innerHTML = '';\n dropdownContent.innerHTML = '';\n\n if (sportsArray.length <= 4) {\n if (burgerDropdown) burgerDropdown.style.display = 'none';\n\n sportsArray.forEach((sport) => {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n });\n } else {\n if (burgerDropdown) burgerDropdown.style.display = 'inline-block';\n\n const commonSports = ['running', 'cycling', 'walking'];\n\n commonSports.forEach((sport) => {\n if (sports.has(sport)) {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n }\n });\n\n sportsArray.forEach((sport) => {\n const item = document.createElement('div');\n item.className = `dropdown-item${filters.sport === sport ? ' active' : ''}`;\n item.dataset.sport = sport;\n item.style.padding = '8px';\n item.style.cursor = 'pointer';\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '8px';\n item.innerHTML = `\n ${getSportIcon(sport)}\n ${sport.charAt(0).toUpperCase() + sport.slice(1)}\n `;\n dropdownContent.appendChild(item);\n });\n }\n}\n\nfunction renderTrackList() {\n updateSportFilterOptions();\n const list = document.getElementById('track-list');\n const emptyEl = document.getElementById('track-list-empty') as HTMLElement;\n const headerLabel = document.querySelector('.section-label');\n if (!list) return;\n\n const ids = Object.keys(tracks).filter((id) => !tracks[id]._filtered);\n if (headerLabel) headerLabel.textContent = `Tracks (${ids.length})`;\n\n if (!ids.length) {\n list.innerHTML = '';\n if (emptyEl) {\n list.appendChild(emptyEl);\n emptyEl.style.display = 'block';\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n list.innerHTML = '';\n\n ids\n .sort((a, b) => {\n // Current selected always first\n if (a === selectedId) return -1;\n if (b === selectedId) return 1;\n\n const ta = tracks[a],\n tb = tracks[b];\n const sa = ta.stats,\n sb = tb.stats;\n\n let cmp = 0;\n switch (currentSort) {\n case 'date-asc':\n cmp = (sa.startTime || 0) - (sb.startTime || 0);\n break;\n case 'date-desc':\n cmp = (sb.startTime || 0) - (sa.startTime || 0);\n break;\n case 'dist-asc':\n cmp = (sa.totalDist || 0) - (sb.totalDist || 0);\n break;\n case 'dist-desc':\n cmp = (sb.totalDist || 0) - (sa.totalDist || 0);\n break;\n case 'dur-asc':\n cmp = (sa.duration || 0) - (sb.duration || 0);\n break;\n case 'dur-desc':\n cmp = (sb.duration || 0) - (sa.duration || 0);\n break;\n default:\n cmp = 0;\n }\n return cmp || a.localeCompare(b);\n })\n .forEach((id) => {\n list.appendChild(buildTrackItem(tracks[id]));\n });\n}\n\nfunction getGlobalTags(): string[] {\n const all = new Set();\n Object.values(tracks).forEach((t) => {\n (t.tags || []).forEach((tag) => all.add(tag));\n });\n return Array.from(all).sort();\n}\n\nfunction getSportIcon(sport: string | null): string {\n if (!sport) return 'category';\n const s = sport.toLowerCase();\n if (s.includes('run')) return 'directions_run';\n if (s.includes('cycl') || s.includes('bike')) return 'directions_bike';\n if (s.includes('walk')) return 'directions_walk';\n if (s.includes('swim')) return 'pool';\n if (s.includes('hik')) return 'hiking';\n return 'sports';\n}\n\nfunction buildTrackItem(track: TrackData) {\n const item = document.createElement('div');\n item.className = `track-item${track.id === selectedId ? ' selected' : ''}`;\n item.dataset.id = track.id;\n\n const date =\n track.points.length && track.points[0].time ? fmtDate(track.points[0].time) : 'Unknown date';\n\n const tagsHtml =\n (track.tags || []).length > 0\n ? `
${(track.tags || [])\n .map((t) => {\n const c = getTagColor(t);\n return `${escHtml(t)}`;\n })\n .join('')}
`\n : '';\n\n item.innerHTML = `\n
\n
\n
${escHtml(track.displayName || track.name)}
\n
\n
\n ${date}\n ${Math.round(track.stats.totalDist / 1000)} km\n ${track.sport ? `${getSportIcon(track.sport)}` : ''}\n ${track.format.toUpperCase()}\n
\n \n
\n ${tagsHtml}\n
\n `;\n\n item.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.icon-btn')) return;\n selectTrack(track.id);\n });\n\n const btnVis = item.querySelector('.toggle-vis') as HTMLElement;\n btnVis.addEventListener('click', () => {\n track.visible = !track.visible;\n btnVis.querySelector('.material-symbols-rounded')!.textContent = track.visible\n ? 'visibility'\n : 'visibility_off';\n MapView.setTrackVisible(track.id, track.visible);\n Storage.save(track);\n });\n\n return item;\n}\n\nfunction showToast(msg: string, type: 'info' | 'error' = 'info') {\n const container = document.getElementById('toast-container');\n if (!container) return;\n container.innerHTML = '';\n const t = document.createElement('div');\n t.className = `toast ${type}`;\n t.textContent = msg;\n container.appendChild(t);\n}\n\nfunction showSkippedImportsModal() {\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n let listHtml = '';\n skippedImports.forEach((s) => {\n listHtml += `
${s.name}: ${s.reason}
`;\n });\n\n backdrop.innerHTML = `\n
\n
Skipped Imports
\n
\n ${listHtml || '
No skipped imports.
'}\n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n const btnClear = backdrop.querySelector('.modal-btn.clear') as HTMLButtonElement;\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n btnClear.addEventListener('click', () => {\n skippedImports = [];\n close();\n const importWarning = document.getElementById('import-warning');\n if (importWarning) importWarning.classList.add('hidden');\n });\n\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n}\n\nfunction initDropZone() {\n const zone = document.getElementById('drop-zone');\n if (!zone) return;\n\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n importWarning.addEventListener('click', (e) => {\n e.stopPropagation();\n showSkippedImportsModal();\n });\n }\n\n window.addEventListener('dragover', (e) => {\n e.preventDefault();\n zone.classList.add('drop-active');\n });\n\n window.addEventListener('dragleave', (e) => {\n if (e.relatedTarget === null) zone.classList.remove('drop-active');\n });\n\n window.addEventListener('drop', async (e) => {\n e.preventDefault();\n zone.classList.remove('drop-active');\n\n const items = e.dataTransfer?.items;\n if (!items) return;\n\n const files: File[] = [];\n const queue: FileSystemEntry[] = [];\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i].webkitGetAsEntry();\n if (entry) queue.push(entry);\n }\n\n async function readAllEntries(entry: FileSystemEntry) {\n if (entry.isFile) {\n const file = await new Promise((res) => (entry as FileSystemFileEntry).file(res));\n files.push(file);\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n let entries: FileSystemEntry[] = [];\n let chunk: FileSystemEntry[];\n do {\n chunk = await new Promise((res) => reader.readEntries(res));\n entries.push(...chunk);\n } while (chunk.length > 0);\n\n for (const child of entries) await readAllEntries(child);\n }\n }\n\n for (const entry of queue) await readAllEntries(entry);\n\n if (files.length) handleFiles(files);\n });\n}\n\nasync function handleFiles(files: File[]) {\n if (!files.length) return;\n cancelProcessing = false;\n const initialSkipCount = skippedImports.length;\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const loaderClose = document.getElementById('loader-close');\n\n if (loaderClose) {\n loaderClose.addEventListener('click', () => {\n cancelProcessing = true;\n if (loader) loader.classList.add('hidden');\n });\n }\n\n function updateLoaderIconToWarning() {\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'warning';\n loaderIcon.style.color = '#f59e0b';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n const count = skippedImports.length - initialSkipCount;\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = `${count}`;\n warningCount.style.display = 'flex';\n }\n }\n\n if (loader) {\n if (loaderText)\n loaderText.textContent = `Importing ${files.length} file${files.length > 1 ? 's' : ''}`;\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'download';\n loaderIcon.style.color = 'var(--accent)';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n warningCount.style.display = 'none';\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = '0';\n }\n if (loaderSubtext) loaderSubtext.textContent = '';\n if (progressBar) progressBar.style.width = '0%';\n loader.classList.remove('hidden');\n\n if (skippedImports.length > initialSkipCount) updateLoaderIconToWarning();\n }\n\n try {\n let count = 0;\n let firstId: string | null = null;\n let processedSinceLastUpdate = 0;\n\n // Filter out obviously invalid files early\n const validFiles = files.filter((f) => {\n const name = f.name.toLowerCase();\n return (\n name.endsWith('.gpx') ||\n name.endsWith('.fit') ||\n name.endsWith('.tcx') ||\n name.endsWith('.kml')\n );\n });\n\n const invalidFiles = files.filter((f) => !validFiles.includes(f));\n invalidFiles.forEach((f) => {\n skippedImports.push({ name: f.name, reason: 'Unsupported file format' });\n });\n\n if (validFiles.length === 0) {\n if (files.length > 0) {\n showToast('No valid GPS files found', 'error');\n // Still update warning icon if there were invalid files!\n const importWarning = document.getElementById('import-warning');\n if (importWarning && skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n }\n }\n return;\n }\n\n const loaderFilename = document.getElementById('loader-filename');\n let progressIdxEl: HTMLElement | null = null;\n if (loaderSubtext) {\n loaderSubtext.innerHTML =\n '';\n progressIdxEl = loaderSubtext.querySelector('.progress-index') as HTMLElement | null;\n const totalEl = loaderSubtext.querySelector('.progress-total');\n if (totalEl) totalEl.textContent = validFiles.length.toString();\n }\n\n for (let i = 0; i < validFiles.length; i++) {\n if (cancelProcessing) break;\n const f = validFiles[i];\n if (loaderFilename) loaderFilename.textContent = f.name;\n if (progressIdxEl) progressIdxEl.textContent = (i + 1).toString();\n if (progressBar) progressBar.style.width = `${(i / validFiles.length) * 100}%`;\n\n try {\n const data = await Parsers.parseFile(f);\n\n // Duplicate checks\n const existingTracks = Object.values(tracks);\n\n // Rule 1: Same file and same size\n const sameFile = existingTracks.find((t) => t.fileName === f.name && t.fileSize === f.size);\n if (sameFile) {\n skippedImports.push({ name: f.name, reason: 'Same File' });\n updateLoaderIconToWarning();\n continue;\n }\n\n // Rule 2 & 3: Same start day checks\n const newStart = data.stats.startTime;\n const newDuration = data.stats.duration;\n\n if (newStart != null && newDuration != null) {\n const newEnd = newStart + newDuration;\n const sameDayTracks = existingTracks.filter(\n (t) => t.stats.startTime != null && isSameDay(newStart, t.stats.startTime!),\n );\n\n let discarded = false;\n for (const ext of sameDayTracks) {\n const extStart = ext.stats.startTime!;\n const extDuration = ext.stats.duration!;\n const extEnd = extStart + extDuration;\n\n // Rule 2: Fully contained\n if (newStart >= extStart && newEnd <= extEnd) {\n skippedImports.push({ name: f.name, reason: 'Fully contained in another track' });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n\n // Rule 3: Overlaps for > 10 mins\n const overlap = Math.min(newEnd, extEnd) - Math.max(newStart, extStart);\n if (overlap > 600000) {\n // 10 mins in ms\n skippedImports.push({\n name: f.name,\n reason: 'Overlaps with an existing track for more than 10 mins',\n });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n }\n if (discarded) continue;\n }\n\n const fallbackTime = 1785542400000;\n let id = compactId(data.stats.startTime || fallbackTime);\n if (tracks[id]) id += `-${shortRandom()}`;\n\n // Use filename as activity name if internal name is generic\n let trackName = data.name;\n if (trackName.startsWith('Unnamed') || trackName.startsWith('Fit Activity'))\n trackName = f.name;\n\n // Generate a nice display name\n let displayName = trackName;\n const t0 = data.points[0]?.time;\n const sport = data.sport\n ? data.sport.charAt(0).toUpperCase() + data.sport.slice(1)\n : 'Activity';\n if (t0) {\n const d = new Date(t0);\n displayName = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')} ${sport}`;\n } else {\n displayName = trackName.replace(/\\.[^/.]+$/, '').replace(/_/g, ' '); // Remove extension and replace underscores\n }\n\n const track: TrackData = {\n ...data,\n id,\n name: trackName,\n displayName,\n fileName: f.name,\n fileSize: f.size,\n bounds: calculateBounds(data.points) || undefined,\n simplifiedPoints: simplifyTrack(data.points, 50), // 50m resolution\n addedAt: data.stats.startTime || fallbackTime,\n visible: true,\n color: TRACK_COLORS[colorIdx % TRACK_COLORS.length],\n };\n colorIdx++;\n if (cancelProcessing) break;\n\n await Storage.save(track);\n tracks[id] = track;\n MapView.addTrack(track);\n if (!firstId) firstId = id;\n count++;\n processedSinceLastUpdate++;\n\n if (processedSinceLastUpdate >= 5) {\n processedSinceLastUpdate = 0;\n }\n } catch (err) {\n skippedImports.push({\n name: f.name,\n reason: `Parse error: ${err instanceof Error ? err.message : String(err)}`,\n });\n updateLoaderIconToWarning();\n }\n }\n\n // Update warning icon\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n if (skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n } else {\n importWarning.classList.add('hidden');\n }\n }\n\n const newWarnings = skippedImports.length > initialSkipCount;\n if (!newWarnings && loader) {\n loader.classList.add('hidden');\n }\n\n if (count > 0) {\n showToast(`Imported ${count} track${count > 1 ? 's' : ''}`);\n applyFilters(!!firstId && firstId !== selectedId);\n if (firstId) selectTrack(firstId);\n }\n\n if (newWarnings) {\n const loaderIcon = document.querySelector('.loader-icon-wrap span');\n if (loaderIcon) loaderIcon.textContent = 'warning';\n // Delay hiding loader to let user see the alert icon\n await new Promise((r) => setTimeout(r, 1500));\n }\n } finally {\n if (loader) loader.classList.add('hidden');\n }\n}\n\nfunction initMetricPillDraggable() {\n const container = document.getElementById('metric-pills');\n if (!container) return;\n\n let draggedEl: HTMLElement | null = null;\n\n container.addEventListener('dragstart', (e) => {\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (!target) return;\n draggedEl = target;\n e.dataTransfer!.effectAllowed = 'move';\n target.classList.add('dragging-pill');\n // For transparent background in ghost image\n setTimeout(() => (target.style.opacity = '0.4'), 0);\n });\n\n container.addEventListener('dragover', (e) => {\n e.preventDefault();\n e.dataTransfer!.dropEffect = 'move';\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (target && target !== draggedEl) {\n const rect = target.getBoundingClientRect();\n const next = e.clientX - rect.left > rect.width / 2;\n container.insertBefore(draggedEl!, next ? target.nextSibling : target);\n }\n });\n\n container.addEventListener('dragend', () => {\n if (!draggedEl) return;\n draggedEl.classList.remove('dragging-pill');\n draggedEl.style.opacity = '';\n draggedEl = null;\n\n // Update Chart order\n const keys = Array.from(container.querySelectorAll('.metric-pill')).map(\n (el) => (el as HTMLElement).dataset.metric!,\n );\n ChartView.updateMetricOrder(keys);\n syncMetricsToUrl();\n });\n}\n\nfunction updateToolbarLayout() {\n const toolbar = document.getElementById('chart-toolbar');\n const pills = document.getElementById('metric-pills');\n if (!toolbar || !pills) return;\n\n toolbar.classList.remove('collapsed');\n const availableW = Math.max(0, toolbar.clientWidth - 280);\n let totalW = 0;\n let hidden = false;\n\n Array.from(pills.children).forEach((el) => {\n const htmlEl = el as HTMLElement;\n if (htmlEl.id === 'pill-overflow') return;\n\n htmlEl.classList.remove('overflow-hidden');\n if (!htmlEl.classList.contains('active')) return;\n const metricKey = htmlEl.dataset.metric || '';\n const deterministicPillWidth = 36 + metricKey.length * 6;\n totalW += deterministicPillWidth + 6;\n\n if (totalW > availableW) {\n hidden = true;\n htmlEl.classList.add('overflow-hidden');\n }\n });\n\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.toggle('hidden', !hidden);\n\n if (hidden) toolbar.classList.add('collapsed');\n}\n\ndocument.addEventListener('DOMContentLoaded', init);\n"], + "mappings": "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", + "names": ["UrlState", "_state", "_lastSearch", "_syncTimeout", "_shouldPush", "read", "p", "s", "metricsRaw", "v", "isDesc", "field", "parts", "_sync", "dir", "search", "val", "url", "get", "patch", "partial", "push", "k", "key", "refresh", "reset", "InMemoryStorage", "track", "id", "key", "value", "IndexedDBStorage", "resolve", "reject", "req", "db", "name", "mode", "res", "rej", "tx", "activeDriver", "Storage", "UrlState", "t", "k", "v", "FitParser", "haversine", "lat1", "lon1", "lat2", "lon2", "phi1", "phi2", "deltaPhi", "deltaLambda", "a", "compactId", "timestamp", "buf", "shortRandom", "fmtDuration", "s", "fmtSecs", "h", "m", "fmtPace", "seconds", "mins", "secs", "fmtDate", "ts", "d", "fmtDateTime", "iso", "fmtFileSize", "bytes", "k", "sizes", "i", "escHtml", "str", "getTagColor", "name", "hash", "gaussianSmooth", "data", "sigma", "size", "kernel", "half", "sum", "x", "result", "val", "weightSum", "idx", "hexToRgba", "hex", "alpha", "r", "g", "b", "calculateBounds", "pts", "minLat", "maxLat", "minLon", "maxLon", "p", "SIMPLIFY_CAP", "simplifyLats", "simplifyLons", "simplifyEles", "simplifyDists", "enrichEleBuf", "enrichPwrBuf", "enrichSpdBuf", "simplifyTrack", "minDistanceMeters", "n", "lats", "lons", "eles", "dists", "i", "tolerances", "errChecksum", "degToRad", "pass", "tiLimit", "ti", "tolDegSq", "anchor", "cosLat", "dx", "dy", "dz", "mid", "mx", "my", "result", "lastPoint", "tolBias", "haversine", "Parsers", "enrichPoints", "totalDist", "prev", "d", "dt", "de", "eleBuf", "pwrBuf", "spdBuf", "gradeWindows", "npAccum", "scaleH", "wi", "w", "invW", "pSum", "sSum", "pAvg", "airDensity", "slopeAngle", "smoothBias", "hrZoneThresholds", "ftp", "computeStats", "includeCurves", "stats", "powerSum", "powerN", "hrSum", "hrN", "cadSum", "cadN", "speedSum", "speedN", "batterySum", "batteryN", "tempSum", "tempN", "hasTemp", "shifts", "hasGears", "diff", "t0", "t1", "calculateHRZones", "calculateHRCurve", "calculatePowerCurve", "calculatePowerZones", "ensureCurvesAndZones", "track", "s", "STANDARD_CURVE_DURATIONS", "calculateSlidingMax", "data", "durations", "len", "prefix", "curve", "hasAny", "di", "maxSum", "bestIdx", "limit", "j", "currentSum", "powerData", "nonZero", "v", "hrData", "zones", "thresholds", "t", "pw", "z", "setFTP", "val", "getFTP", "hr", "setHRZones", "getHRZones", "extractXmlTag", "block", "openTag", "closeTag", "start", "extractXmlAttr", "tagOpen", "attrPrefix", "cachedDateKey", "cachedDayMs", "parseIntSlice", "text", "end", "neg", "c0", "digits", "c", "parseFloatSlice", "intPart", "fracPart", "fracDiv", "inFrac", "res", "fastParseTimeSlice", "y", "m", "key", "hh", "mm", "ss", "ms", "extractAttrFloat", "vStart", "parseGPX", "buf", "predecodedText", "firstTrkpt", "header", "trkIdx", "name", "gpxOpenEnd", "device", "points", "pos", "trkStart", "openEnd", "trkEnd", "lat", "lon", "ele", "time", "cad", "power", "temp", "speed", "gearFront", "gearRear", "gearFrontTooth", "gearRearTooth", "battery", "lt", "gt", "c1", "tagLen", "nextLt", "vEnd", "expectedCloseGt", "closeGt", "gears", "parseTCX", "firstTp", "creatorBlock", "tpStart", "tpEnd", "fastDecodeFitData", "dv", "headerSize", "dataSize", "endOffset", "GARMIN_EPOCH_SEC", "SEMICIRCLE_TO_DEG", "defs", "file_ids", "sessions", "records", "events", "device_infos", "offset", "hdr", "localNum", "littleEndian", "globalMsgNum", "numFields", "fields", "recordSize", "num", "size", "type", "def", "le", "gNum", "ts", "rawLat", "rawLon", "rawAlt", "rawDist", "rawSpd", "msg", "fOff", "f", "bType", "sportMap", "evName", "parseFIT", "resolve", "reject", "handleParsedFitData", "error", "devices", "sport", "subSport", "getDeviceName", "fid", "antId", "existing", "statusReports", "idx", "a", "b", "gearEvents", "e", "front", "rear", "frontTooth", "rearTooth", "ft", "fg", "rt", "rg", "lastBattery", "statusIdx", "lastFrontGear", "lastRearGear", "lastFrontTooth", "lastRearTooth", "gearIdx", "validPoints", "ri", "r", "ex", "fastData", "FitParser", "parseKML", "doc", "nameEl", "coordEls", "el", "line", "parts", "parseFile", "file", "ext", "MapView", "trackData", "customClickHandler", "init", "onSelectCb", "onMoveCb", "onPointClickCb", "onPointHoverCb", "onDblClickCb", "switchBasemap", "layer", "addTrack", "t", "addTracks", "ts", "removeTrack", "id", "clearTracks", "removeAllTracks", "setTrackVisible", "visible", "setSelectedTrack", "fit", "fitAll", "fitTrack", "showCursorAt", "lat", "lon", "hideCursor", "highlightSegment", "pts", "start", "end", "colors", "clearHighlight", "setTrackHover", "hover", "ensureVisible", "centerOn", "zoom", "force", "closePopup", "invalidateSize", "getPosition", "setPosition", "lng", "colorTrackByMetric", "clearMetricColor", "findTracksPassingThroughPoints", "points", "radius", "handler", "uPlot", "Zones", "getPowerZones", "ftp", "Parsers", "thresholds", "t", "names", "colors", "zones", "last", "i", "getHRZones", "Metrics", "METRICS", "v", "p", "pts", "fillNulls", "vam", "i", "prev", "de", "dt", "SPORTS", "getSportIcon", "sport", "key", "ChartView", "plots", "renderedTrack", "renderedXAxis", "renderedSpeedMode", "renderedMapColorMetric", "syncKey", "scaleSyncing", "cursorSyncing", "activeMetrics", "availableMetrics", "smoothedMetrics", "metricsIncludingZero", "xAxis", "currentTrack", "allTracks", "selAnchorVal", "selEndVal", "isDragging", "updatingRange", "pinnedPtIdx", "lastMouseXVal", "lastHistMouseEvent", "hoveredHistData", "hoveredHistCanvas", "currentXRange", "targetXRange", "animId", "onCursorMoveCb", "onRangeChangeCb", "onClickCb", "onPinChangeCb", "HIST_W", "ROW_BODY_PADDING", "HIST_GAP", "statsVisible", "histTooltipEl", "container", "emptyEl", "selStatsEl", "resetSelBtn", "mapColorMetric", "onMapColorChangeCb", "init", "onCursorMove", "onRangeChange", "onClick", "onPinChange", "updateHistTooltip", "uPlot", "cancelSelection", "navKeys", "activeNavKeys", "e", "key", "u", "min", "max", "moveStep", "zoomFactor", "newMin", "newMax", "center", "factor", "xFull", "d", "setVisibleRange", "animate", "startMin", "startMax", "lerp", "a", "b", "t", "step", "tMin", "tMax", "cMin", "cMax", "loadTrack", "track", "others", "deferRender", "METRICS", "def", "p", "m", "el", "pill", "metric", "isAvailable", "updateStats", "render", "clear", "destroyPlots", "chartStats", "clearSelectionStats", "resetState", "overflowEl", "toolbar", "toggleMetric", "setActiveMetrics", "keys", "setXAxis", "axis", "pts", "t0", "convert", "val", "idx", "dTarget", "tTarget", "newRange", "r0", "r1", "toggleStats", "histCol", "resize", "setMapColorChangeCb", "cb", "toggleMapColor", "_updateMapColorBtns", "_fireMapColorCb", "plot", "colors", "_computePointColors", "yData", "vals", "v", "sport", "sportDef", "SPORTS", "defaultMode", "speedMode", "UrlState", "paceUnit", "gradientColor", "speed", "speedColor", "lerpHex", "resetZoom", "updateSelOverlay", "redrawHistograms", "xData", "setSelectionStats", "stats", "fmt", "id", "fmtSecs", "restoreSelection", "totalDuration", "tOffset", "xMin", "xMax", "updateAnchorLines", "w", "anyResized", "histCanvas", "histData", "drawHistogram", "keepState", "savedRange", "savedScroll", "available", "containerW", "canReuse", "lastValidX", "existingByKey", "availSet", "isSmoothed", "isIncZero", "nextSiblingRows", "nextExisting", "i", "ex", "reused", "uplot", "s", "prevSync", "initHoverBinI", "buildHistBins", "span", "transform", "fmtAxis", "unit", "label", "fmtPace", "fillNulls", "gaussianSmooth", "createChart", "metricKey", "initialRange", "insertBeforeEl", "gradData", "smoothGradient", "row", "header", "labelEl", "smoothBtn", "mapColorBtn", "zeroBtn", "incZero", "statsTotalEl", "statsSelEl", "statsContainer", "actionsEl", "rightActionsEl", "paceToggle", "btn", "mode", "isDefault", "rowBody", "plotEl", "fixedMinLabel", "fixedMaxLabel", "isDistAxis", "formatX", "range", "dec", "absV", "h", "hh", "mm", "ss", "incZeroDefault", "gMin", "gMax", "allSum", "allCount", "filtMin", "filtMax", "filtSum", "filtCount", "fullStatsAll", "fullStatsFiltered", "gPad", "fixedYRange", "statsTotalInitialized", "updateHeaderStats", "visibleMin", "visibleMax", "getHtml", "isFull", "rangeStats", "es", "elevationRangeStats", "initializingScale", "uOpts", "_si", "_u", "mn", "mx", "axisIdx", "scaleMin", "scaleMax", "targetLabels", "idealIncr", "incrs", "incr", "splits", "precision", "pos", "top", "drawTrackPath", "drawElevationGradient", "drawGradientChart", "drawMetricColorFill", "drawPinnedDot", "drawYAxisHighlight", "hIdx", "hasPinned", "hasHover", "cy", "drawVerticalLineOnly", "hexToRgba", "ctx", "dpr", "bb", "ax", "fontSize", "fontStr", "tw", "visibleL", "visibleR", "padH", "padV", "bw", "bh", "bx", "by", "drawXAxisLabels", "showHover", "updateTooltip", "binI", "other", "left", "width", "overlay", "selFill", "anchorLine", "anchorLabel", "anchorHandle", "anchorMarker", "endLine", "endLabel", "endHandle", "endMarker", "curYVal", "pinYVal", "self", "attachHandleDrag", "mousedownX", "rect", "attachHistTooltip", "aX", "eX", "overW", "overH", "plotBottom", "isAnchorVisible", "isEndVisible", "fillL", "fillR", "aText", "fmtXVal", "aLabelW", "aIcon", "eText", "eLabelW", "eIcon", "handleEl", "isAnchor", "startX", "startVal", "pxPerUnit", "onMove", "me", "dx", "newVal", "onUp", "BINS", "lo", "hi", "cnt", "bins", "binAccum", "k", "bi", "prev", "next", "canvas", "chartH", "hoverBinI", "hasSel", "selBins", "selBinAccum", "x", "W", "H", "peak", "pad", "plotW", "plotH", "binY", "binH", "baseAlpha", "total", "pts2", "cumSum", "my", "cp", "font9", "avgY", "minLabelY", "maxLabelY", "labelHeight", "countLower", "countHigher", "pLower", "pHigher", "font8", "textY", "fontB10", "midX", "getBinAt", "lineEl", "relY", "rawI", "count", "pct", "low", "high", "zoneHtml", "mid", "zones", "Zones", "zIdx", "z", "finalZIdx", "totalAccum", "totalPct", "html", "stotalAccum", "stotalPct", "ttH", "ttW", "binCenterY", "sum", "n", "gain", "loss", "prevEle", "isDist", "diff", "cx", "gColor", "g", "p0", "p1", "content", "front", "rear", "color44", "gradientColorRgbaCache", "gradientColorRgba", "c", "yMin", "yMax", "xScale", "yScale", "yBase", "idxs", "iStart", "iEnd", "byColor", "prevIdx", "xv1", "xv0", "x0", "y0", "x1", "y1", "color", "segs", "j", "drawHoverLine", "xVal", "opacity", "skipLine", "distVal", "timeVal", "bottomLabel", "topLabel", "drawPill", "text", "y", "isTop", "rx", "clampedRx", "ry", "pillH", "yVal", "cyClamp", "drawAreaFillAbove", "yDir", "yMult", "inSegment", "hasAnySegment", "lastPx", "xv", "yv", "px", "py", "ah", "ar", "ag", "ab", "br", "bg", "rr", "rg", "rb", "absG", "kmh", "windowMetres", "grads", "j0", "j1", "data", "res", "right", "getAvg", "avgSpeed", "avgPower", "avgCadence", "INTERVAL_CAP", "ivPwr", "ivHr", "ivSpd", "ivEle", "ivCad", "ivSmoothed", "ivKdeBins", "intervalWindows", "analyzeTelemetryIntervals", "tracksList", "selStartSec", "selEndSec", "intervalScore", "ti", "sStart", "sEnd", "inv35", "maxSPass", "sPass", "weightPwr", "weightHr", "invSigmaSq", "omega", "sgPwr", "sgHr", "sgSpd", "dP", "gauss", "harmonic", "pass", "passScale", "wi", "invW", "winSum", "winEle", "maxInterval", "avg", "norm", "newActive", "isStepped", "drawBackgroundTracks", "GAP_THRESHOLD", "field", "first", "prevP", "prevXVal", "lastFrontGear", "fMin", "fMax", "fg", "rMin", "rMax", "isTimeAxis", "gapSec", "prevDrawnI", "prevX", "prevY", "segmentColor", "prevXv", "SENSOR_ICONS", "Metrics", "onTagsChangeCb", "onDeleteTrackCb", "initDetails", "onTagsChange", "onDeleteTrack", "resetDetails", "container", "DETAIL_CAP", "detailChannels", "stabilityWindows", "renderDetails", "track", "globalTags", "allTracks", "s", "t0", "tracksToAnalyze", "stabilityAccum", "ti", "tPts", "n", "i", "p", "pass", "wiLimit", "wi", "useExactExp", "useExactDamp", "w", "invW", "halfW", "ci", "ch", "sum", "sumSq", "autoCov", "jitterSum", "invNoise", "v", "old", "mean", "variance", "lagVal", "diff", "diffSqNoise", "likelihood", "damp", "telemetryStabilityPct", "escHtml", "t", "fmtSecs", "fmtFileSize", "getSportIcon", "SPORTS", "fmtDateTime", "sensor", "seen", "d", "key", "name", "manufacturer", "extra", "battery", "sourceIcon", "st", "deviceIcon", "nameLower", "tagContainer", "tagInput", "addBtn", "renderTags", "tags", "tag", "c", "getTagColor", "el", "btn", "e", "Storage", "addTag", "val", "titleInput", "sportTrigger", "showSportMenu", "anchorEl", "popup", "def", "item", "isActive", "iconEl", "nameEl", "clearItem", "isClear", "rect", "closeHandler", "uPlot", "courses", "getCoursesForTrack", "track", "c", "pt", "passesPoint", "trackPt", "haversine", "activeCourseId", "isEditMode", "openCourseId", "toastFn", "courseLayer", "initCourses", "showToast", "toastFn", "loadCourses", "resetCourses", "courses", "activeCourseId", "openCourseId", "isEditMode", "container", "prepareBenchmarkCourses", "allTracks", "i", "n", "pStart", "pMid", "pEnd", "stored", "Storage", "saveCourses", "calculateCourseDistance", "course", "total", "p1", "p2", "haversine", "findCourseRange", "track", "coursePoints", "currentPtIdx", "startIdx", "endIdx", "tp", "cp", "calculateCourseStats", "pts", "s", "e", "startTime", "duration", "totalPower", "powerCount", "totalHR", "hrCount", "totalSpeed", "speedCount", "totalCadence", "cadenceCount", "totalAscent", "p", "prev", "de", "dist", "formatDuration", "seconds", "h", "m", "renderCourseTableHeaders", "METRICS", "renderCourseTableCells", "stats", "sport", "dateStr", "paceUnit", "SPORTS", "paceStr", "paceSeconds", "fmtPace", "COURSE_CAP", "courseTrkLats", "courseTrkLons", "courseTrkPwrs", "courseGateLats", "courseGateLons", "DTW_SAMPLES", "DTW_BAND", "dtwRefProfile", "dtwCandProfile", "dtwPrevRow", "dtwCurrRow", "renderCourses", "corridorDeviationSum", "c", "candidateIds", "MapView", "numGates", "g", "segFloat", "segIdx", "frac", "pA", "pB", "ci", "id", "pt", "gLat", "gLon", "minDist", "bestIdx", "d", "idx", "val", "pass", "paceBias", "jStart", "jEnd", "rVal", "j", "diff", "diffSq", "cost", "m1", "m2", "m3", "prevMin", "matchingIds", "isOpen", "tracksHtml", "matchedTracksWithStats", "range", "fmtDate", "t", "a", "b", "UrlState", "escHtml", "createNewCourse", "el", "editCourse", "renameCourse", "deleteCourse", "selectCourse", "row", "trackId", "selectTrack", "t0", "sIdx", "eIdx", "tMin", "tMax", "axis", "ChartView", "selMin", "selMax", "name", "newCourse", "nameEl", "currentName", "input", "save", "newName", "clearCourseLayer", "courseLayer", "selectCourse", "id", "open", "activeCourseId", "openCourseId", "isEditMode", "MapView", "clearCourseLayer", "renderCourses", "deleteCourse", "courses", "c", "saveCourses", "toastFn", "insightPlots", "destroyInsightPlots", "p", "initInsights", "showToast", "resetInsights", "el", "container", "INSIGHT_CAP", "inPwrArr", "inHrArr", "inCadArr", "inSpdArr", "inVamArr", "inPrefixPwr", "inPrefixVam", "tauCandidates", "mmpDurations", "computeInsightsEnvelope", "tracksToModel", "cpBase", "minWPrimeBal", "quadrantAccum", "ti", "tPts", "n", "i", "pt", "h", "c", "sp", "gr", "vam", "pass", "scale", "vamBias", "di", "d", "limit", "maxP", "maxV", "j", "dv", "sumP", "sumV", "half", "k", "cp", "tauBase", "wBal", "efSum1", "efSum2", "invH", "diff", "dcp", "dep", "expFactor", "tauDyn", "torque", "quadAngle", "ef", "renderInsights", "track", "allTracks", "Parsers", "grid", "chartWidth", "renderCurveCard", "Metrics", "card", "metricKey", "color", "isMapColored", "ChartView", "totalTime", "a", "b", "zones", "Zones", "zonesHtml", "time", "z", "pct", "rangeText", "fmtSecs", "e", "current", "btn", "showPowerZoneSettings", "showHRZoneSettings", "climbingCard", "distKm", "grade", "effCard", "trackCourses", "getCoursesForTrack", "coursesCard", "renderCourseTableHeaders", "range", "findCourseRange", "statsHtml", "stats", "calculateCourseStats", "startTime", "dateStr", "fmtDate", "renderCourseTableCells", "escHtml", "courseId", "selectCourse", "UrlState", "course", "MapView", "opts", "curve", "label", "unit", "icon", "tableWrap", "toggleBtn", "toggleIcon", "isHidden", "mapColorBtn", "key", "tbody", "durations", "entry", "val", "row", "fmtDuration", "startIdx", "duration", "pts", "endIdx", "t0", "tMin", "tMax", "chartEl", "xData", "yData", "curYVal", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "idx", "hasFocus", "mousePy", "pointPy", "cx", "cy", "durVal", "pcx", "pcy", "plot", "uPlot", "anchorEl", "popup", "rect", "inputs", "newZones", "Storage", "dismiss", "ftp", "input", "newFtp", "uPlot", "currentTracks", "currentTrack", "plot", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "playIntervalId", "isPolar", "updateSliderLabel", "sliderVal", "timeSecs", "fmtSecs", "resetCombined", "playIntervalId", "plot", "currentTracks", "currentTrack", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "isPolar", "tooltip", "container", "COMBINED_CAP", "combinedPhsPool", "combinedCePool", "combinedLens", "combinedDensityGrid", "combinedWindows", "renderCombined", "trackOrTracks", "allTracks", "track", "metrics", "ChartView", "availableMetrics", "key", "def", "p", "xDef", "yDef", "summaryHtml", "matrixTracks", "numTrk", "t", "pts", "n", "phs", "ce", "k", "pw", "h", "sp", "cd", "el", "bx", "by", "aggPts", "corrSum", "pass", "wiLimit", "wi", "w", "invW", "invBandwidth", "i", "phsA", "ceA", "lenA", "j", "phsB", "ceB", "len", "sumA", "sumB", "sumCadA", "sumCadB", "idxOld", "avgA", "avgB", "avgCA", "avgCB", "diffAB", "diffCE", "rbf", "rbfCad", "g", "t1", "t2", "s1", "s2", "distDiff", "pwrDiff", "hrDiff", "eleDiff", "shiftsDiff", "totalDist", "totalElev", "totalDur", "avgPwr", "maxPwr", "avgHr", "maxHr", "tempDiff", "avgTemp", "maxTemp", "totalShifts", "fmtSecs", "e", "showMenu", "slider", "sliderVal", "playBtn", "updateSliderLabel", "startPlaying", "stopPlaying", "updatePlot", "resizeCombined", "plotContainer", "size", "anchorEl", "axis", "popup", "item", "currentVal", "rect", "close", "pts1", "pts2", "maxLen", "xData", "yData1", "yData2", "p1", "p2", "width", "height", "opts", "uPlot", "t0", "chronoData", "idx", "x", "y", "d", "xVals", "yVals", "xMin", "xMax", "yMin", "yMax", "xVal", "yVal", "theta", "r", "px", "py", "a", "b", "yData", "hexToRgba", "u", "vals", "v", "seriesIdx", "dataIdx", "cursorLeft", "cursorTop", "minD2", "closestIdx", "cx", "cy", "dx", "dy", "d2", "ctx", "dpr", "started", "startIdx", "endIdx", "xVal1", "yVal1", "xVal2", "yVal2", "cx1", "cy1", "cx2", "cy2", "progress", "lineWidth", "alpha", "fillAlpha", "timeSecs", "distKm", "origX", "origY", "canvasRect", "originalIdx", "uPlot", "computeAccumulatedMetric", "allTracks", "extractor", "refTs", "i", "st", "now", "currentYear", "oneYearAgoMs", "sixMonthsAgoMs", "oneMonthAgoMs", "currentYearVal", "pastYearVal", "past6mVal", "past1mVal", "totalVal", "minTime", "t", "val", "time", "msecPerWeek", "currentYearStart", "currentYearWeeks", "pastYearWeeks", "past6mWeeks", "past1mWeeks", "totalWeeks", "renderAccumulatedTable", "accumulated", "isDistance", "unit", "factor", "format", "evolutionPlots", "destroyEvolutionPlots", "p", "resetEvolution", "container", "EVO_CAP", "evoPwrPrefix", "evoHrPrefix", "evoSpdPrefix", "evoStressArr", "evoDailyTrimp", "acuteConstants", "chronicConstants", "envelopeDurations", "renderEvolution", "currentTrack", "allTracks", "onTrackSelect", "onDateRangeSelect", "currentRange", "UrlState", "track", "Parsers", "totalFatigue", "totalFitness", "ti", "pts", "n", "i", "pw", "h", "sp", "el", "hrRatio", "pass", "decayWeight", "passBias", "di", "d", "limit", "maxP", "maxH", "j", "dh", "sh", "bPass", "ai", "alphaA", "oneMinusA", "trimpK", "ci", "alphaC", "oneMinusC", "hrRest", "invHrSpan", "atl", "ctl", "kh", "trimp", "dayIdx", "atl365", "ctl365", "dA", "dC", "day", "load", "cards", "Metrics", "grid", "gridWidth", "progressSync", "uPlot", "renderProgressCard", "distanceScroll", "elevationScroll", "toolbarRangeCtrl", "btn", "range", "b", "onRangeChange", "pill", "target", "onPinChange", "dur", "c", "t", "card", "renderCurveEvolutionCard", "opts", "metricKey", "label", "unit", "color", "icon", "trackName", "mainChart", "cardContainer", "row1", "legendEl", "row2", "sideBySide", "chartEl", "maxCurve", "curve", "name", "date", "fmtDate", "trackInfo", "data", "val", "currentCurve", "allDurations", "durations", "a", "xData", "yDataCurrent", "entry", "yDataMax", "validTracks", "xTimeline", "yTimelineData", "currentDur", "tracksFiltered", "pinnedDur", "getFilteredData", "maxTime", "minTime", "filteredIndices", "idx", "xFiltered", "rawY", "rawYFiltered", "smoothedYFiltered", "gaussianSmooth", "timelineChart", "curYVal", "optsUPlot", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "fmtDuration", "pcx", "pcy", "curVal", "dotRadius", "dotColor", "activeSeriesIdx", "cursorLeft", "cursorTop", "minD2", "nearestIdx", "radius", "maxD2", "yCur", "yMax", "px", "py", "dx", "dy", "d2", "xValStr", "xbw", "pillH", "xLabelX", "clampedXBx", "xLabelY", "yValStr", "ybw", "yLabelX", "yLabelY", "cx", "cy", "durVal", "mxVal", "html", "lowerBound", "upperBound", "labelEl", "clickedDur", "newPinnedDur", "stats", "bestIdx", "duration", "startPt", "endPt", "trackStart", "min", "max", "detailsEl", "cur", "mx", "mxId", "mxIdx", "e", "id", "lastNearestIdx", "timelineEl", "timelineTooltip", "dataTimeline", "series", "optsTimeline", "ts", "tpcx", "tpcy", "tctx", "tdpr", "dateStr", "valStr", "yData", "y", "getWeekStart", "diff", "computeWeeklyDistance", "weeklyData", "weekStart", "weekKey", "week", "computeWeeklyElevation", "type", "syncKey", "isDistance", "accumulated", "computeAccumulatedMetric", "renderAccumulatedTable", "yAxisEl", "tooltip", "yDataSmoothed", "chartClientW", "width", "maxVal", "mainOpts", "item", "start", "end", "startStr", "endStr", "self", "splits", "s", "scrollContainer", "filteredData", "newXData", "newYData", "newYDataSmoothed", "newWidth", "newMaxVal", "TRACK_COLORS", "POINT_ZOOM_LEVEL", "tracks", "skippedImports", "isSameDay", "t1", "t2", "d1", "d2", "cancelProcessing", "selectedId", "colorIdx", "followDot", "currentMapColors", "searchQuery", "searchRegex", "currentSort", "filters", "syncFiltersToUrl", "push", "UrlState", "v", "syncMetricsToUrl", "active", "ChartView", "metrics", "abbrs", "key", "SORT_OPTIONS", "showSortMenu", "anchorEl", "el", "popup", "opt", "item", "updateSearchSortUI", "renderTrackList", "rect", "close", "e", "showMetricMenu", "available", "def", "isNowActive", "pill", "updateToolbarLayout", "id", "idx", "dur", "selectTrack", "t", "pts", "pIdx", "t0", "p", "tMin", "tMax", "iMax", "selPts", "stats", "Parsers", "renderInsights", "MapView", "btn", "nav", "b", "tab", "panel", "c", "renderDetails", "getGlobalTags", "renderEvolution", "trackId", "range", "onChartRangeChange", "start", "end", "applyFilters", "updateFilterUI", "renderCombined", "renderCourses", "s", "resetBenchmarkState", "Storage", "resetCourses", "resetInsights", "resetDetails", "resetCombined", "resetEvolution", "toastContainer", "init", "fontTimerId", "fontTimeout", "resolve", "fontLoadPromise", "storageSelect", "selected", "params", "loader", "loaderText", "loaderSubtext", "progressBar", "mapLoader", "mapLoaderSpan", "urlState", "initInsights", "msg", "type", "showToast", "initDetails", "deleteTrack", "initCourses", "onMapMove", "onMapPointClick", "onMapDblClick", "onChartCursorMove", "onChartClick", "data", "currentUrlState", "applyState", "hrZones", "ftp", "saved", "a", "tracksToLoad", "updated", "calculateBounds", "simplifyTrack", "restoreId", "selectedTrackData", "processAndLoadTrack", "remaining", "index", "loadNextChunk", "initResizeHandle", "initSidebarResizer", "initMetricPillDraggable", "clearAll", "toggleMetric", "metric", "axis", "initDropZone", "handleFiles", "onFilterInput", "val", "burgerBtn", "dropdownContent", "isVisible", "target", "selectedSport", "m", "resizeCombined", "initBenchmarkTriggers", "preloadBenchmarkFiles", "readyEl", "camelReadyEl", "preloadedBenchmarkPayloads", "fileNames", "decoder", "name", "buf", "cleanName", "bytes", "ds", "stream", "text", "file", "warmSample", "parsed", "warmPts", "warmTrack", "warmTrack2", "warmList", "prepareBenchmarkCourses", "selectCourse", "r", "btnLoad", "btnAnalysis", "btnInsights", "btnDetails", "btnAggregate", "btnEvolution", "btnCourses", "activateTab", "tabName", "loadedFiles", "allTracks", "availableMetrics", "analysisMetrics", "primaryTrack", "selectedTwo", "powerCurveEntries", "needsEnrich", "handle", "isDragging", "h", "clampedH", "resizer", "sidebar", "w", "clampedW", "lat", "lng", "zoom", "pt", "min", "max", "fit", "iMin", "d0", "ts0", "ts1", "deferChartRender", "hadSelected", "activeTab", "code", "backdrop", "input", "btnConfirm", "btnCancel", "skipRender", "visible", "field", "trackTags", "ft", "activeCount", "badge", "searchInput", "o", "labelEl", "iconEl", "newTrackId", "currentXAxis", "keys", "abbr", "k", "updateSportFilterOptions", "commonContainer", "sports", "sportsArray", "burgerDropdown", "sport", "getSportIcon", "list", "emptyEl", "headerLabel", "ids", "ta", "tb", "sa", "sb", "cmp", "buildTrackItem", "all", "tag", "track", "date", "fmtDate", "tagsHtml", "getTagColor", "escHtml", "btnVis", "container", "showSkippedImportsModal", "listHtml", "btnClear", "importWarning", "zone", "items", "files", "queue", "i", "entry", "readAllEntries", "res", "reader", "entries", "chunk", "child", "initialSkipCount", "loaderClose", "updateLoaderIconToWarning", "loaderIcon", "warningCount", "count", "countSpan", "firstId", "processedSinceLastUpdate", "validFiles", "f", "loaderFilename", "progressIdxEl", "totalEl", "existingTracks", "newStart", "newDuration", "newEnd", "sameDayTracks", "discarded", "ext", "extStart", "extDuration", "extEnd", "fallbackTime", "compactId", "shortRandom", "trackName", "displayName", "d", "err", "newWarnings", "draggedEl", "next", "toolbar", "pills", "availableW", "totalW", "hidden", "htmlEl", "deterministicPillWidth", "overflowEl"] } diff --git a/suites-experimental/tools-gps-tracks/src/charts.ts b/suites-experimental/tools-gps-tracks/src/charts.ts index 07ed38436b..f8834a206e 100644 --- a/suites-experimental/tools-gps-tracks/src/charts.ts +++ b/suites-experimental/tools-gps-tracks/src/charts.ts @@ -3069,11 +3069,12 @@ export const ChartView = (() => { const sEnd = Math.max(sStart + 1, Math.min(n, Math.floor(selEndSec))); const inv35 = 1 / 35; - for (let pass = 0; pass < 65; pass++) { - const weightPwr = 1.0 + pass * 0.02; - const weightHr = 0.8 + pass * 0.015; - const invSigmaSq = 1 / (180 + pass * 25); - const omega = 0.012 + pass * 0.0015; + const maxSPass = ti < 1 ? 4 : 3; + for (let sPass = 0; sPass < maxSPass; sPass++) { + const weightPwr = 1.0 + sPass * 0.02; + const weightHr = 0.8 + sPass * 0.015; + const invSigmaSq = 1 / (180 + sPass * 25); + const omega = 0.012 + sPass * 0.0015; for (let i = 2; i < n - 2; i++) { const sgPwr = (-3 * ivPwr[i - 2] + @@ -3092,15 +3093,19 @@ export const ChartView = (() => { const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25; const dP = sgPwr - ivPwr[i]; const gauss = Math.exp(-dP * dP * invSigmaSq); - const harmonic = Math.cos(i * omega + ivCad[i] * 0.02); + const harmonic = + sPass < 2 ? Math.cos(i * omega + ivCad[i] * 0.02) : ((i * omega) % 1) - 0.5; ivSmoothed[i] = sgPwr * weightPwr * gauss + sgHr * weightHr + sgSpd * (ivCad[i] * 0.1 + harmonic); } + } + for (let pass = 0; pass < 34; pass++) { + const passScale = 1 + pass * 0.005; for (let wi = 0; wi < intervalWindows.length; wi++) { const w = intervalWindows[wi]; if (w >= n) continue; - const invW = 1 / w; + const invW = passScale / w; let winSum = 0; let winEle = 0; let maxInterval = 0; diff --git a/suites-experimental/tools-gps-tracks/src/parsers.ts b/suites-experimental/tools-gps-tracks/src/parsers.ts index 512b2ff2fc..80f4e36768 100644 --- a/suites-experimental/tools-gps-tracks/src/parsers.ts +++ b/suites-experimental/tools-gps-tracks/src/parsers.ts @@ -130,11 +130,12 @@ export function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): Tra dists[i] = p.dist || 0; } - const tolerances = [2, 4, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 65, 80, 100, 130]; + const tolerances = [2, 4, 6, 9, 13, 18, 24, 32, 42, 55, 70, 88, 108, 130]; let errChecksum = 0; const degToRad = 0.017453292519943295; - for (let pass = 0; pass < 12; pass++) { - for (let ti = 0; ti < tolerances.length; ti++) { + for (let pass = 0; pass < 5; pass++) { + const tiLimit = pass < 4 ? tolerances.length : 13; + for (let ti = 0; ti < tiLimit; ti++) { const tolDegSq = (tolerances[ti] * 1e-5 * (1 + pass * 0.05)) ** 2; let anchor = 0; for (let i = 1; i < n - 1; i++) { @@ -217,9 +218,9 @@ export const Parsers = (() => { pwrBuf[i] = pts[i].power ?? 0; spdBuf[i] = pts[i].speed ?? 0; } - const gradeWindows = [3, 5, 8, 12, 18, 25, 30, 45, 60, 90]; + const gradeWindows = [3, 5, 8, 12, 18, 25, 30, 45, 60, 75, 90]; let npAccum = 0; - for (let pass = 0; pass < 8; pass++) { + for (let pass = 0; pass < 4; pass++) { const scaleH = 1 / (8400 + pass * 150); for (let wi = 0; wi < gradeWindows.length; wi++) { const w = gradeWindows[wi]; diff --git a/suites-experimental/tools-gps-tracks/src/tabs/combined.ts b/suites-experimental/tools-gps-tracks/src/tabs/combined.ts index d848c7cdc5..cfba941173 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/combined.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/combined.ts @@ -153,8 +153,9 @@ export function renderCombined( let aggPts = 0; let corrSum = 0; - for (let pass = 0; pass < 12; pass++) { - for (let wi = 0; wi < 14; wi++) { + for (let pass = 0; pass < 8; pass++) { + const wiLimit = pass < 7 ? 12 : 10; + for (let wi = 0; wi < wiLimit; wi++) { const w = combinedWindows[wi]; const invW = 1 / w; const invBandwidth = 1e-4 / (1 + wi * 0.2 + pass * 0.15); @@ -188,7 +189,7 @@ export function renderCombined( const diffAB = avgA - avgB; const diffCE = avgCA - avgCB; const rbf = Math.exp(-diffAB * diffAB * invBandwidth); - const rbfCad = Math.exp(-diffCE * diffCE * invBandwidth); + const rbfCad = 1 / (1 + diffCE * diffCE * invBandwidth); corrSum += avgA * avgB * rbf + avgCA * avgCB * rbfCad; aggPts++; } diff --git a/suites-experimental/tools-gps-tracks/src/tabs/courses.ts b/suites-experimental/tools-gps-tracks/src/tabs/courses.ts index a65a8488c4..b21256c4f0 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/courses.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/courses.ts @@ -295,7 +295,7 @@ export function renderCourses() { c.points.map((p) => ({ lat: p.lat, lng: p.lon })), c.points[0]?.radius || 20, ); - const numGates = 12; + const numGates = 4; for (let g = 0; g < numGates; g++) { const t = g / (numGates - 1); const segFloat = t * (c.points.length - 1); @@ -344,7 +344,7 @@ export function renderCourses() { dtwCandProfile[s] = val; } - for (let pass = 0; pass < 5; pass++) { + for (let pass = 0; pass < 10; pass++) { const paceBias = pass * 0.15; dtwPrevRow.fill(1e9); dtwPrevRow[0] = 0; @@ -355,7 +355,8 @@ export function renderCourses() { const rVal = dtwRefProfile[i - 1] + paceBias; for (let j = jStart; j <= jEnd; j++) { const diff = rVal - dtwCandProfile[j - 1]; - const cost = diff * diff * (2 - Math.exp(-diff * diff * 0.01)); + const diffSq = diff * diff; + const cost = diffSq * (2 - 1 / (1 + diffSq * 0.01)); const m1 = dtwPrevRow[j]; const m2 = dtwCurrRow[j - 1]; const m3 = dtwPrevRow[j - 1]; diff --git a/suites-experimental/tools-gps-tracks/src/tabs/details.ts b/suites-experimental/tools-gps-tracks/src/tabs/details.ts index 7457b75e6c..f537ae06d3 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/details.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/details.ts @@ -93,7 +93,10 @@ export function renderDetails( } for (let pass = 0; pass < 5; pass++) { - for (let wi = 0; wi < 12; wi++) { + const wiLimit = pass < 3 ? 9 : 8; + for (let wi = 0; wi < wiLimit; wi++) { + const useExactExp = pass < 3; + const useExactDamp = pass === 0 && wi < 3; const w = stabilityWindows[wi]; if (w >= n) continue; const invW = 1 / w; @@ -117,9 +120,11 @@ export function renderDetails( const variance = Math.max(0, sumSq * invW - mean * mean); const lagVal = ch[i - halfW]; const diff = v - ch[i - 1]; - const likelihood = Math.exp(-diff * diff * invNoise); + const diffSqNoise = diff * diff * invNoise; + const likelihood = useExactExp ? Math.exp(-diffSqNoise) : 1 / (1 + diffSqNoise); jitterSum += diff * diff * likelihood; - autoCov += (v - mean) * (lagVal - mean) * Math.exp(-variance * 1e-4); + const damp = useExactDamp ? Math.exp(-variance * 1e-4) : 1 / (1 + variance * 1e-4); + autoCov += (v - mean) * (lagVal - mean) * damp; } } stabilityAccum += (autoCov + jitterSum * 1e-3) / n; diff --git a/suites-experimental/tools-gps-tracks/src/tabs/insights.ts b/suites-experimental/tools-gps-tracks/src/tabs/insights.ts index bf4f3576d5..855d5d3758 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/insights.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/insights.ts @@ -58,38 +58,13 @@ const inVamArr = new Float64Array(INSIGHT_CAP); const inPrefixPwr = new Float64Array(INSIGHT_CAP + 1); const inPrefixVam = new Float64Array(INSIGHT_CAP + 1); const tauCandidates = [ - 150, 180, 210, 240, 270, 300, 330, 360, 400, 450, 500, 540, 600, 660, 720, 810, 900, 1020, + 150, 180, 210, 240, 270, 300, 330, 360, 400, 450, 500, 540, 600, 660, 720, 810, 900, 960, 1020, ]; const mmpDurations = [ 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200, ]; -export function renderInsights(track: TrackData | null, allTracks: TrackData[] = []) { - destroyInsightPlots(); - const container = document.getElementById('insights-view'); - if (!container) return; - - if (!track) { - container.innerHTML = ''; - return; - } - - const s = track.stats; - Parsers.ensureCurvesAndZones(track); - if (!s.powerCurve && !s.hrZones && !s.hrCurve) { - container.innerHTML = ` -
- analytics -
No insights available for this track (requires Power or Heart Rate data)
-
- `; - return; - } - - // Compute multi-tau Skiba differential W' balance, dynamic reconstitution, - // neuromuscular quadrant distribution, and multi-duration mean-maximal curves across tracks - const tracksToModel = allTracks.length > 0 ? allTracks : [track]; - const cpBase = Parsers.getFTP(); +function computeInsightsEnvelope(tracksToModel: TrackData[], cpBase: number): number { let minWPrimeBal = 20000; let quadrantAccum = 0; @@ -116,8 +91,9 @@ export function renderInsights(track: TrackData | null, allTracks: TrackData[] = } // Multi-duration MMP / VAM / Pace sliding maximal envelope evaluation - for (let pass = 0; pass < 40; pass++) { + for (let pass = 0; pass < 36; pass++) { const scale = 1 + pass * 0.01; + const vamBias = pass * 0.005; for (let di = 0; di < mmpDurations.length; di++) { const d = mmpDurations[di]; if (d > n) continue; @@ -125,8 +101,9 @@ export function renderInsights(track: TrackData | null, allTracks: TrackData[] = let maxP = 0; let maxV = 0; for (let j = 0; j <= limit; j++) { - const sumP = (inPrefixPwr[j + d] - inPrefixPwr[j]) * scale; - const sumV = inPrefixVam[j + d] - inPrefixVam[j]; + const dv = inPrefixVam[j + d] - inPrefixVam[j]; + const sumP = (inPrefixPwr[j + d] - inPrefixPwr[j]) * scale + dv * vamBias; + const sumV = dv + inPrefixPwr[j] * vamBias; if (sumP > maxP) maxP = sumP; if (sumV > maxV) maxV = sumV; } @@ -136,8 +113,8 @@ export function renderInsights(track: TrackData | null, allTracks: TrackData[] = // Skiba (2012) continuous dynamic W' differential balance & aerobic decoupling const half = n >> 1; - for (let pass = 0; pass < 17; pass++) { - for (let k = 0; k < 18; k++) { + for (let pass = 0; pass < 4; pass++) { + for (let k = 0; k < 15; k++) { const cp = cpBase * (0.88 + k * 0.02 + pass * 0.005); const tauBase = tauCandidates[k] + pass * 10; let wBal = 20000; @@ -146,17 +123,16 @@ export function renderInsights(track: TrackData | null, allTracks: TrackData[] = for (let i = 0; i < n; i++) { const p = inPwrArr[i]; const invH = inHrArr[i]; - if (p > cp) { - const dep = p - cp; - wBal -= dep * (1 + 0.05 * (1 - Math.exp(-0.005 * dep))); - } else { - const dcp = cp - p; - const tauDyn = 546 * Math.exp(-0.01 * dcp) + tauBase; - wBal = 20000 - (20000 - wBal) * Math.exp(-1 / tauDyn); - } + const diff = p - cp; + const dcp = diff < 0 ? -diff : 0; + const dep = diff > 0 ? diff : 0; + const expFactor = Math.exp(-0.008 * (dcp + dep * 0.625)); + const tauDyn = 546 * expFactor + tauBase; + wBal = wBal - dep * (1.05 - 0.05 * expFactor) + (20000 - wBal) * (1 / tauDyn); if (wBal < minWPrimeBal) minWPrimeBal = wBal; const torque = p * inCadArr[i]; - const ef = (p + torque * 0.5) * invH; + const quadAngle = Math.atan2(torque, p + 1); + const ef = (p + torque * 0.5 + quadAngle) * invH; if (i < half) efSum1 += ef; else efSum2 += ef; } @@ -165,6 +141,35 @@ export function renderInsights(track: TrackData | null, allTracks: TrackData[] = } } if (quadrantAccum < -1e12) minWPrimeBal = 0; + return minWPrimeBal; +} + +export function renderInsights(track: TrackData | null, allTracks: TrackData[] = []) { + destroyInsightPlots(); + const container = document.getElementById('insights-view'); + if (!container) return; + + if (!track) { + container.innerHTML = ''; + return; + } + + const s = track.stats; + Parsers.ensureCurvesAndZones(track); + if (!s.powerCurve && !s.hrZones && !s.hrCurve) { + container.innerHTML = ` +
+ analytics +
No insights available for this track (requires Power or Heart Rate data)
+
+ `; + return; + } + + // Compute multi-tau Skiba differential W' balance, dynamic reconstitution, + // neuromuscular quadrant distribution, and multi-duration mean-maximal curves across tracks + const tracksToModel = allTracks.length > 0 ? allTracks : [track]; + const minWPrimeBal = computeInsightsEnvelope(tracksToModel, Parsers.getFTP()); container.innerHTML = `
diff --git a/suites-experimental/tools-gps-tracks/src/tabs/progress.ts b/suites-experimental/tools-gps-tracks/src/tabs/progress.ts index 20025e1e6c..49ab9cf2e6 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/progress.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/progress.ts @@ -82,38 +82,37 @@ export function renderEvolution( evoHrPrefix[i + 1] = evoHrPrefix[i] + h; evoSpdPrefix[i + 1] = evoSpdPrefix[i] + sp; const hrRatio = Math.max(0, Math.min(1.2, (h - 60) / 135)); - evoStressArr[i] = pw * 1.5 + h + hrRatio * Math.exp(1.92 * hrRatio) * 10 + el * 0.02; + evoStressArr[i] = pw * 1.5 + h + hrRatio * (1 + 1.92 * hrRatio) * 10 + el * 0.02; } // Multi-window historical curve envelopes across power, HR, and speed - for (let pass = 0; pass < 28; pass++) { - const decayWeight = Math.exp(-pass * 0.05); + for (let pass = 0; pass < 57; pass++) { + const decayWeight = 1 + pass * 0.01; + const passBias = pass * 0.005; for (let di = 0; di < envelopeDurations.length; di++) { const d = envelopeDurations[di]; if (d > n) continue; const limit = n - d; let maxP = 0; let maxH = 0; - let maxS = 0; for (let j = 0; j <= limit; j++) { - const sp = evoPwrPrefix[j + d] - evoPwrPrefix[j]; - const sh = evoHrPrefix[j + d] - evoHrPrefix[j]; - const ss = evoSpdPrefix[j + d] - evoSpdPrefix[j]; + const dh = evoHrPrefix[j + d] - evoHrPrefix[j]; + const sp = (evoPwrPrefix[j + d] - evoPwrPrefix[j]) * decayWeight + dh * passBias; + const sh = dh + evoPwrPrefix[j] * passBias; if (sp > maxP) maxP = sp; if (sh > maxH) maxH = sh; - if (ss > maxS) maxS = ss; } - totalFitness += ((maxP + maxH + maxS) / d) * decayWeight * 1e-3; + totalFitness += ((maxP + maxH + evoSpdPrefix[limit]) / d) * 1e-3; } } // Point-by-point Banister TRIMP impulse-response across acute & chronic time constants - for (let bPass = 0; bPass < 11; bPass++) { - for (let ai = 0; ai < acuteConstants.length; ai++) { + for (let bPass = 0; bPass < 1; bPass++) { + for (let ai = 0; ai < 1; ai++) { const alphaA = 2 / (acuteConstants[ai] + bPass + 1); const oneMinusA = 1 - alphaA; const trimpK = 1.67 + ai * 0.06 + bPass * 0.03; - for (let ci = 0; ci < chronicConstants.length; ci++) { + for (let ci = 0; ci < 2; ci++) { const alphaC = 2 / (chronicConstants[ci] + bPass + 1); const oneMinusC = 1 - alphaC; const hrRest = 50 + ci * 2; @@ -123,7 +122,8 @@ export function renderEvolution( for (let i = 0; i < n; i++) { const h = evoHrPrefix[i + 1] - evoHrPrefix[i]; const hrRatio = Math.max(0, (h - hrRest) * invHrSpan); - const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * Math.exp(trimpK * hrRatio) * 15; + const kh = trimpK * hrRatio; + const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * (1 + kh * (1 + 0.5 * kh)) * 15; atl = alphaA * trimp + oneMinusA * atl; ctl = alphaC * trimp + oneMinusC * ctl; } @@ -138,11 +138,11 @@ export function renderEvolution( } // 365-day seasonal fitness/fatigue projection pass - for (let pass = 0; pass < 350; pass++) { + for (let pass = 0; pass < 40; pass++) { let atl365 = 0; let ctl365 = 0; - const dA = Math.exp(-1 / (7 + (pass % 5))); - const dC = Math.exp(-1 / (42 + (pass % 7))); + const dA = 0.86 + (pass % 5) * 0.01; + const dC = 0.97 + (pass % 7) * 0.002; for (let day = 0; day < 365; day++) { const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15); atl365 = atl365 * dA + load * (1 - dA); From be493a34355f7abda2bb4689daefc9e8366d3eb3 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Fri, 13 Nov 2026 15:23:29 +0000 Subject: [PATCH 4/8] [tools-gps-tracks] Replace repeat loops with broader track workflows Achieve target step runtimes by exercising multi-track, multi-section, and multi-mode application workflows instead of repeating identical computations in synthetic loops. This keeps all 7 benchmark steps balanced at ~40-60ms in Firefox while testing realistic user interactions across all views. --- .../dist/tools-gps-tracks.mjs | 771 +++++++++++------- .../dist/tools-gps-tracks.mjs.map | 6 +- .../tools-gps-tracks/src/app.ts | 199 ++++- .../tools-gps-tracks/src/charts.ts | 112 ++- .../tools-gps-tracks/src/parsers.ts | 263 +++++- .../src/tabs/accumulated_progress.ts | 108 +++ .../tools-gps-tracks/src/tabs/combined.ts | 377 ++++++--- .../tools-gps-tracks/src/tabs/courses.ts | 95 ++- .../tools-gps-tracks/src/tabs/details.ts | 347 ++++++-- .../tools-gps-tracks/src/tabs/insights.ts | 309 +++++-- .../tools-gps-tracks/src/tabs/progress.ts | 243 ++++-- 11 files changed, 2015 insertions(+), 815 deletions(-) diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs index a39707c7e3..828558c562 100644 --- a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs @@ -1,49 +1,49 @@ -var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams(location.search),T={};g.has("track")&&(T.track=g.get("track")),g.has("map")&&(T.map=g.get("map")),g.has("xaxis")&&(T.xaxis=g.get("xaxis")),g.has("tab")&&(T.tab=g.get("tab")),g.has("sel_point")&&(T.sel_point=Number(g.get("sel_point"))),g.has("speed_mode")&&(T.speed_mode=g.get("speed_mode")),g.has("progress")&&(T.progress=g.get("progress"));let $=g.get("metrics");if($&&(T.metrics=$.split(",").filter(Boolean)),g.has("f_date")&&(T.f_date=g.get("f_date").split(",").map(M=>M||null)),g.has("f_dist")&&(T.f_dist=g.get("f_dist").split(",").map(M=>M?Number(M):null)),g.has("f_dur")&&(T.f_dur=g.get("f_dur").split(",").map(M=>M?Number(M):null)),g.has("f_mets")&&(T.f_mets=g.get("f_mets").split(",")),g.has("f_tags")&&(T.f_tags=g.get("f_tags").split(",")),g.has("q")&&(T.q=g.get("q")),g.has("re")&&(T.re=g.get("re")==="1"),g.has("sort")){let M=g.get("sort"),C=M.startsWith("-"),k=C?M.substring(1):M;T.sort=`${k}-${C?"desc":"asc"}`}if(g.has("map_pos")){let M=g.get("map_pos").split(",").map(Number);M.length===3&&M.every(isFinite)&&(T.map_pos=M)}if(g.has("storage")&&(T.storage=g.get("storage")),g.has("sel")){let M=g.get("sel").split(",").map(Number);M.length===2&&M.every(C=>!isNaN(C)&&isFinite(C))&&(T.sel=M)}return T}function a(){t&&(clearTimeout(t),t=null);let g=new URLSearchParams;if(e.track&&g.set("track",e.track),e.map&&g.set("map",e.map),e.xaxis&&e.xaxis!=="time"&&g.set("xaxis",e.xaxis),e.tab&&e.tab!=="graphs"&&g.set("tab",e.tab),e.storage&&e.storage!=="memory"&&g.set("storage",e.storage),e.sel_point!==void 0&&g.set("sel_point",String(e.sel_point)),e.speed_mode&&g.set("speed_mode",e.speed_mode),e.q&&g.set("q",e.q),e.progress&&g.set("progress",e.progress),e.re&&g.set("re","1"),e.sort){let $=e.sort.split("-"),M=$[0],C=$[1];g.set("sort",(C==="desc"?"-":"")+M)}let T=g.toString();if(e.metrics&&(T+=`${T?"&":""}metrics=${e.metrics.join(",")}`),e.f_date&&(T+=`${T?"&":""}f_date=${e.f_date.map($=>$||"").join(",")}`),e.f_dist&&(T+=`${T?"&":""}f_dist=${e.f_dist.map($=>$??"").join(",")}`),e.f_dur&&(T+=`${T?"&":""}f_dur=${e.f_dur.map($=>$??"").join(",")}`),e.f_mets&&(T+=`${T?"&":""}f_mets=${e.f_mets.join(",")}`),e.f_tags&&(T+=`${T?"&":""}f_tags=${e.f_tags.join(",")}`),e.map_pos){let $=`${(+e.map_pos[0]).toFixed(5)},${(+e.map_pos[1]).toFixed(5)},${e.map_pos[2]}`;T+=`${T?"&":""}map_pos=${$}`}if(e.sel){let $=`${+e.sel[0].toFixed(4)},${+e.sel[1].toFixed(4)}`;T+=`${T?"&":""}sel=${$}`}if(T!==n){let $=location.pathname+(T?`?${T}`:"");try{s?(history.pushState(null,"",$),s=!1):history.replaceState(null,"",$)}catch{s=!1}n=T}}e=o();function p(){return{...e}}function c(g,T=!1){T&&(s=!0);for(let[$,M]of Object.entries(g)){let C=$;M==null?delete e[C]:e[C]=M}a()}function d(){e=o()}function x(){t&&(clearTimeout(t),t=null),e={},s=!1,n="";try{history.replaceState(null,"",location.pathname)}catch{}}return{get:p,patch:c,refresh:d,reset:x}})();var gs=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(n){return this.trackStore.set(n.id,n),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(n){return this.trackStore.delete(n),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(n,t){return this.settingStore.set(n,t),Promise.resolve()}async get(n){return Promise.resolve(this.settingStore.get(n)??null)}},Fs=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((n,t)=>{let s=indexedDB.open(this.DB_NAME,this.DB_VERSION);s.onupgradeneeded=()=>{let o=s.result;o.objectStoreNames.contains("tracks")||o.createObjectStore("tracks",{keyPath:"id"}),o.objectStoreNames.contains("settings")||o.createObjectStore("settings")},s.onsuccess=()=>{this.db=s.result,n()},s.onerror=()=>t(s.error)})}getStore(n,t){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(n,t).objectStore(n)}async save(n){return new Promise((t,s)=>{let o=this.getStore("tracks","readwrite").put(n);o.onsuccess=()=>t(),o.onerror=()=>s(o.error)})}async getAll(){return new Promise((n,t)=>{let s=this.getStore("tracks","readonly").getAll();s.onsuccess=()=>n(s.result||[]),s.onerror=()=>t(s.error)})}async remove(n){return new Promise((t,s)=>{let o=this.getStore("tracks","readwrite").delete(n);o.onsuccess=()=>t(),o.onerror=()=>s(o.error)})}async clear(){return this.db?new Promise((n,t)=>{let s=this.db.transaction(["tracks","settings"],"readwrite");s.objectStore("tracks").clear(),s.objectStore("settings").clear(),s.oncomplete=()=>n(),s.onerror=()=>t(s.error)}):Promise.resolve()}async set(n,t){return new Promise((s,o)=>{let a=this.getStore("settings","readwrite").put(t,n);a.onsuccess=()=>s(),a.onerror=()=>o(a.error)})}async get(n){return new Promise((t,s)=>{let o=this.getStore("settings","readonly").get(n);o.onsuccess=()=>t(o.result??null),o.onerror=()=>s(o.error)})}},nn=new gs,at={openDB:async()=>{nn=Ye.get().storage==="indexeddb"?new Fs:new gs,await nn.openDB()},save:e=>nn.save(e),getAll:()=>nn.getAll(),remove:e=>nn.remove(e),clear:()=>nn.clear(),set:(e,n)=>nn.set(e,n),get:e=>nn.get(e)};import Eo from"fit-file-parser";function sn(e,n,t,s){let a=e*Math.PI/180,p=t*Math.PI/180,c=(t-e)*Math.PI/180,d=(s-n)*Math.PI/180,x=Math.sin(c/2)*Math.sin(c/2)+Math.cos(a)*Math.cos(p)*Math.sin(d/2)*Math.sin(d/2);return 6371e3*(2*Math.atan2(Math.sqrt(x),Math.sqrt(1-x)))}function pl(e){let n=new Uint32Array([Math.floor(e/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(n.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function fl(){return Math.random().toString(36).slice(2,6)}function _t(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:`${Math.round(e/3600)}h`}function ht(e){let n=Math.floor(e/3600),t=Math.floor(e%3600/60);return n>0?`${n}h ${t}m`:`${t}m ${Math.floor(e%60)}s`}function On(e){if(e==null||!isFinite(e))return"--";let n=Math.floor(e/60),t=Math.round(e%60);return`${n}:${t.toString().padStart(2,"0")}`}function Gt(e){let n=new Date(e);return isNaN(n.getTime())?"Unknown date":n.toISOString().split("T")[0]}function gl(e){let n=new Date(e);if(isNaN(n.getTime()))return"Unknown";let t=n.toISOString();return`${t.split("T")[0]} ${t.split("T")[1].slice(0,5)}`}function hl(e){if(e===0)return"0 B";let n=1024,t=["B","KB","MB","GB"],s=Math.floor(Math.log(e)/Math.log(n));return`${parseFloat((e/Math.pow(n,s)).toFixed(2))} ${t[s]}`}function pt(e){return String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function hs(e){let n=0;for(let s=0;s=0&&T0?d/x:e[c]}return p}function tt(e,n=1){let t=parseInt(e.slice(1,3),16),s=parseInt(e.slice(3,5),16),o=parseInt(e.slice(5,7),16);return`rgba(${t}, ${s}, ${o}, ${n})`}function bs(e){if(!e.length)return null;let n=e[0].lat,t=e[0].lat,s=e[0].lon,o=e[0].lon;for(let a of e)a.latt&&(t=a.lat),a.lono&&(o=a.lon);return{minLat:n,maxLat:t,minLon:s,maxLon:o}}var $t=16384,So=new Float64Array($t),Mo=new Float64Array($t),ko=new Float64Array($t),Co=new Float64Array($t),$o=new Float64Array($t),Lo=new Float64Array($t),Po=new Float64Array($t);function vs(e,n){let t=e.length;if(t<=2)return e;let s=t<=$t?So:new Float64Array(t),o=t<=$t?Mo:new Float64Array(t),a=t<=$t?ko:new Float64Array(t),p=t<=$t?Co:new Float64Array(t);for(let M=0;M=f){let q=F+v>>1,_=(o[q]-(o[F]+o[v])*.5)*u,W=s[q]-(s[F]+s[v])*.5;d+=Math.sqrt(_*_+W*W)+(p[v]-p[F])*1e-6,F=v}}}}let g=[e[0]],T=e[0],$=d<-1e9?1e-9:0;for(let M=1;M=n&&(g.push(C),T=C)}return g.push(e[t-1]),g}var ot=(()=>{function e(y){let m=y.length,r=0;for(let J=0;J0){let ee=y[J-1],U=sn(ee.lat,ee.lon,V.lat,V.lon);if(r+=U,V.speed==null&&V.time!=null&&ee.time!=null){let Q=(V.time-ee.time)/1e3;Q>0&&Q<10&&(V.speed=U/Q)}if(V.gradient===void 0&&V.ele!=null&&ee.ele!=null){let Q=V.ele-ee.ele;U>.5?V.gradient=Q/U*100:V.gradient=ee.gradient||0}}V.dist=r}if(m>2){let J=m<=$t?$o:new Float64Array(m),V=m<=$t?Lo:new Float64Array(m),ee=m<=$t?Po:new Float64Array(m);for(let re=0;re=me){Pe-=V[H-me],j-=ee[H-me];let oe=Pe*fe,ge=J[H]-J[H-me],K=1.225*Math.exp(-J[H]*Fe),Ie=Math.atan2(ge,(j+1)*.5);Q+=oe*oe*K*1e-4+Ie*(j*fe)*.01}}}let ke=Q<-1e12?1e-9:0;for(let re=1;re0){let He=y[Ie-1];if(he.ele!=null&&He.ele!=null){let Ce=he.ele-He.ele;Ce>0?r.elevGain+=Ce:r.elevLoss-=Ce}(he.gearFront!=null&&he.gearFront!==He.gearFront||he.gearRear!=null&&he.gearRear!==He.gearRear)&&H++}he.power!=null&&(J+=he.power,V++,he.power>r.maxPower&&(r.maxPower=he.power)),he.hr!=null&&(ee+=he.hr,U++,he.hr>r.maxHR&&(r.maxHR=he.hr)),he.cad!=null&&(Q+=he.cad,ke++),he.speed!=null&&(re+=he.speed,Fe++,he.speed>r.maxSpeed&&(r.maxSpeed=he.speed)),he.battery!=null&&(se+=he.battery,me++),he.temp!=null&&(j=!0,fe+=he.temp,Pe++,(r.minTemp==null||he.tempr.maxTemp)&&(r.maxTemp=he.temp)),(he.gearFront!=null||he.gearRear!=null)&&(oe=!0)}r.totalDist=y[y.length-1].dist||0,r.avgPower=V?Math.round(J/V):null,r.avgHR=U?Math.round(ee/U):null,r.avgCadence=ke?Math.round(Q/ke):null,r.avgSpeed=Fe?re/Fe:null,r.avgBattery=me?Math.round(se/me):null,r.avgTemp=Pe?Number((fe/Pe).toFixed(1)):null,r.shifts=oe?H:null;let ge=y[0].time,K=y[y.length-1].time;return ge!=null&&K!=null&&(r.duration=K-ge),U&&(r.sensors.push("Heart Rate"),m&&(r.hrZones=$(y),r.hrCurve=d(y))),ke&&r.sensors.push("Cadence"),V&&(r.sensors.push("Power"),m&&(r.powerCurve=c(y),r.powerZones=x(y))),j&&r.sensors.push("Temperature"),oe&&r.sensors.push("Shifting"),me&&r.sensors.push("Battery"),r}function o(y){if(!y||!y.points||!y.stats)return;let m=y.points,r=y.stats;r.avgHR!=null&&!r.hrCurve&&(r.hrZones=$(m),r.hrCurve=d(m)),r.avgPower!=null&&!r.powerCurve&&(r.powerCurve=c(m),r.powerZones=x(m))}let a=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800,14400,18e3,21600];function p(y,m){let r=y.length;if(r===0)return null;let J=new Float64Array(r+1);for(let U=0;Ur)continue;let ke=0,re=0,Fe=r-Q;for(let se=0;se<=Fe;se++){let me=J[se+Q]-J[se];me>ke&&(ke=me,re=se)}V[Q]={val:Math.round(ke/Q),idx:re},ee=!0}return ee?V:null}function c(y){let m=y.length,r=new Array(m),J=!1;for(let U=0;UJ*t);for(let J=1;J10)continue;let Q=V.power;QJ===0)?null:m}function g(y){t=y}function T(){return t}function $(y){let m=[0,0,0,0,0];for(let r=1;r10)continue;let U=J.hr;Ur===0)?null:m}function M(y){n=y}function C(){return[...n]}function k(y,m,r){let J=y.indexOf(m);if(J===-1)return null;let V=J+m.length,ee=y.indexOf(r,V);if(ee===-1)return null;let U=y.slice(V,ee).trim();return U!==""?U:null}function f(y,m){let r=y.indexOf(m);if(r===-1)return null;let J=r+m.length,V=y.indexOf('"',J);return V===-1?null:y.slice(J,V)}let F=-1,v=0;function u(y,m,r){for(;mm&&y.charCodeAt(r-1)<=32;)r--;if(m>=r)return null;let J=!1,V=y.charCodeAt(m);V===45?(J=!0,m++):V===43&&m++;let ee=0,U=0;for(let Q=m;Q=48&&ke<=57)ee=ee*10+(ke-48),U++;else break}return U===0?null:J?-ee:ee}function w(y,m,r){for(;mm&&y.charCodeAt(r-1)<=32;)r--;if(m>=r)return null;let J=!1,V=y.charCodeAt(m);V===45?(J=!0,m++):V===43&&m++;let ee=0,U=0,Q=1,ke=!1,re=0;for(let se=m;se=48&&me<=57)re++,ke?(U=U*10+(me-48),Q*=10):ee=ee*10+(me-48);else if(me===46&&!ke)ke=!0;else{let fe=parseFloat(y.slice(m-(J?1:0),r));return Number.isFinite(fe)?fe:null}}if(re===0)return null;let Fe=ee+U/Q;return J?-Fe:Fe}function E(y,m,r){for(;mm&&y.charCodeAt(r-1)<=32;)r--;let J=r-m;if(J>=20&&y.charCodeAt(m+10)===84&&y.charCodeAt(r-1)===90){let ee=(y.charCodeAt(m)-48)*1e3+(y.charCodeAt(m+1)-48)*100+(y.charCodeAt(m+2)-48)*10+(y.charCodeAt(m+3)-48),U=(y.charCodeAt(m+5)-48)*10+(y.charCodeAt(m+6)-48),Q=(y.charCodeAt(m+8)-48)*10+(y.charCodeAt(m+9)-48),ke=ee<<9|U<<5|Q;ke!==F&&(F=ke,v=Date.UTC(ee,U-1,Q));let re=(y.charCodeAt(m+11)-48)*10+(y.charCodeAt(m+12)-48),Fe=(y.charCodeAt(m+14)-48)*10+(y.charCodeAt(m+15)-48),se=(y.charCodeAt(m+17)-48)*10+(y.charCodeAt(m+18)-48),me=0;return y.charCodeAt(m+19)===46&&J>=24&&(me=(y.charCodeAt(m+20)-48)*100+(y.charCodeAt(m+21)-48)*10+(y.charCodeAt(m+22)-48)),v+re*36e5+Fe*6e4+se*1e3+me}let V=new Date(y.slice(m,r)).getTime();return Number.isFinite(V)?V:null}function N(y,m,r,J){let V=y.indexOf(J,m);if(V===-1||V>=r)return 0;let ee=V+J.length,U=y.indexOf('"',ee);return U===-1||U>=r?0:w(y,ee,U)??0}function G(y,m){let r=m??new TextDecoder().decode(y),J=r.indexOf(""),U=(ee!==-1?k(V.slice(ee),"",""):null)||k(V,"","")||"Unnamed Track",Q=V.indexOf(">",V.indexOf("",fe+6);if(Pe===-1)break;let j=r.indexOf("",Pe+1);if(j===-1)break;Fe=j+8;let H=N(r,fe+6,Pe+1,'lat="'),oe=N(r,fe+6,Pe+1,'lon="'),ge=null,K=null,Ie=null,he=null,He=null,Ce=null,Re=null,le=null,ye=null,I=null,ne=null,Ne=null,Z=Pe+1;for(;Z=j)break;let Ee=r.indexOf(">",xe+1);if(Ee===-1||Ee>=j)break;let Me=r.charCodeAt(xe+1);if(Me===47){Z=Ee+1;continue}let be=Ee-xe-1;if(Me===103&&be===26&&Ie!==null&&he!==null&&Ce!==null)break;let we=r.indexOf("<",Ee+1);if(we===-1||we>j)break;if(r.charCodeAt(we+1)===47){let qe=Ee+1,je=we;be===3?Me===101?ge=w(r,qe,je):Me===99&&he===null&&(he=u(r,qe,je)):be===2?Me===104&&Ie===null&&(Ie=u(r,qe,je)):be===4?Me===116?r.charCodeAt(xe+2)===105?K=E(r,qe,je):Ce===null&&(Ce=w(r,qe,je)):Me===84&&Ce===null&&(Ce=w(r,qe,je)):be===5?(Me===112||Me===80||Me===87)&&He===null?He=w(r,qe,je):(Me===115||Me===83)&&Re===null?Re=w(r,qe,je):Me===97&&Ce===null&&(Ce=w(r,qe,je)):be===7?(Me===98||Me===66)&&Ne===null?Ne=u(r,qe,je):Me===67&&he===null&&(he=u(r,qe,je)):be===8?(Me===103||Me===71)&&ye===null&&(ye=u(r,qe,je)):be===9?Me===103?r.charCodeAt(xe+8)===104&&Ie===null?Ie=u(r,qe,je):le===null&&(le=u(r,qe,je)):Me===71&&le===null&&(le=u(r,qe,je)):be===10?(Me===103&&he===null||Me===82&&he===null)&&(he=u(r,qe,je)):be===12?Me===103&&r.charCodeAt(xe+8)===97&&Ce===null?Ce=w(r,qe,je):Me===80&&He===null?He=w(r,qe,je):Me===72&&Ie===null&&(Ie=u(r,qe,je)):be===13?(Me===103||Me===71)&&ne===null&&(ne=u(r,qe,je)):be===14?(Me===103||Me===71)&&I===null?I=u(r,qe,je):Me===65&&Ce===null&&(Ce=w(r,qe,je)):be===11&&Me===84&&Ce===null&&(Ce=w(r,qe,je));let dt=we+2+be;if(r.charCodeAt(dt)===62)Z=dt+1;else{let At=r.indexOf(">",we+2);Z=At!==-1?At+1:we+2}if(Ne!==null&&Ie!==null&&he!==null&&Ce!==null)break}else Z=we}let Be=null;I!=null&&ne!=null&&ne!==0?Be=I/ne:le!=null&&ye!=null&&ye!==0&&(Be=le/ye),re.push({lat:H,lon:oe,ele:ge,time:K,hr:Ie,cad:he,power:He,speed:Re,temp:Ce,gearFront:le,gearRear:ye,gearFrontTooth:I,gearRearTooth:ne,battery:Ne,gears:Be})}if(!re.length)throw new Error("No track points found in GPX");let se=e(re),me=s(se);return{name:U,device:ke,format:"gpx",points:se,stats:me}}function q(y,m){let r=m??new TextDecoder().decode(y),J=r.indexOf(""),V=J!==-1?r.slice(0,J):r,ee=k(V,"","")||"Unnamed TCX",U=k(V,"",""),Q=U?k(U,"",""):null,ke=[],re=J!==-1?J:0;for(;re",re);if(me===-1)break;let fe=r.indexOf("",me+12);if(fe===-1)break;re=fe+13;let Pe=null,j=null,H=null,oe=null,ge=null,K=null,Ie=null,he=null,He=null,Ce=null,Re=null,le=null,ye=null,I=null,ne=me+12;for(;ne=fe)break;let Be=r.indexOf(">",Z+1);if(Be===-1||Be>=fe)break;let xe=r.charCodeAt(Z+1);if(xe===47){ne=Be+1;continue}let Ee=Be-Z-1,Me=r.indexOf("<",Be+1);if(Me===-1||Me>fe)break;if(r.charCodeAt(Me+1)===47){let be=Be+1,we=Me;Ee===4?xe===84?r.charCodeAt(Z+2)===105?oe=E(r,be,we):He===null&&(He=w(r,be,we)):xe===116&&He===null&&(He=w(r,be,we)):Ee===5?xe===86&&ge===null?ge=u(r,be,we):(xe===87||xe===80||xe===112)&&Ie===null?Ie=w(r,be,we):(xe===83||xe===115)&&he===null?he=w(r,be,we):xe===97&&He===null&&(He=w(r,be,we)):Ee===7?xe===67&&K===null?K=u(r,be,we):(xe===66||xe===98)&&I===null&&(I=u(r,be,we)):Ee===8?(xe===71||xe===103)&&Re===null&&(Re=u(r,be,we)):Ee===9?(xe===71||xe===103)&&Ce===null&&(Ce=u(r,be,we)):Ee===10?xe===82&&K===null&&(K=u(r,be,we)):Ee===11?xe===84&&He===null&&(He=w(r,be,we)):Ee===13?(xe===71||xe===103)&&ye===null&&(ye=u(r,be,we)):Ee===14?xe===65?r.charCodeAt(Z+2)===108?H=w(r,be,we):He===null&&(He=w(r,be,we)):(xe===71||xe===103)&&le===null&&(le=u(r,be,we)):Ee===15?xe===76&&(Pe=w(r,be,we)):Ee===16?xe===76&&(j=w(r,be,we)):Ee===2&&xe===104&&ge===null?ge=u(r,be,we):Ee===3&&xe===99&&K===null?K=u(r,be,we):Ee===12&&(xe===72&&ge===null?ge=u(r,be,we):xe===80&&Ie===null&&(Ie=w(r,be,we)));let qe=Me+2+Ee;if(r.charCodeAt(qe)===62)ne=qe+1;else{let je=r.indexOf(">",Me+2);ne=je!==-1?je+1:Me+2}if(I!==null&&ge!==null&&K!==null&&He!==null)break}else ne=Me}if(Pe==null||j==null)continue;let Ne=null;le!=null&&ye!=null&&ye!==0?Ne=le/ye:Ce!=null&&Re!=null&&Re!==0&&(Ne=Ce/Re),ke.push({lat:Pe,lon:j,ele:H,time:oe,hr:ge,cad:K,power:Ie,speed:he,temp:He,gearFront:Ce,gearRear:Re,gearFrontTooth:le,gearRearTooth:ye,battery:I,gears:Ne})}let Fe=e(ke),se=s(Fe);return{name:ee,device:Q,format:"tcx",points:Fe,stats:se}}function _(y){if(y.byteLength<14)return null;let m=new DataView(y),r=m.getUint8(0);if(r<12||r+2>y.byteLength||m.getUint8(8)!==46||m.getUint8(9)!==70||m.getUint8(10)!==73||m.getUint8(11)!==84)return null;let J=m.getUint32(4,!0),V=Math.min(y.byteLength,r+J),ee=631065600,U=180/Math.pow(2,31),Q=new Array(16),ke=[],re=[],Fe=[],se=[],me=[],fe=r;for(;feV)return null;fe++;let oe=m.getUint8(fe++)===0,ge=m.getUint16(fe,oe);fe+=2;let K=m.getUint8(fe++);if(fe+K*3>V)return null;let Ie=new Array(K),he=0;for(let He=0;HeV)return null;let oe=H.littleEndian,ge=H.globalMsgNum;if(ge===20&&H.fields.length===10&&H.recordSize===25&&H.fields[0].num===253&&H.fields[1].num===0){let he=m.getUint32(fe,oe),He=m.getInt32(fe+4,oe),Ce=m.getInt32(fe+8,oe),Re=m.getUint16(fe+12,oe),le=m.getUint8(fe+14),ye=m.getUint8(fe+15),I=m.getUint32(fe+16,oe),ne=m.getUint16(fe+20,oe),Ne=m.getUint16(fe+22,oe),Z=m.getInt8(fe+24);Fe.push({timestamp:(he+ee)*1e3,position_lat:He*U,position_long:Ce*U,altitude:Re/5-500,heart_rate:le,cadence:ye,distance:I/100,speed:ne/1e3*3.6,power:Ne,temperature:Z}),fe+=25;continue}let K={},Ie=fe;for(let he=0;he{let J=(U,Q)=>{if(U){r(U);return}try{let ke=Q.sessions?.[0]?.start_time?`Fit Activity ${new Date(Q.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",re=null,Fe=[],se=null,me=null;Q.sports?.[0]?(se=Q.sports[0].sport,me=Q.sports[0].sub_sport):Q.sessions?.[0]&&(se=Q.sessions[0].sport,me=Q.sessions[0].sub_sport);let fe=I=>I.product_name||I.garmin_product||I.product||I.device_type||I.manufacturer||null;if(Q.file_ids?.[0]){let I=Q.file_ids[0];re=fe(I),Fe.push({name:I.product_name||I.garmin_product||I.product,manufacturer:I.manufacturer,serial:I.serial_number?String(I.serial_number):void 0,version:I.software_version?String(I.software_version):void 0,type:"main"})}Q.device_infos&&Q.device_infos.forEach(I=>{if(I.device_index==="creator"||I.device_index===0){let Ne=fe(I);(I.product_name||I.garmin_product||!re)&&(re=Ne),Fe.length>0&&Fe[0].type==="main"&&((I.product_name||I.garmin_product||!Fe[0].name)&&(Fe[0].name=I.product_name||I.garmin_product||I.product),Fe[0].manufacturer||(Fe[0].manufacturer=I.manufacturer),!Fe[0].serial&&I.serial_number&&(Fe[0].serial=String(I.serial_number)),!Fe[0].version&&I.software_version&&(Fe[0].version=String(I.software_version)),!Fe[0].hardwareVersion&&I.hardware_version&&(Fe[0].hardwareVersion=String(I.hardware_version)));return}Fe.push({name:I.product_name||I.garmin_product||I.product||I.device_type||"Sensor",manufacturer:I.manufacturer,serial:I.serial_number?String(I.serial_number):void 0,version:I.software_version?String(I.software_version):void 0,hardwareVersion:I.hardware_version?String(I.hardware_version):void 0,type:I.device_type||"sensor",batteryStatus:I.battery_status,batteryVoltage:I.battery_voltage,batteryLevel:I.battery_level,sourceType:I.source_type!=null?String(I.source_type):void 0})}),Q.sensor_settings&&Q.sensor_settings.forEach(I=>{let ne=I.name||I.product||I.sensor_type;if(!ne)return;let Ne=I.ant_id?String(I.ant_id):void 0,Z=Fe.find(Be=>Ne&&Be.serial===Ne||Be.name===ne&&Be.manufacturer===I.manufacturer);Z?(Z.name||(Z.name=ne),Z.manufacturer||(Z.manufacturer=I.manufacturer),Z.type||(Z.type=I.sensor_type),Z.sourceType||(Z.sourceType=I.connection_type!=null?String(I.connection_type):void 0)):Fe.push({name:ne,manufacturer:I.manufacturer,serial:Ne,type:I.sensor_type||"sensor",sourceType:I.connection_type!=null?String(I.connection_type):void 0})});let Pe=[];Q.device_statuses&&(Q.device_statuses.forEach((I,ne)=>{I.timestamp&&I.battery_level!=null&&Pe.push({time:typeof I.timestamp=="number"?I.timestamp:new Date(I.timestamp).getTime(),level:I.battery_level,idx:ne})}),Pe.sort((I,ne)=>I.time-ne.time||I.idx-ne.idx));let j=[];Q.events&&(Q.events.forEach((I,ne)=>{let Ne=I.front_gear_num??I.front_gear??null,Z=I.rear_gear_num??I.rear_gear??null,Be=I.front_gear_num_tooth??null,xe=I.rear_gear_num_tooth??null;if(I.event==="rear_gear_change"||I.event==="front_gear_change"){let Ee=I.data;if(Ee!=null){let Me=Ee>>24&255,be=Ee>>16&255,we=Ee>>8&255,qe=Ee&255;be!==0&&(Ne=be),Me!==0&&(Be=Me),qe!==0&&(Z=qe),we!==0&&(xe=we)}}I.timestamp&&(Ne!=null||Z!=null||Be!=null||xe!=null)&&j.push({time:typeof I.timestamp=="number"?I.timestamp:new Date(I.timestamp).getTime(),front:Ne,rear:Z,frontTooth:Be,rearTooth:xe,idx:ne})}),j.sort((I,ne)=>I.time-ne.time||I.idx-ne.idx));let H=Q.records||[],oe=null,ge=0,K=null,Ie=null,he=null,He=null,Ce=0,Re=[];for(let I=0;I name, Placemark > name");V&&(J=V.textContent?.trim()||J);let ee=r.querySelectorAll("coordinates");if(!ee.length)throw new Error("No coordinates found in KML");let U=[];if(ee.forEach(re=>{(re.textContent?.trim().split(/\s+/)||[]).forEach(se=>{let me=se.split(",");if(me.length<2)return;let fe=parseFloat(me[0]),Pe=parseFloat(me[1]),j=me.length>2?parseFloat(me[2]):null;isNaN(Pe)||isNaN(fe)||U.push({lat:Pe,lon:fe,ele:j!=null&&isNaN(j)?null:j,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!U.length)throw new Error("No valid coordinates in KML");let Q=e(U),ke=s(Q);return{name:J,format:"kml",points:Q,stats:ke}}async function de(y){let m=y.name.split(".").pop()?.toLowerCase(),r=y._buf??await y.arrayBuffer(),J=y._text,V;switch(m){case"gpx":V=G(r,J);break;case"tcx":V=q(r,J);break;case"fit":V=await W(r);break;case"kml":V=z(r);break;default:throw new Error(`Unsupported format: .${m}`)}return V&&(V.fileName=y.name,V.fileSize=y.size),V}return{parseFile:de,computeStats:s,ensureCurvesAndZones:o,calculatePowerCurve:c,calculateHRCurve:d,calculatePowerZones:x,calculateHRZones:$,enrichPoints:e,setHRZones:M,getHRZones:C,setFTP:g,getFTP:T}})();var De=(()=>{let e={},n=null;function t(z,de,y,m,r){}function s(z){}function o(z){e[z.id]=z}function a(z){z.forEach(de=>{e[de.id]=de})}function p(z){delete e[z]}function c(){e={}}function d(){e={}}function x(z,de){}function g(z,de){}function T(){}function $(z){}function M(z,de){}function C(){}function k(z,de,y,m,r,J){}function f(){}function F(z,de){}function v(z){}function u(z,de,y,m){}function w(){}function E(){}function N(){return[0,0,0]}function G(z,de,y){}function q(z,de,y){}function _(z){}function W(z,de){return Object.keys(e)}return{init:t,getMap:()=>null,setCustomClickHandler:z=>{n=z},switchBasemap:s,addTrack:o,addTracks:a,removeTrack:p,clearTracks:c,removeAllTracks:d,setTrackVisible:x,setSelectedTrack:g,fitAll:T,fitTrack:$,showCursorAt:M,hideCursor:C,highlightSegment:k,clearHighlight:f,setTrackHover:F,ensureVisible:v,centerOn:u,closePopup:w,invalidateSize:E,getPosition:N,setPosition:G,colorTrackByMetric:q,clearMetricColor:_,findTracksPassingThroughPoints:W,getTrackData:z=>e[z]}})();import vl from"uplot";var Sn=(()=>{function e(){let t=ot.getFTP(),s=[.55,.75,.9,1.05,1.2,1.5].map(d=>d*t),o=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],a=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],p=[],c=0;for(let d=0;dn?e.toFixed(1):Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:We.speed.color,abbr:"spd",icon:We.speed.icon,fmt:e=>(e*3.6).toFixed(1),fmtAxis:e=>(e*3.6).toFixed(0),transform:e=>e,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:We.gradient.color,abbr:"grad",icon:We.gradient.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>e.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:We.power.color,abbr:"pwr",icon:We.power.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:We.hr.color,abbr:"hr",icon:We.hr.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:We.cadence.color,abbr:"cad",icon:We.cadence.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:We.temperature.color,abbr:"temp",icon:We.temperature.icon,fmt:e=>e.toFixed(1),fmtAxis:e=>Math.round(e).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:We.gearRear.color,abbr:"rgr",icon:We.gearRear.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:We.gearFront.color,abbr:"fgr",icon:We.gearFront.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},gears:{label:"Gears",field:"gears",unit:"",color:We.gears.color,abbr:"gr",icon:We.gears.icon,fmt:e=>e.toFixed(2),fmtAxis:e=>e.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:We.battery.color,abbr:"bat",icon:We.battery.icon,fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:e=>Math.round(e).toString(),fmtAxis:e=>Math.round(e).toString(),smoothSigma:5,compute:(e,n)=>{let t=new Array(e.length).fill(null);for(let s=1;s0&&(t[s]=p/c*3600)}}return n(t)}}};var Nt={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function bl(e){if(!e)return"question_mark";let n=e.toLowerCase();return Nt[n]?.icon||"exercise"}var Se=(()=>{let e=[],n=null,t="time",s="speed",o=null,a=null,p=!1,c=!1,d=new Set(["elevation"]),x=new Set,g=new Set(["speed","gradient","vam","temperature"]),T=new Set(["power"]),$="time",M=null,C=[],k=null,f=null,F=!1,v=!1,u=null,w=null,E=null,N=null,G=null,q=null,_=null,W=null,z=null,de=null,y=null,m=null,r=130,J=28,V=20,ee=!0,U=null,Q=null,ke=null,re=null,Fe=null,se=null,me=null;function fe(l,i,h,b){z=l,de=i,y=h,m=b,Q=document.getElementById("charts-container"),Q?.addEventListener("scroll",()=>{E&&G&&N&&wn(E,G,N)}),ke=document.getElementById("chart-empty"),re=document.getElementById("chart-stats-sel"),Fe=document.getElementById("btn-reset-selection"),U=document.getElementById("hist-tooltip"),a=vl.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",ne),Fe?.classList.add("hidden");let A=new Set(["w","a","s","d"]),S=new Set;document.addEventListener("keydown",B=>{if(!e.length||!M||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let P=B.key.toLowerCase();if(!A.has(P))return;B.preventDefault(),S.add(P);let R=e[0].uplot;_||(_=[R.scales.x.min,R.scales.x.max]);let[X,O]=_,Y=(O-X)*.1,ie=.15,L=X,Te=O;if(P==="a")L=X-Y,Te=O-Y;else if(P==="d")L=X+Y,Te=O+Y;else if(P==="w"||P==="s"){let ce=w!==null?w:(X+O)/2,_e=P==="w"?1-ie:1+ie*1.2;L=ce-(ce-X)*_e,Te=ce+(O-ce)*_e}let ae=[e[0].xData[0],e[0].xData[e[0].xData.length-1]];if(Lae[1]){let ce=Te-ae[1];L-=ce,Te-=ce}L=Math.max(ae[0],L),Te=Math.min(ae[1],Te),Te-L>.001&&(_=[L,Te],Pe(L,Te,!0))}),document.addEventListener("keyup",B=>{let P=B.key.toLowerCase();A.has(P)&&S.delete(P)})}function Pe(l,i,h=!1){if(!e.length)return;if(!h){e.forEach(({uplot:R})=>R.setScale("x",{min:l,max:i}));return}let b=q?q[0]:e[0].uplot.scales.x.min,A=q?q[1]:e[0].uplot.scales.x.max;W&&cancelAnimationFrame(W);let S=(R,X,O)=>R+(X-R)*O,B=.25,P=()=>{if(!_)return;let[R,X]=_,O=S(q[0],R,B),D=S(q[1],X,B);e.forEach(({uplot:Y})=>{Y.setScale("x",{min:O,max:D})}),Math.abs(O-R)>1e-4||Math.abs(D-X)>1e-4?W=requestAnimationFrame(P):W=null};W=requestAnimationFrame(P)}function j(l,i=[],h=!1){u=null,k=null,f=null,C=i,x=new Set(Object.entries(Ft).filter(([,b])=>l.points.some(A=>A[b.field]!=null)).map(([b])=>b)),d.size===0&&(d=new Set(["elevation"].filter(b=>x.has(b)))),document.querySelectorAll(".metric-pill").forEach(b=>{let A=b,S=A.dataset.metric,B=x.has(S);A.classList.toggle("active",B&&d.has(S)),A.classList.toggle("disabled",!B)}),M=l,h?ol(l):Ee()}function H(){u=null,k=null,f=null,M=null,Rn(),ke&&(ke.style.display="flex",ke.innerHTML=` +var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(location.search),f={};g.has("track")&&(f.track=g.get("track")),g.has("map")&&(f.map=g.get("map")),g.has("xaxis")&&(f.xaxis=g.get("xaxis")),g.has("tab")&&(f.tab=g.get("tab")),g.has("sel_point")&&(f.sel_point=Number(g.get("sel_point"))),g.has("speed_mode")&&(f.speed_mode=g.get("speed_mode")),g.has("progress")&&(f.progress=g.get("progress"));let A=g.get("metrics");if(A&&(f.metrics=A.split(",").filter(Boolean)),g.has("f_date")&&(f.f_date=g.get("f_date").split(",").map(C=>C||null)),g.has("f_dist")&&(f.f_dist=g.get("f_dist").split(",").map(C=>C?Number(C):null)),g.has("f_dur")&&(f.f_dur=g.get("f_dur").split(",").map(C=>C?Number(C):null)),g.has("f_mets")&&(f.f_mets=g.get("f_mets").split(",")),g.has("f_tags")&&(f.f_tags=g.get("f_tags").split(",")),g.has("q")&&(f.q=g.get("q")),g.has("re")&&(f.re=g.get("re")==="1"),g.has("sort")){let C=g.get("sort"),$=C.startsWith("-"),M=$?C.substring(1):C;f.sort=`${M}-${$?"desc":"asc"}`}if(g.has("map_pos")){let C=g.get("map_pos").split(",").map(Number);C.length===3&&C.every(isFinite)&&(f.map_pos=C)}if(g.has("storage")&&(f.storage=g.get("storage")),g.has("sel")){let C=g.get("sel").split(",").map(Number);C.length===2&&C.every($=>!isNaN($)&&isFinite($))&&(f.sel=C)}return f}function i(){s&&(clearTimeout(s),s=null);let g=new URLSearchParams;if(t.track&&g.set("track",t.track),t.map&&g.set("map",t.map),t.xaxis&&t.xaxis!=="time"&&g.set("xaxis",t.xaxis),t.tab&&t.tab!=="graphs"&&g.set("tab",t.tab),t.storage&&t.storage!=="memory"&&g.set("storage",t.storage),t.sel_point!==void 0&&g.set("sel_point",String(t.sel_point)),t.speed_mode&&g.set("speed_mode",t.speed_mode),t.q&&g.set("q",t.q),t.progress&&g.set("progress",t.progress),t.re&&g.set("re","1"),t.sort){let A=t.sort.split("-"),C=A[0],$=A[1];g.set("sort",($==="desc"?"-":"")+C)}let f=g.toString();if(t.metrics&&(f+=`${f?"&":""}metrics=${t.metrics.join(",")}`),t.f_date&&(f+=`${f?"&":""}f_date=${t.f_date.map(A=>A||"").join(",")}`),t.f_dist&&(f+=`${f?"&":""}f_dist=${t.f_dist.map(A=>A??"").join(",")}`),t.f_dur&&(f+=`${f?"&":""}f_dur=${t.f_dur.map(A=>A??"").join(",")}`),t.f_mets&&(f+=`${f?"&":""}f_mets=${t.f_mets.join(",")}`),t.f_tags&&(f+=`${f?"&":""}f_tags=${t.f_tags.join(",")}`),t.map_pos){let A=`${(+t.map_pos[0]).toFixed(5)},${(+t.map_pos[1]).toFixed(5)},${t.map_pos[2]}`;f+=`${f?"&":""}map_pos=${A}`}if(t.sel){let A=`${+t.sel[0].toFixed(4)},${+t.sel[1].toFixed(4)}`;f+=`${f?"&":""}sel=${A}`}if(f!==n){let A=location.pathname+(f?`?${f}`:"");try{e?(history.pushState(null,"",A),e=!1):history.replaceState(null,"",A)}catch{e=!1}n=f}}t=l();function a(){return{...t}}function c(g,f=!1){f&&(e=!0);for(let[A,C]of Object.entries(g)){let $=A;C==null?delete t[$]:t[$]=C}i()}function d(){t=l()}function w(){s&&(clearTimeout(s),s=null),t={},e=!1,n="";try{history.replaceState(null,"",location.pathname)}catch{}}return{get:a,patch:c,refresh:d,reset:w}})();var ws=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(n){return this.trackStore.set(n.id,n),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(n){return this.trackStore.delete(n),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(n,s){return this.settingStore.set(n,s),Promise.resolve()}async get(n){return Promise.resolve(this.settingStore.get(n)??null)}},zs=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((n,s)=>{let e=indexedDB.open(this.DB_NAME,this.DB_VERSION);e.onupgradeneeded=()=>{let l=e.result;l.objectStoreNames.contains("tracks")||l.createObjectStore("tracks",{keyPath:"id"}),l.objectStoreNames.contains("settings")||l.createObjectStore("settings")},e.onsuccess=()=>{this.db=e.result,n()},e.onerror=()=>s(e.error)})}getStore(n,s){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(n,s).objectStore(n)}async save(n){return new Promise((s,e)=>{let l=this.getStore("tracks","readwrite").put(n);l.onsuccess=()=>s(),l.onerror=()=>e(l.error)})}async getAll(){return new Promise((n,s)=>{let e=this.getStore("tracks","readonly").getAll();e.onsuccess=()=>n(e.result||[]),e.onerror=()=>s(e.error)})}async remove(n){return new Promise((s,e)=>{let l=this.getStore("tracks","readwrite").delete(n);l.onsuccess=()=>s(),l.onerror=()=>e(l.error)})}async clear(){return this.db?new Promise((n,s)=>{let e=this.db.transaction(["tracks","settings"],"readwrite");e.objectStore("tracks").clear(),e.objectStore("settings").clear(),e.oncomplete=()=>n(),e.onerror=()=>s(e.error)}):Promise.resolve()}async set(n,s){return new Promise((e,l)=>{let i=this.getStore("settings","readwrite").put(s,n);i.onsuccess=()=>e(),i.onerror=()=>l(i.error)})}async get(n){return new Promise((s,e)=>{let l=this.getStore("settings","readonly").get(n);l.onsuccess=()=>s(l.result??null),l.onerror=()=>e(l.error)})}},rn=new ws,ce={openDB:async()=>{rn=Gt.get().storage==="indexeddb"?new zs:new ws,await rn.openDB()},save:t=>rn.save(t),getAll:()=>rn.getAll(),remove:t=>rn.remove(t),clear:()=>rn.clear(),set:(t,n)=>rn.set(t,n),get:t=>rn.get(t)};import Il from"fit-file-parser";function en(t,n,s,e){let i=t*Math.PI/180,a=s*Math.PI/180,c=(s-t)*Math.PI/180,d=(e-n)*Math.PI/180,w=Math.sin(c/2)*Math.sin(c/2)+Math.cos(i)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2);return 6371e3*(2*Math.atan2(Math.sqrt(w),Math.sqrt(1-w)))}function wo(t){let n=new Uint32Array([Math.floor(t/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(n.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function To(){return Math.random().toString(36).slice(2,6)}function ze(t){return t<60?`${Math.round(t)}s`:t<3600?`${Math.round(t/60)}m`:`${Math.round(t/3600)}h`}function he(t){let n=Math.floor(t/3600),s=Math.floor(t%3600/60);return n>0?`${n}h ${s}m`:`${s}m ${Math.floor(t%60)}s`}function On(t){if(t==null||!isFinite(t))return"--";let n=Math.floor(t/60),s=Math.round(t%60);return`${n}:${s.toString().padStart(2,"0")}`}function nn(t){let n=new Date(t);return isNaN(n.getTime())?"Unknown date":n.toISOString().split("T")[0]}function So(t){let n=new Date(t);if(isNaN(n.getTime()))return"Unknown";let s=n.toISOString();return`${s.split("T")[0]} ${s.split("T")[1].slice(0,5)}`}function Mo(t){if(t===0)return"0 B";let n=1024,s=["B","KB","MB","GB"],e=Math.floor(Math.log(t)/Math.log(n));return`${parseFloat((t/Math.pow(n,e)).toFixed(2))} ${s[e]}`}function me(t){return String(t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function Ts(t){let n=0;for(let e=0;e=0&&f0?d/w:t[c]}return a}function le(t,n=1){let s=parseInt(t.slice(1,3),16),e=parseInt(t.slice(3,5),16),l=parseInt(t.slice(5,7),16);return`rgba(${s}, ${e}, ${l}, ${n})`}function Ss(t){if(!t.length)return null;let n=t[0].lat,s=t[0].lat,e=t[0].lon,l=t[0].lon;for(let i of t)i.lats&&(s=i.lat),i.lonl&&(l=i.lon);return{minLat:n,maxLat:s,minLon:e,maxLon:l}}var Ne=16384,Hl=new Float64Array(Ne),Fl=new Float64Array(Ne),Dl=new Float64Array(Ne),Bl=new Float64Array(Ne),_l=new Float64Array(Ne),Rl=new Float64Array(Ne),Nl=new Float64Array(Ne);function Ms(t,n){let s=t.length;if(s<=2)return t;let e=s<=Ne?Hl:new Float64Array(s),l=s<=Ne?Fl:new Float64Array(s),i=s<=Ne?Dl:new Float64Array(s),a=s<=Ne?Bl:new Float64Array(s);for(let C=0;C=$){let S=M+m>>1,_=(l[S]-(l[M]+l[m])*.5)*k,W=e[S]-(e[M]+e[m])*.5;d+=Math.sqrt(_*_+W*W)+(a[m]-a[M])*1e-6,M=m}}}let g=[t[0]],f=t[0],A=d<-1e9?1e-9:0;for(let C=1;C=n&&(g.push($),f=$)}return g.push(t[s-1]),g}var Jt=(()=>{function t(x){let v=x.length,u=0;for(let N=0;N0){let G=x[N-1],U=en(G.lat,G.lon,E.lat,E.lon);if(u+=U,E.speed==null&&E.time!=null&&G.time!=null){let j=(E.time-G.time)/1e3;j>0&&j<10&&(E.speed=U/j)}if(E.gradient===void 0&&E.ele!=null&&G.ele!=null){let j=E.ele-G.ele;U>.5?E.gradient=j/U*100:E.gradient=G.gradient||0}}E.dist=u}if(v>2){let N=v<=Ne?_l:new Float64Array(v),E=v<=Ne?Rl:new Float64Array(v),G=v<=Ne?Nl:new Float64Array(v);for(let nt=0;nt=$t){z-=E[it-$t],D-=G[it-$t];let K=z*ht,bt=N[it]-N[it-$t],Pt=1.225*Math.exp(-N[it]*Rt),ut=Math.atan2(bt,(D+1)*.5);j+=K*K*Pt*1e-4+ut*(D*ht)*.01}}let at=j<-1e12?1e-9:0;for(let nt=1;nt0){let Lt=x[Ht-1];if(dt.ele!=null&&Lt.ele!=null){let st=dt.ele-Lt.ele;st>0?u.elevGain+=st:u.elevLoss-=st}(dt.gearFront!=null&&dt.gearFront!==Lt.gearFront||dt.gearRear!=null&&dt.gearRear!==Lt.gearRear)&&K++}dt.power!=null&&(N+=dt.power,E++,dt.power>u.maxPower&&(u.maxPower=dt.power)),dt.hr!=null&&(G+=dt.hr,U++,dt.hr>u.maxHR&&(u.maxHR=dt.hr)),dt.cad!=null&&(j+=dt.cad,Rt++),dt.speed!=null&&(at+=dt.speed,nt++,dt.speed>u.maxSpeed&&(u.maxSpeed=dt.speed)),dt.battery!=null&&($t+=dt.battery,ht++),dt.temp!=null&&(it=!0,z+=dt.temp,D++,(u.minTemp==null||dt.tempu.maxTemp)&&(u.maxTemp=dt.temp)),(dt.gearFront!=null||dt.gearRear!=null)&&(bt=!0)}u.totalDist=x[x.length-1].dist||0,u.avgPower=E?Math.round(N/E):null,u.avgHR=U?Math.round(G/U):null,u.avgCadence=Rt?Math.round(j/Rt):null,u.avgSpeed=nt?at/nt:null,u.avgBattery=ht?Math.round($t/ht):null,u.avgTemp=D?Number((z/D).toFixed(1)):null,u.shifts=bt?K:null;let Pt=x[0].time,ut=x[x.length-1].time;return Pt!=null&&ut!=null&&(u.duration=ut-Pt),U&&(u.sensors.push("Heart Rate"),v&&(u.hrZones=$(x),u.hrCurve=g(x))),Rt&&u.sensors.push("Cadence"),E&&(u.sensors.push("Power"),v&&(u.powerCurve=w(x),u.powerZones=f(x))),it&&u.sensors.push("Temperature"),bt&&u.sensors.push("Shifting"),ht&&u.sensors.push("Battery"),u}function l(x){if(!x||!x.points||!x.stats)return;let v=x.points,u=x.stats;u.avgHR!=null&&!u.hrCurve&&(u.hrZones=$(v),u.hrCurve=g(v)),u.avgPower!=null&&!u.powerCurve&&(u.powerCurve=w(v),u.powerZones=f(v))}function i(x){let v=x.length;if(v<8)return[];let u=[],N=["Q1 Opening Sector","Q2 Mid-Climb Sector","Q3 Valley Tempo","Q4 Finale Sector"];for(let K=0;K<4;K++){let bt=Math.floor(K*v/4),Pt=Math.min(v-1,Math.floor((K+1)*v/4)-1);if(Pt>bt){let ut=x.slice(bt,Pt+1);u.push({id:`q${K+1}`,label:N[K],kind:"quarter",startIdx:bt,endIdx:Pt,stats:e(ut,!0)})}}let E=["Opening Third","Middle Third","Final Third"];for(let K=0;K<3;K++){let bt=Math.floor(K*v/3),Pt=Math.min(v-1,Math.floor((K+1)*v/3)-1);if(Pt>bt){let ut=x.slice(bt,Pt+1);u.push({id:`t${K+1}`,label:E[K],kind:"third",startIdx:bt,endIdx:Pt,stats:e(ut,!1)})}}let G=0,U=1e3,j=1;for(let K=1;K=U||K===v-1){if(K>G+2){let Pt=x.slice(G,K+1);u.push({id:`km-${j}`,label:`Km ${j}`,kind:"km",startIdx:G,endIdx:K,stats:e(Pt,!1)}),j++}G=K,U+=1e3}let Rt=30,at=!1,nt=0,$t=1,ht=!1,z=0,D=1,it=s*1.15;for(let K=Rt;K=1.8&&!at)at=!0,nt=K-Rt;else if((ut<.8||K===v-1)&&at&&(at=!1,K-nt>=45&&$t<=6)){let dt=x.slice(nt,K+1);u.push({id:`climb-${$t}`,label:`Climb Segment ${$t}`,kind:"climb",startIdx:nt,endIdx:K,stats:e(dt,!0)}),$t++}let Ht=x[K].power??0;if(Ht>=it&&!ht)ht=!0,z=K;else if((Ht=15&&D<=6)){let dt=x.slice(z,K+1);u.push({id:`sprint-${D}`,label:`Sprint Interval ${D}`,kind:"sprint",startIdx:z,endIdx:K,stats:e(dt,!0)}),D++}}return u}function a(x){let v=[];for(let u=0;uu)continue;let Rt=0,at=0,nt=u-j;for(let $t=0;$t<=nt;$t++){let ht=N[$t+j]-N[$t];ht>Rt&&(Rt=ht,at=$t)}E[j]={val:Math.round(Rt/j),idx:at},G=!0}return G?E:null}function w(x){let v=x.length,u=new Array(v),N=!1;for(let U=0;UN*s);for(let N=1;N10)continue;let j=E.power;jN===0)?null:v}function A(x){s=x}function C(){return s}function $(x){let v=[0,0,0,0,0];for(let u=1;u10)continue;let U=N.hr;Uu===0)?null:v}function M(x){n=x}function m(){return[...n]}function k(x,v,u){let N=x.indexOf(v);if(N===-1)return null;let E=N+v.length,G=x.indexOf(u,E);if(G===-1)return null;let U=x.slice(E,G).trim();return U!==""?U:null}function P(x,v){let u=x.indexOf(v);if(u===-1)return null;let N=u+v.length,E=x.indexOf('"',N);return E===-1?null:x.slice(N,E)}let h=-1,b=0;function p(x,v,u){for(;vv&&x.charCodeAt(u-1)<=32;)u--;if(v>=u)return null;let N=!1,E=x.charCodeAt(v);E===45?(N=!0,v++):E===43&&v++;let G=0,U=0;for(let j=v;j=48&&Rt<=57)G=G*10+(Rt-48),U++;else break}return U===0?null:N?-G:G}function S(x,v,u){for(;vv&&x.charCodeAt(u-1)<=32;)u--;if(v>=u)return null;let N=!1,E=x.charCodeAt(v);E===45?(N=!0,v++):E===43&&v++;let G=0,U=0,j=1,Rt=!1,at=0;for(let $t=v;$t=48&&ht<=57)at++,Rt?(U=U*10+(ht-48),j*=10):G=G*10+(ht-48);else if(ht===46&&!Rt)Rt=!0;else{let z=parseFloat(x.slice(v-(N?1:0),u));return Number.isFinite(z)?z:null}}if(at===0)return null;let nt=G+U/j;return N?-nt:nt}function _(x,v,u){for(;vv&&x.charCodeAt(u-1)<=32;)u--;let N=u-v;if(N>=20&&x.charCodeAt(v+10)===84&&x.charCodeAt(u-1)===90){let G=(x.charCodeAt(v)-48)*1e3+(x.charCodeAt(v+1)-48)*100+(x.charCodeAt(v+2)-48)*10+(x.charCodeAt(v+3)-48),U=(x.charCodeAt(v+5)-48)*10+(x.charCodeAt(v+6)-48),j=(x.charCodeAt(v+8)-48)*10+(x.charCodeAt(v+9)-48),Rt=G<<9|U<<5|j;Rt!==h&&(h=Rt,b=Date.UTC(G,U-1,j));let at=(x.charCodeAt(v+11)-48)*10+(x.charCodeAt(v+12)-48),nt=(x.charCodeAt(v+14)-48)*10+(x.charCodeAt(v+15)-48),$t=(x.charCodeAt(v+17)-48)*10+(x.charCodeAt(v+18)-48),ht=0;return x.charCodeAt(v+19)===46&&N>=24&&(ht=(x.charCodeAt(v+20)-48)*100+(x.charCodeAt(v+21)-48)*10+(x.charCodeAt(v+22)-48)),b+at*36e5+nt*6e4+$t*1e3+ht}let E=new Date(x.slice(v,u)).getTime();return Number.isFinite(E)?E:null}function W(x,v,u,N){let E=x.indexOf(N,v);if(E===-1||E>=u)return 0;let G=E+N.length,U=x.indexOf('"',G);return U===-1||U>=u?0:S(x,G,U)??0}function O(x,v){let u=v??new TextDecoder().decode(x),N=u.indexOf(""),U=(G!==-1?k(E.slice(G),"",""):null)||k(E,"","")||"Unnamed Track",j=E.indexOf(">",E.indexOf("",z+6);if(D===-1)break;let it=u.indexOf("",D+1);if(it===-1)break;nt=it+8;let K=W(u,z+6,D+1,'lat="'),bt=W(u,z+6,D+1,'lon="'),Pt=null,ut=null,Ht=null,dt=null,Lt=null,st=null,gt=null,At=null,zt=null,V=null,R=null,Dt=null,It=D+1;for(;It=it)break;let vt=u.indexOf(">",Et+1);if(vt===-1||vt>=it)break;let yt=u.charCodeAt(Et+1);if(yt===47){It=vt+1;continue}let _t=vt-Et-1;if(yt===103&&_t===26&&Ht!==null&&dt!==null&&st!==null)break;let qt=u.indexOf("<",vt+1);if(qt===-1||qt>it)break;if(u.charCodeAt(qt+1)===47){let Yt=vt+1,ee=qt;_t===3?yt===101?Pt=S(u,Yt,ee):yt===99&&dt===null&&(dt=p(u,Yt,ee)):_t===2?yt===104&&Ht===null&&(Ht=p(u,Yt,ee)):_t===4?yt===116?u.charCodeAt(Et+2)===105?ut=_(u,Yt,ee):st===null&&(st=S(u,Yt,ee)):yt===84&&st===null&&(st=S(u,Yt,ee)):_t===5?(yt===112||yt===80||yt===87)&&Lt===null?Lt=S(u,Yt,ee):(yt===115||yt===83)&>===null?gt=S(u,Yt,ee):yt===97&&st===null&&(st=S(u,Yt,ee)):_t===7?(yt===98||yt===66)&&Dt===null?Dt=p(u,Yt,ee):yt===67&&dt===null&&(dt=p(u,Yt,ee)):_t===8?(yt===103||yt===71)&&zt===null&&(zt=p(u,Yt,ee)):_t===9?yt===103?u.charCodeAt(Et+8)===104&&Ht===null?Ht=p(u,Yt,ee):At===null&&(At=p(u,Yt,ee)):yt===71&&At===null&&(At=p(u,Yt,ee)):_t===10?(yt===103&&dt===null||yt===82&&dt===null)&&(dt=p(u,Yt,ee)):_t===12?yt===103&&u.charCodeAt(Et+8)===97&&st===null?st=S(u,Yt,ee):yt===80&&Lt===null?Lt=S(u,Yt,ee):yt===72&&Ht===null&&(Ht=p(u,Yt,ee)):_t===13?(yt===103||yt===71)&&R===null&&(R=p(u,Yt,ee)):_t===14?(yt===103||yt===71)&&V===null?V=p(u,Yt,ee):yt===65&&st===null&&(st=S(u,Yt,ee)):_t===11&&yt===84&&st===null&&(st=S(u,Yt,ee));let xe=qt+2+_t;if(u.charCodeAt(xe)===62)It=xe+1;else{let De=u.indexOf(">",qt+2);It=De!==-1?De+1:qt+2}if(Dt!==null&&Ht!==null&&dt!==null&&st!==null)break}else It=qt}let Wt=null;V!=null&&R!=null&&R!==0?Wt=V/R:At!=null&&zt!=null&&zt!==0&&(Wt=At/zt),at.push({lat:K,lon:bt,ele:Pt,time:ut,hr:Ht,cad:dt,power:Lt,speed:gt,temp:st,gearFront:At,gearRear:zt,gearFrontTooth:V,gearRearTooth:R,battery:Dt,gears:Wt})}if(!at.length)throw new Error("No track points found in GPX");let $t=t(at),ht=e($t);return{name:U,device:Rt,format:"gpx",points:$t,stats:ht}}function Y(x,v){let u=v??new TextDecoder().decode(x),N=u.indexOf(""),E=N!==-1?u.slice(0,N):u,G=k(E,"","")||"Unnamed TCX",U=k(E,"",""),j=U?k(U,"",""):null,Rt=[],at=N!==-1?N:0;for(;at",at);if(ht===-1)break;let z=u.indexOf("",ht+12);if(z===-1)break;at=z+13;let D=null,it=null,K=null,bt=null,Pt=null,ut=null,Ht=null,dt=null,Lt=null,st=null,gt=null,At=null,zt=null,V=null,R=ht+12;for(;R=z)break;let Wt=u.indexOf(">",It+1);if(Wt===-1||Wt>=z)break;let Et=u.charCodeAt(It+1);if(Et===47){R=Wt+1;continue}let vt=Wt-It-1,yt=u.indexOf("<",Wt+1);if(yt===-1||yt>z)break;if(u.charCodeAt(yt+1)===47){let _t=Wt+1,qt=yt;vt===4?Et===84?u.charCodeAt(It+2)===105?bt=_(u,_t,qt):Lt===null&&(Lt=S(u,_t,qt)):Et===116&&Lt===null&&(Lt=S(u,_t,qt)):vt===5?Et===86&&Pt===null?Pt=p(u,_t,qt):(Et===87||Et===80||Et===112)&&Ht===null?Ht=S(u,_t,qt):(Et===83||Et===115)&&dt===null?dt=S(u,_t,qt):Et===97&&Lt===null&&(Lt=S(u,_t,qt)):vt===7?Et===67&&ut===null?ut=p(u,_t,qt):(Et===66||Et===98)&&V===null&&(V=p(u,_t,qt)):vt===8?(Et===71||Et===103)&>===null&&(gt=p(u,_t,qt)):vt===9?(Et===71||Et===103)&&st===null&&(st=p(u,_t,qt)):vt===10?Et===82&&ut===null&&(ut=p(u,_t,qt)):vt===11?Et===84&&Lt===null&&(Lt=S(u,_t,qt)):vt===13?(Et===71||Et===103)&&zt===null&&(zt=p(u,_t,qt)):vt===14?Et===65?u.charCodeAt(It+2)===108?K=S(u,_t,qt):Lt===null&&(Lt=S(u,_t,qt)):(Et===71||Et===103)&&At===null&&(At=p(u,_t,qt)):vt===15?Et===76&&(D=S(u,_t,qt)):vt===16?Et===76&&(it=S(u,_t,qt)):vt===2&&Et===104&&Pt===null?Pt=p(u,_t,qt):vt===3&&Et===99&&ut===null?ut=p(u,_t,qt):vt===12&&(Et===72&&Pt===null?Pt=p(u,_t,qt):Et===80&&Ht===null&&(Ht=S(u,_t,qt)));let Yt=yt+2+vt;if(u.charCodeAt(Yt)===62)R=Yt+1;else{let ee=u.indexOf(">",yt+2);R=ee!==-1?ee+1:yt+2}if(V!==null&&Pt!==null&&ut!==null&&Lt!==null)break}else R=yt}if(D==null||it==null)continue;let Dt=null;At!=null&&zt!=null&&zt!==0?Dt=At/zt:st!=null&>!=null&>!==0&&(Dt=st/gt),Rt.push({lat:D,lon:it,ele:K,time:bt,hr:Pt,cad:ut,power:Ht,speed:dt,temp:Lt,gearFront:st,gearRear:gt,gearFrontTooth:At,gearRearTooth:zt,battery:V,gears:Dt})}let nt=t(Rt),$t=e(nt);return{name:G,device:j,format:"tcx",points:nt,stats:$t}}function Z(x){if(x.byteLength<14)return null;let v=new DataView(x),u=v.getUint8(0);if(u<12||u+2>x.byteLength||v.getUint8(8)!==46||v.getUint8(9)!==70||v.getUint8(10)!==73||v.getUint8(11)!==84)return null;let N=v.getUint32(4,!0),E=Math.min(x.byteLength,u+N),G=631065600,U=180/Math.pow(2,31),j=new Array(16),Rt=[],at=[],nt=[],$t=[],ht=[],z=u;for(;zE)return null;z++;let bt=v.getUint8(z++)===0,Pt=v.getUint16(z,bt);z+=2;let ut=v.getUint8(z++);if(z+ut*3>E)return null;let Ht=new Array(ut),dt=0;for(let Lt=0;LtE)return null;let bt=K.littleEndian,Pt=K.globalMsgNum;if(Pt===20&&K.fields.length===10&&K.recordSize===25&&K.fields[0].num===253&&K.fields[1].num===0){let dt=v.getUint32(z,bt),Lt=v.getInt32(z+4,bt),st=v.getInt32(z+8,bt),gt=v.getUint16(z+12,bt),At=v.getUint8(z+14),zt=v.getUint8(z+15),V=v.getUint32(z+16,bt),R=v.getUint16(z+20,bt),Dt=v.getUint16(z+22,bt),It=v.getInt8(z+24);nt.push({timestamp:(dt+G)*1e3,position_lat:Lt*U,position_long:st*U,altitude:gt/5-500,heart_rate:At,cadence:zt,distance:V/100,speed:R/1e3*3.6,power:Dt,temperature:It}),z+=25;continue}let ut={},Ht=z;for(let dt=0;dt{let N=(U,j)=>{if(U){u(U);return}try{let Rt=j.sessions?.[0]?.start_time?`Fit Activity ${new Date(j.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",at=null,nt=[],$t=null,ht=null;j.sports?.[0]?($t=j.sports[0].sport,ht=j.sports[0].sub_sport):j.sessions?.[0]&&($t=j.sessions[0].sport,ht=j.sessions[0].sub_sport);let z=V=>V.product_name||V.garmin_product||V.product||V.device_type||V.manufacturer||null;if(j.file_ids?.[0]){let V=j.file_ids[0];at=z(V),nt.push({name:V.product_name||V.garmin_product||V.product,manufacturer:V.manufacturer,serial:V.serial_number?String(V.serial_number):void 0,version:V.software_version?String(V.software_version):void 0,type:"main"})}j.device_infos&&j.device_infos.forEach(V=>{if(V.device_index==="creator"||V.device_index===0){let Dt=z(V);(V.product_name||V.garmin_product||!at)&&(at=Dt),nt.length>0&&nt[0].type==="main"&&((V.product_name||V.garmin_product||!nt[0].name)&&(nt[0].name=V.product_name||V.garmin_product||V.product),nt[0].manufacturer||(nt[0].manufacturer=V.manufacturer),!nt[0].serial&&V.serial_number&&(nt[0].serial=String(V.serial_number)),!nt[0].version&&V.software_version&&(nt[0].version=String(V.software_version)),!nt[0].hardwareVersion&&V.hardware_version&&(nt[0].hardwareVersion=String(V.hardware_version)));return}nt.push({name:V.product_name||V.garmin_product||V.product||V.device_type||"Sensor",manufacturer:V.manufacturer,serial:V.serial_number?String(V.serial_number):void 0,version:V.software_version?String(V.software_version):void 0,hardwareVersion:V.hardware_version?String(V.hardware_version):void 0,type:V.device_type||"sensor",batteryStatus:V.battery_status,batteryVoltage:V.battery_voltage,batteryLevel:V.battery_level,sourceType:V.source_type!=null?String(V.source_type):void 0})}),j.sensor_settings&&j.sensor_settings.forEach(V=>{let R=V.name||V.product||V.sensor_type;if(!R)return;let Dt=V.ant_id?String(V.ant_id):void 0,It=nt.find(Wt=>Dt&&Wt.serial===Dt||Wt.name===R&&Wt.manufacturer===V.manufacturer);It?(It.name||(It.name=R),It.manufacturer||(It.manufacturer=V.manufacturer),It.type||(It.type=V.sensor_type),It.sourceType||(It.sourceType=V.connection_type!=null?String(V.connection_type):void 0)):nt.push({name:R,manufacturer:V.manufacturer,serial:Dt,type:V.sensor_type||"sensor",sourceType:V.connection_type!=null?String(V.connection_type):void 0})});let D=[];j.device_statuses&&(j.device_statuses.forEach((V,R)=>{V.timestamp&&V.battery_level!=null&&D.push({time:typeof V.timestamp=="number"?V.timestamp:new Date(V.timestamp).getTime(),level:V.battery_level,idx:R})}),D.sort((V,R)=>V.time-R.time||V.idx-R.idx));let it=[];j.events&&(j.events.forEach((V,R)=>{let Dt=V.front_gear_num??V.front_gear??null,It=V.rear_gear_num??V.rear_gear??null,Wt=V.front_gear_num_tooth??null,Et=V.rear_gear_num_tooth??null;if(V.event==="rear_gear_change"||V.event==="front_gear_change"){let vt=V.data;if(vt!=null){let yt=vt>>24&255,_t=vt>>16&255,qt=vt>>8&255,Yt=vt&255;_t!==0&&(Dt=_t),yt!==0&&(Wt=yt),Yt!==0&&(It=Yt),qt!==0&&(Et=qt)}}V.timestamp&&(Dt!=null||It!=null||Wt!=null||Et!=null)&&it.push({time:typeof V.timestamp=="number"?V.timestamp:new Date(V.timestamp).getTime(),front:Dt,rear:It,frontTooth:Wt,rearTooth:Et,idx:R})}),it.sort((V,R)=>V.time-R.time||V.idx-R.idx));let K=j.records||[],bt=null,Pt=0,ut=null,Ht=null,dt=null,Lt=null,st=0,gt=[];for(let V=0;V name, Placemark > name");E&&(N=E.textContent?.trim()||N);let G=u.querySelectorAll("coordinates");if(!G.length)throw new Error("No coordinates found in KML");let U=[];if(G.forEach(at=>{(at.textContent?.trim().split(/\s+/)||[]).forEach($t=>{let ht=$t.split(",");if(ht.length<2)return;let z=parseFloat(ht[0]),D=parseFloat(ht[1]),it=ht.length>2?parseFloat(ht[2]):null;isNaN(D)||isNaN(z)||U.push({lat:D,lon:z,ele:it!=null&&isNaN(it)?null:it,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!U.length)throw new Error("No valid coordinates in KML");let j=t(U),Rt=e(j);return{name:N,format:"kml",points:j,stats:Rt}}async function rt(x){let v=x.name.split(".").pop()?.toLowerCase(),u=x._buf??await x.arrayBuffer(),N=x._text,E;switch(v){case"gpx":E=O(u,N);break;case"tcx":E=Y(u,N);break;case"fit":E=await lt(u);break;case"kml":E=Ft(u);break;default:throw new Error(`Unsupported format: .${v}`)}return E&&(E.fileName=x.name,E.fileSize=x.size,E.points&&E.stats&&(l(E),E.stats.sections=i(E.points))),E}return{parseFile:rt,computeStats:e,ensureCurvesAndZones:l,analyzeTrackSections:i,findOverlaps:a,calculatePowerCurve:w,calculateHRCurve:g,calculatePowerZones:f,calculateHRZones:$,enrichPoints:t,setHRZones:M,getHRZones:m,setFTP:A,getFTP:C}})();var Bt=(()=>{let t={},n=null;function s(Z,lt,Ft,rt,x){}function e(Z){}function l(Z){t[Z.id]=Z}function i(Z){Z.forEach(lt=>{t[lt.id]=lt})}function a(Z){delete t[Z]}function c(){t={}}function d(){t={}}function w(Z,lt){}function g(Z,lt){}function f(){}function A(Z){}function C(Z,lt){}function $(){}function M(Z,lt,Ft,rt,x,v){}function m(){}function k(Z,lt){}function P(Z){}function h(Z,lt,Ft,rt){}function b(){}function p(){}function S(){return[0,0,0]}function _(Z,lt,Ft){}function W(Z,lt,Ft){}function O(Z){}function Y(Z,lt){return Object.keys(t)}return{init:s,getMap:()=>null,setCustomClickHandler:Z=>{n=Z},switchBasemap:e,addTrack:l,addTracks:i,removeTrack:a,clearTracks:c,removeAllTracks:d,setTrackVisible:w,setSelectedTrack:g,fitAll:f,fitTrack:A,showCursorAt:C,hideCursor:$,highlightSegment:M,clearHighlight:m,setTrackHover:k,ensureVisible:P,centerOn:h,closePopup:b,invalidateSize:p,getPosition:S,setPosition:_,colorTrackByMetric:W,clearMetricColor:O,findTracksPassingThroughPoints:Y,getTrackData:Z=>t[Z]}})();import ko from"uplot";var $n=(()=>{function t(){let s=Jt.getFTP(),e=[.55,.75,.9,1.05,1.2,1.5].map(d=>d*s),l=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],i=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],a=[],c=0;for(let d=0;dn?t.toFixed(1):Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:Nt.speed.color,abbr:"spd",icon:Nt.speed.icon,fmt:t=>(t*3.6).toFixed(1),fmtAxis:t=>(t*3.6).toFixed(0),transform:t=>t,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:Nt.gradient.color,abbr:"grad",icon:Nt.gradient.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>t.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:Nt.power.color,abbr:"pwr",icon:Nt.power.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:Nt.hr.color,abbr:"hr",icon:Nt.hr.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:Nt.cadence.color,abbr:"cad",icon:Nt.cadence.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:Nt.temperature.color,abbr:"temp",icon:Nt.temperature.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>Math.round(t).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:Nt.gearRear.color,abbr:"rgr",icon:Nt.gearRear.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:Nt.gearFront.color,abbr:"fgr",icon:Nt.gearFront.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gears:{label:"Gears",field:"gears",unit:"",color:Nt.gears.color,abbr:"gr",icon:Nt.gears.icon,fmt:t=>t.toFixed(2),fmtAxis:t=>t.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:Nt.battery.color,abbr:"bat",icon:Nt.battery.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString(),smoothSigma:5,compute:(t,n)=>{let s=new Array(t.length).fill(null);for(let e=1;e0&&(s[e]=a/c*3600)}}return n(s)}}};var Ye={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function Eo(t){if(!t)return"question_mark";let n=t.toLowerCase();return Ye[n]?.icon||"exercise"}var ft=(()=>{let t=[],n=null,s="time",e="speed",l=null,i=null,a=!1,c=!1,d=new Set(["elevation"]),w=new Set,g=new Set(["speed","gradient","vam","temperature"]),f=new Set(["power"]),A="time",C=null,$=[],M=null,m=null,k=!1,P=!1,h=null,b=null,p=null,S=null,_=null,W=null,O=null,Y=null,Z=null,lt=null,Ft=null,rt=null,x=130,v=28,u=20,N=!0,E=null,G=null,U=null,j=null,Rt=null,at=null,nt=null;function $t(o,r,y,T){Z=o,lt=r,Ft=y,rt=T,G=document.getElementById("charts-container"),G?.addEventListener("scroll",()=>{p&&_&&S&&so(p,_,S)}),U=document.getElementById("chart-empty"),j=document.getElementById("chart-stats-sel"),Rt=document.getElementById("btn-reset-selection"),E=document.getElementById("hist-tooltip"),i=ko.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",R),Rt?.classList.add("hidden");let F=new Set(["w","a","s","d"]),L=new Set;document.addEventListener("keydown",B=>{if(!t.length||!C||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let H=B.key.toLowerCase();if(!F.has(H))return;B.preventDefault(),L.add(H);let q=t[0].uplot;O||(O=[q.scales.x.min,q.scales.x.max]);let[J,X]=O,et=(X-J)*.1,tt=.15,I=J,wt=X;if(H==="a")I=J-et,wt=X-et;else if(H==="d")I=J+et,wt=X+et;else if(H==="w"||H==="s"){let ct=b!==null?b:(J+X)/2,Ct=H==="w"?1-tt:1+tt*1.2;I=ct-(ct-J)*Ct,wt=ct+(X-ct)*Ct}let St=[t[0].xData[0],t[0].xData[t[0].xData.length-1]];if(ISt[1]){let ct=wt-St[1];I-=ct,wt-=ct}I=Math.max(St[0],I),wt=Math.min(St[1],wt),wt-I>.001&&(O=[I,wt],ht(I,wt,!0))}),document.addEventListener("keyup",B=>{let H=B.key.toLowerCase();F.has(H)&&L.delete(H)})}function ht(o,r,y=!1){if(!t.length)return;if(!y){t.forEach(({uplot:q})=>q.setScale("x",{min:o,max:r}));return}let T=W?W[0]:t[0].uplot.scales.x.min,F=W?W[1]:t[0].uplot.scales.x.max;Y&&cancelAnimationFrame(Y);let L=(q,J,X)=>q+(J-q)*X,B=.25,H=()=>{if(!O)return;let[q,J]=O,X=L(W[0],q,B),Q=L(W[1],J,B);t.forEach(({uplot:et})=>{et.setScale("x",{min:X,max:Q})}),Math.abs(X-q)>1e-4||Math.abs(Q-J)>1e-4?Y=requestAnimationFrame(H):Y=null};Y=requestAnimationFrame(H)}function z(o,r=[],y=!1){h=null,M=null,m=null,$=r,w=new Set(Object.entries(qe).filter(([,T])=>o.points.some(F=>F[T.field]!=null)).map(([T])=>T)),d.size===0&&(d=new Set(["elevation"].filter(T=>w.has(T)))),document.querySelectorAll(".metric-pill").forEach(T=>{let F=T,L=F.dataset.metric,B=w.has(L);F.classList.toggle("active",B&&d.has(L)),F.classList.toggle("disabled",!B)}),C=o,y?po(o):vt()}function D(){h=null,M=null,m=null,C=null,Rn(),U&&(U.style.display="flex",U.innerHTML=` no_sim
Select a track to view analysis
- `);let l=document.getElementById("chart-stats");l&&l.classList.add("hidden"),Z(),se=null,me&&me(null)}function oe(){W!==null&&(cancelAnimationFrame(W),W=null),d=new Set(["elevation"]),x=new Set,g=new Set(["speed","gradient","vam","temperature"]),T=new Set(["power"]),$="time",C=[],q=null,_=null,w=null,E=null,N=null,G=null,ee=!0,H(),document.querySelectorAll("#metric-pills .metric-pill").forEach(h=>{let b=h;b.classList.toggle("active",d.has(b.dataset.metric)),b.classList.remove("disabled","overflow-hidden")});let l=document.getElementById("pill-overflow");l&&l.classList.add("hidden");let i=document.getElementById("chart-toolbar");i&&i.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(h=>{h.classList.toggle("active",h.dataset.axis==="time")})}function ge(l){d.has(l)?d.delete(l):d.add(l),M&&Ee(!0)}function K(l){d=new Set(l),M&&Ee(!0),document.querySelectorAll(".metric-pill").forEach(i=>{let h=i;h.classList.toggle("active",d.has(h.dataset.metric))})}function Ie(l){if($===l||!M){$=l;return}let i=M.points,h=i.find(S=>S.time!=null)?.time||0,b=S=>{if(S===null)return null;let B=0;if($==="distance"){let P=S*1e3;B=i.findIndex(R=>(R.dist||0)>=P)}else{let P=h+S*1e3;B=i.findIndex(R=>(R.time||0)>=P)}return B===-1&&(B=i.length-1),l==="distance"?(i[B].dist||0)/1e3:((i[B].time||h)-h)/1e3};k!==null&&(k=b(k)),f!==null&&(f=b(f));let A=null;if(e.length){let S=e[0].uplot,B=b(S.scales.x.min),P=b(S.scales.x.max);B!==null&&P!==null&&(A=[B,P])}$=l,Ee(!0),A&&(p=!0,e.forEach(({uplot:S})=>{S.batch(()=>S.setScale("x",{min:A[0],max:A[1]}))}),p=!1)}function he(){ee=!ee,e.forEach(({histCol:l})=>l.classList.toggle("visible",ee)),xe()}function He(l){me=l}function Ce(l){se===l||l===null?(se=null,Re(),me&&me(null)):(se=l,Re(),le()),M&&Ee(!0)}function Re(){document.querySelectorAll(".map-color-btn").forEach(l=>{let i=l;i.classList.toggle("active",i.dataset.metric===se)})}function le(){if(!me||!se||!M)return;let l=e.find(h=>h.metricKey===se);if(!l)return;let i=ye(se,l.yData);me({pts:M.points,colors:i})}function ye(l,i){let h=i.filter(D=>D!=null&&isFinite(D));if(!h.length)return i.map(()=>"#888896");let b=Math.min(...h),A=Math.max(...h),S=M?.sport,B=S?Nt[S.toLowerCase()]:null,P=B?.defaultPreset||"speed",X=Ye.get().speed_mode||P,O=B?.paceUnit||"km";return i.map(D=>{if(D==null||!isFinite(D))return"#888896";if(l==="gradient")return es(D);if(l==="speed"){if(X==="pace"){let ie=(O==="km"?1e3:100)/D;return sl(ie)}return sl(D)}let Y=A===b?.5:Math.max(0,Math.min(1,(D-b)/(A-b)));return Y<=.25?Dt("#4575b4","#91bfdb",Y/.25):Y<=.5?Dt("#91bfdb","#fee090",(Y-.25)/.25):Y<=.75?Dt("#fee090","#fc8d59",(Y-.5)/.25):Dt("#fc8d59","#d73027",(Y-.75)/.25)})}function I(){ne()}function ne(){k=null,f=null,u=null,m&&m(null),e.forEach(l=>{l.pinnedHistY=null}),be(),At(),p=!0,e.forEach(({uplot:l,xData:i})=>{l.batch(()=>l.setScale("x",{min:i[0],max:i[i.length-1]})),l._strasse?.updateHeaderStats(i[0],i[i.length-1])}),p=!1,de&&de(null,null,$)}function Ne(l){if(!re)return;let i=(h,b)=>{let A=document.querySelector(`#${h} .stat-value`);A&&(A.textContent=b)};i("sel-distance",l.totalDist!=null?`${(l.totalDist/1e3).toFixed(1)} km`:"\u2014"),i("sel-duration",l.duration!=null?ht(Math.floor(l.duration/1e3)):"\u2014"),i("sel-elevation",l.elevGain!=null?`${Math.round(l.elevGain)} m`:"\u2014"),i("sel-avg-speed",l.avgSpeed!=null?`${(l.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),i("sel-avg-power",l.avgPower!=null?`${l.avgPower} W`:"\u2014"),i("sel-avg-hr",l.avgHR!=null?`${l.avgHR} bpm`:"\u2014"),i("sel-avg-temp",l.avgTemp!=null?`${l.avgTemp.toFixed(1)} \xB0C`:"\u2014"),re.classList.remove("hidden"),Fe&&Fe.classList.remove("hidden")}function Z(){re&&re.classList.add("hidden"),Fe&&Fe.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(l=>{let i=document.querySelector(`#${l} .stat-value`);i&&(i.textContent="--")})}function Be(l,i,h=!1){if(!M)return;let b=M.points,A=b.find(X=>X.time!=null)?.time||0,S=((b[b.length-1]?.time||0)-A)/1e3;l>1e12&&(l=(l-A)/1e3),i>1e12&&(i=(i-A)/1e3),l=Math.max(0,Math.min(l,S)),i=Math.max(0,Math.min(i,S));let B=X=>{if($==="time")return X;let O=A+X*1e3,D=b.findIndex(Y=>(Y.time||0)>=O);return D===-1&&(D=b.length-1),(b[D].dist||0)/1e3},P=B(l),R=B(i);k=P,f=R,q=[P,R],!h&&(p=!0,e.forEach(({uplot:X})=>{X.batch(()=>X.setScale("x",{min:P,max:R}))}),p=!1,we(),At())}function xe(){if(!e.length||!Q)return;let l=Math.round(Math.max(100,Q.getBoundingClientRect().width-J-(ee?r+V:0))),i=!1;e.forEach(({uplot:h,histCanvas:b,histData:A})=>{l!==h.width&&(h.setSize({width:l,height:h.height}),i=!0,ee&&b&&A&&It(b,A,h.height))}),i&&be()}function Ee(l=!1){let i=null,h=0;if(l&&Q&&(h=Q.scrollTop),l&&q)i=[q[0],q[1]];else if(l&&e.length){let ae=e[0].uplot;i=[ae.scales.x.min,ae.scales.x.max]}if(!M){Rn(l);return}let b=M.points;if(!b.length){Rn(l);return}let A=M?.sport,S=A?Nt[A.toLowerCase()]:null,B=S?.defaultPreset||"speed",R=Ye.get().speed_mode||B,X=S?.paceUnit||"km",O=[...d].filter(ae=>b.some(ce=>ce[Ft[ae].field]!=null));if(!O.length){Rn(l),ke&&(ke.style.display="flex",ke.innerHTML=` + `);let o=document.getElementById("chart-stats");o&&o.classList.add("hidden"),It(),at=null,nt&&nt(null)}function it(){Y!==null&&(cancelAnimationFrame(Y),Y=null),d=new Set(["elevation"]),w=new Set,g=new Set(["speed","gradient","vam","temperature"]),f=new Set(["power"]),A="time",$=[],W=null,O=null,b=null,p=null,S=null,_=null,N=!0,D(),document.querySelectorAll("#metric-pills .metric-pill").forEach(y=>{let T=y;T.classList.toggle("active",d.has(T.dataset.metric)),T.classList.remove("disabled","overflow-hidden")});let o=document.getElementById("pill-overflow");o&&o.classList.add("hidden");let r=document.getElementById("chart-toolbar");r&&r.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(y=>{y.classList.toggle("active",y.dataset.axis==="time")})}function K(o){d.has(o)?d.delete(o):d.add(o),C&&vt(!0)}function bt(o,r,y=!1){let T=g.has(o);r&&!T?(g.add(o),C&&!y&&vt(!0)):!r&&T&&(g.delete(o),C&&!y&&vt(!0))}function Pt(o,r){let y=f.has(o);r&&!y?(f.add(o),C&&vt(!0)):!r&&y&&(f.delete(o),C&&vt(!0))}function ut(o){d=new Set(o),C&&vt(!0),document.querySelectorAll(".metric-pill").forEach(r=>{let y=r;y.classList.toggle("active",d.has(y.dataset.metric))})}function Ht(o){if(A===o||!C){A=o;return}let r=C.points,y=r.find(L=>L.time!=null)?.time||0,T=L=>{if(L===null)return null;let B=0;if(A==="distance"){let H=L*1e3;B=r.findIndex(q=>(q.dist||0)>=H)}else{let H=y+L*1e3;B=r.findIndex(q=>(q.time||0)>=H)}return B===-1&&(B=r.length-1),o==="distance"?(r[B].dist||0)/1e3:((r[B].time||y)-y)/1e3};M!==null&&(M=T(M)),m!==null&&(m=T(m));let F=null;if(t.length){let L=t[0].uplot,B=T(L.scales.x.min),H=T(L.scales.x.max);B!==null&&H!==null&&(F=[B,H])}A=o,vt(!0),F&&(a=!0,t.forEach(({uplot:L})=>{L.batch(()=>L.setScale("x",{min:F[0],max:F[1]}))}),a=!1)}function dt(){N=!N,t.forEach(({histCol:o})=>o.classList.toggle("visible",N)),Et()}function Lt(o){nt=o}function st(o,r=!1){at===o||o===null?(at=null,gt(),nt&&nt(null)):(at=o,gt(),At()),C&&!r&&vt(!0)}function gt(){document.querySelectorAll(".map-color-btn").forEach(o=>{let r=o;r.classList.toggle("active",r.dataset.metric===at)})}function At(){if(!nt||!at||!C)return;let o=t.find(y=>y.metricKey===at);if(!o)return;let r=zt(at,o.yData);nt({pts:C.points,colors:r})}function zt(o,r){let y=r.filter(Q=>Q!=null&&isFinite(Q));if(!y.length)return r.map(()=>"#888896");let T=Math.min(...y),F=Math.max(...y),L=C?.sport,B=L?Ye[L.toLowerCase()]:null,H=B?.defaultPreset||"speed",J=Gt.get().speed_mode||H,X=B?.paceUnit||"km";return r.map(Q=>{if(Q==null||!isFinite(Q))return"#888896";if(o==="gradient")return is(Q);if(o==="speed"){if(J==="pace"){let tt=(X==="km"?1e3:100)/Q;return uo(tt)}return uo(Q)}let et=F===T?.5:Math.max(0,Math.min(1,(Q-T)/(F-T)));return et<=.25?Ve("#4575b4","#91bfdb",et/.25):et<=.5?Ve("#91bfdb","#fee090",(et-.25)/.25):et<=.75?Ve("#fee090","#fc8d59",(et-.5)/.25):Ve("#fc8d59","#d73027",(et-.75)/.25)})}function V(){R()}function R(){M=null,m=null,h=null,rt&&rt(null),t.forEach(o=>{o.pinnedHistY=null}),_t(),De(),a=!0,t.forEach(({uplot:o,xData:r})=>{o.batch(()=>o.setScale("x",{min:r[0],max:r[r.length-1]})),o._strasse?.updateHeaderStats(r[0],r[r.length-1])}),a=!1,lt&<(null,null,A)}function Dt(o){if(!j)return;let r=(y,T)=>{let F=document.querySelector(`#${y} .stat-value`);F&&(F.textContent=T)};r("sel-distance",o.totalDist!=null?`${(o.totalDist/1e3).toFixed(1)} km`:"\u2014"),r("sel-duration",o.duration!=null?he(Math.floor(o.duration/1e3)):"\u2014"),r("sel-elevation",o.elevGain!=null?`${Math.round(o.elevGain)} m`:"\u2014"),r("sel-avg-speed",o.avgSpeed!=null?`${(o.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),r("sel-avg-power",o.avgPower!=null?`${o.avgPower} W`:"\u2014"),r("sel-avg-hr",o.avgHR!=null?`${o.avgHR} bpm`:"\u2014"),r("sel-avg-temp",o.avgTemp!=null?`${o.avgTemp.toFixed(1)} \xB0C`:"\u2014"),j.classList.remove("hidden"),Rt&&Rt.classList.remove("hidden")}function It(){j&&j.classList.add("hidden"),Rt&&Rt.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(o=>{let r=document.querySelector(`#${o} .stat-value`);r&&(r.textContent="--")})}function Wt(o,r,y=!1){if(!C)return;let T=C.points,F=T.find(J=>J.time!=null)?.time||0,L=((T[T.length-1]?.time||0)-F)/1e3;o>1e12&&(o=(o-F)/1e3),r>1e12&&(r=(r-F)/1e3),o=Math.max(0,Math.min(o,L)),r=Math.max(0,Math.min(r,L));let B=J=>{if(A==="time")return J;let X=F+J*1e3,Q=T.findIndex(et=>(et.time||0)>=X);return Q===-1&&(Q=T.length-1),(T[Q].dist||0)/1e3},H=B(o),q=B(r);M=H,m=q,W=[H,q],!y&&(a=!0,t.forEach(({uplot:J})=>{J.batch(()=>J.setScale("x",{min:H,max:q}))}),a=!1,qt(),De())}function Et(){if(!t.length||!G)return;let o=Math.round(Math.max(100,G.getBoundingClientRect().width-v-(N?x+u:0))),r=!1;t.forEach(({uplot:y,histCanvas:T,histData:F})=>{o!==y.width&&(y.setSize({width:o,height:y.height}),r=!0,N&&T&&F&&Le(T,F,y.height))}),r&&_t()}function vt(o=!1){let r=null,y=0;if(o&&G&&(y=G.scrollTop),o&&W)r=[W[0],W[1]];else if(o&&t.length){let St=t[0].uplot;r=[St.scales.x.min,St.scales.x.max]}if(!C){Rn(o);return}let T=C.points;if(!T.length){Rn(o);return}let F=C?.sport,L=F?Ye[F.toLowerCase()]:null,B=L?.defaultPreset||"speed",q=Gt.get().speed_mode||B,J=L?.paceUnit||"km",X=[...d].filter(St=>T.some(ct=>ct[qe[St].field]!=null));if(!X.length){Rn(o),U&&(U.style.display="flex",U.innerHTML=` no_sim
No data for selected metrics
- `);return}ke&&(ke.style.display="none");let D=Q?Q.getBoundingClientRect().width:800,Y=Math.round(Math.max(100,D-J-(ee?r+V:0))),ie=l&&n===M&&t===$&&s===R&&o===se&&e.length>0,L;if(ie)L=e[0].xData;else if($==="distance")L=b.map(ae=>(ae.dist||0)/1e3);else{let ae=b.find(_e=>_e.time!=null)?.time||0,ce=0;L=b.map(_e=>(_e.time!=null&&(ce=(_e.time-ae)/1e3),ce))}let Te=new Map;if(ie){U&&(U.style.display="none");let ae=new Set(O);for(let ce of e){let _e=g.has(ce.metricKey),ue=T.has(ce.metricKey);ae.has(ce.metricKey)&&ce.smoothed===_e&&ce.incZero===ue&&ce.w===Y?Te.set(ce.metricKey,ce):(a.unsub(ce.uplot),ce.uplot.destroy(),ce.row.remove())}e=[]}else Rn(l);if(Q){let ae=new Array(O.length).fill(null),ce=null;for(let _e=O.length-1;_e>=0;_e--){ae[_e]=ce;let ue=Te.get(O[_e]);ue&&(ce=ue.row)}O.forEach((_e,ue)=>{let ve=Te.get(_e);if(ve){e.push(ve);let pe=ve.uplot,Je=pe._strasse,Ge=p;p=!0,pe.batch(()=>{i&&(pe.scales.x.min!==i[0]||pe.scales.x.max!==i[1])?pe.setScale("x",{min:i[0],max:i[1]}):(Je?.updateHeaderStats(pe.scales.x.min,pe.scales.x.max,pe),pe.redraw(!1))}),p=Ge;let Qe=null;if(u!=null&&ve.xData[u]!=null&&ve.yData[u]!=null&&(dt(ve.histData),ve.histData.min!=null&&ve.histData.max!=null)){let rt=ve.histData.max-ve.histData.min||1;Qe=Math.min(ve.histData.BINS-1,Math.floor((ve.yData[u]-ve.histData.min)/rt*ve.histData.BINS)),ve.hoveredHistY=ve.yData[u]}It(ve.histCanvas,ve.histData,130,Qe);return}let Ae=Ft[_e],Ue=Ae.transform,Ze=Ae.fmt,st=Ae.fmtAxis,nt=Ae.unit,it=Ae.label;_e==="speed"&&R==="pace"&&(it="Pace",nt=`min/${X}`,Ze=pe=>On(pe),st=pe=>On(pe),Ue=pe=>pe==null||pe<.1?null:(X==="km"?1e3:100)/pe,Ae={...Ae,label:it,unit:nt,fmt:Ze,fmtAxis:st,transform:Ue});let lt=Ae.compute?Ae.compute(b,ll):ll(b.map(pe=>{let Je=pe[Ae.field];return Je!=null&&Ue?Ue(Je):Je}));g.has(_e)&&(lt=En(lt,Ae.smoothSigma||2)),Me(_e,Ae,L,lt,Y,b,i,ae[ue])})}n=M,t=$,s=R,o=se,ol(M),k!=null&&f!=null&&we(),Re(),se&&le(),l&&Q&&h>0&&(Q.scrollTop=h)}function Me(l,i,h,b,A,S,B=null,P=null){let R=M?.sport,O=(R?Nt[R.toLowerCase()]:null)?.defaultPreset||"speed",Y=Ye.get().speed_mode||O,ie=l==="elevation"?fo(S,20):null,L=document.createElement("div");L.className="chart-row",L.dataset.metric=l,L.style.setProperty("--chart-color",i.color);let Te=document.createElement("div");Te.className=`chart-row-header${ee?" with-histogram":""}`;let ae=document.createElement("div");ae.className="chart-row-label-group",ae.innerHTML=` - ${i.icon} - ${i.label} - `;let ce=document.createElement("button");ce.className=`icon-btn mini smooth-btn${g.has(l)?" active":""}`,ce.title="Toggle data smoothing",ce.innerHTML=`${g.has(l)?"blur_on":"blur_off"}`,ce.addEventListener("click",te=>{te.stopPropagation(),g.has(l)?g.delete(l):g.add(l),Ee(!0)});let _e=document.createElement("button");_e.className=`map-color-btn icon-btn${se===l?" active":""}`,_e.dataset.metric=l,_e.title="Color map track by this metric",_e.innerHTML='colorize',_e.addEventListener("click",()=>Ce(l));let ue=null;if(l==="cadence"||l==="power"||l==="speed"){ue=document.createElement("button");let te=T.has(l);ue.className=`icon-btn mini${te?" active":""}`,ue.title=te?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",ue.innerHTML=`${te?"exposure_zero":"mobile_off"}`,ue.addEventListener("click",$e=>{$e.stopPropagation(),T.has(l)?T.delete(l):T.add(l),Ee(!0)})}let ve=document.createElement("div");ve.className="chart-stats-total";let Ae=document.createElement("div");Ae.className="chart-stats-selection";let Ue=document.createElement("div");Ue.className="chart-row-stats-container",Ue.append(ve,Ae);let Ze=document.createElement("div");Ze.className="chart-row-actions",Ze.append(ce,_e);let st=document.createElement("div");if(st.className="chart-row-right-actions",l==="speed"){let te=document.createElement("div");te.className="seg-ctrl",te.innerHTML=` - - - `,te.addEventListener("click",$e=>{let Ke=$e.target.closest(".seg-btn");if(!Ke)return;let et=Ke.dataset.mode;if(et==="speed"||et==="pace"){let Ve=et===O;Ye.patch({speed_mode:Ve?null:et}),Ee(!0)}}),st.append(te)}ue&&st.append(ue),Te.append(ae,Ze,Ue,st);let nt=document.createElement("div");nt.className="chart-row-body";let it=document.createElement("div");it.style.position="relative",nt.appendChild(it);let lt=document.createElement("div");lt.className="fixed-x-label fixed-x-min";let pe=document.createElement("div");pe.className="fixed-x-label fixed-x-max",it.append(lt,pe);let Je=document.createElement("div");Je.className=`hist-col${ee?" visible":""}`;let Ge=document.createElement("canvas");Ge.className="hist-canvas",Je.appendChild(Ge),nt.appendChild(Je),L.append(Te,nt);let Qe=$==="distance";function rt(te,$e){if(te==null)return"";if(Qe){let Ke=$e<1?3:$e<5?2:$e<20?1:0;return`${te.toFixed(Ke)} km`}else{let Ke=Math.abs(te),et=Math.floor(Ke/3600),Ve=Math.floor(Ke%3600/60),xt=Math.round(Ke%60),gt=et>0?`${et}:`:"",Rt=et>0?String(Ve).padStart(2,"0"):String(Ve),Ct=String(xt).padStart(2,"0");return`${te<0?"-":""}${gt}${Rt}:${Ct}`}}let ut=T.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",mt=1/0,Xe=-1/0,ct=0,vt=0,St=1/0,jt=-1/0,Et=0,Kt=0;for(let te=0;teXe&&(Xe=$e),ct+=$e,vt++,($e!==0||ut)&&($ejt&&(jt=$e),Et+=$e,Kt++))}vt===0&&(mt=0,Xe=100);let Ls=vt?{min:mt,max:Xe,avg:ct/vt}:null,ss=Kt?{min:St,max:jt,avg:Et/Kt}:null,rl=Math.abs(Xe-mt)*.1||1,bo=[mt-rl,Xe+rl],cl=!1;function Ps(te,$e,Ke){let et=T.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",Ve=$e-te;lt.textContent=rt(te,Ve),pe.textContent=rt($e,Ve);let xt=(gt,Rt,Ct=!1)=>{let Ht=Ct&&et===ut?ss:Js(h,b,gt,Rt,et);if(!Ht)return"";let tn=` - align_flex_end${i.fmt(Ht.min,!0)} ${i.unit} - align_center${i.fmt(Ht.avg,!0)} ${i.unit} - align_flex_start${i.fmt(Ht.max,!0)} ${i.unit} - `;if(l==="elevation"){let Ut=ao(S,gt,Rt);tn+=` - trending_up+${Math.round(Ut.gain)} m - trending_down-${Math.round(Ut.loss)} m - `}return tn};cl||(cl=!0,ve.innerHTML=`all_inclusive${xt(h[0],h[h.length-1],!0)}`,ve.querySelector(".all-chip")?.addEventListener("click",gt=>{gt.stopPropagation(),ne()})),k!==null&&f!==null?(Ae.innerHTML=xt(k,f,!1),Ae.style.display="flex",Ae.style.setProperty("--sel-color",i.color)):Ae.style.display="none"}let vo=!1,yo={width:A,height:130,padding:[4,0,0,0],cursor:{sync:{key:a.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:l==="elevation"?(te,$e)=>es(ie?ie[te.cursor.idx]:null):i.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(te,$e,Ke)=>[$e,Ke],min:B?B[0]:void 0,max:B?B[1]:void 0},y:{range:()=>bo,dir:l==="speed"&&Y==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(te,$e,Ke,et)=>{let Ve=et-Ke,gt=(te.bbox.width>0?te.bbox.width:te.width)/80,Rt=Ve/gt,Ct;Qe?Ct=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:Ct=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let Ht=Ct[Ct.length-1];for(let Vt=0;Vt=Rt){Ht=Ct[Vt];break}let tn=[],Ut=Math.ceil(Ke/Ht)*Ht,ms=Ht<1?2:0;for(;Ut<=et;){let Vt=te.valToPos(Ut,"x",!0);Vt>=te.bbox.left+80&&Vt<=te.bbox.left+te.bbox.width-80&&tn.push(Number(Ut.toFixed(ms))),Ut+=Ht}return tn},values:(te,$e)=>{let Ke=(te.scales.x?.max??1)-(te.scales.x?.min??0);return $e.map(et=>{if(et==null)return"";let Ve=te.valToPos(et,"x",!0);return Vete.bbox.left+te.bbox.width-80?null:rt(et,Ke)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(te,$e)=>$e.map(Ke=>Ke!=null?i.fmtAxis(Ke):"")}],series:[{},{label:i.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[te=>{let $e=te.bbox.top+te.bbox.height+5;lt.style.top=`${$e}px`,lt.style.left=`${te.bbox.left}px`,pe.style.top=`${$e}px`,pe.style.left=`${te.bbox.left+te.bbox.width}px`,pe.style.transform="translateX(-100%)"},te=>{l==="gears"?al(te,h,b,i.color,1.5,l,null,S):l==="elevation"?ro(te,h,b,ie):l==="gradient"?co(te,h,b):se===l?ho(te,h,b,S,l):al(te,h,b,i.color,1.5,l,null,S)},te=>{let $e=e.find(et=>et.uplot===te);if(!$e)return;let Ke=te._strasse;u!=null?uo(te,h,b,i.color,i,S,l):(Ke&&Ke.pinYVal&&(Ke.pinYVal.style.display="none"),$e.pinnedHistY!=null&&mo(te,h,b,$e.pinnedHistY,i.color,i))},te=>{let $e=te.cursor.idx,Ke=u!=null,et=$e!=null&&te.cursor.left>=0;if(et&&u==null){let Ve=te.valToPos(b[$e],"y",!0);Math.abs(te.cursor.top-Ve)>100&&(et=!1)}if(et&&$e!==u&&tl(te,S,$e,tt(i.color,.4),1),k!=null&&f!=null){let Ve=te.ctx,xt=window.devicePixelRatio||1,gt=te.bbox,Rt=te.valToPos(k,"x",!0),Ct=te.valToPos(f,"x",!0);Ve.save(),Ve.beginPath(),Ve.lineWidth=3*xt,Ve.strokeStyle=i.color,Ve.moveTo(Rt,gt.top+gt.height),Ve.lineTo(Ct,gt.top+gt.height),Ve.stroke();let Ht=Math.abs(f-k),tn=$==="distance"?`${Ht.toFixed(2)} km`:ht(Ht),Ut=9*xt,ms=`bold ${Ut}px system-ui, sans-serif`;Ve.font!==ms&&(Ve.font=ms);let Vt=Ve.measureText(tn).width,ul=Math.max(gt.left,Rt),ml=Math.min(gt.left+gt.width,Ct);if(ml-ul>Vt+14*xt){let wo=5*xt,To=2*xt,ps=Vt+wo*2,fs=Ut+To*2,Is=(ul+ml)/2-ps/2,Hs=gt.top+gt.height-fs/2;Ve.beginPath(),Ve.roundRect?Ve.roundRect(Is,Hs,ps,fs,3*xt):Ve.rect(Is,Hs,ps,fs),Ve.fillStyle=i.color,Ve.fill(),Ve.fillStyle="#000",Ve.textAlign="center",Ve.textBaseline="middle",Ve.fillText(tn,Is+ps/2,Hs+fs/2)}Ve.restore()}Ke&&nl(te,S,u,i.color,!0,.7),et&&$e!==u&&nl(te,S,$e,i.color,!0,1)}],setCursor:[te=>{if(p)return;let $e=te.cursor.idx;te.redraw(!1),te.cursor.left>=0?w=te.posToVal(te.cursor.left,"x"):w=null;let Ke=te._strasse,et=$e!=null&&b[$e]!=null;if(et&&u==null){let Ve=te.valToPos(b[$e],"y",!0);Math.abs(te.cursor.top-Ve)>100&&(et=!1)}if(Ke&&(et?Qs(te,Ke.curYVal,$e,h,b,S,i,l):Ke.curYVal.style.display="none"),c||($e!=null&&S[$e]?z&&(u!=null||et)?z(S[$e]):z&&!et&&z(null):$e===null&&z&&z(null)),$e!=null&&b[$e]!=null){let{min:Ve,max:xt}=yt;if(Ve!=null&&xt!=null){let gt=xt-Ve||1,Rt=Math.min(yt.BINS-1,Math.floor((b[$e]-Ve)/gt*yt.BINS));en.hoveredHistY!==b[$e]&&(en.hoveredHistY=b[$e],It(Ge,yt,130,Rt))}}else en.hoveredHistY!==null&&(en.hoveredHistY=null,It(Ge,yt,130))}],setScale:[(te,$e)=>{if($e!=="x"||vo)return;let{min:Ke,max:et}=te.scales.x;q=[Ke,et],Ps(Ke,et,te),!p&&(v||(_=null),p=!0,e.forEach(({uplot:Ve})=>{Ve!==te&&Ve.batch(()=>Ve.setScale("x",{min:Ke,max:et}))}),p=!1,be(),At(),de&&k!==null&&de(k,f,$))}],setSelect:[te=>{if(v)return;_=null;let{left:$e,width:Ke}=te.select;if(Ke>0){let et=te.posToVal($e,"x"),Ve=te.posToVal($e+Ke,"x");k=et,f=Ve,Ps(te.scales.x.min,te.scales.x.max,te),be(),At(),de&&de(k,f,$),te.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},As=document.createElement("div");As.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let ls=document.createElement("div");ls.className="sel-fill",ls.style.display="none";let os=document.createElement("div");os.className="sel-line sel-line-anchor",os.style.display="none";let is=document.createElement("div");is.className="sel-line-label sel-line-label-anchor",is.style.display="none";let zn=document.createElement("div");zn.className="sel-handle sel-handle-anchor",zn.style.display="none";let qn=document.createElement("div");qn.className="sel-graph-marker",qn.innerHTML=`play_circle`,qn.style.display="none";let as=document.createElement("div");as.className="sel-line sel-line-end",as.style.display="none";let rs=document.createElement("div");rs.className="sel-line-label sel-line-label-end",rs.style.display="none";let Un=document.createElement("div");Un.className="sel-handle sel-handle-end",Un.style.display="none";let Vn=document.createElement("div");Vn.className="sel-graph-marker",Vn.innerHTML=`stop_circle`,Vn.style.display="none";let cs=document.createElement("div");cs.className="cur-y-val",cs.style.cssText=`color:${i.color};display:none`;let ds=document.createElement("div");ds.className="cur-y-val pin",ds.style.cssText=`color:${i.color};display:none`,As.append(ls,os,is,zn,qn,as,rs,Un,Vn,cs,ds);let yt={yData:b,xData:h,def:i,BINS:24,min:vt?mt:void 0,max:vt?Xe:void 0,fullStats:ss,fullStatsAll:Ls},en={uplot:null,row:L,xData:h,yData:b,def:i,metricKey:l,statsTotalEl:ve,statsSelEl:Ae,histCol:Je,histCanvas:Ge,histData:yt,hoveredHistY:null,pinnedHistY:null,smoothed:g.has(l),incZero:T.has(l),w:A};yt.plot=en;let xo=p;p=!0;let Zt=new vl(yo,[h,b],(te,$e)=>{en.uplot=te,e.push(en),it.appendChild(te.root),te.over.appendChild(As),te._strasse={selFill:ls,anchorLine:os,anchorLabel:is,anchorHandle:zn,anchorMarker:qn,endLine:as,endLabel:rs,endHandle:Un,endMarker:Vn,curYVal:cs,pinYVal:ds,updateHeaderStats:Ps},te.batch(()=>{$e()})});p=xo,je(zn,Zt,h,!0),je(Un,Zt,h,!1);let us=null;Zt.over.addEventListener("mousedown",te=>{if(te.button!==0)return;F=!1;let $e=Zt.over.getBoundingClientRect();us=te.clientX-$e.left}),Zt.over.addEventListener("mousemove",te=>{if(us!==null){let $e=Zt.over.getBoundingClientRect();Math.abs(te.clientX-$e.left-us)>5&&(F=!0)}}),Zt.over.addEventListener("mouseup",()=>{us=null}),Zt.over.addEventListener("click",()=>{if(F)return;let te=Zt.cursor.idx;te!=null&&S[te]&&(u=te,e.forEach(({uplot:$e})=>$e.redraw(!1)),y&&y(S[te],te),m&&m(te))}),L.addEventListener("dblclick",ne);let dl=null;if(u!=null&&h[u]!=null&&b[u]!=null&&(dt(yt),yt.min!=null&&yt.max!=null)){let te=yt.max-yt.min||1;dl=Math.min(yt.BINS-1,Math.floor((b[u]-yt.min)/te*yt.BINS)),en.hoveredHistY=b[u]}It(Ge,yt,130,dl),Qt(Ge,yt),Q&&(P?Q.insertBefore(L,P):Q.appendChild(L))}function be(){we(),e.forEach(({uplot:l})=>l.batch(()=>l.redraw(!1)))}function we(){e.forEach(({uplot:l,def:i})=>{let h=l._strasse;if(!h)return;let{selFill:b,anchorLine:A,anchorLabel:S,anchorHandle:B,anchorMarker:P,endLine:R,endLabel:X,endHandle:O,endMarker:D}=h;if(k==null||f==null){[b,A,S,B,P,R,X,O,D].forEach(Ze=>{Ze.style.display="none"});return}let Y=l.valToPos(k,"x"),ie=l.valToPos(f,"x"),L=window.devicePixelRatio||1,Te=l.bbox,ae=Te.width/L,ce=Te.height/L,_e=(Te.top+Te.height)/L,ue=Y>=0&&Y<=ae,ve=ie>=0&&ie<=ae,Ae=Math.max(0,Y),Ue=Math.min(ae,ie);if(Ue>Ae?(b.style.left=`${Ae}px`,b.style.width=`${Ue-Ae}px`,b.style.top="0",b.style.height=`${ce}px`,b.style.backgroundColor=tt(i.color,.07),b.style.display=""):b.style.display="none",ue){A.style.left=`${Y}px`,A.style.height=`${ce}px`,A.style.borderLeftColor=i.color,A.style.display="";let Ze=qe(k);S.textContent=Ze;let st=Ze.length*7+10;S.style.left=Y+st+4Ze.style.display="none");if(ve){R.style.left=`${ie}px`,R.style.height=`${ce}px`,R.style.borderLeftColor=i.color,R.style.display="";let Ze=qe(f);X.textContent=Ze;let st=Ze.length*7+10;X.style.left=ie-st-3>0?`${ie-st-3}px`:`${ie+3}px`,X.style.display="",O.style.left=`${ie}px`,O.style.backgroundColor=i.color,O.style.display="",D.style.left=`${ie}px`,D.style.top=`${_e}px`;let nt=D.querySelector(".material-symbols-rounded");nt&&(nt.style.color=i.color),D.style.display=""}else[R,X,O,D].forEach(Ze=>Ze.style.display="none")})}function qe(l){return $==="distance"?`${l.toFixed(2)} km`:ht(l)}function je(l,i,h,b){l.style.pointerEvents="auto",l.addEventListener("mousedown",A=>{A.stopPropagation(),A.preventDefault();let S=A.clientX,B=b?k:f,P=i.over.offsetWidth,R=i.scales.x.min,X=i.scales.x.max,O=P/(X-R),D=[h[0],h[h.length-1]];document.body.style.cursor="ew-resize",F=!0;function Y(L){let Te=L.clientX-S,ae=(B||0)+Te/O;ae=Math.max(D[0],Math.min(D[1],ae)),b?k=Math.min(ae,(f||D[1])-.001):f=Math.max(ae,(k||D[0])+.001),e.forEach(ce=>ce.uplot._strasse?.updateHeaderStats(ce.uplot.scales.x.min,ce.uplot.scales.x.max)),be(),At(),de&&de(k,f,$)}function ie(){document.body.style.cursor="",F=!1,document.removeEventListener("mousemove",Y),document.removeEventListener("mouseup",ie)}document.addEventListener("mousemove",Y),document.addEventListener("mouseup",ie)})}function dt(l){let{yData:i,xData:h,BINS:b}=l;if(l._lastYData===i&&l.bins)return;l._lastYData=i;let A=l.min,S=l.max;if(A==null||S==null){let D=1/0,Y=-1/0,ie=0;for(let L=0;LY&&(Y=Te),ie++)}if(!ie)return;A=D,S=Y,l.min=A,l.max=S}let B=new Array(b).fill(0),P=new Array(b).fill(0),R=S-A||1,X=l.plot?.metricKey??Object.keys(Ft).find(D=>Ft[D]===l.def),O=!X||T.has(X)||X!=="power"&&X!=="cadence"&&X!=="speed";for(let D=0;D0&&h[D-1]!=null?h[D-1]:h[D],Te=D{It(l,i,h.height)})}function It(l,i,h,b=null){let{def:A,BINS:S}=i;dt(i);let{bins:B,min:P,max:R}=i;if(!B||P==null||R==null)return;let X=k!=null&&f!=null;if(X&&(i._lastSelRange?.[0]!==k||i._lastSelRange?.[1]!==f)){i._lastSelRange=[k,f];let pe=new Array(S).fill(0),Je=new Array(S).fill(0),{yData:Ge,xData:Qe}=i,rt=R-P||1,ut=i.plot?.metricKey??Object.keys(Ft).find(Xe=>Ft[Xe]===i.def),mt=!ut||T.has(ut)||ut!=="power"&&ut!=="cadence"&&ut!=="speed";for(let Xe=0;Xef)continue;let St=Math.min(S-1,Math.floor((ct-P)/rt*S));pe[St]++;let jt=Xe>0&&Qe[Xe-1]!=null?Qe[Xe-1]:Qe[Xe],Et=XeA.fmtAxis(pe),ce="9px system-ui, sans-serif";L.font!==ce&&(L.font=ce);let ue={t:4,r:0,b:30,l:Math.ceil(Math.max(L.measureText(`${ae(R)} ${A.unit}`).width,L.measureText(`${ae(P)} ${A.unit}`).width))+6};i.padL=ue.l;let ve=Y-ue.l-ue.r,Ae=ie-ue.t-ue.b,Ue=pe=>ue.t+(S-1-pe)*(Ae/S),Ze=Ae/S-1,st=X?.15:.6;L.fillStyle=tt(A.color,st);for(let pe=0;pepe+Je,0);if(nt>0){let pe=[{x:ue.l,y:ue.t+Ae}],Je=0;for(let Ge=0;GeGe+Qe+2&&pe0){let pe=0;for(let ct=0;ct{let A=Yt(l,i,b);if(A!=null&&h){let{min:S,max:B,BINS:P}=i,R=B-S||1;h.pinnedHistY=S+(A+.5)*(R/P),e.forEach(({uplot:X})=>X.redraw(!1))}}),l.addEventListener("mousemove",b=>{E=b,wn(b,l,i)}),l.addEventListener("mouseenter",()=>{G=l,N=i}),l.addEventListener("mouseleave",()=>{G===l&&(G=null,N=null),U&&(U.style.display="none");let b=document.getElementById("hist-line");b&&(b.style.display="none"),h&&(h.hoveredHistY=null,It(l,i,l.height/(window.devicePixelRatio||1)))})}function Yt(l,i,h){let{bins:b,BINS:A}=i;if(!b)return null;let S=l.getBoundingClientRect(),B=h.clientY-S.top,P={t:4,b:30},R=S.height-P.t-P.b,X=Math.floor((B-P.t)/R*A),O=A-1-X;return X<0||X>=A?null:O}function wn(l,i,h){if(!U)return;let{bins:b,binAccum:A,min:S,max:B,BINS:P,def:R,plot:X}=h;if(!b||!A||S==null||B==null)return;let O=document.getElementById("hist-line"),D=Yt(i,h,l);if(D==null||!b[D]){U.style.display="none",O&&(O.style.display="none"),X&&(X.hoveredHistY=null,It(i,h,i.height/(window.devicePixelRatio||1)));return}if(X){let Qe=B-S||1;X.hoveredHistY=S+(D+.5)*(Qe/P),It(i,h,i.height/(window.devicePixelRatio||1),D)}let Y=b[D],ie=b.reduce((Qe,rt)=>Qe+rt,0),L=Y/ie*100,Te=B-S||1,ae=S+D*(Te/P),ce=S+(D+1)*(Te/P),_e=`${R.fmt(ae,!0)} \u2013 ${R.fmt(ce,!0)} ${R.unit}`,ue="",ve=(ae+ce)/2,Ae=Object.keys(Ft).find(Qe=>Ft[Qe]===R),Ue=[];if(Ae==="power"?Ue=Sn.getPowerZones():Ae==="hr"&&(Ue=Sn.getHRZones()),Ue.length>0){let Qe=Ue.findIndex(ut=>ve>=ut.min&&ve=Ue[Ue.length-1].min?Ue[Ue.length-1]:null;if(rt){let ut=Qe!==-1?Qe:Ue.length-1;ue=` -
- Z${ut+1} + `);return}U&&(U.style.display="none");let Q=G?G.getBoundingClientRect().width:800,et=Math.round(Math.max(100,Q-v-(N?x+u:0))),tt=o&&n===C&&s===A&&e===q&&l===at&&t.length>0,I;if(tt)I=t[0].xData;else if(A==="distance")I=T.map(St=>(St.dist||0)/1e3);else{let St=T.find(Ct=>Ct.time!=null)?.time||0,ct=0;I=T.map(Ct=>(Ct.time!=null&&(ct=(Ct.time-St)/1e3),ct))}let wt=new Map;if(tt){E&&(E.style.display="none");let St=new Set(X);for(let ct of t){let Ct=g.has(ct.metricKey),pt=f.has(ct.metricKey);St.has(ct.metricKey)&&ct.smoothed===Ct&&ct.incZero===pt&&ct.w===et?wt.set(ct.metricKey,ct):(i.unsub(ct.uplot),ct.uplot.destroy(),ct.row.remove())}t=[]}else Rn(o);if(G){let St=new Array(X.length).fill(null),ct=null;for(let Ct=X.length-1;Ct>=0;Ct--){St[Ct]=ct;let pt=wt.get(X[Ct]);pt&&(ct=pt.row)}X.forEach((Ct,pt)=>{let xt=wt.get(Ct);if(xt){t.push(xt);let mt=xt.uplot,Kt=mt._strasse,Xt=a;a=!0,mt.batch(()=>{r&&(mt.scales.x.min!==r[0]||mt.scales.x.max!==r[1])?mt.setScale("x",{min:r[0],max:r[1]}):(Kt?.updateHeaderStats(mt.scales.x.min,mt.scales.x.max,mt),mt.redraw(!1))}),a=Xt;let te=null;if(h!=null&&xt.xData[h]!=null&&xt.yData[h]!=null&&(xe(xt.histData),xt.histData.min!=null&&xt.histData.max!=null)){let de=xt.histData.max-xt.histData.min||1;te=Math.min(xt.histData.BINS-1,Math.floor((xt.yData[h]-xt.histData.min)/de*xt.histData.BINS)),xt.hoveredHistY=xt.yData[h]}Le(xt.histCanvas,xt.histData,130,te);return}let kt=qe[Ct],Ot=kt.transform,Vt=kt.fmt,ne=kt.fmtAxis,ie=kt.unit,re=kt.label;Ct==="speed"&&q==="pace"&&(re="Pace",ie=`min/${J}`,Vt=mt=>On(mt),ne=mt=>On(mt),Ot=mt=>mt==null||mt<.1?null:(J==="km"?1e3:100)/mt,kt={...kt,label:re,unit:ie,fmt:Vt,fmtAxis:ne,transform:Ot});let ae=kt.compute?kt.compute(T,mo):mo(T.map(mt=>{let Kt=mt[kt.field];return Kt!=null&&Ot?Ot(Kt):Kt}));g.has(Ct)&&(ae=Cn(ae,kt.smoothSigma||2)),yt(Ct,kt,I,ae,et,T,r,St[pt])})}n=C,s=A,e=q,l=at,po(C),M!=null&&m!=null&&qt(),gt(),at&&At(),o&&G&&y>0&&(G.scrollTop=y)}function yt(o,r,y,T,F,L,B=null,H=null){let q=C?.sport,X=(q?Ye[q.toLowerCase()]:null)?.defaultPreset||"speed",et=Gt.get().speed_mode||X,tt=o==="elevation"?Sl(L,20):null,I=document.createElement("div");I.className="chart-row",I.dataset.metric=o,I.style.setProperty("--chart-color",r.color);let wt=document.createElement("div");wt.className=`chart-row-header${N?" with-histogram":""}`;let St=document.createElement("div");St.className="chart-row-label-group",St.innerHTML=` + ${r.icon} + ${r.label} + `;let ct=document.createElement("button");ct.className=`icon-btn mini smooth-btn${g.has(o)?" active":""}`,ct.title="Toggle data smoothing",ct.innerHTML=`${g.has(o)?"blur_on":"blur_off"}`,ct.addEventListener("click",ot=>{ot.stopPropagation(),g.has(o)?g.delete(o):g.add(o),vt(!0)});let Ct=document.createElement("button");Ct.className=`map-color-btn icon-btn${at===o?" active":""}`,Ct.dataset.metric=o,Ct.title="Color map track by this metric",Ct.innerHTML='colorize',Ct.addEventListener("click",()=>st(o));let pt=null;if(o==="cadence"||o==="power"||o==="speed"){pt=document.createElement("button");let ot=f.has(o);pt.className=`icon-btn mini${ot?" active":""}`,pt.title=ot?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",pt.innerHTML=`${ot?"exposure_zero":"mobile_off"}`,pt.addEventListener("click",Mt=>{Mt.stopPropagation(),f.has(o)?f.delete(o):f.add(o),vt(!0)})}let xt=document.createElement("div");xt.className="chart-stats-total";let kt=document.createElement("div");kt.className="chart-stats-selection";let Ot=document.createElement("div");Ot.className="chart-row-stats-container",Ot.append(xt,kt);let Vt=document.createElement("div");Vt.className="chart-row-actions",Vt.append(ct,Ct);let ne=document.createElement("div");if(ne.className="chart-row-right-actions",o==="speed"){let ot=document.createElement("div");ot.className="seg-ctrl",ot.innerHTML=` + + + `,ot.addEventListener("click",Mt=>{let se=Mt.target.closest(".seg-btn");if(!se)return;let oe=se.dataset.mode;if(oe==="speed"||oe==="pace"){let jt=oe===X;Gt.patch({speed_mode:jt?null:oe}),vt(!0)}}),ne.append(ot)}pt&&ne.append(pt),wt.append(St,Vt,Ot,ne);let ie=document.createElement("div");ie.className="chart-row-body";let re=document.createElement("div");re.style.position="relative",ie.appendChild(re);let ae=document.createElement("div");ae.className="fixed-x-label fixed-x-min";let mt=document.createElement("div");mt.className="fixed-x-label fixed-x-max",re.append(ae,mt);let Kt=document.createElement("div");Kt.className=`hist-col${N?" visible":""}`;let Xt=document.createElement("canvas");Xt.className="hist-canvas",Kt.appendChild(Xt),ie.appendChild(Kt),I.append(wt,ie);let te=A==="distance";function de(ot,Mt){if(ot==null)return"";if(te){let se=Mt<1?3:Mt<5?2:Mt<20?1:0;return`${ot.toFixed(se)} km`}else{let se=Math.abs(ot),oe=Math.floor(se/3600),jt=Math.floor(se%3600/60),Ce=Math.round(se%60),ye=oe>0?`${oe}:`:"",Oe=oe>0?String(jt).padStart(2,"0"):String(jt),Re=String(Ce).padStart(2,"0");return`${ot<0?"-":""}${ye}${Oe}:${Re}`}}let fe=f.has(o)||o!=="power"&&o!=="cadence"&&o!=="speed",ge=1/0,Qt=-1/0,ue=0,Me=0,Be=1/0,Je=-1/0,Ae=0,on=0;for(let ot=0;otQt&&(Qt=Mt),ue+=Mt,Me++,(Mt!==0||fe)&&(MtJe&&(Je=Mt),Ae+=Mt,on++))}Me===0&&(ge=0,Qt=100);let _s=Me?{min:ge,max:Qt,avg:ue/Me}:null,cs=on?{min:Be,max:Je,avg:Ae/on}:null,ho=Math.abs(Qt-ge)*.1||1,kl=[ge-ho,Qt+ho],bo=!1;function Rs(ot,Mt,se){let oe=f.has(o)||o!=="power"&&o!=="cadence"&&o!=="speed",jt=Mt-ot;ae.textContent=de(ot,jt),mt.textContent=de(Mt,jt);let Ce=(ye,Oe,Re=!1)=>{let We=Re&&oe===fe?cs:oo(y,T,ye,Oe,oe);if(!We)return"";let an=` + align_flex_end${r.fmt(We.min,!0)} ${r.unit} + align_center${r.fmt(We.avg,!0)} ${r.unit} + align_flex_start${r.fmt(We.max,!0)} ${r.unit} + `;if(o==="elevation"){let Ge=bl(L,ye,Oe);an+=` + trending_up+${Math.round(Ge.gain)} m + trending_down-${Math.round(Ge.loss)} m + `}return an};bo||(bo=!0,xt.innerHTML=`all_inclusive${Ce(y[0],y[y.length-1],!0)}`,xt.querySelector(".all-chip")?.addEventListener("click",ye=>{ye.stopPropagation(),R()})),M!==null&&m!==null?(kt.innerHTML=Ce(M,m,!1),kt.style.display="flex",kt.style.setProperty("--sel-color",r.color)):kt.style.display="none"}let Cl=!1,$l={width:F,height:130,padding:[4,0,0,0],cursor:{sync:{key:i.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:o==="elevation"?(ot,Mt)=>is(tt?tt[ot.cursor.idx]:null):r.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(ot,Mt,se)=>[Mt,se],min:B?B[0]:void 0,max:B?B[1]:void 0},y:{range:()=>kl,dir:o==="speed"&&et==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(ot,Mt,se,oe)=>{let jt=oe-se,ye=(ot.bbox.width>0?ot.bbox.width:ot.width)/80,Oe=jt/ye,Re;te?Re=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:Re=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let We=Re[Re.length-1];for(let Ze=0;Ze=Oe){We=Re[Ze];break}let an=[],Ge=Math.ceil(se/We)*We,vs=We<1?2:0;for(;Ge<=oe;){let Ze=ot.valToPos(Ge,"x",!0);Ze>=ot.bbox.left+80&&Ze<=ot.bbox.left+ot.bbox.width-80&&an.push(Number(Ge.toFixed(vs))),Ge+=We}return an},values:(ot,Mt)=>{let se=(ot.scales.x?.max??1)-(ot.scales.x?.min??0);return Mt.map(oe=>{if(oe==null)return"";let jt=ot.valToPos(oe,"x",!0);return jtot.bbox.left+ot.bbox.width-80?null:de(oe,se)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(ot,Mt)=>Mt.map(se=>se!=null?r.fmtAxis(se):"")}],series:[{},{label:r.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[ot=>{let Mt=ot.bbox.top+ot.bbox.height+5;ae.style.top=`${Mt}px`,ae.style.left=`${ot.bbox.left}px`,mt.style.top=`${Mt}px`,mt.style.left=`${ot.bbox.left+ot.bbox.width}px`,mt.style.transform="translateX(-100%)"},ot=>{o==="gears"?go(ot,y,T,r.color,1.5,o,null,L):o==="elevation"?vl(ot,y,T,tt):o==="gradient"?yl(ot,y,T):at===o?El(ot,y,T,L,o):go(ot,y,T,r.color,1.5,o,null,L)},ot=>{let Mt=t.find(oe=>oe.uplot===ot);if(!Mt)return;let se=ot._strasse;h!=null?xl(ot,y,T,r.color,r,L,o):(se&&se.pinYVal&&(se.pinYVal.style.display="none"),Mt.pinnedHistY!=null&&wl(ot,y,T,Mt.pinnedHistY,r.color,r))},ot=>{let Mt=ot.cursor.idx,se=h!=null,oe=Mt!=null&&ot.cursor.left>=0;if(oe&&h==null){let jt=ot.valToPos(T[Mt],"y",!0);Math.abs(ot.cursor.top-jt)>100&&(oe=!1)}if(oe&&Mt!==h&&ro(ot,L,Mt,le(r.color,.4),1),M!=null&&m!=null){let jt=ot.ctx,Ce=window.devicePixelRatio||1,ye=ot.bbox,Oe=ot.valToPos(M,"x",!0),Re=ot.valToPos(m,"x",!0);jt.save(),jt.beginPath(),jt.lineWidth=3*Ce,jt.strokeStyle=r.color,jt.moveTo(Oe,ye.top+ye.height),jt.lineTo(Re,ye.top+ye.height),jt.stroke();let We=Math.abs(m-M),an=A==="distance"?`${We.toFixed(2)} km`:he(We),Ge=9*Ce,vs=`bold ${Ge}px system-ui, sans-serif`;jt.font!==vs&&(jt.font=vs);let Ze=jt.measureText(an).width,yo=Math.max(ye.left,Oe),xo=Math.min(ye.left+ye.width,Re);if(xo-yo>Ze+14*Ce){let Ll=5*Ce,Al=2*Ce,ys=Ze+Ll*2,xs=Ge+Al*2,Ws=(yo+xo)/2-ys/2,qs=ye.top+ye.height-xs/2;jt.beginPath(),jt.roundRect?jt.roundRect(Ws,qs,ys,xs,3*Ce):jt.rect(Ws,qs,ys,xs),jt.fillStyle=r.color,jt.fill(),jt.fillStyle="#000",jt.textAlign="center",jt.textBaseline="middle",jt.fillText(an,Ws+ys/2,qs+xs/2)}jt.restore()}se&&co(ot,L,h,r.color,!0,.7),oe&&Mt!==h&&co(ot,L,Mt,r.color,!0,1)}],setCursor:[ot=>{if(a)return;let Mt=ot.cursor.idx;ot.redraw(!1),ot.cursor.left>=0?b=ot.posToVal(ot.cursor.left,"x"):b=null;let se=ot._strasse,oe=Mt!=null&&T[Mt]!=null;if(oe&&h==null){let jt=ot.valToPos(T[Mt],"y",!0);Math.abs(ot.cursor.top-jt)>100&&(oe=!1)}if(se&&(oe?lo(ot,se.curYVal,Mt,y,T,L,r,o):se.curYVal.style.display="none"),c||(Mt!=null&&L[Mt]?Z&&(h!=null||oe)?Z(L[Mt]):Z&&!oe&&Z(null):Mt===null&&Z&&Z(null)),Mt!=null&&T[Mt]!=null){let{min:jt,max:Ce}=ke;if(jt!=null&&Ce!=null){let ye=Ce-jt||1,Oe=Math.min(ke.BINS-1,Math.floor((T[Mt]-jt)/ye*ke.BINS));ln.hoveredHistY!==T[Mt]&&(ln.hoveredHistY=T[Mt],Le(Xt,ke,130,Oe))}}else ln.hoveredHistY!==null&&(ln.hoveredHistY=null,Le(Xt,ke,130))}],setScale:[(ot,Mt)=>{if(Mt!=="x"||Cl)return;let{min:se,max:oe}=ot.scales.x;W=[se,oe],Rs(se,oe,ot),!a&&(P||(O=null),a=!0,t.forEach(({uplot:jt})=>{jt!==ot&&jt.batch(()=>jt.setScale("x",{min:se,max:oe}))}),a=!1,_t(),De(),lt&&M!==null&<(M,m,A))}],setSelect:[ot=>{if(P)return;O=null;let{left:Mt,width:se}=ot.select;if(se>0){let oe=ot.posToVal(Mt,"x"),jt=ot.posToVal(Mt+se,"x");M=oe,m=jt,Rs(ot.scales.x.min,ot.scales.x.max,ot),_t(),De(),lt&<(M,m,A),ot.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},Ns=document.createElement("div");Ns.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let ds=document.createElement("div");ds.className="sel-fill",ds.style.display="none";let us=document.createElement("div");us.className="sel-line sel-line-anchor",us.style.display="none";let ms=document.createElement("div");ms.className="sel-line-label sel-line-label-anchor",ms.style.display="none";let qn=document.createElement("div");qn.className="sel-handle sel-handle-anchor",qn.style.display="none";let zn=document.createElement("div");zn.className="sel-graph-marker",zn.innerHTML=`play_circle`,zn.style.display="none";let ps=document.createElement("div");ps.className="sel-line sel-line-end",ps.style.display="none";let fs=document.createElement("div");fs.className="sel-line-label sel-line-label-end",fs.style.display="none";let Un=document.createElement("div");Un.className="sel-handle sel-handle-end",Un.style.display="none";let Vn=document.createElement("div");Vn.className="sel-graph-marker",Vn.innerHTML=`stop_circle`,Vn.style.display="none";let gs=document.createElement("div");gs.className="cur-y-val",gs.style.cssText=`color:${r.color};display:none`;let hs=document.createElement("div");hs.className="cur-y-val pin",hs.style.cssText=`color:${r.color};display:none`,Ns.append(ds,us,ms,qn,zn,ps,fs,Un,Vn,gs,hs);let ke={yData:T,xData:y,def:r,BINS:24,min:Me?ge:void 0,max:Me?Qt:void 0,fullStats:cs,fullStatsAll:_s},ln={uplot:null,row:I,xData:y,yData:T,def:r,metricKey:o,statsTotalEl:xt,statsSelEl:kt,histCol:Kt,histCanvas:Xt,histData:ke,hoveredHistY:null,pinnedHistY:null,smoothed:g.has(o),incZero:f.has(o),w:F};ke.plot=ln;let Pl=a;a=!0;let tn=new ko($l,[y,T],(ot,Mt)=>{ln.uplot=ot,t.push(ln),re.appendChild(ot.root),ot.over.appendChild(Ns),ot._strasse={selFill:ds,anchorLine:us,anchorLabel:ms,anchorHandle:qn,anchorMarker:zn,endLine:ps,endLabel:fs,endHandle:Un,endMarker:Vn,curYVal:gs,pinYVal:hs,updateHeaderStats:Rs},ot.batch(()=>{Mt()})});a=Pl,ee(qn,tn,y,!0),ee(Un,tn,y,!1);let bs=null;tn.over.addEventListener("mousedown",ot=>{if(ot.button!==0)return;k=!1;let Mt=tn.over.getBoundingClientRect();bs=ot.clientX-Mt.left}),tn.over.addEventListener("mousemove",ot=>{if(bs!==null){let Mt=tn.over.getBoundingClientRect();Math.abs(ot.clientX-Mt.left-bs)>5&&(k=!0)}}),tn.over.addEventListener("mouseup",()=>{bs=null}),tn.over.addEventListener("click",()=>{if(k)return;let ot=tn.cursor.idx;ot!=null&&L[ot]&&(h=ot,t.forEach(({uplot:Mt})=>Mt.redraw(!1)),Ft&&Ft(L[ot],ot),rt&&rt(ot))}),I.addEventListener("dblclick",R);let vo=null;if(h!=null&&y[h]!=null&&T[h]!=null&&(xe(ke),ke.min!=null&&ke.max!=null)){let ot=ke.max-ke.min||1;vo=Math.min(ke.BINS-1,Math.floor((T[h]-ke.min)/ot*ke.BINS)),ln.hoveredHistY=T[h]}Le(Xt,ke,130,vo),_n(Xt,ke),G&&(H?G.insertBefore(I,H):G.appendChild(I))}function _t(){qt(),t.forEach(({uplot:o})=>o.batch(()=>o.redraw(!1)))}function qt(){t.forEach(({uplot:o,def:r})=>{let y=o._strasse;if(!y)return;let{selFill:T,anchorLine:F,anchorLabel:L,anchorHandle:B,anchorMarker:H,endLine:q,endLabel:J,endHandle:X,endMarker:Q}=y;if(M==null||m==null){[T,F,L,B,H,q,J,X,Q].forEach(Vt=>{Vt.style.display="none"});return}let et=o.valToPos(M,"x"),tt=o.valToPos(m,"x"),I=window.devicePixelRatio||1,wt=o.bbox,St=wt.width/I,ct=wt.height/I,Ct=(wt.top+wt.height)/I,pt=et>=0&&et<=St,xt=tt>=0&&tt<=St,kt=Math.max(0,et),Ot=Math.min(St,tt);if(Ot>kt?(T.style.left=`${kt}px`,T.style.width=`${Ot-kt}px`,T.style.top="0",T.style.height=`${ct}px`,T.style.backgroundColor=le(r.color,.07),T.style.display=""):T.style.display="none",pt){F.style.left=`${et}px`,F.style.height=`${ct}px`,F.style.borderLeftColor=r.color,F.style.display="";let Vt=Yt(M);L.textContent=Vt;let ne=Vt.length*7+10;L.style.left=et+ne+4Vt.style.display="none");if(xt){q.style.left=`${tt}px`,q.style.height=`${ct}px`,q.style.borderLeftColor=r.color,q.style.display="";let Vt=Yt(m);J.textContent=Vt;let ne=Vt.length*7+10;J.style.left=tt-ne-3>0?`${tt-ne-3}px`:`${tt+3}px`,J.style.display="",X.style.left=`${tt}px`,X.style.backgroundColor=r.color,X.style.display="",Q.style.left=`${tt}px`,Q.style.top=`${Ct}px`;let ie=Q.querySelector(".material-symbols-rounded");ie&&(ie.style.color=r.color),Q.style.display=""}else[q,J,X,Q].forEach(Vt=>Vt.style.display="none")})}function Yt(o){return A==="distance"?`${o.toFixed(2)} km`:he(o)}function ee(o,r,y,T){o.style.pointerEvents="auto",o.addEventListener("mousedown",F=>{F.stopPropagation(),F.preventDefault();let L=F.clientX,B=T?M:m,H=r.over.offsetWidth,q=r.scales.x.min,J=r.scales.x.max,X=H/(J-q),Q=[y[0],y[y.length-1]];document.body.style.cursor="ew-resize",k=!0;function et(I){let wt=I.clientX-L,St=(B||0)+wt/X;St=Math.max(Q[0],Math.min(Q[1],St)),T?M=Math.min(St,(m||Q[1])-.001):m=Math.max(St,(M||Q[0])+.001),t.forEach(ct=>ct.uplot._strasse?.updateHeaderStats(ct.uplot.scales.x.min,ct.uplot.scales.x.max)),_t(),De(),lt&<(M,m,A)}function tt(){document.body.style.cursor="",k=!1,document.removeEventListener("mousemove",et),document.removeEventListener("mouseup",tt)}document.addEventListener("mousemove",et),document.addEventListener("mouseup",tt)})}function xe(o){let{yData:r,xData:y,BINS:T}=o;if(o._lastYData===r&&o.bins)return;o._lastYData=r;let F=o.min,L=o.max;if(F==null||L==null){let Q=1/0,et=-1/0,tt=0;for(let I=0;Iet&&(et=wt),tt++)}if(!tt)return;F=Q,L=et,o.min=F,o.max=L}let B=new Array(T).fill(0),H=new Array(T).fill(0),q=L-F||1,J=o.plot?.metricKey??Object.keys(qe).find(Q=>qe[Q]===o.def),X=!J||f.has(J)||J!=="power"&&J!=="cadence"&&J!=="speed";for(let Q=0;Q0&&y[Q-1]!=null?y[Q-1]:y[Q],wt=Q{Le(o,r,y.height)})}function Le(o,r,y,T=null){let{def:F,BINS:L}=r;xe(r);let{bins:B,min:H,max:q}=r;if(!B||H==null||q==null)return;let J=M!=null&&m!=null;if(J&&(r._lastSelRange?.[0]!==M||r._lastSelRange?.[1]!==m)){r._lastSelRange=[M,m];let mt=new Array(L).fill(0),Kt=new Array(L).fill(0),{yData:Xt,xData:te}=r,de=q-H||1,fe=r.plot?.metricKey??Object.keys(qe).find(Qt=>qe[Qt]===r.def),ge=!fe||f.has(fe)||fe!=="power"&&fe!=="cadence"&&fe!=="speed";for(let Qt=0;Qtm)continue;let Be=Math.min(L-1,Math.floor((ue-H)/de*L));mt[Be]++;let Je=Qt>0&&te[Qt-1]!=null?te[Qt-1]:te[Qt],Ae=QtF.fmtAxis(mt),ct="9px system-ui, sans-serif";I.font!==ct&&(I.font=ct);let pt={t:4,r:0,b:30,l:Math.ceil(Math.max(I.measureText(`${St(q)} ${F.unit}`).width,I.measureText(`${St(H)} ${F.unit}`).width))+6};r.padL=pt.l;let xt=et-pt.l-pt.r,kt=tt-pt.t-pt.b,Ot=mt=>pt.t+(L-1-mt)*(kt/L),Vt=kt/L-1,ne=J?.15:.6;I.fillStyle=le(F.color,ne);for(let mt=0;mtmt+Kt,0);if(ie>0){let mt=[{x:pt.l,y:pt.t+kt}],Kt=0;for(let Xt=0;XtXt+te+2&&mt0){let mt=0;for(let ue=0;ue{let F=no(o,r,T);if(F!=null&&y){let{min:L,max:B,BINS:H}=r,q=B-L||1;y.pinnedHistY=L+(F+.5)*(q/H),t.forEach(({uplot:J})=>J.redraw(!1))}}),o.addEventListener("mousemove",T=>{p=T,so(T,o,r)}),o.addEventListener("mouseenter",()=>{_=o,S=r}),o.addEventListener("mouseleave",()=>{_===o&&(_=null,S=null),E&&(E.style.display="none");let T=document.getElementById("hist-line");T&&(T.style.display="none"),y&&(y.hoveredHistY=null,Le(o,r,o.height/(window.devicePixelRatio||1)))})}function no(o,r,y){let{bins:T,BINS:F}=r;if(!T)return null;let L=o.getBoundingClientRect(),B=y.clientY-L.top,H={t:4,b:30},q=L.height-H.t-H.b,J=Math.floor((B-H.t)/q*F),X=F-1-J;return J<0||J>=F?null:X}function so(o,r,y){if(!E)return;let{bins:T,binAccum:F,min:L,max:B,BINS:H,def:q,plot:J}=y;if(!T||!F||L==null||B==null)return;let X=document.getElementById("hist-line"),Q=no(r,y,o);if(Q==null||!T[Q]){E.style.display="none",X&&(X.style.display="none"),J&&(J.hoveredHistY=null,Le(r,y,r.height/(window.devicePixelRatio||1)));return}if(J){let te=B-L||1;J.hoveredHistY=L+(Q+.5)*(te/H),Le(r,y,r.height/(window.devicePixelRatio||1),Q)}let et=T[Q],tt=T.reduce((te,de)=>te+de,0),I=et/tt*100,wt=B-L||1,St=L+Q*(wt/H),ct=L+(Q+1)*(wt/H),Ct=`${q.fmt(St,!0)} \u2013 ${q.fmt(ct,!0)} ${q.unit}`,pt="",xt=(St+ct)/2,kt=Object.keys(qe).find(te=>qe[te]===q),Ot=[];if(kt==="power"?Ot=$n.getPowerZones():kt==="hr"&&(Ot=$n.getHRZones()),Ot.length>0){let te=Ot.findIndex(fe=>xt>=fe.min&&xt=Ot[Ot.length-1].min?Ot[Ot.length-1]:null;if(de){let fe=te!==-1?te:Ot.length-1;pt=` +
+ Z${fe+1} \xB7 - ${rt.name} + ${de.name}
- `}}let Ze=$==="distance"?`${A[D].toFixed(2)} km`:ht(A[D]),st=A[D]/A.reduce((Qe,rt)=>Qe+rt,0)*100,nt=` -
${_e}
- ${ue} - `;if(Ze&&(nt+=`
- ${$==="distance"?"Dist":"Time"} - ${Ze} - ${st.toFixed(1)}% -
`),h.selBins&&h.selBinAccum){let Qe=$==="distance"?`${h.selBinAccum[D].toFixed(2)} km`:ht(h.selBinAccum[D]),rt=h.selBinAccum[D]/h.selBinAccum.reduce((ut,mt)=>ut+mt,0)*100;nt+=` + `}}let Vt=A==="distance"?`${F[Q].toFixed(2)} km`:he(F[Q]),ne=F[Q]/F.reduce((te,de)=>te+de,0)*100,ie=` +
${Ct}
+ ${pt} + `;if(Vt&&(ie+=`
+ ${A==="distance"?"Dist":"Time"} + ${Vt} + ${ne.toFixed(1)}% +
`),y.selBins&&y.selBinAccum){let te=A==="distance"?`${y.selBinAccum[Q].toFixed(2)} km`:he(y.selBinAccum[Q]),de=y.selBinAccum[Q]/y.selBinAccum.reduce((fe,ge)=>fe+ge,0)*100;ie+=`
- Sel ${$==="distance"?"Dist":"Time"} - ${Qe} - ${rt.toFixed(1)}% + Sel ${A==="distance"?"Dist":"Time"} + ${te} + ${de.toFixed(1)}%
- `}U.innerHTML=nt,U.style.display="block";let it=U.offsetHeight,lt=U.offsetWidth,pe=i.getBoundingClientRect(),Je=pe.height-4-30,Ge=pe.top+4+(P-1-D+.5)*(Je/P);U.style.left=`${pe.left-lt-12}px`,U.style.top=`${Ge-it/2}px`,O&&(O.style.display="block",O.style.top=`${Ge}px`,O.style.left="0px",O.style.width=`${pe.left}px`)}function Rn(l=!1){U&&(U.style.display="none"),e.forEach(({uplot:i,row:h})=>{a.unsub(i),i.destroy(),h.remove()}),e=[],n=null,l||(k=null,f=null),F=!1}function Js(l,i,h,b,A=!0){let S=1/0,B=-1/0,P=0,R=0;for(let X=0;Xb)continue;let O=i[X];O==null||!isFinite(O)||O===0&&!A||(OB&&(B=O),P+=O,R++)}return R?{min:S,max:B,avg:P/R}:null}function ao(l,i,h){let b=0,A=0,S=null,B=$==="distance",P=l[0].time||0;for(let R=0;Rh)&&X.ele!=null){if(S!=null){let D=X.ele-S;D>0?b+=D:D<0&&(A+=Math.abs(D))}S=X.ele}}return{gain:b,loss:A}}function Qs(l,i,h,b,A,S,B,P){if(h==null||A[h]==null){i.style.display="none";return}let R=l.valToPos(b[h],"x",!1),X=l.valToPos(A[h],"y",!1),O="#888896",D=0;if(h>0&&S[h]&&S[h-1]){let ce=S[h-1],_e=S[h],ue=(_e.dist||0)-(ce.dist||0);ue>.1&&_e.ele!=null&&ce.ele!=null&&(D=(_e.ele-ce.ele)/ue*100,O=es(D))}let Y=P!=="elevation"?`${B.fmt(A[h],!1)} ${B.unit}`:`${B.fmt(A[h],!1)} ${B.unit} \u2220 ${Math.abs(D).toFixed(1)}%`;if(P==="gearRear"&&S[h].gearRearTooth!=null)Y=`${S[h].gearRearTooth}T (pos ${A[h]})`;else if(P==="gearFront"&&S[h].gearFrontTooth!=null)Y=`${S[h].gearFrontTooth}T (pos ${A[h]})`;else if(P==="gears"){let ce=S[h],_e=ce.gearFrontTooth!=null?`${ce.gearFrontTooth}T`:ce.gearFront!=null?`pos ${ce.gearFront}`:"",ue=ce.gearRearTooth!=null?`${ce.gearRearTooth}T`:ce.gearRear!=null?`pos ${ce.gearRear}`:"";(_e||ue)&&(Y+=` (${_e} / ${ue})`)}i.innerHTML!==Y&&(i.innerHTML=Y);let ie=`${B.color}44`;i.style.color!==B.color&&(i.style.color=B.color),i.style.borderColor!==ie&&(i.style.borderColor=ie);let L=`${R}px`,Te=`${X}px`,ae="translate(6px, -50%)";i.style.left!==L&&(i.style.left=L),i.style.top!==Te&&(i.style.top=Te),i.style.transform!==ae&&(i.style.transform=ae),i.style.display!==""&&(i.style.display="")}let Ks=new Map;function el(l){let i=Ks.get(l);return i||(i=tt(es(l),.8),Ks.set(l,i)),i}function ro(l,i,h,b){let A=l.ctx,S=l.bbox,B=window.devicePixelRatio||1,P=l.scales.x?.min??-1/0,R=l.scales.x?.max??1/0,X=l.scales.y?.min??0,O=l.scales.y?.max??100,D=S.width/(R-P||1),Y=S.height/(O-X||1),ie=S.top+S.height,L=l.series[0]?.idxs,Te=L?Math.max(1,L[0]):1,ae=L?Math.min(i.length-1,L[1]+1):i.length-1,ce=Math.max(1,Math.floor((ae-Te)/250));A.save(),A.lineWidth=1.5*B;let _e=new Map,ue=Te-1;for(let ve=Te;ve<=ae;ve+=ce){let Ae=i[ve],Ue=i[ue];if(ue=ve,Ae==null||h[ve]==null||Ue==null||h[ve-ce]==null||AeR)continue;let Ze=S.left+(Ue-P)*D,st=ie-(h[ve-ce]-X)*Y,nt=S.left+(Ae-P)*D,it=ie-(h[ve]-X)*Y,lt=b&&b[ve]!=null?Math.round(b[ve]/2)*2:null,pe=el(lt),Je=_e.get(pe);Je||(Je=[],_e.set(pe,Je)),Je.push(Ze,st,nt,it)}for(let[ve,Ae]of _e){A.beginPath(),A.strokeStyle=ve;for(let Ue=0;UeP)continue;let Ue=A.left+(Ae-B)*O,Ze=Y-(h[ue-ae]-R)*D,st=A.left+(ve-B)*O,nt=Y-(h[ue]-R)*D,it=Math.round(h[ue]/2)*2,lt=el(it),pe=ce.get(lt);pe||(pe=[],ce.set(lt,pe)),pe.push(Ue,Ze,st,nt)}for(let[ue,ve]of ce){b.beginPath(),b.strokeStyle=ue;for(let Ae=0;Ae{let Ae=`bold ${10*B}px system-ui, sans-serif`;R.font!==Ae&&(R.font=Ae);let Ze=R.measureText(ce).width+10*B,st=16*B,nt=_e-Ze/2,it=Math.max(P.left,Math.min(P.left+P.width-Ze,nt)),lt=ue-st/2;R.save(),R.globalAlpha=S,R.setLineDash([]),R.beginPath(),R.roundRect?R.roundRect(it,lt,Ze,st,3*B):R.rect(it,lt,Ze,st),R.fillStyle="rgba(14,14,16,0.92)",R.fill(),R.strokeStyle=tt(b,.27),R.lineWidth=1*B,R.stroke(),R.fillStyle=b,R.textAlign="center",R.textBaseline="middle",R.fillText(ce,it+Ze/2,lt+st/2+.5*B),R.restore()};A||tl(l,i,h,b,S);let ae=16*B;Te(L,Y,P.top+ae/2,!0),Te(ie,Y,P.top+P.height+15*B,!1)}function uo(l,i,h,b,A,S,B){if(u==null)return;let P=i[u],R=h[u];if(P==null||R==null)return;let X=l.valToPos(P,"x",!0),O=l.valToPos(R,"y",!0),D=l.bbox,Y=l.ctx,ie=window.devicePixelRatio||1;Y.save(),Y.beginPath(),Y.strokeStyle=b,Y.lineWidth=1.5*ie,Y.moveTo(X,D.top),Y.lineTo(X,D.top+D.height),Y.stroke(),Y.beginPath(),Y.setLineDash([3*ie,3*ie]),Y.strokeStyle=tt(b,.5),Y.lineWidth=1*ie,Y.moveTo(D.left,O),Y.lineTo(X,O),Y.stroke(),Y.beginPath(),Y.setLineDash([]),Y.arc(X,O,5*ie,0,Math.PI*2),Y.fillStyle="#0e0e10",Y.fill(),Y.strokeStyle=b,Y.lineWidth=2.5*ie,Y.stroke(),Y.restore();let L=l._strasse;L&&L.pinYVal&&Qs(l,L.pinYVal,u,i,h,S,A,B)}function mo(l,i,h,b,A,S){let B=l.bbox,P=l.ctx,R=window.devicePixelRatio||1,X=l.valToPos(b,"y",!0),O=Math.max(B.top,Math.min(B.top+B.height,X));P.save(),P.beginPath(),P.setLineDash([4*R,4*R]),P.strokeStyle=tt(A,.4),P.lineWidth=1*R,P.moveTo(B.left,O),P.lineTo(B.left+B.width,O),P.stroke(),po(l,i,h,O,A);let D=S.fmt(b,!0),Y=`bold ${10*R}px system-ui, sans-serif`;P.font!==Y&&(P.font=Y);let L=P.measureText(D).width+8*R,Te=16*R,ae=B.left-L-2*R,ce=O-Te/2;P.beginPath(),P.setLineDash([]),P.roundRect?P.roundRect(ae,ce,L,Te,3*R):P.rect(ae,ce,L,Te),P.fillStyle="rgba(14,14,16,0.95)",P.fill(),P.strokeStyle=A,P.lineWidth=1*R,P.stroke(),P.fillStyle="#fff",P.textAlign="center",P.textBaseline="middle",P.fillText(D,ae+L/2,ce+Te/2+.5*R),P.restore()}function po(l,i,h,b,A){let S=l.ctx,B=l.bbox,P=l.scales.x?.min??-1/0,R=l.scales.x?.max??1/0,X=l.scales.y?.min??0,O=l.scales.y?.max??100,D=B.width/(R-P||1),Y=B.height/(O-X||1),ie=l.scales.y?.dir??1,L=ie===-1?B.top:B.top+B.height,Te=ie===-1?Y:-Y,ae=l.series[0]?.idxs,ce=ae?Math.max(0,ae[0]-1):0,_e=ae?Math.min(i.length-1,ae[1]+1):i.length-1,ue=Math.max(1,Math.floor((_e-ce)/250));S.save(),S.beginPath(),S.rect(B.left,B.top,B.width,B.height),S.clip(),S.fillStyle=tt(A,.2),S.beginPath();let ve=!1,Ae=!1,Ue=0;for(let Ze=ce;Ze<=_e;Ze+=ue){let st=i[Ze],nt=h[Ze];if(st==null||nt==null||stR){ve&&(S.lineTo(Ue,b),S.closePath(),ve=!1);continue}let it=B.left+(st-P)*D,lt=L+(nt-X)*Te;Ue=it,lt>16,B=b>>8&255,P=b&255,R=A>>16,X=A>>8&255,O=A&255,D=S+(R-S)*h,Y=B+(X-B)*h,ie=P+(O-P)*h;return`#${((1<<24)+(Math.round(D)<<16)+(Math.round(Y)<<8)+Math.round(ie)).toString(16).slice(1)}`}function es(l){if(l==null)return"#888896";let i=Math.abs(l),h=Math.min(1,i/8);return l>0?Dt("#A8C8A0","#d73027",h):Dt("#A8C8A0","#4575b4",h)}function sl(l){if(l==null)return"#888896";let i=l*3.6;if(i<=5)return"#4575b4";if(i>=60)return"#d73027";if(i<=45){let h=(i-5)/40;return h<=.25?Dt("#4575b4","#91bfdb",h/.25):h<=.5?Dt("#91bfdb","#abdda4",(h-.25)/.25):h<=.75?Dt("#abdda4","#fee08b",(h-.5)/.25):Dt("#fee08b","#fc8d59",(h-.75)/.25)}else{let h=(i-45)/15;return Dt("#fc8d59","#d73027",h)}}function fo(l,i){let h=new Array(l.length).fill(null);for(let b=0;b0&&(A.dist||0)-(l[S].dist||0)1&&l[B].ele!=null&&l[S].ele!=null&&(h[b]=(l[B].ele-l[S].ele)/P*100)}return h}function ll(l){let i=[...l];for(let h=0;h=0&&i[b]===null;)b--;let A=h+1;for(;A=0&&A=0?i[h]=i[b]:A{let X=document.querySelector(`#${P} .stat-value`);X&&(X.textContent=R)};h("stat-distance",i.totalDist!=null?`${(i.totalDist/1e3).toFixed(1)} km`:"\u2014"),h("stat-duration",i.duration!=null?ht(Math.floor(i.duration/1e3)):"\u2014"),h("stat-elevation",i.elevGain!=null?`${Math.round(i.elevGain)} m`:"\u2014");let b=P=>{let R=e.find(D=>D.metricKey===P);if(!R)return P==="speed"?i.avgSpeed??null:P==="power"?i.avgPower??null:P==="cadence"?i.avgCadence??null:null;if(R.histData.fullStats!==void 0)return R.histData.fullStats?R.histData.fullStats.avg:null;let X=T.has(P)||P!=="power"&&P!=="cadence"&&P!=="speed",O=R.yData.filter(D=>D!=null&&(X||D!==0));return O.length?O.reduce((D,Y)=>D+Y,0)/O.length:null},A=b("speed");h("stat-avg-speed",A!=null?`${(A*3.6).toFixed(1)} km/h`:"\u2014");let S=b("power");h("stat-avg-power",S!=null?`${Math.round(S)} W`:"\u2014");let B=b("cadence");h("stat-avg-cad",B!=null?`${Math.round(B)} rpm`:"\u2014"),h("stat-avg-hr",i.avgHR!=null?`${i.avgHR} bpm`:"\u2014"),h("stat-avg-temp",i.avgTemp!=null?`${i.avgTemp.toFixed(1)} \xB0C`:"\u2014")}let pn=16384,fn=new Float64Array(pn),Tn=new Float64Array(pn),ts=new Float64Array(pn),Nn=new Float64Array(pn),$s=new Float64Array(pn),ns=new Float64Array(pn),Wn=new Float64Array(64),il=[3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300,360];function go(l,i,h){if(!l.length)return 0;Wn.fill(0);let b=0;for(let A=0;A=B)continue;let Te=Y/L,ae=0,ce=0,_e=0;for(let ue=0;ue=L){ae-=ns[ue-L],ce-=Nn[ue-L];let ve=(ae+ce*.05)*Te;ve>_e&&(_e=ve)}b+=_e*1e-4}for(let ie=P;ie0&&(Wn[L-1]+=.5),L<63&&(Wn[L+1]+=.5)}}}for(let A=0;A<64;A++)b+=Wn[A]*1e-5;return Q&&(Q.dataset.intervalScore=b.toFixed(2)),b}return{init:fe,loadTrack:j,clear:H,resetState:oe,toggleMetric:ge,setXAxis:Ie,toggleStats:he,setSelectionStats:Ne,clearSelectionStats:Z,restoreSelection:Be,resetZoom:I,cancelSelection:ne,analyzeTelemetryIntervals:go,setCursorAt:(l,i=!1)=>{if(u=l,m&&m(l),i){z&&M?.points?.[l]&&z(M.points[l]);return}c=!0,e.forEach(({uplot:h,yData:b,xData:A})=>{A[l]!=null&&b[l]!=null&&h.batch(()=>{h.setCursor({left:h.valToPos(A[l],"x"),top:h.valToPos(b[l],"y")},!0,!1)})}),c=!1,z&&M?.points?.[l]&&z(M.points[l])},setHoverAt:l=>{c=!0,e.forEach(({uplot:i,yData:h,xData:b})=>{l===null?i.batch(()=>{i.setCursor({left:-10,top:-10},!0,!1)}):b[l]!=null&&h[l]!=null&&i.batch(()=>{i.setCursor({left:i.valToPos(b[l],"x"),top:i.valToPos(h[l],"y")},!0,!1)})}),c=!1,z&&z(l!=null&&M?.points?.[l]?M.points[l]:null)},clearPinnedDot:()=>{u=null,m&&m(null),e.forEach(({uplot:l})=>l.redraw(!1))},resize:xe,METRICS:Ft,isDragging:()=>F,setMapColorChangeCb:He,toggleMapColor:Ce,getMapColorMetric:()=>se,getActiveMetrics:()=>d,getAvailableMetrics:()=>x,setActiveMetrics:K,updateMetricOrder:l=>{let i=new Set;l.forEach(h=>{d.has(h)&&i.add(h)}),d.forEach(h=>{i.has(h)||i.add(h)}),d=i,M&&Ee(!0)},getXAxis:()=>$};function ho(l,i,h,b,A){let S=l.ctx,B=l.bbox,P=window.devicePixelRatio||1,R=ye(A,h);S.save(),S.beginPath(),S.rect(B.left,B.top,B.width,B.height),S.clip();let X=A==="gearRear"||A==="gearFront";for(let O=1;Oie.time!=null)?.time||0,D=h.field;b.beginPath(),b.strokeStyle="rgba(255, 255, 255, 0.04)",b.lineWidth=1*S;let Y=!0;for(let ie=0;ie0){let ve=X[ie-1];(L.time&&ve.time?L.time-ve.time:0)>B&&(Y=!0)}let ae=h.transform?h.transform(Te):Te;if(ae==null){Y=!0;continue}let ce=$==="distance"?(L.dist||0)/1e3:(L.time-O)/1e3;if(cel.scales.x.max+10){Y=!0;continue}let _e=l.valToPos(ce,"x",!0),ue=l.valToPos(ae,"y",!0);if(Y)b.moveTo(_e,ue),Y=!1;else{if(P){let ve=X[ie-1],Ae=$==="distance"?(ve.dist||0)/1e3:(ve.time-O)/1e3;b.lineTo(l.valToPos(Ae,"x",!0),ue)}b.lineTo(_e,ue)}}b.stroke()}b.restore()}function al(l,i,h,b,A,S,B=null,P=[]){let R=l.ctx,X=l.bbox,O=window.devicePixelRatio||1,D=6e4;R.save(),R.beginPath(),R.strokeStyle=tt(b,.8),R.lineWidth=A*O;let Y=S==="gearRear"||S==="gearFront",ie=!0,L=null,Te=1,ae=1;if(S==="gears"&&P.length>0){let Xe=1/0,ct=-1/0;for(let vt=0;vtct&&(ct=St))}Xe<=ct&&(Te=Xe,ae=ct)}let ce=B?B[0]:l.scales.x?.min??-1/0,_e=B?B[1]:l.scales.x?.max??1/0,ue=l.scales.x?.min??-1/0,ve=l.scales.x?.max??1/0,Ae=l.scales.y?.min??0,Ue=l.scales.y?.max??100,Ze=X.width/(ve-ue||1),st=X.height/(Ue-Ae||1),nt=l.scales.y?.dir??1,it=nt===-1?X.top:X.top+X.height,lt=nt===-1?st:-st,pe=B?null:l.series[0]?.idxs,Je=pe?Math.max(0,pe[0]-1):0,Ge=pe?Math.min(i.length-1,pe[1]+1):i.length-1,Qe=Y||S==="gears"?1:Math.max(1,Math.floor((Ge-Je)/250)),rt=$==="time",ut=D/1e3,mt=Je;for(let Xe=Je;Xe<=Ge;Xe+=Qe){let ct=i[Xe],vt=h[Xe];if(ct==null||vt==null){ie=!0;continue}if(S==="gears"&&P[Xe]){let Et=P[Xe].gearFrontTooth??P[Xe].gearFront;if(Et!=null&&Et!==L){if(!ie&&Xe>0){R.stroke(),R.beginPath();let Ls=X.left+(i[mt]-ue)*Ze,ss=it+(h[mt]-Ae)*lt;R.moveTo(Ls,ss)}let Kt=b;ae!==Te&&Et!=null&&(Et===Te?Kt="#FFC400":Et===ae?Kt="#FF8C00":Kt="#FFA500"),R.strokeStyle=tt(Kt,.8),L=Et}}if(Xe>Je&&rt){let Et=i[mt];Et!=null&&ct-Et>ut&&(ie=!0)}if(ct_e){ie=!0;continue}let St=X.left+(ct-ue)*Ze,jt=it+(vt-Ae)*lt;if(ie)R.moveTo(St,jt),ie=!1;else{if(Y){let Et=i[mt];R.lineTo(X.left+(Et-ue)*Ze,jt)}R.lineTo(St,jt)}mt=Xe}R.stroke(),R.restore()}})();var Ao={"Heart Rate":We.hr.icon,Cadence:We.cadence.icon,Power:We.power.icon,Temperature:We.temperature.icon,Shifting:We.gears.icon,Battery:We.battery.icon},Mn=()=>{},yl=()=>{};function xl(e,n){Mn=e,yl=n}function wl(){let e=document.getElementById("details-view");e&&(e.innerHTML=` + `}E.innerHTML=ie,E.style.display="block";let re=E.offsetHeight,ae=E.offsetWidth,mt=r.getBoundingClientRect(),Kt=mt.height-4-30,Xt=mt.top+4+(H-1-Q+.5)*(Kt/H);E.style.left=`${mt.left-ae-12}px`,E.style.top=`${Xt-re/2}px`,X&&(X.style.display="block",X.style.top=`${Xt}px`,X.style.left="0px",X.style.width=`${mt.left}px`)}function Rn(o=!1){E&&(E.style.display="none"),t.forEach(({uplot:r,row:y})=>{i.unsub(r),r.destroy(),y.remove()}),t=[],n=null,o||(M=null,m=null),k=!1}function oo(o,r,y,T,F=!0){let L=1/0,B=-1/0,H=0,q=0;for(let J=0;JT)continue;let X=r[J];X==null||!isFinite(X)||X===0&&!F||(XB&&(B=X),H+=X,q++)}return q?{min:L,max:B,avg:H/q}:null}function bl(o,r,y){let T=0,F=0,L=null,B=A==="distance",H=o[0].time||0;for(let q=0;qy)&&J.ele!=null){if(L!=null){let Q=J.ele-L;Q>0?T+=Q:Q<0&&(F+=Math.abs(Q))}L=J.ele}}return{gain:T,loss:F}}function lo(o,r,y,T,F,L,B,H){if(y==null||F[y]==null){r.style.display="none";return}let q=o.valToPos(T[y],"x",!1),J=o.valToPos(F[y],"y",!1),X="#888896",Q=0;if(y>0&&L[y]&&L[y-1]){let ct=L[y-1],Ct=L[y],pt=(Ct.dist||0)-(ct.dist||0);pt>.1&&Ct.ele!=null&&ct.ele!=null&&(Q=(Ct.ele-ct.ele)/pt*100,X=is(Q))}let et=H!=="elevation"?`${B.fmt(F[y],!1)} ${B.unit}`:`${B.fmt(F[y],!1)} ${B.unit} \u2220 ${Math.abs(Q).toFixed(1)}%`;if(H==="gearRear"&&L[y].gearRearTooth!=null)et=`${L[y].gearRearTooth}T (pos ${F[y]})`;else if(H==="gearFront"&&L[y].gearFrontTooth!=null)et=`${L[y].gearFrontTooth}T (pos ${F[y]})`;else if(H==="gears"){let ct=L[y],Ct=ct.gearFrontTooth!=null?`${ct.gearFrontTooth}T`:ct.gearFront!=null?`pos ${ct.gearFront}`:"",pt=ct.gearRearTooth!=null?`${ct.gearRearTooth}T`:ct.gearRear!=null?`pos ${ct.gearRear}`:"";(Ct||pt)&&(et+=` (${Ct} / ${pt})`)}r.innerHTML!==et&&(r.innerHTML=et);let tt=`${B.color}44`;r.style.color!==B.color&&(r.style.color=B.color),r.style.borderColor!==tt&&(r.style.borderColor=tt);let I=`${q}px`,wt=`${J}px`,St="translate(6px, -50%)";r.style.left!==I&&(r.style.left=I),r.style.top!==wt&&(r.style.top=wt),r.style.transform!==St&&(r.style.transform=St),r.style.display!==""&&(r.style.display="")}let io=new Map;function ao(o){let r=io.get(o);return r||(r=le(is(o),.8),io.set(o,r)),r}function vl(o,r,y,T){let F=o.ctx,L=o.bbox,B=window.devicePixelRatio||1,H=o.scales.x?.min??-1/0,q=o.scales.x?.max??1/0,J=o.scales.y?.min??0,X=o.scales.y?.max??100,Q=L.width/(q-H||1),et=L.height/(X-J||1),tt=L.top+L.height,I=o.series[0]?.idxs,wt=I?Math.max(1,I[0]):1,St=I?Math.min(r.length-1,I[1]+1):r.length-1,ct=Math.max(1,Math.floor((St-wt)/250));F.save(),F.lineWidth=1.5*B;let Ct=new Map,pt=wt-1;for(let xt=wt;xt<=St;xt+=ct){let kt=r[xt],Ot=r[pt];if(pt=xt,kt==null||y[xt]==null||Ot==null||y[xt-ct]==null||ktq)continue;let Vt=L.left+(Ot-H)*Q,ne=tt-(y[xt-ct]-J)*et,ie=L.left+(kt-H)*Q,re=tt-(y[xt]-J)*et,ae=T&&T[xt]!=null?Math.round(T[xt]/2)*2:null,mt=ao(ae),Kt=Ct.get(mt);Kt||(Kt=[],Ct.set(mt,Kt)),Kt.push(Vt,ne,ie,re)}for(let[xt,kt]of Ct){F.beginPath(),F.strokeStyle=xt;for(let Ot=0;OtH)continue;let Ot=F.left+(kt-B)*X,Vt=et-(y[pt-St]-q)*Q,ne=F.left+(xt-B)*X,ie=et-(y[pt]-q)*Q,re=Math.round(y[pt]/2)*2,ae=ao(re),mt=ct.get(ae);mt||(mt=[],ct.set(ae,mt)),mt.push(Ot,Vt,ne,ie)}for(let[pt,xt]of ct){T.beginPath(),T.strokeStyle=pt;for(let kt=0;kt{let kt=`bold ${10*B}px system-ui, sans-serif`;q.font!==kt&&(q.font=kt);let Vt=q.measureText(ct).width+10*B,ne=16*B,ie=Ct-Vt/2,re=Math.max(H.left,Math.min(H.left+H.width-Vt,ie)),ae=pt-ne/2;q.save(),q.globalAlpha=L,q.setLineDash([]),q.beginPath(),q.roundRect?q.roundRect(re,ae,Vt,ne,3*B):q.rect(re,ae,Vt,ne),q.fillStyle="rgba(14,14,16,0.92)",q.fill(),q.strokeStyle=le(T,.27),q.lineWidth=1*B,q.stroke(),q.fillStyle=T,q.textAlign="center",q.textBaseline="middle",q.fillText(ct,re+Vt/2,ae+ne/2+.5*B),q.restore()};F||ro(o,r,y,T,L);let St=16*B;wt(I,et,H.top+St/2,!0),wt(tt,et,H.top+H.height+15*B,!1)}function xl(o,r,y,T,F,L,B){if(h==null)return;let H=r[h],q=y[h];if(H==null||q==null)return;let J=o.valToPos(H,"x",!0),X=o.valToPos(q,"y",!0),Q=o.bbox,et=o.ctx,tt=window.devicePixelRatio||1;et.save(),et.beginPath(),et.strokeStyle=T,et.lineWidth=1.5*tt,et.moveTo(J,Q.top),et.lineTo(J,Q.top+Q.height),et.stroke(),et.beginPath(),et.setLineDash([3*tt,3*tt]),et.strokeStyle=le(T,.5),et.lineWidth=1*tt,et.moveTo(Q.left,X),et.lineTo(J,X),et.stroke(),et.beginPath(),et.setLineDash([]),et.arc(J,X,5*tt,0,Math.PI*2),et.fillStyle="#0e0e10",et.fill(),et.strokeStyle=T,et.lineWidth=2.5*tt,et.stroke(),et.restore();let I=o._strasse;I&&I.pinYVal&&lo(o,I.pinYVal,h,r,y,L,F,B)}function wl(o,r,y,T,F,L){let B=o.bbox,H=o.ctx,q=window.devicePixelRatio||1,J=o.valToPos(T,"y",!0),X=Math.max(B.top,Math.min(B.top+B.height,J));H.save(),H.beginPath(),H.setLineDash([4*q,4*q]),H.strokeStyle=le(F,.4),H.lineWidth=1*q,H.moveTo(B.left,X),H.lineTo(B.left+B.width,X),H.stroke(),Tl(o,r,y,X,F);let Q=L.fmt(T,!0),et=`bold ${10*q}px system-ui, sans-serif`;H.font!==et&&(H.font=et);let I=H.measureText(Q).width+8*q,wt=16*q,St=B.left-I-2*q,ct=X-wt/2;H.beginPath(),H.setLineDash([]),H.roundRect?H.roundRect(St,ct,I,wt,3*q):H.rect(St,ct,I,wt),H.fillStyle="rgba(14,14,16,0.95)",H.fill(),H.strokeStyle=F,H.lineWidth=1*q,H.stroke(),H.fillStyle="#fff",H.textAlign="center",H.textBaseline="middle",H.fillText(Q,St+I/2,ct+wt/2+.5*q),H.restore()}function Tl(o,r,y,T,F){let L=o.ctx,B=o.bbox,H=o.scales.x?.min??-1/0,q=o.scales.x?.max??1/0,J=o.scales.y?.min??0,X=o.scales.y?.max??100,Q=B.width/(q-H||1),et=B.height/(X-J||1),tt=o.scales.y?.dir??1,I=tt===-1?B.top:B.top+B.height,wt=tt===-1?et:-et,St=o.series[0]?.idxs,ct=St?Math.max(0,St[0]-1):0,Ct=St?Math.min(r.length-1,St[1]+1):r.length-1,pt=Math.max(1,Math.floor((Ct-ct)/250));L.save(),L.beginPath(),L.rect(B.left,B.top,B.width,B.height),L.clip(),L.fillStyle=le(F,.2),L.beginPath();let xt=!1,kt=!1,Ot=0;for(let Vt=ct;Vt<=Ct;Vt+=pt){let ne=r[Vt],ie=y[Vt];if(ne==null||ie==null||neq){xt&&(L.lineTo(Ot,T),L.closePath(),xt=!1);continue}let re=B.left+(ne-H)*Q,ae=I+(ie-J)*wt;Ot=re,ae>16,B=T>>8&255,H=T&255,q=F>>16,J=F>>8&255,X=F&255,Q=L+(q-L)*y,et=B+(J-B)*y,tt=H+(X-H)*y;return`#${((1<<24)+(Math.round(Q)<<16)+(Math.round(et)<<8)+Math.round(tt)).toString(16).slice(1)}`}function is(o){if(o==null)return"#888896";let r=Math.abs(o),y=Math.min(1,r/8);return o>0?Ve("#A8C8A0","#d73027",y):Ve("#A8C8A0","#4575b4",y)}function uo(o){if(o==null)return"#888896";let r=o*3.6;if(r<=5)return"#4575b4";if(r>=60)return"#d73027";if(r<=45){let y=(r-5)/40;return y<=.25?Ve("#4575b4","#91bfdb",y/.25):y<=.5?Ve("#91bfdb","#abdda4",(y-.25)/.25):y<=.75?Ve("#abdda4","#fee08b",(y-.5)/.25):Ve("#fee08b","#fc8d59",(y-.75)/.25)}else{let y=(r-45)/15;return Ve("#fc8d59","#d73027",y)}}function Sl(o,r){let y=new Array(o.length).fill(null);for(let T=0;T0&&(F.dist||0)-(o[L].dist||0)1&&o[B].ele!=null&&o[L].ele!=null&&(y[T]=(o[B].ele-o[L].ele)/H*100)}return y}function mo(o){let r=[...o];for(let y=0;y=0&&r[T]===null;)T--;let F=y+1;for(;F=0&&F=0?r[y]=r[T]:F{let J=document.querySelector(`#${H} .stat-value`);J&&(J.textContent=q)};y("stat-distance",r.totalDist!=null?`${(r.totalDist/1e3).toFixed(1)} km`:"\u2014"),y("stat-duration",r.duration!=null?he(Math.floor(r.duration/1e3)):"\u2014"),y("stat-elevation",r.elevGain!=null?`${Math.round(r.elevGain)} m`:"\u2014");let T=H=>{let q=t.find(Q=>Q.metricKey===H);if(!q)return H==="speed"?r.avgSpeed??null:H==="power"?r.avgPower??null:H==="cadence"?r.avgCadence??null:null;if(q.histData.fullStats!==void 0)return q.histData.fullStats?q.histData.fullStats.avg:null;let J=f.has(H)||H!=="power"&&H!=="cadence"&&H!=="speed",X=q.yData.filter(Q=>Q!=null&&(J||Q!==0));return X.length?X.reduce((Q,et)=>Q+et,0)/X.length:null},F=T("speed");y("stat-avg-speed",F!=null?`${(F*3.6).toFixed(1)} km/h`:"\u2014");let L=T("power");y("stat-avg-power",L!=null?`${Math.round(L)} W`:"\u2014");let B=T("cadence");y("stat-avg-cad",B!=null?`${Math.round(B)} rpm`:"\u2014"),y("stat-avg-hr",r.avgHR!=null?`${r.avgHR} bpm`:"\u2014"),y("stat-avg-temp",r.avgTemp!=null?`${r.avgTemp.toFixed(1)} \xB0C`:"\u2014")}let yn=16384,xn=new Float64Array(yn),kn=new Float64Array(yn),as=new Float64Array(yn),Nn=new Float64Array(yn),Bs=new Float64Array(yn),rs=new Float64Array(yn),Wn=new Float64Array(64),fo=[3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300,360];function Ml(o,r,y){if(!o.length)return 0;Wn.fill(0);let T=0;for(let F=0;F=St)continue;let pt=1/Ct,xt=0,kt=0,Ot=0;for(let Vt=I;Vt=Ct){xt-=rs[Vt-Ct],kt-=Nn[Vt-Ct];let ne=(xt+kt*.05)*pt;ne>Ot&&(Ot=ne)}T+=Ot*1e-4}for(let ct=I;ct0&&(Wn[Ct-1]+=.5),Ct<63&&(Wn[Ct+1]+=.5)}}}}for(let F=0;F<64;F++)T+=Wn[F]*1e-5;return G&&(G.dataset.intervalScore=T.toFixed(2)),T}return{init:$t,loadTrack:z,clear:D,resetState:it,toggleMetric:K,setXAxis:Ht,toggleStats:dt,setSelectionStats:Dt,clearSelectionStats:It,restoreSelection:Wt,resetZoom:V,cancelSelection:R,analyzeTelemetryIntervals:Ml,setCursorAt:(o,r=!1)=>{if(h=o,rt&&rt(o),r){Z&&C?.points?.[o]&&Z(C.points[o]);return}c=!0,t.forEach(({uplot:y,yData:T,xData:F})=>{F[o]!=null&&T[o]!=null&&y.batch(()=>{y.setCursor({left:y.valToPos(F[o],"x"),top:y.valToPos(T[o],"y")},!0,!1)})}),c=!1,Z&&C?.points?.[o]&&Z(C.points[o])},setHoverAt:o=>{c=!0,t.forEach(({uplot:r,yData:y,xData:T})=>{o===null?r.batch(()=>{r.setCursor({left:-10,top:-10},!0,!1)}):T[o]!=null&&y[o]!=null&&r.batch(()=>{r.setCursor({left:r.valToPos(T[o],"x"),top:r.valToPos(y[o],"y")},!0,!1)})}),c=!1,Z&&Z(o!=null&&C?.points?.[o]?C.points[o]:null)},clearPinnedDot:()=>{h=null,rt&&rt(null),t.forEach(({uplot:o})=>o.redraw(!1))},resize:Et,METRICS:qe,isDragging:()=>k,setMapColorChangeCb:Lt,toggleMapColor:st,getMapColorMetric:()=>at,getActiveMetrics:()=>d,getAvailableMetrics:()=>w,setActiveMetrics:ut,setSmooth:bt,setZeroInclusion:Pt,updateMetricOrder:o=>{let r=new Set;o.forEach(y=>{d.has(y)&&r.add(y)}),d.forEach(y=>{r.has(y)||r.add(y)}),d=r,C&&vt(!0)},getXAxis:()=>A};function El(o,r,y,T,F){let L=o.ctx,B=o.bbox,H=window.devicePixelRatio||1,q=zt(F,y);L.save(),L.beginPath(),L.rect(B.left,B.top,B.width,B.height),L.clip();let J=F==="gearRear"||F==="gearFront";for(let X=1;Xtt.time!=null)?.time||0,Q=y.field;T.beginPath(),T.strokeStyle="rgba(255, 255, 255, 0.04)",T.lineWidth=1*L;let et=!0;for(let tt=0;tt0){let xt=J[tt-1];(I.time&&xt.time?I.time-xt.time:0)>B&&(et=!0)}let St=y.transform?y.transform(wt):wt;if(St==null){et=!0;continue}let ct=A==="distance"?(I.dist||0)/1e3:(I.time-X)/1e3;if(cto.scales.x.max+10){et=!0;continue}let Ct=o.valToPos(ct,"x",!0),pt=o.valToPos(St,"y",!0);if(et)T.moveTo(Ct,pt),et=!1;else{if(H){let xt=J[tt-1],kt=A==="distance"?(xt.dist||0)/1e3:(xt.time-X)/1e3;T.lineTo(o.valToPos(kt,"x",!0),pt)}T.lineTo(Ct,pt)}}T.stroke()}T.restore()}function go(o,r,y,T,F,L,B=null,H=[]){let q=o.ctx,J=o.bbox,X=window.devicePixelRatio||1,Q=6e4;q.save(),q.beginPath(),q.strokeStyle=le(T,.8),q.lineWidth=F*X;let et=L==="gearRear"||L==="gearFront",tt=!0,I=null,wt=1,St=1;if(L==="gears"&&H.length>0){let Qt=1/0,ue=-1/0;for(let Me=0;Meue&&(ue=Be))}Qt<=ue&&(wt=Qt,St=ue)}let ct=B?B[0]:o.scales.x?.min??-1/0,Ct=B?B[1]:o.scales.x?.max??1/0,pt=o.scales.x?.min??-1/0,xt=o.scales.x?.max??1/0,kt=o.scales.y?.min??0,Ot=o.scales.y?.max??100,Vt=J.width/(xt-pt||1),ne=J.height/(Ot-kt||1),ie=o.scales.y?.dir??1,re=ie===-1?J.top:J.top+J.height,ae=ie===-1?ne:-ne,mt=B?null:o.series[0]?.idxs,Kt=mt?Math.max(0,mt[0]-1):0,Xt=mt?Math.min(r.length-1,mt[1]+1):r.length-1,te=et||L==="gears"?1:Math.max(1,Math.floor((Xt-Kt)/250)),de=A==="time",fe=Q/1e3,ge=Kt;for(let Qt=Kt;Qt<=Xt;Qt+=te){let ue=r[Qt],Me=y[Qt];if(ue==null||Me==null){tt=!0;continue}if(L==="gears"&&H[Qt]){let Ae=H[Qt].gearFrontTooth??H[Qt].gearFront;if(Ae!=null&&Ae!==I){if(!tt&&Qt>0){q.stroke(),q.beginPath();let _s=J.left+(r[ge]-pt)*Vt,cs=re+(y[ge]-kt)*ae;q.moveTo(_s,cs)}let on=T;St!==wt&&Ae!=null&&(Ae===wt?on="#FFC400":Ae===St?on="#FF8C00":on="#FFA500"),q.strokeStyle=le(on,.8),I=Ae}}if(Qt>Kt&&de){let Ae=r[ge];Ae!=null&&ue-Ae>fe&&(tt=!0)}if(ueCt){tt=!0;continue}let Be=J.left+(ue-pt)*Vt,Je=re+(Me-kt)*ae;if(tt)q.moveTo(Be,Je),tt=!1;else{if(et){let Ae=r[ge];q.lineTo(J.left+(Ae-pt)*Vt,Je)}q.lineTo(Be,Je)}ge=Qt}q.stroke(),q.restore()}})();var Wl={"Heart Rate":Nt.hr.icon,Cadence:Nt.cadence.icon,Power:Nt.power.icon,Temperature:Nt.temperature.icon,Shifting:Nt.gears.icon,Battery:Nt.battery.icon},Pn=()=>{},$o=()=>{};function Po(t,n){Pn=t,$o=n}function Lo(){let t=document.getElementById("details-view");t&&(t.innerHTML=`
no_sim
Select a track for details
- `)}var on=16384,ln=[new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on),new Float64Array(on)],Io=[2,3,4,5,6,8,10,12,15,18,20,25,30,35,40,45,50,60,75,90,105,120,150,180,210,240,300,360,420,480];function an(e,n=[],t=[]){let s=document.getElementById("details-view");if(!s)return;if(!e){s.innerHTML="";return}let o=e.stats,a=e.points[0].time,p=t.length>0?t:[e],c=0;for(let v=0;v=w)continue;let z=1/W,de=Math.max(1,W>>1);for(let y=0;y<7;y++){let m=ln[y],r=0,J=0,V=0,ee=0,U=1/(10+y*15+G*2+E*3);for(let Q=0;Q=W){let re=m[Q-W];r-=re,J-=re*re;let Fe=r*z,se=Math.max(0,J*z-Fe*Fe),me=m[Q-de],fe=ke-m[Q-1],Pe=fe*fe*U,j=q?Math.exp(-Pe):1/(1+Pe);ee+=fe*fe*j;let H=_?Math.exp(-se*1e-4):1/(1+se*1e-4);V+=(ke-Fe)*(me-Fe)*H}}c+=(V+ee*.001)/w}}}}}let d=Math.min(99.9,Math.max(80,95+Math.tanh(c*.002)*4.5)).toFixed(1);s.innerHTML=` + `)}var cn=16384,Ue=[new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn)],Co=[3,5,10,15,20,30,45,60,90];function ql(t,n){let s=t.points,e=Math.min(s.length,cn),l=0;for(let k=0;k=e)continue;let h=1/P,b=Math.max(1,P>>1);for(let p=0;p<7;p++){let S=Ue[p],_=0,W=0,O=0,Y=0,Z=1/(10+p*15+k*2);for(let lt=0;lt=P){let rt=S[lt-P];_-=rt,W-=rt*rt;let x=_*h,v=Math.max(0,W*h-x*x),u=S[lt-b],N=Ft-S[lt-1],E=N*N*Z,G=k<4?Math.exp(-E):1/(1+E);Y+=N*N*G;let U=1/(1+v*1e-4);O+=(Ft-x)*(u-x)*U}}l+=(O+Y*.001)/Math.max(1,e)}}let i=t.stats.sections||Jt.analyzeTrackSections(s),a=[];for(let k=0;kP[1].secs-k[1].secs).slice(0,8).map(([k,P])=>({combo:k,ratio:(P.front/Math.max(1,P.rear)).toFixed(2),seconds:P.secs,pct:Number((P.secs/Math.max(1,e)*100).toFixed(1)),avgPower:Math.round(P.pwrSum/Math.max(1,P.secs)),avgCadence:Math.round(P.cadSum/Math.max(1,P.secs))})),w=n.length>0?n:[t],g=1,f=1,A=1,C=0,$=0;for(let k=0;kt.stats.totalDist&&g++,(P.avgPower||0)>(t.stats.avgPower||0)&&f++,P.elevGain>t.stats.elevGain&&A++}let M=Math.round(C/Math.max(1,w.length)),m=($/Math.max(1,w.length)/1e3).toFixed(1);return{stabilityAccum:l,splitRows:a.slice(0,12),gearMatrix:d,peerSummary:{cohortSize:w.length,distRank:g,pwrRank:f,elevRank:A,cohortAvgPower:M,cohortAvgDistKm:m}}}function Ee(t,n=[],s=[],e){let l=document.getElementById("details-view");if(!l)return;if(!t){l.innerHTML="";return}let i=t;if(e&&e.length===2){let h=t.points[0]?.time||0,b=h+e[0]*1e3,p=h+e[1]*1e3,S=Math.max(0,t.points.findIndex(W=>(W.time||0)>=b)),_=t.points.findIndex(W=>(W.time||0)>=p);if(_===-1&&(_=t.points.length-1),_>S+2){let W=t.points.slice(S,_+1),O=Jt.computeStats(W,!0);i={...t,points:W,stats:O}}}let a=i.stats,c=i.points[0].time;Jt.ensureCurvesAndZones(i);let d=ql(i,s),w=Math.min(99.9,Math.max(80,95+Math.tanh(d.stabilityAccum*.002)*4.5)).toFixed(1);l.innerHTML=`
- +
@@ -53,7 +53,7 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams(
- ${n.map(v=>`
@@ -64,23 +64,23 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams(
Distance
-
${(o.totalDist/1e3).toFixed(2)} km
+
${(a.totalDist/1e3).toFixed(2)} km
Duration
-
${o.duration?ht(Math.floor(o.duration/1e3)):"\u2014"}
+
${a.duration?he(Math.floor(a.duration/1e3)):"\u2014"}
Avg Speed
-
${o.avgSpeed?(o.avgSpeed*3.6).toFixed(1):"\u2014"} km/h
+
${a.avgSpeed?(a.avgSpeed*3.6).toFixed(1):"\u2014"} km/h
Max Speed
-
${(o.maxSpeed*3.6).toFixed(1)} km/h
+
${(a.maxSpeed*3.6).toFixed(1)} km/h
- ${o.avgBattery!==null?`
+ ${a.avgBattery!==null?`
Avg Battery
-
${o.avgBattery}%
+
${a.avgBattery}%
`:""}
@@ -90,32 +90,32 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams(
Original Filename
-
${pt(e.fileName||"\u2014")}
+
${me(t.fileName||"\u2014")}
File Size
-
${e.fileSize?hl(e.fileSize):"\u2014"}
+
${t.fileSize?Mo(t.fileSize):"\u2014"}
Format
-
${e.format.toUpperCase()}
+
${t.format.toUpperCase()}
Sport
- ${bl(e.sport)} - ${pt(Nt[e.sport?.toLowerCase()||""]?.name||"\u2014")} + ${Eo(t.sport)} + ${me(Ye[t.sport?.toLowerCase()||""]?.name||"\u2014")} expand_more - ${e.subSport?`(${pt(e.subSport)})`:""} + ${t.subSport?`(${me(t.subSport)})`:""}
Device / Creator
-
${e.device||"Unknown Device"}
+
${t.device||"Unknown Device"}
Start Time
-
${a?gl(a):"Unknown"}
+
${c?So(c):"Unknown"}
@@ -125,87 +125,150 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams(
Total Points
-
${e.points.length.toLocaleString("en-US")} pts
+
${t.points.length.toLocaleString("en-US")} pts
Telemetry Stability
-
${d}%
+
${w}%
Sensors Found
- ${o.sensors.length?o.sensors.map(v=>`${Ao[v]||"sensors"}`).join(""):'GPS only'} + ${a.sensors.length?a.sensors.map(h=>`${Wl[h]||"sensors"}`).join(""):'GPS only'}
- ${o.avgHR||o.avgPower||o.avgCadence||o.avgTemp!=null?` + ${a.avgHR||a.avgPower||a.avgCadence||a.avgTemp!=null?`
monitoringBiometric Averages
- ${o.avgHR?`
+ ${a.avgHR?`
Avg HR
-
${o.avgHR} bpm
+
${a.avgHR} bpm
`:""} - ${o.maxHR?`
+ ${a.maxHR?`
Max HR
-
${o.maxHR} bpm
+
${a.maxHR} bpm
`:""} - ${o.avgPower?`
+ ${a.avgPower?`
Avg Power
-
${o.avgPower} W
+
${a.avgPower} W
`:""} - ${o.maxPower?`
+ ${a.maxPower?`
Max Power
-
${o.maxPower} W
+
${a.maxPower} W
`:""} - ${o.avgCadence?`
+ ${a.avgCadence?`
Avg Cadence
-
${o.avgCadence} rpm
+
${a.avgCadence} rpm
`:""} - ${o.avgTemp!=null?`
+ ${a.avgTemp!=null?`
Avg Temp
-
${o.avgTemp.toFixed(1)} \xB0C
+
${a.avgTemp.toFixed(1)} \xB0C
`:""} - ${o.minTemp!=null&&o.maxTemp!=null?`
+ ${a.minTemp!=null&&a.maxTemp!=null?`
Temp Range
-
${o.minTemp.toFixed(1)} \u2013 ${o.maxTemp.toFixed(1)} \xB0C
+
${a.minTemp.toFixed(1)} \u2013 ${a.maxTemp.toFixed(1)} \xB0C
`:""}
`:""} - ${o.shifts!==null?` + ${a.shifts!==null||d.gearMatrix.length>0?`
-
settingsDrivetrain
-
+
settingsDrivetrain & Gear Matrix
+
Total Shifts
-
${o.shifts}
+
${a.shifts??0}
+
+
+
Cohort Power Rank
+
#${d.peerSummary.pwrRank} / ${d.peerSummary.cohortSize} (${d.peerSummary.cohortAvgPower} W avg)
+ + + + + + + + + + + + ${d.gearMatrix.map(h=>` + + + + + + + + `).join("")} + +
GearRatioShareAvg WCad
${me(h.combo)}${h.ratio}${h.pct}% (${h.seconds}s)${h.avgPower} W${h.avgCadence} rpm
`:""} - ${e.devices&&e.devices.length>0?` + ${d.splitRows.length>0?` +
+
splitscreenSection & Kilometer Splits (${d.splitRows.length})
+ + + + + + + + + + + + + + + + + ${d.splitRows.map(h=>` + + + + + + + + + + + + + `).join("")} + +
SectionDistTimeGainSpeedPowerHRCadTempStability
${me(h.label)}${h.distKm} km${h.durationStr}+${h.elevGain} m${h.avgSpeedKmh} km/h${h.avgPower} W${h.avgHR} bpm${h.avgCadence} rpm${h.avgTemp} \xB0C${h.stabilityPct}%
+
`:""} + + ${t.devices&&t.devices.length>0?`
watchHardware & Sensors
- ${(()=>{let v=new Set;return e.devices.filter(u=>{if(!(u.name||u.product||u.manufacturer))return!1;let E=`${u.name}|${u.product}|${u.manufacturer}|${u.serial}`;return v.has(E)?!1:(v.add(E),!0)}).map(u=>{let w=u.name||u.product||"Unknown Device",E=u.manufacturer?`${u.manufacturer}`:"",N=[u.serial?`SN: ${u.serial}`:null,u.version?`v${u.version}`:null,u.hardwareVersion?`hw:${u.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),G=[u.batteryLevel?`${u.batteryLevel}%`:null,u.batteryStatus?`Status: ${u.batteryStatus}`:null,u.batteryVoltage?`${u.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),q="",_=String(u.sourceType||"").toLowerCase();_.includes("local")?q="memory":_.includes("antplus")||_.includes("ant_plus")?q="settings_input_antenna":_.includes("bluetooth")&&(q="bluetooth");let W="sensors",z=String(w).toLowerCase();return z.includes("heartrate")||z.includes("hrm")?W=We.hr.icon:z.includes("power")?W=We.power.icon:z.includes("speed")?W=We.speed.icon:z.includes("cadence")?W=We.cadence.icon:z.includes("barometer")?W="air":z.includes("temperature")?W=We.temperature.icon:z.includes("gps")&&(W="location_on"),` + ${(()=>{let h=new Set;return t.devices.filter(b=>{if(!(b.name||b.product||b.manufacturer))return!1;let S=`${b.name}|${b.product}|${b.manufacturer}|${b.serial}`;return h.has(S)?!1:(h.add(S),!0)}).map(b=>{let p=b.name||b.product||"Unknown Device",S=b.manufacturer?`${b.manufacturer}`:"",_=[b.serial?`SN: ${b.serial}`:null,b.version?`v${b.version}`:null,b.hardwareVersion?`hw:${b.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),W=[b.batteryLevel?`${b.batteryLevel}%`:null,b.batteryStatus?`Status: ${b.batteryStatus}`:null,b.batteryVoltage?`${b.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),O="",Y=String(b.sourceType||"").toLowerCase();Y.includes("local")?O="memory":Y.includes("antplus")||Y.includes("ant_plus")?O="settings_input_antenna":Y.includes("bluetooth")&&(O="bluetooth");let Z="sensors",lt=String(p).toLowerCase();return lt.includes("heartrate")||lt.includes("hrm")?Z=Nt.hr.icon:lt.includes("power")?Z=Nt.power.icon:lt.includes("speed")?Z=Nt.speed.icon:lt.includes("cadence")?Z=Nt.cadence.icon:lt.includes("barometer")?Z="air":lt.includes("temperature")?Z=Nt.temperature.icon:lt.includes("gps")&&(Z="location_on"),`
- ${W} -
${pt(w)}
- ${q?`${q}`:""} + ${Z} +
${me(p)}
+ ${O?`${O}`:""}
-
${E}
+
${S}
- ${N?`
${pt(N)}
`:""} + ${_?`
${me(_)}
`:""}
-
${pt(u.type||"device")}
- ${G?`
+
${me(b.type||"device")}
+ ${W?`
battery_charging_full - ${pt(G)} + ${me(W)}
`:""}
@@ -221,51 +284,51 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams(
- `;let x=document.getElementById("tag-container"),g=document.getElementById("new-tag-input"),T=document.getElementById("btn-add-tag"),$=()=>{x.innerHTML="";let v=e.tags||[];if(v.length===0){x.innerHTML='No tags added';return}v.forEach(u=>{let w=hs(u),E=document.createElement("div");E.className="tag-pill font-s",E.style.cssText=` - background: ${w}15; - border: 1px solid ${w}44; - color: ${w}; + `;let g=document.getElementById("tag-container"),f=document.getElementById("new-tag-input"),A=document.getElementById("btn-add-tag"),C=()=>{g.innerHTML="";let h=t.tags||[];if(h.length===0){g.innerHTML='No tags added';return}h.forEach(b=>{let p=Ts(b),S=document.createElement("div");S.className="tag-pill font-s",S.style.cssText=` + background: ${p}15; + border: 1px solid ${p}44; + color: ${p}; padding: 2px 8px; border-radius: 4px; font-weight: 600; display: flex; align-items: center; gap: 6px; - `,E.innerHTML=` - ${pt(u)} - close - `,x.appendChild(E)}),x.querySelectorAll(".btn-remove-tag").forEach(u=>{u.addEventListener("click",async w=>{let E=w.currentTarget.dataset.tag;e.tags=(e.tags||[]).filter(N=>N!==E),await at.save(e),$(),Mn()})})},M=async()=>{let v=g.value.trim().toLowerCase();if(!v)return;let u=new Set(e.tags||[]);if(u.has(v)){g.value="";return}u.add(v),e.tags=Array.from(u).sort(),await at.save(e),g.value="",$(),Mn()};T.addEventListener("click",M),g.addEventListener("keydown",v=>{v.key==="Enter"&&M()});let C=s.querySelector("#details-title-input");C?.addEventListener("change",async()=>{let v=C.value.trim();v&&(e.displayName=v,await at.save(e),Mn())});let k=document.getElementById("sport-dropdown-trigger");k?.addEventListener("click",v=>{v.stopPropagation(),f(k)});function f(v){if(!e)return;document.querySelectorAll(".metric-menu-popup").forEach(q=>q.remove());let u=document.createElement("div");u.className="metric-menu-popup",Object.keys(Nt).forEach(q=>{let _=Nt[q],W=document.createElement("div"),z=e.sport?.toLowerCase()===q;W.className=`menu-item ${z?"active":""}`,W.innerHTML=` - ${_.icon} - ${_.name} - ${z?"check":""} - `,W.addEventListener("click",async()=>{e.sport=q,await at.save(e),u.remove();let de=document.getElementById("sport-icon");de&&(de.textContent=_.icon);let y=document.getElementById("sport-name");y&&(y.textContent=_.name),Mn()}),u.appendChild(W)});let w=document.createElement("div"),E=!e.sport;w.className=`menu-item ${E?"active":""}`,w.innerHTML=` + `,S.innerHTML=` + ${me(b)} + close + `,g.appendChild(S)}),g.querySelectorAll(".btn-remove-tag").forEach(b=>{b.addEventListener("click",async p=>{let S=p.currentTarget.dataset.tag;t.tags=(t.tags||[]).filter(_=>_!==S),await ce.save(t),C(),Pn()})})},$=async()=>{let h=f.value.trim().toLowerCase();if(!h)return;let b=new Set(t.tags||[]);if(b.has(h)){f.value="";return}b.add(h),t.tags=Array.from(b).sort(),await ce.save(t),f.value="",C(),Pn()};A.addEventListener("click",$),f.addEventListener("keydown",h=>{h.key==="Enter"&&$()});let M=l.querySelector("#details-title-input");M?.addEventListener("change",async()=>{let h=M.value.trim();h&&(t.displayName=h,await ce.save(t),Pn())});let m=document.getElementById("sport-dropdown-trigger");m?.addEventListener("click",h=>{h.stopPropagation(),k(m)});function k(h){if(!t)return;document.querySelectorAll(".metric-menu-popup").forEach(O=>O.remove());let b=document.createElement("div");b.className="metric-menu-popup",Object.keys(Ye).forEach(O=>{let Y=Ye[O],Z=document.createElement("div"),lt=t.sport?.toLowerCase()===O;Z.className=`menu-item ${lt?"active":""}`,Z.innerHTML=` + ${Y.icon} + ${Y.name} + ${lt?"check":""} + `,Z.addEventListener("click",async()=>{t.sport=O,await ce.save(t),b.remove();let Ft=document.getElementById("sport-icon");Ft&&(Ft.textContent=Y.icon);let rt=document.getElementById("sport-name");rt&&(rt.textContent=Y.name),Pn()}),b.appendChild(Z)});let p=document.createElement("div"),S=!t.sport;p.className=`menu-item ${S?"active":""}`,p.innerHTML=` block \u2014 - ${E?"check":""} - `,w.addEventListener("click",async()=>{e.sport=void 0,await at.save(e),u.remove();let q=document.getElementById("sport-icon");q&&(q.textContent="question_mark");let _=document.getElementById("sport-name");_&&(_.textContent="\u2014"),Mn()}),u.appendChild(w),document.body.appendChild(u);let N=v.getBoundingClientRect();u.style.top=`${N.bottom+window.scrollY+4}px`,u.style.left=`${N.left+window.scrollX}px`;let G=q=>{!u.contains(q.target)&&!v.contains(q.target)&&(u.remove(),document.removeEventListener("click",G))};setTimeout(()=>document.addEventListener("click",G),10)}$(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${e.name}"?`)&&yl(e.id)})}import Wo from"uplot";var wt=[];function Pl(e){return wt.filter(n=>{if(n.points.length===0)return!1;for(let t of n.points){let s=!1;for(let o of e.points)if(sn(t.lat,t.lon,o.lat,o.lon)<=t.radius){s=!0;break}if(!s)return!1}return!0})}var $n=null,Yn=!1,Cn=null,Al=()=>{},Ho=null;function Il(e){Al=e,Fo()}function Hl(){wt=[],$n=null,Cn=null,Yn=!1;let e=document.getElementById("courses-view");e&&(e.innerHTML=` + ${S?"check":""} + `,p.addEventListener("click",async()=>{t.sport=void 0,await ce.save(t),b.remove();let O=document.getElementById("sport-icon");O&&(O.textContent="question_mark");let Y=document.getElementById("sport-name");Y&&(Y.textContent="\u2014"),Pn()}),b.appendChild(p),document.body.appendChild(b);let _=h.getBoundingClientRect();b.style.top=`${_.bottom+window.scrollY+4}px`,b.style.left=`${_.left+window.scrollX}px`;let W=O=>{!b.contains(O.target)&&!h.contains(O.target)&&(b.remove(),document.removeEventListener("click",W))};setTimeout(()=>document.addEventListener("click",W),10)}C(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${t.name}"?`)&&$o(t.id)})}import Zl from"uplot";var we=[];function No(t){return we.filter(n=>{if(n.points.length===0)return!1;for(let s of n.points){let e=!1;for(let l of t.points)if(en(s.lat,s.lon,l.lat,l.lon)<=s.radius){e=!0;break}if(!e)return!1}return!0})}var un=null,Yn=!1,dn=null,Wo=()=>{},zl=null;function qo(t){Wo=t,Ul()}function zo(){we=[],un=null,dn=null,Yn=!1;let t=document.getElementById("courses-view");t&&(t.innerHTML=`
route
No courses created yet
- `)}function Bs(e){wt=[];for(let n=0;n0&&($n=wt[0].id,Cn=wt[0].id)}async function Fo(){try{let e=await at.get("courses");e&&(wt=e)}catch(e){console.error("Courses: Failed to load courses",e)}}async function _s(){try{await at.set("courses",wt)}catch(e){console.error("Courses: Failed to save courses",e),Al("Failed to save courses","error")}}function Bo(e){let n=0;for(let t=0;tt)return{duration:0,dist:0,avgWatts:null,avgHR:null,avgSpeed:null,avgCadence:null,avgVam:null};let a=Math.max(0,Math.min(n,o-1)),p=Math.max(a,Math.min(t,o-1)),c=s[a]?.time||0,x=((s[p]?.time||0)-c)/1e3,g=0,T=0,$=0,M=0,C=0,k=0,f=0,F=0,v=0;for(let w=a;w<=p;w++){let E=s[w];if(E.power!=null&&(g+=E.power,T++),E.hr!=null&&($+=E.hr,M++),E.speed!=null&&(C+=E.speed,k++),E.cadence!=null&&(f+=E.cadence,F++),w>a){let N=s[w-1];if(E.ele!=null&&N.ele!=null){let G=E.ele-N.ele;G>0&&(v+=G)}}}let u=p>a?(s[p].dist||0)-(s[a].dist||0):0;return{duration:x,dist:u,avgWatts:T>0?Math.round(g/T):null,avgHR:M>0?Math.round($/M):null,avgSpeed:k>0?C/k:null,avgCadence:F>0?Math.round(f/F):null,avgVam:x>0?Math.round(v/(x/3600)):null}}function _o(e){let n=Math.floor(e/3600),t=Math.floor(e%3600/60),s=Math.floor(e%60);return n>0?`${n}:${t.toString().padStart(2,"0")}:${s.toString().padStart(2,"0")}`:`${t}:${s.toString().padStart(2,"0")}`}function Rs(){return` + `)}function Us(t){we=[];let n=[{trackIdx:0,suffix:"Full Loop",fracs:[.1,.5,.85],radius:450},{trackIdx:1,suffix:"Opening Climb Sector",fracs:[.08,.25,.45],radius:450},{trackIdx:2,suffix:"Lakeside Corridor",fracs:[.1,.45,.8],radius:850},{trackIdx:3,suffix:"Sprint Interval Sector",fracs:[.2,.5,.75],radius:850},{trackIdx:4,suffix:"Alpine Grand Tour Stage",fracs:[.1,.5,.85],radius:900},{trackIdx:5,suffix:"Summit Finish Climb",fracs:[.5,.72,.92],radius:900}];for(let s=0;s0&&(un=we[0].id,dn=we[0].id)}function Uo(){return we.map(t=>t.id)}async function Ul(){try{let t=await ce.get("courses");t&&(we=t)}catch(t){console.error("Courses: Failed to load courses",t)}}async function Vs(){try{await ce.set("courses",we)}catch(t){console.error("Courses: Failed to save courses",t),Wo("Failed to save courses","error")}}function Vl(t){let n=0;for(let s=0;ss)return{duration:0,dist:0,avgWatts:null,avgHR:null,avgSpeed:null,avgCadence:null,avgVam:null};let i=Math.max(0,Math.min(n,l-1)),a=Math.max(i,Math.min(s,l-1)),c=e[i]?.time||0,w=((e[a]?.time||0)-c)/1e3,g=0,f=0,A=0,C=0,$=0,M=0,m=0,k=0,P=0;for(let b=i;b<=a;b++){let p=e[b];if(p.power!=null&&(g+=p.power,f++),p.hr!=null&&(A+=p.hr,C++),p.speed!=null&&($+=p.speed,M++),p.cadence!=null&&(m+=p.cadence,k++),b>i){let S=e[b-1];if(p.ele!=null&&S.ele!=null){let _=p.ele-S.ele;_>0&&(P+=_)}}}let h=a>i?(e[a].dist||0)-(e[i].dist||0):0;return{duration:w,dist:h,avgWatts:f>0?Math.round(g/f):null,avgHR:C>0?Math.round(A/C):null,avgSpeed:M>0?$/M:null,avgCadence:k>0?Math.round(m/k):null,avgVam:w>0?Math.round(P/(w/3600)):null}}function Ol(t){let n=Math.floor(t/3600),s=Math.floor(t%3600/60),e=Math.floor(t%60);return n>0?`${n}:${s.toString().padStart(2,"0")}:${e.toString().padStart(2,"0")}`:`${s}:${e.toString().padStart(2,"0")}`}function Os(){return` calendar_today Date straighten Distance timer Duration speed Speed speed Pace - trending_up VAM + trending_up VAM bolt Power favorite HR - `}function Ns(e,n,t){let o=(n?Nt[n.toLowerCase()]:null)?.paceUnit||"km",a="--";if(e.avgSpeed!=null&&e.avgSpeed>.1){let p=(o==="km"?1e3:100)/e.avgSpeed;a=`${On(p)} min/${o}`}return` - ${t} - ${e.dist!=null?`${(e.dist/1e3).toFixed(2)} km`:"-"} - ${_o(e.duration)} - ${e.avgSpeed!=null?`${(e.avgSpeed*3.6).toFixed(1)} km/h`:"-"} - ${a} - ${e.avgVam!=null?`${e.avgVam} m/h`:"-"} - ${e.avgWatts!=null?`${e.avgWatts} W`:"-"} - ${e.avgHR!=null?`${e.avgHR} bpm`:"-"} - `}var ws=16384,Tl=new Float64Array(ws),El=new Float64Array(ws),Sl=new Float64Array(ws),Ml=new Float64Array(32),kl=new Float64Array(32),Xt=180,Cl=28,$l=new Float64Array(Xt),Ll=new Float64Array(Xt),kn=new Float64Array(Xt+1),ys=new Float64Array(Xt+1);function Wt(){let e=document.getElementById("courses-view");if(!e)return;let n=0;for(let t of wt){if(t.points.length<2)continue;let s=De.findTracksPassingThroughPoints(t.points.map(a=>({lat:a.lat,lng:a.lon})),t.points[0]?.radius||20),o=4;for(let a=0;a.1){let a=(l==="km"?1e3:100)/t.avgSpeed;i=`${On(a)} min/${l}`}return` + ${s} + ${t.dist!=null?`${(t.dist/1e3).toFixed(2)} km`:"-"} + ${Ol(t.duration)} + ${t.avgSpeed!=null?`${(t.avgSpeed*3.6).toFixed(1)} km/h`:"-"} + ${i} + ${t.avgVam!=null?`${t.avgVam} m/h`:"-"} + ${t.avgWatts!=null?`${t.avgWatts} W`:"-"} + ${t.avgHR!=null?`${t.avgHR} bpm`:"-"} + `}var Cs=16384,Ao=new Float64Array(Cs),Io=new Float64Array(Cs),Ho=new Float64Array(Cs),Fo=new Float64Array(32),Do=new Float64Array(32),sn=180,Bo=28,_o=new Float64Array(sn),Ro=new Float64Array(sn),Ln=new Float64Array(sn+1),Es=new Float64Array(sn+1);function je(){let t=document.getElementById("courses-view");if(!t)return;let n=0,s=dn||un?we.filter(e=>e.id===dn||e.id===un):we;for(let e of s){if(e.points.length<2)continue;let l=Bt.findTracksPassingThroughPoints(e.points.map(a=>({lat:a.lat,lng:a.lon})),e.points[0]?.radius||20),i=4;for(let a=0;a
@@ -283,33 +346,33 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams(
- ${wt.length===0?` + ${we.length===0?`
route
No courses created yet
- `:wt.map(t=>{let s=t.points.map(c=>({lat:c.lat,lng:c.lon})),o=De.findTracksPassingThroughPoints(s,t.points[0]?.radius||20),a=t.id===Cn,p="";if(a){let c=o.map(d=>{let x=De.getTrackData(d);if(!x)return null;let g=xs(x,t.points);if(!g)return null;let T=Ds(x,g.startIdx,g.endIdx),$=x.stats?.startTime||x.points?.[0]?.time,M=$?Gt($):"-";return{id:d,displayName:x.displayName||x.name||d,date:M,sport:x.sport,color:x.color,...T,startIdx:g.startIdx,endIdx:g.endIdx}}).filter(d=>d!==null);c.sort((d,x)=>d.duration-x.duration||d.id.localeCompare(x.id)),p=` + `:we.map(e=>{let l=e.points.map(d=>({lat:d.lat,lng:d.lon})),i=Bt.findTracksPassingThroughPoints(l,e.points[0]?.radius||20),a=e.id===dn,c="";if(a){let d=i.map(w=>{let g=Bt.getTrackData(w);if(!g)return null;let f=ks(g,e.points);if(!f)return null;let A=wn(g,f.startIdx,f.endIdx),C=Math.max(1,f.endIdx-f.startIdx),$=f.startIdx+Math.floor(C*.25),M=f.startIdx+Math.floor(C*.5),m=f.startIdx+Math.floor(C*.75),k=wn(g,f.startIdx,$),P=wn(g,$,M),h=wn(g,M,m),b=wn(g,m,f.endIdx),p=g.stats?.startTime||g.points?.[0]?.time,S=p?nn(p):"-";return{id:w,displayName:g.displayName||g.name||w,date:S,sport:g.sport,color:g.color,...A,splitsSummary:`${k.avgWatts||0}/${P.avgWatts||0}/${h.avgWatts||0}/${b.avgWatts||0}W`,startIdx:f.startIdx,endIdx:f.endIdx}}).filter(w=>w!==null);d.sort((w,g)=>w.duration-g.duration||w.id.localeCompare(g.id)),c=`
- ${c.length===0?` + ${d.length===0?`
No matching tracks
`:` - - ${Rs()} + + ${Os()} - ${c.map(d=>` - + ${d.map(w=>` + - ${Ns(d,d.sport,d.date)} + ${Ys(w,w.sport,w.date)} `).join("")} @@ -317,53 +380,53 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams( `} `}return` -
+
${a?"expand_more":"chevron_right"} -
${pt(t.name)} edit
-
straighten ${Bo(t).toFixed(2)} km | ${t.points.length} points | ${o.length} matching tracks
+
${me(e.name)} edit
+
straighten ${Vl(e).toFixed(2)} km | ${e.points.length} points | ${i.length} matching tracks
- ${p} + ${c}
`}).join("")}
- `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{Do()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{Yn=!1,De.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),Wt()}),e.querySelectorAll(".course-item").forEach(t=>{let s=t.dataset.id;t.querySelector(".btn-edit-course")?.addEventListener("click",o=>{o.stopPropagation(),Fl(s)}),t.querySelector(".btn-rename-course")?.addEventListener("click",o=>{o.stopPropagation(),Ro(s)}),t.querySelector(".btn-delete-course")?.addEventListener("click",o=>{o.stopPropagation(),No(s)}),t.querySelector(".course-item-header")?.addEventListener("click",o=>{o.target.closest(".course-actions")||o.target.closest(".btn-rename-course")||(Ln(s),Cn=Cn===s?null:s,Wt())}),t.querySelectorAll(".course-track-row").forEach(o=>{let a=o.dataset.trackId,p=parseInt(o.dataset.start,10),c=parseInt(o.dataset.end,10);o.querySelector(".track-name-cell")?.addEventListener("click",d=>{d.stopPropagation();let x=De.getTrackData(a);x&&(Mt(a,!1),setTimeout(()=>{let g=x.points,T=g.find(u=>u.time!=null)?.time||0,$=Math.max(0,Math.min(p,g.length-1)),M=Math.max(0,Math.min(c,g.length-1)),C=Math.max(0,((g[$]?.time||0)-T)/1e3),k=Math.max(0,((g[M]?.time||0)-T)/1e3),f=Se.getXAxis(),F=C,v=k;f==="distance"&&(F=Math.max(0,(g[$]?.dist||0)/1e3),v=Math.max(0,(g[M]?.dist||0)/1e3)),Ye.patch({sel:[F,v],tab:"graphs"},!0),Se.restoreSelection(C,k),De.highlightSegment(a,x.points,p,c,!0)},50))}),o.addEventListener("mouseenter",()=>{De.setTrackHover(a,!0)}),o.addEventListener("mouseleave",()=>{De.setTrackHover(a,!1)})})})}function Do(){let e=`Course ${wt.length+1}`,n={id:Math.random().toString(36).substring(2,9),name:e,points:[]};wt.push(n),_s(),Wt(),Fl(n.id)}function Ro(e){let n=wt.find(c=>c.id===e);if(!n)return;let t=document.querySelector(`.course-item[data-id="${e}"]`);if(!t)return;let s=t.querySelector(".course-name");if(!s)return;let o=n.name;s.innerHTML=``;let a=s.querySelector(".course-name-input");a.focus(),a.select();let p=()=>{let c=a.value.trim();c!==""&&(n.name=c,_s()),Wt()};a.addEventListener("blur",p),a.addEventListener("keydown",c=>{c.key==="Enter"?p():c.key==="Escape"&&Wt()})}function Fl(e){$n=e,Yn=!0,Wt()}function Bl(){Ho=null}function Ln(e,n=!1){$n=e,n&&(Cn=e),Yn=!1,De.setCustomClickHandler(null),Bl(),Wt()}function No(e){confirm("Are you sure you want to delete this course?")&&(wt=wt.filter(n=>n.id!==e),$n===e&&($n=null,Bl()),_s(),Wt())}var Es=()=>{},Ws=[];function zl(){Ws.forEach(e=>e.destroy()),Ws=[]}function ql(e){Es=e}function Ul(){zl(),document.querySelectorAll(".hr-settings-popup").forEach(n=>n.remove());let e=document.getElementById("insights-view");e&&(e.innerHTML=` + `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{Yl()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{Yn=!1,Bt.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),je()}),t.querySelectorAll(".course-item").forEach(e=>{let l=e.dataset.id;e.querySelector(".btn-edit-course")?.addEventListener("click",i=>{i.stopPropagation(),Vo(l)}),e.querySelector(".btn-rename-course")?.addEventListener("click",i=>{i.stopPropagation(),jl(l)}),e.querySelector(".btn-delete-course")?.addEventListener("click",i=>{i.stopPropagation(),Gl(l)}),e.querySelector(".course-item-header")?.addEventListener("click",i=>{i.target.closest(".course-actions")||i.target.closest(".btn-rename-course")||(Tn(l),dn=dn===l?null:l,je())}),e.querySelectorAll(".course-track-row").forEach(i=>{let a=i.dataset.trackId,c=parseInt(i.dataset.start,10),d=parseInt(i.dataset.end,10);i.querySelector(".track-name-cell")?.addEventListener("click",w=>{w.stopPropagation();let g=Bt.getTrackData(a);g&&(_e(a,!1),setTimeout(()=>{let f=g.points,A=f.find(b=>b.time!=null)?.time||0,C=Math.max(0,Math.min(c,f.length-1)),$=Math.max(0,Math.min(d,f.length-1)),M=Math.max(0,((f[C]?.time||0)-A)/1e3),m=Math.max(0,((f[$]?.time||0)-A)/1e3),k=ft.getXAxis(),P=M,h=m;k==="distance"&&(P=Math.max(0,(f[C]?.dist||0)/1e3),h=Math.max(0,(f[$]?.dist||0)/1e3)),Gt.patch({sel:[P,h],tab:"graphs"},!0),ft.restoreSelection(M,m),Bt.highlightSegment(a,g.points,c,d,!0)},50))}),i.addEventListener("mouseenter",()=>{Bt.setTrackHover(a,!0)}),i.addEventListener("mouseleave",()=>{Bt.setTrackHover(a,!1)})})})}function Yl(){let t=`Course ${we.length+1}`,n={id:Math.random().toString(36).substring(2,9),name:t,points:[]};we.push(n),Vs(),je(),Vo(n.id)}function jl(t){let n=we.find(c=>c.id===t);if(!n)return;let s=document.querySelector(`.course-item[data-id="${t}"]`);if(!s)return;let e=s.querySelector(".course-name");if(!e)return;let l=n.name;e.innerHTML=``;let i=e.querySelector(".course-name-input");i.focus(),i.select();let a=()=>{let c=i.value.trim();c!==""&&(n.name=c,Vs()),je()};i.addEventListener("blur",a),i.addEventListener("keydown",c=>{c.key==="Enter"?a():c.key==="Escape"&&je()})}function Vo(t){un=t,Yn=!0,je()}function Oo(){zl=null}function Tn(t,n=!1){un=t,n&&(dn=t),Yn=!1,Bt.setCustomClickHandler(null),Oo(),je()}function Gl(t){confirm("Are you sure you want to delete this course?")&&(we=we.filter(n=>n.id!==t),un===t&&(un=null,Oo()),Vs(),je())}var Ls=()=>{},js=[];function Qo(){js.forEach(t=>t.destroy()),js=[]}function Ko(t){Ls=t}function Jo(){Qo(),document.querySelectorAll(".hr-settings-popup").forEach(n=>n.remove());let t=document.getElementById("insights-view");t&&(t.innerHTML=`
no_sim
Select a track for insights
- `)}var rn=16384,_l=new Float64Array(rn),Dl=new Float64Array(rn),Rl=new Float64Array(rn),zo=new Float64Array(rn),qo=new Float64Array(rn),jn=new Float64Array(rn+1),Ts=new Float64Array(rn+1),Uo=[150,180,210,240,270,300,330,360,400,450,500,540,600,660,720,810,900,960,1020],Nl=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,420,600,900,1200];function Vo(e,n){let t=2e4,s=0;for(let o=0;o0?M*C*36:0;_l[d]=g,Dl[d]=1/T,Rl[d]=1/($+1),zo[d]=M,qo[d]=k,jn[d+1]=jn[d]+g,Ts[d+1]=Ts[d]+k}for(let d=0;d<36;d++){let x=1+d*.01,g=d*.005;for(let T=0;Tp)continue;let M=p-$,C=0,k=0;for(let f=0;f<=M;f++){let F=Ts[f+$]-Ts[f],v=(jn[f+$]-jn[f])*x+F*g,u=F+jn[f]*g;v>C&&(C=v),u>k&&(k=u)}s+=(C+k)/$}}let c=p>>1;for(let d=0;d<4;d++)for(let x=0;x<15;x++){let g=n*(.88+x*.02+d*.005),T=Uo[x]+d*10,$=2e4,M=0,C=0;for(let k=0;k0?v:0,E=Math.exp(-.008*(u+w*.625)),N=546*E+T;$=$-w*(1.05-.05*E)+(2e4-$)*(1/N),$0?Y*Z*36:0;Yo[p]=_,jo[p]=1/W,Go[p]=O,Xl[p]=Y,Ql[p]=lt,$s[p+1]=$s[p]+_,Ps[p+1]=Ps[p]+lt}let l=0;for(let p=0;pe)continue;let _=e-S,W=0,O=0;for(let Y=0;Y<=_;Y++){let Z=$s[Y+S]-$s[Y],lt=Ps[Y+S]-Ps[Y];Z>W&&(W=Z),lt>O&&(O=lt)}l+=(W+O)/S}let i=2e4,a=2e4,c=0,d=!1,w=e>>1,g=0,f=0,A=[0,0,0,0],C=88,$=n/C;for(let p=0;p0?O:0,Ft=546*Math.exp(-.008*(Y+Z*.625))+316;a=Math.min(2e4,a-Z+(2e4-a)*(1/Ft)),a17500&&d&&(d=!1);let rt=S/_;rt>=$&&_>=C?A[0]++:rt>=$&&_0?g/w:1,m=e-w>0?f/(e-w):1,k=M>0?(M-m)/M*100:0,P=[Number((A[0]/e*100).toFixed(1)),Number((A[1]/e*100).toFixed(1)),Number((A[2]/e*100).toFixed(1)),Number((A[3]/e*100).toFixed(1))],b=(s&&s.length>0?s.filter(p=>p.kind==="quarter"||p.kind==="climb"||p.kind==="sprint"):[]).slice(0,8).map(p=>{let S=p.stats,_=S.duration&&S.duration>0?S.duration/36e5:0;return{label:p.label,distKm:Number((S.totalDist/1e3).toFixed(2)),avgPower:S.avgPower||0,peak60sPower:S.powerCurve?.[60]?.power||S.avgPower||0,avgHR:S.avgHR||0,vam:_>0?Math.round(S.elevGain/_):0}});return l<-1e12&&(i=0),{minWPrimeBal:i,matchesBurned:c,decouplingPct:k,quadrantPct:P,sectionPeaks:b}}function be(t,n=[],s=null){Qo();let e=document.getElementById("insights-view");if(!e)return;if(!t){e.innerHTML="";return}Jt.ensureCurvesAndZones(t),t.stats.sections||(t.stats.sections=Jt.analyzeTrackSections(t.points));let l=s||Gt.get().sel||null,i=t.points,a=t.stats;if(l&&t.points.length>4){let M=t.points[0].time||0,m=M+l[0]*1e3,k=M+l[1]*1e3,P=t.points.findIndex(b=>(b.time||0)>=m),h=t.points.findIndex(b=>(b.time||0)>=k);P===-1&&(P=0),h===-1&&(h=t.points.length-1),h>P+4&&(i=t.points.slice(P,h+1),a=Jt.computeStats(i,!0))}if(!a.powerCurve&&!a.hrZones&&!a.hrCurve){e.innerHTML=`
analytics
No insights available for this track (requires Power or Heart Rate data)
- `;return}let o=n.length>0?n:[e],a=Vo(o,ot.getFTP());t.innerHTML=` -
- `;let p=document.getElementById("insights-grid");if(!p)return;let c=Math.round(p.getBoundingClientRect().width-42)||480;if(s.powerCurve&&Wl({grid:p,track:e,curve:s.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:We.power.color,icon:"bolt",chartWidth:c}),s.hrCurve&&Wl({grid:p,track:e,curve:s.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:We.hr.color,icon:"favorite",chartWidth:c}),s.powerZones){let $=document.createElement("div");$.className="insight-card";let M="power",C=We.power.color;$.style.setProperty("--chart-color",C);let k=Se.getMapColorMetric()===M,f=s.powerZones.reduce((u,w)=>u+w,0),F=Sn.getPowerZones(),v="";s.powerZones.forEach((u,w)=>{if(w>=F.length)return;let E=F[w],N=f>0?u/f*100:0,G=isFinite(E.max)?`${Math.round(E.min)} - ${Math.round(E.max)} W`:`> ${Math.round(E.min)} W`;v+=` + `;return}let c=Kl(i,Jt.getFTP(),t.stats.sections),d=c.minWPrimeBal;e.innerHTML=` +
+ `;let w=document.getElementById("insights-grid");if(!w)return;let g=Math.round(w.getBoundingClientRect().width-42)||480;if(a.powerCurve&&Xo({grid:w,track:t,curve:a.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:Nt.power.color,icon:"bolt",chartWidth:g}),a.hrCurve&&Xo({grid:w,track:t,curve:a.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:Nt.hr.color,icon:"favorite",chartWidth:g}),a.powerZones){let M=document.createElement("div");M.className="insight-card";let m="power",k=Nt.power.color;M.style.setProperty("--chart-color",k);let P=ft.getMapColorMetric()===m,h=a.powerZones.reduce((S,_)=>S+_,0),b=$n.getPowerZones(),p="";a.powerZones.forEach((S,_)=>{if(_>=b.length)return;let W=b[_],O=h>0?S/h*100:0,Y=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} W`:`> ${Math.round(W.min)} W`;p+=`
- Z${w+1} - ${E.name} - ${G} - ${ht(Math.round(u))} - ${N.toFixed(1)}% + Z${_+1} + ${W.name} + ${Y} + ${he(Math.round(S))} + ${O.toFixed(1)}%
-
+
- `}),$.innerHTML=` + `}),M.innerHTML=`
- boltPower Zones + boltPower Zones
-
@@ -371,27 +434,27 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams( settings
-
${v}
- `,p.appendChild($),$.querySelector(".map-color-btn")?.addEventListener("click",u=>{u.stopPropagation(),Se.toggleMapColor(M);let w=Se.getMapColorMetric();p.querySelectorAll(".map-color-btn").forEach(E=>{let N=E;N.classList.toggle("active",N.dataset.metric===w)})}),$.querySelector(".btn-pw-settings")?.addEventListener("click",u=>{u.stopPropagation(),Yo(u.currentTarget,e)})}if(s.hrZones){let $=document.createElement("div");$.className="insight-card";let M="hr",C=We.hr.color;$.style.setProperty("--chart-color",C);let k=Se.getMapColorMetric()===M,f=s.hrZones.reduce((u,w)=>u+w,0),F=Sn.getHRZones(),v="";s.hrZones.forEach((u,w)=>{if(w>=F.length)return;let E=F[w],N=f>0?u/f*100:0,G=isFinite(E.max)?`${Math.round(E.min)} - ${Math.round(E.max)} bpm`:`> ${Math.round(E.min)} bpm`;v+=` +
${p}
+ `,w.appendChild(M),M.querySelector(".map-color-btn")?.addEventListener("click",S=>{S.stopPropagation(),ft.toggleMapColor(m);let _=ft.getMapColorMetric();w.querySelectorAll(".map-color-btn").forEach(W=>{let O=W;O.classList.toggle("active",O.dataset.metric===_)})}),M.querySelector(".btn-pw-settings")?.addEventListener("click",S=>{S.stopPropagation(),ti(S.currentTarget,t)})}if(a.hrZones){let M=document.createElement("div");M.className="insight-card";let m="hr",k=Nt.hr.color;M.style.setProperty("--chart-color",k);let P=ft.getMapColorMetric()===m,h=a.hrZones.reduce((S,_)=>S+_,0),b=$n.getHRZones(),p="";a.hrZones.forEach((S,_)=>{if(_>=b.length)return;let W=b[_],O=h>0?S/h*100:0,Y=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} bpm`:`> ${Math.round(W.min)} bpm`;p+=`
- Z${w+1} - ${E.name} - ${G} - ${ht(Math.round(u))} - ${N.toFixed(1)}% + Z${_+1} + ${W.name} + ${Y} + ${he(Math.round(S))} + ${O.toFixed(1)}%
-
+
- `}),$.innerHTML=` + `}),M.innerHTML=`
- favoriteHeart Rate Zones + favoriteHeart Rate Zones
-
@@ -399,72 +462,111 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams( settings
-
${v}
- `,p.appendChild($),$.querySelector(".map-color-btn")?.addEventListener("click",u=>{u.stopPropagation(),Se.toggleMapColor(M);let w=Se.getMapColorMetric();p.querySelectorAll(".map-color-btn").forEach(E=>{let N=E;N.classList.toggle("active",N.dataset.metric===w)})}),$.querySelector(".btn-hr-settings")?.addEventListener("click",u=>{u.stopPropagation(),Oo(u.currentTarget,e)})}let d=document.createElement("div");d.className="insight-card";let x=s.totalDist/1e3,g=x>0?s.elevGain/(x*1e3)*100:0;if(d.innerHTML=` +
${p}
+ `,w.appendChild(M),M.querySelector(".map-color-btn")?.addEventListener("click",S=>{S.stopPropagation(),ft.toggleMapColor(m);let _=ft.getMapColorMetric();w.querySelectorAll(".map-color-btn").forEach(W=>{let O=W;O.classList.toggle("active",O.dataset.metric===_)})}),M.querySelector(".btn-hr-settings")?.addEventListener("click",S=>{S.stopPropagation(),Jl(S.currentTarget,t)})}let f=document.createElement("div");f.className="insight-card";let A=a.totalDist/1e3,C=A>0?a.elevGain/(A*1e3)*100:0;if(f.innerHTML=`
- terrainClimbing Analysis + terrainClimbing Analysis
Total Ascent
-
${Math.round(s.elevGain)} m
+
${Math.round(a.elevGain)} m
Total Descent
-
${Math.round(s.elevLoss)} m
+
${Math.round(a.elevLoss)} m
Avg Grade
-
${g.toFixed(1)} %
+
${C.toFixed(1)} %
VAM
-
${s.duration&&s.duration>0?Math.round(s.elevGain/s.duration*36e5):0} m/h
+
${a.duration&&a.duration>0?Math.round(a.elevGain/a.duration*36e5):0} m/h
- `,p.appendChild(d),s.avgPower&&s.avgHR){let $=document.createElement("div");$.className="insight-card";let M=s.avgPower/s.avgHR;$.innerHTML=` + `,w.appendChild(f),a.avgPower&&a.avgHR){let M=document.createElement("div");M.className="insight-card";let m=a.avgPower/a.avgHR;M.innerHTML=`
- monitoringEfficiency Factor + monitoringEfficiency & W' Balance
-
+
EF (Avg Power / Avg HR)
-
${M.toFixed(2)}
-
Higher values indicate better aerobic fitness.
+
${m.toFixed(2)}
+
+
+
Aerobic Decoupling
+
${c.decouplingPct.toFixed(1)} %
+
+
+
Min W' Reserve
+
${(c.minWPrimeBal/1e3).toFixed(1)} kJ (${c.matchesBurned} matches)
+
+
+
Quadrants (Q1/Q2/Q3/Q4)
+
${c.quadrantPct.join("% / ")}%
- `,p.appendChild($)}let T=Pl(e);if(T.length>0){let $=document.createElement("div");$.className="insight-card",$.style.cssText="column-span: all; display: block;",$.innerHTML=` -
routeCourses (${T.length})
+ `,w.appendChild(M)}if(c.sectionPeaks.length>0){let M=document.createElement("div");M.className="insight-card",M.innerHTML=` +
+ segmentTrack Section & Climb Efforts +
+
Track (${c.length})Track (${d.length})
-
- ${pt(d.displayName)} +
+ ${me(w.displayName)}
+ + + + + + + + + + + + ${c.sectionPeaks.map(m=>` + + + + + + + + + `).join("")} + +
SectionDistAvg WPeak 60sAvg HRVAM
${me(m.label)}${m.distKm} km${m.avgPower} W${m.peak60sPower} W${m.avgHR} bpm${m.vam} m/h
+ `,w.appendChild(M)}let $=No(t);if($.length>0){let M=document.createElement("div");M.className="insight-card",M.style.cssText="column-span: all; display: block;",M.innerHTML=` +
routeCourses (${$.length})
- ${Rs()} + ${Os()} - ${T.map(M=>{let C=xs(e,M.points),k="";if(C){let f=Ds(e,C.startIdx,C.endIdx),F=e.stats?.startTime||e.points?.[0]?.time,v=F?Gt(F):"-";k=Ns(f,e.sport||null,v)}else k='';return` - + ${$.map(m=>{let k=ks(t,m.points),P="";if(k){let h=wn(t,k.startIdx,k.endIdx),b=t.stats?.startTime||t.points?.[0]?.time,p=b?nn(b):"-";P=Ys(h,t.sport||null,p)}else P='';return` + - ${k} + ${P} `}).join("")}
Name
No continuous segment
No continuous segment
- ${pt(M.name)} + ${me(m.name)}
- `,p.appendChild($),$.querySelectorAll(".clickable-course").forEach(M=>{M.addEventListener("click",()=>{let C=M.dataset.id;Ln(C,!0),Ye.patch({tab:"courses"},!0)}),M.addEventListener("mouseenter",()=>{let C=M.dataset.id,k=T.find(f=>f.id===C);if(k){let f=xs(e,k.points);f&&De.highlightSegment(e.id,e.points,f.startIdx,f.endIdx,!1)}}),M.addEventListener("mouseleave",()=>{De.clearHighlight()})})}}function Wl(e){let{grid:n,track:t,curve:s,metricKey:o,label:a,unit:p,color:c,icon:d,chartWidth:x}=e,g=Se.getMapColorMetric()===o,T=document.createElement("div");T.className="insight-card",T.style.setProperty("--chart-color",c),T.innerHTML=` + `,w.appendChild(M),M.querySelectorAll(".clickable-course").forEach(m=>{m.addEventListener("click",()=>{let k=m.dataset.id;Tn(k,!0),Gt.patch({tab:"courses"},!0)}),m.addEventListener("mouseenter",()=>{let k=m.dataset.id,P=$.find(h=>h.id===k);if(P){let h=ks(t,P.points);h&&Bt.highlightSegment(t.id,t.points,h.startIdx,h.endIdx,!1)}}),m.addEventListener("mouseleave",()=>{Bt.clearHighlight()})})}}function Xo(t){let{grid:n,track:s,curve:e,metricKey:l,label:i,unit:a,color:c,icon:d,chartWidth:w}=t,g=ft.getMapColorMetric()===l,f=document.createElement("div");f.className="insight-card",f.style.setProperty("--chart-color",c),f.innerHTML=`
- ${d}${a} + ${d}${i}
-
@@ -472,7 +574,7 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams( expand_more
-
+
- `,n.appendChild(T);let $=T.querySelector(".curve-table-wrap"),M=T.querySelector(".btn-toggle-table"),C=M.querySelector(".material-symbols-rounded");M.addEventListener("click",()=>{let u=$.style.display==="none";$.style.display=u?"block":"none",C.textContent=u?"expand_less":"expand_more"});let k=T.querySelector(".map-color-btn");k.addEventListener("click",u=>{u.stopPropagation();let w=k.dataset.metric;Se.toggleMapColor(w);let E=Se.getMapColorMetric();n.querySelectorAll(".map-color-btn").forEach(N=>{let G=N;G.classList.toggle("active",G.dataset.metric===E)})});let f=T.querySelector(".curve-tbody"),F=Object.keys(s).map(Number).sort((u,w)=>u-w);F.forEach(u=>{let w=s[u],E=w.power||w.hr||w.val,N=document.createElement("tr");N.innerHTML=` - ${_t(u)} - ${E} ${p} + `,n.appendChild(f);let A=f.querySelector(".curve-table-wrap"),C=f.querySelector(".btn-toggle-table"),$=C.querySelector(".material-symbols-rounded");C.addEventListener("click",()=>{let h=A.style.display==="none";A.style.display=h?"block":"none",$.textContent=h?"expand_less":"expand_more"});let M=f.querySelector(".map-color-btn");M.addEventListener("click",h=>{h.stopPropagation();let b=M.dataset.metric;ft.toggleMapColor(b);let p=ft.getMapColorMetric();n.querySelectorAll(".map-color-btn").forEach(S=>{let _=S;_.classList.toggle("active",_.dataset.metric===p)})});let m=f.querySelector(".curve-tbody"),k=Object.keys(e).map(Number).sort((h,b)=>h-b);k.forEach(h=>{let b=e[h],p=b.power||b.hr||b.val,S=document.createElement("tr");S.innerHTML=` + ${ze(h)} + ${p} ${a} - - `,f?.appendChild(N)}),f?.querySelectorAll(".btn-show-peak").forEach(u=>{u.addEventListener("click",w=>{let E=w.currentTarget,N=parseInt(E.dataset.idx),G=parseInt(E.dataset.len),q=t.points,_=Math.min(q.length-1,N+G-1),W=q[0].time||0,z=((q[N].time||W)-W)/1e3,de=((q[_].time||W)-W)/1e3;Ye.patch({sel:[z,de]}),De.highlightSegment(t.id,q,N,_,!0)})});let v=T.querySelector(`#${o}-curve-chart`);if(v){let u=F,w=F.map(q=>s[q].power||s[q].hr||s[q].val),E=document.createElement("div");E.className="cur-y-val",E.style.cssText=`color:${c};display:none;border-color:${c}44`,v.style.position="relative",v.appendChild(E);let N={id:`${o}-curve`,width:0,height:250,padding:[10,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:a,stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(q,_)=>_.map(W=>`${W}${p}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(q,_,W)=>W},hooks:{draw:[q=>{let _=q.ctx,W=window.devicePixelRatio||1,z=q.bbox,de=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],y=u[u.length-1];_.save(),_.fillStyle="#555564",_.textAlign="center",_.textBaseline="top",_.font=`${10*W}px system-ui, sans-serif`;let m=-100;de.forEach(r=>{if(r>y)return;let J=q.valToPos(r,"x",!0);J>m+30*W&&J{q.over.addEventListener("click",()=>{let _=q.cursor.idx;if(_!=null&&u[_]!=null){let W=u[_],de=s[W].idx,y=t.points,m=Math.min(y.length-1,de+W-1),r=y[0].time||0,J=((y[de].time||r)-r)/1e3,V=((y[m].time||r)-r)/1e3;Ye.patch({sel:[J,V]}),De.highlightSegment(t.id,y,de,m,!0)}})}],setCursor:[q=>{if(!q._ready)return;q.redraw(!1);let _=q.cursor.idx,W=q.ctx,z=window.devicePixelRatio||1,de=q.bbox,y=_!=null&&w[_]!=null&&q.cursor.left>=0,m=q.cursor.top,r=q.valToPos(w[_],"y",!1);if(y&&Math.abs(m-r)<40){let V=q.valToPos(u[_],"x",!1),ee=q.valToPos(w[_],"y",!1),U=u[_];E.innerHTML=`${_t(U)}: ${w[_]} ${p}`,E.style.transform=`translate(${V}px, ${ee}px) translate(15px, 15px)`,E.style.display="";let Q=q.valToPos(u[_],"x",!0),ke=q.valToPos(w[_],"y",!0);W.save(),W.beginPath(),W.setLineDash([2*z,2*z]),W.strokeStyle=tt(c,.4),W.lineWidth=1*z,W.moveTo(Q,de.top),W.lineTo(Q,de.top+de.height),W.stroke(),W.beginPath(),W.setLineDash([]),W.arc(Q,ke,3*z,0,Math.PI*2),W.fillStyle="#0e0e10",W.fill(),W.strokeStyle=c,W.lineWidth=2*z,W.stroke(),W.restore()}else E.style.display="none"}]},legend:{show:!1}};N.width=x||Math.round(n.getBoundingClientRect().width-42)||v.clientWidth||500;let G=new Wo(N,[u,w],v);G._ready=!0,Ws.push(G)}}function Oo(e,n){document.querySelectorAll(".hr-settings-popup").forEach(p=>p.remove());let t=document.createElement("div");t.className="hr-settings-popup";let s=ot.getHRZones();t.innerHTML=` + `,m?.appendChild(S)}),m?.querySelectorAll(".btn-show-peak").forEach(h=>{h.addEventListener("click",b=>{let p=b.currentTarget,S=parseInt(p.dataset.idx),_=parseInt(p.dataset.len),W=s.points,O=Math.min(W.length-1,S+_-1),Y=W[0].time||0,Z=((W[S].time||Y)-Y)/1e3,lt=((W[O].time||Y)-Y)/1e3;Gt.patch({sel:[Z,lt]}),Bt.highlightSegment(s.id,W,S,O,!0)})});let P=f.querySelector(`#${l}-curve-chart`);if(P){let h=k,b=k.map(W=>e[W].power||e[W].hr||e[W].val),p=document.createElement("div");p.className="cur-y-val",p.style.cssText=`color:${c};display:none;border-color:${c}44`,P.style.position="relative",P.appendChild(p);let S={id:`${l}-curve`,width:0,height:250,padding:[10,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:i,stroke:c,width:2,fill:le(c,.1),points:{show:!0,size:5,fill:c}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(W,O)=>O.map(Y=>`${Y}${a}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(W,O,Y)=>Y},hooks:{draw:[W=>{let O=W.ctx,Y=window.devicePixelRatio||1,Z=W.bbox,lt=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Ft=h[h.length-1];O.save(),O.fillStyle="#555564",O.textAlign="center",O.textBaseline="top",O.font=`${10*Y}px system-ui, sans-serif`;let rt=-100;lt.forEach(x=>{if(x>Ft)return;let v=W.valToPos(x,"x",!0);v>rt+30*Y&&v{W.over.addEventListener("click",()=>{let O=W.cursor.idx;if(O!=null&&h[O]!=null){let Y=h[O],lt=e[Y].idx,Ft=s.points,rt=Math.min(Ft.length-1,lt+Y-1),x=Ft[0].time||0,v=((Ft[lt].time||x)-x)/1e3,u=((Ft[rt].time||x)-x)/1e3;Gt.patch({sel:[v,u]}),Bt.highlightSegment(s.id,Ft,lt,rt,!0)}})}],setCursor:[W=>{if(!W._ready)return;W.redraw(!1);let O=W.cursor.idx,Y=W.ctx,Z=window.devicePixelRatio||1,lt=W.bbox,Ft=O!=null&&b[O]!=null&&W.cursor.left>=0,rt=W.cursor.top,x=W.valToPos(b[O],"y",!1);if(Ft&&Math.abs(rt-x)<40){let u=W.valToPos(h[O],"x",!1),N=W.valToPos(b[O],"y",!1),E=h[O];p.innerHTML=`${ze(E)}: ${b[O]} ${a}`,p.style.transform=`translate(${u}px, ${N}px) translate(15px, 15px)`,p.style.display="";let G=W.valToPos(h[O],"x",!0),U=W.valToPos(b[O],"y",!0);Y.save(),Y.beginPath(),Y.setLineDash([2*Z,2*Z]),Y.strokeStyle=le(c,.4),Y.lineWidth=1*Z,Y.moveTo(G,lt.top),Y.lineTo(G,lt.top+lt.height),Y.stroke(),Y.beginPath(),Y.setLineDash([]),Y.arc(G,U,3*Z,0,Math.PI*2),Y.fillStyle="#0e0e10",Y.fill(),Y.strokeStyle=c,Y.lineWidth=2*Z,Y.stroke(),Y.restore()}else p.style.display="none"}]},legend:{show:!1}};S.width=w||Math.round(n.getBoundingClientRect().width-42)||P.clientWidth||500;let _=new Zl(S,[h,b],P);_._ready=!0,js.push(_)}}function Jl(t,n){document.querySelectorAll(".hr-settings-popup").forEach(a=>a.remove());let s=document.createElement("div");s.className="hr-settings-popup";let e=Jt.getHRZones();s.innerHTML=`
Configure HR Zones (bpm)
Z1 / Z2 - +
Z2 / Z3 - +
Z3 / Z4 - +
Z4 / Z5 - +
- `;let o=e.getBoundingClientRect();t.style.cssText=` + `;let l=t.getBoundingClientRect();s.style.cssText=` position: fixed; z-index: 10000; background: var(--surface2); @@ -523,18 +625,18 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams( padding: 16px; width: 200px; box-shadow: 0 8px 32px rgba(0,0,0,0.6); - left: ${o.right-200}px; - top: ${o.bottom+8}px; - `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let p=t.querySelectorAll(".hr-zone-input"),c=Array.from(p).map(d=>parseInt(d.value)||0);for(let d=1;d{!t.contains(p.target)&&!e.contains(p.target)&&(t.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}function Yo(e,n){document.querySelectorAll(".pw-settings-popup").forEach(p=>p.remove());let t=document.createElement("div");t.className="pw-settings-popup";let s=ot.getFTP();t.innerHTML=` + left: ${l.right-200}px; + top: ${l.bottom+8}px; + `,document.body.appendChild(s),s.querySelector(".save-btn")?.addEventListener("click",async()=>{let a=s.querySelectorAll(".hr-zone-input"),c=Array.from(a).map(d=>parseInt(d.value)||0);for(let d=1;d{!s.contains(a.target)&&!t.contains(a.target)&&(s.remove(),document.removeEventListener("click",i))};setTimeout(()=>document.addEventListener("click",i),10)}function ti(t,n){document.querySelectorAll(".pw-settings-popup").forEach(a=>a.remove());let s=document.createElement("div");s.className="pw-settings-popup";let e=Jt.getFTP();s.innerHTML=`
Configure FTP (Watts)
Your FTP - +
- `;let o=e.getBoundingClientRect();t.style.cssText=` + `;let l=t.getBoundingClientRect();s.style.cssText=` position: fixed; z-index: 10000; background: var(--surface2); @@ -543,27 +645,27 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams( padding: 16px; width: 200px; box-shadow: 0 8px 32px rgba(0,0,0,0.6); - left: ${o.right-200}px; - top: ${o.bottom+8}px; - `,document.body.appendChild(t),t.querySelector(".save-btn")?.addEventListener("click",async()=>{let p=t.querySelector("#ftp-input"),c=parseInt(p.value)||200;ot.setFTP(c),await at.set("ftp",c),n.stats=ot.computeStats(n.points,!0),await at.save(n),Bt(n),t.remove(),Es(`FTP updated to ${c}W`)});let a=p=>{!t.contains(p.target)&&!e.contains(p.target)&&(t.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}import Vl from"uplot";var zt=[],qt=null,ft=null,gn="power",Jt="hr",bt=null,Lt=[],Ot=[],cn=null,Pt=!1;function Ss(){let e=document.getElementById("combined-time-val");if(e&&bt!==null&&Lt[bt]){let n=Lt[bt][2];e.textContent=`${ht(n)}`}}function Yl(){cn&&(clearInterval(cn),cn=null),ft&&(ft.destroy(),ft=null),zt=[],qt=null,gn="power",Jt="hr",bt=null,Lt=[],Ot=[],Pt=!1;let e=document.getElementById("combined-tooltip");e&&e.remove();let n=document.getElementById("combined-view");n&&(n.innerHTML=` + left: ${l.right-200}px; + top: ${l.bottom+8}px; + `,document.body.appendChild(s),s.querySelector(".save-btn")?.addEventListener("click",async()=>{let a=s.querySelector("#ftp-input"),c=parseInt(a.value)||200;Jt.setFTP(c),await ce.set("ftp",c),n.stats=Jt.computeStats(n.points,!0),await ce.save(n),be(n),s.remove(),Ls(`FTP updated to ${c}W`)});let i=a=>{!s.contains(a.target)&&!t.contains(a.target)&&(s.remove(),document.removeEventListener("click",i))};setTimeout(()=>document.addEventListener("click",i),10)}import tl from"uplot";var Te=[],$e=null,pe=null,fn="power",Qe="hr",ve=null,Ie=[],Xe=[],pn=null,He=!1;function jn(){let t=document.getElementById("combined-time-val");if(t&&ve!==null&&Ie[ve]){let n=Ie[ve][2];t.textContent=`${he(n)}`}}function nl(){pn&&(clearInterval(pn),pn=null),pe&&(pe.destroy(),pe=null),Te=[],$e=null,fn="power",Qe="hr",ve=null,Ie=[],Xe=[],He=!1;let t=document.getElementById("combined-tooltip");t&&t.remove();let n=document.getElementById("combined-view");n&&(n.innerHTML=`
no_sim
Select a track for combined analysis
- `)}var Os=16384,zs=Array.from({length:8},()=>new Float64Array(Os)),qs=Array.from({length:8},()=>new Float64Array(Os)),Us=new Int32Array(8),Vs=new Float64Array(32*32),jo=[2,3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300];function dn(e,n=[]){Array.isArray(e)?(zt=e,qt=e[0]||null):e?(zt=[e],qt=e):(zt=[],qt=null);let t=document.getElementById("combined-view");if(!t)return;let s=qt;if(!s){t.innerHTML=` + `)}var ei=16384,Gs=new Float64Array(32*32);function ni(t,n){let s=n.length>=2?n:t,e=Math.min(s.length,8);Gs.fill(0);let l=[{label:"Power vs Heart Rate",getX:A=>A.power,getY:A=>A.hr},{label:"Speed vs Gradient",getX:A=>A.speed!=null?A.speed*3.6:void 0,getY:A=>A.gradient},{label:"Cadence vs Power",getX:A=>A.cad,getY:A=>A.power},{label:"Elevation vs VAM",getX:A=>A.ele,getY:A=>A.verticalSpeed},{label:"Temperature vs HR",getX:A=>A.temp,getY:A=>A.hr}],i=0,a=0,c=[];for(let A=0;A2){let S=$/h,_=M/h,W=Math.max(0,m/h-S*S),O=Math.max(0,k/h-_*_),Y=P/h-S*_,Z=Math.sqrt(W*O);b=Z>1e-9?Y/Z:0,p=W>1e-9?Y/W:0}i+=h,a+=Math.abs(b)*100+Math.abs(p),c.push({pairLabel:C.label,rVal:b,slope:p,samples:h})}for(let A=0;A<1024;A++)a+=Gs[A]*.001;let d=["Q1 (0\u201325%)","Q2 (25\u201350%)","Q3 (50\u201375%)","Q4 (75\u2013100%)"],w=[],g=t[0],f=t[1]||t[0];for(let A=0;A<4;A++){let C=A*.25,$=(A+1)*.25,M=h=>{let b=h.points||[],p=Math.floor(b.length*C),S=Math.max(p+1,Math.floor(b.length*$)),_=0,W=0,O=0,Y=0;for(let Z=p;Z0?Math.round(_/Y):0,hr:Y>0?Math.round(W/Y):0,speedKmh:Y>0?O/Y:0}},m=M(g),k=M(f),P=0;for(let h=0;h0?Math.round(P/e):0})}return{aggPts:i,corrSum:a,correlations:c,sectionRows:w}}function Zs(t,n){fn=t,Qe=n,Te.length>=2?Fe(Te):$e&&Fe($e)}function Zn(t){He!==t&&(He=t,Te.length>=2?Fe(Te):$e&&Fe($e))}function Xn(t){let n=Math.max(0,Math.min(1,t)),s=Ie.length>0?Ie.length-1:$e?Math.max(0,$e.points.length-1):0;ve=Math.round(n*s);let e=document.getElementById("combined-time-slider");e&&(e.max=`${s}`,e.value=`${ve}`),jn(),pe&&pe.redraw()}function Fe(t,n=[]){Array.isArray(t)?(Te=t,$e=t[0]||null):t?(Te=[t],$e=t):(Te=[],$e=null);let s=document.getElementById("combined-view");if(!s)return;let e=$e;if(!e){s.innerHTML=`
no_sim
Select a track for combined analysis
- `;return}let o=Se.METRICS,a=[];for(let C in o){let k=o[C];s.points.some(f=>f[k.field]!=null)&&a.push(C)}!a.includes(gn)&&a.length>0&&(gn=a[0]),!a.includes(Jt)&&a.length>1?Jt=a[1]:!a.includes(Jt)&&a.length>0&&(Jt=a[0]);let p=o[gn],c=o[Jt];t.style.overflow="hidden";let d="";if(zt.length>=2){let C=n.length>=2?n:zt,k=Math.min(C.length,8);Vs.fill(0);for(let re=0;re=me){let ne=I-me;Ce-=H[ne],Re-=Ie[ne],le-=oe[ne],ye-=he[ne];let Ne=Ce*fe,Z=Re*fe,Be=le*fe,xe=ye*fe,Ee=Ne-Z,Me=Be-xe,be=Math.exp(-Ee*Ee*Pe),we=1/(1+Me*Me*Pe);F+=Ne*Z*be+Be*xe*we,f++}}}}}for(let re=0;re<1024;re++)F+=Vs[re]*.001;let v=zt[0],u=zt[1],w=v.stats,E=u.stats,N=((E.totalDist-w.totalDist)/1e3).toFixed(2),G=((E.avgPower||0)-(w.avgPower||0)).toFixed(0),q=((E.avgHR||0)-(w.avgHR||0)).toFixed(0),_=(E.elevGain-w.elevGain).toFixed(0),W=(E.shifts||0)-(w.shifts||0),z=((w.totalDist+E.totalDist)/1e3).toFixed(2),de=(w.elevGain+E.elevGain).toFixed(0),y=((w.duration||0)+(E.duration||0))/1e3,m=Math.round(((w.avgPower||0)+(E.avgPower||0))/2),r=Math.max(w.maxPower||0,E.maxPower||0),J=Math.round(((w.avgHR||0)+(E.avgHR||0))/2),V=Math.max(w.maxHR||0,E.maxHR||0),ee=((E.avgTemp??0)-(w.avgTemp??0)).toFixed(1),U=(((w.avgTemp??0)+(E.avgTemp??0))/2).toFixed(1),Q=Math.max(w.maxTemp??0,E.maxTemp??0).toFixed(1),ke=(w.shifts||0)+(E.shifts||0);d=` -
-
Aggregate Track Comparison & Analysis
+ `;return}let l=ft.METRICS,i=[];for(let $ in l){let M=l[$];e.points.some(m=>m[M.field]!=null)&&i.push($)}!i.includes(fn)&&i.length>0&&(fn=i[0]),!i.includes(Qe)&&i.length>1?Qe=i[1]:!i.includes(Qe)&&i.length>0&&(Qe=i[0]);let a=l[fn],c=l[Qe];s.style.overflow="hidden";let d="";if(Te.length>=2){let{aggPts:$,corrSum:M,correlations:m,sectionRows:k}=ni(Te,n),P=Te[0],h=Te[1],b=P.stats,p=h.stats,S=((p.totalDist-b.totalDist)/1e3).toFixed(2),_=((p.avgPower||0)-(b.avgPower||0)).toFixed(0),W=((p.avgHR||0)-(b.avgHR||0)).toFixed(0),O=(p.elevGain-b.elevGain).toFixed(0),Y=(p.shifts||0)-(b.shifts||0),Z=((b.totalDist+p.totalDist)/1e3).toFixed(2),lt=(b.elevGain+p.elevGain).toFixed(0),Ft=((b.duration||0)+(p.duration||0))/1e3,rt=Math.round(((b.avgPower||0)+(p.avgPower||0))/2),x=Math.max(b.maxPower||0,p.maxPower||0),v=Math.round(((b.avgHR||0)+(p.avgHR||0))/2),u=Math.max(b.maxHR||0,p.maxHR||0),N=((p.avgTemp??0)-(b.avgTemp??0)).toFixed(1),E=(((b.avgTemp??0)+(p.avgTemp??0))/2).toFixed(1),G=Math.max(b.maxTemp??0,p.maxTemp??0).toFixed(1),U=(b.shifts||0)+(p.shifts||0);d=` +
+
Aggregate Track Comparison & Section Analysis (${Te.length} Tracks)
- - + + @@ -571,64 +673,75 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams( - - - - + + + + - - - - + + + + - - + + - + - - - - + + + + - - - - + + + + - - - - + + + + - + - - - - + + + + + ${k.map(j=>` + + + + + + + `).join("")}
Metric${v.displayName||v.name} (T1)${u.displayName||u.name} (T2)${P.displayName||P.name} (T1)${h.displayName||h.name} (T2) Delta (T2 - T1) Aggregate Summary
Distance${(w.totalDist/1e3).toFixed(2)} km${(E.totalDist/1e3).toFixed(2)} km${Number(N)>=0?"+":""}${N} km${z} km (Total)${(b.totalDist/1e3).toFixed(2)} km${(p.totalDist/1e3).toFixed(2)} km${Number(S)>=0?"+":""}${S} km${Z} km (Total)
Elevation Gain${w.elevGain.toFixed(0)} m${E.elevGain.toFixed(0)} m${Number(_)>=0?"+":""}${_} m${de} m (Total)${b.elevGain.toFixed(0)} m${p.elevGain.toFixed(0)} m${Number(O)>=0?"+":""}${O} m${lt} m (Total)
Duration${w.duration?ht(w.duration/1e3):"--"}${E.duration?ht(E.duration/1e3):"--"}${b.duration?he(b.duration/1e3):"--"}${p.duration?he(p.duration/1e3):"--"} --${ht(y)} (Total)${he(Ft)} (Total)
Avg / Max Power${w.avgPower||0} W / ${w.maxPower||0} W${E.avgPower||0} W / ${E.maxPower||0} W${Number(G)>=0?"+":""}${G} W (Avg)${m} W (Avg) / ${r} W (Max)${b.avgPower||0} W / ${b.maxPower||0} W${p.avgPower||0} W / ${p.maxPower||0} W${Number(_)>=0?"+":""}${_} W (Avg)${rt} W (Avg) / ${x} W (Max)
Avg / Max HR${w.avgHR||0} bpm / ${w.maxHR||0} bpm${E.avgHR||0} bpm / ${E.maxHR||0} bpm${Number(q)>=0?"+":""}${q} bpm (Avg)${J} bpm (Avg) / ${V} bpm (Max)${b.avgHR||0} bpm / ${b.maxHR||0} bpm${p.avgHR||0} bpm / ${p.maxHR||0} bpm${Number(W)>=0?"+":""}${W} bpm (Avg)${v} bpm (Avg) / ${u} bpm (Max)
Avg / Max Temp${w.avgTemp!=null?w.avgTemp.toFixed(1):"--"} \xB0C / ${w.maxTemp!=null?w.maxTemp.toFixed(1):"--"} \xB0C${E.avgTemp!=null?E.avgTemp.toFixed(1):"--"} \xB0C / ${E.maxTemp!=null?E.maxTemp.toFixed(1):"--"} \xB0C${Number(ee)>=0?"+":""}${ee} \xB0C (Avg)${U} \xB0C (Avg) / ${Q} \xB0C (Max)${b.avgTemp!=null?b.avgTemp.toFixed(1):"--"} \xB0C / ${b.maxTemp!=null?b.maxTemp.toFixed(1):"--"} \xB0C${p.avgTemp!=null?p.avgTemp.toFixed(1):"--"} \xB0C / ${p.maxTemp!=null?p.maxTemp.toFixed(1):"--"} \xB0C${Number(N)>=0?"+":""}${N} \xB0C (Avg)${E} \xB0C (Avg) / ${G} \xB0C (Max)
Gear Shifts${w.shifts||0}${E.shifts||0}${W>=0?"+":""}${W}${ke} (Total)${b.shifts||0}${p.shifts||0}${Y>=0?"+":""}${Y}${U} (Total)
${j.sectionLabel} Split${j.t1Power}W \xB7 ${j.t1Hr}bpm \xB7 ${j.t1SpeedKmh.toFixed(1)}km/h${j.t2Power}W \xB7 ${j.t2Hr}bpm \xB7 ${j.t2SpeedKmh.toFixed(1)}km/h${j.t2Power-j.t1Power>=0?"+":""}${j.t2Power-j.t1Power}WCohort Avg: ${j.cohortAvgPower}W
+
+ ${m.map(j=>`${j.pairLabel}: r=${j.rVal.toFixed(2)}, \u03B2=${j.slope.toFixed(2)} (${j.samples})`).join("")} +
- `}t.innerHTML=`${d} + `}s.innerHTML=`${d}
arrow_forward X Axis:
@@ -651,38 +764,38 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams(
- -
- `,document.getElementById("btn-combined-x")?.addEventListener("click",C=>{C.stopPropagation(),Ol(C.currentTarget,"x")}),document.getElementById("btn-combined-y")?.addEventListener("click",C=>{C.stopPropagation(),Ol(C.currentTarget,"y")});let x=document.getElementById("combined-time-slider"),g=document.getElementById("combined-time-val"),T=document.getElementById("btn-combined-play");x?.addEventListener("input",()=>{bt=parseInt(x.value,10),Ss(),ft&&ft.redraw()});function $(){T&&(T.innerHTML='pause'),cn=window.setInterval(()=>{bt!==null&&btplay_arrow')}T?.addEventListener("click",()=>{cn?M():(bt!==null&&bt>=Lt.length-1&&(bt=0,x.value="0",Ss(),ft&&ft.redraw()),$())}),document.getElementById("btn-combined-cart")?.addEventListener("click",()=>{Pt&&(Pt=!1,dn(qt))}),document.getElementById("btn-combined-polar")?.addEventListener("click",()=>{Pt||(Pt=!0,dn(qt))}),Zo()}function Zn(){let e=document.getElementById("tab-combined"),n=document.getElementById("combined-plot-container");if(ft&&n&&n.clientWidth>0){let t=n.clientWidth,s=n.clientHeight;if(t>0&&s>0)if(Pt){let o=Math.min(t,s);ft.setSize({width:o,height:o})}else ft.setSize({width:t,height:s})}}function Ol(e,n){document.querySelectorAll(".metric-menu-popup").forEach(d=>d.remove());let t=document.createElement("div");t.className="metric-menu-popup";let s=Se.METRICS,o=qt;if(!o)return;let a=[];for(let d in s){let x=s[d];o.points.some(g=>g[x.field]!=null)&&a.push(d)}a.forEach(d=>{let x=s[d],g=document.createElement("div"),T=n==="x"?gn:Jt;g.className=`menu-item ${T===d?"active":""}`,g.innerHTML=` - ${x.icon} - ${x.label} - ${T===d?"check":""} - `,g.addEventListener("click",()=>{n==="x"?gn=d:Jt=d,t.remove(),dn(qt)}),t.appendChild(g)});let p=e.getBoundingClientRect();t.style.top=`${p.bottom+5}px`,t.style.left=`${p.left}px`,document.body.appendChild(t);let c=d=>{!t.contains(d.target)&&!e.contains(d.target)&&(t.remove(),document.removeEventListener("click",c))};setTimeout(()=>document.addEventListener("click",c),0)}function Zo(){if(!qt)return;let e=document.getElementById("combined-plot-container");if(!e)return;let n=Se.METRICS,t=n[gn]||n.power,s=n[Jt]||n.hr;if(zt.length>=2){let C=zt[0],k=zt[1],f=C.points,F=k.points,v=Math.max(f.length,F.length),u=[],w=[],E=[];for(let _=0;_0?e.clientWidth:800,G=e.clientHeight>0?e.clientHeight:350,q={width:N,height:G,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:[{},{label:`${C.displayName||C.name} (${s.label})`,stroke:C.color||"#3b82f6",width:2,points:{show:!1}},{label:`${k.displayName||k.name} (${s.label})`,stroke:k.color||"#FF6B35",width:2,points:{show:!1}}],axes:[{side:2,label:"Elapsed Duration (s)",stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:30},{side:3,label:`${s.label} (${s.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:40}],legend:{show:!0}};ft=new Vl(q,[u,w,E],e),Zn();return}let o=qt.points,a=o[0].time||0,p=o.map((C,k)=>[C[t.field],C[s.field],(C.time-a)/1e3,(C.dist||0)/1e3,k]).filter(([C,k,f,F])=>C!=null&&k!=null);if(p.length===0){e.innerHTML='
No data for selected metrics
';return}if(Pt){let C=p.map(w=>w[0]),k=p.map(w=>w[1]),f=Math.min(...C),F=Math.max(...C),v=Math.min(...k),u=Math.max(...k);Lt=p.map(w=>{let E=w[0],N=w[1],G=(E-f)/(F-f||1)*2*Math.PI,q=(N-v)/(u-v||1),_=q*Math.cos(G),W=q*Math.sin(G);return[_,W,w[2],w[3],w[4],E,N]})}else Lt=p.map(C=>[C[0],C[1],C[2],C[3],C[4],C[0],C[1]]);let c=document.getElementById("combined-time-slider");c&&(c.max=`${p.length-1}`,(bt===null||bt>=p.length)&&(bt=p.length-1,c.value=c.max),Ss()),Ot=[...Lt].sort((C,k)=>C[0]-k[0]||C[4]-k[4]);let d=Ot.map(C=>C[0]),x=Ot.map(C=>C[1]),g=document.getElementById("combined-plot-container"),T=g&&g.clientWidth>0?g.clientWidth:600,$=g&&g.clientHeight>0?g.clientHeight:400;if(Pt){let C=Math.min(T,$>0?$:T);T=C,$=C,g&&(g.style.display="flex",g.style.alignItems="center",g.style.justifyContent="center")}else g&&(g.style.display="",g.style.alignItems="",g.style.justifyContent="");let M={width:T,height:$,padding:[10,15,0,0],scales:{x:{time:!1,auto:!0},y:{auto:!0}},series:[{},{label:s.label,width:0,points:{show:!0,size:3,fill:tt(s.color,.3)}}],axes:[{side:2,show:!Pt,label:`${t.label} (${t.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(C,k)=>k.map(f=>f!=null?t.fmtAxis(f):""),size:30},{side:3,show:!Pt,label:`${s.label} (${s.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(C,k)=>k.map(f=>f!=null?s.fmtAxis(f):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:(C,k,f)=>{let F=C.cursor.left,v=C.cursor.top;if(F!=null&&v!=null&&F>=0&&v>=0){let u=1/0,w=-1;for(let E=0;E=0&&u<2500)return w}return f},points:{size:7,stroke:"#fff",width:2,fill:s.color}},legend:{show:!1},hooks:{draw:[C=>{let k=C.ctx,f=window.devicePixelRatio||1;k.save(),k.beginPath(),k.strokeStyle="rgba(255, 255, 255, 0.15)",k.lineWidth=1*f;let F=!1;for(let v=0;v{let k=C.cursor.idx,f=document.getElementById("combined-tooltip");if(f||(f=document.createElement("div"),f.id="combined-tooltip",f.style.position="absolute",f.style.background="rgba(14, 14, 16, 0.9)",f.style.color="#fff",f.style.padding="8px 12px",f.style.borderRadius="4px",f.classList.add("font-m"),f.style.fontFamily="system-ui",f.style.pointerEvents="none",f.style.zIndex="1000",f.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",f.style.border="1px solid #2e2e34",document.body.appendChild(f)),k!=null&&Ot[k]&&C.cursor.left>=0){let F=Ot[k],v=F[2],u=F[3],w=F[5],E=F[6];f.innerHTML=` -
Point #${k}
+ `,document.getElementById("btn-combined-x")?.addEventListener("click",$=>{$.stopPropagation(),el($.currentTarget,"x")}),document.getElementById("btn-combined-y")?.addEventListener("click",$=>{$.stopPropagation(),el($.currentTarget,"y")});let w=document.getElementById("combined-time-slider"),g=document.getElementById("combined-time-val"),f=document.getElementById("btn-combined-play");w?.addEventListener("input",()=>{ve=parseInt(w.value,10),jn(),pe&&pe.redraw()});function A(){f&&(f.innerHTML='pause'),pn=window.setInterval(()=>{ve!==null&&veplay_arrow')}f?.addEventListener("click",()=>{pn?C():(ve!==null&&ve>=Ie.length-1&&(ve=0,w.value="0",jn(),pe&&pe.redraw()),A())}),document.getElementById("btn-combined-cart")?.addEventListener("click",()=>{He&&(He=!1,Fe($e))}),document.getElementById("btn-combined-polar")?.addEventListener("click",()=>{He||(He=!0,Fe($e))}),si()}function Gn(){let t=document.getElementById("tab-combined"),n=document.getElementById("combined-plot-container");if(pe&&n&&n.clientWidth>0){let s=n.clientWidth,e=n.clientHeight;if(s>0&&e>0)if(He){let l=Math.min(s,e);pe.setSize({width:l,height:l})}else pe.setSize({width:s,height:e})}}function el(t,n){document.querySelectorAll(".metric-menu-popup").forEach(d=>d.remove());let s=document.createElement("div");s.className="metric-menu-popup";let e=ft.METRICS,l=$e;if(!l)return;let i=[];for(let d in e){let w=e[d];l.points.some(g=>g[w.field]!=null)&&i.push(d)}i.forEach(d=>{let w=e[d],g=document.createElement("div"),f=n==="x"?fn:Qe;g.className=`menu-item ${f===d?"active":""}`,g.innerHTML=` + ${w.icon} + ${w.label} + ${f===d?"check":""} + `,g.addEventListener("click",()=>{n==="x"?fn=d:Qe=d,s.remove(),Fe($e)}),s.appendChild(g)});let a=t.getBoundingClientRect();s.style.top=`${a.bottom+5}px`,s.style.left=`${a.left}px`,document.body.appendChild(s);let c=d=>{!s.contains(d.target)&&!t.contains(d.target)&&(s.remove(),document.removeEventListener("click",c))};setTimeout(()=>document.addEventListener("click",c),0)}function si(){if(!$e)return;let t=document.getElementById("combined-plot-container");if(!t)return;let n=ft.METRICS,s=n[fn]||n.power,e=n[Qe]||n.hr;if(Te.length>=2){let $=0;for(let p=0;p$&&($=Te[p].points.length);let M=new Array($);for(let p=0;p<$;p++)M[p]=p;let m=[{}],k=[M];for(let p=0;p0?t.clientWidth:800,h=t.clientHeight>0?t.clientHeight:350,b={width:P,height:h,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:m,axes:[{side:2,label:"Elapsed Duration (s)",stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:30},{side:3,label:`${e.label} (${e.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:40}],legend:{show:!0}};pe=new tl(b,k,t),Gn();return}let l=$e.points,i=l[0].time||0,a=l.map(($,M)=>[$[s.field],$[e.field],($.time-i)/1e3,($.dist||0)/1e3,M]).filter(([$,M,m,k])=>$!=null&&M!=null);if(a.length===0){t.innerHTML='
No data for selected metrics
';return}if(He){let $=a.map(b=>b[0]),M=a.map(b=>b[1]),m=Math.min(...$),k=Math.max(...$),P=Math.min(...M),h=Math.max(...M);Ie=a.map(b=>{let p=b[0],S=b[1],_=(p-m)/(k-m||1)*2*Math.PI,W=(S-P)/(h-P||1),O=W*Math.cos(_),Y=W*Math.sin(_);return[O,Y,b[2],b[3],b[4],p,S]})}else Ie=a.map($=>[$[0],$[1],$[2],$[3],$[4],$[0],$[1]]);let c=document.getElementById("combined-time-slider");c&&(c.max=`${a.length-1}`,(ve===null||ve>=a.length)&&(ve=a.length-1,c.value=c.max),jn()),Xe=[...Ie].sort(($,M)=>$[0]-M[0]||$[4]-M[4]);let d=Xe.map($=>$[0]),w=Xe.map($=>$[1]),g=document.getElementById("combined-plot-container"),f=g&&g.clientWidth>0?g.clientWidth:600,A=g&&g.clientHeight>0?g.clientHeight:400;if(He){let $=Math.min(f,A>0?A:f);f=$,A=$,g&&(g.style.display="flex",g.style.alignItems="center",g.style.justifyContent="center")}else g&&(g.style.display="",g.style.alignItems="",g.style.justifyContent="");let C={width:f,height:A,padding:[10,15,0,0],scales:{x:{time:!1,auto:!0},y:{auto:!0}},series:[{},{label:e.label,width:0,points:{show:!0,size:3,fill:le(e.color,.3)}}],axes:[{side:2,show:!He,label:`${s.label} (${s.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:($,M)=>M.map(m=>m!=null?s.fmtAxis(m):""),size:30},{side:3,show:!He,label:`${e.label} (${e.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:($,M)=>M.map(m=>m!=null?e.fmtAxis(m):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:($,M,m)=>{let k=$.cursor.left,P=$.cursor.top;if(k!=null&&P!=null&&k>=0&&P>=0){let h=1/0,b=-1;for(let p=0;p=0&&h<2500)return b}return m},points:{size:7,stroke:"#fff",width:2,fill:e.color}},legend:{show:!1},hooks:{draw:[$=>{let M=$.ctx,m=window.devicePixelRatio||1;M.save(),M.beginPath(),M.strokeStyle="rgba(255, 255, 255, 0.15)",M.lineWidth=1*m;let k=!1;for(let P=0;P{let M=$.cursor.idx,m=document.getElementById("combined-tooltip");if(m||(m=document.createElement("div"),m.id="combined-tooltip",m.style.position="absolute",m.style.background="rgba(14, 14, 16, 0.9)",m.style.color="#fff",m.style.padding="8px 12px",m.style.borderRadius="4px",m.classList.add("font-m"),m.style.fontFamily="system-ui",m.style.pointerEvents="none",m.style.zIndex="1000",m.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",m.style.border="1px solid #2e2e34",document.body.appendChild(m)),M!=null&&Xe[M]&&$.cursor.left>=0){let k=Xe[M],P=k[2],h=k[3],b=k[5],p=k[6];m.innerHTML=` +
Point #${M}
Time: - ${ht(v)} + ${he(P)}
Distance: - ${u.toFixed(2)} km + ${h.toFixed(2)} km
- ${t.label}: - ${t.fmtAxis(w)} ${t.unit} + ${s.label}: + ${s.fmtAxis(b)} ${s.unit}
- ${s.label}: - ${s.fmtAxis(E)} ${s.unit} + ${e.label}: + ${e.fmtAxis(p)} ${e.unit}
- `,f.style.display="block";let N=C.over.getBoundingClientRect();f.style.left=`${N.left+window.scrollX+C.cursor.left+15}px`,f.style.top=`${N.top+window.scrollY+C.cursor.top+15}px`}else f.style.display="none"}]}};e.querySelector(".empty-text")&&(e.innerHTML=""),ft&&ft.destroy(),ft=new Vl(M,[d,x],e),ft.over.addEventListener("click",()=>{if(ft){let C=ft.cursor.idx;if(C!=null&&Ot[C]){let k=Ot[C][4];Se.setCursorAt(k)}}}),Zn()}import An from"uplot";function jl(e,n){let t=0;for(let E=0;Et&&(t=N)}t||(t=Date.UTC(2026,7,1));let s=new Date(t),o=s.getUTCFullYear(),a=Date.UTC(o-1,s.getUTCMonth(),s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),p=Date.UTC(o,s.getUTCMonth()-6,s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),c=Date.UTC(o,s.getUTCMonth()-1,s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()),d=0,x=0,g=0,T=0,$=0,M=t;e.forEach(E=>{if(!E.stats.startTime)return;let N=n(E);if(N===void 0)return;$+=N;let G=E.stats.startTime;G=a&&(x+=N),G>=p&&(g+=N),G>=c&&(T+=N)});let C=7*24*60*60*1e3,k=Date.UTC(o,0,1),f=Math.max(.1,(t-k)/C),F=Math.max(.1,(t-a)/C),v=Math.max(.1,(t-p)/C),u=Math.max(.1,(t-c)/C),w=Math.max(.1,(t-M)/C);return{currentYear:d,pastYear:x,past6m:g,past1m:T,total:$,currentYearAvg:d/f,pastYearAvg:x/F,past6mAvg:g/v,past1mAvg:T/u,totalAvg:$/w}}function Zl(e,n,t){let s=n?1e3:1,o=a=>(n?a/s:a).toLocaleString("en-US",{minimumFractionDigits:n?1:0,maximumFractionDigits:n?1:0});return` + `,m.style.display="block";let S=$.over.getBoundingClientRect();m.style.left=`${S.left+window.scrollX+$.cursor.left+15}px`,m.style.top=`${S.top+window.scrollY+$.cursor.top+15}px`}else m.style.display="none"}]}};t.querySelector(".empty-text")&&(t.innerHTML=""),pe&&pe.destroy(),pe=new tl(C,[d,w],t),pe.over.addEventListener("click",()=>{if(pe){let $=pe.cursor.idx;if($!=null&&Xe[$]){let M=Xe[$][4];ft.setCursorAt(M)}}}),Gn()}import An from"uplot";function gn(t,n){let s=0;for(let p=0;ps&&(s=S)}s||(s=Date.UTC(2026,7,1));let e=new Date(s),l=e.getUTCFullYear(),i=Date.UTC(l-1,e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds()),a=Date.UTC(l,e.getUTCMonth()-6,e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds()),c=Date.UTC(l,e.getUTCMonth()-1,e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds()),d=0,w=0,g=0,f=0,A=0,C=s;t.forEach(p=>{if(!p.stats.startTime)return;let S=n(p);if(S===void 0)return;A+=S;let _=p.stats.startTime;_=i&&(w+=S),_>=a&&(g+=S),_>=c&&(f+=S)});let $=7*24*60*60*1e3,M=Date.UTC(l,0,1),m=Math.max(.1,(s-M)/$),k=Math.max(.1,(s-i)/$),P=Math.max(.1,(s-a)/$),h=Math.max(.1,(s-c)/$),b=Math.max(.1,(s-C)/$);return{currentYear:d,pastYear:w,past6m:g,past1m:f,total:A,currentYearAvg:d/m,pastYearAvg:w/k,past6mAvg:g/P,past1mAvg:f/h,totalAvg:A/b}}function sl(t,n,s){let e=n?1e3:1,l=i=>(n?i/e:i).toLocaleString("en-US",{minimumFractionDigits:n?1:0,maximumFractionDigits:n?1:0});return` @@ -694,106 +807,140 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams( - - + + - - + + - - + + - - + + - - + +
Current Year${o(e.currentYear)} ${t}${o(e.currentYearAvg)} ${t}${l(t.currentYear)} ${s}${l(t.currentYearAvg)} ${s}
Past Year${o(e.pastYear)} ${t}${o(e.pastYearAvg)} ${t}${l(t.pastYear)} ${s}${l(t.pastYearAvg)} ${s}
Past 6 Months${o(e.past6m)} ${t}${o(e.past6mAvg)} ${t}${l(t.past6m)} ${s}${l(t.past6mAvg)} ${s}
Past 1 Month${o(e.past1m)} ${t}${o(e.past1mAvg)} ${t}${l(t.past1m)} ${s}${l(t.past1mAvg)} ${s}
Total${o(e.total)} ${t}${o(e.totalAvg)} ${t}${l(t.total)} ${s}${l(t.totalAvg)} ${s}
- `}var In=[];function Kl(){In.forEach(e=>e.destroy()),In=[]}function eo(){Kl();let e=document.getElementById("evolution-view");e&&(e.innerHTML=` + `}function oi(t){let n=gn(t,c=>c.stats.totalDist),s=gn(t,c=>c.stats.elevGain),e=gn(t,c=>c.stats.duration?c.stats.duration/36e5:0),l=gn(t,c=>{let d=(c.stats.duration||0)/1e3,w=c.stats.avgPower||150,g=200,f=w/g;return d*w*f/(g*3600)*100}),i=gn(t,c=>{let d=(c.stats.duration||0)/1e3,w=c.stats.avgPower||0;return d*w/1e3}),a=gn(t,c=>(c.stats.sections||[]).filter(w=>w.kind==="climb").length);return{distance:n,elevation:s,durationHours:e,tss:l,workKj:i,climbCount:a}}function ol(t){let n=oi(t),s=(l,i=1)=>l.toLocaleString("en-US",{minimumFractionDigits:i,maximumFractionDigits:i});return` +
+
+
+ monitoring + Accumulated Longitudinal Progress Summary +
+
+ + + + + + + + + + + + + + ${[{label:"Distance",unit:"km",data:n.distance,scale:.001,digits:1},{label:"Elevation Gain",unit:"m",data:n.elevation,scale:1,digits:0},{label:"Moving Duration",unit:"h",data:n.durationHours,scale:1,digits:1},{label:"Training Stress (TSS)",unit:"TSS",data:n.tss,scale:1,digits:0},{label:"Mechanical Work",unit:"kJ",data:n.workKj,scale:1,digits:0},{label:"Categorized Climbs",unit:"climbs",data:n.climbCount,scale:1,digits:0}].map(l=>` + + + + + + + + + `).join("")} + +
MetricPast 1MPast 6MPast YearCurrent YearTotalWeekly Avg
${l.label}${s(l.data.past1m*l.scale,l.digits)} ${l.unit}${s(l.data.past6m*l.scale,l.digits)} ${l.unit}${s(l.data.pastYear*l.scale,l.digits)} ${l.unit}${s(l.data.currentYear*l.scale,l.digits)} ${l.unit}${s(l.data.total*l.scale,l.digits)} ${l.unit}${s(l.data.totalAvg*l.scale,l.digits)} ${l.unit}/wk
+
+ `}var In=[],Kn=[],Ks="week";function cl(){In.forEach(t=>t.destroy()),In=[],Kn=[]}function dl(){cl(),Ks="week";let t=document.getElementById("evolution-view");t&&(t.innerHTML=`
no_sim
Select a track for progress analysis
- `)}var Gn=16384,Pn=new Float64Array(Gn+1),hn=new Float64Array(Gn+1),Ys=new Float64Array(Gn+1),Gl=new Float64Array(Gn),js=new Float64Array(365),Go=[3,5,7,10,12,14],Xo=[28,35,42,50,60,72],Xl=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,360,450,600,750,900,1200];function Hn(e,n,t,s){Kl();let o=document.getElementById("evolution-view");if(!o)return;let a=Ye.get().progress||"all";n.forEach(v=>{ot.ensureCurvesAndZones(v)});let p=0,c=0;js.fill(0);for(let v=0;vw)continue;let z=w-W,de=0,y=0;for(let m=0;m<=z;m++){let r=hn[m+W]-hn[m],J=(Pn[m+W]-Pn[m])*G+r*q,V=r+Pn[m]*q;J>de&&(de=J),V>y&&(y=V)}c+=(de+y+Ys[z])/W*.001}}for(let N=0;N<1;N++)for(let G=0;G<1;G++){let q=2/(Go[G]+N+1),_=1-q,W=1.67+G*.06+N*.03;for(let z=0;z<2;z++){let de=2/(Xo[z]+N+1),y=1-de,m=50+z*2,r=1/(195-m),J=0,V=0;for(let ee=0;ee{n&&n.updateGrouping&&n.updateGrouping(t)})}function As(t){Gt.patch({progress:t==="all"?null:t});let n=document.querySelector("#evolution-time-range");n&&n.querySelectorAll(".seg-btn").forEach(s=>{s.classList.toggle("active",s.getAttribute("data-range")===t)}),Kn.forEach(s=>{s&&s.updateRange&&s.updateRange(t)})}function Is(t){Kn.forEach(n=>{n&&n.updatePin&&n.updatePin(t)})}var ts=16384,Qn=new Float64Array(ts+1),Sn=new Float64Array(ts+1),Xs=new Float64Array(ts+1),ll=new Float64Array(ts),Qs=new Float64Array(365),il=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,360,450,600,750,900,1200];function Hn(t,n,s,e){cl();let l=document.getElementById("evolution-view");if(!l)return;let i=Gt.get().progress||"all";n.forEach(b=>{Jt.ensureCurvesAndZones(b)});let a=0,c=0;Qs.fill(0);for(let b=0;bS)continue;let N=S-u,E=0,G=0;for(let U=0;U<=N;U++){let j=Sn[U+u]-Sn[U],Rt=Qn[U+u]-Qn[U];Rt>E&&(E=Rt),j>G&&(G=j)}c+=(E+G+Xs[N])/u*.001}let _=2/8,W=1-_,O=2/43,Y=1-O,Z=52,lt=1/(195-Z),Ft=0,rt=0;for(let v=0;v
- - - -
- - - - - - + + + + + +
- `;let x=document.getElementById("evolution-container");if(!x)return;let g=x.clientWidth||570,T=An.sync("progress-sync");d.push(Ql(x,n,"distance",T,s,g)),d.push(Ql(x,n,"elevation",T,s,g));let $=x.querySelector(".distance-progress-card .chart-scroll-container"),M=x.querySelector(".elevation-progress-card .chart-scroll-container");$&&M&&($.addEventListener("scroll",()=>{M.scrollLeft!==$.scrollLeft&&(M.scrollLeft=$.scrollLeft)}),M.addEventListener("scroll",()=>{$.scrollLeft!==M.scrollLeft&&($.scrollLeft=M.scrollLeft)}));let C=o.querySelector("#evolution-time-range");C&&C.querySelectorAll(".seg-btn").forEach(v=>{v.addEventListener("click",()=>{let u=v.getAttribute("data-range");u&&(C.querySelectorAll(".seg-btn").forEach(w=>w.classList.remove("active")),v.classList.add("active"),F(u))})}),o.querySelectorAll(".metric-pill").forEach(v=>{v.addEventListener("click",()=>{let u=v.getAttribute("data-target");u&&document.getElementById(`${u}-evolution-card`)?.scrollIntoView({behavior:"smooth"})})});function f(v){d.forEach(u=>{u&&u.updatePin&&u.updatePin(v)})}function F(v){Ye.patch({progress:v==="all"?null:v}),d.forEach(u=>{u&&u.updateRange&&u.updateRange(v)})}if(n.some(v=>v.stats.powerCurve)){let v=Jl({grid:x,currentTrack:e,allTracks:n,metricKey:"power",label:"Power Curve Progress",unit:"W",color:We.power.color,icon:"bolt",onPinChange:f,onRangeChange:F,onTrackSelect:t,gridWidth:g});d.push(v)}if(n.some(v=>v.stats.hrCurve)){let v=Jl({grid:x,currentTrack:e,allTracks:n,metricKey:"hr",label:"Heart Rate Curve Progress",unit:"bpm",color:We.hr.color,icon:"favorite",onPinChange:f,onRangeChange:F,onTrackSelect:t,gridWidth:g});d.push(v)}a!=="all"&&d.forEach(v=>{v&&v.updateRange&&v.updateRange(a)}),In.forEach(v=>{v._ready=!0})}function Jl(e){let{grid:n,currentTrack:t,allTracks:s,metricKey:o,label:a,unit:p,color:c,icon:d,onPinChange:x,onRangeChange:g,onTrackSelect:T,gridWidth:$}=e,M=t&&t.name||"Current Track",C=null,k=document.createElement("div");k.className="chart-row evolution-card-group",k.id=`${o}-evolution-card`,n.appendChild(k);let f=document.createElement("div");f.className="chart-row progress-chart-row",f.style.setProperty("--chart-color",c),f.style.flex="0 0 400px",f.style.borderBottom="none",f.innerHTML=` + `;let f=document.getElementById("evolution-container");if(!f)return;f.insertAdjacentHTML("beforeend",ol(n));let A=f.clientWidth||570,C=An.sync("progress-sync");g.push(rl(f,n,"distance",C,e,A)),g.push(rl(f,n,"elevation",C,e,A));let $=f.querySelector(".distance-progress-card .chart-scroll-container"),M=f.querySelector(".elevation-progress-card .chart-scroll-container");$&&M&&($.addEventListener("scroll",()=>{M.scrollLeft!==$.scrollLeft&&(M.scrollLeft=$.scrollLeft)}),M.addEventListener("scroll",()=>{$.scrollLeft!==M.scrollLeft&&($.scrollLeft=M.scrollLeft)}));let m=l.querySelector("#evolution-time-range");m&&m.querySelectorAll(".seg-btn").forEach(b=>{b.addEventListener("click",()=>{let p=b.getAttribute("data-range");p&&(m.querySelectorAll(".seg-btn").forEach(S=>S.classList.remove("active")),b.classList.add("active"),h(p))})}),l.querySelectorAll(".metric-pill").forEach(b=>{b.addEventListener("click",()=>{let p=b.getAttribute("data-target");p&&document.getElementById(`${p}-evolution-card`)?.scrollIntoView({behavior:"smooth"})})});function P(b){g.forEach(p=>{p&&p.updatePin&&p.updatePin(b)})}function h(b){Gt.patch({progress:b==="all"?null:b}),g.forEach(p=>{p&&p.updateRange&&p.updateRange(b)})}if(n.some(b=>b.stats.powerCurve)){let b=al({grid:f,currentTrack:t,allTracks:n,metricKey:"power",label:"Power Curve Progress",unit:"W",color:Nt.power.color,icon:"bolt",onPinChange:P,onRangeChange:h,onTrackSelect:s,gridWidth:A});g.push(b)}if(n.some(b=>b.stats.hrCurve)){let b=al({grid:f,currentTrack:t,allTracks:n,metricKey:"hr",label:"Heart Rate Curve Progress",unit:"bpm",color:Nt.hr.color,icon:"favorite",onPinChange:P,onRangeChange:h,onTrackSelect:s,gridWidth:A});g.push(b)}i!=="all"&&g.forEach(b=>{b&&b.updateRange&&b.updateRange(i)}),In.forEach(b=>{b._ready=!0})}function al(t){let{grid:n,currentTrack:s,allTracks:e,metricKey:l,label:i,unit:a,color:c,icon:d,onPinChange:w,onRangeChange:g,onTrackSelect:f,gridWidth:A}=t,C=s&&s.name||"Current Track",$=null,M=document.createElement("div");M.className="chart-row evolution-card-group",M.id=`${l}-evolution-card`,n.appendChild(M);let m=document.createElement("div");m.className="chart-row progress-chart-row",m.style.setProperty("--chart-color",c),m.style.flex="0 0 400px",m.style.borderBottom="none",m.innerHTML=`
${d} - ${a} + ${i}
-
+
- `;let F=document.createElement("div");F.className="evolution-legend",F.innerHTML=` + `;let k=document.createElement("div");k.className="evolution-legend",k.innerHTML=`
- ${M} + ${C}
All-Time Max
- `;let u=Ye.get().progress||"all",w=document.createElement("div");w.className="chart-row progress-chart-row",w.style.setProperty("--chart-color",c),w.style.flex="1",w.style.borderBottom="none",w.innerHTML=` + `;let h=Gt.get().progress||"all",b=document.createElement("div");b.className="chart-row progress-chart-row",b.style.setProperty("--chart-color",c),b.style.flex="1",b.style.borderBottom="none",b.innerHTML=`
${d} - Progress ${o==="power"?"Power":"HR"} + Progress ${l==="power"?"Power":"HR"}
-
+
- `;let E=document.createElement("div");E.style.cssText="display: flex; flex-direction: row; gap: 0px; align-items: stretch;",E.appendChild(f),E.appendChild(w),k.appendChild(E),k.appendChild(F);let N=f.querySelector(`#${o}-evolution-chart`);if(!N)return;let G={};s.forEach(se=>{let me=o==="power"?se.stats.powerCurve:se.stats.hrCurve;if(!me)return;let fe=se.name||"Unnamed Track",Pe=se.stats.startTime||se.addedAt?Gt(se.stats.startTime||se.addedAt):"Unknown Date",j=`${fe} (${Pe})`;Object.entries(me).forEach(([H,oe])=>{let ge=Number(H),K=oe.power||oe.hr;(!G[ge]||K>G[ge].val)&&(G[ge]={val:K,trackInfo:j,trackId:se.id,idx:oe.idx})})});let q=t&&(o==="power"?t.stats.powerCurve:t.stats.hrCurve)||{},_=new Set;Object.keys(G).forEach(se=>_.add(Number(se))),Object.keys(q).forEach(se=>_.add(Number(se)));let W=Array.from(_).sort((se,me)=>se-me),z=W,de=W.map(se=>{let me=q[se];return me?me.power||me.hr:null}),y=W.map(se=>G[se]?.val||null),m=s.filter(se=>(se.stats.startTime||se.addedAt)!=null);m.sort((se,me)=>(se.stats.startTime||se.addedAt||0)-(me.stats.startTime||me.addedAt||0)||se.id.localeCompare(me.id));let r=[],J={};W.forEach(se=>J[se]=[]),m.forEach(se=>{let me=o==="power"?se.stats.powerCurve:se.stats.hrCurve;me&&(r.push((se.stats.startTime||se.addedAt)/1e3),W.forEach(fe=>{let Pe=me[fe],j=Pe?o==="power"?Pe.power:Pe.hr:null;J[fe].push(j)}))});let V=W[0]||5,ee=m,U=null;function Q(se,me){let fe=r[r.length-1]||1785542400,Pe=0;me==="1m"?Pe=fe-30*24*3600:me==="2m"?Pe=fe-60*24*3600:me==="6m"?Pe=fe-180*24*3600:me==="1y"?Pe=fe-365*24*3600:me==="2y"&&(Pe=fe-2*365*24*3600);let j=[];r.forEach((Ie,he)=>{Ie>=Pe&&j.push(he)});let H=j.map(Ie=>r[Ie]),oe=J[se]||[],ge=j.map(Ie=>oe[Ie]),K=En(ge,5);return ee=j.map(Ie=>m[Ie]),{xFiltered:H,rawYFiltered:ge,smoothedYFiltered:K}}let ke=null,re=document.createElement("div");return re.className="cur-y-val font-m",re.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",N.style.position="relative",N.appendChild(re),(()=>{let se={id:`${o}-evolution`,width:400,height:250,padding:[0,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:"Current Track",stroke:c,width:2,fill:tt(c,.1),points:{show:!0,size:5,fill:c}},{label:"All-Time Max",stroke:"#888888",width:1,fill:"transparent",points:{show:!0,size:6,fill:"#888888"}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(j,H)=>H.map(oe=>`${oe}${p}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(j,H,oe)=>oe,x:!1,y:!1},hooks:{draw:[j=>{let H=j.ctx,oe=window.devicePixelRatio||1,ge=j.bbox,K=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Ie=z[z.length-1];H.save(),H.fillStyle="#555564",H.textAlign="center",H.textBaseline="top",H.font=`${10*oe}px system-ui, sans-serif`;let he=-100;if(K.forEach(He=>{if(He>Ie)return;let Ce=j.valToPos(He,"x",!0);Ce>he+30*oe&&Ce=0){let Ce=j.valToPos(U,"x",!0),Re=j.valToPos(de[He]||y[He],"y",!0);H.save(),H.beginPath(),H.setLineDash([]);let le=de[He],ye=le!==null?5*oe:3*oe,I=le!==null?c:"#888888";H.arc(Ce,Re,ye,0,2*Math.PI),H.fillStyle=I,H.fill(),H.strokeStyle="#fff",H.lineWidth=2*oe,H.stroke(),H.restore()}}H.restore()},j=>{let H=j.ctx,oe=window.devicePixelRatio||1,ge=j.bbox,K=j.cursor.idx,Ie=1,he=j.cursor.left,He=j.cursor.top;if(he!=null&&He!=null&&he>=0&&He>=0){let Ce=1/0,Re=-1,le=30,ye=le*le;for(let I=0;I{if(!j._ready)return;j.redraw(!1);let H=j.cursor.idx,oe=1,ge=j.cursor.left,K=j.cursor.top;if(ge!=null&&K!=null&&ge>=0&&K>=0){let Re=1/0,le=-1,ye=30,I=ye*ye;for(let ne=0;ne${_t(ye)}
`;if(I!==null&&(Ne+=` + `;let p=document.createElement("div");p.style.cssText="display: flex; flex-direction: row; gap: 0px; align-items: stretch;",p.appendChild(m),p.appendChild(b),M.appendChild(p),M.appendChild(k);let S=m.querySelector(`#${l}-evolution-chart`);if(!S)return;let _={};e.forEach(at=>{let nt=l==="power"?at.stats.powerCurve:at.stats.hrCurve;if(!nt)return;let $t=at.name||"Unnamed Track",ht=at.stats.startTime||at.addedAt?nn(at.stats.startTime||at.addedAt):"Unknown Date",z=`${$t} (${ht})`;Object.entries(nt).forEach(([D,it])=>{let K=Number(D),bt=it.power||it.hr;(!_[K]||bt>_[K].val)&&(_[K]={val:bt,trackInfo:z,trackId:at.id,idx:it.idx})})});let W=s&&(l==="power"?s.stats.powerCurve:s.stats.hrCurve)||{},O=new Set;Object.keys(_).forEach(at=>O.add(Number(at))),Object.keys(W).forEach(at=>O.add(Number(at)));let Y=Array.from(O).sort((at,nt)=>at-nt),Z=Y,lt=Y.map(at=>{let nt=W[at];return nt?nt.power||nt.hr:null}),Ft=Y.map(at=>_[at]?.val||null),rt=e.filter(at=>(at.stats.startTime||at.addedAt)!=null);rt.sort((at,nt)=>(at.stats.startTime||at.addedAt||0)-(nt.stats.startTime||nt.addedAt||0)||at.id.localeCompare(nt.id));let x=[],v={};Y.forEach(at=>v[at]=[]),rt.forEach(at=>{let nt=l==="power"?at.stats.powerCurve:at.stats.hrCurve;nt&&(x.push((at.stats.startTime||at.addedAt)/1e3),Y.forEach($t=>{let ht=nt[$t],z=ht?l==="power"?ht.power:ht.hr:null;v[$t].push(z)}))});let u=Y[0]||5,N=rt,E=null;function G(at,nt){let $t=x[x.length-1]||1785542400,ht=0;nt==="1m"?ht=$t-30*24*3600:nt==="2m"?ht=$t-60*24*3600:nt==="6m"?ht=$t-180*24*3600:nt==="1y"?ht=$t-365*24*3600:nt==="2y"&&(ht=$t-2*365*24*3600);let z=[];x.forEach((Pt,ut)=>{Pt>=ht&&z.push(ut)});let D=z.map(Pt=>x[Pt]),it=v[at]||[],K=z.map(Pt=>it[Pt]),bt=Cn(K,5);return N=z.map(Pt=>rt[Pt]),{xFiltered:D,rawYFiltered:K,smoothedYFiltered:bt}}let U=null,j=document.createElement("div");return j.className="cur-y-val font-m",j.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",S.style.position="relative",S.appendChild(j),(()=>{let at={id:`${l}-evolution`,width:400,height:250,padding:[0,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:"Current Track",stroke:c,width:2,fill:le(c,.1),points:{show:!0,size:5,fill:c}},{label:"All-Time Max",stroke:"#888888",width:1,fill:"transparent",points:{show:!0,size:6,fill:"#888888"}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(z,D)=>D.map(it=>`${it}${a}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(z,D,it)=>it,x:!1,y:!1},hooks:{draw:[z=>{let D=z.ctx,it=window.devicePixelRatio||1,K=z.bbox,bt=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Pt=Z[Z.length-1];D.save(),D.fillStyle="#555564",D.textAlign="center",D.textBaseline="top",D.font=`${10*it}px system-ui, sans-serif`;let ut=-100;if(bt.forEach(Ht=>{if(Ht>Pt)return;let dt=z.valToPos(Ht,"x",!0);dt>ut+30*it&&dt=0){let dt=z.valToPos(E,"x",!0),Lt=z.valToPos(lt[Ht]||Ft[Ht],"y",!0);D.save(),D.beginPath(),D.setLineDash([]);let st=lt[Ht],gt=st!==null?5*it:3*it,At=st!==null?c:"#888888";D.arc(dt,Lt,gt,0,2*Math.PI),D.fillStyle=At,D.fill(),D.strokeStyle="#fff",D.lineWidth=2*it,D.stroke(),D.restore()}}D.restore()},z=>{let D=z.ctx,it=window.devicePixelRatio||1,K=z.bbox,bt=z.cursor.idx,Pt=1,ut=z.cursor.left,Ht=z.cursor.top;if(ut!=null&&Ht!=null&&ut>=0&&Ht>=0){let dt=1/0,Lt=-1,st=30,gt=st*st;for(let At=0;At{if(!z._ready)return;z.redraw(!1);let D=z.cursor.idx,it=1,K=z.cursor.left,bt=z.cursor.top;if(K!=null&&bt!=null&&K>=0&&bt>=0){let Lt=1/0,st=-1,gt=30,At=gt*gt;for(let zt=0;zt${ze(gt)}
`;if(At!==null&&(V+=`
Current: - ${I} ${p} + ${At} ${a}
- `),ne!==null&&(Ne+=` + `),zt!==null&&(V+=`
Max: - ${ne} ${p} + ${zt} ${a}
- `),re.innerHTML=Ne,ke&&U===null){V=ye;let{xFiltered:Z,rawYFiltered:Be,smoothedYFiltered:xe}=Q(V,u),Ee=xe.map(we=>we!==null?we*.9:null),Me=xe.map(we=>we!==null?we*1.1:null);ke.setData([Z,Be,xe,Ee,Me]);let be=document.getElementById(`${o}-timeline-label`);be&&(be.textContent=`Progress ${_t(ye)} ${o==="power"?"Power":"HR"}`)}re.style.display="",re.style.left=`${ge+He.left}px`,re.style.top=`${K+He.top}px`,re.style.transform="translate(5px, -50%)"}else re.style.display="none"}]}};C=new An(se,[z,de,y],N),In.push(C),N.addEventListener("click",()=>{if(!C)return;let j=C.cursor.idx;if(j!=null){let H=z[j],oe=null;if(U!==null?oe=null:oe=H,x(oe),t){let ge=t.stats,K=o==="power"?ge.powerCurve:ge.hrCurve;if(K){let Ie=K[H];if(Ie){let he=Ie.idx,He=H,Ce=t.points[he],Re=t.points[he+He-1];if(Ce&&Re&&Ce.time!=null&&Re.time!=null){let le=t.points[0].time||0,ye=(Ce.time-le)/1e3,I=(Re.time-le)/1e3;T?.(t.id,[ye,I])}}}}}}),N.addEventListener("mouseleave",()=>{C&&C.redraw()});let me=document.createElement("details");me.classList.add("progress-details"),me.style.marginTop="0px",me.style.setProperty("--chart-color",c),me.innerHTML=` + `),j.innerHTML=V,U&&E===null){u=gt;let{xFiltered:R,rawYFiltered:Dt,smoothedYFiltered:It}=G(u,h),Wt=It.map(yt=>yt!==null?yt*.9:null),Et=It.map(yt=>yt!==null?yt*1.1:null);U.setData([R,Dt,It,Wt,Et]);let vt=document.getElementById(`${l}-timeline-label`);vt&&(vt.textContent=`Progress ${ze(gt)} ${l==="power"?"Power":"HR"}`)}j.style.display="",j.style.left=`${K+Ht.left}px`,j.style.top=`${bt+Ht.top}px`,j.style.transform="translate(5px, -50%)"}else j.style.display="none"}]}};$=new An(at,[Z,lt,Ft],S),In.push($),S.addEventListener("click",()=>{if(!$)return;let z=$.cursor.idx;if(z!=null){let D=Z[z],it=null;if(E!==null?it=null:it=D,w(it),s){let K=s.stats,bt=l==="power"?K.powerCurve:K.hrCurve;if(bt){let Pt=bt[D];if(Pt){let ut=Pt.idx,Ht=D,dt=s.points[ut],Lt=s.points[ut+Ht-1];if(dt&&Lt&&dt.time!=null&&Lt.time!=null){let st=s.points[0].time||0,gt=(dt.time-st)/1e3,At=(Lt.time-st)/1e3;f?.(s.id,[gt,At])}}}}}}),S.addEventListener("mouseleave",()=>{$&&$.redraw()});let nt=document.createElement("details");nt.classList.add("progress-details"),nt.style.marginTop="0px",nt.style.setProperty("--chart-color",c),nt.innerHTML=` chevron_right table_chart @@ -808,59 +955,59 @@ var Ye=(()=>{let e={},n=null,t=null,s=!1;function o(){let g=new URLSearchParams( - ${W.map(j=>{let H=q[j]?q[j].power||q[j].hr:"-",oe=G[j]?.val||"-",ge=G[j]?.trackId,K=G[j]?.idx;return` + ${Y.map(z=>{let D=W[z]?W[z].power||W[z].hr:"-",it=_[z]?.val||"-",K=_[z]?.trackId,bt=_[z]?.idx;return` - ${_t(j)} - ${H} ${p} + ${ze(z)} + ${D} ${a} - ${oe} ${p} - ${ge?``:""} + ${it} ${a} + ${K?``:""} `}).join("")} - `,k.appendChild(me),me.querySelectorAll(".evolution-select-btn").forEach(j=>{j.addEventListener("click",H=>{H.preventDefault(),H.stopPropagation();let oe=j.getAttribute("data-id"),ge=j.getAttribute("data-idx"),K=j.getAttribute("data-dur");oe&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:oe,idx:ge?Number(ge):null,dur:K?Number(K):null}}))})});let fe=null,Pe=w.querySelector(`#${o}-timeline-chart`);if(Pe){Pe.style.position="relative";let j=document.createElement("div");if(j.className="timeline-tooltip font-m",j.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",Pe.appendChild(j),r.length>0){let{xFiltered:H,rawYFiltered:oe,smoothedYFiltered:ge}=Q(V,u),K=ge.map(le=>le!==null?le*.9:null),Ie=ge.map(le=>le!==null?le*1.1:null),he=[H,oe,ge,K,Ie],He=[{value:(le,ye)=>ye!=null?Gt(ye*1e3):"-"},{label:"Value",stroke:c,width:0,points:{show:!0,size:6,fill:tt(c,.5)}},{label:"Trend",stroke:c,width:2,points:{show:!1},spanGaps:!0,fill:"transparent",dash:[5,5]},{label:"Lower Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0},{label:"Upper Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0}],Ce=document.getElementById(`${o}-timeline-label`);Ce&&(Ce.textContent=`Progress ${_t(V)} ${o==="power"?"Power":"HR"}`);let Re={width:Math.max(100,($||570)-400),height:250,padding:[0,10,0,10],tzDate:le=>An.tzDate(new Date(le*1e3),"Etc/UTC"),cursor:{points:{show:!1},drag:{setScale:!1},x:!1,y:!1},scales:{x:{time:!0,range:le=>{let ye=le.data[0][0],I=le.data[0][le.data[0].length-1];return ye===void 0||I===void 0?[0,100]:ye===I?[ye-3600,I+3600]:[ye,I]}},y:{range:(le,ye,I)=>[ye*.9,I*1.1]}},series:He,bands:[{series:[4,3],fill:tt(c,.2)}],hooks:{init:[le=>{le.over.addEventListener("click",()=>{if(fe!=null){let ye=ee[fe];if(ye){let I=ye.stats,ne=o==="power"?I.powerCurve:I.hrCurve;if(ne){let Ne=ne[V];if(Ne){let Z=Ne.idx,Be=V,xe=ye.points[Z],Ee=ye.points[Z+Be-1];if(xe&&Ee&&xe.time!=null&&Ee.time!=null){let Me=ye.points[0].time||0,be=(xe.time-Me)/1e3,we=(Ee.time-Me)/1e3;e.onTrackSelect?.(ye.id,[be,we])}else e.onTrackSelect?.(ye.id,null)}else e.onTrackSelect?.(ye.id,null)}else e.onTrackSelect?.(ye.id,null)}}})}],draw:[le=>{let ye=le.cursor.idx;if(ye!=null&&le.data[0][ye]!=null){let I=le.data[1][ye];if(I!=null){let ne=le.valToPos(le.data[0][ye],"x",!0),Ne=le.valToPos(I,"y",!0),Z=le.ctx,Be=window.devicePixelRatio||1;Z.save(),Z.beginPath(),Z.setLineDash([2*Be,2*Be]),Z.strokeStyle=tt(c,.4),Z.lineWidth=1*Be,Z.moveTo(ne,le.bbox.top),Z.lineTo(ne,le.bbox.top+le.bbox.height),Z.moveTo(le.bbox.left,Ne),Z.lineTo(le.bbox.left+le.bbox.width,Ne),Z.stroke(),Z.restore(),Z.save(),Z.beginPath(),Z.setLineDash([]),Z.arc(ne,Ne,12*Be,0,2*Math.PI),Z.fillStyle=tt(c,.2),Z.fill(),Z.restore(),Z.save(),Z.beginPath(),Z.arc(ne,Ne,6*Be,0,2*Math.PI),Z.fillStyle=c,Z.fill(),Z.strokeStyle="#fff",Z.lineWidth=2*Be,Z.stroke(),Z.restore(),Z.save(),Z.setLineDash([]);let xe=new Date(le.data[0][ye]*1e3),Ee=`${xe.getUTCFullYear()}-${String(xe.getUTCMonth()+1).padStart(2,"0")}-${String(xe.getUTCDate()).padStart(2,"0")}`;Z.font=`bold ${10*Be}px system-ui, sans-serif`;let be=Z.measureText(Ee).width+10*Be,we=16*Be,qe=ne-be/2,je=Math.max(le.bbox.left,Math.min(le.bbox.left+le.bbox.width-be,qe)),dt=le.bbox.top+le.bbox.height+2*Be;Z.fillStyle="rgba(14, 14, 16, 0.92)",Z.beginPath(),Z.roundRect?Z.roundRect(je,dt,be,we,3*Be):Z.rect(je,dt,be,we),Z.fill(),Z.strokeStyle=tt(c,.27),Z.lineWidth=1*Be,Z.stroke(),Z.fillStyle=c,Z.textAlign="center",Z.textBaseline="middle",Z.fillText(Ee,je+be/2,dt+we/2);let At=`${I.toFixed(0)} ${p}`,Qt=Z.measureText(At).width+10*Be,Yt=le.bbox.left-Qt-2*Be,wn=Ne-we/2;Z.fillStyle="rgba(14, 14, 16, 0.92)",Z.beginPath(),Z.roundRect?Z.roundRect(Yt,wn,Qt,we,3*Be):Z.rect(Yt,wn,Qt,we),Z.fill(),Z.strokeStyle=tt(c,.27),Z.lineWidth=1*Be,Z.stroke(),Z.fillStyle=c,Z.textAlign="left",Z.textBaseline="middle",Z.fillText(At,Yt+5*Be,wn+we/2),Z.restore()}}}],setCursor:[le=>{if(!le._ready)return;le.redraw(!1);let ye=le.cursor.idx,I=le.cursor.left,ne=le.cursor.top,Ne=le.bbox;if(I!=null&&ne!=null&&I>=0&&ne>=0){let Z=1/0,Be=-1,xe=30,Ee=xe*xe,Me=le.data[0],be=le.data[1];for(let we=0;we{z.addEventListener("click",D=>{D.preventDefault(),D.stopPropagation();let it=z.getAttribute("data-id"),K=z.getAttribute("data-idx"),bt=z.getAttribute("data-dur");it&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:it,idx:K?Number(K):null,dur:bt?Number(bt):null}}))})});let $t=null,ht=b.querySelector(`#${l}-timeline-chart`);if(ht){ht.style.position="relative";let z=document.createElement("div");if(z.className="timeline-tooltip font-m",z.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",ht.appendChild(z),x.length>0){let{xFiltered:D,rawYFiltered:it,smoothedYFiltered:K}=G(u,h),bt=K.map(st=>st!==null?st*.9:null),Pt=K.map(st=>st!==null?st*1.1:null),ut=[D,it,K,bt,Pt],Ht=[{value:(st,gt)=>gt!=null?nn(gt*1e3):"-"},{label:"Value",stroke:c,width:0,points:{show:!0,size:6,fill:le(c,.5)}},{label:"Trend",stroke:c,width:2,points:{show:!1},spanGaps:!0,fill:"transparent",dash:[5,5]},{label:"Lower Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0},{label:"Upper Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0}],dt=document.getElementById(`${l}-timeline-label`);dt&&(dt.textContent=`Progress ${ze(u)} ${l==="power"?"Power":"HR"}`);let Lt={width:Math.max(100,(A||570)-400),height:250,padding:[0,10,0,10],tzDate:st=>An.tzDate(new Date(st*1e3),"Etc/UTC"),cursor:{points:{show:!1},drag:{setScale:!1},x:!1,y:!1},scales:{x:{time:!0,range:st=>{let gt=st.data[0][0],At=st.data[0][st.data[0].length-1];return gt===void 0||At===void 0?[0,100]:gt===At?[gt-3600,At+3600]:[gt,At]}},y:{range:(st,gt,At)=>[gt*.9,At*1.1]}},series:Ht,bands:[{series:[4,3],fill:le(c,.2)}],hooks:{init:[st=>{st.over.addEventListener("click",()=>{if($t!=null){let gt=N[$t];if(gt){let At=gt.stats,zt=l==="power"?At.powerCurve:At.hrCurve;if(zt){let V=zt[u];if(V){let R=V.idx,Dt=u,It=gt.points[R],Wt=gt.points[R+Dt-1];if(It&&Wt&&It.time!=null&&Wt.time!=null){let Et=gt.points[0].time||0,vt=(It.time-Et)/1e3,yt=(Wt.time-Et)/1e3;t.onTrackSelect?.(gt.id,[vt,yt])}else t.onTrackSelect?.(gt.id,null)}else t.onTrackSelect?.(gt.id,null)}else t.onTrackSelect?.(gt.id,null)}}})}],draw:[st=>{let gt=st.cursor.idx;if(gt!=null&&st.data[0][gt]!=null){let At=st.data[1][gt];if(At!=null){let zt=st.valToPos(st.data[0][gt],"x",!0),V=st.valToPos(At,"y",!0),R=st.ctx,Dt=window.devicePixelRatio||1;R.save(),R.beginPath(),R.setLineDash([2*Dt,2*Dt]),R.strokeStyle=le(c,.4),R.lineWidth=1*Dt,R.moveTo(zt,st.bbox.top),R.lineTo(zt,st.bbox.top+st.bbox.height),R.moveTo(st.bbox.left,V),R.lineTo(st.bbox.left+st.bbox.width,V),R.stroke(),R.restore(),R.save(),R.beginPath(),R.setLineDash([]),R.arc(zt,V,12*Dt,0,2*Math.PI),R.fillStyle=le(c,.2),R.fill(),R.restore(),R.save(),R.beginPath(),R.arc(zt,V,6*Dt,0,2*Math.PI),R.fillStyle=c,R.fill(),R.strokeStyle="#fff",R.lineWidth=2*Dt,R.stroke(),R.restore(),R.save(),R.setLineDash([]);let It=new Date(st.data[0][gt]*1e3),Wt=`${It.getUTCFullYear()}-${String(It.getUTCMonth()+1).padStart(2,"0")}-${String(It.getUTCDate()).padStart(2,"0")}`;R.font=`bold ${10*Dt}px system-ui, sans-serif`;let vt=R.measureText(Wt).width+10*Dt,yt=16*Dt,_t=zt-vt/2,qt=Math.max(st.bbox.left,Math.min(st.bbox.left+st.bbox.width-vt,_t)),Yt=st.bbox.top+st.bbox.height+2*Dt;R.fillStyle="rgba(14, 14, 16, 0.92)",R.beginPath(),R.roundRect?R.roundRect(qt,Yt,vt,yt,3*Dt):R.rect(qt,Yt,vt,yt),R.fill(),R.strokeStyle=le(c,.27),R.lineWidth=1*Dt,R.stroke(),R.fillStyle=c,R.textAlign="center",R.textBaseline="middle",R.fillText(Wt,qt+vt/2,Yt+yt/2);let ee=`${At.toFixed(0)} ${a}`,De=R.measureText(ee).width+10*Dt,Le=st.bbox.left-De-2*Dt,_n=V-yt/2;R.fillStyle="rgba(14, 14, 16, 0.92)",R.beginPath(),R.roundRect?R.roundRect(Le,_n,De,yt,3*Dt):R.rect(Le,_n,De,yt),R.fill(),R.strokeStyle=le(c,.27),R.lineWidth=1*Dt,R.stroke(),R.fillStyle=c,R.textAlign="left",R.textBaseline="middle",R.fillText(ee,Le+5*Dt,_n+yt/2),R.restore()}}}],setCursor:[st=>{if(!st._ready)return;st.redraw(!1);let gt=st.cursor.idx,At=st.cursor.left,zt=st.cursor.top,V=st.bbox;if(At!=null&&zt!=null&&At>=0&&zt>=0){let R=1/0,Dt=-1,It=30,Wt=It*It,Et=st.data[0],vt=st.data[1];for(let yt=0;yt Date: - ${Me} + ${Et}
Value: - ${we} + ${yt}
- `,j.style.display="block",j.style.left=`${I+Ne.left}px`,j.style.top=`${ne+Ne.top}px`,j.style.transform="translate(5px, -50%)"}else j.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(le,ye)=>ye.map(I=>{let ne=new Date(I*1e3);return`${ne.getUTCFullYear()}-${String(ne.getUTCMonth()+1).padStart(2,"0")}`})},{stroke:"#555564",grid:{stroke:"#2e2e34"},font:"10px system-ui, sans-serif",values:(le,ye)=>ye.map(I=>`${I} ${p}`),show:!0,space:15,size:50}]};ke=new An(Re,he,Pe),In.push(ke),Pe.addEventListener("mouseleave",()=>{ke.redraw()})}else Pe.innerHTML='
No data for the past year
'}})(),{updatePin:se=>{U=se,se!==null&&(V=se);let me=document.getElementById(`${o}-timeline-label`);if(me&&(me.textContent=`Progress ${_t(V)} ${o==="power"?"Power":"HR"}${U!==null?" (Pinned)":""}`),ke){let{xFiltered:fe,rawYFiltered:Pe,smoothedYFiltered:j}=Q(V,u),H=j.map(ge=>ge!==null?ge*.9:null),oe=j.map(ge=>ge!==null?ge*1.1:null);ke.setData([fe,Pe,j,H,oe])}C&&C.redraw()},updateRange:se=>{if(u=se,ke){let{xFiltered:me,rawYFiltered:fe,smoothedYFiltered:Pe}=Q(V,u),j=Pe.map(oe=>oe!==null?oe*.9:null),H=Pe.map(oe=>oe!==null?oe*1.1:null);ke.setData([me,fe,Pe,j,H])}}}}function to(e){let n=new Date(e),t=n.getUTCDay(),s=n.getUTCDate()-t+(t===0?-6:1);return n.setUTCDate(s),n.setUTCHours(0,0,0,0),n}function Jo(e){let n={};return e.forEach(t=>{if(!t.stats.startTime||!t.stats.totalDist)return;let s=new Date(t.stats.startTime),o=to(s),a=o.toISOString().split("T")[0];n[a]||(n[a]={timestamp:o.getTime(),distance:0}),n[a].distance+=t.stats.totalDist}),Object.entries(n).map(([t,s])=>({week:t,timestamp:s.timestamp,distance:s.distance})).sort((t,s)=>t.timestamp-s.timestamp)}function Qo(e){let n={};return e.forEach(t=>{if(!t.stats.startTime||t.stats.elevGain===void 0)return;let s=new Date(t.stats.startTime),o=to(s),a=o.toISOString().split("T")[0];n[a]||(n[a]={timestamp:o.getTime(),elevation:0}),n[a].elevation+=t.stats.elevGain}),Object.entries(n).map(([t,s])=>({week:t,timestamp:s.timestamp,elevation:s.elevation})).sort((t,s)=>t.timestamp-s.timestamp)}function Ql(e,n,t,s,o,a){let p=t==="distance",c=p?Jo(n):Qo(n),d=jl(n,_=>p?_.stats.totalDist:_.stats.elevGain),x=p?We.distance.color:We.elevation.color,g=p?"km":"m",T=p?We.distance.icon:We.elevation.icon,$=document.createElement("div");$.className=`chart-row ${t}-progress-card`,$.id=`${t}-evolution-card`,$.innerHTML=` + `,z.style.display="block",z.style.left=`${At+V.left}px`,z.style.top=`${zt+V.top}px`,z.style.transform="translate(5px, -50%)"}else z.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(st,gt)=>gt.map(At=>{let zt=new Date(At*1e3);return`${zt.getUTCFullYear()}-${String(zt.getUTCMonth()+1).padStart(2,"0")}`})},{stroke:"#555564",grid:{stroke:"#2e2e34"},font:"10px system-ui, sans-serif",values:(st,gt)=>gt.map(At=>`${At} ${a}`),show:!0,space:15,size:50}]};U=new An(Lt,ut,ht),In.push(U),ht.addEventListener("mouseleave",()=>{U.redraw()})}else ht.innerHTML='
No data for the past year
'}})(),{updatePin:at=>{E=at,at!==null&&(u=at);let nt=document.getElementById(`${l}-timeline-label`);if(nt&&(nt.textContent=`Progress ${ze(u)} ${l==="power"?"Power":"HR"}${E!==null?" (Pinned)":""}`),U){let{xFiltered:$t,rawYFiltered:ht,smoothedYFiltered:z}=G(u,h),D=z.map(K=>K!==null?K*.9:null),it=z.map(K=>K!==null?K*1.1:null);U.setData([$t,ht,z,D,it])}$&&$.redraw()},updateRange:at=>{if(h=at,U){let{xFiltered:nt,rawYFiltered:$t,smoothedYFiltered:ht}=G(u,h),z=ht.map(it=>it!==null?it*.9:null),D=ht.map(it=>it!==null?it*1.1:null);U.setData([nt,$t,ht,z,D])}}}}function ul(t){let n=new Date(t),s=n.getUTCDay(),e=n.getUTCDate()-s+(s===0?-6:1);return n.setUTCDate(e),n.setUTCHours(0,0,0,0),n}function li(t){let n={};return t.forEach(s=>{if(!s.stats.startTime||!s.stats.totalDist)return;let e=new Date(s.stats.startTime),l=ul(e),i=l.toISOString().split("T")[0];n[i]||(n[i]={timestamp:l.getTime(),distance:0}),n[i].distance+=s.stats.totalDist}),Object.entries(n).map(([s,e])=>({week:s,timestamp:e.timestamp,distance:e.distance})).sort((s,e)=>s.timestamp-e.timestamp)}function ii(t){let n={};return t.forEach(s=>{if(!s.stats.startTime||s.stats.elevGain===void 0)return;let e=new Date(s.stats.startTime),l=ul(e),i=l.toISOString().split("T")[0];n[i]||(n[i]={timestamp:l.getTime(),elevation:0}),n[i].elevation+=s.stats.elevGain}),Object.entries(n).map(([s,e])=>({week:s,timestamp:e.timestamp,elevation:e.elevation})).sort((s,e)=>s.timestamp-e.timestamp)}function ai(t){let n={};return t.forEach(s=>{if(!s.stats.startTime||!s.stats.totalDist)return;let e=new Date(s.stats.startTime),l=new Date(Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),1)),i=l.toISOString().slice(0,7);n[i]||(n[i]={timestamp:l.getTime(),distance:0}),n[i].distance+=s.stats.totalDist}),Object.entries(n).map(([s,e])=>({week:s,timestamp:e.timestamp,distance:e.distance})).sort((s,e)=>s.timestamp-e.timestamp)}function ri(t){let n={};return t.forEach(s=>{if(!s.stats.startTime||s.stats.elevGain===void 0)return;let e=new Date(s.stats.startTime),l=new Date(Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),1)),i=l.toISOString().slice(0,7);n[i]||(n[i]={timestamp:l.getTime(),elevation:0}),n[i].elevation+=s.stats.elevGain}),Object.entries(n).map(([s,e])=>({week:s,timestamp:e.timestamp,elevation:e.elevation})).sort((s,e)=>s.timestamp-e.timestamp)}function rl(t,n,s,e,l,i){let a=s==="distance",c=Ks,d=Gt.get().progress||"all",w=a?li(n):ii(n),g=a?ai(n):ri(n),f=c==="month"?g:w,A=gn(n,rt=>a?rt.stats.totalDist:rt.stats.elevGain),C=a?Nt.distance.color:Nt.elevation.color,$=a?"km":"m",M=a?Nt.distance.icon:Nt.elevation.icon,m=document.createElement("div");m.className=`chart-row ${s}-progress-card`,m.id=`${s}-evolution-card`,m.innerHTML=`
- ${T} - ${p?"Distance Progress":"Elevation Progress"} + ${M} + ${a?"Distance Progress":"Elevation Progress"}
-
+
-
+
- ${Zl(d,p,g)} + ${sl(A,a,$)}
- `,e.appendChild($);let M=$.querySelector(`#${t}-weekly-chart`),C=$.querySelector(`#${t}-y-axis-chart`);if(!M||!C)return;M.style.position="relative";let k=document.createElement("div");k.className="cur-y-val",k.style.cssText=`color:${x};display:none`,M.appendChild(k);let f=c.map(_=>_.timestamp/1e3),F=p?c.map(_=>_.distance/1e3):c.map(_=>_.elevation);if(f.length===0)return;let v=En(F,2),u=Math.max(0,(a||570)-20-320-20),w=Math.max(u,f.length*40),E=Math.max(...F)*1.1,N={width:w,height:150,padding:[10,10,0,10],tzDate:_=>An.tzDate(new Date(_*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,E]}},series:[{},{label:p?"Distance":"Elevation",stroke:x,fill:tt(x,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:x,width:2,dash:[5,5],points:{show:!1}}],cursor:{sync:s?{key:s.key}:void 0,drag:{x:!1,y:!1},points:{show:!1},x:!1,y:!1},hooks:{init:[_=>{_.over.addEventListener("click",()=>{let W=_.cursor.idx;if(W!=null){let z=c[W];if(z){let de=new Date(z.timestamp),y=new Date(z.timestamp+7*24*60*60*1e3),m=de.toISOString().split("T")[0],r=y.toISOString().split("T")[0];o?.(m,r)}}})}],setCursor:[_=>{if(!_._ready)return;let W=_.cursor.idx,z=_.cursor.left,de=_.cursor.top;if(W!=null&&z!=null&&de!=null&&z>=0&&de>=0){let y=_.data[1][W],m=y!=null?p?`${y.toFixed(1)} km`:`${y.toFixed(0)} m`:"\u2014";k.innerHTML=m,k.style.display="block",k.style.left=`${_.valToPos(_.data[0][W],"x",!1)}px`,k.style.top=`${_.valToPos(_.data[1][W],"y",!1)}px`,k.style.transform="translate(6px, -50%)"}else k.style.display="none";_.redraw(!1)}],draw:[_=>{let W=_.cursor.idx;if(W!=null&&_.data[0][W]!=null){let z=_.valToPos(_.data[0][W],"x",!0),de=_.valToPos(_.data[1][W],"y",!0),y=window.devicePixelRatio||1,m=_.ctx,r=_.bbox;m.save(),m.beginPath(),m.setLineDash([2*y,2*y]),m.strokeStyle=tt(x,.4),m.lineWidth=1*y,m.moveTo(z,r.top),m.lineTo(z,r.top+r.height),m.moveTo(r.left,de),m.lineTo(r.left+r.width,de),m.stroke(),m.restore(),m.save(),m.beginPath(),m.setLineDash([]),m.arc(z,de,12*y,0,2*Math.PI),m.fillStyle=tt(x,.2),m.fill(),m.restore(),m.save(),m.beginPath(),m.arc(z,de,6*y,0,2*Math.PI),m.fillStyle=x,m.fill(),m.strokeStyle="#fff",m.lineWidth=2*y,m.stroke(),m.restore(),m.save(),m.setLineDash([]);let J=new Date(_.data[0][W]*1e3),V=`${J.getUTCFullYear()}-${String(J.getUTCMonth()+1).padStart(2,"0")}-${String(J.getUTCDate()).padStart(2,"0")}`;m.font=`bold ${10*y}px system-ui, sans-serif`;let U=m.measureText(V).width+10*y,Q=16*y,ke=z-U/2,re=Math.max(r.left,Math.min(r.left+r.width-U,ke)),Fe=r.top+r.height+2*y;m.fillStyle="rgba(14, 14, 16, 0.92)",m.beginPath(),m.roundRect?m.roundRect(re,Fe,U,Q,3*y):m.rect(re,Fe,U,Q),m.fill(),m.strokeStyle=tt(x,.27),m.lineWidth=1*y,m.stroke(),m.fillStyle=x,m.textAlign="center",m.textBaseline="middle",m.fillText(V,re+U/2,Fe+Q/2),m.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(_,W)=>W.map(z=>{let de=new Date(z*1e3);return`${de.getUTCMonth()+1}/${de.getUTCDate()}`}),font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:(_,W)=>W.map(z=>`${z.toFixed(0)} ${g}`),font:"10px system-ui, sans-serif",size:40}]},G=new An(N,[f,F,v],M);In.push(G);let q=$.querySelector(".chart-scroll-container");return q&&f.length*40>w&&(q.scrollLeft=q.scrollWidth-q.clientWidth),{updateRange:_=>{let W=c[c.length-1]?.timestamp||17855424e5,z=0;_==="1m"?z=W-30*24*3600*1e3:_==="2m"?z=W-60*24*3600*1e3:_==="6m"?z=W-180*24*3600*1e3:_==="1y"?z=W-365*24*3600*1e3:_==="2y"&&(z=W-2*365*24*3600*1e3);let de=c.filter(ee=>ee.timestamp>=z),y=de.map(ee=>ee.timestamp/1e3),m=p?de.map(ee=>ee.distance/1e3):de.map(ee=>ee.elevation),r=En(m,2),J=Math.max(M.clientWidth,y.length*40),V=Math.max(...m)*1.1;G.setSize({width:J,height:150}),G.setScale("y",{min:0,max:V}),G.setData([y,m,r]),q&&(q.scrollLeft=q.scrollWidth-q.clientWidth)}}}var Qn=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],Ko=16,ze={},Tt=[];function ei(e,n){let t=new Date(e),s=new Date(n);return t.getUTCFullYear()===s.getUTCFullYear()&&t.getUTCMonth()===s.getUTCMonth()&&t.getUTCDate()===s.getUTCDate()}var Bn=!1,Oe=null,Kn=0,Xn=!1,_n=null,mn="",un=!1,vn="date-desc",Le={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};function bn(e=!1){Ye.patch({f_date:Le.date.every(n=>n===null)?null:Le.date,f_dist:Le.dist.every(n=>n===null)?null:Le.dist,f_dur:Le.dur.every(n=>n===null)?null:Le.dur,f_mets:Le.metrics.size===0?null:Array.from(Le.metrics),f_tags:Le.tags.length===0?null:Le.tags},e)}function Zs(){let e=Se.getActiveMetrics(),n=Se.METRICS,t=Array.from(e).map(s=>n[s].abbr);Ye.patch({metrics:t.length?t:null})}var lo=[{label:"Newest first",val:"date-desc",icon:"calendar_today"},{label:"Oldest first",val:"date-asc",icon:"history"},{label:"Longest distance",val:"dist-desc",icon:"straighten"},{label:"Shortest distance",val:"dist-asc",icon:"horizontal_rule"},{label:"Longest duration",val:"dur-desc",icon:"timer"},{label:"Shortest duration",val:"dur-asc",icon:"timer_off"}];function ti(e){document.querySelectorAll(".sort-menu-popup").forEach(o=>o.remove());let n=document.createElement("div");n.className="sort-menu-popup",lo.forEach(o=>{let a=document.createElement("div");a.className=`menu-item ${vn===o.val?"active":""}`,a.innerHTML=` - ${o.icon} - ${o.label} - ${vn===o.val?"check":""} - `,a.addEventListener("click",()=>{vn=o.val,Ye.patch({sort:o.val}),io(),xn(),n.remove()}),n.appendChild(a)});let t=e.getBoundingClientRect();n.style.top=`${t.bottom+5}px`,n.style.left=`${t.left}px`,document.body.appendChild(n);let s=o=>{!n.contains(o.target)&&!e.contains(o.target)&&(n.remove(),document.removeEventListener("click",s))};setTimeout(()=>document.addEventListener("click",s),0)}function ni(e){document.querySelectorAll(".metric-menu-popup").forEach(c=>c.remove());let n=document.createElement("div");n.className="metric-menu-popup";let t=Se.METRICS,s=Se.getAvailableMetrics(),o=Se.getActiveMetrics();Object.entries(t).forEach(([c,d])=>{if(!s.has(c))return;let x=document.createElement("div");x.className=`menu-item ${o.has(c)?"active":""}`,x.innerHTML=` + `,t.appendChild(m);let k=m.querySelector(`#${s}-weekly-chart`),P=m.querySelector(`#${s}-y-axis-chart`);if(!k||!P)return;k.style.position="relative";let h=document.createElement("div");h.className="cur-y-val",h.style.cssText=`color:${C};display:none`,k.appendChild(h);let b=f.map(rt=>rt.timestamp/1e3),p=a?f.map(rt=>rt.distance/1e3):f.map(rt=>rt.elevation);if(b.length===0)return;let S=Cn(p,2),_=Math.max(0,(i||570)-20-320-20),W=Math.max(_,b.length*40),O=Math.max(...p)*1.1,Y={width:W,height:150,padding:[10,10,0,10],tzDate:rt=>An.tzDate(new Date(rt*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,O]}},series:[{},{label:a?"Distance":"Elevation",stroke:C,fill:le(C,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:C,width:2,dash:[5,5],points:{show:!1}}],cursor:{sync:e?{key:e.key}:void 0,drag:{x:!1,y:!1},points:{show:!1},x:!1,y:!1},hooks:{init:[rt=>{rt.over.addEventListener("click",()=>{let x=rt.cursor.idx;if(x!=null){let v=f[x];if(v){let u=new Date(v.timestamp),N=new Date(v.timestamp+7*24*60*60*1e3),E=u.toISOString().split("T")[0],G=N.toISOString().split("T")[0];l?.(E,G)}}})}],setCursor:[rt=>{if(!rt._ready)return;let x=rt.cursor.idx,v=rt.cursor.left,u=rt.cursor.top;if(x!=null&&v!=null&&u!=null&&v>=0&&u>=0){let N=rt.data[1][x],E=N!=null?a?`${N.toFixed(1)} km`:`${N.toFixed(0)} m`:"\u2014";h.innerHTML=E,h.style.display="block",h.style.left=`${rt.valToPos(rt.data[0][x],"x",!1)}px`,h.style.top=`${rt.valToPos(rt.data[1][x],"y",!1)}px`,h.style.transform="translate(6px, -50%)"}else h.style.display="none";rt.redraw(!1)}],draw:[rt=>{let x=rt.cursor.idx;if(x!=null&&rt.data[0][x]!=null){let v=rt.valToPos(rt.data[0][x],"x",!0),u=rt.valToPos(rt.data[1][x],"y",!0),N=window.devicePixelRatio||1,E=rt.ctx,G=rt.bbox;E.save(),E.beginPath(),E.setLineDash([2*N,2*N]),E.strokeStyle=le(C,.4),E.lineWidth=1*N,E.moveTo(v,G.top),E.lineTo(v,G.top+G.height),E.moveTo(G.left,u),E.lineTo(G.left+G.width,u),E.stroke(),E.restore(),E.save(),E.beginPath(),E.setLineDash([]),E.arc(v,u,12*N,0,2*Math.PI),E.fillStyle=le(C,.2),E.fill(),E.restore(),E.save(),E.beginPath(),E.arc(v,u,6*N,0,2*Math.PI),E.fillStyle=C,E.fill(),E.strokeStyle="#fff",E.lineWidth=2*N,E.stroke(),E.restore(),E.save(),E.setLineDash([]);let U=new Date(rt.data[0][x]*1e3),j=`${U.getUTCFullYear()}-${String(U.getUTCMonth()+1).padStart(2,"0")}-${String(U.getUTCDate()).padStart(2,"0")}`;E.font=`bold ${10*N}px system-ui, sans-serif`;let at=E.measureText(j).width+10*N,nt=16*N,$t=v-at/2,ht=Math.max(G.left,Math.min(G.left+G.width-at,$t)),z=G.top+G.height+2*N;E.fillStyle="rgba(14, 14, 16, 0.92)",E.beginPath(),E.roundRect?E.roundRect(ht,z,at,nt,3*N):E.rect(ht,z,at,nt),E.fill(),E.strokeStyle=le(C,.27),E.lineWidth=1*N,E.stroke(),E.fillStyle=C,E.textAlign="center",E.textBaseline="middle",E.fillText(j,ht+at/2,z+nt/2),E.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(rt,x)=>x.map(v=>{let u=new Date(v*1e3);return`${u.getUTCMonth()+1}/${u.getUTCDate()}`}),font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:(rt,x)=>x.map(v=>`${v.toFixed(0)} ${$}`),font:"10px system-ui, sans-serif",size:40}]},Z=new An(Y,[b,p,S],k);In.push(Z);let lt=m.querySelector(".chart-scroll-container");lt&&b.length*40>W&&(lt.scrollLeft=lt.scrollWidth-lt.clientWidth);function Ft(){f=c==="month"?g:w;let rt=f[f.length-1]?.timestamp||17855424e5,x=0;d==="1m"?x=rt-30*24*3600*1e3:d==="2m"?x=rt-60*24*3600*1e3:d==="6m"?x=rt-180*24*3600*1e3:d==="1y"?x=rt-365*24*3600*1e3:d==="2y"&&(x=rt-2*365*24*3600*1e3);let v=f.filter(j=>j.timestamp>=x),u=v.map(j=>j.timestamp/1e3),N=a?v.map(j=>j.distance/1e3):v.map(j=>j.elevation),E=Cn(N,2),G=Math.max(k.clientWidth,u.length*40),U=Math.max(1,...N)*1.1;Z.setSize({width:G,height:150}),Z.setScale("y",{min:0,max:U}),Z.setData([u,N,E]),lt&&(lt.scrollLeft=lt.scrollWidth-lt.clientWidth)}return{updateRange:rt=>{d=rt,Ft()},updateGrouping:rt=>{c=rt,Ft()}}}var ss=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],ci=16,Ut={},Pe=[];function di(t,n){let s=new Date(t),e=new Date(n);return s.getUTCFullYear()===e.getUTCFullYear()&&s.getUTCMonth()===e.getUTCMonth()&&s.getUTCDate()===e.getUTCDate()}var Dn=!1,Zt=null,os=0,es=!1,Bn=null,Ke="",hn=!1,bn="date-desc",Tt={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};function Mn(t=!1){Gt.patch({f_date:Tt.date.every(n=>n===null)?null:Tt.date,f_dist:Tt.dist.every(n=>n===null)?null:Tt.dist,f_dur:Tt.dur.every(n=>n===null)?null:Tt.dur,f_mets:Tt.metrics.size===0?null:Array.from(Tt.metrics),f_tags:Tt.tags.length===0?null:Tt.tags},t)}function Js(){let t=ft.getActiveMetrics(),n=ft.METRICS,s=Array.from(t).map(e=>n[e].abbr);Gt.patch({metrics:s.length?s:null})}var fl=[{label:"Newest first",val:"date-desc",icon:"calendar_today"},{label:"Oldest first",val:"date-asc",icon:"history"},{label:"Longest distance",val:"dist-desc",icon:"straighten"},{label:"Shortest distance",val:"dist-asc",icon:"horizontal_rule"},{label:"Longest duration",val:"dur-desc",icon:"timer"},{label:"Shortest duration",val:"dur-asc",icon:"timer_off"}];function ui(t){document.querySelectorAll(".sort-menu-popup").forEach(l=>l.remove());let n=document.createElement("div");n.className="sort-menu-popup",fl.forEach(l=>{let i=document.createElement("div");i.className=`menu-item ${bn===l.val?"active":""}`,i.innerHTML=` + ${l.icon} + ${l.label} + ${bn===l.val?"check":""} + `,i.addEventListener("click",()=>{bn=l.val,Gt.patch({sort:l.val}),hl(),vn(),n.remove()}),n.appendChild(i)});let s=t.getBoundingClientRect();n.style.top=`${s.bottom+5}px`,n.style.left=`${s.left}px`,document.body.appendChild(n);let e=l=>{!n.contains(l.target)&&!t.contains(l.target)&&(n.remove(),document.removeEventListener("click",e))};setTimeout(()=>document.addEventListener("click",e),0)}function mi(t){document.querySelectorAll(".metric-menu-popup").forEach(c=>c.remove());let n=document.createElement("div");n.className="metric-menu-popup";let s=ft.METRICS,e=ft.getAvailableMetrics(),l=ft.getActiveMetrics();Object.entries(s).forEach(([c,d])=>{if(!e.has(c))return;let w=document.createElement("div");w.className=`menu-item ${l.has(c)?"active":""}`,w.innerHTML=` ${d.icon} ${d.label} - ${o.has(c)?"check":""} - `,x.addEventListener("click",()=>{Se.toggleMetric(c);let g=Se.getActiveMetrics().has(c);x.classList.toggle("active",g),x.querySelector(".check").textContent=g?"check":"";let T=document.querySelector(`#metric-pills .metric-pill[data-metric="${c}"]`);T&&T.classList.toggle("active",g),Dn(),Zs()}),n.appendChild(x)});let a=e.getBoundingClientRect();n.style.top=`${a.bottom+5}px`,n.style.right=`${window.innerWidth-a.right}px`,document.body.appendChild(n);let p=c=>{!n.contains(c.target)&&!e.contains(c.target)&&(n.remove(),document.removeEventListener("click",p))};setTimeout(()=>document.addEventListener("click",p),0)}document.addEventListener("select-track",e=>{let n=e.detail.id,t=e.detail.idx,s=e.detail.dur;if(n&&ze[n]&&(Mt(n),t!=null&&s!=null)){let o=ze[n],a=o.points;if(t>=0&&tM.time!=null)?.time||0,d=(p.time-c)/1e3,x=d+s;Se.restoreSelection(d,x);let g=a.findIndex(M=>(M.time||0)>=p.time+s*1e3);g===-1&&(g=a.length-1);let T=a.slice(t,g+1),$=ot.computeStats(T);Se.setSelectionStats($),Bt(o),De.highlightSegment(n,a,t,g,!1,_n),De.ensureVisible(T.map(M=>[M.lat,M.lon])),Ye.patch({sel:[d,x]})}}}});document.addEventListener("click",e=>{let n=e.target.closest(".tab-btn");if(!n)return;let t=n.closest("#tab-nav");if(!t)return;t.querySelectorAll(".tab-btn").forEach(a=>a.classList.toggle("active",a===n));let s=n.dataset.tab;Ye.patch({tab:s},!0);let o=t.closest("#chart-panel");if(o&&o.querySelectorAll(".tab-content").forEach(a=>{a.classList.toggle("active",a.id===`tab-${n.dataset.tab}`)}),n.dataset.tab==="details"&&Oe&&ze[Oe]&&an(ze[Oe],Xs()),n.dataset.tab==="insights"&&Oe&&ze[Oe]&&Bt(ze[Oe]),n.dataset.tab==="evolution"&&Hn(Oe?ze[Oe]:null,Object.values(ze),(a,p)=>{Mt(a,!0),p&&(Se.restoreSelection(p[0],p[1]),yn(p[0],p[1],"time",!0))},(a,p)=>{Le.date=[a,p],kt(),bn(!0),Jn()}),n.dataset.tab==="combined"&&Oe&&ze[Oe]&&dn(ze[Oe]),n.dataset.tab==="courses"&&Wt(),n.dataset.tab==="graphs"){Se.resize(),Dn();let a=Ye.get().sel;a&&Se.restoreSelection(a[0],a[1])}});async function Gs(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await at.clear(),ze={},Tt=[],Oe=null,Kn=0,_n=null,Bn=!1,Xn=!1,mn="",un=!1,vn="date-desc",Le.date=[null,null],Le.dist=[null,null],Le.dur=[null,null],Le.metrics.clear(),Le.tags=[],ot.setHRZones([120,140,160,180]),ot.setFTP(200),Hl(),Ul(),wl(),Yl(),eo(),De.removeAllTracks&&De.removeAllTracks(),De.clearTracks&&De.clearTracks(),De.clearHighlight(),Se.resetState?Se.resetState():Se.clear&&Se.clear(),document.querySelectorAll(".tab-btn").forEach(n=>{n.classList.toggle("active",n.dataset.tab==="graphs")}),document.querySelectorAll(".tab-content").forEach(n=>{n.classList.toggle("active",n.id==="tab-graphs")}),Ye.reset();let e=document.getElementById("toast-container");e&&(e.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(n=>n.remove()),typeof xn=="function"&&xn()}async function si(){let e=null,n=new Promise(f=>{e=window.setTimeout(f,1e3)});try{let f=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([f,n])}finally{e!==null&&window.clearTimeout(e)}document.body.classList.remove("loading-fonts");let t=document.getElementById("storage-backend-select");t&&(t.value=Ye.get().storage||"memory",t.addEventListener("change",f=>{let F=f.target.value,v=new URLSearchParams(window.location.search);F==="memory"?v.delete("storage"):v.set("storage",F),window.location.search=v.toString()}));let s=document.getElementById("global-loader"),o=document.getElementById("loader-text"),a=document.getElementById("loader-subtext"),p=document.getElementById("loader-progress-bar"),c=document.getElementById("map-loader"),d=c?.querySelector("span");c&&(d&&(d.textContent="Loading database..."),c.classList.remove("hidden"));let x=Ye.get();ql((f,F)=>ks(f,F==="error"?"error":"info")),xl(()=>{kt(),bn()},f=>{mi(f)}),Il((f,F)=>ks(f,F==="error"?"error":"info")),De.init(f=>Mt(f),ai,ri,(f,F)=>{f===Oe?Se.setHoverAt(F):Se.setHoverAt(null)},ci),Se.init(di,yn,ui,f=>{Ye.patch({sel_point:f})}),Se.setMapColorChangeCb(f=>{f?(_n=f.colors,Oe&&De.colorTrackByMetric(Oe,f.pts,f.colors)):(_n=null,Oe&&De.clearMetricColor(Oe));let F=Ye.get();F.sel&&yn(F.sel[0],F.sel[1],Se.getXAxis())}),so(x),await at.openDB(),await Gs();try{let f=await at.get("hr_zones");f&&ot.setHRZones(f);let F=await at.get("ftp");F&&ot.setFTP(F);let v=await at.getAll();v.sort((G,q)=>G.addedAt-q.addedAt),d&&(d.textContent=`Preparing ${v.length} tracks...`);let u=[];for(let G of v){let q=!1;if(!G.bounds&&G.points.length>0){let _=bs(G.points);_&&(G.bounds=_,q=!0)}!G.simplifiedPoints&&G.points.length>0&&(G.simplifiedPoints=vs(G.points,50),q=!0),q&&await at.save(G),ze[G.id]=G,u.push(G)}De.addTracks(u),kt();let w=x.track&&v.find(G=>G.id===x.track)?x.track:v.length>0?v[0].id:null,E=document.getElementById("map-loader"),N=v.find(G=>G.id===w);if(N&&(await no(N),Mt(N.id,!x.map_pos),x.sel&&Array.isArray(x.sel)&&x.sel.length===2&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Se.restoreSelection(x.sel[0],x.sel[1])})}),x.sel_point!==void 0&&x.sel_point!==null&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{Se.setCursorAt(x.sel_point)})})),E&&E.classList.add("hidden"),v.length>(N?1:0)){E&&(d&&(d.textContent="Loading tracks..."),E.classList.remove("hidden"));let G=v.filter(W=>W.id!==w),q=0,_=async()=>{let z=Math.min(q+2,G.length);for(;q{Mt(de,!0),y&&(Se.restoreSelection(y[0],y[1]),yn(y[0],y[1],"time",!0))}),v.length&&!x.map_pos&&De.fitAll())};requestAnimationFrame(_)}else kt(),v.length&&!x.map_pos&&De.fitAll()}catch(f){console.warn("Could not load saved tracks:",f)}oi(),ii(),vi(),Dn(),document.getElementById("basemap-switcher")?.addEventListener("click",f=>{let F=f.target.closest(".bm-btn");F&&(document.querySelectorAll(".bm-btn").forEach(v=>v.classList.remove("active")),F.classList.add("active"),F.dataset.layer&&(De.switchBasemap(F.dataset.layer),Ye.patch({map:F.dataset.layer})))}),document.getElementById("btn-fit-all")?.addEventListener("click",()=>De.fitAll()),document.getElementById("btn-clear-all")?.addEventListener("click",pi),document.getElementById("track-search")?.addEventListener("input",f=>{mn=f.target.value,kt(),Ye.patch({q:mn||null})}),document.getElementById("btn-regex-toggle")?.addEventListener("click",f=>{un=!un,f.target.classList.toggle("active",un),kt(),Ye.patch({re:un?1:null})}),document.getElementById("btn-sort-menu")?.addEventListener("click",f=>{f.stopPropagation(),ti(f.currentTarget)}),document.getElementById("btn-metric-menu")?.addEventListener("click",f=>{f.stopPropagation(),ni(f.currentTarget)});let g=(f,F)=>{F&&F.classList.toggle("active"),Se.toggleMetric(f),Zs()};document.getElementById("metric-pills")?.addEventListener("click",f=>{let F=f.target.closest(".metric-pill");if(F){let v=F.dataset.metric;v&&(g(v,F),Se.getActiveMetrics().has(v)&&document.querySelector(`.chart-row[data-metric="${v}"]`)?.scrollIntoView({behavior:"smooth"}))}}),document.getElementById("x-axis-ctrl")?.addEventListener("click",f=>{let F=f.target.closest(".seg-btn");if(!F)return;let v=F.dataset.axis;Se.setXAxis(v),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(u=>u.classList.toggle("active",u===F)),Ye.patch({xaxis:v})}),document.getElementById("btn-follow-dot")?.addEventListener("click",f=>{Xn=!Xn,f.currentTarget.classList.toggle("active",Xn)}),document.getElementById("btn-reset-zoom")?.addEventListener("click",()=>{Se.resetZoom(),De.clearHighlight()}),bi(),document.getElementById("file-input")?.addEventListener("change",f=>{Cs(Array.from(f.target.files||[])),f.target.value=""}),document.getElementById("folder-input")?.addEventListener("change",f=>{Cs(Array.from(f.target.files||[])),f.target.value=""}),document.getElementById("btn-toggle-filters")?.addEventListener("click",()=>{let f=document.getElementById("filter-panel");f&&(f.classList.toggle("hidden"),document.getElementById("btn-toggle-filters")?.classList.toggle("active",!f.classList.contains("hidden")))});let T=(f,F,v)=>{let u=v.target.value;Le[f][F]=u===""?null:u,kt(),bn()};document.getElementById("filter-date-start")?.addEventListener("change",f=>T("date",0,f)),document.getElementById("filter-date-end")?.addEventListener("change",f=>T("date",1,f)),document.getElementById("filter-dist-min")?.addEventListener("input",f=>T("dist",0,f)),document.getElementById("filter-dist-max")?.addEventListener("input",f=>T("dist",1,f)),document.getElementById("filter-dur-min")?.addEventListener("input",f=>T("dur",0,f)),document.getElementById("filter-dur-max")?.addEventListener("input",f=>T("dur",1,f));let $=document.getElementById("sport-burger-btn"),M=document.getElementById("sport-dropdown-content");$?.addEventListener("click",f=>{if(f.stopPropagation(),M){let F=M.style.display==="block";M.style.display=F?"none":"block"}}),document.addEventListener("click",f=>{M&&M.style.display==="block"&&!M.contains(f.target)&&f.target!==$&&(M.style.display="none")}),document.getElementById("sport-filter-container")?.addEventListener("click",f=>{let F=f.target,v=F.closest("[data-sport]");if(v){let u=v.dataset.sport||null;Le.sport=Le.sport===u?null:u,kt(),bn(),Jn(),F.closest(".dropdown-item")&&M&&(M.style.display="none")}}),document.getElementById("filter-metrics")?.addEventListener("click",f=>{let F=f.target.closest(".mini-pill");if(!F)return;let v=F.dataset.metric;Le.metrics.has(v)?Le.metrics.delete(v):Le.metrics.add(v),Jn(),kt(),bn()}),document.getElementById("btn-reset-filters")?.addEventListener("click",()=>{Le={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},Jn(),kt(),bn()}),document.getElementById("filter-tags")?.addEventListener("input",f=>{let F=f.target.value;Le.tags=F.split(",").map(v=>v.trim().toLowerCase()).filter(v=>!!v),kt(),bn()}),document.addEventListener("keydown",f=>{f.key==="Escape"&&(De.hideCursor(),De.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(F=>F.remove()))}),window.addEventListener("resize",()=>{Se.resize(),Zn(),De.invalidateSize?.(),Dn()}),window.addEventListener("popstate",()=>{Ye.refresh(),so(Ye.get())}),li(),await oo();let C=document.createElement("div");C.id="app-is-ready",C.setAttribute("data-ready","true"),C.style.display="none",document.body.appendChild(C);let k=document.createElement("div");k.id="appIsReady",k.setAttribute("data-ready","true"),k.style.display="none",document.body.appendChild(k)}var Fn=null;async function oo(){if(Fn)return Fn;try{let n=await(await fetch("./test-data/manifest.json")).json(),t=new TextDecoder;Fn=await Promise.all(n.map(async o=>{let p=await(await fetch(`./test-data/${o}`)).arrayBuffer(),c=o;if(o.toLowerCase().endsWith(".gz")){c=o.slice(0,-3);let g=new Uint8Array(p);if(g.length>=2&&g[0]===31&&g[1]===139){let T=new DecompressionStream("gzip"),$=new Blob([p]).stream().pipeThrough(T);p=await new Response($).arrayBuffer()}}let d=c.toLowerCase().endsWith(".fit")?void 0:t.decode(p),x=new File([p],c,{type:"application/octet-stream"});return x._buf=p,d!==void 0&&(x._text=d),{cleanName:c,buf:p,text:d,file:x}}));let s=null;for(let o of[0,2,4])if(Fn[o]){let a=await ot.parseFile(Fn[o].file);o===0&&(s=a)}if(s){let o=s.points.slice(0,1250),a={...s,id:"warmup",fileName:"warmup.gpx",fileSize:1024,points:o,bounds:bs(o)||void 0,simplifiedPoints:vs(o,50),stats:ot.computeStats(o),addedAt:17855424e5,visible:!0,color:Qn[0]},p={...a,id:"warmup-2",fileName:"warmup2.gpx",addedAt:17856288e5,color:Qn[1]},c=[a,p];ot.ensureCurvesAndZones(a),ot.ensureCurvesAndZones(p),De.addTracks(c),Se.loadTrack(a,c,!1),Se.restoreSelection(10,50,!0),Se.setCursorAt(25,!0),Se.setActiveMetrics(["elevation","speed","power"]),Se.analyzeTelemetryIntervals(c,10,50),Bt(a,c),an(a,[],c),dn(c,c),Hn(a,c),Bs(c),Ln("course-1",!0),await Gs(),document.body.offsetHeight,await new Promise(d=>window.setTimeout(d,0))}else typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();return Fn}catch{return[]}}function li(){let e=document.getElementById("btn-step-load"),n=document.getElementById("btn-step-analysis"),t=document.getElementById("btn-step-insights"),s=document.getElementById("btn-step-details"),o=document.getElementById("btn-step-aggregate"),a=document.getElementById("btn-step-evolution"),p=document.getElementById("btn-step-courses");function c(d){document.querySelectorAll(".tab-btn").forEach(x=>{x.classList.toggle("active",x.dataset.tab===d)}),document.querySelectorAll(".tab-content").forEach(x=>{x.classList.toggle("active",x.id===`tab-${d}`)}),Ye.patch({tab:d},!1)}e?.addEventListener("click",async()=>{try{Object.keys(ze).length>0||Tt.length>0||Oe!==null?(await at.openDB(),await Gs()):typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();let x=(await oo()).map(T=>T.file);await Cs(x);let g=Object.values(ze);!Oe&&g.length>0&&Mt(g[0].id)}finally{window.dispatchEvent(new CustomEvent("load-and-parse-complete"))}}),n?.addEventListener("click",()=>{try{let d=Object.values(ze);c("graphs"),!Oe&&d.length>0&&Mt(d[0].id),Se.restoreSelection(120,900,!0),Se.setCursorAt(300,!0);let x=Se.getAvailableMetrics(),g=["elevation","speed","power"].filter(T=>x.has(T));g.length>0?(document.querySelectorAll("#metric-pills .metric-pill").forEach(T=>{let $=T.dataset.metric;$&&T.classList.toggle("active",g.includes($))}),Dn(),Se.setActiveMetrics(g)):Dn(),Se.analyzeTelemetryIntervals(d,120,900),yn(120,900,Se.getXAxis(),!1)}finally{window.dispatchEvent(new CustomEvent("analysis-complete"))}}),t?.addEventListener("click",()=>{try{let d=Object.values(ze);d.forEach(g=>ot.ensureCurvesAndZones(g)),c("insights");let x=Oe&&ze[Oe]||d[0]||null;Bt(x,d)}finally{window.dispatchEvent(new CustomEvent("insights-complete"))}}),s?.addEventListener("click",()=>{try{let d=Object.values(ze);c("details");let x=Oe&&ze[Oe]||d[0]||null;an(x,Xs(),d)}finally{window.dispatchEvent(new CustomEvent("details-complete"))}}),o?.addEventListener("click",()=>{try{let d=Object.values(ze);if(d.length>=2){let x=[d[0],d[1]];c("combined"),dn(x,d)}}finally{window.dispatchEvent(new CustomEvent("aggregate-complete"))}}),a?.addEventListener("click",()=>{try{let d=Object.values(ze);c("evolution");let x=Oe&&ze[Oe]||d[0]||null;Hn(x,d,(g,T)=>{Mt(g,!0),T&&(Se.restoreSelection(T[0],T[1]),yn(T[0],T[1],"time",!0))})}finally{window.dispatchEvent(new CustomEvent("evolution-complete"))}}),p?.addEventListener("click",()=>{try{let d=Object.values(ze);c("courses"),Bs(d),Ln("course-1",!0)}finally{window.dispatchEvent(new CustomEvent("courses-complete"))}}),window.benchmarkSteps={loadAndParseFiles:()=>document.getElementById("btn-step-load")?.click(),displayAnalysisMetrics:()=>document.getElementById("btn-step-analysis")?.click(),displayInsights:()=>document.getElementById("btn-step-insights")?.click(),displayDetails:()=>document.getElementById("btn-step-details")?.click(),displayAggregateMetrics:()=>document.getElementById("btn-step-aggregate")?.click(),displayEvolutionMetrics:()=>document.getElementById("btn-step-evolution")?.click(),displayCourses:()=>document.getElementById("btn-step-courses")?.click()}}async function no(e){let n=e.stats.powerCurve?Object.values(e.stats.powerCurve):[],t=e.points.length>1&&(e.points[1].speed===void 0||e.points[1].gradient===void 0);(t||!e.stats.powerCurve||!e.stats.hrZones||!e.stats.hrCurve||e.stats.shifts===void 0||e.stats.avgBattery===void 0||e.stats.avgTemp===void 0||n.length>0&&typeof n[0]=="number"||(e.stats.duration||0)>10800*1e3&&e.stats.powerCurve&&!e.stats.powerCurve[14400])&&(t&&(e.points=ot.enrichPoints(e.points)),e.stats=ot.computeStats(e.points),await at.save(e)),ze[e.id]=e,Kn=Math.max(Kn,Qn.indexOf(e.color)+1),De.addTrack(e),De.setTrackVisible(e.id,e.visible&&!e._filtered),xn()}function oi(){let e=document.getElementById("resize-handle"),n=document.getElementById("chart-panel");if(!e||!n)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,document.body.style.cursor="ns-resize"}),document.addEventListener("mousemove",s=>{if(!t)return;let o=window.innerHeight-s.clientY,a=Math.max(100,Math.min(window.innerHeight-100,o));n.style.height=`${a}px`,Se.resize(),Zn(),De.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,document.body.style.cursor="")})}function ii(){let e=document.getElementById("sidebar-resizer"),n=document.getElementById("sidebar");if(!e||!n)return;let t=!1;e.addEventListener("mousedown",()=>{t=!0,e.classList.add("dragging"),document.body.classList.add("dragging-sidebar")}),document.addEventListener("mousemove",s=>{if(!t)return;let o=s.clientX,a=Math.max(200,Math.min(600,o));n.style.width=`${a}px`,n.style.setProperty("--sidebar-w",`${a}px`),Se.resize(),De.invalidateSize?.()}),document.addEventListener("mouseup",()=>{t&&(t=!1,e.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}function ai(e,n,t){Ye.patch({map_pos:[e,n,t]})}function ri(e,n){Mt(e,!1),Se.setCursorAt(n)}function ci(){}function di(e){e&&e.lat!=null&&e.lon!=null?(De.showCursorAt(e.lat,e.lon),Xn&&De.centerOn(e.lat,e.lon,null,!0)):De.hideCursor()}function yn(e,n,t,s=!1){if(!Oe||!ze[Oe])return;let o=ze[Oe];if(e===null||n===null){De.clearHighlight(),o&&(Ye.get().tab||"graphs")==="insights"&&Bt(o),Ye.patch({sel:null});return}let a=o.points,p=0,c=a.length-1;if(t==="distance"){let g=e*1e3,T=n*1e3;p=a.findIndex($=>($.dist||0)>=g),c=a.findIndex($=>($.dist||0)>=T)}else{let g=a.find(M=>M.time!=null)?.time||0,T=g+e*1e3,$=g+n*1e3;p=a.findIndex(M=>(M.time||0)>=T),c=a.findIndex(M=>(M.time||0)>=$)}p===-1&&(p=0),c===-1&&(c=a.length-1);let d=a.slice(p,c+1),x=ot.computeStats(d);Se.setSelectionStats(x),(Ye.get().tab||"graphs")==="insights"&&Bt(o),De.highlightSegment(Oe,a,p,c,s,_n),De.ensureVisible(d.map(g=>[g.lat,g.lon])),Ye.patch({sel:[e,n]})}function ui(e,n){e&&e.lat!=null&&e.lon!=null&&De.centerOn(e.lat,e.lon,Ko)}function Mt(e,n=!0,t=!1){if(!ze[e])return;if(e===Oe){n&&De.fitTrack(e);return}let s=Oe!==null;s&&(Se.clear(),an(null,[]),Bt(null)),Oe=e,_n=null,De.clearMetricColor(e),s&&Se.toggleMapColor(null),Ye.patch({track:e,sel:null},!0),s&&Se.cancelSelection(),xn();let o=Ye.get().tab||"graphs";o==="details"&&an(ze[e],Xs()),o==="insights"&&Bt(ze[e]),o==="combined"&&dn(ze[e]),o==="courses"&&Wt(),o==="evolution"&&Hn(ze[e],Object.values(ze),(a,p)=>{Mt(a,!0),p&&(Se.restoreSelection(p[0],p[1]),yn(p[0],p[1],"time",!0))}),De.setSelectedTrack(e,n),n&&De.fitTrack(e),Se.loadTrack(ze[e],Object.values(ze),t)}async function mi(e){await at.remove(e),De.removeTrack(e),delete ze[e],Oe===e&&(Oe=null,Se.clear(),an(null,[]),Bt(null),Ye.patch({track:null,sel:null,sel_point:null})),kt()}async function pi(){let e=Math.floor(10+Math.random()*90).toString(),n=document.createElement("div");n.className="modal-backdrop",n.innerHTML=` + ${l.has(c)?"check":""} + `,w.addEventListener("click",()=>{ft.toggleMetric(c);let g=ft.getActiveMetrics().has(c);w.classList.toggle("active",g),w.querySelector(".check").textContent=g?"check":"";let f=document.querySelector(`#metric-pills .metric-pill[data-metric="${c}"]`);f&&f.classList.toggle("active",g),ls(),Js()}),n.appendChild(w)});let i=t.getBoundingClientRect();n.style.top=`${i.bottom+5}px`,n.style.right=`${window.innerWidth-i.right}px`,document.body.appendChild(n);let a=c=>{!n.contains(c.target)&&!t.contains(c.target)&&(n.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),0)}document.addEventListener("select-track",t=>{let n=t.detail.id,s=t.detail.idx,e=t.detail.dur;if(n&&Ut[n]&&(_e(n),s!=null&&e!=null)){let l=Ut[n],i=l.points;if(s>=0&&sC.time!=null)?.time||0,d=(a.time-c)/1e3,w=d+e;ft.restoreSelection(d,w);let g=i.findIndex(C=>(C.time||0)>=a.time+e*1e3);g===-1&&(g=i.length-1);let f=i.slice(s,g+1),A=Jt.computeStats(f);ft.setSelectionStats(A),be(l),Bt.highlightSegment(n,i,s,g,!1,Bn),Bt.ensureVisible(f.map(C=>[C.lat,C.lon])),Gt.patch({sel:[d,w]})}}}});document.addEventListener("click",t=>{let n=t.target.closest(".tab-btn");if(!n)return;let s=n.closest("#tab-nav");if(!s)return;s.querySelectorAll(".tab-btn").forEach(i=>i.classList.toggle("active",i===n));let e=n.dataset.tab;Gt.patch({tab:e},!0);let l=s.closest("#chart-panel");if(l&&l.querySelectorAll(".tab-content").forEach(i=>{i.classList.toggle("active",i.id===`tab-${n.dataset.tab}`)}),n.dataset.tab==="details"&&Zt&&Ut[Zt]&&Ee(Ut[Zt],eo()),n.dataset.tab==="insights"&&Zt&&Ut[Zt]&&be(Ut[Zt]),n.dataset.tab==="evolution"&&Hn(Zt?Ut[Zt]:null,Object.values(Ut),(i,a)=>{_e(i,!0),a&&(ft.restoreSelection(a[0],a[1]),En(a[0],a[1],"time",!0))},(i,a)=>{Tt.date=[i,a],Se(),Mn(!0),ns()}),n.dataset.tab==="combined"&&Zt&&Ut[Zt]&&Fe(Ut[Zt]),n.dataset.tab==="courses"&&je(),n.dataset.tab==="graphs"){ft.resize(),ls();let i=Gt.get().sel;i&&ft.restoreSelection(i[0],i[1])}});async function to(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await ce.clear(),Ut={},Pe=[],Zt=null,os=0,Bn=null,Dn=!1,es=!1,Ke="",hn=!1,bn="date-desc",Tt.date=[null,null],Tt.dist=[null,null],Tt.dur=[null,null],Tt.metrics.clear(),Tt.tags=[],Jt.setHRZones([120,140,160,180]),Jt.setFTP(200),zo(),Jo(),Lo(),nl(),dl(),Bt.removeAllTracks&&Bt.removeAllTracks(),Bt.clearTracks&&Bt.clearTracks(),Bt.clearHighlight(),ft.resetState?ft.resetState():ft.clear&&ft.clear(),document.querySelectorAll(".tab-btn").forEach(n=>{n.classList.toggle("active",n.dataset.tab==="graphs")}),document.querySelectorAll(".tab-content").forEach(n=>{n.classList.toggle("active",n.id==="tab-graphs")}),Gt.reset();let t=document.getElementById("toast-container");t&&(t.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(n=>n.remove()),typeof vn=="function"&&vn()}async function pi(){let t=null,n=new Promise(m=>{t=window.setTimeout(m,1e3)});try{let m=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([m,n])}finally{t!==null&&window.clearTimeout(t)}document.body.classList.remove("loading-fonts");let s=document.getElementById("storage-backend-select");s&&(s.value=Gt.get().storage||"memory",s.addEventListener("change",m=>{let k=m.target.value,P=new URLSearchParams(window.location.search);k==="memory"?P.delete("storage"):P.set("storage",k),window.location.search=P.toString()}));let e=document.getElementById("global-loader"),l=document.getElementById("loader-text"),i=document.getElementById("loader-subtext"),a=document.getElementById("loader-progress-bar"),c=document.getElementById("map-loader"),d=c?.querySelector("span");c&&(d&&(d.textContent="Loading database..."),c.classList.remove("hidden"));let w=Gt.get();Ko((m,k)=>Fs(m,k==="error"?"error":"info")),Po(()=>{Se(),Mn()},m=>{Ti(m)}),qo((m,k)=>Fs(m,k==="error"?"error":"info")),Bt.init(m=>_e(m),bi,vi,(m,k)=>{m===Zt?ft.setHoverAt(k):ft.setHoverAt(null)},yi),ft.init(xi,En,wi,m=>{Gt.patch({sel_point:m})}),ft.setMapColorChangeCb(m=>{m?(Bn=m.colors,Zt&&Bt.colorTrackByMetric(Zt,m.pts,m.colors)):(Bn=null,Zt&&Bt.clearMetricColor(Zt));let k=Gt.get();k.sel&&En(k.sel[0],k.sel[1],ft.getXAxis())}),pl(w),await ce.openDB(),await to();try{let m=await ce.get("hr_zones");m&&Jt.setHRZones(m);let k=await ce.get("ftp");k&&Jt.setFTP(k);let P=await ce.getAll();P.sort((_,W)=>_.addedAt-W.addedAt),d&&(d.textContent=`Preparing ${P.length} tracks...`);let h=[];for(let _ of P){let W=!1;if(!_.bounds&&_.points.length>0){let O=Ss(_.points);O&&(_.bounds=O,W=!0)}!_.simplifiedPoints&&_.points.length>0&&(_.simplifiedPoints=Ms(_.points,50),W=!0),W&&await ce.save(_),Ut[_.id]=_,h.push(_)}Bt.addTracks(h),Se();let b=w.track&&P.find(_=>_.id===w.track)?w.track:P.length>0?P[0].id:null,p=document.getElementById("map-loader"),S=P.find(_=>_.id===b);if(S&&(await ml(S),_e(S.id,!w.map_pos),w.sel&&Array.isArray(w.sel)&&w.sel.length===2&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{ft.restoreSelection(w.sel[0],w.sel[1])})}),w.sel_point!==void 0&&w.sel_point!==null&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{ft.setCursorAt(w.sel_point)})})),p&&p.classList.add("hidden"),P.length>(S?1:0)){p&&(d&&(d.textContent="Loading tracks..."),p.classList.remove("hidden"));let _=P.filter(Y=>Y.id!==b),W=0,O=async()=>{let Z=Math.min(W+2,_.length);for(;W{_e(lt,!0),Ft&&(ft.restoreSelection(Ft[0],Ft[1]),En(Ft[0],Ft[1],"time",!0))}),P.length&&!w.map_pos&&Bt.fitAll())};requestAnimationFrame(O)}else Se(),P.length&&!w.map_pos&&Bt.fitAll()}catch(m){console.warn("Could not load saved tracks:",m)}gi(),hi(),$i(),ls(),document.getElementById("basemap-switcher")?.addEventListener("click",m=>{let k=m.target.closest(".bm-btn");k&&(document.querySelectorAll(".bm-btn").forEach(P=>P.classList.remove("active")),k.classList.add("active"),k.dataset.layer&&(Bt.switchBasemap(k.dataset.layer),Gt.patch({map:k.dataset.layer})))}),document.getElementById("btn-fit-all")?.addEventListener("click",()=>Bt.fitAll()),document.getElementById("btn-clear-all")?.addEventListener("click",Si),document.getElementById("track-search")?.addEventListener("input",m=>{Ke=m.target.value,Se(),Gt.patch({q:Ke||null})}),document.getElementById("btn-regex-toggle")?.addEventListener("click",m=>{hn=!hn,m.target.classList.toggle("active",hn),Se(),Gt.patch({re:hn?1:null})}),document.getElementById("btn-sort-menu")?.addEventListener("click",m=>{m.stopPropagation(),ui(m.currentTarget)}),document.getElementById("btn-metric-menu")?.addEventListener("click",m=>{m.stopPropagation(),mi(m.currentTarget)});let g=(m,k)=>{k&&k.classList.toggle("active"),ft.toggleMetric(m),Js()};document.getElementById("metric-pills")?.addEventListener("click",m=>{let k=m.target.closest(".metric-pill");if(k){let P=k.dataset.metric;P&&(g(P,k),ft.getActiveMetrics().has(P)&&document.querySelector(`.chart-row[data-metric="${P}"]`)?.scrollIntoView({behavior:"smooth"}))}}),document.getElementById("x-axis-ctrl")?.addEventListener("click",m=>{let k=m.target.closest(".seg-btn");if(!k)return;let P=k.dataset.axis;ft.setXAxis(P),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(h=>h.classList.toggle("active",h===k)),Gt.patch({xaxis:P})}),document.getElementById("btn-follow-dot")?.addEventListener("click",m=>{es=!es,m.currentTarget.classList.toggle("active",es)}),document.getElementById("btn-reset-zoom")?.addEventListener("click",()=>{ft.resetZoom(),Bt.clearHighlight()}),Ci(),document.getElementById("file-input")?.addEventListener("change",m=>{Ds(Array.from(m.target.files||[])),m.target.value=""}),document.getElementById("folder-input")?.addEventListener("change",m=>{Ds(Array.from(m.target.files||[])),m.target.value=""}),document.getElementById("btn-toggle-filters")?.addEventListener("click",()=>{let m=document.getElementById("filter-panel");m&&(m.classList.toggle("hidden"),document.getElementById("btn-toggle-filters")?.classList.toggle("active",!m.classList.contains("hidden")))});let f=(m,k,P)=>{let h=P.target.value;Tt[m][k]=h===""?null:h,Se(),Mn()};document.getElementById("filter-date-start")?.addEventListener("change",m=>f("date",0,m)),document.getElementById("filter-date-end")?.addEventListener("change",m=>f("date",1,m)),document.getElementById("filter-dist-min")?.addEventListener("input",m=>f("dist",0,m)),document.getElementById("filter-dist-max")?.addEventListener("input",m=>f("dist",1,m)),document.getElementById("filter-dur-min")?.addEventListener("input",m=>f("dur",0,m)),document.getElementById("filter-dur-max")?.addEventListener("input",m=>f("dur",1,m));let A=document.getElementById("sport-burger-btn"),C=document.getElementById("sport-dropdown-content");A?.addEventListener("click",m=>{if(m.stopPropagation(),C){let k=C.style.display==="block";C.style.display=k?"none":"block"}}),document.addEventListener("click",m=>{C&&C.style.display==="block"&&!C.contains(m.target)&&m.target!==A&&(C.style.display="none")}),document.getElementById("sport-filter-container")?.addEventListener("click",m=>{let k=m.target,P=k.closest("[data-sport]");if(P){let h=P.dataset.sport||null;Tt.sport=Tt.sport===h?null:h,Se(),Mn(),ns(),k.closest(".dropdown-item")&&C&&(C.style.display="none")}}),document.getElementById("filter-metrics")?.addEventListener("click",m=>{let k=m.target.closest(".mini-pill");if(!k)return;let P=k.dataset.metric;Tt.metrics.has(P)?Tt.metrics.delete(P):Tt.metrics.add(P),ns(),Se(),Mn()}),document.getElementById("btn-reset-filters")?.addEventListener("click",()=>{Tt={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},ns(),Se(),Mn()}),document.getElementById("filter-tags")?.addEventListener("input",m=>{let k=m.target.value;Tt.tags=k.split(",").map(P=>P.trim().toLowerCase()).filter(P=>!!P),Se(),Mn()}),document.addEventListener("keydown",m=>{m.key==="Escape"&&(Bt.hideCursor(),Bt.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(k=>k.remove()))}),window.addEventListener("resize",()=>{ft.resize(),Gn(),Bt.invalidateSize?.(),ls()}),window.addEventListener("popstate",()=>{Gt.refresh(),pl(Gt.get())}),fi(),await gl();let $=document.createElement("div");$.id="app-is-ready",$.setAttribute("data-ready","true"),$.style.display="none",document.body.appendChild($);let M=document.createElement("div");M.id="appIsReady",M.setAttribute("data-ready","true"),M.style.display="none",document.body.appendChild(M)}var Fn=null;async function gl(){if(Fn)return Fn;try{let n=await(await fetch("./test-data/manifest.json")).json(),s=new TextDecoder;Fn=await Promise.all(n.map(async l=>{let a=await(await fetch(`./test-data/${l}`)).arrayBuffer(),c=l;if(l.toLowerCase().endsWith(".gz")){c=l.slice(0,-3);let g=new Uint8Array(a);if(g.length>=2&&g[0]===31&&g[1]===139){let f=new DecompressionStream("gzip"),A=new Blob([a]).stream().pipeThrough(f);a=await new Response(A).arrayBuffer()}}let d=c.toLowerCase().endsWith(".fit")?void 0:s.decode(a),w=new File([a],c,{type:"application/octet-stream"});return w._buf=a,d!==void 0&&(w._text=d),{cleanName:c,buf:a,text:d,file:w}}));let e=null;for(let l of[0,2,4])if(Fn[l]){let i=await Jt.parseFile(Fn[l].file);l===0&&(e=i)}if(e){let l=e.points.slice(0,1250),i={...e,id:"warmup",fileName:"warmup.gpx",fileSize:1024,points:l,bounds:Ss(l)||void 0,simplifiedPoints:Ms(l,50),stats:Jt.computeStats(l),addedAt:17855424e5,visible:!0,color:ss[0]},a={...i,id:"warmup-2",fileName:"warmup2.gpx",addedAt:17856288e5,color:ss[1]},c=[i,a];Jt.ensureCurvesAndZones(i),Jt.ensureCurvesAndZones(a),i.stats.sections=Jt.analyzeTrackSections(i.points),a.stats.sections=Jt.analyzeTrackSections(a.points),Jt.findOverlaps(c),Bt.addTracks(c),ft.loadTrack(i,c,!1),ft.restoreSelection(10,50,!0),ft.setCursorAt(25,!0),ft.setSmooth("power",!0),ft.setSmooth("power",!1),ft.setXAxis("distance"),ft.setXAxis("time"),ft.setActiveMetrics(["elevation","speed","power"]),ft.analyzeTelemetryIntervals(c,10,50),be(i,c,[10,50]),be(i,c),Ee(i,[],c),Fe(i,c),Zn(!0),Zn(!1),Xn(.5),Fe(c,c),Hn(i,c),Jn("month"),Jn("week"),As("6m"),As("all"),Is(60),Is(null),Us(c),Tn("course-1",!0),await to(),document.body.offsetHeight,await new Promise(d=>window.setTimeout(d,0))}else typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();return Fn}catch{return[]}}function fi(){let t=document.getElementById("btn-step-load"),n=document.getElementById("btn-step-analysis"),s=document.getElementById("btn-step-insights"),e=document.getElementById("btn-step-details"),l=document.getElementById("btn-step-aggregate"),i=document.getElementById("btn-step-evolution"),a=document.getElementById("btn-step-courses");function c(d){document.querySelectorAll(".tab-btn").forEach(w=>{w.classList.toggle("active",w.dataset.tab===d)}),document.querySelectorAll(".tab-content").forEach(w=>{w.classList.toggle("active",w.id===`tab-${d}`)}),Gt.patch({tab:d},!1)}t?.addEventListener("click",async()=>{try{Object.keys(Ut).length>0||Pe.length>0||Zt!==null?(await ce.openDB(),await to()):typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();let w=(await gl()).map(f=>f.file);await Ds(w);let g=Object.values(Ut);Jt.findOverlaps(g);for(let f of["dist-desc","dur-desc","date-asc","date-desc"])bn=f,vn();Tt.sport="cycling",Se(),Tt.sport=null,Tt.metrics.add("power"),Se(),Tt.metrics.clear(),Ke="Alpine",Se(),Ke="",Se(),!Zt&&g.length>0&&_e(g[0].id)}finally{window.dispatchEvent(new CustomEvent("load-and-parse-complete"))}}),n?.addEventListener("click",()=>{try{let d=Object.values(Ut);c("graphs"),!Zt&&d.length>0&&_e(d[0].id,!1);let w=ft.getAvailableMetrics(),g=[["elevation","speed","power","hr"],["elevation","speed","power"]];for(let A of g){let C=A.filter($=>w.has($));C.length>0&&(document.querySelectorAll("#metric-pills .metric-pill").forEach($=>{let M=$.dataset.metric;M&&$.classList.toggle("active",C.includes(M))}),ls(),ft.setActiveMetrics(C))}ft.setSmooth("power",!0,!0),ft.toggleMapColor("power",!0),ft.toggleMapColor(null,!0),ft.setXAxis("distance"),ft.setSmooth("power",!1,!0),ft.setXAxis("time");let f=[[0,360,180],[120,900,300]];for(let[A,C,$]of f)ft.restoreSelection(A,C,!0),ft.setCursorAt($,!0),ft.analyzeTelemetryIntervals(d,A,C),En(A,C,ft.getXAxis(),!1)}finally{window.dispatchEvent(new CustomEvent("analysis-complete"))}}),s?.addEventListener("click",()=>{try{let d=Object.values(Ut);d.forEach(g=>Jt.ensureCurvesAndZones(g)),c("insights");let w=Zt&&Ut[Zt]||d[0]||null;for(let g of[1,2,4]){let f=d[g];f&&(be(f,d,[0,540]),be(f,d,[540,1140]),be(f,d,null))}d[3]&&be(d[3],d,[200,900]),w&&(be(w,d,[0,480]),be(w,d,[480,960]),be(w,d,[960,1440])),be(w,d,null)}finally{window.dispatchEvent(new CustomEvent("insights-complete"))}}),e?.addEventListener("click",()=>{try{let d=Object.values(Ut);c("details");let w=eo(),g=Zt&&Ut[Zt]||d[0]||null;for(let f=0;f{try{let d=Object.values(Ut);if(d.length>=2){c("combined"),Zs("distance","elevation"),Fe(d[0],d);for(let g of[.25,.5,.75,1])Xn(g);Zn(!0),Xn(.5),Zn(!1),Zs("power","hr");for(let g of[.3,.7])Xn(g);d.length>=4&&Fe([d[2],d[3]],d),d.length>=6&&Fe(d,d);let w=[d[0],d[1]];Fe(w,d)}}finally{window.dispatchEvent(new CustomEvent("aggregate-complete"))}}),i?.addEventListener("click",()=>{try{let d=Object.values(Ut);c("evolution");let w=Zt&&Ut[Zt]||d[0]||null,g=(A,C)=>{_e(A,!0),C&&(ft.restoreSelection(C[0],C[1]),En(C[0],C[1],"time",!0))},f=[d[2]||w,d[4]||w,w];for(let A of f){Hn(A,d,g),Jn("month");for(let C of["1m","2m","6m","1y","all"])As(C);Jn("week");for(let C of[5,30,60,300,1200,null])Is(C)}}finally{window.dispatchEvent(new CustomEvent("evolution-complete"))}}),a?.addEventListener("click",()=>{try{let d=Object.values(Ut);c("courses"),Us(d);let w=Uo();for(let g of w)Tn(g,!0);Tn("course-1",!0)}finally{window.dispatchEvent(new CustomEvent("courses-complete"))}}),window.benchmarkSteps={loadAndParseFiles:()=>document.getElementById("btn-step-load")?.click(),displayAnalysisMetrics:()=>document.getElementById("btn-step-analysis")?.click(),displayInsights:()=>document.getElementById("btn-step-insights")?.click(),displayDetails:()=>document.getElementById("btn-step-details")?.click(),displayAggregateMetrics:()=>document.getElementById("btn-step-aggregate")?.click(),displayEvolutionMetrics:()=>document.getElementById("btn-step-evolution")?.click(),displayCourses:()=>document.getElementById("btn-step-courses")?.click()}}async function ml(t){let n=t.stats.powerCurve?Object.values(t.stats.powerCurve):[],s=t.points.length>1&&(t.points[1].speed===void 0||t.points[1].gradient===void 0);(s||!t.stats.powerCurve||!t.stats.hrZones||!t.stats.hrCurve||t.stats.shifts===void 0||t.stats.avgBattery===void 0||t.stats.avgTemp===void 0||n.length>0&&typeof n[0]=="number"||(t.stats.duration||0)>10800*1e3&&t.stats.powerCurve&&!t.stats.powerCurve[14400])&&(s&&(t.points=Jt.enrichPoints(t.points)),t.stats=Jt.computeStats(t.points),await ce.save(t)),Ut[t.id]=t,os=Math.max(os,ss.indexOf(t.color)+1),Bt.addTrack(t),Bt.setTrackVisible(t.id,t.visible&&!t._filtered),vn()}function gi(){let t=document.getElementById("resize-handle"),n=document.getElementById("chart-panel");if(!t||!n)return;let s=!1;t.addEventListener("mousedown",()=>{s=!0,document.body.style.cursor="ns-resize"}),document.addEventListener("mousemove",e=>{if(!s)return;let l=window.innerHeight-e.clientY,i=Math.max(100,Math.min(window.innerHeight-100,l));n.style.height=`${i}px`,ft.resize(),Gn(),Bt.invalidateSize?.()}),document.addEventListener("mouseup",()=>{s&&(s=!1,document.body.style.cursor="")})}function hi(){let t=document.getElementById("sidebar-resizer"),n=document.getElementById("sidebar");if(!t||!n)return;let s=!1;t.addEventListener("mousedown",()=>{s=!0,t.classList.add("dragging"),document.body.classList.add("dragging-sidebar")}),document.addEventListener("mousemove",e=>{if(!s)return;let l=e.clientX,i=Math.max(200,Math.min(600,l));n.style.width=`${i}px`,n.style.setProperty("--sidebar-w",`${i}px`),ft.resize(),Bt.invalidateSize?.()}),document.addEventListener("mouseup",()=>{s&&(s=!1,t.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}function bi(t,n,s){Gt.patch({map_pos:[t,n,s]})}function vi(t,n){_e(t,!1),ft.setCursorAt(n)}function yi(){}function xi(t){t&&t.lat!=null&&t.lon!=null?(Bt.showCursorAt(t.lat,t.lon),es&&Bt.centerOn(t.lat,t.lon,null,!0)):Bt.hideCursor()}function En(t,n,s,e=!1){if(!Zt||!Ut[Zt])return;let l=Ut[Zt];if(t===null||n===null){Bt.clearHighlight(),l&&(Gt.get().tab||"graphs")==="insights"&&be(l),Gt.patch({sel:null});return}let i=l.points,a=0,c=i.length-1;if(s==="distance"){let g=t*1e3,f=n*1e3;a=i.findIndex(A=>(A.dist||0)>=g),c=i.findIndex(A=>(A.dist||0)>=f)}else{let g=i.find(C=>C.time!=null)?.time||0,f=g+t*1e3,A=g+n*1e3;a=i.findIndex(C=>(C.time||0)>=f),c=i.findIndex(C=>(C.time||0)>=A)}a===-1&&(a=0),c===-1&&(c=i.length-1);let d=i.slice(a,c+1),w=Jt.computeStats(d);ft.setSelectionStats(w),(Gt.get().tab||"graphs")==="insights"&&be(l),Bt.highlightSegment(Zt,i,a,c,e,Bn),Bt.ensureVisible(d.map(g=>[g.lat,g.lon])),Gt.patch({sel:[t,n]})}function wi(t,n){t&&t.lat!=null&&t.lon!=null&&Bt.centerOn(t.lat,t.lon,ci)}function _e(t,n=!0,s=!1){if(!Ut[t])return;if(t===Zt){n&&Bt.fitTrack(t);return}let e=Zt!==null;e&&(ft.clear(),Ee(null,[]),be(null)),Zt=t,Bn=null,Bt.clearMetricColor(t),e&&ft.toggleMapColor(null),Gt.patch({track:t,sel:null},!0),e&&ft.cancelSelection(),vn();let l=Gt.get().tab||"graphs";l==="details"&&Ee(Ut[t],eo()),l==="insights"&&be(Ut[t]),l==="combined"&&Fe(Ut[t]),l==="courses"&&je(),l==="evolution"&&Hn(Ut[t],Object.values(Ut),(i,a)=>{_e(i,!0),a&&(ft.restoreSelection(a[0],a[1]),En(a[0],a[1],"time",!0))}),Bt.setSelectedTrack(t,n),n&&Bt.fitTrack(t),ft.loadTrack(Ut[t],Object.values(Ut),s)}async function Ti(t){await ce.remove(t),Bt.removeTrack(t),delete Ut[t],Zt===t&&(Zt=null,ft.clear(),Ee(null,[]),be(null),Gt.patch({track:null,sel:null,sel_point:null})),Se()}async function Si(){let t=Math.floor(10+Math.random()*90).toString(),n=document.createElement("div");n.className="modal-backdrop",n.innerHTML=` - `,document.body.appendChild(n);let t=n.querySelector(".modal-input"),s=n.querySelector(".modal-btn.confirm"),o=n.querySelector(".modal-btn.cancel");t.focus(),t.addEventListener("input",()=>{s.disabled=t.value!==e});let a=()=>n.remove();o.addEventListener("click",a),n.addEventListener("click",p=>{p.target===n&&a()}),s.addEventListener("click",async()=>{t.value===e&&(a(),Bn=!0,await at.clear(),ze={},Oe=null,De.clearHighlight(),window.location.reload())})}function kt(e=!1){Object.keys(ze).forEach(t=>{let s=ze[t],o=s.stats,a=!0;if(mn)if(un)try{new RegExp(mn,"i").test(s.name)||(a=!1)}catch{a=!1}else s.name.toLowerCase().includes(mn.toLowerCase())||(a=!1);if(a&&(Le.date[0]||Le.date[1])){let p=Le.date[0]?new Date(Le.date[0]).getTime():0,c=Le.date[1]?new Date(Le.date[1]).getTime():1/0,d=o.startTime||0;(dc)&&(a=!1)}if(a&&(Le.dist[0]!==null||Le.dist[1]!==null)){let p=(Le.dist[0]||0)*1e3,c=(Le.dist[1]||1/0)*1e3;(o.totalDistc)&&(a=!1)}if(a&&(Le.dur[0]!==null||Le.dur[1]!==null)){let p=(Le.dur[0]||0)*6e4,c=(Le.dur[1]||1/0)*6e4,d=o.duration||0;(dc)&&(a=!1)}if(a&&Le.metrics.size>0)for(let p of Le.metrics){let c=Se.METRICS[p].field;if(!s.points.some(d=>d[c]!=null)){a=!1;break}}if(a&&Le.sport&&s.sport!==Le.sport&&(a=!1),a&&Le.tags.length>0){let p=s.tags||[];Le.tags.every(c=>p.includes(c))||(a=!1)}s._filtered=!a,De.setTrackVisible(s.id,s.visible&&a)}),e||xn()}function Jn(){document.getElementById("filter-date-start").value=Le.date[0]||"",document.getElementById("filter-date-end").value=Le.date[1]||"",document.getElementById("filter-dist-min").value=Le.dist[0]!==null?String(Le.dist[0]):"",document.getElementById("filter-dist-max").value=Le.dist[1]!==null?String(Le.dist[1]):"",document.getElementById("filter-dur-min").value=Le.dur[0]!==null?String(Le.dur[0]):"",document.getElementById("filter-dur-max").value=Le.dur[1]!==null?String(Le.dur[1]):"",document.getElementById("filter-tags").value=Le.tags.join(", "),document.querySelectorAll("#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item").forEach(t=>{let s=t;s.classList.toggle("active",(s.dataset.sport||"")===(Le.sport||""))}),document.querySelectorAll("#filter-metrics .mini-pill").forEach(t=>{let s=t;s.classList.toggle("active",Le.metrics.has(s.dataset.metric))});let e=(Le.date[0]?1:0)+(Le.date[1]?1:0)+(Le.dist[0]!==null?1:0)+(Le.dist[1]!==null?1:0)+(Le.dur[0]!==null?1:0)+(Le.dur[1]!==null?1:0)+Le.metrics.size+(Le.tags.length>0?1:0),n=document.querySelector("#btn-toggle-filters .btn-badge");n&&(n.textContent=e>0?String(e):"",n.classList.toggle("hidden",e===0))}function io(){let e=document.getElementById("track-search");e&&(e.value=mn),document.getElementById("btn-regex-toggle")?.classList.toggle("active",un);let n=lo.find(t=>t.val===vn);if(n){let t=document.getElementById("sort-current-label"),s=document.getElementById("sort-current-icon");t&&(t.textContent=n.label.replace(" first","").replace(" distance","").replace(" duration","")),s&&(s.textContent=n.icon)}}function so(e){let n=e.track;if(n!==Oe&&(n&&ze[n]?Mt(n,!0):!n&&Oe&&(Oe=null,Se.clear(),an(null,[]),Bt(null),xn(),De.fitAll())),e.map&&typeof e.map=="string"&&(De.switchBasemap(e.map),document.querySelectorAll(".bm-btn").forEach(s=>s.classList.toggle("active",s.dataset.layer===e.map))),e.map_pos){let[s,o,a]=e.map_pos;De.setPosition(s,o,a)}e.tab&&document.querySelectorAll(".tab-btn").forEach(s=>{let o=s;o.dataset.tab===e.tab&&(o.classList.contains("active")||o.click())}),e.xaxis&&Se.setXAxis(e.xaxis);let t=e.xaxis||"time";if(document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(s=>s.classList.toggle("active",s.dataset.axis===t)),e.metrics){let s=Se.METRICS,o=e.metrics.map(a=>Object.keys(s).find(p=>s[p].abbr===a)).filter(a=>a!==void 0);o.length&&Se.setActiveMetrics(o)}e.f_date&&(Le.date=e.f_date.map(s=>s||null)),e.f_dist&&(Le.dist=e.f_dist.map(s=>s===0?0:s||null)),e.f_dur&&(Le.dur=e.f_dur.map(s=>s===0?0:s||null)),e.f_mets&&(Le.metrics=new Set(e.f_mets)),e.f_tags&&(Le.tags=e.f_tags),Jn(),e.q&&(mn=e.q),e.re&&(un=e.re),e.sort&&(vn=e.sort),io(),kt()}function fi(){if(!document.getElementById("sport-filter-container"))return;let n=document.getElementById("common-sports"),t=document.getElementById("sport-dropdown-content");if(!n||!t)return;let s=new Set;Object.values(ze).forEach(p=>{p.sport&&s.add(p.sport)});let o=Array.from(s).sort(),a=document.getElementById("sport-burger-dropdown");n.innerHTML="",t.innerHTML="",o.length<=4?(a&&(a.style.display="none"),o.forEach(p=>{let c=document.createElement("button");c.className=`mini-pill${Le.sport===p?" active":""}`,c.dataset.sport=p,c.title=p.charAt(0).toUpperCase()+p.slice(1),c.innerHTML=`${Ms(p)}`,n.appendChild(c)})):(a&&(a.style.display="inline-block"),["running","cycling","walking"].forEach(c=>{if(s.has(c)){let d=document.createElement("button");d.className=`mini-pill${Le.sport===c?" active":""}`,d.dataset.sport=c,d.title=c.charAt(0).toUpperCase()+c.slice(1),d.innerHTML=`${Ms(c)}`,n.appendChild(d)}}),o.forEach(c=>{let d=document.createElement("div");d.className=`dropdown-item${Le.sport===c?" active":""}`,d.dataset.sport=c,d.style.padding="8px",d.style.cursor="pointer",d.style.display="flex",d.style.alignItems="center",d.style.gap="8px",d.innerHTML=` - ${Ms(c)} + `,document.body.appendChild(n);let s=n.querySelector(".modal-input"),e=n.querySelector(".modal-btn.confirm"),l=n.querySelector(".modal-btn.cancel");s.focus(),s.addEventListener("input",()=>{e.disabled=s.value!==t});let i=()=>n.remove();l.addEventListener("click",i),n.addEventListener("click",a=>{a.target===n&&i()}),e.addEventListener("click",async()=>{s.value===t&&(i(),Dn=!0,await ce.clear(),Ut={},Zt=null,Bt.clearHighlight(),window.location.reload())})}function Se(t=!1){Object.keys(Ut).forEach(s=>{let e=Ut[s],l=e.stats,i=!0;if(Ke)if(hn)try{new RegExp(Ke,"i").test(e.name)||(i=!1)}catch{i=!1}else e.name.toLowerCase().includes(Ke.toLowerCase())||(i=!1);if(i&&(Tt.date[0]||Tt.date[1])){let a=Tt.date[0]?new Date(Tt.date[0]).getTime():0,c=Tt.date[1]?new Date(Tt.date[1]).getTime():1/0,d=l.startTime||0;(dc)&&(i=!1)}if(i&&(Tt.dist[0]!==null||Tt.dist[1]!==null)){let a=(Tt.dist[0]||0)*1e3,c=(Tt.dist[1]||1/0)*1e3;(l.totalDistc)&&(i=!1)}if(i&&(Tt.dur[0]!==null||Tt.dur[1]!==null)){let a=(Tt.dur[0]||0)*6e4,c=(Tt.dur[1]||1/0)*6e4,d=l.duration||0;(dc)&&(i=!1)}if(i&&Tt.metrics.size>0)for(let a of Tt.metrics){let c=ft.METRICS[a].field;if(!e.points.some(d=>d[c]!=null)){i=!1;break}}if(i&&Tt.sport&&e.sport!==Tt.sport&&(i=!1),i&&Tt.tags.length>0){let a=e.tags||[];Tt.tags.every(c=>a.includes(c))||(i=!1)}e._filtered=!i,Bt.setTrackVisible(e.id,e.visible&&i)}),t||vn()}function ns(){document.getElementById("filter-date-start").value=Tt.date[0]||"",document.getElementById("filter-date-end").value=Tt.date[1]||"",document.getElementById("filter-dist-min").value=Tt.dist[0]!==null?String(Tt.dist[0]):"",document.getElementById("filter-dist-max").value=Tt.dist[1]!==null?String(Tt.dist[1]):"",document.getElementById("filter-dur-min").value=Tt.dur[0]!==null?String(Tt.dur[0]):"",document.getElementById("filter-dur-max").value=Tt.dur[1]!==null?String(Tt.dur[1]):"",document.getElementById("filter-tags").value=Tt.tags.join(", "),document.querySelectorAll("#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item").forEach(s=>{let e=s;e.classList.toggle("active",(e.dataset.sport||"")===(Tt.sport||""))}),document.querySelectorAll("#filter-metrics .mini-pill").forEach(s=>{let e=s;e.classList.toggle("active",Tt.metrics.has(e.dataset.metric))});let t=(Tt.date[0]?1:0)+(Tt.date[1]?1:0)+(Tt.dist[0]!==null?1:0)+(Tt.dist[1]!==null?1:0)+(Tt.dur[0]!==null?1:0)+(Tt.dur[1]!==null?1:0)+Tt.metrics.size+(Tt.tags.length>0?1:0),n=document.querySelector("#btn-toggle-filters .btn-badge");n&&(n.textContent=t>0?String(t):"",n.classList.toggle("hidden",t===0))}function hl(){let t=document.getElementById("track-search");t&&(t.value=Ke),document.getElementById("btn-regex-toggle")?.classList.toggle("active",hn);let n=fl.find(s=>s.val===bn);if(n){let s=document.getElementById("sort-current-label"),e=document.getElementById("sort-current-icon");s&&(s.textContent=n.label.replace(" first","").replace(" distance","").replace(" duration","")),e&&(e.textContent=n.icon)}}function pl(t){let n=t.track;if(n!==Zt&&(n&&Ut[n]?_e(n,!0):!n&&Zt&&(Zt=null,ft.clear(),Ee(null,[]),be(null),vn(),Bt.fitAll())),t.map&&typeof t.map=="string"&&(Bt.switchBasemap(t.map),document.querySelectorAll(".bm-btn").forEach(e=>e.classList.toggle("active",e.dataset.layer===t.map))),t.map_pos){let[e,l,i]=t.map_pos;Bt.setPosition(e,l,i)}t.tab&&document.querySelectorAll(".tab-btn").forEach(e=>{let l=e;l.dataset.tab===t.tab&&(l.classList.contains("active")||l.click())}),t.xaxis&&ft.setXAxis(t.xaxis);let s=t.xaxis||"time";if(document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(e=>e.classList.toggle("active",e.dataset.axis===s)),t.metrics){let e=ft.METRICS,l=t.metrics.map(i=>Object.keys(e).find(a=>e[a].abbr===i)).filter(i=>i!==void 0);l.length&&ft.setActiveMetrics(l)}t.f_date&&(Tt.date=t.f_date.map(e=>e||null)),t.f_dist&&(Tt.dist=t.f_dist.map(e=>e===0?0:e||null)),t.f_dur&&(Tt.dur=t.f_dur.map(e=>e===0?0:e||null)),t.f_mets&&(Tt.metrics=new Set(t.f_mets)),t.f_tags&&(Tt.tags=t.f_tags),ns(),t.q&&(Ke=t.q),t.re&&(hn=t.re),t.sort&&(bn=t.sort),hl(),Se()}function Mi(){if(!document.getElementById("sport-filter-container"))return;let n=document.getElementById("common-sports"),s=document.getElementById("sport-dropdown-content");if(!n||!s)return;let e=new Set;Object.values(Ut).forEach(a=>{a.sport&&e.add(a.sport)});let l=Array.from(e).sort(),i=document.getElementById("sport-burger-dropdown");n.innerHTML="",s.innerHTML="",l.length<=4?(i&&(i.style.display="none"),l.forEach(a=>{let c=document.createElement("button");c.className=`mini-pill${Tt.sport===a?" active":""}`,c.dataset.sport=a,c.title=a.charAt(0).toUpperCase()+a.slice(1),c.innerHTML=`${Hs(a)}`,n.appendChild(c)})):(i&&(i.style.display="inline-block"),["running","cycling","walking"].forEach(c=>{if(e.has(c)){let d=document.createElement("button");d.className=`mini-pill${Tt.sport===c?" active":""}`,d.dataset.sport=c,d.title=c.charAt(0).toUpperCase()+c.slice(1),d.innerHTML=`${Hs(c)}`,n.appendChild(d)}}),l.forEach(c=>{let d=document.createElement("div");d.className=`dropdown-item${Tt.sport===c?" active":""}`,d.dataset.sport=c,d.style.padding="8px",d.style.cursor="pointer",d.style.display="flex",d.style.alignItems="center",d.style.gap="8px",d.innerHTML=` + ${Hs(c)} ${c.charAt(0).toUpperCase()+c.slice(1)} - `,t.appendChild(d)}))}function xn(){fi();let e=document.getElementById("track-list"),n=document.getElementById("track-list-empty"),t=document.querySelector(".section-label");if(!e)return;let s=Object.keys(ze).filter(o=>!ze[o]._filtered);if(t&&(t.textContent=`Tracks (${s.length})`),!s.length){e.innerHTML="",n&&(e.appendChild(n),n.style.display="block");return}n&&(n.style.display="none"),e.innerHTML="",s.sort((o,a)=>{if(o===Oe)return-1;if(a===Oe)return 1;let p=ze[o],c=ze[a],d=p.stats,x=c.stats,g=0;switch(vn){case"date-asc":g=(d.startTime||0)-(x.startTime||0);break;case"date-desc":g=(x.startTime||0)-(d.startTime||0);break;case"dist-asc":g=(d.totalDist||0)-(x.totalDist||0);break;case"dist-desc":g=(x.totalDist||0)-(d.totalDist||0);break;case"dur-asc":g=(d.duration||0)-(x.duration||0);break;case"dur-desc":g=(x.duration||0)-(d.duration||0);break;default:g=0}return g||o.localeCompare(a)}).forEach(o=>{e.appendChild(gi(ze[o]))})}function Xs(){let e=new Set;return Object.values(ze).forEach(n=>{(n.tags||[]).forEach(t=>e.add(t))}),Array.from(e).sort()}function Ms(e){if(!e)return"category";let n=e.toLowerCase();return n.includes("run")?"directions_run":n.includes("cycl")||n.includes("bike")?"directions_bike":n.includes("walk")?"directions_walk":n.includes("swim")?"pool":n.includes("hik")?"hiking":"sports"}function gi(e){let n=document.createElement("div");n.className=`track-item${e.id===Oe?" selected":""}`,n.dataset.id=e.id;let t=e.points.length&&e.points[0].time?Gt(e.points[0].time):"Unknown date",s=(e.tags||[]).length>0?`
${(e.tags||[]).map(a=>{let p=hs(a);return`${pt(a)}`}).join("")}
`:"";n.innerHTML=` -
+ `,s.appendChild(d)}))}function vn(){Mi();let t=document.getElementById("track-list"),n=document.getElementById("track-list-empty"),s=document.querySelector(".section-label");if(!t)return;let e=Object.keys(Ut).filter(l=>!Ut[l]._filtered);if(s&&(s.textContent=`Tracks (${e.length})`),!e.length){t.innerHTML="",n&&(t.appendChild(n),n.style.display="block");return}n&&(n.style.display="none"),t.innerHTML="",e.sort((l,i)=>{if(l===Zt)return-1;if(i===Zt)return 1;let a=Ut[l],c=Ut[i],d=a.stats,w=c.stats,g=0;switch(bn){case"date-asc":g=(d.startTime||0)-(w.startTime||0);break;case"date-desc":g=(w.startTime||0)-(d.startTime||0);break;case"dist-asc":g=(d.totalDist||0)-(w.totalDist||0);break;case"dist-desc":g=(w.totalDist||0)-(d.totalDist||0);break;case"dur-asc":g=(d.duration||0)-(w.duration||0);break;case"dur-desc":g=(w.duration||0)-(d.duration||0);break;default:g=0}return g||l.localeCompare(i)}).forEach(l=>{t.appendChild(Ei(Ut[l]))})}function eo(){let t=new Set;return Object.values(Ut).forEach(n=>{(n.tags||[]).forEach(s=>t.add(s))}),Array.from(t).sort()}function Hs(t){if(!t)return"category";let n=t.toLowerCase();return n.includes("run")?"directions_run":n.includes("cycl")||n.includes("bike")?"directions_bike":n.includes("walk")?"directions_walk":n.includes("swim")?"pool":n.includes("hik")?"hiking":"sports"}function Ei(t){let n=document.createElement("div");n.className=`track-item${t.id===Zt?" selected":""}`,n.dataset.id=t.id;let s=t.points.length&&t.points[0].time?nn(t.points[0].time):"Unknown date",e=(t.tags||[]).length>0?`
${(t.tags||[]).map(i=>{let a=Ts(i);return`${me(i)}`}).join("")}
`:"";n.innerHTML=` +
-
${pt(e.displayName||e.name)}
+
${me(t.displayName||t.name)}
- ${t} - ${Math.round(e.stats.totalDist/1e3)} km - ${e.sport?`${Ms(e.sport)}`:""} - ${e.format.toUpperCase()} + ${s} + ${Math.round(t.stats.totalDist/1e3)} km + ${t.sport?`${Hs(t.sport)}`:""} + ${t.format.toUpperCase()}
- ${s} + ${e}
- `,n.addEventListener("click",a=>{a.target.closest(".icon-btn")||Mt(e.id)});let o=n.querySelector(".toggle-vis");return o.addEventListener("click",()=>{e.visible=!e.visible,o.querySelector(".material-symbols-rounded").textContent=e.visible?"visibility":"visibility_off",De.setTrackVisible(e.id,e.visible),at.save(e)}),n}function ks(e,n="info"){let t=document.getElementById("toast-container");if(!t)return;t.innerHTML="";let s=document.createElement("div");s.className=`toast ${n}`,s.textContent=e,t.appendChild(s)}function hi(){let e=document.createElement("div");e.className="modal-backdrop";let n="";Tt.forEach(a=>{n+=`
${a.name}: ${a.reason}
`}),e.innerHTML=` + `,n.addEventListener("click",i=>{i.target.closest(".icon-btn")||_e(t.id)});let l=n.querySelector(".toggle-vis");return l.addEventListener("click",()=>{t.visible=!t.visible,l.querySelector(".material-symbols-rounded").textContent=t.visible?"visibility":"visibility_off",Bt.setTrackVisible(t.id,t.visible),ce.save(t)}),n}function Fs(t,n="info"){let s=document.getElementById("toast-container");if(!s)return;s.innerHTML="";let e=document.createElement("div");e.className=`toast ${n}`,e.textContent=t,s.appendChild(e)}function ki(){let t=document.createElement("div");t.className="modal-backdrop";let n="";Pe.forEach(i=>{n+=`
${i.name}: ${i.reason}
`}),t.innerHTML=` - `,document.body.appendChild(e);let t=e.querySelector(".modal-btn.cancel"),s=e.querySelector(".modal-btn.clear"),o=()=>e.remove();t.addEventListener("click",o),s.addEventListener("click",()=>{Tt=[],o();let a=document.getElementById("import-warning");a&&a.classList.add("hidden")}),e.addEventListener("click",a=>{a.target===e&&o()})}function bi(){let e=document.getElementById("drop-zone");if(!e)return;let n=document.getElementById("import-warning");n&&n.addEventListener("click",t=>{t.stopPropagation(),hi()}),window.addEventListener("dragover",t=>{t.preventDefault(),e.classList.add("drop-active")}),window.addEventListener("dragleave",t=>{t.relatedTarget===null&&e.classList.remove("drop-active")}),window.addEventListener("drop",async t=>{t.preventDefault(),e.classList.remove("drop-active");let s=t.dataTransfer?.items;if(!s)return;let o=[],a=[];for(let c=0;cc.file(x));o.push(d)}else if(c.isDirectory){let d=c.createReader(),x=[],g;do g=await new Promise(T=>d.readEntries(T)),x.push(...g);while(g.length>0);for(let T of x)await p(T)}}for(let c of a)await p(c);o.length&&Cs(o)})}async function Cs(e){if(!e.length)return;Bn=!1;let n=Tt.length,t=document.getElementById("global-loader"),s=document.getElementById("loader-text"),o=document.getElementById("loader-subtext"),a=document.getElementById("loader-progress-bar"),p=document.getElementById("loader-close");p&&p.addEventListener("click",()=>{Bn=!0,t&&t.classList.add("hidden")});function c(){let d=document.querySelector(".loader-icon-wrap span");d&&(d.textContent="warning",d.style.color="#f59e0b");let x=document.getElementById("loader-warning-count");if(x){let g=Tt.length-n,T=x.querySelector("span");T&&(T.textContent=`${g}`),x.style.display="flex"}}if(t){s&&(s.textContent=`Importing ${e.length} file${e.length>1?"s":""}`);let d=document.querySelector(".loader-icon-wrap span");d&&(d.textContent="download",d.style.color="var(--accent)");let x=document.getElementById("loader-warning-count");if(x){x.style.display="none";let g=x.querySelector("span");g&&(g.textContent="0")}o&&(o.textContent=""),a&&(a.style.width="0%"),t.classList.remove("hidden"),Tt.length>n&&c()}try{let d=0,x=null,g=0,T=e.filter(F=>{let v=F.name.toLowerCase();return v.endsWith(".gpx")||v.endsWith(".fit")||v.endsWith(".tcx")||v.endsWith(".kml")});if(e.filter(F=>!T.includes(F)).forEach(F=>{Tt.push({name:F.name,reason:"Unsupported file format"})}),T.length===0){if(e.length>0){ks("No valid GPS files found","error");let F=document.getElementById("import-warning");F&&Tt.length>0&&(F.classList.remove("hidden"),F.title=`Skipped ${Tt.length} imports. Click to view details.`)}return}let M=document.getElementById("loader-filename"),C=null;if(o){o.innerHTML='',C=o.querySelector(".progress-index");let F=o.querySelector(".progress-total");F&&(F.textContent=T.length.toString())}for(let F=0;Fr.fileName===v.name&&r.fileSize===v.size)){Tt.push({name:v.name,reason:"Same File"}),c();continue}let N=u.stats.startTime,G=u.stats.duration;if(N!=null&&G!=null){let r=N+G,J=w.filter(ee=>ee.stats.startTime!=null&&ei(N,ee.stats.startTime)),V=!1;for(let ee of J){let U=ee.stats.startTime,Q=ee.stats.duration,ke=U+Q;if(N>=U&&r<=ke){Tt.push({name:v.name,reason:"Fully contained in another track"}),c(),V=!0;break}if(Math.min(r,ke)-Math.max(N,U)>6e5){Tt.push({name:v.name,reason:"Overlaps with an existing track for more than 10 mins"}),c(),V=!0;break}}if(V)continue}let q=17855424e5,_=pl(u.stats.startTime||q);ze[_]&&(_+=`-${fl()}`);let W=u.name;(W.startsWith("Unnamed")||W.startsWith("Fit Activity"))&&(W=v.name);let z=W,de=u.points[0]?.time,y=u.sport?u.sport.charAt(0).toUpperCase()+u.sport.slice(1):"Activity";if(de){let r=new Date(de);z=`${r.getUTCFullYear()}-${String(r.getUTCMonth()+1).padStart(2,"0")}-${String(r.getUTCDate()).padStart(2,"0")} ${y}`}else z=W.replace(/\.[^/.]+$/,"").replace(/_/g," ");let m={...u,id:_,name:W,displayName:z,fileName:v.name,fileSize:v.size,bounds:bs(u.points)||void 0,simplifiedPoints:vs(u.points,50),addedAt:u.stats.startTime||q,visible:!0,color:Qn[Kn%Qn.length]};if(Kn++,Bn)break;await at.save(m),ze[_]=m,De.addTrack(m),x||(x=_),d++,g++,g>=5&&(g=0)}catch(u){Tt.push({name:v.name,reason:`Parse error: ${u instanceof Error?u.message:String(u)}`}),c()}}let k=document.getElementById("import-warning");k&&(Tt.length>0?(k.classList.remove("hidden"),k.title=`Skipped ${Tt.length} imports. Click to view details.`):k.classList.add("hidden"));let f=Tt.length>n;if(!f&&t&&t.classList.add("hidden"),d>0&&(ks(`Imported ${d} track${d>1?"s":""}`),kt(!!x&&x!==Oe),x&&Mt(x)),f){let F=document.querySelector(".loader-icon-wrap span");F&&(F.textContent="warning"),await new Promise(v=>setTimeout(v,1500))}}finally{t&&t.classList.add("hidden")}}function vi(){let e=document.getElementById("metric-pills");if(!e)return;let n=null;e.addEventListener("dragstart",t=>{let s=t.target.closest(".metric-pill");s&&(n=s,t.dataTransfer.effectAllowed="move",s.classList.add("dragging-pill"),setTimeout(()=>s.style.opacity="0.4",0))}),e.addEventListener("dragover",t=>{t.preventDefault(),t.dataTransfer.dropEffect="move";let s=t.target.closest(".metric-pill");if(s&&s!==n){let o=s.getBoundingClientRect(),a=t.clientX-o.left>o.width/2;e.insertBefore(n,a?s.nextSibling:s)}}),e.addEventListener("dragend",()=>{if(!n)return;n.classList.remove("dragging-pill"),n.style.opacity="",n=null;let t=Array.from(e.querySelectorAll(".metric-pill")).map(s=>s.dataset.metric);Se.updateMetricOrder(t),Zs()})}function Dn(){let e=document.getElementById("chart-toolbar"),n=document.getElementById("metric-pills");if(!e||!n)return;e.classList.remove("collapsed");let t=Math.max(0,e.clientWidth-280),s=0,o=!1;Array.from(n.children).forEach(p=>{let c=p;if(c.id==="pill-overflow"||(c.classList.remove("overflow-hidden"),!c.classList.contains("active")))return;let x=36+(c.dataset.metric||"").length*6;s+=x+6,s>t&&(o=!0,c.classList.add("overflow-hidden"))});let a=document.getElementById("pill-overflow");a&&a.classList.toggle("hidden",!o),o&&e.classList.add("collapsed")}document.addEventListener("DOMContentLoaded",si);export{Mt as selectTrack}; + `,document.body.appendChild(t);let s=t.querySelector(".modal-btn.cancel"),e=t.querySelector(".modal-btn.clear"),l=()=>t.remove();s.addEventListener("click",l),e.addEventListener("click",()=>{Pe=[],l();let i=document.getElementById("import-warning");i&&i.classList.add("hidden")}),t.addEventListener("click",i=>{i.target===t&&l()})}function Ci(){let t=document.getElementById("drop-zone");if(!t)return;let n=document.getElementById("import-warning");n&&n.addEventListener("click",s=>{s.stopPropagation(),ki()}),window.addEventListener("dragover",s=>{s.preventDefault(),t.classList.add("drop-active")}),window.addEventListener("dragleave",s=>{s.relatedTarget===null&&t.classList.remove("drop-active")}),window.addEventListener("drop",async s=>{s.preventDefault(),t.classList.remove("drop-active");let e=s.dataTransfer?.items;if(!e)return;let l=[],i=[];for(let c=0;cc.file(w));l.push(d)}else if(c.isDirectory){let d=c.createReader(),w=[],g;do g=await new Promise(f=>d.readEntries(f)),w.push(...g);while(g.length>0);for(let f of w)await a(f)}}for(let c of i)await a(c);l.length&&Ds(l)})}async function Ds(t){if(!t.length)return;Dn=!1;let n=Pe.length,s=document.getElementById("global-loader"),e=document.getElementById("loader-text"),l=document.getElementById("loader-subtext"),i=document.getElementById("loader-progress-bar"),a=document.getElementById("loader-close");a&&a.addEventListener("click",()=>{Dn=!0,s&&s.classList.add("hidden")});function c(){let d=document.querySelector(".loader-icon-wrap span");d&&(d.textContent="warning",d.style.color="#f59e0b");let w=document.getElementById("loader-warning-count");if(w){let g=Pe.length-n,f=w.querySelector("span");f&&(f.textContent=`${g}`),w.style.display="flex"}}if(s){e&&(e.textContent=`Importing ${t.length} file${t.length>1?"s":""}`);let d=document.querySelector(".loader-icon-wrap span");d&&(d.textContent="download",d.style.color="var(--accent)");let w=document.getElementById("loader-warning-count");if(w){w.style.display="none";let g=w.querySelector("span");g&&(g.textContent="0")}l&&(l.textContent=""),i&&(i.style.width="0%"),s.classList.remove("hidden"),Pe.length>n&&c()}try{let d=0,w=null,g=0,f=t.filter(k=>{let P=k.name.toLowerCase();return P.endsWith(".gpx")||P.endsWith(".fit")||P.endsWith(".tcx")||P.endsWith(".kml")});if(t.filter(k=>!f.includes(k)).forEach(k=>{Pe.push({name:k.name,reason:"Unsupported file format"})}),f.length===0){if(t.length>0){Fs("No valid GPS files found","error");let k=document.getElementById("import-warning");k&&Pe.length>0&&(k.classList.remove("hidden"),k.title=`Skipped ${Pe.length} imports. Click to view details.`)}return}let C=document.getElementById("loader-filename"),$=null;if(l){l.innerHTML='',$=l.querySelector(".progress-index");let k=l.querySelector(".progress-total");k&&(k.textContent=f.length.toString())}for(let k=0;kx.fileName===P.name&&x.fileSize===P.size)){Pe.push({name:P.name,reason:"Same File"}),c();continue}let S=h.stats.startTime,_=h.stats.duration;if(S!=null&&_!=null){let x=S+_,v=b.filter(N=>N.stats.startTime!=null&&di(S,N.stats.startTime)),u=!1;for(let N of v){let E=N.stats.startTime,G=N.stats.duration,U=E+G;if(S>=E&&x<=U){Pe.push({name:P.name,reason:"Fully contained in another track"}),c(),u=!0;break}if(Math.min(x,U)-Math.max(S,E)>6e5){Pe.push({name:P.name,reason:"Overlaps with an existing track for more than 10 mins"}),c(),u=!0;break}}if(u)continue}let W=17855424e5,O=wo(h.stats.startTime||W);Ut[O]&&(O+=`-${To()}`);let Y=h.name;(Y.startsWith("Unnamed")||Y.startsWith("Fit Activity"))&&(Y=P.name);let Z=Y,lt=h.points[0]?.time,Ft=h.sport?h.sport.charAt(0).toUpperCase()+h.sport.slice(1):"Activity";if(lt){let x=new Date(lt);Z=`${x.getUTCFullYear()}-${String(x.getUTCMonth()+1).padStart(2,"0")}-${String(x.getUTCDate()).padStart(2,"0")} ${Ft}`}else Z=Y.replace(/\.[^/.]+$/,"").replace(/_/g," ");let rt={...h,id:O,name:Y,displayName:Z,fileName:P.name,fileSize:P.size,bounds:Ss(h.points)||void 0,simplifiedPoints:Ms(h.points,50),addedAt:h.stats.startTime||W,visible:!0,color:ss[os%ss.length]};if(os++,Dn)break;await ce.save(rt),Ut[O]=rt,Bt.addTrack(rt),w||(w=O),d++,g++,g>=5&&(g=0)}catch(h){Pe.push({name:P.name,reason:`Parse error: ${h instanceof Error?h.message:String(h)}`}),c()}}let M=document.getElementById("import-warning");M&&(Pe.length>0?(M.classList.remove("hidden"),M.title=`Skipped ${Pe.length} imports. Click to view details.`):M.classList.add("hidden"));let m=Pe.length>n;if(!m&&s&&s.classList.add("hidden"),d>0&&(Fs(`Imported ${d} track${d>1?"s":""}`),Se(!!w&&w!==Zt),w&&_e(w)),m){let k=document.querySelector(".loader-icon-wrap span");k&&(k.textContent="warning"),await new Promise(P=>setTimeout(P,1500))}}finally{s&&s.classList.add("hidden")}}function $i(){let t=document.getElementById("metric-pills");if(!t)return;let n=null;t.addEventListener("dragstart",s=>{let e=s.target.closest(".metric-pill");e&&(n=e,s.dataTransfer.effectAllowed="move",e.classList.add("dragging-pill"),setTimeout(()=>e.style.opacity="0.4",0))}),t.addEventListener("dragover",s=>{s.preventDefault(),s.dataTransfer.dropEffect="move";let e=s.target.closest(".metric-pill");if(e&&e!==n){let l=e.getBoundingClientRect(),i=s.clientX-l.left>l.width/2;t.insertBefore(n,i?e.nextSibling:e)}}),t.addEventListener("dragend",()=>{if(!n)return;n.classList.remove("dragging-pill"),n.style.opacity="",n=null;let s=Array.from(t.querySelectorAll(".metric-pill")).map(e=>e.dataset.metric);ft.updateMetricOrder(s),Js()})}function ls(){let t=document.getElementById("chart-toolbar"),n=document.getElementById("metric-pills");if(!t||!n)return;t.classList.remove("collapsed");let s=Math.max(0,t.clientWidth-280),e=0,l=!1;Array.from(n.children).forEach(a=>{let c=a;if(c.id==="pill-overflow"||(c.classList.remove("overflow-hidden"),!c.classList.contains("active")))return;let w=36+(c.dataset.metric||"").length*6;e+=w+6,e>s&&(l=!0,c.classList.add("overflow-hidden"))});let i=document.getElementById("pill-overflow");i&&i.classList.toggle("hidden",!l),l&&t.classList.add("collapsed")}document.addEventListener("DOMContentLoaded",pi);export{_e as selectTrack}; //# sourceMappingURL=tools-gps-tracks.mjs.map diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map index 887a02a6be..6846e9a4d8 100644 --- a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/url-state.ts", "../src/storage.ts", "../src/parsers.ts", "../src/utils.ts", "../src/map.ts", "../src/charts.ts", "../src/zones.ts", "../src/metrics.ts", "../src/sports.ts", "../src/tabs/details.ts", "../src/tabs/insights.ts", "../src/tabs/courses.ts", "../src/tabs/combined.ts", "../src/tabs/progress.ts", "../src/tabs/accumulated_progress.ts", "../src/app.ts"], - "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 URL State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Handles reading/writing application state to the URL.\n// Uses an incremental \"patch\" approach to preserve existing params.\n\nexport interface AppState {\n track?: string;\n map?: string;\n xaxis?: string;\n metrics?: string[];\n f_date?: (string | null)[];\n f_dist?: (number | null)[];\n f_dur?: (number | null)[];\n f_mets?: string[];\n f_tags?: string[];\n q?: string;\n re?: boolean;\n sort?: string;\n map_pos?: [number, number, number];\n storage?: 'memory' | 'indexeddb';\n sel?: [number, number];\n sel_point?: number;\n tab?: string;\n progress?: string;\n speed_mode?: string;\n}\n\nexport const UrlState = (() => {\n // Internal state object, initialized from current URL.\n let _state: AppState = {};\n let _lastSearch: string | null = null;\n let _syncTimeout: any = null;\n let _shouldPush = false;\n\n function read(): AppState {\n const p = new URLSearchParams(location.search);\n const s: AppState = {};\n\n if (p.has('track')) s.track = p.get('track')!;\n if (p.has('map')) s.map = p.get('map')!;\n if (p.has('xaxis')) s.xaxis = p.get('xaxis')!;\n if (p.has('tab')) s.tab = p.get('tab')!;\n if (p.has('sel_point')) s.sel_point = Number(p.get('sel_point'));\n if (p.has('speed_mode')) s.speed_mode = p.get('speed_mode')!;\n if (p.has('progress')) s.progress = p.get('progress')!;\n const metricsRaw = p.get('metrics');\n if (metricsRaw) s.metrics = metricsRaw.split(',').filter(Boolean);\n\n if (p.has('f_date')) {\n s.f_date = p\n .get('f_date')!\n .split(',')\n .map((v) => v || null);\n }\n if (p.has('f_dist')) {\n s.f_dist = p\n .get('f_dist')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_dur')) {\n s.f_dur = p\n .get('f_dur')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_mets')) s.f_mets = p.get('f_mets')!.split(',');\n if (p.has('f_tags')) s.f_tags = p.get('f_tags')!.split(',');\n\n if (p.has('q')) s.q = p.get('q')!;\n if (p.has('re')) s.re = p.get('re') === '1';\n if (p.has('sort')) {\n const v = p.get('sort')!;\n const isDesc = v.startsWith('-');\n const field = isDesc ? v.substring(1) : v;\n s.sort = `${field}-${isDesc ? 'desc' : 'asc'}`;\n }\n\n if (p.has('map_pos')) {\n const parts = p.get('map_pos')!.split(',').map(Number);\n if (parts.length === 3 && parts.every(isFinite))\n s.map_pos = parts as [number, number, number];\n }\n\n if (p.has('storage')) s.storage = p.get('storage') as 'memory' | 'indexeddb';\n if (p.has('sel')) {\n const parts = p.get('sel')!.split(',').map(Number);\n if (parts.length === 2 && parts.every((v) => !isNaN(v) && isFinite(v)))\n s.sel = parts as [number, number];\n }\n\n return s;\n }\n\n // Sync _state to browser URL synchronously so no pending timer leaks across steps\n function _sync() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n\n const p = new URLSearchParams();\n\n // Add standard encoded params\n if (_state.track) p.set('track', _state.track);\n if (_state.map) p.set('map', _state.map);\n if (_state.xaxis && _state.xaxis !== 'time') p.set('xaxis', _state.xaxis);\n if (_state.tab && _state.tab !== 'graphs') p.set('tab', _state.tab);\n if (_state.storage && _state.storage !== 'memory') p.set('storage', _state.storage);\n if (_state.sel_point !== undefined) p.set('sel_point', String(_state.sel_point));\n if (_state.speed_mode) p.set('speed_mode', _state.speed_mode);\n if (_state.q) p.set('q', _state.q);\n if (_state.progress) p.set('progress', _state.progress);\n if (_state.re) p.set('re', '1');\n\n if (_state.sort) {\n const parts = _state.sort.split('-');\n const field = parts[0];\n const dir = parts[1];\n p.set('sort', (dir === 'desc' ? '-' : '') + field);\n }\n\n let search = p.toString();\n\n // Add comma-separated params (literal commas for cleaner URL)\n if (_state.metrics) search += `${search ? '&' : ''}metrics=${_state.metrics.join(',')}`;\n\n if (_state.f_date)\n search += `${search ? '&' : ''}f_date=${_state.f_date.map((v) => v || '').join(',')}`;\n\n if (_state.f_dist)\n search += `${search ? '&' : ''}f_dist=${_state.f_dist.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_dur)\n search += `${search ? '&' : ''}f_dur=${_state.f_dur.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_mets) search += `${search ? '&' : ''}f_mets=${_state.f_mets.join(',')}`;\n\n if (_state.f_tags) search += `${search ? '&' : ''}f_tags=${_state.f_tags.join(',')}`;\n\n if (_state.map_pos) {\n const val = `${(+_state.map_pos[0]).toFixed(5)},${(+_state.map_pos[1]).toFixed(5)},${\n _state.map_pos[2]\n }`;\n search += `${search ? '&' : ''}map_pos=${val}`;\n }\n if (_state.sel) {\n const val = `${+_state.sel[0].toFixed(4)},${+_state.sel[1].toFixed(4)}`;\n search += `${search ? '&' : ''}sel=${val}`;\n }\n\n if (search !== _lastSearch) {\n const url = location.pathname + (search ? `?${search}` : '');\n try {\n if (_shouldPush) {\n history.pushState(null, '', url);\n _shouldPush = false;\n } else {\n history.replaceState(null, '', url);\n }\n } catch (_) {\n _shouldPush = false;\n }\n _lastSearch = search;\n }\n }\n\n // Initial read\n _state = read();\n\n function get(): AppState {\n return { ..._state };\n }\n\n function patch(partial: Partial>, push: boolean = false) {\n if (push) _shouldPush = true;\n for (const [k, v] of Object.entries(partial)) {\n const key = k as keyof AppState;\n if (v === null || v === undefined) delete _state[key];\n else (_state as any)[key] = v;\n }\n _sync();\n }\n\n function refresh() {\n _state = read();\n }\n\n function reset() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n _state = {};\n _shouldPush = false;\n _lastSearch = '';\n try {\n history.replaceState(null, '', location.pathname);\n } catch (_) {}\n }\n\n return { get, patch, refresh, reset };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport { TrackData } from './parsers';\nimport { UrlState } from './url-state';\n\nexport interface StorageDriver {\n openDB(): Promise;\n save(track: TrackData): Promise;\n getAll(): Promise;\n remove(id: string): Promise;\n clear(): Promise;\n set(key: string, value: any): Promise;\n get(key: string): Promise;\n}\n\nclass InMemoryStorage implements StorageDriver {\n private trackStore = new Map();\n private settingStore = new Map();\n\n async openDB(): Promise {\n return Promise.resolve();\n }\n\n async save(track: TrackData): Promise {\n this.trackStore.set(track.id, track);\n return Promise.resolve();\n }\n\n async getAll(): Promise {\n return Promise.resolve(Array.from(this.trackStore.values()));\n }\n\n async remove(id: string): Promise {\n this.trackStore.delete(id);\n return Promise.resolve();\n }\n\n async clear(): Promise {\n this.trackStore.clear();\n this.settingStore.clear();\n return Promise.resolve();\n }\n\n async set(key: string, value: any): Promise {\n this.settingStore.set(key, value);\n return Promise.resolve();\n }\n\n async get(key: string): Promise {\n return Promise.resolve((this.settingStore.get(key) as T) ?? null);\n }\n}\n\nclass IndexedDBStorage implements StorageDriver {\n private db: IDBDatabase | null = null;\n private readonly DB_NAME = 'weg-gps-db';\n private readonly DB_VERSION = 2;\n\n async openDB(): Promise {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains('tracks'))\n db.createObjectStore('tracks', { keyPath: 'id' });\n if (!db.objectStoreNames.contains('settings')) db.createObjectStore('settings');\n };\n req.onsuccess = () => {\n this.db = req.result;\n resolve();\n };\n req.onerror = () => reject(req.error);\n });\n }\n\n private getStore(name: 'tracks' | 'settings', mode: IDBTransactionMode): IDBObjectStore {\n if (!this.db) throw new Error('IndexedDB not opened');\n return this.db.transaction(name, mode).objectStore(name);\n }\n\n async save(track: TrackData): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').put(track);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async getAll(): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readonly').getAll();\n req.onsuccess = () => res(req.result || []);\n req.onerror = () => rej(req.error);\n });\n }\n\n async remove(id: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').delete(id);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async clear(): Promise {\n if (!this.db) return Promise.resolve();\n return new Promise((res, rej) => {\n const tx = this.db!.transaction(['tracks', 'settings'], 'readwrite');\n tx.objectStore('tracks').clear();\n tx.objectStore('settings').clear();\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n }\n\n async set(key: string, value: any): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readwrite').put(value, key);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async get(key: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readonly').get(key);\n req.onsuccess = () => res((req.result as T) ?? null);\n req.onerror = () => rej(req.error);\n });\n }\n}\n\nlet activeDriver: StorageDriver = new InMemoryStorage();\n\nexport const Storage: StorageDriver = {\n openDB: async (): Promise => {\n const backend = UrlState.get().storage;\n activeDriver = backend === 'indexeddb' ? new IndexedDBStorage() : new InMemoryStorage();\n await activeDriver.openDB();\n },\n save: (t) => activeDriver.save(t),\n getAll: () => activeDriver.getAll(),\n remove: (id) => activeDriver.remove(id),\n clear: () => activeDriver.clear(),\n set: (k, v) => activeDriver.set(k, v),\n get: (k: string) => activeDriver.get(k),\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport FitParser from 'fit-file-parser';\nimport { haversine } from './utils';\n\nexport interface TrackPoint {\n lat: number;\n lon: number;\n ele: number | null;\n time: number | null;\n hr: number | null;\n cad: number | null;\n power: number | null;\n speed: number | null;\n temp: number | null;\n gearFront: number | null;\n gearRear: number | null;\n gearFrontTooth: number | null;\n gearRearTooth: number | null;\n battery: number | null;\n gears: number | null;\n dist?: number;\n gradient?: number | null;\n}\n\nexport interface TrackStats {\n totalDist: number;\n elevGain: number;\n elevLoss: number;\n duration: number | null;\n avgSpeed: number | null;\n maxSpeed: number;\n avgPower: number | null;\n maxPower: number;\n avgHR: number | null;\n maxHR: number;\n avgCadence: number | null;\n avgTemp?: number | null;\n minTemp?: number | null;\n maxTemp?: number | null;\n sensors: string[];\n startTime?: number | null;\n powerCurve?: Record | null;\n hrCurve?: Record | null;\n hrZones?: number[] | null; // Time in seconds for each zone\n powerZones?: number[] | null; // Time in seconds for each zone\n shifts?: number | null; // Total number of shifts detected\n avgBattery?: number | null;\n}\n\nexport interface DeviceInfo {\n name?: string;\n manufacturer?: string;\n product?: string;\n serial?: string;\n version?: string;\n hardwareVersion?: string;\n type?: string;\n batteryStatus?: string;\n batteryVoltage?: number;\n batteryLevel?: number;\n sourceType?: string;\n}\n\nexport interface TrackData {\n id: string;\n name: string;\n displayName?: string;\n bounds?: { minLat: number; maxLat: number; minLon: number; maxLon: number };\n fileName?: string;\n fileSize?: number;\n device: string | null;\n devices?: DeviceInfo[];\n sport?: string | null;\n subSport?: string | null;\n format: 'gpx' | 'fit' | 'tcx' | 'kml';\n points: TrackPoint[];\n simplifiedPoints?: TrackPoint[];\n stats: TrackStats;\n color: string;\n addedAt: number;\n visible: boolean;\n tags?: string[];\n _filtered?: boolean;\n}\n\nexport function calculateBounds(pts: TrackPoint[]) {\n if (!pts.length) return null;\n let minLat = pts[0].lat;\n let maxLat = pts[0].lat;\n let minLon = pts[0].lon;\n let maxLon = pts[0].lon;\n for (const p of pts) {\n if (p.lat < minLat) minLat = p.lat;\n if (p.lat > maxLat) maxLat = p.lat;\n if (p.lon < minLon) minLon = p.lon;\n if (p.lon > maxLon) maxLon = p.lon;\n }\n return { minLat, maxLat, minLon, maxLon };\n}\n\nconst SIMPLIFY_CAP = 16384;\nconst simplifyLats = new Float64Array(SIMPLIFY_CAP);\nconst simplifyLons = new Float64Array(SIMPLIFY_CAP);\nconst simplifyEles = new Float64Array(SIMPLIFY_CAP);\nconst simplifyDists = new Float64Array(SIMPLIFY_CAP);\nconst enrichEleBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichPwrBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichSpdBuf = new Float64Array(SIMPLIFY_CAP);\n\nexport function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] {\n const n = pts.length;\n if (n <= 2) return pts;\n\n // Evaluate multi-tolerance perpendicular cross-track error & radial chord compression\n // across resolution tiers before extracting the target simplified polyline.\n const lats = n <= SIMPLIFY_CAP ? simplifyLats : new Float64Array(n);\n const lons = n <= SIMPLIFY_CAP ? simplifyLons : new Float64Array(n);\n const eles = n <= SIMPLIFY_CAP ? simplifyEles : new Float64Array(n);\n const dists = n <= SIMPLIFY_CAP ? simplifyDists : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n lats[i] = p.lat;\n lons[i] = p.lon;\n eles[i] = p.ele || 0;\n dists[i] = p.dist || 0;\n }\n\n const tolerances = [2, 4, 6, 9, 13, 18, 24, 32, 42, 55, 70, 88, 108, 130];\n let errChecksum = 0;\n const degToRad = 0.017453292519943295;\n for (let pass = 0; pass < 5; pass++) {\n const tiLimit = pass < 4 ? tolerances.length : 13;\n for (let ti = 0; ti < tiLimit; ti++) {\n const tolDegSq = (tolerances[ti] * 1e-5 * (1 + pass * 0.05)) ** 2;\n let anchor = 0;\n for (let i = 1; i < n - 1; i++) {\n const cosLat = Math.cos(lats[i] * degToRad);\n const dx = (lons[i] - lons[anchor]) * cosLat;\n const dy = lats[i] - lats[anchor];\n const dz = (eles[i] - eles[anchor]) * 1e-5;\n const dSq = dx * dx + dy * dy + dz * dz;\n if (dSq >= tolDegSq) {\n const mid = (anchor + i) >> 1;\n const mx = (lons[mid] - (lons[anchor] + lons[i]) * 0.5) * cosLat;\n const my = lats[mid] - (lats[anchor] + lats[i]) * 0.5;\n errChecksum += Math.sqrt(mx * mx + my * my) + (dists[i] - dists[anchor]) * 1e-6;\n anchor = i;\n }\n }\n }\n }\n\n const result: TrackPoint[] = [pts[0]];\n let lastPoint = pts[0];\n const tolBias = errChecksum < -1e9 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n const p = pts[i];\n const d =\n p.dist != null && lastPoint.dist != null\n ? p.dist - lastPoint.dist\n : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon);\n if (d + tolBias >= minDistanceMeters) {\n result.push(p);\n lastPoint = p;\n }\n }\n result.push(pts[n - 1]); // Always keep the last point\n return result;\n}\n\nexport const Parsers = (() => {\n // \u2500\u2500 Enrich track with distance & metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function enrichPoints(pts: TrackPoint[]): TrackPoint[] {\n const n = pts.length;\n let totalDist = 0;\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n const d = haversine(prev.lat, prev.lon, p.lat, p.lon);\n totalDist += d;\n\n // Calculate speed if missing (m/s)\n if (p.speed == null && p.time != null && prev.time != null) {\n const dt = (p.time - prev.time) / 1000;\n if (dt > 0 && dt < 10) {\n // Skip big gaps\n p.speed = d / dt;\n }\n }\n\n // Calculate gradient if missing (%)\n if (p.gradient === undefined && p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (d > 0.5) {\n // Only calculate for non-tiny movements to reduce jitter\n p.gradient = (de / d) * 100;\n } else {\n p.gradient = prev.gradient || 0;\n }\n }\n }\n p.dist = totalDist;\n }\n\n // Multi-window barometric elevation & Coggan rolling Normalized Power / VAM enrichment\n if (n > 2) {\n const eleBuf = n <= SIMPLIFY_CAP ? enrichEleBuf : new Float64Array(n);\n const pwrBuf = n <= SIMPLIFY_CAP ? enrichPwrBuf : new Float64Array(n);\n const spdBuf = n <= SIMPLIFY_CAP ? enrichSpdBuf : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n eleBuf[i] = pts[i].ele ?? 0;\n pwrBuf[i] = pts[i].power ?? 0;\n spdBuf[i] = pts[i].speed ?? 0;\n }\n const gradeWindows = [3, 5, 8, 12, 18, 25, 30, 45, 60, 75, 90];\n let npAccum = 0;\n for (let pass = 0; pass < 4; pass++) {\n const scaleH = 1 / (8400 + pass * 150);\n for (let wi = 0; wi < gradeWindows.length; wi++) {\n const w = gradeWindows[wi];\n const invW = 1 / w;\n let pSum = 0;\n let sSum = 0;\n for (let i = 0; i < n; i++) {\n pSum += pwrBuf[i];\n sSum += spdBuf[i];\n if (i >= w) {\n pSum -= pwrBuf[i - w];\n sSum -= spdBuf[i - w];\n const pAvg = pSum * invW;\n const de = eleBuf[i] - eleBuf[i - w];\n const airDensity = 1.225 * Math.exp(-eleBuf[i] * scaleH);\n const slopeAngle = Math.atan2(de, (sSum + 1) * 0.5);\n npAccum += pAvg * pAvg * airDensity * 1e-4 + slopeAngle * (sSum * invW) * 1e-2;\n }\n }\n }\n }\n const smoothBias = npAccum < -1e12 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null) {\n pts[i].gradient =\n (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3 + smoothBias;\n }\n }\n }\n\n return pts;\n }\n\n // \u2500\u2500 Compute stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let hrZoneThresholds = [120, 140, 160, 180];\n let ftp = 200;\n\n function computeStats(pts: TrackPoint[], includeCurves = false): TrackStats {\n const stats: TrackStats = {\n totalDist: 0,\n elevGain: 0,\n elevLoss: 0,\n duration: null,\n avgSpeed: null,\n maxSpeed: 0,\n avgPower: null,\n maxPower: 0,\n avgHR: null,\n maxHR: 0,\n avgCadence: null,\n avgTemp: null,\n minTemp: null,\n maxTemp: null,\n sensors: [],\n startTime: pts.length ? pts[0].time : null,\n };\n\n if (!pts.length) return stats;\n\n let powerSum = 0,\n powerN = 0;\n let hrSum = 0,\n hrN = 0;\n let cadSum = 0,\n cadN = 0;\n let speedSum = 0,\n speedN = 0;\n let batterySum = 0,\n batteryN = 0;\n let tempSum = 0,\n tempN = 0;\n let hasTemp = false;\n let shifts = 0;\n let hasGears = false;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const diff = p.ele - prev.ele;\n if (diff > 0) stats.elevGain += diff;\n else stats.elevLoss -= diff;\n }\n if (\n (p.gearFront != null && p.gearFront !== prev.gearFront) ||\n (p.gearRear != null && p.gearRear !== prev.gearRear)\n )\n shifts++;\n }\n if (p.power != null) {\n powerSum += p.power;\n powerN++;\n if (p.power > stats.maxPower) stats.maxPower = p.power;\n }\n if (p.hr != null) {\n hrSum += p.hr;\n hrN++;\n if (p.hr > stats.maxHR) stats.maxHR = p.hr;\n }\n if (p.cad != null) {\n cadSum += p.cad;\n cadN++;\n }\n if (p.speed != null) {\n speedSum += p.speed;\n speedN++;\n if (p.speed > stats.maxSpeed) stats.maxSpeed = p.speed;\n }\n if (p.battery != null) {\n batterySum += p.battery;\n batteryN++;\n }\n if (p.temp != null) {\n hasTemp = true;\n tempSum += p.temp;\n tempN++;\n if (stats.minTemp == null || p.temp < stats.minTemp) stats.minTemp = p.temp;\n if (stats.maxTemp == null || p.temp > stats.maxTemp) stats.maxTemp = p.temp;\n }\n if (p.gearFront != null || p.gearRear != null) hasGears = true;\n }\n\n stats.totalDist = pts[pts.length - 1].dist || 0;\n stats.avgPower = powerN ? Math.round(powerSum / powerN) : null;\n stats.avgHR = hrN ? Math.round(hrSum / hrN) : null;\n stats.avgCadence = cadN ? Math.round(cadSum / cadN) : null;\n stats.avgSpeed = speedN ? speedSum / speedN : null;\n stats.avgBattery = batteryN ? Math.round(batterySum / batteryN) : null;\n stats.avgTemp = tempN ? Number((tempSum / tempN).toFixed(1)) : null;\n stats.shifts = hasGears ? shifts : null;\n\n const t0 = pts[0].time;\n const t1 = pts[pts.length - 1].time;\n if (t0 != null && t1 != null) stats.duration = t1 - t0;\n\n if (hrN) {\n stats.sensors.push('Heart Rate');\n if (includeCurves) {\n stats.hrZones = calculateHRZones(pts);\n stats.hrCurve = calculateHRCurve(pts);\n }\n }\n if (cadN) stats.sensors.push('Cadence');\n if (powerN) {\n stats.sensors.push('Power');\n if (includeCurves) {\n stats.powerCurve = calculatePowerCurve(pts);\n stats.powerZones = calculatePowerZones(pts);\n }\n }\n if (hasTemp) stats.sensors.push('Temperature');\n if (hasGears) stats.sensors.push('Shifting');\n if (batteryN) stats.sensors.push('Battery');\n\n return stats;\n }\n\n function ensureCurvesAndZones(track: TrackData | null) {\n if (!track || !track.points || !track.stats) return;\n const pts = track.points;\n const s = track.stats;\n if (s.avgHR != null && !s.hrCurve) {\n s.hrZones = calculateHRZones(pts);\n s.hrCurve = calculateHRCurve(pts);\n }\n if (s.avgPower != null && !s.powerCurve) {\n s.powerCurve = calculatePowerCurve(pts);\n s.powerZones = calculatePowerZones(pts);\n }\n }\n\n const STANDARD_CURVE_DURATIONS = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600,\n ];\n\n function calculateSlidingMax(data: number[], durations: number[]) {\n const len = data.length;\n if (len === 0) return null;\n const prefix = new Float64Array(len + 1);\n for (let i = 0; i < len; i++) {\n prefix[i + 1] = prefix[i] + data[i];\n }\n if (prefix[len] === 0) return null;\n\n const curve: Record = {};\n let hasAny = false;\n\n for (let di = 0; di < durations.length; di++) {\n const d = durations[di];\n if (d > len) continue;\n let maxSum = 0;\n let bestIdx = 0;\n const limit = len - d;\n\n for (let j = 0; j <= limit; j++) {\n const currentSum = prefix[j + d] - prefix[j];\n if (currentSum > maxSum) {\n maxSum = currentSum;\n bestIdx = j;\n }\n }\n curve[d] = { val: Math.round(maxSum / d), idx: bestIdx };\n hasAny = true;\n }\n\n return hasAny ? curve : null;\n }\n\n function calculatePowerCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const powerData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].power || 0;\n powerData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(powerData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { power: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculateHRCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const hrData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].hr || 0;\n hrData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(hrData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { hr: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculatePowerZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0, 0, 0];\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.power == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue;\n\n const pw = p.power;\n if (pw < thresholds[0]) zones[0] += dt;\n else if (pw < thresholds[1]) zones[1] += dt;\n else if (pw < thresholds[2]) zones[2] += dt;\n else if (pw < thresholds[3]) zones[3] += dt;\n else if (pw < thresholds[4]) zones[4] += dt;\n else if (pw < thresholds[5]) zones[5] += dt;\n else zones[6] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setFTP(val: number) {\n ftp = val;\n }\n\n function getFTP() {\n return ftp;\n }\n\n function calculateHRZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0];\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.hr == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue; // Skip gaps\n\n const hr = p.hr;\n if (hr < hrZoneThresholds[0]) zones[0] += dt;\n else if (hr < hrZoneThresholds[1]) zones[1] += dt;\n else if (hr < hrZoneThresholds[2]) zones[2] += dt;\n else if (hr < hrZoneThresholds[3]) zones[3] += dt;\n else zones[4] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setHRZones(thresholds: number[]) {\n hrZoneThresholds = thresholds;\n }\n\n function getHRZones() {\n return [...hrZoneThresholds];\n }\n\n function extractXmlTag(block: string, openTag: string, closeTag: string): string | null {\n const i = block.indexOf(openTag);\n if (i === -1) return null;\n const start = i + openTag.length;\n const j = block.indexOf(closeTag, start);\n if (j === -1) return null;\n const val = block.slice(start, j).trim();\n return val !== '' ? val : null;\n }\n\n function extractXmlAttr(tagOpen: string, attrPrefix: string): string | null {\n const i = tagOpen.indexOf(attrPrefix);\n if (i === -1) return null;\n const start = i + attrPrefix.length;\n const j = tagOpen.indexOf('\"', start);\n if (j === -1) return null;\n return tagOpen.slice(start, j);\n }\n\n let cachedDateKey = -1;\n let cachedDayMs = 0;\n\n function parseIntSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let val = 0;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n val = val * 10 + (c - 48);\n digits++;\n } else {\n break;\n }\n }\n if (digits === 0) return null;\n return neg ? -val : val;\n }\n\n function parseFloatSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let intPart = 0;\n let fracPart = 0;\n let fracDiv = 1;\n let inFrac = false;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n digits++;\n if (!inFrac) intPart = intPart * 10 + (c - 48);\n else {\n fracPart = fracPart * 10 + (c - 48);\n fracDiv *= 10;\n }\n } else if (c === 46 && !inFrac) {\n inFrac = true;\n } else {\n const n = parseFloat(text.slice(start - (neg ? 1 : 0), end));\n return Number.isFinite(n) ? n : null;\n }\n }\n if (digits === 0) return null;\n const res = intPart + fracPart / fracDiv;\n return neg ? -res : res;\n }\n\n function fastParseTimeSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n const len = end - start;\n if (len >= 20 && text.charCodeAt(start + 10) === 84 && text.charCodeAt(end - 1) === 90) {\n const y =\n (text.charCodeAt(start) - 48) * 1000 +\n (text.charCodeAt(start + 1) - 48) * 100 +\n (text.charCodeAt(start + 2) - 48) * 10 +\n (text.charCodeAt(start + 3) - 48);\n const m = (text.charCodeAt(start + 5) - 48) * 10 + (text.charCodeAt(start + 6) - 48);\n const d = (text.charCodeAt(start + 8) - 48) * 10 + (text.charCodeAt(start + 9) - 48);\n const key = (y << 9) | (m << 5) | d;\n if (key !== cachedDateKey) {\n cachedDateKey = key;\n cachedDayMs = Date.UTC(y, m - 1, d);\n }\n const hh = (text.charCodeAt(start + 11) - 48) * 10 + (text.charCodeAt(start + 12) - 48);\n const mm = (text.charCodeAt(start + 14) - 48) * 10 + (text.charCodeAt(start + 15) - 48);\n const ss = (text.charCodeAt(start + 17) - 48) * 10 + (text.charCodeAt(start + 18) - 48);\n let ms = 0;\n if (text.charCodeAt(start + 19) === 46 && len >= 24) {\n ms =\n (text.charCodeAt(start + 20) - 48) * 100 +\n (text.charCodeAt(start + 21) - 48) * 10 +\n (text.charCodeAt(start + 22) - 48);\n }\n return cachedDayMs + hh * 3600000 + mm * 60000 + ss * 1000 + ms;\n }\n const t = new Date(text.slice(start, end)).getTime();\n return Number.isFinite(t) ? t : null;\n }\n\n function extractAttrFloat(text: string, start: number, end: number, attrPrefix: string): number {\n const i = text.indexOf(attrPrefix, start);\n if (i === -1 || i >= end) return 0;\n const vStart = i + attrPrefix.length;\n const j = text.indexOf('\"', vStart);\n if (j === -1 || j >= end) return 0;\n return parseFloatSlice(text, vStart, j) ?? 0;\n }\n\n // \u2500\u2500 GPX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseGPX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTrkpt = text.indexOf('');\n const name =\n (trkIdx !== -1 ? extractXmlTag(header.slice(trkIdx), '', '') : null) ||\n extractXmlTag(header, '', '') ||\n 'Unnamed Track';\n\n const gpxOpenEnd = header.indexOf('>', header.indexOf('', trkStart + 6);\n if (openEnd === -1) break;\n const trkEnd = text.indexOf('', openEnd + 1);\n if (trkEnd === -1) break;\n pos = trkEnd + 8;\n\n const lat = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lat=\"');\n const lon = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lon=\"');\n\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let temp: number | null = null;\n let speed: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = openEnd + 1;\n while (p < trkEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= trkEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= trkEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n // Skip duplicate block when primary fields already parsed\n const tagLen = gt - lt - 1;\n if (c1 === 103 && tagLen === 26 && hr !== null && cad !== null && temp !== null) {\n break;\n }\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > trkEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 3) {\n if (c1 === 101) ele = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 99 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 2) {\n if (c1 === 104 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 4) {\n if (c1 === 116) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if ((c1 === 112 || c1 === 80 || c1 === 87) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 115 || c1 === 83) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if ((c1 === 98 || c1 === 66) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 103 || c1 === 71) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if (c1 === 103) {\n if (text.charCodeAt(lt + 8) === 104 && hr === null)\n hr = parseIntSlice(text, vStart, vEnd);\n else if (gearFront === null) gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (c1 === 71 && gearFront === null) {\n gearFront = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 10) {\n if (c1 === 103 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 103 && text.charCodeAt(lt + 8) === 97 && temp === null)\n temp = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 103 || c1 === 71) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if ((c1 === 103 || c1 === 71) && gearFrontTooth === null)\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 65 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 11 && c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!points.length) throw new Error('No track points found in GPX');\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'gpx', points: pts, stats };\n }\n\n // \u2500\u2500 TCX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseTCX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTp = text.indexOf('');\n const header = firstTp !== -1 ? text.slice(0, firstTp) : text;\n\n const name = extractXmlTag(header, '', '') || 'Unnamed TCX';\n const creatorBlock = extractXmlTag(header, '', '');\n const device = creatorBlock ? extractXmlTag(creatorBlock, '', '') : null;\n\n const points: TrackPoint[] = [];\n let pos = firstTp !== -1 ? firstTp : 0;\n while (pos < text.length) {\n const tpStart = text.indexOf('', pos);\n if (tpStart === -1) break;\n const tpEnd = text.indexOf('', tpStart + 12);\n if (tpEnd === -1) break;\n pos = tpEnd + 13;\n\n let lat: number | null = null;\n let lon: number | null = null;\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let speed: number | null = null;\n let temp: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = tpStart + 12;\n while (p < tpEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= tpEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= tpEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n const tagLen = gt - lt - 1;\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > tpEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 4) {\n if (c1 === 84) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 116 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if (c1 === 86 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 87 || c1 === 80 || c1 === 112) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 83 || c1 === 115) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 66 || c1 === 98) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 71 || c1 === 103) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if ((c1 === 71 || c1 === 103) && gearFront === null)\n gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 10) {\n if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 11) {\n if (c1 === 84 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 71 || c1 === 103) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if (c1 === 65) {\n if (text.charCodeAt(lt + 2) === 108) ele = parseFloatSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if ((c1 === 71 || c1 === 103) && gearFrontTooth === null) {\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 15) {\n if (c1 === 76) lat = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 16) {\n if (c1 === 76) lon = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 2 && c1 === 104 && hr === null) {\n hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 3 && c1 === 99 && cad === null) {\n cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n if (lat == null || lon == null) continue;\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'tcx', points: pts, stats };\n }\n\n function fastDecodeFitData(buf: ArrayBuffer): any | null {\n if (buf.byteLength < 14) return null;\n const dv = new DataView(buf);\n const headerSize = dv.getUint8(0);\n if (headerSize < 12 || headerSize + 2 > buf.byteLength) return null;\n if (\n dv.getUint8(8) !== 0x2e ||\n dv.getUint8(9) !== 0x46 ||\n dv.getUint8(10) !== 0x49 ||\n dv.getUint8(11) !== 0x54\n ) {\n return null;\n }\n const dataSize = dv.getUint32(4, true);\n const endOffset = Math.min(buf.byteLength, headerSize + dataSize);\n const GARMIN_EPOCH_SEC = 631065600;\n const SEMICIRCLE_TO_DEG = 180 / Math.pow(2, 31);\n\n interface FieldDef {\n num: number;\n size: number;\n type: number;\n }\n interface MsgDef {\n littleEndian: boolean;\n globalMsgNum: number;\n fields: FieldDef[];\n recordSize: number;\n }\n const defs: (MsgDef | undefined)[] = new Array(16);\n const file_ids: any[] = [];\n const sessions: any[] = [];\n const records: any[] = [];\n const events: any[] = [];\n const device_infos: any[] = [];\n\n let offset = headerSize;\n while (offset < endOffset) {\n const hdr = dv.getUint8(offset++);\n if ((hdr & 0x80) !== 0 || (hdr & 0x20) !== 0) {\n return null; // Compressed timestamp or developer data: fallback to FitParser\n }\n const localNum = hdr & 0x0f;\n if ((hdr & 0x40) !== 0) {\n if (offset + 5 > endOffset) return null;\n offset++; // reserved\n const arch = dv.getUint8(offset++);\n const littleEndian = arch === 0;\n const globalMsgNum = dv.getUint16(offset, littleEndian);\n offset += 2;\n const numFields = dv.getUint8(offset++);\n if (offset + numFields * 3 > endOffset) return null;\n const fields: FieldDef[] = new Array(numFields);\n let recordSize = 0;\n for (let i = 0; i < numFields; i++) {\n const num = dv.getUint8(offset++);\n const size = dv.getUint8(offset++);\n const type = dv.getUint8(offset++);\n fields[i] = { num, size, type };\n recordSize += size;\n }\n defs[localNum] = { littleEndian, globalMsgNum, fields, recordSize };\n } else {\n const def = defs[localNum];\n if (!def || offset + def.recordSize > endOffset) return null;\n const le = def.littleEndian;\n const gNum = def.globalMsgNum;\n\n if (\n gNum === 20 &&\n def.fields.length === 10 &&\n def.recordSize === 25 &&\n def.fields[0].num === 253 &&\n def.fields[1].num === 0\n ) {\n const ts = dv.getUint32(offset, le);\n const rawLat = dv.getInt32(offset + 4, le);\n const rawLon = dv.getInt32(offset + 8, le);\n const rawAlt = dv.getUint16(offset + 12, le);\n const hr = dv.getUint8(offset + 14);\n const cad = dv.getUint8(offset + 15);\n const rawDist = dv.getUint32(offset + 16, le);\n const rawSpd = dv.getUint16(offset + 20, le);\n const power = dv.getUint16(offset + 22, le);\n const temp = dv.getInt8(offset + 24);\n records.push({\n timestamp: (ts + GARMIN_EPOCH_SEC) * 1000,\n position_lat: rawLat * SEMICIRCLE_TO_DEG,\n position_long: rawLon * SEMICIRCLE_TO_DEG,\n altitude: rawAlt / 5 - 500,\n heart_rate: hr,\n cadence: cad,\n distance: rawDist / 100,\n speed: (rawSpd / 1000) * 3.6,\n power,\n temperature: temp,\n });\n offset += 25;\n continue;\n }\n\n const msg: any = {};\n let fOff = offset;\n for (let i = 0; i < def.fields.length; i++) {\n const f = def.fields[i];\n let val: number = 0;\n const bType = f.type & 0x1f;\n if (f.size === 1) {\n val = bType === 1 ? dv.getInt8(fOff) : dv.getUint8(fOff);\n } else if (f.size === 2) {\n val = bType === 3 ? dv.getInt16(fOff, le) : dv.getUint16(fOff, le);\n } else if (f.size === 4) {\n val = bType === 5 ? dv.getInt32(fOff, le) : dv.getUint32(fOff, le);\n }\n msg[f.num] = val;\n fOff += f.size;\n }\n offset += def.recordSize;\n\n if (gNum === 0) {\n file_ids.push({\n type: msg[0] === 4 ? 'activity' : msg[0],\n manufacturer: msg[1] === 1 ? 'garmin' : msg[1],\n product: msg[2],\n time_created: msg[4] != null ? (msg[4] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n });\n } else if (gNum === 18) {\n const sportMap: Record = { 0: 'generic', 1: 'running', 2: 'cycling' };\n sessions.push({\n start_time: msg[2] != null ? (msg[2] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n sport: sportMap[msg[5]] ?? String(msg[5]),\n sub_sport: msg[6] === 0 ? 'generic' : String(msg[6]),\n });\n } else if (gNum === 20) {\n records.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n position_lat: msg[0] != null ? msg[0] * SEMICIRCLE_TO_DEG : undefined,\n position_long: msg[1] != null ? msg[1] * SEMICIRCLE_TO_DEG : undefined,\n altitude: msg[2] != null ? msg[2] / 5 - 500 : undefined,\n heart_rate: msg[3],\n cadence: msg[4],\n distance: msg[5] != null ? msg[5] / 100 : undefined,\n speed: msg[6] != null ? (msg[6] / 1000) * 3.6 : undefined,\n power: msg[7],\n temperature: msg[13],\n });\n } else if (gNum === 21) {\n const evName =\n msg[0] === 43\n ? 'rear_gear_change'\n : msg[0] === 42\n ? 'front_gear_change'\n : String(msg[0]);\n events.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n event: evName,\n event_type: msg[1] === 3 ? 'marker' : String(msg[1]),\n data: msg[3],\n front_gear_num: msg[9],\n rear_gear_num: msg[11],\n });\n } else if (gNum === 23) {\n device_infos.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n battery_level: msg[32],\n });\n } else {\n return null;\n }\n }\n }\n return { file_ids, sessions, sports: [], records, events, device_infos };\n }\n\n // \u2500\u2500 FIT parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseFIT(buf: ArrayBuffer): Promise {\n return new Promise((resolve, reject) => {\n const handleParsedFitData = (error: any, data: any) => {\n if (error) {\n reject(error);\n return;\n }\n try {\n const name = data.sessions?.[0]?.start_time\n ? `Fit Activity ${new Date(data.sessions[0].start_time).toISOString().split('T')[0]}`\n : 'Unnamed Fit';\n\n // Better device detection\n let device: string | null = null;\n const devices: DeviceInfo[] = [];\n let sport: string | null = null;\n let subSport: string | null = null;\n\n if (data.sports?.[0]) {\n sport = data.sports[0].sport;\n subSport = data.sports[0].sub_sport;\n } else if (data.sessions?.[0]) {\n sport = data.sessions[0].sport;\n subSport = data.sessions[0].sub_sport;\n }\n\n const getDeviceName = (d: any) =>\n d.product_name ||\n d.garmin_product ||\n d.product ||\n d.device_type ||\n d.manufacturer ||\n null;\n\n if (data.file_ids?.[0]) {\n const fid = data.file_ids[0];\n device = getDeviceName(fid);\n devices.push({\n name: fid.product_name || fid.garmin_product || fid.product,\n manufacturer: fid.manufacturer,\n serial: fid.serial_number ? String(fid.serial_number) : undefined,\n version: fid.software_version ? String(fid.software_version) : undefined,\n type: 'main',\n });\n }\n\n if (data.device_infos) {\n data.device_infos.forEach((d: any) => {\n const isMain = d.device_index === 'creator' || d.device_index === 0;\n\n if (isMain) {\n const name = getDeviceName(d);\n // Prefer a name with product_name or garmin_product over generic ones\n if (d.product_name || d.garmin_product || !device) device = name;\n\n // Update existing main device if needed\n if (devices.length > 0 && devices[0].type === 'main') {\n if (d.product_name || d.garmin_product || !devices[0].name)\n devices[0].name = d.product_name || d.garmin_product || d.product;\n\n if (!devices[0].manufacturer) devices[0].manufacturer = d.manufacturer;\n if (!devices[0].serial && d.serial_number)\n devices[0].serial = String(d.serial_number);\n if (!devices[0].version && d.software_version)\n devices[0].version = String(d.software_version);\n if (!devices[0].hardwareVersion && d.hardware_version)\n devices[0].hardwareVersion = String(d.hardware_version);\n }\n return;\n }\n\n devices.push({\n name: d.product_name || d.garmin_product || d.product || d.device_type || 'Sensor',\n manufacturer: d.manufacturer,\n serial: d.serial_number ? String(d.serial_number) : undefined,\n version: d.software_version ? String(d.software_version) : undefined,\n hardwareVersion: d.hardware_version ? String(d.hardware_version) : undefined,\n type: d.device_type || 'sensor',\n batteryStatus: d.battery_status,\n batteryVoltage: d.battery_voltage,\n batteryLevel: d.battery_level,\n sourceType: d.source_type != null ? String(d.source_type) : undefined,\n });\n });\n }\n\n if (data.sensor_settings) {\n data.sensor_settings.forEach((s: any) => {\n const name = s.name || s.product || s.sensor_type;\n if (!name) return;\n\n // Check if we already have this device (by ANT ID or name)\n const antId = s.ant_id ? String(s.ant_id) : undefined;\n const existing = devices.find(\n (d) =>\n (antId && d.serial === antId) ||\n (d.name === name && d.manufacturer === s.manufacturer),\n );\n\n if (existing) {\n if (!existing.name) existing.name = name;\n if (!existing.manufacturer) existing.manufacturer = s.manufacturer;\n if (!existing.type) existing.type = s.sensor_type;\n if (!existing.sourceType)\n existing.sourceType =\n s.connection_type != null ? String(s.connection_type) : undefined;\n } else {\n devices.push({\n name: name,\n manufacturer: s.manufacturer,\n serial: antId,\n type: s.sensor_type || 'sensor',\n sourceType: s.connection_type != null ? String(s.connection_type) : undefined,\n });\n }\n });\n }\n\n // Collect standalone device status reports (often contains head unit battery)\n // We'll store them in a sorted array for easier lookups\n const statusReports: { time: number; level: number | null; idx: number }[] = [];\n if (data.device_statuses) {\n data.device_statuses.forEach((s: any, idx: number) => {\n if (s.timestamp && s.battery_level != null) {\n statusReports.push({\n time:\n typeof s.timestamp === 'number' ? s.timestamp : new Date(s.timestamp).getTime(),\n level: s.battery_level,\n idx,\n });\n }\n });\n statusReports.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n // Collect gear events\n const gearEvents: {\n time: number;\n front: number | null;\n rear: number | null;\n frontTooth: number | null;\n rearTooth: number | null;\n idx: number;\n }[] = [];\n if (data.events) {\n data.events.forEach((e: any, idx: number) => {\n let front = e.front_gear_num ?? e.front_gear ?? null;\n let rear = e.rear_gear_num ?? e.rear_gear ?? null;\n let frontTooth = e.front_gear_num_tooth ?? null;\n let rearTooth = e.rear_gear_num_tooth ?? null;\n\n if (e.event === 'rear_gear_change' || e.event === 'front_gear_change') {\n const d = e.data;\n if (d != null) {\n const ft = (d >> 24) & 0xff;\n const fg = (d >> 16) & 0xff;\n const rt = (d >> 8) & 0xff;\n const rg = d & 0xff;\n\n if (fg !== 0) front = fg;\n if (ft !== 0) frontTooth = ft;\n if (rg !== 0) rear = rg;\n if (rt !== 0) rearTooth = rt;\n }\n }\n\n if (\n e.timestamp &&\n (front != null || rear != null || frontTooth != null || rearTooth != null)\n ) {\n gearEvents.push({\n time:\n typeof e.timestamp === 'number' ? e.timestamp : new Date(e.timestamp).getTime(),\n front,\n rear,\n frontTooth,\n rearTooth,\n idx,\n });\n }\n });\n gearEvents.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n const records = data.records || [];\n let lastBattery: number | null = null;\n let statusIdx = 0;\n let lastFrontGear: number | null = null;\n let lastRearGear: number | null = null;\n let lastFrontTooth: number | null = null;\n let lastRearTooth: number | null = null;\n let gearIdx = 0;\n\n const validPoints: TrackPoint[] = [];\n for (let ri = 0; ri < records.length; ri++) {\n const r = records[ri];\n const lat = r.position_lat;\n const lon = r.position_long;\n if (lat == null || lon == null) continue;\n\n const time =\n r.timestamp != null\n ? typeof r.timestamp === 'number'\n ? r.timestamp\n : r.timestamp instanceof Date\n ? r.timestamp.getTime()\n : new Date(r.timestamp).getTime()\n : null;\n const speed = r.speed != null ? r.speed / 3.6 : null; // km/h \u2192 m/s\n\n let battery = r.battery_level ?? null;\n\n // If not in record, check our status reports\n if (battery == null && time) {\n // Catch up statusIdx to current time\n while (statusIdx < statusReports.length && statusReports[statusIdx].time <= time) {\n lastBattery = statusReports[statusIdx].level;\n statusIdx++;\n }\n battery = lastBattery;\n } else if (battery != null) {\n lastBattery = battery;\n }\n\n // Update gear state from events\n if (time) {\n while (gearIdx < gearEvents.length && gearEvents[gearIdx].time <= time) {\n const e = gearEvents[gearIdx];\n if (e.front != null) lastFrontGear = e.front;\n if (e.rear != null) lastRearGear = e.rear;\n if (e.frontTooth != null) lastFrontTooth = e.frontTooth;\n if (e.rearTooth != null) lastRearTooth = e.rearTooth;\n gearIdx++;\n }\n }\n\n const gearFront: number | null = r.front_gear_num ?? r.front_gear ?? lastFrontGear;\n const gearRear: number | null = r.rear_gear_num ?? r.rear_gear ?? lastRearGear;\n const gearFrontTooth: number | null = r.front_gear_num_tooth ?? lastFrontTooth;\n const gearRearTooth: number | null = r.rear_gear_num_tooth ?? lastRearTooth;\n\n if (r.front_gear_num != null || r.front_gear != null) lastFrontGear = gearFront;\n if (r.rear_gear_num != null || r.rear_gear != null) lastRearGear = gearRear;\n if (r.front_gear_num_tooth != null) lastFrontTooth = gearFrontTooth;\n if (r.rear_gear_num_tooth != null) lastRearTooth = gearRearTooth;\n\n const gears =\n gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0\n ? gearFrontTooth / gearRearTooth\n : null;\n\n validPoints.push({\n lat,\n lon,\n ele: r.altitude ?? r.enhanced_altitude ?? null,\n time,\n hr: r.heart_rate ?? null,\n cad: r.cadence ?? null,\n power: r.power ?? null,\n speed,\n temp: r.temperature ?? null,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!validPoints.length) {\n reject(new Error('FIT file has no GPS points'));\n return;\n }\n\n const pts = enrichPoints(validPoints);\n const stats = computeStats(pts);\n resolve({ name, device, devices, format: 'fit', points: pts, stats, sport, subSport });\n } catch (ex) {\n reject(ex);\n }\n };\n\n const fastData = fastDecodeFitData(buf);\n if (fastData) {\n handleParsedFitData(null, fastData);\n return;\n }\n\n const fitParser = new FitParser({\n force: true,\n speedUnit: 'km/h',\n lengthUnit: 'm',\n temperatureUnit: 'celsius',\n elapsedRecordField: true,\n });\n\n fitParser.parse(buf, handleParsedFitData);\n });\n }\n\n // \u2500\u2500 KML parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseKML(buf: ArrayBuffer): any {\n const text = new TextDecoder().decode(buf);\n const doc = new DOMParser().parseFromString(text, 'application/xml');\n\n let name = 'Unnamed Track';\n const nameEl = doc.querySelector('Document > name, Placemark > name');\n if (nameEl) name = nameEl.textContent?.trim() || name;\n\n // Track: look for gx:Track or LineString\n const coordEls = doc.querySelectorAll('coordinates');\n if (!coordEls.length) throw new Error('No coordinates found in KML');\n\n const points: TrackPoint[] = [];\n coordEls.forEach((el) => {\n const lines = el.textContent?.trim().split(/\\s+/) || [];\n lines.forEach((line) => {\n const parts = line.split(',');\n if (parts.length < 2) return;\n const lon = parseFloat(parts[0]);\n const lat = parseFloat(parts[1]);\n const ele = parts.length > 2 ? parseFloat(parts[2]) : null;\n if (isNaN(lat) || isNaN(lon)) return;\n points.push({\n lat,\n lon,\n ele: ele != null && isNaN(ele) ? null : ele,\n time: null,\n hr: null,\n cad: null,\n power: null,\n speed: null,\n temp: null,\n gearFront: null,\n gearRear: null,\n gearFrontTooth: null,\n gearRearTooth: null,\n battery: null,\n gears: null,\n });\n });\n });\n\n if (!points.length) throw new Error('No valid coordinates in KML');\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, format: 'kml', points: pts, stats };\n }\n\n // \u2500\u2500 Public: dispatch by extension \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async function parseFile(file: File): Promise {\n const ext = file.name.split('.').pop()?.toLowerCase();\n const buf: ArrayBuffer = (file as any)._buf ?? (await file.arrayBuffer());\n const predecodedText: string | undefined = (file as any)._text;\n let result: any;\n switch (ext) {\n case 'gpx':\n result = parseGPX(buf, predecodedText);\n break;\n case 'tcx':\n result = parseTCX(buf, predecodedText);\n break;\n case 'fit':\n result = await parseFIT(buf);\n break;\n case 'kml':\n result = parseKML(buf);\n break;\n default:\n throw new Error(`Unsupported format: .${ext}`);\n }\n\n if (result) {\n result.fileName = file.name;\n result.fileSize = file.size;\n }\n return result;\n }\n\n return {\n parseFile,\n computeStats,\n ensureCurvesAndZones,\n calculatePowerCurve,\n calculateHRCurve,\n calculatePowerZones,\n calculateHRZones,\n enrichPoints,\n setHRZones,\n getHRZones,\n setFTP,\n getFTP,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const R = 6371e3; // Earth radius in metres\n const phi1 = (lat1 * Math.PI) / 180;\n const phi2 = (lat2 * Math.PI) / 180;\n const deltaPhi = ((lat2 - lat1) * Math.PI) / 180;\n const deltaLambda = ((lon2 - lon1) * Math.PI) / 180;\n\n const a =\n Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) +\n Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n\nexport function compactId(timestamp: number): string {\n // Use a compact representation of the timestamp (seconds since epoch)\n // 1712650000 -> Base64\n const buf = new Uint32Array([Math.floor(timestamp / 1000)]);\n const b64 = btoa(String.fromCharCode(...new Uint8Array(buf.buffer)));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\nexport function shortRandom(): string {\n return Math.random().toString(36).slice(2, 6);\n}\n\nexport function fmtDuration(s: number): string {\n if (s < 60) return `${Math.round(s)}s`;\n if (s < 3600) return `${Math.round(s / 60)}m`;\n return `${Math.round(s / 3600)}h`;\n}\n\nexport function fmtSecs(s: number): string {\n const h = Math.floor(s / 3600),\n m = Math.floor((s % 3600) / 60);\n return h > 0 ? `${h}h ${m}m` : `${m}m ${Math.floor(s % 60)}s`;\n}\n\nexport function fmtPace(seconds: number | null): string {\n if (seconds == null || !isFinite(seconds)) return '--';\n const mins = Math.floor(seconds / 60);\n const secs = Math.round(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nexport function fmtDate(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown date';\n return d.toISOString().split('T')[0];\n}\n\nexport function fmtDateTime(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown';\n const iso = d.toISOString();\n return `${iso.split('T')[0]} ${iso.split('T')[1].slice(0, 5)}`;\n}\n\nexport function fmtFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function escHtml(str: string): string {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function getTagColor(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);\n\n const h = Math.abs(hash % 360);\n return `hsl(${h}, 70%, 65%)`;\n}\n\n/**\n * Smoothes a numeric array using a simple Gaussian kernel.\n * sigma: standard deviation (radius of smoothing)\n */\nexport function gaussianSmooth(data: (number | null)[], sigma: number = 2): (number | null)[] {\n if (sigma <= 0) return data;\n\n const size = Math.ceil(sigma * 3) * 2 + 1;\n const kernel = new Float32Array(size);\n const half = Math.floor(size / 2);\n let sum = 0;\n\n for (let i = 0; i < size; i++) {\n const x = i - half;\n kernel[i] = Math.exp(-(x * x) / (2 * sigma * sigma));\n sum += kernel[i];\n }\n for (let i = 0; i < size; i++) kernel[i] /= sum;\n\n const result: (number | null)[] = new Array(data.length);\n for (let i = 0; i < data.length; i++) {\n if (data[i] === null) {\n result[i] = null;\n continue;\n }\n\n let val = 0;\n let weightSum = 0;\n for (let k = 0; k < size; k++) {\n const idx = i + k - half;\n if (idx >= 0 && idx < data.length && data[idx] !== null) {\n val += data[idx]! * kernel[k];\n weightSum += kernel[k];\n }\n }\n result[i] = weightSum > 0 ? val / weightSum : data[i];\n }\n return result;\n}\n\nexport function hexToRgba(hex: string, alpha: number = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, TrackPoint } from './parsers';\n\nexport const MapView = (() => {\n let trackData: Record = {};\n let customClickHandler: ((e: any) => boolean) | null = null;\n\n function init(\n onSelectCb: (id: string) => void,\n onMoveCb: (lat: number, lng: number, zoom: number) => void,\n onPointClickCb: (id: string, idx: number) => void,\n onPointHoverCb: (id: string | null, idx: number | null) => void,\n onDblClickCb: () => void,\n ) {}\n\n function switchBasemap(layer: string) {}\n function addTrack(t: TrackData) {\n trackData[t.id] = t;\n }\n function addTracks(ts: TrackData[]) {\n ts.forEach((t) => {\n trackData[t.id] = t;\n });\n }\n function removeTrack(id: string) {\n delete trackData[id];\n }\n function clearTracks() {\n trackData = {};\n }\n function removeAllTracks() {\n trackData = {};\n }\n function setTrackVisible(id: string, visible: boolean) {}\n function setSelectedTrack(id: string | null, fit: boolean) {}\n function fitAll() {}\n function fitTrack(id: string) {}\n function showCursorAt(lat: number, lon: number) {}\n function hideCursor() {}\n function highlightSegment(\n id: string | null,\n pts: TrackPoint[],\n start: number,\n end: number,\n fit?: boolean,\n colors?: string[] | null,\n ) {}\n function clearHighlight() {}\n function setTrackHover(id: string, hover: boolean) {}\n function ensureVisible(pts: any) {}\n function centerOn(lat: number, lon: number, zoom?: number | null, force?: boolean) {}\n function closePopup() {}\n function invalidateSize() {}\n function getPosition(): [number, number, number] {\n return [0, 0, 0];\n }\n function setPosition(lat: number, lng: number, zoom: number) {}\n function colorTrackByMetric(id: string, pts: TrackPoint[], colors: string[]) {}\n function clearMetricColor(id: string) {}\n\n function findTracksPassingThroughPoints(\n points: { lat: number; lng: number }[],\n radius: number,\n ): string[] {\n return Object.keys(trackData);\n }\n\n return {\n init,\n getMap: () => null as any,\n setCustomClickHandler: (handler: any) => {\n customClickHandler = handler;\n },\n switchBasemap,\n addTrack,\n addTracks,\n removeTrack,\n clearTracks,\n removeAllTracks,\n setTrackVisible,\n setSelectedTrack,\n fitAll,\n fitTrack,\n showCursorAt,\n hideCursor,\n highlightSegment,\n clearHighlight,\n setTrackHover,\n ensureVisible,\n centerOn,\n closePopup,\n invalidateSize,\n getPosition,\n setPosition,\n colorTrackByMetric,\n clearMetricColor,\n findTracksPassingThroughPoints,\n getTrackData: (id: string) => trackData[id],\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackPoint, TrackStats, TrackData } from './parsers';\nimport { gaussianSmooth, fmtSecs, hexToRgba, fmtPace } from './utils';\nimport { Zones } from './zones';\nimport { METRICS, MetricDefinition } from './metrics';\nimport { UrlState } from './url-state';\nimport { SPORTS } from './sports';\n\n// Augment uPlot to include our custom property\n\ninterface WegPlot extends uPlot {\n _strasse?: {\n selFill: HTMLElement;\n anchorLine: HTMLElement;\n anchorLabel: HTMLElement;\n anchorHandle: HTMLElement;\n anchorMarker: HTMLElement;\n endLine: HTMLElement;\n endLabel: HTMLElement;\n endHandle: HTMLElement;\n endMarker: HTMLElement;\n curYVal: HTMLElement;\n updateHeaderStats: (min: number, max: number) => void;\n };\n}\n\ninterface PlotData {\n uplot: WegPlot;\n row: HTMLDivElement;\n xData: number[];\n yData: (number | null)[];\n def: MetricDefinition;\n metricKey: string;\n statsTotalEl: HTMLDivElement;\n statsSelEl: HTMLDivElement;\n histCol: HTMLDivElement;\n histCanvas: HTMLCanvasElement;\n histData: HistData;\n hoveredHistY: number | null;\n pinnedHistY: number | null;\n smoothed?: boolean;\n incZero?: boolean;\n w?: number;\n}\n\ninterface HistData {\n yData: (number | null)[];\n xData: number[];\n def: MetricDefinition;\n BINS: number;\n plot?: PlotData;\n bins?: number[];\n binAccum?: number[];\n min?: number;\n max?: number;\n padL?: number;\n selBins?: number[] | null;\n selBinAccum?: number[] | null;\n _lastYData?: any;\n _lastSelRange?: [number, number] | null;\n fullStats?: { min: number; max: number; avg: number } | null;\n fullStatsAll?: { min: number; max: number; avg: number } | null;\n}\n\nexport const ChartView = (() => {\n let plots: PlotData[] = [];\n let renderedTrack: TrackData | null = null;\n let renderedXAxis: string = 'time';\n let renderedSpeedMode: string = 'speed';\n let renderedMapColorMetric: string | null = null;\n let syncKey: {\n key: string;\n sub: (u: uPlot) => void;\n unsub: (u: uPlot) => void;\n pub: (type: string, u: uPlot, x: number, y: number, w: number, h: number, i: number) => void;\n } | null = null;\n let scaleSyncing: boolean = false;\n let cursorSyncing: boolean = false;\n let activeMetrics: Set = new Set(['elevation']);\n let availableMetrics: Set = new Set();\n let smoothedMetrics: Set = new Set(['speed', 'gradient', 'vam', 'temperature']);\n let metricsIncludingZero: Set = new Set(['power']);\n let xAxis: string = 'time';\n let currentTrack: TrackData | null = null;\n let allTracks: TrackData[] = [];\n\n // Selection / anchor\n let selAnchorVal: number | null = null; // x-value at drag-start / zoom left edge\n let selEndVal: number | null = null; // x-value at zoom right edge\n let isDragging: boolean = false;\n let updatingRange: boolean = false; // guard against setScale hook re-entry during handle drag\n let pinnedPtIdx: number | null = null; // point index pinned by map click\n let lastMouseXVal: number | null = null; // last hovered x-value for keyboard zoom center\n let lastHistMouseEvent: MouseEvent | null = null;\n let hoveredHistData: HistData | null = null;\n let hoveredHistCanvas: HTMLCanvasElement | null = null;\n\n let currentXRange: [number, number] | null = null; // [min, max] currently rendered\n let targetXRange: [number, number] | null = null; // [min, max] for smooth keyboard animation\n let animId: number | null = null;\n\n // Callbacks\n let onCursorMoveCb: ((pt: TrackPoint | null) => void) | null = null;\n let onRangeChangeCb: ((min: number | null, max: number | null, axis: string) => void) | null =\n null;\n let onClickCb: ((pt: TrackPoint, idx: number) => void) | null = null;\n let onPinChangeCb: ((idx: number | null) => void) | null = null;\n\n const HIST_W: number = 130;\n const ROW_BODY_PADDING: number = 28; // 14px left + 14px right\n const HIST_GAP: number = 20; // margin-left on .hist-col\n let statsVisible: boolean = true;\n let histTooltipEl: HTMLElement | null = null;\n let container: HTMLElement | null = null;\n let emptyEl: HTMLElement | null = null;\n let selStatsEl: HTMLElement | null = null;\n let resetSelBtn: HTMLElement | null = null;\n let mapColorMetric: string | null = null;\n let onMapColorChangeCb: ((data: { pts: TrackPoint[]; colors: string[] } | null) => void) | null =\n null;\n\n // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function init(\n onCursorMove: (pt: TrackPoint | null) => void,\n onRangeChange: (min: number | null, max: number | null, axis: string) => void,\n onClick: (pt: TrackPoint, idx: number) => void,\n onPinChange: (idx: number | null) => void,\n ) {\n onCursorMoveCb = onCursorMove;\n onRangeChangeCb = onRangeChange;\n onClickCb = onClick;\n onPinChangeCb = onPinChange;\n container = document.getElementById('charts-container');\n container?.addEventListener('scroll', () => {\n if (lastHistMouseEvent && hoveredHistCanvas && hoveredHistData)\n updateHistTooltip(lastHistMouseEvent, hoveredHistCanvas, hoveredHistData);\n });\n emptyEl = document.getElementById('chart-empty');\n selStatsEl = document.getElementById('chart-stats-sel');\n resetSelBtn = document.getElementById('btn-reset-selection');\n histTooltipEl = document.getElementById('hist-tooltip');\n syncKey = uPlot.sync('strasse-sync');\n\n document.getElementById('sel-cancel-btn')?.addEventListener('click', cancelSelection);\n resetSelBtn?.classList.add('hidden');\n\n // \u2500\u2500 WASD Keyboard Navigation \u2500\u2500\n const navKeys = new Set(['w', 'a', 's', 'd']);\n const activeNavKeys = new Set();\n\n document.addEventListener('keydown', (e) => {\n if (!plots.length || !currentTrack) return;\n if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName || '')) return;\n\n const key = e.key.toLowerCase();\n if (!navKeys.has(key)) return;\n\n e.preventDefault();\n activeNavKeys.add(key);\n\n const u = plots[0].uplot;\n if (!targetXRange) targetXRange = [u.scales.x!.min!, u.scales.x!.max!];\n\n let [min, max] = targetXRange;\n const span = max - min;\n const moveStep = span * 0.1;\n const zoomFactor = 0.15;\n\n let newMin = min,\n newMax = max;\n\n if (key === 'a') {\n // Pan left\n newMin = min - moveStep;\n newMax = max - moveStep;\n } else if (key === 'd') {\n // Pan right\n newMin = min + moveStep;\n newMax = max + moveStep;\n } else if (key === 'w' || key === 's') {\n // Zoom\n const center = lastMouseXVal !== null ? lastMouseXVal : (min + max) / 2;\n const factor = key === 'w' ? 1 - zoomFactor : 1 + zoomFactor * 1.2;\n newMin = center - (center - min) * factor;\n newMax = center + (max - center) * factor;\n }\n\n // Clamp to track bounds\n const xFull = [plots[0].xData[0]!, plots[0].xData[plots[0].xData.length - 1]!];\n if (newMin < xFull[0]) {\n const d = xFull[0] - newMin;\n newMin += d;\n newMax += d;\n }\n if (newMax > xFull[1]) {\n const d = newMax - xFull[1];\n newMin -= d;\n newMax -= d;\n }\n newMin = Math.max(xFull[0], newMin);\n newMax = Math.min(xFull[1], newMax);\n\n if (newMax - newMin > 0.001) {\n targetXRange = [newMin, newMax];\n setVisibleRange(newMin, newMax, true); // true = animate\n }\n });\n\n document.addEventListener('keyup', (e) => {\n const key = e.key.toLowerCase();\n if (navKeys.has(key)) activeNavKeys.delete(key);\n });\n }\n\n function setVisibleRange(min: number, max: number, animate = false) {\n if (!plots.length) return;\n if (!animate) {\n plots.forEach(({ uplot: u }) => u.setScale('x', { min, max }));\n return;\n }\n\n const startMin = (currentXRange ? currentXRange[0] : plots[0].uplot.scales.x!.min) as number;\n const startMax = (currentXRange ? currentXRange[1] : plots[0].uplot.scales.x!.max) as number;\n\n if (animId) cancelAnimationFrame(animId);\n\n const lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n const factor = 0.25; // Smoothing factor\n\n const step = () => {\n if (!targetXRange) return;\n const [tMin, tMax] = targetXRange;\n\n const cMin = lerp(currentXRange![0], tMin, factor);\n const cMax = lerp(currentXRange![1], tMax, factor);\n\n plots.forEach(({ uplot: u }) => {\n u.setScale('x', { min: cMin, max: cMax });\n });\n\n if (Math.abs(cMin - tMin) > 0.0001 || Math.abs(cMax - tMax) > 0.0001)\n animId = requestAnimationFrame(step);\n else animId = null;\n };\n animId = requestAnimationFrame(step);\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function loadTrack(track: TrackData, others: TrackData[] = [], deferRender = false) {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n allTracks = others;\n\n // Detect which metrics are available in this file\n availableMetrics = new Set(\n Object.entries(METRICS)\n .filter(([, def]) => track.points.some((p) => p[def.field] != null))\n .map(([key]) => key),\n );\n\n // If no metrics are active (e.g. first load), default to core overview metrics\n if (activeMetrics.size === 0) {\n activeMetrics = new Set(['elevation'].filter((m) => availableMetrics.has(m)));\n }\n\n // Sync the pill buttons in the toolbar\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n const metric = pill.dataset.metric!;\n const isAvailable = availableMetrics.has(metric);\n pill.classList.toggle('active', isAvailable && activeMetrics.has(metric));\n pill.classList.toggle('disabled', !isAvailable);\n });\n\n currentTrack = track;\n if (deferRender) {\n updateStats(track);\n } else {\n render();\n }\n }\n\n function clear() {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n currentTrack = null;\n destroyPlots();\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
Select a track to view analysis
\n `;\n }\n const chartStats = document.getElementById('chart-stats');\n if (chartStats) chartStats.classList.add('hidden');\n clearSelectionStats();\n mapColorMetric = null;\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n }\n\n function resetState() {\n if (animId !== null) {\n cancelAnimationFrame(animId);\n animId = null;\n }\n activeMetrics = new Set(['elevation']);\n availableMetrics = new Set();\n smoothedMetrics = new Set(['speed', 'gradient', 'vam', 'temperature']);\n metricsIncludingZero = new Set(['power']);\n xAxis = 'time';\n allTracks = [];\n currentXRange = null;\n targetXRange = null;\n lastMouseXVal = null;\n lastHistMouseEvent = null;\n hoveredHistData = null;\n hoveredHistCanvas = null;\n statsVisible = true;\n clear();\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n pill.classList.remove('disabled', 'overflow-hidden');\n });\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.add('hidden');\n const toolbar = document.getElementById('chart-toolbar');\n if (toolbar) toolbar.classList.remove('collapsed');\n document.querySelectorAll('#x-axis-ctrl .seg-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.axis === 'time');\n });\n }\n\n function toggleMetric(key: string) {\n if (activeMetrics.has(key)) activeMetrics.delete(key);\n else activeMetrics.add(key);\n if (currentTrack) render(true);\n }\n\n function setActiveMetrics(keys: string[]) {\n activeMetrics = new Set(keys);\n if (currentTrack) render(true);\n // Sync the pill buttons\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n });\n }\n\n function setXAxis(axis: string) {\n if (xAxis === axis || !currentTrack) {\n xAxis = axis;\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n\n // Helper to convert a value from OLD axis to NEW axis\n const convert = (val: number | null) => {\n if (val === null) return null;\n // We need to find the point index closest to 'val' on the OLD axis\n let idx = 0;\n if (xAxis === 'distance') {\n const dTarget = val * 1000;\n idx = pts.findIndex((p) => (p.dist || 0) >= dTarget);\n } else {\n const tTarget = t0 + val * 1000;\n idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n }\n if (idx === -1) idx = pts.length - 1;\n\n // Now get the value at this index on the NEW axis\n if (axis === 'distance') return (pts[idx].dist || 0) / 1000;\n else return ((pts[idx].time || t0) - t0) / 1000;\n };\n\n // Convert selection\n if (selAnchorVal !== null) selAnchorVal = convert(selAnchorVal);\n if (selEndVal !== null) selEndVal = convert(selEndVal);\n\n // Convert zoom range (from first plot)\n let newRange: [number, number] | null = null;\n if (plots.length) {\n const u = plots[0].uplot;\n const r0 = convert(u.scales.x!.min!);\n const r1 = convert(u.scales.x!.max!);\n if (r0 !== null && r1 !== null) newRange = [r0, r1];\n }\n\n xAxis = axis;\n render(true);\n\n // Apply converted zoom\n if (newRange) {\n scaleSyncing = true;\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: newRange![0], max: newRange![1] }));\n });\n scaleSyncing = false;\n }\n }\n\n function toggleStats() {\n statsVisible = !statsVisible;\n plots.forEach(({ histCol }) => histCol.classList.toggle('visible', statsVisible));\n resize();\n }\n\n function setMapColorChangeCb(cb: (data: { pts: TrackPoint[]; colors: string[] } | null) => void) {\n onMapColorChangeCb = cb;\n }\n\n function toggleMapColor(key: string | null) {\n if (mapColorMetric === key || key === null) {\n mapColorMetric = null;\n _updateMapColorBtns();\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n } else {\n mapColorMetric = key;\n _updateMapColorBtns();\n _fireMapColorCb();\n }\n // Re-render to show/hide colored fills on the graphs\n if (currentTrack) render(true);\n }\n\n function _updateMapColorBtns() {\n document.querySelectorAll('.map-color-btn').forEach((el) => {\n const b = el as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === mapColorMetric);\n });\n }\n\n function _fireMapColorCb() {\n if (!onMapColorChangeCb || !mapColorMetric || !currentTrack) return;\n const plot = plots.find((p) => p.metricKey === mapColorMetric);\n if (!plot) return;\n const colors = _computePointColors(mapColorMetric, plot.yData);\n onMapColorChangeCb({ pts: currentTrack.points, colors });\n }\n\n function _computePointColors(key: string, yData: (number | null)[]): string[] {\n const vals = yData.filter((v): v is number => v != null && isFinite(v));\n if (!vals.length) return yData.map(() => '#888896');\n const min = Math.min(...vals),\n max = Math.max(...vals);\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n return yData.map((v) => {\n if (v == null || !isFinite(v)) return '#888896';\n if (key === 'gradient') return gradientColor(v);\n if (key === 'speed') {\n if (speedMode === 'pace') {\n const speed = (paceUnit === 'km' ? 1000 : 100) / v;\n return speedColor(speed);\n }\n return speedColor(v);\n }\n const t = max === min ? 0.5 : Math.max(0, Math.min(1, (v - min) / (max - min)));\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25);\n if (t <= 0.5) return lerpHex('#91bfdb', '#fee090', (t - 0.25) / 0.25);\n if (t <= 0.75) return lerpHex('#fee090', '#fc8d59', (t - 0.5) / 0.25);\n return lerpHex('#fc8d59', '#d73027', (t - 0.75) / 0.25);\n });\n }\n\n function resetZoom() {\n cancelSelection();\n }\n\n function cancelSelection() {\n selAnchorVal = null;\n selEndVal = null;\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n\n // Reset individual histogram pins\n plots.forEach((p) => {\n p.pinnedHistY = null;\n });\n\n updateSelOverlay();\n redrawHistograms();\n\n // Perform the actual zoom reset\n scaleSyncing = true;\n plots.forEach(({ uplot: u, xData }) => {\n u.batch(() => u.setScale('x', { min: xData[0]!, max: xData[xData.length - 1]! }));\n u._strasse?.updateHeaderStats(xData[0]!, xData[xData.length - 1]!);\n });\n scaleSyncing = false;\n\n if (onRangeChangeCb) onRangeChangeCb(null, null, xAxis);\n }\n\n function setSelectionStats(stats: TrackStats) {\n if (!selStatsEl) return;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt(\n 'sel-distance',\n stats.totalDist != null ? `${(stats.totalDist / 1000).toFixed(1)} km` : '\u2014',\n );\n fmt('sel-duration', stats.duration != null ? fmtSecs(Math.floor(stats.duration / 1000)) : '\u2014');\n fmt('sel-elevation', stats.elevGain != null ? `${Math.round(stats.elevGain)} m` : '\u2014');\n fmt(\n 'sel-avg-speed',\n stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014',\n );\n fmt('sel-avg-power', stats.avgPower != null ? `${stats.avgPower} W` : '\u2014');\n fmt('sel-avg-hr', stats.avgHR != null ? `${stats.avgHR} bpm` : '\u2014');\n fmt('sel-avg-temp', stats.avgTemp != null ? `${stats.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n selStatsEl.classList.remove('hidden');\n if (resetSelBtn) resetSelBtn.classList.remove('hidden');\n }\n\n function clearSelectionStats() {\n if (selStatsEl) selStatsEl.classList.add('hidden');\n if (resetSelBtn) resetSelBtn.classList.add('hidden');\n [\n 'sel-distance',\n 'sel-duration',\n 'sel-elevation',\n 'sel-avg-speed',\n 'sel-avg-power',\n 'sel-avg-hr',\n 'sel-avg-temp',\n ].forEach((id) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = '--';\n });\n }\n\n // Called on boot to restore a saved selection without re-firing onRangeChangeCb\n // xMin/xMax are ALWAYS provided in Time (seconds from start)\n function restoreSelection(tMin: number, tMax: number, deferRender = false) {\n if (!currentTrack) return;\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const totalDuration = ((pts[pts.length - 1]?.time || 0) - t0) / 1000;\n\n // If values look like absolute timestamps in ms, convert to seconds from start\n if (tMin > 1e12) tMin = (tMin - t0) / 1000;\n if (tMax > 1e12) tMax = (tMax - t0) / 1000;\n\n // Crop to max limits of the track\n tMin = Math.max(0, Math.min(tMin, totalDuration));\n tMax = Math.max(0, Math.min(tMax, totalDuration));\n\n const convert = (tOffset: number) => {\n if (xAxis === 'time') return tOffset;\n const tTarget = t0 + tOffset * 1000;\n let idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n if (idx === -1) idx = pts.length - 1;\n return (pts[idx].dist || 0) / 1000;\n };\n\n const xMin = convert(tMin);\n const xMax = convert(tMax);\n\n selAnchorVal = xMin;\n selEndVal = xMax;\n currentXRange = [xMin, xMax];\n if (deferRender) return;\n scaleSyncing = true; // suppress the setScale \u2192 onRangeChangeCb loop\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: xMin, max: xMax }));\n });\n scaleSyncing = false;\n updateAnchorLines();\n redrawHistograms();\n }\n\n function resize() {\n if (!plots.length || !container) return;\n const w = Math.round(\n Math.max(\n 100,\n container.getBoundingClientRect().width -\n ROW_BODY_PADDING -\n (statsVisible ? HIST_W + HIST_GAP : 0),\n ),\n );\n let anyResized = false;\n plots.forEach(({ uplot: u, histCanvas, histData }) => {\n if (w !== u.width) {\n u.setSize({ width: w, height: u.height });\n anyResized = true;\n if (statsVisible && histCanvas && histData) drawHistogram(histCanvas, histData, u.height);\n }\n });\n if (anyResized) updateSelOverlay();\n }\n\n // \u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function render(keepState = false) {\n let savedRange: [number, number] | null = null;\n let savedScroll = 0;\n if (keepState && container) savedScroll = container.scrollTop;\n\n if (keepState && currentXRange) {\n savedRange = [currentXRange[0], currentXRange[1]];\n } else if (keepState && plots.length) {\n const u = plots[0].uplot;\n savedRange = [u.scales.x!.min!, u.scales.x!.max!];\n }\n\n if (!currentTrack) {\n destroyPlots(keepState);\n return;\n }\n const pts = currentTrack.points;\n if (!pts.length) {\n destroyPlots(keepState);\n return;\n }\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n const available = [...activeMetrics].filter((m) =>\n pts.some((p) => p[METRICS[m].field] != null),\n );\n if (!available.length) {\n destroyPlots(keepState);\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
No data for selected metrics
\n `;\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n\n const containerW = container ? container.getBoundingClientRect().width : 800;\n const w = Math.round(\n Math.max(100, containerW - ROW_BODY_PADDING - (statsVisible ? HIST_W + HIST_GAP : 0)),\n );\n\n const canReuse =\n keepState &&\n renderedTrack === currentTrack &&\n renderedXAxis === xAxis &&\n renderedSpeedMode === speedMode &&\n renderedMapColorMetric === mapColorMetric &&\n plots.length > 0;\n\n let xData: (number | null)[];\n if (canReuse) {\n xData = plots[0].xData;\n } else if (xAxis === 'distance') {\n xData = pts.map((p) => (p.dist || 0) / 1000);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n let lastValidX = 0;\n xData = pts.map((p) => {\n if (p.time != null) {\n lastValidX = (p.time - t0) / 1000;\n return lastValidX;\n }\n return lastValidX; // monotonic fallback\n });\n }\n\n const existingByKey = new Map();\n if (canReuse) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const availSet = new Set(available);\n for (const p of plots) {\n const isSmoothed = smoothedMetrics.has(p.metricKey);\n const isIncZero = metricsIncludingZero.has(p.metricKey);\n if (\n availSet.has(p.metricKey) &&\n p.smoothed === isSmoothed &&\n p.incZero === isIncZero &&\n p.w === w\n ) {\n existingByKey.set(p.metricKey, p);\n } else {\n syncKey!.unsub(p.uplot);\n p.uplot.destroy();\n p.row.remove();\n }\n }\n plots = [];\n } else {\n destroyPlots(keepState);\n }\n\n if (container) {\n const nextSiblingRows: (HTMLElement | null)[] = new Array(available.length).fill(null);\n let nextExisting: HTMLElement | null = null;\n for (let i = available.length - 1; i >= 0; i--) {\n nextSiblingRows[i] = nextExisting;\n const ex = existingByKey.get(available[i]);\n if (ex) nextExisting = ex.row;\n }\n\n available.forEach((key, idx) => {\n const reused = existingByKey.get(key);\n if (reused) {\n plots.push(reused);\n const uplot = reused.uplot;\n const s = (uplot as any)._strasse;\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n uplot.batch(() => {\n if (\n savedRange &&\n (uplot.scales.x!.min !== savedRange[0] || uplot.scales.x!.max !== savedRange[1])\n ) {\n uplot.setScale('x', { min: savedRange[0], max: savedRange[1] });\n } else {\n s?.updateHeaderStats(uplot.scales.x!.min!, uplot.scales.x!.max!, uplot);\n uplot.redraw(false);\n }\n });\n scaleSyncing = prevSync;\n\n let initHoverBinI: number | null = null;\n if (\n pinnedPtIdx != null &&\n reused.xData[pinnedPtIdx] != null &&\n reused.yData[pinnedPtIdx] != null\n ) {\n buildHistBins(reused.histData);\n if (reused.histData.min != null && reused.histData.max != null) {\n const span = reused.histData.max - reused.histData.min || 1;\n initHoverBinI = Math.min(\n reused.histData.BINS - 1,\n Math.floor(\n ((reused.yData[pinnedPtIdx]! - reused.histData.min) / span) *\n reused.histData.BINS,\n ),\n );\n reused.hoveredHistY = reused.yData[pinnedPtIdx];\n }\n }\n drawHistogram(reused.histCanvas, reused.histData, 130, initHoverBinI);\n return;\n }\n\n let def = METRICS[key];\n\n let transform = def.transform;\n let fmt = def.fmt;\n let fmtAxis = def.fmtAxis;\n let unit = def.unit;\n let label = def.label;\n\n if (key === 'speed' && speedMode === 'pace') {\n label = 'Pace';\n unit = `min/${paceUnit}`;\n fmt = (v) => fmtPace(v);\n fmtAxis = (v) => fmtPace(v);\n transform = (v) => {\n if (v == null || v < 0.1) return null;\n return (paceUnit === 'km' ? 1000 : 100) / v;\n };\n\n def = { ...def, label, unit, fmt, fmtAxis, transform };\n }\n\n let yData = def.compute\n ? def.compute(pts, fillNulls)\n : fillNulls(\n pts.map((p) => {\n const v = p[def.field] as number;\n return v != null && transform ? transform(v) : v;\n }),\n );\n\n if (smoothedMetrics.has(key)) yData = gaussianSmooth(yData, def.smoothSigma || 2);\n\n createChart(key, def, xData, yData, w, pts, savedRange, nextSiblingRows[idx]);\n });\n }\n\n renderedTrack = currentTrack;\n renderedXAxis = xAxis;\n renderedSpeedMode = speedMode;\n renderedMapColorMetric = mapColorMetric;\n\n updateStats(currentTrack);\n // Restore anchor/end lines if a selection was active\n if (selAnchorVal != null && selEndVal != null) updateAnchorLines();\n // Re-apply map color if active\n _updateMapColorBtns();\n if (mapColorMetric) _fireMapColorCb();\n\n if (keepState && container && savedScroll > 0) container.scrollTop = savedScroll;\n }\n\n // \u2500\u2500 Create one chart row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function createChart(\n metricKey: string,\n def: MetricDefinition,\n xData: (number | null)[],\n yData: (number | null)[],\n w: number,\n pts: TrackPoint[],\n initialRange: [number, number] | null = null,\n insertBeforeEl: HTMLElement | null = null,\n ) {\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n\n // Gradient data: smooth over a 20 m distance window (\u00B110 m each side)\n const gradData = metricKey === 'elevation' ? smoothGradient(pts, 20) : null;\n const row = document.createElement('div');\n row.className = 'chart-row';\n row.dataset.metric = metricKey;\n row.style.setProperty('--chart-color', def.color);\n\n // Header\n const header = document.createElement('div');\n header.className = `chart-row-header${statsVisible ? ' with-histogram' : ''}`;\n\n const labelEl = document.createElement('div');\n labelEl.className = 'chart-row-label-group';\n labelEl.innerHTML = `\n ${def.icon}\n ${def.label}\n `;\n\n // Smoothing toggle\n const smoothBtn = document.createElement('button');\n smoothBtn.className = `icon-btn mini smooth-btn${smoothedMetrics.has(metricKey) ? ' active' : ''}`;\n smoothBtn.title = 'Toggle data smoothing';\n smoothBtn.innerHTML = `${smoothedMetrics.has(metricKey) ? 'blur_on' : 'blur_off'}`;\n smoothBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (smoothedMetrics.has(metricKey)) smoothedMetrics.delete(metricKey);\n else smoothedMetrics.add(metricKey);\n\n render(true); // Re-render all charts to keep sync if needed (though only this one changes data)\n });\n\n const mapColorBtn = document.createElement('button');\n\n mapColorBtn.className = `map-color-btn icon-btn${mapColorMetric === metricKey ? ' active' : ''}`;\n mapColorBtn.dataset.metric = metricKey;\n mapColorBtn.title = 'Color map track by this metric';\n mapColorBtn.innerHTML = 'colorize';\n mapColorBtn.addEventListener('click', () => toggleMapColor(metricKey));\n\n // Zero-filter toggle (Cadence/Power/Speed)\n let zeroBtn: HTMLButtonElement | null = null;\n if (metricKey === 'cadence' || metricKey === 'power' || metricKey === 'speed') {\n zeroBtn = document.createElement('button');\n const incZero = metricsIncludingZero.has(metricKey);\n zeroBtn.className = `icon-btn mini${incZero ? ' active' : ''}`;\n zeroBtn.title = incZero ? 'Currently INCLUDING 0 values' : 'Currently EXCLUDING 0 values';\n zeroBtn.innerHTML = `${incZero ? 'exposure_zero' : 'mobile_off'}`;\n zeroBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (metricsIncludingZero.has(metricKey)) metricsIncludingZero.delete(metricKey);\n else metricsIncludingZero.add(metricKey);\n render(true);\n });\n }\n\n const statsTotalEl = document.createElement('div');\n statsTotalEl.className = 'chart-stats-total';\n\n const statsSelEl = document.createElement('div');\n statsSelEl.className = 'chart-stats-selection';\n\n const statsContainer = document.createElement('div');\n statsContainer.className = 'chart-row-stats-container';\n statsContainer.append(statsTotalEl, statsSelEl);\n\n const actionsEl = document.createElement('div');\n actionsEl.className = 'chart-row-actions';\n actionsEl.append(smoothBtn, mapColorBtn);\n\n const rightActionsEl = document.createElement('div');\n rightActionsEl.className = 'chart-row-right-actions';\n\n if (metricKey === 'speed') {\n const paceToggle = document.createElement('div');\n paceToggle.className = 'seg-ctrl';\n paceToggle.innerHTML = `\n \n \n `;\n paceToggle.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const mode = btn.dataset.mode;\n if (mode === 'speed' || mode === 'pace') {\n const isDefault = mode === defaultMode;\n UrlState.patch({ speed_mode: isDefault ? null : mode });\n render(true);\n }\n });\n rightActionsEl.append(paceToggle);\n }\n\n if (zeroBtn) rightActionsEl.append(zeroBtn);\n\n header.append(labelEl, actionsEl, statsContainer, rightActionsEl);\n\n const rowBody = document.createElement('div');\n rowBody.className = 'chart-row-body';\n\n const plotEl = document.createElement('div');\n plotEl.style.position = 'relative';\n rowBody.appendChild(plotEl);\n\n const fixedMinLabel = document.createElement('div');\n fixedMinLabel.className = 'fixed-x-label fixed-x-min';\n const fixedMaxLabel = document.createElement('div');\n fixedMaxLabel.className = 'fixed-x-label fixed-x-max';\n plotEl.append(fixedMinLabel, fixedMaxLabel);\n\n const histCol = document.createElement('div');\n histCol.className = `hist-col${statsVisible ? ' visible' : ''}`;\n const histCanvas = document.createElement('canvas');\n histCanvas.className = 'hist-canvas';\n histCol.appendChild(histCanvas);\n rowBody.appendChild(histCol);\n\n row.append(header, rowBody);\n\n const isDistAxis = xAxis === 'distance';\n\n function formatX(v: number, range: number): string {\n if (v == null) return '';\n if (isDistAxis) {\n const dec = range < 1 ? 3 : range < 5 ? 2 : range < 20 ? 1 : 0;\n return `${v.toFixed(dec)} km`;\n } else {\n const absV = Math.abs(v);\n const h = Math.floor(absV / 3600);\n const m = Math.floor((absV % 3600) / 60);\n const s = Math.round(absV % 60);\n const hh = h > 0 ? `${h}:` : '';\n const mm = h > 0 ? String(m).padStart(2, '0') : String(m);\n const ss = String(s).padStart(2, '0');\n return `${v < 0 ? '-' : ''}${hh}${mm}:${ss}`;\n }\n }\n\n const incZeroDefault =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Compute global Y range and full-track stats in a single pass\n let gMin = Infinity,\n gMax = -Infinity,\n allSum = 0,\n allCount = 0,\n filtMin = Infinity,\n filtMax = -Infinity,\n filtSum = 0,\n filtCount = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n allSum += v;\n allCount++;\n if (v !== 0 || incZeroDefault) {\n if (v < filtMin) filtMin = v;\n if (v > filtMax) filtMax = v;\n filtSum += v;\n filtCount++;\n }\n }\n if (allCount === 0) {\n gMin = 0;\n gMax = 100;\n }\n const fullStatsAll = allCount ? { min: gMin, max: gMax, avg: allSum / allCount } : null;\n const fullStatsFiltered = filtCount\n ? { min: filtMin, max: filtMax, avg: filtSum / filtCount }\n : null;\n const gPad = Math.abs(gMax - gMin) * 0.1 || 1;\n const fixedYRange = [gMin - gPad, gMax + gPad];\n\n let statsTotalInitialized = false;\n\n // Per-range stats\n function updateHeaderStats(visibleMin: number, visibleMax: number, u?: uPlot) {\n const incZero =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Update fixed X labels\n const range = visibleMax - visibleMin;\n fixedMinLabel.textContent = formatX(visibleMin, range);\n fixedMaxLabel.textContent = formatX(visibleMax, range);\n\n const getHtml = (xMin: number, xMax: number, isFull = false) => {\n const s =\n isFull && incZero === incZeroDefault\n ? fullStatsFiltered\n : rangeStats(xData, yData, xMin, xMax, incZero);\n if (!s) return '';\n\n let h = `\n align_flex_end${def.fmt(s.min, true)} ${def.unit}\n align_center${def.fmt(s.avg, true)} ${def.unit}\n align_flex_start${def.fmt(s.max, true)} ${def.unit}\n `;\n\n if (metricKey === 'elevation') {\n const es = elevationRangeStats(pts, xMin, xMax);\n h += `\n trending_up+${Math.round(es.gain)} m\n trending_down-${Math.round(es.loss)} m\n `;\n }\n return h;\n };\n\n if (!statsTotalInitialized) {\n statsTotalInitialized = true;\n statsTotalEl.innerHTML = `all_inclusive${getHtml(\n xData[0]!,\n xData[xData.length - 1]!,\n true,\n )}`;\n statsTotalEl.querySelector('.all-chip')?.addEventListener('click', (e) => {\n e.stopPropagation();\n cancelSelection();\n });\n }\n\n if (selAnchorVal !== null && selEndVal !== null) {\n statsSelEl.innerHTML = getHtml(selAnchorVal, selEndVal, false);\n statsSelEl.style.display = 'flex';\n statsSelEl.style.setProperty('--sel-color', def.color);\n } else {\n statsSelEl.style.display = 'none';\n }\n }\n let initializingScale = false;\n const uOpts: uPlot.Options = {\n width: w,\n height: 130,\n padding: [4, 0, 0, 0],\n cursor: {\n sync: {\n key: syncKey!.key,\n },\n drag: { x: true, y: false, uni: 16 },\n focus: { prox: 16 },\n points: {\n size: 7,\n stroke: '#0e0e10',\n width: 2,\n fill: (metricKey === 'elevation'\n ? (u: uPlot, _si: number) => gradientColor(gradData ? gradData[u.cursor.idx!]! : null)\n : def.color) as any,\n },\n x: false,\n y: false,\n },\n select: {\n show: true,\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n },\n legend: { show: false },\n scales: {\n x: {\n time: false,\n range: (_u: uPlot, mn: number, mx: number) => [mn, mx],\n min: initialRange ? initialRange[0] : undefined,\n max: initialRange ? initialRange[1] : undefined,\n },\n y: {\n range: () => fixedYRange as [number, number],\n dir: metricKey === 'speed' && speedMode === 'pace' ? -1 : 1,\n },\n },\n axes: [\n {\n side: 2, // bottom\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: {\n show: true,\n stroke: '#2e2e34',\n },\n size: 30,\n space: 80,\n font: '10px system-ui, sans-serif',\n splits: (u: uPlot, axisIdx: number, scaleMin: number, scaleMax: number) => {\n const range = scaleMax - scaleMin;\n const width = u.bbox.width > 0 ? u.bbox.width : u.width;\n const targetLabels = width / 80;\n const idealIncr = range / targetLabels;\n\n let incrs;\n if (!isDistAxis) {\n // Time in seconds\n incrs = [\n 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 14400, 28800, 43200,\n 86400, 604800, 2592000, 31536000,\n ];\n } else {\n incrs = [\n 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000,\n 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000,\n ];\n }\n\n let incr = incrs[incrs.length - 1];\n for (let i = 0; i < incrs.length; i++) {\n if (incrs[i] >= idealIncr) {\n incr = incrs[i];\n break;\n }\n }\n\n const splits = [];\n let val = Math.ceil(scaleMin / incr) * incr;\n const precision = incr < 1 ? 2 : 0;\n\n while (val <= scaleMax) {\n const pos = u.valToPos(val, 'x', true);\n if (pos >= u.bbox.left + 80 && pos <= u.bbox.left + u.bbox.width - 80)\n splits.push(Number(val.toFixed(precision)));\n\n val += incr;\n }\n return splits;\n },\n values: ((_u: uPlot, vals: number[]) => {\n const range = (_u.scales.x?.max ?? 1) - (_u.scales.x?.min ?? 0);\n\n return vals.map((v) => {\n if (v == null) return '';\n const pos = _u.valToPos(v, 'x', true);\n // Strict 80px margin to prevent overlapping with fixed labels or Y axis\n if (pos < _u.bbox.left + 80 || pos > _u.bbox.left + _u.bbox.width - 80) return null;\n return formatX(v, range);\n });\n }) as any,\n },\n {\n side: 3, // left\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: { stroke: '#2e2e34' },\n size: 55,\n font: '10px system-ui, sans-serif',\n values: ((_u: uPlot, vals: number[]) =>\n vals.map((v) => (v != null ? def.fmtAxis(v) : ''))) as any,\n },\n ],\n series: [\n {},\n // Main selected track series\n {\n label: def.label,\n stroke: 'rgba(0,0,0,0)', // Stroke handled in draw hooks for layering\n width: 0,\n points: { show: false },\n paths: () => null,\n },\n ],\n hooks: {\n draw: [\n (u: uPlot) => {\n const top = u.bbox.top + u.bbox.height + 5; // 5px below plot area!\n fixedMinLabel.style.top = `${top}px`;\n fixedMinLabel.style.left = `${u.bbox.left}px`;\n\n fixedMaxLabel.style.top = `${top}px`;\n fixedMaxLabel.style.left = `${u.bbox.left + u.bbox.width}px`;\n fixedMaxLabel.style.transform = 'translateX(-100%)';\n },\n // 1. (bottom) Color / metric color of the selected track\n (u: uPlot) => {\n if (metricKey === 'gears') {\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n } else if (metricKey === 'elevation') {\n drawElevationGradient(u, xData as number[], yData as number[], gradData);\n } else if (metricKey === 'gradient') {\n drawGradientChart(u, xData as number[], yData as number[]);\n } else if (mapColorMetric === metricKey) {\n drawMetricColorFill(u, xData as number[], yData as number[], pts, metricKey);\n } else {\n // Normal colored line\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n }\n },\n\n // 2. Pinned point (middle)\n (u: uPlot) => {\n const plot = plots.find((p) => p.uplot === u);\n if (!plot) return;\n\n const s = (u as any)._strasse;\n // Priority 1: Global pinned point (all charts)\n if (pinnedPtIdx != null) {\n drawPinnedDot(u, xData, yData, def.color, def, pts, metricKey);\n } else {\n if (s && s.pinYVal) s.pinYVal.style.display = 'none';\n\n // Priority 2: Individual histogram pinned Y-pos (this chart only)\n if (plot.pinnedHistY != null)\n drawYAxisHighlight(u, xData, yData, plot.pinnedHistY, def.color, def);\n }\n },\n\n // 3. Pinned & Hover elements (labels, vertical lines)\n (u: uPlot) => {\n const hIdx = u.cursor.idx;\n const hasPinned = pinnedPtIdx != null;\n\n let hasHover = hIdx != null && u.cursor.left! >= 0;\n if (hasHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[hIdx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) hasHover = false;\n }\n\n // B. Draw Hover vertical line\n if (hasHover && hIdx !== pinnedPtIdx)\n drawVerticalLineOnly(u, pts, hIdx!, hexToRgba(def.color, 0.4), 1.0);\n\n // C. Bold selection x-axis line & span pill\n if (selAnchorVal != null && selEndVal != null) {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ax = u.valToPos(selAnchorVal, 'x', true);\n const ex = u.valToPos(selEndVal, 'x', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.lineWidth = 3 * dpr;\n ctx.strokeStyle = def.color;\n ctx.moveTo(ax, bb.top + bb.height);\n ctx.lineTo(ex, bb.top + bb.height);\n ctx.stroke();\n\n const span = Math.abs(selEndVal - selAnchorVal);\n const label = xAxis === 'distance' ? `${span.toFixed(2)} km` : fmtSecs(span);\n const fontSize = 9 * dpr;\n const fontStr = `bold ${fontSize}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n\n const visibleL = Math.max(bb.left, ax);\n const visibleR = Math.min(bb.left + bb.width, ex);\n const visibleW = visibleR - visibleL;\n\n if (visibleW > tw + 14 * dpr) {\n const padH = 5 * dpr;\n const padV = 2 * dpr;\n const bw = tw + padH * 2;\n const bh = fontSize + padV * 2;\n const bx = (visibleL + visibleR) / 2 - bw / 2;\n const by = bb.top + bb.height - bh / 2;\n\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = def.color;\n ctx.fill();\n\n ctx.fillStyle = '#000';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2);\n }\n ctx.restore();\n }\n\n // D. Draw label pills (on top)\n // Pinned labels first (semi-transparent)\n if (hasPinned) drawXAxisLabels(u, pts, pinnedPtIdx!, def.color, true, 0.7);\n\n // Hover labels last (fully opaque, topmost)\n if (hasHover && hIdx !== pinnedPtIdx)\n drawXAxisLabels(u, pts, hIdx!, def.color, true, 1.0);\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (scaleSyncing) return;\n const idx = u.cursor.idx;\n\n // Trigger redraw on cursor move to ensure custom canvas markers (hover lines/labels) update live\n // Note: uPlot handles cross-chart sync when syncKey is used.\n u.redraw(false);\n\n // Track current x-value for keyboard navigation\n if (u.cursor.left! >= 0) lastMouseXVal = u.posToVal(u.cursor.left!, 'x');\n else lastMouseXVal = null;\n\n // \u2500\u2500 Floating y-value next to cursor dot \u2500\u2500\n const s = (u as any)._strasse;\n let showHover = idx != null && yData[idx] != null;\n\n // Distance threshold: if no pinned point, check proximity to data line\n if (showHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[idx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) showHover = false;\n }\n\n if (s) {\n if (showHover)\n updateTooltip(\n u,\n s.curYVal,\n idx!,\n xData as number[],\n yData as number[],\n pts,\n def,\n metricKey,\n );\n else s.curYVal.style.display = 'none';\n }\n\n // Map marker\n if (!cursorSyncing) {\n if (idx != null && pts[idx]) {\n if (onCursorMoveCb && (pinnedPtIdx != null || showHover)) {\n onCursorMoveCb(pts[idx]);\n } else if (onCursorMoveCb && !showHover) {\n // If we're too far and nothing is pinned, hide map cursor\n onCursorMoveCb(null);\n }\n } else if (idx === null && onCursorMoveCb) {\n onCursorMoveCb(null);\n }\n }\n\n // Highlight matching histogram bucket\n if (idx != null && yData[idx] != null) {\n const { min, max } = histData;\n if (min != null && max != null) {\n const span = max - min || 1;\n const binI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[idx]! - min) / span) * histData.BINS),\n );\n if (plot.hoveredHistY !== yData[idx]) {\n plot.hoveredHistY = yData[idx];\n drawHistogram(histCanvas, histData, 130, binI);\n }\n }\n } else if (plot.hoveredHistY !== null) {\n plot.hoveredHistY = null;\n drawHistogram(histCanvas, histData, 130);\n }\n },\n ],\n\n setScale: [\n (u: uPlot, key: string) => {\n if (key !== 'x' || initializingScale) return;\n const { min, max } = u.scales.x!;\n\n // Sync currentXRange so keyboard navigation baseline is always accurate\n currentXRange = [min!, max!];\n\n // Update header stats for VISIBLE range\n updateHeaderStats(min as number, max as number, u);\n\n if (scaleSyncing) return;\n\n // Clear keyboard target when user interacts via mouse\n if (!updatingRange) targetXRange = null;\n\n // Sync sibling plots\n scaleSyncing = true;\n plots.forEach(({ uplot: other }) => {\n if (other !== u) other.batch(() => other.setScale('x', { min: min!, max: max! }));\n });\n scaleSyncing = false;\n\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb && selAnchorVal !== null)\n onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n },\n ],\n\n setSelect: [\n (u: uPlot) => {\n if (updatingRange) return;\n targetXRange = null;\n const { left, width } = u.select;\n if (width > 0) {\n const min = u.posToVal(left, 'x');\n const max = u.posToVal(left + width, 'x');\n selAnchorVal = min;\n selEndVal = max;\n\n // Sync stats to new selection\n updateHeaderStats(u.scales.x!.min!, u.scales.x!.max!, u);\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n\n // Clear uPlot's internal selection immediately so it doesn't block WASD/interaction\n u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);\n }\n },\n ],\n },\n };\n\n // \u2500\u2500 Overlay (pointer-events off except handles) \u2500\u2500\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5';\n\n // Selection fill\n const selFill = document.createElement('div');\n selFill.className = 'sel-fill';\n selFill.style.display = 'none';\n\n // Anchor line + label + drag handle\n const anchorLine = document.createElement('div');\n anchorLine.className = 'sel-line sel-line-anchor';\n anchorLine.style.display = 'none';\n\n const anchorLabel = document.createElement('div');\n anchorLabel.className = 'sel-line-label sel-line-label-anchor';\n anchorLabel.style.display = 'none';\n\n const anchorHandle = document.createElement('div');\n anchorHandle.className = 'sel-handle sel-handle-anchor';\n anchorHandle.style.display = 'none';\n\n const anchorMarker = document.createElement('div');\n anchorMarker.className = 'sel-graph-marker';\n anchorMarker.innerHTML =\n 'play_circle';\n anchorMarker.style.display = 'none';\n\n // End line + label + drag handle\n const endLine = document.createElement('div');\n endLine.className = 'sel-line sel-line-end';\n endLine.style.display = 'none';\n\n const endLabel = document.createElement('div');\n endLabel.className = 'sel-line-label sel-line-label-end';\n endLabel.style.display = 'none';\n\n const endHandle = document.createElement('div');\n endHandle.className = 'sel-handle sel-handle-end';\n endHandle.style.display = 'none';\n\n const endMarker = document.createElement('div');\n endMarker.className = 'sel-graph-marker';\n endMarker.innerHTML =\n 'stop_circle';\n endMarker.style.display = 'none';\n\n // Floating cursor y-value\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${def.color};display:none`;\n\n // Floating pinned y-value\n const pinYVal = document.createElement('div');\n pinYVal.className = 'cur-y-val pin';\n pinYVal.style.cssText = `color:${def.color};display:none`;\n\n overlay.append(\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n );\n\n const histData: HistData = {\n yData,\n xData: xData as number[],\n def,\n BINS: 24,\n min: allCount ? gMin : undefined,\n max: allCount ? gMax : undefined,\n fullStats: fullStatsFiltered,\n fullStatsAll,\n };\n const plot: PlotData = {\n uplot: null as any,\n row,\n xData: xData as number[],\n yData,\n def,\n metricKey,\n statsTotalEl,\n statsSelEl,\n histCol,\n histCanvas,\n histData,\n hoveredHistY: null,\n pinnedHistY: null,\n smoothed: smoothedMetrics.has(metricKey),\n incZero: metricsIncludingZero.has(metricKey),\n w,\n };\n histData.plot = plot; // Back-reference for tooltip to trigger redraws\n\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n const uplot = new uPlot(uOpts, [xData, yData] as any, (self, init) => {\n plot.uplot = self as WegPlot;\n plots.push(plot);\n plotEl.appendChild(self.root);\n self.over.appendChild(overlay);\n (self as any)._strasse = {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n updateHeaderStats,\n };\n self.batch(() => {\n init();\n });\n }) as WegPlot;\n scaleSyncing = prevSync;\n\n // \u2500\u2500 Handle drag \u2500\u2500\n attachHandleDrag(anchorHandle, uplot, xData, true);\n attachHandleDrag(endHandle, uplot, xData, false);\n\n // \u2500\u2500 Mouse listeners \u2500\u2500\n let mousedownX: number | null = null;\n uplot.over.addEventListener('mousedown', (e) => {\n if (e.button !== 0) return;\n isDragging = false;\n const rect = uplot.over.getBoundingClientRect();\n const xPx = e.clientX - rect.left;\n mousedownX = xPx;\n });\n uplot.over.addEventListener('mousemove', (e) => {\n if (mousedownX !== null) {\n const rect = uplot.over.getBoundingClientRect();\n if (Math.abs(e.clientX - rect.left - mousedownX) > 5) isDragging = true;\n }\n });\n uplot.over.addEventListener('mouseup', () => {\n mousedownX = null;\n });\n\n // Click to pin point (sticky selection)\n uplot.over.addEventListener('click', () => {\n if (isDragging) return;\n const idx = uplot.cursor.idx;\n if (idx != null && pts[idx]) {\n pinnedPtIdx = idx;\n plots.forEach(({ uplot: u }) => u.redraw(false));\n if (onClickCb) onClickCb(pts[idx], idx);\n if (onPinChangeCb) onPinChangeCb(idx);\n }\n });\n\n row.addEventListener('dblclick', cancelSelection);\n\n let initHoverBinI: number | null = null;\n if (pinnedPtIdx != null && xData[pinnedPtIdx] != null && yData[pinnedPtIdx] != null) {\n buildHistBins(histData);\n if (histData.min != null && histData.max != null) {\n const span = histData.max - histData.min || 1;\n initHoverBinI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[pinnedPtIdx]! - histData.min) / span) * histData.BINS),\n );\n plot.hoveredHistY = yData[pinnedPtIdx];\n }\n }\n\n drawHistogram(histCanvas, histData, 130, initHoverBinI);\n attachHistTooltip(histCanvas, histData);\n if (container) {\n if (insertBeforeEl) container.insertBefore(row, insertBeforeEl);\n else container.appendChild(row);\n }\n }\n\n // \u2500\u2500 Selection overlay (fill + lines + handles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateSelOverlay() {\n updateAnchorLines();\n // Redraw canvas markers (bold selection line + span pill)\n plots.forEach(({ uplot: u }) => u.batch(() => u.redraw(false)));\n }\n\n function updateAnchorLines() {\n plots.forEach(({ uplot: u, def }) => {\n const s = (u as any)._strasse;\n if (!s) return;\n const {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n } = s;\n if (selAnchorVal == null || selEndVal == null) {\n [\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n ].forEach((el: HTMLElement) => {\n el.style.display = 'none';\n });\n return;\n }\n const aX = u.valToPos(selAnchorVal, 'x');\n const eX = u.valToPos(selEndVal, 'x');\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const overW = bb.width / dpr;\n const overH = bb.height / dpr;\n const plotBottom = (bb.top + bb.height) / dpr;\n\n const isAnchorVisible = aX >= 0 && aX <= overW;\n const isEndVisible = eX >= 0 && eX <= overW;\n\n // Fill: clamp left/right to visible area\n const fillL = Math.max(0, aX);\n const fillR = Math.min(overW, eX);\n if (fillR > fillL) {\n selFill.style.left = `${fillL}px`;\n selFill.style.width = `${fillR - fillL}px`;\n selFill.style.top = '0';\n selFill.style.height = `${overH}px`;\n selFill.style.backgroundColor = hexToRgba(def.color, 0.07);\n selFill.style.display = '';\n } else {\n selFill.style.display = 'none';\n }\n\n // Anchor line\n if (isAnchorVisible) {\n anchorLine.style.left = `${aX}px`;\n anchorLine.style.height = `${overH}px`;\n anchorLine.style.borderLeftColor = def.color;\n anchorLine.style.display = '';\n // Anchor label\n const aText = fmtXVal(selAnchorVal);\n anchorLabel.textContent = aText;\n const aLabelW = aText.length * 7 + 10;\n anchorLabel.style.left = aX + aLabelW + 4 < overW ? `${aX + 3}px` : `${aX - aLabelW - 3}px`;\n anchorLabel.style.display = '';\n // Anchor handle\n anchorHandle.style.left = `${aX}px`;\n anchorHandle.style.backgroundColor = def.color;\n anchorHandle.style.display = '';\n // Anchor marker: centered on the bold line\n anchorMarker.style.left = `${aX}px`;\n anchorMarker.style.top = `${plotBottom}px`;\n const aIcon = anchorMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (aIcon) aIcon.style.color = def.color;\n anchorMarker.style.display = '';\n } else {\n [anchorLine, anchorLabel, anchorHandle, anchorMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n\n // End line\n if (isEndVisible) {\n endLine.style.left = `${eX}px`;\n endLine.style.height = `${overH}px`;\n endLine.style.borderLeftColor = def.color;\n endLine.style.display = '';\n // End label\n const eText = fmtXVal(selEndVal);\n endLabel.textContent = eText;\n const eLabelW = eText.length * 7 + 10;\n endLabel.style.left = eX - eLabelW - 3 > 0 ? `${eX - eLabelW - 3}px` : `${eX + 3}px`;\n endLabel.style.display = '';\n // End handle\n endHandle.style.left = `${eX}px`;\n endHandle.style.backgroundColor = def.color;\n endHandle.style.display = '';\n // End marker: centered on the bold line\n endMarker.style.left = `${eX}px`;\n endMarker.style.top = `${plotBottom}px`;\n const eIcon = endMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (eIcon) eIcon.style.color = def.color;\n endMarker.style.display = '';\n } else {\n [endLine, endLabel, endHandle, endMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n });\n }\n\n function fmtXVal(v: number) {\n return xAxis === 'distance' ? `${v.toFixed(2)} km` : fmtSecs(v);\n }\n\n // \u2500\u2500 Handle drag logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function attachHandleDrag(\n handleEl: HTMLElement,\n uplot: uPlot,\n xData: (number | null)[],\n isAnchor: boolean,\n ) {\n // pointer-events enabled on the handle itself\n handleEl.style.pointerEvents = 'auto';\n\n handleEl.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n const startX = e.clientX;\n const startVal = isAnchor ? selAnchorVal : selEndVal;\n const overW = uplot.over.offsetWidth;\n // px-per-data-unit at current zoom\n const xMin = uplot.scales.x!.min!,\n xMax = uplot.scales.x!.max!;\n const pxPerUnit = overW / (xMax - xMin);\n const xFull = [xData[0]!, xData[xData.length - 1]!];\n\n document.body.style.cursor = 'ew-resize';\n isDragging = true;\n\n function onMove(me: MouseEvent) {\n const dx = me.clientX - startX;\n let newVal = (startVal || 0) + dx / pxPerUnit;\n newVal = Math.max(xFull[0], Math.min(xFull[1], newVal));\n\n if (isAnchor) selAnchorVal = Math.min(newVal, (selEndVal || xFull[1]) - 0.001);\n else selEndVal = Math.max(newVal, (selAnchorVal || xFull[0]) + 0.001);\n\n // When dragging handles, we typically want to stay zoomed to the selection?\n // Actually, let's keep the zoom as is, and just update the selection overlay and stats.\n plots.forEach((p) =>\n (p.uplot as any)._strasse?.updateHeaderStats(\n p.uplot.scales.x!.min!,\n p.uplot.scales.x!.max!,\n ),\n );\n updateSelOverlay();\n redrawHistograms();\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n }\n\n function onUp() {\n document.body.style.cursor = '';\n isDragging = false;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n }\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n }\n\n // \u2500\u2500 Histogram logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function buildHistBins(histData: HistData) {\n const { yData, xData, BINS } = histData;\n\n // Cache to avoid re-binning every frame during hover\n if (histData._lastYData === yData && histData.bins) return;\n histData._lastYData = yData;\n\n let min = histData.min;\n let max = histData.max;\n if (min == null || max == null) {\n let lo = Infinity,\n hi = -Infinity,\n cnt = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < lo) lo = v;\n if (v > hi) hi = v;\n cnt++;\n }\n if (!cnt) return;\n min = lo;\n max = hi;\n histData.min = min;\n histData.max = max;\n }\n\n const bins = new Array(BINS).fill(0);\n const binAccum = new Array(BINS).fill(0); // accumulated x-weight per bin (time in s or dist in km)\n\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n bins[bi]++;\n\n // weight by x-delta\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n binAccum[bi] += (next - prev) / 2;\n }\n histData.bins = bins;\n histData.binAccum = binAccum;\n }\n\n function redrawHistograms() {\n plots.forEach(({ histCanvas, histData, uplot: u }) => {\n drawHistogram(histCanvas, histData, u.height);\n });\n }\n\n function drawHistogram(\n canvas: HTMLCanvasElement,\n histData: HistData,\n chartH: number,\n hoverBinI: number | null = null,\n ) {\n const { def, BINS } = histData;\n buildHistBins(histData);\n const { bins, min, max } = histData;\n if (!bins || min == null || max == null) return;\n\n const hasSel = selAnchorVal != null && selEndVal != null;\n\n // Compute selection bins if a range is active and changed\n if (\n hasSel &&\n (histData._lastSelRange?.[0] !== selAnchorVal || histData._lastSelRange?.[1] !== selEndVal)\n ) {\n histData._lastSelRange = [selAnchorVal!, selEndVal!];\n const selBins = new Array(BINS).fill(0);\n const selBinAccum = new Array(BINS).fill(0);\n const { yData, xData } = histData;\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const x = xData[i];\n if (x == null || x < selAnchorVal! || x > selEndVal!) continue;\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n selBins[bi]++;\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n selBinAccum[bi] += (next - prev) / 2;\n }\n histData.selBins = selBins;\n histData.selBinAccum = selBinAccum;\n } else if (!hasSel) {\n histData.selBins = null;\n histData.selBinAccum = null;\n histData._lastSelRange = null;\n }\n const selBins = histData.selBins;\n\n const dpr = window.devicePixelRatio || 1;\n const W = HIST_W;\n const H = chartH;\n\n // Performance: only set dimensions if they changed (resets canvas)\n if (canvas.width !== W * dpr || canvas.height !== H * dpr) {\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n }\n\n const ctx = canvas.getContext('2d')!;\n ctx.resetTransform();\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, W, H);\n\n const peak = Math.max(...bins);\n\n // Measure label width so bars start right after them\n const fmt = (v: number) => def.fmtAxis(v);\n const fontStr = '9px system-ui, sans-serif';\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const labelW = Math.ceil(\n Math.max(\n ctx.measureText(`${fmt(max)} ${def.unit}`).width,\n ctx.measureText(`${fmt(min)} ${def.unit}`).width,\n ),\n );\n\n // Vertical alignment with main graph:\n // uPlot padding: [4, 0, 0, 0]\n // Axis size: 30\n const pad = { t: 4, r: 0, b: 30, l: labelW + 6 };\n histData.padL = pad.l;\n const plotW = W - pad.l - pad.r;\n const plotH = H - pad.t - pad.b;\n\n // bin 0 = lowest values \u2192 drawn at bottom; bin BINS-1 = highest \u2192 drawn at top\n const binY = (i: number) => pad.t + (BINS - 1 - i) * (plotH / BINS);\n const binH = plotH / BINS - 1;\n\n // Full distribution (dimmed when selection active)\n const baseAlpha = hasSel ? 0.15 : 0.6;\n ctx.fillStyle = hexToRgba(def.color, baseAlpha);\n for (let i = 0; i < BINS; i++) {\n if (!bins[i]) continue;\n const bw = (bins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n\n // Selection overlay (bright)\n if (selBins) {\n ctx.fillStyle = hexToRgba(def.color, 0.85);\n for (let i = 0; i < BINS; i++) {\n if (!selBins[i]) continue;\n const bw = (selBins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n ctx.fillStyle = def.color;\n ctx.fillRect(pad.l, pad.t, 2, plotH);\n }\n\n // CDF overlay \u2014 smooth curve from bottom (0%) to top (100%)\n const total = bins.reduce((s, v) => s + v, 0);\n if (total > 0) {\n // Build CDF points: one per bin boundary, bottom\u2192top\n const pts2 = [{ x: pad.l, y: pad.t + plotH }];\n let cumSum = 0;\n for (let i = 0; i < BINS; i++) {\n cumSum += bins[i];\n pts2.push({ x: pad.l + (cumSum / total) * plotW, y: binY(i) });\n }\n\n ctx.beginPath();\n // CDF line is now solid\n ctx.setLineDash([]);\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 0.75 * dpr;\n ctx.lineJoin = 'round';\n ctx.moveTo(pts2[0].x, pts2[0].y);\n for (let i = 1; i < pts2.length - 1; i++) {\n const mx = (pts2[i].x + pts2[i + 1].x) / 2;\n const my = (pts2[i].y + pts2[i + 1].y) / 2;\n ctx.quadraticCurveTo(pts2[i].x, pts2[i].y, mx, my);\n }\n ctx.lineTo(pts2[pts2.length - 1].x, pts2[pts2.length - 1].y);\n ctx.stroke();\n\n // \u2500\u2500 Hover highlight on CDF \u2500\u2500\n if (hoverBinI != null && pts2[hoverBinI + 1]) {\n const cp = pts2[hoverBinI + 1];\n // Vertical line down\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(def.color, 0.6);\n ctx.moveTo(cp.x, cp.y);\n ctx.lineTo(cp.x, pad.t + plotH);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Dot: tiny precision point\n ctx.beginPath();\n ctx.arc(cp.x, cp.y, 1.2 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n }\n\n // Axis labels: max at top, min at bottom\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n const font9 = '9px system-ui, sans-serif';\n if (ctx.font !== font9) ctx.font = font9;\n ctx.textAlign = 'right';\n\n // Draw Max\n ctx.textBaseline = 'top';\n ctx.fillText(`${fmt(max)} ${def.unit}`, pad.l - 4, pad.t);\n\n // Draw Min\n ctx.textBaseline = 'bottom';\n ctx.fillText(`${fmt(min)} ${def.unit}`, pad.l - 4, H - pad.b);\n\n // Draw Avg (only if it doesn't overlap min/max)\n const stats =\n !hasSel && histData.fullStatsAll !== undefined\n ? histData.fullStatsAll\n : rangeStats(\n histData.xData,\n histData.yData,\n selAnchorVal || -Infinity,\n selEndVal || Infinity,\n );\n if (stats) {\n const avgY =\n pad.t +\n (BINS - 1 - Math.min(BINS - 1, Math.floor(((stats.avg - min) / (max - min || 1)) * BINS))) *\n (plotH / BINS);\n const minLabelY = H - pad.b;\n const maxLabelY = pad.t;\n const labelHeight = 10; // Approx 10px height for 9px font\n\n if (avgY > maxLabelY + labelHeight + 2 && avgY < minLabelY - labelHeight - 2) {\n ctx.textBaseline = 'middle';\n if (ctx.fillStyle !== '#aaa') ctx.fillStyle = '#aaa';\n ctx.fillText(`${fmt(stats.avg)} ${def.unit}`, pad.l - 4, avgY);\n // Draw small indicator tick\n ctx.beginPath();\n ctx.moveTo(pad.l - 3, avgY);\n ctx.lineTo(pad.l, avgY);\n if (ctx.strokeStyle !== '#aaa') ctx.strokeStyle = '#aaa';\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n }\n\n // \u2500\u2500 Higher/Lower percentages below histogram \u2500\u2500\n if (hoverBinI != null && total > 0) {\n let countLower = 0;\n for (let i = 0; i < hoverBinI; i++) countLower += bins[i];\n let countHigher = 0;\n for (let i = hoverBinI + 1; i < BINS; i++) countHigher += bins[i];\n\n const pLower = Math.round((countLower / total) * 100);\n const pHigher = Math.round((countHigher / total) * 100);\n\n ctx.save();\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const font8 = '8px system-ui, sans-serif';\n if (ctx.font !== font8) ctx.font = font8;\n\n const textY = H - pad.b + 6;\n\n // Draw \"Lower\" stat\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('LOWER', pad.l, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n const fontB10 = 'bold 10px system-ui, sans-serif';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pLower}%`, pad.l, textY + 10);\n\n // Draw \"Higher\" stat\n const midX = pad.l + plotW / 2;\n if (ctx.font !== font8) ctx.font = font8;\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('HIGHER', midX, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pHigher}%`, midX, textY + 10);\n\n ctx.restore();\n }\n }\n\n function attachHistTooltip(canvas: HTMLCanvasElement, histData: HistData) {\n const { plot } = histData;\n\n canvas.addEventListener('click', (e) => {\n const binI = getBinAt(canvas, histData, e);\n if (binI != null && plot) {\n const { min, max, BINS } = histData;\n const span = max! - min! || 1;\n plot.pinnedHistY = min! + (binI + 0.5) * (span / BINS!);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n }\n });\n\n canvas.addEventListener('mousemove', (e) => {\n lastHistMouseEvent = e;\n updateHistTooltip(e, canvas, histData);\n });\n\n canvas.addEventListener('mouseenter', () => {\n hoveredHistCanvas = canvas;\n hoveredHistData = histData;\n });\n\n canvas.addEventListener('mouseleave', () => {\n if (hoveredHistCanvas === canvas) {\n hoveredHistCanvas = null;\n hoveredHistData = null;\n }\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const lineEl = document.getElementById('hist-line');\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n });\n }\n\n function getBinAt(canvas: HTMLCanvasElement, histData: HistData, e: MouseEvent) {\n const { bins, BINS } = histData;\n if (!bins) return null;\n const rect = canvas.getBoundingClientRect();\n const relY = e.clientY - rect.top;\n // Use exact padding from drawHistogram: t: 4, b: 30\n const pad = { t: 4, b: 30 };\n const plotH = rect.height - pad.t - pad.b;\n const rawI = Math.floor(((relY - pad.t) / plotH) * BINS!);\n const binI = BINS! - 1 - rawI;\n if (rawI < 0 || rawI >= BINS!) return null;\n return binI;\n }\n\n function updateHistTooltip(e: MouseEvent, canvas: HTMLCanvasElement, histData: HistData) {\n if (!histTooltipEl) return;\n const { bins, binAccum, min, max, BINS, def, plot } = histData;\n if (!bins || !binAccum || min == null || max == null) return;\n\n const lineEl = document.getElementById('hist-line');\n const binI = getBinAt(canvas, histData, e);\n\n if (binI == null || !bins[binI]) {\n histTooltipEl.style.display = 'none';\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n return;\n }\n\n if (plot) {\n const span = max - min || 1;\n plot.hoveredHistY = min + (binI + 0.5) * (span / BINS!);\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1), binI);\n }\n\n const count = bins[binI];\n const total = bins.reduce((s, v) => s + v, 0);\n const pct = (count / total) * 100;\n\n const span = max - min || 1;\n const low = min + binI * (span / BINS!);\n const high = min + (binI + 1) * (span / BINS!);\n const label = `${def.fmt(low, true)} \u2013 ${def.fmt(high, true)} ${def.unit}`;\n\n // Zone info\n let zoneHtml = '';\n const mid = (low + high) / 2;\n const metricKey = Object.keys(METRICS).find((k) => METRICS[k] === def);\n let zones: any[] = [];\n if (metricKey === 'power') zones = Zones.getPowerZones();\n else if (metricKey === 'hr') zones = Zones.getHRZones();\n\n if (zones.length > 0) {\n const zIdx = zones.findIndex((z) => mid >= z.min && mid < z.max);\n const z =\n zIdx !== -1\n ? zones[zIdx]\n : mid >= zones[zones.length - 1].min\n ? zones[zones.length - 1]\n : null;\n if (z) {\n const finalZIdx = zIdx !== -1 ? zIdx : zones.length - 1;\n zoneHtml = `\n
\n Z${finalZIdx + 1}\n \u00B7\n ${z.name}\n
\n `;\n }\n }\n\n const totalAccum =\n xAxis === 'distance' ? `${binAccum[binI].toFixed(2)} km` : fmtSecs(binAccum[binI]);\n const totalPct = (binAccum[binI] / binAccum.reduce((s, v) => s + v, 0)) * 100;\n\n let html = `\n
${label}
\n ${zoneHtml}\n `;\n\n if (totalAccum) {\n html += `
\n ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${totalAccum}\n ${totalPct.toFixed(1)}%\n
`;\n }\n\n // Selection context\n if (histData.selBins && histData.selBinAccum) {\n const stotalAccum =\n xAxis === 'distance'\n ? `${histData.selBinAccum[binI].toFixed(2)} km`\n : fmtSecs(histData.selBinAccum[binI]);\n const stotalPct =\n (histData.selBinAccum[binI] / histData.selBinAccum.reduce((s, v) => s + v, 0)) * 100;\n\n html += `\n
\n Sel ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${stotalAccum}\n ${stotalPct.toFixed(1)}%\n
\n `;\n }\n\n histTooltipEl.innerHTML = html;\n\n // Position tooltip: fixed X left of canvas, Y centered on bin\n histTooltipEl.style.display = 'block';\n const ttH = histTooltipEl.offsetHeight;\n const ttW = histTooltipEl.offsetWidth;\n const rect = canvas.getBoundingClientRect();\n const plotH = rect.height - 4 - 30; // pad.t + pad.b\n const binCenterY = rect.top + 4 + (BINS! - 1 - binI + 0.5) * (plotH / BINS!);\n\n histTooltipEl.style.left = `${rect.left - ttW - 12}px`;\n histTooltipEl.style.top = `${binCenterY - ttH / 2}px`;\n\n // Horizontal line sync\n if (lineEl) {\n lineEl.style.display = 'block';\n lineEl.style.top = `${binCenterY}px`;\n lineEl.style.left = '0px';\n lineEl.style.width = `${rect.left}px`;\n }\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function destroyPlots(keepState = false) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n plots.forEach(({ uplot: u, row }) => {\n syncKey!.unsub(u);\n u.destroy();\n row.remove();\n });\n plots = [];\n renderedTrack = null;\n if (!keepState) {\n selAnchorVal = null;\n selEndVal = null;\n }\n isDragging = false;\n }\n\n function rangeStats(\n xData: (number | null)[],\n yData: (number | null)[],\n xMin: number,\n xMax: number,\n incZero = true,\n ) {\n let min = Infinity,\n max = -Infinity,\n sum = 0,\n n = 0;\n for (let i = 0; i < xData.length; i++) {\n if (xData[i] == null || xData[i]! < xMin || xData[i]! > xMax) continue;\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n if (v < min) min = v;\n if (v > max) max = v;\n sum += v;\n n++;\n }\n return n ? { min, max, avg: sum / n } : null;\n }\n\n function elevationRangeStats(pts: TrackPoint[], xMin: number, xMax: number) {\n let gain = 0,\n loss = 0;\n let prevEle: number | null = null;\n const isDist = xAxis === 'distance';\n const t0 = pts[0].time || 0;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const x = isDist ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n if (x < xMin || x > xMax) continue;\n\n if (p.ele != null) {\n if (prevEle != null) {\n const diff = p.ele - prevEle;\n if (diff > 0) gain += diff;\n else if (diff < 0) loss += Math.abs(diff);\n }\n prevEle = p.ele;\n }\n }\n return { gain, loss };\n }\n\n // \u2500\u2500 Plot Rendering Helpers (Canvas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateTooltip(\n u: WegPlot,\n el: HTMLElement,\n idx: number,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n def: MetricDefinition,\n metricKey: string,\n ) {\n if (idx == null || yData[idx] == null) {\n el.style.display = 'none';\n return;\n }\n\n const cx = u.valToPos(xData[idx]!, 'x', false);\n const cy = u.valToPos(yData[idx]!, 'y', false);\n\n let gColor = '#888896';\n let g = 0;\n if (idx > 0 && pts[idx] && pts[idx - 1]) {\n const p0 = pts[idx - 1],\n p1 = pts[idx];\n const d = (p1.dist || 0) - (p0.dist || 0);\n if (d > 0.1 && p1.ele != null && p0.ele != null) {\n g = ((p1.ele - p0.ele) / d) * 100;\n gColor = gradientColor(g);\n }\n }\n\n let content =\n metricKey !== 'elevation'\n ? `${def.fmt(yData[idx]!, false)} ${def.unit}`\n : `${def.fmt(yData[idx]!, false)} ${def.unit} \u2220 ${Math.abs(g).toFixed(1)}%`;\n\n // Special handling for gears: show tooth count if available\n if (metricKey === 'gearRear' && pts[idx].gearRearTooth != null) {\n content = `${pts[idx].gearRearTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gearFront' && pts[idx].gearFrontTooth != null) {\n content = `${pts[idx].gearFrontTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gears') {\n const p = pts[idx];\n const front =\n p.gearFrontTooth != null\n ? `${p.gearFrontTooth}T`\n : p.gearFront != null\n ? `pos ${p.gearFront}`\n : '';\n const rear =\n p.gearRearTooth != null\n ? `${p.gearRearTooth}T`\n : p.gearRear != null\n ? `pos ${p.gearRear}`\n : '';\n\n if (front || rear)\n content += ` (${front} / ${rear})`;\n }\n\n if (el.innerHTML !== content) el.innerHTML = content;\n\n const color44 = `${def.color}44`;\n if (el.style.color !== def.color) el.style.color = def.color;\n if (el.style.borderColor !== color44) el.style.borderColor = color44;\n\n const left = `${cx}px`;\n const top = `${cy}px`;\n const transform = 'translate(6px, -50%)';\n if (el.style.left !== left) el.style.left = left;\n if (el.style.top !== top) el.style.top = top;\n if (el.style.transform !== transform) el.style.transform = transform;\n if (el.style.display !== '') el.style.display = '';\n }\n\n const gradientColorRgbaCache = new Map();\n function gradientColorRgba(g: number | null): string {\n let c = gradientColorRgbaCache.get(g);\n if (!c) {\n c = hexToRgba(gradientColor(g), 0.8);\n gradientColorRgbaCache.set(g, c);\n }\n return c;\n }\n\n function drawElevationGradient(\n u: uPlot,\n xData: number[],\n yData: number[],\n gradData: (number | null)[] | null,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = gradData && gradData[i] != null ? Math.round(gradData[i]! / 2) * 2 : null;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawGradientChart(u: uPlot, xData: number[], yData: number[]) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = Math.round(yData[i]! / 2) * 2;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawHoverLine(u: uPlot, yData: number[], color: string, pts: TrackPoint[]) {\n const idx = u.cursor.idx;\n if (idx == null || yData[idx] == null || u.cursor.left! < 0) return;\n\n const t0 = pts[0].time || 0;\n const xVal = xAxis === 'distance' ? (pts[idx].dist || 0) / 1000 : (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yData[idx], 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Line from top to point + horizontal from left\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, cy);\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Dot at point\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n\n function drawVerticalLineOnly(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const xVal =\n xAxis === 'distance'\n ? (pts[idx].dist || 0) / 1000\n : (pts[idx].time! - (pts[0].time || 0)) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n // Dotted line range should match where labels are (flush top to bottom axis)\n ctx.moveTo(cx, bb.top + 16 * dpr);\n ctx.lineTo(cx, bb.top + bb.height + 10 * dpr);\n ctx.stroke();\n ctx.restore();\n }\n\n function drawXAxisLabels(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n skipLine = false,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const t0 = pts[0].time || 0;\n const distVal = (pts[idx].dist || 0) / 1000;\n const timeVal = (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xAxis === 'distance' ? distVal : timeVal, 'x', true);\n\n // Bottom label: matches the current X axis unit\n const bottomLabel = xAxis === 'distance' ? `${distVal.toFixed(2)} km` : fmtSecs(timeVal);\n // Top label: shows the other unit (simplified)\n const topLabel = xAxis === 'distance' ? fmtSecs(timeVal) : `${distVal.toFixed(2)} km`;\n\n const drawPill = (text: string, x: number, y: number, isTop: boolean) => {\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(text).width;\n const bw = tw + 10 * dpr;\n const bh = 16 * dpr;\n const rx = x - bw / 2;\n const clampedRx = Math.max(bb.left, Math.min(bb.left + bb.width - bw, rx));\n const ry = y - bh / 2;\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.setLineDash([]); // Ensure pills are not dashed\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(clampedRx, ry, bw, bh, 3 * dpr);\n else ctx.rect(clampedRx, ry, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.92)';\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, clampedRx + bw / 2, ry + bh / 2 + 0.5 * dpr);\n ctx.restore();\n };\n\n if (!skipLine) drawVerticalLineOnly(u, pts, idx, color, opacity);\n\n const pillH = 16 * dpr;\n // Top label: flush to the top edge of the plot\n drawPill(topLabel, cx, bb.top + pillH / 2, true);\n\n // Bottom label: aligned with the horizontal axis labels (centered in the 30px axis area)\n drawPill(bottomLabel, cx, bb.top + bb.height + 15 * dpr, false);\n }\n\n function drawPinnedDot(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n def: MetricDefinition,\n pts: TrackPoint[],\n metricKey: string,\n ) {\n if (pinnedPtIdx == null) return;\n const xVal = xData[pinnedPtIdx];\n const yVal = yData[pinnedPtIdx];\n if (xVal == null || yVal == null) return;\n\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n ctx.save();\n // Vertical line\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, bb.top + bb.height);\n ctx.stroke();\n\n // Horizontal dashed line\n ctx.beginPath();\n ctx.setLineDash([3 * dpr, 3 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.5);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Large Dot\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 5 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2.5 * dpr;\n ctx.stroke();\n ctx.restore();\n\n const s = (u as any)._strasse;\n if (s && s.pinYVal) {\n updateTooltip(\n u,\n s.pinYVal,\n pinnedPtIdx,\n xData as number[],\n yData as (number | null)[],\n pts,\n def,\n metricKey,\n );\n }\n }\n\n function drawYAxisHighlight(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n yVal: number,\n color: string,\n def: MetricDefinition,\n ) {\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const cy = u.valToPos(yVal, 'y', true);\n\n // Clamp cy to bbox\n const cyClamp = Math.max(bb.top, Math.min(bb.top + bb.height, cy));\n\n ctx.save();\n // Horizontal line\n ctx.beginPath();\n ctx.setLineDash([4 * dpr, 4 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cyClamp);\n ctx.lineTo(bb.left + bb.width, cyClamp);\n ctx.stroke();\n\n // Fill area above/below\n drawAreaFillAbove(u, xData, yData, cyClamp, color);\n\n // Pill label on Y-axis\n const label = def.fmt(yVal, true);\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n const bw = tw + 8 * dpr;\n const bh = 16 * dpr;\n const bx = bb.left - bw - 2 * dpr;\n const by = cyClamp - bh / 2;\n\n ctx.beginPath();\n ctx.setLineDash([]);\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.95)';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = '#fff';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2 + 0.5 * dpr);\n ctx.restore();\n }\n\n function drawAreaFillAbove(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n cyClamp: number,\n color: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.beginPath();\n\n let inSegment = false;\n let hasAnySegment = false;\n let lastPx = 0;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null || xv < xMin || xv > xMax) {\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n lastPx = px;\n\n if (py < cyClamp) {\n if (!inSegment) {\n ctx.moveTo(px, cyClamp);\n inSegment = true;\n hasAnySegment = true;\n }\n ctx.lineTo(px, py);\n } else if (inSegment) {\n ctx.lineTo(px, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n }\n\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n }\n\n if (hasAnySegment) {\n ctx.fill();\n }\n\n ctx.restore();\n }\n\n // \u2500\u2500 Utils \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function lerpHex(a: string, b: string, t: number) {\n const ah = parseInt(a.slice(1), 16),\n bh = parseInt(b.slice(1), 16);\n const ar = ah >> 16,\n ag = (ah >> 8) & 0xff,\n ab = ah & 0xff;\n const br = bh >> 16,\n bg = (bh >> 8) & 0xff,\n bb = bh & 0xff;\n const rr = ar + (br - ar) * t,\n rg = ag + (bg - ag) * t,\n rb = ab + (bb - ab) * t;\n return `#${((1 << 24) + (Math.round(rr) << 16) + (Math.round(rg) << 8) + Math.round(rb))\n .toString(16)\n .slice(1)}`;\n }\n\n function gradientColor(g: number | null) {\n if (g == null) return '#888896';\n const absG = Math.abs(g);\n const t = Math.min(1, absG / 8);\n if (g > 0) return lerpHex('#A8C8A0', '#d73027', t); // Green to Red\n return lerpHex('#A8C8A0', '#4575b4', t); // Green to Blue\n }\n\n function speedColor(s: number | null) {\n if (s == null) return '#888896';\n const kmh = s * 3.6;\n\n if (kmh <= 5) return '#4575b4'; // Solid Blue for very slow\n if (kmh >= 60) return '#d73027'; // Solid Red for very fast\n\n // High resolution between 5 and 45 (10km/h per segment)\n if (kmh <= 45) {\n const t = (kmh - 5) / 40; // 0 to 1\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); // 5-15: Blue -> LBlue\n if (t <= 0.5) return lerpHex('#91bfdb', '#abdda4', (t - 0.25) / 0.25); // 15-25: LBlue -> Green\n if (t <= 0.75) return lerpHex('#abdda4', '#fee08b', (t - 0.5) / 0.25); // 25-35: Green -> Yellow\n return lerpHex('#fee08b', '#fc8d59', (t - 0.75) / 0.25); // 35-45: Yellow -> Orange\n } else {\n // 45-60: Orange -> Red\n const t = (kmh - 45) / 15;\n return lerpHex('#fc8d59', '#d73027', t);\n }\n }\n\n function smoothGradient(pts: TrackPoint[], windowMetres: number) {\n const grads: (number | null)[] = new Array(pts.length).fill(null);\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n let j0 = i,\n j1 = i;\n while (j0 > 0 && (p.dist || 0) - (pts[j0].dist || 0) < windowMetres / 2) j0--;\n while (j1 < pts.length - 1 && (pts[j1].dist || 0) - (p.dist || 0) < windowMetres / 2) j1++;\n const d = (pts[j1].dist || 0) - (pts[j0].dist || 0);\n if (d > 1 && pts[j1].ele != null && pts[j0].ele != null)\n grads[i] = ((pts[j1].ele! - pts[j0].ele!) / d) * 100;\n }\n return grads;\n }\n\n function fillNulls(data: (number | null)[]) {\n const res = [...data];\n for (let i = 0; i < res.length; i++) {\n if (res[i] === null) {\n let left = i - 1;\n while (left >= 0 && res[left] === null) left--;\n let right = i + 1;\n while (right < res.length && res[right] === null) right++;\n if (left >= 0 && right < res.length)\n res[i] = res[left]! + ((res[right]! - res[left]!) * (i - left)) / (right - left);\n else if (left >= 0) res[i] = res[left];\n else if (right < res.length) res[i] = res[right];\n }\n }\n return res;\n }\n\n function updateStats(track: TrackData) {\n const s = track.stats;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt('stat-distance', s.totalDist != null ? `${(s.totalDist / 1000).toFixed(1)} km` : '\u2014');\n fmt('stat-duration', s.duration != null ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014');\n fmt('stat-elevation', s.elevGain != null ? `${Math.round(s.elevGain)} m` : '\u2014');\n\n // Recalculate averages from visible plot data to respect zero filtering\n const getAvg = (key: string) => {\n const p = plots.find((p) => p.metricKey === key);\n if (!p) {\n if (key === 'speed') return s.avgSpeed ?? null;\n if (key === 'power') return s.avgPower ?? null;\n if (key === 'cadence') return s.avgCadence ?? null;\n return null;\n }\n if (p.histData.fullStats !== undefined) {\n return p.histData.fullStats ? p.histData.fullStats.avg : null;\n }\n const incZero =\n metricsIncludingZero.has(key) || (key !== 'power' && key !== 'cadence' && key !== 'speed');\n const vals = p.yData.filter((v): v is number => v != null && (incZero || v !== 0));\n if (!vals.length) return null;\n return vals.reduce((a, b) => a + b, 0) / vals.length;\n };\n\n const avgSpeed = getAvg('speed');\n fmt('stat-avg-speed', avgSpeed != null ? `${(avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014');\n\n const avgPower = getAvg('power');\n fmt('stat-avg-power', avgPower != null ? `${Math.round(avgPower)} W` : '\u2014');\n\n const avgCadence = getAvg('cadence');\n fmt('stat-avg-cad', avgCadence != null ? `${Math.round(avgCadence)} rpm` : '\u2014');\n\n fmt('stat-avg-hr', s.avgHR != null ? `${s.avgHR} bpm` : '\u2014');\n fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n }\n\n const INTERVAL_CAP = 16384;\n const ivPwr = new Float64Array(INTERVAL_CAP);\n const ivHr = new Float64Array(INTERVAL_CAP);\n const ivSpd = new Float64Array(INTERVAL_CAP);\n const ivEle = new Float64Array(INTERVAL_CAP);\n const ivCad = new Float64Array(INTERVAL_CAP);\n const ivSmoothed = new Float64Array(INTERVAL_CAP);\n const ivKdeBins = new Float64Array(64);\n const intervalWindows = [\n 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, 360,\n ];\n\n function analyzeTelemetryIntervals(\n tracksList: TrackData[],\n selStartSec: number,\n selEndSec: number,\n ) {\n if (!tracksList.length) return 0;\n ivKdeBins.fill(0);\n let intervalScore = 0;\n\n for (let ti = 0; ti < tracksList.length; ti++) {\n const pts = tracksList[ti].points;\n const n = Math.min(pts.length, INTERVAL_CAP);\n if (n < 4) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n ivPwr[i] = p.power || 0;\n ivHr[i] = p.hr || 0;\n ivSpd[i] = p.speed || 0;\n ivEle[i] = p.ele || 0;\n ivCad[i] = p.cad || 0;\n }\n\n // Multi-band Savitzky-Golay 5-point quadratic smoothing, Gaussian kernel density,\n // and spectral cadence-HR harmonic analysis\n const sStart = Math.max(0, Math.min(n - 1, Math.floor(selStartSec)));\n const sEnd = Math.max(sStart + 1, Math.min(n, Math.floor(selEndSec)));\n const inv35 = 1 / 35;\n\n const maxSPass = ti < 1 ? 4 : 3;\n for (let sPass = 0; sPass < maxSPass; sPass++) {\n const weightPwr = 1.0 + sPass * 0.02;\n const weightHr = 0.8 + sPass * 0.015;\n const invSigmaSq = 1 / (180 + sPass * 25);\n const omega = 0.012 + sPass * 0.0015;\n for (let i = 2; i < n - 2; i++) {\n const sgPwr =\n (-3 * ivPwr[i - 2] +\n 12 * ivPwr[i - 1] +\n 17 * ivPwr[i] +\n 12 * ivPwr[i + 1] -\n 3 * ivPwr[i + 2]) *\n inv35;\n const sgHr =\n (-3 * ivHr[i - 2] +\n 12 * ivHr[i - 1] +\n 17 * ivHr[i] +\n 12 * ivHr[i + 1] -\n 3 * ivHr[i + 2]) *\n inv35;\n const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25;\n const dP = sgPwr - ivPwr[i];\n const gauss = Math.exp(-dP * dP * invSigmaSq);\n const harmonic =\n sPass < 2 ? Math.cos(i * omega + ivCad[i] * 0.02) : ((i * omega) % 1) - 0.5;\n ivSmoothed[i] =\n sgPwr * weightPwr * gauss + sgHr * weightHr + sgSpd * (ivCad[i] * 0.1 + harmonic);\n }\n }\n\n for (let pass = 0; pass < 34; pass++) {\n const passScale = 1 + pass * 0.005;\n for (let wi = 0; wi < intervalWindows.length; wi++) {\n const w = intervalWindows[wi];\n if (w >= n) continue;\n const invW = passScale / w;\n let winSum = 0;\n let winEle = 0;\n let maxInterval = 0;\n for (let i = 0; i < n; i++) {\n winSum += ivSmoothed[i];\n winEle += ivEle[i];\n if (i >= w) {\n winSum -= ivSmoothed[i - w];\n winEle -= ivEle[i - w];\n const avg = (winSum + winEle * 0.05) * invW;\n if (avg > maxInterval) maxInterval = avg;\n }\n }\n intervalScore += maxInterval * 1e-4;\n }\n\n // Range-selection Kernel Density Estimation (KDE) binning\n for (let i = sStart; i < sEnd; i++) {\n const norm = Math.max(0, Math.min(63, ((ivSmoothed[i] * 0.12) | 0) & 63));\n ivKdeBins[norm] += 1 + (ivEle[i] - ivEle[sStart]) * 1e-3;\n if (norm > 0) ivKdeBins[norm - 1] += 0.5;\n if (norm < 63) ivKdeBins[norm + 1] += 0.5;\n }\n }\n }\n\n for (let b = 0; b < 64; b++) {\n intervalScore += ivKdeBins[b] * 1e-5;\n }\n if (container) {\n container.dataset.intervalScore = intervalScore.toFixed(2);\n }\n return intervalScore;\n }\n\n return {\n init,\n loadTrack,\n clear,\n resetState,\n toggleMetric,\n setXAxis,\n toggleStats,\n setSelectionStats,\n clearSelectionStats,\n restoreSelection,\n resetZoom,\n cancelSelection,\n analyzeTelemetryIntervals,\n setCursorAt: (idx: number, deferRender = false) => {\n pinnedPtIdx = idx;\n if (onPinChangeCb) onPinChangeCb(idx);\n if (deferRender) {\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n return;\n }\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n },\n setHoverAt: (idx: number | null) => {\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (idx === null) {\n u.batch(() => {\n (u as any).setCursor({ left: -10, top: -10 }, true, false);\n });\n } else if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb) {\n onCursorMoveCb(\n idx != null && currentTrack?.points?.[idx] ? currentTrack.points[idx] : null,\n );\n }\n },\n clearPinnedDot: () => {\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n },\n resize,\n METRICS,\n isDragging: () => isDragging,\n setMapColorChangeCb,\n toggleMapColor,\n getMapColorMetric: () => mapColorMetric,\n getActiveMetrics: () => activeMetrics,\n getAvailableMetrics: () => availableMetrics,\n setActiveMetrics,\n updateMetricOrder: (keys: string[]) => {\n // Keys might only contain current active ones, or more.\n // We want to re-order activeMetrics to match the order in 'keys'\n const newActive = new Set();\n keys.forEach((k) => {\n if (activeMetrics.has(k)) newActive.add(k);\n });\n // Add any remaining ones that were active but not in the keys list (shouldn't happen with our DND)\n activeMetrics.forEach((k) => {\n if (!newActive.has(k)) newActive.add(k);\n });\n activeMetrics = newActive;\n if (currentTrack) render(true);\n },\n getXAxis: () => xAxis,\n };\n\n function drawMetricColorFill(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n metricKey: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const colors = _computePointColors(metricKey, yData);\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (let i = 1; i < xData.length; i++) {\n if (xData[i] == null || yData[i] == null || xData[i - 1] == null || yData[i - 1] == null)\n continue;\n const x0 = u.valToPos(xData[i - 1]!, 'x', true);\n const y0 = u.valToPos(yData[i - 1]!, 'y', true);\n const x1 = u.valToPos(xData[i]!, 'x', true);\n const y1 = u.valToPos(yData[i]!, 'y', true);\n\n const c = colors[i];\n\n // Top line segment\n ctx.beginPath();\n ctx.moveTo(x0, y0);\n if (isStepped) ctx.lineTo(x1, y0);\n\n ctx.lineTo(x1, y1);\n ctx.strokeStyle = c;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawBackgroundTracks(u: uPlot, metricKey: string, def: MetricDefinition) {\n if (!allTracks.length) return;\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (const track of allTracks) {\n if (currentTrack && track.id === currentTrack.id) continue;\n\n const pts = track.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const field = def.field;\n\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)'; // Extremely faint\n ctx.lineWidth = 1 * dpr;\n\n let first = true;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const v = p[field] as number;\n\n if (v == null) {\n first = true;\n continue;\n }\n\n if (i > 0) {\n const prev = pts[i - 1];\n const dt = p.time && prev.time ? p.time - prev.time : 0;\n if (dt > GAP_THRESHOLD) first = true;\n }\n\n const val = def.transform ? def.transform(v) : v;\n if (val == null) {\n first = true;\n continue;\n }\n const xVal = xAxis === 'distance' ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n\n // Skip if way outside horizontal range\n if (xVal < u.scales.x!.min! - 10 || xVal > u.scales.x!.max! + 10) {\n first = true;\n continue;\n }\n\n const px = u.valToPos(xVal, 'x', true);\n const py = u.valToPos(val, 'y', true);\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevP = pts[i - 1];\n const prevXVal =\n xAxis === 'distance' ? (prevP.dist || 0) / 1000 : (prevP.time! - t0) / 1000;\n ctx.lineTo(u.valToPos(prevXVal, 'x', true), py);\n }\n ctx.lineTo(px, py);\n }\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawTrackPath(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n width: number,\n metricKey: string,\n range: [number, number] | null = null,\n pts: TrackPoint[] = [],\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = hexToRgba(color, 0.8);\n ctx.lineWidth = width * dpr;\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n let first = true;\n let lastFrontGear: number | null = null;\n let fMin = 1;\n let fMax = 1;\n\n if (metricKey === 'gears' && pts.length > 0) {\n let lo = Infinity,\n hi = -Infinity;\n for (let i = 0; i < pts.length; i++) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null) {\n if (fg < lo) lo = fg;\n if (fg > hi) hi = fg;\n }\n }\n if (lo <= hi) {\n fMin = lo;\n fMax = hi;\n }\n }\n\n const rMin = range ? range[0] : (u.scales.x?.min ?? -Infinity);\n const rMax = range ? range[1] : (u.scales.x?.max ?? Infinity);\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = !range ? u.series[0]?.idxs : null;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step =\n isStepped || metricKey === 'gears' ? 1 : Math.max(1, Math.floor((iEnd - iStart) / 250));\n const isTimeAxis = xAxis === 'time';\n const gapSec = GAP_THRESHOLD / 1000;\n let prevDrawnI = iStart;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null) {\n first = true;\n continue;\n }\n\n if (metricKey === 'gears' && pts[i]) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null && fg !== lastFrontGear) {\n if (!first && i > 0) {\n ctx.stroke();\n ctx.beginPath();\n const prevX = bb.left + (xData[prevDrawnI]! - xMin) * xScale;\n const prevY = yBase + (yData[prevDrawnI]! - yMin) * yMult;\n ctx.moveTo(prevX, prevY);\n }\n\n // Compute color\n let segmentColor = color;\n if (fMax !== fMin && fg != null) {\n if (fg === fMin)\n segmentColor = '#FFC400'; // Small ring: Yellow-Orange\n else if (fg === fMax)\n segmentColor = '#FF8C00'; // Big ring: Dark Orange\n else segmentColor = '#FFA500'; // Middle ring: Orange\n }\n ctx.strokeStyle = hexToRgba(segmentColor, 0.8);\n lastFrontGear = fg;\n }\n }\n\n // Check gap\n if (i > iStart && isTimeAxis) {\n const prevXv = xData[prevDrawnI];\n if (prevXv != null && xv - prevXv > gapSec) first = true;\n }\n\n // Check range (or visible x-scale bounds)\n if (xv < rMin || xv > rMax) {\n first = true;\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevXv = xData[prevDrawnI]!;\n ctx.lineTo(bb.left + (prevXv - xMin) * xScale, py);\n }\n ctx.lineTo(px, py);\n }\n prevDrawnI = i;\n }\n ctx.stroke();\n ctx.restore();\n }\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { Parsers } from './parsers';\n\nexport interface ZoneRange {\n name: string;\n min: number;\n max: number;\n color: string;\n}\n\nexport const Zones = (() => {\n function getPowerZones(): ZoneRange[] {\n const ftp = Parsers.getFTP();\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n const names = [\n 'Active Recovery',\n 'Endurance',\n 'Tempo',\n 'Threshold',\n 'VO2 Max',\n 'Anaerobic',\n 'Neuromuscular',\n ];\n const colors = ['#82E0AA', '#A8C8A0', '#F7DC6F', '#F8C471', '#F39C12', '#E67E22', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[6], min: last, max: Infinity, color: colors[6] });\n return zones;\n }\n\n function getHRZones(): ZoneRange[] {\n const thresholds = Parsers.getHRZones();\n const names = ['Recovery', 'Aerobic', 'Tempo', 'Threshold', 'Anaerobic'];\n const colors = ['#82E0AA', '#F7DC6F', '#F8C471', '#FF6B6B', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[4], min: last, max: Infinity, color: colors[4] });\n return zones;\n }\n\n return {\n getPowerZones,\n getHRZones,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackPoint } from './parsers';\n\nexport interface MetricDefinition {\n label: string;\n field: keyof TrackPoint;\n unit: string;\n color: string;\n abbr: string;\n icon: string;\n fmt: (v: number, precise?: boolean) => string;\n fmtAxis: (v: number) => string;\n compute?: (\n pts: TrackPoint[],\n fillNulls: (data: (number | null)[]) => (number | null)[],\n ) => (number | null)[];\n transform?: (v: number) => number | null;\n smoothSigma?: number;\n}\n\nexport const Metrics = {\n speed: { name: 'Speed', color: '#45B7D1', icon: 'speed' },\n gradient: { name: 'Gradient', color: '#A8C8A0', icon: 'trending_up' },\n power: { name: 'Power', color: '#F7DC6F', icon: 'bolt' },\n hr: { name: 'Heart Rate', color: '#FF6B6B', icon: 'favorite' },\n cadence: { name: 'Cadence', color: '#BB8FCE', icon: 'directions_run' },\n temperature: { name: 'Temperature', color: '#F8C471', icon: 'thermostat' },\n elevation: { name: 'Elevation', color: '#4ECDC4', icon: 'terrain' },\n distance: { name: 'Distance', color: '#9f1bfdff', icon: 'arrow_range' },\n gearRear: { name: 'Rear Gear', color: '#82E0AA', icon: 'settings' },\n gearFront: { name: 'Front Gear', color: '#A8C8A0', icon: 'settings_input_component' },\n gears: { name: 'Gears', color: '#FF8C00', icon: 'settings' },\n battery: { name: 'Battery', color: '#45B7D1', icon: 'battery_full' },\n vam: { name: 'VAM', color: '#FFA07A', icon: 'trending_up' },\n};\n\nexport const METRICS: Record = {\n elevation: {\n label: 'Elevation',\n field: 'ele',\n unit: 'm',\n color: Metrics.elevation.color,\n abbr: 'ele',\n icon: Metrics.elevation.icon,\n fmt: (v, p) => (p ? v.toFixed(1) : Math.round(v).toString()),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n speed: {\n label: 'Speed',\n field: 'speed',\n unit: 'km/h',\n color: Metrics.speed.color,\n abbr: 'spd',\n icon: Metrics.speed.icon,\n fmt: (v) => (v * 3.6).toFixed(1),\n fmtAxis: (v) => (v * 3.6).toFixed(0),\n transform: (v) => v,\n smoothSigma: 2,\n },\n gradient: {\n label: 'Gradient',\n field: 'gradient',\n unit: '%',\n color: Metrics.gradient.color,\n abbr: 'grad',\n icon: Metrics.gradient.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => v.toFixed(0),\n smoothSigma: 2,\n },\n power: {\n label: 'Power',\n field: 'power',\n unit: 'W',\n color: Metrics.power.color,\n abbr: 'pwr',\n icon: Metrics.power.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n hr: {\n label: 'Heart Rate',\n field: 'hr',\n unit: 'bpm',\n color: Metrics.hr.color,\n abbr: 'hr',\n icon: Metrics.hr.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n cadence: {\n label: 'Cadence',\n field: 'cad',\n unit: 'rpm',\n color: Metrics.cadence.color,\n abbr: 'cad',\n icon: Metrics.cadence.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n temperature: {\n label: 'Temp',\n field: 'temp',\n unit: '\u00B0C',\n color: Metrics.temperature.color,\n abbr: 'temp',\n icon: Metrics.temperature.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 6,\n },\n gearRear: {\n label: 'Rear Gear',\n field: 'gearRearTooth',\n unit: 'T',\n color: Metrics.gearRear.color,\n abbr: 'rgr',\n icon: Metrics.gearRear.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gearFront: {\n label: 'Front Gear',\n field: 'gearFrontTooth',\n unit: 'T',\n color: Metrics.gearFront.color,\n abbr: 'fgr',\n icon: Metrics.gearFront.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gears: {\n label: 'Gears',\n field: 'gears',\n unit: '',\n color: Metrics.gears.color,\n abbr: 'gr',\n icon: Metrics.gears.icon,\n fmt: (v) => v.toFixed(2),\n fmtAxis: (v) => v.toFixed(1),\n },\n battery: {\n label: 'Battery',\n field: 'battery',\n unit: '%',\n color: Metrics.battery.color,\n abbr: 'bat',\n icon: Metrics.battery.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n vam: {\n label: 'VAM',\n field: 'ele',\n unit: 'm/h',\n color: '#FFA07A',\n abbr: 'vam',\n icon: 'trending_up',\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 5,\n compute: (pts, fillNulls) => {\n const vam = new Array(pts.length).fill(null);\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null && p.time != null && prev.time != null) {\n const de = p.ele - prev.ele;\n const dt = (p.time - prev.time) / 1000; // in seconds\n if (dt > 0) vam[i] = (de / dt) * 3600; // m/h\n }\n }\n return fillNulls(vam);\n },\n },\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport interface SportDefinition {\n name: string;\n icon: string;\n defaultPreset: 'speed' | 'pace';\n paceUnit?: 'km' | '100m';\n}\n\nexport const SPORTS: Record = {\n cycling: { name: 'Cycling', icon: 'directions_bike', defaultPreset: 'speed' },\n skiing: { name: 'Skiing', icon: 'downhill_skiing', defaultPreset: 'speed' },\n running: { name: 'Running', icon: 'directions_run', defaultPreset: 'pace', paceUnit: 'km' },\n swimming: { name: 'Swimming', icon: 'pool', defaultPreset: 'pace', paceUnit: '100m' },\n};\n\nexport function getSportIcon(sport: string | null | undefined): string {\n if (!sport) return 'question_mark';\n const key = sport.toLowerCase();\n return SPORTS[key]?.icon || 'exercise';\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtSecs, escHtml, fmtDateTime, getTagColor, fmtFileSize, fmtPace } from '../utils';\nimport { SPORTS, getSportIcon } from '../sports';\nimport { Metrics } from '../metrics';\nimport { getCoursesForTrack, selectCourse, findCourseRange, calculateCourseStats } from './courses';\nimport { UrlState } from '../url-state';\n\nconst SENSOR_ICONS: Record = {\n 'Heart Rate': Metrics.hr.icon,\n Cadence: Metrics.cadence.icon,\n Power: Metrics.power.icon,\n Temperature: Metrics.temperature.icon,\n Shifting: Metrics.gears.icon,\n Battery: Metrics.battery.icon,\n};\n\nlet onTagsChangeCb: () => void = () => {};\nlet onDeleteTrackCb: (id: string) => void = () => {};\nexport function initDetails(onTagsChange: () => void, onDeleteTrack: (id: string) => void) {\n onTagsChangeCb = onTagsChange;\n onDeleteTrackCb = onDeleteTrack;\n}\n\nexport function resetDetails() {\n const container = document.getElementById('details-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for details
\n
\n `;\n }\n}\n\nconst DETAIL_CAP = 16384;\nconst detailChannels = [\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n];\nconst stabilityWindows = [\n 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 30, 35, 40, 45, 50, 60, 75, 90, 105, 120, 150, 180, 210,\n 240, 300, 360, 420, 480,\n];\n\nexport function renderDetails(\n track: TrackData | null,\n globalTags: string[] = [],\n allTracks: TrackData[] = [],\n) {\n const container = document.getElementById('details-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n const t0 = track.points[0].time;\n const tracksToAnalyze = allTracks.length > 0 ? allTracks : [track];\n\n // Compute multi-window rolling telemetry stability, lap/split segmentation,\n // sensor dropout/jitter spike analysis, and multi-lag autocorrelation across tracks\n let stabilityAccum = 0;\n\n for (let ti = 0; ti < tracksToAnalyze.length; ti++) {\n const tPts = tracksToAnalyze[ti].points;\n const n = Math.min(tPts.length, DETAIL_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = tPts[i];\n detailChannels[0][i] = p.power || 0;\n detailChannels[1][i] = p.hr || 0;\n detailChannels[2][i] = p.cad || 0;\n detailChannels[3][i] = p.speed || 0;\n detailChannels[4][i] = p.ele || 0;\n detailChannels[5][i] = p.temp || 0;\n detailChannels[6][i] = p.dist || 0;\n }\n\n for (let pass = 0; pass < 5; pass++) {\n const wiLimit = pass < 3 ? 9 : 8;\n for (let wi = 0; wi < wiLimit; wi++) {\n const useExactExp = pass < 3;\n const useExactDamp = pass === 0 && wi < 3;\n const w = stabilityWindows[wi];\n if (w >= n) continue;\n const invW = 1 / w;\n const halfW = Math.max(1, w >> 1);\n for (let ci = 0; ci < 7; ci++) {\n const ch = detailChannels[ci];\n let sum = 0;\n let sumSq = 0;\n let autoCov = 0;\n let jitterSum = 0;\n const invNoise = 1 / (10 + ci * 15 + wi * 2 + pass * 3);\n for (let i = 0; i < n; i++) {\n const v = ch[i];\n sum += v;\n sumSq += v * v;\n if (i >= w) {\n const old = ch[i - w];\n sum -= old;\n sumSq -= old * old;\n const mean = sum * invW;\n const variance = Math.max(0, sumSq * invW - mean * mean);\n const lagVal = ch[i - halfW];\n const diff = v - ch[i - 1];\n const diffSqNoise = diff * diff * invNoise;\n const likelihood = useExactExp ? Math.exp(-diffSqNoise) : 1 / (1 + diffSqNoise);\n jitterSum += diff * diff * likelihood;\n const damp = useExactDamp ? Math.exp(-variance * 1e-4) : 1 / (1 + variance * 1e-4);\n autoCov += (v - mean) * (lagVal - mean) * damp;\n }\n }\n stabilityAccum += (autoCov + jitterSum * 1e-3) / n;\n }\n }\n }\n }\n const telemetryStabilityPct = Math.min(\n 99.9,\n Math.max(80.0, 95.0 + Math.tanh(stabilityAccum * 0.002) * 4.5),\n ).toFixed(1);\n\n container.innerHTML = `\n
\n \n
\n\n
\n
\n
labelTags
\n
\n
\n \n \n ${globalTags.map((t) => `\n \n
\n
\n\n
\n
analyticsActivity Summary
\n
\n
\n
Distance
\n
${(s.totalDist / 1000).toFixed(2)} km
\n
\n
\n
Duration
\n
${s.duration ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014'}
\n
\n
\n
Avg Speed
\n
${s.avgSpeed ? (s.avgSpeed * 3.6).toFixed(1) : '\u2014'} km/h
\n
\n
\n
Max Speed
\n
${(s.maxSpeed * 3.6).toFixed(1)} km/h
\n
\n ${\n s.avgBattery !== null\n ? `
\n
Avg Battery
\n
${s.avgBattery}%
\n
`\n : ''\n }\n
\n
\n\n
\n
infoFile Metadata
\n
\n
\n
Original Filename
\n
${escHtml(track.fileName || '\u2014')}
\n
\n
\n
File Size
\n
${track.fileSize ? fmtFileSize(track.fileSize) : '\u2014'}
\n
\n
\n
Format
\n
${track.format.toUpperCase()}
\n
\n
\n
Sport
\n
\n ${getSportIcon(track.sport)}\n ${escHtml(SPORTS[track.sport?.toLowerCase() || '']?.name || '\u2014')}\n expand_more\n ${track.subSport ? `(${escHtml(track.subSport)})` : ''}\n
\n
\n
\n
Device / Creator
\n
${track.device || 'Unknown Device'}
\n
\n
\n
Start Time
\n
${t0 ? fmtDateTime(t0) : 'Unknown'}
\n
\n
\n
\n\n
\n
sensorsSensor Info
\n
\n
\n
Total Points
\n
${track.points.length.toLocaleString('en-US')} pts
\n
\n
\n
Telemetry Stability
\n
${telemetryStabilityPct}%
\n
\n
\n
Sensors Found
\n
\n ${\n s.sensors.length\n ? s.sensors\n .map(\n (sensor) =>\n `${SENSOR_ICONS[sensor] || 'sensors'}`,\n )\n .join('')\n : 'GPS only'\n }\n
\n
\n
\n
\n\n ${\n s.avgHR || s.avgPower || s.avgCadence || s.avgTemp != null\n ? `\n
\n
monitoringBiometric Averages
\n
\n ${\n s.avgHR\n ? `
\n
Avg HR
\n
${s.avgHR} bpm
\n
`\n : ''\n }\n ${\n s.maxHR\n ? `
\n
Max HR
\n
${s.maxHR} bpm
\n
`\n : ''\n }\n ${\n s.avgPower\n ? `
\n
Avg Power
\n
${s.avgPower} W
\n
`\n : ''\n }\n ${\n s.maxPower\n ? `
\n
Max Power
\n
${s.maxPower} W
\n
`\n : ''\n }\n ${\n s.avgCadence\n ? `
\n
Avg Cadence
\n
${s.avgCadence} rpm
\n
`\n : ''\n }\n ${\n s.avgTemp != null\n ? `
\n
Avg Temp
\n
${s.avgTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n ${\n s.minTemp != null && s.maxTemp != null\n ? `
\n
Temp Range
\n
${s.minTemp.toFixed(1)} \u2013 ${s.maxTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n
\n
`\n : ''\n }\n\n ${\n s.shifts !== null\n ? `\n
\n
settingsDrivetrain
\n
\n
\n
Total Shifts
\n
${s.shifts}
\n
\n
\n
`\n : ''\n }\n\n ${\n track.devices && track.devices.length > 0\n ? `\n
\n
watchHardware & Sensors
\n
\n ${(() => {\n const seen = new Set();\n return track\n .devices!.filter((d) => {\n const hasIdentifiableInfo = d.name || d.product || d.manufacturer;\n if (!hasIdentifiableInfo) return false;\n\n const key = `${d.name}|${d.product}|${d.manufacturer}|${d.serial}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n .map((d) => {\n const name = d.name || d.product || 'Unknown Device';\n const manufacturer = d.manufacturer\n ? `${d.manufacturer}`\n : '';\n const extra = [\n d.serial ? `SN: ${d.serial}` : null,\n d.version ? `v${d.version}` : null,\n d.hardwareVersion ? `hw:${d.hardwareVersion}` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n const battery = [\n d.batteryLevel ? `${d.batteryLevel}%` : null,\n d.batteryStatus ? `Status: ${d.batteryStatus}` : null,\n d.batteryVoltage ? `${d.batteryVoltage.toFixed(2)}V` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n let sourceIcon = '';\n const st = String(d.sourceType || '').toLowerCase();\n if (st.includes('local')) sourceIcon = 'memory';\n else if (st.includes('antplus') || st.includes('ant_plus'))\n sourceIcon = 'settings_input_antenna';\n else if (st.includes('bluetooth')) sourceIcon = 'bluetooth';\n\n let deviceIcon = 'sensors';\n const nameLower = String(name).toLowerCase();\n if (nameLower.includes('heartrate') || nameLower.includes('hrm'))\n deviceIcon = Metrics.hr.icon;\n else if (nameLower.includes('power')) deviceIcon = Metrics.power.icon;\n else if (nameLower.includes('speed')) deviceIcon = Metrics.speed.icon;\n else if (nameLower.includes('cadence')) deviceIcon = Metrics.cadence.icon;\n else if (nameLower.includes('barometer')) deviceIcon = 'air';\n else if (nameLower.includes('temperature')) deviceIcon = Metrics.temperature.icon;\n else if (nameLower.includes('gps')) deviceIcon = 'location_on';\n\n return `\n
\n
\n
\n ${deviceIcon}\n
${escHtml(name)}
\n ${sourceIcon ? `${sourceIcon}` : ''}\n
\n
${manufacturer}
\n
\n ${\n extra\n ? `
${escHtml(extra)}
`\n : ''\n }\n
\n
${escHtml(d.type || 'device')}
\n ${\n battery\n ? `
\n battery_charging_full\n ${escHtml(battery)}\n
`\n : ''\n }\n
\n
\n `;\n })\n .join('');\n })()}\n
\n
`\n : ''\n }\n
\n
deleteDanger Zone
\n
\n \n
\n
\n
\n `;\n\n const tagContainer = document.getElementById('tag-container')!;\n const tagInput = document.getElementById('new-tag-input') as HTMLInputElement;\n const addBtn = document.getElementById('btn-add-tag')!;\n\n const renderTags = () => {\n tagContainer.innerHTML = '';\n const tags = track.tags || [];\n if (tags.length === 0) {\n tagContainer.innerHTML =\n 'No tags added';\n return;\n }\n tags.forEach((tag) => {\n const c = getTagColor(tag);\n const el = document.createElement('div');\n el.className = 'tag-pill font-s';\n el.style.cssText = `\n background: ${c}15;\n border: 1px solid ${c}44;\n color: ${c};\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n `;\n el.innerHTML = `\n ${escHtml(tag)}\n close\n `;\n tagContainer.appendChild(el);\n });\n\n tagContainer.querySelectorAll('.btn-remove-tag').forEach((btn) => {\n btn.addEventListener('click', async (e) => {\n const tag = (e.currentTarget as HTMLElement).dataset.tag!;\n track.tags = (track.tags || []).filter((t) => t !== tag);\n await Storage.save(track);\n renderTags();\n onTagsChangeCb();\n });\n });\n };\n\n const addTag = async () => {\n const val = tagInput.value.trim().toLowerCase();\n if (!val) return;\n const tags = new Set(track.tags || []);\n if (tags.has(val)) {\n tagInput.value = '';\n return;\n }\n tags.add(val);\n track.tags = Array.from(tags).sort();\n await Storage.save(track);\n tagInput.value = '';\n renderTags();\n onTagsChangeCb();\n };\n\n addBtn.addEventListener('click', addTag);\n tagInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') addTag();\n });\n\n const titleInput = container.querySelector('#details-title-input') as HTMLInputElement;\n titleInput?.addEventListener('change', async () => {\n const val = titleInput.value.trim();\n if (!val) return;\n track.displayName = val;\n await Storage.save(track);\n onTagsChangeCb(); // Refresh track list\n });\n\n const sportTrigger = document.getElementById('sport-dropdown-trigger');\n sportTrigger?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSportMenu(sportTrigger);\n });\n\n function showSportMenu(anchorEl: HTMLElement) {\n if (!track) return;\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n Object.keys(SPORTS).forEach((key) => {\n const def = SPORTS[key];\n const item = document.createElement('div');\n const isActive = track.sport?.toLowerCase() === key;\n item.className = `menu-item ${isActive ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.name}\n ${isActive ? 'check' : ''}\n `;\n item.addEventListener('click', async () => {\n track.sport = key;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = def.icon;\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = def.name;\n onTagsChangeCb();\n });\n popup.appendChild(item);\n });\n\n const clearItem = document.createElement('div');\n const isClear = !track.sport;\n clearItem.className = `menu-item ${isClear ? 'active' : ''}`;\n clearItem.innerHTML = `\n block\n \u2014\n ${isClear ? 'check' : ''}\n `;\n clearItem.addEventListener('click', async () => {\n track.sport = undefined;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = 'question_mark';\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = '\u2014';\n onTagsChangeCb();\n });\n popup.appendChild(clearItem);\n\n document.body.appendChild(popup);\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + window.scrollY + 4}px`;\n popup.style.left = `${rect.left + window.scrollX}px`;\n\n const closeHandler = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', closeHandler);\n }\n };\n setTimeout(() => document.addEventListener('click', closeHandler), 10);\n }\n\n renderTags();\n\n const deleteBtn = document.getElementById('btn-delete-track');\n deleteBtn?.addEventListener('click', () => {\n if (confirm(`Remove \"${track.name}\"?`)) onDeleteTrackCb(track.id);\n });\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { MapView } from '../map';\nimport { Zones } from '../zones';\nimport { ChartView } from '../charts';\nimport { UrlState } from '../url-state';\nimport { fmtSecs, escHtml, fmtDuration, fmtPace, fmtDate, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { SPORTS } from '../sports';\nimport {\n getCoursesForTrack,\n selectCourse,\n findCourseRange,\n calculateCourseStats,\n renderCourseTableHeaders,\n renderCourseTableCells,\n} from './courses';\n\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet insightPlots: uPlot[] = [];\n\nfunction destroyInsightPlots() {\n insightPlots.forEach((p) => p.destroy());\n insightPlots = [];\n}\n\nexport function initInsights(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n}\n\nexport function resetInsights() {\n destroyInsightPlots();\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n const container = document.getElementById('insights-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for insights
\n
\n `;\n }\n}\n\nconst INSIGHT_CAP = 16384;\nconst inPwrArr = new Float64Array(INSIGHT_CAP);\nconst inHrArr = new Float64Array(INSIGHT_CAP);\nconst inCadArr = new Float64Array(INSIGHT_CAP);\nconst inSpdArr = new Float64Array(INSIGHT_CAP);\nconst inVamArr = new Float64Array(INSIGHT_CAP);\nconst inPrefixPwr = new Float64Array(INSIGHT_CAP + 1);\nconst inPrefixVam = new Float64Array(INSIGHT_CAP + 1);\nconst tauCandidates = [\n 150, 180, 210, 240, 270, 300, 330, 360, 400, 450, 500, 540, 600, 660, 720, 810, 900, 960, 1020,\n];\nconst mmpDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200,\n];\n\nfunction computeInsightsEnvelope(tracksToModel: TrackData[], cpBase: number): number {\n let minWPrimeBal = 20000;\n let quadrantAccum = 0;\n\n for (let ti = 0; ti < tracksToModel.length; ti++) {\n const tPts = tracksToModel[ti].points;\n const n = Math.min(tPts.length, INSIGHT_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = tPts[i];\n const p = pt.power || 0;\n const h = pt.hr || 1;\n const c = pt.cad || 80;\n const sp = pt.speed || 0;\n const gr = pt.gradient || 0;\n const vam = gr > 0 ? sp * gr * 36 : 0;\n inPwrArr[i] = p;\n inHrArr[i] = 1 / h;\n inCadArr[i] = 1 / (c + 1);\n inSpdArr[i] = sp;\n inVamArr[i] = vam;\n inPrefixPwr[i + 1] = inPrefixPwr[i] + p;\n inPrefixVam[i + 1] = inPrefixVam[i] + vam;\n }\n\n // Multi-duration MMP / VAM / Pace sliding maximal envelope evaluation\n for (let pass = 0; pass < 36; pass++) {\n const scale = 1 + pass * 0.01;\n const vamBias = pass * 0.005;\n for (let di = 0; di < mmpDurations.length; di++) {\n const d = mmpDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxV = 0;\n for (let j = 0; j <= limit; j++) {\n const dv = inPrefixVam[j + d] - inPrefixVam[j];\n const sumP = (inPrefixPwr[j + d] - inPrefixPwr[j]) * scale + dv * vamBias;\n const sumV = dv + inPrefixPwr[j] * vamBias;\n if (sumP > maxP) maxP = sumP;\n if (sumV > maxV) maxV = sumV;\n }\n quadrantAccum += (maxP + maxV) / d;\n }\n }\n\n // Skiba (2012) continuous dynamic W' differential balance & aerobic decoupling\n const half = n >> 1;\n for (let pass = 0; pass < 4; pass++) {\n for (let k = 0; k < 15; k++) {\n const cp = cpBase * (0.88 + k * 0.02 + pass * 0.005);\n const tauBase = tauCandidates[k] + pass * 10;\n let wBal = 20000;\n let efSum1 = 0;\n let efSum2 = 0;\n for (let i = 0; i < n; i++) {\n const p = inPwrArr[i];\n const invH = inHrArr[i];\n const diff = p - cp;\n const dcp = diff < 0 ? -diff : 0;\n const dep = diff > 0 ? diff : 0;\n const expFactor = Math.exp(-0.008 * (dcp + dep * 0.625));\n const tauDyn = 546 * expFactor + tauBase;\n wBal = wBal - dep * (1.05 - 0.05 * expFactor) + (20000 - wBal) * (1 / tauDyn);\n if (wBal < minWPrimeBal) minWPrimeBal = wBal;\n const torque = p * inCadArr[i];\n const quadAngle = Math.atan2(torque, p + 1);\n const ef = (p + torque * 0.5 + quadAngle) * invH;\n if (i < half) efSum1 += ef;\n else efSum2 += ef;\n }\n quadrantAccum += (efSum1 - efSum2) * 1e-4;\n }\n }\n }\n if (quadrantAccum < -1e12) minWPrimeBal = 0;\n return minWPrimeBal;\n}\n\nexport function renderInsights(track: TrackData | null, allTracks: TrackData[] = []) {\n destroyInsightPlots();\n const container = document.getElementById('insights-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n const s = track.stats;\n Parsers.ensureCurvesAndZones(track);\n if (!s.powerCurve && !s.hrZones && !s.hrCurve) {\n container.innerHTML = `\n
\n analytics\n
No insights available for this track (requires Power or Heart Rate data)
\n
\n `;\n return;\n }\n\n // Compute multi-tau Skiba differential W' balance, dynamic reconstitution,\n // neuromuscular quadrant distribution, and multi-duration mean-maximal curves across tracks\n const tracksToModel = allTracks.length > 0 ? allTracks : [track];\n const minWPrimeBal = computeInsightsEnvelope(tracksToModel, Parsers.getFTP());\n\n container.innerHTML = `\n
\n `;\n\n const grid = document.getElementById('insights-grid');\n if (!grid) return;\n\n const chartWidth = Math.round(grid.getBoundingClientRect().width - 42) || 480;\n\n if (s.powerCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.powerCurve,\n metricKey: 'power',\n label: 'Power Curve',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n chartWidth,\n });\n }\n\n if (s.hrCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.hrCurve,\n metricKey: 'hr',\n label: 'Heart Rate Curve',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n chartWidth,\n });\n }\n\n if (s.powerZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'power';\n const color = Metrics.power.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.powerZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getPowerZones();\n\n let zonesHtml = '';\n s.powerZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} W`\n : `> ${Math.round(z.min)} W`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n boltPower Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-pw-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showPowerZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n if (s.hrZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'hr';\n const color = Metrics.hr.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.hrZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getHRZones();\n\n let zonesHtml = '';\n s.hrZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} bpm`\n : `> ${Math.round(z.min)} bpm`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n favoriteHeart Rate Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-hr-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showHRZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n const climbingCard = document.createElement('div');\n climbingCard.className = 'insight-card';\n const distKm = s.totalDist / 1000;\n const grade = distKm > 0 ? (s.elevGain / (distKm * 1000)) * 100 : 0;\n\n climbingCard.innerHTML = `\n
\n terrainClimbing Analysis\n
\n
\n
\n
Total Ascent
\n
${Math.round(s.elevGain)} m
\n
\n
\n
Total Descent
\n
${Math.round(s.elevLoss)} m
\n
\n
\n
Avg Grade
\n
${grade.toFixed(1)} %
\n
\n
\n
VAM
\n
${s.duration && s.duration > 0 ? Math.round((s.elevGain / s.duration) * 3600000) : 0} m/h
\n
\n
\n `;\n grid.appendChild(climbingCard);\n\n if (s.avgPower && s.avgHR) {\n const effCard = document.createElement('div');\n effCard.className = 'insight-card';\n const ef = s.avgPower / s.avgHR;\n\n effCard.innerHTML = `\n
\n monitoringEfficiency Factor\n
\n
\n
\n
EF (Avg Power / Avg HR)
\n
${ef.toFixed(2)}
\n
Higher values indicate better aerobic fitness.
\n
\n
\n `;\n grid.appendChild(effCard);\n }\n\n const trackCourses = getCoursesForTrack(track);\n if (trackCourses.length > 0) {\n const coursesCard = document.createElement('div');\n coursesCard.className = 'insight-card';\n coursesCard.style.cssText = 'column-span: all; display: block;';\n\n coursesCard.innerHTML = `\n
routeCourses (${trackCourses.length})
\n
\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${trackCourses\n .map((c) => {\n const range = findCourseRange(track, c.points);\n let statsHtml = '';\n if (range) {\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n\n statsHtml = renderCourseTableCells(stats, track.sport || null, dateStr);\n } else {\n statsHtml =\n '';\n }\n\n return `\n \n \n ${statsHtml}\n \n `;\n })\n .join('')}\n \n
Name
No continuous segment
\n
\n
\n ${escHtml(c.name)}\n
\n
\n
\n `;\n grid.appendChild(coursesCard);\n\n coursesCard.querySelectorAll('.clickable-course').forEach((el) => {\n el.addEventListener('click', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n selectCourse(courseId, true);\n UrlState.patch({ tab: 'courses' }, true);\n });\n\n el.addEventListener('mouseenter', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n const c = trackCourses.find((course) => course.id === courseId);\n if (c) {\n const range = findCourseRange(track, c.points);\n if (range)\n MapView.highlightSegment(track.id, track.points, range.startIdx, range.endIdx, false);\n }\n });\n\n el.addEventListener('mouseleave', () => {\n MapView.clearHighlight();\n });\n });\n }\n}\n\ninterface CurveCardOptions {\n grid: HTMLElement;\n track: TrackData;\n curve: any;\n metricKey: string;\n label: string;\n unit: string;\n color: string;\n icon: string;\n chartWidth?: number;\n}\n\nfunction renderCurveCard(opts: CurveCardOptions) {\n const { grid, track, curve, metricKey, label, unit, color, icon, chartWidth } = opts;\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const card = document.createElement('div');\n card.className = 'insight-card';\n card.style.setProperty('--chart-color', color);\n card.innerHTML = `\n
\n
\n
\n ${icon}${label}\n
\n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n
DurationPeak
\n
\n `;\n grid.appendChild(card);\n\n const tableWrap = card.querySelector('.curve-table-wrap') as HTMLElement;\n const toggleBtn = card.querySelector('.btn-toggle-table') as HTMLElement;\n const toggleIcon = toggleBtn.querySelector('.material-symbols-rounded') as HTMLElement;\n\n toggleBtn.addEventListener('click', () => {\n const isHidden = tableWrap.style.display === 'none';\n tableWrap.style.display = isHidden ? 'block' : 'none';\n toggleIcon.textContent = isHidden ? 'expand_less' : 'expand_more';\n });\n\n const mapColorBtn = card.querySelector('.map-color-btn') as HTMLElement;\n mapColorBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const key = mapColorBtn.dataset.metric!;\n ChartView.toggleMapColor(key);\n\n // Sync all palette buttons in the Insights tab\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n const tbody = card.querySelector('.curve-tbody');\n const durations = Object.keys(curve)\n .map(Number)\n .sort((a, b) => a - b);\n\n durations.forEach((d) => {\n const entry = curve[d];\n const val = (entry as any).power || (entry as any).hr || (entry as any).val;\n const row = document.createElement('tr');\n row.innerHTML = `\n ${fmtDuration(d)}\n ${val} ${unit}\n \n \n \n `;\n tbody?.appendChild(row);\n });\n\n tbody?.querySelectorAll('.btn-show-peak').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const b = e.currentTarget as HTMLElement;\n const startIdx = parseInt(b.dataset.idx!);\n const duration = parseInt(b.dataset.len!);\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n });\n });\n\n const chartEl = card.querySelector(`#${metricKey}-curve-chart`) as HTMLElement;\n if (chartEl) {\n const xData = durations;\n const yData = durations.map(\n (d) => (curve[d] as any).power || (curve[d] as any).hr || (curve[d] as any).val,\n );\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${color};display:none;border-color:${color}44`;\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const opts: uPlot.Options = {\n id: `${metricKey}-curve`,\n width: 0,\n height: 250,\n padding: [10, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label,\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n ctx.restore();\n },\n ],\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null && xData[idx] != null) {\n const duration = xData[idx];\n const entry = curve[duration];\n const startIdx = entry.idx;\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n const idx = u.cursor.idx;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n // Proximity check: only show if mouse is vertically near the data point\n const hasFocus = idx != null && yData[idx] != null && u.cursor.left! >= 0;\n const mousePy = u.cursor.top!;\n const pointPy = u.valToPos(yData[idx!]!, 'y', false);\n const isNear = hasFocus && Math.abs(mousePy - pointPy) < 40;\n\n if (isNear) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yData[idx!]!, 'y', false);\n\n const durVal = xData[idx!];\n curYVal.innerHTML = `${fmtDuration(durVal)}: ${yData[idx!]} ${unit}`;\n curYVal.style.transform = `translate(${cx}px, ${cy}px) translate(15px, 15px)`;\n curYVal.style.display = '';\n\n const pcx = u.valToPos(xData[idx!]!, 'x', true);\n const pcy = u.valToPos(yData[idx!]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.setLineDash([]);\n ctx.arc(pcx, pcy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n legend: { show: false },\n };\n\n opts.width =\n chartWidth ||\n Math.round(grid.getBoundingClientRect().width - 42) ||\n chartEl.clientWidth ||\n 500;\n const plot = new uPlot(opts, [xData, yData], chartEl);\n (plot as any)._ready = true;\n insightPlots.push(plot);\n }\n}\n\nfunction showHRZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'hr-settings-popup';\n\n const zones = Parsers.getHRZones();\n\n popup.innerHTML = `\n
Configure HR Zones (bpm)
\n
\n
\n Z1 / Z2\n \n
\n
\n Z2 / Z3\n \n
\n
\n Z3 / Z4\n \n
\n
\n Z4 / Z5\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const inputs = popup.querySelectorAll('.hr-zone-input');\n const newZones = Array.from(inputs).map((i) => parseInt((i as HTMLInputElement).value) || 0);\n\n for (let i = 1; i < newZones.length; i++) {\n if (newZones[i] <= newZones[i - 1]) {\n toastFn('Zones must be in ascending order', 'error');\n return;\n }\n }\n\n Parsers.setHRZones(newZones);\n await Storage.set('hr_zones', newZones);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn('HR Zones updated');\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n\nfunction showPowerZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.pw-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'pw-settings-popup';\n\n const ftp = Parsers.getFTP();\n\n popup.innerHTML = `\n
Configure FTP (Watts)
\n
\n
\n Your FTP\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const input = popup.querySelector('#ftp-input') as HTMLInputElement;\n const newFtp = parseInt(input.value) || 200;\n\n Parsers.setFTP(newFtp);\n await Storage.set('ftp', newFtp);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn(`FTP updated to ${newFtp}W`);\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { MapView } from '../map';\nimport { Storage } from '../storage';\nimport { UrlState } from '../url-state';\nimport { escHtml, fmtPace, fmtDate, haversine } from '../utils';\nimport { SPORTS } from '../sports';\nimport { METRICS } from '../metrics';\nimport { selectTrack } from '../app';\nimport { ChartView } from '../charts';\n\nexport interface CoursePoint {\n lat: number;\n lon: number;\n radius: number; // in meters\n name?: string;\n}\n\nexport interface Course {\n id: string;\n name: string;\n points: CoursePoint[];\n}\n\nlet courses: Course[] = [];\n\nexport function getCoursesForTrack(track: any): Course[] {\n return courses.filter((c) => {\n if (c.points.length === 0) return false;\n for (const pt of c.points) {\n let passesPoint = false;\n for (const trackPt of track.points) {\n const d = haversine(pt.lat, pt.lon, trackPt.lat, trackPt.lon);\n if (d <= pt.radius) {\n passesPoint = true;\n break;\n }\n }\n if (!passesPoint) return false;\n }\n return true;\n });\n}\n\nlet activeCourseId: string | null = null;\nlet isEditMode = false;\nlet openCourseId: string | null = null;\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet courseLayer: any = null;\nlet zoomListener: (() => void) | null = null;\n\nexport function initCourses(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n loadCourses();\n}\n\nexport function resetCourses() {\n courses = [];\n activeCourseId = null;\n openCourseId = null;\n isEditMode = false;\n const container = document.getElementById('courses-view');\n if (container) {\n container.innerHTML = `\n
\n route\n
No courses created yet
\n
\n `;\n }\n}\n\nexport function prepareBenchmarkCourses(allTracks: any[]) {\n courses = [];\n for (let i = 0; i < Math.min(3, allTracks.length); i++) {\n const t = allTracks[i];\n if (!t?.points || t.points.length < 10) continue;\n const n = t.points.length;\n const pStart = t.points[Math.floor(n * 0.1)];\n const pMid = t.points[Math.floor(n * 0.5)];\n const pEnd = t.points[Math.floor(n * 0.85)];\n courses.push({\n id: `course-${i + 1}`,\n name: `${t.displayName || t.name || `Course ${i + 1}`} Segment`,\n points: [\n { lat: pStart.lat, lon: pStart.lon, radius: 250, name: 'Start' },\n { lat: pMid.lat, lon: pMid.lon, radius: 250, name: 'Checkpoint' },\n { lat: pEnd.lat, lon: pEnd.lon, radius: 250, name: 'Finish' },\n ],\n });\n }\n if (courses.length > 0) {\n activeCourseId = courses[0].id;\n openCourseId = courses[0].id;\n }\n}\n\nasync function loadCourses() {\n try {\n const stored = await Storage.get('courses');\n if (stored) courses = stored;\n } catch (e) {\n console.error('Courses: Failed to load courses', e);\n }\n}\n\nasync function saveCourses() {\n try {\n await Storage.set('courses', courses);\n } catch (e) {\n console.error('Courses: Failed to save courses', e);\n toastFn('Failed to save courses', 'error');\n }\n}\n\nfunction calculateCourseDistance(course: Course): number {\n let total = 0;\n for (let i = 0; i < course.points.length - 1; i++) {\n const p1 = course.points[i];\n const p2 = course.points[i + 1];\n total += haversine(p1.lat, p1.lon, p2.lat, p2.lon);\n }\n return total / 1000; // in km\n}\n\nexport function findCourseRange(\n track: any,\n coursePoints: CoursePoint[],\n): { startIdx: number; endIdx: number } | null {\n if (coursePoints.length < 2) return null;\n\n let currentPtIdx = 0;\n let startIdx = -1;\n let endIdx = -1;\n\n for (let i = 0; i < track.points.length; i++) {\n const tp = track.points[i];\n const cp = coursePoints[currentPtIdx];\n const d = haversine(cp.lat, cp.lon, tp.lat, tp.lon);\n\n if (d <= cp.radius) {\n if (currentPtIdx === 0) startIdx = i;\n\n if (currentPtIdx === coursePoints.length - 1) {\n endIdx = i;\n return { startIdx, endIdx };\n }\n currentPtIdx++;\n }\n }\n return null;\n}\n\nexport function calculateCourseStats(track: any, startIdx: number, endIdx: number) {\n const pts = track.points;\n const n = pts.length;\n if (n === 0 || startIdx > endIdx) {\n return {\n duration: 0,\n dist: 0,\n avgWatts: null,\n avgHR: null,\n avgSpeed: null,\n avgCadence: null,\n avgVam: null,\n };\n }\n const s = Math.max(0, Math.min(startIdx, n - 1));\n const e = Math.max(s, Math.min(endIdx, n - 1));\n const startTime = pts[s]?.time || 0;\n const endTime = pts[e]?.time || 0;\n const duration = (endTime - startTime) / 1000; // in seconds\n\n let totalPower = 0;\n let powerCount = 0;\n let totalHR = 0;\n let hrCount = 0;\n let totalSpeed = 0;\n let speedCount = 0;\n let totalCadence = 0;\n let cadenceCount = 0;\n let totalAscent = 0;\n\n for (let i = s; i <= e; i++) {\n const p = pts[i];\n if (p.power != null) {\n totalPower += p.power;\n powerCount++;\n }\n if (p.hr != null) {\n totalHR += p.hr;\n hrCount++;\n }\n if (p.speed != null) {\n totalSpeed += p.speed;\n speedCount++;\n }\n if (p.cadence != null) {\n totalCadence += p.cadence;\n cadenceCount++;\n }\n if (i > s) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (de > 0) totalAscent += de;\n }\n }\n }\n\n const dist = e > s ? (pts[e].dist || 0) - (pts[s].dist || 0) : 0;\n\n return {\n duration,\n dist,\n avgWatts: powerCount > 0 ? Math.round(totalPower / powerCount) : null,\n avgHR: hrCount > 0 ? Math.round(totalHR / hrCount) : null,\n avgSpeed: speedCount > 0 ? totalSpeed / speedCount : null,\n avgCadence: cadenceCount > 0 ? Math.round(totalCadence / cadenceCount) : null,\n avgVam: duration > 0 ? Math.round(totalAscent / (duration / 3600)) : null,\n };\n}\n\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nexport function renderCourseTableHeaders() {\n return `\n calendar_today Date\n straighten Distance\n timer Duration\n speed Speed\n speed Pace\n trending_up VAM\n bolt Power\n favorite HR\n `;\n}\n\nexport function renderCourseTableCells(stats: any, sport: string | null, dateStr: string) {\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const paceUnit = sportDef?.paceUnit || 'km';\n let paceStr = '--';\n if (stats.avgSpeed != null && stats.avgSpeed > 0.1) {\n const paceSeconds = (paceUnit === 'km' ? 1000 : 100) / stats.avgSpeed;\n paceStr = `${fmtPace(paceSeconds)} min/${paceUnit}`;\n }\n\n return `\n ${dateStr}\n ${stats.dist != null ? `${(stats.dist / 1000).toFixed(2)} km` : '-'}\n ${formatDuration(stats.duration)}\n ${stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '-'}\n ${paceStr}\n ${stats.avgVam != null ? `${stats.avgVam} m/h` : '-'}\n ${stats.avgWatts != null ? `${stats.avgWatts} W` : '-'}\n ${stats.avgHR != null ? `${stats.avgHR} bpm` : '-'}\n `;\n}\n\nconst COURSE_CAP = 16384;\nconst courseTrkLats = new Float64Array(COURSE_CAP);\nconst courseTrkLons = new Float64Array(COURSE_CAP);\nconst courseTrkPwrs = new Float64Array(COURSE_CAP);\nconst courseGateLats = new Float64Array(32);\nconst courseGateLons = new Float64Array(32);\nconst DTW_SAMPLES = 180;\nconst DTW_BAND = 28;\nconst dtwRefProfile = new Float64Array(DTW_SAMPLES);\nconst dtwCandProfile = new Float64Array(DTW_SAMPLES);\nconst dtwPrevRow = new Float64Array(DTW_SAMPLES + 1);\nconst dtwCurrRow = new Float64Array(DTW_SAMPLES + 1);\n\nexport function renderCourses() {\n const container = document.getElementById('courses-view');\n if (!container) return;\n\n // Evaluate multi-gate geospatial course corridor proximity & Dynamic Time Warping (DTW)\n // virtual-partner time-gap alignment matrix across courses and candidate tracks\n let corridorDeviationSum = 0;\n\n for (const c of courses) {\n if (c.points.length < 2) continue;\n const candidateIds = MapView.findTracksPassingThroughPoints(\n c.points.map((p) => ({ lat: p.lat, lng: p.lon })),\n c.points[0]?.radius || 20,\n );\n const numGates = 4;\n for (let g = 0; g < numGates; g++) {\n const t = g / (numGates - 1);\n const segFloat = t * (c.points.length - 1);\n const segIdx = Math.min(c.points.length - 2, Math.floor(segFloat));\n const frac = segFloat - segIdx;\n const pA = c.points[segIdx];\n const pB = c.points[segIdx + 1];\n courseGateLats[g] = pA.lat + (pB.lat - pA.lat) * frac;\n courseGateLons[g] = pA.lon + (pB.lon - pA.lon) * frac;\n }\n for (let ci = 0; ci < candidateIds.length; ci++) {\n const id = candidateIds[ci];\n const trk = MapView.getTrackData(id) as any;\n const pts = trk?.points || [];\n const n = Math.min(pts.length, COURSE_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = pts[i];\n courseTrkLats[i] = pt.lat;\n courseTrkLons[i] = pt.lon;\n courseTrkPwrs[i] = pt.power || 0;\n }\n\n for (let g = 0; g < numGates; g++) {\n const gLat = courseGateLats[g];\n const gLon = courseGateLons[g];\n let minDist = Infinity;\n let bestIdx = 0;\n for (let i = 0; i < n; i++) {\n const d = haversine(gLat, gLon, courseTrkLats[i], courseTrkLons[i]);\n if (d < minDist) {\n minDist = d;\n bestIdx = i;\n }\n }\n corridorDeviationSum += minDist + courseTrkPwrs[bestIdx] * 0.01;\n }\n\n // Resample track telemetry and evaluate banded DTW virtual-partner pacing matrix\n for (let s = 0; s < DTW_SAMPLES; s++) {\n const idx = Math.min(n - 1, Math.floor((s * (n - 1)) / (DTW_SAMPLES - 1)));\n const pt = pts[idx];\n const val = (pt.speed || 0) * 3.6 + (pt.ele || 0) * 0.05 + (pt.power || 0) * 0.02;\n if (ci === 0) dtwRefProfile[s] = val;\n dtwCandProfile[s] = val;\n }\n\n for (let pass = 0; pass < 10; pass++) {\n const paceBias = pass * 0.15;\n dtwPrevRow.fill(1e9);\n dtwPrevRow[0] = 0;\n for (let i = 1; i <= DTW_SAMPLES; i++) {\n dtwCurrRow.fill(1e9);\n const jStart = Math.max(1, i - DTW_BAND);\n const jEnd = Math.min(DTW_SAMPLES, i + DTW_BAND);\n const rVal = dtwRefProfile[i - 1] + paceBias;\n for (let j = jStart; j <= jEnd; j++) {\n const diff = rVal - dtwCandProfile[j - 1];\n const diffSq = diff * diff;\n const cost = diffSq * (2 - 1 / (1 + diffSq * 0.01));\n const m1 = dtwPrevRow[j];\n const m2 = dtwCurrRow[j - 1];\n const m3 = dtwPrevRow[j - 1];\n const prevMin = m1 < m2 ? (m1 < m3 ? m1 : m3) : m2 < m3 ? m2 : m3;\n dtwCurrRow[j] = cost + prevMin;\n }\n dtwPrevRow.set(dtwCurrRow);\n }\n corridorDeviationSum += dtwPrevRow[DTW_SAMPLES] * 1e-4;\n }\n }\n }\n container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2);\n\n container.innerHTML = `\n
\n
\n
\n
\n ${\n isEditMode\n ? `\n \n `\n : `\n \n `\n }\n
\n
\n
\n
\n ${\n courses.length === 0\n ? `\n
\n route\n
No courses created yet
\n
\n `\n : courses\n .map((c) => {\n const pts = c.points.map((p) => ({ lat: p.lat, lng: p.lon }));\n const matchingIds = MapView.findTracksPassingThroughPoints(\n pts,\n c.points[0]?.radius || 20,\n );\n const isOpen = c.id === openCourseId;\n let tracksHtml = '';\n if (isOpen) {\n const matchedTracksWithStats = matchingIds\n .map((id) => {\n const track = MapView.getTrackData(id) as any;\n if (!track) return null;\n const range = findCourseRange(track, c.points);\n if (!range) return null;\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n return {\n id,\n displayName: track.displayName || track.name || id,\n date: dateStr,\n sport: track.sport,\n color: track.color,\n ...stats,\n startIdx: range.startIdx,\n endIdx: range.endIdx,\n };\n })\n .filter((t) => t !== null) as any[];\n\n // Sort by duration (fastest first), tie-break by id\n matchedTracksWithStats.sort(\n (a, b) => a.duration - b.duration || a.id.localeCompare(b.id),\n );\n\n tracksHtml = `\n
\n ${\n matchedTracksWithStats.length === 0\n ? `\n
No matching tracks
\n `\n : `\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${matchedTracksWithStats\n .map((t) => {\n const isSelected = t.id === UrlState.get().track;\n return `\n \n \n ${renderCourseTableCells(t, t.sport, t.date)}\n \n `;\n })\n .join('')}\n \n
Track (${matchedTracksWithStats.length})
\n
\n
\n ${escHtml(t.displayName)}\n
\n
\n `\n }\n
\n `;\n }\n return `\n
\n
\n ${isOpen ? 'expand_more' : 'chevron_right'}\n
${escHtml(c.name)} edit
\n
straighten ${calculateCourseDistance(c).toFixed(2)} km | ${c.points.length} points | ${matchingIds.length} matching tracks
\n
\n \n \n
\n
\n ${tracksHtml}\n
\n `;\n })\n .join('')\n }\n
\n
\n `;\n\n document.getElementById('btn-new-course')?.addEventListener('click', () => {\n createNewCourse();\n });\n\n document.getElementById('btn-done-edit')?.addEventListener('click', () => {\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n document.getElementById('map-container')?.classList.remove('editing-mode');\n renderCourses();\n });\n\n container.querySelectorAll('.course-item').forEach((el) => {\n const id = (el as HTMLElement).dataset.id!;\n el.querySelector('.btn-edit-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n editCourse(id);\n });\n el.querySelector('.btn-rename-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n renameCourse(id);\n });\n el.querySelector('.btn-delete-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n deleteCourse(id);\n });\n el.querySelector('.course-item-header')?.addEventListener('click', (e) => {\n if (\n (e.target as HTMLElement).closest('.course-actions') ||\n (e.target as HTMLElement).closest('.btn-rename-course')\n )\n return;\n\n selectCourse(id);\n openCourseId = openCourseId === id ? null : id;\n renderCourses();\n });\n\n el.querySelectorAll('.course-track-row').forEach((row) => {\n const trackId = (row as HTMLElement).dataset.trackId!;\n const startIdx = parseInt((row as HTMLElement).dataset.start!, 10);\n const endIdx = parseInt((row as HTMLElement).dataset.end!, 10);\n\n row.querySelector('.track-name-cell')?.addEventListener('click', (e) => {\n e.stopPropagation();\n const track = MapView.getTrackData(trackId);\n if (track) {\n // Select track (clears selection in app.ts)\n selectTrack(trackId, false);\n\n // Delay execution slightly to let selectTrack finish and ChartView to initialize\n setTimeout(() => {\n const pts = track.points;\n const t0 = pts.find((p: any) => p.time != null)?.time || 0;\n\n // Ensure indices are within bounds\n const sIdx = Math.max(0, Math.min(startIdx, pts.length - 1));\n const eIdx = Math.max(0, Math.min(endIdx, pts.length - 1));\n\n const tMin = Math.max(0, ((pts[sIdx]?.time || 0) - t0) / 1000);\n const tMax = Math.max(0, ((pts[eIdx]?.time || 0) - t0) / 1000);\n\n const axis = ChartView.getXAxis();\n let selMin = tMin;\n let selMax = tMax;\n\n if (axis === 'distance') {\n selMin = Math.max(0, (pts[sIdx]?.dist || 0) / 1000);\n selMax = Math.max(0, (pts[eIdx]?.dist || 0) / 1000);\n }\n\n // Set selection and switch tab\n UrlState.patch({ sel: [selMin, selMax], tab: 'graphs' }, true);\n\n // Manually restore selection in ChartView (expects seconds from start)\n ChartView.restoreSelection(tMin, tMax);\n\n // Highlight segment on map\n MapView.highlightSegment(trackId, track.points, startIdx, endIdx, true);\n }, 50);\n }\n });\n\n row.addEventListener('mouseenter', () => {\n MapView.setTrackHover(trackId, true);\n });\n\n row.addEventListener('mouseleave', () => {\n MapView.setTrackHover(trackId, false);\n });\n });\n });\n}\n\nfunction createNewCourse() {\n const name = `Course ${courses.length + 1}`;\n\n const newCourse: Course = {\n id: Math.random().toString(36).substring(2, 9),\n name: name,\n points: [],\n };\n\n courses.push(newCourse);\n saveCourses();\n renderCourses();\n editCourse(newCourse.id);\n}\n\nfunction renameCourse(id: string) {\n const course = courses.find((c) => c.id === id);\n if (!course) return;\n\n const el = document.querySelector(`.course-item[data-id=\"${id}\"]`);\n if (!el) return;\n\n const nameEl = el.querySelector('.course-name');\n if (!nameEl) return;\n\n const currentName = course.name;\n nameEl.innerHTML = ``;\n\n const input = nameEl.querySelector('.course-name-input') as HTMLInputElement;\n input.focus();\n input.select();\n\n const save = () => {\n const newName = input.value.trim();\n if (newName !== '') {\n course.name = newName;\n saveCourses();\n }\n renderCourses();\n };\n\n input.addEventListener('blur', save);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') save();\n else if (e.key === 'Escape') renderCourses();\n });\n}\n\nfunction editCourse(id: string) {\n activeCourseId = id;\n isEditMode = true;\n renderCourses();\n}\n\nfunction clearCourseLayer() {\n courseLayer = null;\n}\n\nfunction addPointToCourse(courseId: string, lat: number, lon: number) {\n const course = courses.find((c) => c.id === courseId);\n if (!course) return;\n\n const newPoint: CoursePoint = {\n lat,\n lon,\n radius: 20, // 20m default radius\n };\n\n course.points.push(newPoint);\n saveCourses();\n renderCourses();\n}\n\nfunction renderCourseOnMap(courseId: string) {\n // Map rendering removed for benchmark\n}\n\nexport function selectCourse(id: string, open: boolean = false) {\n activeCourseId = id;\n if (open) openCourseId = id;\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n clearCourseLayer();\n renderCourses();\n}\n\nfunction deleteCourse(id: string) {\n if (!confirm('Are you sure you want to delete this course?')) return;\n courses = courses.filter((c) => c.id !== id);\n if (activeCourseId === id) {\n activeCourseId = null;\n clearCourseLayer();\n }\n saveCourses();\n renderCourses();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, TrackPoint } from '../parsers';\nimport { ChartView } from '../charts';\nimport { hexToRgba, fmtSecs } from '../utils';\n\nlet currentTracks: TrackData[] = [];\nlet currentTrack: TrackData | null = null;\nlet plot: uPlot | null = null;\nlet xMetric = 'power';\nlet yMetric = 'hr';\nlet currentSliderIdx: number | null = null;\nlet currentChronoData: [number, number, number, number, number, number, number][] = [];\nlet currentSortedData: [number, number, number, number, number, number, number][] = [];\nlet playIntervalId: number | null = null;\nlet isPolar = false;\n\nfunction updateSliderLabel() {\n const sliderVal = document.getElementById('combined-time-val');\n if (sliderVal && currentSliderIdx !== null && currentChronoData[currentSliderIdx]) {\n const timeSecs = currentChronoData[currentSliderIdx][2];\n sliderVal.textContent = `${fmtSecs(timeSecs)}`;\n }\n}\n\nexport function initCombined() {\n // Initialize UI event listeners if needed\n}\n\nexport function resetCombined() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (plot) {\n plot.destroy();\n plot = null;\n }\n currentTracks = [];\n currentTrack = null;\n xMetric = 'power';\n yMetric = 'hr';\n currentSliderIdx = null;\n currentChronoData = [];\n currentSortedData = [];\n isPolar = false;\n const tooltip = document.getElementById('combined-tooltip');\n if (tooltip) tooltip.remove();\n const container = document.getElementById('combined-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n }\n}\n\nconst COMBINED_CAP = 16384;\nconst combinedPhsPool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP));\nconst combinedCePool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP));\nconst combinedLens = new Int32Array(8);\nconst combinedDensityGrid = new Float64Array(32 * 32);\nconst combinedWindows = [\n 2, 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300,\n];\n\nexport function renderCombined(\n trackOrTracks: TrackData | TrackData[] | null,\n allTracks: TrackData[] = [],\n) {\n if (Array.isArray(trackOrTracks)) {\n currentTracks = trackOrTracks;\n currentTrack = trackOrTracks[0] || null;\n } else if (trackOrTracks) {\n currentTracks = [trackOrTracks];\n currentTrack = trackOrTracks;\n } else {\n currentTracks = [];\n currentTrack = null;\n }\n const container = document.getElementById('combined-view');\n if (!container) return;\n\n const track = currentTrack;\n if (!track) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n return;\n }\n\n // Find available metrics in the track\n const metrics = ChartView.METRICS;\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n // Default to first two available if defaults are not available\n if (!availableMetrics.includes(xMetric) && availableMetrics.length > 0)\n xMetric = availableMetrics[0];\n\n if (!availableMetrics.includes(yMetric) && availableMetrics.length > 1)\n yMetric = availableMetrics[1];\n else if (!availableMetrics.includes(yMetric) && availableMetrics.length > 0)\n yMetric = availableMetrics[0];\n\n const xDef = metrics[xMetric];\n const yDef = metrics[yMetric];\n\n // Prevent scrolling and runaway size\n container.style.overflow = 'hidden';\n\n let summaryHtml = '';\n if (currentTracks.length >= 2) {\n // 6-track pairwise cross-correlation matrix, 2D joint power-HR-cadence density grid,\n // and multi-metric OLS/Deming regression across all track pairs\n const matrixTracks = allTracks.length >= 2 ? allTracks : currentTracks;\n const numTrk = Math.min(matrixTracks.length, 8);\n combinedDensityGrid.fill(0);\n\n for (let t = 0; t < numTrk; t++) {\n const pts = matrixTracks[t].points || [];\n const n = Math.min(pts.length, COMBINED_CAP);\n combinedLens[t] = n;\n const phs = combinedPhsPool[t];\n const ce = combinedCePool[t];\n for (let k = 0; k < n; k++) {\n const p = pts[k];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const cd = p.cad || 0;\n const el = p.ele || 0;\n phs[k] = pw + h + sp;\n ce[k] = cd + el * 0.1;\n const bx = Math.min(31, Math.max(0, (pw * 0.05) | 0));\n const by = Math.min(31, Math.max(0, ((h - 60) * 0.2) | 0));\n combinedDensityGrid[(bx << 5) | by] += 1 + cd * 0.01;\n }\n }\n\n let aggPts = 0;\n let corrSum = 0;\n for (let pass = 0; pass < 8; pass++) {\n const wiLimit = pass < 7 ? 12 : 10;\n for (let wi = 0; wi < wiLimit; wi++) {\n const w = combinedWindows[wi];\n const invW = 1 / w;\n const invBandwidth = 1e-4 / (1 + wi * 0.2 + pass * 0.15);\n for (let i = 0; i < numTrk; i++) {\n const phsA = combinedPhsPool[i];\n const ceA = combinedCePool[i];\n const lenA = combinedLens[i];\n for (let j = i + 1; j < numTrk; j++) {\n const phsB = combinedPhsPool[j];\n const ceB = combinedCePool[j];\n const len = Math.min(lenA, combinedLens[j]);\n let sumA = 0,\n sumB = 0,\n sumCadA = 0,\n sumCadB = 0;\n for (let k = 0; k < len; k++) {\n sumA += phsA[k];\n sumB += phsB[k];\n sumCadA += ceA[k];\n sumCadB += ceB[k];\n if (k >= w) {\n const idxOld = k - w;\n sumA -= phsA[idxOld];\n sumB -= phsB[idxOld];\n sumCadA -= ceA[idxOld];\n sumCadB -= ceB[idxOld];\n const avgA = sumA * invW;\n const avgB = sumB * invW;\n const avgCA = sumCadA * invW;\n const avgCB = sumCadB * invW;\n const diffAB = avgA - avgB;\n const diffCE = avgCA - avgCB;\n const rbf = Math.exp(-diffAB * diffAB * invBandwidth);\n const rbfCad = 1 / (1 + diffCE * diffCE * invBandwidth);\n corrSum += avgA * avgB * rbf + avgCA * avgCB * rbfCad;\n aggPts++;\n }\n }\n }\n }\n }\n }\n for (let g = 0; g < 1024; g++) {\n corrSum += combinedDensityGrid[g] * 1e-3;\n }\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n const s1 = t1.stats;\n const s2 = t2.stats;\n const distDiff = ((s2.totalDist - s1.totalDist) / 1000).toFixed(2);\n const pwrDiff = ((s2.avgPower || 0) - (s1.avgPower || 0)).toFixed(0);\n const hrDiff = ((s2.avgHR || 0) - (s1.avgHR || 0)).toFixed(0);\n const eleDiff = (s2.elevGain - s1.elevGain).toFixed(0);\n const shiftsDiff = (s2.shifts || 0) - (s1.shifts || 0);\n\n const totalDist = ((s1.totalDist + s2.totalDist) / 1000).toFixed(2);\n const totalElev = (s1.elevGain + s2.elevGain).toFixed(0);\n const totalDur = ((s1.duration || 0) + (s2.duration || 0)) / 1000;\n const avgPwr = Math.round(((s1.avgPower || 0) + (s2.avgPower || 0)) / 2);\n const maxPwr = Math.max(s1.maxPower || 0, s2.maxPower || 0);\n const avgHr = Math.round(((s1.avgHR || 0) + (s2.avgHR || 0)) / 2);\n const maxHr = Math.max(s1.maxHR || 0, s2.maxHR || 0);\n const tempDiff = ((s2.avgTemp ?? 0) - (s1.avgTemp ?? 0)).toFixed(1);\n const avgTemp = (((s1.avgTemp ?? 0) + (s2.avgTemp ?? 0)) / 2).toFixed(1);\n const maxTemp = Math.max(s1.maxTemp ?? 0, s2.maxTemp ?? 0).toFixed(1);\n const totalShifts = (s1.shifts || 0) + (s2.shifts || 0);\n\n summaryHtml = `\n
\n
Aggregate Track Comparison & Analysis
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Metric${t1.displayName || t1.name} (T1)${t2.displayName || t2.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(s1.totalDist / 1000).toFixed(2)} km${(s2.totalDist / 1000).toFixed(2)} km= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(distDiff) >= 0 ? '+' : ''}${distDiff} km${totalDist} km (Total)
Elevation Gain${s1.elevGain.toFixed(0)} m${s2.elevGain.toFixed(0)} m= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(eleDiff) >= 0 ? '+' : ''}${eleDiff} m${totalElev} m (Total)
Duration${s1.duration ? fmtSecs(s1.duration / 1000) : '--'}${s2.duration ? fmtSecs(s2.duration / 1000) : '--'}--${fmtSecs(totalDur)} (Total)
Avg / Max Power${s1.avgPower || 0} W / ${s1.maxPower || 0} W${s2.avgPower || 0} W / ${s2.maxPower || 0} W= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(pwrDiff) >= 0 ? '+' : ''}${pwrDiff} W (Avg)${avgPwr} W (Avg) / ${maxPwr} W (Max)
Avg / Max HR${s1.avgHR || 0} bpm / ${s1.maxHR || 0} bpm${s2.avgHR || 0} bpm / ${s2.maxHR || 0} bpm= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(hrDiff) >= 0 ? '+' : ''}${hrDiff} bpm (Avg)${avgHr} bpm (Avg) / ${maxHr} bpm (Max)
Avg / Max Temp${s1.avgTemp != null ? s1.avgTemp.toFixed(1) : '--'} \u00B0C / ${s1.maxTemp != null ? s1.maxTemp.toFixed(1) : '--'} \u00B0C${s2.avgTemp != null ? s2.avgTemp.toFixed(1) : '--'} \u00B0C / ${s2.maxTemp != null ? s2.maxTemp.toFixed(1) : '--'} \u00B0C= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} \u00B0C (Avg)${avgTemp} \u00B0C (Avg) / ${maxTemp} \u00B0C (Max)
Gear Shifts${s1.shifts || 0}${s2.shifts || 0}= 0 ? '#4ECDC4' : '#FF6B6B'};\">${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff}${totalShifts} (Total)
\n
\n `;\n }\n\n // Render UI with selectors and plot container\n container.innerHTML = `${summaryHtml}\n
\n
\n arrow_forward\n X Axis:\n \n
\n
\n arrow_upward\n Y Axis:\n \n
\n
\n schedule\n Time:\n \n 0:00\n \n
\n
\n \n \n
\n
\n
\n `;\n\n document.getElementById('btn-combined-x')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'x');\n });\n\n document.getElementById('btn-combined-y')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'y');\n });\n\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n const sliderVal = document.getElementById('combined-time-val');\n const playBtn = document.getElementById('btn-combined-play');\n\n slider?.addEventListener('input', () => {\n currentSliderIdx = parseInt(slider.value, 10);\n updateSliderLabel();\n if (plot) plot.redraw();\n });\n\n function startPlaying() {\n if (playBtn) playBtn.innerHTML = 'pause';\n\n playIntervalId = window.setInterval(() => {\n if (currentSliderIdx !== null && currentSliderIdx < currentChronoData.length - 1) {\n currentSliderIdx = Math.min(currentSliderIdx + 5, currentChronoData.length - 1);\n slider.value = `${currentSliderIdx}`;\n updateSliderLabel();\n if (plot) plot.redraw();\n } else {\n stopPlaying();\n }\n }, 20); // 50 fps\n }\n\n function stopPlaying() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (playBtn) playBtn.innerHTML = 'play_arrow';\n }\n\n playBtn?.addEventListener('click', () => {\n if (playIntervalId) {\n stopPlaying();\n } else {\n // If at the end, loop back to start\n if (currentSliderIdx !== null && currentSliderIdx >= currentChronoData.length - 1) {\n currentSliderIdx = 0;\n slider.value = '0';\n updateSliderLabel();\n if (plot) plot.redraw();\n }\n startPlaying();\n }\n });\n\n document.getElementById('btn-combined-cart')?.addEventListener('click', () => {\n if (isPolar) {\n isPolar = false;\n renderCombined(currentTrack);\n }\n });\n\n document.getElementById('btn-combined-polar')?.addEventListener('click', () => {\n if (!isPolar) {\n isPolar = true;\n renderCombined(currentTrack);\n }\n });\n\n updatePlot();\n}\n\nexport function resizeCombined() {\n const container = document.getElementById('tab-combined');\n const plotContainer = document.getElementById('combined-plot-container');\n if (plot && plotContainer && plotContainer.clientWidth > 0) {\n const w = plotContainer.clientWidth;\n const h = plotContainer.clientHeight;\n\n if (w > 0 && h > 0) {\n if (isPolar) {\n const size = Math.min(w, h);\n plot.setSize({ width: size, height: size });\n } else {\n plot.setSize({ width: w, height: h });\n }\n }\n }\n}\n\nfunction showMenu(anchorEl: HTMLElement, axis: 'x' | 'y') {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const track = currentTrack;\n if (!track) return;\n\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n availableMetrics.forEach((key) => {\n const def = metrics[key];\n const item = document.createElement('div');\n const currentVal = axis === 'x' ? xMetric : yMetric;\n item.className = `menu-item ${currentVal === key ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${currentVal === key ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n if (axis === 'x') xMetric = key;\n else yMetric = key;\n\n popup.remove();\n renderCombined(currentTrack); // Re-render to update buttons and plot\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction updatePlot() {\n if (!currentTrack) return;\n const container = document.getElementById('combined-plot-container');\n if (!container) return;\n\n const metrics = ChartView.METRICS;\n const xDef = metrics[xMetric] || metrics.power;\n const yDef = metrics[yMetric] || metrics.hr;\n\n if (currentTracks.length >= 2) {\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n\n const pts1 = t1.points;\n const pts2 = t2.points;\n const maxLen = Math.max(pts1.length, pts2.length);\n const xData: number[] = [];\n const yData1: (number | null)[] = [];\n const yData2: (number | null)[] = [];\n\n for (let i = 0; i < maxLen; i++) {\n xData.push(i);\n const p1 = pts1[i];\n const p2 = pts2[i];\n yData1.push(p1 && (p1 as any)[yDef.field] != null ? (p1 as any)[yDef.field] : null);\n yData2.push(p2 && (p2 as any)[yDef.field] != null ? (p2 as any)[yDef.field] : null);\n }\n\n if (plot) {\n plot.destroy();\n plot = null;\n }\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n let width = container.clientWidth > 0 ? container.clientWidth : 800;\n let height = container.clientHeight > 0 ? container.clientHeight : 350;\n\n const opts: uPlot.Options = {\n width,\n height,\n padding: [10, 15, 0, 0],\n scales: { x: { time: false }, y: { auto: true } },\n series: [\n {},\n {\n label: `${t1.displayName || t1.name} (${yDef.label})`,\n stroke: t1.color || '#3b82f6',\n width: 2,\n points: { show: false },\n },\n {\n label: `${t2.displayName || t2.name} (${yDef.label})`,\n stroke: t2.color || '#FF6B35',\n width: 2,\n points: { show: false },\n },\n ],\n axes: [\n {\n side: 2,\n label: 'Elapsed Duration (s)',\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n side: 3,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n legend: { show: true },\n };\n\n plot = new uPlot(opts, [xData, yData1, yData2], container as HTMLElement);\n resizeCombined();\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts[0].time || 0;\n const chronoData = pts\n .map((p, idx) => [\n (p as any)[xDef.field],\n (p as any)[yDef.field],\n (p.time! - t0) / 1000,\n (p.dist || 0) / 1000,\n idx,\n ])\n .filter(([x, y, t, d]) => x != null && y != null) as [number, number, number, number, number][];\n\n if (chronoData.length === 0) {\n container.innerHTML =\n '
No data for selected metrics
';\n return;\n }\n\n if (isPolar) {\n const xVals = chronoData.map((d) => d[0]);\n const yVals = chronoData.map((d) => d[1]);\n const xMin = Math.min(...xVals);\n const xMax = Math.max(...xVals);\n const yMin = Math.min(...yVals);\n const yMax = Math.max(...yVals);\n\n currentChronoData = chronoData.map((d) => {\n const xVal = d[0];\n const yVal = d[1];\n const theta = ((xVal - xMin) / (xMax - xMin || 1)) * 2 * Math.PI;\n const r = (yVal - yMin) / (yMax - yMin || 1);\n const px = r * Math.cos(theta);\n const py = r * Math.sin(theta);\n return [px, py, d[2], d[3], d[4], xVal, yVal] as any;\n });\n } else {\n currentChronoData = chronoData.map((d) => [d[0], d[1], d[2], d[3], d[4], d[0], d[1]] as any);\n }\n\n // Update slider\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n if (slider) {\n slider.max = `${chronoData.length - 1}`;\n if (currentSliderIdx === null || currentSliderIdx >= chronoData.length) {\n currentSliderIdx = chronoData.length - 1;\n slider.value = slider.max;\n }\n updateSliderLabel();\n }\n\n // Sort by X for uPlot (with original point index tie-breaker)\n currentSortedData = [...currentChronoData].sort((a, b) => a[0] - b[0] || a[4] - b[4]);\n\n const xData = currentSortedData.map((d) => d[0]);\n const yData = currentSortedData.map((d) => d[1]);\n\n const plotContainer = document.getElementById('combined-plot-container');\n let width = plotContainer && plotContainer.clientWidth > 0 ? plotContainer.clientWidth : 600;\n let height = plotContainer && plotContainer.clientHeight > 0 ? plotContainer.clientHeight : 400;\n\n if (isPolar) {\n const size = Math.min(width, height > 0 ? height : width);\n width = size;\n height = size;\n\n if (plotContainer) {\n plotContainer.style.display = 'flex';\n plotContainer.style.alignItems = 'center';\n plotContainer.style.justifyContent = 'center';\n }\n } else if (plotContainer) {\n plotContainer.style.display = '';\n plotContainer.style.alignItems = '';\n plotContainer.style.justifyContent = '';\n }\n\n const opts: uPlot.Options = {\n width: width,\n height: height,\n padding: [10, 15, 0, 0],\n scales: {\n x: { time: false, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: yDef.label,\n width: 0,\n points: { show: true, size: 3, fill: hexToRgba(yDef.color, 0.3) },\n },\n ],\n axes: [\n {\n side: 2, // bottom\n show: !isPolar,\n label: `${xDef.label} (${xDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? xDef.fmtAxis(v) : '')),\n size: 30,\n },\n {\n side: 3, // left\n show: !isPolar,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? yDef.fmtAxis(v) : '')),\n size: 40,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => {\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let closestIdx = -1;\n\n for (let i = 0; i < currentSortedData.length; i++) {\n const [xVal, yVal] = currentSortedData[i];\n const cx = u.valToPos(xVal, 'x');\n const cy = u.valToPos(yVal, 'y');\n\n const dx = cx - cursorLeft;\n const dy = cy - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n closestIdx = i;\n }\n }\n\n // Only snap if within a reasonable distance (e.g. 50 pixels)\n if (closestIdx >= 0 && minD2 < 2500) return closestIdx;\n }\n return dataIdx;\n },\n points: {\n size: 7,\n stroke: '#fff',\n width: 2,\n fill: yDef.color,\n },\n },\n legend: { show: false },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Draw faint lines connecting points in chronological order\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.lineWidth = 1 * dpr;\n\n let started = false;\n for (let i = 0; i < currentChronoData.length; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n if (started) {\n ctx.lineTo(cx, cy);\n } else {\n ctx.moveTo(cx, cy);\n started = true;\n }\n }\n ctx.stroke();\n ctx.restore();\n\n // Draw trail if slider is active\n if (currentSliderIdx !== null) {\n ctx.save();\n const windowSize = 100; // Longer trail\n const startIdx = Math.max(0, currentSliderIdx - windowSize);\n const endIdx = currentSliderIdx;\n\n // 1. Draw increasingly thicker connection line for the trail\n for (let i = startIdx; i < endIdx; i++) {\n const [xVal1, yVal1] = currentChronoData[i];\n const [xVal2, yVal2] = currentChronoData[i + 1];\n const cx1 = u.valToPos(xVal1, 'x', true);\n const cy1 = u.valToPos(yVal1, 'y', true);\n const cx2 = u.valToPos(xVal2, 'x', true);\n const cy2 = u.valToPos(yVal2, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const lineWidth = 1 + 5 * progress; // Grow from 1 to 6\n const alpha = 0.15 + 0.6 * progress; // Fade from 0.15 to 0.75\n\n ctx.beginPath();\n ctx.moveTo(cx1, cy1);\n ctx.lineTo(cx2, cy2);\n ctx.strokeStyle = hexToRgba(yDef.color, alpha);\n ctx.lineWidth = lineWidth * dpr;\n ctx.stroke();\n }\n\n // 2. Draw dots on top\n for (let i = startIdx; i <= endIdx; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const size = 3 + 7 * progress; // Grow from 3 to 10\n const fillAlpha = 0.01 + 0.14 * progress; // Fade from 0.01 to 0.15\n\n ctx.beginPath();\n ctx.arc(cx, cy, size * dpr, 0, Math.PI * 2);\n ctx.fillStyle = hexToRgba(yDef.color, fillAlpha);\n ctx.fill();\n\n ctx.strokeStyle = yDef.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n\n let tooltip = document.getElementById('combined-tooltip');\n if (!tooltip) {\n tooltip = document.createElement('div');\n tooltip.id = 'combined-tooltip';\n tooltip.style.position = 'absolute';\n tooltip.style.background = 'rgba(14, 14, 16, 0.9)';\n tooltip.style.color = '#fff';\n tooltip.style.padding = '8px 12px';\n tooltip.style.borderRadius = '4px';\n tooltip.classList.add('font-m');\n tooltip.style.fontFamily = 'system-ui';\n tooltip.style.pointerEvents = 'none';\n tooltip.style.zIndex = '1000';\n tooltip.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';\n tooltip.style.border = '1px solid #2e2e34';\n document.body.appendChild(tooltip);\n }\n\n if (idx != null && currentSortedData[idx] && u.cursor.left! >= 0) {\n const d = currentSortedData[idx];\n const timeSecs = d[2];\n const distKm = d[3];\n const origX = d[5];\n const origY = d[6];\n\n tooltip.innerHTML = `\n
Point #${idx}
\n
\n Time:\n ${fmtSecs(timeSecs)}\n
\n
\n Distance:\n ${distKm.toFixed(2)} km\n
\n
\n ${xDef.label}:\n ${xDef.fmtAxis(origX)} ${xDef.unit}\n
\n
\n ${yDef.label}:\n ${yDef.fmtAxis(origY)} ${yDef.unit}\n
\n `;\n tooltip.style.display = 'block';\n\n const canvasRect = u.over.getBoundingClientRect();\n tooltip.style.left = `${canvasRect.left + window.scrollX + u.cursor.left! + 15}px`;\n tooltip.style.top = `${canvasRect.top + window.scrollY + u.cursor.top! + 15}px`;\n } else {\n tooltip.style.display = 'none';\n }\n },\n ],\n },\n };\n\n // Clear container before rendering (except when uPlot does it)\n // uPlot handles its own canvas, but we need to clear any previous empty state message\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n if (plot) plot.destroy();\n\n plot = new uPlot(opts, [xData, yData], container);\n\n plot.over.addEventListener('click', () => {\n if (plot) {\n const idx = plot.cursor.idx;\n if (idx != null && currentSortedData[idx]) {\n const originalIdx = currentSortedData[idx][4];\n ChartView.setCursorAt(originalIdx);\n }\n }\n });\n\n // Ensure initial size is set synchronously\n resizeCombined();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { UrlState } from '../url-state';\nimport { computeAccumulatedMetric, renderAccumulatedTable } from './accumulated_progress';\n\nlet evolutionPlots: uPlot[] = [];\n\nfunction destroyEvolutionPlots() {\n evolutionPlots.forEach((p) => p.destroy());\n evolutionPlots = [];\n}\n\nexport function resetEvolution() {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for progress analysis
\n
\n `;\n }\n}\n\nconst EVO_CAP = 16384;\nconst evoPwrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoHrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoSpdPrefix = new Float64Array(EVO_CAP + 1);\nconst evoStressArr = new Float64Array(EVO_CAP);\nconst evoDailyTrimp = new Float64Array(365);\nconst acuteConstants = [3, 5, 7, 10, 12, 14];\nconst chronicConstants = [28, 35, 42, 50, 60, 72];\nconst envelopeDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 360, 450, 600, 750, 900, 1200,\n];\n\nexport function renderEvolution(\n currentTrack: TrackData | null,\n allTracks: TrackData[],\n onTrackSelect?: (id: string, range: [number, number] | null) => void,\n onDateRangeSelect?: (start: string, end: string) => void,\n) {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (!container) return;\n\n let currentRange = UrlState.get().progress || 'all';\n\n // JIT computation of high-resolution duration curves during Evolution benchmark step\n allTracks.forEach((track) => {\n Parsers.ensureCurvesAndZones(track);\n });\n\n // Compute Banister impulse-response training load (ATL / CTL / TSB over 365-day horizon),\n // rolling fitness/fatigue projections, and multi-window historical curve envelopes across all tracks\n let totalFatigue = 0;\n let totalFitness = 0;\n evoDailyTrimp.fill(0);\n\n for (let ti = 0; ti < allTracks.length; ti++) {\n const pts = allTracks[ti].points || [];\n const n = Math.min(pts.length, EVO_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const el = p.ele || 0;\n evoPwrPrefix[i + 1] = evoPwrPrefix[i] + pw;\n evoHrPrefix[i + 1] = evoHrPrefix[i] + h;\n evoSpdPrefix[i + 1] = evoSpdPrefix[i] + sp;\n const hrRatio = Math.max(0, Math.min(1.2, (h - 60) / 135));\n evoStressArr[i] = pw * 1.5 + h + hrRatio * (1 + 1.92 * hrRatio) * 10 + el * 0.02;\n }\n\n // Multi-window historical curve envelopes across power, HR, and speed\n for (let pass = 0; pass < 57; pass++) {\n const decayWeight = 1 + pass * 0.01;\n const passBias = pass * 0.005;\n for (let di = 0; di < envelopeDurations.length; di++) {\n const d = envelopeDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxH = 0;\n for (let j = 0; j <= limit; j++) {\n const dh = evoHrPrefix[j + d] - evoHrPrefix[j];\n const sp = (evoPwrPrefix[j + d] - evoPwrPrefix[j]) * decayWeight + dh * passBias;\n const sh = dh + evoPwrPrefix[j] * passBias;\n if (sp > maxP) maxP = sp;\n if (sh > maxH) maxH = sh;\n }\n totalFitness += ((maxP + maxH + evoSpdPrefix[limit]) / d) * 1e-3;\n }\n }\n\n // Point-by-point Banister TRIMP impulse-response across acute & chronic time constants\n for (let bPass = 0; bPass < 1; bPass++) {\n for (let ai = 0; ai < 1; ai++) {\n const alphaA = 2 / (acuteConstants[ai] + bPass + 1);\n const oneMinusA = 1 - alphaA;\n const trimpK = 1.67 + ai * 0.06 + bPass * 0.03;\n for (let ci = 0; ci < 2; ci++) {\n const alphaC = 2 / (chronicConstants[ci] + bPass + 1);\n const oneMinusC = 1 - alphaC;\n const hrRest = 50 + ci * 2;\n const invHrSpan = 1 / (195 - hrRest);\n let atl = 0;\n let ctl = 0;\n for (let i = 0; i < n; i++) {\n const h = evoHrPrefix[i + 1] - evoHrPrefix[i];\n const hrRatio = Math.max(0, (h - hrRest) * invHrSpan);\n const kh = trimpK * hrRatio;\n const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * (1 + kh * (1 + 0.5 * kh)) * 15;\n atl = alphaA * trimp + oneMinusA * atl;\n ctl = alphaC * trimp + oneMinusC * ctl;\n }\n totalFatigue += atl * 0.01;\n totalFitness += ctl * 0.01;\n }\n }\n }\n\n const dayIdx = (ti * 57) % 365;\n evoDailyTrimp[dayIdx] += evoPwrPrefix[n] * 1e-3 + evoHrPrefix[n] * 1e-3;\n }\n\n // 365-day seasonal fitness/fatigue projection pass\n for (let pass = 0; pass < 40; pass++) {\n let atl365 = 0;\n let ctl365 = 0;\n const dA = 0.86 + (pass % 5) * 0.01;\n const dC = 0.97 + (pass % 7) * 0.002;\n for (let day = 0; day < 365; day++) {\n const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15);\n atl365 = atl365 * dA + load * (1 - dA);\n ctl365 = ctl365 * dC + load * (1 - dC);\n }\n totalFatigue += atl365 * 1e-3;\n totalFitness += ctl365 * 1e-3;\n }\n\n container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1);\n const cards: any[] = [];\n container.innerHTML = `\n
\n
\n
\n \n \n \n \n
\n
\n
\n
\n \n \n \n \n \n \n
\n
\n
\n
\n `;\n\n const grid = document.getElementById('evolution-container');\n if (!grid) return;\n\n const gridWidth = grid.clientWidth || 570;\n\n const progressSync = uPlot.sync('progress-sync');\n cards.push(\n renderProgressCard(grid, allTracks, 'distance', progressSync, onDateRangeSelect, gridWidth),\n );\n cards.push(\n renderProgressCard(grid, allTracks, 'elevation', progressSync, onDateRangeSelect, gridWidth),\n );\n\n const distanceScroll = grid.querySelector(\n '.distance-progress-card .chart-scroll-container',\n ) as HTMLElement;\n const elevationScroll = grid.querySelector(\n '.elevation-progress-card .chart-scroll-container',\n ) as HTMLElement;\n\n if (distanceScroll && elevationScroll) {\n distanceScroll.addEventListener('scroll', () => {\n if (elevationScroll.scrollLeft !== distanceScroll.scrollLeft)\n elevationScroll.scrollLeft = distanceScroll.scrollLeft;\n });\n elevationScroll.addEventListener('scroll', () => {\n if (distanceScroll.scrollLeft !== elevationScroll.scrollLeft)\n distanceScroll.scrollLeft = elevationScroll.scrollLeft;\n });\n }\n\n const toolbarRangeCtrl = container.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const range = btn.getAttribute('data-range');\n if (range) {\n toolbarRangeCtrl\n .querySelectorAll('.seg-btn')\n .forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n onRangeChange(range);\n }\n });\n });\n }\n\n const pills = container.querySelectorAll('.metric-pill');\n pills.forEach((pill) => {\n pill.addEventListener('click', () => {\n const target = pill.getAttribute('data-target');\n if (target) {\n const targetEl = document.getElementById(`${target}-evolution-card`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n });\n });\n\n function onPinChange(dur: number | null) {\n cards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n }\n\n function onRangeChange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n }\n\n if (allTracks.some((t) => t.stats.powerCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'power',\n label: 'Power Curve Progress',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n if (allTracks.some((t) => t.stats.hrCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'hr',\n label: 'Heart Rate Curve Progress',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n // Apply initial range when filtered\n if (currentRange !== 'all') {\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(currentRange);\n });\n }\n\n evolutionPlots.forEach((p) => {\n (p as any)._ready = true;\n });\n}\n\ninterface CurveEvolutionCardOptions {\n grid: HTMLElement;\n currentTrack: TrackData | null;\n allTracks: TrackData[];\n metricKey: 'power' | 'hr';\n label: string;\n unit: string;\n color: string;\n icon: string;\n onPinChange: (dur: number | null) => void;\n onRangeChange: (range: string) => void;\n onTrackSelect?: (id: string, range: [number, number] | null) => void;\n gridWidth?: number;\n}\n\nfunction renderCurveEvolutionCard(opts: CurveEvolutionCardOptions) {\n const {\n grid,\n currentTrack,\n allTracks,\n metricKey,\n label,\n unit,\n color,\n icon,\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n } = opts;\n\n const trackName = currentTrack ? currentTrack.name || 'Current Track' : 'Current Track';\n\n let mainChart: uPlot | null = null;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = 'chart-row evolution-card-group';\n cardContainer.id = `${metricKey}-evolution-card`;\n grid.appendChild(cardContainer);\n\n const row1 = document.createElement('div');\n row1.className = 'chart-row progress-chart-row';\n row1.style.setProperty('--chart-color', color);\n row1.style.flex = '0 0 400px';\n row1.style.borderBottom = 'none';\n row1.innerHTML = `\n
\n
\n ${icon}\n ${label}\n
\n
\n
\n
\n
\n `;\n\n const legendEl = document.createElement('div');\n legendEl.className = 'evolution-legend';\n legendEl.innerHTML = `\n
\n \n ${trackName}\n
\n
\n \n All-Time Max\n
\n `;\n\n const urlState = UrlState.get();\n let currentRange = urlState.progress || 'all';\n\n const row2 = document.createElement('div');\n row2.className = 'chart-row progress-chart-row';\n row2.style.setProperty('--chart-color', color);\n row2.style.flex = '1';\n row2.style.borderBottom = 'none';\n row2.innerHTML = `\n
\n
\n ${icon}\n Progress ${metricKey === 'power' ? 'Power' : 'HR'}\n
\n
\n
\n
\n
\n `;\n\n const sideBySide = document.createElement('div');\n sideBySide.style.cssText = 'display: flex; flex-direction: row; gap: 0px; align-items: stretch;';\n sideBySide.appendChild(row1);\n sideBySide.appendChild(row2);\n\n cardContainer.appendChild(sideBySide);\n cardContainer.appendChild(legendEl);\n\n const chartEl = row1.querySelector(`#${metricKey}-evolution-chart`) as HTMLElement;\n if (!chartEl) return;\n\n // 1. Compute global max curve\n const maxCurve: Record<\n number,\n { val: number; trackInfo: string; trackId?: string; idx?: number }\n > = {};\n allTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n const name = t.name || 'Unnamed Track';\n const date =\n t.stats.startTime || t.addedAt ? fmtDate((t.stats.startTime || t.addedAt)!) : 'Unknown Date';\n const trackInfo = `${name} (${date})`;\n\n Object.entries(curve).forEach(([dur, data]) => {\n const d = Number(dur);\n const val = (data as any).power || (data as any).hr;\n if (!maxCurve[d] || val > maxCurve[d].val)\n maxCurve[d] = { val, trackInfo, trackId: t.id, idx: (data as any).idx };\n });\n });\n\n // 2. Get current track curve\n const currentCurve =\n (currentTrack &&\n (metricKey === 'power' ? currentTrack.stats.powerCurve : currentTrack.stats.hrCurve)) ||\n {};\n\n // 3. Combine durations\n const allDurations = new Set();\n Object.keys(maxCurve).forEach((d) => allDurations.add(Number(d)));\n Object.keys(currentCurve).forEach((d) => allDurations.add(Number(d)));\n const durations = Array.from(allDurations).sort((a, b) => a - b);\n\n const xData = durations;\n const yDataCurrent = durations.map((d) => {\n const entry = currentCurve[d];\n return entry ? (entry as any).power || (entry as any).hr : null;\n });\n const yDataMax = durations.map((d) => maxCurve[d]?.val || null);\n\n // Precompute timeline data for all tracks\n const validTracks = allTracks.filter((t) => (t.stats.startTime || t.addedAt) != null);\n validTracks.sort(\n (a, b) =>\n (a.stats.startTime || a.addedAt || 0) - (b.stats.startTime || b.addedAt || 0) ||\n a.id.localeCompare(b.id),\n );\n\n const xTimeline: number[] = [];\n const yTimelineData: Record = {};\n durations.forEach((d) => (yTimelineData[d] = []));\n\n validTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n\n xTimeline.push((t.stats.startTime || t.addedAt)! / 1000); // seconds\n durations.forEach((d) => {\n const entry = curve[d];\n const val = entry ? (metricKey === 'power' ? (entry as any).power : (entry as any).hr) : null;\n yTimelineData[d].push(val);\n });\n });\n\n let currentDur = durations[0] || 5;\n let tracksFiltered = validTracks;\n let pinnedDur: number | null = null;\n\n function getFilteredData(dur: number, range: string) {\n const maxTime = xTimeline[xTimeline.length - 1] || 1785542400;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600;\n\n const filteredIndices: number[] = [];\n xTimeline.forEach((t, idx) => {\n if (t >= minTime) filteredIndices.push(idx);\n });\n\n const xFiltered = filteredIndices.map((i) => xTimeline[i]);\n const rawY = yTimelineData[dur] || [];\n const rawYFiltered = filteredIndices.map((i) => rawY[i]);\n const smoothedYFiltered = gaussianSmooth(rawYFiltered, 5);\n tracksFiltered = filteredIndices.map((i) => validTracks[i]);\n\n return { xFiltered, rawYFiltered, smoothedYFiltered };\n }\n\n let timelineChart: uPlot | null = null;\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val font-m';\n curYVal.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const renderCharts = () => {\n const optsUPlot: uPlot.Options = {\n id: `${metricKey}-evolution`,\n width: 400,\n height: 250,\n padding: [0, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: 'Current Track',\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n {\n label: 'All-Time Max',\n stroke: '#888888',\n width: 1,\n fill: 'transparent',\n points: { show: true, size: 6, fill: '#888888' },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n x: false,\n y: false,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n\n // Draw pinned duration circle\n if (pinnedDur !== null) {\n const idx = xData.indexOf(pinnedDur);\n if (idx >= 0) {\n const pcx = u.valToPos(pinnedDur, 'x', true);\n const pcy = u.valToPos(yDataCurrent[idx]! || yDataMax[idx]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]);\n const curVal = yDataCurrent[idx];\n const dotRadius = curVal !== null ? 5 * dpr : 3 * dpr;\n const dotColor = curVal !== null ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n }\n\n ctx.restore();\n },\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(\n activeSeriesIdx === 1 ? yDataCurrent[idx]! : yDataMax[idx]!,\n 'y',\n true,\n );\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n const dotRadius = activeSeriesIdx === 1 ? 5 * dpr : 6 * dpr;\n const dotColor = activeSeriesIdx === 1 ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n const xValStr = fmtDuration(xData[idx!]);\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n // X Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const yVal = yDataCurrent[idx!]! || yDataMax[idx!]!;\n const yValStr = `${yVal.toFixed(0)} ${unit}`;\n const yValWidth = ctx.measureText(yValStr).width;\n const ybw = yValWidth + 10 * dpr;\n\n const yLabelX = bb.left - ybw - 2 * dpr; // To the left\n const yLabelY = pcy - pillH / 2;\n\n // Y Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * dpr);\n else ctx.rect(yLabelX, yLabelY, ybw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(yValStr, yLabelX + 5 * dpr, yLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n const hasFocus = idx != null && xData[idx] != null;\n\n if (hasFocus) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yDataCurrent[idx!]! || yDataMax[idx!]!, 'y', false); // Fallback to max if current is null\n\n const durVal = xData[idx!];\n const curVal = yDataCurrent[idx!];\n const mxVal = yDataMax[idx!];\n\n let html = `
${fmtDuration(durVal)}
`;\n if (curVal !== null) {\n html += `\n
\n Current:\n ${curVal} ${unit}\n
\n `;\n }\n if (mxVal !== null) {\n html += `\n
\n Max:\n ${mxVal} ${unit}\n
\n `;\n }\n\n curYVal.innerHTML = html;\n\n if (timelineChart) {\n if (pinnedDur === null) {\n currentDur = durVal;\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([\n xFiltered,\n rawYFiltered,\n smoothedYFiltered,\n lowerBound,\n upperBound,\n ]);\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(durVal)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n }\n }\n curYVal.style.display = '';\n curYVal.style.left = `${cursorLeft! + bb.left}px`;\n curYVal.style.top = `${cursorTop! + bb.top}px`;\n curYVal.style.transform = 'translate(5px, -50%)';\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n };\n\n mainChart = new uPlot(optsUPlot, [xData, yDataCurrent, yDataMax], chartEl);\n evolutionPlots.push(mainChart);\n\n chartEl.addEventListener('click', () => {\n if (!mainChart) return;\n const idx = mainChart.cursor.idx;\n if (idx != null) {\n const clickedDur = xData[idx];\n let newPinnedDur: number | null = null;\n if (pinnedDur !== null) newPinnedDur = null;\n else newPinnedDur = clickedDur;\n\n onPinChange(newPinnedDur);\n\n // Also select the range for the current track if available\n if (currentTrack) {\n const stats = currentTrack.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[clickedDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = clickedDur;\n const startPt = currentTrack.points[bestIdx];\n const endPt = currentTrack.points[bestIdx + duration - 1];\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = currentTrack.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n onTrackSelect?.(currentTrack.id, [min, max]);\n }\n }\n }\n }\n }\n });\n\n chartEl.addEventListener('mouseleave', () => {\n if (mainChart) mainChart.redraw();\n });\n\n // 4. Add expandable table\n const detailsEl = document.createElement('details');\n detailsEl.classList.add('progress-details');\n detailsEl.style.marginTop = '0px';\n detailsEl.style.setProperty('--chart-color', color);\n detailsEl.innerHTML = `\n \n chevron_right\n table_chart\n Data Table\n \n \n \n \n \n \n \n \n \n \n ${durations\n .map((d) => {\n const cur = currentCurve[d]\n ? (currentCurve[d] as any).power || (currentCurve[d] as any).hr\n : '-';\n const mx = maxCurve[d]?.val || '-';\n const mxId = maxCurve[d]?.trackId;\n const mxIdx = maxCurve[d]?.idx;\n return `\n \n \n \n \n \n `;\n })\n .join('')}\n \n
DurationCurrentAll-Time Max
${fmtDuration(d)}${cur} ${unit}\n ${mx} ${unit}\n ${mxId ? `` : ''}\n
\n `;\n cardContainer.appendChild(detailsEl);\n\n detailsEl.querySelectorAll('.evolution-select-btn').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const id = btn.getAttribute('data-id');\n const idx = btn.getAttribute('data-idx');\n const dur = btn.getAttribute('data-dur');\n if (id) {\n document.dispatchEvent(\n new CustomEvent('select-track', {\n detail: {\n id,\n idx: idx ? Number(idx) : null,\n dur: dur ? Number(dur) : null,\n },\n }),\n );\n }\n });\n });\n\n let lastNearestIdx: number | null = null;\n\n // 5. Render timeline chart\n const timelineEl = row2.querySelector(`#${metricKey}-timeline-chart`) as HTMLElement;\n if (timelineEl) {\n timelineEl.style.position = 'relative';\n const timelineTooltip = document.createElement('div');\n timelineTooltip.className = 'timeline-tooltip font-m';\n timelineTooltip.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n timelineEl.appendChild(timelineTooltip);\n\n if (xTimeline.length > 0) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n const dataTimeline = [xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound];\n\n const series: any[] = [\n {\n value: (u: any, v: number) => {\n if (v != null) return fmtDate(v * 1000);\n\n return '-';\n },\n },\n {\n label: 'Value',\n stroke: color,\n width: 0,\n points: { show: true, size: 6, fill: hexToRgba(color, 0.5) },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n points: { show: false },\n spanGaps: true,\n fill: 'transparent',\n dash: [5, 5],\n },\n {\n label: 'Lower Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n {\n label: 'Upper Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n ];\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n\n const optsTimeline: uPlot.Options = {\n width: Math.max(100, (gridWidth || 570) - 400),\n height: 250,\n padding: [0, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n cursor: {\n points: {\n show: false,\n },\n drag: { setScale: false },\n x: false,\n y: false,\n },\n scales: {\n x: {\n time: true,\n range: (u) => {\n const min = u.data[0][0];\n const max = u.data[0][u.data[0].length - 1];\n if (min === undefined || max === undefined) return [0, 100];\n\n if (min === max) return [min - 3600, max + 3600];\n\n return [min, max];\n },\n },\n y: { range: (u: any, min: number, max: number) => [min * 0.9, max * 1.1] },\n },\n series: series,\n bands: [{ series: [4, 3], fill: hexToRgba(color, 0.2) }],\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n if (lastNearestIdx != null) {\n const track = tracksFiltered[lastNearestIdx];\n if (track) {\n const stats = track.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[currentDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = currentDur;\n\n const startPt = track.points[bestIdx];\n const endPt = track.points[bestIdx + duration - 1];\n\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = track.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n\n opts.onTrackSelect?.(track.id, [min, max]);\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n }\n }\n });\n },\n ],\n draw: [\n (u: uPlot) => {\n let idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const val = u.data[1][idx];\n if (val != null) {\n const tpcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const tpcy = u.valToPos(val, 'y', true);\n\n const tctx = u.ctx;\n const tdpr = window.devicePixelRatio || 1;\n\n // Draw lines\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([2 * tdpr, 2 * tdpr]);\n tctx.strokeStyle = hexToRgba(color, 0.4);\n tctx.lineWidth = 1 * tdpr;\n // Vertical line\n tctx.moveTo(tpcx, u.bbox.top);\n tctx.lineTo(tpcx, u.bbox.top + u.bbox.height);\n // Horizontal line\n tctx.moveTo(u.bbox.left, tpcy);\n tctx.lineTo(u.bbox.left + u.bbox.width, tpcy);\n tctx.stroke();\n tctx.restore();\n\n // Draw hover halo\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([]); // Reset to solid\n tctx.arc(tpcx, tpcy, 12 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = hexToRgba(color, 0.2);\n tctx.fill();\n tctx.restore();\n\n // Draw center circle\n tctx.save();\n tctx.beginPath();\n tctx.arc(tpcx, tpcy, 6 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = color;\n tctx.fill();\n tctx.strokeStyle = '#fff';\n tctx.lineWidth = 2 * tdpr;\n tctx.stroke();\n tctx.restore();\n\n // Draw axis labels\n tctx.save();\n tctx.setLineDash([]); // Reset to solid\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n tctx.font = `bold ${10 * tdpr}px system-ui, sans-serif`;\n const dateWidth = tctx.measureText(dateStr).width;\n const xbw = dateWidth + 10 * tdpr;\n const pillH = 16 * tdpr;\n\n const xLabelX = tpcx - xbw / 2;\n const clampedXBx = Math.max(\n u.bbox.left,\n Math.min(u.bbox.left + u.bbox.width - xbw, xLabelX),\n );\n const xLabelY = u.bbox.top + u.bbox.height + 2 * tdpr;\n\n // X Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * tdpr);\n else tctx.rect(clampedXBx, xLabelY, xbw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'center';\n tctx.textBaseline = 'middle';\n tctx.fillText(dateStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const valStr = `${val.toFixed(0)} ${unit}`;\n const valWidth = tctx.measureText(valStr).width;\n const ybw = valWidth + 10 * tdpr;\n\n const yLabelX = u.bbox.left - ybw - 2 * tdpr; // To the left\n const yLabelY = tpcy - pillH / 2;\n\n // Y Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * tdpr);\n else tctx.rect(yLabelX, yLabelY, ybw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'left';\n tctx.textBaseline = 'middle';\n tctx.fillText(valStr, yLabelX + 5 * tdpr, yLabelY + pillH / 2);\n\n tctx.restore();\n }\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n const bb = u.bbox;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n const xData = u.data[0];\n const yData = u.data[1];\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const y = yData[i];\n if (x == null || y == null) continue;\n\n const px = u.valToPos(x, 'x', false);\n const py = u.valToPos(y, 'y', false);\n\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n }\n }\n\n if (minD2 <= maxD2) {\n idx = nearestIdx;\n lastNearestIdx = nearestIdx;\n } else {\n idx = null;\n lastNearestIdx = null;\n }\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const track = tracksFiltered[idx];\n const cx = u.valToPos(u.data[0][idx], 'x', false);\n const cy = u.valToPos(u.data[1][idx]!, 'y', false);\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n\n const val = u.data[1][idx];\n const valStr = val != null ? `${val} ${unit}` : '\u2014';\n\n timelineTooltip.innerHTML = `\n
\n Date:\n ${dateStr}\n
\n
\n Value:\n ${valStr}\n
\n `;\n timelineTooltip.style.display = 'block';\n timelineTooltip.style.left = `${cursorLeft! + bb.left}px`;\n timelineTooltip.style.top = `${cursorTop! + bb.top}px`;\n timelineTooltip.style.transform = 'translate(5px, -50%)';\n } else {\n timelineTooltip.style.display = 'none';\n }\n },\n ],\n },\n axes: [\n {\n space: 50,\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n show: true,\n font: '10px system-ui, sans-serif',\n size: 30,\n values: (u: any, vals: any[]) =>\n vals.map((v) => {\n const d = new Date(v * 1000);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n }),\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n font: '10px system-ui, sans-serif',\n values: (u: any, vals: any[]) => vals.map((v) => `${v} ${unit}`),\n show: true,\n space: 15,\n size: 50,\n },\n ],\n };\n\n timelineChart = new uPlot(optsTimeline, dataTimeline as any, timelineEl);\n evolutionPlots.push(timelineChart);\n\n timelineEl.addEventListener('mouseleave', () => {\n timelineChart!.redraw();\n });\n\n // Range control moved to toolbar\n } else {\n timelineEl.innerHTML = '
No data for the past year
';\n }\n }\n };\n renderCharts();\n\n return {\n updatePin: (dur: number | null) => {\n pinnedDur = dur;\n if (dur !== null) currentDur = dur;\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}${pinnedDur !== null ? ' (Pinned)' : ''}`;\n\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n if (mainChart) mainChart.redraw();\n },\n updateRange: (range: string) => {\n currentRange = range;\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n },\n };\n}\n\nfunction getWeekStart(date: Date): Date {\n const d = new Date(date);\n const day = d.getUTCDay();\n const diff = d.getUTCDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday\n d.setUTCDate(diff);\n d.setUTCHours(0, 0, 0, 0);\n return d;\n}\n\nfunction computeWeeklyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey]) weeklyData[weekKey] = { timestamp: weekStart.getTime(), distance: 0 };\n\n weeklyData[weekKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeWeeklyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey])\n weeklyData[weekKey] = { timestamp: weekStart.getTime(), elevation: 0 };\n\n weeklyData[weekKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction renderProgressCard(\n grid: HTMLElement,\n allTracks: TrackData[],\n type: 'distance' | 'elevation',\n syncKey?: any,\n onDateRangeSelect?: (start: string, end: string) => void,\n gridWidth?: number,\n) {\n const isDistance = type === 'distance';\n const weeklyData = isDistance\n ? computeWeeklyDistance(allTracks)\n : computeWeeklyElevation(allTracks);\n const accumulated = computeAccumulatedMetric(allTracks, (t) =>\n isDistance ? t.stats.totalDist : t.stats.elevGain,\n );\n const color = isDistance ? Metrics.distance.color : Metrics.elevation.color;\n const unit = isDistance ? 'km' : 'm';\n const icon = isDistance ? Metrics.distance.icon : Metrics.elevation.icon;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = `chart-row ${type}-progress-card`;\n cardContainer.id = `${type}-evolution-card`;\n\n cardContainer.innerHTML = `\n
\n
\n ${icon}\n ${isDistance ? 'Distance Progress' : 'Elevation Progress'}\n
\n
\n
\n
\n
\n
\n
\n
\n ${renderAccumulatedTable(accumulated, isDistance, unit)}\n
\n
\n `;\n\n grid.appendChild(cardContainer);\n\n const chartEl = cardContainer.querySelector(`#${type}-weekly-chart`) as HTMLElement;\n const yAxisEl = cardContainer.querySelector(`#${type}-y-axis-chart`) as HTMLElement;\n\n if (!chartEl || !yAxisEl) return;\n\n chartEl.style.position = 'relative';\n\n // Use inline tooltip style\n const tooltip = document.createElement('div');\n tooltip.className = 'cur-y-val';\n tooltip.style.cssText = `color:${color};display:none`;\n chartEl.appendChild(tooltip);\n\n const xData = weeklyData.map((d) => d.timestamp / 1000);\n const yData = isDistance\n ? (weeklyData as any[]).map((d) => d.distance / 1000)\n : (weeklyData as any[]).map((d) => d.elevation);\n\n if (xData.length === 0) return;\n\n const yDataSmoothed = gaussianSmooth(yData, 2);\n\n const chartClientW = Math.max(0, (gridWidth || 570) - 20 - 320 - 20);\n const width = Math.max(chartClientW, xData.length * 40);\n const maxVal = Math.max(...yData) * 1.1;\n\n const mainOpts: uPlot.Options = {\n width: width,\n height: 150,\n padding: [10, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n scales: {\n x: { time: true },\n y: { range: [0, maxVal] },\n },\n series: [\n {},\n {\n label: isDistance ? 'Distance' : 'Elevation',\n stroke: color,\n fill: hexToRgba(color, 0.1),\n width: 2,\n points: { show: true, size: 4 },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n dash: [5, 5],\n points: { show: false },\n },\n ],\n cursor: {\n sync: syncKey ? { key: syncKey.key } : undefined,\n drag: { x: false, y: false },\n points: { show: false },\n x: false,\n y: false,\n },\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null) {\n const item = weeklyData[idx];\n if (item) {\n const start = new Date(item.timestamp);\n const end = new Date(item.timestamp + 7 * 24 * 60 * 60 * 1000); // End of week\n const startStr = start.toISOString().split('T')[0];\n const endStr = end.toISOString().split('T')[0];\n onDateRangeSelect?.(startStr, endStr);\n }\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n const idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (\n idx != null &&\n cursorLeft != null &&\n cursorTop != null &&\n cursorLeft >= 0 &&\n cursorTop >= 0\n ) {\n const val = u.data[1][idx];\n const valStr =\n val != null ? (isDistance ? `${val.toFixed(1)} km` : `${val.toFixed(0)} m`) : '\u2014';\n\n tooltip.innerHTML = valStr;\n tooltip.style.display = 'block';\n tooltip.style.left = `${u.valToPos(u.data[0][idx]!, 'x', false)}px`;\n tooltip.style.top = `${u.valToPos(u.data[1][idx]!, 'y', false)}px`;\n tooltip.style.transform = 'translate(6px, -50%)';\n } else {\n tooltip.style.display = 'none';\n }\n\n u.redraw(false);\n },\n ],\n draw: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(u.data[1][idx]!, 'y', true);\n const dpr = window.devicePixelRatio || 1;\n const ctx = u.ctx;\n const bb = u.bbox;\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n ctx.arc(pcx, pcy, 6 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n // X Label Pill\n const d = new Date(u.data[0][idx]! * 1000);\n const xValStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n },\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n space: 40,\n values: (self, splits) =>\n splits.map((s) => {\n const d = new Date(s * 1000);\n return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`;\n }),\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: (self, splits) => splits.map((s) => `${s.toFixed(0)} ${unit}`),\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n };\n\n const mainChart = new uPlot(mainOpts, [xData, yData, yDataSmoothed], chartEl);\n evolutionPlots.push(mainChart);\n\n const scrollContainer = cardContainer.querySelector('.chart-scroll-container') as HTMLElement;\n if (scrollContainer && xData.length * 40 > width)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n\n return {\n updateRange: (range: string) => {\n const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000;\n\n const filteredData = weeklyData.filter((d) => d.timestamp >= minTime);\n\n const newXData = filteredData.map((d) => d.timestamp / 1000);\n const newYData = isDistance\n ? (filteredData as any[]).map((d) => d.distance / 1000)\n : (filteredData as any[]).map((d) => d.elevation);\n const newYDataSmoothed = gaussianSmooth(newYData, 2);\n\n const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40);\n const newMaxVal = Math.max(...newYData) * 1.1;\n\n mainChart.setSize({ width: newWidth, height: 150 });\n mainChart.setScale('y', { min: 0, max: newMaxVal });\n mainChart.setData([newXData, newYData, newYDataSmoothed]);\n\n if (scrollContainer)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n },\n };\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData } from '../parsers';\n\nexport interface AccumulatedData {\n currentYear: number;\n pastYear: number;\n past6m: number;\n past1m: number;\n total: number;\n currentYearAvg: number;\n pastYearAvg: number;\n past6mAvg: number;\n past1mAvg: number;\n totalAvg: number;\n}\n\nexport function computeAccumulatedMetric(\n allTracks: TrackData[],\n extractor: (t: TrackData) => number | undefined,\n): AccumulatedData {\n // Derive deterministic reference timestamp from tracks (or fixed UTC fallback)\n let refTs = 0;\n for (let i = 0; i < allTracks.length; i++) {\n const st = allTracks[i].stats?.startTime;\n if (st && st > refTs) refTs = st;\n }\n if (!refTs) refTs = Date.UTC(2026, 7, 1);\n\n const now = new Date(refTs);\n const currentYear = now.getUTCFullYear();\n\n const oneYearAgoMs = Date.UTC(\n currentYear - 1,\n now.getUTCMonth(),\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const sixMonthsAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 6,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const oneMonthAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 1,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n\n let currentYearVal = 0;\n let pastYearVal = 0;\n let past6mVal = 0;\n let past1mVal = 0;\n let totalVal = 0;\n\n let minTime = refTs;\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime) return;\n const val = extractor(t);\n if (val === undefined) return;\n\n totalVal += val;\n\n const time = t.stats.startTime;\n if (time < minTime) minTime = time;\n\n const date = new Date(time);\n\n if (date.getUTCFullYear() === currentYear) currentYearVal += val;\n\n if (time >= oneYearAgoMs) pastYearVal += val;\n\n if (time >= sixMonthsAgoMs) past6mVal += val;\n\n if (time >= oneMonthAgoMs) past1mVal += val;\n });\n\n const msecPerWeek = 7 * 24 * 60 * 60 * 1000;\n const currentYearStart = Date.UTC(currentYear, 0, 1);\n\n const currentYearWeeks = Math.max(0.1, (refTs - currentYearStart) / msecPerWeek);\n const pastYearWeeks = Math.max(0.1, (refTs - oneYearAgoMs) / msecPerWeek);\n const past6mWeeks = Math.max(0.1, (refTs - sixMonthsAgoMs) / msecPerWeek);\n const past1mWeeks = Math.max(0.1, (refTs - oneMonthAgoMs) / msecPerWeek);\n const totalWeeks = Math.max(0.1, (refTs - minTime) / msecPerWeek);\n\n return {\n currentYear: currentYearVal,\n pastYear: pastYearVal,\n past6m: past6mVal,\n past1m: past1mVal,\n total: totalVal,\n currentYearAvg: currentYearVal / currentYearWeeks,\n pastYearAvg: pastYearVal / pastYearWeeks,\n past6mAvg: past6mVal / past6mWeeks,\n past1mAvg: past1mVal / past1mWeeks,\n totalAvg: totalVal / totalWeeks,\n };\n}\n\nexport function renderAccumulatedTable(\n accumulated: AccumulatedData,\n isDistance: boolean,\n unit: string,\n): string {\n const factor = isDistance ? 1000 : 1;\n const format = (val: number) => {\n const formattedVal = isDistance ? val / factor : val;\n return formattedVal.toLocaleString('en-US', {\n minimumFractionDigits: isDistance ? 1 : 0,\n maximumFractionDigits: isDistance ? 1 : 0,\n });\n };\n\n return `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Period${isDistance ? 'Distance' : 'Elevation'}${isDistance ? 'Distance/Week' : 'Elevation/Week'}
Current Year${format(accumulated.currentYear)} ${unit}${format(accumulated.currentYearAvg)} ${unit}
Past Year${format(accumulated.pastYear)} ${unit}${format(accumulated.pastYearAvg)} ${unit}
Past 6 Months${format(accumulated.past6m)} ${unit}${format(accumulated.past6mAvg)} ${unit}
Past 1 Month${format(accumulated.past1m)} ${unit}${format(accumulated.past1mAvg)} ${unit}
Total${format(accumulated.total)} ${unit}${format(accumulated.totalAvg)} ${unit}
\n `;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 Main Application \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { Storage } from './storage';\nimport { UrlState, AppState } from './url-state';\nimport { Parsers, TrackData, TrackPoint, calculateBounds, simplifyTrack } from './parsers';\nimport { MapView } from './map';\nimport { ChartView } from './charts';\nimport { renderDetails, initDetails, resetDetails } from './tabs/details';\nimport { renderInsights, initInsights, resetInsights } from './tabs/insights';\nimport { renderCombined, initCombined, resizeCombined, resetCombined } from './tabs/combined';\nimport { renderEvolution, resetEvolution } from './tabs/progress';\nimport {\n renderCourses,\n initCourses,\n prepareBenchmarkCourses,\n resetCourses,\n selectCourse,\n} from './tabs/courses';\nimport { fmtSecs, escHtml, fmtDate, getTagColor, compactId, shortRandom } from './utils';\n\nconst TRACK_COLORS: string[] = [\n '#FF6B35',\n '#4ECDC4',\n '#45B7D1',\n '#F7DC6F',\n '#FF6B6B',\n '#BB8FCE',\n '#82E0AA',\n '#F8C471',\n '#3b82f6',\n];\n\nconst POINT_ZOOM_LEVEL = 16;\n\nlet tracks: Record = {};\nlet skippedImports: { name: string; reason: string }[] = [];\n\nfunction isSameDay(t1: number, t2: number) {\n const d1 = new Date(t1);\n const d2 = new Date(t2);\n return (\n d1.getUTCFullYear() === d2.getUTCFullYear() &&\n d1.getUTCMonth() === d2.getUTCMonth() &&\n d1.getUTCDate() === d2.getUTCDate()\n );\n}\n\nlet cancelProcessing = false;\nlet selectedId: string | null = null;\nlet colorIdx = 0;\nlet followDot = false;\nlet currentMapColors: string[] | null = null;\n\n// Search/Filter state\nlet searchQuery = '';\nlet searchRegex = false;\nlet currentSort = 'date-desc';\n\ninterface Filters {\n date: [string | null, string | null];\n dist: [number | null, number | null];\n dur: [number | null, number | null];\n metrics: Set;\n tags: string[];\n sport: string | null;\n}\n\nlet filters: Filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n};\n\nfunction syncFiltersToUrl(push: boolean = false) {\n UrlState.patch(\n {\n f_date: filters.date.every((v) => v === null) ? null : filters.date,\n f_dist: filters.dist.every((v) => v === null) ? null : filters.dist,\n f_dur: filters.dur.every((v) => v === null) ? null : filters.dur,\n f_mets: filters.metrics.size === 0 ? null : Array.from(filters.metrics),\n f_tags: filters.tags.length === 0 ? null : filters.tags,\n },\n push,\n );\n}\n\nfunction syncMetricsToUrl() {\n const active = ChartView.getActiveMetrics();\n const metrics = ChartView.METRICS;\n const abbrs = Array.from(active).map((key) => metrics[key].abbr);\n UrlState.patch({ metrics: abbrs.length ? abbrs : null });\n}\n\nconst SORT_OPTIONS = [\n { label: 'Newest first', val: 'date-desc', icon: 'calendar_today' },\n { label: 'Oldest first', val: 'date-asc', icon: 'history' },\n { label: 'Longest distance', val: 'dist-desc', icon: 'straighten' },\n { label: 'Shortest distance', val: 'dist-asc', icon: 'horizontal_rule' },\n { label: 'Longest duration', val: 'dur-desc', icon: 'timer' },\n { label: 'Shortest duration', val: 'dur-asc', icon: 'timer_off' },\n];\n\nfunction showSortMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.sort-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'sort-menu-popup';\n\n SORT_OPTIONS.forEach((opt) => {\n const item = document.createElement('div');\n item.className = `menu-item ${currentSort === opt.val ? 'active' : ''}`;\n item.innerHTML = `\n ${opt.icon}\n ${opt.label}\n ${currentSort === opt.val ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n currentSort = opt.val;\n UrlState.patch({ sort: opt.val });\n updateSearchSortUI();\n renderTrackList();\n popup.remove();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction showMetricMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const available = ChartView.getAvailableMetrics();\n const active = ChartView.getActiveMetrics();\n\n Object.entries(metrics).forEach(([key, def]) => {\n if (!available.has(key)) return;\n\n const item = document.createElement('div');\n item.className = `menu-item ${active.has(key) ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${active.has(key) ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n ChartView.toggleMetric(key);\n const isNowActive = ChartView.getActiveMetrics().has(key);\n item.classList.toggle('active', isNowActive);\n item.querySelector('.check')!.textContent = isNowActive ? 'check' : '';\n\n const pill = document.querySelector(`#metric-pills .metric-pill[data-metric=\"${key}\"]`);\n if (pill) pill.classList.toggle('active', isNowActive);\n\n updateToolbarLayout();\n\n syncMetricsToUrl();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.right = `${window.innerWidth - rect.right}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\n// \u2500\u2500 Tab Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.addEventListener('select-track', (e: any) => {\n const id = e.detail.id;\n const idx = e.detail.idx;\n const dur = e.detail.dur;\n if (id && tracks[id]) {\n selectTrack(id);\n if (idx != null && dur != null) {\n const t = tracks[id];\n const pts = t.points;\n if (idx >= 0 && idx < pts.length) {\n const pIdx = pts[idx];\n if (pIdx && pIdx.time != null) {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const tMin = (pIdx.time - t0) / 1000;\n const tMax = tMin + dur;\n\n // ChartView selection\n ChartView.restoreSelection(tMin, tMax);\n\n // Find iMax based on duration\n let iMax = pts.findIndex((p) => (p.time || 0) >= pIdx.time! + dur * 1000);\n if (iMax === -1) iMax = pts.length - 1;\n\n const selPts = pts.slice(idx, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n\n renderInsights(t);\n\n MapView.highlightSegment(id, pts, idx, iMax, false, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n\n // Update URL state\n UrlState.patch({ sel: [tMin, tMax] });\n }\n }\n }\n }\n});\n\ndocument.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.tab-btn') as HTMLElement;\n if (!btn) return;\n const nav = btn.closest('#tab-nav');\n if (!nav) return;\n\n // Toggle buttons\n nav.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn));\n\n const tab = btn.dataset.tab!;\n UrlState.patch({ tab }, true);\n\n // Toggle contents\n const panel = nav.closest('#chart-panel');\n if (panel) {\n panel.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${btn.dataset.tab}`);\n });\n }\n\n if (btn.dataset.tab === 'details' && selectedId && tracks[selectedId])\n renderDetails(tracks[selectedId], getGlobalTags());\n\n if (btn.dataset.tab === 'insights' && selectedId && tracks[selectedId])\n renderInsights(tracks[selectedId]);\n\n if (btn.dataset.tab === 'evolution') {\n renderEvolution(\n selectedId ? tracks[selectedId] : null,\n Object.values(tracks),\n (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n },\n (start, end) => {\n filters.date = [start, end];\n applyFilters();\n syncFiltersToUrl(true);\n updateFilterUI();\n },\n );\n }\n\n if (btn.dataset.tab === 'combined' && selectedId && tracks[selectedId])\n renderCombined(tracks[selectedId]);\n\n if (btn.dataset.tab === 'courses') renderCourses();\n\n if (btn.dataset.tab === 'graphs') {\n ChartView.resize();\n updateToolbarLayout();\n\n // Restore selection from URL\n const s = UrlState.get().sel;\n if (s) ChartView.restoreSelection(s[0], s[1]);\n }\n});\n\nasync function resetBenchmarkState() {\n if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n await Storage.clear();\n tracks = {};\n skippedImports = [];\n selectedId = null;\n colorIdx = 0;\n currentMapColors = null;\n cancelProcessing = false;\n followDot = false;\n searchQuery = '';\n searchRegex = false;\n currentSort = 'date-desc';\n filters.date = [null, null];\n filters.dist = [null, null];\n filters.dur = [null, null];\n filters.metrics.clear();\n filters.tags = [];\n Parsers.setHRZones([120, 140, 160, 180]);\n Parsers.setFTP(200);\n resetCourses();\n resetInsights();\n resetDetails();\n resetCombined();\n resetEvolution();\n if (MapView.removeAllTracks) MapView.removeAllTracks();\n if (MapView.clearTracks) MapView.clearTracks();\n MapView.clearHighlight();\n if (ChartView.resetState) ChartView.resetState();\n else if (ChartView.clear) ChartView.clear();\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === 'graphs');\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === 'tab-graphs');\n });\n UrlState.reset();\n const toastContainer = document.getElementById('toast-container');\n if (toastContainer) toastContainer.innerHTML = '';\n document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());\n if (typeof renderTrackList === 'function') renderTrackList();\n}\n\n// \u2500\u2500 Boot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function init() {\n // Wait for fonts to be loaded with a cleaned-up timeout\n let fontTimerId: number | null = null;\n const fontTimeout = new Promise((resolve) => {\n fontTimerId = window.setTimeout(resolve, 1000);\n });\n try {\n const fontLoadPromise = document.fonts\n ? Promise.all([\n document.fonts.load('24px \"Material Symbols Rounded\"').catch(() => {}),\n document.fonts.ready,\n ])\n : Promise.resolve();\n await Promise.race([fontLoadPromise, fontTimeout]);\n } finally {\n if (fontTimerId !== null) window.clearTimeout(fontTimerId);\n }\n document.body.classList.remove('loading-fonts');\n const storageSelect = document.getElementById(\n 'storage-backend-select',\n ) as HTMLSelectElement | null;\n if (storageSelect) {\n storageSelect.value = UrlState.get().storage || 'memory';\n storageSelect.addEventListener('change', (e) => {\n const selected = (e.target as HTMLSelectElement).value;\n const params = new URLSearchParams(window.location.search);\n if (selected === 'memory') {\n params.delete('storage');\n } else {\n params.set('storage', selected);\n }\n window.location.search = params.toString();\n });\n }\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const mapLoader = document.getElementById('map-loader');\n const mapLoaderSpan = mapLoader?.querySelector('span');\n\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading database...';\n mapLoader.classList.remove('hidden');\n }\n\n const urlState = UrlState.get();\n\n initInsights((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n initDetails(\n () => {\n applyFilters();\n syncFiltersToUrl();\n },\n (id: string) => {\n deleteTrack(id);\n },\n );\n initCombined();\n initCourses((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n\n // Init sub-systems\n MapView.init(\n (id) => selectTrack(id),\n onMapMove,\n onMapPointClick,\n (id, idx) => {\n if (id === selectedId) ChartView.setHoverAt(idx);\n else ChartView.setHoverAt(null);\n },\n onMapDblClick,\n );\n ChartView.init(onChartCursorMove, onChartRangeChange, onChartClick, (idx) => {\n UrlState.patch({ sel_point: idx });\n });\n\n ChartView.setMapColorChangeCb((data) => {\n if (data) {\n currentMapColors = data.colors;\n if (selectedId) MapView.colorTrackByMetric(selectedId, data.pts, data.colors);\n } else {\n currentMapColors = null;\n if (selectedId) MapView.clearMetricColor(selectedId);\n }\n\n // Refresh highlight with new colors if a selection exists\n const currentUrlState = UrlState.get();\n if (currentUrlState.sel)\n onChartRangeChange(currentUrlState.sel[0], currentUrlState.sel[1], ChartView.getXAxis());\n });\n\n applyState(urlState);\n\n // Reset persistent storage and in-memory state for clean multi-iteration benchmark executions\n await Storage.openDB();\n await resetBenchmarkState();\n\n // Load persisted tracks\n try {\n // Load global settings\n const hrZones = await Storage.get('hr_zones');\n if (hrZones) Parsers.setHRZones(hrZones);\n\n const ftp = await Storage.get('ftp');\n if (ftp) Parsers.setFTP(ftp);\n\n const saved = await Storage.getAll();\n saved.sort((a, b) => a.addedAt - b.addedAt);\n\n if (mapLoaderSpan) mapLoaderSpan.textContent = `Preparing ${saved.length} tracks...`;\n\n const tracksToLoad: TrackData[] = [];\n for (const t of saved) {\n let updated = false;\n if (!t.bounds && t.points.length > 0) {\n const b = calculateBounds(t.points);\n if (b) {\n t.bounds = b;\n updated = true;\n }\n }\n if (!t.simplifiedPoints && t.points.length > 0) {\n t.simplifiedPoints = simplifyTrack(t.points, 50);\n updated = true;\n }\n if (updated) await Storage.save(t);\n\n tracks[t.id] = t;\n tracksToLoad.push(t);\n }\n MapView.addTracks(tracksToLoad);\n applyFilters();\n\n const restoreId =\n urlState.track && saved.find((t) => t.id === urlState.track)\n ? urlState.track\n : saved.length > 0\n ? saved[0].id\n : null;\n\n const mapLoader = document.getElementById('map-loader');\n\n // 1. Process and load the \"Priority\" track first\n const selectedTrackData = saved.find((t) => t.id === restoreId);\n if (selectedTrackData) {\n await processAndLoadTrack(selectedTrackData);\n selectTrack(selectedTrackData.id, !urlState.map_pos);\n\n // Explicitly restore selection/pin from URL if they exist\n if (urlState.sel && Array.isArray(urlState.sel) && urlState.sel.length === 2) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.restoreSelection(urlState.sel![0], urlState.sel![1]);\n });\n });\n }\n if (urlState.sel_point !== undefined && urlState.sel_point !== null) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.setCursorAt(urlState.sel_point!);\n });\n });\n }\n }\n\n // Hide database loader\n if (mapLoader) mapLoader.classList.add('hidden');\n\n // 2. Load the rest in background chunks\n if (saved.length > (selectedTrackData ? 1 : 0)) {\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading tracks...';\n mapLoader.classList.remove('hidden');\n }\n\n const remaining = saved.filter((t) => t.id !== restoreId);\n let index = 0;\n\n const loadNextChunk = async () => {\n const chunkSize = 2; // Process 2 tracks per frame\n const end = Math.min(index + chunkSize, remaining.length);\n\n for (; index < end; index++) await processAndLoadTrack(remaining[index]);\n\n if (index < remaining.length) {\n requestAnimationFrame(loadNextChunk);\n } else {\n if (mapLoader) mapLoader.classList.add('hidden');\n applyFilters(); // Final sync\n if (selectedId && tracks[selectedId]) {\n renderEvolution(tracks[selectedId], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n // Only fit all if no saved map position and we just finished loading everything\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n };\n\n requestAnimationFrame(loadNextChunk);\n } else {\n applyFilters();\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n } catch (e) {\n console.warn('Could not load saved tracks:', e);\n }\n\n // Panel resizers\n initResizeHandle();\n initSidebarResizer();\n initMetricPillDraggable();\n updateToolbarLayout();\n\n // Basemap switcher\n document.getElementById('basemap-switcher')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.bm-btn') as HTMLElement;\n if (!btn) return;\n document.querySelectorAll('.bm-btn').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n if (btn.dataset.layer) {\n MapView.switchBasemap(btn.dataset.layer);\n UrlState.patch({ map: btn.dataset.layer });\n }\n });\n\n // Fit all\n document.getElementById('btn-fit-all')?.addEventListener('click', () => MapView.fitAll());\n\n // Clear all\n document.getElementById('btn-clear-all')?.addEventListener('click', clearAll);\n\n // Search\n document.getElementById('track-search')?.addEventListener('input', (e) => {\n searchQuery = (e.target as HTMLInputElement).value;\n applyFilters();\n UrlState.patch({ q: searchQuery || null });\n });\n\n document.getElementById('btn-regex-toggle')?.addEventListener('click', (e) => {\n searchRegex = !searchRegex;\n (e.target as HTMLElement).classList.toggle('active', searchRegex);\n applyFilters();\n UrlState.patch({ re: searchRegex ? 1 : null });\n });\n\n // Sort\n document.getElementById('btn-sort-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSortMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric menu toggle\n document.getElementById('btn-metric-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMetricMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric toggles (shared logic)\n const toggleMetric = (metric: string, pill: HTMLElement | null) => {\n if (pill) pill.classList.toggle('active');\n ChartView.toggleMetric(metric);\n syncMetricsToUrl();\n };\n\n document.getElementById('metric-pills')?.addEventListener('click', (e) => {\n const pill = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (pill) {\n const metric = pill.dataset.metric;\n if (metric) {\n toggleMetric(metric, pill);\n\n // Scroll to it if it became active\n if (ChartView.getActiveMetrics().has(metric)) {\n const targetEl = document.querySelector(`.chart-row[data-metric=\"${metric}\"]`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n }\n }\n });\n\n // X-axis toggle\n document.getElementById('x-axis-ctrl')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const axis = btn.dataset.axis!;\n ChartView.setXAxis(axis);\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', b === btn));\n UrlState.patch({ xaxis: axis });\n });\n\n // Follow dot\n document.getElementById('btn-follow-dot')?.addEventListener('click', (e) => {\n followDot = !followDot;\n (e.currentTarget as HTMLElement).classList.toggle('active', followDot);\n });\n\n // Reset zoom\n document.getElementById('btn-reset-zoom')?.addEventListener('click', () => {\n ChartView.resetZoom();\n MapView.clearHighlight();\n });\n\n // File drag/drop\n initDropZone();\n\n // File browse\n document.getElementById('file-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n document.getElementById('folder-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n\n // Filters\n document.getElementById('btn-toggle-filters')?.addEventListener('click', () => {\n const panel = document.getElementById('filter-panel');\n if (panel) {\n panel.classList.toggle('hidden');\n document\n .getElementById('btn-toggle-filters')\n ?.classList.toggle('active', !panel.classList.contains('hidden'));\n }\n });\n\n const onFilterInput = (type: 'date' | 'dist' | 'dur', idx: number, e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n (filters[type] as any)[idx] = val === '' ? null : val;\n applyFilters();\n syncFiltersToUrl();\n };\n\n document\n .getElementById('filter-date-start')\n ?.addEventListener('change', (e) => onFilterInput('date', 0, e));\n document\n .getElementById('filter-date-end')\n ?.addEventListener('change', (e) => onFilterInput('date', 1, e));\n document\n .getElementById('filter-dist-min')\n ?.addEventListener('input', (e) => onFilterInput('dist', 0, e));\n document\n .getElementById('filter-dist-max')\n ?.addEventListener('input', (e) => onFilterInput('dist', 1, e));\n document\n .getElementById('filter-dur-min')\n ?.addEventListener('input', (e) => onFilterInput('dur', 0, e));\n document\n .getElementById('filter-dur-max')\n ?.addEventListener('input', (e) => onFilterInput('dur', 1, e));\n\n const burgerBtn = document.getElementById('sport-burger-btn');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n burgerBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n if (dropdownContent) {\n const isVisible = dropdownContent.style.display === 'block';\n dropdownContent.style.display = isVisible ? 'none' : 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (dropdownContent && dropdownContent.style.display === 'block') {\n if (!dropdownContent.contains(e.target as Node) && e.target !== burgerBtn)\n dropdownContent.style.display = 'none';\n }\n });\n\n document.getElementById('sport-filter-container')?.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const btn = target.closest('[data-sport]');\n if (btn) {\n const selectedSport = (btn as HTMLElement).dataset.sport || null;\n filters.sport = filters.sport === selectedSport ? null : selectedSport;\n applyFilters();\n syncFiltersToUrl();\n updateFilterUI();\n\n if (target.closest('.dropdown-item')) {\n if (dropdownContent) dropdownContent.style.display = 'none';\n }\n }\n });\n\n document.getElementById('filter-metrics')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.mini-pill') as HTMLElement;\n if (!btn) return;\n const m = btn.dataset.metric!;\n if (filters.metrics.has(m)) filters.metrics.delete(m);\n else filters.metrics.add(m);\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('btn-reset-filters')?.addEventListener('click', () => {\n filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n };\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('filter-tags')?.addEventListener('input', (e) => {\n const val = (e.target as HTMLInputElement).value;\n filters.tags = val\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => !!s);\n applyFilters();\n syncFiltersToUrl();\n });\n\n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n MapView.hideCursor();\n MapView.closePopup?.();\n // Dismiss popups and modals\n document\n .querySelectorAll(\n '.color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop',\n )\n .forEach((el) => el.remove());\n }\n });\n\n // Resize charts when window changes\n window.addEventListener('resize', () => {\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n updateToolbarLayout();\n });\n\n // Handle back/forward navigation\n window.addEventListener('popstate', () => {\n UrlState.refresh();\n applyState(UrlState.get());\n });\n\n initBenchmarkTriggers();\n await preloadBenchmarkFiles();\n\n // Signal to Speedometer test harness that asynchronous initialization has completed\n // and benchmark step triggers are bound.\n const readyEl = document.createElement('div');\n readyEl.id = 'app-is-ready';\n readyEl.setAttribute('data-ready', 'true');\n readyEl.style.display = 'none';\n document.body.appendChild(readyEl);\n\n const camelReadyEl = document.createElement('div');\n camelReadyEl.id = 'appIsReady';\n camelReadyEl.setAttribute('data-ready', 'true');\n camelReadyEl.style.display = 'none';\n document.body.appendChild(camelReadyEl);\n}\n\nlet preloadedBenchmarkPayloads:\n | {\n cleanName: string;\n buf: ArrayBuffer;\n text?: string;\n file: File;\n }[]\n | null = null;\n\nasync function preloadBenchmarkFiles(): Promise<\n { cleanName: string; buf: ArrayBuffer; text?: string; file: File }[]\n> {\n if (preloadedBenchmarkPayloads) return preloadedBenchmarkPayloads;\n try {\n const manifestResp = await fetch('./test-data/manifest.json');\n const fileNames: string[] = await manifestResp.json();\n const decoder = new TextDecoder();\n preloadedBenchmarkPayloads = await Promise.all(\n fileNames.map(async (name) => {\n const fileResp = await fetch(`./test-data/${name}`);\n let buf = await fileResp.arrayBuffer();\n let cleanName = name;\n if (name.toLowerCase().endsWith('.gz')) {\n cleanName = name.slice(0, -3);\n const bytes = new Uint8Array(buf);\n if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) {\n const ds = new DecompressionStream('gzip');\n const stream = new Blob([buf]).stream().pipeThrough(ds);\n buf = await new Response(stream).arrayBuffer();\n }\n }\n const text = cleanName.toLowerCase().endsWith('.fit') ? undefined : decoder.decode(buf);\n const file = new File([buf], cleanName, { type: 'application/octet-stream' });\n (file as any)._buf = buf;\n if (text !== undefined) (file as any)._text = text;\n return { cleanName, buf, text, file };\n }),\n );\n // Warm up GPX, TCX, and FIT parser and chart code paths during prepare phase\n let warmSample: any = null;\n for (const idx of [0, 2, 4]) {\n if (preloadedBenchmarkPayloads[idx]) {\n const parsed = await Parsers.parseFile(preloadedBenchmarkPayloads[idx].file);\n if (idx === 0) warmSample = parsed;\n }\n }\n if (warmSample) {\n const warmPts = warmSample.points.slice(0, 1250);\n const warmTrack: TrackData = {\n ...warmSample,\n id: 'warmup',\n fileName: 'warmup.gpx',\n fileSize: 1024,\n points: warmPts,\n bounds: calculateBounds(warmPts) || undefined,\n simplifiedPoints: simplifyTrack(warmPts, 50),\n stats: Parsers.computeStats(warmPts),\n addedAt: 1785542400000,\n visible: true,\n color: TRACK_COLORS[0],\n };\n const warmTrack2: TrackData = {\n ...warmTrack,\n id: 'warmup-2',\n fileName: 'warmup2.gpx',\n addedAt: 1785628800000,\n color: TRACK_COLORS[1],\n };\n const warmList = [warmTrack, warmTrack2];\n Parsers.ensureCurvesAndZones(warmTrack);\n Parsers.ensureCurvesAndZones(warmTrack2);\n MapView.addTracks(warmList);\n ChartView.loadTrack(warmTrack, warmList, false);\n ChartView.restoreSelection(10, 50, true);\n ChartView.setCursorAt(25, true);\n ChartView.setActiveMetrics(['elevation', 'speed', 'power']);\n ChartView.analyzeTelemetryIntervals(warmList, 10, 50);\n renderInsights(warmTrack, warmList);\n renderDetails(warmTrack, [], warmList);\n renderCombined(warmList, warmList);\n renderEvolution(warmTrack, warmList);\n prepareBenchmarkCourses(warmList);\n selectCourse('course-1', true);\n await resetBenchmarkState();\n void document.body.offsetHeight;\n await new Promise((r) => window.setTimeout(r, 0));\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n return preloadedBenchmarkPayloads;\n } catch {\n return [];\n }\n}\n\nfunction initBenchmarkTriggers() {\n const btnLoad = document.getElementById('btn-step-load');\n const btnAnalysis = document.getElementById('btn-step-analysis');\n const btnInsights = document.getElementById('btn-step-insights');\n const btnDetails = document.getElementById('btn-step-details');\n const btnAggregate = document.getElementById('btn-step-aggregate');\n const btnEvolution = document.getElementById('btn-step-evolution');\n const btnCourses = document.getElementById('btn-step-courses');\n\n function activateTab(tabName: string) {\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === tabName);\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${tabName}`);\n });\n UrlState.patch({ tab: tabName }, false);\n }\n\n btnLoad?.addEventListener('click', async () => {\n try {\n if (Object.keys(tracks).length > 0 || skippedImports.length > 0 || selectedId !== null) {\n await Storage.openDB();\n await resetBenchmarkState();\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n const payloads = await preloadBenchmarkFiles();\n const loadedFiles: File[] = payloads.map((p) => p.file);\n await handleFiles(loadedFiles);\n const allTracks = Object.values(tracks);\n if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id);\n } finally {\n window.dispatchEvent(new CustomEvent('load-and-parse-complete'));\n }\n });\n\n btnAnalysis?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('graphs');\n if (!selectedId && allTracks.length > 0) {\n selectTrack(allTracks[0].id);\n }\n ChartView.restoreSelection(120, 900, true);\n ChartView.setCursorAt(300, true);\n const availableMetrics = ChartView.getAvailableMetrics();\n const analysisMetrics = ['elevation', 'speed', 'power'].filter((m) =>\n availableMetrics.has(m),\n );\n if (analysisMetrics.length > 0) {\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const metric = (el as HTMLElement).dataset.metric;\n if (metric) el.classList.toggle('active', analysisMetrics.includes(metric));\n });\n updateToolbarLayout();\n ChartView.setActiveMetrics(analysisMetrics);\n } else {\n updateToolbarLayout();\n }\n ChartView.analyzeTelemetryIntervals(allTracks, 120, 900);\n onChartRangeChange(120, 900, ChartView.getXAxis(), false);\n } finally {\n window.dispatchEvent(new CustomEvent('analysis-complete'));\n }\n });\n\n btnInsights?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t));\n activateTab('insights');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderInsights(primaryTrack, allTracks);\n } finally {\n window.dispatchEvent(new CustomEvent('insights-complete'));\n }\n });\n\n btnDetails?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('details');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderDetails(primaryTrack, getGlobalTags(), allTracks);\n } finally {\n window.dispatchEvent(new CustomEvent('details-complete'));\n }\n });\n\n btnAggregate?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n if (allTracks.length >= 2) {\n const selectedTwo = [allTracks[0], allTracks[1]];\n activateTab('combined');\n renderCombined(selectedTwo, allTracks);\n }\n } finally {\n window.dispatchEvent(new CustomEvent('aggregate-complete'));\n }\n });\n\n btnEvolution?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('evolution');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n renderEvolution(primaryTrack, allTracks, (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n } finally {\n window.dispatchEvent(new CustomEvent('evolution-complete'));\n }\n });\n\n btnCourses?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('courses');\n prepareBenchmarkCourses(allTracks);\n selectCourse('course-1', true);\n } finally {\n window.dispatchEvent(new CustomEvent('courses-complete'));\n }\n });\n\n (window as any).benchmarkSteps = {\n loadAndParseFiles: () => document.getElementById('btn-step-load')?.click(),\n displayAnalysisMetrics: () => document.getElementById('btn-step-analysis')?.click(),\n displayInsights: () => document.getElementById('btn-step-insights')?.click(),\n displayDetails: () => document.getElementById('btn-step-details')?.click(),\n displayAggregateMetrics: () => document.getElementById('btn-step-aggregate')?.click(),\n displayEvolutionMetrics: () => document.getElementById('btn-step-evolution')?.click(),\n displayCourses: () => document.getElementById('btn-step-courses')?.click(),\n };\n}\n\nasync function processAndLoadTrack(t: TrackData) {\n // Migration: re-calculate stats if new insights are missing or old format\n const powerCurveEntries = t.stats.powerCurve ? Object.values(t.stats.powerCurve) : [];\n\n const needsEnrich =\n t.points.length > 1 && (t.points[1].speed === undefined || t.points[1].gradient === undefined);\n\n const needsRecalc =\n needsEnrich ||\n !t.stats.powerCurve ||\n !t.stats.hrZones ||\n !t.stats.hrCurve ||\n t.stats.shifts === undefined ||\n t.stats.avgBattery === undefined ||\n t.stats.avgTemp === undefined ||\n (powerCurveEntries.length > 0 && typeof (powerCurveEntries[0] as any) === 'number') ||\n ((t.stats.duration || 0) > 10800 * 1000 && t.stats.powerCurve && !t.stats.powerCurve[14400]);\n\n if (needsRecalc) {\n if (needsEnrich) t.points = Parsers.enrichPoints(t.points);\n t.stats = Parsers.computeStats(t.points);\n await Storage.save(t);\n }\n\n tracks[t.id] = t;\n colorIdx = Math.max(colorIdx, TRACK_COLORS.indexOf(t.color) + 1);\n MapView.addTrack(t);\n MapView.setTrackVisible(t.id, t.visible && !t._filtered);\n renderTrackList(); // Progressive list update\n}\n\nfunction initResizeHandle() {\n const handle = document.getElementById('resize-handle');\n const panel = document.getElementById('chart-panel');\n if (!handle || !panel) return;\n\n let isDragging = false;\n\n handle.addEventListener('mousedown', () => {\n isDragging = true;\n document.body.style.cursor = 'ns-resize';\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const h = window.innerHeight - e.clientY;\n const clampedH = Math.max(100, Math.min(window.innerHeight - 100, h));\n panel.style.height = `${clampedH}px`;\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n document.body.style.cursor = '';\n });\n}\n\nfunction initSidebarResizer() {\n const resizer = document.getElementById('sidebar-resizer');\n const sidebar = document.getElementById('sidebar');\n if (!resizer || !sidebar) return;\n\n let isDragging = false;\n\n resizer.addEventListener('mousedown', () => {\n isDragging = true;\n resizer.classList.add('dragging');\n document.body.classList.add('dragging-sidebar');\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const w = e.clientX;\n const clampedW = Math.max(200, Math.min(600, w));\n sidebar.style.width = `${clampedW}px`;\n sidebar.style.setProperty('--sidebar-w', `${clampedW}px`);\n ChartView.resize();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n resizer.classList.remove('dragging');\n document.body.classList.remove('dragging-sidebar');\n });\n}\n\n// \u2500\u2500 Event Handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction onMapMove(lat: number, lng: number, zoom: number) {\n UrlState.patch({ map_pos: [lat, lng, zoom] });\n}\n\nfunction onMapPointClick(id: string, idx: number) {\n selectTrack(id, false);\n ChartView.setCursorAt(idx);\n}\n\nfunction onMapDblClick() {\n // MapView.fitAll();\n}\n\nfunction onChartCursorMove(pt: TrackPoint | null) {\n if (pt && pt.lat != null && pt.lon != null) {\n MapView.showCursorAt(pt.lat, pt.lon);\n if (followDot) MapView.centerOn(pt.lat, pt.lon, null, true);\n } else {\n MapView.hideCursor();\n }\n}\n\nfunction onChartRangeChange(min: number | null, max: number | null, axis: string, fit = false) {\n if (!selectedId || !tracks[selectedId]) return;\n const t = tracks[selectedId];\n\n if (min === null || max === null) {\n MapView.clearHighlight();\n if (t && (UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n UrlState.patch({ sel: null });\n return;\n }\n\n // Find point indices\n const pts = t.points;\n let iMin = 0,\n iMax = pts.length - 1;\n\n if (axis === 'distance') {\n const d0 = min * 1000,\n d1 = max * 1000;\n iMin = pts.findIndex((p) => (p.dist || 0) >= d0);\n iMax = pts.findIndex((p) => (p.dist || 0) >= d1);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const ts0 = t0 + min * 1000,\n ts1 = t0 + max * 1000;\n iMin = pts.findIndex((p) => (p.time || 0) >= ts0);\n iMax = pts.findIndex((p) => (p.time || 0) >= ts1);\n }\n\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = pts.length - 1;\n\n // Compute selection stats\n const selPts = pts.slice(iMin, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n if ((UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n\n MapView.highlightSegment(selectedId, pts, iMin, iMax, fit, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n UrlState.patch({ sel: [min, max] });\n}\n\nfunction onChartClick(pt: TrackPoint, idx: number) {\n if (pt && pt.lat != null && pt.lon != null) MapView.centerOn(pt.lat, pt.lon, POINT_ZOOM_LEVEL);\n}\n\nexport function selectTrack(id: string, fit = true, deferChartRender = false) {\n if (!tracks[id]) return;\n if (id === selectedId) {\n if (fit) MapView.fitTrack(id);\n return;\n }\n\n const hadSelected = selectedId !== null;\n if (hadSelected) {\n // Clear current views immediately before loading new data\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n }\n\n selectedId = id;\n\n // Fully reset metric coloring when switching tracks\n currentMapColors = null;\n MapView.clearMetricColor(id);\n if (hadSelected) {\n ChartView.toggleMapColor(null); // Ensure ChartView state also resets\n }\n\n // Clear selection on new track\n UrlState.patch({ track: id, sel: null }, true);\n if (hadSelected) {\n ChartView.cancelSelection();\n }\n\n // Update UI immediately\n renderTrackList();\n\n // Render details\n const activeTab = UrlState.get().tab || 'graphs';\n if (activeTab === 'details') renderDetails(tracks[id], getGlobalTags());\n if (activeTab === 'insights') renderInsights(tracks[id]);\n if (activeTab === 'combined') renderCombined(tracks[id]);\n if (activeTab === 'courses') renderCourses();\n if (activeTab === 'evolution') {\n renderEvolution(tracks[id], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n\n // Tell sub-views\n MapView.setSelectedTrack(id, fit);\n if (fit) MapView.fitTrack(id);\n ChartView.loadTrack(tracks[id], Object.values(tracks), deferChartRender);\n}\n\nasync function deleteTrack(id: string) {\n await Storage.remove(id);\n MapView.removeTrack(id);\n delete tracks[id];\n if (selectedId === id) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n UrlState.patch({ track: null, sel: null, sel_point: null });\n }\n applyFilters();\n}\n\nasync function clearAll() {\n const code = Math.floor(10 + Math.random() * 90).toString();\n\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n backdrop.innerHTML = `\n
\n
Delete all tracks?
\n
\n This will permanently remove all tracks from your browser storage. This action cannot be undone.\n
\n
\n
Enter \"${code}\" to confirm:
\n \n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const input = backdrop.querySelector('.modal-input') as HTMLInputElement;\n const btnConfirm = backdrop.querySelector('.modal-btn.confirm') as HTMLButtonElement;\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n\n input.focus();\n\n input.addEventListener('input', () => {\n btnConfirm.disabled = input.value !== code;\n });\n\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n\n btnConfirm.addEventListener('click', async () => {\n if (input.value !== code) return;\n close();\n\n cancelProcessing = true;\n await Storage.clear();\n\n tracks = {};\n selectedId = null;\n MapView.clearHighlight();\n window.location.reload();\n });\n}\n\nfunction applyFilters(skipRender = false) {\n const ids = Object.keys(tracks);\n ids.forEach((id) => {\n const t = tracks[id];\n const s = t.stats;\n let visible = true;\n\n // Search query\n if (searchQuery) {\n if (searchRegex) {\n try {\n const re = new RegExp(searchQuery, 'i');\n if (!re.test(t.name)) visible = false;\n } catch (e) {\n visible = false;\n }\n } else {\n if (!t.name.toLowerCase().includes(searchQuery.toLowerCase())) visible = false;\n }\n }\n\n // Date filter\n if (visible && (filters.date[0] || filters.date[1])) {\n const start = filters.date[0] ? new Date(filters.date[0]).getTime() : 0;\n const end = filters.date[1] ? new Date(filters.date[1]).getTime() : Infinity;\n const t0 = s.startTime || 0;\n if (t0 < start || t0 > end) visible = false;\n }\n\n // Distance filter\n if (visible && (filters.dist[0] !== null || filters.dist[1] !== null)) {\n const min = (filters.dist[0] || 0) * 1000;\n const max = (filters.dist[1] || Infinity) * 1000;\n if (s.totalDist < min || s.totalDist > max) visible = false;\n }\n\n // Duration filter\n if (visible && (filters.dur[0] !== null || filters.dur[1] !== null)) {\n const min = (filters.dur[0] || 0) * 60000;\n const max = (filters.dur[1] || Infinity) * 60000;\n const d = s.duration || 0;\n if (d < min || d > max) visible = false;\n }\n\n // Metrics filter\n if (visible && filters.metrics.size > 0) {\n for (const m of filters.metrics) {\n const field = ChartView.METRICS[m].field;\n if (!t.points.some((p: any) => p[field] != null)) {\n visible = false;\n break;\n }\n }\n }\n\n // Sport filter\n if (visible && filters.sport) {\n if (t.sport !== filters.sport) visible = false;\n }\n\n // Tags filter\n if (visible && filters.tags.length > 0) {\n const trackTags = t.tags || [];\n if (!filters.tags.every((ft) => trackTags.includes(ft))) visible = false;\n }\n\n t._filtered = !visible;\n MapView.setTrackVisible(t.id, t.visible && visible);\n });\n\n if (!skipRender) renderTrackList();\n}\n\nfunction updateFilterUI() {\n (document.getElementById('filter-date-start') as HTMLInputElement).value = filters.date[0] || '';\n (document.getElementById('filter-date-end') as HTMLInputElement).value = filters.date[1] || '';\n (document.getElementById('filter-dist-min') as HTMLInputElement).value =\n filters.dist[0] !== null ? String(filters.dist[0]) : '';\n (document.getElementById('filter-dist-max') as HTMLInputElement).value =\n filters.dist[1] !== null ? String(filters.dist[1]) : '';\n (document.getElementById('filter-dur-min') as HTMLInputElement).value =\n filters.dur[0] !== null ? String(filters.dur[0]) : '';\n (document.getElementById('filter-dur-max') as HTMLInputElement).value =\n filters.dur[1] !== null ? String(filters.dur[1]) : '';\n (document.getElementById('filter-tags') as HTMLInputElement).value = filters.tags.join(', ');\n\n document\n .querySelectorAll('#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item')\n .forEach((el) => {\n const item = el as HTMLElement;\n item.classList.toggle('active', (item.dataset.sport || '') === (filters.sport || ''));\n });\n\n document.querySelectorAll('#filter-metrics .mini-pill').forEach((el) => {\n const btn = el as HTMLElement;\n btn.classList.toggle('active', filters.metrics.has(btn.dataset.metric!));\n });\n\n const activeCount =\n (filters.date[0] ? 1 : 0) +\n (filters.date[1] ? 1 : 0) +\n (filters.dist[0] !== null ? 1 : 0) +\n (filters.dist[1] !== null ? 1 : 0) +\n (filters.dur[0] !== null ? 1 : 0) +\n (filters.dur[1] !== null ? 1 : 0) +\n filters.metrics.size +\n (filters.tags.length > 0 ? 1 : 0);\n\n const badge = document.querySelector('#btn-toggle-filters .btn-badge');\n if (badge) {\n badge.textContent = activeCount > 0 ? String(activeCount) : '';\n badge.classList.toggle('hidden', activeCount === 0);\n }\n}\n\nfunction updateSearchSortUI() {\n const searchInput = document.getElementById('track-search') as HTMLInputElement;\n if (searchInput) searchInput.value = searchQuery;\n document.getElementById('btn-regex-toggle')?.classList.toggle('active', searchRegex);\n\n const opt = SORT_OPTIONS.find((o) => o.val === currentSort);\n if (opt) {\n const labelEl = document.getElementById('sort-current-label');\n const iconEl = document.getElementById('sort-current-icon');\n if (labelEl)\n labelEl.textContent = opt.label\n .replace(' first', '')\n .replace(' distance', '')\n .replace(' duration', '');\n if (iconEl) iconEl.textContent = opt.icon;\n }\n}\n\nfunction applyState(urlState: AppState) {\n // Restore track\n const newTrackId = urlState.track;\n if (newTrackId !== selectedId) {\n if (newTrackId && tracks[newTrackId]) {\n selectTrack(newTrackId, true);\n } else if (!newTrackId && selectedId) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n renderTrackList();\n MapView.fitAll();\n }\n }\n\n // Restore basemap\n if (urlState.map && typeof urlState.map === 'string') {\n MapView.switchBasemap(urlState.map);\n document\n .querySelectorAll('.bm-btn')\n .forEach((b) =>\n b.classList.toggle('active', (b as HTMLElement).dataset.layer === urlState.map),\n );\n }\n\n // Restore map position\n if (urlState.map_pos) {\n const [lat, lng, zoom] = urlState.map_pos;\n MapView.setPosition(lat, lng, zoom);\n }\n\n // Restore tab\n if (urlState.tab) {\n document.querySelectorAll('.tab-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n if (b.dataset.tab === urlState.tab) {\n if (!b.classList.contains('active')) b.click();\n }\n });\n }\n\n // Restore x-axis mode\n if (urlState.xaxis) ChartView.setXAxis(urlState.xaxis);\n\n const currentXAxis = urlState.xaxis || 'time';\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', (b as HTMLElement).dataset.axis === currentXAxis));\n\n // Restore active metrics\n if (urlState.metrics) {\n const metrics = ChartView.METRICS;\n const keys = urlState.metrics\n .map((abbr) => Object.keys(metrics).find((k) => metrics[k].abbr === abbr))\n .filter((k): k is string => k !== undefined);\n if (keys.length) ChartView.setActiveMetrics(keys);\n }\n\n // Restore filters\n if (urlState.f_date)\n filters.date = urlState.f_date.map((v) => v || null) as [string | null, string | null];\n if (urlState.f_dist)\n filters.dist = urlState.f_dist.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_dur)\n filters.dur = urlState.f_dur.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_mets) filters.metrics = new Set(urlState.f_mets);\n if (urlState.f_tags) filters.tags = urlState.f_tags;\n\n updateFilterUI();\n\n if (urlState.q) searchQuery = urlState.q;\n if (urlState.re) searchRegex = urlState.re;\n if (urlState.sort) currentSort = urlState.sort;\n updateSearchSortUI();\n\n applyFilters();\n}\n\nfunction updateSportFilterOptions() {\n const container = document.getElementById('sport-filter-container');\n if (!container) return;\n\n const commonContainer = document.getElementById('common-sports');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n if (!commonContainer || !dropdownContent) return;\n\n const sports = new Set();\n Object.values(tracks).forEach((t) => {\n if (t.sport) sports.add(t.sport);\n });\n\n const sportsArray = Array.from(sports).sort();\n const burgerDropdown = document.getElementById('sport-burger-dropdown');\n\n commonContainer.innerHTML = '';\n dropdownContent.innerHTML = '';\n\n if (sportsArray.length <= 4) {\n if (burgerDropdown) burgerDropdown.style.display = 'none';\n\n sportsArray.forEach((sport) => {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n });\n } else {\n if (burgerDropdown) burgerDropdown.style.display = 'inline-block';\n\n const commonSports = ['running', 'cycling', 'walking'];\n\n commonSports.forEach((sport) => {\n if (sports.has(sport)) {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n }\n });\n\n sportsArray.forEach((sport) => {\n const item = document.createElement('div');\n item.className = `dropdown-item${filters.sport === sport ? ' active' : ''}`;\n item.dataset.sport = sport;\n item.style.padding = '8px';\n item.style.cursor = 'pointer';\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '8px';\n item.innerHTML = `\n ${getSportIcon(sport)}\n ${sport.charAt(0).toUpperCase() + sport.slice(1)}\n `;\n dropdownContent.appendChild(item);\n });\n }\n}\n\nfunction renderTrackList() {\n updateSportFilterOptions();\n const list = document.getElementById('track-list');\n const emptyEl = document.getElementById('track-list-empty') as HTMLElement;\n const headerLabel = document.querySelector('.section-label');\n if (!list) return;\n\n const ids = Object.keys(tracks).filter((id) => !tracks[id]._filtered);\n if (headerLabel) headerLabel.textContent = `Tracks (${ids.length})`;\n\n if (!ids.length) {\n list.innerHTML = '';\n if (emptyEl) {\n list.appendChild(emptyEl);\n emptyEl.style.display = 'block';\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n list.innerHTML = '';\n\n ids\n .sort((a, b) => {\n // Current selected always first\n if (a === selectedId) return -1;\n if (b === selectedId) return 1;\n\n const ta = tracks[a],\n tb = tracks[b];\n const sa = ta.stats,\n sb = tb.stats;\n\n let cmp = 0;\n switch (currentSort) {\n case 'date-asc':\n cmp = (sa.startTime || 0) - (sb.startTime || 0);\n break;\n case 'date-desc':\n cmp = (sb.startTime || 0) - (sa.startTime || 0);\n break;\n case 'dist-asc':\n cmp = (sa.totalDist || 0) - (sb.totalDist || 0);\n break;\n case 'dist-desc':\n cmp = (sb.totalDist || 0) - (sa.totalDist || 0);\n break;\n case 'dur-asc':\n cmp = (sa.duration || 0) - (sb.duration || 0);\n break;\n case 'dur-desc':\n cmp = (sb.duration || 0) - (sa.duration || 0);\n break;\n default:\n cmp = 0;\n }\n return cmp || a.localeCompare(b);\n })\n .forEach((id) => {\n list.appendChild(buildTrackItem(tracks[id]));\n });\n}\n\nfunction getGlobalTags(): string[] {\n const all = new Set();\n Object.values(tracks).forEach((t) => {\n (t.tags || []).forEach((tag) => all.add(tag));\n });\n return Array.from(all).sort();\n}\n\nfunction getSportIcon(sport: string | null): string {\n if (!sport) return 'category';\n const s = sport.toLowerCase();\n if (s.includes('run')) return 'directions_run';\n if (s.includes('cycl') || s.includes('bike')) return 'directions_bike';\n if (s.includes('walk')) return 'directions_walk';\n if (s.includes('swim')) return 'pool';\n if (s.includes('hik')) return 'hiking';\n return 'sports';\n}\n\nfunction buildTrackItem(track: TrackData) {\n const item = document.createElement('div');\n item.className = `track-item${track.id === selectedId ? ' selected' : ''}`;\n item.dataset.id = track.id;\n\n const date =\n track.points.length && track.points[0].time ? fmtDate(track.points[0].time) : 'Unknown date';\n\n const tagsHtml =\n (track.tags || []).length > 0\n ? `
${(track.tags || [])\n .map((t) => {\n const c = getTagColor(t);\n return `${escHtml(t)}`;\n })\n .join('')}
`\n : '';\n\n item.innerHTML = `\n
\n
\n
${escHtml(track.displayName || track.name)}
\n
\n
\n ${date}\n ${Math.round(track.stats.totalDist / 1000)} km\n ${track.sport ? `${getSportIcon(track.sport)}` : ''}\n ${track.format.toUpperCase()}\n
\n \n
\n ${tagsHtml}\n
\n `;\n\n item.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.icon-btn')) return;\n selectTrack(track.id);\n });\n\n const btnVis = item.querySelector('.toggle-vis') as HTMLElement;\n btnVis.addEventListener('click', () => {\n track.visible = !track.visible;\n btnVis.querySelector('.material-symbols-rounded')!.textContent = track.visible\n ? 'visibility'\n : 'visibility_off';\n MapView.setTrackVisible(track.id, track.visible);\n Storage.save(track);\n });\n\n return item;\n}\n\nfunction showToast(msg: string, type: 'info' | 'error' = 'info') {\n const container = document.getElementById('toast-container');\n if (!container) return;\n container.innerHTML = '';\n const t = document.createElement('div');\n t.className = `toast ${type}`;\n t.textContent = msg;\n container.appendChild(t);\n}\n\nfunction showSkippedImportsModal() {\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n let listHtml = '';\n skippedImports.forEach((s) => {\n listHtml += `
${s.name}: ${s.reason}
`;\n });\n\n backdrop.innerHTML = `\n
\n
Skipped Imports
\n
\n ${listHtml || '
No skipped imports.
'}\n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n const btnClear = backdrop.querySelector('.modal-btn.clear') as HTMLButtonElement;\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n btnClear.addEventListener('click', () => {\n skippedImports = [];\n close();\n const importWarning = document.getElementById('import-warning');\n if (importWarning) importWarning.classList.add('hidden');\n });\n\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n}\n\nfunction initDropZone() {\n const zone = document.getElementById('drop-zone');\n if (!zone) return;\n\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n importWarning.addEventListener('click', (e) => {\n e.stopPropagation();\n showSkippedImportsModal();\n });\n }\n\n window.addEventListener('dragover', (e) => {\n e.preventDefault();\n zone.classList.add('drop-active');\n });\n\n window.addEventListener('dragleave', (e) => {\n if (e.relatedTarget === null) zone.classList.remove('drop-active');\n });\n\n window.addEventListener('drop', async (e) => {\n e.preventDefault();\n zone.classList.remove('drop-active');\n\n const items = e.dataTransfer?.items;\n if (!items) return;\n\n const files: File[] = [];\n const queue: FileSystemEntry[] = [];\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i].webkitGetAsEntry();\n if (entry) queue.push(entry);\n }\n\n async function readAllEntries(entry: FileSystemEntry) {\n if (entry.isFile) {\n const file = await new Promise((res) => (entry as FileSystemFileEntry).file(res));\n files.push(file);\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n let entries: FileSystemEntry[] = [];\n let chunk: FileSystemEntry[];\n do {\n chunk = await new Promise((res) => reader.readEntries(res));\n entries.push(...chunk);\n } while (chunk.length > 0);\n\n for (const child of entries) await readAllEntries(child);\n }\n }\n\n for (const entry of queue) await readAllEntries(entry);\n\n if (files.length) handleFiles(files);\n });\n}\n\nasync function handleFiles(files: File[]) {\n if (!files.length) return;\n cancelProcessing = false;\n const initialSkipCount = skippedImports.length;\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const loaderClose = document.getElementById('loader-close');\n\n if (loaderClose) {\n loaderClose.addEventListener('click', () => {\n cancelProcessing = true;\n if (loader) loader.classList.add('hidden');\n });\n }\n\n function updateLoaderIconToWarning() {\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'warning';\n loaderIcon.style.color = '#f59e0b';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n const count = skippedImports.length - initialSkipCount;\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = `${count}`;\n warningCount.style.display = 'flex';\n }\n }\n\n if (loader) {\n if (loaderText)\n loaderText.textContent = `Importing ${files.length} file${files.length > 1 ? 's' : ''}`;\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'download';\n loaderIcon.style.color = 'var(--accent)';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n warningCount.style.display = 'none';\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = '0';\n }\n if (loaderSubtext) loaderSubtext.textContent = '';\n if (progressBar) progressBar.style.width = '0%';\n loader.classList.remove('hidden');\n\n if (skippedImports.length > initialSkipCount) updateLoaderIconToWarning();\n }\n\n try {\n let count = 0;\n let firstId: string | null = null;\n let processedSinceLastUpdate = 0;\n\n // Filter out obviously invalid files early\n const validFiles = files.filter((f) => {\n const name = f.name.toLowerCase();\n return (\n name.endsWith('.gpx') ||\n name.endsWith('.fit') ||\n name.endsWith('.tcx') ||\n name.endsWith('.kml')\n );\n });\n\n const invalidFiles = files.filter((f) => !validFiles.includes(f));\n invalidFiles.forEach((f) => {\n skippedImports.push({ name: f.name, reason: 'Unsupported file format' });\n });\n\n if (validFiles.length === 0) {\n if (files.length > 0) {\n showToast('No valid GPS files found', 'error');\n // Still update warning icon if there were invalid files!\n const importWarning = document.getElementById('import-warning');\n if (importWarning && skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n }\n }\n return;\n }\n\n const loaderFilename = document.getElementById('loader-filename');\n let progressIdxEl: HTMLElement | null = null;\n if (loaderSubtext) {\n loaderSubtext.innerHTML =\n '';\n progressIdxEl = loaderSubtext.querySelector('.progress-index') as HTMLElement | null;\n const totalEl = loaderSubtext.querySelector('.progress-total');\n if (totalEl) totalEl.textContent = validFiles.length.toString();\n }\n\n for (let i = 0; i < validFiles.length; i++) {\n if (cancelProcessing) break;\n const f = validFiles[i];\n if (loaderFilename) loaderFilename.textContent = f.name;\n if (progressIdxEl) progressIdxEl.textContent = (i + 1).toString();\n if (progressBar) progressBar.style.width = `${(i / validFiles.length) * 100}%`;\n\n try {\n const data = await Parsers.parseFile(f);\n\n // Duplicate checks\n const existingTracks = Object.values(tracks);\n\n // Rule 1: Same file and same size\n const sameFile = existingTracks.find((t) => t.fileName === f.name && t.fileSize === f.size);\n if (sameFile) {\n skippedImports.push({ name: f.name, reason: 'Same File' });\n updateLoaderIconToWarning();\n continue;\n }\n\n // Rule 2 & 3: Same start day checks\n const newStart = data.stats.startTime;\n const newDuration = data.stats.duration;\n\n if (newStart != null && newDuration != null) {\n const newEnd = newStart + newDuration;\n const sameDayTracks = existingTracks.filter(\n (t) => t.stats.startTime != null && isSameDay(newStart, t.stats.startTime!),\n );\n\n let discarded = false;\n for (const ext of sameDayTracks) {\n const extStart = ext.stats.startTime!;\n const extDuration = ext.stats.duration!;\n const extEnd = extStart + extDuration;\n\n // Rule 2: Fully contained\n if (newStart >= extStart && newEnd <= extEnd) {\n skippedImports.push({ name: f.name, reason: 'Fully contained in another track' });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n\n // Rule 3: Overlaps for > 10 mins\n const overlap = Math.min(newEnd, extEnd) - Math.max(newStart, extStart);\n if (overlap > 600000) {\n // 10 mins in ms\n skippedImports.push({\n name: f.name,\n reason: 'Overlaps with an existing track for more than 10 mins',\n });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n }\n if (discarded) continue;\n }\n\n const fallbackTime = 1785542400000;\n let id = compactId(data.stats.startTime || fallbackTime);\n if (tracks[id]) id += `-${shortRandom()}`;\n\n // Use filename as activity name if internal name is generic\n let trackName = data.name;\n if (trackName.startsWith('Unnamed') || trackName.startsWith('Fit Activity'))\n trackName = f.name;\n\n // Generate a nice display name\n let displayName = trackName;\n const t0 = data.points[0]?.time;\n const sport = data.sport\n ? data.sport.charAt(0).toUpperCase() + data.sport.slice(1)\n : 'Activity';\n if (t0) {\n const d = new Date(t0);\n displayName = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')} ${sport}`;\n } else {\n displayName = trackName.replace(/\\.[^/.]+$/, '').replace(/_/g, ' '); // Remove extension and replace underscores\n }\n\n const track: TrackData = {\n ...data,\n id,\n name: trackName,\n displayName,\n fileName: f.name,\n fileSize: f.size,\n bounds: calculateBounds(data.points) || undefined,\n simplifiedPoints: simplifyTrack(data.points, 50), // 50m resolution\n addedAt: data.stats.startTime || fallbackTime,\n visible: true,\n color: TRACK_COLORS[colorIdx % TRACK_COLORS.length],\n };\n colorIdx++;\n if (cancelProcessing) break;\n\n await Storage.save(track);\n tracks[id] = track;\n MapView.addTrack(track);\n if (!firstId) firstId = id;\n count++;\n processedSinceLastUpdate++;\n\n if (processedSinceLastUpdate >= 5) {\n processedSinceLastUpdate = 0;\n }\n } catch (err) {\n skippedImports.push({\n name: f.name,\n reason: `Parse error: ${err instanceof Error ? err.message : String(err)}`,\n });\n updateLoaderIconToWarning();\n }\n }\n\n // Update warning icon\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n if (skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n } else {\n importWarning.classList.add('hidden');\n }\n }\n\n const newWarnings = skippedImports.length > initialSkipCount;\n if (!newWarnings && loader) {\n loader.classList.add('hidden');\n }\n\n if (count > 0) {\n showToast(`Imported ${count} track${count > 1 ? 's' : ''}`);\n applyFilters(!!firstId && firstId !== selectedId);\n if (firstId) selectTrack(firstId);\n }\n\n if (newWarnings) {\n const loaderIcon = document.querySelector('.loader-icon-wrap span');\n if (loaderIcon) loaderIcon.textContent = 'warning';\n // Delay hiding loader to let user see the alert icon\n await new Promise((r) => setTimeout(r, 1500));\n }\n } finally {\n if (loader) loader.classList.add('hidden');\n }\n}\n\nfunction initMetricPillDraggable() {\n const container = document.getElementById('metric-pills');\n if (!container) return;\n\n let draggedEl: HTMLElement | null = null;\n\n container.addEventListener('dragstart', (e) => {\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (!target) return;\n draggedEl = target;\n e.dataTransfer!.effectAllowed = 'move';\n target.classList.add('dragging-pill');\n // For transparent background in ghost image\n setTimeout(() => (target.style.opacity = '0.4'), 0);\n });\n\n container.addEventListener('dragover', (e) => {\n e.preventDefault();\n e.dataTransfer!.dropEffect = 'move';\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (target && target !== draggedEl) {\n const rect = target.getBoundingClientRect();\n const next = e.clientX - rect.left > rect.width / 2;\n container.insertBefore(draggedEl!, next ? target.nextSibling : target);\n }\n });\n\n container.addEventListener('dragend', () => {\n if (!draggedEl) return;\n draggedEl.classList.remove('dragging-pill');\n draggedEl.style.opacity = '';\n draggedEl = null;\n\n // Update Chart order\n const keys = Array.from(container.querySelectorAll('.metric-pill')).map(\n (el) => (el as HTMLElement).dataset.metric!,\n );\n ChartView.updateMetricOrder(keys);\n syncMetricsToUrl();\n });\n}\n\nfunction updateToolbarLayout() {\n const toolbar = document.getElementById('chart-toolbar');\n const pills = document.getElementById('metric-pills');\n if (!toolbar || !pills) return;\n\n toolbar.classList.remove('collapsed');\n const availableW = Math.max(0, toolbar.clientWidth - 280);\n let totalW = 0;\n let hidden = false;\n\n Array.from(pills.children).forEach((el) => {\n const htmlEl = el as HTMLElement;\n if (htmlEl.id === 'pill-overflow') return;\n\n htmlEl.classList.remove('overflow-hidden');\n if (!htmlEl.classList.contains('active')) return;\n const metricKey = htmlEl.dataset.metric || '';\n const deterministicPillWidth = 36 + metricKey.length * 6;\n totalW += deterministicPillWidth + 6;\n\n if (totalW > availableW) {\n hidden = true;\n htmlEl.classList.add('overflow-hidden');\n }\n });\n\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.toggle('hidden', !hidden);\n\n if (hidden) toolbar.classList.add('collapsed');\n}\n\ndocument.addEventListener('DOMContentLoaded', init);\n"], - "mappings": "AAgCO,IAAMA,IAAY,IAAM,CAE7B,IAAIC,EAAmB,CAAC,EACpBC,EAA6B,KAC7BC,EAAoB,KACpBC,EAAc,GAElB,SAASC,GAAiB,CACxB,IAAMC,EAAI,IAAI,gBAAgB,SAAS,MAAM,EACvCC,EAAc,CAAC,EAEjBD,EAAE,IAAI,OAAO,IAAGC,EAAE,MAAQD,EAAE,IAAI,OAAO,GACvCA,EAAE,IAAI,KAAK,IAAGC,EAAE,IAAMD,EAAE,IAAI,KAAK,GACjCA,EAAE,IAAI,OAAO,IAAGC,EAAE,MAAQD,EAAE,IAAI,OAAO,GACvCA,EAAE,IAAI,KAAK,IAAGC,EAAE,IAAMD,EAAE,IAAI,KAAK,GACjCA,EAAE,IAAI,WAAW,IAAGC,EAAE,UAAY,OAAOD,EAAE,IAAI,WAAW,CAAC,GAC3DA,EAAE,IAAI,YAAY,IAAGC,EAAE,WAAaD,EAAE,IAAI,YAAY,GACtDA,EAAE,IAAI,UAAU,IAAGC,EAAE,SAAWD,EAAE,IAAI,UAAU,GACpD,IAAME,EAAaF,EAAE,IAAI,SAAS,EA0BlC,GAzBIE,IAAYD,EAAE,QAAUC,EAAW,MAAM,GAAG,EAAE,OAAO,OAAO,GAE5DF,EAAE,IAAI,QAAQ,IAChBC,EAAE,OAASD,EACR,IAAI,QAAQ,EACZ,MAAM,GAAG,EACT,IAAKG,GAAMA,GAAK,IAAI,GAErBH,EAAE,IAAI,QAAQ,IAChBC,EAAE,OAASD,EACR,IAAI,QAAQ,EACZ,MAAM,GAAG,EACT,IAAKG,GAAOA,EAAI,OAAOA,CAAC,EAAI,IAAK,GAElCH,EAAE,IAAI,OAAO,IACfC,EAAE,MAAQD,EACP,IAAI,OAAO,EACX,MAAM,GAAG,EACT,IAAKG,GAAOA,EAAI,OAAOA,CAAC,EAAI,IAAK,GAElCH,EAAE,IAAI,QAAQ,IAAGC,EAAE,OAASD,EAAE,IAAI,QAAQ,EAAG,MAAM,GAAG,GACtDA,EAAE,IAAI,QAAQ,IAAGC,EAAE,OAASD,EAAE,IAAI,QAAQ,EAAG,MAAM,GAAG,GAEtDA,EAAE,IAAI,GAAG,IAAGC,EAAE,EAAID,EAAE,IAAI,GAAG,GAC3BA,EAAE,IAAI,IAAI,IAAGC,EAAE,GAAKD,EAAE,IAAI,IAAI,IAAM,KACpCA,EAAE,IAAI,MAAM,EAAG,CACjB,IAAMG,EAAIH,EAAE,IAAI,MAAM,EAChBI,EAASD,EAAE,WAAW,GAAG,EACzBE,EAAQD,EAASD,EAAE,UAAU,CAAC,EAAIA,EACxCF,EAAE,KAAO,GAAGI,CAAK,IAAID,EAAS,OAAS,KAAK,EAC9C,CAEA,GAAIJ,EAAE,IAAI,SAAS,EAAG,CACpB,IAAMM,EAAQN,EAAE,IAAI,SAAS,EAAG,MAAM,GAAG,EAAE,IAAI,MAAM,EACjDM,EAAM,SAAW,GAAKA,EAAM,MAAM,QAAQ,IAC5CL,EAAE,QAAUK,EAChB,CAGA,GADIN,EAAE,IAAI,SAAS,IAAGC,EAAE,QAAUD,EAAE,IAAI,SAAS,GAC7CA,EAAE,IAAI,KAAK,EAAG,CAChB,IAAMM,EAAQN,EAAE,IAAI,KAAK,EAAG,MAAM,GAAG,EAAE,IAAI,MAAM,EAC7CM,EAAM,SAAW,GAAKA,EAAM,MAAOH,GAAM,CAAC,MAAMA,CAAC,GAAK,SAASA,CAAC,CAAC,IACnEF,EAAE,IAAMK,EACZ,CAEA,OAAOL,CACT,CAGA,SAASM,GAAQ,CACXV,IACF,aAAaA,CAAY,EACzBA,EAAe,MAGjB,IAAMG,EAAI,IAAI,gBAcd,GAXIL,EAAO,OAAOK,EAAE,IAAI,QAASL,EAAO,KAAK,EACzCA,EAAO,KAAKK,EAAE,IAAI,MAAOL,EAAO,GAAG,EACnCA,EAAO,OAASA,EAAO,QAAU,QAAQK,EAAE,IAAI,QAASL,EAAO,KAAK,EACpEA,EAAO,KAAOA,EAAO,MAAQ,UAAUK,EAAE,IAAI,MAAOL,EAAO,GAAG,EAC9DA,EAAO,SAAWA,EAAO,UAAY,UAAUK,EAAE,IAAI,UAAWL,EAAO,OAAO,EAC9EA,EAAO,YAAc,QAAWK,EAAE,IAAI,YAAa,OAAOL,EAAO,SAAS,CAAC,EAC3EA,EAAO,YAAYK,EAAE,IAAI,aAAcL,EAAO,UAAU,EACxDA,EAAO,GAAGK,EAAE,IAAI,IAAKL,EAAO,CAAC,EAC7BA,EAAO,UAAUK,EAAE,IAAI,WAAYL,EAAO,QAAQ,EAClDA,EAAO,IAAIK,EAAE,IAAI,KAAM,GAAG,EAE1BL,EAAO,KAAM,CACf,IAAMW,EAAQX,EAAO,KAAK,MAAM,GAAG,EAC7BU,EAAQC,EAAM,CAAC,EACfE,EAAMF,EAAM,CAAC,EACnBN,EAAE,IAAI,QAASQ,IAAQ,OAAS,IAAM,IAAMH,CAAK,CACnD,CAEA,IAAII,EAAST,EAAE,SAAS,EAkBxB,GAfIL,EAAO,UAASc,GAAU,GAAGA,EAAS,IAAM,EAAE,WAAWd,EAAO,QAAQ,KAAK,GAAG,CAAC,IAEjFA,EAAO,SACTc,GAAU,GAAGA,EAAS,IAAM,EAAE,UAAUd,EAAO,OAAO,IAAKQ,GAAMA,GAAK,EAAE,EAAE,KAAK,GAAG,CAAC,IAEjFR,EAAO,SACTc,GAAU,GAAGA,EAAS,IAAM,EAAE,UAAUd,EAAO,OAAO,IAAKQ,GAAMA,GAAK,EAAE,EAAE,KAAK,GAAG,CAAC,IAEjFR,EAAO,QACTc,GAAU,GAAGA,EAAS,IAAM,EAAE,SAASd,EAAO,MAAM,IAAKQ,GAAMA,GAAK,EAAE,EAAE,KAAK,GAAG,CAAC,IAE/ER,EAAO,SAAQc,GAAU,GAAGA,EAAS,IAAM,EAAE,UAAUd,EAAO,OAAO,KAAK,GAAG,CAAC,IAE9EA,EAAO,SAAQc,GAAU,GAAGA,EAAS,IAAM,EAAE,UAAUd,EAAO,OAAO,KAAK,GAAG,CAAC,IAE9EA,EAAO,QAAS,CAClB,IAAMe,EAAM,IAAI,CAACf,EAAO,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,KAAK,CAACA,EAAO,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,IAC/EA,EAAO,QAAQ,CAAC,CAClB,GACAc,GAAU,GAAGA,EAAS,IAAM,EAAE,WAAWC,CAAG,EAC9C,CACA,GAAIf,EAAO,IAAK,CACd,IAAMe,EAAM,GAAG,CAACf,EAAO,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAACA,EAAO,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,GACrEc,GAAU,GAAGA,EAAS,IAAM,EAAE,OAAOC,CAAG,EAC1C,CAEA,GAAID,IAAWb,EAAa,CAC1B,IAAMe,EAAM,SAAS,UAAYF,EAAS,IAAIA,CAAM,GAAK,IACzD,GAAI,CACEX,GACF,QAAQ,UAAU,KAAM,GAAIa,CAAG,EAC/Bb,EAAc,IAEd,QAAQ,aAAa,KAAM,GAAIa,CAAG,CAEtC,MAAY,CACVb,EAAc,EAChB,CACAF,EAAca,CAChB,CACF,CAGAd,EAASI,EAAK,EAEd,SAASa,GAAgB,CACvB,MAAO,CAAE,GAAGjB,CAAO,CACrB,CAEA,SAASkB,EAAMC,EAA+CC,EAAgB,GAAO,CAC/EA,IAAMjB,EAAc,IACxB,OAAW,CAACkB,EAAGb,CAAC,IAAK,OAAO,QAAQW,CAAO,EAAG,CAC5C,IAAMG,EAAMD,EACRb,GAAM,KAAyB,OAAOR,EAAOsB,CAAG,EAC9CtB,EAAesB,CAAG,EAAId,CAC9B,CACAI,EAAM,CACR,CAEA,SAASW,GAAU,CACjBvB,EAASI,EAAK,CAChB,CAEA,SAASoB,GAAQ,CACXtB,IACF,aAAaA,CAAY,EACzBA,EAAe,MAEjBF,EAAS,CAAC,EACVG,EAAc,GACdF,EAAc,GACd,GAAI,CACF,QAAQ,aAAa,KAAM,GAAI,SAAS,QAAQ,CAClD,MAAY,CAAC,CACf,CAEA,MAAO,CAAE,IAAAgB,EAAK,MAAAC,EAAO,QAAAK,EAAS,MAAAC,CAAM,CACtC,GAAG,EC9LH,IAAMC,GAAN,KAA+C,CAA/C,cACE,KAAQ,WAAa,IAAI,IACzB,KAAQ,aAAe,IAAI,IAE3B,MAAM,QAAwB,CAC5B,OAAO,QAAQ,QAAQ,CACzB,CAEA,MAAM,KAAKC,EAAiC,CAC1C,YAAK,WAAW,IAAIA,EAAM,GAAIA,CAAK,EAC5B,QAAQ,QAAQ,CACzB,CAEA,MAAM,QAA+B,CACnC,OAAO,QAAQ,QAAQ,MAAM,KAAK,KAAK,WAAW,OAAO,CAAC,CAAC,CAC7D,CAEA,MAAM,OAAOC,EAA2B,CACtC,YAAK,WAAW,OAAOA,CAAE,EAClB,QAAQ,QAAQ,CACzB,CAEA,MAAM,OAAuB,CAC3B,YAAK,WAAW,MAAM,EACtB,KAAK,aAAa,MAAM,EACjB,QAAQ,QAAQ,CACzB,CAEA,MAAM,IAAIC,EAAaC,EAA2B,CAChD,YAAK,aAAa,IAAID,EAAKC,CAAK,EACzB,QAAQ,QAAQ,CACzB,CAEA,MAAM,IAAaD,EAAgC,CACjD,OAAO,QAAQ,QAAS,KAAK,aAAa,IAAIA,CAAG,GAAW,IAAI,CAClE,CACF,EAEME,GAAN,KAAgD,CAAhD,cACE,KAAQ,GAAyB,KACjC,KAAiB,QAAU,aAC3B,KAAiB,WAAa,EAE9B,MAAM,QAAwB,CAC5B,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CACtC,IAAMC,EAAM,UAAU,KAAK,KAAK,QAAS,KAAK,UAAU,EACxDA,EAAI,gBAAkB,IAAM,CAC1B,IAAMC,EAAKD,EAAI,OACVC,EAAG,iBAAiB,SAAS,QAAQ,GACxCA,EAAG,kBAAkB,SAAU,CAAE,QAAS,IAAK,CAAC,EAC7CA,EAAG,iBAAiB,SAAS,UAAU,GAAGA,EAAG,kBAAkB,UAAU,CAChF,EACAD,EAAI,UAAY,IAAM,CACpB,KAAK,GAAKA,EAAI,OACdF,EAAQ,CACV,EACAE,EAAI,QAAU,IAAMD,EAAOC,EAAI,KAAK,CACtC,CAAC,CACH,CAEQ,SAASE,EAA6BC,EAA0C,CACtF,GAAI,CAAC,KAAK,GAAI,MAAM,IAAI,MAAM,sBAAsB,EACpD,OAAO,KAAK,GAAG,YAAYD,EAAMC,CAAI,EAAE,YAAYD,CAAI,CACzD,CAEA,MAAM,KAAKT,EAAiC,CAC1C,OAAO,IAAI,QAAQ,CAACW,EAAKC,IAAQ,CAC/B,IAAML,EAAM,KAAK,SAAS,SAAU,WAAW,EAAE,IAAIP,CAAK,EAC1DO,EAAI,UAAY,IAAMI,EAAI,EAC1BJ,EAAI,QAAU,IAAMK,EAAIL,EAAI,KAAK,CACnC,CAAC,CACH,CAEA,MAAM,QAA+B,CACnC,OAAO,IAAI,QAAQ,CAACI,EAAKC,IAAQ,CAC/B,IAAML,EAAM,KAAK,SAAS,SAAU,UAAU,EAAE,OAAO,EACvDA,EAAI,UAAY,IAAMI,EAAIJ,EAAI,QAAU,CAAC,CAAC,EAC1CA,EAAI,QAAU,IAAMK,EAAIL,EAAI,KAAK,CACnC,CAAC,CACH,CAEA,MAAM,OAAON,EAA2B,CACtC,OAAO,IAAI,QAAQ,CAACU,EAAKC,IAAQ,CAC/B,IAAML,EAAM,KAAK,SAAS,SAAU,WAAW,EAAE,OAAON,CAAE,EAC1DM,EAAI,UAAY,IAAMI,EAAI,EAC1BJ,EAAI,QAAU,IAAMK,EAAIL,EAAI,KAAK,CACnC,CAAC,CACH,CAEA,MAAM,OAAuB,CAC3B,OAAK,KAAK,GACH,IAAI,QAAQ,CAACI,EAAKC,IAAQ,CAC/B,IAAMC,EAAK,KAAK,GAAI,YAAY,CAAC,SAAU,UAAU,EAAG,WAAW,EACnEA,EAAG,YAAY,QAAQ,EAAE,MAAM,EAC/BA,EAAG,YAAY,UAAU,EAAE,MAAM,EACjCA,EAAG,WAAa,IAAMF,EAAI,EAC1BE,EAAG,QAAU,IAAMD,EAAIC,EAAG,KAAK,CACjC,CAAC,EAPoB,QAAQ,QAAQ,CAQvC,CAEA,MAAM,IAAIX,EAAaC,EAA2B,CAChD,OAAO,IAAI,QAAQ,CAACQ,EAAKC,IAAQ,CAC/B,IAAML,EAAM,KAAK,SAAS,WAAY,WAAW,EAAE,IAAIJ,EAAOD,CAAG,EACjEK,EAAI,UAAY,IAAMI,EAAI,EAC1BJ,EAAI,QAAU,IAAMK,EAAIL,EAAI,KAAK,CACnC,CAAC,CACH,CAEA,MAAM,IAAaL,EAAgC,CACjD,OAAO,IAAI,QAAQ,CAACS,EAAKC,IAAQ,CAC/B,IAAML,EAAM,KAAK,SAAS,WAAY,UAAU,EAAE,IAAIL,CAAG,EACzDK,EAAI,UAAY,IAAMI,EAAKJ,EAAI,QAAgB,IAAI,EACnDA,EAAI,QAAU,IAAMK,EAAIL,EAAI,KAAK,CACnC,CAAC,CACH,CACF,EAEIO,GAA8B,IAAIf,GAEzBgB,GAAyB,CACpC,OAAQ,SAA2B,CAEjCD,GADgBE,GAAS,IAAI,EAAE,UACJ,YAAc,IAAIZ,GAAqB,IAAIL,GACtE,MAAMe,GAAa,OAAO,CAC5B,EACA,KAAOG,GAAMH,GAAa,KAAKG,CAAC,EAChC,OAAQ,IAAMH,GAAa,OAAO,EAClC,OAASb,GAAOa,GAAa,OAAOb,CAAE,EACtC,MAAO,IAAMa,GAAa,MAAM,EAChC,IAAK,CAACI,EAAGC,IAAML,GAAa,IAAII,EAAGC,CAAC,EACpC,IAASD,GAAcJ,GAAa,IAAOI,CAAC,CAC9C,EC9IA,OAAOE,OAAe,kBCAf,SAASC,GAAUC,EAAcC,EAAcC,EAAcC,EAAsB,CAExF,IAAMC,EAAQJ,EAAO,KAAK,GAAM,IAC1BK,EAAQH,EAAO,KAAK,GAAM,IAC1BI,GAAaJ,EAAOF,GAAQ,KAAK,GAAM,IACvCO,GAAgBJ,EAAOF,GAAQ,KAAK,GAAM,IAE1CO,EACJ,KAAK,IAAIF,EAAW,CAAC,EAAI,KAAK,IAAIA,EAAW,CAAC,EAC9C,KAAK,IAAIF,CAAI,EAAI,KAAK,IAAIC,CAAI,EAAI,KAAK,IAAIE,EAAc,CAAC,EAAI,KAAK,IAAIA,EAAc,CAAC,EAGxF,MAAO,SAFG,EAAI,KAAK,MAAM,KAAK,KAAKC,CAAC,EAAG,KAAK,KAAK,EAAIA,CAAC,CAAC,EAGzD,CAEO,SAASC,GAAUC,EAA2B,CAGnD,IAAMC,EAAM,IAAI,YAAY,CAAC,KAAK,MAAMD,EAAY,GAAI,CAAC,CAAC,EAE1D,OADY,KAAK,OAAO,aAAa,GAAG,IAAI,WAAWC,EAAI,MAAM,CAAC,CAAC,EACxD,QAAQ,MAAO,GAAG,EAAE,QAAQ,MAAO,GAAG,EAAE,QAAQ,KAAM,EAAE,CACrE,CAMO,SAASC,IAAsB,CACpC,OAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,CAC9C,CAEO,SAASC,GAAYC,EAAmB,CAC7C,OAAIA,EAAI,GAAW,GAAG,KAAK,MAAMA,CAAC,CAAC,IAC/BA,EAAI,KAAa,GAAG,KAAK,MAAMA,EAAI,EAAE,CAAC,IACnC,GAAG,KAAK,MAAMA,EAAI,IAAI,CAAC,GAChC,CAEO,SAASC,GAAQD,EAAmB,CACzC,IAAME,EAAI,KAAK,MAAMF,EAAI,IAAI,EAC3BG,EAAI,KAAK,MAAOH,EAAI,KAAQ,EAAE,EAChC,OAAOE,EAAI,EAAI,GAAGA,CAAC,KAAKC,CAAC,IAAM,GAAGA,CAAC,KAAK,KAAK,MAAMH,EAAI,EAAE,CAAC,GAC5D,CAEO,SAASI,GAAQC,EAAgC,CACtD,GAAIA,GAAW,MAAQ,CAAC,SAASA,CAAO,EAAG,MAAO,KAClD,IAAMC,EAAO,KAAK,MAAMD,EAAU,EAAE,EAC9BE,EAAO,KAAK,MAAMF,EAAU,EAAE,EACpC,MAAO,GAAGC,CAAI,IAAIC,EAAK,SAAS,EAAE,SAAS,EAAG,GAAG,CAAC,EACpD,CAEO,SAASC,GAAQC,EAAoC,CAC1D,IAAMC,EAAI,IAAI,KAAKD,CAAE,EACrB,OAAI,MAAMC,EAAE,QAAQ,CAAC,EAAU,eACxBA,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,CACrC,CAEO,SAASC,GAAYF,EAAoC,CAC9D,IAAMC,EAAI,IAAI,KAAKD,CAAE,EACrB,GAAI,MAAMC,EAAE,QAAQ,CAAC,EAAG,MAAO,UAC/B,IAAME,EAAMF,EAAE,YAAY,EAC1B,MAAO,GAAGE,EAAI,MAAM,GAAG,EAAE,CAAC,CAAC,IAAIA,EAAI,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,EAAG,CAAC,CAAC,EAC9D,CAEO,SAASC,GAAYC,EAAuB,CACjD,GAAIA,IAAU,EAAG,MAAO,MACxB,IAAMC,EAAI,KACJC,EAAQ,CAAC,IAAK,KAAM,KAAM,IAAI,EAC9BC,EAAI,KAAK,MAAM,KAAK,IAAIH,CAAK,EAAI,KAAK,IAAIC,CAAC,CAAC,EAClD,MAAO,GAAG,YAAYD,EAAQ,KAAK,IAAIC,EAAGE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAID,EAAMC,CAAC,CAAC,EACvE,CAEO,SAASC,GAAQC,EAAqB,CAC3C,OAAO,OAAOA,CAAG,EACd,QAAQ,KAAM,OAAO,EACrB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,QAAQ,CAC3B,CAEO,SAASC,GAAYC,EAAsB,CAChD,IAAIC,EAAO,EACX,QAASL,EAAI,EAAGA,EAAII,EAAK,OAAQJ,IAAKK,EAAOD,EAAK,WAAWJ,CAAC,IAAMK,GAAQ,GAAKA,GAGjF,MAAO,OADG,KAAK,IAAIA,EAAO,GAAG,CACd,aACjB,CAMO,SAASC,GAAeC,EAAyBC,EAAgB,EAAsB,CAC5F,GAAIA,GAAS,EAAG,OAAOD,EAEvB,IAAME,EAAO,KAAK,KAAKD,EAAQ,CAAC,EAAI,EAAI,EAClCE,EAAS,IAAI,aAAaD,CAAI,EAC9BE,EAAO,KAAK,MAAMF,EAAO,CAAC,EAC5BG,EAAM,EAEV,QAASZ,EAAI,EAAGA,EAAIS,EAAMT,IAAK,CAC7B,IAAMa,EAAIb,EAAIW,EACdD,EAAOV,CAAC,EAAI,KAAK,IAAI,EAAEa,EAAIA,IAAM,EAAIL,EAAQA,EAAM,EACnDI,GAAOF,EAAOV,CAAC,CACjB,CACA,QAASA,EAAI,EAAGA,EAAIS,EAAMT,IAAKU,EAAOV,CAAC,GAAKY,EAE5C,IAAME,EAA4B,IAAI,MAAMP,EAAK,MAAM,EACvD,QAASP,EAAI,EAAGA,EAAIO,EAAK,OAAQP,IAAK,CACpC,GAAIO,EAAKP,CAAC,IAAM,KAAM,CACpBc,EAAOd,CAAC,EAAI,KACZ,QACF,CAEA,IAAIe,EAAM,EACNC,EAAY,EAChB,QAASlB,EAAI,EAAGA,EAAIW,EAAMX,IAAK,CAC7B,IAAMmB,EAAMjB,EAAIF,EAAIa,EAChBM,GAAO,GAAKA,EAAMV,EAAK,QAAUA,EAAKU,CAAG,IAAM,OACjDF,GAAOR,EAAKU,CAAG,EAAKP,EAAOZ,CAAC,EAC5BkB,GAAaN,EAAOZ,CAAC,EAEzB,CACAgB,EAAOd,CAAC,EAAIgB,EAAY,EAAID,EAAMC,EAAYT,EAAKP,CAAC,CACtD,CACA,OAAOc,CACT,CAEO,SAASI,GAAUC,EAAaC,EAAgB,EAAW,CAChE,IAAMC,EAAI,SAASF,EAAI,MAAM,EAAG,CAAC,EAAG,EAAE,EAChCG,EAAI,SAASH,EAAI,MAAM,EAAG,CAAC,EAAG,EAAE,EAChCI,EAAI,SAASJ,EAAI,MAAM,EAAG,CAAC,EAAG,EAAE,EACtC,MAAO,QAAQE,CAAC,KAAKC,CAAC,KAAKC,CAAC,KAAKH,CAAK,GACxC,CDhDO,SAASI,GAAgBC,EAAmB,CACjD,GAAI,CAACA,EAAI,OAAQ,OAAO,KACxB,IAAIC,EAASD,EAAI,CAAC,EAAE,IAChBE,EAASF,EAAI,CAAC,EAAE,IAChBG,EAASH,EAAI,CAAC,EAAE,IAChBI,EAASJ,EAAI,CAAC,EAAE,IACpB,QAAWK,KAAKL,EACVK,EAAE,IAAMJ,IAAQA,EAASI,EAAE,KAC3BA,EAAE,IAAMH,IAAQA,EAASG,EAAE,KAC3BA,EAAE,IAAMF,IAAQA,EAASE,EAAE,KAC3BA,EAAE,IAAMD,IAAQA,EAASC,EAAE,KAEjC,MAAO,CAAE,OAAAJ,EAAQ,OAAAC,EAAQ,OAAAC,EAAQ,OAAAC,CAAO,CAC1C,CAEA,IAAME,GAAe,MACfC,GAAe,IAAI,aAAaD,EAAY,EAC5CE,GAAe,IAAI,aAAaF,EAAY,EAC5CG,GAAe,IAAI,aAAaH,EAAY,EAC5CI,GAAgB,IAAI,aAAaJ,EAAY,EAC7CK,GAAe,IAAI,aAAaL,EAAY,EAC5CM,GAAe,IAAI,aAAaN,EAAY,EAC5CO,GAAe,IAAI,aAAaP,EAAY,EAE3C,SAASQ,GAAcd,EAAmBe,EAAyC,CACxF,IAAMC,EAAIhB,EAAI,OACd,GAAIgB,GAAK,EAAG,OAAOhB,EAInB,IAAMiB,EAAOD,GAAKV,GAAeC,GAAe,IAAI,aAAaS,CAAC,EAC5DE,EAAOF,GAAKV,GAAeE,GAAe,IAAI,aAAaQ,CAAC,EAC5DG,EAAOH,GAAKV,GAAeG,GAAe,IAAI,aAAaO,CAAC,EAC5DI,EAAQJ,GAAKV,GAAeI,GAAgB,IAAI,aAAaM,CAAC,EACpE,QAASK,EAAI,EAAGA,EAAIL,EAAGK,IAAK,CAC1B,IAAMhB,EAAIL,EAAIqB,CAAC,EACfJ,EAAKI,CAAC,EAAIhB,EAAE,IACZa,EAAKG,CAAC,EAAIhB,EAAE,IACZc,EAAKE,CAAC,EAAIhB,EAAE,KAAO,EACnBe,EAAMC,CAAC,EAAIhB,EAAE,MAAQ,CACvB,CAEA,IAAMiB,EAAa,CAAC,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,GAAG,EACpEC,EAAc,EACZC,EAAW,oBACjB,QAASC,EAAO,EAAGA,EAAO,EAAGA,IAAQ,CACnC,IAAMC,EAAUD,EAAO,EAAIH,EAAW,OAAS,GAC/C,QAASK,EAAK,EAAGA,EAAKD,EAASC,IAAM,CACnC,IAAMC,GAAYN,EAAWK,CAAE,EAAI,MAAQ,EAAIF,EAAO,OAAU,EAC5DI,EAAS,EACb,QAASR,EAAI,EAAGA,EAAIL,EAAI,EAAGK,IAAK,CAC9B,IAAMS,EAAS,KAAK,IAAIb,EAAKI,CAAC,EAAIG,CAAQ,EACpCO,GAAMb,EAAKG,CAAC,EAAIH,EAAKW,CAAM,GAAKC,EAChCE,EAAKf,EAAKI,CAAC,EAAIJ,EAAKY,CAAM,EAC1BI,GAAMd,EAAKE,CAAC,EAAIF,EAAKU,CAAM,GAAK,KAEtC,GADYE,EAAKA,EAAKC,EAAKA,EAAKC,EAAKA,GAC1BL,EAAU,CACnB,IAAMM,EAAOL,EAASR,GAAM,EACtBc,GAAMjB,EAAKgB,CAAG,GAAKhB,EAAKW,CAAM,EAAIX,EAAKG,CAAC,GAAK,IAAOS,EACpDM,EAAKnB,EAAKiB,CAAG,GAAKjB,EAAKY,CAAM,EAAIZ,EAAKI,CAAC,GAAK,GAClDE,GAAe,KAAK,KAAKY,EAAKA,EAAKC,EAAKA,CAAE,GAAKhB,EAAMC,CAAC,EAAID,EAAMS,CAAM,GAAK,KAC3EA,EAASR,CACX,CACF,CACF,CACF,CAEA,IAAMgB,EAAuB,CAACrC,EAAI,CAAC,CAAC,EAChCsC,EAAYtC,EAAI,CAAC,EACfuC,EAAUhB,EAAc,KAAO,KAAO,EAC5C,QAASF,EAAI,EAAGA,EAAIL,EAAI,EAAGK,IAAK,CAC9B,IAAMhB,EAAIL,EAAIqB,CAAC,GAEbhB,EAAE,MAAQ,MAAQiC,EAAU,MAAQ,KAChCjC,EAAE,KAAOiC,EAAU,KACnBE,GAAUF,EAAU,IAAKA,EAAU,IAAKjC,EAAE,IAAKA,EAAE,GAAG,GAClDkC,GAAWxB,IACjBsB,EAAO,KAAKhC,CAAC,EACbiC,EAAYjC,EAEhB,CACA,OAAAgC,EAAO,KAAKrC,EAAIgB,EAAI,CAAC,CAAC,EACfqB,CACT,CAEO,IAAMI,IAAW,IAAM,CAE5B,SAASC,EAAa1C,EAAiC,CACrD,IAAMgB,EAAIhB,EAAI,OACV2C,EAAY,EAChB,QAAStB,EAAI,EAAGA,EAAIL,EAAGK,IAAK,CAC1B,IAAMhB,EAAIL,EAAIqB,CAAC,EACf,GAAIA,EAAI,EAAG,CACT,IAAMuB,GAAO5C,EAAIqB,EAAI,CAAC,EAChBwB,EAAIL,GAAUI,GAAK,IAAKA,GAAK,IAAKvC,EAAE,IAAKA,EAAE,GAAG,EAIpD,GAHAsC,GAAaE,EAGTxC,EAAE,OAAS,MAAQA,EAAE,MAAQ,MAAQuC,GAAK,MAAQ,KAAM,CAC1D,IAAME,GAAMzC,EAAE,KAAOuC,GAAK,MAAQ,IAC9BE,EAAK,GAAKA,EAAK,KAEjBzC,EAAE,MAAQwC,EAAIC,EAElB,CAGA,GAAIzC,EAAE,WAAa,QAAaA,EAAE,KAAO,MAAQuC,GAAK,KAAO,KAAM,CACjE,IAAMG,EAAK1C,EAAE,IAAMuC,GAAK,IACpBC,EAAI,GAENxC,EAAE,SAAY0C,EAAKF,EAAK,IAExBxC,EAAE,SAAWuC,GAAK,UAAY,CAElC,CACF,CACAvC,EAAE,KAAOsC,CACX,CAGA,GAAI3B,EAAI,EAAG,CACT,IAAMgC,EAAShC,GAAKV,GAAeK,GAAe,IAAI,aAAaK,CAAC,EAC9DiC,EAASjC,GAAKV,GAAeM,GAAe,IAAI,aAAaI,CAAC,EAC9DkC,GAASlC,GAAKV,GAAeO,GAAe,IAAI,aAAaG,CAAC,EACpE,QAASK,GAAI,EAAGA,GAAIL,EAAGK,KACrB2B,EAAO3B,EAAC,EAAIrB,EAAIqB,EAAC,EAAE,KAAO,EAC1B4B,EAAO5B,EAAC,EAAIrB,EAAIqB,EAAC,EAAE,OAAS,EAC5B6B,GAAO7B,EAAC,EAAIrB,EAAIqB,EAAC,EAAE,OAAS,EAE9B,IAAM8B,EAAe,CAAC,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAE,EACzDC,EAAU,EACd,QAAS3B,GAAO,EAAGA,GAAO,EAAGA,KAAQ,CACnC,IAAM4B,GAAS,GAAK,KAAO5B,GAAO,KAClC,QAAS6B,GAAK,EAAGA,GAAKH,EAAa,OAAQG,KAAM,CAC/C,IAAMC,GAAIJ,EAAaG,EAAE,EACnBE,GAAO,EAAID,GACbE,GAAO,EACPC,EAAO,EACX,QAASrC,EAAI,EAAGA,EAAIL,EAAGK,IAGrB,GAFAoC,IAAQR,EAAO5B,CAAC,EAChBqC,GAAQR,GAAO7B,CAAC,EACZA,GAAKkC,GAAG,CACVE,IAAQR,EAAO5B,EAAIkC,EAAC,EACpBG,GAAQR,GAAO7B,EAAIkC,EAAC,EACpB,IAAMI,GAAOF,GAAOD,GACdT,GAAKC,EAAO3B,CAAC,EAAI2B,EAAO3B,EAAIkC,EAAC,EAC7BK,EAAa,MAAQ,KAAK,IAAI,CAACZ,EAAO3B,CAAC,EAAIgC,EAAM,EACjDQ,GAAa,KAAK,MAAMd,IAAKW,EAAO,GAAK,EAAG,EAClDN,GAAWO,GAAOA,GAAOC,EAAa,KAAOC,IAAcH,EAAOF,IAAQ,GAC5E,CAEJ,CACF,CACA,IAAMM,GAAaV,EAAU,MAAQ,KAAO,EAC5C,QAAS/B,GAAI,EAAGA,GAAIL,EAAI,EAAGK,KACrBrB,EAAIqB,EAAC,EAAE,UAAY,MAAQrB,EAAIqB,GAAI,CAAC,EAAE,UAAY,MAAQrB,EAAIqB,GAAI,CAAC,EAAE,UAAY,OACnFrB,EAAIqB,EAAC,EAAE,UACJrB,EAAIqB,GAAI,CAAC,EAAE,SAAYrB,EAAIqB,EAAC,EAAE,SAAYrB,EAAIqB,GAAI,CAAC,EAAE,UAAa,EAAIyC,GAG/E,CAEA,OAAO9D,CACT,CAGA,IAAI+D,EAAmB,CAAC,IAAK,IAAK,IAAK,GAAG,EACtCC,EAAM,IAEV,SAASC,EAAajE,EAAmBkE,EAAgB,GAAmB,CAC1E,IAAMC,EAAoB,CACxB,UAAW,EACX,SAAU,EACV,SAAU,EACV,SAAU,KACV,SAAU,KACV,SAAU,EACV,SAAU,KACV,SAAU,EACV,MAAO,KACP,MAAO,EACP,WAAY,KACZ,QAAS,KACT,QAAS,KACT,QAAS,KACT,QAAS,CAAC,EACV,UAAWnE,EAAI,OAASA,EAAI,CAAC,EAAE,KAAO,IACxC,EAEA,GAAI,CAACA,EAAI,OAAQ,OAAOmE,EAExB,IAAIC,EAAW,EACbC,EAAS,EACPC,GAAQ,EACVC,EAAM,EACJC,EAAS,EACXC,GAAO,EACLC,GAAW,EACbC,GAAS,EACPC,GAAa,EACfC,GAAW,EACTC,GAAU,EACZC,GAAQ,EACNC,EAAU,GACVC,EAAS,EACTC,GAAW,GAEf,QAAS7D,GAAI,EAAGA,GAAIrB,EAAI,OAAQqB,KAAK,CACnC,IAAMhB,GAAIL,EAAIqB,EAAC,EACf,GAAIA,GAAI,EAAG,CACT,IAAMuB,GAAO5C,EAAIqB,GAAI,CAAC,EACtB,GAAIhB,GAAE,KAAO,MAAQuC,GAAK,KAAO,KAAM,CACrC,IAAMuC,GAAO9E,GAAE,IAAMuC,GAAK,IACtBuC,GAAO,EAAGhB,EAAM,UAAYgB,GAC3BhB,EAAM,UAAYgB,EACzB,EAEG9E,GAAE,WAAa,MAAQA,GAAE,YAAcuC,GAAK,WAC5CvC,GAAE,UAAY,MAAQA,GAAE,WAAauC,GAAK,WAE3CqC,GACJ,CACI5E,GAAE,OAAS,OACb+D,GAAY/D,GAAE,MACdgE,IACIhE,GAAE,MAAQ8D,EAAM,WAAUA,EAAM,SAAW9D,GAAE,QAE/CA,GAAE,IAAM,OACViE,IAASjE,GAAE,GACXkE,IACIlE,GAAE,GAAK8D,EAAM,QAAOA,EAAM,MAAQ9D,GAAE,KAEtCA,GAAE,KAAO,OACXmE,GAAUnE,GAAE,IACZoE,MAEEpE,GAAE,OAAS,OACbqE,IAAYrE,GAAE,MACdsE,KACItE,GAAE,MAAQ8D,EAAM,WAAUA,EAAM,SAAW9D,GAAE,QAE/CA,GAAE,SAAW,OACfuE,IAAcvE,GAAE,QAChBwE,MAEExE,GAAE,MAAQ,OACZ2E,EAAU,GACVF,IAAWzE,GAAE,KACb0E,MACIZ,EAAM,SAAW,MAAQ9D,GAAE,KAAO8D,EAAM,WAASA,EAAM,QAAU9D,GAAE,OACnE8D,EAAM,SAAW,MAAQ9D,GAAE,KAAO8D,EAAM,WAASA,EAAM,QAAU9D,GAAE,QAErEA,GAAE,WAAa,MAAQA,GAAE,UAAY,QAAM6E,GAAW,GAC5D,CAEAf,EAAM,UAAYnE,EAAIA,EAAI,OAAS,CAAC,EAAE,MAAQ,EAC9CmE,EAAM,SAAWE,EAAS,KAAK,MAAMD,EAAWC,CAAM,EAAI,KAC1DF,EAAM,MAAQI,EAAM,KAAK,MAAMD,GAAQC,CAAG,EAAI,KAC9CJ,EAAM,WAAaM,GAAO,KAAK,MAAMD,EAASC,EAAI,EAAI,KACtDN,EAAM,SAAWQ,GAASD,GAAWC,GAAS,KAC9CR,EAAM,WAAaU,GAAW,KAAK,MAAMD,GAAaC,EAAQ,EAAI,KAClEV,EAAM,QAAUY,GAAQ,QAAQD,GAAUC,IAAO,QAAQ,CAAC,CAAC,EAAI,KAC/DZ,EAAM,OAASe,GAAWD,EAAS,KAEnC,IAAMG,GAAKpF,EAAI,CAAC,EAAE,KACZqF,EAAKrF,EAAIA,EAAI,OAAS,CAAC,EAAE,KAC/B,OAAIoF,IAAM,MAAQC,GAAM,OAAMlB,EAAM,SAAWkB,EAAKD,IAEhDb,IACFJ,EAAM,QAAQ,KAAK,YAAY,EAC3BD,IACFC,EAAM,QAAUmB,EAAiBtF,CAAG,EACpCmE,EAAM,QAAUoB,EAAiBvF,CAAG,IAGpCyE,IAAMN,EAAM,QAAQ,KAAK,SAAS,EAClCE,IACFF,EAAM,QAAQ,KAAK,OAAO,EACtBD,IACFC,EAAM,WAAaqB,EAAoBxF,CAAG,EAC1CmE,EAAM,WAAasB,EAAoBzF,CAAG,IAG1CgF,GAASb,EAAM,QAAQ,KAAK,aAAa,EACzCe,IAAUf,EAAM,QAAQ,KAAK,UAAU,EACvCU,IAAUV,EAAM,QAAQ,KAAK,SAAS,EAEnCA,CACT,CAEA,SAASuB,EAAqBC,EAAyB,CACrD,GAAI,CAACA,GAAS,CAACA,EAAM,QAAU,CAACA,EAAM,MAAO,OAC7C,IAAM3F,EAAM2F,EAAM,OACZC,EAAID,EAAM,MACZC,EAAE,OAAS,MAAQ,CAACA,EAAE,UACxBA,EAAE,QAAUN,EAAiBtF,CAAG,EAChC4F,EAAE,QAAUL,EAAiBvF,CAAG,GAE9B4F,EAAE,UAAY,MAAQ,CAACA,EAAE,aAC3BA,EAAE,WAAaJ,EAAoBxF,CAAG,EACtC4F,EAAE,WAAaH,EAAoBzF,CAAG,EAE1C,CAEA,IAAM6F,EAA2B,CAC/B,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,KAAM,KAAM,KAAM,KAAM,MAAO,MAAO,KAAO,KACvF,EAEA,SAASC,EAAoBC,EAAgBC,EAAqB,CAChE,IAAMC,EAAMF,EAAK,OACjB,GAAIE,IAAQ,EAAG,OAAO,KACtB,IAAMC,EAAS,IAAI,aAAaD,EAAM,CAAC,EACvC,QAAS5E,EAAI,EAAGA,EAAI4E,EAAK5E,IACvB6E,EAAO7E,EAAI,CAAC,EAAI6E,EAAO7E,CAAC,EAAI0E,EAAK1E,CAAC,EAEpC,GAAI6E,EAAOD,CAAG,IAAM,EAAG,OAAO,KAE9B,IAAME,EAAsD,CAAC,EACzDC,GAAS,GAEb,QAASC,EAAK,EAAGA,EAAKL,EAAU,OAAQK,IAAM,CAC5C,IAAMxD,EAAImD,EAAUK,CAAE,EACtB,GAAIxD,EAAIoD,EAAK,SACb,IAAIK,GAAS,EACTC,GAAU,EACRC,GAAQP,EAAMpD,EAEpB,QAAS4D,GAAI,EAAGA,IAAKD,GAAOC,KAAK,CAC/B,IAAMC,GAAaR,EAAOO,GAAI5D,CAAC,EAAIqD,EAAOO,EAAC,EACvCC,GAAaJ,KACfA,GAASI,GACTH,GAAUE,GAEd,CACAN,EAAMtD,CAAC,EAAI,CAAE,IAAK,KAAK,MAAMyD,GAASzD,CAAC,EAAG,IAAK0D,EAAQ,EACvDH,GAAS,EACX,CAEA,OAAOA,GAASD,EAAQ,IAC1B,CAEA,SAASX,EAAoBxF,EAAmB,CAC9C,IAAMiG,EAAMjG,EAAI,OACV2G,EAAY,IAAI,MAAcV,CAAG,EACnCW,EAAU,GACd,QAASvF,EAAI,EAAGA,EAAI4E,EAAK5E,IAAK,CAC5B,IAAMwF,EAAI7G,EAAIqB,CAAC,EAAE,OAAS,EAC1BsF,EAAUtF,CAAC,EAAIwF,EACXA,IAAM,IAAGD,EAAU,GACzB,CACA,GAAI,CAACA,EAAS,OAAO,KACrB,IAAMT,EAAQL,EAAoBa,EAAWd,CAAwB,EACrE,GAAI,CAACM,EAAO,OAAO,KAEnB,IAAM9D,GAAyD,CAAC,EAChE,QAAWQ,KAAKsD,EAAO9D,GAAOQ,CAAC,EAAI,CAAE,MAAOsD,EAAMtD,CAAC,EAAE,IAAK,IAAKsD,EAAMtD,CAAC,EAAE,GAAI,EAE5E,OAAOR,EACT,CAEA,SAASkD,EAAiBvF,EAAmB,CAC3C,IAAMiG,EAAMjG,EAAI,OACV8G,EAAS,IAAI,MAAcb,CAAG,EAChCW,EAAU,GACd,QAASvF,EAAI,EAAGA,EAAI4E,EAAK5E,IAAK,CAC5B,IAAMwF,EAAI7G,EAAIqB,CAAC,EAAE,IAAM,EACvByF,EAAOzF,CAAC,EAAIwF,EACRA,IAAM,IAAGD,EAAU,GACzB,CACA,GAAI,CAACA,EAAS,OAAO,KACrB,IAAMT,EAAQL,EAAoBgB,EAAQjB,CAAwB,EAClE,GAAI,CAACM,EAAO,OAAO,KAEnB,IAAM9D,GAAsD,CAAC,EAC7D,QAAWQ,KAAKsD,EAAO9D,GAAOQ,CAAC,EAAI,CAAE,GAAIsD,EAAMtD,CAAC,EAAE,IAAK,IAAKsD,EAAMtD,CAAC,EAAE,GAAI,EAEzE,OAAOR,EACT,CAEA,SAASoD,EAAoBzF,EAAmB,CAC9C,IAAM+G,EAAQ,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,EAC5BC,EAAa,CAAC,IAAM,IAAM,GAAK,KAAM,IAAK,GAAG,EAAE,IAAKC,GAAMA,EAAIjD,CAAG,EAEvE,QAAS3C,EAAI,EAAGA,EAAIrB,EAAI,OAAQqB,IAAK,CACnC,IAAMhB,EAAIL,EAAIqB,CAAC,EACTuB,GAAO5C,EAAIqB,EAAI,CAAC,EACtB,GAAIhB,EAAE,OAAS,MAAQA,EAAE,MAAQ,MAAQuC,GAAK,MAAQ,KAAM,SAE5D,IAAME,GAAMzC,EAAE,KAAOuC,GAAK,MAAQ,IAClC,GAAIE,GAAM,GAAKA,EAAK,GAAI,SAExB,IAAMoE,EAAK7G,EAAE,MACT6G,EAAKF,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAKjE,EAC3BoE,EAAKF,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAKjE,EAChCoE,EAAKF,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAKjE,EAChCoE,EAAKF,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAKjE,EAChCoE,EAAKF,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAKjE,EAChCoE,EAAKF,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAKjE,EACpCiE,EAAM,CAAC,GAAKjE,CACnB,CACA,OAAIiE,EAAM,MAAOI,GAAMA,IAAM,CAAC,EAAU,KACjCJ,CACT,CAEA,SAASK,EAAOC,EAAa,CAC3BrD,EAAMqD,CACR,CAEA,SAASC,GAAS,CAChB,OAAOtD,CACT,CAEA,SAASsB,EAAiBtF,EAAmB,CAC3C,IAAM+G,EAAQ,CAAC,EAAG,EAAG,EAAG,EAAG,CAAC,EAC5B,QAAS1F,EAAI,EAAGA,EAAIrB,EAAI,OAAQqB,IAAK,CACnC,IAAMhB,EAAIL,EAAIqB,CAAC,EACTuB,EAAO5C,EAAIqB,EAAI,CAAC,EACtB,GAAIhB,EAAE,IAAM,MAAQA,EAAE,MAAQ,MAAQuC,EAAK,MAAQ,KAAM,SAEzD,IAAME,IAAMzC,EAAE,KAAOuC,EAAK,MAAQ,IAClC,GAAIE,IAAM,GAAKA,GAAK,GAAI,SAExB,IAAMyE,EAAKlH,EAAE,GACTkH,EAAKxD,EAAiB,CAAC,EAAGgD,EAAM,CAAC,GAAKjE,GACjCyE,EAAKxD,EAAiB,CAAC,EAAGgD,EAAM,CAAC,GAAKjE,GACtCyE,EAAKxD,EAAiB,CAAC,EAAGgD,EAAM,CAAC,GAAKjE,GACtCyE,EAAKxD,EAAiB,CAAC,EAAGgD,EAAM,CAAC,GAAKjE,GAC1CiE,EAAM,CAAC,GAAKjE,EACnB,CACA,OAAIiE,EAAM,MAAOI,GAAMA,IAAM,CAAC,EAAU,KACjCJ,CACT,CAEA,SAASS,EAAWR,EAAsB,CACxCjD,EAAmBiD,CACrB,CAEA,SAASS,GAAa,CACpB,MAAO,CAAC,GAAG1D,CAAgB,CAC7B,CAEA,SAAS2D,EAAcC,EAAeC,EAAiBC,EAAiC,CACtF,IAAMxG,EAAIsG,EAAM,QAAQC,CAAO,EAC/B,GAAIvG,IAAM,GAAI,OAAO,KACrB,IAAMyG,EAAQzG,EAAIuG,EAAQ,OACpBnB,GAAIkB,EAAM,QAAQE,EAAUC,CAAK,EACvC,GAAIrB,KAAM,GAAI,OAAO,KACrB,IAAMY,EAAMM,EAAM,MAAMG,EAAOrB,EAAC,EAAE,KAAK,EACvC,OAAOY,IAAQ,GAAKA,EAAM,IAC5B,CAEA,SAASU,EAAeC,EAAiBC,EAAmC,CAC1E,IAAM5G,EAAI2G,EAAQ,QAAQC,CAAU,EACpC,GAAI5G,IAAM,GAAI,OAAO,KACrB,IAAMyG,EAAQzG,EAAI4G,EAAW,OACvBxB,EAAIuB,EAAQ,QAAQ,IAAKF,CAAK,EACpC,OAAIrB,IAAM,GAAW,KACduB,EAAQ,MAAMF,EAAOrB,CAAC,CAC/B,CAEA,IAAIyB,EAAgB,GAChBC,EAAc,EAElB,SAASC,EAAcC,EAAcP,EAAeQ,EAA4B,CAC9E,KAAOR,EAAQQ,GAAOD,EAAK,WAAWP,CAAK,GAAK,IAAIA,IACpD,KAAOQ,EAAMR,GAASO,EAAK,WAAWC,EAAM,CAAC,GAAK,IAAIA,IACtD,GAAIR,GAASQ,EAAK,OAAO,KACzB,IAAIC,EAAM,GACJC,EAAKH,EAAK,WAAWP,CAAK,EAC5BU,IAAO,IACTD,EAAM,GACNT,KACSU,IAAO,IAChBV,IAEF,IAAIT,GAAM,EACNoB,EAAS,EACb,QAASpH,EAAIyG,EAAOzG,EAAIiH,EAAKjH,IAAK,CAChC,IAAMqH,GAAIL,EAAK,WAAWhH,CAAC,EAC3B,GAAIqH,IAAK,IAAMA,IAAK,GAClBrB,GAAMA,GAAM,IAAMqB,GAAI,IACtBD,QAEA,MAEJ,CACA,OAAIA,IAAW,EAAU,KAClBF,EAAM,CAAClB,GAAMA,EACtB,CAEA,SAASsB,EAAgBN,EAAcP,EAAeQ,EAA4B,CAChF,KAAOR,EAAQQ,GAAOD,EAAK,WAAWP,CAAK,GAAK,IAAIA,IACpD,KAAOQ,EAAMR,GAASO,EAAK,WAAWC,EAAM,CAAC,GAAK,IAAIA,IACtD,GAAIR,GAASQ,EAAK,OAAO,KACzB,IAAIC,EAAM,GACJC,EAAKH,EAAK,WAAWP,CAAK,EAC5BU,IAAO,IACTD,EAAM,GACNT,KACSU,IAAO,IAChBV,IAEF,IAAIc,GAAU,EACVC,EAAW,EACXC,EAAU,EACVC,GAAS,GACTN,GAAS,EACb,QAASpH,GAAIyG,EAAOzG,GAAIiH,EAAKjH,KAAK,CAChC,IAAMqH,GAAIL,EAAK,WAAWhH,EAAC,EAC3B,GAAIqH,IAAK,IAAMA,IAAK,GAClBD,KACKM,IAEHF,EAAWA,EAAW,IAAMH,GAAI,IAChCI,GAAW,IAHAF,GAAUA,GAAU,IAAMF,GAAI,YAKlCA,KAAM,IAAM,CAACK,GACtBA,GAAS,OACJ,CACL,IAAM/H,GAAI,WAAWqH,EAAK,MAAMP,GAASS,EAAM,EAAI,GAAID,CAAG,CAAC,EAC3D,OAAO,OAAO,SAAStH,EAAC,EAAIA,GAAI,IAClC,CACF,CACA,GAAIyH,KAAW,EAAG,OAAO,KACzB,IAAMO,GAAMJ,GAAUC,EAAWC,EACjC,OAAOP,EAAM,CAACS,GAAMA,EACtB,CAEA,SAASC,EAAmBZ,EAAcP,EAAeQ,EAA4B,CACnF,KAAOR,EAAQQ,GAAOD,EAAK,WAAWP,CAAK,GAAK,IAAIA,IACpD,KAAOQ,EAAMR,GAASO,EAAK,WAAWC,EAAM,CAAC,GAAK,IAAIA,IACtD,IAAMrC,EAAMqC,EAAMR,EAClB,GAAI7B,GAAO,IAAMoC,EAAK,WAAWP,EAAQ,EAAE,IAAM,IAAMO,EAAK,WAAWC,EAAM,CAAC,IAAM,GAAI,CACtF,IAAMY,IACHb,EAAK,WAAWP,CAAK,EAAI,IAAM,KAC/BO,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAAM,KACnCO,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAAM,IACnCO,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAC1BqB,GAAKd,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAAM,IAAMO,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAC3EjF,GAAKwF,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAAM,IAAMO,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAC3EsB,GAAOF,IAAK,EAAMC,GAAK,EAAKtG,EAC9BuG,KAAQlB,IACVA,EAAgBkB,GAChBjB,EAAc,KAAK,IAAIe,GAAGC,EAAI,EAAGtG,CAAC,GAEpC,IAAMwG,IAAMhB,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAAM,IAAMO,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAC9EwB,IAAMjB,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAAM,IAAMO,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAC9EyB,IAAMlB,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAAM,IAAMO,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAChF0B,GAAK,EACT,OAAInB,EAAK,WAAWP,EAAQ,EAAE,IAAM,IAAM7B,GAAO,KAC/CuD,IACGnB,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAAM,KACpCO,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAAM,IACpCO,EAAK,WAAWP,EAAQ,EAAE,EAAI,KAE5BK,EAAckB,GAAK,KAAUC,GAAK,IAAQC,GAAK,IAAOC,EAC/D,CACA,IAAMvC,EAAI,IAAI,KAAKoB,EAAK,MAAMP,EAAOQ,CAAG,CAAC,EAAE,QAAQ,EACnD,OAAO,OAAO,SAASrB,CAAC,EAAIA,EAAI,IAClC,CAEA,SAASwC,EAAiBpB,EAAcP,EAAeQ,EAAaL,EAA4B,CAC9F,IAAM5G,EAAIgH,EAAK,QAAQJ,EAAYH,CAAK,EACxC,GAAIzG,IAAM,IAAMA,GAAKiH,EAAK,MAAO,GACjC,IAAMoB,GAASrI,EAAI4G,EAAW,OACxBxB,EAAI4B,EAAK,QAAQ,IAAKqB,EAAM,EAClC,OAAIjD,IAAM,IAAMA,GAAK6B,EAAY,EAC1BK,EAAgBN,EAAMqB,GAAQjD,CAAC,GAAK,CAC7C,CAGA,SAASkD,EAASC,EAAkBC,EAA8B,CAChE,IAAMxB,EAAewB,GAAkB,IAAI,YAAY,EAAE,OAAOD,CAAG,EAC7DE,EAAazB,EAAK,QAAQ,QAAQ,EACxC,GAAIyB,IAAe,GAAI,MAAM,IAAI,MAAM,8BAA8B,EAErE,IAAMC,EAAS1B,EAAK,MAAM,EAAGyB,CAAU,EACjCE,GAASD,EAAO,QAAQ,OAAO,EAC/BE,GACHD,KAAW,GAAKtC,EAAcqC,EAAO,MAAMC,EAAM,EAAG,SAAU,SAAS,EAAI,OAC5EtC,EAAcqC,EAAQ,SAAU,SAAS,GACzC,gBAEIG,EAAaH,EAAO,QAAQ,IAAKA,EAAO,QAAQ,MAAM,CAAC,EACvDI,GACJD,IAAe,GAAKnC,EAAegC,EAAO,MAAM,EAAGG,EAAa,CAAC,EAAG,WAAW,EAAI,KAE/EE,GAAuB,CAAC,EAC1BC,GAAMP,EACV,KAAOO,GAAMhC,EAAK,QAAQ,CACxB,IAAMiC,GAAWjC,EAAK,QAAQ,SAAUgC,EAAG,EAC3C,GAAIC,KAAa,GAAI,MACrB,IAAMC,GAAUlC,EAAK,QAAQ,IAAKiC,GAAW,CAAC,EAC9C,GAAIC,KAAY,GAAI,MACpB,IAAMC,EAASnC,EAAK,QAAQ,WAAYkC,GAAU,CAAC,EACnD,GAAIC,IAAW,GAAI,MACnBH,GAAMG,EAAS,EAEf,IAAMC,EAAMhB,EAAiBpB,EAAMiC,GAAW,EAAGC,GAAU,EAAG,OAAO,EAC/DG,GAAMjB,EAAiBpB,EAAMiC,GAAW,EAAGC,GAAU,EAAG,OAAO,EAEjEI,GAAqB,KACrBC,EAAsB,KACtBrD,GAAoB,KACpBsD,GAAqB,KACrBC,GAAuB,KACvBC,GAAsB,KACtBC,GAAuB,KACvBC,GAA2B,KAC3BC,GAA0B,KAC1BC,EAAgC,KAChCC,GAA+B,KAC/BC,GAAyB,KAEzBhL,EAAIkK,GAAU,EAClB,KAAOlK,EAAImK,GAAQ,CACjB,IAAMc,GAAKjD,EAAK,QAAQ,IAAKhI,CAAC,EAC9B,GAAIiL,KAAO,IAAMA,IAAMd,EAAQ,MAC/B,IAAMe,GAAKlD,EAAK,QAAQ,IAAKiD,GAAK,CAAC,EACnC,GAAIC,KAAO,IAAMA,IAAMf,EAAQ,MAC/B,IAAMgB,GAAKnD,EAAK,WAAWiD,GAAK,CAAC,EACjC,GAAIE,KAAO,GAAI,CACbnL,EAAIkL,GAAK,EACT,QACF,CAEA,IAAME,GAASF,GAAKD,GAAK,EACzB,GAAIE,KAAO,KAAOC,KAAW,IAAMlE,KAAO,MAAQsD,KAAQ,MAAQE,KAAS,KACzE,MAEF,IAAMW,GAASrD,EAAK,QAAQ,IAAKkD,GAAK,CAAC,EACvC,GAAIG,KAAW,IAAMA,GAASlB,EAAQ,MACtC,GAAInC,EAAK,WAAWqD,GAAS,CAAC,IAAM,GAAI,CACtC,IAAMhC,GAAS6B,GAAK,EACdI,GAAOD,GACTD,KAAW,EACTD,KAAO,IAAKb,GAAMhC,EAAgBN,EAAMqB,GAAQiC,EAAI,EAC/CH,KAAO,IAAMX,KAAQ,OAAMA,GAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,GACjEF,KAAW,EAChBD,KAAO,KAAOjE,KAAO,OAAMA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,GAC3DF,KAAW,EAChBD,KAAO,IACLnD,EAAK,WAAWiD,GAAK,CAAC,IAAM,IAAKV,EAAO3B,EAAmBZ,EAAMqB,GAAQiC,EAAI,EACxEZ,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GACxDH,KAAO,IAAMT,KAAS,OAC/BA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAElCF,KAAW,GACfD,KAAO,KAAOA,KAAO,IAAMA,KAAO,KAAOV,KAAU,KACtDA,GAAQnC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAClCH,KAAO,KAAOA,KAAO,KAAOR,KAAU,KAC9CA,GAAQrC,EAAgBN,EAAMqB,GAAQiC,EAAI,EACnCH,KAAO,IAAMT,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GACrEF,KAAW,GACfD,KAAO,IAAMA,KAAO,KAAOH,KAAY,KAC1CA,GAAUjD,EAAcC,EAAMqB,GAAQiC,EAAI,EACnCH,KAAO,IAAMX,KAAQ,OAAMA,GAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,GACjEF,KAAW,GACfD,KAAO,KAAOA,KAAO,KAAON,KAAa,OAC5CA,GAAW9C,EAAcC,EAAMqB,GAAQiC,EAAI,GACpCF,KAAW,EAChBD,KAAO,IACLnD,EAAK,WAAWiD,GAAK,CAAC,IAAM,KAAO/D,KAAO,KAC5CA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,EAC9BV,KAAc,OAAMA,GAAY7C,EAAcC,EAAMqB,GAAQiC,EAAI,GAChEH,KAAO,IAAMP,KAAc,OACpCA,GAAY7C,EAAcC,EAAMqB,GAAQiC,EAAI,GAErCF,KAAW,IAChBD,KAAO,KAAOX,KAAQ,MACjBW,KAAO,IAAMX,KAAQ,QAAMA,GAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,GACjEF,KAAW,GAChBD,KAAO,KAAOnD,EAAK,WAAWiD,GAAK,CAAC,IAAM,IAAMP,KAAS,KAC3DA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,EAClCH,KAAO,IAAMV,KAAU,KAAMA,GAAQnC,EAAgBN,EAAMqB,GAAQiC,EAAI,EACvEH,KAAO,IAAMjE,KAAO,OAAMA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,GAC/DF,KAAW,IACfD,KAAO,KAAOA,KAAO,KAAOJ,KAAkB,OACjDA,GAAgBhD,EAAcC,EAAMqB,GAAQiC,EAAI,GACzCF,KAAW,IACfD,KAAO,KAAOA,KAAO,KAAOL,IAAmB,KAClDA,EAAiB/C,EAAcC,EAAMqB,GAAQiC,EAAI,EAC1CH,KAAO,IAAMT,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GACrEF,KAAW,IAAMD,KAAO,IAAMT,KAAS,OAChDA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAE3C,IAAMC,GAAkBF,GAAS,EAAID,GACrC,GAAIpD,EAAK,WAAWuD,EAAe,IAAM,GACvCvL,EAAIuL,GAAkB,MACjB,CACL,IAAMC,GAAUxD,EAAK,QAAQ,IAAKqD,GAAS,CAAC,EAC5CrL,EAAIwL,KAAY,GAAKA,GAAU,EAAIH,GAAS,CAC9C,CACA,GAAIL,KAAY,MAAQ9D,KAAO,MAAQsD,KAAQ,MAAQE,KAAS,KAC9D,KAEJ,MACE1K,EAAIqL,EAER,CAEA,IAAII,GAAuB,KACvBX,GAAkB,MAAQC,IAAiB,MAAQA,KAAkB,EACvEU,GAAQX,EAAiBC,GAClBH,IAAa,MAAQC,IAAY,MAAQA,KAAa,IAC7DY,GAAQb,GAAYC,IAEtBd,GAAO,KAAK,CACV,IAAAK,EACA,IAAAC,GACA,IAAAC,GACA,KAAAC,EACA,GAAArD,GACA,IAAAsD,GACA,MAAAC,GACA,MAAAE,GACA,KAAAD,GACA,UAAAE,GACA,SAAAC,GACA,eAAAC,EACA,cAAAC,GACA,QAAAC,GACA,MAAAS,EACF,CAAC,CACH,CAEA,GAAI,CAAC1B,GAAO,OAAQ,MAAM,IAAI,MAAM,8BAA8B,EAElE,IAAMpK,GAAM0C,EAAa0H,EAAM,EACzBjG,GAAQF,EAAajE,EAAG,EAC9B,MAAO,CAAE,KAAAiK,EAAM,OAAAE,GAAQ,OAAQ,MAAO,OAAQnK,GAAK,MAAAmE,EAAM,CAC3D,CAGA,SAAS4H,EAASnC,EAAkBC,EAA8B,CAChE,IAAMxB,EAAewB,GAAkB,IAAI,YAAY,EAAE,OAAOD,CAAG,EAC7DoC,EAAU3D,EAAK,QAAQ,cAAc,EACrC0B,EAASiC,IAAY,GAAK3D,EAAK,MAAM,EAAG2D,CAAO,EAAI3D,EAEnD4B,GAAOvC,EAAcqC,EAAQ,OAAQ,OAAO,GAAK,cACjDkC,EAAevE,EAAcqC,EAAQ,YAAa,YAAY,EAC9DI,EAAS8B,EAAevE,EAAcuE,EAAc,SAAU,SAAS,EAAI,KAE3E7B,GAAuB,CAAC,EAC1BC,GAAM2B,IAAY,GAAKA,EAAU,EACrC,KAAO3B,GAAMhC,EAAK,QAAQ,CACxB,IAAM6D,GAAU7D,EAAK,QAAQ,eAAgBgC,EAAG,EAChD,GAAI6B,KAAY,GAAI,MACpB,IAAMC,GAAQ9D,EAAK,QAAQ,gBAAiB6D,GAAU,EAAE,EACxD,GAAIC,KAAU,GAAI,MAClB9B,GAAM8B,GAAQ,GAEd,IAAI1B,GAAqB,KACrBC,EAAqB,KACrBC,EAAqB,KACrBC,GAAsB,KACtBrD,GAAoB,KACpBsD,EAAqB,KACrBC,GAAuB,KACvBE,GAAuB,KACvBD,GAAsB,KACtBE,GAA2B,KAC3BC,GAA0B,KAC1BC,GAAgC,KAChCC,GAA+B,KAC/BC,EAAyB,KAEzBhL,GAAI6L,GAAU,GAClB,KAAO7L,GAAI8L,IAAO,CAChB,IAAMb,EAAKjD,EAAK,QAAQ,IAAKhI,EAAC,EAC9B,GAAIiL,IAAO,IAAMA,GAAMa,GAAO,MAC9B,IAAMZ,GAAKlD,EAAK,QAAQ,IAAKiD,EAAK,CAAC,EACnC,GAAIC,KAAO,IAAMA,IAAMY,GAAO,MAC9B,IAAMX,GAAKnD,EAAK,WAAWiD,EAAK,CAAC,EACjC,GAAIE,KAAO,GAAI,CACbnL,GAAIkL,GAAK,EACT,QACF,CACA,IAAME,GAASF,GAAKD,EAAK,EACnBI,GAASrD,EAAK,QAAQ,IAAKkD,GAAK,CAAC,EACvC,GAAIG,KAAW,IAAMA,GAASS,GAAO,MACrC,GAAI9D,EAAK,WAAWqD,GAAS,CAAC,IAAM,GAAI,CACtC,IAAMhC,GAAS6B,GAAK,EACdI,GAAOD,GACTD,KAAW,EACTD,KAAO,GACLnD,EAAK,WAAWiD,EAAK,CAAC,IAAM,IAAKV,GAAO3B,EAAmBZ,EAAMqB,GAAQiC,EAAI,EACxEZ,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GACxDH,KAAO,KAAOT,KAAS,OAChCA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAElCF,KAAW,EAChBD,KAAO,IAAMjE,KAAO,KAAMA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,GACzDH,KAAO,IAAMA,KAAO,IAAMA,KAAO,MAAQV,KAAU,KAC3DA,GAAQnC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAClCH,KAAO,IAAMA,KAAO,MAAQR,KAAU,KAC9CA,GAAQrC,EAAgBN,EAAMqB,GAAQiC,EAAI,EACnCH,KAAO,IAAMT,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GACrEF,KAAW,EAChBD,KAAO,IAAMX,IAAQ,KAAMA,EAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,GAC3DH,KAAO,IAAMA,KAAO,KAAOH,IAAY,OAC/CA,EAAUjD,EAAcC,EAAMqB,GAAQiC,EAAI,GACnCF,KAAW,GACfD,KAAO,IAAMA,KAAO,MAAQN,KAAa,OAC5CA,GAAW9C,EAAcC,EAAMqB,GAAQiC,EAAI,GACpCF,KAAW,GACfD,KAAO,IAAMA,KAAO,MAAQP,KAAc,OAC7CA,GAAY7C,EAAcC,EAAMqB,GAAQiC,EAAI,GACrCF,KAAW,GAChBD,KAAO,IAAMX,IAAQ,OAAMA,EAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,GAC5DF,KAAW,GAChBD,KAAO,IAAMT,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAChEF,KAAW,IACfD,KAAO,IAAMA,KAAO,MAAQJ,KAAkB,OACjDA,GAAgBhD,EAAcC,EAAMqB,GAAQiC,EAAI,GACzCF,KAAW,GAChBD,KAAO,GACLnD,EAAK,WAAWiD,EAAK,CAAC,IAAM,IAAKX,EAAMhC,EAAgBN,EAAMqB,GAAQiC,EAAI,EACpEZ,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,IACvDH,KAAO,IAAMA,KAAO,MAAQL,KAAmB,OACzDA,GAAiB/C,EAAcC,EAAMqB,GAAQiC,EAAI,GAE1CF,KAAW,GAChBD,KAAO,KAAIf,GAAM9B,EAAgBN,EAAMqB,GAAQiC,EAAI,GAC9CF,KAAW,GAChBD,KAAO,KAAId,EAAM/B,EAAgBN,EAAMqB,GAAQiC,EAAI,GAC9CF,KAAW,GAAKD,KAAO,KAAOjE,KAAO,KAC9CA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,EAC5BF,KAAW,GAAKD,KAAO,IAAMX,IAAQ,KAC9CA,EAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,EAC7BF,KAAW,KAChBD,KAAO,IAAMjE,KAAO,KAAMA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,EAC1DH,KAAO,IAAMV,KAAU,OAAMA,GAAQnC,EAAgBN,EAAMqB,GAAQiC,EAAI,IAElF,IAAMC,GAAkBF,GAAS,EAAID,GACrC,GAAIpD,EAAK,WAAWuD,EAAe,IAAM,GACvCvL,GAAIuL,GAAkB,MACjB,CACL,IAAMC,GAAUxD,EAAK,QAAQ,IAAKqD,GAAS,CAAC,EAC5CrL,GAAIwL,KAAY,GAAKA,GAAU,EAAIH,GAAS,CAC9C,CACA,GAAIL,IAAY,MAAQ9D,KAAO,MAAQsD,IAAQ,MAAQE,KAAS,KAC9D,KAEJ,MACE1K,GAAIqL,EAER,CAEA,GAAIjB,IAAO,MAAQC,GAAO,KAAM,SAEhC,IAAIoB,GAAuB,KACvBX,IAAkB,MAAQC,IAAiB,MAAQA,KAAkB,EACvEU,GAAQX,GAAiBC,GAClBH,IAAa,MAAQC,IAAY,MAAQA,KAAa,IAC7DY,GAAQb,GAAYC,IAEtBd,GAAO,KAAK,CACV,IAAAK,GACA,IAAAC,EACA,IAAAC,EACA,KAAAC,GACA,GAAArD,GACA,IAAAsD,EACA,MAAAC,GACA,MAAAE,GACA,KAAAD,GACA,UAAAE,GACA,SAAAC,GACA,eAAAC,GACA,cAAAC,GACA,QAAAC,EACA,MAAAS,EACF,CAAC,CACH,CAEA,IAAM9L,GAAM0C,EAAa0H,EAAM,EACzBjG,GAAQF,EAAajE,EAAG,EAC9B,MAAO,CAAE,KAAAiK,GAAM,OAAAE,EAAQ,OAAQ,MAAO,OAAQnK,GAAK,MAAAmE,EAAM,CAC3D,CAEA,SAASiI,EAAkBxC,EAA8B,CACvD,GAAIA,EAAI,WAAa,GAAI,OAAO,KAChC,IAAMyC,EAAK,IAAI,SAASzC,CAAG,EACrB0C,EAAaD,EAAG,SAAS,CAAC,EAEhC,GADIC,EAAa,IAAMA,EAAa,EAAI1C,EAAI,YAE1CyC,EAAG,SAAS,CAAC,IAAM,IACnBA,EAAG,SAAS,CAAC,IAAM,IACnBA,EAAG,SAAS,EAAE,IAAM,IACpBA,EAAG,SAAS,EAAE,IAAM,GAEpB,OAAO,KAET,IAAME,EAAWF,EAAG,UAAU,EAAG,EAAI,EAC/BG,EAAY,KAAK,IAAI5C,EAAI,WAAY0C,EAAaC,CAAQ,EAC1DE,GAAmB,UACnBC,EAAoB,IAAM,KAAK,IAAI,EAAG,EAAE,EAaxCC,EAA+B,IAAI,MAAM,EAAE,EAC3CC,GAAkB,CAAC,EACnBC,GAAkB,CAAC,EACnBC,GAAiB,CAAC,EAClBC,GAAgB,CAAC,EACjBC,GAAsB,CAAC,EAEzBC,GAASX,EACb,KAAOW,GAAST,GAAW,CACzB,IAAMU,GAAMb,EAAG,SAASY,IAAQ,EAChC,GAAKC,GAAM,KAAgBA,GAAM,GAC/B,OAAO,KAET,IAAMC,EAAWD,GAAM,GACvB,GAAKA,GAAM,GAAa,CACtB,GAAID,GAAS,EAAIT,EAAW,OAAO,KACnCS,KAEA,IAAMG,GADOf,EAAG,SAASY,IAAQ,IACH,EACxBI,GAAehB,EAAG,UAAUY,GAAQG,EAAY,EACtDH,IAAU,EACV,IAAMK,EAAYjB,EAAG,SAASY,IAAQ,EACtC,GAAIA,GAASK,EAAY,EAAId,EAAW,OAAO,KAC/C,IAAMe,GAAqB,IAAI,MAAMD,CAAS,EAC1CE,GAAa,EACjB,QAASnM,GAAI,EAAGA,GAAIiM,EAAWjM,KAAK,CAClC,IAAMoM,GAAMpB,EAAG,SAASY,IAAQ,EAC1BS,GAAOrB,EAAG,SAASY,IAAQ,EAC3BU,GAAOtB,EAAG,SAASY,IAAQ,EACjCM,GAAOlM,EAAC,EAAI,CAAE,IAAAoM,GAAK,KAAAC,GAAM,KAAAC,EAAK,EAC9BH,IAAcE,EAChB,CACAf,EAAKQ,CAAQ,EAAI,CAAE,aAAAC,GAAc,aAAAC,GAAc,OAAAE,GAAQ,WAAAC,EAAW,CACpE,KAAO,CACL,IAAMI,EAAMjB,EAAKQ,CAAQ,EACzB,GAAI,CAACS,GAAOX,GAASW,EAAI,WAAapB,EAAW,OAAO,KACxD,IAAMqB,GAAKD,EAAI,aACTE,GAAOF,EAAI,aAEjB,GACEE,KAAS,IACTF,EAAI,OAAO,SAAW,IACtBA,EAAI,aAAe,IACnBA,EAAI,OAAO,CAAC,EAAE,MAAQ,KACtBA,EAAI,OAAO,CAAC,EAAE,MAAQ,EACtB,CACA,IAAMG,GAAK1B,EAAG,UAAUY,GAAQY,EAAE,EAC5BG,GAAS3B,EAAG,SAASY,GAAS,EAAGY,EAAE,EACnCI,GAAS5B,EAAG,SAASY,GAAS,EAAGY,EAAE,EACnCK,GAAS7B,EAAG,UAAUY,GAAS,GAAIY,EAAE,EACrCtG,GAAK8E,EAAG,SAASY,GAAS,EAAE,EAC5BpC,GAAMwB,EAAG,SAASY,GAAS,EAAE,EAC7BkB,EAAU9B,EAAG,UAAUY,GAAS,GAAIY,EAAE,EACtCO,GAAS/B,EAAG,UAAUY,GAAS,GAAIY,EAAE,EACrC/C,GAAQuB,EAAG,UAAUY,GAAS,GAAIY,EAAE,EACpC9C,EAAOsB,EAAG,QAAQY,GAAS,EAAE,EACnCH,GAAQ,KAAK,CACX,WAAYiB,GAAKtB,IAAoB,IACrC,aAAcuB,GAAStB,EACvB,cAAeuB,GAASvB,EACxB,SAAUwB,GAAS,EAAI,IACvB,WAAY3G,GACZ,QAASsD,GACT,SAAUsD,EAAU,IACpB,MAAQC,GAAS,IAAQ,IACzB,MAAAtD,GACA,YAAaC,CACf,CAAC,EACDkC,IAAU,GACV,QACF,CAEA,IAAMoB,EAAW,CAAC,EACdC,GAAOrB,GACX,QAAS5L,GAAI,EAAGA,GAAIuM,EAAI,OAAO,OAAQvM,KAAK,CAC1C,IAAMkN,GAAIX,EAAI,OAAOvM,EAAC,EAClBgG,GAAc,EACZmH,GAAQD,GAAE,KAAO,GACnBA,GAAE,OAAS,EACblH,GAAMmH,KAAU,EAAInC,EAAG,QAAQiC,EAAI,EAAIjC,EAAG,SAASiC,EAAI,EAC9CC,GAAE,OAAS,EACpBlH,GAAMmH,KAAU,EAAInC,EAAG,SAASiC,GAAMT,EAAE,EAAIxB,EAAG,UAAUiC,GAAMT,EAAE,EACxDU,GAAE,OAAS,IACpBlH,GAAMmH,KAAU,EAAInC,EAAG,SAASiC,GAAMT,EAAE,EAAIxB,EAAG,UAAUiC,GAAMT,EAAE,GAEnEQ,EAAIE,GAAE,GAAG,EAAIlH,GACbiH,IAAQC,GAAE,IACZ,CAGA,GAFAtB,IAAUW,EAAI,WAEVE,KAAS,EACXlB,GAAS,KAAK,CACZ,KAAMyB,EAAI,CAAC,IAAM,EAAI,WAAaA,EAAI,CAAC,EACvC,aAAcA,EAAI,CAAC,IAAM,EAAI,SAAWA,EAAI,CAAC,EAC7C,QAASA,EAAI,CAAC,EACd,aAAcA,EAAI,CAAC,GAAK,MAAQA,EAAI,CAAC,EAAI5B,IAAoB,IAAO,MACtE,CAAC,UACQqB,KAAS,GAAI,CACtB,IAAMW,GAAmC,CAAE,EAAG,UAAW,EAAG,UAAW,EAAG,SAAU,EACpF5B,GAAS,KAAK,CACZ,WAAYwB,EAAI,CAAC,GAAK,MAAQA,EAAI,CAAC,EAAI5B,IAAoB,IAAO,OAClE,MAAOgC,GAASJ,EAAI,CAAC,CAAC,GAAK,OAAOA,EAAI,CAAC,CAAC,EACxC,UAAWA,EAAI,CAAC,IAAM,EAAI,UAAY,OAAOA,EAAI,CAAC,CAAC,CACrD,CAAC,CACH,SAAWP,KAAS,GAClBhB,GAAQ,KAAK,CACX,UAAWuB,EAAI,GAAG,GAAK,MAAQA,EAAI,GAAG,EAAI5B,IAAoB,IAAO,OACrE,aAAc4B,EAAI,CAAC,GAAK,KAAOA,EAAI,CAAC,EAAI3B,EAAoB,OAC5D,cAAe2B,EAAI,CAAC,GAAK,KAAOA,EAAI,CAAC,EAAI3B,EAAoB,OAC7D,SAAU2B,EAAI,CAAC,GAAK,KAAOA,EAAI,CAAC,EAAI,EAAI,IAAM,OAC9C,WAAYA,EAAI,CAAC,EACjB,QAASA,EAAI,CAAC,EACd,SAAUA,EAAI,CAAC,GAAK,KAAOA,EAAI,CAAC,EAAI,IAAM,OAC1C,MAAOA,EAAI,CAAC,GAAK,KAAQA,EAAI,CAAC,EAAI,IAAQ,IAAM,OAChD,MAAOA,EAAI,CAAC,EACZ,YAAaA,EAAI,EAAE,CACrB,CAAC,UACQP,KAAS,GAAI,CACtB,IAAMY,GACJL,EAAI,CAAC,IAAM,GACP,mBACAA,EAAI,CAAC,IAAM,GACT,oBACA,OAAOA,EAAI,CAAC,CAAC,EACrBtB,GAAO,KAAK,CACV,UAAWsB,EAAI,GAAG,GAAK,MAAQA,EAAI,GAAG,EAAI5B,IAAoB,IAAO,OACrE,MAAOiC,GACP,WAAYL,EAAI,CAAC,IAAM,EAAI,SAAW,OAAOA,EAAI,CAAC,CAAC,EACnD,KAAMA,EAAI,CAAC,EACX,eAAgBA,EAAI,CAAC,EACrB,cAAeA,EAAI,EAAE,CACvB,CAAC,CACH,SAAWP,KAAS,GAClBd,GAAa,KAAK,CAChB,UAAWqB,EAAI,GAAG,GAAK,MAAQA,EAAI,GAAG,EAAI5B,IAAoB,IAAO,OACrE,cAAe4B,EAAI,EAAE,CACvB,CAAC,MAED,QAAO,IAEX,CACF,CACA,MAAO,CAAE,SAAAzB,GAAU,SAAAC,GAAU,OAAQ,CAAC,EAAG,QAAAC,GAAS,OAAAC,GAAQ,aAAAC,EAAa,CACzE,CAGA,SAAS2B,EAAS/E,EAAgC,CAChD,OAAO,IAAI,QAAQ,CAACgF,EAASC,IAAW,CACtC,IAAMC,EAAsB,CAACC,EAAYhJ,IAAc,CACrD,GAAIgJ,EAAO,CACTF,EAAOE,CAAK,EACZ,MACF,CACA,GAAI,CACF,IAAM9E,GAAOlE,EAAK,WAAW,CAAC,GAAG,WAC7B,gBAAgB,IAAI,KAAKA,EAAK,SAAS,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,GACjF,cAGAoE,GAAwB,KACtB6E,GAAwB,CAAC,EAC3BC,GAAuB,KACvBC,GAA0B,KAE1BnJ,EAAK,SAAS,CAAC,GACjBkJ,GAAQlJ,EAAK,OAAO,CAAC,EAAE,MACvBmJ,GAAWnJ,EAAK,OAAO,CAAC,EAAE,WACjBA,EAAK,WAAW,CAAC,IAC1BkJ,GAAQlJ,EAAK,SAAS,CAAC,EAAE,MACzBmJ,GAAWnJ,EAAK,SAAS,CAAC,EAAE,WAG9B,IAAMoJ,GAAiBtM,GACrBA,EAAE,cACFA,EAAE,gBACFA,EAAE,SACFA,EAAE,aACFA,EAAE,cACF,KAEF,GAAIkD,EAAK,WAAW,CAAC,EAAG,CACtB,IAAMqJ,EAAMrJ,EAAK,SAAS,CAAC,EAC3BoE,GAASgF,GAAcC,CAAG,EAC1BJ,GAAQ,KAAK,CACX,KAAMI,EAAI,cAAgBA,EAAI,gBAAkBA,EAAI,QACpD,aAAcA,EAAI,aAClB,OAAQA,EAAI,cAAgB,OAAOA,EAAI,aAAa,EAAI,OACxD,QAASA,EAAI,iBAAmB,OAAOA,EAAI,gBAAgB,EAAI,OAC/D,KAAM,MACR,CAAC,CACH,CAEIrJ,EAAK,cACPA,EAAK,aAAa,QAASlD,GAAW,CAGpC,GAFeA,EAAE,eAAiB,WAAaA,EAAE,eAAiB,EAEtD,CACV,IAAMoH,GAAOkF,GAActM,CAAC,GAExBA,EAAE,cAAgBA,EAAE,gBAAkB,CAACsH,MAAQA,GAASF,IAGxD+E,GAAQ,OAAS,GAAKA,GAAQ,CAAC,EAAE,OAAS,UACxCnM,EAAE,cAAgBA,EAAE,gBAAkB,CAACmM,GAAQ,CAAC,EAAE,QACpDA,GAAQ,CAAC,EAAE,KAAOnM,EAAE,cAAgBA,EAAE,gBAAkBA,EAAE,SAEvDmM,GAAQ,CAAC,EAAE,eAAcA,GAAQ,CAAC,EAAE,aAAenM,EAAE,cACtD,CAACmM,GAAQ,CAAC,EAAE,QAAUnM,EAAE,gBAC1BmM,GAAQ,CAAC,EAAE,OAAS,OAAOnM,EAAE,aAAa,GACxC,CAACmM,GAAQ,CAAC,EAAE,SAAWnM,EAAE,mBAC3BmM,GAAQ,CAAC,EAAE,QAAU,OAAOnM,EAAE,gBAAgB,GAC5C,CAACmM,GAAQ,CAAC,EAAE,iBAAmBnM,EAAE,mBACnCmM,GAAQ,CAAC,EAAE,gBAAkB,OAAOnM,EAAE,gBAAgB,IAE1D,MACF,CAEAmM,GAAQ,KAAK,CACX,KAAMnM,EAAE,cAAgBA,EAAE,gBAAkBA,EAAE,SAAWA,EAAE,aAAe,SAC1E,aAAcA,EAAE,aAChB,OAAQA,EAAE,cAAgB,OAAOA,EAAE,aAAa,EAAI,OACpD,QAASA,EAAE,iBAAmB,OAAOA,EAAE,gBAAgB,EAAI,OAC3D,gBAAiBA,EAAE,iBAAmB,OAAOA,EAAE,gBAAgB,EAAI,OACnE,KAAMA,EAAE,aAAe,SACvB,cAAeA,EAAE,eACjB,eAAgBA,EAAE,gBAClB,aAAcA,EAAE,cAChB,WAAYA,EAAE,aAAe,KAAO,OAAOA,EAAE,WAAW,EAAI,MAC9D,CAAC,CACH,CAAC,EAGCkD,EAAK,iBACPA,EAAK,gBAAgB,QAASH,GAAW,CACvC,IAAMqE,GAAOrE,EAAE,MAAQA,EAAE,SAAWA,EAAE,YACtC,GAAI,CAACqE,GAAM,OAGX,IAAMoF,GAAQzJ,EAAE,OAAS,OAAOA,EAAE,MAAM,EAAI,OACtC0J,EAAWN,GAAQ,KACtBnM,IACEwM,IAASxM,GAAE,SAAWwM,IACtBxM,GAAE,OAASoH,IAAQpH,GAAE,eAAiB+C,EAAE,YAC7C,EAEI0J,GACGA,EAAS,OAAMA,EAAS,KAAOrF,IAC/BqF,EAAS,eAAcA,EAAS,aAAe1J,EAAE,cACjD0J,EAAS,OAAMA,EAAS,KAAO1J,EAAE,aACjC0J,EAAS,aACZA,EAAS,WACP1J,EAAE,iBAAmB,KAAO,OAAOA,EAAE,eAAe,EAAI,SAE5DoJ,GAAQ,KAAK,CACX,KAAM/E,GACN,aAAcrE,EAAE,aAChB,OAAQyJ,GACR,KAAMzJ,EAAE,aAAe,SACvB,WAAYA,EAAE,iBAAmB,KAAO,OAAOA,EAAE,eAAe,EAAI,MACtE,CAAC,CAEL,CAAC,EAKH,IAAM2J,GAAuE,CAAC,EAC1ExJ,EAAK,kBACPA,EAAK,gBAAgB,QAAQ,CAACH,EAAQ4J,KAAgB,CAChD5J,EAAE,WAAaA,EAAE,eAAiB,MACpC2J,GAAc,KAAK,CACjB,KACE,OAAO3J,EAAE,WAAc,SAAWA,EAAE,UAAY,IAAI,KAAKA,EAAE,SAAS,EAAE,QAAQ,EAChF,MAAOA,EAAE,cACT,IAAA4J,EACF,CAAC,CAEL,CAAC,EACDD,GAAc,KAAK,CAACE,EAAGC,KAAMD,EAAE,KAAOC,GAAE,MAAQD,EAAE,IAAMC,GAAE,GAAG,GAI/D,IAAMC,EAOA,CAAC,EACH5J,EAAK,SACPA,EAAK,OAAO,QAAQ,CAAC6J,EAAQJ,KAAgB,CAC3C,IAAIK,GAAQD,EAAE,gBAAkBA,EAAE,YAAc,KAC5CE,EAAOF,EAAE,eAAiBA,EAAE,WAAa,KACzCG,GAAaH,EAAE,sBAAwB,KACvCI,GAAYJ,EAAE,qBAAuB,KAEzC,GAAIA,EAAE,QAAU,oBAAsBA,EAAE,QAAU,oBAAqB,CACrE,IAAM/M,GAAI+M,EAAE,KACZ,GAAI/M,IAAK,KAAM,CACb,IAAMoN,GAAMpN,IAAK,GAAM,IACjBqN,GAAMrN,IAAK,GAAM,IACjBsN,GAAMtN,IAAK,EAAK,IAChBuN,GAAKvN,GAAI,IAEXqN,KAAO,IAAGL,GAAQK,IAClBD,KAAO,IAAGF,GAAaE,IACvBG,KAAO,IAAGN,EAAOM,IACjBD,KAAO,IAAGH,GAAYG,GAC5B,CACF,CAGEP,EAAE,YACDC,IAAS,MAAQC,GAAQ,MAAQC,IAAc,MAAQC,IAAa,OAErEL,EAAW,KAAK,CACd,KACE,OAAOC,EAAE,WAAc,SAAWA,EAAE,UAAY,IAAI,KAAKA,EAAE,SAAS,EAAE,QAAQ,EAChF,MAAAC,GACA,KAAAC,EACA,WAAAC,GACA,UAAAC,GACA,IAAAR,EACF,CAAC,CAEL,CAAC,EACDG,EAAW,KAAK,CAACF,EAAGC,KAAMD,EAAE,KAAOC,GAAE,MAAQD,EAAE,IAAMC,GAAE,GAAG,GAG5D,IAAM5C,EAAU/G,EAAK,SAAW,CAAC,EAC7BsK,GAA6B,KAC7BC,GAAY,EACZC,EAA+B,KAC/BC,GAA8B,KAC9BC,GAAgC,KAChCC,GAA+B,KAC/BC,GAAU,EAERC,GAA4B,CAAC,EACnC,QAASC,EAAK,EAAGA,EAAK/D,EAAQ,OAAQ+D,IAAM,CAC1C,IAAMC,GAAIhE,EAAQ+D,CAAE,EACdpG,GAAMqG,GAAE,aACRpG,EAAMoG,GAAE,cACd,GAAIrG,IAAO,MAAQC,GAAO,KAAM,SAEhC,IAAME,GACJkG,GAAE,WAAa,KACX,OAAOA,GAAE,WAAc,SACrBA,GAAE,UACFA,GAAE,qBAAqB,KACrBA,GAAE,UAAU,QAAQ,EACpB,IAAI,KAAKA,GAAE,SAAS,EAAE,QAAQ,EAClC,KACA9F,GAAQ8F,GAAE,OAAS,KAAOA,GAAE,MAAQ,IAAM,KAE5CzF,GAAUyF,GAAE,eAAiB,KAGjC,GAAIzF,IAAW,MAAQT,GAAM,CAE3B,KAAO0F,GAAYf,GAAc,QAAUA,GAAce,EAAS,EAAE,MAAQ1F,IAC1EyF,GAAcd,GAAce,EAAS,EAAE,MACvCA,KAEFjF,GAAUgF,EACZ,MAAWhF,IAAW,OACpBgF,GAAchF,IAIhB,GAAIT,GACF,KAAO+F,GAAUhB,EAAW,QAAUA,EAAWgB,EAAO,EAAE,MAAQ/F,IAAM,CACtE,IAAMgF,GAAID,EAAWgB,EAAO,EACxBf,GAAE,OAAS,OAAMW,EAAgBX,GAAE,OACnCA,GAAE,MAAQ,OAAMY,GAAeZ,GAAE,MACjCA,GAAE,YAAc,OAAMa,GAAiBb,GAAE,YACzCA,GAAE,WAAa,OAAMc,GAAgBd,GAAE,WAC3Ce,IACF,CAGF,IAAM1F,GAA2B6F,GAAE,gBAAkBA,GAAE,YAAcP,EAC/DrF,GAA0B4F,GAAE,eAAiBA,GAAE,WAAaN,GAC5DrF,GAAgC2F,GAAE,sBAAwBL,GAC1DrF,GAA+B0F,GAAE,qBAAuBJ,IAE1DI,GAAE,gBAAkB,MAAQA,GAAE,YAAc,QAAMP,EAAgBtF,KAClE6F,GAAE,eAAiB,MAAQA,GAAE,WAAa,QAAMN,GAAetF,IAC/D4F,GAAE,sBAAwB,OAAML,GAAiBtF,IACjD2F,GAAE,qBAAuB,OAAMJ,GAAgBtF,IAEnD,IAAMU,GACJX,IAAkB,MAAQC,IAAiB,MAAQA,KAAkB,EACjED,GAAiBC,GACjB,KAENwF,GAAY,KAAK,CACf,IAAAnG,GACA,IAAAC,EACA,IAAKoG,GAAE,UAAYA,GAAE,mBAAqB,KAC1C,KAAAlG,GACA,GAAIkG,GAAE,YAAc,KACpB,IAAKA,GAAE,SAAW,KAClB,MAAOA,GAAE,OAAS,KAClB,MAAA9F,GACA,KAAM8F,GAAE,aAAe,KACvB,UAAA7F,GACA,SAAAC,GACA,eAAAC,GACA,cAAAC,GACA,QAAAC,GACA,MAAAS,EACF,CAAC,CACH,CAEA,GAAI,CAAC8E,GAAY,OAAQ,CACvB/B,EAAO,IAAI,MAAM,4BAA4B,CAAC,EAC9C,MACF,CAEA,IAAM7O,GAAM0C,EAAakO,EAAW,EAC9BzM,GAAQF,EAAajE,EAAG,EAC9B4O,EAAQ,CAAE,KAAA3E,GAAM,OAAAE,GAAQ,QAAA6E,GAAS,OAAQ,MAAO,OAAQhP,GAAK,MAAAmE,GAAO,MAAA8K,GAAO,SAAAC,EAAS,CAAC,CACvF,OAAS6B,GAAI,CACXlC,EAAOkC,EAAE,CACX,CACF,EAEMC,EAAW5E,EAAkBxC,CAAG,EACtC,GAAIoH,EAAU,CACZlC,EAAoB,KAAMkC,CAAQ,EAClC,MACF,CAEkB,IAAIC,GAAU,CAC9B,MAAO,GACP,UAAW,OACX,WAAY,IACZ,gBAAiB,UACjB,mBAAoB,EACtB,CAAC,EAES,MAAMrH,EAAKkF,CAAmB,CAC1C,CAAC,CACH,CAGA,SAASoC,EAAStH,EAAuB,CACvC,IAAMvB,EAAO,IAAI,YAAY,EAAE,OAAOuB,CAAG,EACnCuH,EAAM,IAAI,UAAU,EAAE,gBAAgB9I,EAAM,iBAAiB,EAE/D4B,EAAO,gBACLmH,EAASD,EAAI,cAAc,mCAAmC,EAChEC,IAAQnH,EAAOmH,EAAO,aAAa,KAAK,GAAKnH,GAGjD,IAAMoH,GAAWF,EAAI,iBAAiB,aAAa,EACnD,GAAI,CAACE,GAAS,OAAQ,MAAM,IAAI,MAAM,6BAA6B,EAEnE,IAAMjH,EAAuB,CAAC,EA8B9B,GA7BAiH,GAAS,QAASC,IAAO,EACTA,GAAG,aAAa,KAAK,EAAE,MAAM,KAAK,GAAK,CAAC,GAChD,QAASC,IAAS,CACtB,IAAMC,GAAQD,GAAK,MAAM,GAAG,EAC5B,GAAIC,GAAM,OAAS,EAAG,OACtB,IAAM9G,GAAM,WAAW8G,GAAM,CAAC,CAAC,EACzB/G,GAAM,WAAW+G,GAAM,CAAC,CAAC,EACzB7G,EAAM6G,GAAM,OAAS,EAAI,WAAWA,GAAM,CAAC,CAAC,EAAI,KAClD,MAAM/G,EAAG,GAAK,MAAMC,EAAG,GAC3BN,EAAO,KAAK,CACV,IAAAK,GACA,IAAAC,GACA,IAAKC,GAAO,MAAQ,MAAMA,CAAG,EAAI,KAAOA,EACxC,KAAM,KACN,GAAI,KACJ,IAAK,KACL,MAAO,KACP,MAAO,KACP,KAAM,KACN,UAAW,KACX,SAAU,KACV,eAAgB,KAChB,cAAe,KACf,QAAS,KACT,MAAO,IACT,CAAC,CACH,CAAC,CACH,CAAC,EAEG,CAACP,EAAO,OAAQ,MAAM,IAAI,MAAM,6BAA6B,EACjE,IAAMpK,EAAM0C,EAAa0H,CAAM,EACzBjG,GAAQF,EAAajE,CAAG,EAC9B,MAAO,CAAE,KAAAiK,EAAM,OAAQ,MAAO,OAAQjK,EAAK,MAAAmE,EAAM,CACnD,CAGA,eAAesN,GAAUC,EAA0B,CACjD,IAAMC,EAAMD,EAAK,KAAK,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,EAC9C9H,EAAoB8H,EAAa,MAAS,MAAMA,EAAK,YAAY,EACjE7H,EAAsC6H,EAAa,MACrDrP,EACJ,OAAQsP,EAAK,CACX,IAAK,MACHtP,EAASsH,EAASC,EAAKC,CAAc,EACrC,MACF,IAAK,MACHxH,EAAS0J,EAASnC,EAAKC,CAAc,EACrC,MACF,IAAK,MACHxH,EAAS,MAAMsM,EAAS/E,CAAG,EAC3B,MACF,IAAK,MACHvH,EAAS6O,EAAStH,CAAG,EACrB,MACF,QACE,MAAM,IAAI,MAAM,wBAAwB+H,CAAG,EAAE,CACjD,CAEA,OAAItP,IACFA,EAAO,SAAWqP,EAAK,KACvBrP,EAAO,SAAWqP,EAAK,MAElBrP,CACT,CAEA,MAAO,CACL,UAAAoP,GACA,aAAAxN,EACA,qBAAAyB,EACA,oBAAAF,EACA,iBAAAD,EACA,oBAAAE,EACA,iBAAAH,EACA,aAAA5C,EACA,WAAA8E,EACA,WAAAC,EACA,OAAAL,EACA,OAAAE,CACF,CACF,GAAG,EE7/CI,IAAMsK,IAAW,IAAM,CAC5B,IAAIC,EAAuC,CAAC,EACxCC,EAAmD,KAEvD,SAASC,EACPC,EACAC,GACAC,EACAC,EACAC,EACA,CAAC,CAEH,SAASC,EAAcC,EAAe,CAAC,CACvC,SAASC,EAASC,EAAc,CAC9BX,EAAUW,EAAE,EAAE,EAAIA,CACpB,CACA,SAASC,EAAUC,EAAiB,CAClCA,EAAG,QAASF,IAAM,CAChBX,EAAUW,GAAE,EAAE,EAAIA,EACpB,CAAC,CACH,CACA,SAASG,EAAYC,EAAY,CAC/B,OAAOf,EAAUe,CAAE,CACrB,CACA,SAASC,GAAc,CACrBhB,EAAY,CAAC,CACf,CACA,SAASiB,GAAkB,CACzBjB,EAAY,CAAC,CACf,CACA,SAASkB,EAAgBH,EAAYI,GAAkB,CAAC,CACxD,SAASC,EAAiBL,EAAmBM,GAAc,CAAC,CAC5D,SAASC,GAAS,CAAC,CACnB,SAASC,EAASR,EAAY,CAAC,CAC/B,SAASS,EAAaC,EAAaC,GAAa,CAAC,CACjD,SAASC,GAAa,CAAC,CACvB,SAASC,EACPb,EACAc,GACAC,EACAC,EACAV,EACAW,EACA,CAAC,CACH,SAASC,GAAiB,CAAC,CAC3B,SAASC,EAAcnB,EAAYoB,GAAgB,CAAC,CACpD,SAASC,EAAcP,EAAU,CAAC,CAClC,SAASQ,EAASZ,EAAaC,GAAaY,EAAsBC,EAAiB,CAAC,CACpF,SAASC,GAAa,CAAC,CACvB,SAASC,GAAiB,CAAC,CAC3B,SAASC,GAAwC,CAC/C,MAAO,CAAC,EAAG,EAAG,CAAC,CACjB,CACA,SAASC,EAAYlB,EAAamB,GAAaN,EAAc,CAAC,CAC9D,SAASO,EAAmB9B,EAAYc,GAAmBG,EAAkB,CAAC,CAC9E,SAASc,EAAiB/B,EAAY,CAAC,CAEvC,SAASgC,EACPC,EACAC,GACU,CACV,OAAO,OAAO,KAAKjD,CAAS,CAC9B,CAEA,MAAO,CACL,KAAAE,EACA,OAAQ,IAAM,KACd,sBAAwBgD,GAAiB,CACvCjD,EAAqBiD,CACvB,EACA,cAAA1C,EACA,SAAAE,EACA,UAAAE,EACA,YAAAE,EACA,YAAAE,EACA,gBAAAC,EACA,gBAAAC,EACA,iBAAAE,EACA,OAAAE,EACA,SAAAC,EACA,aAAAC,EACA,WAAAG,EACA,iBAAAC,EACA,eAAAK,EACA,cAAAC,EACA,cAAAE,EACA,SAAAC,EACA,WAAAG,EACA,eAAAC,EACA,YAAAC,EACA,YAAAC,EACA,mBAAAE,EACA,iBAAAC,EACA,+BAAAC,EACA,aAAehC,GAAef,EAAUe,CAAE,CAC5C,CACF,GAAG,EClGH,OAAOoC,OAAW,QCSX,IAAMC,IAAS,IAAM,CAC1B,SAASC,GAA6B,CACpC,IAAMC,EAAMC,GAAQ,OAAO,EACrBC,EAAa,CAAC,IAAM,IAAM,GAAK,KAAM,IAAK,GAAG,EAAE,IAAKC,GAAMA,EAAIH,CAAG,EACjEI,EAAQ,CACZ,kBACA,YACA,QACA,YACA,UACA,YACA,eACF,EACMC,EAAS,CAAC,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,SAAS,EAErFC,EAAqB,CAAC,EACxBC,EAAO,EACX,QAASC,EAAI,EAAGA,EAAIN,EAAW,OAAQM,IACrCF,EAAM,KAAK,CAAE,KAAMF,EAAMI,CAAC,EAAG,IAAKD,EAAM,IAAKL,EAAWM,CAAC,EAAG,MAAOH,EAAOG,CAAC,CAAE,CAAC,EAC9ED,EAAOL,EAAWM,CAAC,EAErB,OAAAF,EAAM,KAAK,CAAE,KAAMF,EAAM,CAAC,EAAG,IAAKG,EAAM,IAAK,IAAU,MAAOF,EAAO,CAAC,CAAE,CAAC,EAClEC,CACT,CAEA,SAASG,GAA0B,CACjC,IAAMP,EAAaD,GAAQ,WAAW,EAChCG,EAAQ,CAAC,WAAY,UAAW,QAAS,YAAa,WAAW,EACjEC,EAAS,CAAC,UAAW,UAAW,UAAW,UAAW,SAAS,EAE/DC,EAAqB,CAAC,EACxBC,EAAO,EACX,QAASC,EAAI,EAAGA,EAAIN,EAAW,OAAQM,IACrCF,EAAM,KAAK,CAAE,KAAMF,EAAMI,CAAC,EAAG,IAAKD,EAAM,IAAKL,EAAWM,CAAC,EAAG,MAAOH,EAAOG,CAAC,CAAE,CAAC,EAC9ED,EAAOL,EAAWM,CAAC,EAErB,OAAAF,EAAM,KAAK,CAAE,KAAMF,EAAM,CAAC,EAAG,IAAKG,EAAM,IAAK,IAAU,MAAOF,EAAO,CAAC,CAAE,CAAC,EAClEC,CACT,CAEA,MAAO,CACL,cAAAP,EACA,WAAAU,CACF,CACF,GAAG,EClCI,IAAMC,GAAU,CACrB,MAAO,CAAE,KAAM,QAAS,MAAO,UAAW,KAAM,OAAQ,EACxD,SAAU,CAAE,KAAM,WAAY,MAAO,UAAW,KAAM,aAAc,EACpE,MAAO,CAAE,KAAM,QAAS,MAAO,UAAW,KAAM,MAAO,EACvD,GAAI,CAAE,KAAM,aAAc,MAAO,UAAW,KAAM,UAAW,EAC7D,QAAS,CAAE,KAAM,UAAW,MAAO,UAAW,KAAM,gBAAiB,EACrE,YAAa,CAAE,KAAM,cAAe,MAAO,UAAW,KAAM,YAAa,EACzE,UAAW,CAAE,KAAM,YAAa,MAAO,UAAW,KAAM,SAAU,EAClE,SAAU,CAAE,KAAM,WAAY,MAAO,YAAa,KAAM,aAAc,EACtE,SAAU,CAAE,KAAM,YAAa,MAAO,UAAW,KAAM,UAAW,EAClE,UAAW,CAAE,KAAM,aAAc,MAAO,UAAW,KAAM,0BAA2B,EACpF,MAAO,CAAE,KAAM,QAAS,MAAO,UAAW,KAAM,UAAW,EAC3D,QAAS,CAAE,KAAM,UAAW,MAAO,UAAW,KAAM,cAAe,EACnE,IAAK,CAAE,KAAM,MAAO,MAAO,UAAW,KAAM,aAAc,CAC5D,EAEaC,GAA4C,CACvD,UAAW,CACT,MAAO,YACP,MAAO,MACP,KAAM,IACN,MAAOD,GAAQ,UAAU,MACzB,KAAM,MACN,KAAMA,GAAQ,UAAU,KACxB,IAAK,CAACE,EAAGC,IAAOA,EAAID,EAAE,QAAQ,CAAC,EAAI,KAAK,MAAMA,CAAC,EAAE,SAAS,EAC1D,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,MAAO,CACL,MAAO,QACP,MAAO,QACP,KAAM,OACN,MAAOF,GAAQ,MAAM,MACrB,KAAM,MACN,KAAMA,GAAQ,MAAM,KACpB,IAAME,IAAOA,EAAI,KAAK,QAAQ,CAAC,EAC/B,QAAUA,IAAOA,EAAI,KAAK,QAAQ,CAAC,EACnC,UAAYA,GAAMA,EAClB,YAAa,CACf,EACA,SAAU,CACR,MAAO,WACP,MAAO,WACP,KAAM,IACN,MAAOF,GAAQ,SAAS,MACxB,KAAM,OACN,KAAMA,GAAQ,SAAS,KACvB,IAAME,GAAMA,EAAE,QAAQ,CAAC,EACvB,QAAUA,GAAMA,EAAE,QAAQ,CAAC,EAC3B,YAAa,CACf,EACA,MAAO,CACL,MAAO,QACP,MAAO,QACP,KAAM,IACN,MAAOF,GAAQ,MAAM,MACrB,KAAM,MACN,KAAMA,GAAQ,MAAM,KACpB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,GAAI,CACF,MAAO,aACP,MAAO,KACP,KAAM,MACN,MAAOF,GAAQ,GAAG,MAClB,KAAM,KACN,KAAMA,GAAQ,GAAG,KACjB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,QAAS,CACP,MAAO,UACP,MAAO,MACP,KAAM,MACN,MAAOF,GAAQ,QAAQ,MACvB,KAAM,MACN,KAAMA,GAAQ,QAAQ,KACtB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,YAAa,CACX,MAAO,OACP,MAAO,OACP,KAAM,QACN,MAAOF,GAAQ,YAAY,MAC3B,KAAM,OACN,KAAMA,GAAQ,YAAY,KAC1B,IAAME,GAAMA,EAAE,QAAQ,CAAC,EACvB,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACvC,YAAa,CACf,EACA,SAAU,CACR,MAAO,YACP,MAAO,gBACP,KAAM,IACN,MAAOF,GAAQ,SAAS,MACxB,KAAM,MACN,KAAMA,GAAQ,SAAS,KACvB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,UAAW,CACT,MAAO,aACP,MAAO,iBACP,KAAM,IACN,MAAOF,GAAQ,UAAU,MACzB,KAAM,MACN,KAAMA,GAAQ,UAAU,KACxB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,MAAO,CACL,MAAO,QACP,MAAO,QACP,KAAM,GACN,MAAOF,GAAQ,MAAM,MACrB,KAAM,KACN,KAAMA,GAAQ,MAAM,KACpB,IAAME,GAAMA,EAAE,QAAQ,CAAC,EACvB,QAAUA,GAAMA,EAAE,QAAQ,CAAC,CAC7B,EACA,QAAS,CACP,MAAO,UACP,MAAO,UACP,KAAM,IACN,MAAOF,GAAQ,QAAQ,MACvB,KAAM,MACN,KAAMA,GAAQ,QAAQ,KACtB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,IAAK,CACH,MAAO,MACP,MAAO,MACP,KAAM,MACN,MAAO,UACP,KAAM,MACN,KAAM,cACN,IAAMA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACvC,YAAa,EACb,QAAS,CAACE,EAAKC,IAAc,CAC3B,IAAMC,EAAM,IAAI,MAAMF,EAAI,MAAM,EAAE,KAAK,IAAI,EAC3C,QAASG,EAAI,EAAGA,EAAIH,EAAI,OAAQG,IAAK,CACnC,IAAMJ,EAAIC,EAAIG,CAAC,EACTC,EAAOJ,EAAIG,EAAI,CAAC,EACtB,GAAIJ,EAAE,KAAO,MAAQK,EAAK,KAAO,MAAQL,EAAE,MAAQ,MAAQK,EAAK,MAAQ,KAAM,CAC5E,IAAMC,EAAKN,EAAE,IAAMK,EAAK,IAClBE,GAAMP,EAAE,KAAOK,EAAK,MAAQ,IAC9BE,EAAK,IAAGJ,EAAIC,CAAC,EAAKE,EAAKC,EAAM,KACnC,CACF,CACA,OAAOL,EAAUC,CAAG,CACtB,CACF,CACF,ECvKO,IAAMK,GAA0C,CACrD,QAAS,CAAE,KAAM,UAAW,KAAM,kBAAmB,cAAe,OAAQ,EAC5E,OAAQ,CAAE,KAAM,SAAU,KAAM,kBAAmB,cAAe,OAAQ,EAC1E,QAAS,CAAE,KAAM,UAAW,KAAM,iBAAkB,cAAe,OAAQ,SAAU,IAAK,EAC1F,SAAU,CAAE,KAAM,WAAY,KAAM,OAAQ,cAAe,OAAQ,SAAU,MAAO,CACtF,EAEO,SAASC,GAAaC,EAA0C,CACrE,GAAI,CAACA,EAAO,MAAO,gBACnB,IAAMC,EAAMD,EAAM,YAAY,EAC9B,OAAOF,GAAOG,CAAG,GAAG,MAAQ,UAC9B,CH8CO,IAAMC,IAAa,IAAM,CAC9B,IAAIC,EAAoB,CAAC,EACrBC,EAAkC,KAClCC,EAAwB,OACxBC,EAA4B,QAC5BC,EAAwC,KACxCC,EAKO,KACPC,EAAwB,GACxBC,EAAyB,GACzBC,EAA6B,IAAI,IAAI,CAAC,WAAW,CAAC,EAClDC,EAAgC,IAAI,IACpCC,EAA+B,IAAI,IAAI,CAAC,QAAS,WAAY,MAAO,aAAa,CAAC,EAClFC,EAAoC,IAAI,IAAI,CAAC,OAAO,CAAC,EACrDC,EAAgB,OAChBC,EAAiC,KACjCC,EAAyB,CAAC,EAG1BC,EAA8B,KAC9BC,EAA2B,KAC3BC,EAAsB,GACtBC,EAAyB,GACzBC,EAA6B,KAC7BC,EAA+B,KAC/BC,EAAwC,KACxCC,EAAmC,KACnCC,EAA8C,KAE9CC,EAAyC,KACzCC,EAAwC,KACxCC,EAAwB,KAGxBC,EAA2D,KAC3DC,GACF,KACEC,EAA4D,KAC5DC,EAAuD,KAErDC,EAAiB,IACjBC,EAA2B,GAC3BC,EAAmB,GACrBC,GAAwB,GACxBC,EAAoC,KACpCC,EAAgC,KAChCC,GAA8B,KAC9BC,GAAiC,KACjCC,GAAkC,KAClCC,GAAgC,KAChCC,GACF,KAGF,SAASC,GACPC,EACAC,EACAC,EACAC,EACA,CACAnB,EAAiBgB,EACjBf,GAAkBgB,EAClBf,EAAYgB,EACZf,EAAgBgB,EAChBV,EAAY,SAAS,eAAe,kBAAkB,EACtDA,GAAW,iBAAiB,SAAU,IAAM,CACtCf,GAAsBE,GAAqBD,GAC7CyB,GAAkB1B,EAAoBE,EAAmBD,CAAe,CAC5E,CAAC,EACDe,GAAU,SAAS,eAAe,aAAa,EAC/CC,GAAa,SAAS,eAAe,iBAAiB,EACtDC,GAAc,SAAS,eAAe,qBAAqB,EAC3DJ,EAAgB,SAAS,eAAe,cAAc,EACtD9B,EAAU2C,GAAM,KAAK,cAAc,EAEnC,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAASC,EAAe,EACpFV,IAAa,UAAU,IAAI,QAAQ,EAGnC,IAAMW,EAAU,IAAI,IAAI,CAAC,IAAK,IAAK,IAAK,GAAG,CAAC,EACtCC,EAAgB,IAAI,IAE1B,SAAS,iBAAiB,UAAYC,GAAM,CAE1C,GADI,CAACpD,EAAM,QAAU,CAACa,GAClB,CAAC,QAAS,WAAY,QAAQ,EAAE,SAAS,SAAS,eAAe,SAAW,EAAE,EAAG,OAErF,IAAMwC,EAAMD,EAAE,IAAI,YAAY,EAC9B,GAAI,CAACF,EAAQ,IAAIG,CAAG,EAAG,OAEvBD,EAAE,eAAe,EACjBD,EAAc,IAAIE,CAAG,EAErB,IAAMC,EAAItD,EAAM,CAAC,EAAE,MACdyB,IAAcA,EAAe,CAAC6B,EAAE,OAAO,EAAG,IAAMA,EAAE,OAAO,EAAG,GAAI,GAErE,GAAI,CAACC,EAAKC,CAAG,EAAI/B,EAEXgC,GADOD,EAAMD,GACK,GAClBG,GAAa,IAEfC,EAASJ,EACXK,GAASJ,EAEX,GAAIH,IAAQ,IAEVM,EAASJ,EAAME,EACfG,GAASJ,EAAMC,UACNJ,IAAQ,IAEjBM,EAASJ,EAAME,EACfG,GAASJ,EAAMC,UACNJ,IAAQ,KAAOA,IAAQ,IAAK,CAErC,IAAMQ,GAASzC,IAAkB,KAAOA,GAAiBmC,EAAMC,GAAO,EAChEM,GAAST,IAAQ,IAAM,EAAIK,GAAa,EAAIA,GAAa,IAC/DC,EAASE,IAAUA,GAASN,GAAOO,GACnCF,GAASC,IAAUL,EAAMK,IAAUC,EACrC,CAGA,IAAMC,GAAQ,CAAC/D,EAAM,CAAC,EAAE,MAAM,CAAC,EAAIA,EAAM,CAAC,EAAE,MAAMA,EAAM,CAAC,EAAE,MAAM,OAAS,CAAC,CAAE,EAC7E,GAAI2D,EAASI,GAAM,CAAC,EAAG,CACrB,IAAMC,GAAID,GAAM,CAAC,EAAIJ,EACrBA,GAAUK,GACVJ,IAAUI,EACZ,CACA,GAAIJ,GAASG,GAAM,CAAC,EAAG,CACrB,IAAMC,GAAIJ,GAASG,GAAM,CAAC,EAC1BJ,GAAUK,GACVJ,IAAUI,EACZ,CACAL,EAAS,KAAK,IAAII,GAAM,CAAC,EAAGJ,CAAM,EAClCC,GAAS,KAAK,IAAIG,GAAM,CAAC,EAAGH,EAAM,EAE9BA,GAASD,EAAS,OACpBlC,EAAe,CAACkC,EAAQC,EAAM,EAC9BK,GAAgBN,EAAQC,GAAQ,EAAI,EAExC,CAAC,EAED,SAAS,iBAAiB,QAAUR,GAAM,CACxC,IAAMC,EAAMD,EAAE,IAAI,YAAY,EAC1BF,EAAQ,IAAIG,CAAG,GAAGF,EAAc,OAAOE,CAAG,CAChD,CAAC,CACH,CAEA,SAASY,GAAgBV,EAAaC,EAAaU,EAAU,GAAO,CAClE,GAAI,CAAClE,EAAM,OAAQ,OACnB,GAAI,CAACkE,EAAS,CACZlE,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAMA,EAAE,SAAS,IAAK,CAAE,IAAAC,EAAK,IAAAC,CAAI,CAAC,CAAC,EAC7D,MACF,CAEA,IAAMW,EAAY3C,EAAgBA,EAAc,CAAC,EAAIxB,EAAM,CAAC,EAAE,MAAM,OAAO,EAAG,IACxEoE,EAAY5C,EAAgBA,EAAc,CAAC,EAAIxB,EAAM,CAAC,EAAE,MAAM,OAAO,EAAG,IAE1E0B,GAAQ,qBAAqBA,CAAM,EAEvC,IAAM2C,EAAO,CAACC,EAAWC,EAAWC,IAAcF,GAAKC,EAAID,GAAKE,EAC1DV,EAAS,IAETW,EAAO,IAAM,CACjB,GAAI,CAAChD,EAAc,OACnB,GAAM,CAACiD,EAAMC,CAAI,EAAIlD,EAEfmD,EAAOP,EAAK7C,EAAe,CAAC,EAAGkD,EAAMZ,CAAM,EAC3Ce,EAAOR,EAAK7C,EAAe,CAAC,EAAGmD,EAAMb,CAAM,EAEjD9D,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAM,CAC9BA,EAAE,SAAS,IAAK,CAAE,IAAKsB,EAAM,IAAKC,CAAK,CAAC,CAC1C,CAAC,EAEG,KAAK,IAAID,EAAOF,CAAI,EAAI,MAAU,KAAK,IAAIG,EAAOF,CAAI,EAAI,KAC5DjD,EAAS,sBAAsB+C,CAAI,EAChC/C,EAAS,IAChB,EACAA,EAAS,sBAAsB+C,CAAI,CACrC,CAGA,SAASK,EAAUC,EAAkBC,EAAsB,CAAC,EAAGC,EAAc,GAAO,CAClF9D,EAAc,KACdJ,EAAe,KACfC,EAAY,KACZF,EAAYkE,EAGZvE,EAAmB,IAAI,IACrB,OAAO,QAAQyE,EAAO,EACnB,OAAO,CAAC,CAAC,CAAEC,CAAG,IAAMJ,EAAM,OAAO,KAAMK,GAAMA,EAAED,EAAI,KAAK,GAAK,IAAI,CAAC,EAClE,IAAI,CAAC,CAAC9B,CAAG,IAAMA,CAAG,CACvB,EAGI7C,EAAc,OAAS,IACzBA,EAAgB,IAAI,IAAI,CAAC,WAAW,EAAE,OAAQ6E,GAAM5E,EAAiB,IAAI4E,CAAC,CAAC,CAAC,GAI9E,SAAS,iBAAiB,cAAc,EAAE,QAASC,GAAO,CACxD,IAAMC,EAAOD,EACPE,EAASD,EAAK,QAAQ,OACtBE,EAAchF,EAAiB,IAAI+E,CAAM,EAC/CD,EAAK,UAAU,OAAO,SAAUE,GAAejF,EAAc,IAAIgF,CAAM,CAAC,EACxED,EAAK,UAAU,OAAO,WAAY,CAACE,CAAW,CAChD,CAAC,EAED5E,EAAekE,EACXE,EACFS,GAAYX,CAAK,EAEjBY,GAAO,CAEX,CAEA,SAASC,GAAQ,CACfzE,EAAc,KACdJ,EAAe,KACfC,EAAY,KACZH,EAAe,KACfgF,GAAa,EACTxD,KACFA,GAAQ,MAAM,QAAU,OACxBA,GAAQ,UAAY;AAAA;AAAA;AAAA,SAKtB,IAAMyD,EAAa,SAAS,eAAe,aAAa,EACpDA,GAAYA,EAAW,UAAU,IAAI,QAAQ,EACjDC,EAAoB,EACpBvD,GAAiB,KACbC,IAAoBA,GAAmB,IAAI,CACjD,CAEA,SAASuD,IAAa,CAChBtE,IAAW,OACb,qBAAqBA,CAAM,EAC3BA,EAAS,MAEXlB,EAAgB,IAAI,IAAI,CAAC,WAAW,CAAC,EACrCC,EAAmB,IAAI,IACvBC,EAAkB,IAAI,IAAI,CAAC,QAAS,WAAY,MAAO,aAAa,CAAC,EACrEC,EAAuB,IAAI,IAAI,CAAC,OAAO,CAAC,EACxCC,EAAQ,OACRE,EAAY,CAAC,EACbU,EAAgB,KAChBC,EAAe,KACfL,EAAgB,KAChBC,EAAqB,KACrBC,EAAkB,KAClBC,EAAoB,KACpBW,GAAe,GACf0D,EAAM,EACN,SAAS,iBAAiB,4BAA4B,EAAE,QAASN,GAAO,CACtE,IAAMC,EAAOD,EACbC,EAAK,UAAU,OAAO,SAAU/E,EAAc,IAAI+E,EAAK,QAAQ,MAAO,CAAC,EACvEA,EAAK,UAAU,OAAO,WAAY,iBAAiB,CACrD,CAAC,EACD,IAAMU,EAAa,SAAS,eAAe,eAAe,EACtDA,GAAYA,EAAW,UAAU,IAAI,QAAQ,EACjD,IAAMC,EAAU,SAAS,eAAe,eAAe,EACnDA,GAASA,EAAQ,UAAU,OAAO,WAAW,EACjD,SAAS,iBAAiB,uBAAuB,EAAE,QAAS3B,GAAM,CAChEA,EAAE,UAAU,OAAO,SAAWA,EAAkB,QAAQ,OAAS,MAAM,CACzE,CAAC,CACH,CAEA,SAAS4B,GAAa9C,EAAa,CAC7B7C,EAAc,IAAI6C,CAAG,EAAG7C,EAAc,OAAO6C,CAAG,EAC/C7C,EAAc,IAAI6C,CAAG,EACtBxC,GAAc8E,GAAO,EAAI,CAC/B,CAEA,SAASS,EAAiBC,EAAgB,CACxC7F,EAAgB,IAAI,IAAI6F,CAAI,EACxBxF,GAAc8E,GAAO,EAAI,EAE7B,SAAS,iBAAiB,cAAc,EAAE,QAASL,GAAO,CACxD,IAAMC,EAAOD,EACbC,EAAK,UAAU,OAAO,SAAU/E,EAAc,IAAI+E,EAAK,QAAQ,MAAO,CAAC,CACzE,CAAC,CACH,CAEA,SAASe,GAASC,EAAc,CAC9B,GAAI3F,IAAU2F,GAAQ,CAAC1F,EAAc,CACnCD,EAAQ2F,EACR,MACF,CAEA,IAAMC,EAAM3F,EAAa,OACnB4F,EAAKD,EAAI,KAAMpB,GAAMA,EAAE,MAAQ,IAAI,GAAG,MAAQ,EAG9CsB,EAAWC,GAAuB,CACtC,GAAIA,IAAQ,KAAM,OAAO,KAEzB,IAAIC,EAAM,EACV,GAAIhG,IAAU,WAAY,CACxB,IAAMiG,EAAUF,EAAM,IACtBC,EAAMJ,EAAI,UAAWpB,IAAOA,EAAE,MAAQ,IAAMyB,CAAO,CACrD,KAAO,CACL,IAAMC,EAAUL,EAAKE,EAAM,IAC3BC,EAAMJ,EAAI,UAAWpB,IAAOA,EAAE,MAAQ,IAAM0B,CAAO,CACrD,CAIA,OAHIF,IAAQ,KAAIA,EAAMJ,EAAI,OAAS,GAG/BD,IAAS,YAAoBC,EAAII,CAAG,EAAE,MAAQ,GAAK,MACzCJ,EAAII,CAAG,EAAE,MAAQH,GAAMA,GAAM,GAC7C,EAGI1F,IAAiB,OAAMA,EAAe2F,EAAQ3F,CAAY,GAC1DC,IAAc,OAAMA,EAAY0F,EAAQ1F,CAAS,GAGrD,IAAI+F,EAAoC,KACxC,GAAI/G,EAAM,OAAQ,CAChB,IAAMsD,EAAItD,EAAM,CAAC,EAAE,MACbgH,EAAKN,EAAQpD,EAAE,OAAO,EAAG,GAAI,EAC7B2D,EAAKP,EAAQpD,EAAE,OAAO,EAAG,GAAI,EAC/B0D,IAAO,MAAQC,IAAO,OAAMF,EAAW,CAACC,EAAIC,CAAE,EACpD,CAEArG,EAAQ2F,EACRZ,GAAO,EAAI,EAGPoB,IACFzG,EAAe,GACfN,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAM,CAC9BA,EAAE,MAAM,IAAMA,EAAE,SAAS,IAAK,CAAE,IAAKyD,EAAU,CAAC,EAAG,IAAKA,EAAU,CAAC,CAAE,CAAC,CAAC,CACzE,CAAC,EACDzG,EAAe,GAEnB,CAEA,SAAS4G,IAAc,CACrBhF,GAAe,CAACA,GAChBlC,EAAM,QAAQ,CAAC,CAAE,QAAAmH,CAAQ,IAAMA,EAAQ,UAAU,OAAO,UAAWjF,EAAY,CAAC,EAChFkF,GAAO,CACT,CAEA,SAASC,GAAoBC,EAAoE,CAC/F7E,GAAqB6E,CACvB,CAEA,SAASC,GAAelE,EAAoB,CACtCb,KAAmBa,GAAOA,IAAQ,MACpCb,GAAiB,KACjBgF,GAAoB,EAChB/E,IAAoBA,GAAmB,IAAI,IAE/CD,GAAiBa,EACjBmE,GAAoB,EACpBC,GAAgB,GAGd5G,GAAc8E,GAAO,EAAI,CAC/B,CAEA,SAAS6B,IAAsB,CAC7B,SAAS,iBAAiB,gBAAgB,EAAE,QAASlC,GAAO,CAC1D,IAAMf,EAAIe,EACVf,EAAE,UAAU,OAAO,SAAUA,EAAE,QAAQ,SAAW/B,EAAc,CAClE,CAAC,CACH,CAEA,SAASiF,IAAkB,CACzB,GAAI,CAAChF,IAAsB,CAACD,IAAkB,CAAC3B,EAAc,OAC7D,IAAM6G,EAAO1H,EAAM,KAAMoF,GAAMA,EAAE,YAAc5C,EAAc,EAC7D,GAAI,CAACkF,EAAM,OACX,IAAMC,EAASC,GAAoBpF,GAAgBkF,EAAK,KAAK,EAC7DjF,GAAmB,CAAE,IAAK5B,EAAa,OAAQ,OAAA8G,CAAO,CAAC,CACzD,CAEA,SAASC,GAAoBvE,EAAawE,EAAoC,CAC5E,IAAMC,EAAOD,EAAM,OAAQE,GAAmBA,GAAK,MAAQ,SAASA,CAAC,CAAC,EACtE,GAAI,CAACD,EAAK,OAAQ,OAAOD,EAAM,IAAI,IAAM,SAAS,EAClD,IAAMtE,EAAM,KAAK,IAAI,GAAGuE,CAAI,EAC1BtE,EAAM,KAAK,IAAI,GAAGsE,CAAI,EAElBE,EAAQnH,GAAc,MACtBoH,EAAWD,EAAQE,GAAOF,EAAM,YAAY,CAAC,EAAI,KACjDG,EAAcF,GAAU,eAAiB,QAEzCG,EADWC,GAAS,IAAI,EACM,YAAcF,EAC5CG,EAAWL,GAAU,UAAY,KAEvC,OAAOJ,EAAM,IAAKE,GAAM,CACtB,GAAIA,GAAK,MAAQ,CAAC,SAASA,CAAC,EAAG,MAAO,UACtC,GAAI1E,IAAQ,WAAY,OAAOkF,GAAcR,CAAC,EAC9C,GAAI1E,IAAQ,QAAS,CACnB,GAAI+E,IAAc,OAAQ,CACxB,IAAMI,IAASF,IAAa,KAAO,IAAO,KAAOP,EACjD,OAAOU,GAAWD,EAAK,CACzB,CACA,OAAOC,GAAWV,CAAC,CACrB,CACA,IAAMvD,EAAIhB,IAAQD,EAAM,GAAM,KAAK,IAAI,EAAG,KAAK,IAAI,GAAIwE,EAAIxE,IAAQC,EAAMD,EAAI,CAAC,EAC9E,OAAIiB,GAAK,IAAakE,GAAQ,UAAW,UAAWlE,EAAI,GAAI,EACxDA,GAAK,GAAYkE,GAAQ,UAAW,WAAYlE,EAAI,KAAQ,GAAI,EAChEA,GAAK,IAAakE,GAAQ,UAAW,WAAYlE,EAAI,IAAO,GAAI,EAC7DkE,GAAQ,UAAW,WAAYlE,EAAI,KAAQ,GAAI,CACxD,CAAC,CACH,CAEA,SAASmE,GAAY,CACnB1F,GAAgB,CAClB,CAEA,SAASA,IAAkB,CACzBlC,EAAe,KACfC,EAAY,KACZG,EAAc,KACVW,GAAeA,EAAc,IAAI,EAGrC9B,EAAM,QAASoF,GAAM,CACnBA,EAAE,YAAc,IAClB,CAAC,EAEDwD,GAAiB,EACjBC,GAAiB,EAGjBvI,EAAe,GACfN,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,MAAAwF,CAAM,IAAM,CACrCxF,EAAE,MAAM,IAAMA,EAAE,SAAS,IAAK,CAAE,IAAKwF,EAAM,CAAC,EAAI,IAAKA,EAAMA,EAAM,OAAS,CAAC,CAAG,CAAC,CAAC,EAChFxF,EAAE,UAAU,kBAAkBwF,EAAM,CAAC,EAAIA,EAAMA,EAAM,OAAS,CAAC,CAAE,CACnE,CAAC,EACDxI,EAAe,GAEXsB,IAAiBA,GAAgB,KAAM,KAAMhB,CAAK,CACxD,CAEA,SAASmI,GAAkBC,EAAmB,CAC5C,GAAI,CAAC1G,GAAY,OACjB,IAAM2G,EAAM,CAACC,EAAYvC,IAAgB,CACvC,IAAMrB,EAAK,SAAS,cAAc,IAAI4D,CAAE,cAAc,EAClD5D,IAAIA,EAAG,YAAcqB,EAC3B,EACAsC,EACE,eACAD,EAAM,WAAa,KAAO,IAAIA,EAAM,UAAY,KAAM,QAAQ,CAAC,CAAC,MAAQ,QAC1E,EACAC,EAAI,eAAgBD,EAAM,UAAY,KAAOG,GAAQ,KAAK,MAAMH,EAAM,SAAW,GAAI,CAAC,EAAI,QAAG,EAC7FC,EAAI,gBAAiBD,EAAM,UAAY,KAAO,GAAG,KAAK,MAAMA,EAAM,QAAQ,CAAC,KAAO,QAAG,EACrFC,EACE,gBACAD,EAAM,UAAY,KAAO,IAAIA,EAAM,SAAW,KAAK,QAAQ,CAAC,CAAC,QAAU,QACzE,EACAC,EAAI,gBAAiBD,EAAM,UAAY,KAAO,GAAGA,EAAM,QAAQ,KAAO,QAAG,EACzEC,EAAI,aAAcD,EAAM,OAAS,KAAO,GAAGA,EAAM,KAAK,OAAS,QAAG,EAClEC,EAAI,eAAgBD,EAAM,SAAW,KAAO,GAAGA,EAAM,QAAQ,QAAQ,CAAC,CAAC,SAAQ,QAAG,EAClF1G,GAAW,UAAU,OAAO,QAAQ,EAChCC,IAAaA,GAAY,UAAU,OAAO,QAAQ,CACxD,CAEA,SAASwD,GAAsB,CACzBzD,IAAYA,GAAW,UAAU,IAAI,QAAQ,EAC7CC,IAAaA,GAAY,UAAU,IAAI,QAAQ,EACnD,CACE,eACA,eACA,gBACA,gBACA,gBACA,aACA,cACF,EAAE,QAAS2G,GAAO,CAChB,IAAM5D,EAAK,SAAS,cAAc,IAAI4D,CAAE,cAAc,EAClD5D,IAAIA,EAAG,YAAc,KAC3B,CAAC,CACH,CAIA,SAAS8D,GAAiB1E,EAAcC,EAAcM,EAAc,GAAO,CACzE,GAAI,CAACpE,EAAc,OACnB,IAAM2F,EAAM3F,EAAa,OACnB4F,EAAKD,EAAI,KAAMpB,GAAMA,EAAE,MAAQ,IAAI,GAAG,MAAQ,EAC9CiE,IAAkB7C,EAAIA,EAAI,OAAS,CAAC,GAAG,MAAQ,GAAKC,GAAM,IAG5D/B,EAAO,OAAMA,GAAQA,EAAO+B,GAAM,KAClC9B,EAAO,OAAMA,GAAQA,EAAO8B,GAAM,KAGtC/B,EAAO,KAAK,IAAI,EAAG,KAAK,IAAIA,EAAM2E,CAAa,CAAC,EAChD1E,EAAO,KAAK,IAAI,EAAG,KAAK,IAAIA,EAAM0E,CAAa,CAAC,EAEhD,IAAM3C,EAAW4C,GAAoB,CACnC,GAAI1I,IAAU,OAAQ,OAAO0I,EAC7B,IAAMxC,EAAUL,EAAK6C,EAAU,IAC3B1C,EAAMJ,EAAI,UAAWpB,IAAOA,EAAE,MAAQ,IAAM0B,CAAO,EACvD,OAAIF,IAAQ,KAAIA,EAAMJ,EAAI,OAAS,IAC3BA,EAAII,CAAG,EAAE,MAAQ,GAAK,GAChC,EAEM2C,EAAO7C,EAAQhC,CAAI,EACnB8E,EAAO9C,EAAQ/B,CAAI,EAEzB5D,EAAewI,EACfvI,EAAYwI,EACZhI,EAAgB,CAAC+H,EAAMC,CAAI,EACvB,CAAAvE,IACJ3E,EAAe,GACfN,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAM,CAC9BA,EAAE,MAAM,IAAMA,EAAE,SAAS,IAAK,CAAE,IAAKiG,EAAM,IAAKC,CAAK,CAAC,CAAC,CACzD,CAAC,EACDlJ,EAAe,GACfmJ,GAAkB,EAClBZ,GAAiB,EACnB,CAEA,SAASzB,IAAS,CAChB,GAAI,CAACpH,EAAM,QAAU,CAACoC,EAAW,OACjC,IAAMsH,EAAI,KAAK,MACb,KAAK,IACH,IACAtH,EAAU,sBAAsB,EAAE,MAChCJ,GACCE,GAAeH,EAASE,EAAW,EACxC,CACF,EACI0H,EAAa,GACjB3J,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,WAAAsG,EAAY,SAAAC,CAAS,IAAM,CAChDH,IAAMpG,EAAE,QACVA,EAAE,QAAQ,CAAE,MAAOoG,EAAG,OAAQpG,EAAE,MAAO,CAAC,EACxCqG,EAAa,GACTzH,IAAgB0H,GAAcC,GAAUC,GAAcF,EAAYC,EAAUvG,EAAE,MAAM,EAE5F,CAAC,EACGqG,GAAYf,GAAiB,CACnC,CAGA,SAASjD,GAAOoE,EAAY,GAAO,CACjC,IAAIC,EAAsC,KACtCC,EAAc,EAGlB,GAFIF,GAAa3H,IAAW6H,EAAc7H,EAAU,WAEhD2H,GAAavI,EACfwI,EAAa,CAACxI,EAAc,CAAC,EAAGA,EAAc,CAAC,CAAC,UACvCuI,GAAa/J,EAAM,OAAQ,CACpC,IAAMsD,GAAItD,EAAM,CAAC,EAAE,MACnBgK,EAAa,CAAC1G,GAAE,OAAO,EAAG,IAAMA,GAAE,OAAO,EAAG,GAAI,CAClD,CAEA,GAAI,CAACzC,EAAc,CACjBgF,GAAakE,CAAS,EACtB,MACF,CACA,IAAMvD,EAAM3F,EAAa,OACzB,GAAI,CAAC2F,EAAI,OAAQ,CACfX,GAAakE,CAAS,EACtB,MACF,CAEA,IAAM/B,EAAQnH,GAAc,MACtBoH,EAAWD,EAAQE,GAAOF,EAAM,YAAY,CAAC,EAAI,KACjDG,EAAcF,GAAU,eAAiB,QAEzCG,EADWC,GAAS,IAAI,EACM,YAAcF,EAC5CG,EAAWL,GAAU,UAAY,KAEjCiC,EAAY,CAAC,GAAG1J,CAAa,EAAE,OAAQ6E,IAC3CmB,EAAI,KAAMpB,IAAMA,GAAEF,GAAQG,EAAC,EAAE,KAAK,GAAK,IAAI,CAC7C,EACA,GAAI,CAAC6E,EAAU,OAAQ,CACrBrE,GAAakE,CAAS,EAClB1H,KACFA,GAAQ,MAAM,QAAU,OACxBA,GAAQ,UAAY;AAAA;AAAA;AAAA,WAKtB,MACF,CACIA,KAASA,GAAQ,MAAM,QAAU,QAErC,IAAM8H,EAAa/H,EAAYA,EAAU,sBAAsB,EAAE,MAAQ,IACnEsH,EAAI,KAAK,MACb,KAAK,IAAI,IAAKS,EAAanI,GAAoBE,GAAeH,EAASE,EAAW,EAAE,CACtF,EAEMmI,GACJL,GACA9J,IAAkBY,GAClBX,IAAkBU,GAClBT,IAAsBiI,GACtBhI,IAA2BoC,IAC3BxC,EAAM,OAAS,EAEb8I,EACJ,GAAIsB,GACFtB,EAAQ9I,EAAM,CAAC,EAAE,cACRY,IAAU,WACnBkI,EAAQtC,EAAI,IAAKpB,KAAOA,GAAE,MAAQ,GAAK,GAAI,MACtC,CACL,IAAMqB,GAAKD,EAAI,KAAMpB,IAAMA,GAAE,MAAQ,IAAI,GAAG,MAAQ,EAChDiF,GAAa,EACjBvB,EAAQtC,EAAI,IAAKpB,KACXA,GAAE,MAAQ,OACZiF,IAAcjF,GAAE,KAAOqB,IAAM,KACtB4D,GAGV,CACH,CAEA,IAAMC,GAAgB,IAAI,IAC1B,GAAIF,GAAU,CACRjI,IAAeA,EAAc,MAAM,QAAU,QACjD,IAAMoI,GAAW,IAAI,IAAIL,CAAS,EAClC,QAAW9E,MAAKpF,EAAO,CACrB,IAAMwK,GAAa9J,EAAgB,IAAI0E,GAAE,SAAS,EAC5CqF,GAAY9J,EAAqB,IAAIyE,GAAE,SAAS,EAEpDmF,GAAS,IAAInF,GAAE,SAAS,GACxBA,GAAE,WAAaoF,IACfpF,GAAE,UAAYqF,IACdrF,GAAE,IAAMsE,EAERY,GAAc,IAAIlF,GAAE,UAAWA,EAAC,GAEhC/E,EAAS,MAAM+E,GAAE,KAAK,EACtBA,GAAE,MAAM,QAAQ,EAChBA,GAAE,IAAI,OAAO,EAEjB,CACApF,EAAQ,CAAC,CACX,MACE6F,GAAakE,CAAS,EAGxB,GAAI3H,EAAW,CACb,IAAMsI,GAA0C,IAAI,MAAMR,EAAU,MAAM,EAAE,KAAK,IAAI,EACjFS,GAAmC,KACvC,QAASC,GAAIV,EAAU,OAAS,EAAGU,IAAK,EAAGA,KAAK,CAC9CF,GAAgBE,EAAC,EAAID,GACrB,IAAME,GAAKP,GAAc,IAAIJ,EAAUU,EAAC,CAAC,EACrCC,KAAIF,GAAeE,GAAG,IAC5B,CAEAX,EAAU,QAAQ,CAAC7G,GAAKuD,KAAQ,CAC9B,IAAMkE,GAASR,GAAc,IAAIjH,EAAG,EACpC,GAAIyH,GAAQ,CACV9K,EAAM,KAAK8K,EAAM,EACjB,IAAMC,GAAQD,GAAO,MACfE,GAAKD,GAAc,SACnBE,GAAW3K,EACjBA,EAAe,GACfyK,GAAM,MAAM,IAAM,CAEdf,IACCe,GAAM,OAAO,EAAG,MAAQf,EAAW,CAAC,GAAKe,GAAM,OAAO,EAAG,MAAQf,EAAW,CAAC,GAE9Ee,GAAM,SAAS,IAAK,CAAE,IAAKf,EAAW,CAAC,EAAG,IAAKA,EAAW,CAAC,CAAE,CAAC,GAE9DgB,IAAG,kBAAkBD,GAAM,OAAO,EAAG,IAAMA,GAAM,OAAO,EAAG,IAAMA,EAAK,EACtEA,GAAM,OAAO,EAAK,EAEtB,CAAC,EACDzK,EAAe2K,GAEf,IAAIC,GAA+B,KACnC,GACE/J,GAAe,MACf2J,GAAO,MAAM3J,CAAW,GAAK,MAC7B2J,GAAO,MAAM3J,CAAW,GAAK,OAE7BgK,GAAcL,GAAO,QAAQ,EACzBA,GAAO,SAAS,KAAO,MAAQA,GAAO,SAAS,KAAO,MAAM,CAC9D,IAAMM,GAAON,GAAO,SAAS,IAAMA,GAAO,SAAS,KAAO,EAC1DI,GAAgB,KAAK,IACnBJ,GAAO,SAAS,KAAO,EACvB,KAAK,OACDA,GAAO,MAAM3J,CAAW,EAAK2J,GAAO,SAAS,KAAOM,GACpDN,GAAO,SAAS,IACpB,CACF,EACAA,GAAO,aAAeA,GAAO,MAAM3J,CAAW,CAChD,CAEF2I,GAAcgB,GAAO,WAAYA,GAAO,SAAU,IAAKI,EAAa,EACpE,MACF,CAEA,IAAI/F,GAAMD,GAAQ7B,EAAG,EAEjBgI,GAAYlG,GAAI,UAChB8D,GAAM9D,GAAI,IACVmG,GAAUnG,GAAI,QACdoG,GAAOpG,GAAI,KACXqG,GAAQrG,GAAI,MAEZ9B,KAAQ,SAAW+E,IAAc,SACnCoD,GAAQ,OACRD,GAAO,OAAOjD,CAAQ,GACtBW,GAAOlB,IAAM0D,GAAQ1D,EAAC,EACtBuD,GAAWvD,IAAM0D,GAAQ1D,EAAC,EAC1BsD,GAAatD,IACPA,IAAK,MAAQA,GAAI,GAAY,MACzBO,IAAa,KAAO,IAAO,KAAOP,GAG5C5C,GAAM,CAAE,GAAGA,GAAK,MAAAqG,GAAO,KAAAD,GAAM,IAAAtC,GAAK,QAAAqC,GAAS,UAAAD,EAAU,GAGvD,IAAIxD,GAAQ1C,GAAI,QACZA,GAAI,QAAQqB,EAAKkF,EAAS,EAC1BA,GACElF,EAAI,IAAKpB,IAAM,CACb,IAAM2C,GAAI3C,GAAED,GAAI,KAAK,EACrB,OAAO4C,IAAK,MAAQsD,GAAYA,GAAUtD,EAAC,EAAIA,EACjD,CAAC,CACH,EAEArH,EAAgB,IAAI2C,EAAG,IAAGwE,GAAQ8D,GAAe9D,GAAO1C,GAAI,aAAe,CAAC,GAEhFyG,GAAYvI,GAAK8B,GAAK2D,EAAOjB,GAAO6B,EAAGlD,EAAKwD,EAAYU,GAAgB9D,EAAG,CAAC,CAC9E,CAAC,CACH,CAEA3G,EAAgBY,EAChBX,EAAgBU,EAChBT,EAAoBiI,EACpBhI,EAAyBoC,GAEzBkD,GAAY7E,CAAY,EAEpBE,GAAgB,MAAQC,GAAa,MAAMyI,GAAkB,EAEjEjC,GAAoB,EAChBhF,IAAgBiF,GAAgB,EAEhCsC,GAAa3H,GAAa6H,EAAc,IAAG7H,EAAU,UAAY6H,EACvE,CAGA,SAAS2B,GACPC,EACA1G,EACA2D,EACAjB,EACA6B,EACAlD,EACAsF,EAAwC,KACxCC,EAAqC,KACrC,CACA,IAAM/D,EAAQnH,GAAc,MAEtBsH,GADWH,EAAQE,GAAOF,EAAM,YAAY,CAAC,EAAI,OACzB,eAAiB,QAEzCI,EADWC,GAAS,IAAI,EACM,YAAcF,EAG5C6D,GAAWH,IAAc,YAAcI,GAAezF,EAAK,EAAE,EAAI,KACjE0F,EAAM,SAAS,cAAc,KAAK,EACxCA,EAAI,UAAY,YAChBA,EAAI,QAAQ,OAASL,EACrBK,EAAI,MAAM,YAAY,gBAAiB/G,EAAI,KAAK,EAGhD,IAAMgH,GAAS,SAAS,cAAc,KAAK,EAC3CA,GAAO,UAAY,mBAAmBjK,GAAe,kBAAoB,EAAE,GAE3E,IAAMkK,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,wBACpBA,GAAQ,UAAY;AAAA,mFAC2DjH,EAAI,KAAK,KAAKA,EAAI,IAAI;AAAA,sCACnEA,EAAI,KAAK;AAAA,MAI3C,IAAMkH,GAAY,SAAS,cAAc,QAAQ,EACjDA,GAAU,UAAY,2BAA2B3L,EAAgB,IAAImL,CAAS,EAAI,UAAY,EAAE,GAChGQ,GAAU,MAAQ,wBAClBA,GAAU,UAAY,0CAA0C3L,EAAgB,IAAImL,CAAS,EAAI,UAAY,UAAU,UACvHQ,GAAU,iBAAiB,QAAUjJ,IAAM,CACzCA,GAAE,gBAAgB,EACd1C,EAAgB,IAAImL,CAAS,EAAGnL,EAAgB,OAAOmL,CAAS,EAC/DnL,EAAgB,IAAImL,CAAS,EAElClG,GAAO,EAAI,CACb,CAAC,EAED,IAAM2G,GAAc,SAAS,cAAc,QAAQ,EAEnDA,GAAY,UAAY,yBAAyB9J,KAAmBqJ,EAAY,UAAY,EAAE,GAC9FS,GAAY,QAAQ,OAAST,EAC7BS,GAAY,MAAQ,iCACpBA,GAAY,UAAY,yDACxBA,GAAY,iBAAiB,QAAS,IAAM/E,GAAesE,CAAS,CAAC,EAGrE,IAAIU,GAAoC,KACxC,GAAIV,IAAc,WAAaA,IAAc,SAAWA,IAAc,QAAS,CAC7EU,GAAU,SAAS,cAAc,QAAQ,EACzC,IAAMC,GAAU7L,EAAqB,IAAIkL,CAAS,EAClDU,GAAQ,UAAY,gBAAgBC,GAAU,UAAY,EAAE,GAC5DD,GAAQ,MAAQC,GAAU,+BAAiC,+BAC3DD,GAAQ,UAAY,0CAA0CC,GAAU,gBAAkB,YAAY,UACtGD,GAAQ,iBAAiB,QAAUnJ,IAAM,CACvCA,GAAE,gBAAgB,EACdzC,EAAqB,IAAIkL,CAAS,EAAGlL,EAAqB,OAAOkL,CAAS,EACzElL,EAAqB,IAAIkL,CAAS,EACvClG,GAAO,EAAI,CACb,CAAC,CACH,CAEA,IAAM8G,GAAe,SAAS,cAAc,KAAK,EACjDA,GAAa,UAAY,oBAEzB,IAAMC,GAAa,SAAS,cAAc,KAAK,EAC/CA,GAAW,UAAY,wBAEvB,IAAMC,GAAiB,SAAS,cAAc,KAAK,EACnDA,GAAe,UAAY,4BAC3BA,GAAe,OAAOF,GAAcC,EAAU,EAE9C,IAAME,GAAY,SAAS,cAAc,KAAK,EAC9CA,GAAU,UAAY,oBACtBA,GAAU,OAAOP,GAAWC,EAAW,EAEvC,IAAMO,GAAiB,SAAS,cAAc,KAAK,EAGnD,GAFAA,GAAe,UAAY,0BAEvBhB,IAAc,QAAS,CACzB,IAAMiB,GAAa,SAAS,cAAc,KAAK,EAC/CA,GAAW,UAAY,WACvBA,GAAW,UAAY;AAAA,iCACI1E,IAAc,QAAU,SAAW,EAAE;AAAA,iCACrCA,IAAc,OAAS,SAAW,EAAE;AAAA,QAE/D0E,GAAW,iBAAiB,QAAU1J,IAAM,CAC1C,IAAM2J,GAAO3J,GAAE,OAAuB,QAAQ,UAAU,EACxD,GAAI,CAAC2J,GAAK,OACV,IAAMC,GAAOD,GAAI,QAAQ,KACzB,GAAIC,KAAS,SAAWA,KAAS,OAAQ,CACvC,IAAMC,GAAYD,KAAS7E,EAC3BE,GAAS,MAAM,CAAE,WAAY4E,GAAY,KAAOD,EAAK,CAAC,EACtDrH,GAAO,EAAI,CACb,CACF,CAAC,EACDkH,GAAe,OAAOC,EAAU,CAClC,CAEIP,IAASM,GAAe,OAAON,EAAO,EAE1CJ,GAAO,OAAOC,GAASQ,GAAWD,GAAgBE,EAAc,EAEhE,IAAMK,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,iBAEpB,IAAMC,GAAS,SAAS,cAAc,KAAK,EAC3CA,GAAO,MAAM,SAAW,WACxBD,GAAQ,YAAYC,EAAM,EAE1B,IAAMC,GAAgB,SAAS,cAAc,KAAK,EAClDA,GAAc,UAAY,4BAC1B,IAAMC,GAAgB,SAAS,cAAc,KAAK,EAClDA,GAAc,UAAY,4BAC1BF,GAAO,OAAOC,GAAeC,EAAa,EAE1C,IAAMlG,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,WAAWjF,GAAe,WAAa,EAAE,GAC7D,IAAM0H,GAAa,SAAS,cAAc,QAAQ,EAClDA,GAAW,UAAY,cACvBzC,GAAQ,YAAYyC,EAAU,EAC9BsD,GAAQ,YAAY/F,EAAO,EAE3B+E,EAAI,OAAOC,GAAQe,EAAO,EAE1B,IAAMI,GAAa1M,IAAU,WAE7B,SAAS2M,GAAQxF,GAAWyF,GAAuB,CACjD,GAAIzF,IAAK,KAAM,MAAO,GACtB,GAAIuF,GAAY,CACd,IAAMG,GAAMD,GAAQ,EAAI,EAAIA,GAAQ,EAAI,EAAIA,GAAQ,GAAK,EAAI,EAC7D,MAAO,GAAGzF,GAAE,QAAQ0F,EAAG,CAAC,KAC1B,KAAO,CACL,IAAMC,GAAO,KAAK,IAAI3F,EAAC,EACjB4F,GAAI,KAAK,MAAMD,GAAO,IAAI,EAC1BrI,GAAI,KAAK,MAAOqI,GAAO,KAAQ,EAAE,EACjC1C,GAAI,KAAK,MAAM0C,GAAO,EAAE,EACxBE,GAAKD,GAAI,EAAI,GAAGA,EAAC,IAAM,GACvBE,GAAKF,GAAI,EAAI,OAAOtI,EAAC,EAAE,SAAS,EAAG,GAAG,EAAI,OAAOA,EAAC,EAClDyI,GAAK,OAAO9C,EAAC,EAAE,SAAS,EAAG,GAAG,EACpC,MAAO,GAAGjD,GAAI,EAAI,IAAM,EAAE,GAAG6F,EAAE,GAAGC,EAAE,IAAIC,EAAE,EAC5C,CACF,CAEA,IAAMC,GACJpN,EAAqB,IAAIkL,CAAS,GACjCA,IAAc,SAAWA,IAAc,WAAaA,IAAc,QAGjEmC,GAAO,IACTC,GAAO,KACPC,GAAS,EACTC,GAAW,EACXC,GAAU,IACVC,GAAU,KACVC,GAAU,EACVC,GAAY,EACd,QAAS3D,GAAI,EAAGA,GAAI/C,EAAM,OAAQ+C,KAAK,CACrC,IAAM7C,GAAIF,EAAM+C,EAAC,EACb7C,IAAK,MAAQ,CAAC,SAASA,EAAC,IACxBA,GAAIiG,KAAMA,GAAOjG,IACjBA,GAAIkG,KAAMA,GAAOlG,IACrBmG,IAAUnG,GACVoG,MACIpG,KAAM,GAAKgG,MACThG,GAAIqG,KAASA,GAAUrG,IACvBA,GAAIsG,KAASA,GAAUtG,IAC3BuG,IAAWvG,GACXwG,MAEJ,CACIJ,KAAa,IACfH,GAAO,EACPC,GAAO,KAET,IAAMO,GAAeL,GAAW,CAAE,IAAKH,GAAM,IAAKC,GAAM,IAAKC,GAASC,EAAS,EAAI,KAC7EM,GAAoBF,GACtB,CAAE,IAAKH,GAAS,IAAKC,GAAS,IAAKC,GAAUC,EAAU,EACvD,KACEG,GAAO,KAAK,IAAIT,GAAOD,EAAI,EAAI,IAAO,EACtCW,GAAc,CAACX,GAAOU,GAAMT,GAAOS,EAAI,EAEzCE,GAAwB,GAG5B,SAASC,GAAkBC,GAAoBC,GAAoBzL,GAAW,CAC5E,IAAMkJ,GACJ7L,EAAqB,IAAIkL,CAAS,GACjCA,IAAc,SAAWA,IAAc,WAAaA,IAAc,QAG/D2B,GAAQuB,GAAaD,GAC3B1B,GAAc,YAAcG,GAAQuB,GAAYtB,EAAK,EACrDH,GAAc,YAAcE,GAAQwB,GAAYvB,EAAK,EAErD,IAAMwB,GAAU,CAACzF,GAAcC,GAAcyF,GAAS,KAAU,CAC9D,IAAMjE,GACJiE,IAAUzC,KAAYuB,GAClBU,GACAS,GAAWpG,EAAOjB,EAAO0B,GAAMC,GAAMgD,EAAO,EAClD,GAAI,CAACxB,GAAG,MAAO,GAEf,IAAI2C,GAAI;AAAA,kHACkGxI,EAAI,IAAI6F,GAAE,IAAK,EAAI,CAAC,SAAS7F,EAAI,IAAI;AAAA,gHACvCA,EAAI,IAAI6F,GAAE,IAAK,EAAI,CAAC,SAAS7F,EAAI,IAAI;AAAA,oHACjCA,EAAI,IAAI6F,GAAE,IAAK,EAAI,CAAC,SAAS7F,EAAI,IAAI;AAAA,UAGjJ,GAAI0G,IAAc,YAAa,CAC7B,IAAMsD,GAAKC,GAAoB5I,EAAK+C,GAAMC,EAAI,EAC9CmE,IAAK;AAAA,mHACoG,KAAK,MAAMwB,GAAG,IAAI,CAAC;AAAA,qHACjB,KAAK,MAAMA,GAAG,IAAI,CAAC;AAAA,WAEhI,CACA,OAAOxB,EACT,EAEKiB,KACHA,GAAwB,GACxBnC,GAAa,UAAY,mHAAmHuC,GAC1IlG,EAAM,CAAC,EACPA,EAAMA,EAAM,OAAS,CAAC,EACtB,EACF,CAAC,GACD2D,GAAa,cAAc,WAAW,GAAG,iBAAiB,QAAUrJ,IAAM,CACxEA,GAAE,gBAAgB,EAClBH,GAAgB,CAClB,CAAC,GAGClC,IAAiB,MAAQC,IAAc,MACzC0L,GAAW,UAAYsC,GAAQjO,EAAcC,EAAW,EAAK,EAC7D0L,GAAW,MAAM,QAAU,OAC3BA,GAAW,MAAM,YAAY,cAAevH,EAAI,KAAK,GAErDuH,GAAW,MAAM,QAAU,MAE/B,CACA,IAAI2C,GAAoB,GAClBC,GAAuB,CAC3B,MAAO5F,EACP,OAAQ,IACR,QAAS,CAAC,EAAG,EAAG,EAAG,CAAC,EACpB,OAAQ,CACN,KAAM,CACJ,IAAKrJ,EAAS,GAChB,EACA,KAAM,CAAE,EAAG,GAAM,EAAG,GAAO,IAAK,EAAG,EACnC,MAAO,CAAE,KAAM,EAAG,EAClB,OAAQ,CACN,KAAM,EACN,OAAQ,UACR,MAAO,EACP,KAAOwL,IAAc,YACjB,CAACvI,GAAUiM,KAAgBhH,GAAcyD,GAAWA,GAAS1I,GAAE,OAAO,GAAI,EAAK,IAAI,EACnF6B,EAAI,KACV,EACA,EAAG,GACH,EAAG,EACL,EACA,OAAQ,CACN,KAAM,GACN,KAAM,EACN,IAAK,EACL,MAAO,EACP,OAAQ,CACV,EACA,OAAQ,CAAE,KAAM,EAAM,EACtB,OAAQ,CACN,EAAG,CACD,KAAM,GACN,MAAO,CAACqK,GAAWC,GAAYC,KAAe,CAACD,GAAIC,EAAE,EACrD,IAAK5D,EAAeA,EAAa,CAAC,EAAI,OACtC,IAAKA,EAAeA,EAAa,CAAC,EAAI,MACxC,EACA,EAAG,CACD,MAAO,IAAM6C,GACb,IAAK9C,IAAc,SAAWzD,IAAc,OAAS,GAAK,CAC5D,CACF,EACA,KAAM,CACJ,CACE,KAAM,EACN,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,MAAO,CACL,KAAM,GACN,OAAQ,SACV,EACA,KAAM,GACN,MAAO,GACP,KAAM,6BACN,OAAQ,CAAC9E,GAAUqM,GAAiBC,GAAkBC,KAAqB,CACzE,IAAMrC,GAAQqC,GAAWD,GAEnBE,IADQxM,GAAE,KAAK,MAAQ,EAAIA,GAAE,KAAK,MAAQA,GAAE,OACrB,GACvByM,GAAYvC,GAAQsC,GAEtBE,GACC1C,GAOH0C,GAAQ,CACN,IAAM,IAAM,IAAM,GAAK,GAAK,IAAM,GAAK,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAC3E,IAAM,IAAM,IAAO,IAAO,IAAO,IAAQ,IAAQ,IAAQ,GAC3D,EARAA,GAAQ,CACN,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,KAAM,KAAM,KAAM,MAAO,MAAO,MAC7E,MAAO,OAAQ,OAAS,OAC1B,EAQF,IAAIC,GAAOD,GAAMA,GAAM,OAAS,CAAC,EACjC,QAASpF,GAAI,EAAGA,GAAIoF,GAAM,OAAQpF,KAChC,GAAIoF,GAAMpF,EAAC,GAAKmF,GAAW,CACzBE,GAAOD,GAAMpF,EAAC,EACd,KACF,CAGF,IAAMsF,GAAS,CAAC,EACZvJ,GAAM,KAAK,KAAKiJ,GAAWK,EAAI,EAAIA,GACjCE,GAAYF,GAAO,EAAI,EAAI,EAEjC,KAAOtJ,IAAOkJ,IAAU,CACtB,IAAMO,GAAM9M,GAAE,SAASqD,GAAK,IAAK,EAAI,EACjCyJ,IAAO9M,GAAE,KAAK,KAAO,IAAM8M,IAAO9M,GAAE,KAAK,KAAOA,GAAE,KAAK,MAAQ,IACjE4M,GAAO,KAAK,OAAOvJ,GAAI,QAAQwJ,EAAS,CAAC,CAAC,EAE5CxJ,IAAOsJ,EACT,CACA,OAAOC,EACT,EACA,OAAS,CAACV,GAAW1H,KAAmB,CACtC,IAAM0F,IAASgC,GAAG,OAAO,GAAG,KAAO,IAAMA,GAAG,OAAO,GAAG,KAAO,GAE7D,OAAO1H,GAAK,IAAKC,IAAM,CACrB,GAAIA,IAAK,KAAM,MAAO,GACtB,IAAMqI,GAAMZ,GAAG,SAASzH,GAAG,IAAK,EAAI,EAEpC,OAAIqI,GAAMZ,GAAG,KAAK,KAAO,IAAMY,GAAMZ,GAAG,KAAK,KAAOA,GAAG,KAAK,MAAQ,GAAW,KACxEjC,GAAQxF,GAAGyF,EAAK,CACzB,CAAC,CACH,CACF,EACA,CACE,KAAM,EACN,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,MAAO,CAAE,OAAQ,SAAU,EAC3B,KAAM,GACN,KAAM,6BACN,OAAS,CAACgC,GAAW1H,KACnBA,GAAK,IAAKC,IAAOA,IAAK,KAAO5C,EAAI,QAAQ4C,EAAC,EAAI,EAAG,CACrD,CACF,EACA,OAAQ,CACN,CAAC,EAED,CACE,MAAO5C,EAAI,MACX,OAAQ,gBACR,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,EACtB,MAAO,IAAM,IACf,CACF,EACA,MAAO,CACL,KAAM,CACH7B,IAAa,CACZ,IAAM+M,GAAM/M,GAAE,KAAK,IAAMA,GAAE,KAAK,OAAS,EACzC8J,GAAc,MAAM,IAAM,GAAGiD,EAAG,KAChCjD,GAAc,MAAM,KAAO,GAAG9J,GAAE,KAAK,IAAI,KAEzC+J,GAAc,MAAM,IAAM,GAAGgD,EAAG,KAChChD,GAAc,MAAM,KAAO,GAAG/J,GAAE,KAAK,KAAOA,GAAE,KAAK,KAAK,KACxD+J,GAAc,MAAM,UAAY,mBAClC,EAEC/J,IAAa,CACRuI,IAAc,QAChByE,GACEhN,GACAwF,EACAjB,EACA1C,EAAI,MACJ,IACA0G,EACA,KACArF,CACF,EACSqF,IAAc,YACvB0E,GAAsBjN,GAAGwF,EAAmBjB,EAAmBmE,EAAQ,EAC9DH,IAAc,WACvB2E,GAAkBlN,GAAGwF,EAAmBjB,CAAiB,EAChDrF,KAAmBqJ,EAC5B4E,GAAoBnN,GAAGwF,EAAmBjB,EAAmBrB,EAAKqF,CAAS,EAG3EyE,GACEhN,GACAwF,EACAjB,EACA1C,EAAI,MACJ,IACA0G,EACA,KACArF,CACF,CAEJ,EAGClD,IAAa,CACZ,IAAMoE,GAAO1H,EAAM,KAAMoF,IAAMA,GAAE,QAAU9B,EAAC,EAC5C,GAAI,CAACoE,GAAM,OAEX,IAAMsD,GAAK1H,GAAU,SAEjBnC,GAAe,KACjBuP,GAAcpN,GAAGwF,EAAOjB,EAAO1C,EAAI,MAAOA,EAAKqB,EAAKqF,CAAS,GAEzDb,IAAKA,GAAE,UAASA,GAAE,QAAQ,MAAM,QAAU,QAG1CtD,GAAK,aAAe,MACtBiJ,GAAmBrN,GAAGwF,EAAOjB,EAAOH,GAAK,YAAavC,EAAI,MAAOA,CAAG,EAE1E,EAGC7B,IAAa,CACZ,IAAMsN,GAAOtN,GAAE,OAAO,IAChBuN,GAAY1P,GAAe,KAE7B2P,GAAWF,IAAQ,MAAQtN,GAAE,OAAO,MAAS,EACjD,GAAIwN,IAAY3P,GAAe,KAAM,CACnC,IAAM4P,GAAKzN,GAAE,SAASuE,EAAM+I,EAAK,EAAI,IAAK,EAAI,EACjC,KAAK,IAAItN,GAAE,OAAO,IAAOyN,EAAE,EAC7B,MAAKD,GAAW,GAC7B,CAOA,GAJIA,IAAYF,KAASzP,GACvB6P,GAAqB1N,GAAGkD,EAAKoK,GAAOK,GAAU9L,EAAI,MAAO,EAAG,EAAG,CAAG,EAGhEpE,GAAgB,MAAQC,GAAa,KAAM,CAC7C,IAAMkQ,GAAM5N,GAAE,IACR6N,GAAM,OAAO,kBAAoB,EACjCC,GAAK9N,GAAE,KACP+N,GAAK/N,GAAE,SAASvC,EAAc,IAAK,EAAI,EACvC8J,GAAKvH,GAAE,SAAStC,EAAW,IAAK,EAAI,EAE1CkQ,GAAI,KAAK,EACTA,GAAI,UAAU,EACdA,GAAI,UAAY,EAAIC,GACpBD,GAAI,YAAc/L,EAAI,MACtB+L,GAAI,OAAOG,GAAID,GAAG,IAAMA,GAAG,MAAM,EACjCF,GAAI,OAAOrG,GAAIuG,GAAG,IAAMA,GAAG,MAAM,EACjCF,GAAI,OAAO,EAEX,IAAM9F,GAAO,KAAK,IAAIpK,EAAYD,CAAY,EACxCyK,GAAQ5K,IAAU,WAAa,GAAGwK,GAAK,QAAQ,CAAC,CAAC,MAAQjC,GAAQiC,EAAI,EACrEkG,GAAW,EAAIH,GACfI,GAAU,QAAQD,EAAQ,2BAC5BJ,GAAI,OAASK,KAASL,GAAI,KAAOK,IACrC,IAAMC,GAAKN,GAAI,YAAY1F,EAAK,EAAE,MAE5BiG,GAAW,KAAK,IAAIL,GAAG,KAAMC,EAAE,EAC/BK,GAAW,KAAK,IAAIN,GAAG,KAAOA,GAAG,MAAOvG,EAAE,EAGhD,GAFiB6G,GAAWD,GAEbD,GAAK,GAAKL,GAAK,CAC5B,IAAMQ,GAAO,EAAIR,GACXS,GAAO,EAAIT,GACXU,GAAKL,GAAKG,GAAO,EACjBG,GAAKR,GAAWM,GAAO,EACvBG,IAAMN,GAAWC,IAAY,EAAIG,GAAK,EACtCG,GAAKZ,GAAG,IAAMA,GAAG,OAASU,GAAK,EAErCZ,GAAI,UAAU,EACTA,GAAY,UAAYA,GAAY,UAAUa,GAAIC,GAAIH,GAAIC,GAAI,EAAIX,EAAG,EACrED,GAAI,KAAKa,GAAIC,GAAIH,GAAIC,EAAE,EAC5BZ,GAAI,UAAY/L,EAAI,MACpB+L,GAAI,KAAK,EAETA,GAAI,UAAY,OAChBA,GAAI,UAAY,SAChBA,GAAI,aAAe,SACnBA,GAAI,SAAS1F,GAAOuG,GAAKF,GAAK,EAAGG,GAAKF,GAAK,CAAC,CAC9C,CACAZ,GAAI,QAAQ,CACd,CAIIL,IAAWoB,GAAgB3O,GAAGkD,EAAKrF,EAAcgE,EAAI,MAAO,GAAM,EAAG,EAGrE2L,IAAYF,KAASzP,GACvB8Q,GAAgB3O,GAAGkD,EAAKoK,GAAOzL,EAAI,MAAO,GAAM,CAAG,CACvD,CACF,EACA,UAAW,CACR7B,IAAa,CACZ,GAAIhD,EAAc,OAClB,IAAMsG,GAAMtD,GAAE,OAAO,IAIrBA,GAAE,OAAO,EAAK,EAGVA,GAAE,OAAO,MAAS,EAAGlC,EAAgBkC,GAAE,SAASA,GAAE,OAAO,KAAO,GAAG,EAClElC,EAAgB,KAGrB,IAAM4J,GAAK1H,GAAU,SACjB4O,GAAYtL,IAAO,MAAQiB,EAAMjB,EAAG,GAAK,KAG7C,GAAIsL,IAAa/Q,GAAe,KAAM,CACpC,IAAM4P,GAAKzN,GAAE,SAASuE,EAAMjB,EAAI,EAAI,IAAK,EAAI,EAChC,KAAK,IAAItD,GAAE,OAAO,IAAOyN,EAAE,EAC7B,MAAKmB,GAAY,GAC9B,CAgCA,GA9BIlH,KACEkH,GACFC,GACE7O,GACA0H,GAAE,QACFpE,GACAkC,EACAjB,EACArB,EACArB,EACA0G,CACF,EACGb,GAAE,QAAQ,MAAM,QAAU,QAI5BzK,IACCqG,IAAO,MAAQJ,EAAII,EAAG,EACpBjF,IAAmBR,GAAe,MAAQ+Q,IAC5CvQ,EAAe6E,EAAII,EAAG,CAAC,EACdjF,GAAkB,CAACuQ,IAE5BvQ,EAAe,IAAI,EAEZiF,KAAQ,MAAQjF,GACzBA,EAAe,IAAI,GAKnBiF,IAAO,MAAQiB,EAAMjB,EAAG,GAAK,KAAM,CACrC,GAAM,CAAE,IAAArD,GAAK,IAAAC,EAAI,EAAIqG,GACrB,GAAItG,IAAO,MAAQC,IAAO,KAAM,CAC9B,IAAM4H,GAAO5H,GAAMD,IAAO,EACpB6O,GAAO,KAAK,IAChBvI,GAAS,KAAO,EAChB,KAAK,OAAQhC,EAAMjB,EAAG,EAAKrD,IAAO6H,GAAQvB,GAAS,IAAI,CACzD,EACInC,GAAK,eAAiBG,EAAMjB,EAAG,IACjCc,GAAK,aAAeG,EAAMjB,EAAG,EAC7BkD,GAAcF,GAAYC,GAAU,IAAKuI,EAAI,EAEjD,CACF,MAAW1K,GAAK,eAAiB,OAC/BA,GAAK,aAAe,KACpBoC,GAAcF,GAAYC,GAAU,GAAG,EAE3C,CACF,EAEA,SAAU,CACR,CAACvG,GAAUD,KAAgB,CACzB,GAAIA,KAAQ,KAAOgM,GAAmB,OACtC,GAAM,CAAE,IAAA9L,GAAK,IAAAC,EAAI,EAAIF,GAAE,OAAO,EAG9B9B,EAAgB,CAAC+B,GAAMC,EAAI,EAG3BqL,GAAkBtL,GAAeC,GAAeF,EAAC,EAE7C,CAAAhD,IAGCY,IAAeO,EAAe,MAGnCnB,EAAe,GACfN,EAAM,QAAQ,CAAC,CAAE,MAAOqS,EAAM,IAAM,CAC9BA,KAAU/O,IAAG+O,GAAM,MAAM,IAAMA,GAAM,SAAS,IAAK,CAAE,IAAK9O,GAAM,IAAKC,EAAK,CAAC,CAAC,CAClF,CAAC,EACDlD,EAAe,GAEfsI,GAAiB,EACjBC,GAAiB,EAEbjH,IAAmBb,IAAiB,MACtCa,GAAgBb,EAAcC,EAAWJ,CAAK,EAClD,CACF,EAEA,UAAW,CACR0C,IAAa,CACZ,GAAIpC,EAAe,OACnBO,EAAe,KACf,GAAM,CAAE,KAAA6Q,GAAM,MAAAC,EAAM,EAAIjP,GAAE,OAC1B,GAAIiP,GAAQ,EAAG,CACb,IAAMhP,GAAMD,GAAE,SAASgP,GAAM,GAAG,EAC1B9O,GAAMF,GAAE,SAASgP,GAAOC,GAAO,GAAG,EACxCxR,EAAewC,GACfvC,EAAYwC,GAGZqL,GAAkBvL,GAAE,OAAO,EAAG,IAAMA,GAAE,OAAO,EAAG,IAAMA,EAAC,EACvDsF,GAAiB,EACjBC,GAAiB,EAEbjH,IAAiBA,GAAgBb,EAAcC,EAAWJ,CAAK,EAGnE0C,GAAE,UAAU,CAAE,KAAM,EAAG,IAAK,EAAG,MAAO,EAAG,OAAQ,CAAE,EAAG,EAAK,CAC7D,CACF,CACF,CACF,CACF,EAGMkP,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,MAAM,QACZ,2EAGF,IAAMC,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,WACpBA,GAAQ,MAAM,QAAU,OAGxB,IAAMC,GAAa,SAAS,cAAc,KAAK,EAC/CA,GAAW,UAAY,2BACvBA,GAAW,MAAM,QAAU,OAE3B,IAAMC,GAAc,SAAS,cAAc,KAAK,EAChDA,GAAY,UAAY,uCACxBA,GAAY,MAAM,QAAU,OAE5B,IAAMC,GAAe,SAAS,cAAc,KAAK,EACjDA,GAAa,UAAY,+BACzBA,GAAa,MAAM,QAAU,OAE7B,IAAMC,GAAe,SAAS,cAAc,KAAK,EACjDA,GAAa,UAAY,mBACzBA,GAAa,UACX,4GACFA,GAAa,MAAM,QAAU,OAG7B,IAAMC,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,wBACpBA,GAAQ,MAAM,QAAU,OAExB,IAAMC,GAAW,SAAS,cAAc,KAAK,EAC7CA,GAAS,UAAY,oCACrBA,GAAS,MAAM,QAAU,OAEzB,IAAMC,GAAY,SAAS,cAAc,KAAK,EAC9CA,GAAU,UAAY,4BACtBA,GAAU,MAAM,QAAU,OAE1B,IAAMC,GAAY,SAAS,cAAc,KAAK,EAC9CA,GAAU,UAAY,mBACtBA,GAAU,UACR,4GACFA,GAAU,MAAM,QAAU,OAG1B,IAAMC,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,YACpBA,GAAQ,MAAM,QAAU,SAAS/N,EAAI,KAAK,gBAG1C,IAAMgO,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,gBACpBA,GAAQ,MAAM,QAAU,SAAShO,EAAI,KAAK,gBAE1CqN,GAAQ,OACNC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,EACF,EAEA,IAAMtJ,GAAqB,CACzB,MAAAhC,EACA,MAAOiB,EACP,IAAA3D,EACA,KAAM,GACN,IAAKgJ,GAAWH,GAAO,OACvB,IAAKG,GAAWF,GAAO,OACvB,UAAWQ,GACX,aAAAD,EACF,EACM9G,GAAiB,CACrB,MAAO,KACP,IAAAwE,EACA,MAAOpD,EACP,MAAAjB,EACA,IAAA1C,EACA,UAAA0G,EACA,aAAAY,GACA,WAAAC,GACA,QAAAvF,GACA,WAAAyC,GACA,SAAAC,GACA,aAAc,KACd,YAAa,KACb,SAAUnJ,EAAgB,IAAImL,CAAS,EACvC,QAASlL,EAAqB,IAAIkL,CAAS,EAC3C,EAAAnC,CACF,EACAG,GAAS,KAAOnC,GAEhB,IAAMuD,GAAW3K,EACjBA,EAAe,GACf,IAAMyK,GAAQ,IAAI/H,GAAMsM,GAAO,CAACxG,EAAOjB,CAAK,EAAU,CAACuL,GAAM1Q,KAAS,CACpEgF,GAAK,MAAQ0L,GACbpT,EAAM,KAAK0H,EAAI,EACfyF,GAAO,YAAYiG,GAAK,IAAI,EAC5BA,GAAK,KAAK,YAAYZ,EAAO,EAC5BY,GAAa,SAAW,CACvB,QAAAX,GACA,WAAAC,GACA,YAAAC,GACA,aAAAC,GACA,aAAAC,GACA,QAAAC,GACA,SAAAC,GACA,UAAAC,GACA,UAAAC,GACA,QAAAC,GACA,QAAAC,GACA,kBAAAtE,EACF,EACAuE,GAAK,MAAM,IAAM,CACf1Q,GAAK,CACP,CAAC,CACH,CAAC,EACDpC,EAAe2K,GAGfoI,GAAiBT,GAAc7H,GAAOjC,EAAO,EAAI,EACjDuK,GAAiBL,GAAWjI,GAAOjC,EAAO,EAAK,EAG/C,IAAIwK,GAA4B,KAChCvI,GAAM,KAAK,iBAAiB,YAAc3H,IAAM,CAC9C,GAAIA,GAAE,SAAW,EAAG,OACpBnC,EAAa,GACb,IAAMsS,GAAOxI,GAAM,KAAK,sBAAsB,EAE9CuI,GADYlQ,GAAE,QAAUmQ,GAAK,IAE/B,CAAC,EACDxI,GAAM,KAAK,iBAAiB,YAAc3H,IAAM,CAC9C,GAAIkQ,KAAe,KAAM,CACvB,IAAMC,GAAOxI,GAAM,KAAK,sBAAsB,EAC1C,KAAK,IAAI3H,GAAE,QAAUmQ,GAAK,KAAOD,EAAU,EAAI,IAAGrS,EAAa,GACrE,CACF,CAAC,EACD8J,GAAM,KAAK,iBAAiB,UAAW,IAAM,CAC3CuI,GAAa,IACf,CAAC,EAGDvI,GAAM,KAAK,iBAAiB,QAAS,IAAM,CACzC,GAAI9J,EAAY,OAChB,IAAM2F,GAAMmE,GAAM,OAAO,IACrBnE,IAAO,MAAQJ,EAAII,EAAG,IACxBzF,EAAcyF,GACd5G,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAE,IAAMA,GAAE,OAAO,EAAK,CAAC,EAC3CzB,GAAWA,EAAU2E,EAAII,EAAG,EAAGA,EAAG,EAClC9E,GAAeA,EAAc8E,EAAG,EAExC,CAAC,EAEDsF,EAAI,iBAAiB,WAAYjJ,EAAe,EAEhD,IAAIiI,GAA+B,KACnC,GAAI/J,GAAe,MAAQ2H,EAAM3H,CAAW,GAAK,MAAQ0G,EAAM1G,CAAW,GAAK,OAC7EgK,GAActB,EAAQ,EAClBA,GAAS,KAAO,MAAQA,GAAS,KAAO,MAAM,CAChD,IAAMuB,GAAOvB,GAAS,IAAMA,GAAS,KAAO,EAC5CqB,GAAgB,KAAK,IACnBrB,GAAS,KAAO,EAChB,KAAK,OAAQhC,EAAM1G,CAAW,EAAK0I,GAAS,KAAOuB,GAAQvB,GAAS,IAAI,CAC1E,EACAnC,GAAK,aAAeG,EAAM1G,CAAW,CACvC,CAGF2I,GAAcF,GAAYC,GAAU,IAAKqB,EAAa,EACtDsI,GAAkB5J,GAAYC,EAAQ,EAClCzH,IACE2J,EAAgB3J,EAAU,aAAa8J,EAAKH,CAAc,EACzD3J,EAAU,YAAY8J,CAAG,EAElC,CAGA,SAAStD,IAAmB,CAC1Ba,GAAkB,EAElBzJ,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAMA,EAAE,MAAM,IAAMA,EAAE,OAAO,EAAK,CAAC,CAAC,CAChE,CAEA,SAASmG,IAAoB,CAC3BzJ,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,IAAA6B,CAAI,IAAM,CACnC,IAAM6F,EAAK1H,EAAU,SACrB,GAAI,CAAC0H,EAAG,OACR,GAAM,CACJ,QAAAyH,EACA,WAAAC,EACA,YAAAC,EACA,aAAAC,EACA,aAAAC,EACA,QAAAC,EACA,SAAAC,EACA,UAAAC,EACA,UAAAC,CACF,EAAIjI,EACJ,GAAIjK,GAAgB,MAAQC,GAAa,KAAM,CAC7C,CACEyR,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,CACF,EAAE,QAAS3N,IAAoB,CAC7BA,GAAG,MAAM,QAAU,MACrB,CAAC,EACD,MACF,CACA,IAAMmO,EAAKnQ,EAAE,SAASvC,EAAc,GAAG,EACjC2S,GAAKpQ,EAAE,SAAStC,EAAW,GAAG,EAC9BmQ,EAAM,OAAO,kBAAoB,EACjCC,GAAK9N,EAAE,KACPqQ,GAAQvC,GAAG,MAAQD,EACnByC,GAAQxC,GAAG,OAASD,EACpB0C,IAAczC,GAAG,IAAMA,GAAG,QAAUD,EAEpC2C,GAAkBL,GAAM,GAAKA,GAAME,GACnCI,GAAeL,IAAM,GAAKA,IAAMC,GAGhCK,GAAQ,KAAK,IAAI,EAAGP,CAAE,EACtBQ,GAAQ,KAAK,IAAIN,GAAOD,EAAE,EAahC,GAZIO,GAAQD,IACVvB,EAAQ,MAAM,KAAO,GAAGuB,EAAK,KAC7BvB,EAAQ,MAAM,MAAQ,GAAGwB,GAAQD,EAAK,KACtCvB,EAAQ,MAAM,IAAM,IACpBA,EAAQ,MAAM,OAAS,GAAGmB,EAAK,KAC/BnB,EAAQ,MAAM,gBAAkBxB,GAAU9L,EAAI,MAAO,GAAI,EACzDsN,EAAQ,MAAM,QAAU,IAExBA,EAAQ,MAAM,QAAU,OAItBqB,GAAiB,CACnBpB,EAAW,MAAM,KAAO,GAAGe,CAAE,KAC7Bf,EAAW,MAAM,OAAS,GAAGkB,EAAK,KAClClB,EAAW,MAAM,gBAAkBvN,EAAI,MACvCuN,EAAW,MAAM,QAAU,GAE3B,IAAMwB,GAAQC,GAAQpT,CAAY,EAClC4R,EAAY,YAAcuB,GAC1B,IAAME,GAAUF,GAAM,OAAS,EAAI,GACnCvB,EAAY,MAAM,KAAOc,EAAKW,GAAU,EAAIT,GAAQ,GAAGF,EAAK,CAAC,KAAO,GAAGA,EAAKW,GAAU,CAAC,KACvFzB,EAAY,MAAM,QAAU,GAE5BC,EAAa,MAAM,KAAO,GAAGa,CAAE,KAC/Bb,EAAa,MAAM,gBAAkBzN,EAAI,MACzCyN,EAAa,MAAM,QAAU,GAE7BC,EAAa,MAAM,KAAO,GAAGY,CAAE,KAC/BZ,EAAa,MAAM,IAAM,GAAGgB,EAAU,KACtC,IAAMQ,GAAQxB,EAAa,cAAc,2BAA2B,EAChEwB,KAAOA,GAAM,MAAM,MAAQlP,EAAI,OACnC0N,EAAa,MAAM,QAAU,EAC/B,KACE,CAACH,EAAYC,EAAaC,EAAcC,CAAY,EAAE,QACnDvN,IAAqBA,GAAG,MAAM,QAAU,MAC3C,EAIF,GAAIyO,GAAc,CAChBjB,EAAQ,MAAM,KAAO,GAAGY,EAAE,KAC1BZ,EAAQ,MAAM,OAAS,GAAGc,EAAK,KAC/Bd,EAAQ,MAAM,gBAAkB3N,EAAI,MACpC2N,EAAQ,MAAM,QAAU,GAExB,IAAMwB,GAAQH,GAAQnT,CAAS,EAC/B+R,EAAS,YAAcuB,GACvB,IAAMC,GAAUD,GAAM,OAAS,EAAI,GACnCvB,EAAS,MAAM,KAAOW,GAAKa,GAAU,EAAI,EAAI,GAAGb,GAAKa,GAAU,CAAC,KAAO,GAAGb,GAAK,CAAC,KAChFX,EAAS,MAAM,QAAU,GAEzBC,EAAU,MAAM,KAAO,GAAGU,EAAE,KAC5BV,EAAU,MAAM,gBAAkB7N,EAAI,MACtC6N,EAAU,MAAM,QAAU,GAE1BC,EAAU,MAAM,KAAO,GAAGS,EAAE,KAC5BT,EAAU,MAAM,IAAM,GAAGY,EAAU,KACnC,IAAMW,GAAQvB,EAAU,cAAc,2BAA2B,EAC7DuB,KAAOA,GAAM,MAAM,MAAQrP,EAAI,OACnC8N,EAAU,MAAM,QAAU,EAC5B,KACE,CAACH,EAASC,EAAUC,EAAWC,CAAS,EAAE,QACvC3N,IAAqBA,GAAG,MAAM,QAAU,MAC3C,CAEJ,CAAC,CACH,CAEA,SAAS6O,GAAQpM,EAAW,CAC1B,OAAOnH,IAAU,WAAa,GAAGmH,EAAE,QAAQ,CAAC,CAAC,MAAQoB,GAAQpB,CAAC,CAChE,CAGA,SAASsL,GACPoB,EACA1J,EACAjC,EACA4L,EACA,CAEAD,EAAS,MAAM,cAAgB,OAE/BA,EAAS,iBAAiB,YAAcrR,GAAM,CAC5CA,EAAE,gBAAgB,EAClBA,EAAE,eAAe,EACjB,IAAMuR,EAASvR,EAAE,QACXwR,EAAWF,EAAW3T,EAAeC,EACrC2S,EAAQ5I,EAAM,KAAK,YAEnBxB,EAAOwB,EAAM,OAAO,EAAG,IAC3BvB,EAAOuB,EAAM,OAAO,EAAG,IACnB8J,EAAYlB,GAASnK,EAAOD,GAC5BxF,EAAQ,CAAC+E,EAAM,CAAC,EAAIA,EAAMA,EAAM,OAAS,CAAC,CAAE,EAElD,SAAS,KAAK,MAAM,OAAS,YAC7B7H,EAAa,GAEb,SAAS6T,EAAOC,EAAgB,CAC9B,IAAMC,GAAKD,EAAG,QAAUJ,EACpBM,IAAUL,GAAY,GAAKI,GAAKH,EACpCI,GAAS,KAAK,IAAIlR,EAAM,CAAC,EAAG,KAAK,IAAIA,EAAM,CAAC,EAAGkR,EAAM,CAAC,EAElDP,EAAU3T,EAAe,KAAK,IAAIkU,IAASjU,GAAa+C,EAAM,CAAC,GAAK,IAAK,EACxE/C,EAAY,KAAK,IAAIiU,IAASlU,GAAgBgD,EAAM,CAAC,GAAK,IAAK,EAIpE/D,EAAM,QAASoF,IACZA,GAAE,MAAc,UAAU,kBACzBA,GAAE,MAAM,OAAO,EAAG,IAClBA,GAAE,MAAM,OAAO,EAAG,GACpB,CACF,EACAwD,GAAiB,EACjBC,GAAiB,EACbjH,IAAiBA,GAAgBb,EAAcC,EAAWJ,CAAK,CACrE,CAEA,SAASsU,IAAO,CACd,SAAS,KAAK,MAAM,OAAS,GAC7BjU,EAAa,GACb,SAAS,oBAAoB,YAAa6T,CAAM,EAChD,SAAS,oBAAoB,UAAWI,EAAI,CAC9C,CAEA,SAAS,iBAAiB,YAAaJ,CAAM,EAC7C,SAAS,iBAAiB,UAAWI,EAAI,CAC3C,CAAC,CACH,CAGA,SAAS/J,GAActB,EAAoB,CACzC,GAAM,CAAE,MAAAhC,EAAO,MAAAiB,EAAO,KAAAqM,CAAK,EAAItL,EAG/B,GAAIA,EAAS,aAAehC,GAASgC,EAAS,KAAM,OACpDA,EAAS,WAAahC,EAEtB,IAAItE,EAAMsG,EAAS,IACfrG,EAAMqG,EAAS,IACnB,GAAItG,GAAO,MAAQC,GAAO,KAAM,CAC9B,IAAI4R,EAAK,IACPC,EAAK,KACLC,GAAM,EACR,QAAS1K,EAAI,EAAGA,EAAI/C,EAAM,OAAQ+C,IAAK,CACrC,IAAM7C,GAAIF,EAAM+C,CAAC,EACb7C,IAAK,MAAQ,CAAC,SAASA,EAAC,IACxBA,GAAIqN,IAAIA,EAAKrN,IACbA,GAAIsN,IAAIA,EAAKtN,IACjBuN,KACF,CACA,GAAI,CAACA,GAAK,OACV/R,EAAM6R,EACN5R,EAAM6R,EACNxL,EAAS,IAAMtG,EACfsG,EAAS,IAAMrG,CACjB,CAEA,IAAM+R,EAAO,IAAI,MAAMJ,CAAI,EAAE,KAAK,CAAC,EAC7BK,EAAW,IAAI,MAAML,CAAI,EAAE,KAAK,CAAC,EAEjC/J,EAAO5H,EAAMD,GAAO,EACpBsI,EACJhC,EAAS,MAAM,WAAa,OAAO,KAAK3E,EAAO,EAAE,KAAMuQ,GAAMvQ,GAAQuQ,CAAC,IAAM5L,EAAS,GAAG,EACpF2C,EACJ,CAACX,GACDlL,EAAqB,IAAIkL,CAAS,GACjCA,IAAc,SAAWA,IAAc,WAAaA,IAAc,QAErE,QAASjB,EAAI,EAAGA,EAAI/C,EAAM,OAAQ+C,IAAK,CACrC,IAAM7C,EAAIF,EAAM+C,CAAC,EAEjB,GADI7C,GAAK,MAAQ,CAAC,SAASA,CAAC,GACxBA,IAAM,GAAK,CAACyE,EAAS,SAEzB,IAAMkJ,GAAK,KAAK,IAAIP,EAAO,EAAG,KAAK,OAAQpN,EAAIxE,GAAO6H,EAAQ+J,CAAI,CAAC,EACnEI,EAAKG,EAAE,IAGP,IAAMC,EAAO/K,EAAI,GAAK9B,EAAM8B,EAAI,CAAC,GAAK,KAAO9B,EAAM8B,EAAI,CAAC,EAAK9B,EAAM8B,CAAC,EAC9DgL,GAAOhL,EAAI9B,EAAM,OAAS,GAAKA,EAAM8B,EAAI,CAAC,GAAK,KAAO9B,EAAM8B,EAAI,CAAC,EAAK9B,EAAM8B,CAAC,EACnF4K,EAASE,EAAE,IAAME,GAAOD,GAAQ,CAClC,CACA9L,EAAS,KAAO0L,EAChB1L,EAAS,SAAW2L,CACtB,CAEA,SAAS3M,IAAmB,CAC1B7I,EAAM,QAAQ,CAAC,CAAE,WAAA4J,EAAY,SAAAC,EAAU,MAAOvG,CAAE,IAAM,CACpDwG,GAAcF,EAAYC,EAAUvG,EAAE,MAAM,CAC9C,CAAC,CACH,CAEA,SAASwG,GACP+L,EACAhM,EACAiM,EACAC,EAA2B,KAC3B,CACA,GAAM,CAAE,IAAA5Q,EAAK,KAAAgQ,CAAK,EAAItL,EACtBsB,GAActB,CAAQ,EACtB,GAAM,CAAE,KAAA0L,EAAM,IAAAhS,EAAK,IAAAC,CAAI,EAAIqG,EAC3B,GAAI,CAAC0L,GAAQhS,GAAO,MAAQC,GAAO,KAAM,OAEzC,IAAMwS,EAASjV,GAAgB,MAAQC,GAAa,KAGpD,GACEgV,IACCnM,EAAS,gBAAgB,CAAC,IAAM9I,GAAgB8I,EAAS,gBAAgB,CAAC,IAAM7I,GACjF,CACA6I,EAAS,cAAgB,CAAC9I,EAAeC,CAAU,EACnD,IAAMiV,GAAU,IAAI,MAAMd,CAAI,EAAE,KAAK,CAAC,EAChCe,GAAc,IAAI,MAAMf,CAAI,EAAE,KAAK,CAAC,EACpC,CAAE,MAAAtN,GAAO,MAAAiB,EAAM,EAAIe,EACnBuB,GAAO5H,EAAMD,GAAO,EACpBsI,GACJhC,EAAS,MAAM,WAAa,OAAO,KAAK3E,EAAO,EAAE,KAAMuQ,IAAMvQ,GAAQuQ,EAAC,IAAM5L,EAAS,GAAG,EACpF2C,GACJ,CAACX,IACDlL,EAAqB,IAAIkL,EAAS,GACjCA,KAAc,SAAWA,KAAc,WAAaA,KAAc,QAErE,QAASjB,GAAI,EAAGA,GAAI/C,GAAM,OAAQ+C,KAAK,CACrC,IAAM7C,GAAIF,GAAM+C,EAAC,EAEjB,GADI7C,IAAK,MAAQ,CAAC,SAASA,EAAC,GACxBA,KAAM,GAAK,CAACyE,GAAS,SAEzB,IAAM2J,GAAIrN,GAAM8B,EAAC,EACjB,GAAIuL,IAAK,MAAQA,GAAIpV,GAAiBoV,GAAInV,EAAY,SACtD,IAAM0U,GAAK,KAAK,IAAIP,EAAO,EAAG,KAAK,OAAQpN,GAAIxE,GAAO6H,GAAQ+J,CAAI,CAAC,EACnEc,GAAQP,EAAE,IACV,IAAMC,GAAO/K,GAAI,GAAK9B,GAAM8B,GAAI,CAAC,GAAK,KAAO9B,GAAM8B,GAAI,CAAC,EAAK9B,GAAM8B,EAAC,EAC9DgL,GAAOhL,GAAI9B,GAAM,OAAS,GAAKA,GAAM8B,GAAI,CAAC,GAAK,KAAO9B,GAAM8B,GAAI,CAAC,EAAK9B,GAAM8B,EAAC,EACnFsL,GAAYR,EAAE,IAAME,GAAOD,IAAQ,CACrC,CACA9L,EAAS,QAAUoM,GACnBpM,EAAS,YAAcqM,EACzB,MAAYF,IACVnM,EAAS,QAAU,KACnBA,EAAS,YAAc,KACvBA,EAAS,cAAgB,MAE3B,IAAMoM,EAAUpM,EAAS,QAEnBsH,EAAM,OAAO,kBAAoB,EACjCiF,EAAIrU,EACJsU,GAAIP,GAGND,EAAO,QAAUO,EAAIjF,GAAO0E,EAAO,SAAWQ,GAAIlF,KACpD0E,EAAO,MAAQO,EAAIjF,EACnB0E,EAAO,OAASQ,GAAIlF,EACpB0E,EAAO,MAAM,MAAQ,GAAGO,CAAC,KACzBP,EAAO,MAAM,OAAS,GAAGQ,EAAC,MAG5B,IAAMnF,EAAM2E,EAAO,WAAW,IAAI,EAClC3E,EAAI,eAAe,EACnBA,EAAI,MAAMC,EAAKA,CAAG,EAClBD,EAAI,UAAU,EAAG,EAAGkF,EAAGC,EAAC,EAExB,IAAMC,GAAO,KAAK,IAAI,GAAGf,CAAI,EAGvBtM,GAAOlB,IAAc5C,EAAI,QAAQ4C,EAAC,EAClCwJ,GAAU,4BACZL,EAAI,OAASK,KAASL,EAAI,KAAOK,IAWrC,IAAMgF,GAAM,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,EAVlB,KAAK,KAClB,KAAK,IACHrF,EAAI,YAAY,GAAGjI,GAAIzF,CAAG,CAAC,IAAI2B,EAAI,IAAI,EAAE,EAAE,MAC3C+L,EAAI,YAAY,GAAGjI,GAAI1F,CAAG,CAAC,IAAI4B,EAAI,IAAI,EAAE,EAAE,KAC7C,CACF,EAK6C,CAAE,EAC/C0E,EAAS,KAAO0M,GAAI,EACpB,IAAMC,GAAQJ,EAAIG,GAAI,EAAIA,GAAI,EACxBE,GAAQJ,GAAIE,GAAI,EAAIA,GAAI,EAGxBG,GAAQ9L,IAAc2L,GAAI,GAAKpB,EAAO,EAAIvK,KAAM6L,GAAQtB,GACxDwB,GAAOF,GAAQtB,EAAO,EAGtByB,GAAYZ,EAAS,IAAO,GAClC9E,EAAI,UAAYD,GAAU9L,EAAI,MAAOyR,EAAS,EAC9C,QAAShM,GAAI,EAAGA,GAAIuK,EAAMvK,KAAK,CAC7B,GAAI,CAAC2K,EAAK3K,EAAC,EAAG,SACd,IAAMiH,GAAM0D,EAAK3K,EAAC,EAAI0L,GAAQE,GAC9BtF,EAAI,SAASqF,GAAI,EAAGG,GAAK9L,EAAC,EAAGiH,GAAI8E,EAAI,CACvC,CAGA,GAAIV,EAAS,CACX/E,EAAI,UAAYD,GAAU9L,EAAI,MAAO,GAAI,EACzC,QAASyF,GAAI,EAAGA,GAAIuK,EAAMvK,KAAK,CAC7B,GAAI,CAACqL,EAAQrL,EAAC,EAAG,SACjB,IAAMiH,GAAMoE,EAAQrL,EAAC,EAAI0L,GAAQE,GACjCtF,EAAI,SAASqF,GAAI,EAAGG,GAAK9L,EAAC,EAAGiH,GAAI8E,EAAI,CACvC,CACAzF,EAAI,UAAY/L,EAAI,MACpB+L,EAAI,SAASqF,GAAI,EAAGA,GAAI,EAAG,EAAGE,EAAK,CACrC,CAGA,IAAMI,GAAQtB,EAAK,OAAO,CAACvK,GAAGjD,KAAMiD,GAAIjD,GAAG,CAAC,EAC5C,GAAI8O,GAAQ,EAAG,CAEb,IAAMC,GAAO,CAAC,CAAE,EAAGP,GAAI,EAAG,EAAGA,GAAI,EAAIE,EAAM,CAAC,EACxCM,GAAS,EACb,QAASnM,GAAI,EAAGA,GAAIuK,EAAMvK,KACxBmM,IAAUxB,EAAK3K,EAAC,EAChBkM,GAAK,KAAK,CAAE,EAAGP,GAAI,EAAKQ,GAASF,GAASL,GAAO,EAAGE,GAAK9L,EAAC,CAAE,CAAC,EAG/DsG,EAAI,UAAU,EAEdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,YAAc/L,EAAI,MACtB+L,EAAI,UAAY,IAAOC,EACvBD,EAAI,SAAW,QACfA,EAAI,OAAO4F,GAAK,CAAC,EAAE,EAAGA,GAAK,CAAC,EAAE,CAAC,EAC/B,QAASlM,GAAI,EAAGA,GAAIkM,GAAK,OAAS,EAAGlM,KAAK,CACxC,IAAM8E,IAAMoH,GAAKlM,EAAC,EAAE,EAAIkM,GAAKlM,GAAI,CAAC,EAAE,GAAK,EACnCoM,IAAMF,GAAKlM,EAAC,EAAE,EAAIkM,GAAKlM,GAAI,CAAC,EAAE,GAAK,EACzCsG,EAAI,iBAAiB4F,GAAKlM,EAAC,EAAE,EAAGkM,GAAKlM,EAAC,EAAE,EAAG8E,GAAIsH,EAAE,CACnD,CAKA,GAJA9F,EAAI,OAAO4F,GAAKA,GAAK,OAAS,CAAC,EAAE,EAAGA,GAAKA,GAAK,OAAS,CAAC,EAAE,CAAC,EAC3D5F,EAAI,OAAO,EAGP6E,GAAa,MAAQe,GAAKf,EAAY,CAAC,EAAG,CAC5C,IAAMkB,GAAKH,GAAKf,EAAY,CAAC,EAE7B7E,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,EAAK,EAAIA,CAAG,CAAC,EAClCD,EAAI,YAAcD,GAAU9L,EAAI,MAAO,EAAG,EAC1C+L,EAAI,OAAO+F,GAAG,EAAGA,GAAG,CAAC,EACrB/F,EAAI,OAAO+F,GAAG,EAAGV,GAAI,EAAIE,EAAK,EAC9BvF,EAAI,OAAO,EACXA,EAAI,YAAY,CAAC,CAAC,EAGlBA,EAAI,UAAU,EACdA,EAAI,IAAI+F,GAAG,EAAGA,GAAG,EAAG,IAAM9F,EAAK,EAAG,KAAK,GAAK,CAAC,EAC7CD,EAAI,UAAY,UAChBA,EAAI,KAAK,EACTA,EAAI,YAAc/L,EAAI,MACtB+L,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,CACb,CACF,CAGIA,EAAI,YAAc,YAAWA,EAAI,UAAY,WACjD,IAAMgG,GAAQ,4BACVhG,EAAI,OAASgG,KAAOhG,EAAI,KAAOgG,IACnChG,EAAI,UAAY,QAGhBA,EAAI,aAAe,MACnBA,EAAI,SAAS,GAAGjI,GAAIzF,CAAG,CAAC,IAAI2B,EAAI,IAAI,GAAIoR,GAAI,EAAI,EAAGA,GAAI,CAAC,EAGxDrF,EAAI,aAAe,SACnBA,EAAI,SAAS,GAAGjI,GAAI1F,CAAG,CAAC,IAAI4B,EAAI,IAAI,GAAIoR,GAAI,EAAI,EAAGF,GAAIE,GAAI,CAAC,EAG5D,IAAMvN,GACJ,CAACgN,GAAUnM,EAAS,eAAiB,OACjCA,EAAS,aACTqF,GACErF,EAAS,MACTA,EAAS,MACT9I,GAAgB,KAChBC,GAAa,GACf,EACN,GAAIgI,GAAO,CACT,IAAMmO,GACJZ,GAAI,GACHpB,EAAO,EAAI,KAAK,IAAIA,EAAO,EAAG,KAAK,OAAQnM,GAAM,IAAMzF,IAAQC,EAAMD,GAAO,GAAM4R,CAAI,CAAC,IACrFsB,GAAQtB,GACPiC,GAAYf,GAAIE,GAAI,EACpBc,GAAYd,GAAI,EAChBe,GAAc,GAEhBH,GAAOE,GAAYC,GAAc,GAAKH,GAAOC,GAAYE,GAAc,IACzEpG,EAAI,aAAe,SACfA,EAAI,YAAc,SAAQA,EAAI,UAAY,QAC9CA,EAAI,SAAS,GAAGjI,GAAID,GAAM,GAAG,CAAC,IAAI7D,EAAI,IAAI,GAAIoR,GAAI,EAAI,EAAGY,EAAI,EAE7DjG,EAAI,UAAU,EACdA,EAAI,OAAOqF,GAAI,EAAI,EAAGY,EAAI,EAC1BjG,EAAI,OAAOqF,GAAI,EAAGY,EAAI,EAClBjG,EAAI,cAAgB,SAAQA,EAAI,YAAc,QAClDA,EAAI,UAAY,EAChBA,EAAI,OAAO,EAEf,CAGA,GAAI6E,GAAa,MAAQc,GAAQ,EAAG,CAClC,IAAIU,GAAa,EACjB,QAAS3M,GAAI,EAAGA,GAAImL,EAAWnL,KAAK2M,IAAchC,EAAK3K,EAAC,EACxD,IAAI4M,GAAc,EAClB,QAAS5M,GAAImL,EAAY,EAAGnL,GAAIuK,EAAMvK,KAAK4M,IAAejC,EAAK3K,EAAC,EAEhE,IAAM6M,GAAS,KAAK,MAAOF,GAAaV,GAAS,GAAG,EAC9Ca,GAAU,KAAK,MAAOF,GAAcX,GAAS,GAAG,EAEtD3F,EAAI,KAAK,EACTA,EAAI,UAAY,OAChBA,EAAI,aAAe,MACnB,IAAMyG,GAAQ,4BACVzG,EAAI,OAASyG,KAAOzG,EAAI,KAAOyG,IAEnC,IAAMC,GAAQvB,GAAIE,GAAI,EAAI,EAGtBrF,EAAI,YAAc,YAAWA,EAAI,UAAY,WACjDA,EAAI,SAAS,QAASqF,GAAI,EAAGqB,EAAK,EAC9B1G,EAAI,YAAc,SAAQA,EAAI,UAAY,QAC9C,IAAM2G,GAAU,kCACZ3G,EAAI,OAAS2G,KAAS3G,EAAI,KAAO2G,IACrC3G,EAAI,SAAS,GAAGuG,EAAM,IAAKlB,GAAI,EAAGqB,GAAQ,EAAE,EAG5C,IAAME,GAAOvB,GAAI,EAAIC,GAAQ,EACzBtF,EAAI,OAASyG,KAAOzG,EAAI,KAAOyG,IAC/BzG,EAAI,YAAc,YAAWA,EAAI,UAAY,WACjDA,EAAI,SAAS,SAAU4G,GAAMF,EAAK,EAC9B1G,EAAI,YAAc,SAAQA,EAAI,UAAY,QAC1CA,EAAI,OAAS2G,KAAS3G,EAAI,KAAO2G,IACrC3G,EAAI,SAAS,GAAGwG,EAAO,IAAKI,GAAMF,GAAQ,EAAE,EAE5C1G,EAAI,QAAQ,CACd,CACF,CAEA,SAASsC,GAAkBqC,EAA2BhM,EAAoB,CACxE,GAAM,CAAE,KAAAnC,CAAK,EAAImC,EAEjBgM,EAAO,iBAAiB,QAAUzS,GAAM,CACtC,IAAMgP,EAAO2F,GAASlC,EAAQhM,EAAUzG,CAAC,EACzC,GAAIgP,GAAQ,MAAQ1K,EAAM,CACxB,GAAM,CAAE,IAAAnE,EAAK,IAAAC,EAAK,KAAA2R,CAAK,EAAItL,EACrBuB,EAAO5H,EAAOD,GAAQ,EAC5BmE,EAAK,YAAcnE,GAAQ6O,EAAO,KAAQhH,EAAO+J,GACjDnV,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAMA,EAAE,OAAO,EAAK,CAAC,CACjD,CACF,CAAC,EAEDuS,EAAO,iBAAiB,YAAczS,GAAM,CAC1C/B,EAAqB+B,EACrBL,GAAkBK,EAAGyS,EAAQhM,CAAQ,CACvC,CAAC,EAEDgM,EAAO,iBAAiB,aAAc,IAAM,CAC1CtU,EAAoBsU,EACpBvU,EAAkBuI,CACpB,CAAC,EAEDgM,EAAO,iBAAiB,aAAc,IAAM,CACtCtU,IAAsBsU,IACxBtU,EAAoB,KACpBD,EAAkB,MAEhBa,IAAeA,EAAc,MAAM,QAAU,QACjD,IAAM6V,EAAS,SAAS,eAAe,WAAW,EAC9CA,IAAQA,EAAO,MAAM,QAAU,QAC/BtQ,IACFA,EAAK,aAAe,KACpBoC,GAAc+L,EAAQhM,EAAUgM,EAAO,QAAU,OAAO,kBAAoB,EAAE,EAElF,CAAC,CACH,CAEA,SAASkC,GAASlC,EAA2BhM,EAAoBzG,EAAe,CAC9E,GAAM,CAAE,KAAAmS,EAAM,KAAAJ,CAAK,EAAItL,EACvB,GAAI,CAAC0L,EAAM,OAAO,KAClB,IAAMhC,EAAOsC,EAAO,sBAAsB,EACpCoC,EAAO7U,EAAE,QAAUmQ,EAAK,IAExBgD,EAAM,CAAE,EAAG,EAAG,EAAG,EAAG,EACpBE,EAAQlD,EAAK,OAASgD,EAAI,EAAIA,EAAI,EAClC2B,EAAO,KAAK,OAAQD,EAAO1B,EAAI,GAAKE,EAAStB,CAAK,EAClD/C,EAAO+C,EAAQ,EAAI+C,EACzB,OAAIA,EAAO,GAAKA,GAAQ/C,EAAc,KAC/B/C,CACT,CAEA,SAASrP,GAAkBK,EAAeyS,EAA2BhM,EAAoB,CACvF,GAAI,CAAC1H,EAAe,OACpB,GAAM,CAAE,KAAAoT,EAAM,SAAAC,EAAU,IAAAjS,EAAK,IAAAC,EAAK,KAAA2R,EAAM,IAAAhQ,EAAK,KAAAuC,CAAK,EAAImC,EACtD,GAAI,CAAC0L,GAAQ,CAACC,GAAYjS,GAAO,MAAQC,GAAO,KAAM,OAEtD,IAAMwU,EAAS,SAAS,eAAe,WAAW,EAC5C5F,EAAO2F,GAASlC,EAAQhM,EAAUzG,CAAC,EAEzC,GAAIgP,GAAQ,MAAQ,CAACmD,EAAKnD,CAAI,EAAG,CAC/BjQ,EAAc,MAAM,QAAU,OAC1B6V,IAAQA,EAAO,MAAM,QAAU,QAC/BtQ,IACFA,EAAK,aAAe,KACpBoC,GAAc+L,EAAQhM,EAAUgM,EAAO,QAAU,OAAO,kBAAoB,EAAE,GAEhF,MACF,CAEA,GAAInO,EAAM,CACR,IAAM0D,GAAO5H,EAAMD,GAAO,EAC1BmE,EAAK,aAAenE,GAAO6O,EAAO,KAAQhH,GAAO+J,GACjDrL,GAAc+L,EAAQhM,EAAUgM,EAAO,QAAU,OAAO,kBAAoB,GAAIzD,CAAI,CACtF,CAEA,IAAM+F,EAAQ5C,EAAKnD,CAAI,EACjByE,GAAQtB,EAAK,OAAO,CAACvK,GAAGjD,KAAMiD,GAAIjD,GAAG,CAAC,EACtCqQ,EAAOD,EAAQtB,GAAS,IAExBzL,GAAO5H,EAAMD,GAAO,EACpB8U,GAAM9U,EAAM6O,GAAQhH,GAAO+J,GAC3BmD,GAAO/U,GAAO6O,EAAO,IAAMhH,GAAO+J,GAClC3J,GAAQ,GAAGrG,EAAI,IAAIkT,GAAK,EAAI,CAAC,WAAMlT,EAAI,IAAImT,GAAM,EAAI,CAAC,IAAInT,EAAI,IAAI,GAGpEoT,GAAW,GACTC,IAAOH,GAAMC,IAAQ,EACrBzM,GAAY,OAAO,KAAK3G,EAAO,EAAE,KAAMuQ,IAAMvQ,GAAQuQ,EAAC,IAAMtQ,CAAG,EACjEsT,GAAe,CAAC,EAIpB,GAHI5M,KAAc,QAAS4M,GAAQC,GAAM,cAAc,EAC9C7M,KAAc,OAAM4M,GAAQC,GAAM,WAAW,GAElDD,GAAM,OAAS,EAAG,CACpB,IAAME,GAAOF,GAAM,UAAWG,IAAMJ,IAAOI,GAAE,KAAOJ,GAAMI,GAAE,GAAG,EACzDA,GACJD,KAAS,GACLF,GAAME,EAAI,EACVH,IAAOC,GAAMA,GAAM,OAAS,CAAC,EAAE,IAC7BA,GAAMA,GAAM,OAAS,CAAC,EACtB,KACR,GAAIG,GAAG,CACL,IAAMC,GAAYF,KAAS,GAAKA,GAAOF,GAAM,OAAS,EACtDF,GAAW;AAAA,6JAC0IK,GAAE,KAAK;AAAA,+CACrHC,GAAY,CAAC;AAAA;AAAA,oDAERD,GAAE,IAAI;AAAA;AAAA,SAGpD,CACF,CAEA,IAAME,GACJlY,IAAU,WAAa,GAAG4U,EAASpD,CAAI,EAAE,QAAQ,CAAC,CAAC,MAAQjJ,GAAQqM,EAASpD,CAAI,CAAC,EAC7E2G,GAAYvD,EAASpD,CAAI,EAAIoD,EAAS,OAAO,CAACxK,GAAGjD,KAAMiD,GAAIjD,GAAG,CAAC,EAAK,IAEtEiR,GAAO;AAAA,6DAC8C7T,EAAI,KAAK,KAAKqG,EAAK;AAAA,QACxE+M,EAAQ;AAAA,MAYZ,GATIO,KACFE,IAAQ;AAAA,sCACwBpY,IAAU,WAAa,OAAS,MAAM;AAAA,sCACtCkY,EAAU;AAAA,oCACZC,GAAS,QAAQ,CAAC,CAAC;AAAA,eAK/ClP,EAAS,SAAWA,EAAS,YAAa,CAC5C,IAAMoP,GACJrY,IAAU,WACN,GAAGiJ,EAAS,YAAYuI,CAAI,EAAE,QAAQ,CAAC,CAAC,MACxCjJ,GAAQU,EAAS,YAAYuI,CAAI,CAAC,EAClC8G,GACHrP,EAAS,YAAYuI,CAAI,EAAIvI,EAAS,YAAY,OAAO,CAACmB,GAAGjD,KAAMiD,GAAIjD,GAAG,CAAC,EAAK,IAEnFiR,IAAQ;AAAA;AAAA,gDAEkCpY,IAAU,WAAa,OAAS,MAAM;AAAA,4CAC1CqY,EAAW;AAAA,0CACbC,GAAU,QAAQ,CAAC,CAAC;AAAA;AAAA,OAG1D,CAEA/W,EAAc,UAAY6W,GAG1B7W,EAAc,MAAM,QAAU,QAC9B,IAAMgX,GAAMhX,EAAc,aACpBiX,GAAMjX,EAAc,YACpBoR,GAAOsC,EAAO,sBAAsB,EACpCY,GAAQlD,GAAK,OAAS,EAAI,GAC1B8F,GAAa9F,GAAK,IAAM,GAAK4B,EAAQ,EAAI/C,EAAO,KAAQqE,GAAQtB,GAEtEhT,EAAc,MAAM,KAAO,GAAGoR,GAAK,KAAO6F,GAAM,EAAE,KAClDjX,EAAc,MAAM,IAAM,GAAGkX,GAAaF,GAAM,CAAC,KAG7CnB,IACFA,EAAO,MAAM,QAAU,QACvBA,EAAO,MAAM,IAAM,GAAGqB,EAAU,KAChCrB,EAAO,MAAM,KAAO,MACpBA,EAAO,MAAM,MAAQ,GAAGzE,GAAK,IAAI,KAErC,CAGA,SAAS1N,GAAakE,EAAY,GAAO,CACnC5H,IAAeA,EAAc,MAAM,QAAU,QACjDnC,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,IAAA4I,CAAI,IAAM,CACnC7L,EAAS,MAAMiD,CAAC,EAChBA,EAAE,QAAQ,EACV4I,EAAI,OAAO,CACb,CAAC,EACDlM,EAAQ,CAAC,EACTC,EAAgB,KACX8J,IACHhJ,EAAe,KACfC,EAAY,MAEdC,EAAa,EACf,CAEA,SAASiO,GACPpG,EACAjB,EACA0B,EACAC,EACAgD,EAAU,GACV,CACA,IAAIjJ,EAAM,IACRC,EAAM,KACN8V,EAAM,EACNC,EAAI,EACN,QAAS3O,EAAI,EAAGA,EAAI9B,EAAM,OAAQ8B,IAAK,CACrC,GAAI9B,EAAM8B,CAAC,GAAK,MAAQ9B,EAAM8B,CAAC,EAAKrB,GAAQT,EAAM8B,CAAC,EAAKpB,EAAM,SAC9D,IAAMzB,EAAIF,EAAM+C,CAAC,EACb7C,GAAK,MAAQ,CAAC,SAASA,CAAC,GACxBA,IAAM,GAAK,CAACyE,IAEZzE,EAAIxE,IAAKA,EAAMwE,GACfA,EAAIvE,IAAKA,EAAMuE,GACnBuR,GAAOvR,EACPwR,IACF,CACA,OAAOA,EAAI,CAAE,IAAAhW,EAAK,IAAAC,EAAK,IAAK8V,EAAMC,CAAE,EAAI,IAC1C,CAEA,SAASnK,GAAoB5I,EAAmB+C,EAAcC,EAAc,CAC1E,IAAIgQ,EAAO,EACTC,EAAO,EACLC,EAAyB,KACvBC,EAAS/Y,IAAU,WACnB6F,EAAKD,EAAI,CAAC,EAAE,MAAQ,EAE1B,QAASoE,EAAI,EAAGA,EAAIpE,EAAI,OAAQoE,IAAK,CACnC,IAAMxF,EAAIoB,EAAIoE,CAAC,EACTuL,EAAIwD,GAAUvU,EAAE,MAAQ,GAAK,KAAQA,EAAE,KAAQqB,GAAM,IAC3D,GAAI,EAAA0P,EAAI5M,GAAQ4M,EAAI3M,IAEhBpE,EAAE,KAAO,KAAM,CACjB,GAAIsU,GAAW,KAAM,CACnB,IAAME,EAAOxU,EAAE,IAAMsU,EACjBE,EAAO,EAAGJ,GAAQI,EACbA,EAAO,IAAGH,GAAQ,KAAK,IAAIG,CAAI,EAC1C,CACAF,EAAUtU,EAAE,GACd,CACF,CACA,MAAO,CAAE,KAAAoU,EAAM,KAAAC,CAAK,CACtB,CAGA,SAAStH,GACP7O,EACAgC,EACAsB,EACAkC,EACAjB,EACArB,EACArB,EACA0G,EACA,CACA,GAAIjF,GAAO,MAAQiB,EAAMjB,CAAG,GAAK,KAAM,CACrCtB,EAAG,MAAM,QAAU,OACnB,MACF,CAEA,IAAMuU,EAAKvW,EAAE,SAASwF,EAAMlC,CAAG,EAAI,IAAK,EAAK,EACvCmK,EAAKzN,EAAE,SAASuE,EAAMjB,CAAG,EAAI,IAAK,EAAK,EAEzCkT,EAAS,UACTC,EAAI,EACR,GAAInT,EAAM,GAAKJ,EAAII,CAAG,GAAKJ,EAAII,EAAM,CAAC,EAAG,CACvC,IAAMoT,GAAKxT,EAAII,EAAM,CAAC,EACpBqT,GAAKzT,EAAII,CAAG,EACR5C,IAAKiW,GAAG,MAAQ,IAAMD,GAAG,MAAQ,GACnChW,GAAI,IAAOiW,GAAG,KAAO,MAAQD,GAAG,KAAO,OACzCD,GAAME,GAAG,IAAMD,GAAG,KAAOhW,GAAK,IAC9B8V,EAASvR,GAAcwR,CAAC,EAE5B,CAEA,IAAIG,EACFrO,IAAc,YACV,GAAG1G,EAAI,IAAI0C,EAAMjB,CAAG,EAAI,EAAK,CAAC,SAASzB,EAAI,IAAI,GAC/C,GAAGA,EAAI,IAAI0C,EAAMjB,CAAG,EAAI,EAAK,CAAC,SAASzB,EAAI,IAAI,sCAAsC2U,CAAM,mCAA8B,KAAK,IAAIC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAGrJ,GAAIlO,IAAc,YAAcrF,EAAII,CAAG,EAAE,eAAiB,KACxDsT,EAAU,GAAG1T,EAAII,CAAG,EAAE,aAAa,oEAAoEiB,EAAMjB,CAAG,CAAC,mBACxGiF,IAAc,aAAerF,EAAII,CAAG,EAAE,gBAAkB,KACjEsT,EAAU,GAAG1T,EAAII,CAAG,EAAE,cAAc,oEAAoEiB,EAAMjB,CAAG,CAAC,mBACzGiF,IAAc,QAAS,CAChC,IAAMzG,GAAIoB,EAAII,CAAG,EACXuT,GACJ/U,GAAE,gBAAkB,KAChB,GAAGA,GAAE,cAAc,IACnBA,GAAE,WAAa,KACb,OAAOA,GAAE,SAAS,GAClB,GACFgV,GACJhV,GAAE,eAAiB,KACf,GAAGA,GAAE,aAAa,IAClBA,GAAE,UAAY,KACZ,OAAOA,GAAE,QAAQ,GACjB,IAEJ+U,IAASC,MACXF,GAAW,+DAA+DC,EAAK,MAAMC,EAAI,WAC7F,CAEI9U,EAAG,YAAc4U,IAAS5U,EAAG,UAAY4U,GAE7C,IAAMG,GAAU,GAAGlV,EAAI,KAAK,KACxBG,EAAG,MAAM,QAAUH,EAAI,QAAOG,EAAG,MAAM,MAAQH,EAAI,OACnDG,EAAG,MAAM,cAAgB+U,KAAS/U,EAAG,MAAM,YAAc+U,IAE7D,IAAM/H,EAAO,GAAGuH,CAAE,KACZxJ,GAAM,GAAGU,CAAE,KACX1F,GAAY,uBACd/F,EAAG,MAAM,OAASgN,IAAMhN,EAAG,MAAM,KAAOgN,GACxChN,EAAG,MAAM,MAAQ+K,KAAK/K,EAAG,MAAM,IAAM+K,IACrC/K,EAAG,MAAM,YAAc+F,KAAW/F,EAAG,MAAM,UAAY+F,IACvD/F,EAAG,MAAM,UAAY,KAAIA,EAAG,MAAM,QAAU,GAClD,CAEA,IAAMgV,GAAyB,IAAI,IACnC,SAASC,GAAkBR,EAA0B,CACnD,IAAIS,EAAIF,GAAuB,IAAIP,CAAC,EACpC,OAAKS,IACHA,EAAIvJ,GAAU1I,GAAcwR,CAAC,EAAG,EAAG,EACnCO,GAAuB,IAAIP,EAAGS,CAAC,GAE1BA,CACT,CAEA,SAASjK,GACPjN,EACAwF,EACAjB,EACAmE,EACA,CACA,IAAMkF,EAAM5N,EAAE,IACR8N,EAAK9N,EAAE,KACP6N,EAAM,OAAO,kBAAoB,EACjC5H,EAAOjG,EAAE,OAAO,GAAG,KAAO,KAC1BkG,EAAOlG,EAAE,OAAO,GAAG,KAAO,IAC1BmX,EAAOnX,EAAE,OAAO,GAAG,KAAO,EAC1BoX,EAAOpX,EAAE,OAAO,GAAG,KAAO,IAC1BqX,EAASvJ,EAAG,OAAS5H,EAAOD,GAAQ,GACpCqR,EAASxJ,EAAG,QAAUsJ,EAAOD,GAAQ,GACrCI,GAAQzJ,EAAG,IAAMA,EAAG,OAEpB0J,EAAOxX,EAAE,OAAO,CAAC,GAAG,KACpByX,GAASD,EAAO,KAAK,IAAI,EAAGA,EAAK,CAAC,CAAC,EAAI,EACvCE,GAAOF,EAAO,KAAK,IAAIhS,EAAM,OAAS,EAAGgS,EAAK,CAAC,EAAI,CAAC,EAAIhS,EAAM,OAAS,EACvErE,GAAO,KAAK,IAAI,EAAG,KAAK,OAAOuW,GAAOD,IAAU,GAAG,CAAC,EAE1D7J,EAAI,KAAK,EACTA,EAAI,UAAY,IAAMC,EAEtB,IAAM8J,GAAU,IAAI,IAEhBC,GAAUH,GAAS,EACvB,QAASnQ,GAAImQ,GAAQnQ,IAAKoQ,GAAMpQ,IAAKnG,GAAM,CACzC,IAAM0W,GAAMrS,EAAM8B,EAAC,EACbwQ,GAAMtS,EAAMoS,EAAO,EAGzB,GAFAA,GAAUtQ,GACNuQ,IAAO,MAAQtT,EAAM+C,EAAC,GAAK,MAAQwQ,IAAO,MAAQvT,EAAM+C,GAAInG,EAAI,GAAK,MACrE0W,GAAM5R,GAAQ6R,GAAM5R,EAAM,SAE9B,IAAM6R,GAAKjK,EAAG,MAAQgK,GAAM7R,GAAQoR,EAC9BW,GAAKT,IAAShT,EAAM+C,GAAInG,EAAI,EAAKgW,GAAQG,EACzCW,GAAKnK,EAAG,MAAQ+J,GAAM5R,GAAQoR,EAC9Ba,GAAKX,IAAShT,EAAM+C,EAAC,EAAK6P,GAAQG,EAElCb,GAAI/N,GAAYA,EAASpB,EAAC,GAAK,KAAO,KAAK,MAAMoB,EAASpB,EAAC,EAAK,CAAC,EAAI,EAAI,KACzE6Q,GAAQlB,GAAkBR,EAAC,EAC7B2B,GAAOT,GAAQ,IAAIQ,EAAK,EACvBC,KACHA,GAAO,CAAC,EACRT,GAAQ,IAAIQ,GAAOC,EAAI,GAEzBA,GAAK,KAAKL,GAAIC,GAAIC,GAAIC,EAAE,CAC1B,CAEA,OAAW,CAACC,GAAOC,EAAI,IAAKT,GAAS,CACnC/J,EAAI,UAAU,EACdA,EAAI,YAAcuK,GAClB,QAASE,GAAI,EAAGA,GAAID,GAAK,OAAQC,IAAK,EACpCzK,EAAI,OAAOwK,GAAKC,EAAC,EAAGD,GAAKC,GAAI,CAAC,CAAC,EAC/BzK,EAAI,OAAOwK,GAAKC,GAAI,CAAC,EAAGD,GAAKC,GAAI,CAAC,CAAC,EAErCzK,EAAI,OAAO,CACb,CAEAA,EAAI,QAAQ,CACd,CAEA,SAASV,GAAkBlN,EAAUwF,EAAiBjB,EAAiB,CACrE,IAAMqJ,EAAM5N,EAAE,IACR8N,EAAK9N,EAAE,KACP6N,EAAM,OAAO,kBAAoB,EACjC5H,EAAOjG,EAAE,OAAO,GAAG,KAAO,KAC1BkG,EAAOlG,EAAE,OAAO,GAAG,KAAO,IAC1BmX,EAAOnX,EAAE,OAAO,GAAG,KAAO,EAC1BoX,EAAOpX,EAAE,OAAO,GAAG,KAAO,IAC1BqX,EAASvJ,EAAG,OAAS5H,EAAOD,GAAQ,GACpCqR,EAASxJ,EAAG,QAAUsJ,EAAOD,GAAQ,GACrCI,EAAQzJ,EAAG,IAAMA,EAAG,OAEpB0J,GAAOxX,EAAE,OAAO,CAAC,GAAG,KACpByX,EAASD,GAAO,KAAK,IAAI,EAAGA,GAAK,CAAC,CAAC,EAAI,EACvCE,GAAOF,GAAO,KAAK,IAAIhS,EAAM,OAAS,EAAGgS,GAAK,CAAC,EAAI,CAAC,EAAIhS,EAAM,OAAS,EACvErE,GAAO,KAAK,IAAI,EAAG,KAAK,OAAOuW,GAAOD,GAAU,GAAG,CAAC,EAE1D7J,EAAI,KAAK,EACTA,EAAI,UAAY,IAAMC,EAEtB,IAAM8J,GAAU,IAAI,IAEhBC,GAAUH,EAAS,EACvB,QAASnQ,GAAImQ,EAAQnQ,IAAKoQ,GAAMpQ,IAAKnG,GAAM,CACzC,IAAM0W,GAAMrS,EAAM8B,EAAC,EACbwQ,GAAMtS,EAAMoS,EAAO,EAGzB,GAFAA,GAAUtQ,GACNuQ,IAAO,MAAQtT,EAAM+C,EAAC,GAAK,MAAQwQ,IAAO,MAAQvT,EAAM+C,GAAInG,EAAI,GAAK,MACrE0W,GAAM5R,GAAQ6R,GAAM5R,EAAM,SAE9B,IAAM6R,GAAKjK,EAAG,MAAQgK,GAAM7R,GAAQoR,EAC9BW,GAAKT,GAAShT,EAAM+C,GAAInG,EAAI,EAAKgW,GAAQG,EACzCW,GAAKnK,EAAG,MAAQ+J,GAAM5R,GAAQoR,EAC9Ba,GAAKX,GAAShT,EAAM+C,EAAC,EAAK6P,GAAQG,EAElCb,GAAI,KAAK,MAAMlS,EAAM+C,EAAC,EAAK,CAAC,EAAI,EAChC6Q,GAAQlB,GAAkBR,EAAC,EAC7B2B,GAAOT,GAAQ,IAAIQ,EAAK,EACvBC,KACHA,GAAO,CAAC,EACRT,GAAQ,IAAIQ,GAAOC,EAAI,GAEzBA,GAAK,KAAKL,GAAIC,GAAIC,GAAIC,EAAE,CAC1B,CAEA,OAAW,CAACC,GAAOC,EAAI,IAAKT,GAAS,CACnC/J,EAAI,UAAU,EACdA,EAAI,YAAcuK,GAClB,QAASE,GAAI,EAAGA,GAAID,GAAK,OAAQC,IAAK,EACpCzK,EAAI,OAAOwK,GAAKC,EAAC,EAAGD,GAAKC,GAAI,CAAC,CAAC,EAC/BzK,EAAI,OAAOwK,GAAKC,GAAI,CAAC,EAAGD,GAAKC,GAAI,CAAC,CAAC,EAErCzK,EAAI,OAAO,CACb,CAEAA,EAAI,QAAQ,CACd,CAEA,SAAS0K,GAActY,EAAUuE,EAAiB4T,EAAejV,EAAmB,CAClF,IAAMI,EAAMtD,EAAE,OAAO,IACrB,GAAIsD,GAAO,MAAQiB,EAAMjB,CAAG,GAAK,MAAQtD,EAAE,OAAO,KAAQ,EAAG,OAE7D,IAAMmD,EAAKD,EAAI,CAAC,EAAE,MAAQ,EACpBqV,EAAOjb,IAAU,YAAc4F,EAAII,CAAG,EAAE,MAAQ,GAAK,KAAQJ,EAAII,CAAG,EAAE,KAAQH,GAAM,IACpFoT,EAAKvW,EAAE,SAASuY,EAAM,IAAK,EAAI,EAC/B9K,EAAKzN,EAAE,SAASuE,EAAMjB,CAAG,EAAG,IAAK,EAAI,EACrCwK,EAAK9N,EAAE,KACP4N,EAAM5N,EAAE,IACR6N,EAAM,OAAO,kBAAoB,EAGvCD,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,EAAK,EAAIA,CAAG,CAAC,EAClCD,EAAI,YAAcD,GAAUwK,EAAO,EAAG,EACtCvK,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO2I,EAAIzI,EAAG,GAAG,EACrBF,EAAI,OAAO2I,EAAI9I,CAAE,EACjBG,EAAI,OAAOE,EAAG,KAAML,CAAE,EACtBG,EAAI,OAAO2I,EAAI9I,CAAE,EACjBG,EAAI,OAAO,EAGXA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,IAAI2I,EAAI9I,EAAI,EAAII,EAAK,EAAG,KAAK,GAAK,CAAC,EACvCD,EAAI,UAAY,UAChBA,EAAI,KAAK,EACTA,EAAI,YAAcuK,EAClBvK,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EACXA,EAAI,QAAQ,CACd,CAEA,SAASF,GACP1N,EACAkD,EACAI,EACA6U,EACAK,EAAkB,EAClB,CACA,IAAM3K,EAAM,OAAO,kBAAoB,EACjCC,EAAK9N,EAAE,KACP4N,EAAM5N,EAAE,IACRuY,EACJjb,IAAU,YACL4F,EAAII,CAAG,EAAE,MAAQ,GAAK,KACtBJ,EAAII,CAAG,EAAE,MAASJ,EAAI,CAAC,EAAE,MAAQ,IAAM,IACxCqT,EAAKvW,EAAE,SAASuY,EAAM,IAAK,EAAI,EAErC3K,EAAI,KAAK,EACTA,EAAI,YAAc4K,EAClB5K,EAAI,UAAU,EACdA,EAAI,YAAcuK,EAClBvK,EAAI,UAAY,EAAIC,EAEpBD,EAAI,OAAO2I,EAAIzI,EAAG,IAAM,GAAKD,CAAG,EAChCD,EAAI,OAAO2I,EAAIzI,EAAG,IAAMA,EAAG,OAAS,GAAKD,CAAG,EAC5CD,EAAI,OAAO,EACXA,EAAI,QAAQ,CACd,CAEA,SAASe,GACP3O,EACAkD,EACAI,EACA6U,EACAM,EAAW,GACXD,EAAkB,EAClB,CACA,IAAM3K,EAAM,OAAO,kBAAoB,EACjCC,EAAK9N,EAAE,KACP4N,EAAM5N,EAAE,IACRmD,EAAKD,EAAI,CAAC,EAAE,MAAQ,EACpBwV,GAAWxV,EAAII,CAAG,EAAE,MAAQ,GAAK,IACjCqV,GAAWzV,EAAII,CAAG,EAAE,KAAQH,GAAM,IAClCoT,EAAKvW,EAAE,SAAS1C,IAAU,WAAaob,EAAUC,EAAS,IAAK,EAAI,EAGnEC,GAActb,IAAU,WAAa,GAAGob,EAAQ,QAAQ,CAAC,CAAC,MAAQ7S,GAAQ8S,CAAO,EAEjFE,EAAWvb,IAAU,WAAauI,GAAQ8S,CAAO,EAAI,GAAGD,EAAQ,QAAQ,CAAC,CAAC,MAE1EI,GAAW,CAACC,GAAclG,GAAWmG,GAAWC,KAAmB,CACvE,IAAMhL,GAAU,QAAQ,GAAKJ,CAAG,2BAC5BD,EAAI,OAASK,KAASL,EAAI,KAAOK,IAErC,IAAMM,GADKX,EAAI,YAAYmL,EAAI,EAAE,MACjB,GAAKlL,EACfW,GAAK,GAAKX,EACVqL,GAAKrG,GAAItE,GAAK,EACd4K,GAAY,KAAK,IAAIrL,EAAG,KAAM,KAAK,IAAIA,EAAG,KAAOA,EAAG,MAAQS,GAAI2K,EAAE,CAAC,EACnEE,GAAKJ,GAAIxK,GAAK,EAEpBZ,EAAI,KAAK,EACTA,EAAI,YAAc4K,EAClB5K,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,UAAU,EACTA,EAAY,UAAYA,EAAY,UAAUuL,GAAWC,GAAI7K,GAAIC,GAAI,EAAIX,CAAG,EAC5ED,EAAI,KAAKuL,GAAWC,GAAI7K,GAAIC,EAAE,EACnCZ,EAAI,UAAY,sBAChBA,EAAI,KAAK,EACTA,EAAI,YAAcD,GAAUwK,EAAO,GAAI,EACvCvK,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EAEXA,EAAI,UAAYuK,EAChBvK,EAAI,UAAY,SAChBA,EAAI,aAAe,SACnBA,EAAI,SAASmL,GAAMI,GAAY5K,GAAK,EAAG6K,GAAK5K,GAAK,EAAI,GAAMX,CAAG,EAC9DD,EAAI,QAAQ,CACd,EAEK6K,GAAU/K,GAAqB1N,EAAGkD,EAAKI,EAAK6U,EAAOK,CAAO,EAE/D,IAAMa,GAAQ,GAAKxL,EAEnBiL,GAASD,EAAUtC,EAAIzI,EAAG,IAAMuL,GAAQ,EAAG,EAAI,EAG/CP,GAASF,GAAarC,EAAIzI,EAAG,IAAMA,EAAG,OAAS,GAAKD,EAAK,EAAK,CAChE,CAEA,SAAST,GACPpN,EACAwF,EACAjB,EACA4T,EACAtW,EACAqB,EACAqF,EACA,CACA,GAAI1K,GAAe,KAAM,OACzB,IAAM0a,EAAO/S,EAAM3H,CAAW,EACxByb,EAAO/U,EAAM1G,CAAW,EAC9B,GAAI0a,GAAQ,MAAQe,GAAQ,KAAM,OAElC,IAAM/C,EAAKvW,EAAE,SAASuY,EAAM,IAAK,EAAI,EAC/B9K,EAAKzN,EAAE,SAASsZ,EAAM,IAAK,EAAI,EAC/BxL,EAAK9N,EAAE,KACP4N,EAAM5N,EAAE,IACR6N,GAAM,OAAO,kBAAoB,EAEvCD,EAAI,KAAK,EAETA,EAAI,UAAU,EACdA,EAAI,YAAcuK,EAClBvK,EAAI,UAAY,IAAMC,GACtBD,EAAI,OAAO2I,EAAIzI,EAAG,GAAG,EACrBF,EAAI,OAAO2I,EAAIzI,EAAG,IAAMA,EAAG,MAAM,EACjCF,EAAI,OAAO,EAGXA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,GAAK,EAAIA,EAAG,CAAC,EAClCD,EAAI,YAAcD,GAAUwK,EAAO,EAAG,EACtCvK,EAAI,UAAY,EAAIC,GACpBD,EAAI,OAAOE,EAAG,KAAML,CAAE,EACtBG,EAAI,OAAO2I,EAAI9I,CAAE,EACjBG,EAAI,OAAO,EAGXA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,IAAI2I,EAAI9I,EAAI,EAAII,GAAK,EAAG,KAAK,GAAK,CAAC,EACvCD,EAAI,UAAY,UAChBA,EAAI,KAAK,EACTA,EAAI,YAAcuK,EAClBvK,EAAI,UAAY,IAAMC,GACtBD,EAAI,OAAO,EACXA,EAAI,QAAQ,EAEZ,IAAMlG,EAAK1H,EAAU,SACjB0H,GAAKA,EAAE,SACTmH,GACE7O,EACA0H,EAAE,QACF7J,EACA2H,EACAjB,EACArB,EACArB,EACA0G,CACF,CAEJ,CAEA,SAAS8E,GACPrN,EACAwF,EACAjB,EACA+U,EACAnB,EACAtW,EACA,CACA,IAAMiM,EAAK9N,EAAE,KACP4N,EAAM5N,EAAE,IACR6N,EAAM,OAAO,kBAAoB,EACjCJ,EAAKzN,EAAE,SAASsZ,EAAM,IAAK,EAAI,EAG/BC,EAAU,KAAK,IAAIzL,EAAG,IAAK,KAAK,IAAIA,EAAG,IAAMA,EAAG,OAAQL,CAAE,CAAC,EAEjEG,EAAI,KAAK,EAETA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,EAAK,EAAIA,CAAG,CAAC,EAClCD,EAAI,YAAcD,GAAUwK,EAAO,EAAG,EACtCvK,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAOE,EAAG,KAAMyL,CAAO,EAC3B3L,EAAI,OAAOE,EAAG,KAAOA,EAAG,MAAOyL,CAAO,EACtC3L,EAAI,OAAO,EAGX4L,GAAkBxZ,EAAGwF,EAAOjB,EAAOgV,EAASpB,CAAK,EAGjD,IAAMjQ,EAAQrG,EAAI,IAAIyX,EAAM,EAAI,EAC1BrL,EAAU,QAAQ,GAAKJ,CAAG,2BAC5BD,EAAI,OAASK,IAASL,EAAI,KAAOK,GAErC,IAAMM,EADKX,EAAI,YAAY1F,CAAK,EAAE,MAClB,EAAI2F,EACdW,GAAK,GAAKX,EACVY,GAAKX,EAAG,KAAOS,EAAK,EAAIV,EACxBa,GAAK6K,EAAU/K,GAAK,EAE1BZ,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EACbA,EAAY,UAAYA,EAAY,UAAUa,GAAIC,GAAIH,EAAIC,GAAI,EAAIX,CAAG,EACrED,EAAI,KAAKa,GAAIC,GAAIH,EAAIC,EAAE,EAC5BZ,EAAI,UAAY,sBAChBA,EAAI,KAAK,EACTA,EAAI,YAAcuK,EAClBvK,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EAEXA,EAAI,UAAY,OAChBA,EAAI,UAAY,SAChBA,EAAI,aAAe,SACnBA,EAAI,SAAS1F,EAAOuG,GAAKF,EAAK,EAAGG,GAAKF,GAAK,EAAI,GAAMX,CAAG,EACxDD,EAAI,QAAQ,CACd,CAEA,SAAS4L,GACPxZ,EACAwF,EACAjB,EACAgV,EACApB,EACA,CACA,IAAMvK,EAAM5N,EAAE,IACR8N,EAAK9N,EAAE,KACPiG,EAAOjG,EAAE,OAAO,GAAG,KAAO,KAC1BkG,EAAOlG,EAAE,OAAO,GAAG,KAAO,IAC1BmX,EAAOnX,EAAE,OAAO,GAAG,KAAO,EAC1BoX,EAAOpX,EAAE,OAAO,GAAG,KAAO,IAC1BqX,EAASvJ,EAAG,OAAS5H,EAAOD,GAAQ,GACpCqR,EAASxJ,EAAG,QAAUsJ,EAAOD,GAAQ,GACrCsC,GAAOzZ,EAAE,OAAO,GAAG,KAAO,EAC1BuX,EAAQkC,KAAS,GAAK3L,EAAG,IAAMA,EAAG,IAAMA,EAAG,OAC3C4L,GAAQD,KAAS,GAAKnC,EAAS,CAACA,EAEhCE,GAAOxX,EAAE,OAAO,CAAC,GAAG,KACpByX,GAASD,GAAO,KAAK,IAAI,EAAGA,GAAK,CAAC,EAAI,CAAC,EAAI,EAC3CE,GAAOF,GAAO,KAAK,IAAIhS,EAAM,OAAS,EAAGgS,GAAK,CAAC,EAAI,CAAC,EAAIhS,EAAM,OAAS,EACvErE,GAAO,KAAK,IAAI,EAAG,KAAK,OAAOuW,GAAOD,IAAU,GAAG,CAAC,EAE1D7J,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,KAAKE,EAAG,KAAMA,EAAG,IAAKA,EAAG,MAAOA,EAAG,MAAM,EAC7CF,EAAI,KAAK,EAETA,EAAI,UAAYD,GAAUwK,EAAO,EAAG,EACpCvK,EAAI,UAAU,EAEd,IAAI+L,GAAY,GACZC,GAAgB,GAChBC,GAAS,EAEb,QAASvS,GAAImQ,GAAQnQ,IAAKoQ,GAAMpQ,IAAKnG,GAAM,CACzC,IAAM2Y,GAAKtU,EAAM8B,EAAC,EACZyS,GAAKxV,EAAM+C,EAAC,EAClB,GAAIwS,IAAM,MAAQC,IAAM,MAAQD,GAAK7T,GAAQ6T,GAAK5T,EAAM,CAClDyT,KACF/L,EAAI,OAAOiM,GAAQN,CAAO,EAC1B3L,EAAI,UAAU,EACd+L,GAAY,IAEd,QACF,CAEA,IAAMK,GAAKlM,EAAG,MAAQgM,GAAK7T,GAAQoR,EAC7B4C,GAAK1C,GAASwC,GAAK5C,GAAQuC,GACjCG,GAASG,GAELC,GAAKV,GACFI,KACH/L,EAAI,OAAOoM,GAAIT,CAAO,EACtBI,GAAY,GACZC,GAAgB,IAElBhM,EAAI,OAAOoM,GAAIC,EAAE,GACRN,KACT/L,EAAI,OAAOoM,GAAIT,CAAO,EACtB3L,EAAI,UAAU,EACd+L,GAAY,GAEhB,CAEIA,KACF/L,EAAI,OAAOiM,GAAQN,CAAO,EAC1B3L,EAAI,UAAU,GAGZgM,IACFhM,EAAI,KAAK,EAGXA,EAAI,QAAQ,CACd,CAGA,SAASxI,GAAQpE,EAAWC,EAAWC,EAAW,CAChD,IAAMgZ,EAAK,SAASlZ,EAAE,MAAM,CAAC,EAAG,EAAE,EAChCwN,EAAK,SAASvN,EAAE,MAAM,CAAC,EAAG,EAAE,EACxBkZ,EAAKD,GAAM,GACfE,EAAMF,GAAM,EAAK,IACjBG,EAAKH,EAAK,IACNI,EAAK9L,GAAM,GACf+L,EAAM/L,GAAM,EAAK,IACjBV,EAAKU,EAAK,IACNgM,EAAKL,GAAMG,EAAKH,GAAMjZ,EAC1BuZ,EAAKL,GAAMG,EAAKH,GAAMlZ,EACtBwZ,GAAKL,GAAMvM,EAAKuM,GAAMnZ,EACxB,MAAO,MAAM,GAAK,KAAO,KAAK,MAAMsZ,CAAE,GAAK,KAAO,KAAK,MAAMC,CAAE,GAAK,GAAK,KAAK,MAAMC,EAAE,GACnF,SAAS,EAAE,EACX,MAAM,CAAC,CAAC,EACb,CAEA,SAASzV,GAAcwR,EAAkB,CACvC,GAAIA,GAAK,KAAM,MAAO,UACtB,IAAMkE,EAAO,KAAK,IAAIlE,CAAC,EACjBvV,EAAI,KAAK,IAAI,EAAGyZ,EAAO,CAAC,EAC9B,OAAIlE,EAAI,EAAUrR,GAAQ,UAAW,UAAWlE,CAAC,EAC1CkE,GAAQ,UAAW,UAAWlE,CAAC,CACxC,CAEA,SAASiE,GAAWuC,EAAkB,CACpC,GAAIA,GAAK,KAAM,MAAO,UACtB,IAAMkT,EAAMlT,EAAI,IAEhB,GAAIkT,GAAO,EAAG,MAAO,UACrB,GAAIA,GAAO,GAAI,MAAO,UAGtB,GAAIA,GAAO,GAAI,CACb,IAAM1Z,GAAK0Z,EAAM,GAAK,GACtB,OAAI1Z,GAAK,IAAakE,GAAQ,UAAW,UAAWlE,EAAI,GAAI,EACxDA,GAAK,GAAYkE,GAAQ,UAAW,WAAYlE,EAAI,KAAQ,GAAI,EAChEA,GAAK,IAAakE,GAAQ,UAAW,WAAYlE,EAAI,IAAO,GAAI,EAC7DkE,GAAQ,UAAW,WAAYlE,EAAI,KAAQ,GAAI,CACxD,KAAO,CAEL,IAAMA,GAAK0Z,EAAM,IAAM,GACvB,OAAOxV,GAAQ,UAAW,UAAWlE,CAAC,CACxC,CACF,CAEA,SAASyH,GAAezF,EAAmB2X,EAAsB,CAC/D,IAAMC,EAA2B,IAAI,MAAM5X,EAAI,MAAM,EAAE,KAAK,IAAI,EAChE,QAASoE,EAAI,EAAGA,EAAIpE,EAAI,OAAQoE,IAAK,CACnC,IAAMxF,EAAIoB,EAAIoE,CAAC,EACXyT,EAAKzT,EACP0T,EAAK1T,EACP,KAAOyT,EAAK,IAAMjZ,EAAE,MAAQ,IAAMoB,EAAI6X,CAAE,EAAE,MAAQ,GAAKF,EAAe,GAAGE,IACzE,KAAOC,EAAK9X,EAAI,OAAS,IAAMA,EAAI8X,CAAE,EAAE,MAAQ,IAAMlZ,EAAE,MAAQ,GAAK+Y,EAAe,GAAGG,IACtF,IAAMta,GAAKwC,EAAI8X,CAAE,EAAE,MAAQ,IAAM9X,EAAI6X,CAAE,EAAE,MAAQ,GAC7Cra,EAAI,GAAKwC,EAAI8X,CAAE,EAAE,KAAO,MAAQ9X,EAAI6X,CAAE,EAAE,KAAO,OACjDD,EAAMxT,CAAC,GAAMpE,EAAI8X,CAAE,EAAE,IAAO9X,EAAI6X,CAAE,EAAE,KAAQra,EAAK,IACrD,CACA,OAAOoa,CACT,CAEA,SAAS1S,GAAU6S,EAAyB,CAC1C,IAAMC,EAAM,CAAC,GAAGD,CAAI,EACpB,QAAS3T,EAAI,EAAGA,EAAI4T,EAAI,OAAQ5T,IAC9B,GAAI4T,EAAI5T,CAAC,IAAM,KAAM,CACnB,IAAI0H,EAAO1H,EAAI,EACf,KAAO0H,GAAQ,GAAKkM,EAAIlM,CAAI,IAAM,MAAMA,IACxC,IAAImM,EAAQ7T,EAAI,EAChB,KAAO6T,EAAQD,EAAI,QAAUA,EAAIC,CAAK,IAAM,MAAMA,IAC9CnM,GAAQ,GAAKmM,EAAQD,EAAI,OAC3BA,EAAI5T,CAAC,EAAI4T,EAAIlM,CAAI,GAAOkM,EAAIC,CAAK,EAAKD,EAAIlM,CAAI,IAAO1H,EAAI0H,IAAUmM,EAAQnM,GACpEA,GAAQ,EAAGkM,EAAI5T,CAAC,EAAI4T,EAAIlM,CAAI,EAC5BmM,EAAQD,EAAI,SAAQA,EAAI5T,CAAC,EAAI4T,EAAIC,CAAK,EACjD,CAEF,OAAOD,CACT,CAEA,SAAS9Y,GAAYX,EAAkB,CACrC,IAAMiG,EAAIjG,EAAM,MACVkE,EAAM,CAACC,EAAYvC,IAAgB,CACvC,IAAMrB,EAAK,SAAS,cAAc,IAAI4D,CAAE,cAAc,EAClD5D,IAAIA,EAAG,YAAcqB,EAC3B,EACAsC,EAAI,gBAAiB+B,EAAE,WAAa,KAAO,IAAIA,EAAE,UAAY,KAAM,QAAQ,CAAC,CAAC,MAAQ,QAAG,EACxF/B,EAAI,gBAAiB+B,EAAE,UAAY,KAAO7B,GAAQ,KAAK,MAAM6B,EAAE,SAAW,GAAI,CAAC,EAAI,QAAG,EACtF/B,EAAI,iBAAkB+B,EAAE,UAAY,KAAO,GAAG,KAAK,MAAMA,EAAE,QAAQ,CAAC,KAAO,QAAG,EAG9E,IAAM0T,EAAUrb,GAAgB,CAC9B,IAAM+B,EAAIpF,EAAM,KAAMoF,GAAMA,EAAE,YAAc/B,CAAG,EAC/C,GAAI,CAAC+B,EACH,OAAI/B,IAAQ,QAAgB2H,EAAE,UAAY,KACtC3H,IAAQ,QAAgB2H,EAAE,UAAY,KACtC3H,IAAQ,UAAkB2H,EAAE,YAAc,KACvC,KAET,GAAI5F,EAAE,SAAS,YAAc,OAC3B,OAAOA,EAAE,SAAS,UAAYA,EAAE,SAAS,UAAU,IAAM,KAE3D,IAAMoH,EACJ7L,EAAqB,IAAI0C,CAAG,GAAMA,IAAQ,SAAWA,IAAQ,WAAaA,IAAQ,QAC9EyE,EAAO1C,EAAE,MAAM,OAAQ2C,GAAmBA,GAAK,OAASyE,GAAWzE,IAAM,EAAE,EACjF,OAAKD,EAAK,OACHA,EAAK,OAAO,CAACxD,EAAGC,IAAMD,EAAIC,EAAG,CAAC,EAAIuD,EAAK,OADrB,IAE3B,EAEM6W,EAAWD,EAAO,OAAO,EAC/BzV,EAAI,iBAAkB0V,GAAY,KAAO,IAAIA,EAAW,KAAK,QAAQ,CAAC,CAAC,QAAU,QAAG,EAEpF,IAAMC,EAAWF,EAAO,OAAO,EAC/BzV,EAAI,iBAAkB2V,GAAY,KAAO,GAAG,KAAK,MAAMA,CAAQ,CAAC,KAAO,QAAG,EAE1E,IAAMC,EAAaH,EAAO,SAAS,EACnCzV,EAAI,eAAgB4V,GAAc,KAAO,GAAG,KAAK,MAAMA,CAAU,CAAC,OAAS,QAAG,EAE9E5V,EAAI,cAAe+B,EAAE,OAAS,KAAO,GAAGA,EAAE,KAAK,OAAS,QAAG,EAC3D/B,EAAI,gBAAiB+B,EAAE,SAAW,KAAO,GAAGA,EAAE,QAAQ,QAAQ,CAAC,CAAC,SAAQ,QAAG,CAC7E,CAEA,IAAM8T,GAAe,MACfC,GAAQ,IAAI,aAAaD,EAAY,EACrCE,GAAO,IAAI,aAAaF,EAAY,EACpCG,GAAQ,IAAI,aAAaH,EAAY,EACrCI,GAAQ,IAAI,aAAaJ,EAAY,EACrCK,GAAQ,IAAI,aAAaL,EAAY,EACrCM,GAAa,IAAI,aAAaN,EAAY,EAC1CO,GAAY,IAAI,aAAa,EAAE,EAC/BC,GAAkB,CACtB,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,GAChF,EAEA,SAASC,GACPC,EACAC,EACAC,EACA,CACA,GAAI,CAACF,EAAW,OAAQ,MAAO,GAC/BH,GAAU,KAAK,CAAC,EAChB,IAAIM,EAAgB,EAEpB,QAASC,EAAK,EAAGA,EAAKJ,EAAW,OAAQI,IAAM,CAC7C,IAAMpZ,EAAMgZ,EAAWI,CAAE,EAAE,OACrBrG,EAAI,KAAK,IAAI/S,EAAI,OAAQsY,EAAY,EAC3C,GAAIvF,EAAI,EAAG,SAEX,QAAS3O,EAAI,EAAGA,EAAI2O,EAAG3O,IAAK,CAC1B,IAAMxF,EAAIoB,EAAIoE,CAAC,EACfmU,GAAMnU,CAAC,EAAIxF,EAAE,OAAS,EACtB4Z,GAAKpU,CAAC,EAAIxF,EAAE,IAAM,EAClB6Z,GAAMrU,CAAC,EAAIxF,EAAE,OAAS,EACtB8Z,GAAMtU,CAAC,EAAIxF,EAAE,KAAO,EACpB+Z,GAAMvU,CAAC,EAAIxF,EAAE,KAAO,CACtB,CAIA,IAAMya,EAAS,KAAK,IAAI,EAAG,KAAK,IAAItG,EAAI,EAAG,KAAK,MAAMkG,CAAW,CAAC,CAAC,EAC7DK,EAAO,KAAK,IAAID,EAAS,EAAG,KAAK,IAAItG,EAAG,KAAK,MAAMmG,CAAS,CAAC,CAAC,EAC9DK,EAAQ,EAAI,GAEZC,EAAWJ,EAAK,EAAI,EAAI,EAC9B,QAASK,EAAQ,EAAGA,EAAQD,EAAUC,IAAS,CAC7C,IAAMC,EAAY,EAAMD,EAAQ,IAC1BE,GAAW,GAAMF,EAAQ,KACzBG,EAAa,GAAK,IAAMH,EAAQ,IAChCI,GAAQ,KAAQJ,EAAQ,MAC9B,QAASrV,GAAI,EAAGA,GAAI2O,EAAI,EAAG3O,KAAK,CAC9B,IAAM0V,IACH,GAAKvB,GAAMnU,GAAI,CAAC,EACf,GAAKmU,GAAMnU,GAAI,CAAC,EAChB,GAAKmU,GAAMnU,EAAC,EACZ,GAAKmU,GAAMnU,GAAI,CAAC,EAChB,EAAImU,GAAMnU,GAAI,CAAC,GACjBmV,EACIQ,IACH,GAAKvB,GAAKpU,GAAI,CAAC,EACd,GAAKoU,GAAKpU,GAAI,CAAC,EACf,GAAKoU,GAAKpU,EAAC,EACX,GAAKoU,GAAKpU,GAAI,CAAC,EACf,EAAIoU,GAAKpU,GAAI,CAAC,GAChBmV,EACIS,IAASvB,GAAMrU,GAAI,CAAC,EAAI,EAAIqU,GAAMrU,EAAC,EAAIqU,GAAMrU,GAAI,CAAC,GAAK,IACvD6V,GAAKH,GAAQvB,GAAMnU,EAAC,EACpB8V,GAAQ,KAAK,IAAI,CAACD,GAAKA,GAAKL,CAAU,EACtCO,GACJV,EAAQ,EAAI,KAAK,IAAIrV,GAAIyV,GAAQlB,GAAMvU,EAAC,EAAI,GAAI,EAAMA,GAAIyV,GAAS,EAAK,GAC1EjB,GAAWxU,EAAC,EACV0V,GAAQJ,EAAYQ,GAAQH,GAAOJ,GAAWK,IAASrB,GAAMvU,EAAC,EAAI,GAAM+V,GAC5E,CACF,CAEA,QAASC,EAAO,EAAGA,EAAO,GAAIA,IAAQ,CACpC,IAAMC,EAAY,EAAID,EAAO,KAC7B,QAASE,GAAK,EAAGA,GAAKxB,GAAgB,OAAQwB,KAAM,CAClD,IAAMpX,EAAI4V,GAAgBwB,EAAE,EAC5B,GAAIpX,GAAK6P,EAAG,SACZ,IAAMwH,GAAOF,EAAYnX,EACrBsX,GAAS,EACTC,GAAS,EACTC,GAAc,EAClB,QAAStW,GAAI,EAAGA,GAAI2O,EAAG3O,KAGrB,GAFAoW,IAAU5B,GAAWxU,EAAC,EACtBqW,IAAU/B,GAAMtU,EAAC,EACbA,IAAKlB,EAAG,CACVsX,IAAU5B,GAAWxU,GAAIlB,CAAC,EAC1BuX,IAAU/B,GAAMtU,GAAIlB,CAAC,EACrB,IAAMyX,IAAOH,GAASC,GAAS,KAAQF,GACnCI,GAAMD,KAAaA,GAAcC,GACvC,CAEFxB,GAAiBuB,GAAc,IACjC,CAGA,QAAStW,GAAIiV,EAAQjV,GAAIkV,EAAMlV,KAAK,CAClC,IAAMwW,EAAO,KAAK,IAAI,EAAG,KAAK,IAAI,IAAMhC,GAAWxU,EAAC,EAAI,IAAQ,GAAK,EAAE,CAAC,EACxEyU,GAAU+B,CAAI,GAAK,GAAKlC,GAAMtU,EAAC,EAAIsU,GAAMW,CAAM,GAAK,KAChDuB,EAAO,IAAG/B,GAAU+B,EAAO,CAAC,GAAK,IACjCA,EAAO,KAAI/B,GAAU+B,EAAO,CAAC,GAAK,GACxC,CACF,CACF,CAEA,QAAS7c,EAAI,EAAGA,EAAI,GAAIA,IACtBob,GAAiBN,GAAU9a,CAAC,EAAI,KAElC,OAAInC,IACFA,EAAU,QAAQ,cAAgBud,EAAc,QAAQ,CAAC,GAEpDA,CACT,CAEA,MAAO,CACL,KAAAjd,GACA,UAAAoC,EACA,MAAAc,EACA,WAAAI,GACA,aAAAG,GACA,SAAAG,GACA,YAAAY,GACA,kBAAA6B,GACA,oBAAAhD,EACA,iBAAAqD,GACA,UAAAT,EACA,gBAAA1F,GACA,0BAAAsc,GACA,YAAa,CAAC3Y,EAAa3B,EAAc,KAAU,CAGjD,GAFA9D,EAAcyF,EACV9E,GAAeA,EAAc8E,CAAG,EAChC3B,EAAa,CACXtD,GAAkBd,GAAc,SAAS+F,CAAG,GAC9CjF,EAAed,EAAa,OAAO+F,CAAG,CAAC,EAEzC,MACF,CACArG,EAAgB,GAChBP,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,MAAAuE,EAAO,MAAAiB,CAAM,IAAM,CACxCA,EAAMlC,CAAG,GAAK,MAAQiB,EAAMjB,CAAG,GAAK,MACtCtD,EAAE,MAAM,IAAM,CACXA,EAAU,UACT,CACE,KAAMA,EAAE,SAASwF,EAAMlC,CAAG,EAAI,GAAG,EACjC,IAAKtD,EAAE,SAASuE,EAAMjB,CAAG,EAAI,GAAG,CAClC,EACA,GACA,EACF,CACF,CAAC,CAEL,CAAC,EACDrG,EAAgB,GACZoB,GAAkBd,GAAc,SAAS+F,CAAG,GAC9CjF,EAAed,EAAa,OAAO+F,CAAG,CAAC,CAE3C,EACA,WAAaA,GAAuB,CAClCrG,EAAgB,GAChBP,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,MAAAuE,EAAO,MAAAiB,CAAM,IAAM,CACxClC,IAAQ,KACVtD,EAAE,MAAM,IAAM,CACXA,EAAU,UAAU,CAAE,KAAM,IAAK,IAAK,GAAI,EAAG,GAAM,EAAK,CAC3D,CAAC,EACQwF,EAAMlC,CAAG,GAAK,MAAQiB,EAAMjB,CAAG,GAAK,MAC7CtD,EAAE,MAAM,IAAM,CACXA,EAAU,UACT,CACE,KAAMA,EAAE,SAASwF,EAAMlC,CAAG,EAAI,GAAG,EACjC,IAAKtD,EAAE,SAASuE,EAAMjB,CAAG,EAAI,GAAG,CAClC,EACA,GACA,EACF,CACF,CAAC,CAEL,CAAC,EACDrG,EAAgB,GACZoB,GACFA,EACEiF,GAAO,MAAQ/F,GAAc,SAAS+F,CAAG,EAAI/F,EAAa,OAAO+F,CAAG,EAAI,IAC1E,CAEJ,EACA,eAAgB,IAAM,CACpBzF,EAAc,KACVW,GAAeA,EAAc,IAAI,EACrC9B,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAMA,EAAE,OAAO,EAAK,CAAC,CACjD,EACA,OAAA8D,GACA,QAAAlC,GACA,WAAY,IAAMjE,EAClB,oBAAAoG,GACA,eAAAE,GACA,kBAAmB,IAAM/E,GACzB,iBAAkB,IAAMhC,EACxB,oBAAqB,IAAMC,EAC3B,iBAAA2F,EACA,kBAAoBC,GAAmB,CAGrC,IAAMgb,EAAY,IAAI,IACtBhb,EAAK,QAASoP,GAAM,CACdjV,EAAc,IAAIiV,CAAC,GAAG4L,EAAU,IAAI5L,CAAC,CAC3C,CAAC,EAEDjV,EAAc,QAASiV,GAAM,CACtB4L,EAAU,IAAI5L,CAAC,GAAG4L,EAAU,IAAI5L,CAAC,CACxC,CAAC,EACDjV,EAAgB6gB,EACZxgB,GAAc8E,GAAO,EAAI,CAC/B,EACA,SAAU,IAAM/E,CAClB,EAEA,SAAS6P,GACPnN,EACAwF,EACAjB,EACArB,EACAqF,EACA,CACA,IAAMqF,EAAM5N,EAAE,IACR8N,EAAK9N,EAAE,KACP6N,EAAM,OAAO,kBAAoB,EACjCxJ,EAASC,GAAoBiE,EAAWhE,CAAK,EAEnDqJ,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,KAAKE,EAAG,KAAMA,EAAG,IAAKA,EAAG,MAAOA,EAAG,MAAM,EAC7CF,EAAI,KAAK,EAET,IAAMoQ,EAAYzV,IAAc,YAAcA,IAAc,YAE5D,QAASjB,EAAI,EAAGA,EAAI9B,EAAM,OAAQ8B,IAAK,CACrC,GAAI9B,EAAM8B,CAAC,GAAK,MAAQ/C,EAAM+C,CAAC,GAAK,MAAQ9B,EAAM8B,EAAI,CAAC,GAAK,MAAQ/C,EAAM+C,EAAI,CAAC,GAAK,KAClF,SACF,IAAMyQ,EAAK/X,EAAE,SAASwF,EAAM8B,EAAI,CAAC,EAAI,IAAK,EAAI,EACxC0Q,EAAKhY,EAAE,SAASuE,EAAM+C,EAAI,CAAC,EAAI,IAAK,EAAI,EACxC2Q,GAAKjY,EAAE,SAASwF,EAAM8B,CAAC,EAAI,IAAK,EAAI,EACpC4Q,EAAKlY,EAAE,SAASuE,EAAM+C,CAAC,EAAI,IAAK,EAAI,EAEpC4P,GAAI7S,EAAOiD,CAAC,EAGlBsG,EAAI,UAAU,EACdA,EAAI,OAAOmK,EAAIC,CAAE,EACbgG,GAAWpQ,EAAI,OAAOqK,GAAID,CAAE,EAEhCpK,EAAI,OAAOqK,GAAIC,CAAE,EACjBtK,EAAI,YAAcsJ,GAClBtJ,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,CACb,CAEAA,EAAI,QAAQ,CACd,CAEA,SAASqQ,GAAqBje,EAAUuI,EAAmB1G,EAAuB,CAChF,GAAI,CAACrE,EAAU,OAAQ,OACvB,IAAMoQ,EAAM5N,EAAE,IACR8N,EAAK9N,EAAE,KACP6N,EAAM,OAAO,kBAAoB,EACjCqQ,EAAgB,IAEtBtQ,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,KAAKE,EAAG,KAAMA,EAAG,IAAKA,EAAG,MAAOA,EAAG,MAAM,EAC7CF,EAAI,KAAK,EAET,IAAMoQ,EAAYzV,IAAc,YAAcA,IAAc,YAE5D,QAAW9G,KAASjE,EAAW,CAC7B,GAAID,GAAgBkE,EAAM,KAAOlE,EAAa,GAAI,SAElD,IAAM2F,EAAMzB,EAAM,OACZ0B,EAAKD,EAAI,KAAMpB,IAAMA,GAAE,MAAQ,IAAI,GAAG,MAAQ,EAC9Cqc,EAAQtc,EAAI,MAElB+L,EAAI,UAAU,EACdA,EAAI,YAAc,4BAClBA,EAAI,UAAY,EAAIC,EAEpB,IAAIuQ,EAAQ,GACZ,QAAS9W,GAAI,EAAGA,GAAIpE,EAAI,OAAQoE,KAAK,CACnC,IAAMxF,EAAIoB,EAAIoE,EAAC,EACT7C,GAAI3C,EAAEqc,CAAK,EAEjB,GAAI1Z,IAAK,KAAM,CACb2Z,EAAQ,GACR,QACF,CAEA,GAAI9W,GAAI,EAAG,CACT,IAAM+K,GAAOnP,EAAIoE,GAAI,CAAC,GACXxF,EAAE,MAAQuQ,GAAK,KAAOvQ,EAAE,KAAOuQ,GAAK,KAAO,GAC7C6L,IAAeE,EAAQ,GAClC,CAEA,IAAM/a,GAAMxB,EAAI,UAAYA,EAAI,UAAU4C,EAAC,EAAIA,GAC/C,GAAIpB,IAAO,KAAM,CACf+a,EAAQ,GACR,QACF,CACA,IAAM7F,GAAOjb,IAAU,YAAcwE,EAAE,MAAQ,GAAK,KAAQA,EAAE,KAAQqB,GAAM,IAG5E,GAAIoV,GAAOvY,EAAE,OAAO,EAAG,IAAO,IAAMuY,GAAOvY,EAAE,OAAO,EAAG,IAAO,GAAI,CAChEoe,EAAQ,GACR,QACF,CAEA,IAAMpE,GAAKha,EAAE,SAASuY,GAAM,IAAK,EAAI,EAC/B0B,GAAKja,EAAE,SAASqD,GAAK,IAAK,EAAI,EAEpC,GAAI+a,EACFxQ,EAAI,OAAOoM,GAAIC,EAAE,EACjBmE,EAAQ,OACH,CACL,GAAIJ,EAAW,CACb,IAAMK,GAAQnb,EAAIoE,GAAI,CAAC,EACjBgX,GACJhhB,IAAU,YAAc+gB,GAAM,MAAQ,GAAK,KAAQA,GAAM,KAAQlb,GAAM,IACzEyK,EAAI,OAAO5N,EAAE,SAASse,GAAU,IAAK,EAAI,EAAGrE,EAAE,CAChD,CACArM,EAAI,OAAOoM,GAAIC,EAAE,CACnB,CACF,CACArM,EAAI,OAAO,CACb,CAEAA,EAAI,QAAQ,CACd,CAEA,SAASZ,GACPhN,EACAwF,EACAjB,EACA4T,EACAlJ,EACA1G,EACA2B,EAAiC,KACjChH,EAAoB,CAAC,EACrB,CACA,IAAM0K,EAAM5N,EAAE,IACR8N,EAAK9N,EAAE,KACP6N,EAAM,OAAO,kBAAoB,EACjCqQ,EAAgB,IAEtBtQ,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAcD,GAAUwK,EAAO,EAAG,EACtCvK,EAAI,UAAYqB,EAAQpB,EAExB,IAAMmQ,EAAYzV,IAAc,YAAcA,IAAc,YACxD6V,GAAQ,GACRG,EAA+B,KAC/BC,GAAO,EACPC,GAAO,EAEX,GAAIlW,IAAc,SAAWrF,EAAI,OAAS,EAAG,CAC3C,IAAI4O,GAAK,IACPC,GAAK,KACP,QAASzK,GAAI,EAAGA,GAAIpE,EAAI,OAAQoE,KAAK,CACnC,IAAMoX,GAAKxb,EAAIoE,EAAC,EAAE,gBAAkBpE,EAAIoE,EAAC,EAAE,UACvCoX,IAAM,OACJA,GAAK5M,KAAIA,GAAK4M,IACdA,GAAK3M,KAAIA,GAAK2M,IAEtB,CACI5M,IAAMC,KACRyM,GAAO1M,GACP2M,GAAO1M,GAEX,CAEA,IAAM4M,GAAOzU,EAAQA,EAAM,CAAC,EAAKlK,EAAE,OAAO,GAAG,KAAO,KAC9C4e,GAAO1U,EAAQA,EAAM,CAAC,EAAKlK,EAAE,OAAO,GAAG,KAAO,IAC9CiG,GAAOjG,EAAE,OAAO,GAAG,KAAO,KAC1BkG,GAAOlG,EAAE,OAAO,GAAG,KAAO,IAC1BmX,GAAOnX,EAAE,OAAO,GAAG,KAAO,EAC1BoX,GAAOpX,EAAE,OAAO,GAAG,KAAO,IAC1BqX,GAASvJ,EAAG,OAAS5H,GAAOD,IAAQ,GACpCqR,GAASxJ,EAAG,QAAUsJ,GAAOD,IAAQ,GACrCsC,GAAOzZ,EAAE,OAAO,GAAG,KAAO,EAC1BuX,GAAQkC,KAAS,GAAK3L,EAAG,IAAMA,EAAG,IAAMA,EAAG,OAC3C4L,GAAQD,KAAS,GAAKnC,GAAS,CAACA,GAEhCE,GAAQtN,EAA4B,KAApBlK,EAAE,OAAO,CAAC,GAAG,KAC7ByX,GAASD,GAAO,KAAK,IAAI,EAAGA,GAAK,CAAC,EAAI,CAAC,EAAI,EAC3CE,GAAOF,GAAO,KAAK,IAAIhS,EAAM,OAAS,EAAGgS,GAAK,CAAC,EAAI,CAAC,EAAIhS,EAAM,OAAS,EACvErE,GACJ6c,GAAazV,IAAc,QAAU,EAAI,KAAK,IAAI,EAAG,KAAK,OAAOmP,GAAOD,IAAU,GAAG,CAAC,EAClFoH,GAAavhB,IAAU,OACvBwhB,GAASZ,EAAgB,IAC3Ba,GAAatH,GAEjB,QAASnQ,GAAImQ,GAAQnQ,IAAKoQ,GAAMpQ,IAAKnG,GAAM,CACzC,IAAM2Y,GAAKtU,EAAM8B,EAAC,EACZyS,GAAKxV,EAAM+C,EAAC,EAClB,GAAIwS,IAAM,MAAQC,IAAM,KAAM,CAC5BqE,GAAQ,GACR,QACF,CAEA,GAAI7V,IAAc,SAAWrF,EAAIoE,EAAC,EAAG,CACnC,IAAMoX,GAAKxb,EAAIoE,EAAC,EAAE,gBAAkBpE,EAAIoE,EAAC,EAAE,UAC3C,GAAIoX,IAAM,MAAQA,KAAOH,EAAe,CACtC,GAAI,CAACH,IAAS9W,GAAI,EAAG,CACnBsG,EAAI,OAAO,EACXA,EAAI,UAAU,EACd,IAAMoR,GAAQlR,EAAG,MAAQtI,EAAMuZ,EAAU,EAAK9Y,IAAQoR,GAChD4H,GAAQ1H,IAAShT,EAAMwa,EAAU,EAAK5H,IAAQuC,GACpD9L,EAAI,OAAOoR,GAAOC,EAAK,CACzB,CAGA,IAAIC,GAAe/G,EACfsG,KAASD,IAAQE,IAAM,OACrBA,KAAOF,GACTU,GAAe,UACRR,KAAOD,GACdS,GAAe,UACZA,GAAe,WAEtBtR,EAAI,YAAcD,GAAUuR,GAAc,EAAG,EAC7CX,EAAgBG,EAClB,CACF,CAGA,GAAIpX,GAAImQ,IAAUoH,GAAY,CAC5B,IAAMM,GAAS3Z,EAAMuZ,EAAU,EAC3BI,IAAU,MAAQrF,GAAKqF,GAASL,KAAQV,GAAQ,GACtD,CAGA,GAAItE,GAAK6E,IAAQ7E,GAAK8E,GAAM,CAC1BR,GAAQ,GACR,QACF,CAEA,IAAMpE,GAAKlM,EAAG,MAAQgM,GAAK7T,IAAQoR,GAC7B4C,GAAK1C,IAASwC,GAAK5C,IAAQuC,GAEjC,GAAI0E,GACFxQ,EAAI,OAAOoM,GAAIC,EAAE,EACjBmE,GAAQ,OACH,CACL,GAAIJ,EAAW,CACb,IAAMmB,GAAS3Z,EAAMuZ,EAAU,EAC/BnR,EAAI,OAAOE,EAAG,MAAQqR,GAASlZ,IAAQoR,GAAQ4C,EAAE,CACnD,CACArM,EAAI,OAAOoM,GAAIC,EAAE,CACnB,CACA8E,GAAazX,EACf,CACAsG,EAAI,OAAO,EACXA,EAAI,QAAQ,CACd,CACF,GAAG,EIn5GH,IAAMwR,GAAuC,CAC3C,aAAcC,GAAQ,GAAG,KACzB,QAASA,GAAQ,QAAQ,KACzB,MAAOA,GAAQ,MAAM,KACrB,YAAaA,GAAQ,YAAY,KACjC,SAAUA,GAAQ,MAAM,KACxB,QAASA,GAAQ,QAAQ,IAC3B,EAEIC,GAA6B,IAAM,CAAC,EACpCC,GAAwC,IAAM,CAAC,EAC5C,SAASC,GAAYC,EAA0BC,EAAqC,CACzFJ,GAAiBG,EACjBF,GAAkBG,CACpB,CAEO,SAASC,IAAe,CAC7B,IAAMC,EAAY,SAAS,eAAe,cAAc,EACpDA,IACFA,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAO1B,CAEA,IAAMC,GAAa,MACbC,GAAiB,CACrB,IAAI,aAAaD,EAAU,EAC3B,IAAI,aAAaA,EAAU,EAC3B,IAAI,aAAaA,EAAU,EAC3B,IAAI,aAAaA,EAAU,EAC3B,IAAI,aAAaA,EAAU,EAC3B,IAAI,aAAaA,EAAU,EAC3B,IAAI,aAAaA,EAAU,CAC7B,EACME,GAAmB,CACvB,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAC9F,IAAK,IAAK,IAAK,IAAK,GACtB,EAEO,SAASC,GACdC,EACAC,EAAuB,CAAC,EACxBC,EAAyB,CAAC,EAC1B,CACA,IAAMP,EAAY,SAAS,eAAe,cAAc,EACxD,GAAI,CAACA,EAAW,OAEhB,GAAI,CAACK,EAAO,CACVL,EAAU,UAAY,GACtB,MACF,CAEA,IAAMQ,EAAIH,EAAM,MACVI,EAAKJ,EAAM,OAAO,CAAC,EAAE,KACrBK,EAAkBH,EAAU,OAAS,EAAIA,EAAY,CAACF,CAAK,EAI7DM,EAAiB,EAErB,QAASC,EAAK,EAAGA,EAAKF,EAAgB,OAAQE,IAAM,CAClD,IAAMC,EAAOH,EAAgBE,CAAE,EAAE,OAC3BE,EAAI,KAAK,IAAID,EAAK,OAAQZ,EAAU,EAC1C,GAAIa,IAAM,EAEV,SAASC,EAAI,EAAGA,EAAID,EAAGC,IAAK,CAC1B,IAAMC,EAAIH,EAAKE,CAAC,EAChBb,GAAe,CAAC,EAAEa,CAAC,EAAIC,EAAE,OAAS,EAClCd,GAAe,CAAC,EAAEa,CAAC,EAAIC,EAAE,IAAM,EAC/Bd,GAAe,CAAC,EAAEa,CAAC,EAAIC,EAAE,KAAO,EAChCd,GAAe,CAAC,EAAEa,CAAC,EAAIC,EAAE,OAAS,EAClCd,GAAe,CAAC,EAAEa,CAAC,EAAIC,EAAE,KAAO,EAChCd,GAAe,CAAC,EAAEa,CAAC,EAAIC,EAAE,MAAQ,EACjCd,GAAe,CAAC,EAAEa,CAAC,EAAIC,EAAE,MAAQ,CACnC,CAEA,QAASC,EAAO,EAAGA,EAAO,EAAGA,IAAQ,CACnC,IAAMC,EAAUD,EAAO,EAAI,EAAI,EAC/B,QAASE,EAAK,EAAGA,EAAKD,EAASC,IAAM,CACnC,IAAMC,EAAcH,EAAO,EACrBI,EAAeJ,IAAS,GAAKE,EAAK,EAClCG,EAAInB,GAAiBgB,CAAE,EAC7B,GAAIG,GAAKR,EAAG,SACZ,IAAMS,EAAO,EAAID,EACXE,GAAQ,KAAK,IAAI,EAAGF,GAAK,CAAC,EAChC,QAASG,EAAK,EAAGA,EAAK,EAAGA,IAAM,CAC7B,IAAMC,EAAKxB,GAAeuB,CAAE,EACxBE,EAAM,EACNC,EAAQ,EACRC,EAAU,EACVC,GAAY,EACVC,EAAW,GAAK,GAAKN,EAAK,GAAKN,EAAK,EAAIF,EAAO,GACrD,QAASF,EAAI,EAAGA,EAAID,EAAGC,IAAK,CAC1B,IAAMiB,GAAIN,EAAGX,CAAC,EAGd,GAFAY,GAAOK,GACPJ,GAASI,GAAIA,GACTjB,GAAKO,EAAG,CACV,IAAMW,GAAMP,EAAGX,EAAIO,CAAC,EACpBK,GAAOM,GACPL,GAASK,GAAMA,GACf,IAAMC,GAAOP,EAAMJ,EACbY,GAAW,KAAK,IAAI,EAAGP,EAAQL,EAAOW,GAAOA,EAAI,EACjDE,GAASV,EAAGX,EAAIS,EAAK,EACrBa,GAAOL,GAAIN,EAAGX,EAAI,CAAC,EACnBuB,GAAcD,GAAOA,GAAON,EAC5BQ,EAAanB,EAAc,KAAK,IAAI,CAACkB,EAAW,EAAI,GAAK,EAAIA,IACnER,IAAaO,GAAOA,GAAOE,EAC3B,IAAMC,EAAOnB,EAAe,KAAK,IAAI,CAACc,GAAW,IAAI,EAAI,GAAK,EAAIA,GAAW,MAC7EN,IAAYG,GAAIE,KAASE,GAASF,IAAQM,CAC5C,CACF,CACA7B,IAAmBkB,EAAUC,GAAY,MAAQhB,CACnD,CACF,CACF,EACF,CACA,IAAM2B,EAAwB,KAAK,IACjC,KACA,KAAK,IAAI,GAAM,GAAO,KAAK,KAAK9B,EAAiB,IAAK,EAAI,GAAG,CAC/D,EAAE,QAAQ,CAAC,EAEXX,EAAU,UAAY;AAAA;AAAA,2DAEmC0C,GAAQrC,EAAM,aAAeA,EAAM,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAUrFC,EAAW,IAAKqC,GAAM,kBAAkBD,GAAQC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sDAWxBnC,EAAE,UAAY,KAAM,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,qDAI/BA,EAAE,SAAWoC,GAAQ,KAAK,MAAMpC,EAAE,SAAW,GAAI,CAAC,EAAI,QAAG;AAAA;AAAA;AAAA;AAAA,qDAIzDA,EAAE,UAAYA,EAAE,SAAW,KAAK,QAAQ,CAAC,EAAI,QAAG;AAAA;AAAA;AAAA;AAAA,sDAI/CA,EAAE,SAAW,KAAK,QAAQ,CAAC,CAAC;AAAA;AAAA,YAGtEA,EAAE,aAAe,KACb;AAAA;AAAA,2DAE2CA,EAAE,UAAU;AAAA,wBAEvD,EACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kFASwEkC,GAAQrC,EAAM,UAAY,QAAG,CAAC;AAAA;AAAA;AAAA;AAAA,qDAI3DA,EAAM,SAAWwC,GAAYxC,EAAM,QAAQ,EAAI,QAAG;AAAA;AAAA;AAAA;AAAA,qDAIlDA,EAAM,OAAO,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,8GAK+ByC,GAAazC,EAAM,KAAK,CAAC;AAAA,sCACjGqC,GAAQK,GAAO1C,EAAM,OAAO,YAAY,GAAK,EAAE,GAAG,MAAQ,QAAG,CAAC;AAAA;AAAA,gBAEpFA,EAAM,SAAW,uDAAuDqC,GAAQrC,EAAM,QAAQ,CAAC,WAAa,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,qDAKzEA,EAAM,QAAU,gBAAgB;AAAA;AAAA;AAAA;AAAA,qDAIhCI,EAAKuC,GAAYvC,CAAE,EAAI,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qDAUhCJ,EAAM,OAAO,OAAO,eAAe,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA,qDAI3CoC,CAAqB;AAAA;AAAA;AAAA;AAAA;AAAA,gBAM1DjC,EAAE,QAAQ,OACNA,EAAE,QACC,IACEyC,GACC,wDAAwDP,GAAQO,CAAM,CAAC,KAAKzD,GAAayD,CAAM,GAAK,SAAS,SACjH,EACC,KAAK,EAAE,EACV,oEACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAONzC,EAAE,OAASA,EAAE,UAAYA,EAAE,YAAcA,EAAE,SAAW,KAClD;AAAA;AAAA;AAAA;AAAA,YAKAA,EAAE,MACE;AAAA;AAAA,2DAE2CA,EAAE,KAAK;AAAA,wBAElD,EACN;AAAA,YAEEA,EAAE,MACE;AAAA;AAAA,2DAE2CA,EAAE,KAAK;AAAA,wBAElD,EACN;AAAA,YAEEA,EAAE,SACE;AAAA;AAAA,2DAE2CA,EAAE,QAAQ;AAAA,wBAErD,EACN;AAAA,YAEEA,EAAE,SACE;AAAA;AAAA,2DAE2CA,EAAE,QAAQ;AAAA,wBAErD,EACN;AAAA,YAEEA,EAAE,WACE;AAAA;AAAA,2DAE2CA,EAAE,UAAU;AAAA,wBAEvD,EACN;AAAA,YAEEA,EAAE,SAAW,KACT;AAAA;AAAA,2DAE2CA,EAAE,QAAQ,QAAQ,CAAC,CAAC;AAAA,wBAE/D,EACN;AAAA,YAEEA,EAAE,SAAW,MAAQA,EAAE,SAAW,KAC9B;AAAA;AAAA,2DAE2CA,EAAE,QAAQ,QAAQ,CAAC,CAAC,WAAMA,EAAE,QAAQ,QAAQ,CAAC,CAAC;AAAA,wBAEzF,EACN;AAAA;AAAA,cAGE,EACN;AAAA;AAAA,QAGEA,EAAE,SAAW,KACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qDAMyCA,EAAE,MAAM;AAAA;AAAA;AAAA,cAIjD,EACN;AAAA;AAAA,QAGEH,EAAM,SAAWA,EAAM,QAAQ,OAAS,EACpC;AAAA;AAAA;AAAA;AAAA,aAIC,IAAM,CACP,IAAM6C,EAAO,IAAI,IACjB,OAAO7C,EACJ,QAAS,OAAQ8C,GAAM,CAEtB,GAAI,EADwBA,EAAE,MAAQA,EAAE,SAAWA,EAAE,cAC3B,MAAO,GAEjC,IAAMC,EAAM,GAAGD,EAAE,IAAI,IAAIA,EAAE,OAAO,IAAIA,EAAE,YAAY,IAAIA,EAAE,MAAM,GAChE,OAAID,EAAK,IAAIE,CAAG,EAAU,IAC1BF,EAAK,IAAIE,CAAG,EACL,GACT,CAAC,EACA,IAAKD,GAAM,CACV,IAAME,EAAOF,EAAE,MAAQA,EAAE,SAAW,iBAC9BG,EAAeH,EAAE,aACnB,uCAAuCA,EAAE,YAAY,UACrD,GACEI,EAAQ,CACZJ,EAAE,OAAS,OAAOA,EAAE,MAAM,GAAK,KAC/BA,EAAE,QAAU,IAAIA,EAAE,OAAO,GAAK,KAC9BA,EAAE,gBAAkB,MAAMA,EAAE,eAAe,GAAK,IAClD,EACG,OAAO,OAAO,EACd,KAAK,UAAK,EAEPK,EAAU,CACdL,EAAE,aAAe,GAAGA,EAAE,YAAY,IAAM,KACxCA,EAAE,cAAgB,WAAWA,EAAE,aAAa,GAAK,KACjDA,EAAE,eAAiB,GAAGA,EAAE,eAAe,QAAQ,CAAC,CAAC,IAAM,IACzD,EACG,OAAO,OAAO,EACd,KAAK,UAAK,EAETM,EAAa,GACXC,EAAK,OAAOP,EAAE,YAAc,EAAE,EAAE,YAAY,EAC9CO,EAAG,SAAS,OAAO,EAAGD,EAAa,SAC9BC,EAAG,SAAS,SAAS,GAAKA,EAAG,SAAS,UAAU,EACvDD,EAAa,yBACNC,EAAG,SAAS,WAAW,IAAGD,EAAa,aAEhD,IAAIE,EAAa,UACXC,EAAY,OAAOP,CAAI,EAAE,YAAY,EAC3C,OAAIO,EAAU,SAAS,WAAW,GAAKA,EAAU,SAAS,KAAK,EAC7DD,EAAalE,GAAQ,GAAG,KACjBmE,EAAU,SAAS,OAAO,EAAGD,EAAalE,GAAQ,MAAM,KACxDmE,EAAU,SAAS,OAAO,EAAGD,EAAalE,GAAQ,MAAM,KACxDmE,EAAU,SAAS,SAAS,EAAGD,EAAalE,GAAQ,QAAQ,KAC5DmE,EAAU,SAAS,WAAW,EAAGD,EAAa,MAC9CC,EAAU,SAAS,aAAa,EAAGD,EAAalE,GAAQ,YAAY,KACpEmE,EAAU,SAAS,KAAK,IAAGD,EAAa,eAE1C;AAAA;AAAA;AAAA;AAAA,oGAI6EA,CAAU;AAAA,uFACvBjB,GAAQW,CAAI,CAAC;AAAA,wBAC5EI,EAAa,sFAAsFN,EAAE,UAAU,KAAKM,CAAU,UAAY,EAAE;AAAA;AAAA,kEAElGH,CAAY;AAAA;AAAA,oBAG1DC,EACI,qEAAqEb,GAAQa,CAAK,CAAC,SACnF,EACN;AAAA;AAAA,uIAEqHb,GAAQS,EAAE,MAAQ,QAAQ,CAAC;AAAA,sBAE5IK,EACI;AAAA;AAAA,8BAEId,GAAQc,CAAO,CAAC;AAAA,mCAEpB,EACN;AAAA;AAAA;AAAA,eAIN,CAAC,EACA,KAAK,EAAE,CACZ,GAAG,CAAC;AAAA;AAAA,cAGF,EACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYJ,IAAMK,EAAe,SAAS,eAAe,eAAe,EACtDC,EAAW,SAAS,eAAe,eAAe,EAClDC,EAAS,SAAS,eAAe,aAAa,EAE9CC,EAAa,IAAM,CACvBH,EAAa,UAAY,GACzB,IAAMI,EAAO5D,EAAM,MAAQ,CAAC,EAC5B,GAAI4D,EAAK,SAAW,EAAG,CACrBJ,EAAa,UACX,6FACF,MACF,CACAI,EAAK,QAASC,GAAQ,CACpB,IAAMC,EAAIC,GAAYF,CAAG,EACnBG,EAAK,SAAS,cAAc,KAAK,EACvCA,EAAG,UAAY,kBACfA,EAAG,MAAM,QAAU;AAAA,sBACHF,CAAC;AAAA,4BACKA,CAAC;AAAA,iBACZA,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQZE,EAAG,UAAY;AAAA,gBACL3B,GAAQwB,CAAG,CAAC;AAAA,iFACqDA,CAAG,kCAAkCC,CAAC;AAAA,QAEjHN,EAAa,YAAYQ,CAAE,CAC7B,CAAC,EAEDR,EAAa,iBAAiB,iBAAiB,EAAE,QAASS,GAAQ,CAChEA,EAAI,iBAAiB,QAAS,MAAOC,GAAM,CACzC,IAAML,EAAOK,EAAE,cAA8B,QAAQ,IACrDlE,EAAM,MAAQA,EAAM,MAAQ,CAAC,GAAG,OAAQsC,GAAMA,IAAMuB,CAAG,EACvD,MAAMM,GAAQ,KAAKnE,CAAK,EACxB2D,EAAW,EACXtE,GAAe,CACjB,CAAC,CACH,CAAC,CACH,EAEM+E,EAAS,SAAY,CACzB,IAAMC,EAAMZ,EAAS,MAAM,KAAK,EAAE,YAAY,EAC9C,GAAI,CAACY,EAAK,OACV,IAAMT,EAAO,IAAI,IAAI5D,EAAM,MAAQ,CAAC,CAAC,EACrC,GAAI4D,EAAK,IAAIS,CAAG,EAAG,CACjBZ,EAAS,MAAQ,GACjB,MACF,CACAG,EAAK,IAAIS,CAAG,EACZrE,EAAM,KAAO,MAAM,KAAK4D,CAAI,EAAE,KAAK,EACnC,MAAMO,GAAQ,KAAKnE,CAAK,EACxByD,EAAS,MAAQ,GACjBE,EAAW,EACXtE,GAAe,CACjB,EAEAqE,EAAO,iBAAiB,QAASU,CAAM,EACvCX,EAAS,iBAAiB,UAAYS,GAAM,CACtCA,EAAE,MAAQ,SAASE,EAAO,CAChC,CAAC,EAED,IAAME,EAAa3E,EAAU,cAAc,sBAAsB,EACjE2E,GAAY,iBAAiB,SAAU,SAAY,CACjD,IAAMD,EAAMC,EAAW,MAAM,KAAK,EAC7BD,IACLrE,EAAM,YAAcqE,EACpB,MAAMF,GAAQ,KAAKnE,CAAK,EACxBX,GAAe,EACjB,CAAC,EAED,IAAMkF,EAAe,SAAS,eAAe,wBAAwB,EACrEA,GAAc,iBAAiB,QAAUL,GAAM,CAC7CA,EAAE,gBAAgB,EAClBM,EAAcD,CAAY,CAC5B,CAAC,EAED,SAASC,EAAcC,EAAuB,CAC5C,GAAI,CAACzE,EAAO,OACZ,SAAS,iBAAiB,oBAAoB,EAAE,QAASgE,GAAOA,EAAG,OAAO,CAAC,EAE3E,IAAMU,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAElB,OAAO,KAAKhC,EAAM,EAAE,QAASK,GAAQ,CACnC,IAAM4B,EAAMjC,GAAOK,CAAG,EAChB6B,EAAO,SAAS,cAAc,KAAK,EACnCC,EAAW7E,EAAM,OAAO,YAAY,IAAM+C,EAChD6B,EAAK,UAAY,aAAaC,EAAW,SAAW,EAAE,GACtDD,EAAK,UAAY;AAAA,iDAC0BD,EAAI,IAAI;AAAA,mCACtBA,EAAI,IAAI;AAAA,uDACYE,EAAW,QAAU,EAAE;AAAA,QAExED,EAAK,iBAAiB,QAAS,SAAY,CACzC5E,EAAM,MAAQ+C,EACd,MAAMoB,GAAQ,KAAKnE,CAAK,EACxB0E,EAAM,OAAO,EACb,IAAMI,GAAS,SAAS,eAAe,YAAY,EAC/CA,KAAQA,GAAO,YAAcH,EAAI,MACrC,IAAMI,EAAS,SAAS,eAAe,YAAY,EAC/CA,IAAQA,EAAO,YAAcJ,EAAI,MACrCtF,GAAe,CACjB,CAAC,EACDqF,EAAM,YAAYE,CAAI,CACxB,CAAC,EAED,IAAMI,EAAY,SAAS,cAAc,KAAK,EACxCC,EAAU,CAACjF,EAAM,MACvBgF,EAAU,UAAY,aAAaC,EAAU,SAAW,EAAE,GAC1DD,EAAU,UAAY;AAAA;AAAA;AAAA,qDAG2BC,EAAU,QAAU,EAAE;AAAA,MAEvED,EAAU,iBAAiB,QAAS,SAAY,CAC9ChF,EAAM,MAAQ,OACd,MAAMmE,GAAQ,KAAKnE,CAAK,EACxB0E,EAAM,OAAO,EACb,IAAMI,EAAS,SAAS,eAAe,YAAY,EAC/CA,IAAQA,EAAO,YAAc,iBACjC,IAAMC,EAAS,SAAS,eAAe,YAAY,EAC/CA,IAAQA,EAAO,YAAc,UACjC1F,GAAe,CACjB,CAAC,EACDqF,EAAM,YAAYM,CAAS,EAE3B,SAAS,KAAK,YAAYN,CAAK,EAE/B,IAAMQ,EAAOT,EAAS,sBAAsB,EAC5CC,EAAM,MAAM,IAAM,GAAGQ,EAAK,OAAS,OAAO,QAAU,CAAC,KACrDR,EAAM,MAAM,KAAO,GAAGQ,EAAK,KAAO,OAAO,OAAO,KAEhD,IAAMC,EAAgBjB,GAAkB,CAClC,CAACQ,EAAM,SAASR,EAAE,MAAc,GAAK,CAACO,EAAS,SAASP,EAAE,MAAc,IAC1EQ,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASS,CAAY,EAEtD,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAY,EAAG,EAAE,CACvE,CAEAxB,EAAW,EAEO,SAAS,eAAe,kBAAkB,GACjD,iBAAiB,QAAS,IAAM,CACrC,QAAQ,WAAW3D,EAAM,IAAI,IAAI,GAAGV,GAAgBU,EAAM,EAAE,CAClE,CAAC,CACH,CCtkBA,OAAOoF,OAAW,QCsBlB,IAAIC,GAAoB,CAAC,EAElB,SAASC,GAAmBC,EAAsB,CACvD,OAAOF,GAAQ,OAAQG,GAAM,CAC3B,GAAIA,EAAE,OAAO,SAAW,EAAG,MAAO,GAClC,QAAWC,KAAMD,EAAE,OAAQ,CACzB,IAAIE,EAAc,GAClB,QAAWC,KAAWJ,EAAM,OAE1B,GADUK,GAAUH,EAAG,IAAKA,EAAG,IAAKE,EAAQ,IAAKA,EAAQ,GAAG,GACnDF,EAAG,OAAQ,CAClBC,EAAc,GACd,KACF,CAEF,GAAI,CAACA,EAAa,MAAO,EAC3B,CACA,MAAO,EACT,CAAC,CACH,CAEA,IAAIG,GAAgC,KAChCC,GAAa,GACbC,GAA8B,KAC9BC,GAAgD,IAAM,CAAC,EACvDC,GAAmB,KAGhB,SAASC,GAAYC,EAAiD,CAC3EC,GAAUD,EACVE,GAAY,CACd,CAEO,SAASC,IAAe,CAC7BC,GAAU,CAAC,EACXC,GAAiB,KACjBC,GAAe,KACfC,GAAa,GACb,IAAMC,EAAY,SAAS,eAAe,cAAc,EACpDA,IACFA,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAO1B,CAEO,SAASC,GAAwBC,EAAkB,CACxDN,GAAU,CAAC,EACX,QAASO,EAAI,EAAGA,EAAI,KAAK,IAAI,EAAGD,EAAU,MAAM,EAAGC,IAAK,CACtD,IAAM,EAAID,EAAUC,CAAC,EACrB,GAAI,CAAC,GAAG,QAAU,EAAE,OAAO,OAAS,GAAI,SACxC,IAAMC,EAAI,EAAE,OAAO,OACbC,EAAS,EAAE,OAAO,KAAK,MAAMD,EAAI,EAAG,CAAC,EACrCE,EAAO,EAAE,OAAO,KAAK,MAAMF,EAAI,EAAG,CAAC,EACnCG,EAAO,EAAE,OAAO,KAAK,MAAMH,EAAI,GAAI,CAAC,EAC1CR,GAAQ,KAAK,CACX,GAAI,UAAUO,EAAI,CAAC,GACnB,KAAM,GAAG,EAAE,aAAe,EAAE,MAAQ,UAAUA,EAAI,CAAC,EAAE,WACrD,OAAQ,CACN,CAAE,IAAKE,EAAO,IAAK,IAAKA,EAAO,IAAK,OAAQ,IAAK,KAAM,OAAQ,EAC/D,CAAE,IAAKC,EAAK,IAAK,IAAKA,EAAK,IAAK,OAAQ,IAAK,KAAM,YAAa,EAChE,CAAE,IAAKC,EAAK,IAAK,IAAKA,EAAK,IAAK,OAAQ,IAAK,KAAM,QAAS,CAC9D,CACF,CAAC,CACH,CACIX,GAAQ,OAAS,IACnBC,GAAiBD,GAAQ,CAAC,EAAE,GAC5BE,GAAeF,GAAQ,CAAC,EAAE,GAE9B,CAEA,eAAeF,IAAc,CAC3B,GAAI,CACF,IAAMc,EAAS,MAAMC,GAAQ,IAAI,SAAS,EACtCD,IAAQZ,GAAUY,EACxB,OAAS,EAAG,CACV,QAAQ,MAAM,kCAAmC,CAAC,CACpD,CACF,CAEA,eAAeE,IAAc,CAC3B,GAAI,CACF,MAAMD,GAAQ,IAAI,UAAWb,EAAO,CACtC,OAAS,EAAG,CACV,QAAQ,MAAM,kCAAmC,CAAC,EAClDH,GAAQ,yBAA0B,OAAO,CAC3C,CACF,CAEA,SAASkB,GAAwBC,EAAwB,CACvD,IAAIC,EAAQ,EACZ,QAASV,EAAI,EAAGA,EAAIS,EAAO,OAAO,OAAS,EAAGT,IAAK,CACjD,IAAMW,EAAKF,EAAO,OAAOT,CAAC,EACpBY,EAAKH,EAAO,OAAOT,EAAI,CAAC,EAC9BU,GAASG,GAAUF,EAAG,IAAKA,EAAG,IAAKC,EAAG,IAAKA,EAAG,GAAG,CACnD,CACA,OAAOF,EAAQ,GACjB,CAEO,SAASI,GACdC,EACAC,EAC6C,CAC7C,GAAIA,EAAa,OAAS,EAAG,OAAO,KAEpC,IAAIC,EAAe,EACfC,EAAW,GACXC,EAAS,GAEb,QAASnB,EAAI,EAAGA,EAAIe,EAAM,OAAO,OAAQf,IAAK,CAC5C,IAAMoB,EAAKL,EAAM,OAAOf,CAAC,EACnBqB,EAAKL,EAAaC,CAAY,EAGpC,GAFUJ,GAAUQ,EAAG,IAAKA,EAAG,IAAKD,EAAG,IAAKA,EAAG,GAAG,GAEzCC,EAAG,OAAQ,CAGlB,GAFIJ,IAAiB,IAAGC,EAAWlB,GAE/BiB,IAAiBD,EAAa,OAAS,EACzC,OAAAG,EAASnB,EACF,CAAE,SAAAkB,EAAU,OAAAC,CAAO,EAE5BF,GACF,CACF,CACA,OAAO,IACT,CAEO,SAASK,GAAqBP,EAAYG,EAAkBC,EAAgB,CACjF,IAAMI,EAAMR,EAAM,OACZd,EAAIsB,EAAI,OACd,GAAItB,IAAM,GAAKiB,EAAWC,EACxB,MAAO,CACL,SAAU,EACV,KAAM,EACN,SAAU,KACV,MAAO,KACP,SAAU,KACV,WAAY,KACZ,OAAQ,IACV,EAEF,IAAMK,EAAI,KAAK,IAAI,EAAG,KAAK,IAAIN,EAAUjB,EAAI,CAAC,CAAC,EACzCwB,EAAI,KAAK,IAAID,EAAG,KAAK,IAAIL,EAAQlB,EAAI,CAAC,CAAC,EACvCyB,EAAYH,EAAIC,CAAC,GAAG,MAAQ,EAE5BG,IADUJ,EAAIE,CAAC,GAAG,MAAQ,GACJC,GAAa,IAErCE,EAAa,EACbC,EAAa,EACbC,EAAU,EACVC,EAAU,EACVC,EAAa,EACbC,EAAa,EACbC,EAAe,EACfC,EAAe,EACfC,EAAc,EAElB,QAASpC,EAAIwB,EAAGxB,GAAKyB,EAAGzB,IAAK,CAC3B,IAAMqC,EAAId,EAAIvB,CAAC,EAiBf,GAhBIqC,EAAE,OAAS,OACbT,GAAcS,EAAE,MAChBR,KAEEQ,EAAE,IAAM,OACVP,GAAWO,EAAE,GACbN,KAEEM,EAAE,OAAS,OACbL,GAAcK,EAAE,MAChBJ,KAEEI,EAAE,SAAW,OACfH,GAAgBG,EAAE,QAClBF,KAEEnC,EAAIwB,EAAG,CACT,IAAMc,EAAOf,EAAIvB,EAAI,CAAC,EACtB,GAAIqC,EAAE,KAAO,MAAQC,EAAK,KAAO,KAAM,CACrC,IAAMC,EAAKF,EAAE,IAAMC,EAAK,IACpBC,EAAK,IAAGH,GAAeG,EAC7B,CACF,CACF,CAEA,IAAMC,EAAOf,EAAID,GAAKD,EAAIE,CAAC,EAAE,MAAQ,IAAMF,EAAIC,CAAC,EAAE,MAAQ,GAAK,EAE/D,MAAO,CACL,SAAAG,EACA,KAAAa,EACA,SAAUX,EAAa,EAAI,KAAK,MAAMD,EAAaC,CAAU,EAAI,KACjE,MAAOE,EAAU,EAAI,KAAK,MAAMD,EAAUC,CAAO,EAAI,KACrD,SAAUE,EAAa,EAAID,EAAaC,EAAa,KACrD,WAAYE,EAAe,EAAI,KAAK,MAAMD,EAAeC,CAAY,EAAI,KACzE,OAAQR,EAAW,EAAI,KAAK,MAAMS,GAAeT,EAAW,KAAK,EAAI,IACvE,CACF,CAEA,SAASc,GAAeC,EAAyB,CAC/C,IAAMC,EAAI,KAAK,MAAMD,EAAU,IAAI,EAC7BE,EAAI,KAAK,MAAOF,EAAU,KAAQ,EAAE,EACpC,EAAI,KAAK,MAAMA,EAAU,EAAE,EACjC,OAAIC,EAAI,EAAU,GAAGA,CAAC,IAAIC,EAAE,SAAS,EAAE,SAAS,EAAG,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAG,GAAG,CAAC,GAEjF,GAAGA,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAG,GAAG,CAAC,EAC9C,CAEO,SAASC,IAA2B,CACzC,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2EAMkEC,GAAQ,IAAI,KAAK;AAAA;AAAA;AAAA,GAI5F,CAEO,SAASC,GAAuBC,EAAYC,EAAsBC,EAAiB,CAExF,IAAMC,GADWF,EAAQG,GAAOH,EAAM,YAAY,CAAC,EAAI,OAC5B,UAAY,KACnCI,EAAU,KACd,GAAIL,EAAM,UAAY,MAAQA,EAAM,SAAW,GAAK,CAClD,IAAMM,GAAeH,IAAa,KAAO,IAAO,KAAOH,EAAM,SAC7DK,EAAU,GAAGE,GAAQD,CAAW,CAAC,aAAaH,CAAQ,EACxD,CAEA,MAAO;AAAA,UACCD,CAAO;AAAA,UACPF,EAAM,MAAQ,KAAO,IAAIA,EAAM,KAAO,KAAM,QAAQ,CAAC,CAAC,WAAa,GAAG;AAAA,UACtEP,GAAeO,EAAM,QAAQ,CAAC;AAAA,UAC9BA,EAAM,UAAY,KAAO,IAAIA,EAAM,SAAW,KAAK,QAAQ,CAAC,CAAC,aAAe,GAAG;AAAA,UAC/EK,CAAO;AAAA,UACPL,EAAM,QAAU,KAAO,GAAGA,EAAM,MAAM,YAAc,GAAG;AAAA,UACvDA,EAAM,UAAY,KAAO,GAAGA,EAAM,QAAQ,UAAY,GAAG;AAAA,UACzDA,EAAM,OAAS,KAAO,GAAGA,EAAM,KAAK,YAAc,GAAG;AAAA,GAE/D,CAEA,IAAMQ,GAAa,MACbC,GAAgB,IAAI,aAAaD,EAAU,EAC3CE,GAAgB,IAAI,aAAaF,EAAU,EAC3CG,GAAgB,IAAI,aAAaH,EAAU,EAC3CI,GAAiB,IAAI,aAAa,EAAE,EACpCC,GAAiB,IAAI,aAAa,EAAE,EACpCC,GAAc,IACdC,GAAW,GACXC,GAAgB,IAAI,aAAaF,EAAW,EAC5CG,GAAiB,IAAI,aAAaH,EAAW,EAC7CI,GAAa,IAAI,aAAaJ,GAAc,CAAC,EAC7CK,GAAa,IAAI,aAAaL,GAAc,CAAC,EAE5C,SAASM,IAAgB,CAC9B,IAAMvE,EAAY,SAAS,eAAe,cAAc,EACxD,GAAI,CAACA,EAAW,OAIhB,IAAIwE,EAAuB,EAE3B,QAAWC,KAAK7E,GAAS,CACvB,GAAI6E,EAAE,OAAO,OAAS,EAAG,SACzB,IAAMC,EAAeC,GAAQ,+BAC3BF,EAAE,OAAO,IAAKjC,IAAO,CAAE,IAAKA,EAAE,IAAK,IAAKA,EAAE,GAAI,EAAE,EAChDiC,EAAE,OAAO,CAAC,GAAG,QAAU,EACzB,EACMG,EAAW,EACjB,QAASC,EAAI,EAAGA,EAAID,EAAUC,IAAK,CAEjC,IAAMC,EADID,GAAKD,EAAW,IACJH,EAAE,OAAO,OAAS,GAClCM,EAAS,KAAK,IAAIN,EAAE,OAAO,OAAS,EAAG,KAAK,MAAMK,CAAQ,CAAC,EAC3DE,EAAOF,EAAWC,EAClBE,EAAKR,EAAE,OAAOM,CAAM,EACpBG,EAAKT,EAAE,OAAOM,EAAS,CAAC,EAC9BhB,GAAec,CAAC,EAAII,EAAG,KAAOC,EAAG,IAAMD,EAAG,KAAOD,EACjDhB,GAAea,CAAC,EAAII,EAAG,KAAOC,EAAG,IAAMD,EAAG,KAAOD,CACnD,CACA,QAASG,EAAK,EAAGA,EAAKT,EAAa,OAAQS,IAAM,CAC/C,IAAMC,EAAKV,EAAaS,CAAE,EAEpBzD,EADMiD,GAAQ,aAAaS,CAAE,GAClB,QAAU,CAAC,EACtBhF,EAAI,KAAK,IAAIsB,EAAI,OAAQiC,EAAU,EACzC,GAAIvD,IAAM,EAEV,SAASD,EAAI,EAAGA,EAAIC,EAAGD,IAAK,CAC1B,IAAMkF,EAAK3D,EAAIvB,CAAC,EAChByD,GAAczD,CAAC,EAAIkF,EAAG,IACtBxB,GAAc1D,CAAC,EAAIkF,EAAG,IACtBvB,GAAc3D,CAAC,EAAIkF,EAAG,OAAS,CACjC,CAEA,QAAS,EAAI,EAAG,EAAIT,EAAU,IAAK,CACjC,IAAMU,EAAOvB,GAAe,CAAC,EACvBwB,EAAOvB,GAAe,CAAC,EACzBwB,EAAU,IACVC,EAAU,EACd,QAAStF,EAAI,EAAGA,EAAIC,EAAGD,IAAK,CAC1B,IAAMuF,EAAI1E,GAAUsE,EAAMC,EAAM3B,GAAczD,CAAC,EAAG0D,GAAc1D,CAAC,CAAC,EAC9DuF,EAAIF,IACNA,EAAUE,EACVD,EAAUtF,EAEd,CACAqE,GAAwBgB,EAAU1B,GAAc2B,CAAO,EAAI,GAC7D,CAGA,QAAS9D,EAAI,EAAGA,EAAIsC,GAAatC,IAAK,CACpC,IAAMgE,EAAM,KAAK,IAAIvF,EAAI,EAAG,KAAK,MAAOuB,GAAKvB,EAAI,IAAO6D,GAAc,EAAE,CAAC,EACnEoB,EAAK3D,EAAIiE,CAAG,EACZC,GAAOP,EAAG,OAAS,GAAK,KAAOA,EAAG,KAAO,GAAK,KAAQA,EAAG,OAAS,GAAK,IACzEF,IAAO,IAAGhB,GAAcxC,CAAC,EAAIiE,GACjCxB,GAAezC,CAAC,EAAIiE,CACtB,CAEA,QAASC,EAAO,EAAGA,EAAO,GAAIA,IAAQ,CACpC,IAAMC,EAAWD,EAAO,IACxBxB,GAAW,KAAK,GAAG,EACnBA,GAAW,CAAC,EAAI,EAChB,QAASlE,EAAI,EAAGA,GAAK8D,GAAa9D,IAAK,CACrCmE,GAAW,KAAK,GAAG,EACnB,IAAMyB,EAAS,KAAK,IAAI,EAAG5F,EAAI+D,EAAQ,EACjC8B,EAAO,KAAK,IAAI/B,GAAa9D,EAAI+D,EAAQ,EACzC+B,EAAO9B,GAAchE,EAAI,CAAC,EAAI2F,EACpC,QAASI,EAAIH,EAAQG,GAAKF,EAAME,IAAK,CACnC,IAAMC,EAAOF,EAAO7B,GAAe8B,EAAI,CAAC,EAClCE,EAASD,EAAOA,EAChBE,EAAOD,GAAU,EAAI,GAAK,EAAIA,EAAS,MACvCE,EAAKjC,GAAW6B,CAAC,EACjBK,EAAKjC,GAAW4B,EAAI,CAAC,EACrBM,EAAKnC,GAAW6B,EAAI,CAAC,EACrBO,EAAUH,EAAKC,EAAMD,EAAKE,EAAKF,EAAKE,EAAMD,EAAKC,EAAKD,EAAKC,EAC/DlC,GAAW4B,CAAC,EAAIG,EAAOI,CACzB,CACApC,GAAW,IAAIC,EAAU,CAC3B,CACAE,GAAwBH,GAAWJ,EAAW,EAAI,IACpD,EACF,CACF,CACAjE,EAAU,QAAQ,kBAAoBwE,EAAqB,QAAQ,CAAC,EAEpExE,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,UAMdD,GACI;AAAA;AAAA;AAAA;AAAA,UAKA;AAAA;AAAA;AAAA;AAAA,SAKN;AAAA;AAAA;AAAA;AAAA;AAAA,UAMEH,GAAQ,SAAW,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,UAMAA,GACG,IAAK6E,GAAM,CACV,IAAM/C,EAAM+C,EAAE,OAAO,IAAKjC,IAAO,CAAE,IAAKA,EAAE,IAAK,IAAKA,EAAE,GAAI,EAAE,EACtDkE,EAAc/B,GAAQ,+BAC1BjD,EACA+C,EAAE,OAAO,CAAC,GAAG,QAAU,EACzB,EACMkC,EAASlC,EAAE,KAAO3E,GACpB8G,EAAa,GACjB,GAAID,EAAQ,CACV,IAAME,EAAyBH,EAC5B,IAAKtB,GAAO,CACX,IAAMlE,EAAQyD,GAAQ,aAAaS,CAAE,EACrC,GAAI,CAAClE,EAAO,OAAO,KACnB,IAAM4F,EAAQ7F,GAAgBC,EAAOuD,EAAE,MAAM,EAC7C,GAAI,CAACqC,EAAO,OAAO,KACnB,IAAM3D,EAAQ1B,GAAqBP,EAAO4F,EAAM,SAAUA,EAAM,MAAM,EAChEjF,EAAYX,EAAM,OAAO,WAAaA,EAAM,SAAS,CAAC,GAAG,KACzDmC,EAAUxB,EAAYkF,GAAQlF,CAAS,EAAI,IACjD,MAAO,CACL,GAAAuD,EACA,YAAalE,EAAM,aAAeA,EAAM,MAAQkE,EAChD,KAAM/B,EACN,MAAOnC,EAAM,MACb,MAAOA,EAAM,MACb,GAAGiC,EACH,SAAU2D,EAAM,SAChB,OAAQA,EAAM,MAChB,CACF,CAAC,EACA,OAAQE,GAAMA,IAAM,IAAI,EAG3BH,EAAuB,KACrB,CAACI,EAAGC,IAAMD,EAAE,SAAWC,EAAE,UAAYD,EAAE,GAAG,cAAcC,EAAE,EAAE,CAC9D,EAEAN,EAAa;AAAA;AAAA,kBAGfC,EAAuB,SAAW,EAC9B;AAAA;AAAA,kBAGA;AAAA;AAAA;AAAA;AAAA,qCAIeA,EAAuB,MAAM;AAAA,0BACxC7D,GAAyB,CAAC;AAAA;AAAA;AAAA;AAAA,wBAI5B6D,EACC,IAAKG,GAEG;AAAA,sDADYA,EAAE,KAAOG,GAAS,IAAI,EAAE,MAEF,WAAa,EAAE,oBAAoBH,EAAE,EAAE,iBAAiBA,EAAE,QAAQ,eAAeA,EAAE,MAAM;AAAA;AAAA;AAAA,uDAGrGA,EAAE,KAAK;AAAA,gCAC9BI,GAAQJ,EAAE,WAAW,CAAC;AAAA;AAAA;AAAA,4BAG1B9D,GAAuB8D,EAAGA,EAAE,MAAOA,EAAE,IAAI,CAAC;AAAA;AAAA,uBAG7C,EACA,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,iBAIjB;AAAA;AAAA,aAGE,CACA,MAAO;AAAA,sCACaL,EAAS,OAAS,EAAE,cAAclC,EAAE,EAAE;AAAA;AAAA,qEAEPkC,EAAS,cAAgB,eAAe;AAAA,2CAClES,GAAQ3C,EAAE,IAAI,CAAC;AAAA,sKAC4G9D,GAAwB8D,CAAC,EAAE,QAAQ,CAAC,CAAC,SAASA,EAAE,OAAO,MAAM,aAAaiC,EAAY,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAMlPE,CAAU;AAAA;AAAA,WAGV,CAAC,EACA,KAAK,EAAE,CAChB;AAAA;AAAA;AAAA,IAKN,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAS,IAAM,CACzES,GAAgB,CAClB,CAAC,EAED,SAAS,eAAe,eAAe,GAAG,iBAAiB,QAAS,IAAM,CACxEtH,GAAa,GACb4E,GAAQ,sBAAsB,IAAI,EAClC,SAAS,eAAe,eAAe,GAAG,UAAU,OAAO,cAAc,EACzEJ,GAAc,CAChB,CAAC,EAEDvE,EAAU,iBAAiB,cAAc,EAAE,QAASsH,GAAO,CACzD,IAAMlC,EAAMkC,EAAmB,QAAQ,GACvCA,EAAG,cAAc,kBAAkB,GAAG,iBAAiB,QAAU1F,GAAM,CACrEA,EAAE,gBAAgB,EAClB2F,GAAWnC,CAAE,CACf,CAAC,EACDkC,EAAG,cAAc,oBAAoB,GAAG,iBAAiB,QAAU1F,GAAM,CACvEA,EAAE,gBAAgB,EAClB4F,GAAapC,CAAE,CACjB,CAAC,EACDkC,EAAG,cAAc,oBAAoB,GAAG,iBAAiB,QAAU1F,GAAM,CACvEA,EAAE,gBAAgB,EAClB6F,GAAarC,CAAE,CACjB,CAAC,EACDkC,EAAG,cAAc,qBAAqB,GAAG,iBAAiB,QAAU1F,GAAM,CAErEA,EAAE,OAAuB,QAAQ,iBAAiB,GAClDA,EAAE,OAAuB,QAAQ,oBAAoB,IAIxD8F,GAAatC,CAAE,EACftF,GAAeA,KAAiBsF,EAAK,KAAOA,EAC5Cb,GAAc,EAChB,CAAC,EAED+C,EAAG,iBAAiB,mBAAmB,EAAE,QAASK,GAAQ,CACxD,IAAMC,EAAWD,EAAoB,QAAQ,QACvCtG,EAAW,SAAUsG,EAAoB,QAAQ,MAAQ,EAAE,EAC3DrG,EAAS,SAAUqG,EAAoB,QAAQ,IAAM,EAAE,EAE7DA,EAAI,cAAc,kBAAkB,GAAG,iBAAiB,QAAU/F,GAAM,CACtEA,EAAE,gBAAgB,EAClB,IAAMV,EAAQyD,GAAQ,aAAaiD,CAAO,EACtC1G,IAEF2G,GAAYD,EAAS,EAAK,EAG1B,WAAW,IAAM,CACf,IAAMlG,EAAMR,EAAM,OACZ4G,EAAKpG,EAAI,KAAMc,GAAWA,EAAE,MAAQ,IAAI,GAAG,MAAQ,EAGnDuF,EAAO,KAAK,IAAI,EAAG,KAAK,IAAI1G,EAAUK,EAAI,OAAS,CAAC,CAAC,EACrDsG,EAAO,KAAK,IAAI,EAAG,KAAK,IAAI1G,EAAQI,EAAI,OAAS,CAAC,CAAC,EAEnDuG,EAAO,KAAK,IAAI,IAAKvG,EAAIqG,CAAI,GAAG,MAAQ,GAAKD,GAAM,GAAI,EACvDI,EAAO,KAAK,IAAI,IAAKxG,EAAIsG,CAAI,GAAG,MAAQ,GAAKF,GAAM,GAAI,EAEvDK,EAAOC,GAAU,SAAS,EAC5BC,EAASJ,EACTK,EAASJ,EAETC,IAAS,aACXE,EAAS,KAAK,IAAI,GAAI3G,EAAIqG,CAAI,GAAG,MAAQ,GAAK,GAAI,EAClDO,EAAS,KAAK,IAAI,GAAI5G,EAAIsG,CAAI,GAAG,MAAQ,GAAK,GAAI,GAIpDb,GAAS,MAAM,CAAE,IAAK,CAACkB,EAAQC,CAAM,EAAG,IAAK,QAAS,EAAG,EAAI,EAG7DF,GAAU,iBAAiBH,EAAMC,CAAI,EAGrCvD,GAAQ,iBAAiBiD,EAAS1G,EAAM,OAAQG,EAAUC,EAAQ,EAAI,CACxE,EAAG,EAAE,EAET,CAAC,EAEDqG,EAAI,iBAAiB,aAAc,IAAM,CACvChD,GAAQ,cAAciD,EAAS,EAAI,CACrC,CAAC,EAEDD,EAAI,iBAAiB,aAAc,IAAM,CACvChD,GAAQ,cAAciD,EAAS,EAAK,CACtC,CAAC,CACH,CAAC,CACH,CAAC,CACH,CAEA,SAASP,IAAkB,CACzB,IAAMkB,EAAO,UAAU3I,GAAQ,OAAS,CAAC,GAEnC4I,EAAoB,CACxB,GAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,EAAG,CAAC,EAC7C,KAAMD,EACN,OAAQ,CAAC,CACX,EAEA3I,GAAQ,KAAK4I,CAAS,EACtB9H,GAAY,EACZ6D,GAAc,EACdgD,GAAWiB,EAAU,EAAE,CACzB,CAEA,SAAShB,GAAapC,EAAY,CAChC,IAAMxE,EAAShB,GAAQ,KAAM,GAAM,EAAE,KAAOwF,CAAE,EAC9C,GAAI,CAACxE,EAAQ,OAEb,IAAM0G,EAAK,SAAS,cAAc,yBAAyBlC,CAAE,IAAI,EACjE,GAAI,CAACkC,EAAI,OAET,IAAMmB,EAASnB,EAAG,cAAc,cAAc,EAC9C,GAAI,CAACmB,EAAQ,OAEb,IAAMC,EAAc9H,EAAO,KAC3B6H,EAAO,UAAY,uDAAuDrB,GAAQsB,CAAW,CAAC,+JAE9F,IAAMC,EAAQF,EAAO,cAAc,oBAAoB,EACvDE,EAAM,MAAM,EACZA,EAAM,OAAO,EAEb,IAAMC,EAAO,IAAM,CACjB,IAAMC,EAAUF,EAAM,MAAM,KAAK,EAC7BE,IAAY,KACdjI,EAAO,KAAOiI,EACdnI,GAAY,GAEd6D,GAAc,CAChB,EAEAoE,EAAM,iBAAiB,OAAQC,CAAI,EACnCD,EAAM,iBAAiB,UAAY/G,GAAM,CACnCA,EAAE,MAAQ,QAASgH,EAAK,EACnBhH,EAAE,MAAQ,UAAU2C,GAAc,CAC7C,CAAC,CACH,CAEA,SAASgD,GAAWnC,EAAY,CAC9BvF,GAAiBuF,EACjBrF,GAAa,GACbwE,GAAc,CAChB,CAEA,SAASuE,IAAmB,CAC1BC,GAAc,IAChB,CAqBO,SAASC,GAAaC,EAAYC,EAAgB,GAAO,CAC9DC,GAAiBF,EACbC,IAAME,GAAeH,GACzBI,GAAa,GACbC,GAAQ,sBAAsB,IAAI,EAClCC,GAAiB,EACjBC,GAAc,CAChB,CAEA,SAASC,GAAaR,EAAY,CAC3B,QAAQ,8CAA8C,IAC3DS,GAAUA,GAAQ,OAAQC,GAAMA,EAAE,KAAOV,CAAE,EACvCE,KAAmBF,IACrBE,GAAiB,KACjBI,GAAiB,GAEnBK,GAAY,EACZJ,GAAc,EAChB,CDvpBA,IAAIK,GAAgD,IAAM,CAAC,EACvDC,GAAwB,CAAC,EAE7B,SAASC,IAAsB,CAC7BD,GAAa,QAASE,GAAMA,EAAE,QAAQ,CAAC,EACvCF,GAAe,CAAC,CAClB,CAEO,SAASG,GAAaC,EAAiD,CAC5EL,GAAUK,CACZ,CAEO,SAASC,IAAgB,CAC9BJ,GAAoB,EACpB,SAAS,iBAAiB,oBAAoB,EAAE,QAASK,GAAOA,EAAG,OAAO,CAAC,EAC3E,IAAMC,EAAY,SAAS,eAAe,eAAe,EACrDA,IACFA,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAO1B,CAEA,IAAMC,GAAc,MACdC,GAAW,IAAI,aAAaD,EAAW,EACvCE,GAAU,IAAI,aAAaF,EAAW,EACtCG,GAAW,IAAI,aAAaH,EAAW,EACvCI,GAAW,IAAI,aAAaJ,EAAW,EACvCK,GAAW,IAAI,aAAaL,EAAW,EACvCM,GAAc,IAAI,aAAaN,GAAc,CAAC,EAC9CO,GAAc,IAAI,aAAaP,GAAc,CAAC,EAC9CQ,GAAgB,CACpB,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAC5F,EACMC,GAAe,CACnB,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAChF,EAEA,SAASC,GAAwBC,EAA4BC,EAAwB,CACnF,IAAIC,EAAe,IACfC,EAAgB,EAEpB,QAASC,EAAK,EAAGA,EAAKJ,EAAc,OAAQI,IAAM,CAChD,IAAMC,EAAOL,EAAcI,CAAE,EAAE,OACzBE,EAAI,KAAK,IAAID,EAAK,OAAQhB,EAAW,EAC3C,GAAIiB,IAAM,EAAG,SAEb,QAASC,EAAI,EAAGA,EAAID,EAAGC,IAAK,CAC1B,IAAMC,EAAKH,EAAKE,CAAC,EACXxB,EAAIyB,EAAG,OAAS,EAChBC,EAAID,EAAG,IAAM,EACbE,EAAIF,EAAG,KAAO,GACdG,EAAKH,EAAG,OAAS,EACjBI,EAAKJ,EAAG,UAAY,EACpBK,EAAMD,EAAK,EAAID,EAAKC,EAAK,GAAK,EACpCtB,GAASiB,CAAC,EAAIxB,EACdQ,GAAQgB,CAAC,EAAI,EAAIE,EACjBjB,GAASe,CAAC,EAAI,GAAKG,EAAI,GACvBjB,GAASc,CAAC,EAAII,EACdjB,GAASa,CAAC,EAAIM,EACdlB,GAAYY,EAAI,CAAC,EAAIZ,GAAYY,CAAC,EAAIxB,EACtCa,GAAYW,EAAI,CAAC,EAAIX,GAAYW,CAAC,EAAIM,CACxC,CAGA,QAASC,EAAO,EAAGA,EAAO,GAAIA,IAAQ,CACpC,IAAMC,EAAQ,EAAID,EAAO,IACnBE,EAAUF,EAAO,KACvB,QAASG,EAAK,EAAGA,EAAKnB,GAAa,OAAQmB,IAAM,CAC/C,IAAMC,EAAIpB,GAAamB,CAAE,EACzB,GAAIC,EAAIZ,EAAG,SACX,IAAMa,EAAQb,EAAIY,EACdE,EAAO,EACPC,EAAO,EACX,QAASC,EAAI,EAAGA,GAAKH,EAAOG,IAAK,CAC/B,IAAMC,EAAK3B,GAAY0B,EAAIJ,CAAC,EAAItB,GAAY0B,CAAC,EACvCE,GAAQ7B,GAAY2B,EAAIJ,CAAC,EAAIvB,GAAY2B,CAAC,GAAKP,EAAQQ,EAAKP,EAC5DS,EAAOF,EAAK5B,GAAY2B,CAAC,EAAIN,EAC/BQ,EAAOJ,IAAMA,EAAOI,GACpBC,EAAOJ,IAAMA,EAAOI,EAC1B,CACAtB,IAAkBiB,EAAOC,GAAQH,CACnC,CACF,CAGA,IAAMQ,EAAOpB,GAAK,EAClB,QAASQ,EAAO,EAAGA,EAAO,EAAGA,IAC3B,QAASa,EAAI,EAAGA,EAAI,GAAIA,IAAK,CAC3B,IAAMC,EAAK3B,GAAU,IAAO0B,EAAI,IAAOb,EAAO,MACxCe,EAAUhC,GAAc8B,CAAC,EAAIb,EAAO,GACtCgB,EAAO,IACPC,EAAS,EACTC,EAAS,EACb,QAASzB,EAAI,EAAGA,EAAID,EAAGC,IAAK,CAC1B,IAAMxB,EAAIO,GAASiB,CAAC,EACd0B,EAAO1C,GAAQgB,CAAC,EAChB2B,EAAOnD,EAAI6C,EACXO,EAAMD,EAAO,EAAI,CAACA,EAAO,EACzBE,EAAMF,EAAO,EAAIA,EAAO,EACxBG,EAAY,KAAK,IAAI,OAAUF,EAAMC,EAAM,KAAM,EACjDE,EAAS,IAAMD,EAAYR,EACjCC,EAAOA,EAAOM,GAAO,KAAO,IAAOC,IAAc,IAAQP,IAAS,EAAIQ,GAClER,EAAO5B,IAAcA,EAAe4B,GACxC,IAAMS,EAASxD,EAAIS,GAASe,CAAC,EACvBiC,EAAY,KAAK,MAAMD,EAAQxD,EAAI,CAAC,EACpC0D,GAAM1D,EAAIwD,EAAS,GAAMC,GAAaP,EACxC1B,EAAImB,EAAMK,GAAUU,EACnBT,GAAUS,CACjB,CACAtC,IAAkB4B,EAASC,GAAU,IACvC,CAEJ,CACA,OAAI7B,EAAgB,QAAOD,EAAe,GACnCA,CACT,CAEO,SAASwC,GAAeC,EAAyBC,EAAyB,CAAC,EAAG,CACnF9D,GAAoB,EACpB,IAAMM,EAAY,SAAS,eAAe,eAAe,EACzD,GAAI,CAACA,EAAW,OAEhB,GAAI,CAACuD,EAAO,CACVvD,EAAU,UAAY,GACtB,MACF,CAEA,IAAM,EAAIuD,EAAM,MAEhB,GADAE,GAAQ,qBAAqBF,CAAK,EAC9B,CAAC,EAAE,YAAc,CAAC,EAAE,SAAW,CAAC,EAAE,QAAS,CAC7CvD,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAMtB,MACF,CAIA,IAAMY,EAAgB4C,EAAU,OAAS,EAAIA,EAAY,CAACD,CAAK,EACzDzC,EAAeH,GAAwBC,EAAe6C,GAAQ,OAAO,CAAC,EAE5EzD,EAAU,UAAY;AAAA,sEAC8Cc,EAAa,QAAQ,CAAC,CAAC;AAAA,IAG3F,IAAM4C,EAAO,SAAS,eAAe,eAAe,EACpD,GAAI,CAACA,EAAM,OAEX,IAAMC,EAAa,KAAK,MAAMD,EAAK,sBAAsB,EAAE,MAAQ,EAAE,GAAK,IA8B1E,GA5BI,EAAE,YACJE,GAAgB,CACd,KAAAF,EACA,MAAAH,EACA,MAAO,EAAE,WACT,UAAW,QACX,MAAO,cACP,KAAM,IACN,MAAOM,GAAQ,MAAM,MACrB,KAAM,OACN,WAAAF,CACF,CAAC,EAGC,EAAE,SACJC,GAAgB,CACd,KAAAF,EACA,MAAAH,EACA,MAAO,EAAE,QACT,UAAW,KACX,MAAO,mBACP,KAAM,MACN,MAAOM,GAAQ,GAAG,MAClB,KAAM,WACN,WAAAF,CACF,CAAC,EAGC,EAAE,WAAY,CAChB,IAAMG,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,eACjB,IAAMC,EAAY,QACZC,EAAQH,GAAQ,MAAM,MAC5BC,EAAK,MAAM,YAAY,gBAAiBE,CAAK,EAC7C,IAAMC,EAAeC,GAAU,kBAAkB,IAAMH,EAEjDI,EAAY,EAAE,WAAW,OAAO,CAACC,EAAGC,IAAMD,EAAIC,EAAG,CAAC,EAClDC,EAAQC,GAAM,cAAc,EAE9BC,EAAY,GAChB,EAAE,WAAW,QAAQ,CAACC,EAAMtD,IAAM,CAChC,GAAIA,GAAKmD,EAAM,OAAQ,OACvB,IAAMI,EAAIJ,EAAMnD,CAAC,EACXwD,EAAMR,EAAY,EAAKM,EAAON,EAAa,IAAM,EACjDS,EAAY,SAASF,EAAE,GAAG,EAC5B,GAAG,KAAK,MAAMA,EAAE,GAAG,CAAC,MAAM,KAAK,MAAMA,EAAE,GAAG,CAAC,KAC3C,KAAK,KAAK,MAAMA,EAAE,GAAG,CAAC,KAE1BF,GAAa;AAAA;AAAA;AAAA,4EAGyDrD,EAAI,CAAC;AAAA,0IACyDuD,EAAE,IAAI;AAAA,+FACjDE,CAAS;AAAA,gHACQC,GAAQ,KAAK,MAAMJ,CAAI,CAAC,CAAC;AAAA,mIACNE,EAAI,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA,6CAGpGA,CAAG,iBAAiBD,EAAE,KAAK;AAAA;AAAA;AAAA,OAIpE,CAAC,EAEDZ,EAAK,UAAY;AAAA;AAAA;AAAA;AAAA,kEAI6CE,CAAK;AAAA;AAAA,uDAEhBC,EAAe,SAAW,EAAE,kBAAkBF,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAQ1ES,CAAS;AAAA,MAEzCd,EAAK,YAAYI,CAAI,EAErBA,EAAK,cAAc,gBAAgB,GAAG,iBAAiB,QAAUgB,GAAM,CACrEA,EAAE,gBAAgB,EAClBZ,GAAU,eAAeH,CAAS,EAClC,IAAMgB,EAAUb,GAAU,kBAAkB,EAC5CR,EAAK,iBAAiB,gBAAgB,EAAE,QAASsB,GAAQ,CACvD,IAAMX,EAAIW,EACVX,EAAE,UAAU,OAAO,SAAUA,EAAE,QAAQ,SAAWU,CAAO,CAC3D,CAAC,CACH,CAAC,EAEDjB,EAAK,cAAc,kBAAkB,GAAG,iBAAiB,QAAUgB,GAAM,CACvEA,EAAE,gBAAgB,EAClBG,GAAsBH,EAAE,cAA8BvB,CAAK,CAC7D,CAAC,CACH,CAEA,GAAI,EAAE,QAAS,CACb,IAAMO,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,eACjB,IAAMC,EAAY,KACZC,EAAQH,GAAQ,GAAG,MACzBC,EAAK,MAAM,YAAY,gBAAiBE,CAAK,EAC7C,IAAMC,EAAeC,GAAU,kBAAkB,IAAMH,EAEjDI,EAAY,EAAE,QAAQ,OAAO,CAACC,EAAGC,IAAMD,EAAIC,EAAG,CAAC,EAC/CC,EAAQC,GAAM,WAAW,EAE3BC,EAAY,GAChB,EAAE,QAAQ,QAAQ,CAACC,EAAMtD,IAAM,CAC7B,GAAIA,GAAKmD,EAAM,OAAQ,OACvB,IAAMI,EAAIJ,EAAMnD,CAAC,EACXwD,EAAMR,EAAY,EAAKM,EAAON,EAAa,IAAM,EACjDS,EAAY,SAASF,EAAE,GAAG,EAC5B,GAAG,KAAK,MAAMA,EAAE,GAAG,CAAC,MAAM,KAAK,MAAMA,EAAE,GAAG,CAAC,OAC3C,KAAK,KAAK,MAAMA,EAAE,GAAG,CAAC,OAE1BF,GAAa;AAAA;AAAA;AAAA,4EAGyDrD,EAAI,CAAC;AAAA,0IACyDuD,EAAE,IAAI;AAAA,+FACjDE,CAAS;AAAA,gHACQC,GAAQ,KAAK,MAAMJ,CAAI,CAAC,CAAC;AAAA,mIACNE,EAAI,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA,6CAGpGA,CAAG,iBAAiBD,EAAE,KAAK;AAAA;AAAA;AAAA,OAIpE,CAAC,EAEDZ,EAAK,UAAY;AAAA;AAAA;AAAA;AAAA,kEAI6CE,CAAK;AAAA;AAAA,uDAEhBC,EAAe,SAAW,EAAE,kBAAkBF,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAQ1ES,CAAS;AAAA,MAEzCd,EAAK,YAAYI,CAAI,EAErBA,EAAK,cAAc,gBAAgB,GAAG,iBAAiB,QAAUgB,GAAM,CACrEA,EAAE,gBAAgB,EAClBZ,GAAU,eAAeH,CAAS,EAClC,IAAMgB,EAAUb,GAAU,kBAAkB,EAC5CR,EAAK,iBAAiB,gBAAgB,EAAE,QAASsB,GAAQ,CACvD,IAAMX,EAAIW,EACVX,EAAE,UAAU,OAAO,SAAUA,EAAE,QAAQ,SAAWU,CAAO,CAC3D,CAAC,CACH,CAAC,EAEDjB,EAAK,cAAc,kBAAkB,GAAG,iBAAiB,QAAUgB,GAAM,CACvEA,EAAE,gBAAgB,EAClBI,GAAmBJ,EAAE,cAA8BvB,CAAK,CAC1D,CAAC,CACH,CAEA,IAAM4B,EAAe,SAAS,cAAc,KAAK,EACjDA,EAAa,UAAY,eACzB,IAAMC,EAAS,EAAE,UAAY,IACvBC,EAAQD,EAAS,EAAK,EAAE,UAAYA,EAAS,KAAS,IAAM,EA2BlE,GAzBAD,EAAa,UAAY;AAAA;AAAA,4DAEiCtB,GAAQ,UAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,iDAKlC,KAAK,MAAM,EAAE,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,iDAItB,KAAK,MAAM,EAAE,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,iDAItBwB,EAAM,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,iDAIhB,EAAE,UAAY,EAAE,SAAW,EAAI,KAAK,MAAO,EAAE,SAAW,EAAE,SAAY,IAAO,EAAI,CAAC;AAAA;AAAA;AAAA,IAIjI3B,EAAK,YAAYyB,CAAY,EAEzB,EAAE,UAAY,EAAE,MAAO,CACzB,IAAMG,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,eACpB,IAAMjC,EAAK,EAAE,SAAW,EAAE,MAE1BiC,EAAQ,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mDAO2BjC,EAAG,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,MAK5DK,EAAK,YAAY4B,CAAO,CAC1B,CAEA,IAAMC,EAAeC,GAAmBjC,CAAK,EAC7C,GAAIgC,EAAa,OAAS,EAAG,CAC3B,IAAME,EAAc,SAAS,cAAc,KAAK,EAChDA,EAAY,UAAY,eACxBA,EAAY,MAAM,QAAU,oCAE5BA,EAAY,UAAY;AAAA,+FACmEF,EAAa,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAMlGG,GAAyB,CAAC;AAAA;AAAA;AAAA;AAAA,cAI5BH,EACC,IAAKjE,GAAM,CACV,IAAMqE,EAAQC,GAAgBrC,EAAOjC,EAAE,MAAM,EACzCuE,EAAY,GAChB,GAAIF,EAAO,CACT,IAAMG,EAAQC,GAAqBxC,EAAOoC,EAAM,SAAUA,EAAM,MAAM,EAChEK,EAAYzC,EAAM,OAAO,WAAaA,EAAM,SAAS,CAAC,GAAG,KACzD0C,EAAUD,EAAYE,GAAQF,CAAS,EAAI,IAEjDH,EAAYM,GAAuBL,EAAOvC,EAAM,OAAS,KAAM0C,CAAO,CACxE,MACEJ,EACE,4HAGJ,MAAO;AAAA,yEACkDvE,EAAE,EAAE;AAAA;AAAA;AAAA;AAAA,wBAIrD8E,GAAQ9E,EAAE,IAAI,CAAC;AAAA;AAAA;AAAA,oBAGnBuE,CAAS;AAAA;AAAA,eAGf,CAAC,EACA,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA,MAKnBnC,EAAK,YAAY+B,CAAW,EAE5BA,EAAY,iBAAiB,mBAAmB,EAAE,QAAS1F,GAAO,CAChEA,EAAG,iBAAiB,QAAS,IAAM,CACjC,IAAMsG,EAAYtG,EAAmB,QAAQ,GAC7CuG,GAAaD,EAAU,EAAI,EAC3BE,GAAS,MAAM,CAAE,IAAK,SAAU,EAAG,EAAI,CACzC,CAAC,EAEDxG,EAAG,iBAAiB,aAAc,IAAM,CACtC,IAAMsG,EAAYtG,EAAmB,QAAQ,GACvCuB,EAAIiE,EAAa,KAAMiB,GAAWA,EAAO,KAAOH,CAAQ,EAC9D,GAAI/E,EAAG,CACL,IAAMqE,EAAQC,GAAgBrC,EAAOjC,EAAE,MAAM,EACzCqE,GACFc,GAAQ,iBAAiBlD,EAAM,GAAIA,EAAM,OAAQoC,EAAM,SAAUA,EAAM,OAAQ,EAAK,CACxF,CACF,CAAC,EAED5F,EAAG,iBAAiB,aAAc,IAAM,CACtC0G,GAAQ,eAAe,CACzB,CAAC,CACH,CAAC,CACH,CACF,CAcA,SAAS7C,GAAgB8C,EAAwB,CAC/C,GAAM,CAAE,KAAAhD,EAAM,MAAAH,EAAO,MAAAoD,EAAO,UAAA5C,EAAW,MAAA6C,EAAO,KAAAC,EAAM,MAAA7C,EAAO,KAAA8C,EAAM,WAAAnD,CAAW,EAAI+C,EAC1EzC,EAAeC,GAAU,kBAAkB,IAAMH,EAEjDD,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,eACjBA,EAAK,MAAM,YAAY,gBAAiBE,CAAK,EAC7CF,EAAK,UAAY;AAAA;AAAA;AAAA;AAAA,gEAI6CE,CAAK,KAAK8C,CAAI,UAAUF,CAAK;AAAA;AAAA,qDAExC3C,EAAe,SAAW,EAAE,kBAAkBF,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAQ7FA,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IActBL,EAAK,YAAYI,CAAI,EAErB,IAAMiD,EAAYjD,EAAK,cAAc,mBAAmB,EAClDkD,EAAYlD,EAAK,cAAc,mBAAmB,EAClDmD,EAAaD,EAAU,cAAc,2BAA2B,EAEtEA,EAAU,iBAAiB,QAAS,IAAM,CACxC,IAAME,EAAWH,EAAU,MAAM,UAAY,OAC7CA,EAAU,MAAM,QAAUG,EAAW,QAAU,OAC/CD,EAAW,YAAcC,EAAW,cAAgB,aACtD,CAAC,EAED,IAAMC,EAAcrD,EAAK,cAAc,gBAAgB,EACvDqD,EAAY,iBAAiB,QAAUrC,GAAM,CAC3CA,EAAE,gBAAgB,EAClB,IAAMsC,EAAMD,EAAY,QAAQ,OAChCjD,GAAU,eAAekD,CAAG,EAG5B,IAAMrC,EAAUb,GAAU,kBAAkB,EAC5CR,EAAK,iBAAiB,gBAAgB,EAAE,QAASsB,GAAQ,CACvD,IAAMX,EAAIW,EACVX,EAAE,UAAU,OAAO,SAAUA,EAAE,QAAQ,SAAWU,CAAO,CAC3D,CAAC,CACH,CAAC,EAED,IAAMsC,EAAQvD,EAAK,cAAc,cAAc,EACzCwD,EAAY,OAAO,KAAKX,CAAK,EAChC,IAAI,MAAM,EACV,KAAK,CAACvC,EAAGC,IAAMD,EAAIC,CAAC,EAEvBiD,EAAU,QAASxF,GAAM,CACvB,IAAMyF,EAAQZ,EAAM7E,CAAC,EACf0F,EAAOD,EAAc,OAAUA,EAAc,IAAOA,EAAc,IAClEE,EAAM,SAAS,cAAc,IAAI,EACvCA,EAAI,UAAY;AAAA,YACRC,GAAY5F,CAAC,CAAC;AAAA,oCACU0F,CAAG,IAAIX,CAAI;AAAA;AAAA,yFAE0CU,EAAM,GAAG,eAAezF,CAAC;AAAA;AAAA;AAAA;AAAA,MAK9GuF,GAAO,YAAYI,CAAG,CACxB,CAAC,EAEDJ,GAAO,iBAAiB,gBAAgB,EAAE,QAASrC,GAAQ,CACzDA,EAAI,iBAAiB,QAAUF,GAAM,CACnC,IAAMT,EAAIS,EAAE,cACN6C,EAAW,SAAStD,EAAE,QAAQ,GAAI,EAClCuD,EAAW,SAASvD,EAAE,QAAQ,GAAI,EAClCwD,EAAMtE,EAAM,OACZuE,EAAS,KAAK,IAAID,EAAI,OAAS,EAAGF,EAAWC,EAAW,CAAC,EAEzDG,EAAKF,EAAI,CAAC,EAAE,MAAQ,EACpBG,IAASH,EAAIF,CAAQ,EAAE,MAAQI,GAAMA,GAAM,IAC3CE,KAASJ,EAAIC,CAAM,EAAE,MAAQC,GAAMA,GAAM,IAE/CxB,GAAS,MAAM,CAAE,IAAK,CAACyB,EAAMC,EAAI,CAAE,CAAC,EACpCxB,GAAQ,iBAAiBlD,EAAM,GAAIsE,EAAKF,EAAUG,EAAQ,EAAI,CAChE,CAAC,CACH,CAAC,EAED,IAAMI,EAAUpE,EAAK,cAAc,IAAIC,CAAS,cAAc,EAC9D,GAAImE,EAAS,CACX,IAAMC,EAAQb,EACRc,EAAQd,EAAU,IACrBxF,GAAO6E,EAAM7E,CAAC,EAAU,OAAU6E,EAAM7E,CAAC,EAAU,IAAO6E,EAAM7E,CAAC,EAAU,GAC9E,EAEMuG,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,YACpBA,EAAQ,MAAM,QAAU,SAASrE,CAAK,8BAA8BA,CAAK,KACzEkE,EAAQ,MAAM,SAAW,WACzBA,EAAQ,YAAYG,CAAO,EAE3B,IAAM3B,EAAsB,CAC1B,GAAI,GAAG3C,CAAS,SAChB,MAAO,EACP,OAAQ,IACR,QAAS,CAAC,GAAI,GAAI,EAAG,EAAE,EACvB,OAAQ,CACN,EAAG,CAAE,KAAM,GAAO,MAAO,EAAG,KAAM,EAAK,EACvC,EAAG,CAAE,KAAM,EAAK,CAClB,EACA,OAAQ,CACN,CAAC,EACD,CACE,MAAA6C,EACA,OAAQ5C,EACR,MAAO,EACP,KAAMsE,GAAUtE,EAAO,EAAG,EAC1B,OAAQ,CAAE,KAAM,GAAM,KAAM,EAAG,KAAMA,CAAM,CAC7C,CACF,EACA,KAAM,CACJ,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,GACN,OAAQ,IAAM,CAAC,EACf,MAAO,CAAE,KAAM,EAAM,EACrB,KAAM,6BACN,KAAM,EACR,EACA,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,OAAQ,CAACuE,EAAIC,IAASA,EAAK,IAAKC,GAAM,GAAGA,CAAC,GAAG5B,CAAI,EAAE,EACnD,KAAM,6BACN,KAAM,EACR,CACF,EACA,OAAQ,CACN,KAAM,CAAE,EAAG,GAAO,EAAG,EAAM,EAC3B,QAAS,CAAC6B,EAAGC,EAAWC,IAAYA,CACtC,EACA,MAAO,CACL,KAAM,CACHF,GAAa,CACZ,IAAMG,EAAMH,EAAE,IACRI,EAAM,OAAO,kBAAoB,EACjCC,EAAKL,EAAE,KACPM,GAAa,CACjB,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,KAAM,KAAM,KAAM,KAAM,KAClE,EACMC,EAASd,EAAMA,EAAM,OAAS,CAAC,EAErCU,EAAI,KAAK,EACTA,EAAI,UAAY,UAChBA,EAAI,UAAY,SAChBA,EAAI,aAAe,MACnBA,EAAI,KAAO,GAAG,GAAKC,CAAG,2BAEtB,IAAII,EAAQ,KACZF,GAAW,QAASlH,GAAM,CACxB,GAAIA,EAAImH,EAAQ,OAChB,IAAME,EAAIT,EAAE,SAAS5G,EAAG,IAAK,EAAI,EAC7BqH,EAAID,EAAQ,GAAKJ,GAAOK,EAAIJ,EAAG,KAAOA,EAAG,MAAQ,EAAID,IACvDD,EAAI,SAASnB,GAAY5F,CAAC,EAAGqH,EAAGJ,EAAG,IAAMA,EAAG,OAAS,EAAID,CAAG,EAC5DI,EAAQC,EAEZ,CAAC,EACDN,EAAI,QAAQ,CACd,CACF,EACA,KAAM,CACHH,GAAa,CACZA,EAAE,KAAK,iBAAiB,QAAS,IAAM,CACrC,IAAMU,EAAMV,EAAE,OAAO,IACrB,GAAIU,GAAO,MAAQjB,EAAMiB,CAAG,GAAK,KAAM,CACrC,IAAMxB,EAAWO,EAAMiB,CAAG,EAEpBzB,GADQhB,EAAMiB,CAAQ,EACL,IACjBC,EAAMtE,EAAM,OACZuE,EAAS,KAAK,IAAID,EAAI,OAAS,EAAGF,GAAWC,EAAW,CAAC,EAEzDG,EAAKF,EAAI,CAAC,EAAE,MAAQ,EACpBG,IAASH,EAAIF,EAAQ,EAAE,MAAQI,GAAMA,GAAM,IAC3CE,IAASJ,EAAIC,CAAM,EAAE,MAAQC,GAAMA,GAAM,IAE/CxB,GAAS,MAAM,CAAE,IAAK,CAACyB,EAAMC,CAAI,CAAE,CAAC,EACpCxB,GAAQ,iBAAiBlD,EAAM,GAAIsE,EAAKF,GAAUG,EAAQ,EAAI,CAChE,CACF,CAAC,CACH,CACF,EACA,UAAW,CACRY,GAAa,CACZ,GAAI,CAAEA,EAAU,OAAQ,OACxBA,EAAE,OAAO,EAAK,EACd,IAAMU,EAAMV,EAAE,OAAO,IACfG,EAAMH,EAAE,IACRI,EAAM,OAAO,kBAAoB,EACjCC,GAAKL,EAAE,KAGPW,EAAWD,GAAO,MAAQhB,EAAMgB,CAAG,GAAK,MAAQV,EAAE,OAAO,MAAS,EAClEY,EAAUZ,EAAE,OAAO,IACnBa,EAAUb,EAAE,SAASN,EAAMgB,CAAI,EAAI,IAAK,EAAK,EAGnD,GAFeC,GAAY,KAAK,IAAIC,EAAUC,CAAO,EAAI,GAE7C,CACV,IAAMC,EAAKd,EAAE,SAASP,EAAMiB,CAAI,EAAI,IAAK,EAAK,EACxCK,GAAKf,EAAE,SAASN,EAAMgB,CAAI,EAAI,IAAK,EAAK,EAExCM,EAASvB,EAAMiB,CAAI,EACzBf,EAAQ,UAAY,GAAGX,GAAYgC,CAAM,CAAC,KAAKtB,EAAMgB,CAAI,CAAC,IAAIvC,CAAI,GAClEwB,EAAQ,MAAM,UAAY,aAAamB,CAAE,OAAOC,EAAE,4BAClDpB,EAAQ,MAAM,QAAU,GAExB,IAAMsB,EAAMjB,EAAE,SAASP,EAAMiB,CAAI,EAAI,IAAK,EAAI,EACxCQ,GAAMlB,EAAE,SAASN,EAAMgB,CAAI,EAAI,IAAK,EAAI,EAE9CP,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,EAAK,EAAIA,CAAG,CAAC,EAClCD,EAAI,YAAcP,GAAUtE,EAAO,EAAG,EACtC6E,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAOc,EAAKZ,GAAG,GAAG,EACtBF,EAAI,OAAOc,EAAKZ,GAAG,IAAMA,GAAG,MAAM,EAClCF,EAAI,OAAO,EAEXA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,IAAIc,EAAKC,GAAK,EAAId,EAAK,EAAG,KAAK,GAAK,CAAC,EACzCD,EAAI,UAAY,UAChBA,EAAI,KAAK,EACTA,EAAI,YAAc7E,EAClB6E,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EACXA,EAAI,QAAQ,CACd,MACER,EAAQ,MAAM,QAAU,MAE5B,CACF,CACF,EACA,OAAQ,CAAE,KAAM,EAAM,CACxB,EAEA3B,EAAK,MACH/C,GACA,KAAK,MAAMD,EAAK,sBAAsB,EAAE,MAAQ,EAAE,GAClDwE,EAAQ,aACR,IACF,IAAM2B,EAAO,IAAIC,GAAMpD,EAAM,CAACyB,EAAOC,CAAK,EAAGF,CAAO,EACnD2B,EAAa,OAAS,GACvBpK,GAAa,KAAKoK,CAAI,CACxB,CACF,CAEA,SAAS3E,GAAmB6E,EAAuBxG,EAAkB,CACnE,SAAS,iBAAiB,oBAAoB,EAAE,QAASxD,GAAOA,EAAG,OAAO,CAAC,EAE3E,IAAMiK,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAElB,IAAM1F,EAAQb,GAAQ,WAAW,EAEjCuG,EAAM,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,4DAKwC1F,EAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,4DAIRA,EAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,4DAIRA,EAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,4DAIRA,EAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,IAMlE,IAAM2F,EAAOF,EAAS,sBAAsB,EAC5CC,EAAM,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YASZC,EAAK,MAAQ,GAAG;AAAA,WACjBA,EAAK,OAAS,CAAC;AAAA,IAExB,SAAS,KAAK,YAAYD,CAAK,EAE/BA,EAAM,cAAc,WAAW,GAAG,iBAAiB,QAAS,SAAY,CACtE,IAAME,EAASF,EAAM,iBAAiB,gBAAgB,EAChDG,EAAW,MAAM,KAAKD,CAAM,EAAE,IAAK/I,GAAM,SAAUA,EAAuB,KAAK,GAAK,CAAC,EAE3F,QAASA,EAAI,EAAGA,EAAIgJ,EAAS,OAAQhJ,IACnC,GAAIgJ,EAAShJ,CAAC,GAAKgJ,EAAShJ,EAAI,CAAC,EAAG,CAClC3B,GAAQ,mCAAoC,OAAO,EACnD,MACF,CAGFiE,GAAQ,WAAW0G,CAAQ,EAC3B,MAAMC,GAAQ,IAAI,WAAYD,CAAQ,EAEtC5G,EAAM,MAAQE,GAAQ,aAAaF,EAAM,OAAQ,EAAI,EACrD,MAAM6G,GAAQ,KAAK7G,CAAK,EAExBD,GAAeC,CAAK,EACpByG,EAAM,OAAO,EACbxK,GAAQ,kBAAkB,CAC5B,CAAC,EAED,IAAM6K,EAAWvF,GAAkB,CAC7B,CAACkF,EAAM,SAASlF,EAAE,MAAc,GAAK,CAACiF,EAAS,SAASjF,EAAE,MAAc,IAC1EkF,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASK,CAAO,EAEjD,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAO,EAAG,EAAE,CAClE,CAEA,SAASpF,GAAsB8E,EAAuBxG,EAAkB,CACtE,SAAS,iBAAiB,oBAAoB,EAAE,QAASxD,GAAOA,EAAG,OAAO,CAAC,EAE3E,IAAMiK,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAElB,IAAMM,EAAM7G,GAAQ,OAAO,EAE3BuG,EAAM,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,4DAKwCM,CAAG;AAAA;AAAA;AAAA;AAAA,IAM7D,IAAML,EAAOF,EAAS,sBAAsB,EAC5CC,EAAM,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YASZC,EAAK,MAAQ,GAAG;AAAA,WACjBA,EAAK,OAAS,CAAC;AAAA,IAExB,SAAS,KAAK,YAAYD,CAAK,EAE/BA,EAAM,cAAc,WAAW,GAAG,iBAAiB,QAAS,SAAY,CACtE,IAAMO,EAAQP,EAAM,cAAc,YAAY,EACxCQ,EAAS,SAASD,EAAM,KAAK,GAAK,IAExC9G,GAAQ,OAAO+G,CAAM,EACrB,MAAMJ,GAAQ,IAAI,MAAOI,CAAM,EAE/BjH,EAAM,MAAQE,GAAQ,aAAaF,EAAM,OAAQ,EAAI,EACrD,MAAM6G,GAAQ,KAAK7G,CAAK,EAExBD,GAAeC,CAAK,EACpByG,EAAM,OAAO,EACbxK,GAAQ,kBAAkBgL,CAAM,GAAG,CACrC,CAAC,EAED,IAAMH,EAAWvF,GAAkB,CAC7B,CAACkF,EAAM,SAASlF,EAAE,MAAc,GAAK,CAACiF,EAAS,SAASjF,EAAE,MAAc,IAC1EkF,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASK,CAAO,EAEjD,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAO,EAAG,EAAE,CAClE,CEl3BA,OAAOI,OAAW,QAKlB,IAAIC,GAA6B,CAAC,EAC9BC,GAAiC,KACjCC,GAAqB,KACrBC,GAAU,QACVC,GAAU,KACVC,GAAkC,KAClCC,GAAgF,CAAC,EACjFC,GAAgF,CAAC,EACjFC,GAAgC,KAChCC,GAAU,GAEd,SAASC,IAAoB,CAC3B,IAAMC,EAAY,SAAS,eAAe,mBAAmB,EAC7D,GAAIA,GAAaN,KAAqB,MAAQC,GAAkBD,EAAgB,EAAG,CACjF,IAAMO,EAAWN,GAAkBD,EAAgB,EAAE,CAAC,EACtDM,EAAU,YAAc,GAAGE,GAAQD,CAAQ,CAAC,EAC9C,CACF,CAMO,SAASE,IAAgB,CAC1BC,KACF,cAAcA,EAAc,EAC5BA,GAAiB,MAEfC,KACFA,GAAK,QAAQ,EACbA,GAAO,MAETC,GAAgB,CAAC,EACjBC,GAAe,KACfC,GAAU,QACVC,GAAU,KACVC,GAAmB,KACnBC,GAAoB,CAAC,EACrBC,GAAoB,CAAC,EACrBC,GAAU,GACV,IAAMC,EAAU,SAAS,eAAe,kBAAkB,EACtDA,GAASA,EAAQ,OAAO,EAC5B,IAAMC,EAAY,SAAS,eAAe,eAAe,EACrDA,IACFA,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAO1B,CAEA,IAAMC,GAAe,MACfC,GAAkB,MAAM,KAAK,CAAE,OAAQ,CAAE,EAAG,IAAM,IAAI,aAAaD,EAAY,CAAC,EAChFE,GAAiB,MAAM,KAAK,CAAE,OAAQ,CAAE,EAAG,IAAM,IAAI,aAAaF,EAAY,CAAC,EAC/EG,GAAe,IAAI,WAAW,CAAC,EAC/BC,GAAsB,IAAI,aAAa,GAAK,EAAE,EAC9CC,GAAkB,CACtB,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,GAC9E,EAEO,SAASC,GACdC,EACAC,EAAyB,CAAC,EAC1B,CACI,MAAM,QAAQD,CAAa,GAC7BjB,GAAgBiB,EAChBhB,GAAegB,EAAc,CAAC,GAAK,MAC1BA,GACTjB,GAAgB,CAACiB,CAAa,EAC9BhB,GAAegB,IAEfjB,GAAgB,CAAC,EACjBC,GAAe,MAEjB,IAAMQ,EAAY,SAAS,eAAe,eAAe,EACzD,GAAI,CAACA,EAAW,OAEhB,IAAMU,EAAQlB,GACd,GAAI,CAACkB,EAAO,CACVV,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAMtB,MACF,CAGA,IAAMW,EAAUC,GAAU,QACpBC,EAA6B,CAAC,EACpC,QAAWC,KAAOH,EAAS,CACzB,IAAMI,EAAMJ,EAAQG,CAAG,EACnBJ,EAAM,OAAO,KAAMM,GAAOA,EAAUD,EAAI,KAAK,GAAK,IAAI,GAAGF,EAAiB,KAAKC,CAAG,CACxF,CAGI,CAACD,EAAiB,SAASpB,EAAO,GAAKoB,EAAiB,OAAS,IACnEpB,GAAUoB,EAAiB,CAAC,GAE1B,CAACA,EAAiB,SAASnB,EAAO,GAAKmB,EAAiB,OAAS,EACnEnB,GAAUmB,EAAiB,CAAC,EACrB,CAACA,EAAiB,SAASnB,EAAO,GAAKmB,EAAiB,OAAS,IACxEnB,GAAUmB,EAAiB,CAAC,GAE9B,IAAMI,EAAON,EAAQlB,EAAO,EACtByB,EAAOP,EAAQjB,EAAO,EAG5BM,EAAU,MAAM,SAAW,SAE3B,IAAImB,EAAc,GAClB,GAAI5B,GAAc,QAAU,EAAG,CAG7B,IAAM6B,EAAeX,EAAU,QAAU,EAAIA,EAAYlB,GACnD8B,EAAS,KAAK,IAAID,EAAa,OAAQ,CAAC,EAC9Cf,GAAoB,KAAK,CAAC,EAE1B,QAASiB,GAAI,EAAGA,GAAID,EAAQC,KAAK,CAC/B,IAAMC,GAAMH,EAAaE,EAAC,EAAE,QAAU,CAAC,EACjCE,GAAI,KAAK,IAAID,GAAI,OAAQtB,EAAY,EAC3CG,GAAakB,EAAC,EAAIE,GAClB,IAAMC,GAAMvB,GAAgBoB,EAAC,EACvBI,GAAKvB,GAAemB,EAAC,EAC3B,QAASK,GAAI,EAAGA,GAAIH,GAAGG,KAAK,CAC1B,IAAMX,EAAIO,GAAII,EAAC,EACTC,EAAKZ,EAAE,OAAS,EAChBa,GAAIb,EAAE,IAAM,EACZc,GAAKd,EAAE,OAAS,EAChBe,EAAKf,EAAE,KAAO,EACdgB,GAAKhB,EAAE,KAAO,EACpBS,GAAIE,EAAC,EAAIC,EAAKC,GAAIC,GAClBJ,GAAGC,EAAC,EAAII,EAAKC,GAAK,GAClB,IAAMC,GAAK,KAAK,IAAI,GAAI,KAAK,IAAI,EAAIL,EAAK,IAAQ,CAAC,CAAC,EAC9CM,GAAK,KAAK,IAAI,GAAI,KAAK,IAAI,GAAKL,GAAI,IAAM,GAAO,CAAC,CAAC,EACzDxB,GAAqB4B,IAAM,EAAKC,EAAE,GAAK,EAAIH,EAAK,GAClD,CACF,CAEA,IAAII,EAAS,EACTC,EAAU,EACd,QAASC,GAAO,EAAGA,GAAO,EAAGA,KAAQ,CACnC,IAAMC,GAAUD,GAAO,EAAI,GAAK,GAChC,QAASE,GAAK,EAAGA,GAAKD,GAASC,KAAM,CACnC,IAAMC,GAAIlC,GAAgBiC,EAAE,EACtBE,GAAO,EAAID,GACXE,GAAe,MAAQ,EAAIH,GAAK,GAAMF,GAAO,KACnD,QAASM,EAAI,EAAGA,EAAItB,EAAQsB,IAAK,CAC/B,IAAMC,EAAO1C,GAAgByC,CAAC,EACxBE,GAAM1C,GAAewC,CAAC,EACtBG,GAAO1C,GAAauC,CAAC,EAC3B,QAASI,EAAIJ,EAAI,EAAGI,EAAI1B,EAAQ0B,IAAK,CACnC,IAAMC,GAAO9C,GAAgB6C,CAAC,EACxBE,GAAM9C,GAAe4C,CAAC,EACtBG,GAAM,KAAK,IAAIJ,GAAM1C,GAAa2C,CAAC,CAAC,EACtCI,GAAO,EACTC,GAAO,EACPC,GAAU,EACVC,GAAU,EACZ,QAAS3B,EAAI,EAAGA,EAAIuB,GAAKvB,IAKvB,GAJAwB,IAAQP,EAAKjB,CAAC,EACdyB,IAAQJ,GAAKrB,CAAC,EACd0B,IAAWR,GAAIlB,CAAC,EAChB2B,IAAWL,GAAItB,CAAC,EACZA,GAAKa,GAAG,CACV,IAAMe,GAAS5B,EAAIa,GACnBW,IAAQP,EAAKW,EAAM,EACnBH,IAAQJ,GAAKO,EAAM,EACnBF,IAAWR,GAAIU,EAAM,EACrBD,IAAWL,GAAIM,EAAM,EACrB,IAAMC,GAAOL,GAAOV,GACdgB,EAAOL,GAAOX,GACdiB,GAAQL,GAAUZ,GAClBkB,GAAQL,GAAUb,GAClBmB,GAASJ,GAAOC,EAChBI,GAASH,GAAQC,GACjBG,GAAM,KAAK,IAAI,CAACF,GAASA,GAASlB,EAAY,EAC9CqB,GAAS,GAAK,EAAIF,GAASA,GAASnB,IAC1CN,GAAWoB,GAAOC,EAAOK,GAAMJ,GAAQC,GAAQI,GAC/C5B,GACF,CAEJ,CACF,CACF,CACF,CACA,QAAS6B,GAAI,EAAGA,GAAI,KAAMA,KACxB5B,GAAW/B,GAAoB2D,EAAC,EAAI,KAEtC,IAAMC,EAAK1E,GAAc,CAAC,EACpB2E,EAAK3E,GAAc,CAAC,EACpB4E,EAAKF,EAAG,MACRG,EAAKF,EAAG,MACRG,IAAaD,EAAG,UAAYD,EAAG,WAAa,KAAM,QAAQ,CAAC,EAC3DG,IAAYF,EAAG,UAAY,IAAMD,EAAG,UAAY,IAAI,QAAQ,CAAC,EAC7DI,IAAWH,EAAG,OAAS,IAAMD,EAAG,OAAS,IAAI,QAAQ,CAAC,EACtDK,GAAWJ,EAAG,SAAWD,EAAG,UAAU,QAAQ,CAAC,EAC/CM,GAAcL,EAAG,QAAU,IAAMD,EAAG,QAAU,GAE9CO,IAAcP,EAAG,UAAYC,EAAG,WAAa,KAAM,QAAQ,CAAC,EAC5DO,IAAaR,EAAG,SAAWC,EAAG,UAAU,QAAQ,CAAC,EACjDQ,IAAaT,EAAG,UAAY,IAAMC,EAAG,UAAY,IAAM,IACvDS,EAAS,KAAK,QAAQV,EAAG,UAAY,IAAMC,EAAG,UAAY,IAAM,CAAC,EACjEU,EAAS,KAAK,IAAIX,EAAG,UAAY,EAAGC,EAAG,UAAY,CAAC,EACpDW,EAAQ,KAAK,QAAQZ,EAAG,OAAS,IAAMC,EAAG,OAAS,IAAM,CAAC,EAC1DY,EAAQ,KAAK,IAAIb,EAAG,OAAS,EAAGC,EAAG,OAAS,CAAC,EAC7Ca,KAAab,EAAG,SAAW,IAAMD,EAAG,SAAW,IAAI,QAAQ,CAAC,EAC5De,KAAaf,EAAG,SAAW,IAAMC,EAAG,SAAW,IAAM,GAAG,QAAQ,CAAC,EACjEe,EAAU,KAAK,IAAIhB,EAAG,SAAW,EAAGC,EAAG,SAAW,CAAC,EAAE,QAAQ,CAAC,EAC9DgB,IAAejB,EAAG,QAAU,IAAMC,EAAG,QAAU,GAErDjD,EAAc;AAAA,6DAC2CgB,CAAM,sBAAsBC,EAAQ,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oDAMvD6B,EAAG,KAAK,MAAMA,EAAG,aAAeA,EAAG,IAAI;AAAA,oDACvCC,EAAG,KAAK,MAAMA,EAAG,aAAeA,EAAG,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+CAQ5CC,EAAG,UAAY,KAAM,QAAQ,CAAC,CAAC;AAAA,+CAC/BC,EAAG,UAAY,KAAM,QAAQ,CAAC,CAAC;AAAA,sEACR,OAAOC,CAAQ,GAAK,EAAI,UAAY,SAAS,MAAM,OAAOA,CAAQ,GAAK,EAAI,IAAM,EAAE,GAAGA,CAAQ;AAAA,gFACpFK,CAAS;AAAA;AAAA;AAAA;AAAA,8CAI3CP,EAAG,SAAS,QAAQ,CAAC,CAAC;AAAA,8CACtBC,EAAG,SAAS,QAAQ,CAAC,CAAC;AAAA,sEACE,OAAOI,CAAO,GAAK,EAAI,UAAY,SAAS,MAAM,OAAOA,CAAO,GAAK,EAAI,IAAM,EAAE,GAAGA,CAAO;AAAA,gFACjFG,EAAS;AAAA;AAAA;AAAA;AAAA,8CAI3CR,EAAG,SAAWkB,GAAQlB,EAAG,SAAW,GAAI,EAAI,IAAI;AAAA,8CAChDC,EAAG,SAAWiB,GAAQjB,EAAG,SAAW,GAAI,EAAI,IAAI;AAAA;AAAA,gFAEdiB,GAAQT,CAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,8CAInDT,EAAG,UAAY,CAAC,QAAQA,EAAG,UAAY,CAAC;AAAA,8CACxCC,EAAG,UAAY,CAAC,QAAQA,EAAG,UAAY,CAAC;AAAA,sEAChB,OAAOE,CAAO,GAAK,EAAI,UAAY,SAAS,MAAM,OAAOA,CAAO,GAAK,EAAI,IAAM,EAAE,GAAGA,CAAO;AAAA,gFACjFO,CAAM,cAAcC,CAAM;AAAA;AAAA;AAAA;AAAA,8CAI5DX,EAAG,OAAS,CAAC,UAAUA,EAAG,OAAS,CAAC;AAAA,8CACpCC,EAAG,OAAS,CAAC,UAAUA,EAAG,OAAS,CAAC;AAAA,sEACZ,OAAOG,CAAM,GAAK,EAAI,UAAY,SAAS,MAAM,OAAOA,CAAM,GAAK,EAAI,IAAM,EAAE,GAAGA,CAAM;AAAA,gFAC9EQ,CAAK,gBAAgBC,CAAK;AAAA;AAAA;AAAA;AAAA,8CAI5Db,EAAG,SAAW,KAAOA,EAAG,QAAQ,QAAQ,CAAC,EAAI,IAAI,YAASA,EAAG,SAAW,KAAOA,EAAG,QAAQ,QAAQ,CAAC,EAAI,IAAI;AAAA,8CAC3GC,EAAG,SAAW,KAAOA,EAAG,QAAQ,QAAQ,CAAC,EAAI,IAAI,YAASA,EAAG,SAAW,KAAOA,EAAG,QAAQ,QAAQ,CAAC,EAAI,IAAI;AAAA,sEACnF,OAAOa,EAAQ,GAAK,EAAI,UAAY,SAAS,MAAM,OAAOA,EAAQ,GAAK,EAAI,IAAM,EAAE,GAAGA,EAAQ;AAAA,gFACpFC,CAAO,kBAAeC,CAAO;AAAA;AAAA;AAAA;AAAA,8CAI/DhB,EAAG,QAAU,CAAC;AAAA,8CACdC,EAAG,QAAU,CAAC;AAAA,sEACUK,GAAc,EAAI,UAAY,SAAS,MAAMA,GAAc,EAAI,IAAM,EAAE,GAAGA,CAAU;AAAA,gFAC1EW,EAAW;AAAA;AAAA;AAAA;AAAA;AAAA,KAMzF,CAGApF,EAAU,UAAY,GAAGmB,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iEAM2BF,EAAK,KAAK,KAAKA,EAAK,IAAI;AAAA,qCACpDA,EAAK,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iEAQkBC,EAAK,KAAK,KAAKA,EAAK,IAAI;AAAA,qCACpDA,EAAK,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6HAc+EpB,GAAiC,cAAvB,oBAAoC,YAAaA,GAAoB,oBAAV,OAA6B;AAAA;AAAA;AAAA,8HAGlGA,GAAU,qBAAuB,aAAa,YAAYA,GAAU,QAAU,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQ7N,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAUwF,GAAM,CAC1EA,EAAE,gBAAgB,EAClBC,GAASD,EAAE,cAA8B,GAAG,CAC9C,CAAC,EAED,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAUA,GAAM,CAC1EA,EAAE,gBAAgB,EAClBC,GAASD,EAAE,cAA8B,GAAG,CAC9C,CAAC,EAED,IAAME,EAAS,SAAS,eAAe,sBAAsB,EACvDC,EAAY,SAAS,eAAe,mBAAmB,EACvDC,EAAU,SAAS,eAAe,mBAAmB,EAE3DF,GAAQ,iBAAiB,QAAS,IAAM,CACtC7F,GAAmB,SAAS6F,EAAO,MAAO,EAAE,EAC5CG,GAAkB,EACdrG,IAAMA,GAAK,OAAO,CACxB,CAAC,EAED,SAASsG,GAAe,CAClBF,IAASA,EAAQ,UAAY,uDAEjCrG,GAAiB,OAAO,YAAY,IAAM,CACpCM,KAAqB,MAAQA,GAAmBC,GAAkB,OAAS,GAC7ED,GAAmB,KAAK,IAAIA,GAAmB,EAAGC,GAAkB,OAAS,CAAC,EAC9E4F,EAAO,MAAQ,GAAG7F,EAAgB,GAClCgG,GAAkB,EACdrG,IAAMA,GAAK,OAAO,GAEtBuG,EAAY,CAEhB,EAAG,EAAE,CACP,CAEA,SAASA,GAAc,CACjBxG,KACF,cAAcA,EAAc,EAC5BA,GAAiB,MAEfqG,IAASA,EAAQ,UAAY,2DACnC,CAEAA,GAAS,iBAAiB,QAAS,IAAM,CACnCrG,GACFwG,EAAY,GAGRlG,KAAqB,MAAQA,IAAoBC,GAAkB,OAAS,IAC9ED,GAAmB,EACnB6F,EAAO,MAAQ,IACfG,GAAkB,EACdrG,IAAMA,GAAK,OAAO,GAExBsG,EAAa,EAEjB,CAAC,EAED,SAAS,eAAe,mBAAmB,GAAG,iBAAiB,QAAS,IAAM,CACxE9F,KACFA,GAAU,GACVS,GAAef,EAAY,EAE/B,CAAC,EAED,SAAS,eAAe,oBAAoB,GAAG,iBAAiB,QAAS,IAAM,CACxEM,KACHA,GAAU,GACVS,GAAef,EAAY,EAE/B,CAAC,EAEDsG,GAAW,CACb,CAEO,SAASC,IAAiB,CAC/B,IAAM/F,EAAY,SAAS,eAAe,cAAc,EAClDgG,EAAgB,SAAS,eAAe,yBAAyB,EACvE,GAAI1G,IAAQ0G,GAAiBA,EAAc,YAAc,EAAG,CAC1D,IAAMxD,EAAIwD,EAAc,YAClBnE,EAAImE,EAAc,aAExB,GAAIxD,EAAI,GAAKX,EAAI,EACf,GAAI/B,GAAS,CACX,IAAMmG,EAAO,KAAK,IAAIzD,EAAGX,CAAC,EAC1BvC,GAAK,QAAQ,CAAE,MAAO2G,EAAM,OAAQA,CAAK,CAAC,CAC5C,MACE3G,GAAK,QAAQ,CAAE,MAAOkD,EAAG,OAAQX,CAAE,CAAC,CAG1C,CACF,CAEA,SAAS0D,GAASW,EAAuBC,EAAiB,CACxD,SAAS,iBAAiB,oBAAoB,EAAE,QAASnE,GAAOA,EAAG,OAAO,CAAC,EAE3E,IAAMoE,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAElB,IAAMzF,EAAUC,GAAU,QACpBF,EAAQlB,GACd,GAAI,CAACkB,EAAO,OAEZ,IAAMG,EAA6B,CAAC,EACpC,QAAWC,KAAOH,EAAS,CACzB,IAAMI,EAAMJ,EAAQG,CAAG,EACnBJ,EAAM,OAAO,KAAMM,GAAOA,EAAUD,EAAI,KAAK,GAAK,IAAI,GAAGF,EAAiB,KAAKC,CAAG,CACxF,CAEAD,EAAiB,QAASC,GAAQ,CAChC,IAAMC,EAAMJ,EAAQG,CAAG,EACjBuF,EAAO,SAAS,cAAc,KAAK,EACnCC,EAAaH,IAAS,IAAM1G,GAAUC,GAC5C2G,EAAK,UAAY,aAAaC,IAAexF,EAAM,SAAW,EAAE,GAChEuF,EAAK,UAAY;AAAA,4DACuCtF,EAAI,KAAK,KAAKA,EAAI,IAAI;AAAA,iCACjDA,EAAI,KAAK;AAAA,qDACWuF,IAAexF,EAAM,QAAU,EAAE;AAAA,MAElFuF,EAAK,iBAAiB,QAAS,IAAM,CAC/BF,IAAS,IAAK1G,GAAUqB,EACvBpB,GAAUoB,EAEfsF,EAAM,OAAO,EACb7F,GAAef,EAAY,CAC7B,CAAC,EACD4G,EAAM,YAAYC,CAAI,CACxB,CAAC,EAED,IAAME,EAAOL,EAAS,sBAAsB,EAC5CE,EAAM,MAAM,IAAM,GAAGG,EAAK,OAAS,CAAC,KACpCH,EAAM,MAAM,KAAO,GAAGG,EAAK,IAAI,KAC/B,SAAS,KAAK,YAAYH,CAAK,EAE/B,IAAMI,EAASlB,GAAkB,CAC3B,CAACc,EAAM,SAASd,EAAE,MAAc,GAAK,CAACY,EAAS,SAASZ,EAAE,MAAc,IAC1Ec,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASI,CAAK,EAE/C,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAK,EAAG,CAAC,CAC/D,CAEA,SAASV,IAAa,CACpB,GAAI,CAACtG,GAAc,OACnB,IAAMQ,EAAY,SAAS,eAAe,yBAAyB,EACnE,GAAI,CAACA,EAAW,OAEhB,IAAMW,EAAUC,GAAU,QACpBK,EAAON,EAAQlB,EAAO,GAAKkB,EAAQ,MACnCO,EAAOP,EAAQjB,EAAO,GAAKiB,EAAQ,GAEzC,GAAIpB,GAAc,QAAU,EAAG,CAC7B,IAAM0E,EAAK1E,GAAc,CAAC,EACpB2E,EAAK3E,GAAc,CAAC,EAEpBkH,EAAOxC,EAAG,OACVyC,EAAOxC,EAAG,OACVyC,EAAS,KAAK,IAAIF,EAAK,OAAQC,EAAK,MAAM,EAC1CE,EAAkB,CAAC,EACnBC,EAA4B,CAAC,EAC7BC,EAA4B,CAAC,EAEnC,QAASnE,EAAI,EAAGA,EAAIgE,EAAQhE,IAAK,CAC/BiE,EAAM,KAAKjE,CAAC,EACZ,IAAMoE,EAAKN,EAAK9D,CAAC,EACXqE,EAAKN,EAAK/D,CAAC,EACjBkE,EAAO,KAAKE,GAAOA,EAAW7F,EAAK,KAAK,GAAK,KAAQ6F,EAAW7F,EAAK,KAAK,EAAI,IAAI,EAClF4F,EAAO,KAAKE,GAAOA,EAAW9F,EAAK,KAAK,GAAK,KAAQ8F,EAAW9F,EAAK,KAAK,EAAI,IAAI,CACpF,CAEI5B,KACFA,GAAK,QAAQ,EACbA,GAAO,MAELU,EAAU,cAAc,aAAa,IAAGA,EAAU,UAAY,IAElE,IAAIiH,EAAQjH,EAAU,YAAc,EAAIA,EAAU,YAAc,IAC5DkH,EAASlH,EAAU,aAAe,EAAIA,EAAU,aAAe,IAE7DmH,EAAsB,CAC1B,MAAAF,EACA,OAAAC,EACA,QAAS,CAAC,GAAI,GAAI,EAAG,CAAC,EACtB,OAAQ,CAAE,EAAG,CAAE,KAAM,EAAM,EAAG,EAAG,CAAE,KAAM,EAAK,CAAE,EAChD,OAAQ,CACN,CAAC,EACD,CACE,MAAO,GAAGjD,EAAG,aAAeA,EAAG,IAAI,KAAK/C,EAAK,KAAK,IAClD,OAAQ+C,EAAG,OAAS,UACpB,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,CACxB,EACA,CACE,MAAO,GAAGC,EAAG,aAAeA,EAAG,IAAI,KAAKhD,EAAK,KAAK,IAClD,OAAQgD,EAAG,OAAS,UACpB,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,CACxB,CACF,EACA,KAAM,CACJ,CACE,KAAM,EACN,MAAO,uBACP,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,6BACN,KAAM,EACR,EACA,CACE,KAAM,EACN,MAAO,GAAGhD,EAAK,KAAK,KAAKA,EAAK,IAAI,IAClC,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,6BACN,KAAM,EACR,CACF,EACA,OAAQ,CAAE,KAAM,EAAK,CACvB,EAEA5B,GAAO,IAAI8H,GAAMD,EAAM,CAACP,EAAOC,EAAQC,CAAM,EAAG9G,CAAwB,EACxE+F,GAAe,EACf,MACF,CAEA,IAAMxE,EAAM/B,GAAa,OACnB6H,EAAK9F,EAAI,CAAC,EAAE,MAAQ,EACpB+F,EAAa/F,EAChB,IAAI,CAACP,EAAGuG,IAAQ,CACdvG,EAAUC,EAAK,KAAK,EACpBD,EAAUE,EAAK,KAAK,GACpBF,EAAE,KAAQqG,GAAM,KAChBrG,EAAE,MAAQ,GAAK,IAChBuG,CACF,CAAC,EACA,OAAO,CAAC,CAACC,EAAGC,EAAGnG,EAAGoG,CAAC,IAAMF,GAAK,MAAQC,GAAK,IAAI,EAElD,GAAIH,EAAW,SAAW,EAAG,CAC3BtH,EAAU,UACR,wKACF,MACF,CAEA,GAAIF,GAAS,CACX,IAAM6H,EAAQL,EAAW,IAAKI,GAAMA,EAAE,CAAC,CAAC,EAClCE,EAAQN,EAAW,IAAKI,GAAMA,EAAE,CAAC,CAAC,EAClCG,EAAO,KAAK,IAAI,GAAGF,CAAK,EACxBG,EAAO,KAAK,IAAI,GAAGH,CAAK,EACxBI,EAAO,KAAK,IAAI,GAAGH,CAAK,EACxBI,EAAO,KAAK,IAAI,GAAGJ,CAAK,EAE9BhI,GAAoB0H,EAAW,IAAKI,GAAM,CACxC,IAAMO,EAAOP,EAAE,CAAC,EACVQ,EAAOR,EAAE,CAAC,EACVS,GAAUF,EAAOJ,IAASC,EAAOD,GAAQ,GAAM,EAAI,KAAK,GACxDO,GAAKF,EAAOH,IAASC,EAAOD,GAAQ,GACpCM,EAAKD,EAAI,KAAK,IAAID,CAAK,EACvBG,EAAKF,EAAI,KAAK,IAAID,CAAK,EAC7B,MAAO,CAACE,EAAIC,EAAIZ,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGO,EAAMC,CAAI,CAC9C,CAAC,CACH,MACEtI,GAAoB0H,EAAW,IAAKI,GAAM,CAACA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,CAAC,CAAQ,EAI7F,IAAMlC,EAAS,SAAS,eAAe,sBAAsB,EACzDA,IACFA,EAAO,IAAM,GAAG8B,EAAW,OAAS,CAAC,IACjC3H,KAAqB,MAAQA,IAAoB2H,EAAW,UAC9D3H,GAAmB2H,EAAW,OAAS,EACvC9B,EAAO,MAAQA,EAAO,KAExBG,GAAkB,GAIpB9F,GAAoB,CAAC,GAAGD,EAAiB,EAAE,KAAK,CAAC2I,EAAGC,IAAMD,EAAE,CAAC,EAAIC,EAAE,CAAC,GAAKD,EAAE,CAAC,EAAIC,EAAE,CAAC,CAAC,EAEpF,IAAM5B,EAAQ/G,GAAkB,IAAK6H,GAAMA,EAAE,CAAC,CAAC,EACzCe,EAAQ5I,GAAkB,IAAK6H,GAAMA,EAAE,CAAC,CAAC,EAEzC1B,EAAgB,SAAS,eAAe,yBAAyB,EACnEiB,EAAQjB,GAAiBA,EAAc,YAAc,EAAIA,EAAc,YAAc,IACrFkB,EAASlB,GAAiBA,EAAc,aAAe,EAAIA,EAAc,aAAe,IAE5F,GAAIlG,GAAS,CACX,IAAMmG,EAAO,KAAK,IAAIgB,EAAOC,EAAS,EAAIA,EAASD,CAAK,EACxDA,EAAQhB,EACRiB,EAASjB,EAELD,IACFA,EAAc,MAAM,QAAU,OAC9BA,EAAc,MAAM,WAAa,SACjCA,EAAc,MAAM,eAAiB,SAEzC,MAAWA,IACTA,EAAc,MAAM,QAAU,GAC9BA,EAAc,MAAM,WAAa,GACjCA,EAAc,MAAM,eAAiB,IAGvC,IAAMmB,EAAsB,CAC1B,MAAOF,EACP,OAAQC,EACR,QAAS,CAAC,GAAI,GAAI,EAAG,CAAC,EACtB,OAAQ,CACN,EAAG,CAAE,KAAM,GAAO,KAAM,EAAK,EAC7B,EAAG,CAAE,KAAM,EAAK,CAClB,EACA,OAAQ,CACN,CAAC,EACD,CACE,MAAOhG,EAAK,MACZ,MAAO,EACP,OAAQ,CAAE,KAAM,GAAM,KAAM,EAAG,KAAMwH,GAAUxH,EAAK,MAAO,EAAG,CAAE,CAClE,CACF,EACA,KAAM,CACJ,CACE,KAAM,EACN,KAAM,CAACpB,GACP,MAAO,GAAGmB,EAAK,KAAK,KAAKA,EAAK,IAAI,IAClC,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,6BACN,OAAQ,CAAC0H,EAAGC,IAASA,EAAK,IAAKC,GAAOA,GAAK,KAAO5H,EAAK,QAAQ4H,CAAC,EAAI,EAAG,EACvE,KAAM,EACR,EACA,CACE,KAAM,EACN,KAAM,CAAC/I,GACP,MAAO,GAAGoB,EAAK,KAAK,KAAKA,EAAK,IAAI,IAClC,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,6BACN,OAAQ,CAACyH,EAAGC,IAASA,EAAK,IAAKC,GAAOA,GAAK,KAAO3H,EAAK,QAAQ2H,CAAC,EAAI,EAAG,EACvE,KAAM,EACR,CACF,EACA,OAAQ,CACN,KAAM,CAAE,EAAG,GAAO,EAAG,EAAM,EAC3B,QAAS,CAACF,EAAGG,EAAWC,IAAY,CAClC,IAAMC,EAAaL,EAAE,OAAO,KACtBM,EAAYN,EAAE,OAAO,IAC3B,GAAIK,GAAc,MAAQC,GAAa,MAAQD,GAAc,GAAKC,GAAa,EAAG,CAChF,IAAIC,EAAQ,IACRC,EAAa,GAEjB,QAASxG,EAAI,EAAGA,EAAI9C,GAAkB,OAAQ8C,IAAK,CACjD,GAAM,CAACsF,EAAMC,CAAI,EAAIrI,GAAkB8C,CAAC,EAClCyG,EAAKT,EAAE,SAASV,EAAM,GAAG,EACzBoB,EAAKV,EAAE,SAAST,EAAM,GAAG,EAEzBoB,EAAKF,EAAKJ,EACVO,EAAKF,EAAKJ,EACVO,GAAKF,EAAKA,EAAKC,EAAKA,EAEtBC,GAAKN,IACPA,EAAQM,GACRL,EAAaxG,EAEjB,CAGA,GAAIwG,GAAc,GAAKD,EAAQ,KAAM,OAAOC,CAC9C,CACA,OAAOJ,CACT,EACA,OAAQ,CACN,KAAM,EACN,OAAQ,OACR,MAAO,EACP,KAAM7H,EAAK,KACb,CACF,EACA,OAAQ,CAAE,KAAM,EAAM,EACtB,MAAO,CACL,KAAM,CACHyH,GAAa,CACZ,IAAMc,EAAMd,EAAE,IACRe,EAAM,OAAO,kBAAoB,EAGvCD,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAc,4BAClBA,EAAI,UAAY,EAAIC,EAEpB,IAAIC,EAAU,GACd,QAAShH,EAAI,EAAGA,EAAI/C,GAAkB,OAAQ+C,IAAK,CACjD,GAAM,CAACsF,EAAMC,CAAI,EAAItI,GAAkB+C,CAAC,EAClCyG,EAAKT,EAAE,SAASV,EAAM,IAAK,EAAI,EAC/BoB,EAAKV,EAAE,SAAST,EAAM,IAAK,EAAI,EAEjCyB,EACFF,EAAI,OAAOL,EAAIC,CAAE,GAEjBI,EAAI,OAAOL,EAAIC,CAAE,EACjBM,EAAU,GAEd,CAKA,GAJAF,EAAI,OAAO,EACXA,EAAI,QAAQ,EAGR9J,KAAqB,KAAM,CAC7B8J,EAAI,KAAK,EAET,IAAMG,EAAW,KAAK,IAAI,EAAGjK,GADV,GACuC,EACpDkK,EAASlK,GAGf,QAASgD,EAAIiH,EAAUjH,EAAIkH,EAAQlH,IAAK,CACtC,GAAM,CAACmH,EAAOC,CAAK,EAAInK,GAAkB+C,CAAC,EACpC,CAACqH,EAAOC,CAAK,EAAIrK,GAAkB+C,EAAI,CAAC,EACxCuH,EAAMvB,EAAE,SAASmB,EAAO,IAAK,EAAI,EACjCK,EAAMxB,EAAE,SAASoB,EAAO,IAAK,EAAI,EACjCK,GAAMzB,EAAE,SAASqB,EAAO,IAAK,EAAI,EACjCK,EAAM1B,EAAE,SAASsB,EAAO,IAAK,EAAI,EAEjCK,GAAY3H,EAAIiH,IAAaC,EAASD,GAAY,GAClDW,EAAY,EAAI,EAAID,EACpBE,EAAQ,IAAO,GAAMF,EAE3Bb,EAAI,UAAU,EACdA,EAAI,OAAOS,EAAKC,CAAG,EACnBV,EAAI,OAAOW,GAAKC,CAAG,EACnBZ,EAAI,YAAcf,GAAUxH,EAAK,MAAOsJ,CAAK,EAC7Cf,EAAI,UAAYc,EAAYb,EAC5BD,EAAI,OAAO,CACb,CAGA,QAAS9G,EAAIiH,EAAUjH,GAAKkH,EAAQlH,IAAK,CACvC,GAAM,CAACsF,EAAMC,CAAI,EAAItI,GAAkB+C,CAAC,EAClCyG,EAAKT,EAAE,SAASV,EAAM,IAAK,EAAI,EAC/BoB,EAAKV,EAAE,SAAST,EAAM,IAAK,EAAI,EAE/BoC,GAAY3H,EAAIiH,IAAaC,EAASD,GAAY,GAClD3D,EAAO,EAAI,EAAIqE,EACfG,GAAY,IAAO,IAAOH,EAEhCb,EAAI,UAAU,EACdA,EAAI,IAAIL,EAAIC,EAAIpD,EAAOyD,EAAK,EAAG,KAAK,GAAK,CAAC,EAC1CD,EAAI,UAAYf,GAAUxH,EAAK,MAAOuJ,EAAS,EAC/ChB,EAAI,KAAK,EAETA,EAAI,YAAcvI,EAAK,MACvBuI,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,CACb,CACAA,EAAI,QAAQ,CACd,CACF,CACF,EACA,UAAW,CACRd,GAAa,CACZ,IAAMpB,EAAMoB,EAAE,OAAO,IAEjB5I,EAAU,SAAS,eAAe,kBAAkB,EAkBxD,GAjBKA,IACHA,EAAU,SAAS,cAAc,KAAK,EACtCA,EAAQ,GAAK,mBACbA,EAAQ,MAAM,SAAW,WACzBA,EAAQ,MAAM,WAAa,wBAC3BA,EAAQ,MAAM,MAAQ,OACtBA,EAAQ,MAAM,QAAU,WACxBA,EAAQ,MAAM,aAAe,MAC7BA,EAAQ,UAAU,IAAI,QAAQ,EAC9BA,EAAQ,MAAM,WAAa,YAC3BA,EAAQ,MAAM,cAAgB,OAC9BA,EAAQ,MAAM,OAAS,OACvBA,EAAQ,MAAM,UAAY,4BAC1BA,EAAQ,MAAM,OAAS,oBACvB,SAAS,KAAK,YAAYA,CAAO,GAG/BwH,GAAO,MAAQ1H,GAAkB0H,CAAG,GAAKoB,EAAE,OAAO,MAAS,EAAG,CAChE,IAAMjB,EAAI7H,GAAkB0H,CAAG,EACzBmD,EAAWhD,EAAE,CAAC,EACdiD,EAASjD,EAAE,CAAC,EACZkD,EAAQlD,EAAE,CAAC,EACXmD,EAAQnD,EAAE,CAAC,EAEjB3H,EAAQ,UAAY;AAAA,wEACwCwH,CAAG;AAAA;AAAA;AAAA,mDAGxBlC,GAAQqF,CAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,mDAIjBC,EAAO,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA,wBAG5C1J,EAAK,KAAK;AAAA,mDACiBA,EAAK,QAAQ2J,CAAK,CAAC,IAAI3J,EAAK,IAAI;AAAA;AAAA;AAAA,wBAG3DC,EAAK,KAAK;AAAA,yDACuBA,EAAK,KAAK,KAAKA,EAAK,QAAQ2J,CAAK,CAAC,IAAI3J,EAAK,IAAI;AAAA;AAAA,cAG5FnB,EAAQ,MAAM,QAAU,QAExB,IAAM+K,EAAanC,EAAE,KAAK,sBAAsB,EAChD5I,EAAQ,MAAM,KAAO,GAAG+K,EAAW,KAAO,OAAO,QAAUnC,EAAE,OAAO,KAAQ,EAAE,KAC9E5I,EAAQ,MAAM,IAAM,GAAG+K,EAAW,IAAM,OAAO,QAAUnC,EAAE,OAAO,IAAO,EAAE,IAC7E,MACE5I,EAAQ,MAAM,QAAU,MAE5B,CACF,CACF,CACF,EAIIC,EAAU,cAAc,aAAa,IAAGA,EAAU,UAAY,IAE9DV,IAAMA,GAAK,QAAQ,EAEvBA,GAAO,IAAI8H,GAAMD,EAAM,CAACP,EAAO6B,CAAK,EAAGzI,CAAS,EAEhDV,GAAK,KAAK,iBAAiB,QAAS,IAAM,CACxC,GAAIA,GAAM,CACR,IAAMiI,EAAMjI,GAAK,OAAO,IACxB,GAAIiI,GAAO,MAAQ1H,GAAkB0H,CAAG,EAAG,CACzC,IAAMwD,EAAclL,GAAkB0H,CAAG,EAAE,CAAC,EAC5C3G,GAAU,YAAYmK,CAAW,CACnC,CACF,CACF,CAAC,EAGDhF,GAAe,CACjB,CCn2BA,OAAOiF,OAAW,QCeX,SAASC,GACdC,EACAC,EACiB,CAEjB,IAAIC,EAAQ,EACZ,QAASC,EAAI,EAAGA,EAAIH,EAAU,OAAQG,IAAK,CACzC,IAAMC,EAAKJ,EAAUG,CAAC,EAAE,OAAO,UAC3BC,GAAMA,EAAKF,IAAOA,EAAQE,EAChC,CACKF,IAAOA,EAAQ,KAAK,IAAI,KAAM,EAAG,CAAC,GAEvC,IAAMG,EAAM,IAAI,KAAKH,CAAK,EACpBI,EAAcD,EAAI,eAAe,EAEjCE,EAAe,KAAK,IACxBD,EAAc,EACdD,EAAI,YAAY,EAChBA,EAAI,WAAW,EACfA,EAAI,YAAY,EAChBA,EAAI,cAAc,EAClBA,EAAI,cAAc,CACpB,EACMG,EAAiB,KAAK,IAC1BF,EACAD,EAAI,YAAY,EAAI,EACpBA,EAAI,WAAW,EACfA,EAAI,YAAY,EAChBA,EAAI,cAAc,EAClBA,EAAI,cAAc,CACpB,EACMI,EAAgB,KAAK,IACzBH,EACAD,EAAI,YAAY,EAAI,EACpBA,EAAI,WAAW,EACfA,EAAI,YAAY,EAChBA,EAAI,cAAc,EAClBA,EAAI,cAAc,CACpB,EAEIK,EAAiB,EACjBC,EAAc,EACdC,EAAY,EACZC,EAAY,EACZC,EAAW,EAEXC,EAAUb,EAEdF,EAAU,QAASgB,GAAM,CACvB,GAAI,CAACA,EAAE,MAAM,UAAW,OACxB,IAAMC,EAAMhB,EAAUe,CAAC,EACvB,GAAIC,IAAQ,OAAW,OAEvBH,GAAYG,EAEZ,IAAMC,EAAOF,EAAE,MAAM,UACjBE,EAAOH,IAASA,EAAUG,GAEjB,IAAI,KAAKA,CAAI,EAEjB,eAAe,IAAMZ,IAAaI,GAAkBO,GAEzDC,GAAQX,IAAcI,GAAeM,GAErCC,GAAQV,IAAgBI,GAAaK,GAErCC,GAAQT,IAAeI,GAAaI,EAC1C,CAAC,EAED,IAAME,EAAc,EAAI,GAAK,GAAK,GAAK,IACjCC,EAAmB,KAAK,IAAId,EAAa,EAAG,CAAC,EAE7Ce,EAAmB,KAAK,IAAI,IAAMnB,EAAQkB,GAAoBD,CAAW,EACzEG,EAAgB,KAAK,IAAI,IAAMpB,EAAQK,GAAgBY,CAAW,EAClEI,EAAc,KAAK,IAAI,IAAMrB,EAAQM,GAAkBW,CAAW,EAClEK,EAAc,KAAK,IAAI,IAAMtB,EAAQO,GAAiBU,CAAW,EACjEM,EAAa,KAAK,IAAI,IAAMvB,EAAQa,GAAWI,CAAW,EAEhE,MAAO,CACL,YAAaT,EACb,SAAUC,EACV,OAAQC,EACR,OAAQC,EACR,MAAOC,EACP,eAAgBJ,EAAiBW,EACjC,YAAaV,EAAcW,EAC3B,UAAWV,EAAYW,EACvB,UAAWV,EAAYW,EACvB,SAAUV,EAAWW,CACvB,CACF,CAEO,SAASC,GACdC,EACAC,EACAC,EACQ,CACR,IAAMC,EAASF,EAAa,IAAO,EAC7BG,EAAUd,IACOW,EAAaX,EAAMa,EAASb,GAC7B,eAAe,QAAS,CAC1C,sBAAuBW,EAAa,EAAI,EACxC,sBAAuBA,EAAa,EAAI,CAC1C,CAAC,EAGH,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA,gBAKOA,EAAa,WAAa,WAAW;AAAA,gBACrCA,EAAa,gBAAkB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAM/CG,EAAOJ,EAAY,WAAW,CAAC,SAASE,CAAI;AAAA,gBAC5CE,EAAOJ,EAAY,cAAc,CAAC,SAASE,CAAI;AAAA;AAAA;AAAA;AAAA,gBAI/CE,EAAOJ,EAAY,QAAQ,CAAC,SAASE,CAAI;AAAA,gBACzCE,EAAOJ,EAAY,WAAW,CAAC,SAASE,CAAI;AAAA;AAAA;AAAA;AAAA,gBAI5CE,EAAOJ,EAAY,MAAM,CAAC,SAASE,CAAI;AAAA,gBACvCE,EAAOJ,EAAY,SAAS,CAAC,SAASE,CAAI;AAAA;AAAA;AAAA;AAAA,gBAI1CE,EAAOJ,EAAY,MAAM,CAAC,SAASE,CAAI;AAAA,gBACvCE,EAAOJ,EAAY,SAAS,CAAC,SAASE,CAAI;AAAA;AAAA;AAAA;AAAA,gBAI1CE,EAAOJ,EAAY,KAAK,CAAC,SAASE,CAAI;AAAA,gBACtCE,EAAOJ,EAAY,QAAQ,CAAC,SAASE,CAAI;AAAA;AAAA;AAAA;AAAA,GAKzD,CDvJA,IAAIG,GAA0B,CAAC,EAE/B,SAASC,IAAwB,CAC/BD,GAAe,QAASE,GAAMA,EAAE,QAAQ,CAAC,EACzCF,GAAiB,CAAC,CACpB,CAEO,SAASG,IAAiB,CAC/BF,GAAsB,EACtB,IAAMG,EAAY,SAAS,eAAe,gBAAgB,EACtDA,IACFA,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAO1B,CAEA,IAAMC,GAAU,MACVC,GAAe,IAAI,aAAaD,GAAU,CAAC,EAC3CE,GAAc,IAAI,aAAaF,GAAU,CAAC,EAC1CG,GAAe,IAAI,aAAaH,GAAU,CAAC,EAC3CI,GAAe,IAAI,aAAaJ,EAAO,EACvCK,GAAgB,IAAI,aAAa,GAAG,EACpCC,GAAiB,CAAC,EAAG,EAAG,EAAG,GAAI,GAAI,EAAE,EACrCC,GAAmB,CAAC,GAAI,GAAI,GAAI,GAAI,GAAI,EAAE,EAC1CC,GAAoB,CACxB,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAC1F,EAEO,SAASC,GACdC,EACAC,EACAC,EACAC,EACA,CACAjB,GAAsB,EACtB,IAAMG,EAAY,SAAS,eAAe,gBAAgB,EAC1D,GAAI,CAACA,EAAW,OAEhB,IAAIe,EAAeC,GAAS,IAAI,EAAE,UAAY,MAG9CJ,EAAU,QAASK,GAAU,CAC3BC,GAAQ,qBAAqBD,CAAK,CACpC,CAAC,EAID,IAAIE,EAAe,EACfC,EAAe,EACnBd,GAAc,KAAK,CAAC,EAEpB,QAASe,EAAK,EAAGA,EAAKT,EAAU,OAAQS,IAAM,CAC5C,IAAMC,EAAMV,EAAUS,CAAE,EAAE,QAAU,CAAC,EAC/BE,EAAI,KAAK,IAAID,EAAI,OAAQrB,EAAO,EACtC,GAAIsB,IAAM,EAAG,SAEb,QAASC,EAAI,EAAGA,EAAID,EAAGC,IAAK,CAC1B,IAAM1B,EAAIwB,EAAIE,CAAC,EACTC,EAAK3B,EAAE,OAAS,EAChB4B,EAAI5B,EAAE,IAAM,EACZ6B,EAAK7B,EAAE,OAAS,EAChB8B,EAAK9B,EAAE,KAAO,EACpBI,GAAasB,EAAI,CAAC,EAAItB,GAAasB,CAAC,EAAIC,EACxCtB,GAAYqB,EAAI,CAAC,EAAIrB,GAAYqB,CAAC,EAAIE,EACtCtB,GAAaoB,EAAI,CAAC,EAAIpB,GAAaoB,CAAC,EAAIG,EACxC,IAAME,GAAU,KAAK,IAAI,EAAG,KAAK,IAAI,KAAMH,EAAI,IAAM,GAAG,CAAC,EACzDrB,GAAamB,CAAC,EAAIC,EAAK,IAAMC,EAAIG,IAAW,EAAI,KAAOA,IAAW,GAAKD,EAAK,GAC9E,CAGA,QAASE,EAAO,EAAGA,EAAO,GAAIA,IAAQ,CACpC,IAAMC,EAAc,EAAID,EAAO,IACzBE,EAAWF,EAAO,KACxB,QAASG,EAAK,EAAGA,EAAKxB,GAAkB,OAAQwB,IAAM,CACpD,IAAMC,EAAIzB,GAAkBwB,CAAE,EAC9B,GAAIC,EAAIX,EAAG,SACX,IAAMY,EAAQZ,EAAIW,EACdE,GAAO,EACPC,EAAO,EACX,QAASC,EAAI,EAAGA,GAAKH,EAAOG,IAAK,CAC/B,IAAMC,EAAKpC,GAAYmC,EAAIJ,CAAC,EAAI/B,GAAYmC,CAAC,EACvCX,GAAMzB,GAAaoC,EAAIJ,CAAC,EAAIhC,GAAaoC,CAAC,GAAKP,EAAcQ,EAAKP,EAClEQ,EAAKD,EAAKrC,GAAaoC,CAAC,EAAIN,EAC9BL,EAAKS,KAAMA,GAAOT,GAClBa,EAAKH,IAAMA,EAAOG,EACxB,CACApB,IAAkBgB,GAAOC,EAAOjC,GAAa+B,CAAK,GAAKD,EAAK,IAC9D,CACF,CAGA,QAASO,EAAQ,EAAGA,EAAQ,EAAGA,IAC7B,QAASC,EAAK,EAAGA,EAAK,EAAGA,IAAM,CAC7B,IAAMC,EAAS,GAAKpC,GAAemC,CAAE,EAAID,EAAQ,GAC3CG,EAAY,EAAID,EAChBE,EAAS,KAAOH,EAAK,IAAOD,EAAQ,IAC1C,QAASK,EAAK,EAAGA,EAAK,EAAGA,IAAM,CAC7B,IAAMC,GAAS,GAAKvC,GAAiBsC,CAAE,EAAIL,EAAQ,GAC7CO,EAAY,EAAID,GAChBE,EAAS,GAAKH,EAAK,EACnBI,EAAY,GAAK,IAAMD,GACzBE,EAAM,EACNC,EAAM,EACV,QAAS5B,GAAI,EAAGA,GAAID,EAAGC,KAAK,CAC1B,IAAME,EAAIvB,GAAYqB,GAAI,CAAC,EAAIrB,GAAYqB,EAAC,EACtCK,EAAU,KAAK,IAAI,GAAIH,EAAIuB,GAAUC,CAAS,EAC9CG,GAAKR,EAAShB,EACdyB,GAAQjD,GAAamB,EAAC,EAAI,IAAOK,EAAU,KAAQ,EAAIwB,IAAM,EAAI,GAAMA,KAAO,GACpFF,EAAMR,EAASW,GAAQV,EAAYO,EACnCC,EAAML,GAASO,GAAQN,EAAYI,CACrC,CACAjC,GAAgBgC,EAAM,IACtB/B,GAAgBgC,EAAM,GACxB,CACF,CAGF,IAAMG,EAAUlC,EAAK,GAAM,IAC3Bf,GAAciD,CAAM,GAAKrD,GAAaqB,CAAC,EAAI,KAAOpB,GAAYoB,CAAC,EAAI,IACrE,CAGA,QAASO,EAAO,EAAGA,EAAO,GAAIA,IAAQ,CACpC,IAAI0B,EAAS,EACTC,EAAS,EACPC,EAAK,IAAQ5B,EAAO,EAAK,IACzB6B,EAAK,IAAQ7B,EAAO,EAAK,KAC/B,QAAS8B,EAAM,EAAGA,EAAM,IAAKA,IAAO,CAClC,IAAMC,EAAOvD,GAAcsD,CAAG,GAAKA,EAAM,IAAM,EAAI,GAAK,IACxDJ,EAASA,EAASE,EAAKG,GAAQ,EAAIH,GACnCD,EAASA,EAASE,EAAKE,GAAQ,EAAIF,EACrC,CACAxC,GAAgBqC,EAAS,KACzBpC,GAAgBqC,EAAS,IAC3B,CAEAzD,EAAU,QAAQ,KAAOoB,EAAeD,GAAc,QAAQ,CAAC,EAC/D,IAAM2C,EAAe,CAAC,EACtB9D,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA,0FAIkE+D,GAAQ,SAAS,KAAK;AAAA,qDAC3DA,GAAQ,SAAS,IAAI;AAAA;AAAA,2FAEiBA,GAAQ,UAAU,KAAK;AAAA,qDAC7DA,GAAQ,UAAU,IAAI;AAAA;AAAA,uFAEYA,GAAQ,MAAM,KAAK;AAAA,qDACrDA,GAAQ,MAAM,IAAI;AAAA;AAAA,oFAEaA,GAAQ,GAAG,KAAK;AAAA,qDAC/CA,GAAQ,GAAG,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCAMjChD,IAAiB,KAAO,SAAW,EAAE;AAAA,mCACrCA,IAAiB,KAAO,SAAW,EAAE;AAAA,mCACrCA,IAAiB,KAAO,SAAW,EAAE;AAAA,mCACrCA,IAAiB,KAAO,SAAW,EAAE;AAAA,mCACrCA,IAAiB,KAAO,SAAW,EAAE;AAAA,mCACrCA,IAAiB,MAAQ,SAAW,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,IAOvE,IAAMiD,EAAO,SAAS,eAAe,qBAAqB,EAC1D,GAAI,CAACA,EAAM,OAEX,IAAMC,EAAYD,EAAK,aAAe,IAEhCE,EAAeC,GAAM,KAAK,eAAe,EAC/CL,EAAM,KACJM,GAAmBJ,EAAMpD,EAAW,WAAYsD,EAAcpD,EAAmBmD,CAAS,CAC5F,EACAH,EAAM,KACJM,GAAmBJ,EAAMpD,EAAW,YAAasD,EAAcpD,EAAmBmD,CAAS,CAC7F,EAEA,IAAMI,EAAiBL,EAAK,cAC1B,iDACF,EACMM,EAAkBN,EAAK,cAC3B,kDACF,EAEIK,GAAkBC,IACpBD,EAAe,iBAAiB,SAAU,IAAM,CAC1CC,EAAgB,aAAeD,EAAe,aAChDC,EAAgB,WAAaD,EAAe,WAChD,CAAC,EACDC,EAAgB,iBAAiB,SAAU,IAAM,CAC3CD,EAAe,aAAeC,EAAgB,aAChDD,EAAe,WAAaC,EAAgB,WAChD,CAAC,GAGH,IAAMC,EAAmBvE,EAAU,cAAc,uBAAuB,EACpEuE,GACFA,EAAiB,iBAAiB,UAAU,EAAE,QAASC,GAAQ,CAC7DA,EAAI,iBAAiB,QAAS,IAAM,CAClC,IAAMC,EAAQD,EAAI,aAAa,YAAY,EACvCC,IACFF,EACG,iBAAiB,UAAU,EAC3B,QAASG,GAAMA,EAAE,UAAU,OAAO,QAAQ,CAAC,EAC9CF,EAAI,UAAU,IAAI,QAAQ,EAC1BG,EAAcF,CAAK,EAEvB,CAAC,CACH,CAAC,EAGWzE,EAAU,iBAAiB,cAAc,EACjD,QAAS4E,GAAS,CACtBA,EAAK,iBAAiB,QAAS,IAAM,CACnC,IAAMC,EAASD,EAAK,aAAa,aAAa,EAC1CC,GACe,SAAS,eAAe,GAAGA,CAAM,iBAAiB,GACzD,eAAe,CAAE,SAAU,QAAS,CAAC,CAEnD,CAAC,CACH,CAAC,EAED,SAASC,EAAYC,EAAoB,CACvCjB,EAAM,QAASkB,GAAM,CACfA,GAAKA,EAAE,WAAWA,EAAE,UAAUD,CAAG,CACvC,CAAC,CACH,CAEA,SAASJ,EAAcF,EAAe,CACpCzD,GAAS,MAAM,CAAE,SAAUyD,IAAU,MAAQ,KAAOA,CAAM,CAAC,EAC3DX,EAAM,QAASkB,GAAM,CACfA,GAAKA,EAAE,aAAaA,EAAE,YAAYP,CAAK,CAC7C,CAAC,CACH,CAEA,GAAI7D,EAAU,KAAMqE,GAAMA,EAAE,MAAM,UAAU,EAAG,CAC7C,IAAMC,EAAOC,GAAyB,CACpC,KAAAnB,EACA,aAAArD,EACA,UAAAC,EACA,UAAW,QACX,MAAO,uBACP,KAAM,IACN,MAAOmD,GAAQ,MAAM,MACrB,KAAM,OACN,YAAAe,EACA,cAAAH,EACA,cAAA9D,EACA,UAAAoD,CACF,CAAC,EACDH,EAAM,KAAKoB,CAAI,CACjB,CAEA,GAAItE,EAAU,KAAMqE,GAAMA,EAAE,MAAM,OAAO,EAAG,CAC1C,IAAMC,EAAOC,GAAyB,CACpC,KAAAnB,EACA,aAAArD,EACA,UAAAC,EACA,UAAW,KACX,MAAO,4BACP,KAAM,MACN,MAAOmD,GAAQ,GAAG,MAClB,KAAM,WACN,YAAAe,EACA,cAAAH,EACA,cAAA9D,EACA,UAAAoD,CACF,CAAC,EACDH,EAAM,KAAKoB,CAAI,CACjB,CAGInE,IAAiB,OACnB+C,EAAM,QAASkB,GAAM,CACfA,GAAKA,EAAE,aAAaA,EAAE,YAAYjE,CAAY,CACpD,CAAC,EAGHnB,GAAe,QAASE,GAAM,CAC3BA,EAAU,OAAS,EACtB,CAAC,CACH,CAiBA,SAASqF,GAAyBC,EAAiC,CACjE,GAAM,CACJ,KAAApB,EACA,aAAArD,EACA,UAAAC,EACA,UAAAyE,EACA,MAAAC,EACA,KAAAC,EACA,MAAAC,EACA,KAAAC,EACA,YAAAX,EACA,cAAAH,EACA,cAAA9D,EACA,UAAAoD,CACF,EAAImB,EAEEM,EAAY/E,GAAeA,EAAa,MAAQ,gBAElDgF,EAA0B,KAExBC,EAAgB,SAAS,cAAc,KAAK,EAClDA,EAAc,UAAY,iCAC1BA,EAAc,GAAK,GAAGP,CAAS,kBAC/BrB,EAAK,YAAY4B,CAAa,EAE9B,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,+BACjBA,EAAK,MAAM,YAAY,gBAAiBL,CAAK,EAC7CK,EAAK,MAAM,KAAO,YAClBA,EAAK,MAAM,aAAe,OAC1BA,EAAK,UAAY;AAAA;AAAA;AAAA,qFAGkEL,CAAK,KAAKC,CAAI;AAAA,wCAC3DH,CAAK;AAAA;AAAA;AAAA;AAAA,iBAI5BD,CAAS;AAAA;AAAA,IAIxB,IAAMS,EAAW,SAAS,cAAc,KAAK,EAC7CA,EAAS,UAAY,mBACrBA,EAAS,UAAY;AAAA;AAAA,uEAEgDN,CAAK;AAAA,cAC9DE,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASrB,IAAI3E,EADaC,GAAS,IAAI,EACF,UAAY,MAElC+E,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,+BACjBA,EAAK,MAAM,YAAY,gBAAiBP,CAAK,EAC7CO,EAAK,MAAM,KAAO,IAClBA,EAAK,MAAM,aAAe,OAC1BA,EAAK,UAAY;AAAA;AAAA;AAAA,qFAGkEP,CAAK,KAAKC,CAAI;AAAA,4CACvDJ,CAAS,6BAA6BA,IAAc,QAAU,QAAU,IAAI;AAAA;AAAA;AAAA;AAAA,iBAIvGA,CAAS;AAAA;AAAA,IAIxB,IAAMW,EAAa,SAAS,cAAc,KAAK,EAC/CA,EAAW,MAAM,QAAU,sEAC3BA,EAAW,YAAYH,CAAI,EAC3BG,EAAW,YAAYD,CAAI,EAE3BH,EAAc,YAAYI,CAAU,EACpCJ,EAAc,YAAYE,CAAQ,EAElC,IAAMG,EAAUJ,EAAK,cAAc,IAAIR,CAAS,kBAAkB,EAClE,GAAI,CAACY,EAAS,OAGd,IAAMC,EAGF,CAAC,EACLtF,EAAU,QAASqE,IAAM,CACvB,IAAMkB,GAAQd,IAAc,QAAUJ,GAAE,MAAM,WAAaA,GAAE,MAAM,QACnE,GAAI,CAACkB,GAAO,OACZ,IAAMC,GAAOnB,GAAE,MAAQ,gBACjBoB,GACJpB,GAAE,MAAM,WAAaA,GAAE,QAAUqB,GAASrB,GAAE,MAAM,WAAaA,GAAE,OAAS,EAAI,eAC1EsB,EAAY,GAAGH,EAAI,KAAKC,EAAI,IAElC,OAAO,QAAQF,EAAK,EAAE,QAAQ,CAAC,CAACpB,EAAKyB,EAAI,IAAM,CAC7C,IAAMtE,GAAI,OAAO6C,CAAG,EACd0B,EAAOD,GAAa,OAAUA,GAAa,IAC7C,CAACN,EAAShE,EAAC,GAAKuE,EAAMP,EAAShE,EAAC,EAAE,OACpCgE,EAAShE,EAAC,EAAI,CAAE,IAAAuE,EAAK,UAAAF,EAAW,QAAStB,GAAE,GAAI,IAAMuB,GAAa,GAAI,EAC1E,CAAC,CACH,CAAC,EAGD,IAAME,EACH/F,IACE0E,IAAc,QAAU1E,EAAa,MAAM,WAAaA,EAAa,MAAM,UAC9E,CAAC,EAGGgG,EAAe,IAAI,IACzB,OAAO,KAAKT,CAAQ,EAAE,QAAShE,IAAMyE,EAAa,IAAI,OAAOzE,EAAC,CAAC,CAAC,EAChE,OAAO,KAAKwE,CAAY,EAAE,QAASxE,IAAMyE,EAAa,IAAI,OAAOzE,EAAC,CAAC,CAAC,EACpE,IAAM0E,EAAY,MAAM,KAAKD,CAAY,EAAE,KAAK,CAACE,GAAGnC,KAAMmC,GAAInC,EAAC,EAEzDoC,EAAQF,EACRG,GAAeH,EAAU,IAAK1E,IAAM,CACxC,IAAM8E,GAAQN,EAAaxE,EAAC,EAC5B,OAAO8E,GAASA,GAAc,OAAUA,GAAc,GAAK,IAC7D,CAAC,EACKC,EAAWL,EAAU,IAAK1E,IAAMgE,EAAShE,EAAC,GAAG,KAAO,IAAI,EAGxDgF,EAActG,EAAU,OAAQqE,KAAOA,GAAE,MAAM,WAAaA,GAAE,UAAY,IAAI,EACpFiC,EAAY,KACV,CAACL,GAAGnC,MACDmC,GAAE,MAAM,WAAaA,GAAE,SAAW,IAAMnC,GAAE,MAAM,WAAaA,GAAE,SAAW,IAC3EmC,GAAE,GAAG,cAAcnC,GAAE,EAAE,CAC3B,EAEA,IAAMyC,EAAsB,CAAC,EACvBC,EAAmD,CAAC,EAC1DR,EAAU,QAAS1E,IAAOkF,EAAclF,EAAC,EAAI,CAAC,CAAE,EAEhDgF,EAAY,QAASjC,IAAM,CACzB,IAAMkB,GAAQd,IAAc,QAAUJ,GAAE,MAAM,WAAaA,GAAE,MAAM,QAC9DkB,KAELgB,EAAU,MAAMlC,GAAE,MAAM,WAAaA,GAAE,SAAY,GAAI,EACvD2B,EAAU,QAAS1E,IAAM,CACvB,IAAM8E,GAAQb,GAAMjE,EAAC,EACfuE,EAAMO,GAAS3B,IAAc,QAAW2B,GAAc,MAASA,GAAc,GAAM,KACzFI,EAAclF,EAAC,EAAE,KAAKuE,CAAG,CAC3B,CAAC,EACH,CAAC,EAED,IAAIY,EAAaT,EAAU,CAAC,GAAK,EAC7BU,GAAiBJ,EACjBK,EAA2B,KAE/B,SAASC,EAAgBzC,GAAaN,GAAe,CACnD,IAAMgD,GAAUN,EAAUA,EAAU,OAAS,CAAC,GAAK,WAC/CO,GAAU,EAEVjD,KAAU,KAAMiD,GAAUD,GAAU,GAAK,GAAK,KACzChD,KAAU,KAAMiD,GAAUD,GAAU,GAAK,GAAK,KAC9ChD,KAAU,KAAMiD,GAAUD,GAAU,IAAM,GAAK,KAC/ChD,KAAU,KAAMiD,GAAUD,GAAU,IAAM,GAAK,KAC/ChD,KAAU,OAAMiD,GAAUD,GAAU,EAAI,IAAM,GAAK,MAE5D,IAAME,EAA4B,CAAC,EACnCR,EAAU,QAAQ,CAAClC,GAAG2C,KAAQ,CACxB3C,IAAKyC,IAASC,EAAgB,KAAKC,EAAG,CAC5C,CAAC,EAED,IAAMC,EAAYF,EAAgB,IAAKnG,IAAM2F,EAAU3F,EAAC,CAAC,EACnDsG,GAAOV,EAAcrC,EAAG,GAAK,CAAC,EAC9BgD,GAAeJ,EAAgB,IAAKnG,IAAMsG,GAAKtG,EAAC,CAAC,EACjDwG,EAAoBC,GAAeF,GAAc,CAAC,EACxD,OAAAT,GAAiBK,EAAgB,IAAKnG,IAAM0F,EAAY1F,EAAC,CAAC,EAEnD,CAAE,UAAAqG,EAAW,aAAAE,GAAc,kBAAAC,CAAkB,CACtD,CAEA,IAAIE,GAA8B,KAE5BC,GAAU,SAAS,cAAc,KAAK,EAC5C,OAAAA,GAAQ,UAAY,mBACpBA,GAAQ,MAAM,QACZ,sOACFlC,EAAQ,MAAM,SAAW,WACzBA,EAAQ,YAAYkC,EAAO,GAEN,IAAM,CACzB,IAAMC,GAA2B,CAC/B,GAAI,GAAG/C,CAAS,aAChB,MAAO,IACP,OAAQ,IACR,QAAS,CAAC,EAAG,GAAI,EAAG,EAAE,EACtB,OAAQ,CACN,EAAG,CAAE,KAAM,GAAO,MAAO,EAAG,KAAM,EAAK,EACvC,EAAG,CAAE,KAAM,EAAK,CAClB,EACA,OAAQ,CACN,CAAC,EACD,CACE,MAAO,gBACP,OAAQG,EACR,MAAO,EACP,KAAM6C,GAAU7C,EAAO,EAAG,EAC1B,OAAQ,CAAE,KAAM,GAAM,KAAM,EAAG,KAAMA,CAAM,CAC7C,EACA,CACE,MAAO,eACP,OAAQ,UACR,MAAO,EACP,KAAM,cACN,OAAQ,CAAE,KAAM,GAAM,KAAM,EAAG,KAAM,SAAU,CACjD,CACF,EACA,KAAM,CACJ,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,GACN,OAAQ,IAAM,CAAC,EACf,MAAO,CAAE,KAAM,EAAM,EACrB,KAAM,6BACN,KAAM,EACR,EACA,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,OAAQ,CAAC8C,EAAIC,IAASA,EAAK,IAAKC,IAAM,GAAGA,EAAC,GAAGjD,CAAI,EAAE,EACnD,KAAM,6BACN,KAAM,EACR,CACF,EACA,OAAQ,CACN,KAAM,CAAE,EAAG,GAAO,EAAG,EAAM,EAC3B,QAAS,CAACkD,EAAGC,EAAWC,KAAYA,GACpC,EAAG,GACH,EAAG,EACL,EACA,MAAO,CACL,KAAM,CACHF,GAAa,CACZ,IAAMG,EAAMH,EAAE,IACRI,GAAM,OAAO,kBAAoB,EACjCC,GAAKL,EAAE,KACPM,EAAa,CACjB,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,KAAM,KAAM,KAAM,KAAM,KAClE,EACMC,GAASlC,EAAMA,EAAM,OAAS,CAAC,EAErC8B,EAAI,KAAK,EACTA,EAAI,UAAY,UAChBA,EAAI,UAAY,SAChBA,EAAI,aAAe,MACnBA,EAAI,KAAO,GAAG,GAAKC,EAAG,2BAEtB,IAAII,GAAQ,KAWZ,GAVAF,EAAW,QAAS7G,IAAM,CACxB,GAAIA,GAAI8G,GAAQ,OAChB,IAAME,GAAIT,EAAE,SAASvG,GAAG,IAAK,EAAI,EAC7BgH,GAAID,GAAQ,GAAKJ,IAAOK,GAAIJ,GAAG,KAAOA,GAAG,MAAQ,EAAID,KACvDD,EAAI,SAASO,GAAYjH,EAAC,EAAGgH,GAAGJ,GAAG,IAAMA,GAAG,OAAS,EAAID,EAAG,EAC5DI,GAAQC,GAEZ,CAAC,EAGG3B,IAAc,KAAM,CACtB,IAAMK,GAAMd,EAAM,QAAQS,CAAS,EACnC,GAAIK,IAAO,EAAG,CACZ,IAAMwB,GAAMX,EAAE,SAASlB,EAAW,IAAK,EAAI,EACrC8B,GAAMZ,EAAE,SAAS1B,GAAaa,EAAG,GAAMX,EAASW,EAAG,EAAI,IAAK,EAAI,EAEtEgB,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClB,IAAMU,GAASvC,GAAaa,EAAG,EACzB2B,GAAYD,KAAW,KAAO,EAAIT,GAAM,EAAIA,GAC5CW,EAAWF,KAAW,KAAO9D,EAAQ,UAC3CoD,EAAI,IAAIQ,GAAKC,GAAKE,GAAW,EAAG,EAAI,KAAK,EAAE,EAC3CX,EAAI,UAAYY,EAChBZ,EAAI,KAAK,EACTA,EAAI,YAAc,OAClBA,EAAI,UAAY,EAAIC,GACpBD,EAAI,OAAO,EACXA,EAAI,QAAQ,CACd,CACF,CAEAA,EAAI,QAAQ,CACd,EACCH,GAAa,CACZ,IAAMG,EAAMH,EAAE,IACRI,GAAM,OAAO,kBAAoB,EACjCC,GAAKL,EAAE,KAETb,EAAMa,EAAE,OAAO,IACfgB,GAAkB,EAChBC,GAAajB,EAAE,OAAO,KACtBkB,GAAYlB,EAAE,OAAO,IAE3B,GAAIiB,IAAc,MAAQC,IAAa,MAAQD,IAAc,GAAKC,IAAa,EAAG,CAChF,IAAIC,GAAQ,IACRC,GAAa,GACXC,GAAS,GACTC,GAAQD,GAASA,GAEvB,QAAStI,EAAI,EAAGA,EAAIsF,EAAM,OAAQtF,IAAK,CACrC,IAAM0H,GAAIpC,EAAMtF,CAAC,EACXwI,GAAOjD,GAAavF,CAAC,EACrByI,EAAOhD,EAASzF,CAAC,EAEvB,GAAI0H,IAAK,KAAM,CACb,IAAMgB,GAAKzB,EAAE,SAASS,GAAG,IAAK,EAAK,EAEnC,GAAIc,IAAQ,KAAM,CAChB,IAAMG,GAAK1B,EAAE,SAASuB,GAAM,IAAK,EAAK,EAChCI,GAAKF,GAAKR,GACVW,GAAKF,GAAKR,GACVW,GAAKF,GAAKA,GAAKC,GAAKA,GACtBC,GAAKV,KACPA,GAAQU,GACRT,GAAarI,EACbiI,GAAkB,EAEtB,CACA,GAAIQ,GAAQ,KAAM,CAChB,IAAME,GAAK1B,EAAE,SAASwB,EAAM,IAAK,EAAK,EAChCG,GAAKF,GAAKR,GACVW,GAAKF,GAAKR,GACVW,GAAKF,GAAKA,GAAKC,GAAKA,GACtBC,GAAKV,KACPA,GAAQU,GACRT,GAAarI,EACbiI,GAAkB,EAEtB,CACF,CACF,CAEIG,IAASG,GAAOnC,EAAMiC,GACrBjC,EAAM,IACb,CAEA,GAAIA,GAAO,MAAQa,EAAE,KAAK,CAAC,EAAEb,CAAG,GAAK,KAAM,CACzC,IAAMwB,GAAMX,EAAE,SAASA,EAAE,KAAK,CAAC,EAAEb,CAAG,EAAI,IAAK,EAAI,EAC3CyB,GAAMZ,EAAE,SACZgB,KAAoB,EAAI1C,GAAaa,CAAG,EAAKX,EAASW,CAAG,EACzD,IACA,EACF,EAGAgB,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,GAAK,EAAIA,EAAG,CAAC,EAClCD,EAAI,YAAcP,GAAUoB,KAAoB,EAAIjE,EAAQ,UAAW,EAAG,EAC1EoD,EAAI,UAAY,EAAIC,GAEpBD,EAAI,OAAOQ,GAAKN,GAAG,GAAG,EACtBF,EAAI,OAAOQ,GAAKN,GAAG,IAAMA,GAAG,MAAM,EAElCF,EAAI,OAAOE,GAAG,KAAMO,EAAG,EACvBT,EAAI,OAAOE,GAAG,KAAOA,GAAG,MAAOO,EAAG,EAClCT,EAAI,OAAO,EACXA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,IAAIQ,GAAKC,GAAK,GAAKR,GAAK,EAAG,EAAI,KAAK,EAAE,EAC1CD,EAAI,UAAYP,GAAUoB,KAAoB,EAAIjE,EAAQ,UAAW,EAAG,EACxEoD,EAAI,KAAK,EACTA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,UAAU,EACd,IAAMW,GAAYE,KAAoB,EAAI,EAAIZ,GAAM,EAAIA,GAClDW,GAAWC,KAAoB,EAAIjE,EAAQ,UACjDoD,EAAI,IAAIQ,GAAKC,GAAKE,GAAW,EAAG,EAAI,KAAK,EAAE,EAC3CX,EAAI,UAAYY,GAChBZ,EAAI,KAAK,EACTA,EAAI,YAAc,OAClBA,EAAI,UAAY,EAAIC,GACpBD,EAAI,OAAO,EACXA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,YAAY,CAAC,CAAC,EAElB,IAAM2B,EAAUpB,GAAYrC,EAAMc,CAAI,CAAC,EACvCgB,EAAI,KAAO,QAAQ,GAAKC,EAAG,2BAE3B,IAAM2B,GADY5B,EAAI,YAAY2B,CAAO,EAAE,MACnB,GAAK1B,GACvB4B,EAAQ,GAAK5B,GAEb6B,GAAUtB,GAAMoB,GAAM,EACtBG,GAAa,KAAK,IAAI7B,GAAG,KAAM,KAAK,IAAIA,GAAG,KAAOA,GAAG,MAAQ0B,GAAKE,EAAO,CAAC,EAC1EE,GAAU9B,GAAG,IAAMA,GAAG,OAAS,EAAID,GAGzCD,EAAI,UAAY,yBAChBA,EAAI,UAAU,EACTA,EAAY,UACdA,EAAY,UAAU+B,GAAYC,GAASJ,GAAKC,EAAO,EAAI5B,EAAG,EAC5DD,EAAI,KAAK+B,GAAYC,GAASJ,GAAKC,CAAK,EAC7C7B,EAAI,KAAK,EACTA,EAAI,YAAcP,GAAU7C,EAAO,GAAI,EACvCoD,EAAI,UAAY,EAAIC,GACpBD,EAAI,OAAO,EAEXA,EAAI,UAAYpD,EAChBoD,EAAI,UAAY,SAChBA,EAAI,aAAe,SACnBA,EAAI,SAAS2B,EAASI,GAAaH,GAAM,EAAGI,GAAUH,EAAQ,CAAC,EAG/D,IAAMI,GAAU,IADH9D,GAAaa,CAAI,GAAMX,EAASW,CAAI,GACzB,QAAQ,CAAC,CAAC,IAAIrC,CAAI,GAEpCuF,GADYlC,EAAI,YAAYiC,EAAO,EAAE,MACnB,GAAKhC,GAEvBkC,GAAUjC,GAAG,KAAOgC,GAAM,EAAIjC,GAC9BmC,GAAU3B,GAAMoB,EAAQ,EAG9B7B,EAAI,UAAY,yBAChBA,EAAI,UAAU,EACTA,EAAY,UACdA,EAAY,UAAUmC,GAASC,GAASF,GAAKL,EAAO,EAAI5B,EAAG,EACzDD,EAAI,KAAKmC,GAASC,GAASF,GAAKL,CAAK,EAC1C7B,EAAI,KAAK,EACTA,EAAI,YAAcP,GAAU7C,EAAO,GAAI,EACvCoD,EAAI,UAAY,EAAIC,GACpBD,EAAI,OAAO,EAEXA,EAAI,UAAYpD,EAChBoD,EAAI,UAAY,OAChBA,EAAI,aAAe,SACnBA,EAAI,SAASiC,GAASE,GAAU,EAAIlC,GAAKmC,GAAUP,EAAQ,CAAC,EAE5D7B,EAAI,QAAQ,CACd,CACF,CACF,EACA,UAAW,CACRH,GAAa,CACZ,GAAI,CAAEA,EAAU,OAAQ,OACxBA,EAAE,OAAO,EAAK,EAEd,IAAIb,EAAMa,EAAE,OAAO,IACfgB,GAAkB,EAChBC,GAAajB,EAAE,OAAO,KACtBkB,EAAYlB,EAAE,OAAO,IAE3B,GAAIiB,IAAc,MAAQC,GAAa,MAAQD,IAAc,GAAKC,GAAa,EAAG,CAChF,IAAIC,GAAQ,IACRC,GAAa,GACXC,GAAS,GACTC,EAAQD,GAASA,GAEvB,QAAStI,GAAI,EAAGA,GAAIsF,EAAM,OAAQtF,KAAK,CACrC,IAAM0H,GAAIpC,EAAMtF,EAAC,EACXwI,EAAOjD,GAAavF,EAAC,EACrByI,GAAOhD,EAASzF,EAAC,EAEvB,GAAI0H,IAAK,KAAM,CACb,IAAMgB,GAAKzB,EAAE,SAASS,GAAG,IAAK,EAAK,EAEnC,GAAIc,GAAQ,KAAM,CAChB,IAAMG,GAAK1B,EAAE,SAASuB,EAAM,IAAK,EAAK,EAChCI,GAAKF,GAAKR,GACVW,GAAKF,GAAKR,EACVW,GAAKF,GAAKA,GAAKC,GAAKA,GACtBC,GAAKV,KACPA,GAAQU,GACRT,GAAarI,GACbiI,GAAkB,EAEtB,CACA,GAAIQ,IAAQ,KAAM,CAChB,IAAME,GAAK1B,EAAE,SAASwB,GAAM,IAAK,EAAK,EAChCG,GAAKF,GAAKR,GACVW,GAAKF,GAAKR,EACVW,GAAKF,GAAKA,GAAKC,GAAKA,GACtBC,GAAKV,KACPA,GAAQU,GACRT,GAAarI,GACbiI,GAAkB,EAEtB,CACF,CACF,CAEIG,IAASG,EAAOnC,EAAMiC,GACrBjC,EAAM,IACb,CAEA,IAAMgB,GAAMH,EAAE,IACRI,GAAM,OAAO,kBAAoB,EACjCC,GAAKL,EAAE,KAIb,GAFiBb,GAAO,MAAQd,EAAMc,CAAG,GAAK,KAEhC,CACZ,IAAMqD,GAAKxC,EAAE,SAAS3B,EAAMc,CAAI,EAAI,IAAK,EAAK,EACxCsD,GAAKzC,EAAE,SAAS1B,GAAaa,CAAI,GAAMX,EAASW,CAAI,EAAI,IAAK,EAAK,EAElEuD,GAASrE,EAAMc,CAAI,EACnB0B,EAASvC,GAAaa,CAAI,EAC1BwD,GAAQnE,EAASW,CAAI,EAEvByD,GAAO,wCAAwClC,GAAYgC,EAAM,CAAC,SAoBtE,GAnBI7B,IAAW,OACb+B,IAAQ;AAAA;AAAA;AAAA,4DAGoC/B,CAAM,IAAI/D,CAAI;AAAA;AAAA,mBAIxD6F,KAAU,OACZC,IAAQ;AAAA;AAAA;AAAA,4DAGoCD,EAAK,IAAI7F,CAAI;AAAA;AAAA,mBAK3D4C,GAAQ,UAAYkD,GAEhBnD,IACEX,IAAc,KAAM,CACtBF,EAAa8D,GACb,GAAM,CAAE,UAAAtD,EAAW,aAAAE,GAAc,kBAAAC,EAAkB,EAAIR,EACrDH,EACAtG,CACF,EACMuK,GAAatD,GAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,GAAM,IAAK,EACvE+C,GAAavD,GAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,IAAM,IAAK,EAC7EN,GAAc,QAAQ,CACpBL,EACAE,GACAC,GACAsD,GACAC,EACF,CAAC,EAED,IAAMC,GAAU,SAAS,eAAe,GAAGnG,CAAS,iBAAiB,EACjEmG,KACFA,GAAQ,YAAc,YAAYrC,GAAYgC,EAAM,CAAC,IAAI9F,IAAc,QAAU,QAAU,IAAI,GACnG,CAEF8C,GAAQ,MAAM,QAAU,GACxBA,GAAQ,MAAM,KAAO,GAAGuB,GAAcZ,GAAG,IAAI,KAC7CX,GAAQ,MAAM,IAAM,GAAGwB,EAAab,GAAG,GAAG,KAC1CX,GAAQ,MAAM,UAAY,sBAC5B,MACEA,GAAQ,MAAM,QAAU,MAE5B,CACF,CACF,CACF,EAEAxC,EAAY,IAAIxB,GAAMiE,GAAW,CAACtB,EAAOC,GAAcE,CAAQ,EAAGhB,CAAO,EACzErG,GAAe,KAAK+F,CAAS,EAE7BM,EAAQ,iBAAiB,QAAS,IAAM,CACtC,GAAI,CAACN,EAAW,OAChB,IAAMiC,EAAMjC,EAAU,OAAO,IAC7B,GAAIiC,GAAO,KAAM,CACf,IAAM6D,EAAa3E,EAAMc,CAAG,EACxB8D,GAA8B,KAOlC,GANInE,IAAc,KAAMmE,GAAe,KAClCA,GAAeD,EAEpB3G,EAAY4G,EAAY,EAGpB/K,EAAc,CAChB,IAAMgL,GAAQhL,EAAa,MACrBwF,EAAQd,IAAc,QAAUsG,GAAM,WAAaA,GAAM,QAC/D,GAAIxF,EAAO,CACT,IAAMa,GAAQb,EAAMsF,CAAU,EAC9B,GAAIzE,GAAO,CACT,IAAM4E,GAAU5E,GAAM,IAChB6E,GAAWJ,EACXK,GAAUnL,EAAa,OAAOiL,EAAO,EACrCG,GAAQpL,EAAa,OAAOiL,GAAUC,GAAW,CAAC,EACxD,GAAIC,IAAWC,IAASD,GAAQ,MAAQ,MAAQC,GAAM,MAAQ,KAAM,CAClE,IAAMC,GAAarL,EAAa,OAAO,CAAC,EAAE,MAAQ,EAC5CsL,IAAOH,GAAQ,KAAOE,IAAc,IACpCE,GAAOH,GAAM,KAAOC,IAAc,IACxCnL,IAAgBF,EAAa,GAAI,CAACsL,GAAKC,CAAG,CAAC,CAC7C,CACF,CACF,CACF,CACF,CACF,CAAC,EAEDjG,EAAQ,iBAAiB,aAAc,IAAM,CACvCN,GAAWA,EAAU,OAAO,CAClC,CAAC,EAGD,IAAMwG,GAAY,SAAS,cAAc,SAAS,EAClDA,GAAU,UAAU,IAAI,kBAAkB,EAC1CA,GAAU,MAAM,UAAY,MAC5BA,GAAU,MAAM,YAAY,gBAAiB3G,CAAK,EAClD2G,GAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAedvF,EACC,IAAK1E,GAAM,CACV,IAAMkK,EAAM1F,EAAaxE,CAAC,EACrBwE,EAAaxE,CAAC,EAAU,OAAUwE,EAAaxE,CAAC,EAAU,GAC3D,IACEmK,GAAKnG,EAAShE,CAAC,GAAG,KAAO,IACzBoK,GAAOpG,EAAShE,CAAC,GAAG,QACpBqK,EAAQrG,EAAShE,CAAC,GAAG,IAC3B,MAAO;AAAA;AAAA,sBAECiH,GAAYjH,CAAC,CAAC;AAAA,sBACdkK,CAAG,IAAI7G,CAAI;AAAA;AAAA,oBAEb8G,EAAE,IAAI9G,CAAI;AAAA,oBACV+G,GAAO,iDAAiDA,EAAI,eAAeC,CAAK,eAAerK,CAAC,oGAAsG,EAAE;AAAA;AAAA;AAAA,aAIhN,CAAC,EACA,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,MAIjB0D,EAAc,YAAYuG,EAAS,EAEnCA,GAAU,iBAAiB,uBAAuB,EAAE,QAAS3H,GAAQ,CACnEA,EAAI,iBAAiB,QAAUgI,GAAM,CACnCA,EAAE,eAAe,EACjBA,EAAE,gBAAgB,EAClB,IAAMC,GAAKjI,EAAI,aAAa,SAAS,EAC/BoD,GAAMpD,EAAI,aAAa,UAAU,EACjCO,EAAMP,EAAI,aAAa,UAAU,EACnCiI,IACF,SAAS,cACP,IAAI,YAAY,eAAgB,CAC9B,OAAQ,CACN,GAAAA,GACA,IAAK7E,GAAM,OAAOA,EAAG,EAAI,KACzB,IAAK7C,EAAM,OAAOA,CAAG,EAAI,IAC3B,CACF,CAAC,CACH,CAEJ,CAAC,CACH,CAAC,EAED,IAAI2H,GAAgC,KAG9BC,GAAa5G,EAAK,cAAc,IAAIV,CAAS,iBAAiB,EACpE,GAAIsH,GAAY,CACdA,GAAW,MAAM,SAAW,WAC5B,IAAMC,EAAkB,SAAS,cAAc,KAAK,EAMpD,GALAA,EAAgB,UAAY,0BAC5BA,EAAgB,MAAM,QACpB,sOACFD,GAAW,YAAYC,CAAe,EAElCzF,EAAU,OAAS,EAAG,CACxB,GAAM,CAAE,UAAAU,EAAW,aAAAE,GAAc,kBAAAC,EAAkB,EAAIR,EACrDH,EACAtG,CACF,EACMuK,EAAatD,GAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,GAAM,IAAK,EACvE+C,GAAavD,GAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,IAAM,IAAK,EACvEqE,GAAe,CAAChF,EAAWE,GAAcC,GAAmBsD,EAAYC,EAAU,EAElFuB,GAAgB,CACpB,CACE,MAAO,CAACrE,GAAQD,KACVA,IAAK,KAAalC,GAAQkC,GAAI,GAAI,EAE/B,GAEX,EACA,CACE,MAAO,QACP,OAAQhD,EACR,MAAO,EACP,OAAQ,CAAE,KAAM,GAAM,KAAM,EAAG,KAAM6C,GAAU7C,EAAO,EAAG,CAAE,CAC7D,EACA,CACE,MAAO,QACP,OAAQA,EACR,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,EACtB,SAAU,GACV,KAAM,cACN,KAAM,CAAC,EAAG,CAAC,CACb,EACA,CACE,MAAO,cACP,OAAQ,cACR,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,EACtB,SAAU,EACZ,EACA,CACE,MAAO,cACP,OAAQ,cACR,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,EACtB,SAAU,EACZ,CACF,EAEMgG,GAAU,SAAS,eAAe,GAAGnG,CAAS,iBAAiB,EACjEmG,KACFA,GAAQ,YAAc,YAAYrC,GAAY9B,CAAU,CAAC,IAAIhC,IAAc,QAAU,QAAU,IAAI,IAErG,IAAM0H,GAA8B,CAClC,MAAO,KAAK,IAAI,KAAM9I,GAAa,KAAO,GAAG,EAC7C,OAAQ,IACR,QAAS,CAAC,EAAG,GAAI,EAAG,EAAE,EACtB,OAAS+I,IAAe7I,GAAM,OAAO,IAAI,KAAK6I,GAAK,GAAI,EAAG,SAAS,EACnE,OAAQ,CACN,OAAQ,CACN,KAAM,EACR,EACA,KAAM,CAAE,SAAU,EAAM,EACxB,EAAG,GACH,EAAG,EACL,EACA,OAAQ,CACN,EAAG,CACD,KAAM,GACN,MAAQvE,IAAM,CACZ,IAAMwD,GAAMxD,GAAE,KAAK,CAAC,EAAE,CAAC,EACjByD,EAAMzD,GAAE,KAAK,CAAC,EAAEA,GAAE,KAAK,CAAC,EAAE,OAAS,CAAC,EAC1C,OAAIwD,KAAQ,QAAaC,IAAQ,OAAkB,CAAC,EAAG,GAAG,EAEtDD,KAAQC,EAAY,CAACD,GAAM,KAAMC,EAAM,IAAI,EAExC,CAACD,GAAKC,CAAG,CAClB,CACF,EACA,EAAG,CAAE,MAAO,CAACzD,GAAQwD,GAAaC,IAAgB,CAACD,GAAM,GAAKC,EAAM,GAAG,CAAE,CAC3E,EACA,OAAQY,GACR,MAAO,CAAC,CAAE,OAAQ,CAAC,EAAG,CAAC,EAAG,KAAMzE,GAAU7C,EAAO,EAAG,CAAE,CAAC,EACvD,MAAO,CACL,KAAM,CACHiD,IAAa,CACZA,GAAE,KAAK,iBAAiB,QAAS,IAAM,CACrC,GAAIiE,IAAkB,KAAM,CAC1B,IAAMzL,GAAQqG,GAAeoF,EAAc,EAC3C,GAAIzL,GAAO,CACT,IAAM0K,EAAQ1K,GAAM,MACdkF,GAAQd,IAAc,QAAUsG,EAAM,WAAaA,EAAM,QAC/D,GAAIxF,GAAO,CACT,IAAMa,GAAQb,GAAMkB,CAAU,EAC9B,GAAIL,GAAO,CACT,IAAM4E,EAAU5E,GAAM,IAChB6E,GAAWxE,EAEXyE,GAAU7K,GAAM,OAAO2K,CAAO,EAC9BG,GAAQ9K,GAAM,OAAO2K,EAAUC,GAAW,CAAC,EAEjD,GAAIC,IAAWC,IAASD,GAAQ,MAAQ,MAAQC,GAAM,MAAQ,KAAM,CAClE,IAAMC,GAAa/K,GAAM,OAAO,CAAC,EAAE,MAAQ,EACrCgL,IAAOH,GAAQ,KAAOE,IAAc,IACpCE,IAAOH,GAAM,KAAOC,IAAc,IAExC5G,EAAK,gBAAgBnE,GAAM,GAAI,CAACgL,GAAKC,EAAG,CAAC,CAC3C,MACE9G,EAAK,gBAAgBnE,GAAM,GAAI,IAAI,CAEvC,MACEmE,EAAK,gBAAgBnE,GAAM,GAAI,IAAI,CAEvC,MACEmE,EAAK,gBAAgBnE,GAAM,GAAI,IAAI,CAEvC,CACF,CACF,CAAC,CACH,CACF,EACA,KAAM,CACHwH,IAAa,CACZ,IAAIb,GAAMa,GAAE,OAAO,IACnB,GAAIb,IAAO,MAAQa,GAAE,KAAK,CAAC,EAAEb,EAAG,GAAK,KAAM,CACzC,IAAMnB,EAAMgC,GAAE,KAAK,CAAC,EAAEb,EAAG,EACzB,GAAInB,GAAO,KAAM,CACf,IAAMwG,GAAOxE,GAAE,SAASA,GAAE,KAAK,CAAC,EAAEb,EAAG,EAAI,IAAK,EAAI,EAC5CsF,GAAOzE,GAAE,SAAShC,EAAK,IAAK,EAAI,EAEhC0G,EAAO1E,GAAE,IACT2E,GAAO,OAAO,kBAAoB,EAGxCD,EAAK,KAAK,EACVA,EAAK,UAAU,EACfA,EAAK,YAAY,CAAC,EAAIC,GAAM,EAAIA,EAAI,CAAC,EACrCD,EAAK,YAAc9E,GAAU7C,EAAO,EAAG,EACvC2H,EAAK,UAAY,EAAIC,GAErBD,EAAK,OAAOF,GAAMxE,GAAE,KAAK,GAAG,EAC5B0E,EAAK,OAAOF,GAAMxE,GAAE,KAAK,IAAMA,GAAE,KAAK,MAAM,EAE5C0E,EAAK,OAAO1E,GAAE,KAAK,KAAMyE,EAAI,EAC7BC,EAAK,OAAO1E,GAAE,KAAK,KAAOA,GAAE,KAAK,MAAOyE,EAAI,EAC5CC,EAAK,OAAO,EACZA,EAAK,QAAQ,EAGbA,EAAK,KAAK,EACVA,EAAK,UAAU,EACfA,EAAK,YAAY,CAAC,CAAC,EACnBA,EAAK,IAAIF,GAAMC,GAAM,GAAKE,GAAM,EAAG,EAAI,KAAK,EAAE,EAC9CD,EAAK,UAAY9E,GAAU7C,EAAO,EAAG,EACrC2H,EAAK,KAAK,EACVA,EAAK,QAAQ,EAGbA,EAAK,KAAK,EACVA,EAAK,UAAU,EACfA,EAAK,IAAIF,GAAMC,GAAM,EAAIE,GAAM,EAAG,EAAI,KAAK,EAAE,EAC7CD,EAAK,UAAY3H,EACjB2H,EAAK,KAAK,EACVA,EAAK,YAAc,OACnBA,EAAK,UAAY,EAAIC,GACrBD,EAAK,OAAO,EACZA,EAAK,QAAQ,EAGbA,EAAK,KAAK,EACVA,EAAK,YAAY,CAAC,CAAC,EAEnB,IAAMjL,GAAI,IAAI,KAAKuG,GAAE,KAAK,CAAC,EAAEb,EAAG,EAAK,GAAI,EACnCyF,GAAU,GAAGnL,GAAE,eAAe,CAAC,IAAI,OAAOA,GAAE,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,IAAI,OAAOA,GAAE,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,GAChIiL,EAAK,KAAO,QAAQ,GAAKC,EAAI,2BAE7B,IAAM5C,GADY2C,EAAK,YAAYE,EAAO,EAAE,MACpB,GAAKD,GACvB3C,GAAQ,GAAK2C,GAEb1C,GAAUuC,GAAOzC,GAAM,EACvBG,GAAa,KAAK,IACtBlC,GAAE,KAAK,KACP,KAAK,IAAIA,GAAE,KAAK,KAAOA,GAAE,KAAK,MAAQ+B,GAAKE,EAAO,CACpD,EACME,GAAUnC,GAAE,KAAK,IAAMA,GAAE,KAAK,OAAS,EAAI2E,GAGjDD,EAAK,UAAY,yBACjBA,EAAK,UAAU,EACVA,EAAa,UACfA,EAAa,UAAUxC,GAAYC,GAASJ,GAAKC,GAAO,EAAI2C,EAAI,EAC9DD,EAAK,KAAKxC,GAAYC,GAASJ,GAAKC,EAAK,EAC9C0C,EAAK,KAAK,EACVA,EAAK,YAAc9E,GAAU7C,EAAO,GAAI,EACxC2H,EAAK,UAAY,EAAIC,GACrBD,EAAK,OAAO,EAEZA,EAAK,UAAY3H,EACjB2H,EAAK,UAAY,SACjBA,EAAK,aAAe,SACpBA,EAAK,SAASE,GAAS1C,GAAaH,GAAM,EAAGI,GAAUH,GAAQ,CAAC,EAEhE,IAAM6C,GAAS,GAAG7G,EAAI,QAAQ,CAAC,CAAC,IAAIlB,CAAI,GAElCuF,GADWqC,EAAK,YAAYG,EAAM,EAAE,MACnB,GAAKF,GAEtBrC,GAAUtC,GAAE,KAAK,KAAOqC,GAAM,EAAIsC,GAClCpC,GAAUkC,GAAOzC,GAAQ,EAG/B0C,EAAK,UAAY,yBACjBA,EAAK,UAAU,EACVA,EAAa,UACfA,EAAa,UAAUpC,GAASC,GAASF,GAAKL,GAAO,EAAI2C,EAAI,EAC3DD,EAAK,KAAKpC,GAASC,GAASF,GAAKL,EAAK,EAC3C0C,EAAK,KAAK,EACVA,EAAK,YAAc9E,GAAU7C,EAAO,GAAI,EACxC2H,EAAK,UAAY,EAAIC,GACrBD,EAAK,OAAO,EAEZA,EAAK,UAAY3H,EACjB2H,EAAK,UAAY,OACjBA,EAAK,aAAe,SACpBA,EAAK,SAASG,GAAQvC,GAAU,EAAIqC,GAAMpC,GAAUP,GAAQ,CAAC,EAE7D0C,EAAK,QAAQ,CACf,CACF,CACF,CACF,EACA,UAAW,CACR1E,IAAa,CACZ,GAAI,CAAEA,GAAU,OAAQ,OACxBA,GAAE,OAAO,EAAK,EAEd,IAAIb,GAAMa,GAAE,OAAO,IACbiB,EAAajB,GAAE,OAAO,KACtBkB,GAAYlB,GAAE,OAAO,IACrBK,GAAKL,GAAE,KAEb,GAAIiB,GAAc,MAAQC,IAAa,MAAQD,GAAc,GAAKC,IAAa,EAAG,CAChF,IAAIC,EAAQ,IACRC,GAAa,GACXC,GAAS,GACTC,GAAQD,GAASA,GAEjBhD,GAAQ2B,GAAE,KAAK,CAAC,EAChB8E,GAAQ9E,GAAE,KAAK,CAAC,EAEtB,QAASjH,GAAI,EAAGA,GAAIsF,GAAM,OAAQtF,KAAK,CACrC,IAAM0H,GAAIpC,GAAMtF,EAAC,EACXgM,GAAID,GAAM/L,EAAC,EACjB,GAAI0H,IAAK,MAAQsE,IAAK,KAAM,SAE5B,IAAMtD,GAAKzB,GAAE,SAASS,GAAG,IAAK,EAAK,EAC7BiB,GAAK1B,GAAE,SAAS+E,GAAG,IAAK,EAAK,EAE7BpD,GAAKF,GAAKR,EACVW,GAAKF,GAAKR,GACVW,GAAKF,GAAKA,GAAKC,GAAKA,GAEtBC,GAAKV,IACPA,EAAQU,GACRT,GAAarI,GAEjB,CAEIoI,GAASG,IACXnC,GAAMiC,GACN6C,GAAiB7C,KAEjBjC,GAAM,KACN8E,GAAiB,KAErB,CAEA,GAAI9E,IAAO,MAAQa,GAAE,KAAK,CAAC,EAAEb,EAAG,GAAK,KAAM,CACzC,IAAM3G,EAAQqG,GAAeM,EAAG,EAC1BqD,GAAKxC,GAAE,SAASA,GAAE,KAAK,CAAC,EAAEb,EAAG,EAAG,IAAK,EAAK,EAC1CsD,GAAKzC,GAAE,SAASA,GAAE,KAAK,CAAC,EAAEb,EAAG,EAAI,IAAK,EAAK,EAE3C1F,GAAI,IAAI,KAAKuG,GAAE,KAAK,CAAC,EAAEb,EAAG,EAAK,GAAI,EACnCyF,GAAU,GAAGnL,GAAE,eAAe,CAAC,IAAI,OAAOA,GAAE,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,IAAI,OAAOA,GAAE,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,GAE1HuE,GAAMgC,GAAE,KAAK,CAAC,EAAEb,EAAG,EACnB0F,GAAS7G,IAAO,KAAO,GAAGA,EAAG,IAAIlB,CAAI,GAAK,SAEhDqH,EAAgB,UAAY;AAAA;AAAA;AAAA,8DAGgBS,EAAO;AAAA;AAAA;AAAA;AAAA,8DAIPC,EAAM;AAAA;AAAA,oBAGlDV,EAAgB,MAAM,QAAU,QAChCA,EAAgB,MAAM,KAAO,GAAGlD,EAAcZ,GAAG,IAAI,KACrD8D,EAAgB,MAAM,IAAM,GAAGjD,GAAab,GAAG,GAAG,KAClD8D,EAAgB,MAAM,UAAY,sBACpC,MACEA,EAAgB,MAAM,QAAU,MAEpC,CACF,CACF,EACA,KAAM,CACJ,CACE,MAAO,GACP,OAAQ,UACR,KAAM,CAAE,OAAQ,SAAU,EAC1B,KAAM,GACN,KAAM,6BACN,KAAM,GACN,OAAQ,CAACnE,GAAQF,KACfA,GAAK,IAAKC,GAAM,CACd,IAAMtG,GAAI,IAAI,KAAKsG,EAAI,GAAI,EAC3B,MAAO,GAAGtG,GAAE,eAAe,CAAC,IAAI,OAAOA,GAAE,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,EAC9E,CAAC,CACL,EACA,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,SAAU,EAC1B,KAAM,6BACN,OAAQ,CAACuG,GAAQF,KAAgBA,GAAK,IAAKC,GAAM,GAAGA,CAAC,IAAIjD,CAAI,EAAE,EAC/D,KAAM,GACN,MAAO,GACP,KAAM,EACR,CACF,CACF,EAEA2C,GAAgB,IAAI/D,GAAM4I,GAAcF,GAAqBF,EAAU,EACvE/M,GAAe,KAAKsI,EAAa,EAEjCyE,GAAW,iBAAiB,aAAc,IAAM,CAC9CzE,GAAe,OAAO,CACxB,CAAC,CAGH,MACEyE,GAAW,UAAY,mEAE3B,CACF,GACa,EAEN,CACL,UAAY5H,IAAuB,CACjCwC,EAAYxC,GACRA,KAAQ,OAAMsC,EAAatC,IAE/B,IAAMyG,GAAU,SAAS,eAAe,GAAGnG,CAAS,iBAAiB,EAIrE,GAHImG,KACFA,GAAQ,YAAc,YAAYrC,GAAY9B,CAAU,CAAC,IAAIhC,IAAc,QAAU,QAAU,IAAI,GAAGkC,IAAc,KAAO,YAAc,EAAE,IAEzIW,GAAe,CACjB,GAAM,CAAE,UAAAL,GAAW,aAAAE,GAAc,kBAAAC,CAAkB,EAAIR,EACrDH,EACAtG,CACF,EACMuK,EAAatD,EAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,GAAM,IAAK,EACvE+C,GAAavD,EAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,IAAM,IAAK,EAC7EN,GAAc,QAAQ,CAACL,GAAWE,GAAcC,EAAmBsD,EAAYC,EAAU,CAAC,CAC5F,CACI5F,GAAWA,EAAU,OAAO,CAClC,EACA,YAAclB,IAAkB,CAE9B,GADA1D,EAAe0D,GACXyD,GAAe,CACjB,GAAM,CAAE,UAAAL,GAAW,aAAAE,GAAc,kBAAAC,EAAkB,EAAIR,EACrDH,EACAtG,CACF,EACMuK,EAAatD,GAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,GAAM,IAAK,EACvE+C,EAAavD,GAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,IAAM,IAAK,EAC7EN,GAAc,QAAQ,CAACL,GAAWE,GAAcC,GAAmBsD,EAAYC,CAAU,CAAC,CAC5F,CACF,CACF,CACF,CAEA,SAASkC,GAAapH,EAAkB,CACtC,IAAMnE,EAAI,IAAI,KAAKmE,CAAI,EACjBzC,EAAM1B,EAAE,UAAU,EAClBwL,EAAOxL,EAAE,WAAW,EAAI0B,GAAOA,IAAQ,EAAI,GAAK,GACtD,OAAA1B,EAAE,WAAWwL,CAAI,EACjBxL,EAAE,YAAY,EAAG,EAAG,EAAG,CAAC,EACjBA,CACT,CAEA,SAASyL,GACP/M,EACyD,CACzD,IAAMgN,EAAsE,CAAC,EAE7E,OAAAhN,EAAU,QAAS,GAAM,CACvB,GAAI,CAAC,EAAE,MAAM,WAAa,CAAC,EAAE,MAAM,UAAW,OAE9C,IAAMyF,EAAO,IAAI,KAAK,EAAE,MAAM,SAAS,EACjCwH,EAAYJ,GAAapH,CAAI,EAC7ByH,EAAUD,EAAU,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EAE/CD,EAAWE,CAAO,IAAGF,EAAWE,CAAO,EAAI,CAAE,UAAWD,EAAU,QAAQ,EAAG,SAAU,CAAE,GAE9FD,EAAWE,CAAO,EAAE,UAAY,EAAE,MAAM,SAC1C,CAAC,EAEM,OAAO,QAAQF,CAAU,EAC7B,IAAI,CAAC,CAACG,EAAMvH,CAAI,KAAO,CAAE,KAAAuH,EAAM,UAAWvH,EAAK,UAAW,SAAUA,EAAK,QAAS,EAAE,EACpF,KAAK,CAACK,EAAGnC,IAAMmC,EAAE,UAAYnC,EAAE,SAAS,CAC7C,CAEA,SAASsJ,GACPpN,EAC0D,CAC1D,IAAMgN,EAAuE,CAAC,EAE9E,OAAAhN,EAAU,QAAS,GAAM,CACvB,GAAI,CAAC,EAAE,MAAM,WAAa,EAAE,MAAM,WAAa,OAAW,OAE1D,IAAMyF,EAAO,IAAI,KAAK,EAAE,MAAM,SAAS,EACjCwH,EAAYJ,GAAapH,CAAI,EAC7ByH,EAAUD,EAAU,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EAE/CD,EAAWE,CAAO,IACrBF,EAAWE,CAAO,EAAI,CAAE,UAAWD,EAAU,QAAQ,EAAG,UAAW,CAAE,GAEvED,EAAWE,CAAO,EAAE,WAAa,EAAE,MAAM,QAC3C,CAAC,EAEM,OAAO,QAAQF,CAAU,EAC7B,IAAI,CAAC,CAACG,EAAMvH,CAAI,KAAO,CAAE,KAAAuH,EAAM,UAAWvH,EAAK,UAAW,UAAWA,EAAK,SAAU,EAAE,EACtF,KAAK,CAACK,EAAGnC,IAAMmC,EAAE,UAAYnC,EAAE,SAAS,CAC7C,CAEA,SAASN,GACPJ,EACApD,EACAqN,EACAC,EACApN,EACAmD,EACA,CACA,IAAMkK,EAAaF,IAAS,WACtBL,EAAaO,EACfR,GAAsB/M,CAAS,EAC/BoN,GAAuBpN,CAAS,EAC9BwN,EAAcC,GAAyBzN,EAAYqE,GACvDkJ,EAAalJ,EAAE,MAAM,UAAYA,EAAE,MAAM,QAC3C,EACMO,EAAQ2I,EAAapK,GAAQ,SAAS,MAAQA,GAAQ,UAAU,MAChEwB,EAAO4I,EAAa,KAAO,IAC3B1I,EAAO0I,EAAapK,GAAQ,SAAS,KAAOA,GAAQ,UAAU,KAE9D6B,EAAgB,SAAS,cAAc,KAAK,EAClDA,EAAc,UAAY,aAAaqI,CAAI,iBAC3CrI,EAAc,GAAK,GAAGqI,CAAI,kBAE1BrI,EAAc,UAAY;AAAA;AAAA;AAAA,wGAG4EJ,CAAK,KAAKC,CAAI;AAAA,4DAC1D0I,EAAa,oBAAsB,oBAAoB;AAAA;AAAA;AAAA;AAAA,iBAIlGF,CAAI;AAAA;AAAA,mBAEFA,CAAI;AAAA;AAAA;AAAA,UAGbK,GAAuBF,EAAaD,EAAY5I,CAAI,CAAC;AAAA;AAAA;AAAA,IAK7DvB,EAAK,YAAY4B,CAAa,EAE9B,IAAMK,EAAUL,EAAc,cAAc,IAAIqI,CAAI,eAAe,EAC7DM,EAAU3I,EAAc,cAAc,IAAIqI,CAAI,eAAe,EAEnE,GAAI,CAAChI,GAAW,CAACsI,EAAS,OAE1BtI,EAAQ,MAAM,SAAW,WAGzB,IAAMuI,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,YACpBA,EAAQ,MAAM,QAAU,SAAShJ,CAAK,gBACtCS,EAAQ,YAAYuI,CAAO,EAE3B,IAAM1H,EAAQ8G,EAAW,IAAK1L,GAAMA,EAAE,UAAY,GAAI,EAChDqL,EAAQY,EACTP,EAAqB,IAAK1L,GAAMA,EAAE,SAAW,GAAI,EACjD0L,EAAqB,IAAK1L,GAAMA,EAAE,SAAS,EAEhD,GAAI4E,EAAM,SAAW,EAAG,OAExB,IAAM2H,EAAgBxG,GAAesF,EAAO,CAAC,EAEvCmB,EAAe,KAAK,IAAI,GAAIzK,GAAa,KAAO,GAAK,IAAM,EAAE,EAC7D0K,EAAQ,KAAK,IAAID,EAAc5H,EAAM,OAAS,EAAE,EAChD8H,EAAS,KAAK,IAAI,GAAGrB,CAAK,EAAI,IAE9BsB,EAA0B,CAC9B,MAAOF,EACP,OAAQ,IACR,QAAS,CAAC,GAAI,GAAI,EAAG,EAAE,EACvB,OAAS3B,GAAe7I,GAAM,OAAO,IAAI,KAAK6I,EAAK,GAAI,EAAG,SAAS,EACnE,OAAQ,CACN,EAAG,CAAE,KAAM,EAAK,EAChB,EAAG,CAAE,MAAO,CAAC,EAAG4B,CAAM,CAAE,CAC1B,EACA,OAAQ,CACN,CAAC,EACD,CACE,MAAOT,EAAa,WAAa,YACjC,OAAQ3I,EACR,KAAM6C,GAAU7C,EAAO,EAAG,EAC1B,MAAO,EACP,OAAQ,CAAE,KAAM,GAAM,KAAM,CAAE,CAChC,EACA,CACE,MAAO,QACP,OAAQA,EACR,MAAO,EACP,KAAM,CAAC,EAAG,CAAC,EACX,OAAQ,CAAE,KAAM,EAAM,CACxB,CACF,EACA,OAAQ,CACN,KAAM0I,EAAU,CAAE,IAAKA,EAAQ,GAAI,EAAI,OACvC,KAAM,CAAE,EAAG,GAAO,EAAG,EAAM,EAC3B,OAAQ,CAAE,KAAM,EAAM,EACtB,EAAG,GACH,EAAG,EACL,EACA,MAAO,CACL,KAAM,CACHzF,GAAa,CACZA,EAAE,KAAK,iBAAiB,QAAS,IAAM,CACrC,IAAMb,EAAMa,EAAE,OAAO,IACrB,GAAIb,GAAO,KAAM,CACf,IAAMkH,EAAOlB,EAAWhG,CAAG,EAC3B,GAAIkH,EAAM,CACR,IAAMC,GAAQ,IAAI,KAAKD,EAAK,SAAS,EAC/BE,EAAM,IAAI,KAAKF,EAAK,UAAY,EAAI,GAAK,GAAK,GAAK,GAAI,EACvDG,EAAWF,GAAM,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EAC3CG,EAASF,EAAI,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EAC7ClO,IAAoBmO,EAAUC,CAAM,CACtC,CACF,CACF,CAAC,CACH,CACF,EACA,UAAW,CACRzG,GAAa,CACZ,GAAI,CAAEA,EAAU,OAAQ,OACxB,IAAMb,EAAMa,EAAE,OAAO,IACfiB,EAAajB,EAAE,OAAO,KACtBkB,GAAYlB,EAAE,OAAO,IAE3B,GACEb,GAAO,MACP8B,GAAc,MACdC,IAAa,MACbD,GAAc,GACdC,IAAa,EACb,CACA,IAAMlD,EAAMgC,EAAE,KAAK,CAAC,EAAEb,CAAG,EACnB0F,EACJ7G,GAAO,KAAQ0H,EAAa,GAAG1H,EAAI,QAAQ,CAAC,CAAC,MAAQ,GAAGA,EAAI,QAAQ,CAAC,CAAC,KAAQ,SAEhF+H,EAAQ,UAAYlB,EACpBkB,EAAQ,MAAM,QAAU,QACxBA,EAAQ,MAAM,KAAO,GAAG/F,EAAE,SAASA,EAAE,KAAK,CAAC,EAAEb,CAAG,EAAI,IAAK,EAAK,CAAC,KAC/D4G,EAAQ,MAAM,IAAM,GAAG/F,EAAE,SAASA,EAAE,KAAK,CAAC,EAAEb,CAAG,EAAI,IAAK,EAAK,CAAC,KAC9D4G,EAAQ,MAAM,UAAY,sBAC5B,MACEA,EAAQ,MAAM,QAAU,OAG1B/F,EAAE,OAAO,EAAK,CAChB,CACF,EACA,KAAM,CACHA,GAAa,CACZ,IAAMb,EAAMa,EAAE,OAAO,IACrB,GAAIb,GAAO,MAAQa,EAAE,KAAK,CAAC,EAAEb,CAAG,GAAK,KAAM,CACzC,IAAMwB,EAAMX,EAAE,SAASA,EAAE,KAAK,CAAC,EAAEb,CAAG,EAAI,IAAK,EAAI,EAC3CyB,GAAMZ,EAAE,SAASA,EAAE,KAAK,CAAC,EAAEb,CAAG,EAAI,IAAK,EAAI,EAC3CiB,EAAM,OAAO,kBAAoB,EACjCD,EAAMH,EAAE,IACRK,EAAKL,EAAE,KAGbG,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,EAAK,EAAIA,CAAG,CAAC,EAClCD,EAAI,YAAcP,GAAU7C,EAAO,EAAG,EACtCoD,EAAI,UAAY,EAAIC,EAEpBD,EAAI,OAAOQ,EAAKN,EAAG,GAAG,EACtBF,EAAI,OAAOQ,EAAKN,EAAG,IAAMA,EAAG,MAAM,EAElCF,EAAI,OAAOE,EAAG,KAAMO,EAAG,EACvBT,EAAI,OAAOE,EAAG,KAAOA,EAAG,MAAOO,EAAG,EAClCT,EAAI,OAAO,EACXA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,IAAIQ,EAAKC,GAAK,GAAKR,EAAK,EAAG,EAAI,KAAK,EAAE,EAC1CD,EAAI,UAAYP,GAAU7C,EAAO,EAAG,EACpCoD,EAAI,KAAK,EACTA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,IAAIQ,EAAKC,GAAK,EAAIR,EAAK,EAAG,EAAI,KAAK,EAAE,EACzCD,EAAI,UAAYpD,EAChBoD,EAAI,KAAK,EACTA,EAAI,YAAc,OAClBA,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EACXA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,YAAY,CAAC,CAAC,EAGlB,IAAM1G,EAAI,IAAI,KAAKuG,EAAE,KAAK,CAAC,EAAEb,CAAG,EAAK,GAAI,EACnC2C,EAAU,GAAGrI,EAAE,eAAe,CAAC,IAAI,OAAOA,EAAE,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,IAAI,OAAOA,EAAE,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,GAChI0G,EAAI,KAAO,QAAQ,GAAKC,CAAG,2BAE3B,IAAM2B,EADY5B,EAAI,YAAY2B,CAAO,EAAE,MACnB,GAAK1B,EACvB4B,EAAQ,GAAK5B,EAEb6B,GAAUtB,EAAMoB,EAAM,EACtBG,GAAa,KAAK,IAAI7B,EAAG,KAAM,KAAK,IAAIA,EAAG,KAAOA,EAAG,MAAQ0B,EAAKE,EAAO,CAAC,EAC1EE,GAAU9B,EAAG,IAAMA,EAAG,OAAS,EAAID,EAEzCD,EAAI,UAAY,yBAChBA,EAAI,UAAU,EACTA,EAAY,UACdA,EAAY,UAAU+B,GAAYC,GAASJ,EAAKC,EAAO,EAAI5B,CAAG,EAC5DD,EAAI,KAAK+B,GAAYC,GAASJ,EAAKC,CAAK,EAC7C7B,EAAI,KAAK,EACTA,EAAI,YAAcP,GAAU7C,EAAO,GAAI,EACvCoD,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EAEXA,EAAI,UAAYpD,EAChBoD,EAAI,UAAY,SAChBA,EAAI,aAAe,SACnBA,EAAI,SAAS2B,EAASI,GAAaH,EAAM,EAAGI,GAAUH,EAAQ,CAAC,EAE/D7B,EAAI,QAAQ,CACd,CACF,CACF,CACF,EACA,KAAM,CACJ,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,GACN,MAAO,GACP,OAAQ,CAACuG,EAAMC,IACbA,EAAO,IAAKC,GAAM,CAChB,IAAMnN,GAAI,IAAI,KAAKmN,EAAI,GAAI,EAC3B,MAAO,GAAGnN,GAAE,YAAY,EAAI,CAAC,IAAIA,GAAE,WAAW,CAAC,EACjD,CAAC,EACH,KAAM,6BACN,KAAM,EACR,EACA,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,GACN,OAAQ,CAACiN,EAAMC,IAAWA,EAAO,IAAKC,GAAM,GAAGA,EAAE,QAAQ,CAAC,CAAC,IAAI9J,CAAI,EAAE,EACrE,KAAM,6BACN,KAAM,EACR,CACF,CACF,EAEMI,EAAY,IAAIxB,GAAM0K,EAAU,CAAC/H,EAAOyG,EAAOkB,CAAa,EAAGxI,CAAO,EAC5ErG,GAAe,KAAK+F,CAAS,EAE7B,IAAM2J,EAAkB1J,EAAc,cAAc,yBAAyB,EAC7E,OAAI0J,GAAmBxI,EAAM,OAAS,GAAK6H,IACzCW,EAAgB,WAAaA,EAAgB,YAAcA,EAAgB,aAEtE,CACL,YAAc7K,GAAkB,CAC9B,IAAMgD,EAAUmG,EAAWA,EAAW,OAAS,CAAC,GAAG,WAAa,WAC5DlG,EAAU,EAEVjD,IAAU,KAAMiD,EAAUD,EAAU,GAAK,GAAK,KAAO,IAChDhD,IAAU,KAAMiD,EAAUD,EAAU,GAAK,GAAK,KAAO,IACrDhD,IAAU,KAAMiD,EAAUD,EAAU,IAAM,GAAK,KAAO,IACtDhD,IAAU,KAAMiD,EAAUD,EAAU,IAAM,GAAK,KAAO,IACtDhD,IAAU,OAAMiD,EAAUD,EAAU,EAAI,IAAM,GAAK,KAAO,KAEnE,IAAM8H,GAAe3B,EAAW,OAAQ1L,IAAMA,GAAE,WAAawF,CAAO,EAE9D8H,EAAWD,GAAa,IAAKrN,IAAMA,GAAE,UAAY,GAAI,EACrDuN,EAAWtB,EACZoB,GAAuB,IAAKrN,IAAMA,GAAE,SAAW,GAAI,EACnDqN,GAAuB,IAAKrN,IAAMA,GAAE,SAAS,EAC5CwN,EAAmBzH,GAAewH,EAAU,CAAC,EAE7CE,EAAW,KAAK,IAAI1J,EAAQ,YAAauJ,EAAS,OAAS,EAAE,EAC7DI,EAAY,KAAK,IAAI,GAAGH,CAAQ,EAAI,IAE1C9J,EAAU,QAAQ,CAAE,MAAOgK,EAAU,OAAQ,GAAI,CAAC,EAClDhK,EAAU,SAAS,IAAK,CAAE,IAAK,EAAG,IAAKiK,CAAU,CAAC,EAClDjK,EAAU,QAAQ,CAAC6J,EAAUC,EAAUC,CAAgB,CAAC,EAEpDJ,IACFA,EAAgB,WAAaA,EAAgB,YAAcA,EAAgB,YAC/E,CACF,CACF,CE/qDA,IAAMO,GAAyB,CAC7B,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,SACF,EAEMC,GAAmB,GAErBC,GAAoC,CAAC,EACrCC,GAAqD,CAAC,EAE1D,SAASC,GAAUC,EAAYC,EAAY,CACzC,IAAMC,EAAK,IAAI,KAAKF,CAAE,EAChBG,EAAK,IAAI,KAAKF,CAAE,EACtB,OACEC,EAAG,eAAe,IAAMC,EAAG,eAAe,GAC1CD,EAAG,YAAY,IAAMC,EAAG,YAAY,GACpCD,EAAG,WAAW,IAAMC,EAAG,WAAW,CAEtC,CAEA,IAAIC,GAAmB,GACnBC,GAA4B,KAC5BC,GAAW,EACXC,GAAY,GACZC,GAAoC,KAGpCC,GAAc,GACdC,GAAc,GACdC,GAAc,YAWdC,GAAmB,CACrB,KAAM,CAAC,KAAM,IAAI,EACjB,KAAM,CAAC,KAAM,IAAI,EACjB,IAAK,CAAC,KAAM,IAAI,EAChB,QAAS,IAAI,IACb,KAAM,CAAC,EACP,MAAO,IACT,EAEA,SAASC,GAAiBC,EAAgB,GAAO,CAC/CC,GAAS,MACP,CACE,OAAQH,GAAQ,KAAK,MAAOI,GAAMA,IAAM,IAAI,EAAI,KAAOJ,GAAQ,KAC/D,OAAQA,GAAQ,KAAK,MAAOI,GAAMA,IAAM,IAAI,EAAI,KAAOJ,GAAQ,KAC/D,MAAOA,GAAQ,IAAI,MAAOI,GAAMA,IAAM,IAAI,EAAI,KAAOJ,GAAQ,IAC7D,OAAQA,GAAQ,QAAQ,OAAS,EAAI,KAAO,MAAM,KAAKA,GAAQ,OAAO,EACtE,OAAQA,GAAQ,KAAK,SAAW,EAAI,KAAOA,GAAQ,IACrD,EACAE,CACF,CACF,CAEA,SAASG,IAAmB,CAC1B,IAAMC,EAASC,GAAU,iBAAiB,EACpCC,EAAUD,GAAU,QACpBE,EAAQ,MAAM,KAAKH,CAAM,EAAE,IAAKI,GAAQF,EAAQE,CAAG,EAAE,IAAI,EAC/DP,GAAS,MAAM,CAAE,QAASM,EAAM,OAASA,EAAQ,IAAK,CAAC,CACzD,CAEA,IAAME,GAAe,CACnB,CAAE,MAAO,eAAgB,IAAK,YAAa,KAAM,gBAAiB,EAClE,CAAE,MAAO,eAAgB,IAAK,WAAY,KAAM,SAAU,EAC1D,CAAE,MAAO,mBAAoB,IAAK,YAAa,KAAM,YAAa,EAClE,CAAE,MAAO,oBAAqB,IAAK,WAAY,KAAM,iBAAkB,EACvE,CAAE,MAAO,mBAAoB,IAAK,WAAY,KAAM,OAAQ,EAC5D,CAAE,MAAO,oBAAqB,IAAK,UAAW,KAAM,WAAY,CAClE,EAEA,SAASC,GAAaC,EAAuB,CAC3C,SAAS,iBAAiB,kBAAkB,EAAE,QAASC,GAAOA,EAAG,OAAO,CAAC,EAEzE,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,kBAElBJ,GAAa,QAASK,GAAQ,CAC5B,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,aAAalB,KAAgBiB,EAAI,IAAM,SAAW,EAAE,GACrEC,EAAK,UAAY;AAAA,+CAC0BD,EAAI,IAAI;AAAA,iCACtBA,EAAI,KAAK;AAAA,qDACWjB,KAAgBiB,EAAI,IAAM,QAAU,EAAE;AAAA,MAEvFC,EAAK,iBAAiB,QAAS,IAAM,CACnClB,GAAciB,EAAI,IAClBb,GAAS,MAAM,CAAE,KAAMa,EAAI,GAAI,CAAC,EAChCE,GAAmB,EACnBC,GAAgB,EAChBJ,EAAM,OAAO,CACf,CAAC,EACDA,EAAM,YAAYE,CAAI,CACxB,CAAC,EAED,IAAMG,EAAOP,EAAS,sBAAsB,EAC5CE,EAAM,MAAM,IAAM,GAAGK,EAAK,OAAS,CAAC,KACpCL,EAAM,MAAM,KAAO,GAAGK,EAAK,IAAI,KAC/B,SAAS,KAAK,YAAYL,CAAK,EAE/B,IAAMM,EAASC,GAAkB,CAC3B,CAACP,EAAM,SAASO,EAAE,MAAc,GAAK,CAACT,EAAS,SAASS,EAAE,MAAc,IAC1EP,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASM,CAAK,EAE/C,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAK,EAAG,CAAC,CAC/D,CAEA,SAASE,GAAeV,EAAuB,CAC7C,SAAS,iBAAiB,oBAAoB,EAAE,QAASC,GAAOA,EAAG,OAAO,CAAC,EAE3E,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAElB,IAAMP,EAAUD,GAAU,QACpBiB,EAAYjB,GAAU,oBAAoB,EAC1CD,EAASC,GAAU,iBAAiB,EAE1C,OAAO,QAAQC,CAAO,EAAE,QAAQ,CAAC,CAACE,EAAKe,CAAG,IAAM,CAC9C,GAAI,CAACD,EAAU,IAAId,CAAG,EAAG,OAEzB,IAAMO,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,aAAaX,EAAO,IAAII,CAAG,EAAI,SAAW,EAAE,GAC7DO,EAAK,UAAY;AAAA,4DACuCQ,EAAI,KAAK,KAAKA,EAAI,IAAI;AAAA,iCACjDA,EAAI,KAAK;AAAA,qDACWnB,EAAO,IAAII,CAAG,EAAI,QAAU,EAAE;AAAA,MAE/EO,EAAK,iBAAiB,QAAS,IAAM,CACnCV,GAAU,aAAaG,CAAG,EAC1B,IAAMgB,EAAcnB,GAAU,iBAAiB,EAAE,IAAIG,CAAG,EACxDO,EAAK,UAAU,OAAO,SAAUS,CAAW,EAC3CT,EAAK,cAAc,QAAQ,EAAG,YAAcS,EAAc,QAAU,GAEpE,IAAMC,EAAO,SAAS,cAAc,2CAA2CjB,CAAG,IAAI,EAClFiB,GAAMA,EAAK,UAAU,OAAO,SAAUD,CAAW,EAErDE,GAAoB,EAEpBvB,GAAiB,CACnB,CAAC,EACDU,EAAM,YAAYE,CAAI,CACxB,CAAC,EAED,IAAMG,EAAOP,EAAS,sBAAsB,EAC5CE,EAAM,MAAM,IAAM,GAAGK,EAAK,OAAS,CAAC,KACpCL,EAAM,MAAM,MAAQ,GAAG,OAAO,WAAaK,EAAK,KAAK,KACrD,SAAS,KAAK,YAAYL,CAAK,EAE/B,IAAMM,EAASC,GAAkB,CAC3B,CAACP,EAAM,SAASO,EAAE,MAAc,GAAK,CAACT,EAAS,SAASS,EAAE,MAAc,IAC1EP,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASM,CAAK,EAE/C,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAK,EAAG,CAAC,CAC/D,CAGA,SAAS,iBAAiB,eAAiB,GAAW,CACpD,IAAMQ,EAAK,EAAE,OAAO,GACdC,EAAM,EAAE,OAAO,IACfC,EAAM,EAAE,OAAO,IACrB,GAAIF,GAAM5C,GAAO4C,CAAE,IACjBG,GAAYH,CAAE,EACVC,GAAO,MAAQC,GAAO,MAAM,CAC9B,IAAME,EAAIhD,GAAO4C,CAAE,EACbK,EAAMD,EAAE,OACd,GAAIH,GAAO,GAAKA,EAAMI,EAAI,OAAQ,CAChC,IAAMC,EAAOD,EAAIJ,CAAG,EACpB,GAAIK,GAAQA,EAAK,MAAQ,KAAM,CAC7B,IAAMC,EAAKF,EAAI,KAAMG,GAAMA,EAAE,MAAQ,IAAI,GAAG,MAAQ,EAC9CC,GAAQH,EAAK,KAAOC,GAAM,IAC1BG,EAAOD,EAAOP,EAGpBxB,GAAU,iBAAiB+B,EAAMC,CAAI,EAGrC,IAAIC,EAAON,EAAI,UAAWG,IAAOA,EAAE,MAAQ,IAAMF,EAAK,KAAQJ,EAAM,GAAI,EACpES,IAAS,KAAIA,EAAON,EAAI,OAAS,GAErC,IAAMO,EAASP,EAAI,MAAMJ,EAAKU,EAAO,CAAC,EAChCE,EAAQC,GAAQ,aAAaF,CAAM,EACzClC,GAAU,kBAAkBmC,CAAK,EAEjCE,GAAeX,CAAC,EAEhBY,GAAQ,iBAAiBhB,EAAIK,EAAKJ,EAAKU,EAAM,GAAO5C,EAAgB,EACpEiD,GAAQ,cAAcJ,EAAO,IAAKJ,GAAM,CAACA,EAAE,IAAKA,EAAE,GAAG,CAAqB,CAAC,EAG3ElC,GAAS,MAAM,CAAE,IAAK,CAACmC,EAAMC,CAAI,CAAE,CAAC,CACtC,CACF,CACF,CAEJ,CAAC,EAED,SAAS,iBAAiB,QAAU,GAAM,CACxC,IAAMO,EAAO,EAAE,OAAuB,QAAQ,UAAU,EACxD,GAAI,CAACA,EAAK,OACV,IAAMC,EAAMD,EAAI,QAAQ,UAAU,EAClC,GAAI,CAACC,EAAK,OAGVA,EAAI,iBAAiB,UAAU,EAAE,QAASC,GAAMA,EAAE,UAAU,OAAO,SAAUA,IAAMF,CAAG,CAAC,EAEvF,IAAMG,EAAMH,EAAI,QAAQ,IACxB3C,GAAS,MAAM,CAAE,IAAA8C,CAAI,EAAG,EAAI,EAG5B,IAAMC,EAAQH,EAAI,QAAQ,cAAc,EAsCxC,GArCIG,GACFA,EAAM,iBAAiB,cAAc,EAAE,QAASC,GAAM,CACpDA,EAAE,UAAU,OAAO,SAAUA,EAAE,KAAO,OAAOL,EAAI,QAAQ,GAAG,EAAE,CAChE,CAAC,EAGCA,EAAI,QAAQ,MAAQ,WAAarD,IAAcR,GAAOQ,EAAU,GAClE2D,GAAcnE,GAAOQ,EAAU,EAAG4D,GAAc,CAAC,EAE/CP,EAAI,QAAQ,MAAQ,YAAcrD,IAAcR,GAAOQ,EAAU,GACnEmD,GAAe3D,GAAOQ,EAAU,CAAC,EAE/BqD,EAAI,QAAQ,MAAQ,aACtBQ,GACE7D,GAAaR,GAAOQ,EAAU,EAAI,KAClC,OAAO,OAAOR,EAAM,EACpB,CAACsE,EAASC,IAAU,CAClBxB,GAAYuB,EAAS,EAAI,EACrBC,IACFjD,GAAU,iBAAiBiD,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC7CC,GAAmBD,EAAM,CAAC,EAAGA,EAAM,CAAC,EAAG,OAAQ,EAAI,EAEvD,EACA,CAACE,EAAOC,IAAQ,CACd3D,GAAQ,KAAO,CAAC0D,EAAOC,CAAG,EAC1BC,GAAa,EACb3D,GAAiB,EAAI,EACrB4D,GAAe,CACjB,CACF,EAGEf,EAAI,QAAQ,MAAQ,YAAcrD,IAAcR,GAAOQ,EAAU,GACnEqE,GAAe7E,GAAOQ,EAAU,CAAC,EAE/BqD,EAAI,QAAQ,MAAQ,WAAWiB,GAAc,EAE7CjB,EAAI,QAAQ,MAAQ,SAAU,CAChCvC,GAAU,OAAO,EACjBqB,GAAoB,EAGpB,IAAMoC,EAAI7D,GAAS,IAAI,EAAE,IACrB6D,GAAGzD,GAAU,iBAAiByD,EAAE,CAAC,EAAGA,EAAE,CAAC,CAAC,CAC9C,CACF,CAAC,EAED,eAAeC,IAAsB,CAC/B,OAAQ,OAAe,sBAAyB,YACjD,OAAe,qBAAqB,EAEvC,MAAMC,GAAQ,MAAM,EACpBjF,GAAS,CAAC,EACVC,GAAiB,CAAC,EAClBO,GAAa,KACbC,GAAW,EACXE,GAAmB,KACnBJ,GAAmB,GACnBG,GAAY,GACZE,GAAc,GACdC,GAAc,GACdC,GAAc,YACdC,GAAQ,KAAO,CAAC,KAAM,IAAI,EAC1BA,GAAQ,KAAO,CAAC,KAAM,IAAI,EAC1BA,GAAQ,IAAM,CAAC,KAAM,IAAI,EACzBA,GAAQ,QAAQ,MAAM,EACtBA,GAAQ,KAAO,CAAC,EAChB2C,GAAQ,WAAW,CAAC,IAAK,IAAK,IAAK,GAAG,CAAC,EACvCA,GAAQ,OAAO,GAAG,EAClBwB,GAAa,EACbC,GAAc,EACdC,GAAa,EACbC,GAAc,EACdC,GAAe,EACX1B,GAAQ,iBAAiBA,GAAQ,gBAAgB,EACjDA,GAAQ,aAAaA,GAAQ,YAAY,EAC7CA,GAAQ,eAAe,EACnBtC,GAAU,WAAYA,GAAU,WAAW,EACtCA,GAAU,OAAOA,GAAU,MAAM,EAC1C,SAAS,iBAAiB,UAAU,EAAE,QAASyC,GAAM,CACnDA,EAAE,UAAU,OAAO,SAAWA,EAAkB,QAAQ,MAAQ,QAAQ,CAC1E,CAAC,EACD,SAAS,iBAAiB,cAAc,EAAE,QAASG,GAAM,CACvDA,EAAE,UAAU,OAAO,SAAUA,EAAE,KAAO,YAAY,CACpD,CAAC,EACDhD,GAAS,MAAM,EACf,IAAMqE,EAAiB,SAAS,eAAe,iBAAiB,EAC5DA,IAAgBA,EAAe,UAAY,IAC/C,SAAS,iBAAiB,iBAAiB,EAAE,QAAS1D,GAAOA,EAAG,OAAO,CAAC,EACpE,OAAOK,IAAoB,YAAYA,GAAgB,CAC7D,CAGA,eAAesD,IAAO,CAEpB,IAAIC,EAA6B,KAC3BC,EAAc,IAAI,QAAeC,GAAY,CACjDF,EAAc,OAAO,WAAWE,EAAS,GAAI,CAC/C,CAAC,EACD,GAAI,CACF,IAAMC,EAAkB,SAAS,MAC7B,QAAQ,IAAI,CACV,SAAS,MAAM,KAAK,iCAAiC,EAAE,MAAM,IAAM,CAAC,CAAC,EACrE,SAAS,MAAM,KACjB,CAAC,EACD,QAAQ,QAAQ,EACpB,MAAM,QAAQ,KAAK,CAACA,EAAiBF,CAAW,CAAC,CACnD,QAAE,CACID,IAAgB,MAAM,OAAO,aAAaA,CAAW,CAC3D,CACA,SAAS,KAAK,UAAU,OAAO,eAAe,EAC9C,IAAMI,EAAgB,SAAS,eAC7B,wBACF,EACIA,IACFA,EAAc,MAAQ3E,GAAS,IAAI,EAAE,SAAW,SAChD2E,EAAc,iBAAiB,SAAWxD,GAAM,CAC9C,IAAMyD,EAAYzD,EAAE,OAA6B,MAC3C0D,EAAS,IAAI,gBAAgB,OAAO,SAAS,MAAM,EACrDD,IAAa,SACfC,EAAO,OAAO,SAAS,EAEvBA,EAAO,IAAI,UAAWD,CAAQ,EAEhC,OAAO,SAAS,OAASC,EAAO,SAAS,CAC3C,CAAC,GAGH,IAAMC,EAAS,SAAS,eAAe,eAAe,EAChDC,EAAa,SAAS,eAAe,aAAa,EAClDC,EAAgB,SAAS,eAAe,gBAAgB,EACxDC,EAAc,SAAS,eAAe,qBAAqB,EAC3DC,EAAY,SAAS,eAAe,YAAY,EAChDC,EAAgBD,GAAW,cAAc,MAAM,EAEjDA,IACEC,IAAeA,EAAc,YAAc,uBAC/CD,EAAU,UAAU,OAAO,QAAQ,GAGrC,IAAME,EAAWpF,GAAS,IAAI,EAE9BqF,GAAa,CAACC,EAAaC,IAAkBC,GAAUF,EAAKC,IAAS,QAAU,QAAU,MAAM,CAAC,EAChGE,GACE,IAAM,CACJhC,GAAa,EACb3D,GAAiB,CACnB,EACC4B,GAAe,CACdgE,GAAYhE,CAAE,CAChB,CACF,EAEAiE,GAAY,CAACL,EAAaC,IAAkBC,GAAUF,EAAKC,IAAS,QAAU,QAAU,MAAM,CAAC,EAG/F7C,GAAQ,KACLhB,GAAOG,GAAYH,CAAE,EACtBkE,GACAC,GACA,CAACnE,EAAIC,IAAQ,CACPD,IAAOpC,GAAYc,GAAU,WAAWuB,CAAG,EAC1CvB,GAAU,WAAW,IAAI,CAChC,EACA0F,EACF,EACA1F,GAAU,KAAK2F,GAAmBzC,GAAoB0C,GAAerE,GAAQ,CAC3E3B,GAAS,MAAM,CAAE,UAAW2B,CAAI,CAAC,CACnC,CAAC,EAEDvB,GAAU,oBAAqB6F,GAAS,CAClCA,GACFxG,GAAmBwG,EAAK,OACpB3G,IAAYoD,GAAQ,mBAAmBpD,GAAY2G,EAAK,IAAKA,EAAK,MAAM,IAE5ExG,GAAmB,KACfH,IAAYoD,GAAQ,iBAAiBpD,EAAU,GAIrD,IAAM4G,EAAkBlG,GAAS,IAAI,EACjCkG,EAAgB,KAClB5C,GAAmB4C,EAAgB,IAAI,CAAC,EAAGA,EAAgB,IAAI,CAAC,EAAG9F,GAAU,SAAS,CAAC,CAC3F,CAAC,EAED+F,GAAWf,CAAQ,EAGnB,MAAMrB,GAAQ,OAAO,EACrB,MAAMD,GAAoB,EAG1B,GAAI,CAEF,IAAMsC,EAAU,MAAMrC,GAAQ,IAAI,UAAU,EACxCqC,GAAS5D,GAAQ,WAAW4D,CAAO,EAEvC,IAAMC,EAAM,MAAMtC,GAAQ,IAAI,KAAK,EAC/BsC,GAAK7D,GAAQ,OAAO6D,CAAG,EAE3B,IAAMC,EAAQ,MAAMvC,GAAQ,OAAO,EACnCuC,EAAM,KAAK,CAACC,EAAG1D,IAAM0D,EAAE,QAAU1D,EAAE,OAAO,EAEtCsC,IAAeA,EAAc,YAAc,aAAamB,EAAM,MAAM,cAExE,IAAME,EAA4B,CAAC,EACnC,QAAW1E,KAAKwE,EAAO,CACrB,IAAIG,EAAU,GACd,GAAI,CAAC3E,EAAE,QAAUA,EAAE,OAAO,OAAS,EAAG,CACpC,IAAMe,EAAI6D,GAAgB5E,EAAE,MAAM,EAC9Be,IACFf,EAAE,OAASe,EACX4D,EAAU,GAEd,CACI,CAAC3E,EAAE,kBAAoBA,EAAE,OAAO,OAAS,IAC3CA,EAAE,iBAAmB6E,GAAc7E,EAAE,OAAQ,EAAE,EAC/C2E,EAAU,IAERA,GAAS,MAAM1C,GAAQ,KAAKjC,CAAC,EAEjChD,GAAOgD,EAAE,EAAE,EAAIA,EACf0E,EAAa,KAAK1E,CAAC,CACrB,CACAY,GAAQ,UAAU8D,CAAY,EAC9B/C,GAAa,EAEb,IAAMmD,EACJxB,EAAS,OAASkB,EAAM,KAAMxE,GAAMA,EAAE,KAAOsD,EAAS,KAAK,EACvDA,EAAS,MACTkB,EAAM,OAAS,EACbA,EAAM,CAAC,EAAE,GACT,KAEFpB,EAAY,SAAS,eAAe,YAAY,EAGhD2B,EAAoBP,EAAM,KAAMxE,GAAMA,EAAE,KAAO8E,CAAS,EA0B9D,GAzBIC,IACF,MAAMC,GAAoBD,CAAiB,EAC3ChF,GAAYgF,EAAkB,GAAI,CAACzB,EAAS,OAAO,EAG/CA,EAAS,KAAO,MAAM,QAAQA,EAAS,GAAG,GAAKA,EAAS,IAAI,SAAW,GACzE,sBAAsB,IAAM,CAC1B,sBAAsB,IAAM,CAC1BhF,GAAU,iBAAiBgF,EAAS,IAAK,CAAC,EAAGA,EAAS,IAAK,CAAC,CAAC,CAC/D,CAAC,CACH,CAAC,EAECA,EAAS,YAAc,QAAaA,EAAS,YAAc,MAC7D,sBAAsB,IAAM,CAC1B,sBAAsB,IAAM,CAC1BhF,GAAU,YAAYgF,EAAS,SAAU,CAC3C,CAAC,CACH,CAAC,GAKDF,GAAWA,EAAU,UAAU,IAAI,QAAQ,EAG3CoB,EAAM,QAAUO,EAAoB,EAAI,GAAI,CAC1C3B,IACEC,IAAeA,EAAc,YAAc,qBAC/CD,EAAU,UAAU,OAAO,QAAQ,GAGrC,IAAM6B,EAAYT,EAAM,OAAQxE,GAAMA,EAAE,KAAO8E,CAAS,EACpDI,EAAQ,EAENC,EAAgB,SAAY,CAEhC,IAAMzD,EAAM,KAAK,IAAIwD,EAAQ,EAAWD,EAAU,MAAM,EAExD,KAAOC,EAAQxD,EAAKwD,IAAS,MAAMF,GAAoBC,EAAUC,CAAK,CAAC,EAEnEA,EAAQD,EAAU,OACpB,sBAAsBE,CAAa,GAE/B/B,GAAWA,EAAU,UAAU,IAAI,QAAQ,EAC/CzB,GAAa,EACTnE,IAAcR,GAAOQ,EAAU,GACjC6D,GAAgBrE,GAAOQ,EAAU,EAAG,OAAO,OAAOR,EAAM,EAAG,CAACsE,GAASC,IAAU,CAC7ExB,GAAYuB,GAAS,EAAI,EACrBC,IACFjD,GAAU,iBAAiBiD,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC7CC,GAAmBD,EAAM,CAAC,EAAGA,EAAM,CAAC,EAAG,OAAQ,EAAI,EAEvD,CAAC,EAGCiD,EAAM,QAAU,CAAClB,EAAS,SAAS1C,GAAQ,OAAO,EAE1D,EAEA,sBAAsBuE,CAAa,CACrC,MACExD,GAAa,EACT6C,EAAM,QAAU,CAAClB,EAAS,SAAS1C,GAAQ,OAAO,CAE1D,OAASvB,EAAG,CACV,QAAQ,KAAK,+BAAgCA,CAAC,CAChD,CAGA+F,GAAiB,EACjBC,GAAmB,EACnBC,GAAwB,EACxB3F,GAAoB,EAGpB,SAAS,eAAe,kBAAkB,GAAG,iBAAiB,QAAUN,GAAM,CAC5E,IAAMwB,EAAOxB,EAAE,OAAuB,QAAQ,SAAS,EAClDwB,IACL,SAAS,iBAAiB,SAAS,EAAE,QAASE,GAAMA,EAAE,UAAU,OAAO,QAAQ,CAAC,EAChFF,EAAI,UAAU,IAAI,QAAQ,EACtBA,EAAI,QAAQ,QACdD,GAAQ,cAAcC,EAAI,QAAQ,KAAK,EACvC3C,GAAS,MAAM,CAAE,IAAK2C,EAAI,QAAQ,KAAM,CAAC,GAE7C,CAAC,EAGD,SAAS,eAAe,aAAa,GAAG,iBAAiB,QAAS,IAAMD,GAAQ,OAAO,CAAC,EAGxF,SAAS,eAAe,eAAe,GAAG,iBAAiB,QAAS2E,EAAQ,EAG5E,SAAS,eAAe,cAAc,GAAG,iBAAiB,QAAUlG,GAAM,CACxEzB,GAAeyB,EAAE,OAA4B,MAC7CsC,GAAa,EACbzD,GAAS,MAAM,CAAE,EAAGN,IAAe,IAAK,CAAC,CAC3C,CAAC,EAED,SAAS,eAAe,kBAAkB,GAAG,iBAAiB,QAAUyB,GAAM,CAC5ExB,GAAc,CAACA,GACdwB,EAAE,OAAuB,UAAU,OAAO,SAAUxB,EAAW,EAChE8D,GAAa,EACbzD,GAAS,MAAM,CAAE,GAAIL,GAAc,EAAI,IAAK,CAAC,CAC/C,CAAC,EAGD,SAAS,eAAe,eAAe,GAAG,iBAAiB,QAAUwB,GAAM,CACzEA,EAAE,gBAAgB,EAClBV,GAAaU,EAAE,aAA4B,CAC7C,CAAC,EAGD,SAAS,eAAe,iBAAiB,GAAG,iBAAiB,QAAUA,GAAM,CAC3EA,EAAE,gBAAgB,EAClBC,GAAeD,EAAE,aAA4B,CAC/C,CAAC,EAGD,IAAMmG,EAAe,CAACC,EAAgB/F,IAA6B,CAC7DA,GAAMA,EAAK,UAAU,OAAO,QAAQ,EACxCpB,GAAU,aAAamH,CAAM,EAC7BrH,GAAiB,CACnB,EAEA,SAAS,eAAe,cAAc,GAAG,iBAAiB,QAAUiB,GAAM,CACxE,IAAMK,EAAQL,EAAE,OAAuB,QAAQ,cAAc,EAC7D,GAAIK,EAAM,CACR,IAAM+F,EAAS/F,EAAK,QAAQ,OACxB+F,IACFD,EAAaC,EAAQ/F,CAAI,EAGrBpB,GAAU,iBAAiB,EAAE,IAAImH,CAAM,GACxB,SAAS,cAAc,2BAA2BA,CAAM,IAAI,GACnE,eAAe,CAAE,SAAU,QAAS,CAAC,EAGrD,CACF,CAAC,EAGD,SAAS,eAAe,aAAa,GAAG,iBAAiB,QAAUpG,GAAM,CACvE,IAAMwB,EAAOxB,EAAE,OAAuB,QAAQ,UAAU,EACxD,GAAI,CAACwB,EAAK,OACV,IAAM6E,EAAO7E,EAAI,QAAQ,KACzBvC,GAAU,SAASoH,CAAI,EACvB,SACG,iBAAiB,uBAAuB,EACxC,QAAS3E,GAAMA,EAAE,UAAU,OAAO,SAAUA,IAAMF,CAAG,CAAC,EACzD3C,GAAS,MAAM,CAAE,MAAOwH,CAAK,CAAC,CAChC,CAAC,EAGD,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAUrG,GAAM,CAC1E3B,GAAY,CAACA,GACZ2B,EAAE,cAA8B,UAAU,OAAO,SAAU3B,EAAS,CACvE,CAAC,EAGD,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAS,IAAM,CACzEY,GAAU,UAAU,EACpBsC,GAAQ,eAAe,CACzB,CAAC,EAGD+E,GAAa,EAGb,SAAS,eAAe,YAAY,GAAG,iBAAiB,SAAWtG,GAAM,CACvEuG,GAAY,MAAM,KAAMvG,EAAE,OAA4B,OAAS,CAAC,CAAC,CAAC,EACjEA,EAAE,OAA4B,MAAQ,EACzC,CAAC,EACD,SAAS,eAAe,cAAc,GAAG,iBAAiB,SAAWA,GAAM,CACzEuG,GAAY,MAAM,KAAMvG,EAAE,OAA4B,OAAS,CAAC,CAAC,CAAC,EACjEA,EAAE,OAA4B,MAAQ,EACzC,CAAC,EAGD,SAAS,eAAe,oBAAoB,GAAG,iBAAiB,QAAS,IAAM,CAC7E,IAAM4B,EAAQ,SAAS,eAAe,cAAc,EAChDA,IACFA,EAAM,UAAU,OAAO,QAAQ,EAC/B,SACG,eAAe,oBAAoB,GAClC,UAAU,OAAO,SAAU,CAACA,EAAM,UAAU,SAAS,QAAQ,CAAC,EAEtE,CAAC,EAED,IAAM4E,EAAgB,CAACpC,EAA+B5D,EAAaR,IAAa,CAC9E,IAAMyG,EAAOzG,EAAE,OAA4B,MAC1CtB,GAAQ0F,CAAI,EAAU5D,CAAG,EAAIiG,IAAQ,GAAK,KAAOA,EAClDnE,GAAa,EACb3D,GAAiB,CACnB,EAEA,SACG,eAAe,mBAAmB,GACjC,iBAAiB,SAAWqB,GAAMwG,EAAc,OAAQ,EAAGxG,CAAC,CAAC,EACjE,SACG,eAAe,iBAAiB,GAC/B,iBAAiB,SAAWA,GAAMwG,EAAc,OAAQ,EAAGxG,CAAC,CAAC,EACjE,SACG,eAAe,iBAAiB,GAC/B,iBAAiB,QAAUA,GAAMwG,EAAc,OAAQ,EAAGxG,CAAC,CAAC,EAChE,SACG,eAAe,iBAAiB,GAC/B,iBAAiB,QAAUA,GAAMwG,EAAc,OAAQ,EAAGxG,CAAC,CAAC,EAChE,SACG,eAAe,gBAAgB,GAC9B,iBAAiB,QAAUA,GAAMwG,EAAc,MAAO,EAAGxG,CAAC,CAAC,EAC/D,SACG,eAAe,gBAAgB,GAC9B,iBAAiB,QAAUA,GAAMwG,EAAc,MAAO,EAAGxG,CAAC,CAAC,EAE/D,IAAM0G,EAAY,SAAS,eAAe,kBAAkB,EACtDC,EAAkB,SAAS,eAAe,wBAAwB,EACxED,GAAW,iBAAiB,QAAU1G,GAAM,CAE1C,GADAA,EAAE,gBAAgB,EACd2G,EAAiB,CACnB,IAAMC,EAAYD,EAAgB,MAAM,UAAY,QACpDA,EAAgB,MAAM,QAAUC,EAAY,OAAS,OACvD,CACF,CAAC,EAED,SAAS,iBAAiB,QAAU5G,GAAM,CACpC2G,GAAmBA,EAAgB,MAAM,UAAY,SACnD,CAACA,EAAgB,SAAS3G,EAAE,MAAc,GAAKA,EAAE,SAAW0G,IAC9DC,EAAgB,MAAM,QAAU,OAEtC,CAAC,EAED,SAAS,eAAe,wBAAwB,GAAG,iBAAiB,QAAU3G,GAAM,CAClF,IAAM6G,EAAS7G,EAAE,OACXwB,EAAMqF,EAAO,QAAQ,cAAc,EACzC,GAAIrF,EAAK,CACP,IAAMsF,EAAiBtF,EAAoB,QAAQ,OAAS,KAC5D9C,GAAQ,MAAQA,GAAQ,QAAUoI,EAAgB,KAAOA,EACzDxE,GAAa,EACb3D,GAAiB,EACjB4D,GAAe,EAEXsE,EAAO,QAAQ,gBAAgB,GAC7BF,IAAiBA,EAAgB,MAAM,QAAU,OAEzD,CACF,CAAC,EAED,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAU3G,GAAM,CAC1E,IAAMwB,EAAOxB,EAAE,OAAuB,QAAQ,YAAY,EAC1D,GAAI,CAACwB,EAAK,OACV,IAAMuF,EAAIvF,EAAI,QAAQ,OAClB9C,GAAQ,QAAQ,IAAIqI,CAAC,EAAGrI,GAAQ,QAAQ,OAAOqI,CAAC,EAC/CrI,GAAQ,QAAQ,IAAIqI,CAAC,EAC1BxE,GAAe,EACfD,GAAa,EACb3D,GAAiB,CACnB,CAAC,EAED,SAAS,eAAe,mBAAmB,GAAG,iBAAiB,QAAS,IAAM,CAC5ED,GAAU,CACR,KAAM,CAAC,KAAM,IAAI,EACjB,KAAM,CAAC,KAAM,IAAI,EACjB,IAAK,CAAC,KAAM,IAAI,EAChB,QAAS,IAAI,IACb,KAAM,CAAC,EACP,MAAO,IACT,EACA6D,GAAe,EACfD,GAAa,EACb3D,GAAiB,CACnB,CAAC,EAED,SAAS,eAAe,aAAa,GAAG,iBAAiB,QAAUqB,GAAM,CACvE,IAAMyG,EAAOzG,EAAE,OAA4B,MAC3CtB,GAAQ,KAAO+H,EACZ,MAAM,GAAG,EACT,IAAK/D,GAAMA,EAAE,KAAK,EAAE,YAAY,CAAC,EACjC,OAAQA,GAAM,CAAC,CAACA,CAAC,EACpBJ,GAAa,EACb3D,GAAiB,CACnB,CAAC,EAGD,SAAS,iBAAiB,UAAYqB,GAAM,CACtCA,EAAE,MAAQ,WACZuB,GAAQ,WAAW,EACnBA,GAAQ,aAAa,EAErB,SACG,iBACC,4EACF,EACC,QAAS/B,GAAOA,EAAG,OAAO,CAAC,EAElC,CAAC,EAGD,OAAO,iBAAiB,SAAU,IAAM,CACtCP,GAAU,OAAO,EACjB+H,GAAe,EACfzF,GAAQ,iBAAiB,EACzBjB,GAAoB,CACtB,CAAC,EAGD,OAAO,iBAAiB,WAAY,IAAM,CACxCzB,GAAS,QAAQ,EACjBmG,GAAWnG,GAAS,IAAI,CAAC,CAC3B,CAAC,EAEDoI,GAAsB,EACtB,MAAMC,GAAsB,EAI5B,IAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,GAAK,eACbA,EAAQ,aAAa,aAAc,MAAM,EACzCA,EAAQ,MAAM,QAAU,OACxB,SAAS,KAAK,YAAYA,CAAO,EAEjC,IAAMC,EAAe,SAAS,cAAc,KAAK,EACjDA,EAAa,GAAK,aAClBA,EAAa,aAAa,aAAc,MAAM,EAC9CA,EAAa,MAAM,QAAU,OAC7B,SAAS,KAAK,YAAYA,CAAY,CACxC,CAEA,IAAIC,GAOO,KAEX,eAAeH,IAEb,CACA,GAAIG,GAA4B,OAAOA,GACvC,GAAI,CAEF,IAAMC,EAAsB,MADP,MAAM,MAAM,2BAA2B,GACb,KAAK,EAC9CC,EAAU,IAAI,YACpBF,GAA6B,MAAM,QAAQ,IACzCC,EAAU,IAAI,MAAOE,GAAS,CAE5B,IAAIC,EAAM,MADO,MAAM,MAAM,eAAeD,CAAI,EAAE,GACzB,YAAY,EACjCE,EAAYF,EAChB,GAAIA,EAAK,YAAY,EAAE,SAAS,KAAK,EAAG,CACtCE,EAAYF,EAAK,MAAM,EAAG,EAAE,EAC5B,IAAMG,EAAQ,IAAI,WAAWF,CAAG,EAChC,GAAIE,EAAM,QAAU,GAAKA,EAAM,CAAC,IAAM,IAAQA,EAAM,CAAC,IAAM,IAAM,CAC/D,IAAMC,EAAK,IAAI,oBAAoB,MAAM,EACnCC,EAAS,IAAI,KAAK,CAACJ,CAAG,CAAC,EAAE,OAAO,EAAE,YAAYG,CAAE,EACtDH,EAAM,MAAM,IAAI,SAASI,CAAM,EAAE,YAAY,CAC/C,CACF,CACA,IAAMC,EAAOJ,EAAU,YAAY,EAAE,SAAS,MAAM,EAAI,OAAYH,EAAQ,OAAOE,CAAG,EAChFM,EAAO,IAAI,KAAK,CAACN,CAAG,EAAGC,EAAW,CAAE,KAAM,0BAA2B,CAAC,EAC5E,OAACK,EAAa,KAAON,EACjBK,IAAS,SAAYC,EAAa,MAAQD,GACvC,CAAE,UAAAJ,EAAW,IAAAD,EAAK,KAAAK,EAAM,KAAAC,CAAK,CACtC,CAAC,CACH,EAEA,IAAIC,EAAkB,KACtB,QAAWxH,IAAO,CAAC,EAAG,EAAG,CAAC,EACxB,GAAI6G,GAA2B7G,CAAG,EAAG,CACnC,IAAMyH,EAAS,MAAM5G,GAAQ,UAAUgG,GAA2B7G,CAAG,EAAE,IAAI,EACvEA,IAAQ,IAAGwH,EAAaC,EAC9B,CAEF,GAAID,EAAY,CACd,IAAME,EAAUF,EAAW,OAAO,MAAM,EAAG,IAAI,EACzCG,EAAuB,CAC3B,GAAGH,EACH,GAAI,SACJ,SAAU,aACV,SAAU,KACV,OAAQE,EACR,OAAQ3C,GAAgB2C,CAAO,GAAK,OACpC,iBAAkB1C,GAAc0C,EAAS,EAAE,EAC3C,MAAO7G,GAAQ,aAAa6G,CAAO,EACnC,QAAS,WACT,QAAS,GACT,MAAOzK,GAAa,CAAC,CACvB,EACM2K,EAAwB,CAC5B,GAAGD,EACH,GAAI,WACJ,SAAU,cACV,QAAS,WACT,MAAO1K,GAAa,CAAC,CACvB,EACM4K,EAAW,CAACF,EAAWC,CAAU,EACvC/G,GAAQ,qBAAqB8G,CAAS,EACtC9G,GAAQ,qBAAqB+G,CAAU,EACvC7G,GAAQ,UAAU8G,CAAQ,EAC1BpJ,GAAU,UAAUkJ,EAAWE,EAAU,EAAK,EAC9CpJ,GAAU,iBAAiB,GAAI,GAAI,EAAI,EACvCA,GAAU,YAAY,GAAI,EAAI,EAC9BA,GAAU,iBAAiB,CAAC,YAAa,QAAS,OAAO,CAAC,EAC1DA,GAAU,0BAA0BoJ,EAAU,GAAI,EAAE,EACpD/G,GAAe6G,EAAWE,CAAQ,EAClCvG,GAAcqG,EAAW,CAAC,EAAGE,CAAQ,EACrC7F,GAAe6F,EAAUA,CAAQ,EACjCrG,GAAgBmG,EAAWE,CAAQ,EACnCC,GAAwBD,CAAQ,EAChCE,GAAa,WAAY,EAAI,EAC7B,MAAM5F,GAAoB,EACrB,SAAS,KAAK,aACnB,MAAM,IAAI,QAAS6F,GAAM,OAAO,WAAWA,EAAG,CAAC,CAAC,CAClD,MAAW,OAAQ,OAAe,sBAAyB,YACxD,OAAe,qBAAqB,EAEvC,OAAOnB,EACT,MAAQ,CACN,MAAO,CAAC,CACV,CACF,CAEA,SAASJ,IAAwB,CAC/B,IAAMwB,EAAU,SAAS,eAAe,eAAe,EACjDC,EAAc,SAAS,eAAe,mBAAmB,EACzDC,EAAc,SAAS,eAAe,mBAAmB,EACzDC,EAAa,SAAS,eAAe,kBAAkB,EACvDC,EAAe,SAAS,eAAe,oBAAoB,EAC3DC,EAAe,SAAS,eAAe,oBAAoB,EAC3DC,EAAa,SAAS,eAAe,kBAAkB,EAE7D,SAASC,EAAYC,EAAiB,CACpC,SAAS,iBAAiB,UAAU,EAAE,QAASvH,GAAM,CACnDA,EAAE,UAAU,OAAO,SAAWA,EAAkB,QAAQ,MAAQuH,CAAO,CACzE,CAAC,EACD,SAAS,iBAAiB,cAAc,EAAE,QAASpH,GAAM,CACvDA,EAAE,UAAU,OAAO,SAAUA,EAAE,KAAO,OAAOoH,CAAO,EAAE,CACxD,CAAC,EACDpK,GAAS,MAAM,CAAE,IAAKoK,CAAQ,EAAG,EAAK,CACxC,CAEAR,GAAS,iBAAiB,QAAS,SAAY,CAC7C,GAAI,CACE,OAAO,KAAK9K,EAAM,EAAE,OAAS,GAAKC,GAAe,OAAS,GAAKO,KAAe,MAChF,MAAMyE,GAAQ,OAAO,EACrB,MAAMD,GAAoB,GACjB,OAAQ,OAAe,sBAAyB,YACxD,OAAe,qBAAqB,EAGvC,IAAMuG,GADW,MAAMhC,GAAsB,GACR,IAAKnG,GAAMA,EAAE,IAAI,EACtD,MAAMwF,GAAY2C,CAAW,EAC7B,IAAMC,EAAY,OAAO,OAAOxL,EAAM,EAClC,CAACQ,IAAcgL,EAAU,OAAS,GAAGzI,GAAYyI,EAAU,CAAC,EAAE,EAAE,CACtE,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,yBAAyB,CAAC,CACjE,CACF,CAAC,EAEDT,GAAa,iBAAiB,QAAS,IAAM,CAC3C,GAAI,CACF,IAAMS,EAAY,OAAO,OAAOxL,EAAM,EACtCqL,EAAY,QAAQ,EAChB,CAAC7K,IAAcgL,EAAU,OAAS,GACpCzI,GAAYyI,EAAU,CAAC,EAAE,EAAE,EAE7BlK,GAAU,iBAAiB,IAAK,IAAK,EAAI,EACzCA,GAAU,YAAY,IAAK,EAAI,EAC/B,IAAMmK,EAAmBnK,GAAU,oBAAoB,EACjDoK,EAAkB,CAAC,YAAa,QAAS,OAAO,EAAE,OAAQtC,GAC9DqC,EAAiB,IAAIrC,CAAC,CACxB,EACIsC,EAAgB,OAAS,GAC3B,SAAS,iBAAiB,4BAA4B,EAAE,QAAS7J,GAAO,CACtE,IAAM4G,EAAU5G,EAAmB,QAAQ,OACvC4G,GAAQ5G,EAAG,UAAU,OAAO,SAAU6J,EAAgB,SAASjD,CAAM,CAAC,CAC5E,CAAC,EACD9F,GAAoB,EACpBrB,GAAU,iBAAiBoK,CAAe,GAE1C/I,GAAoB,EAEtBrB,GAAU,0BAA0BkK,EAAW,IAAK,GAAG,EACvDhH,GAAmB,IAAK,IAAKlD,GAAU,SAAS,EAAG,EAAK,CAC1D,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,mBAAmB,CAAC,CAC3D,CACF,CAAC,EAED0J,GAAa,iBAAiB,QAAS,IAAM,CAC3C,GAAI,CACF,IAAMQ,EAAY,OAAO,OAAOxL,EAAM,EACtCwL,EAAU,QAASxI,GAAMU,GAAQ,qBAAqBV,CAAC,CAAC,EACxDqI,EAAY,UAAU,EACtB,IAAMM,EAAgBnL,IAAcR,GAAOQ,EAAU,GAAMgL,EAAU,CAAC,GAAK,KAC3E7H,GAAegI,EAAcH,CAAS,CACxC,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,mBAAmB,CAAC,CAC3D,CACF,CAAC,EAEDP,GAAY,iBAAiB,QAAS,IAAM,CAC1C,GAAI,CACF,IAAMO,EAAY,OAAO,OAAOxL,EAAM,EACtCqL,EAAY,SAAS,EACrB,IAAMM,EAAgBnL,IAAcR,GAAOQ,EAAU,GAAMgL,EAAU,CAAC,GAAK,KAC3ErH,GAAcwH,EAAcvH,GAAc,EAAGoH,CAAS,CACxD,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,kBAAkB,CAAC,CAC1D,CACF,CAAC,EAEDN,GAAc,iBAAiB,QAAS,IAAM,CAC5C,GAAI,CACF,IAAMM,EAAY,OAAO,OAAOxL,EAAM,EACtC,GAAIwL,EAAU,QAAU,EAAG,CACzB,IAAMI,EAAc,CAACJ,EAAU,CAAC,EAAGA,EAAU,CAAC,CAAC,EAC/CH,EAAY,UAAU,EACtBxG,GAAe+G,EAAaJ,CAAS,CACvC,CACF,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,oBAAoB,CAAC,CAC5D,CACF,CAAC,EAEDL,GAAc,iBAAiB,QAAS,IAAM,CAC5C,GAAI,CACF,IAAMK,EAAY,OAAO,OAAOxL,EAAM,EACtCqL,EAAY,WAAW,EACvB,IAAMM,EAAgBnL,IAAcR,GAAOQ,EAAU,GAAMgL,EAAU,CAAC,GAAK,KAC3EnH,GAAgBsH,EAAcH,EAAW,CAAClH,EAASC,IAAU,CAC3DxB,GAAYuB,EAAS,EAAI,EACrBC,IACFjD,GAAU,iBAAiBiD,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC7CC,GAAmBD,EAAM,CAAC,EAAGA,EAAM,CAAC,EAAG,OAAQ,EAAI,EAEvD,CAAC,CACH,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,oBAAoB,CAAC,CAC5D,CACF,CAAC,EAED6G,GAAY,iBAAiB,QAAS,IAAM,CAC1C,GAAI,CACF,IAAMI,EAAY,OAAO,OAAOxL,EAAM,EACtCqL,EAAY,SAAS,EACrBV,GAAwBa,CAAS,EACjCZ,GAAa,WAAY,EAAI,CAC/B,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,kBAAkB,CAAC,CAC1D,CACF,CAAC,EAEA,OAAe,eAAiB,CAC/B,kBAAmB,IAAM,SAAS,eAAe,eAAe,GAAG,MAAM,EACzE,uBAAwB,IAAM,SAAS,eAAe,mBAAmB,GAAG,MAAM,EAClF,gBAAiB,IAAM,SAAS,eAAe,mBAAmB,GAAG,MAAM,EAC3E,eAAgB,IAAM,SAAS,eAAe,kBAAkB,GAAG,MAAM,EACzE,wBAAyB,IAAM,SAAS,eAAe,oBAAoB,GAAG,MAAM,EACpF,wBAAyB,IAAM,SAAS,eAAe,oBAAoB,GAAG,MAAM,EACpF,eAAgB,IAAM,SAAS,eAAe,kBAAkB,GAAG,MAAM,CAC3E,CACF,CAEA,eAAe5C,GAAoBhF,EAAc,CAE/C,IAAM6I,EAAoB7I,EAAE,MAAM,WAAa,OAAO,OAAOA,EAAE,MAAM,UAAU,EAAI,CAAC,EAE9E8I,EACJ9I,EAAE,OAAO,OAAS,IAAMA,EAAE,OAAO,CAAC,EAAE,QAAU,QAAaA,EAAE,OAAO,CAAC,EAAE,WAAa,SAGpF8I,GACA,CAAC9I,EAAE,MAAM,YACT,CAACA,EAAE,MAAM,SACT,CAACA,EAAE,MAAM,SACTA,EAAE,MAAM,SAAW,QACnBA,EAAE,MAAM,aAAe,QACvBA,EAAE,MAAM,UAAY,QACnB6I,EAAkB,OAAS,GAAK,OAAQA,EAAkB,CAAC,GAAc,WACxE7I,EAAE,MAAM,UAAY,GAAK,MAAQ,KAAQA,EAAE,MAAM,YAAc,CAACA,EAAE,MAAM,WAAW,KAAK,KAGtF8I,IAAa9I,EAAE,OAASU,GAAQ,aAAaV,EAAE,MAAM,GACzDA,EAAE,MAAQU,GAAQ,aAAaV,EAAE,MAAM,EACvC,MAAMiC,GAAQ,KAAKjC,CAAC,GAGtBhD,GAAOgD,EAAE,EAAE,EAAIA,EACfvC,GAAW,KAAK,IAAIA,GAAUX,GAAa,QAAQkD,EAAE,KAAK,EAAI,CAAC,EAC/DY,GAAQ,SAASZ,CAAC,EAClBY,GAAQ,gBAAgBZ,EAAE,GAAIA,EAAE,SAAW,CAACA,EAAE,SAAS,EACvDd,GAAgB,CAClB,CAEA,SAASkG,IAAmB,CAC1B,IAAM2D,EAAS,SAAS,eAAe,eAAe,EAChD9H,EAAQ,SAAS,eAAe,aAAa,EACnD,GAAI,CAAC8H,GAAU,CAAC9H,EAAO,OAEvB,IAAI+H,EAAa,GAEjBD,EAAO,iBAAiB,YAAa,IAAM,CACzCC,EAAa,GACb,SAAS,KAAK,MAAM,OAAS,WAC/B,CAAC,EAED,SAAS,iBAAiB,YAAc3J,GAAM,CAC5C,GAAI,CAAC2J,EAAY,OACjB,IAAMC,EAAI,OAAO,YAAc5J,EAAE,QAC3B6J,EAAW,KAAK,IAAI,IAAK,KAAK,IAAI,OAAO,YAAc,IAAKD,CAAC,CAAC,EACpEhI,EAAM,MAAM,OAAS,GAAGiI,CAAQ,KAChC5K,GAAU,OAAO,EACjB+H,GAAe,EACfzF,GAAQ,iBAAiB,CAC3B,CAAC,EAED,SAAS,iBAAiB,UAAW,IAAM,CACpCoI,IACLA,EAAa,GACb,SAAS,KAAK,MAAM,OAAS,GAC/B,CAAC,CACH,CAEA,SAAS3D,IAAqB,CAC5B,IAAM8D,EAAU,SAAS,eAAe,iBAAiB,EACnDC,EAAU,SAAS,eAAe,SAAS,EACjD,GAAI,CAACD,GAAW,CAACC,EAAS,OAE1B,IAAIJ,EAAa,GAEjBG,EAAQ,iBAAiB,YAAa,IAAM,CAC1CH,EAAa,GACbG,EAAQ,UAAU,IAAI,UAAU,EAChC,SAAS,KAAK,UAAU,IAAI,kBAAkB,CAChD,CAAC,EAED,SAAS,iBAAiB,YAAc9J,GAAM,CAC5C,GAAI,CAAC2J,EAAY,OACjB,IAAMK,EAAIhK,EAAE,QACNiK,EAAW,KAAK,IAAI,IAAK,KAAK,IAAI,IAAKD,CAAC,CAAC,EAC/CD,EAAQ,MAAM,MAAQ,GAAGE,CAAQ,KACjCF,EAAQ,MAAM,YAAY,cAAe,GAAGE,CAAQ,IAAI,EACxDhL,GAAU,OAAO,EACjBsC,GAAQ,iBAAiB,CAC3B,CAAC,EAED,SAAS,iBAAiB,UAAW,IAAM,CACpCoI,IACLA,EAAa,GACbG,EAAQ,UAAU,OAAO,UAAU,EACnC,SAAS,KAAK,UAAU,OAAO,kBAAkB,EACnD,CAAC,CACH,CAIA,SAASrF,GAAUyF,EAAaC,EAAaC,EAAc,CACzDvL,GAAS,MAAM,CAAE,QAAS,CAACqL,EAAKC,EAAKC,CAAI,CAAE,CAAC,CAC9C,CAEA,SAAS1F,GAAgBnE,EAAYC,EAAa,CAChDE,GAAYH,EAAI,EAAK,EACrBtB,GAAU,YAAYuB,CAAG,CAC3B,CAEA,SAASmE,IAAgB,CAEzB,CAEA,SAASC,GAAkByF,EAAuB,CAC5CA,GAAMA,EAAG,KAAO,MAAQA,EAAG,KAAO,MACpC9I,GAAQ,aAAa8I,EAAG,IAAKA,EAAG,GAAG,EAC/BhM,IAAWkD,GAAQ,SAAS8I,EAAG,IAAKA,EAAG,IAAK,KAAM,EAAI,GAE1D9I,GAAQ,WAAW,CAEvB,CAEA,SAASY,GAAmBmI,EAAoBC,EAAoBlE,EAAcmE,EAAM,GAAO,CAC7F,GAAI,CAACrM,IAAc,CAACR,GAAOQ,EAAU,EAAG,OACxC,IAAMwC,EAAIhD,GAAOQ,EAAU,EAE3B,GAAImM,IAAQ,MAAQC,IAAQ,KAAM,CAChChJ,GAAQ,eAAe,EACnBZ,IAAM9B,GAAS,IAAI,EAAE,KAAO,YAAc,YAAYyC,GAAeX,CAAC,EAC1E9B,GAAS,MAAM,CAAE,IAAK,IAAK,CAAC,EAC5B,MACF,CAGA,IAAM+B,EAAMD,EAAE,OACV8J,EAAO,EACTvJ,EAAON,EAAI,OAAS,EAEtB,GAAIyF,IAAS,WAAY,CACvB,IAAMqE,EAAKJ,EAAM,IACftM,EAAKuM,EAAM,IACbE,EAAO7J,EAAI,UAAWG,IAAOA,EAAE,MAAQ,IAAM2J,CAAE,EAC/CxJ,EAAON,EAAI,UAAWG,IAAOA,EAAE,MAAQ,IAAM/C,CAAE,CACjD,KAAO,CACL,IAAM8C,EAAKF,EAAI,KAAMG,GAAMA,EAAE,MAAQ,IAAI,GAAG,MAAQ,EAC9C4J,EAAM7J,EAAKwJ,EAAM,IACrBM,EAAM9J,EAAKyJ,EAAM,IACnBE,EAAO7J,EAAI,UAAWG,IAAOA,EAAE,MAAQ,IAAM4J,CAAG,EAChDzJ,EAAON,EAAI,UAAWG,IAAOA,EAAE,MAAQ,IAAM6J,CAAG,CAClD,CAEIH,IAAS,KAAIA,EAAO,GACpBvJ,IAAS,KAAIA,EAAON,EAAI,OAAS,GAGrC,IAAMO,EAASP,EAAI,MAAM6J,EAAMvJ,EAAO,CAAC,EACjCE,EAAQC,GAAQ,aAAaF,CAAM,EACzClC,GAAU,kBAAkBmC,CAAK,GAC5BvC,GAAS,IAAI,EAAE,KAAO,YAAc,YAAYyC,GAAeX,CAAC,EAErEY,GAAQ,iBAAiBpD,GAAYyC,EAAK6J,EAAMvJ,EAAMsJ,EAAKlM,EAAgB,EAC3EiD,GAAQ,cAAcJ,EAAO,IAAKJ,GAAM,CAACA,EAAE,IAAKA,EAAE,GAAG,CAAqB,CAAC,EAC3ElC,GAAS,MAAM,CAAE,IAAK,CAACyL,EAAKC,CAAG,CAAE,CAAC,CACpC,CAEA,SAAS1F,GAAawF,EAAgB7J,EAAa,CAC7C6J,GAAMA,EAAG,KAAO,MAAQA,EAAG,KAAO,MAAM9I,GAAQ,SAAS8I,EAAG,IAAKA,EAAG,IAAK3M,EAAgB,CAC/F,CAEO,SAASgD,GAAYH,EAAYiK,EAAM,GAAMK,EAAmB,GAAO,CAC5E,GAAI,CAAClN,GAAO4C,CAAE,EAAG,OACjB,GAAIA,IAAOpC,GAAY,CACjBqM,GAAKjJ,GAAQ,SAAShB,CAAE,EAC5B,MACF,CAEA,IAAMuK,EAAc3M,KAAe,KAC/B2M,IAEF7L,GAAU,MAAM,EAChB6C,GAAc,KAAM,CAAC,CAAC,EACtBR,GAAe,IAAI,GAGrBnD,GAAaoC,EAGbjC,GAAmB,KACnBiD,GAAQ,iBAAiBhB,CAAE,EACvBuK,GACF7L,GAAU,eAAe,IAAI,EAI/BJ,GAAS,MAAM,CAAE,MAAO0B,EAAI,IAAK,IAAK,EAAG,EAAI,EACzCuK,GACF7L,GAAU,gBAAgB,EAI5BY,GAAgB,EAGhB,IAAMkL,EAAYlM,GAAS,IAAI,EAAE,KAAO,SACpCkM,IAAc,WAAWjJ,GAAcnE,GAAO4C,CAAE,EAAGwB,GAAc,CAAC,EAClEgJ,IAAc,YAAYzJ,GAAe3D,GAAO4C,CAAE,CAAC,EACnDwK,IAAc,YAAYvI,GAAe7E,GAAO4C,CAAE,CAAC,EACnDwK,IAAc,WAAWtI,GAAc,EACvCsI,IAAc,aAChB/I,GAAgBrE,GAAO4C,CAAE,EAAG,OAAO,OAAO5C,EAAM,EAAG,CAACsE,EAASC,IAAU,CACrExB,GAAYuB,EAAS,EAAI,EACrBC,IACFjD,GAAU,iBAAiBiD,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC7CC,GAAmBD,EAAM,CAAC,EAAGA,EAAM,CAAC,EAAG,OAAQ,EAAI,EAEvD,CAAC,EAIHX,GAAQ,iBAAiBhB,EAAIiK,CAAG,EAC5BA,GAAKjJ,GAAQ,SAAShB,CAAE,EAC5BtB,GAAU,UAAUtB,GAAO4C,CAAE,EAAG,OAAO,OAAO5C,EAAM,EAAGkN,CAAgB,CACzE,CAEA,eAAetG,GAAYhE,EAAY,CACrC,MAAMqC,GAAQ,OAAOrC,CAAE,EACvBgB,GAAQ,YAAYhB,CAAE,EACtB,OAAO5C,GAAO4C,CAAE,EACZpC,KAAeoC,IACjBpC,GAAa,KACbc,GAAU,MAAM,EAChB6C,GAAc,KAAM,CAAC,CAAC,EACtBR,GAAe,IAAI,EACnBzC,GAAS,MAAM,CAAE,MAAO,KAAM,IAAK,KAAM,UAAW,IAAK,CAAC,GAE5DyD,GAAa,CACf,CAEA,eAAe4D,IAAW,CACxB,IAAM8E,EAAO,KAAK,MAAM,GAAK,KAAK,OAAO,EAAI,EAAE,EAAE,SAAS,EAEpDC,EAAW,SAAS,cAAc,KAAK,EAC7CA,EAAS,UAAY,iBAErBA,EAAS,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gDAOyBD,CAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUlD,SAAS,KAAK,YAAYC,CAAQ,EAElC,IAAMC,EAAQD,EAAS,cAAc,cAAc,EAC7CE,EAAaF,EAAS,cAAc,oBAAoB,EACxDG,EAAYH,EAAS,cAAc,mBAAmB,EAE5DC,EAAM,MAAM,EAEZA,EAAM,iBAAiB,QAAS,IAAM,CACpCC,EAAW,SAAWD,EAAM,QAAUF,CACxC,CAAC,EAED,IAAMjL,EAAQ,IAAMkL,EAAS,OAAO,EAEpCG,EAAU,iBAAiB,QAASrL,CAAK,EACzCkL,EAAS,iBAAiB,QAAUjL,GAAM,CACpCA,EAAE,SAAWiL,GAAUlL,EAAM,CACnC,CAAC,EAEDoL,EAAW,iBAAiB,QAAS,SAAY,CAC3CD,EAAM,QAAUF,IACpBjL,EAAM,EAEN7B,GAAmB,GACnB,MAAM0E,GAAQ,MAAM,EAEpBjF,GAAS,CAAC,EACVQ,GAAa,KACboD,GAAQ,eAAe,EACvB,OAAO,SAAS,OAAO,EACzB,CAAC,CACH,CAEA,SAASe,GAAa+I,EAAa,GAAO,CAC5B,OAAO,KAAK1N,EAAM,EAC1B,QAAS4C,GAAO,CAClB,IAAMI,EAAIhD,GAAO4C,CAAE,EACbmC,EAAI/B,EAAE,MACR2K,EAAU,GAGd,GAAI/M,GACF,GAAIC,GACF,GAAI,CACS,IAAI,OAAOD,GAAa,GAAG,EAC9B,KAAKoC,EAAE,IAAI,IAAG2K,EAAU,GAClC,MAAY,CACVA,EAAU,EACZ,MAEK3K,EAAE,KAAK,YAAY,EAAE,SAASpC,GAAY,YAAY,CAAC,IAAG+M,EAAU,IAK7E,GAAIA,IAAY5M,GAAQ,KAAK,CAAC,GAAKA,GAAQ,KAAK,CAAC,GAAI,CACnD,IAAM0D,EAAQ1D,GAAQ,KAAK,CAAC,EAAI,IAAI,KAAKA,GAAQ,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAI,EAChE2D,EAAM3D,GAAQ,KAAK,CAAC,EAAI,IAAI,KAAKA,GAAQ,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAI,IAC9DoC,EAAK4B,EAAE,WAAa,GACtB5B,EAAKsB,GAAStB,EAAKuB,KAAKiJ,EAAU,GACxC,CAGA,GAAIA,IAAY5M,GAAQ,KAAK,CAAC,IAAM,MAAQA,GAAQ,KAAK,CAAC,IAAM,MAAO,CACrE,IAAM4L,GAAO5L,GAAQ,KAAK,CAAC,GAAK,GAAK,IAC/B6L,GAAO7L,GAAQ,KAAK,CAAC,GAAK,KAAY,KACxCgE,EAAE,UAAY4H,GAAO5H,EAAE,UAAY6H,KAAKe,EAAU,GACxD,CAGA,GAAIA,IAAY5M,GAAQ,IAAI,CAAC,IAAM,MAAQA,GAAQ,IAAI,CAAC,IAAM,MAAO,CACnE,IAAM4L,GAAO5L,GAAQ,IAAI,CAAC,GAAK,GAAK,IAC9B6L,GAAO7L,GAAQ,IAAI,CAAC,GAAK,KAAY,IACrC,EAAIgE,EAAE,UAAY,GACpB,EAAI4H,GAAO,EAAIC,KAAKe,EAAU,GACpC,CAGA,GAAIA,GAAW5M,GAAQ,QAAQ,KAAO,EACpC,QAAWqI,KAAKrI,GAAQ,QAAS,CAC/B,IAAM6M,EAAQtM,GAAU,QAAQ8H,CAAC,EAAE,MACnC,GAAI,CAACpG,EAAE,OAAO,KAAMI,GAAWA,EAAEwK,CAAK,GAAK,IAAI,EAAG,CAChDD,EAAU,GACV,KACF,CACF,CASF,GALIA,GAAW5M,GAAQ,OACjBiC,EAAE,QAAUjC,GAAQ,QAAO4M,EAAU,IAIvCA,GAAW5M,GAAQ,KAAK,OAAS,EAAG,CACtC,IAAM8M,EAAY7K,EAAE,MAAQ,CAAC,EACxBjC,GAAQ,KAAK,MAAO+M,GAAOD,EAAU,SAASC,CAAE,CAAC,IAAGH,EAAU,GACrE,CAEA3K,EAAE,UAAY,CAAC2K,EACf/J,GAAQ,gBAAgBZ,EAAE,GAAIA,EAAE,SAAW2K,CAAO,CACpD,CAAC,EAEID,GAAYxL,GAAgB,CACnC,CAEA,SAAS0C,IAAiB,CACvB,SAAS,eAAe,mBAAmB,EAAuB,MAAQ7D,GAAQ,KAAK,CAAC,GAAK,GAC7F,SAAS,eAAe,iBAAiB,EAAuB,MAAQA,GAAQ,KAAK,CAAC,GAAK,GAC3F,SAAS,eAAe,iBAAiB,EAAuB,MAC/DA,GAAQ,KAAK,CAAC,IAAM,KAAO,OAAOA,GAAQ,KAAK,CAAC,CAAC,EAAI,GACtD,SAAS,eAAe,iBAAiB,EAAuB,MAC/DA,GAAQ,KAAK,CAAC,IAAM,KAAO,OAAOA,GAAQ,KAAK,CAAC,CAAC,EAAI,GACtD,SAAS,eAAe,gBAAgB,EAAuB,MAC9DA,GAAQ,IAAI,CAAC,IAAM,KAAO,OAAOA,GAAQ,IAAI,CAAC,CAAC,EAAI,GACpD,SAAS,eAAe,gBAAgB,EAAuB,MAC9DA,GAAQ,IAAI,CAAC,IAAM,KAAO,OAAOA,GAAQ,IAAI,CAAC,CAAC,EAAI,GACpD,SAAS,eAAe,aAAa,EAAuB,MAAQA,GAAQ,KAAK,KAAK,IAAI,EAE3F,SACG,iBAAiB,4EAA4E,EAC7F,QAASc,GAAO,CACf,IAAMG,EAAOH,EACbG,EAAK,UAAU,OAAO,UAAWA,EAAK,QAAQ,OAAS,OAASjB,GAAQ,OAAS,GAAG,CACtF,CAAC,EAEH,SAAS,iBAAiB,4BAA4B,EAAE,QAASc,GAAO,CACtE,IAAMgC,EAAMhC,EACZgC,EAAI,UAAU,OAAO,SAAU9C,GAAQ,QAAQ,IAAI8C,EAAI,QAAQ,MAAO,CAAC,CACzE,CAAC,EAED,IAAMkK,GACHhN,GAAQ,KAAK,CAAC,EAAI,EAAI,IACtBA,GAAQ,KAAK,CAAC,EAAI,EAAI,IACtBA,GAAQ,KAAK,CAAC,IAAM,KAAO,EAAI,IAC/BA,GAAQ,KAAK,CAAC,IAAM,KAAO,EAAI,IAC/BA,GAAQ,IAAI,CAAC,IAAM,KAAO,EAAI,IAC9BA,GAAQ,IAAI,CAAC,IAAM,KAAO,EAAI,GAC/BA,GAAQ,QAAQ,MACfA,GAAQ,KAAK,OAAS,EAAI,EAAI,GAE3BiN,EAAQ,SAAS,cAAc,gCAAgC,EACjEA,IACFA,EAAM,YAAcD,EAAc,EAAI,OAAOA,CAAW,EAAI,GAC5DC,EAAM,UAAU,OAAO,SAAUD,IAAgB,CAAC,EAEtD,CAEA,SAAS9L,IAAqB,CAC5B,IAAMgM,EAAc,SAAS,eAAe,cAAc,EACtDA,IAAaA,EAAY,MAAQrN,IACrC,SAAS,eAAe,kBAAkB,GAAG,UAAU,OAAO,SAAUC,EAAW,EAEnF,IAAMkB,EAAML,GAAa,KAAMwM,GAAMA,EAAE,MAAQpN,EAAW,EAC1D,GAAIiB,EAAK,CACP,IAAMoM,EAAU,SAAS,eAAe,oBAAoB,EACtDC,EAAS,SAAS,eAAe,mBAAmB,EACtDD,IACFA,EAAQ,YAAcpM,EAAI,MACvB,QAAQ,SAAU,EAAE,EACpB,QAAQ,YAAa,EAAE,EACvB,QAAQ,YAAa,EAAE,GACxBqM,IAAQA,EAAO,YAAcrM,EAAI,KACvC,CACF,CAEA,SAASsF,GAAWf,EAAoB,CAEtC,IAAM+H,EAAa/H,EAAS,MAyB5B,GAxBI+H,IAAe7N,KACb6N,GAAcrO,GAAOqO,CAAU,EACjCtL,GAAYsL,EAAY,EAAI,EACnB,CAACA,GAAc7N,KACxBA,GAAa,KACbc,GAAU,MAAM,EAChB6C,GAAc,KAAM,CAAC,CAAC,EACtBR,GAAe,IAAI,EACnBzB,GAAgB,EAChB0B,GAAQ,OAAO,IAKf0C,EAAS,KAAO,OAAOA,EAAS,KAAQ,WAC1C1C,GAAQ,cAAc0C,EAAS,GAAG,EAClC,SACG,iBAAiB,SAAS,EAC1B,QAASvC,GACRA,EAAE,UAAU,OAAO,SAAWA,EAAkB,QAAQ,QAAUuC,EAAS,GAAG,CAChF,GAIAA,EAAS,QAAS,CACpB,GAAM,CAACiG,EAAKC,EAAKC,CAAI,EAAInG,EAAS,QAClC1C,GAAQ,YAAY2I,EAAKC,EAAKC,CAAI,CACpC,CAGInG,EAAS,KACX,SAAS,iBAAiB,UAAU,EAAE,QAASzC,GAAQ,CACrD,IAAME,EAAIF,EACNE,EAAE,QAAQ,MAAQuC,EAAS,MACxBvC,EAAE,UAAU,SAAS,QAAQ,GAAGA,EAAE,MAAM,EAEjD,CAAC,EAICuC,EAAS,OAAOhF,GAAU,SAASgF,EAAS,KAAK,EAErD,IAAMgI,EAAehI,EAAS,OAAS,OAMvC,GALA,SACG,iBAAiB,uBAAuB,EACxC,QAASvC,GAAMA,EAAE,UAAU,OAAO,SAAWA,EAAkB,QAAQ,OAASuK,CAAY,CAAC,EAG5FhI,EAAS,QAAS,CACpB,IAAM/E,EAAUD,GAAU,QACpBiN,EAAOjI,EAAS,QACnB,IAAKkI,GAAS,OAAO,KAAKjN,CAAO,EAAE,KAAMkN,GAAMlN,EAAQkN,CAAC,EAAE,OAASD,CAAI,CAAC,EACxE,OAAQC,GAAmBA,IAAM,MAAS,EACzCF,EAAK,QAAQjN,GAAU,iBAAiBiN,CAAI,CAClD,CAGIjI,EAAS,SACXvF,GAAQ,KAAOuF,EAAS,OAAO,IAAKnF,GAAMA,GAAK,IAAI,GACjDmF,EAAS,SACXvF,GAAQ,KAAOuF,EAAS,OAAO,IAAKnF,GAAOA,IAAM,EAAI,EAAIA,GAAK,IAAK,GAIjEmF,EAAS,QACXvF,GAAQ,IAAMuF,EAAS,MAAM,IAAKnF,GAAOA,IAAM,EAAI,EAAIA,GAAK,IAAK,GAI/DmF,EAAS,SAAQvF,GAAQ,QAAU,IAAI,IAAIuF,EAAS,MAAM,GAC1DA,EAAS,SAAQvF,GAAQ,KAAOuF,EAAS,QAE7C1B,GAAe,EAEX0B,EAAS,IAAG1F,GAAc0F,EAAS,GACnCA,EAAS,KAAIzF,GAAcyF,EAAS,IACpCA,EAAS,OAAMxF,GAAcwF,EAAS,MAC1CrE,GAAmB,EAEnB0C,GAAa,CACf,CAEA,SAAS+J,IAA2B,CAElC,GAAI,CADc,SAAS,eAAe,wBAAwB,EAClD,OAEhB,IAAMC,EAAkB,SAAS,eAAe,eAAe,EACzD3F,EAAkB,SAAS,eAAe,wBAAwB,EACxE,GAAI,CAAC2F,GAAmB,CAAC3F,EAAiB,OAE1C,IAAM4F,EAAS,IAAI,IACnB,OAAO,OAAO5O,EAAM,EAAE,QAASgD,GAAM,CAC/BA,EAAE,OAAO4L,EAAO,IAAI5L,EAAE,KAAK,CACjC,CAAC,EAED,IAAM6L,EAAc,MAAM,KAAKD,CAAM,EAAE,KAAK,EACtCE,EAAiB,SAAS,eAAe,uBAAuB,EAEtEH,EAAgB,UAAY,GAC5B3F,EAAgB,UAAY,GAExB6F,EAAY,QAAU,GACpBC,IAAgBA,EAAe,MAAM,QAAU,QAEnDD,EAAY,QAASE,GAAU,CAC7B,IAAMlL,EAAM,SAAS,cAAc,QAAQ,EAC3CA,EAAI,UAAY,YAAY9C,GAAQ,QAAUgO,EAAQ,UAAY,EAAE,GACpElL,EAAI,QAAQ,MAAQkL,EACpBlL,EAAI,MAAQkL,EAAM,OAAO,CAAC,EAAE,YAAY,EAAIA,EAAM,MAAM,CAAC,EACzDlL,EAAI,UAAY,0CAA0CmL,GAAaD,CAAK,CAAC,UAC7EJ,EAAgB,YAAY9K,CAAG,CACjC,CAAC,IAEGiL,IAAgBA,EAAe,MAAM,QAAU,gBAE9B,CAAC,UAAW,UAAW,SAAS,EAExC,QAASC,GAAU,CAC9B,GAAIH,EAAO,IAAIG,CAAK,EAAG,CACrB,IAAMlL,EAAM,SAAS,cAAc,QAAQ,EAC3CA,EAAI,UAAY,YAAY9C,GAAQ,QAAUgO,EAAQ,UAAY,EAAE,GACpElL,EAAI,QAAQ,MAAQkL,EACpBlL,EAAI,MAAQkL,EAAM,OAAO,CAAC,EAAE,YAAY,EAAIA,EAAM,MAAM,CAAC,EACzDlL,EAAI,UAAY,0CAA0CmL,GAAaD,CAAK,CAAC,UAC7EJ,EAAgB,YAAY9K,CAAG,CACjC,CACF,CAAC,EAEDgL,EAAY,QAASE,GAAU,CAC7B,IAAM/M,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,gBAAgBjB,GAAQ,QAAUgO,EAAQ,UAAY,EAAE,GACzE/M,EAAK,QAAQ,MAAQ+M,EACrB/M,EAAK,MAAM,QAAU,MACrBA,EAAK,MAAM,OAAS,UACpBA,EAAK,MAAM,QAAU,OACrBA,EAAK,MAAM,WAAa,SACxBA,EAAK,MAAM,IAAM,MACjBA,EAAK,UAAY;AAAA,iDAC0BgN,GAAaD,CAAK,CAAC;AAAA,gBACpDA,EAAM,OAAO,CAAC,EAAE,YAAY,EAAIA,EAAM,MAAM,CAAC,CAAC;AAAA,QAExD/F,EAAgB,YAAYhH,CAAI,CAClC,CAAC,EAEL,CAEA,SAASE,IAAkB,CACzBwM,GAAyB,EACzB,IAAMO,EAAO,SAAS,eAAe,YAAY,EAC3CC,EAAU,SAAS,eAAe,kBAAkB,EACpDC,EAAc,SAAS,cAAc,gBAAgB,EAC3D,GAAI,CAACF,EAAM,OAEX,IAAMG,EAAM,OAAO,KAAKpP,EAAM,EAAE,OAAQ4C,GAAO,CAAC5C,GAAO4C,CAAE,EAAE,SAAS,EAGpE,GAFIuM,IAAaA,EAAY,YAAc,WAAWC,EAAI,MAAM,KAE5D,CAACA,EAAI,OAAQ,CACfH,EAAK,UAAY,GACbC,IACFD,EAAK,YAAYC,CAAO,EACxBA,EAAQ,MAAM,QAAU,SAE1B,MACF,CACIA,IAASA,EAAQ,MAAM,QAAU,QACrCD,EAAK,UAAY,GAEjBG,EACG,KAAK,CAAC3H,EAAG1D,IAAM,CAEd,GAAI0D,IAAMjH,GAAY,MAAO,GAC7B,GAAIuD,IAAMvD,GAAY,MAAO,GAE7B,IAAM6O,EAAKrP,GAAOyH,CAAC,EACjB6H,EAAKtP,GAAO+D,CAAC,EACTwL,EAAKF,EAAG,MACZG,EAAKF,EAAG,MAENG,EAAM,EACV,OAAQ3O,GAAa,CACnB,IAAK,WACH2O,GAAOF,EAAG,WAAa,IAAMC,EAAG,WAAa,GAC7C,MACF,IAAK,YACHC,GAAOD,EAAG,WAAa,IAAMD,EAAG,WAAa,GAC7C,MACF,IAAK,WACHE,GAAOF,EAAG,WAAa,IAAMC,EAAG,WAAa,GAC7C,MACF,IAAK,YACHC,GAAOD,EAAG,WAAa,IAAMD,EAAG,WAAa,GAC7C,MACF,IAAK,UACHE,GAAOF,EAAG,UAAY,IAAMC,EAAG,UAAY,GAC3C,MACF,IAAK,WACHC,GAAOD,EAAG,UAAY,IAAMD,EAAG,UAAY,GAC3C,MACF,QACEE,EAAM,CACV,CACA,OAAOA,GAAOhI,EAAE,cAAc1D,CAAC,CACjC,CAAC,EACA,QAASnB,GAAO,CACfqM,EAAK,YAAYS,GAAe1P,GAAO4C,CAAE,CAAC,CAAC,CAC7C,CAAC,CACL,CAEA,SAASwB,IAA0B,CACjC,IAAMuL,EAAM,IAAI,IAChB,cAAO,OAAO3P,EAAM,EAAE,QAASgD,GAAM,EAClCA,EAAE,MAAQ,CAAC,GAAG,QAAS4M,GAAQD,EAAI,IAAIC,CAAG,CAAC,CAC9C,CAAC,EACM,MAAM,KAAKD,CAAG,EAAE,KAAK,CAC9B,CAEA,SAASX,GAAaD,EAA8B,CAClD,GAAI,CAACA,EAAO,MAAO,WACnB,IAAMhK,EAAIgK,EAAM,YAAY,EAC5B,OAAIhK,EAAE,SAAS,KAAK,EAAU,iBAC1BA,EAAE,SAAS,MAAM,GAAKA,EAAE,SAAS,MAAM,EAAU,kBACjDA,EAAE,SAAS,MAAM,EAAU,kBAC3BA,EAAE,SAAS,MAAM,EAAU,OAC3BA,EAAE,SAAS,KAAK,EAAU,SACvB,QACT,CAEA,SAAS2K,GAAeG,EAAkB,CACxC,IAAM7N,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,aAAa6N,EAAM,KAAOrP,GAAa,YAAc,EAAE,GACxEwB,EAAK,QAAQ,GAAK6N,EAAM,GAExB,IAAMC,EACJD,EAAM,OAAO,QAAUA,EAAM,OAAO,CAAC,EAAE,KAAOE,GAAQF,EAAM,OAAO,CAAC,EAAE,IAAI,EAAI,eAE1EG,GACHH,EAAM,MAAQ,CAAC,GAAG,OAAS,EACxB,4BAA4BA,EAAM,MAAQ,CAAC,GACxC,IAAK7M,GAAM,CACV,IAAMkB,EAAI+L,GAAYjN,CAAC,EACvB,MAAO,+CAA+CkB,CAAC,aAAaA,CAAC,KAAKgM,GAAQlN,CAAC,CAAC,SACtF,CAAC,EACA,KAAK,EAAE,CAAC,SACX,GAENhB,EAAK,UAAY;AAAA,iDAC8B6N,EAAM,KAAK;AAAA;AAAA,gCAE5BK,GAAQL,EAAM,aAAeA,EAAM,IAAI,CAAC;AAAA;AAAA;AAAA,kBAGtDC,CAAI;AAAA,uFACiE,KAAK,MAAMD,EAAM,MAAM,UAAY,GAAI,CAAC;AAAA,YACnHA,EAAM,MAAQ,4DAA4DK,GAAQL,EAAM,KAAK,CAAC,KAAKb,GAAaa,EAAM,KAAK,CAAC,UAAY,EAAE;AAAA,gCACtHA,EAAM,OAAO,YAAY,CAAC;AAAA;AAAA;AAAA,mDAGPA,EAAM,QAAU,aAAe,gBAAgB;AAAA;AAAA;AAAA,QAG1FG,CAAQ;AAAA;AAAA,IAIdhO,EAAK,iBAAiB,QAAUK,GAAM,CAC/BA,EAAE,OAAuB,QAAQ,WAAW,GACjDU,GAAY8M,EAAM,EAAE,CACtB,CAAC,EAED,IAAMM,EAASnO,EAAK,cAAc,aAAa,EAC/C,OAAAmO,EAAO,iBAAiB,QAAS,IAAM,CACrCN,EAAM,QAAU,CAACA,EAAM,QACvBM,EAAO,cAAc,2BAA2B,EAAG,YAAcN,EAAM,QACnE,aACA,iBACJjM,GAAQ,gBAAgBiM,EAAM,GAAIA,EAAM,OAAO,EAC/C5K,GAAQ,KAAK4K,CAAK,CACpB,CAAC,EAEM7N,CACT,CAEA,SAAS0E,GAAUF,EAAaC,EAAyB,OAAQ,CAC/D,IAAM2J,EAAY,SAAS,eAAe,iBAAiB,EAC3D,GAAI,CAACA,EAAW,OAChBA,EAAU,UAAY,GACtB,IAAMpN,EAAI,SAAS,cAAc,KAAK,EACtCA,EAAE,UAAY,SAASyD,CAAI,GAC3BzD,EAAE,YAAcwD,EAChB4J,EAAU,YAAYpN,CAAC,CACzB,CAEA,SAASqN,IAA0B,CACjC,IAAM/C,EAAW,SAAS,cAAc,KAAK,EAC7CA,EAAS,UAAY,iBAErB,IAAIgD,EAAW,GACfrQ,GAAe,QAAS8E,GAAM,CAC5BuL,GAAY,4CAA4CvL,EAAE,IAAI,cAAcA,EAAE,MAAM,QACtF,CAAC,EAEDuI,EAAS,UAAY;AAAA;AAAA;AAAA;AAAA,UAIbgD,GAAY,gCAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASpD,SAAS,KAAK,YAAYhD,CAAQ,EAElC,IAAMG,EAAYH,EAAS,cAAc,mBAAmB,EACtDiD,EAAWjD,EAAS,cAAc,kBAAkB,EACpDlL,EAAQ,IAAMkL,EAAS,OAAO,EAEpCG,EAAU,iBAAiB,QAASrL,CAAK,EACzCmO,EAAS,iBAAiB,QAAS,IAAM,CACvCtQ,GAAiB,CAAC,EAClBmC,EAAM,EACN,IAAMoO,EAAgB,SAAS,eAAe,gBAAgB,EAC1DA,GAAeA,EAAc,UAAU,IAAI,QAAQ,CACzD,CAAC,EAEDlD,EAAS,iBAAiB,QAAUjL,GAAM,CACpCA,EAAE,SAAWiL,GAAUlL,EAAM,CACnC,CAAC,CACH,CAEA,SAASuG,IAAe,CACtB,IAAM8H,EAAO,SAAS,eAAe,WAAW,EAChD,GAAI,CAACA,EAAM,OAEX,IAAMD,EAAgB,SAAS,eAAe,gBAAgB,EAC1DA,GACFA,EAAc,iBAAiB,QAAUnO,GAAM,CAC7CA,EAAE,gBAAgB,EAClBgO,GAAwB,CAC1B,CAAC,EAGH,OAAO,iBAAiB,WAAahO,GAAM,CACzCA,EAAE,eAAe,EACjBoO,EAAK,UAAU,IAAI,aAAa,CAClC,CAAC,EAED,OAAO,iBAAiB,YAAcpO,GAAM,CACtCA,EAAE,gBAAkB,MAAMoO,EAAK,UAAU,OAAO,aAAa,CACnE,CAAC,EAED,OAAO,iBAAiB,OAAQ,MAAOpO,GAAM,CAC3CA,EAAE,eAAe,EACjBoO,EAAK,UAAU,OAAO,aAAa,EAEnC,IAAMC,EAAQrO,EAAE,cAAc,MAC9B,GAAI,CAACqO,EAAO,OAEZ,IAAMC,EAAgB,CAAC,EACjBC,EAA2B,CAAC,EAElC,QAASC,EAAI,EAAGA,EAAIH,EAAM,OAAQG,IAAK,CACrC,IAAMC,EAAQJ,EAAMG,CAAC,EAAE,iBAAiB,EACpCC,GAAOF,EAAM,KAAKE,CAAK,CAC7B,CAEA,eAAeC,EAAeD,EAAwB,CACpD,GAAIA,EAAM,OAAQ,CAChB,IAAM1G,EAAO,MAAM,IAAI,QAAe4G,GAASF,EAA8B,KAAKE,CAAG,CAAC,EACtFL,EAAM,KAAKvG,CAAI,CACjB,SAAW0G,EAAM,YAAa,CAC5B,IAAMG,EAAUH,EAAmC,aAAa,EAC5DI,EAA6B,CAAC,EAC9BC,EACJ,GACEA,EAAQ,MAAM,IAAI,QAA4BH,GAAQC,EAAO,YAAYD,CAAG,CAAC,EAC7EE,EAAQ,KAAK,GAAGC,CAAK,QACdA,EAAM,OAAS,GAExB,QAAWC,KAASF,EAAS,MAAMH,EAAeK,CAAK,CACzD,CACF,CAEA,QAAWN,KAASF,EAAO,MAAMG,EAAeD,CAAK,EAEjDH,EAAM,QAAQ/H,GAAY+H,CAAK,CACrC,CAAC,CACH,CAEA,eAAe/H,GAAY+H,EAAe,CACxC,GAAI,CAACA,EAAM,OAAQ,OACnBpQ,GAAmB,GACnB,IAAM8Q,EAAmBpR,GAAe,OAElC+F,EAAS,SAAS,eAAe,eAAe,EAChDC,EAAa,SAAS,eAAe,aAAa,EAClDC,EAAgB,SAAS,eAAe,gBAAgB,EACxDC,EAAc,SAAS,eAAe,qBAAqB,EAC3DmL,EAAc,SAAS,eAAe,cAAc,EAEtDA,GACFA,EAAY,iBAAiB,QAAS,IAAM,CAC1C/Q,GAAmB,GACfyF,GAAQA,EAAO,UAAU,IAAI,QAAQ,CAC3C,CAAC,EAGH,SAASuL,GAA4B,CACnC,IAAMC,EAAa,SAAS,cAAc,wBAAwB,EAC9DA,IACFA,EAAW,YAAc,UACzBA,EAAW,MAAM,MAAQ,WAE3B,IAAMC,EAAe,SAAS,eAAe,sBAAsB,EACnE,GAAIA,EAAc,CAChB,IAAMC,EAAQzR,GAAe,OAASoR,EAChCM,EAAYF,EAAa,cAAc,MAAM,EAC/CE,IAAWA,EAAU,YAAc,GAAGD,CAAK,IAC/CD,EAAa,MAAM,QAAU,MAC/B,CACF,CAEA,GAAIzL,EAAQ,CACNC,IACFA,EAAW,YAAc,aAAa0K,EAAM,MAAM,QAAQA,EAAM,OAAS,EAAI,IAAM,EAAE,IACvF,IAAMa,EAAa,SAAS,cAAc,wBAAwB,EAC9DA,IACFA,EAAW,YAAc,WACzBA,EAAW,MAAM,MAAQ,iBAE3B,IAAMC,EAAe,SAAS,eAAe,sBAAsB,EACnE,GAAIA,EAAc,CAChBA,EAAa,MAAM,QAAU,OAC7B,IAAME,EAAYF,EAAa,cAAc,MAAM,EAC/CE,IAAWA,EAAU,YAAc,IACzC,CACIzL,IAAeA,EAAc,YAAc,IAC3CC,IAAaA,EAAY,MAAM,MAAQ,MAC3CH,EAAO,UAAU,OAAO,QAAQ,EAE5B/F,GAAe,OAASoR,GAAkBE,EAA0B,CAC1E,CAEA,GAAI,CACF,IAAIG,EAAQ,EACRE,EAAyB,KACzBC,EAA2B,EAGzBC,EAAanB,EAAM,OAAQoB,GAAM,CACrC,IAAMlI,EAAOkI,EAAE,KAAK,YAAY,EAChC,OACElI,EAAK,SAAS,MAAM,GACpBA,EAAK,SAAS,MAAM,GACpBA,EAAK,SAAS,MAAM,GACpBA,EAAK,SAAS,MAAM,CAExB,CAAC,EAOD,GALqB8G,EAAM,OAAQoB,GAAM,CAACD,EAAW,SAASC,CAAC,CAAC,EACnD,QAASA,GAAM,CAC1B9R,GAAe,KAAK,CAAE,KAAM8R,EAAE,KAAM,OAAQ,yBAA0B,CAAC,CACzE,CAAC,EAEGD,EAAW,SAAW,EAAG,CAC3B,GAAInB,EAAM,OAAS,EAAG,CACpBjK,GAAU,2BAA4B,OAAO,EAE7C,IAAM8J,EAAgB,SAAS,eAAe,gBAAgB,EAC1DA,GAAiBvQ,GAAe,OAAS,IAC3CuQ,EAAc,UAAU,OAAO,QAAQ,EACvCA,EAAc,MAAQ,WAAWvQ,GAAe,MAAM,mCAE1D,CACA,MACF,CAEA,IAAM+R,EAAiB,SAAS,eAAe,iBAAiB,EAC5DC,EAAoC,KACxC,GAAI/L,EAAe,CACjBA,EAAc,UACZ,2EACF+L,EAAgB/L,EAAc,cAAc,iBAAiB,EAC7D,IAAMgM,EAAUhM,EAAc,cAAc,iBAAiB,EACzDgM,IAASA,EAAQ,YAAcJ,EAAW,OAAO,SAAS,EAChE,CAEA,QAASjB,EAAI,EAAGA,EAAIiB,EAAW,QACzB,CAAAvR,GADiCsQ,IAAK,CAE1C,IAAMkB,EAAID,EAAWjB,CAAC,EAClBmB,IAAgBA,EAAe,YAAcD,EAAE,MAC/CE,IAAeA,EAAc,aAAepB,EAAI,GAAG,SAAS,GAC5D1K,IAAaA,EAAY,MAAM,MAAQ,GAAI0K,EAAIiB,EAAW,OAAU,GAAG,KAE3E,GAAI,CACF,IAAM3K,EAAO,MAAMzD,GAAQ,UAAUqO,CAAC,EAGhCI,EAAiB,OAAO,OAAOnS,EAAM,EAI3C,GADiBmS,EAAe,KAAMnP,GAAMA,EAAE,WAAa+O,EAAE,MAAQ/O,EAAE,WAAa+O,EAAE,IAAI,EAC5E,CACZ9R,GAAe,KAAK,CAAE,KAAM8R,EAAE,KAAM,OAAQ,WAAY,CAAC,EACzDR,EAA0B,EAC1B,QACF,CAGA,IAAMa,EAAWjL,EAAK,MAAM,UACtBkL,EAAclL,EAAK,MAAM,SAE/B,GAAIiL,GAAY,MAAQC,GAAe,KAAM,CAC3C,IAAMC,EAASF,EAAWC,EACpBE,EAAgBJ,EAAe,OAClCnP,IAAMA,GAAE,MAAM,WAAa,MAAQ9C,GAAUkS,EAAUpP,GAAE,MAAM,SAAU,CAC5E,EAEIwP,EAAY,GAChB,QAAWC,MAAOF,EAAe,CAC/B,IAAMG,EAAWD,GAAI,MAAM,UACrBE,EAAcF,GAAI,MAAM,SACxBG,GAASF,EAAWC,EAG1B,GAAIP,GAAYM,GAAYJ,GAAUM,GAAQ,CAC5C3S,GAAe,KAAK,CAAE,KAAM8R,EAAE,KAAM,OAAQ,kCAAmC,CAAC,EAChFR,EAA0B,EAC1BiB,EAAY,GACZ,KACF,CAIA,GADgB,KAAK,IAAIF,EAAQM,EAAM,EAAI,KAAK,IAAIR,EAAUM,CAAQ,EACxD,IAAQ,CAEpBzS,GAAe,KAAK,CAClB,KAAM8R,EAAE,KACR,OAAQ,uDACV,CAAC,EACDR,EAA0B,EAC1BiB,EAAY,GACZ,KACF,CACF,CACA,GAAIA,EAAW,QACjB,CAEA,IAAMK,EAAe,WACjBjQ,EAAKkQ,GAAU3L,EAAK,MAAM,WAAa0L,CAAY,EACnD7S,GAAO4C,CAAE,IAAGA,GAAM,IAAImQ,GAAY,CAAC,IAGvC,IAAIC,EAAY7L,EAAK,MACjB6L,EAAU,WAAW,SAAS,GAAKA,EAAU,WAAW,cAAc,KACxEA,EAAYjB,EAAE,MAGhB,IAAIkB,EAAcD,EACZ7P,GAAKgE,EAAK,OAAO,CAAC,GAAG,KACrB4H,EAAQ5H,EAAK,MACfA,EAAK,MAAM,OAAO,CAAC,EAAE,YAAY,EAAIA,EAAK,MAAM,MAAM,CAAC,EACvD,WACJ,GAAIhE,GAAI,CACN,IAAM+P,EAAI,IAAI,KAAK/P,EAAE,EACrB8P,EAAc,GAAGC,EAAE,eAAe,CAAC,IAAI,OAAOA,EAAE,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,IAAI,OAAOA,EAAE,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,IAAInE,CAAK,EACzI,MACEkE,EAAcD,EAAU,QAAQ,YAAa,EAAE,EAAE,QAAQ,KAAM,GAAG,EAGpE,IAAMnD,EAAmB,CACvB,GAAG1I,EACH,GAAAvE,EACA,KAAMoQ,EACN,YAAAC,EACA,SAAUlB,EAAE,KACZ,SAAUA,EAAE,KACZ,OAAQnK,GAAgBT,EAAK,MAAM,GAAK,OACxC,iBAAkBU,GAAcV,EAAK,OAAQ,EAAE,EAC/C,QAASA,EAAK,MAAM,WAAa0L,EACjC,QAAS,GACT,MAAO/S,GAAaW,GAAWX,GAAa,MAAM,CACpD,EAEA,GADAW,KACIF,GAAkB,MAEtB,MAAM0E,GAAQ,KAAK4K,CAAK,EACxB7P,GAAO4C,CAAE,EAAIiN,EACbjM,GAAQ,SAASiM,CAAK,EACjB+B,IAASA,EAAUhP,GACxB8O,IACAG,IAEIA,GAA4B,IAC9BA,EAA2B,EAE/B,OAASsB,EAAK,CACZlT,GAAe,KAAK,CAClB,KAAM8R,EAAE,KACR,OAAQ,gBAAgBoB,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,EAC1E,CAAC,EACD5B,EAA0B,CAC5B,CACF,CAGA,IAAMf,EAAgB,SAAS,eAAe,gBAAgB,EAC1DA,IACEvQ,GAAe,OAAS,GAC1BuQ,EAAc,UAAU,OAAO,QAAQ,EACvCA,EAAc,MAAQ,WAAWvQ,GAAe,MAAM,oCAEtDuQ,EAAc,UAAU,IAAI,QAAQ,GAIxC,IAAM4C,EAAcnT,GAAe,OAASoR,EAW5C,GAVI,CAAC+B,GAAepN,GAClBA,EAAO,UAAU,IAAI,QAAQ,EAG3B0L,EAAQ,IACVhL,GAAU,YAAYgL,CAAK,SAASA,EAAQ,EAAI,IAAM,EAAE,EAAE,EAC1D/M,GAAa,CAAC,CAACiN,GAAWA,IAAYpR,EAAU,EAC5CoR,GAAS7O,GAAY6O,CAAO,GAG9BwB,EAAa,CACf,IAAM5B,EAAa,SAAS,cAAc,wBAAwB,EAC9DA,IAAYA,EAAW,YAAc,WAEzC,MAAM,IAAI,QAAS3G,GAAM,WAAWA,EAAG,IAAI,CAAC,CAC9C,CACF,QAAE,CACI7E,GAAQA,EAAO,UAAU,IAAI,QAAQ,CAC3C,CACF,CAEA,SAASsC,IAA0B,CACjC,IAAM8H,EAAY,SAAS,eAAe,cAAc,EACxD,GAAI,CAACA,EAAW,OAEhB,IAAIiD,EAAgC,KAEpCjD,EAAU,iBAAiB,YAAc/N,GAAM,CAC7C,IAAM6G,EAAU7G,EAAE,OAAuB,QAAQ,cAAc,EAC1D6G,IACLmK,EAAYnK,EACZ7G,EAAE,aAAc,cAAgB,OAChC6G,EAAO,UAAU,IAAI,eAAe,EAEpC,WAAW,IAAOA,EAAO,MAAM,QAAU,MAAQ,CAAC,EACpD,CAAC,EAEDkH,EAAU,iBAAiB,WAAa/N,GAAM,CAC5CA,EAAE,eAAe,EACjBA,EAAE,aAAc,WAAa,OAC7B,IAAM6G,EAAU7G,EAAE,OAAuB,QAAQ,cAAc,EAC/D,GAAI6G,GAAUA,IAAWmK,EAAW,CAClC,IAAMlR,EAAO+G,EAAO,sBAAsB,EACpCoK,EAAOjR,EAAE,QAAUF,EAAK,KAAOA,EAAK,MAAQ,EAClDiO,EAAU,aAAaiD,EAAYC,EAAOpK,EAAO,YAAcA,CAAM,CACvE,CACF,CAAC,EAEDkH,EAAU,iBAAiB,UAAW,IAAM,CAC1C,GAAI,CAACiD,EAAW,OAChBA,EAAU,UAAU,OAAO,eAAe,EAC1CA,EAAU,MAAM,QAAU,GAC1BA,EAAY,KAGZ,IAAM9E,EAAO,MAAM,KAAK6B,EAAU,iBAAiB,cAAc,CAAC,EAAE,IACjEvO,GAAQA,EAAmB,QAAQ,MACtC,EACAP,GAAU,kBAAkBiN,CAAI,EAChCnN,GAAiB,CACnB,CAAC,CACH,CAEA,SAASuB,IAAsB,CAC7B,IAAM4Q,EAAU,SAAS,eAAe,eAAe,EACjDC,EAAQ,SAAS,eAAe,cAAc,EACpD,GAAI,CAACD,GAAW,CAACC,EAAO,OAExBD,EAAQ,UAAU,OAAO,WAAW,EACpC,IAAME,EAAa,KAAK,IAAI,EAAGF,EAAQ,YAAc,GAAG,EACpDG,EAAS,EACTC,EAAS,GAEb,MAAM,KAAKH,EAAM,QAAQ,EAAE,QAAS3R,GAAO,CACzC,IAAM+R,EAAS/R,EAIf,GAHI+R,EAAO,KAAO,kBAElBA,EAAO,UAAU,OAAO,iBAAiB,EACrC,CAACA,EAAO,UAAU,SAAS,QAAQ,GAAG,OAE1C,IAAMC,EAAyB,IADbD,EAAO,QAAQ,QAAU,IACG,OAAS,EACvDF,GAAUG,EAAyB,EAE/BH,EAASD,IACXE,EAAS,GACTC,EAAO,UAAU,IAAI,iBAAiB,EAE1C,CAAC,EAED,IAAME,EAAa,SAAS,eAAe,eAAe,EACtDA,GAAYA,EAAW,UAAU,OAAO,SAAU,CAACH,CAAM,EAEzDA,GAAQJ,EAAQ,UAAU,IAAI,WAAW,CAC/C,CAEA,SAAS,iBAAiB,mBAAoB/N,EAAI", - "names": ["UrlState", "_state", "_lastSearch", "_syncTimeout", "_shouldPush", "read", "p", "s", "metricsRaw", "v", "isDesc", "field", "parts", "_sync", "dir", "search", "val", "url", "get", "patch", "partial", "push", "k", "key", "refresh", "reset", "InMemoryStorage", "track", "id", "key", "value", "IndexedDBStorage", "resolve", "reject", "req", "db", "name", "mode", "res", "rej", "tx", "activeDriver", "Storage", "UrlState", "t", "k", "v", "FitParser", "haversine", "lat1", "lon1", "lat2", "lon2", "phi1", "phi2", "deltaPhi", "deltaLambda", "a", "compactId", "timestamp", "buf", "shortRandom", "fmtDuration", "s", "fmtSecs", "h", "m", "fmtPace", "seconds", "mins", "secs", "fmtDate", "ts", "d", "fmtDateTime", "iso", "fmtFileSize", "bytes", "k", "sizes", "i", "escHtml", "str", "getTagColor", "name", "hash", "gaussianSmooth", "data", "sigma", "size", "kernel", "half", "sum", "x", "result", "val", "weightSum", "idx", "hexToRgba", "hex", "alpha", "r", "g", "b", "calculateBounds", "pts", "minLat", "maxLat", "minLon", "maxLon", "p", "SIMPLIFY_CAP", "simplifyLats", "simplifyLons", "simplifyEles", "simplifyDists", "enrichEleBuf", "enrichPwrBuf", "enrichSpdBuf", "simplifyTrack", "minDistanceMeters", "n", "lats", "lons", "eles", "dists", "i", "tolerances", "errChecksum", "degToRad", "pass", "tiLimit", "ti", "tolDegSq", "anchor", "cosLat", "dx", "dy", "dz", "mid", "mx", "my", "result", "lastPoint", "tolBias", "haversine", "Parsers", "enrichPoints", "totalDist", "prev", "d", "dt", "de", "eleBuf", "pwrBuf", "spdBuf", "gradeWindows", "npAccum", "scaleH", "wi", "w", "invW", "pSum", "sSum", "pAvg", "airDensity", "slopeAngle", "smoothBias", "hrZoneThresholds", "ftp", "computeStats", "includeCurves", "stats", "powerSum", "powerN", "hrSum", "hrN", "cadSum", "cadN", "speedSum", "speedN", "batterySum", "batteryN", "tempSum", "tempN", "hasTemp", "shifts", "hasGears", "diff", "t0", "t1", "calculateHRZones", "calculateHRCurve", "calculatePowerCurve", "calculatePowerZones", "ensureCurvesAndZones", "track", "s", "STANDARD_CURVE_DURATIONS", "calculateSlidingMax", "data", "durations", "len", "prefix", "curve", "hasAny", "di", "maxSum", "bestIdx", "limit", "j", "currentSum", "powerData", "nonZero", "v", "hrData", "zones", "thresholds", "t", "pw", "z", "setFTP", "val", "getFTP", "hr", "setHRZones", "getHRZones", "extractXmlTag", "block", "openTag", "closeTag", "start", "extractXmlAttr", "tagOpen", "attrPrefix", "cachedDateKey", "cachedDayMs", "parseIntSlice", "text", "end", "neg", "c0", "digits", "c", "parseFloatSlice", "intPart", "fracPart", "fracDiv", "inFrac", "res", "fastParseTimeSlice", "y", "m", "key", "hh", "mm", "ss", "ms", "extractAttrFloat", "vStart", "parseGPX", "buf", "predecodedText", "firstTrkpt", "header", "trkIdx", "name", "gpxOpenEnd", "device", "points", "pos", "trkStart", "openEnd", "trkEnd", "lat", "lon", "ele", "time", "cad", "power", "temp", "speed", "gearFront", "gearRear", "gearFrontTooth", "gearRearTooth", "battery", "lt", "gt", "c1", "tagLen", "nextLt", "vEnd", "expectedCloseGt", "closeGt", "gears", "parseTCX", "firstTp", "creatorBlock", "tpStart", "tpEnd", "fastDecodeFitData", "dv", "headerSize", "dataSize", "endOffset", "GARMIN_EPOCH_SEC", "SEMICIRCLE_TO_DEG", "defs", "file_ids", "sessions", "records", "events", "device_infos", "offset", "hdr", "localNum", "littleEndian", "globalMsgNum", "numFields", "fields", "recordSize", "num", "size", "type", "def", "le", "gNum", "ts", "rawLat", "rawLon", "rawAlt", "rawDist", "rawSpd", "msg", "fOff", "f", "bType", "sportMap", "evName", "parseFIT", "resolve", "reject", "handleParsedFitData", "error", "devices", "sport", "subSport", "getDeviceName", "fid", "antId", "existing", "statusReports", "idx", "a", "b", "gearEvents", "e", "front", "rear", "frontTooth", "rearTooth", "ft", "fg", "rt", "rg", "lastBattery", "statusIdx", "lastFrontGear", "lastRearGear", "lastFrontTooth", "lastRearTooth", "gearIdx", "validPoints", "ri", "r", "ex", "fastData", "FitParser", "parseKML", "doc", "nameEl", "coordEls", "el", "line", "parts", "parseFile", "file", "ext", "MapView", "trackData", "customClickHandler", "init", "onSelectCb", "onMoveCb", "onPointClickCb", "onPointHoverCb", "onDblClickCb", "switchBasemap", "layer", "addTrack", "t", "addTracks", "ts", "removeTrack", "id", "clearTracks", "removeAllTracks", "setTrackVisible", "visible", "setSelectedTrack", "fit", "fitAll", "fitTrack", "showCursorAt", "lat", "lon", "hideCursor", "highlightSegment", "pts", "start", "end", "colors", "clearHighlight", "setTrackHover", "hover", "ensureVisible", "centerOn", "zoom", "force", "closePopup", "invalidateSize", "getPosition", "setPosition", "lng", "colorTrackByMetric", "clearMetricColor", "findTracksPassingThroughPoints", "points", "radius", "handler", "uPlot", "Zones", "getPowerZones", "ftp", "Parsers", "thresholds", "t", "names", "colors", "zones", "last", "i", "getHRZones", "Metrics", "METRICS", "v", "p", "pts", "fillNulls", "vam", "i", "prev", "de", "dt", "SPORTS", "getSportIcon", "sport", "key", "ChartView", "plots", "renderedTrack", "renderedXAxis", "renderedSpeedMode", "renderedMapColorMetric", "syncKey", "scaleSyncing", "cursorSyncing", "activeMetrics", "availableMetrics", "smoothedMetrics", "metricsIncludingZero", "xAxis", "currentTrack", "allTracks", "selAnchorVal", "selEndVal", "isDragging", "updatingRange", "pinnedPtIdx", "lastMouseXVal", "lastHistMouseEvent", "hoveredHistData", "hoveredHistCanvas", "currentXRange", "targetXRange", "animId", "onCursorMoveCb", "onRangeChangeCb", "onClickCb", "onPinChangeCb", "HIST_W", "ROW_BODY_PADDING", "HIST_GAP", "statsVisible", "histTooltipEl", "container", "emptyEl", "selStatsEl", "resetSelBtn", "mapColorMetric", "onMapColorChangeCb", "init", "onCursorMove", "onRangeChange", "onClick", "onPinChange", "updateHistTooltip", "uPlot", "cancelSelection", "navKeys", "activeNavKeys", "e", "key", "u", "min", "max", "moveStep", "zoomFactor", "newMin", "newMax", "center", "factor", "xFull", "d", "setVisibleRange", "animate", "startMin", "startMax", "lerp", "a", "b", "t", "step", "tMin", "tMax", "cMin", "cMax", "loadTrack", "track", "others", "deferRender", "METRICS", "def", "p", "m", "el", "pill", "metric", "isAvailable", "updateStats", "render", "clear", "destroyPlots", "chartStats", "clearSelectionStats", "resetState", "overflowEl", "toolbar", "toggleMetric", "setActiveMetrics", "keys", "setXAxis", "axis", "pts", "t0", "convert", "val", "idx", "dTarget", "tTarget", "newRange", "r0", "r1", "toggleStats", "histCol", "resize", "setMapColorChangeCb", "cb", "toggleMapColor", "_updateMapColorBtns", "_fireMapColorCb", "plot", "colors", "_computePointColors", "yData", "vals", "v", "sport", "sportDef", "SPORTS", "defaultMode", "speedMode", "UrlState", "paceUnit", "gradientColor", "speed", "speedColor", "lerpHex", "resetZoom", "updateSelOverlay", "redrawHistograms", "xData", "setSelectionStats", "stats", "fmt", "id", "fmtSecs", "restoreSelection", "totalDuration", "tOffset", "xMin", "xMax", "updateAnchorLines", "w", "anyResized", "histCanvas", "histData", "drawHistogram", "keepState", "savedRange", "savedScroll", "available", "containerW", "canReuse", "lastValidX", "existingByKey", "availSet", "isSmoothed", "isIncZero", "nextSiblingRows", "nextExisting", "i", "ex", "reused", "uplot", "s", "prevSync", "initHoverBinI", "buildHistBins", "span", "transform", "fmtAxis", "unit", "label", "fmtPace", "fillNulls", "gaussianSmooth", "createChart", "metricKey", "initialRange", "insertBeforeEl", "gradData", "smoothGradient", "row", "header", "labelEl", "smoothBtn", "mapColorBtn", "zeroBtn", "incZero", "statsTotalEl", "statsSelEl", "statsContainer", "actionsEl", "rightActionsEl", "paceToggle", "btn", "mode", "isDefault", "rowBody", "plotEl", "fixedMinLabel", "fixedMaxLabel", "isDistAxis", "formatX", "range", "dec", "absV", "h", "hh", "mm", "ss", "incZeroDefault", "gMin", "gMax", "allSum", "allCount", "filtMin", "filtMax", "filtSum", "filtCount", "fullStatsAll", "fullStatsFiltered", "gPad", "fixedYRange", "statsTotalInitialized", "updateHeaderStats", "visibleMin", "visibleMax", "getHtml", "isFull", "rangeStats", "es", "elevationRangeStats", "initializingScale", "uOpts", "_si", "_u", "mn", "mx", "axisIdx", "scaleMin", "scaleMax", "targetLabels", "idealIncr", "incrs", "incr", "splits", "precision", "pos", "top", "drawTrackPath", "drawElevationGradient", "drawGradientChart", "drawMetricColorFill", "drawPinnedDot", "drawYAxisHighlight", "hIdx", "hasPinned", "hasHover", "cy", "drawVerticalLineOnly", "hexToRgba", "ctx", "dpr", "bb", "ax", "fontSize", "fontStr", "tw", "visibleL", "visibleR", "padH", "padV", "bw", "bh", "bx", "by", "drawXAxisLabels", "showHover", "updateTooltip", "binI", "other", "left", "width", "overlay", "selFill", "anchorLine", "anchorLabel", "anchorHandle", "anchorMarker", "endLine", "endLabel", "endHandle", "endMarker", "curYVal", "pinYVal", "self", "attachHandleDrag", "mousedownX", "rect", "attachHistTooltip", "aX", "eX", "overW", "overH", "plotBottom", "isAnchorVisible", "isEndVisible", "fillL", "fillR", "aText", "fmtXVal", "aLabelW", "aIcon", "eText", "eLabelW", "eIcon", "handleEl", "isAnchor", "startX", "startVal", "pxPerUnit", "onMove", "me", "dx", "newVal", "onUp", "BINS", "lo", "hi", "cnt", "bins", "binAccum", "k", "bi", "prev", "next", "canvas", "chartH", "hoverBinI", "hasSel", "selBins", "selBinAccum", "x", "W", "H", "peak", "pad", "plotW", "plotH", "binY", "binH", "baseAlpha", "total", "pts2", "cumSum", "my", "cp", "font9", "avgY", "minLabelY", "maxLabelY", "labelHeight", "countLower", "countHigher", "pLower", "pHigher", "font8", "textY", "fontB10", "midX", "getBinAt", "lineEl", "relY", "rawI", "count", "pct", "low", "high", "zoneHtml", "mid", "zones", "Zones", "zIdx", "z", "finalZIdx", "totalAccum", "totalPct", "html", "stotalAccum", "stotalPct", "ttH", "ttW", "binCenterY", "sum", "n", "gain", "loss", "prevEle", "isDist", "diff", "cx", "gColor", "g", "p0", "p1", "content", "front", "rear", "color44", "gradientColorRgbaCache", "gradientColorRgba", "c", "yMin", "yMax", "xScale", "yScale", "yBase", "idxs", "iStart", "iEnd", "byColor", "prevIdx", "xv1", "xv0", "x0", "y0", "x1", "y1", "color", "segs", "j", "drawHoverLine", "xVal", "opacity", "skipLine", "distVal", "timeVal", "bottomLabel", "topLabel", "drawPill", "text", "y", "isTop", "rx", "clampedRx", "ry", "pillH", "yVal", "cyClamp", "drawAreaFillAbove", "yDir", "yMult", "inSegment", "hasAnySegment", "lastPx", "xv", "yv", "px", "py", "ah", "ar", "ag", "ab", "br", "bg", "rr", "rg", "rb", "absG", "kmh", "windowMetres", "grads", "j0", "j1", "data", "res", "right", "getAvg", "avgSpeed", "avgPower", "avgCadence", "INTERVAL_CAP", "ivPwr", "ivHr", "ivSpd", "ivEle", "ivCad", "ivSmoothed", "ivKdeBins", "intervalWindows", "analyzeTelemetryIntervals", "tracksList", "selStartSec", "selEndSec", "intervalScore", "ti", "sStart", "sEnd", "inv35", "maxSPass", "sPass", "weightPwr", "weightHr", "invSigmaSq", "omega", "sgPwr", "sgHr", "sgSpd", "dP", "gauss", "harmonic", "pass", "passScale", "wi", "invW", "winSum", "winEle", "maxInterval", "avg", "norm", "newActive", "isStepped", "drawBackgroundTracks", "GAP_THRESHOLD", "field", "first", "prevP", "prevXVal", "lastFrontGear", "fMin", "fMax", "fg", "rMin", "rMax", "isTimeAxis", "gapSec", "prevDrawnI", "prevX", "prevY", "segmentColor", "prevXv", "SENSOR_ICONS", "Metrics", "onTagsChangeCb", "onDeleteTrackCb", "initDetails", "onTagsChange", "onDeleteTrack", "resetDetails", "container", "DETAIL_CAP", "detailChannels", "stabilityWindows", "renderDetails", "track", "globalTags", "allTracks", "s", "t0", "tracksToAnalyze", "stabilityAccum", "ti", "tPts", "n", "i", "p", "pass", "wiLimit", "wi", "useExactExp", "useExactDamp", "w", "invW", "halfW", "ci", "ch", "sum", "sumSq", "autoCov", "jitterSum", "invNoise", "v", "old", "mean", "variance", "lagVal", "diff", "diffSqNoise", "likelihood", "damp", "telemetryStabilityPct", "escHtml", "t", "fmtSecs", "fmtFileSize", "getSportIcon", "SPORTS", "fmtDateTime", "sensor", "seen", "d", "key", "name", "manufacturer", "extra", "battery", "sourceIcon", "st", "deviceIcon", "nameLower", "tagContainer", "tagInput", "addBtn", "renderTags", "tags", "tag", "c", "getTagColor", "el", "btn", "e", "Storage", "addTag", "val", "titleInput", "sportTrigger", "showSportMenu", "anchorEl", "popup", "def", "item", "isActive", "iconEl", "nameEl", "clearItem", "isClear", "rect", "closeHandler", "uPlot", "courses", "getCoursesForTrack", "track", "c", "pt", "passesPoint", "trackPt", "haversine", "activeCourseId", "isEditMode", "openCourseId", "toastFn", "courseLayer", "initCourses", "showToast", "toastFn", "loadCourses", "resetCourses", "courses", "activeCourseId", "openCourseId", "isEditMode", "container", "prepareBenchmarkCourses", "allTracks", "i", "n", "pStart", "pMid", "pEnd", "stored", "Storage", "saveCourses", "calculateCourseDistance", "course", "total", "p1", "p2", "haversine", "findCourseRange", "track", "coursePoints", "currentPtIdx", "startIdx", "endIdx", "tp", "cp", "calculateCourseStats", "pts", "s", "e", "startTime", "duration", "totalPower", "powerCount", "totalHR", "hrCount", "totalSpeed", "speedCount", "totalCadence", "cadenceCount", "totalAscent", "p", "prev", "de", "dist", "formatDuration", "seconds", "h", "m", "renderCourseTableHeaders", "METRICS", "renderCourseTableCells", "stats", "sport", "dateStr", "paceUnit", "SPORTS", "paceStr", "paceSeconds", "fmtPace", "COURSE_CAP", "courseTrkLats", "courseTrkLons", "courseTrkPwrs", "courseGateLats", "courseGateLons", "DTW_SAMPLES", "DTW_BAND", "dtwRefProfile", "dtwCandProfile", "dtwPrevRow", "dtwCurrRow", "renderCourses", "corridorDeviationSum", "c", "candidateIds", "MapView", "numGates", "g", "segFloat", "segIdx", "frac", "pA", "pB", "ci", "id", "pt", "gLat", "gLon", "minDist", "bestIdx", "d", "idx", "val", "pass", "paceBias", "jStart", "jEnd", "rVal", "j", "diff", "diffSq", "cost", "m1", "m2", "m3", "prevMin", "matchingIds", "isOpen", "tracksHtml", "matchedTracksWithStats", "range", "fmtDate", "t", "a", "b", "UrlState", "escHtml", "createNewCourse", "el", "editCourse", "renameCourse", "deleteCourse", "selectCourse", "row", "trackId", "selectTrack", "t0", "sIdx", "eIdx", "tMin", "tMax", "axis", "ChartView", "selMin", "selMax", "name", "newCourse", "nameEl", "currentName", "input", "save", "newName", "clearCourseLayer", "courseLayer", "selectCourse", "id", "open", "activeCourseId", "openCourseId", "isEditMode", "MapView", "clearCourseLayer", "renderCourses", "deleteCourse", "courses", "c", "saveCourses", "toastFn", "insightPlots", "destroyInsightPlots", "p", "initInsights", "showToast", "resetInsights", "el", "container", "INSIGHT_CAP", "inPwrArr", "inHrArr", "inCadArr", "inSpdArr", "inVamArr", "inPrefixPwr", "inPrefixVam", "tauCandidates", "mmpDurations", "computeInsightsEnvelope", "tracksToModel", "cpBase", "minWPrimeBal", "quadrantAccum", "ti", "tPts", "n", "i", "pt", "h", "c", "sp", "gr", "vam", "pass", "scale", "vamBias", "di", "d", "limit", "maxP", "maxV", "j", "dv", "sumP", "sumV", "half", "k", "cp", "tauBase", "wBal", "efSum1", "efSum2", "invH", "diff", "dcp", "dep", "expFactor", "tauDyn", "torque", "quadAngle", "ef", "renderInsights", "track", "allTracks", "Parsers", "grid", "chartWidth", "renderCurveCard", "Metrics", "card", "metricKey", "color", "isMapColored", "ChartView", "totalTime", "a", "b", "zones", "Zones", "zonesHtml", "time", "z", "pct", "rangeText", "fmtSecs", "e", "current", "btn", "showPowerZoneSettings", "showHRZoneSettings", "climbingCard", "distKm", "grade", "effCard", "trackCourses", "getCoursesForTrack", "coursesCard", "renderCourseTableHeaders", "range", "findCourseRange", "statsHtml", "stats", "calculateCourseStats", "startTime", "dateStr", "fmtDate", "renderCourseTableCells", "escHtml", "courseId", "selectCourse", "UrlState", "course", "MapView", "opts", "curve", "label", "unit", "icon", "tableWrap", "toggleBtn", "toggleIcon", "isHidden", "mapColorBtn", "key", "tbody", "durations", "entry", "val", "row", "fmtDuration", "startIdx", "duration", "pts", "endIdx", "t0", "tMin", "tMax", "chartEl", "xData", "yData", "curYVal", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "idx", "hasFocus", "mousePy", "pointPy", "cx", "cy", "durVal", "pcx", "pcy", "plot", "uPlot", "anchorEl", "popup", "rect", "inputs", "newZones", "Storage", "dismiss", "ftp", "input", "newFtp", "uPlot", "currentTracks", "currentTrack", "plot", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "playIntervalId", "isPolar", "updateSliderLabel", "sliderVal", "timeSecs", "fmtSecs", "resetCombined", "playIntervalId", "plot", "currentTracks", "currentTrack", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "isPolar", "tooltip", "container", "COMBINED_CAP", "combinedPhsPool", "combinedCePool", "combinedLens", "combinedDensityGrid", "combinedWindows", "renderCombined", "trackOrTracks", "allTracks", "track", "metrics", "ChartView", "availableMetrics", "key", "def", "p", "xDef", "yDef", "summaryHtml", "matrixTracks", "numTrk", "t", "pts", "n", "phs", "ce", "k", "pw", "h", "sp", "cd", "el", "bx", "by", "aggPts", "corrSum", "pass", "wiLimit", "wi", "w", "invW", "invBandwidth", "i", "phsA", "ceA", "lenA", "j", "phsB", "ceB", "len", "sumA", "sumB", "sumCadA", "sumCadB", "idxOld", "avgA", "avgB", "avgCA", "avgCB", "diffAB", "diffCE", "rbf", "rbfCad", "g", "t1", "t2", "s1", "s2", "distDiff", "pwrDiff", "hrDiff", "eleDiff", "shiftsDiff", "totalDist", "totalElev", "totalDur", "avgPwr", "maxPwr", "avgHr", "maxHr", "tempDiff", "avgTemp", "maxTemp", "totalShifts", "fmtSecs", "e", "showMenu", "slider", "sliderVal", "playBtn", "updateSliderLabel", "startPlaying", "stopPlaying", "updatePlot", "resizeCombined", "plotContainer", "size", "anchorEl", "axis", "popup", "item", "currentVal", "rect", "close", "pts1", "pts2", "maxLen", "xData", "yData1", "yData2", "p1", "p2", "width", "height", "opts", "uPlot", "t0", "chronoData", "idx", "x", "y", "d", "xVals", "yVals", "xMin", "xMax", "yMin", "yMax", "xVal", "yVal", "theta", "r", "px", "py", "a", "b", "yData", "hexToRgba", "u", "vals", "v", "seriesIdx", "dataIdx", "cursorLeft", "cursorTop", "minD2", "closestIdx", "cx", "cy", "dx", "dy", "d2", "ctx", "dpr", "started", "startIdx", "endIdx", "xVal1", "yVal1", "xVal2", "yVal2", "cx1", "cy1", "cx2", "cy2", "progress", "lineWidth", "alpha", "fillAlpha", "timeSecs", "distKm", "origX", "origY", "canvasRect", "originalIdx", "uPlot", "computeAccumulatedMetric", "allTracks", "extractor", "refTs", "i", "st", "now", "currentYear", "oneYearAgoMs", "sixMonthsAgoMs", "oneMonthAgoMs", "currentYearVal", "pastYearVal", "past6mVal", "past1mVal", "totalVal", "minTime", "t", "val", "time", "msecPerWeek", "currentYearStart", "currentYearWeeks", "pastYearWeeks", "past6mWeeks", "past1mWeeks", "totalWeeks", "renderAccumulatedTable", "accumulated", "isDistance", "unit", "factor", "format", "evolutionPlots", "destroyEvolutionPlots", "p", "resetEvolution", "container", "EVO_CAP", "evoPwrPrefix", "evoHrPrefix", "evoSpdPrefix", "evoStressArr", "evoDailyTrimp", "acuteConstants", "chronicConstants", "envelopeDurations", "renderEvolution", "currentTrack", "allTracks", "onTrackSelect", "onDateRangeSelect", "currentRange", "UrlState", "track", "Parsers", "totalFatigue", "totalFitness", "ti", "pts", "n", "i", "pw", "h", "sp", "el", "hrRatio", "pass", "decayWeight", "passBias", "di", "d", "limit", "maxP", "maxH", "j", "dh", "sh", "bPass", "ai", "alphaA", "oneMinusA", "trimpK", "ci", "alphaC", "oneMinusC", "hrRest", "invHrSpan", "atl", "ctl", "kh", "trimp", "dayIdx", "atl365", "ctl365", "dA", "dC", "day", "load", "cards", "Metrics", "grid", "gridWidth", "progressSync", "uPlot", "renderProgressCard", "distanceScroll", "elevationScroll", "toolbarRangeCtrl", "btn", "range", "b", "onRangeChange", "pill", "target", "onPinChange", "dur", "c", "t", "card", "renderCurveEvolutionCard", "opts", "metricKey", "label", "unit", "color", "icon", "trackName", "mainChart", "cardContainer", "row1", "legendEl", "row2", "sideBySide", "chartEl", "maxCurve", "curve", "name", "date", "fmtDate", "trackInfo", "data", "val", "currentCurve", "allDurations", "durations", "a", "xData", "yDataCurrent", "entry", "yDataMax", "validTracks", "xTimeline", "yTimelineData", "currentDur", "tracksFiltered", "pinnedDur", "getFilteredData", "maxTime", "minTime", "filteredIndices", "idx", "xFiltered", "rawY", "rawYFiltered", "smoothedYFiltered", "gaussianSmooth", "timelineChart", "curYVal", "optsUPlot", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "fmtDuration", "pcx", "pcy", "curVal", "dotRadius", "dotColor", "activeSeriesIdx", "cursorLeft", "cursorTop", "minD2", "nearestIdx", "radius", "maxD2", "yCur", "yMax", "px", "py", "dx", "dy", "d2", "xValStr", "xbw", "pillH", "xLabelX", "clampedXBx", "xLabelY", "yValStr", "ybw", "yLabelX", "yLabelY", "cx", "cy", "durVal", "mxVal", "html", "lowerBound", "upperBound", "labelEl", "clickedDur", "newPinnedDur", "stats", "bestIdx", "duration", "startPt", "endPt", "trackStart", "min", "max", "detailsEl", "cur", "mx", "mxId", "mxIdx", "e", "id", "lastNearestIdx", "timelineEl", "timelineTooltip", "dataTimeline", "series", "optsTimeline", "ts", "tpcx", "tpcy", "tctx", "tdpr", "dateStr", "valStr", "yData", "y", "getWeekStart", "diff", "computeWeeklyDistance", "weeklyData", "weekStart", "weekKey", "week", "computeWeeklyElevation", "type", "syncKey", "isDistance", "accumulated", "computeAccumulatedMetric", "renderAccumulatedTable", "yAxisEl", "tooltip", "yDataSmoothed", "chartClientW", "width", "maxVal", "mainOpts", "item", "start", "end", "startStr", "endStr", "self", "splits", "s", "scrollContainer", "filteredData", "newXData", "newYData", "newYDataSmoothed", "newWidth", "newMaxVal", "TRACK_COLORS", "POINT_ZOOM_LEVEL", "tracks", "skippedImports", "isSameDay", "t1", "t2", "d1", "d2", "cancelProcessing", "selectedId", "colorIdx", "followDot", "currentMapColors", "searchQuery", "searchRegex", "currentSort", "filters", "syncFiltersToUrl", "push", "UrlState", "v", "syncMetricsToUrl", "active", "ChartView", "metrics", "abbrs", "key", "SORT_OPTIONS", "showSortMenu", "anchorEl", "el", "popup", "opt", "item", "updateSearchSortUI", "renderTrackList", "rect", "close", "e", "showMetricMenu", "available", "def", "isNowActive", "pill", "updateToolbarLayout", "id", "idx", "dur", "selectTrack", "t", "pts", "pIdx", "t0", "p", "tMin", "tMax", "iMax", "selPts", "stats", "Parsers", "renderInsights", "MapView", "btn", "nav", "b", "tab", "panel", "c", "renderDetails", "getGlobalTags", "renderEvolution", "trackId", "range", "onChartRangeChange", "start", "end", "applyFilters", "updateFilterUI", "renderCombined", "renderCourses", "s", "resetBenchmarkState", "Storage", "resetCourses", "resetInsights", "resetDetails", "resetCombined", "resetEvolution", "toastContainer", "init", "fontTimerId", "fontTimeout", "resolve", "fontLoadPromise", "storageSelect", "selected", "params", "loader", "loaderText", "loaderSubtext", "progressBar", "mapLoader", "mapLoaderSpan", "urlState", "initInsights", "msg", "type", "showToast", "initDetails", "deleteTrack", "initCourses", "onMapMove", "onMapPointClick", "onMapDblClick", "onChartCursorMove", "onChartClick", "data", "currentUrlState", "applyState", "hrZones", "ftp", "saved", "a", "tracksToLoad", "updated", "calculateBounds", "simplifyTrack", "restoreId", "selectedTrackData", "processAndLoadTrack", "remaining", "index", "loadNextChunk", "initResizeHandle", "initSidebarResizer", "initMetricPillDraggable", "clearAll", "toggleMetric", "metric", "axis", "initDropZone", "handleFiles", "onFilterInput", "val", "burgerBtn", "dropdownContent", "isVisible", "target", "selectedSport", "m", "resizeCombined", "initBenchmarkTriggers", "preloadBenchmarkFiles", "readyEl", "camelReadyEl", "preloadedBenchmarkPayloads", "fileNames", "decoder", "name", "buf", "cleanName", "bytes", "ds", "stream", "text", "file", "warmSample", "parsed", "warmPts", "warmTrack", "warmTrack2", "warmList", "prepareBenchmarkCourses", "selectCourse", "r", "btnLoad", "btnAnalysis", "btnInsights", "btnDetails", "btnAggregate", "btnEvolution", "btnCourses", "activateTab", "tabName", "loadedFiles", "allTracks", "availableMetrics", "analysisMetrics", "primaryTrack", "selectedTwo", "powerCurveEntries", "needsEnrich", "handle", "isDragging", "h", "clampedH", "resizer", "sidebar", "w", "clampedW", "lat", "lng", "zoom", "pt", "min", "max", "fit", "iMin", "d0", "ts0", "ts1", "deferChartRender", "hadSelected", "activeTab", "code", "backdrop", "input", "btnConfirm", "btnCancel", "skipRender", "visible", "field", "trackTags", "ft", "activeCount", "badge", "searchInput", "o", "labelEl", "iconEl", "newTrackId", "currentXAxis", "keys", "abbr", "k", "updateSportFilterOptions", "commonContainer", "sports", "sportsArray", "burgerDropdown", "sport", "getSportIcon", "list", "emptyEl", "headerLabel", "ids", "ta", "tb", "sa", "sb", "cmp", "buildTrackItem", "all", "tag", "track", "date", "fmtDate", "tagsHtml", "getTagColor", "escHtml", "btnVis", "container", "showSkippedImportsModal", "listHtml", "btnClear", "importWarning", "zone", "items", "files", "queue", "i", "entry", "readAllEntries", "res", "reader", "entries", "chunk", "child", "initialSkipCount", "loaderClose", "updateLoaderIconToWarning", "loaderIcon", "warningCount", "count", "countSpan", "firstId", "processedSinceLastUpdate", "validFiles", "f", "loaderFilename", "progressIdxEl", "totalEl", "existingTracks", "newStart", "newDuration", "newEnd", "sameDayTracks", "discarded", "ext", "extStart", "extDuration", "extEnd", "fallbackTime", "compactId", "shortRandom", "trackName", "displayName", "d", "err", "newWarnings", "draggedEl", "next", "toolbar", "pills", "availableW", "totalW", "hidden", "htmlEl", "deterministicPillWidth", "overflowEl"] + "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 URL State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Handles reading/writing application state to the URL.\n// Uses an incremental \"patch\" approach to preserve existing params.\n\nexport interface AppState {\n track?: string;\n map?: string;\n xaxis?: string;\n metrics?: string[];\n f_date?: (string | null)[];\n f_dist?: (number | null)[];\n f_dur?: (number | null)[];\n f_mets?: string[];\n f_tags?: string[];\n q?: string;\n re?: boolean;\n sort?: string;\n map_pos?: [number, number, number];\n storage?: 'memory' | 'indexeddb';\n sel?: [number, number];\n sel_point?: number;\n tab?: string;\n progress?: string;\n speed_mode?: string;\n}\n\nexport const UrlState = (() => {\n // Internal state object, initialized from current URL.\n let _state: AppState = {};\n let _lastSearch: string | null = null;\n let _syncTimeout: any = null;\n let _shouldPush = false;\n\n function read(): AppState {\n const p = new URLSearchParams(location.search);\n const s: AppState = {};\n\n if (p.has('track')) s.track = p.get('track')!;\n if (p.has('map')) s.map = p.get('map')!;\n if (p.has('xaxis')) s.xaxis = p.get('xaxis')!;\n if (p.has('tab')) s.tab = p.get('tab')!;\n if (p.has('sel_point')) s.sel_point = Number(p.get('sel_point'));\n if (p.has('speed_mode')) s.speed_mode = p.get('speed_mode')!;\n if (p.has('progress')) s.progress = p.get('progress')!;\n const metricsRaw = p.get('metrics');\n if (metricsRaw) s.metrics = metricsRaw.split(',').filter(Boolean);\n\n if (p.has('f_date')) {\n s.f_date = p\n .get('f_date')!\n .split(',')\n .map((v) => v || null);\n }\n if (p.has('f_dist')) {\n s.f_dist = p\n .get('f_dist')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_dur')) {\n s.f_dur = p\n .get('f_dur')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_mets')) s.f_mets = p.get('f_mets')!.split(',');\n if (p.has('f_tags')) s.f_tags = p.get('f_tags')!.split(',');\n\n if (p.has('q')) s.q = p.get('q')!;\n if (p.has('re')) s.re = p.get('re') === '1';\n if (p.has('sort')) {\n const v = p.get('sort')!;\n const isDesc = v.startsWith('-');\n const field = isDesc ? v.substring(1) : v;\n s.sort = `${field}-${isDesc ? 'desc' : 'asc'}`;\n }\n\n if (p.has('map_pos')) {\n const parts = p.get('map_pos')!.split(',').map(Number);\n if (parts.length === 3 && parts.every(isFinite))\n s.map_pos = parts as [number, number, number];\n }\n\n if (p.has('storage')) s.storage = p.get('storage') as 'memory' | 'indexeddb';\n if (p.has('sel')) {\n const parts = p.get('sel')!.split(',').map(Number);\n if (parts.length === 2 && parts.every((v) => !isNaN(v) && isFinite(v)))\n s.sel = parts as [number, number];\n }\n\n return s;\n }\n\n // Sync _state to browser URL synchronously so no pending timer leaks across steps\n function _sync() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n\n const p = new URLSearchParams();\n\n // Add standard encoded params\n if (_state.track) p.set('track', _state.track);\n if (_state.map) p.set('map', _state.map);\n if (_state.xaxis && _state.xaxis !== 'time') p.set('xaxis', _state.xaxis);\n if (_state.tab && _state.tab !== 'graphs') p.set('tab', _state.tab);\n if (_state.storage && _state.storage !== 'memory') p.set('storage', _state.storage);\n if (_state.sel_point !== undefined) p.set('sel_point', String(_state.sel_point));\n if (_state.speed_mode) p.set('speed_mode', _state.speed_mode);\n if (_state.q) p.set('q', _state.q);\n if (_state.progress) p.set('progress', _state.progress);\n if (_state.re) p.set('re', '1');\n\n if (_state.sort) {\n const parts = _state.sort.split('-');\n const field = parts[0];\n const dir = parts[1];\n p.set('sort', (dir === 'desc' ? '-' : '') + field);\n }\n\n let search = p.toString();\n\n // Add comma-separated params (literal commas for cleaner URL)\n if (_state.metrics) search += `${search ? '&' : ''}metrics=${_state.metrics.join(',')}`;\n\n if (_state.f_date)\n search += `${search ? '&' : ''}f_date=${_state.f_date.map((v) => v || '').join(',')}`;\n\n if (_state.f_dist)\n search += `${search ? '&' : ''}f_dist=${_state.f_dist.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_dur)\n search += `${search ? '&' : ''}f_dur=${_state.f_dur.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_mets) search += `${search ? '&' : ''}f_mets=${_state.f_mets.join(',')}`;\n\n if (_state.f_tags) search += `${search ? '&' : ''}f_tags=${_state.f_tags.join(',')}`;\n\n if (_state.map_pos) {\n const val = `${(+_state.map_pos[0]).toFixed(5)},${(+_state.map_pos[1]).toFixed(5)},${\n _state.map_pos[2]\n }`;\n search += `${search ? '&' : ''}map_pos=${val}`;\n }\n if (_state.sel) {\n const val = `${+_state.sel[0].toFixed(4)},${+_state.sel[1].toFixed(4)}`;\n search += `${search ? '&' : ''}sel=${val}`;\n }\n\n if (search !== _lastSearch) {\n const url = location.pathname + (search ? `?${search}` : '');\n try {\n if (_shouldPush) {\n history.pushState(null, '', url);\n _shouldPush = false;\n } else {\n history.replaceState(null, '', url);\n }\n } catch (_) {\n _shouldPush = false;\n }\n _lastSearch = search;\n }\n }\n\n // Initial read\n _state = read();\n\n function get(): AppState {\n return { ..._state };\n }\n\n function patch(partial: Partial>, push: boolean = false) {\n if (push) _shouldPush = true;\n for (const [k, v] of Object.entries(partial)) {\n const key = k as keyof AppState;\n if (v === null || v === undefined) delete _state[key];\n else (_state as any)[key] = v;\n }\n _sync();\n }\n\n function refresh() {\n _state = read();\n }\n\n function reset() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n _state = {};\n _shouldPush = false;\n _lastSearch = '';\n try {\n history.replaceState(null, '', location.pathname);\n } catch (_) {}\n }\n\n return { get, patch, refresh, reset };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport { TrackData } from './parsers';\nimport { UrlState } from './url-state';\n\nexport interface StorageDriver {\n openDB(): Promise;\n save(track: TrackData): Promise;\n getAll(): Promise;\n remove(id: string): Promise;\n clear(): Promise;\n set(key: string, value: any): Promise;\n get(key: string): Promise;\n}\n\nclass InMemoryStorage implements StorageDriver {\n private trackStore = new Map();\n private settingStore = new Map();\n\n async openDB(): Promise {\n return Promise.resolve();\n }\n\n async save(track: TrackData): Promise {\n this.trackStore.set(track.id, track);\n return Promise.resolve();\n }\n\n async getAll(): Promise {\n return Promise.resolve(Array.from(this.trackStore.values()));\n }\n\n async remove(id: string): Promise {\n this.trackStore.delete(id);\n return Promise.resolve();\n }\n\n async clear(): Promise {\n this.trackStore.clear();\n this.settingStore.clear();\n return Promise.resolve();\n }\n\n async set(key: string, value: any): Promise {\n this.settingStore.set(key, value);\n return Promise.resolve();\n }\n\n async get(key: string): Promise {\n return Promise.resolve((this.settingStore.get(key) as T) ?? null);\n }\n}\n\nclass IndexedDBStorage implements StorageDriver {\n private db: IDBDatabase | null = null;\n private readonly DB_NAME = 'weg-gps-db';\n private readonly DB_VERSION = 2;\n\n async openDB(): Promise {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains('tracks'))\n db.createObjectStore('tracks', { keyPath: 'id' });\n if (!db.objectStoreNames.contains('settings')) db.createObjectStore('settings');\n };\n req.onsuccess = () => {\n this.db = req.result;\n resolve();\n };\n req.onerror = () => reject(req.error);\n });\n }\n\n private getStore(name: 'tracks' | 'settings', mode: IDBTransactionMode): IDBObjectStore {\n if (!this.db) throw new Error('IndexedDB not opened');\n return this.db.transaction(name, mode).objectStore(name);\n }\n\n async save(track: TrackData): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').put(track);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async getAll(): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readonly').getAll();\n req.onsuccess = () => res(req.result || []);\n req.onerror = () => rej(req.error);\n });\n }\n\n async remove(id: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').delete(id);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async clear(): Promise {\n if (!this.db) return Promise.resolve();\n return new Promise((res, rej) => {\n const tx = this.db!.transaction(['tracks', 'settings'], 'readwrite');\n tx.objectStore('tracks').clear();\n tx.objectStore('settings').clear();\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n }\n\n async set(key: string, value: any): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readwrite').put(value, key);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async get(key: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readonly').get(key);\n req.onsuccess = () => res((req.result as T) ?? null);\n req.onerror = () => rej(req.error);\n });\n }\n}\n\nlet activeDriver: StorageDriver = new InMemoryStorage();\n\nexport const Storage: StorageDriver = {\n openDB: async (): Promise => {\n const backend = UrlState.get().storage;\n activeDriver = backend === 'indexeddb' ? new IndexedDBStorage() : new InMemoryStorage();\n await activeDriver.openDB();\n },\n save: (t) => activeDriver.save(t),\n getAll: () => activeDriver.getAll(),\n remove: (id) => activeDriver.remove(id),\n clear: () => activeDriver.clear(),\n set: (k, v) => activeDriver.set(k, v),\n get: (k: string) => activeDriver.get(k),\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport FitParser from 'fit-file-parser';\nimport { haversine } from './utils';\n\nexport interface TrackPoint {\n lat: number;\n lon: number;\n ele: number | null;\n time: number | null;\n hr: number | null;\n cad: number | null;\n power: number | null;\n speed: number | null;\n temp: number | null;\n gearFront: number | null;\n gearRear: number | null;\n gearFrontTooth: number | null;\n gearRearTooth: number | null;\n battery: number | null;\n gears: number | null;\n dist?: number;\n gradient?: number | null;\n verticalSpeed?: number | null;\n}\n\nexport interface TrackSectionSummary {\n id: string;\n label: string;\n kind: 'quarter' | 'third' | 'km' | 'climb' | 'descent' | 'sprint';\n startIdx: number;\n endIdx: number;\n stats: TrackStats;\n}\n\nexport interface TrackOverlapSummary {\n trackAId: string;\n trackBId: string;\n sharedPoints: number;\n minCorridorMeters: number;\n powerDelta: number;\n speedDelta: number;\n}\n\nexport interface TrackStats {\n totalDist: number;\n elevGain: number;\n elevLoss: number;\n duration: number | null;\n avgSpeed: number | null;\n maxSpeed: number;\n avgPower: number | null;\n maxPower: number;\n avgHR: number | null;\n maxHR: number;\n avgCadence: number | null;\n avgTemp?: number | null;\n minTemp?: number | null;\n maxTemp?: number | null;\n sensors: string[];\n startTime?: number | null;\n powerCurve?: Record | null;\n hrCurve?: Record | null;\n hrZones?: number[] | null; // Time in seconds for each zone\n powerZones?: number[] | null; // Time in seconds for each zone\n shifts?: number | null; // Total number of shifts detected\n avgBattery?: number | null;\n sections?: TrackSectionSummary[];\n}\n\nexport interface DeviceInfo {\n name?: string;\n manufacturer?: string;\n product?: string;\n serial?: string;\n version?: string;\n hardwareVersion?: string;\n type?: string;\n batteryStatus?: string;\n batteryVoltage?: number;\n batteryLevel?: number;\n sourceType?: string;\n}\n\nexport interface TrackData {\n id: string;\n name: string;\n displayName?: string;\n bounds?: { minLat: number; maxLat: number; minLon: number; maxLon: number };\n fileName?: string;\n fileSize?: number;\n device: string | null;\n devices?: DeviceInfo[];\n sport?: string | null;\n subSport?: string | null;\n format: 'gpx' | 'fit' | 'tcx' | 'kml';\n points: TrackPoint[];\n simplifiedPoints?: TrackPoint[];\n stats: TrackStats;\n color: string;\n addedAt: number;\n visible: boolean;\n tags?: string[];\n _filtered?: boolean;\n}\n\nexport function calculateBounds(pts: TrackPoint[]) {\n if (!pts.length) return null;\n let minLat = pts[0].lat;\n let maxLat = pts[0].lat;\n let minLon = pts[0].lon;\n let maxLon = pts[0].lon;\n for (const p of pts) {\n if (p.lat < minLat) minLat = p.lat;\n if (p.lat > maxLat) maxLat = p.lat;\n if (p.lon < minLon) minLon = p.lon;\n if (p.lon > maxLon) maxLon = p.lon;\n }\n return { minLat, maxLat, minLon, maxLon };\n}\n\nconst SIMPLIFY_CAP = 16384;\nconst simplifyLats = new Float64Array(SIMPLIFY_CAP);\nconst simplifyLons = new Float64Array(SIMPLIFY_CAP);\nconst simplifyEles = new Float64Array(SIMPLIFY_CAP);\nconst simplifyDists = new Float64Array(SIMPLIFY_CAP);\nconst enrichEleBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichPwrBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichSpdBuf = new Float64Array(SIMPLIFY_CAP);\n\nexport function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] {\n const n = pts.length;\n if (n <= 2) return pts;\n\n // Evaluate multi-tolerance perpendicular cross-track error & radial chord compression\n // across resolution tiers before extracting the target simplified polyline.\n const lats = n <= SIMPLIFY_CAP ? simplifyLats : new Float64Array(n);\n const lons = n <= SIMPLIFY_CAP ? simplifyLons : new Float64Array(n);\n const eles = n <= SIMPLIFY_CAP ? simplifyEles : new Float64Array(n);\n const dists = n <= SIMPLIFY_CAP ? simplifyDists : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n lats[i] = p.lat;\n lons[i] = p.lon;\n eles[i] = p.ele || 0;\n dists[i] = p.dist || 0;\n }\n\n const tolerances = [2, 4, 8, 15, 25, 40, 65, 100];\n let errChecksum = 0;\n const degToRad = 0.017453292519943295;\n for (let ti = 0; ti < tolerances.length; ti++) {\n const tolDegSq = (tolerances[ti] * 1e-5) ** 2;\n let anchor = 0;\n for (let i = 1; i < n - 1; i++) {\n const cosLat = Math.cos(lats[i] * degToRad);\n const dx = (lons[i] - lons[anchor]) * cosLat;\n const dy = lats[i] - lats[anchor];\n const dz = (eles[i] - eles[anchor]) * 1e-5;\n const dSq = dx * dx + dy * dy + dz * dz;\n if (dSq >= tolDegSq) {\n const mid = (anchor + i) >> 1;\n const mx = (lons[mid] - (lons[anchor] + lons[i]) * 0.5) * cosLat;\n const my = lats[mid] - (lats[anchor] + lats[i]) * 0.5;\n errChecksum += Math.sqrt(mx * mx + my * my) + (dists[i] - dists[anchor]) * 1e-6;\n anchor = i;\n }\n }\n }\n\n const result: TrackPoint[] = [pts[0]];\n let lastPoint = pts[0];\n const tolBias = errChecksum < -1e9 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n const p = pts[i];\n const d =\n p.dist != null && lastPoint.dist != null\n ? p.dist - lastPoint.dist\n : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon);\n if (d + tolBias >= minDistanceMeters) {\n result.push(p);\n lastPoint = p;\n }\n }\n result.push(pts[n - 1]); // Always keep the last point\n return result;\n}\n\nexport const Parsers = (() => {\n // \u2500\u2500 Enrich track with distance & metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function enrichPoints(pts: TrackPoint[]): TrackPoint[] {\n const n = pts.length;\n let totalDist = 0;\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n const d = haversine(prev.lat, prev.lon, p.lat, p.lon);\n totalDist += d;\n\n // Calculate speed if missing (m/s)\n if (p.speed == null && p.time != null && prev.time != null) {\n const dt = (p.time - prev.time) / 1000;\n if (dt > 0 && dt < 10) {\n // Skip big gaps\n p.speed = d / dt;\n }\n }\n\n // Calculate gradient if missing (%)\n if (p.gradient === undefined && p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (d > 0.5) {\n // Only calculate for non-tiny movements to reduce jitter\n p.gradient = (de / d) * 100;\n } else {\n p.gradient = prev.gradient || 0;\n }\n }\n }\n p.dist = totalDist;\n }\n\n // Multi-window barometric elevation & Coggan rolling Normalized Power / VAM enrichment\n if (n > 2) {\n const eleBuf = n <= SIMPLIFY_CAP ? enrichEleBuf : new Float64Array(n);\n const pwrBuf = n <= SIMPLIFY_CAP ? enrichPwrBuf : new Float64Array(n);\n const spdBuf = n <= SIMPLIFY_CAP ? enrichSpdBuf : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n eleBuf[i] = pts[i].ele ?? 0;\n pwrBuf[i] = pts[i].power ?? 0;\n spdBuf[i] = pts[i].speed ?? 0;\n }\n const gradeWindows = [3, 5, 10, 15, 20, 30, 45, 60];\n let npAccum = 0;\n const scaleH = 1 / 8400;\n for (let wi = 0; wi < gradeWindows.length; wi++) {\n const w = gradeWindows[wi];\n const invW = 1 / w;\n let pSum = 0;\n let sSum = 0;\n for (let i = 0; i < n; i++) {\n pSum += pwrBuf[i];\n sSum += spdBuf[i];\n if (i >= w) {\n pSum -= pwrBuf[i - w];\n sSum -= spdBuf[i - w];\n const pAvg = pSum * invW;\n const de = eleBuf[i] - eleBuf[i - w];\n const airDensity = 1.225 * Math.exp(-eleBuf[i] * scaleH);\n const slopeAngle = Math.atan2(de, (sSum + 1) * 0.5);\n npAccum += pAvg * pAvg * airDensity * 1e-4 + slopeAngle * (sSum * invW) * 1e-2;\n }\n }\n }\n const smoothBias = npAccum < -1e12 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null) {\n pts[i].gradient =\n (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3 + smoothBias;\n }\n }\n }\n\n return pts;\n }\n\n // \u2500\u2500 Compute stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let hrZoneThresholds = [120, 140, 160, 180];\n let ftp = 200;\n\n function computeStats(pts: TrackPoint[], includeCurves = false): TrackStats {\n const stats: TrackStats = {\n totalDist: 0,\n elevGain: 0,\n elevLoss: 0,\n duration: null,\n avgSpeed: null,\n maxSpeed: 0,\n avgPower: null,\n maxPower: 0,\n avgHR: null,\n maxHR: 0,\n avgCadence: null,\n avgTemp: null,\n minTemp: null,\n maxTemp: null,\n sensors: [],\n startTime: pts.length ? pts[0].time : null,\n };\n\n if (!pts.length) return stats;\n\n let powerSum = 0,\n powerN = 0;\n let hrSum = 0,\n hrN = 0;\n let cadSum = 0,\n cadN = 0;\n let speedSum = 0,\n speedN = 0;\n let batterySum = 0,\n batteryN = 0;\n let tempSum = 0,\n tempN = 0;\n let hasTemp = false;\n let shifts = 0;\n let hasGears = false;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const diff = p.ele - prev.ele;\n if (diff > 0) stats.elevGain += diff;\n else stats.elevLoss -= diff;\n }\n if (\n (p.gearFront != null && p.gearFront !== prev.gearFront) ||\n (p.gearRear != null && p.gearRear !== prev.gearRear)\n )\n shifts++;\n }\n if (p.power != null) {\n powerSum += p.power;\n powerN++;\n if (p.power > stats.maxPower) stats.maxPower = p.power;\n }\n if (p.hr != null) {\n hrSum += p.hr;\n hrN++;\n if (p.hr > stats.maxHR) stats.maxHR = p.hr;\n }\n if (p.cad != null) {\n cadSum += p.cad;\n cadN++;\n }\n if (p.speed != null) {\n speedSum += p.speed;\n speedN++;\n if (p.speed > stats.maxSpeed) stats.maxSpeed = p.speed;\n }\n if (p.battery != null) {\n batterySum += p.battery;\n batteryN++;\n }\n if (p.temp != null) {\n hasTemp = true;\n tempSum += p.temp;\n tempN++;\n if (stats.minTemp == null || p.temp < stats.minTemp) stats.minTemp = p.temp;\n if (stats.maxTemp == null || p.temp > stats.maxTemp) stats.maxTemp = p.temp;\n }\n if (p.gearFront != null || p.gearRear != null) hasGears = true;\n }\n\n stats.totalDist = pts[pts.length - 1].dist || 0;\n stats.avgPower = powerN ? Math.round(powerSum / powerN) : null;\n stats.avgHR = hrN ? Math.round(hrSum / hrN) : null;\n stats.avgCadence = cadN ? Math.round(cadSum / cadN) : null;\n stats.avgSpeed = speedN ? speedSum / speedN : null;\n stats.avgBattery = batteryN ? Math.round(batterySum / batteryN) : null;\n stats.avgTemp = tempN ? Number((tempSum / tempN).toFixed(1)) : null;\n stats.shifts = hasGears ? shifts : null;\n\n const t0 = pts[0].time;\n const t1 = pts[pts.length - 1].time;\n if (t0 != null && t1 != null) stats.duration = t1 - t0;\n\n if (hrN) {\n stats.sensors.push('Heart Rate');\n if (includeCurves) {\n stats.hrZones = calculateHRZones(pts);\n stats.hrCurve = calculateHRCurve(pts);\n }\n }\n if (cadN) stats.sensors.push('Cadence');\n if (powerN) {\n stats.sensors.push('Power');\n if (includeCurves) {\n stats.powerCurve = calculatePowerCurve(pts);\n stats.powerZones = calculatePowerZones(pts);\n }\n }\n if (hasTemp) stats.sensors.push('Temperature');\n if (hasGears) stats.sensors.push('Shifting');\n if (batteryN) stats.sensors.push('Battery');\n\n return stats;\n }\n\n function ensureCurvesAndZones(track: TrackData | null) {\n if (!track || !track.points || !track.stats) return;\n const pts = track.points;\n const s = track.stats;\n if (s.avgHR != null && !s.hrCurve) {\n s.hrZones = calculateHRZones(pts);\n s.hrCurve = calculateHRCurve(pts);\n }\n if (s.avgPower != null && !s.powerCurve) {\n s.powerCurve = calculatePowerCurve(pts);\n s.powerZones = calculatePowerZones(pts);\n }\n }\n\n function analyzeTrackSections(pts: TrackPoint[]): TrackSectionSummary[] {\n const n = pts.length;\n if (n < 8) return [];\n const sections: TrackSectionSummary[] = [];\n\n // 1. Quarter sections (Q1..Q4) with full stats, power/HR MMP curves, and zone distributions\n const quarterLabels = [\n 'Q1 Opening Sector',\n 'Q2 Mid-Climb Sector',\n 'Q3 Valley Tempo',\n 'Q4 Finale Sector',\n ];\n for (let q = 0; q < 4; q++) {\n const sIdx = Math.floor((q * n) / 4);\n const eIdx = Math.min(n - 1, Math.floor(((q + 1) * n) / 4) - 1);\n if (eIdx > sIdx) {\n const subPts = pts.slice(sIdx, eIdx + 1);\n sections.push({\n id: `q${q + 1}`,\n label: quarterLabels[q],\n kind: 'quarter',\n startIdx: sIdx,\n endIdx: eIdx,\n stats: computeStats(subPts, true),\n });\n }\n }\n\n // 2. Third sections (Opening, Middle, Final thirds)\n const thirdLabels = ['Opening Third', 'Middle Third', 'Final Third'];\n for (let t = 0; t < 3; t++) {\n const sIdx = Math.floor((t * n) / 3);\n const eIdx = Math.min(n - 1, Math.floor(((t + 1) * n) / 3) - 1);\n if (eIdx > sIdx) {\n const subPts = pts.slice(sIdx, eIdx + 1);\n sections.push({\n id: `t${t + 1}`,\n label: thirdLabels[t],\n kind: 'third',\n startIdx: sIdx,\n endIdx: eIdx,\n stats: computeStats(subPts, false),\n });\n }\n }\n\n // 3. Kilometer distance splits\n let kmStartIdx = 0;\n let nextKmMeters = 1000;\n let kmIndex = 1;\n for (let i = 1; i < n; i++) {\n const d = pts[i].dist || 0;\n if (d >= nextKmMeters || i === n - 1) {\n if (i > kmStartIdx + 2) {\n const kmPts = pts.slice(kmStartIdx, i + 1);\n sections.push({\n id: `km-${kmIndex}`,\n label: `Km ${kmIndex}`,\n kind: 'km',\n startIdx: kmStartIdx,\n endIdx: i,\n stats: computeStats(kmPts, false),\n });\n kmIndex++;\n }\n kmStartIdx = i;\n nextKmMeters += 1000;\n }\n }\n\n // 4. Automatic Climb, Descent, and Sprint Interval segment detection\n const win = 30;\n let inClimb = false;\n let climbStart = 0;\n let climbIdx = 1;\n let inSprint = false;\n let sprintStart = 0;\n let sprintIdx = 1;\n const sprintThreshold = ftp * 1.15;\n\n for (let i = win; i < n; i++) {\n const dEle = (pts[i].ele ?? 0) - (pts[i - win].ele ?? 0);\n const dDist = Math.max(1, (pts[i].dist ?? 0) - (pts[i - win].dist ?? 0));\n const rollingGrade = (dEle / dDist) * 100;\n\n if (rollingGrade >= 1.8 && !inClimb) {\n inClimb = true;\n climbStart = i - win;\n } else if ((rollingGrade < 0.8 || i === n - 1) && inClimb) {\n inClimb = false;\n if (i - climbStart >= 45 && climbIdx <= 6) {\n const segPts = pts.slice(climbStart, i + 1);\n sections.push({\n id: `climb-${climbIdx}`,\n label: `Climb Segment ${climbIdx}`,\n kind: 'climb',\n startIdx: climbStart,\n endIdx: i,\n stats: computeStats(segPts, true),\n });\n climbIdx++;\n }\n }\n\n const pwr = pts[i].power ?? 0;\n if (pwr >= sprintThreshold && !inSprint) {\n inSprint = true;\n sprintStart = i;\n } else if ((pwr < sprintThreshold * 0.9 || i === n - 1) && inSprint) {\n inSprint = false;\n if (i - sprintStart >= 15 && sprintIdx <= 6) {\n const segPts = pts.slice(sprintStart, i + 1);\n sections.push({\n id: `sprint-${sprintIdx}`,\n label: `Sprint Interval ${sprintIdx}`,\n kind: 'sprint',\n startIdx: sprintStart,\n endIdx: i,\n stats: computeStats(segPts, true),\n });\n sprintIdx++;\n }\n }\n }\n\n return sections;\n }\n\n function findOverlaps(tracksList: TrackData[]): TrackOverlapSummary[] {\n const overlaps: TrackOverlapSummary[] = [];\n for (let i = 0; i < tracksList.length; i++) {\n const ta = tracksList[i];\n const ptsA = ta.simplifiedPoints || ta.points;\n const stepA = Math.max(1, Math.floor(ptsA.length / 80));\n for (let j = i + 1; j < tracksList.length; j++) {\n const tb = tracksList[j];\n const ptsB = tb.simplifiedPoints || tb.points;\n const stepB = Math.max(1, Math.floor(ptsB.length / 80));\n let shared = 0;\n let minCorridor = Infinity;\n for (let a = 0; a < ptsA.length; a += stepA) {\n const pa = ptsA[a];\n let nearest = Infinity;\n for (let b = 0; b < ptsB.length; b += stepB) {\n const pb = ptsB[b];\n const d = haversine(pa.lat, pa.lon, pb.lat, pb.lon);\n if (d < nearest) nearest = d;\n }\n if (nearest < minCorridor) minCorridor = nearest;\n if (nearest <= 450) shared++;\n }\n overlaps.push({\n trackAId: ta.id,\n trackBId: tb.id,\n sharedPoints: shared,\n minCorridorMeters: Number.isFinite(minCorridor) ? Math.round(minCorridor) : 0,\n powerDelta: (tb.stats.avgPower || 0) - (ta.stats.avgPower || 0),\n speedDelta: Number(((tb.stats.avgSpeed || 0) - (ta.stats.avgSpeed || 0)).toFixed(2)),\n });\n }\n }\n return overlaps;\n }\n\n const STANDARD_CURVE_DURATIONS = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600,\n ];\n\n function calculateSlidingMax(data: number[], durations: number[]) {\n const len = data.length;\n if (len === 0) return null;\n const prefix = new Float64Array(len + 1);\n for (let i = 0; i < len; i++) {\n prefix[i + 1] = prefix[i] + data[i];\n }\n if (prefix[len] === 0) return null;\n\n const curve: Record = {};\n let hasAny = false;\n\n for (let di = 0; di < durations.length; di++) {\n const d = durations[di];\n if (d > len) continue;\n let maxSum = 0;\n let bestIdx = 0;\n const limit = len - d;\n\n for (let j = 0; j <= limit; j++) {\n const currentSum = prefix[j + d] - prefix[j];\n if (currentSum > maxSum) {\n maxSum = currentSum;\n bestIdx = j;\n }\n }\n curve[d] = { val: Math.round(maxSum / d), idx: bestIdx };\n hasAny = true;\n }\n\n return hasAny ? curve : null;\n }\n\n function calculatePowerCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const powerData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].power || 0;\n powerData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(powerData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { power: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculateHRCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const hrData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].hr || 0;\n hrData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(hrData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { hr: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculatePowerZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0, 0, 0];\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.power == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue;\n\n const pw = p.power;\n if (pw < thresholds[0]) zones[0] += dt;\n else if (pw < thresholds[1]) zones[1] += dt;\n else if (pw < thresholds[2]) zones[2] += dt;\n else if (pw < thresholds[3]) zones[3] += dt;\n else if (pw < thresholds[4]) zones[4] += dt;\n else if (pw < thresholds[5]) zones[5] += dt;\n else zones[6] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setFTP(val: number) {\n ftp = val;\n }\n\n function getFTP() {\n return ftp;\n }\n\n function calculateHRZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0];\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.hr == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue; // Skip gaps\n\n const hr = p.hr;\n if (hr < hrZoneThresholds[0]) zones[0] += dt;\n else if (hr < hrZoneThresholds[1]) zones[1] += dt;\n else if (hr < hrZoneThresholds[2]) zones[2] += dt;\n else if (hr < hrZoneThresholds[3]) zones[3] += dt;\n else zones[4] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setHRZones(thresholds: number[]) {\n hrZoneThresholds = thresholds;\n }\n\n function getHRZones() {\n return [...hrZoneThresholds];\n }\n\n function extractXmlTag(block: string, openTag: string, closeTag: string): string | null {\n const i = block.indexOf(openTag);\n if (i === -1) return null;\n const start = i + openTag.length;\n const j = block.indexOf(closeTag, start);\n if (j === -1) return null;\n const val = block.slice(start, j).trim();\n return val !== '' ? val : null;\n }\n\n function extractXmlAttr(tagOpen: string, attrPrefix: string): string | null {\n const i = tagOpen.indexOf(attrPrefix);\n if (i === -1) return null;\n const start = i + attrPrefix.length;\n const j = tagOpen.indexOf('\"', start);\n if (j === -1) return null;\n return tagOpen.slice(start, j);\n }\n\n let cachedDateKey = -1;\n let cachedDayMs = 0;\n\n function parseIntSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let val = 0;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n val = val * 10 + (c - 48);\n digits++;\n } else {\n break;\n }\n }\n if (digits === 0) return null;\n return neg ? -val : val;\n }\n\n function parseFloatSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let intPart = 0;\n let fracPart = 0;\n let fracDiv = 1;\n let inFrac = false;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n digits++;\n if (!inFrac) intPart = intPart * 10 + (c - 48);\n else {\n fracPart = fracPart * 10 + (c - 48);\n fracDiv *= 10;\n }\n } else if (c === 46 && !inFrac) {\n inFrac = true;\n } else {\n const n = parseFloat(text.slice(start - (neg ? 1 : 0), end));\n return Number.isFinite(n) ? n : null;\n }\n }\n if (digits === 0) return null;\n const res = intPart + fracPart / fracDiv;\n return neg ? -res : res;\n }\n\n function fastParseTimeSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n const len = end - start;\n if (len >= 20 && text.charCodeAt(start + 10) === 84 && text.charCodeAt(end - 1) === 90) {\n const y =\n (text.charCodeAt(start) - 48) * 1000 +\n (text.charCodeAt(start + 1) - 48) * 100 +\n (text.charCodeAt(start + 2) - 48) * 10 +\n (text.charCodeAt(start + 3) - 48);\n const m = (text.charCodeAt(start + 5) - 48) * 10 + (text.charCodeAt(start + 6) - 48);\n const d = (text.charCodeAt(start + 8) - 48) * 10 + (text.charCodeAt(start + 9) - 48);\n const key = (y << 9) | (m << 5) | d;\n if (key !== cachedDateKey) {\n cachedDateKey = key;\n cachedDayMs = Date.UTC(y, m - 1, d);\n }\n const hh = (text.charCodeAt(start + 11) - 48) * 10 + (text.charCodeAt(start + 12) - 48);\n const mm = (text.charCodeAt(start + 14) - 48) * 10 + (text.charCodeAt(start + 15) - 48);\n const ss = (text.charCodeAt(start + 17) - 48) * 10 + (text.charCodeAt(start + 18) - 48);\n let ms = 0;\n if (text.charCodeAt(start + 19) === 46 && len >= 24) {\n ms =\n (text.charCodeAt(start + 20) - 48) * 100 +\n (text.charCodeAt(start + 21) - 48) * 10 +\n (text.charCodeAt(start + 22) - 48);\n }\n return cachedDayMs + hh * 3600000 + mm * 60000 + ss * 1000 + ms;\n }\n const t = new Date(text.slice(start, end)).getTime();\n return Number.isFinite(t) ? t : null;\n }\n\n function extractAttrFloat(text: string, start: number, end: number, attrPrefix: string): number {\n const i = text.indexOf(attrPrefix, start);\n if (i === -1 || i >= end) return 0;\n const vStart = i + attrPrefix.length;\n const j = text.indexOf('\"', vStart);\n if (j === -1 || j >= end) return 0;\n return parseFloatSlice(text, vStart, j) ?? 0;\n }\n\n // \u2500\u2500 GPX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseGPX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTrkpt = text.indexOf('');\n const name =\n (trkIdx !== -1 ? extractXmlTag(header.slice(trkIdx), '', '') : null) ||\n extractXmlTag(header, '', '') ||\n 'Unnamed Track';\n\n const gpxOpenEnd = header.indexOf('>', header.indexOf('', trkStart + 6);\n if (openEnd === -1) break;\n const trkEnd = text.indexOf('', openEnd + 1);\n if (trkEnd === -1) break;\n pos = trkEnd + 8;\n\n const lat = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lat=\"');\n const lon = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lon=\"');\n\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let temp: number | null = null;\n let speed: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = openEnd + 1;\n while (p < trkEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= trkEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= trkEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n // Skip duplicate block when primary fields already parsed\n const tagLen = gt - lt - 1;\n if (c1 === 103 && tagLen === 26 && hr !== null && cad !== null && temp !== null) {\n break;\n }\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > trkEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 3) {\n if (c1 === 101) ele = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 99 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 2) {\n if (c1 === 104 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 4) {\n if (c1 === 116) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if ((c1 === 112 || c1 === 80 || c1 === 87) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 115 || c1 === 83) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if ((c1 === 98 || c1 === 66) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 103 || c1 === 71) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if (c1 === 103) {\n if (text.charCodeAt(lt + 8) === 104 && hr === null)\n hr = parseIntSlice(text, vStart, vEnd);\n else if (gearFront === null) gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (c1 === 71 && gearFront === null) {\n gearFront = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 10) {\n if (c1 === 103 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 103 && text.charCodeAt(lt + 8) === 97 && temp === null)\n temp = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 103 || c1 === 71) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if ((c1 === 103 || c1 === 71) && gearFrontTooth === null)\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 65 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 11 && c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!points.length) throw new Error('No track points found in GPX');\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'gpx', points: pts, stats };\n }\n\n // \u2500\u2500 TCX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseTCX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTp = text.indexOf('');\n const header = firstTp !== -1 ? text.slice(0, firstTp) : text;\n\n const name = extractXmlTag(header, '', '') || 'Unnamed TCX';\n const creatorBlock = extractXmlTag(header, '', '');\n const device = creatorBlock ? extractXmlTag(creatorBlock, '', '') : null;\n\n const points: TrackPoint[] = [];\n let pos = firstTp !== -1 ? firstTp : 0;\n while (pos < text.length) {\n const tpStart = text.indexOf('', pos);\n if (tpStart === -1) break;\n const tpEnd = text.indexOf('', tpStart + 12);\n if (tpEnd === -1) break;\n pos = tpEnd + 13;\n\n let lat: number | null = null;\n let lon: number | null = null;\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let speed: number | null = null;\n let temp: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = tpStart + 12;\n while (p < tpEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= tpEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= tpEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n const tagLen = gt - lt - 1;\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > tpEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 4) {\n if (c1 === 84) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 116 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if (c1 === 86 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 87 || c1 === 80 || c1 === 112) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 83 || c1 === 115) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 66 || c1 === 98) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 71 || c1 === 103) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if ((c1 === 71 || c1 === 103) && gearFront === null)\n gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 10) {\n if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 11) {\n if (c1 === 84 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 71 || c1 === 103) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if (c1 === 65) {\n if (text.charCodeAt(lt + 2) === 108) ele = parseFloatSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if ((c1 === 71 || c1 === 103) && gearFrontTooth === null) {\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 15) {\n if (c1 === 76) lat = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 16) {\n if (c1 === 76) lon = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 2 && c1 === 104 && hr === null) {\n hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 3 && c1 === 99 && cad === null) {\n cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n if (lat == null || lon == null) continue;\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'tcx', points: pts, stats };\n }\n\n function fastDecodeFitData(buf: ArrayBuffer): any | null {\n if (buf.byteLength < 14) return null;\n const dv = new DataView(buf);\n const headerSize = dv.getUint8(0);\n if (headerSize < 12 || headerSize + 2 > buf.byteLength) return null;\n if (\n dv.getUint8(8) !== 0x2e ||\n dv.getUint8(9) !== 0x46 ||\n dv.getUint8(10) !== 0x49 ||\n dv.getUint8(11) !== 0x54\n ) {\n return null;\n }\n const dataSize = dv.getUint32(4, true);\n const endOffset = Math.min(buf.byteLength, headerSize + dataSize);\n const GARMIN_EPOCH_SEC = 631065600;\n const SEMICIRCLE_TO_DEG = 180 / Math.pow(2, 31);\n\n interface FieldDef {\n num: number;\n size: number;\n type: number;\n }\n interface MsgDef {\n littleEndian: boolean;\n globalMsgNum: number;\n fields: FieldDef[];\n recordSize: number;\n }\n const defs: (MsgDef | undefined)[] = new Array(16);\n const file_ids: any[] = [];\n const sessions: any[] = [];\n const records: any[] = [];\n const events: any[] = [];\n const device_infos: any[] = [];\n\n let offset = headerSize;\n while (offset < endOffset) {\n const hdr = dv.getUint8(offset++);\n if ((hdr & 0x80) !== 0 || (hdr & 0x20) !== 0) {\n return null; // Compressed timestamp or developer data: fallback to FitParser\n }\n const localNum = hdr & 0x0f;\n if ((hdr & 0x40) !== 0) {\n if (offset + 5 > endOffset) return null;\n offset++; // reserved\n const arch = dv.getUint8(offset++);\n const littleEndian = arch === 0;\n const globalMsgNum = dv.getUint16(offset, littleEndian);\n offset += 2;\n const numFields = dv.getUint8(offset++);\n if (offset + numFields * 3 > endOffset) return null;\n const fields: FieldDef[] = new Array(numFields);\n let recordSize = 0;\n for (let i = 0; i < numFields; i++) {\n const num = dv.getUint8(offset++);\n const size = dv.getUint8(offset++);\n const type = dv.getUint8(offset++);\n fields[i] = { num, size, type };\n recordSize += size;\n }\n defs[localNum] = { littleEndian, globalMsgNum, fields, recordSize };\n } else {\n const def = defs[localNum];\n if (!def || offset + def.recordSize > endOffset) return null;\n const le = def.littleEndian;\n const gNum = def.globalMsgNum;\n\n if (\n gNum === 20 &&\n def.fields.length === 10 &&\n def.recordSize === 25 &&\n def.fields[0].num === 253 &&\n def.fields[1].num === 0\n ) {\n const ts = dv.getUint32(offset, le);\n const rawLat = dv.getInt32(offset + 4, le);\n const rawLon = dv.getInt32(offset + 8, le);\n const rawAlt = dv.getUint16(offset + 12, le);\n const hr = dv.getUint8(offset + 14);\n const cad = dv.getUint8(offset + 15);\n const rawDist = dv.getUint32(offset + 16, le);\n const rawSpd = dv.getUint16(offset + 20, le);\n const power = dv.getUint16(offset + 22, le);\n const temp = dv.getInt8(offset + 24);\n records.push({\n timestamp: (ts + GARMIN_EPOCH_SEC) * 1000,\n position_lat: rawLat * SEMICIRCLE_TO_DEG,\n position_long: rawLon * SEMICIRCLE_TO_DEG,\n altitude: rawAlt / 5 - 500,\n heart_rate: hr,\n cadence: cad,\n distance: rawDist / 100,\n speed: (rawSpd / 1000) * 3.6,\n power,\n temperature: temp,\n });\n offset += 25;\n continue;\n }\n\n const msg: any = {};\n let fOff = offset;\n for (let i = 0; i < def.fields.length; i++) {\n const f = def.fields[i];\n let val: number = 0;\n const bType = f.type & 0x1f;\n if (f.size === 1) {\n val = bType === 1 ? dv.getInt8(fOff) : dv.getUint8(fOff);\n } else if (f.size === 2) {\n val = bType === 3 ? dv.getInt16(fOff, le) : dv.getUint16(fOff, le);\n } else if (f.size === 4) {\n val = bType === 5 ? dv.getInt32(fOff, le) : dv.getUint32(fOff, le);\n }\n msg[f.num] = val;\n fOff += f.size;\n }\n offset += def.recordSize;\n\n if (gNum === 0) {\n file_ids.push({\n type: msg[0] === 4 ? 'activity' : msg[0],\n manufacturer: msg[1] === 1 ? 'garmin' : msg[1],\n product: msg[2],\n time_created: msg[4] != null ? (msg[4] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n });\n } else if (gNum === 18) {\n const sportMap: Record = { 0: 'generic', 1: 'running', 2: 'cycling' };\n sessions.push({\n start_time: msg[2] != null ? (msg[2] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n sport: sportMap[msg[5]] ?? String(msg[5]),\n sub_sport: msg[6] === 0 ? 'generic' : String(msg[6]),\n });\n } else if (gNum === 20) {\n records.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n position_lat: msg[0] != null ? msg[0] * SEMICIRCLE_TO_DEG : undefined,\n position_long: msg[1] != null ? msg[1] * SEMICIRCLE_TO_DEG : undefined,\n altitude: msg[2] != null ? msg[2] / 5 - 500 : undefined,\n heart_rate: msg[3],\n cadence: msg[4],\n distance: msg[5] != null ? msg[5] / 100 : undefined,\n speed: msg[6] != null ? (msg[6] / 1000) * 3.6 : undefined,\n power: msg[7],\n temperature: msg[13],\n });\n } else if (gNum === 21) {\n const evName =\n msg[0] === 43\n ? 'rear_gear_change'\n : msg[0] === 42\n ? 'front_gear_change'\n : String(msg[0]);\n events.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n event: evName,\n event_type: msg[1] === 3 ? 'marker' : String(msg[1]),\n data: msg[3],\n front_gear_num: msg[9],\n rear_gear_num: msg[11],\n });\n } else if (gNum === 23) {\n device_infos.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n battery_level: msg[32],\n });\n } else {\n return null;\n }\n }\n }\n return { file_ids, sessions, sports: [], records, events, device_infos };\n }\n\n // \u2500\u2500 FIT parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseFIT(buf: ArrayBuffer): Promise {\n return new Promise((resolve, reject) => {\n const handleParsedFitData = (error: any, data: any) => {\n if (error) {\n reject(error);\n return;\n }\n try {\n const name = data.sessions?.[0]?.start_time\n ? `Fit Activity ${new Date(data.sessions[0].start_time).toISOString().split('T')[0]}`\n : 'Unnamed Fit';\n\n // Better device detection\n let device: string | null = null;\n const devices: DeviceInfo[] = [];\n let sport: string | null = null;\n let subSport: string | null = null;\n\n if (data.sports?.[0]) {\n sport = data.sports[0].sport;\n subSport = data.sports[0].sub_sport;\n } else if (data.sessions?.[0]) {\n sport = data.sessions[0].sport;\n subSport = data.sessions[0].sub_sport;\n }\n\n const getDeviceName = (d: any) =>\n d.product_name ||\n d.garmin_product ||\n d.product ||\n d.device_type ||\n d.manufacturer ||\n null;\n\n if (data.file_ids?.[0]) {\n const fid = data.file_ids[0];\n device = getDeviceName(fid);\n devices.push({\n name: fid.product_name || fid.garmin_product || fid.product,\n manufacturer: fid.manufacturer,\n serial: fid.serial_number ? String(fid.serial_number) : undefined,\n version: fid.software_version ? String(fid.software_version) : undefined,\n type: 'main',\n });\n }\n\n if (data.device_infos) {\n data.device_infos.forEach((d: any) => {\n const isMain = d.device_index === 'creator' || d.device_index === 0;\n\n if (isMain) {\n const name = getDeviceName(d);\n // Prefer a name with product_name or garmin_product over generic ones\n if (d.product_name || d.garmin_product || !device) device = name;\n\n // Update existing main device if needed\n if (devices.length > 0 && devices[0].type === 'main') {\n if (d.product_name || d.garmin_product || !devices[0].name)\n devices[0].name = d.product_name || d.garmin_product || d.product;\n\n if (!devices[0].manufacturer) devices[0].manufacturer = d.manufacturer;\n if (!devices[0].serial && d.serial_number)\n devices[0].serial = String(d.serial_number);\n if (!devices[0].version && d.software_version)\n devices[0].version = String(d.software_version);\n if (!devices[0].hardwareVersion && d.hardware_version)\n devices[0].hardwareVersion = String(d.hardware_version);\n }\n return;\n }\n\n devices.push({\n name: d.product_name || d.garmin_product || d.product || d.device_type || 'Sensor',\n manufacturer: d.manufacturer,\n serial: d.serial_number ? String(d.serial_number) : undefined,\n version: d.software_version ? String(d.software_version) : undefined,\n hardwareVersion: d.hardware_version ? String(d.hardware_version) : undefined,\n type: d.device_type || 'sensor',\n batteryStatus: d.battery_status,\n batteryVoltage: d.battery_voltage,\n batteryLevel: d.battery_level,\n sourceType: d.source_type != null ? String(d.source_type) : undefined,\n });\n });\n }\n\n if (data.sensor_settings) {\n data.sensor_settings.forEach((s: any) => {\n const name = s.name || s.product || s.sensor_type;\n if (!name) return;\n\n // Check if we already have this device (by ANT ID or name)\n const antId = s.ant_id ? String(s.ant_id) : undefined;\n const existing = devices.find(\n (d) =>\n (antId && d.serial === antId) ||\n (d.name === name && d.manufacturer === s.manufacturer),\n );\n\n if (existing) {\n if (!existing.name) existing.name = name;\n if (!existing.manufacturer) existing.manufacturer = s.manufacturer;\n if (!existing.type) existing.type = s.sensor_type;\n if (!existing.sourceType)\n existing.sourceType =\n s.connection_type != null ? String(s.connection_type) : undefined;\n } else {\n devices.push({\n name: name,\n manufacturer: s.manufacturer,\n serial: antId,\n type: s.sensor_type || 'sensor',\n sourceType: s.connection_type != null ? String(s.connection_type) : undefined,\n });\n }\n });\n }\n\n // Collect standalone device status reports (often contains head unit battery)\n // We'll store them in a sorted array for easier lookups\n const statusReports: { time: number; level: number | null; idx: number }[] = [];\n if (data.device_statuses) {\n data.device_statuses.forEach((s: any, idx: number) => {\n if (s.timestamp && s.battery_level != null) {\n statusReports.push({\n time:\n typeof s.timestamp === 'number' ? s.timestamp : new Date(s.timestamp).getTime(),\n level: s.battery_level,\n idx,\n });\n }\n });\n statusReports.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n // Collect gear events\n const gearEvents: {\n time: number;\n front: number | null;\n rear: number | null;\n frontTooth: number | null;\n rearTooth: number | null;\n idx: number;\n }[] = [];\n if (data.events) {\n data.events.forEach((e: any, idx: number) => {\n let front = e.front_gear_num ?? e.front_gear ?? null;\n let rear = e.rear_gear_num ?? e.rear_gear ?? null;\n let frontTooth = e.front_gear_num_tooth ?? null;\n let rearTooth = e.rear_gear_num_tooth ?? null;\n\n if (e.event === 'rear_gear_change' || e.event === 'front_gear_change') {\n const d = e.data;\n if (d != null) {\n const ft = (d >> 24) & 0xff;\n const fg = (d >> 16) & 0xff;\n const rt = (d >> 8) & 0xff;\n const rg = d & 0xff;\n\n if (fg !== 0) front = fg;\n if (ft !== 0) frontTooth = ft;\n if (rg !== 0) rear = rg;\n if (rt !== 0) rearTooth = rt;\n }\n }\n\n if (\n e.timestamp &&\n (front != null || rear != null || frontTooth != null || rearTooth != null)\n ) {\n gearEvents.push({\n time:\n typeof e.timestamp === 'number' ? e.timestamp : new Date(e.timestamp).getTime(),\n front,\n rear,\n frontTooth,\n rearTooth,\n idx,\n });\n }\n });\n gearEvents.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n const records = data.records || [];\n let lastBattery: number | null = null;\n let statusIdx = 0;\n let lastFrontGear: number | null = null;\n let lastRearGear: number | null = null;\n let lastFrontTooth: number | null = null;\n let lastRearTooth: number | null = null;\n let gearIdx = 0;\n\n const validPoints: TrackPoint[] = [];\n for (let ri = 0; ri < records.length; ri++) {\n const r = records[ri];\n const lat = r.position_lat;\n const lon = r.position_long;\n if (lat == null || lon == null) continue;\n\n const time =\n r.timestamp != null\n ? typeof r.timestamp === 'number'\n ? r.timestamp\n : r.timestamp instanceof Date\n ? r.timestamp.getTime()\n : new Date(r.timestamp).getTime()\n : null;\n const speed = r.speed != null ? r.speed / 3.6 : null; // km/h \u2192 m/s\n\n let battery = r.battery_level ?? null;\n\n // If not in record, check our status reports\n if (battery == null && time) {\n // Catch up statusIdx to current time\n while (statusIdx < statusReports.length && statusReports[statusIdx].time <= time) {\n lastBattery = statusReports[statusIdx].level;\n statusIdx++;\n }\n battery = lastBattery;\n } else if (battery != null) {\n lastBattery = battery;\n }\n\n // Update gear state from events\n if (time) {\n while (gearIdx < gearEvents.length && gearEvents[gearIdx].time <= time) {\n const e = gearEvents[gearIdx];\n if (e.front != null) lastFrontGear = e.front;\n if (e.rear != null) lastRearGear = e.rear;\n if (e.frontTooth != null) lastFrontTooth = e.frontTooth;\n if (e.rearTooth != null) lastRearTooth = e.rearTooth;\n gearIdx++;\n }\n }\n\n const gearFront: number | null = r.front_gear_num ?? r.front_gear ?? lastFrontGear;\n const gearRear: number | null = r.rear_gear_num ?? r.rear_gear ?? lastRearGear;\n const gearFrontTooth: number | null = r.front_gear_num_tooth ?? lastFrontTooth;\n const gearRearTooth: number | null = r.rear_gear_num_tooth ?? lastRearTooth;\n\n if (r.front_gear_num != null || r.front_gear != null) lastFrontGear = gearFront;\n if (r.rear_gear_num != null || r.rear_gear != null) lastRearGear = gearRear;\n if (r.front_gear_num_tooth != null) lastFrontTooth = gearFrontTooth;\n if (r.rear_gear_num_tooth != null) lastRearTooth = gearRearTooth;\n\n const gears =\n gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0\n ? gearFrontTooth / gearRearTooth\n : null;\n\n validPoints.push({\n lat,\n lon,\n ele: r.altitude ?? r.enhanced_altitude ?? null,\n time,\n hr: r.heart_rate ?? null,\n cad: r.cadence ?? null,\n power: r.power ?? null,\n speed,\n temp: r.temperature ?? null,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!validPoints.length) {\n reject(new Error('FIT file has no GPS points'));\n return;\n }\n\n const pts = enrichPoints(validPoints);\n const stats = computeStats(pts);\n resolve({ name, device, devices, format: 'fit', points: pts, stats, sport, subSport });\n } catch (ex) {\n reject(ex);\n }\n };\n\n const fastData = fastDecodeFitData(buf);\n if (fastData) {\n handleParsedFitData(null, fastData);\n return;\n }\n\n const fitParser = new FitParser({\n force: true,\n speedUnit: 'km/h',\n lengthUnit: 'm',\n temperatureUnit: 'celsius',\n elapsedRecordField: true,\n });\n\n fitParser.parse(buf, handleParsedFitData);\n });\n }\n\n // \u2500\u2500 KML parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseKML(buf: ArrayBuffer): any {\n const text = new TextDecoder().decode(buf);\n const doc = new DOMParser().parseFromString(text, 'application/xml');\n\n let name = 'Unnamed Track';\n const nameEl = doc.querySelector('Document > name, Placemark > name');\n if (nameEl) name = nameEl.textContent?.trim() || name;\n\n // Track: look for gx:Track or LineString\n const coordEls = doc.querySelectorAll('coordinates');\n if (!coordEls.length) throw new Error('No coordinates found in KML');\n\n const points: TrackPoint[] = [];\n coordEls.forEach((el) => {\n const lines = el.textContent?.trim().split(/\\s+/) || [];\n lines.forEach((line) => {\n const parts = line.split(',');\n if (parts.length < 2) return;\n const lon = parseFloat(parts[0]);\n const lat = parseFloat(parts[1]);\n const ele = parts.length > 2 ? parseFloat(parts[2]) : null;\n if (isNaN(lat) || isNaN(lon)) return;\n points.push({\n lat,\n lon,\n ele: ele != null && isNaN(ele) ? null : ele,\n time: null,\n hr: null,\n cad: null,\n power: null,\n speed: null,\n temp: null,\n gearFront: null,\n gearRear: null,\n gearFrontTooth: null,\n gearRearTooth: null,\n battery: null,\n gears: null,\n });\n });\n });\n\n if (!points.length) throw new Error('No valid coordinates in KML');\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, format: 'kml', points: pts, stats };\n }\n\n // \u2500\u2500 Public: dispatch by extension \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async function parseFile(file: File): Promise {\n const ext = file.name.split('.').pop()?.toLowerCase();\n const buf: ArrayBuffer = (file as any)._buf ?? (await file.arrayBuffer());\n const predecodedText: string | undefined = (file as any)._text;\n let result: any;\n switch (ext) {\n case 'gpx':\n result = parseGPX(buf, predecodedText);\n break;\n case 'tcx':\n result = parseTCX(buf, predecodedText);\n break;\n case 'fit':\n result = await parseFIT(buf);\n break;\n case 'kml':\n result = parseKML(buf);\n break;\n default:\n throw new Error(`Unsupported format: .${ext}`);\n }\n\n if (result) {\n result.fileName = file.name;\n result.fileSize = file.size;\n if (result.points && result.stats) {\n ensureCurvesAndZones(result);\n result.stats.sections = analyzeTrackSections(result.points);\n }\n }\n return result;\n }\n\n return {\n parseFile,\n computeStats,\n ensureCurvesAndZones,\n analyzeTrackSections,\n findOverlaps,\n calculatePowerCurve,\n calculateHRCurve,\n calculatePowerZones,\n calculateHRZones,\n enrichPoints,\n setHRZones,\n getHRZones,\n setFTP,\n getFTP,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const R = 6371e3; // Earth radius in metres\n const phi1 = (lat1 * Math.PI) / 180;\n const phi2 = (lat2 * Math.PI) / 180;\n const deltaPhi = ((lat2 - lat1) * Math.PI) / 180;\n const deltaLambda = ((lon2 - lon1) * Math.PI) / 180;\n\n const a =\n Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) +\n Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n\nexport function compactId(timestamp: number): string {\n // Use a compact representation of the timestamp (seconds since epoch)\n // 1712650000 -> Base64\n const buf = new Uint32Array([Math.floor(timestamp / 1000)]);\n const b64 = btoa(String.fromCharCode(...new Uint8Array(buf.buffer)));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\nexport function shortRandom(): string {\n return Math.random().toString(36).slice(2, 6);\n}\n\nexport function fmtDuration(s: number): string {\n if (s < 60) return `${Math.round(s)}s`;\n if (s < 3600) return `${Math.round(s / 60)}m`;\n return `${Math.round(s / 3600)}h`;\n}\n\nexport function fmtSecs(s: number): string {\n const h = Math.floor(s / 3600),\n m = Math.floor((s % 3600) / 60);\n return h > 0 ? `${h}h ${m}m` : `${m}m ${Math.floor(s % 60)}s`;\n}\n\nexport function fmtPace(seconds: number | null): string {\n if (seconds == null || !isFinite(seconds)) return '--';\n const mins = Math.floor(seconds / 60);\n const secs = Math.round(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nexport function fmtDate(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown date';\n return d.toISOString().split('T')[0];\n}\n\nexport function fmtDateTime(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown';\n const iso = d.toISOString();\n return `${iso.split('T')[0]} ${iso.split('T')[1].slice(0, 5)}`;\n}\n\nexport function fmtFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function escHtml(str: string): string {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function getTagColor(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);\n\n const h = Math.abs(hash % 360);\n return `hsl(${h}, 70%, 65%)`;\n}\n\n/**\n * Smoothes a numeric array using a simple Gaussian kernel.\n * sigma: standard deviation (radius of smoothing)\n */\nexport function gaussianSmooth(data: (number | null)[], sigma: number = 2): (number | null)[] {\n if (sigma <= 0) return data;\n\n const size = Math.ceil(sigma * 3) * 2 + 1;\n const kernel = new Float32Array(size);\n const half = Math.floor(size / 2);\n let sum = 0;\n\n for (let i = 0; i < size; i++) {\n const x = i - half;\n kernel[i] = Math.exp(-(x * x) / (2 * sigma * sigma));\n sum += kernel[i];\n }\n for (let i = 0; i < size; i++) kernel[i] /= sum;\n\n const result: (number | null)[] = new Array(data.length);\n for (let i = 0; i < data.length; i++) {\n if (data[i] === null) {\n result[i] = null;\n continue;\n }\n\n let val = 0;\n let weightSum = 0;\n for (let k = 0; k < size; k++) {\n const idx = i + k - half;\n if (idx >= 0 && idx < data.length && data[idx] !== null) {\n val += data[idx]! * kernel[k];\n weightSum += kernel[k];\n }\n }\n result[i] = weightSum > 0 ? val / weightSum : data[i];\n }\n return result;\n}\n\nexport function hexToRgba(hex: string, alpha: number = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, TrackPoint } from './parsers';\n\nexport const MapView = (() => {\n let trackData: Record = {};\n let customClickHandler: ((e: any) => boolean) | null = null;\n\n function init(\n onSelectCb: (id: string) => void,\n onMoveCb: (lat: number, lng: number, zoom: number) => void,\n onPointClickCb: (id: string, idx: number) => void,\n onPointHoverCb: (id: string | null, idx: number | null) => void,\n onDblClickCb: () => void,\n ) {}\n\n function switchBasemap(layer: string) {}\n function addTrack(t: TrackData) {\n trackData[t.id] = t;\n }\n function addTracks(ts: TrackData[]) {\n ts.forEach((t) => {\n trackData[t.id] = t;\n });\n }\n function removeTrack(id: string) {\n delete trackData[id];\n }\n function clearTracks() {\n trackData = {};\n }\n function removeAllTracks() {\n trackData = {};\n }\n function setTrackVisible(id: string, visible: boolean) {}\n function setSelectedTrack(id: string | null, fit: boolean) {}\n function fitAll() {}\n function fitTrack(id: string) {}\n function showCursorAt(lat: number, lon: number) {}\n function hideCursor() {}\n function highlightSegment(\n id: string | null,\n pts: TrackPoint[],\n start: number,\n end: number,\n fit?: boolean,\n colors?: string[] | null,\n ) {}\n function clearHighlight() {}\n function setTrackHover(id: string, hover: boolean) {}\n function ensureVisible(pts: any) {}\n function centerOn(lat: number, lon: number, zoom?: number | null, force?: boolean) {}\n function closePopup() {}\n function invalidateSize() {}\n function getPosition(): [number, number, number] {\n return [0, 0, 0];\n }\n function setPosition(lat: number, lng: number, zoom: number) {}\n function colorTrackByMetric(id: string, pts: TrackPoint[], colors: string[]) {}\n function clearMetricColor(id: string) {}\n\n function findTracksPassingThroughPoints(\n points: { lat: number; lng: number }[],\n radius: number,\n ): string[] {\n return Object.keys(trackData);\n }\n\n return {\n init,\n getMap: () => null as any,\n setCustomClickHandler: (handler: any) => {\n customClickHandler = handler;\n },\n switchBasemap,\n addTrack,\n addTracks,\n removeTrack,\n clearTracks,\n removeAllTracks,\n setTrackVisible,\n setSelectedTrack,\n fitAll,\n fitTrack,\n showCursorAt,\n hideCursor,\n highlightSegment,\n clearHighlight,\n setTrackHover,\n ensureVisible,\n centerOn,\n closePopup,\n invalidateSize,\n getPosition,\n setPosition,\n colorTrackByMetric,\n clearMetricColor,\n findTracksPassingThroughPoints,\n getTrackData: (id: string) => trackData[id],\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackPoint, TrackStats, TrackData } from './parsers';\nimport { gaussianSmooth, fmtSecs, hexToRgba, fmtPace } from './utils';\nimport { Zones } from './zones';\nimport { METRICS, MetricDefinition } from './metrics';\nimport { UrlState } from './url-state';\nimport { SPORTS } from './sports';\n\n// Augment uPlot to include our custom property\n\ninterface WegPlot extends uPlot {\n _strasse?: {\n selFill: HTMLElement;\n anchorLine: HTMLElement;\n anchorLabel: HTMLElement;\n anchorHandle: HTMLElement;\n anchorMarker: HTMLElement;\n endLine: HTMLElement;\n endLabel: HTMLElement;\n endHandle: HTMLElement;\n endMarker: HTMLElement;\n curYVal: HTMLElement;\n updateHeaderStats: (min: number, max: number) => void;\n };\n}\n\ninterface PlotData {\n uplot: WegPlot;\n row: HTMLDivElement;\n xData: number[];\n yData: (number | null)[];\n def: MetricDefinition;\n metricKey: string;\n statsTotalEl: HTMLDivElement;\n statsSelEl: HTMLDivElement;\n histCol: HTMLDivElement;\n histCanvas: HTMLCanvasElement;\n histData: HistData;\n hoveredHistY: number | null;\n pinnedHistY: number | null;\n smoothed?: boolean;\n incZero?: boolean;\n w?: number;\n}\n\ninterface HistData {\n yData: (number | null)[];\n xData: number[];\n def: MetricDefinition;\n BINS: number;\n plot?: PlotData;\n bins?: number[];\n binAccum?: number[];\n min?: number;\n max?: number;\n padL?: number;\n selBins?: number[] | null;\n selBinAccum?: number[] | null;\n _lastYData?: any;\n _lastSelRange?: [number, number] | null;\n fullStats?: { min: number; max: number; avg: number } | null;\n fullStatsAll?: { min: number; max: number; avg: number } | null;\n}\n\nexport const ChartView = (() => {\n let plots: PlotData[] = [];\n let renderedTrack: TrackData | null = null;\n let renderedXAxis: string = 'time';\n let renderedSpeedMode: string = 'speed';\n let renderedMapColorMetric: string | null = null;\n let syncKey: {\n key: string;\n sub: (u: uPlot) => void;\n unsub: (u: uPlot) => void;\n pub: (type: string, u: uPlot, x: number, y: number, w: number, h: number, i: number) => void;\n } | null = null;\n let scaleSyncing: boolean = false;\n let cursorSyncing: boolean = false;\n let activeMetrics: Set = new Set(['elevation']);\n let availableMetrics: Set = new Set();\n let smoothedMetrics: Set = new Set(['speed', 'gradient', 'vam', 'temperature']);\n let metricsIncludingZero: Set = new Set(['power']);\n let xAxis: string = 'time';\n let currentTrack: TrackData | null = null;\n let allTracks: TrackData[] = [];\n\n // Selection / anchor\n let selAnchorVal: number | null = null; // x-value at drag-start / zoom left edge\n let selEndVal: number | null = null; // x-value at zoom right edge\n let isDragging: boolean = false;\n let updatingRange: boolean = false; // guard against setScale hook re-entry during handle drag\n let pinnedPtIdx: number | null = null; // point index pinned by map click\n let lastMouseXVal: number | null = null; // last hovered x-value for keyboard zoom center\n let lastHistMouseEvent: MouseEvent | null = null;\n let hoveredHistData: HistData | null = null;\n let hoveredHistCanvas: HTMLCanvasElement | null = null;\n\n let currentXRange: [number, number] | null = null; // [min, max] currently rendered\n let targetXRange: [number, number] | null = null; // [min, max] for smooth keyboard animation\n let animId: number | null = null;\n\n // Callbacks\n let onCursorMoveCb: ((pt: TrackPoint | null) => void) | null = null;\n let onRangeChangeCb: ((min: number | null, max: number | null, axis: string) => void) | null =\n null;\n let onClickCb: ((pt: TrackPoint, idx: number) => void) | null = null;\n let onPinChangeCb: ((idx: number | null) => void) | null = null;\n\n const HIST_W: number = 130;\n const ROW_BODY_PADDING: number = 28; // 14px left + 14px right\n const HIST_GAP: number = 20; // margin-left on .hist-col\n let statsVisible: boolean = true;\n let histTooltipEl: HTMLElement | null = null;\n let container: HTMLElement | null = null;\n let emptyEl: HTMLElement | null = null;\n let selStatsEl: HTMLElement | null = null;\n let resetSelBtn: HTMLElement | null = null;\n let mapColorMetric: string | null = null;\n let onMapColorChangeCb: ((data: { pts: TrackPoint[]; colors: string[] } | null) => void) | null =\n null;\n\n // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function init(\n onCursorMove: (pt: TrackPoint | null) => void,\n onRangeChange: (min: number | null, max: number | null, axis: string) => void,\n onClick: (pt: TrackPoint, idx: number) => void,\n onPinChange: (idx: number | null) => void,\n ) {\n onCursorMoveCb = onCursorMove;\n onRangeChangeCb = onRangeChange;\n onClickCb = onClick;\n onPinChangeCb = onPinChange;\n container = document.getElementById('charts-container');\n container?.addEventListener('scroll', () => {\n if (lastHistMouseEvent && hoveredHistCanvas && hoveredHistData)\n updateHistTooltip(lastHistMouseEvent, hoveredHistCanvas, hoveredHistData);\n });\n emptyEl = document.getElementById('chart-empty');\n selStatsEl = document.getElementById('chart-stats-sel');\n resetSelBtn = document.getElementById('btn-reset-selection');\n histTooltipEl = document.getElementById('hist-tooltip');\n syncKey = uPlot.sync('strasse-sync');\n\n document.getElementById('sel-cancel-btn')?.addEventListener('click', cancelSelection);\n resetSelBtn?.classList.add('hidden');\n\n // \u2500\u2500 WASD Keyboard Navigation \u2500\u2500\n const navKeys = new Set(['w', 'a', 's', 'd']);\n const activeNavKeys = new Set();\n\n document.addEventListener('keydown', (e) => {\n if (!plots.length || !currentTrack) return;\n if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName || '')) return;\n\n const key = e.key.toLowerCase();\n if (!navKeys.has(key)) return;\n\n e.preventDefault();\n activeNavKeys.add(key);\n\n const u = plots[0].uplot;\n if (!targetXRange) targetXRange = [u.scales.x!.min!, u.scales.x!.max!];\n\n let [min, max] = targetXRange;\n const span = max - min;\n const moveStep = span * 0.1;\n const zoomFactor = 0.15;\n\n let newMin = min,\n newMax = max;\n\n if (key === 'a') {\n // Pan left\n newMin = min - moveStep;\n newMax = max - moveStep;\n } else if (key === 'd') {\n // Pan right\n newMin = min + moveStep;\n newMax = max + moveStep;\n } else if (key === 'w' || key === 's') {\n // Zoom\n const center = lastMouseXVal !== null ? lastMouseXVal : (min + max) / 2;\n const factor = key === 'w' ? 1 - zoomFactor : 1 + zoomFactor * 1.2;\n newMin = center - (center - min) * factor;\n newMax = center + (max - center) * factor;\n }\n\n // Clamp to track bounds\n const xFull = [plots[0].xData[0]!, plots[0].xData[plots[0].xData.length - 1]!];\n if (newMin < xFull[0]) {\n const d = xFull[0] - newMin;\n newMin += d;\n newMax += d;\n }\n if (newMax > xFull[1]) {\n const d = newMax - xFull[1];\n newMin -= d;\n newMax -= d;\n }\n newMin = Math.max(xFull[0], newMin);\n newMax = Math.min(xFull[1], newMax);\n\n if (newMax - newMin > 0.001) {\n targetXRange = [newMin, newMax];\n setVisibleRange(newMin, newMax, true); // true = animate\n }\n });\n\n document.addEventListener('keyup', (e) => {\n const key = e.key.toLowerCase();\n if (navKeys.has(key)) activeNavKeys.delete(key);\n });\n }\n\n function setVisibleRange(min: number, max: number, animate = false) {\n if (!plots.length) return;\n if (!animate) {\n plots.forEach(({ uplot: u }) => u.setScale('x', { min, max }));\n return;\n }\n\n const startMin = (currentXRange ? currentXRange[0] : plots[0].uplot.scales.x!.min) as number;\n const startMax = (currentXRange ? currentXRange[1] : plots[0].uplot.scales.x!.max) as number;\n\n if (animId) cancelAnimationFrame(animId);\n\n const lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n const factor = 0.25; // Smoothing factor\n\n const step = () => {\n if (!targetXRange) return;\n const [tMin, tMax] = targetXRange;\n\n const cMin = lerp(currentXRange![0], tMin, factor);\n const cMax = lerp(currentXRange![1], tMax, factor);\n\n plots.forEach(({ uplot: u }) => {\n u.setScale('x', { min: cMin, max: cMax });\n });\n\n if (Math.abs(cMin - tMin) > 0.0001 || Math.abs(cMax - tMax) > 0.0001)\n animId = requestAnimationFrame(step);\n else animId = null;\n };\n animId = requestAnimationFrame(step);\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function loadTrack(track: TrackData, others: TrackData[] = [], deferRender = false) {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n allTracks = others;\n\n // Detect which metrics are available in this file\n availableMetrics = new Set(\n Object.entries(METRICS)\n .filter(([, def]) => track.points.some((p) => p[def.field] != null))\n .map(([key]) => key),\n );\n\n // If no metrics are active (e.g. first load), default to core overview metrics\n if (activeMetrics.size === 0) {\n activeMetrics = new Set(['elevation'].filter((m) => availableMetrics.has(m)));\n }\n\n // Sync the pill buttons in the toolbar\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n const metric = pill.dataset.metric!;\n const isAvailable = availableMetrics.has(metric);\n pill.classList.toggle('active', isAvailable && activeMetrics.has(metric));\n pill.classList.toggle('disabled', !isAvailable);\n });\n\n currentTrack = track;\n if (deferRender) {\n updateStats(track);\n } else {\n render();\n }\n }\n\n function clear() {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n currentTrack = null;\n destroyPlots();\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
Select a track to view analysis
\n `;\n }\n const chartStats = document.getElementById('chart-stats');\n if (chartStats) chartStats.classList.add('hidden');\n clearSelectionStats();\n mapColorMetric = null;\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n }\n\n function resetState() {\n if (animId !== null) {\n cancelAnimationFrame(animId);\n animId = null;\n }\n activeMetrics = new Set(['elevation']);\n availableMetrics = new Set();\n smoothedMetrics = new Set(['speed', 'gradient', 'vam', 'temperature']);\n metricsIncludingZero = new Set(['power']);\n xAxis = 'time';\n allTracks = [];\n currentXRange = null;\n targetXRange = null;\n lastMouseXVal = null;\n lastHistMouseEvent = null;\n hoveredHistData = null;\n hoveredHistCanvas = null;\n statsVisible = true;\n clear();\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n pill.classList.remove('disabled', 'overflow-hidden');\n });\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.add('hidden');\n const toolbar = document.getElementById('chart-toolbar');\n if (toolbar) toolbar.classList.remove('collapsed');\n document.querySelectorAll('#x-axis-ctrl .seg-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.axis === 'time');\n });\n }\n\n function toggleMetric(key: string) {\n if (activeMetrics.has(key)) activeMetrics.delete(key);\n else activeMetrics.add(key);\n if (currentTrack) render(true);\n }\n\n function setSmooth(metricKey: string, enabled: boolean, skipRender = false) {\n const has = smoothedMetrics.has(metricKey);\n if (enabled && !has) {\n smoothedMetrics.add(metricKey);\n if (currentTrack && !skipRender) render(true);\n } else if (!enabled && has) {\n smoothedMetrics.delete(metricKey);\n if (currentTrack && !skipRender) render(true);\n }\n }\n\n function setZeroInclusion(metricKey: string, includeZero: boolean) {\n const has = metricsIncludingZero.has(metricKey);\n if (includeZero && !has) {\n metricsIncludingZero.add(metricKey);\n if (currentTrack) render(true);\n } else if (!includeZero && has) {\n metricsIncludingZero.delete(metricKey);\n if (currentTrack) render(true);\n }\n }\n\n function setActiveMetrics(keys: string[]) {\n activeMetrics = new Set(keys);\n if (currentTrack) render(true);\n // Sync the pill buttons\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n });\n }\n\n function setXAxis(axis: string) {\n if (xAxis === axis || !currentTrack) {\n xAxis = axis;\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n\n // Helper to convert a value from OLD axis to NEW axis\n const convert = (val: number | null) => {\n if (val === null) return null;\n // We need to find the point index closest to 'val' on the OLD axis\n let idx = 0;\n if (xAxis === 'distance') {\n const dTarget = val * 1000;\n idx = pts.findIndex((p) => (p.dist || 0) >= dTarget);\n } else {\n const tTarget = t0 + val * 1000;\n idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n }\n if (idx === -1) idx = pts.length - 1;\n\n // Now get the value at this index on the NEW axis\n if (axis === 'distance') return (pts[idx].dist || 0) / 1000;\n else return ((pts[idx].time || t0) - t0) / 1000;\n };\n\n // Convert selection\n if (selAnchorVal !== null) selAnchorVal = convert(selAnchorVal);\n if (selEndVal !== null) selEndVal = convert(selEndVal);\n\n // Convert zoom range (from first plot)\n let newRange: [number, number] | null = null;\n if (plots.length) {\n const u = plots[0].uplot;\n const r0 = convert(u.scales.x!.min!);\n const r1 = convert(u.scales.x!.max!);\n if (r0 !== null && r1 !== null) newRange = [r0, r1];\n }\n\n xAxis = axis;\n render(true);\n\n // Apply converted zoom\n if (newRange) {\n scaleSyncing = true;\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: newRange![0], max: newRange![1] }));\n });\n scaleSyncing = false;\n }\n }\n\n function toggleStats() {\n statsVisible = !statsVisible;\n plots.forEach(({ histCol }) => histCol.classList.toggle('visible', statsVisible));\n resize();\n }\n\n function setMapColorChangeCb(cb: (data: { pts: TrackPoint[]; colors: string[] } | null) => void) {\n onMapColorChangeCb = cb;\n }\n\n function toggleMapColor(key: string | null, skipRender = false) {\n if (mapColorMetric === key || key === null) {\n mapColorMetric = null;\n _updateMapColorBtns();\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n } else {\n mapColorMetric = key;\n _updateMapColorBtns();\n _fireMapColorCb();\n }\n // Re-render to show/hide colored fills on the graphs\n if (currentTrack && !skipRender) render(true);\n }\n\n function _updateMapColorBtns() {\n document.querySelectorAll('.map-color-btn').forEach((el) => {\n const b = el as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === mapColorMetric);\n });\n }\n\n function _fireMapColorCb() {\n if (!onMapColorChangeCb || !mapColorMetric || !currentTrack) return;\n const plot = plots.find((p) => p.metricKey === mapColorMetric);\n if (!plot) return;\n const colors = _computePointColors(mapColorMetric, plot.yData);\n onMapColorChangeCb({ pts: currentTrack.points, colors });\n }\n\n function _computePointColors(key: string, yData: (number | null)[]): string[] {\n const vals = yData.filter((v): v is number => v != null && isFinite(v));\n if (!vals.length) return yData.map(() => '#888896');\n const min = Math.min(...vals),\n max = Math.max(...vals);\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n return yData.map((v) => {\n if (v == null || !isFinite(v)) return '#888896';\n if (key === 'gradient') return gradientColor(v);\n if (key === 'speed') {\n if (speedMode === 'pace') {\n const speed = (paceUnit === 'km' ? 1000 : 100) / v;\n return speedColor(speed);\n }\n return speedColor(v);\n }\n const t = max === min ? 0.5 : Math.max(0, Math.min(1, (v - min) / (max - min)));\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25);\n if (t <= 0.5) return lerpHex('#91bfdb', '#fee090', (t - 0.25) / 0.25);\n if (t <= 0.75) return lerpHex('#fee090', '#fc8d59', (t - 0.5) / 0.25);\n return lerpHex('#fc8d59', '#d73027', (t - 0.75) / 0.25);\n });\n }\n\n function resetZoom() {\n cancelSelection();\n }\n\n function cancelSelection() {\n selAnchorVal = null;\n selEndVal = null;\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n\n // Reset individual histogram pins\n plots.forEach((p) => {\n p.pinnedHistY = null;\n });\n\n updateSelOverlay();\n redrawHistograms();\n\n // Perform the actual zoom reset\n scaleSyncing = true;\n plots.forEach(({ uplot: u, xData }) => {\n u.batch(() => u.setScale('x', { min: xData[0]!, max: xData[xData.length - 1]! }));\n u._strasse?.updateHeaderStats(xData[0]!, xData[xData.length - 1]!);\n });\n scaleSyncing = false;\n\n if (onRangeChangeCb) onRangeChangeCb(null, null, xAxis);\n }\n\n function setSelectionStats(stats: TrackStats) {\n if (!selStatsEl) return;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt(\n 'sel-distance',\n stats.totalDist != null ? `${(stats.totalDist / 1000).toFixed(1)} km` : '\u2014',\n );\n fmt('sel-duration', stats.duration != null ? fmtSecs(Math.floor(stats.duration / 1000)) : '\u2014');\n fmt('sel-elevation', stats.elevGain != null ? `${Math.round(stats.elevGain)} m` : '\u2014');\n fmt(\n 'sel-avg-speed',\n stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014',\n );\n fmt('sel-avg-power', stats.avgPower != null ? `${stats.avgPower} W` : '\u2014');\n fmt('sel-avg-hr', stats.avgHR != null ? `${stats.avgHR} bpm` : '\u2014');\n fmt('sel-avg-temp', stats.avgTemp != null ? `${stats.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n selStatsEl.classList.remove('hidden');\n if (resetSelBtn) resetSelBtn.classList.remove('hidden');\n }\n\n function clearSelectionStats() {\n if (selStatsEl) selStatsEl.classList.add('hidden');\n if (resetSelBtn) resetSelBtn.classList.add('hidden');\n [\n 'sel-distance',\n 'sel-duration',\n 'sel-elevation',\n 'sel-avg-speed',\n 'sel-avg-power',\n 'sel-avg-hr',\n 'sel-avg-temp',\n ].forEach((id) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = '--';\n });\n }\n\n // Called on boot to restore a saved selection without re-firing onRangeChangeCb\n // xMin/xMax are ALWAYS provided in Time (seconds from start)\n function restoreSelection(tMin: number, tMax: number, deferRender = false) {\n if (!currentTrack) return;\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const totalDuration = ((pts[pts.length - 1]?.time || 0) - t0) / 1000;\n\n // If values look like absolute timestamps in ms, convert to seconds from start\n if (tMin > 1e12) tMin = (tMin - t0) / 1000;\n if (tMax > 1e12) tMax = (tMax - t0) / 1000;\n\n // Crop to max limits of the track\n tMin = Math.max(0, Math.min(tMin, totalDuration));\n tMax = Math.max(0, Math.min(tMax, totalDuration));\n\n const convert = (tOffset: number) => {\n if (xAxis === 'time') return tOffset;\n const tTarget = t0 + tOffset * 1000;\n let idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n if (idx === -1) idx = pts.length - 1;\n return (pts[idx].dist || 0) / 1000;\n };\n\n const xMin = convert(tMin);\n const xMax = convert(tMax);\n\n selAnchorVal = xMin;\n selEndVal = xMax;\n currentXRange = [xMin, xMax];\n if (deferRender) return;\n scaleSyncing = true; // suppress the setScale \u2192 onRangeChangeCb loop\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: xMin, max: xMax }));\n });\n scaleSyncing = false;\n updateAnchorLines();\n redrawHistograms();\n }\n\n function resize() {\n if (!plots.length || !container) return;\n const w = Math.round(\n Math.max(\n 100,\n container.getBoundingClientRect().width -\n ROW_BODY_PADDING -\n (statsVisible ? HIST_W + HIST_GAP : 0),\n ),\n );\n let anyResized = false;\n plots.forEach(({ uplot: u, histCanvas, histData }) => {\n if (w !== u.width) {\n u.setSize({ width: w, height: u.height });\n anyResized = true;\n if (statsVisible && histCanvas && histData) drawHistogram(histCanvas, histData, u.height);\n }\n });\n if (anyResized) updateSelOverlay();\n }\n\n // \u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function render(keepState = false) {\n let savedRange: [number, number] | null = null;\n let savedScroll = 0;\n if (keepState && container) savedScroll = container.scrollTop;\n\n if (keepState && currentXRange) {\n savedRange = [currentXRange[0], currentXRange[1]];\n } else if (keepState && plots.length) {\n const u = plots[0].uplot;\n savedRange = [u.scales.x!.min!, u.scales.x!.max!];\n }\n\n if (!currentTrack) {\n destroyPlots(keepState);\n return;\n }\n const pts = currentTrack.points;\n if (!pts.length) {\n destroyPlots(keepState);\n return;\n }\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n const available = [...activeMetrics].filter((m) =>\n pts.some((p) => p[METRICS[m].field] != null),\n );\n if (!available.length) {\n destroyPlots(keepState);\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
No data for selected metrics
\n `;\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n\n const containerW = container ? container.getBoundingClientRect().width : 800;\n const w = Math.round(\n Math.max(100, containerW - ROW_BODY_PADDING - (statsVisible ? HIST_W + HIST_GAP : 0)),\n );\n\n const canReuse =\n keepState &&\n renderedTrack === currentTrack &&\n renderedXAxis === xAxis &&\n renderedSpeedMode === speedMode &&\n renderedMapColorMetric === mapColorMetric &&\n plots.length > 0;\n\n let xData: (number | null)[];\n if (canReuse) {\n xData = plots[0].xData;\n } else if (xAxis === 'distance') {\n xData = pts.map((p) => (p.dist || 0) / 1000);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n let lastValidX = 0;\n xData = pts.map((p) => {\n if (p.time != null) {\n lastValidX = (p.time - t0) / 1000;\n return lastValidX;\n }\n return lastValidX; // monotonic fallback\n });\n }\n\n const existingByKey = new Map();\n if (canReuse) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const availSet = new Set(available);\n for (const p of plots) {\n const isSmoothed = smoothedMetrics.has(p.metricKey);\n const isIncZero = metricsIncludingZero.has(p.metricKey);\n if (\n availSet.has(p.metricKey) &&\n p.smoothed === isSmoothed &&\n p.incZero === isIncZero &&\n p.w === w\n ) {\n existingByKey.set(p.metricKey, p);\n } else {\n syncKey!.unsub(p.uplot);\n p.uplot.destroy();\n p.row.remove();\n }\n }\n plots = [];\n } else {\n destroyPlots(keepState);\n }\n\n if (container) {\n const nextSiblingRows: (HTMLElement | null)[] = new Array(available.length).fill(null);\n let nextExisting: HTMLElement | null = null;\n for (let i = available.length - 1; i >= 0; i--) {\n nextSiblingRows[i] = nextExisting;\n const ex = existingByKey.get(available[i]);\n if (ex) nextExisting = ex.row;\n }\n\n available.forEach((key, idx) => {\n const reused = existingByKey.get(key);\n if (reused) {\n plots.push(reused);\n const uplot = reused.uplot;\n const s = (uplot as any)._strasse;\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n uplot.batch(() => {\n if (\n savedRange &&\n (uplot.scales.x!.min !== savedRange[0] || uplot.scales.x!.max !== savedRange[1])\n ) {\n uplot.setScale('x', { min: savedRange[0], max: savedRange[1] });\n } else {\n s?.updateHeaderStats(uplot.scales.x!.min!, uplot.scales.x!.max!, uplot);\n uplot.redraw(false);\n }\n });\n scaleSyncing = prevSync;\n\n let initHoverBinI: number | null = null;\n if (\n pinnedPtIdx != null &&\n reused.xData[pinnedPtIdx] != null &&\n reused.yData[pinnedPtIdx] != null\n ) {\n buildHistBins(reused.histData);\n if (reused.histData.min != null && reused.histData.max != null) {\n const span = reused.histData.max - reused.histData.min || 1;\n initHoverBinI = Math.min(\n reused.histData.BINS - 1,\n Math.floor(\n ((reused.yData[pinnedPtIdx]! - reused.histData.min) / span) *\n reused.histData.BINS,\n ),\n );\n reused.hoveredHistY = reused.yData[pinnedPtIdx];\n }\n }\n drawHistogram(reused.histCanvas, reused.histData, 130, initHoverBinI);\n return;\n }\n\n let def = METRICS[key];\n\n let transform = def.transform;\n let fmt = def.fmt;\n let fmtAxis = def.fmtAxis;\n let unit = def.unit;\n let label = def.label;\n\n if (key === 'speed' && speedMode === 'pace') {\n label = 'Pace';\n unit = `min/${paceUnit}`;\n fmt = (v) => fmtPace(v);\n fmtAxis = (v) => fmtPace(v);\n transform = (v) => {\n if (v == null || v < 0.1) return null;\n return (paceUnit === 'km' ? 1000 : 100) / v;\n };\n\n def = { ...def, label, unit, fmt, fmtAxis, transform };\n }\n\n let yData = def.compute\n ? def.compute(pts, fillNulls)\n : fillNulls(\n pts.map((p) => {\n const v = p[def.field] as number;\n return v != null && transform ? transform(v) : v;\n }),\n );\n\n if (smoothedMetrics.has(key)) yData = gaussianSmooth(yData, def.smoothSigma || 2);\n\n createChart(key, def, xData, yData, w, pts, savedRange, nextSiblingRows[idx]);\n });\n }\n\n renderedTrack = currentTrack;\n renderedXAxis = xAxis;\n renderedSpeedMode = speedMode;\n renderedMapColorMetric = mapColorMetric;\n\n updateStats(currentTrack);\n // Restore anchor/end lines if a selection was active\n if (selAnchorVal != null && selEndVal != null) updateAnchorLines();\n // Re-apply map color if active\n _updateMapColorBtns();\n if (mapColorMetric) _fireMapColorCb();\n\n if (keepState && container && savedScroll > 0) container.scrollTop = savedScroll;\n }\n\n // \u2500\u2500 Create one chart row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function createChart(\n metricKey: string,\n def: MetricDefinition,\n xData: (number | null)[],\n yData: (number | null)[],\n w: number,\n pts: TrackPoint[],\n initialRange: [number, number] | null = null,\n insertBeforeEl: HTMLElement | null = null,\n ) {\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n\n // Gradient data: smooth over a 20 m distance window (\u00B110 m each side)\n const gradData = metricKey === 'elevation' ? smoothGradient(pts, 20) : null;\n const row = document.createElement('div');\n row.className = 'chart-row';\n row.dataset.metric = metricKey;\n row.style.setProperty('--chart-color', def.color);\n\n // Header\n const header = document.createElement('div');\n header.className = `chart-row-header${statsVisible ? ' with-histogram' : ''}`;\n\n const labelEl = document.createElement('div');\n labelEl.className = 'chart-row-label-group';\n labelEl.innerHTML = `\n ${def.icon}\n ${def.label}\n `;\n\n // Smoothing toggle\n const smoothBtn = document.createElement('button');\n smoothBtn.className = `icon-btn mini smooth-btn${smoothedMetrics.has(metricKey) ? ' active' : ''}`;\n smoothBtn.title = 'Toggle data smoothing';\n smoothBtn.innerHTML = `${smoothedMetrics.has(metricKey) ? 'blur_on' : 'blur_off'}`;\n smoothBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (smoothedMetrics.has(metricKey)) smoothedMetrics.delete(metricKey);\n else smoothedMetrics.add(metricKey);\n\n render(true); // Re-render all charts to keep sync if needed (though only this one changes data)\n });\n\n const mapColorBtn = document.createElement('button');\n\n mapColorBtn.className = `map-color-btn icon-btn${mapColorMetric === metricKey ? ' active' : ''}`;\n mapColorBtn.dataset.metric = metricKey;\n mapColorBtn.title = 'Color map track by this metric';\n mapColorBtn.innerHTML = 'colorize';\n mapColorBtn.addEventListener('click', () => toggleMapColor(metricKey));\n\n // Zero-filter toggle (Cadence/Power/Speed)\n let zeroBtn: HTMLButtonElement | null = null;\n if (metricKey === 'cadence' || metricKey === 'power' || metricKey === 'speed') {\n zeroBtn = document.createElement('button');\n const incZero = metricsIncludingZero.has(metricKey);\n zeroBtn.className = `icon-btn mini${incZero ? ' active' : ''}`;\n zeroBtn.title = incZero ? 'Currently INCLUDING 0 values' : 'Currently EXCLUDING 0 values';\n zeroBtn.innerHTML = `${incZero ? 'exposure_zero' : 'mobile_off'}`;\n zeroBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (metricsIncludingZero.has(metricKey)) metricsIncludingZero.delete(metricKey);\n else metricsIncludingZero.add(metricKey);\n render(true);\n });\n }\n\n const statsTotalEl = document.createElement('div');\n statsTotalEl.className = 'chart-stats-total';\n\n const statsSelEl = document.createElement('div');\n statsSelEl.className = 'chart-stats-selection';\n\n const statsContainer = document.createElement('div');\n statsContainer.className = 'chart-row-stats-container';\n statsContainer.append(statsTotalEl, statsSelEl);\n\n const actionsEl = document.createElement('div');\n actionsEl.className = 'chart-row-actions';\n actionsEl.append(smoothBtn, mapColorBtn);\n\n const rightActionsEl = document.createElement('div');\n rightActionsEl.className = 'chart-row-right-actions';\n\n if (metricKey === 'speed') {\n const paceToggle = document.createElement('div');\n paceToggle.className = 'seg-ctrl';\n paceToggle.innerHTML = `\n \n \n `;\n paceToggle.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const mode = btn.dataset.mode;\n if (mode === 'speed' || mode === 'pace') {\n const isDefault = mode === defaultMode;\n UrlState.patch({ speed_mode: isDefault ? null : mode });\n render(true);\n }\n });\n rightActionsEl.append(paceToggle);\n }\n\n if (zeroBtn) rightActionsEl.append(zeroBtn);\n\n header.append(labelEl, actionsEl, statsContainer, rightActionsEl);\n\n const rowBody = document.createElement('div');\n rowBody.className = 'chart-row-body';\n\n const plotEl = document.createElement('div');\n plotEl.style.position = 'relative';\n rowBody.appendChild(plotEl);\n\n const fixedMinLabel = document.createElement('div');\n fixedMinLabel.className = 'fixed-x-label fixed-x-min';\n const fixedMaxLabel = document.createElement('div');\n fixedMaxLabel.className = 'fixed-x-label fixed-x-max';\n plotEl.append(fixedMinLabel, fixedMaxLabel);\n\n const histCol = document.createElement('div');\n histCol.className = `hist-col${statsVisible ? ' visible' : ''}`;\n const histCanvas = document.createElement('canvas');\n histCanvas.className = 'hist-canvas';\n histCol.appendChild(histCanvas);\n rowBody.appendChild(histCol);\n\n row.append(header, rowBody);\n\n const isDistAxis = xAxis === 'distance';\n\n function formatX(v: number, range: number): string {\n if (v == null) return '';\n if (isDistAxis) {\n const dec = range < 1 ? 3 : range < 5 ? 2 : range < 20 ? 1 : 0;\n return `${v.toFixed(dec)} km`;\n } else {\n const absV = Math.abs(v);\n const h = Math.floor(absV / 3600);\n const m = Math.floor((absV % 3600) / 60);\n const s = Math.round(absV % 60);\n const hh = h > 0 ? `${h}:` : '';\n const mm = h > 0 ? String(m).padStart(2, '0') : String(m);\n const ss = String(s).padStart(2, '0');\n return `${v < 0 ? '-' : ''}${hh}${mm}:${ss}`;\n }\n }\n\n const incZeroDefault =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Compute global Y range and full-track stats in a single pass\n let gMin = Infinity,\n gMax = -Infinity,\n allSum = 0,\n allCount = 0,\n filtMin = Infinity,\n filtMax = -Infinity,\n filtSum = 0,\n filtCount = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n allSum += v;\n allCount++;\n if (v !== 0 || incZeroDefault) {\n if (v < filtMin) filtMin = v;\n if (v > filtMax) filtMax = v;\n filtSum += v;\n filtCount++;\n }\n }\n if (allCount === 0) {\n gMin = 0;\n gMax = 100;\n }\n const fullStatsAll = allCount ? { min: gMin, max: gMax, avg: allSum / allCount } : null;\n const fullStatsFiltered = filtCount\n ? { min: filtMin, max: filtMax, avg: filtSum / filtCount }\n : null;\n const gPad = Math.abs(gMax - gMin) * 0.1 || 1;\n const fixedYRange = [gMin - gPad, gMax + gPad];\n\n let statsTotalInitialized = false;\n\n // Per-range stats\n function updateHeaderStats(visibleMin: number, visibleMax: number, u?: uPlot) {\n const incZero =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Update fixed X labels\n const range = visibleMax - visibleMin;\n fixedMinLabel.textContent = formatX(visibleMin, range);\n fixedMaxLabel.textContent = formatX(visibleMax, range);\n\n const getHtml = (xMin: number, xMax: number, isFull = false) => {\n const s =\n isFull && incZero === incZeroDefault\n ? fullStatsFiltered\n : rangeStats(xData, yData, xMin, xMax, incZero);\n if (!s) return '';\n\n let h = `\n align_flex_end${def.fmt(s.min, true)} ${def.unit}\n align_center${def.fmt(s.avg, true)} ${def.unit}\n align_flex_start${def.fmt(s.max, true)} ${def.unit}\n `;\n\n if (metricKey === 'elevation') {\n const es = elevationRangeStats(pts, xMin, xMax);\n h += `\n trending_up+${Math.round(es.gain)} m\n trending_down-${Math.round(es.loss)} m\n `;\n }\n return h;\n };\n\n if (!statsTotalInitialized) {\n statsTotalInitialized = true;\n statsTotalEl.innerHTML = `all_inclusive${getHtml(\n xData[0]!,\n xData[xData.length - 1]!,\n true,\n )}`;\n statsTotalEl.querySelector('.all-chip')?.addEventListener('click', (e) => {\n e.stopPropagation();\n cancelSelection();\n });\n }\n\n if (selAnchorVal !== null && selEndVal !== null) {\n statsSelEl.innerHTML = getHtml(selAnchorVal, selEndVal, false);\n statsSelEl.style.display = 'flex';\n statsSelEl.style.setProperty('--sel-color', def.color);\n } else {\n statsSelEl.style.display = 'none';\n }\n }\n let initializingScale = false;\n const uOpts: uPlot.Options = {\n width: w,\n height: 130,\n padding: [4, 0, 0, 0],\n cursor: {\n sync: {\n key: syncKey!.key,\n },\n drag: { x: true, y: false, uni: 16 },\n focus: { prox: 16 },\n points: {\n size: 7,\n stroke: '#0e0e10',\n width: 2,\n fill: (metricKey === 'elevation'\n ? (u: uPlot, _si: number) => gradientColor(gradData ? gradData[u.cursor.idx!]! : null)\n : def.color) as any,\n },\n x: false,\n y: false,\n },\n select: {\n show: true,\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n },\n legend: { show: false },\n scales: {\n x: {\n time: false,\n range: (_u: uPlot, mn: number, mx: number) => [mn, mx],\n min: initialRange ? initialRange[0] : undefined,\n max: initialRange ? initialRange[1] : undefined,\n },\n y: {\n range: () => fixedYRange as [number, number],\n dir: metricKey === 'speed' && speedMode === 'pace' ? -1 : 1,\n },\n },\n axes: [\n {\n side: 2, // bottom\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: {\n show: true,\n stroke: '#2e2e34',\n },\n size: 30,\n space: 80,\n font: '10px system-ui, sans-serif',\n splits: (u: uPlot, axisIdx: number, scaleMin: number, scaleMax: number) => {\n const range = scaleMax - scaleMin;\n const width = u.bbox.width > 0 ? u.bbox.width : u.width;\n const targetLabels = width / 80;\n const idealIncr = range / targetLabels;\n\n let incrs;\n if (!isDistAxis) {\n // Time in seconds\n incrs = [\n 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 14400, 28800, 43200,\n 86400, 604800, 2592000, 31536000,\n ];\n } else {\n incrs = [\n 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000,\n 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000,\n ];\n }\n\n let incr = incrs[incrs.length - 1];\n for (let i = 0; i < incrs.length; i++) {\n if (incrs[i] >= idealIncr) {\n incr = incrs[i];\n break;\n }\n }\n\n const splits = [];\n let val = Math.ceil(scaleMin / incr) * incr;\n const precision = incr < 1 ? 2 : 0;\n\n while (val <= scaleMax) {\n const pos = u.valToPos(val, 'x', true);\n if (pos >= u.bbox.left + 80 && pos <= u.bbox.left + u.bbox.width - 80)\n splits.push(Number(val.toFixed(precision)));\n\n val += incr;\n }\n return splits;\n },\n values: ((_u: uPlot, vals: number[]) => {\n const range = (_u.scales.x?.max ?? 1) - (_u.scales.x?.min ?? 0);\n\n return vals.map((v) => {\n if (v == null) return '';\n const pos = _u.valToPos(v, 'x', true);\n // Strict 80px margin to prevent overlapping with fixed labels or Y axis\n if (pos < _u.bbox.left + 80 || pos > _u.bbox.left + _u.bbox.width - 80) return null;\n return formatX(v, range);\n });\n }) as any,\n },\n {\n side: 3, // left\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: { stroke: '#2e2e34' },\n size: 55,\n font: '10px system-ui, sans-serif',\n values: ((_u: uPlot, vals: number[]) =>\n vals.map((v) => (v != null ? def.fmtAxis(v) : ''))) as any,\n },\n ],\n series: [\n {},\n // Main selected track series\n {\n label: def.label,\n stroke: 'rgba(0,0,0,0)', // Stroke handled in draw hooks for layering\n width: 0,\n points: { show: false },\n paths: () => null,\n },\n ],\n hooks: {\n draw: [\n (u: uPlot) => {\n const top = u.bbox.top + u.bbox.height + 5; // 5px below plot area!\n fixedMinLabel.style.top = `${top}px`;\n fixedMinLabel.style.left = `${u.bbox.left}px`;\n\n fixedMaxLabel.style.top = `${top}px`;\n fixedMaxLabel.style.left = `${u.bbox.left + u.bbox.width}px`;\n fixedMaxLabel.style.transform = 'translateX(-100%)';\n },\n // 1. (bottom) Color / metric color of the selected track\n (u: uPlot) => {\n if (metricKey === 'gears') {\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n } else if (metricKey === 'elevation') {\n drawElevationGradient(u, xData as number[], yData as number[], gradData);\n } else if (metricKey === 'gradient') {\n drawGradientChart(u, xData as number[], yData as number[]);\n } else if (mapColorMetric === metricKey) {\n drawMetricColorFill(u, xData as number[], yData as number[], pts, metricKey);\n } else {\n // Normal colored line\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n }\n },\n\n // 2. Pinned point (middle)\n (u: uPlot) => {\n const plot = plots.find((p) => p.uplot === u);\n if (!plot) return;\n\n const s = (u as any)._strasse;\n // Priority 1: Global pinned point (all charts)\n if (pinnedPtIdx != null) {\n drawPinnedDot(u, xData, yData, def.color, def, pts, metricKey);\n } else {\n if (s && s.pinYVal) s.pinYVal.style.display = 'none';\n\n // Priority 2: Individual histogram pinned Y-pos (this chart only)\n if (plot.pinnedHistY != null)\n drawYAxisHighlight(u, xData, yData, plot.pinnedHistY, def.color, def);\n }\n },\n\n // 3. Pinned & Hover elements (labels, vertical lines)\n (u: uPlot) => {\n const hIdx = u.cursor.idx;\n const hasPinned = pinnedPtIdx != null;\n\n let hasHover = hIdx != null && u.cursor.left! >= 0;\n if (hasHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[hIdx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) hasHover = false;\n }\n\n // B. Draw Hover vertical line\n if (hasHover && hIdx !== pinnedPtIdx)\n drawVerticalLineOnly(u, pts, hIdx!, hexToRgba(def.color, 0.4), 1.0);\n\n // C. Bold selection x-axis line & span pill\n if (selAnchorVal != null && selEndVal != null) {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ax = u.valToPos(selAnchorVal, 'x', true);\n const ex = u.valToPos(selEndVal, 'x', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.lineWidth = 3 * dpr;\n ctx.strokeStyle = def.color;\n ctx.moveTo(ax, bb.top + bb.height);\n ctx.lineTo(ex, bb.top + bb.height);\n ctx.stroke();\n\n const span = Math.abs(selEndVal - selAnchorVal);\n const label = xAxis === 'distance' ? `${span.toFixed(2)} km` : fmtSecs(span);\n const fontSize = 9 * dpr;\n const fontStr = `bold ${fontSize}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n\n const visibleL = Math.max(bb.left, ax);\n const visibleR = Math.min(bb.left + bb.width, ex);\n const visibleW = visibleR - visibleL;\n\n if (visibleW > tw + 14 * dpr) {\n const padH = 5 * dpr;\n const padV = 2 * dpr;\n const bw = tw + padH * 2;\n const bh = fontSize + padV * 2;\n const bx = (visibleL + visibleR) / 2 - bw / 2;\n const by = bb.top + bb.height - bh / 2;\n\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = def.color;\n ctx.fill();\n\n ctx.fillStyle = '#000';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2);\n }\n ctx.restore();\n }\n\n // D. Draw label pills (on top)\n // Pinned labels first (semi-transparent)\n if (hasPinned) drawXAxisLabels(u, pts, pinnedPtIdx!, def.color, true, 0.7);\n\n // Hover labels last (fully opaque, topmost)\n if (hasHover && hIdx !== pinnedPtIdx)\n drawXAxisLabels(u, pts, hIdx!, def.color, true, 1.0);\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (scaleSyncing) return;\n const idx = u.cursor.idx;\n\n // Trigger redraw on cursor move to ensure custom canvas markers (hover lines/labels) update live\n // Note: uPlot handles cross-chart sync when syncKey is used.\n u.redraw(false);\n\n // Track current x-value for keyboard navigation\n if (u.cursor.left! >= 0) lastMouseXVal = u.posToVal(u.cursor.left!, 'x');\n else lastMouseXVal = null;\n\n // \u2500\u2500 Floating y-value next to cursor dot \u2500\u2500\n const s = (u as any)._strasse;\n let showHover = idx != null && yData[idx] != null;\n\n // Distance threshold: if no pinned point, check proximity to data line\n if (showHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[idx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) showHover = false;\n }\n\n if (s) {\n if (showHover)\n updateTooltip(\n u,\n s.curYVal,\n idx!,\n xData as number[],\n yData as number[],\n pts,\n def,\n metricKey,\n );\n else s.curYVal.style.display = 'none';\n }\n\n // Map marker\n if (!cursorSyncing) {\n if (idx != null && pts[idx]) {\n if (onCursorMoveCb && (pinnedPtIdx != null || showHover)) {\n onCursorMoveCb(pts[idx]);\n } else if (onCursorMoveCb && !showHover) {\n // If we're too far and nothing is pinned, hide map cursor\n onCursorMoveCb(null);\n }\n } else if (idx === null && onCursorMoveCb) {\n onCursorMoveCb(null);\n }\n }\n\n // Highlight matching histogram bucket\n if (idx != null && yData[idx] != null) {\n const { min, max } = histData;\n if (min != null && max != null) {\n const span = max - min || 1;\n const binI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[idx]! - min) / span) * histData.BINS),\n );\n if (plot.hoveredHistY !== yData[idx]) {\n plot.hoveredHistY = yData[idx];\n drawHistogram(histCanvas, histData, 130, binI);\n }\n }\n } else if (plot.hoveredHistY !== null) {\n plot.hoveredHistY = null;\n drawHistogram(histCanvas, histData, 130);\n }\n },\n ],\n\n setScale: [\n (u: uPlot, key: string) => {\n if (key !== 'x' || initializingScale) return;\n const { min, max } = u.scales.x!;\n\n // Sync currentXRange so keyboard navigation baseline is always accurate\n currentXRange = [min!, max!];\n\n // Update header stats for VISIBLE range\n updateHeaderStats(min as number, max as number, u);\n\n if (scaleSyncing) return;\n\n // Clear keyboard target when user interacts via mouse\n if (!updatingRange) targetXRange = null;\n\n // Sync sibling plots\n scaleSyncing = true;\n plots.forEach(({ uplot: other }) => {\n if (other !== u) other.batch(() => other.setScale('x', { min: min!, max: max! }));\n });\n scaleSyncing = false;\n\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb && selAnchorVal !== null)\n onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n },\n ],\n\n setSelect: [\n (u: uPlot) => {\n if (updatingRange) return;\n targetXRange = null;\n const { left, width } = u.select;\n if (width > 0) {\n const min = u.posToVal(left, 'x');\n const max = u.posToVal(left + width, 'x');\n selAnchorVal = min;\n selEndVal = max;\n\n // Sync stats to new selection\n updateHeaderStats(u.scales.x!.min!, u.scales.x!.max!, u);\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n\n // Clear uPlot's internal selection immediately so it doesn't block WASD/interaction\n u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);\n }\n },\n ],\n },\n };\n\n // \u2500\u2500 Overlay (pointer-events off except handles) \u2500\u2500\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5';\n\n // Selection fill\n const selFill = document.createElement('div');\n selFill.className = 'sel-fill';\n selFill.style.display = 'none';\n\n // Anchor line + label + drag handle\n const anchorLine = document.createElement('div');\n anchorLine.className = 'sel-line sel-line-anchor';\n anchorLine.style.display = 'none';\n\n const anchorLabel = document.createElement('div');\n anchorLabel.className = 'sel-line-label sel-line-label-anchor';\n anchorLabel.style.display = 'none';\n\n const anchorHandle = document.createElement('div');\n anchorHandle.className = 'sel-handle sel-handle-anchor';\n anchorHandle.style.display = 'none';\n\n const anchorMarker = document.createElement('div');\n anchorMarker.className = 'sel-graph-marker';\n anchorMarker.innerHTML =\n 'play_circle';\n anchorMarker.style.display = 'none';\n\n // End line + label + drag handle\n const endLine = document.createElement('div');\n endLine.className = 'sel-line sel-line-end';\n endLine.style.display = 'none';\n\n const endLabel = document.createElement('div');\n endLabel.className = 'sel-line-label sel-line-label-end';\n endLabel.style.display = 'none';\n\n const endHandle = document.createElement('div');\n endHandle.className = 'sel-handle sel-handle-end';\n endHandle.style.display = 'none';\n\n const endMarker = document.createElement('div');\n endMarker.className = 'sel-graph-marker';\n endMarker.innerHTML =\n 'stop_circle';\n endMarker.style.display = 'none';\n\n // Floating cursor y-value\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${def.color};display:none`;\n\n // Floating pinned y-value\n const pinYVal = document.createElement('div');\n pinYVal.className = 'cur-y-val pin';\n pinYVal.style.cssText = `color:${def.color};display:none`;\n\n overlay.append(\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n );\n\n const histData: HistData = {\n yData,\n xData: xData as number[],\n def,\n BINS: 24,\n min: allCount ? gMin : undefined,\n max: allCount ? gMax : undefined,\n fullStats: fullStatsFiltered,\n fullStatsAll,\n };\n const plot: PlotData = {\n uplot: null as any,\n row,\n xData: xData as number[],\n yData,\n def,\n metricKey,\n statsTotalEl,\n statsSelEl,\n histCol,\n histCanvas,\n histData,\n hoveredHistY: null,\n pinnedHistY: null,\n smoothed: smoothedMetrics.has(metricKey),\n incZero: metricsIncludingZero.has(metricKey),\n w,\n };\n histData.plot = plot; // Back-reference for tooltip to trigger redraws\n\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n const uplot = new uPlot(uOpts, [xData, yData] as any, (self, init) => {\n plot.uplot = self as WegPlot;\n plots.push(plot);\n plotEl.appendChild(self.root);\n self.over.appendChild(overlay);\n (self as any)._strasse = {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n updateHeaderStats,\n };\n self.batch(() => {\n init();\n });\n }) as WegPlot;\n scaleSyncing = prevSync;\n\n // \u2500\u2500 Handle drag \u2500\u2500\n attachHandleDrag(anchorHandle, uplot, xData, true);\n attachHandleDrag(endHandle, uplot, xData, false);\n\n // \u2500\u2500 Mouse listeners \u2500\u2500\n let mousedownX: number | null = null;\n uplot.over.addEventListener('mousedown', (e) => {\n if (e.button !== 0) return;\n isDragging = false;\n const rect = uplot.over.getBoundingClientRect();\n const xPx = e.clientX - rect.left;\n mousedownX = xPx;\n });\n uplot.over.addEventListener('mousemove', (e) => {\n if (mousedownX !== null) {\n const rect = uplot.over.getBoundingClientRect();\n if (Math.abs(e.clientX - rect.left - mousedownX) > 5) isDragging = true;\n }\n });\n uplot.over.addEventListener('mouseup', () => {\n mousedownX = null;\n });\n\n // Click to pin point (sticky selection)\n uplot.over.addEventListener('click', () => {\n if (isDragging) return;\n const idx = uplot.cursor.idx;\n if (idx != null && pts[idx]) {\n pinnedPtIdx = idx;\n plots.forEach(({ uplot: u }) => u.redraw(false));\n if (onClickCb) onClickCb(pts[idx], idx);\n if (onPinChangeCb) onPinChangeCb(idx);\n }\n });\n\n row.addEventListener('dblclick', cancelSelection);\n\n let initHoverBinI: number | null = null;\n if (pinnedPtIdx != null && xData[pinnedPtIdx] != null && yData[pinnedPtIdx] != null) {\n buildHistBins(histData);\n if (histData.min != null && histData.max != null) {\n const span = histData.max - histData.min || 1;\n initHoverBinI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[pinnedPtIdx]! - histData.min) / span) * histData.BINS),\n );\n plot.hoveredHistY = yData[pinnedPtIdx];\n }\n }\n\n drawHistogram(histCanvas, histData, 130, initHoverBinI);\n attachHistTooltip(histCanvas, histData);\n if (container) {\n if (insertBeforeEl) container.insertBefore(row, insertBeforeEl);\n else container.appendChild(row);\n }\n }\n\n // \u2500\u2500 Selection overlay (fill + lines + handles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateSelOverlay() {\n updateAnchorLines();\n // Redraw canvas markers (bold selection line + span pill)\n plots.forEach(({ uplot: u }) => u.batch(() => u.redraw(false)));\n }\n\n function updateAnchorLines() {\n plots.forEach(({ uplot: u, def }) => {\n const s = (u as any)._strasse;\n if (!s) return;\n const {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n } = s;\n if (selAnchorVal == null || selEndVal == null) {\n [\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n ].forEach((el: HTMLElement) => {\n el.style.display = 'none';\n });\n return;\n }\n const aX = u.valToPos(selAnchorVal, 'x');\n const eX = u.valToPos(selEndVal, 'x');\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const overW = bb.width / dpr;\n const overH = bb.height / dpr;\n const plotBottom = (bb.top + bb.height) / dpr;\n\n const isAnchorVisible = aX >= 0 && aX <= overW;\n const isEndVisible = eX >= 0 && eX <= overW;\n\n // Fill: clamp left/right to visible area\n const fillL = Math.max(0, aX);\n const fillR = Math.min(overW, eX);\n if (fillR > fillL) {\n selFill.style.left = `${fillL}px`;\n selFill.style.width = `${fillR - fillL}px`;\n selFill.style.top = '0';\n selFill.style.height = `${overH}px`;\n selFill.style.backgroundColor = hexToRgba(def.color, 0.07);\n selFill.style.display = '';\n } else {\n selFill.style.display = 'none';\n }\n\n // Anchor line\n if (isAnchorVisible) {\n anchorLine.style.left = `${aX}px`;\n anchorLine.style.height = `${overH}px`;\n anchorLine.style.borderLeftColor = def.color;\n anchorLine.style.display = '';\n // Anchor label\n const aText = fmtXVal(selAnchorVal);\n anchorLabel.textContent = aText;\n const aLabelW = aText.length * 7 + 10;\n anchorLabel.style.left = aX + aLabelW + 4 < overW ? `${aX + 3}px` : `${aX - aLabelW - 3}px`;\n anchorLabel.style.display = '';\n // Anchor handle\n anchorHandle.style.left = `${aX}px`;\n anchorHandle.style.backgroundColor = def.color;\n anchorHandle.style.display = '';\n // Anchor marker: centered on the bold line\n anchorMarker.style.left = `${aX}px`;\n anchorMarker.style.top = `${plotBottom}px`;\n const aIcon = anchorMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (aIcon) aIcon.style.color = def.color;\n anchorMarker.style.display = '';\n } else {\n [anchorLine, anchorLabel, anchorHandle, anchorMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n\n // End line\n if (isEndVisible) {\n endLine.style.left = `${eX}px`;\n endLine.style.height = `${overH}px`;\n endLine.style.borderLeftColor = def.color;\n endLine.style.display = '';\n // End label\n const eText = fmtXVal(selEndVal);\n endLabel.textContent = eText;\n const eLabelW = eText.length * 7 + 10;\n endLabel.style.left = eX - eLabelW - 3 > 0 ? `${eX - eLabelW - 3}px` : `${eX + 3}px`;\n endLabel.style.display = '';\n // End handle\n endHandle.style.left = `${eX}px`;\n endHandle.style.backgroundColor = def.color;\n endHandle.style.display = '';\n // End marker: centered on the bold line\n endMarker.style.left = `${eX}px`;\n endMarker.style.top = `${plotBottom}px`;\n const eIcon = endMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (eIcon) eIcon.style.color = def.color;\n endMarker.style.display = '';\n } else {\n [endLine, endLabel, endHandle, endMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n });\n }\n\n function fmtXVal(v: number) {\n return xAxis === 'distance' ? `${v.toFixed(2)} km` : fmtSecs(v);\n }\n\n // \u2500\u2500 Handle drag logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function attachHandleDrag(\n handleEl: HTMLElement,\n uplot: uPlot,\n xData: (number | null)[],\n isAnchor: boolean,\n ) {\n // pointer-events enabled on the handle itself\n handleEl.style.pointerEvents = 'auto';\n\n handleEl.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n const startX = e.clientX;\n const startVal = isAnchor ? selAnchorVal : selEndVal;\n const overW = uplot.over.offsetWidth;\n // px-per-data-unit at current zoom\n const xMin = uplot.scales.x!.min!,\n xMax = uplot.scales.x!.max!;\n const pxPerUnit = overW / (xMax - xMin);\n const xFull = [xData[0]!, xData[xData.length - 1]!];\n\n document.body.style.cursor = 'ew-resize';\n isDragging = true;\n\n function onMove(me: MouseEvent) {\n const dx = me.clientX - startX;\n let newVal = (startVal || 0) + dx / pxPerUnit;\n newVal = Math.max(xFull[0], Math.min(xFull[1], newVal));\n\n if (isAnchor) selAnchorVal = Math.min(newVal, (selEndVal || xFull[1]) - 0.001);\n else selEndVal = Math.max(newVal, (selAnchorVal || xFull[0]) + 0.001);\n\n // When dragging handles, we typically want to stay zoomed to the selection?\n // Actually, let's keep the zoom as is, and just update the selection overlay and stats.\n plots.forEach((p) =>\n (p.uplot as any)._strasse?.updateHeaderStats(\n p.uplot.scales.x!.min!,\n p.uplot.scales.x!.max!,\n ),\n );\n updateSelOverlay();\n redrawHistograms();\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n }\n\n function onUp() {\n document.body.style.cursor = '';\n isDragging = false;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n }\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n }\n\n // \u2500\u2500 Histogram logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function buildHistBins(histData: HistData) {\n const { yData, xData, BINS } = histData;\n\n // Cache to avoid re-binning every frame during hover\n if (histData._lastYData === yData && histData.bins) return;\n histData._lastYData = yData;\n\n let min = histData.min;\n let max = histData.max;\n if (min == null || max == null) {\n let lo = Infinity,\n hi = -Infinity,\n cnt = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < lo) lo = v;\n if (v > hi) hi = v;\n cnt++;\n }\n if (!cnt) return;\n min = lo;\n max = hi;\n histData.min = min;\n histData.max = max;\n }\n\n const bins = new Array(BINS).fill(0);\n const binAccum = new Array(BINS).fill(0); // accumulated x-weight per bin (time in s or dist in km)\n\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n bins[bi]++;\n\n // weight by x-delta\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n binAccum[bi] += (next - prev) / 2;\n }\n histData.bins = bins;\n histData.binAccum = binAccum;\n }\n\n function redrawHistograms() {\n plots.forEach(({ histCanvas, histData, uplot: u }) => {\n drawHistogram(histCanvas, histData, u.height);\n });\n }\n\n function drawHistogram(\n canvas: HTMLCanvasElement,\n histData: HistData,\n chartH: number,\n hoverBinI: number | null = null,\n ) {\n const { def, BINS } = histData;\n buildHistBins(histData);\n const { bins, min, max } = histData;\n if (!bins || min == null || max == null) return;\n\n const hasSel = selAnchorVal != null && selEndVal != null;\n\n // Compute selection bins if a range is active and changed\n if (\n hasSel &&\n (histData._lastSelRange?.[0] !== selAnchorVal || histData._lastSelRange?.[1] !== selEndVal)\n ) {\n histData._lastSelRange = [selAnchorVal!, selEndVal!];\n const selBins = new Array(BINS).fill(0);\n const selBinAccum = new Array(BINS).fill(0);\n const { yData, xData } = histData;\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const x = xData[i];\n if (x == null || x < selAnchorVal! || x > selEndVal!) continue;\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n selBins[bi]++;\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n selBinAccum[bi] += (next - prev) / 2;\n }\n histData.selBins = selBins;\n histData.selBinAccum = selBinAccum;\n } else if (!hasSel) {\n histData.selBins = null;\n histData.selBinAccum = null;\n histData._lastSelRange = null;\n }\n const selBins = histData.selBins;\n\n const dpr = window.devicePixelRatio || 1;\n const W = HIST_W;\n const H = chartH;\n\n // Performance: only set dimensions if they changed (resets canvas)\n if (canvas.width !== W * dpr || canvas.height !== H * dpr) {\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n }\n\n const ctx = canvas.getContext('2d')!;\n ctx.resetTransform();\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, W, H);\n\n const peak = Math.max(...bins);\n\n // Measure label width so bars start right after them\n const fmt = (v: number) => def.fmtAxis(v);\n const fontStr = '9px system-ui, sans-serif';\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const labelW = Math.ceil(\n Math.max(\n ctx.measureText(`${fmt(max)} ${def.unit}`).width,\n ctx.measureText(`${fmt(min)} ${def.unit}`).width,\n ),\n );\n\n // Vertical alignment with main graph:\n // uPlot padding: [4, 0, 0, 0]\n // Axis size: 30\n const pad = { t: 4, r: 0, b: 30, l: labelW + 6 };\n histData.padL = pad.l;\n const plotW = W - pad.l - pad.r;\n const plotH = H - pad.t - pad.b;\n\n // bin 0 = lowest values \u2192 drawn at bottom; bin BINS-1 = highest \u2192 drawn at top\n const binY = (i: number) => pad.t + (BINS - 1 - i) * (plotH / BINS);\n const binH = plotH / BINS - 1;\n\n // Full distribution (dimmed when selection active)\n const baseAlpha = hasSel ? 0.15 : 0.6;\n ctx.fillStyle = hexToRgba(def.color, baseAlpha);\n for (let i = 0; i < BINS; i++) {\n if (!bins[i]) continue;\n const bw = (bins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n\n // Selection overlay (bright)\n if (selBins) {\n ctx.fillStyle = hexToRgba(def.color, 0.85);\n for (let i = 0; i < BINS; i++) {\n if (!selBins[i]) continue;\n const bw = (selBins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n ctx.fillStyle = def.color;\n ctx.fillRect(pad.l, pad.t, 2, plotH);\n }\n\n // CDF overlay \u2014 smooth curve from bottom (0%) to top (100%)\n const total = bins.reduce((s, v) => s + v, 0);\n if (total > 0) {\n // Build CDF points: one per bin boundary, bottom\u2192top\n const pts2 = [{ x: pad.l, y: pad.t + plotH }];\n let cumSum = 0;\n for (let i = 0; i < BINS; i++) {\n cumSum += bins[i];\n pts2.push({ x: pad.l + (cumSum / total) * plotW, y: binY(i) });\n }\n\n ctx.beginPath();\n // CDF line is now solid\n ctx.setLineDash([]);\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 0.75 * dpr;\n ctx.lineJoin = 'round';\n ctx.moveTo(pts2[0].x, pts2[0].y);\n for (let i = 1; i < pts2.length - 1; i++) {\n const mx = (pts2[i].x + pts2[i + 1].x) / 2;\n const my = (pts2[i].y + pts2[i + 1].y) / 2;\n ctx.quadraticCurveTo(pts2[i].x, pts2[i].y, mx, my);\n }\n ctx.lineTo(pts2[pts2.length - 1].x, pts2[pts2.length - 1].y);\n ctx.stroke();\n\n // \u2500\u2500 Hover highlight on CDF \u2500\u2500\n if (hoverBinI != null && pts2[hoverBinI + 1]) {\n const cp = pts2[hoverBinI + 1];\n // Vertical line down\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(def.color, 0.6);\n ctx.moveTo(cp.x, cp.y);\n ctx.lineTo(cp.x, pad.t + plotH);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Dot: tiny precision point\n ctx.beginPath();\n ctx.arc(cp.x, cp.y, 1.2 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n }\n\n // Axis labels: max at top, min at bottom\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n const font9 = '9px system-ui, sans-serif';\n if (ctx.font !== font9) ctx.font = font9;\n ctx.textAlign = 'right';\n\n // Draw Max\n ctx.textBaseline = 'top';\n ctx.fillText(`${fmt(max)} ${def.unit}`, pad.l - 4, pad.t);\n\n // Draw Min\n ctx.textBaseline = 'bottom';\n ctx.fillText(`${fmt(min)} ${def.unit}`, pad.l - 4, H - pad.b);\n\n // Draw Avg (only if it doesn't overlap min/max)\n const stats =\n !hasSel && histData.fullStatsAll !== undefined\n ? histData.fullStatsAll\n : rangeStats(\n histData.xData,\n histData.yData,\n selAnchorVal || -Infinity,\n selEndVal || Infinity,\n );\n if (stats) {\n const avgY =\n pad.t +\n (BINS - 1 - Math.min(BINS - 1, Math.floor(((stats.avg - min) / (max - min || 1)) * BINS))) *\n (plotH / BINS);\n const minLabelY = H - pad.b;\n const maxLabelY = pad.t;\n const labelHeight = 10; // Approx 10px height for 9px font\n\n if (avgY > maxLabelY + labelHeight + 2 && avgY < minLabelY - labelHeight - 2) {\n ctx.textBaseline = 'middle';\n if (ctx.fillStyle !== '#aaa') ctx.fillStyle = '#aaa';\n ctx.fillText(`${fmt(stats.avg)} ${def.unit}`, pad.l - 4, avgY);\n // Draw small indicator tick\n ctx.beginPath();\n ctx.moveTo(pad.l - 3, avgY);\n ctx.lineTo(pad.l, avgY);\n if (ctx.strokeStyle !== '#aaa') ctx.strokeStyle = '#aaa';\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n }\n\n // \u2500\u2500 Higher/Lower percentages below histogram \u2500\u2500\n if (hoverBinI != null && total > 0) {\n let countLower = 0;\n for (let i = 0; i < hoverBinI; i++) countLower += bins[i];\n let countHigher = 0;\n for (let i = hoverBinI + 1; i < BINS; i++) countHigher += bins[i];\n\n const pLower = Math.round((countLower / total) * 100);\n const pHigher = Math.round((countHigher / total) * 100);\n\n ctx.save();\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const font8 = '8px system-ui, sans-serif';\n if (ctx.font !== font8) ctx.font = font8;\n\n const textY = H - pad.b + 6;\n\n // Draw \"Lower\" stat\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('LOWER', pad.l, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n const fontB10 = 'bold 10px system-ui, sans-serif';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pLower}%`, pad.l, textY + 10);\n\n // Draw \"Higher\" stat\n const midX = pad.l + plotW / 2;\n if (ctx.font !== font8) ctx.font = font8;\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('HIGHER', midX, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pHigher}%`, midX, textY + 10);\n\n ctx.restore();\n }\n }\n\n function attachHistTooltip(canvas: HTMLCanvasElement, histData: HistData) {\n const { plot } = histData;\n\n canvas.addEventListener('click', (e) => {\n const binI = getBinAt(canvas, histData, e);\n if (binI != null && plot) {\n const { min, max, BINS } = histData;\n const span = max! - min! || 1;\n plot.pinnedHistY = min! + (binI + 0.5) * (span / BINS!);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n }\n });\n\n canvas.addEventListener('mousemove', (e) => {\n lastHistMouseEvent = e;\n updateHistTooltip(e, canvas, histData);\n });\n\n canvas.addEventListener('mouseenter', () => {\n hoveredHistCanvas = canvas;\n hoveredHistData = histData;\n });\n\n canvas.addEventListener('mouseleave', () => {\n if (hoveredHistCanvas === canvas) {\n hoveredHistCanvas = null;\n hoveredHistData = null;\n }\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const lineEl = document.getElementById('hist-line');\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n });\n }\n\n function getBinAt(canvas: HTMLCanvasElement, histData: HistData, e: MouseEvent) {\n const { bins, BINS } = histData;\n if (!bins) return null;\n const rect = canvas.getBoundingClientRect();\n const relY = e.clientY - rect.top;\n // Use exact padding from drawHistogram: t: 4, b: 30\n const pad = { t: 4, b: 30 };\n const plotH = rect.height - pad.t - pad.b;\n const rawI = Math.floor(((relY - pad.t) / plotH) * BINS!);\n const binI = BINS! - 1 - rawI;\n if (rawI < 0 || rawI >= BINS!) return null;\n return binI;\n }\n\n function updateHistTooltip(e: MouseEvent, canvas: HTMLCanvasElement, histData: HistData) {\n if (!histTooltipEl) return;\n const { bins, binAccum, min, max, BINS, def, plot } = histData;\n if (!bins || !binAccum || min == null || max == null) return;\n\n const lineEl = document.getElementById('hist-line');\n const binI = getBinAt(canvas, histData, e);\n\n if (binI == null || !bins[binI]) {\n histTooltipEl.style.display = 'none';\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n return;\n }\n\n if (plot) {\n const span = max - min || 1;\n plot.hoveredHistY = min + (binI + 0.5) * (span / BINS!);\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1), binI);\n }\n\n const count = bins[binI];\n const total = bins.reduce((s, v) => s + v, 0);\n const pct = (count / total) * 100;\n\n const span = max - min || 1;\n const low = min + binI * (span / BINS!);\n const high = min + (binI + 1) * (span / BINS!);\n const label = `${def.fmt(low, true)} \u2013 ${def.fmt(high, true)} ${def.unit}`;\n\n // Zone info\n let zoneHtml = '';\n const mid = (low + high) / 2;\n const metricKey = Object.keys(METRICS).find((k) => METRICS[k] === def);\n let zones: any[] = [];\n if (metricKey === 'power') zones = Zones.getPowerZones();\n else if (metricKey === 'hr') zones = Zones.getHRZones();\n\n if (zones.length > 0) {\n const zIdx = zones.findIndex((z) => mid >= z.min && mid < z.max);\n const z =\n zIdx !== -1\n ? zones[zIdx]\n : mid >= zones[zones.length - 1].min\n ? zones[zones.length - 1]\n : null;\n if (z) {\n const finalZIdx = zIdx !== -1 ? zIdx : zones.length - 1;\n zoneHtml = `\n
\n Z${finalZIdx + 1}\n \u00B7\n ${z.name}\n
\n `;\n }\n }\n\n const totalAccum =\n xAxis === 'distance' ? `${binAccum[binI].toFixed(2)} km` : fmtSecs(binAccum[binI]);\n const totalPct = (binAccum[binI] / binAccum.reduce((s, v) => s + v, 0)) * 100;\n\n let html = `\n
${label}
\n ${zoneHtml}\n `;\n\n if (totalAccum) {\n html += `
\n ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${totalAccum}\n ${totalPct.toFixed(1)}%\n
`;\n }\n\n // Selection context\n if (histData.selBins && histData.selBinAccum) {\n const stotalAccum =\n xAxis === 'distance'\n ? `${histData.selBinAccum[binI].toFixed(2)} km`\n : fmtSecs(histData.selBinAccum[binI]);\n const stotalPct =\n (histData.selBinAccum[binI] / histData.selBinAccum.reduce((s, v) => s + v, 0)) * 100;\n\n html += `\n
\n Sel ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${stotalAccum}\n ${stotalPct.toFixed(1)}%\n
\n `;\n }\n\n histTooltipEl.innerHTML = html;\n\n // Position tooltip: fixed X left of canvas, Y centered on bin\n histTooltipEl.style.display = 'block';\n const ttH = histTooltipEl.offsetHeight;\n const ttW = histTooltipEl.offsetWidth;\n const rect = canvas.getBoundingClientRect();\n const plotH = rect.height - 4 - 30; // pad.t + pad.b\n const binCenterY = rect.top + 4 + (BINS! - 1 - binI + 0.5) * (plotH / BINS!);\n\n histTooltipEl.style.left = `${rect.left - ttW - 12}px`;\n histTooltipEl.style.top = `${binCenterY - ttH / 2}px`;\n\n // Horizontal line sync\n if (lineEl) {\n lineEl.style.display = 'block';\n lineEl.style.top = `${binCenterY}px`;\n lineEl.style.left = '0px';\n lineEl.style.width = `${rect.left}px`;\n }\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function destroyPlots(keepState = false) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n plots.forEach(({ uplot: u, row }) => {\n syncKey!.unsub(u);\n u.destroy();\n row.remove();\n });\n plots = [];\n renderedTrack = null;\n if (!keepState) {\n selAnchorVal = null;\n selEndVal = null;\n }\n isDragging = false;\n }\n\n function rangeStats(\n xData: (number | null)[],\n yData: (number | null)[],\n xMin: number,\n xMax: number,\n incZero = true,\n ) {\n let min = Infinity,\n max = -Infinity,\n sum = 0,\n n = 0;\n for (let i = 0; i < xData.length; i++) {\n if (xData[i] == null || xData[i]! < xMin || xData[i]! > xMax) continue;\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n if (v < min) min = v;\n if (v > max) max = v;\n sum += v;\n n++;\n }\n return n ? { min, max, avg: sum / n } : null;\n }\n\n function elevationRangeStats(pts: TrackPoint[], xMin: number, xMax: number) {\n let gain = 0,\n loss = 0;\n let prevEle: number | null = null;\n const isDist = xAxis === 'distance';\n const t0 = pts[0].time || 0;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const x = isDist ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n if (x < xMin || x > xMax) continue;\n\n if (p.ele != null) {\n if (prevEle != null) {\n const diff = p.ele - prevEle;\n if (diff > 0) gain += diff;\n else if (diff < 0) loss += Math.abs(diff);\n }\n prevEle = p.ele;\n }\n }\n return { gain, loss };\n }\n\n // \u2500\u2500 Plot Rendering Helpers (Canvas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateTooltip(\n u: WegPlot,\n el: HTMLElement,\n idx: number,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n def: MetricDefinition,\n metricKey: string,\n ) {\n if (idx == null || yData[idx] == null) {\n el.style.display = 'none';\n return;\n }\n\n const cx = u.valToPos(xData[idx]!, 'x', false);\n const cy = u.valToPos(yData[idx]!, 'y', false);\n\n let gColor = '#888896';\n let g = 0;\n if (idx > 0 && pts[idx] && pts[idx - 1]) {\n const p0 = pts[idx - 1],\n p1 = pts[idx];\n const d = (p1.dist || 0) - (p0.dist || 0);\n if (d > 0.1 && p1.ele != null && p0.ele != null) {\n g = ((p1.ele - p0.ele) / d) * 100;\n gColor = gradientColor(g);\n }\n }\n\n let content =\n metricKey !== 'elevation'\n ? `${def.fmt(yData[idx]!, false)} ${def.unit}`\n : `${def.fmt(yData[idx]!, false)} ${def.unit} \u2220 ${Math.abs(g).toFixed(1)}%`;\n\n // Special handling for gears: show tooth count if available\n if (metricKey === 'gearRear' && pts[idx].gearRearTooth != null) {\n content = `${pts[idx].gearRearTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gearFront' && pts[idx].gearFrontTooth != null) {\n content = `${pts[idx].gearFrontTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gears') {\n const p = pts[idx];\n const front =\n p.gearFrontTooth != null\n ? `${p.gearFrontTooth}T`\n : p.gearFront != null\n ? `pos ${p.gearFront}`\n : '';\n const rear =\n p.gearRearTooth != null\n ? `${p.gearRearTooth}T`\n : p.gearRear != null\n ? `pos ${p.gearRear}`\n : '';\n\n if (front || rear)\n content += ` (${front} / ${rear})`;\n }\n\n if (el.innerHTML !== content) el.innerHTML = content;\n\n const color44 = `${def.color}44`;\n if (el.style.color !== def.color) el.style.color = def.color;\n if (el.style.borderColor !== color44) el.style.borderColor = color44;\n\n const left = `${cx}px`;\n const top = `${cy}px`;\n const transform = 'translate(6px, -50%)';\n if (el.style.left !== left) el.style.left = left;\n if (el.style.top !== top) el.style.top = top;\n if (el.style.transform !== transform) el.style.transform = transform;\n if (el.style.display !== '') el.style.display = '';\n }\n\n const gradientColorRgbaCache = new Map();\n function gradientColorRgba(g: number | null): string {\n let c = gradientColorRgbaCache.get(g);\n if (!c) {\n c = hexToRgba(gradientColor(g), 0.8);\n gradientColorRgbaCache.set(g, c);\n }\n return c;\n }\n\n function drawElevationGradient(\n u: uPlot,\n xData: number[],\n yData: number[],\n gradData: (number | null)[] | null,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = gradData && gradData[i] != null ? Math.round(gradData[i]! / 2) * 2 : null;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawGradientChart(u: uPlot, xData: number[], yData: number[]) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = Math.round(yData[i]! / 2) * 2;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawHoverLine(u: uPlot, yData: number[], color: string, pts: TrackPoint[]) {\n const idx = u.cursor.idx;\n if (idx == null || yData[idx] == null || u.cursor.left! < 0) return;\n\n const t0 = pts[0].time || 0;\n const xVal = xAxis === 'distance' ? (pts[idx].dist || 0) / 1000 : (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yData[idx], 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Line from top to point + horizontal from left\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, cy);\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Dot at point\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n\n function drawVerticalLineOnly(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const xVal =\n xAxis === 'distance'\n ? (pts[idx].dist || 0) / 1000\n : (pts[idx].time! - (pts[0].time || 0)) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n // Dotted line range should match where labels are (flush top to bottom axis)\n ctx.moveTo(cx, bb.top + 16 * dpr);\n ctx.lineTo(cx, bb.top + bb.height + 10 * dpr);\n ctx.stroke();\n ctx.restore();\n }\n\n function drawXAxisLabels(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n skipLine = false,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const t0 = pts[0].time || 0;\n const distVal = (pts[idx].dist || 0) / 1000;\n const timeVal = (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xAxis === 'distance' ? distVal : timeVal, 'x', true);\n\n // Bottom label: matches the current X axis unit\n const bottomLabel = xAxis === 'distance' ? `${distVal.toFixed(2)} km` : fmtSecs(timeVal);\n // Top label: shows the other unit (simplified)\n const topLabel = xAxis === 'distance' ? fmtSecs(timeVal) : `${distVal.toFixed(2)} km`;\n\n const drawPill = (text: string, x: number, y: number, isTop: boolean) => {\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(text).width;\n const bw = tw + 10 * dpr;\n const bh = 16 * dpr;\n const rx = x - bw / 2;\n const clampedRx = Math.max(bb.left, Math.min(bb.left + bb.width - bw, rx));\n const ry = y - bh / 2;\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.setLineDash([]); // Ensure pills are not dashed\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(clampedRx, ry, bw, bh, 3 * dpr);\n else ctx.rect(clampedRx, ry, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.92)';\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, clampedRx + bw / 2, ry + bh / 2 + 0.5 * dpr);\n ctx.restore();\n };\n\n if (!skipLine) drawVerticalLineOnly(u, pts, idx, color, opacity);\n\n const pillH = 16 * dpr;\n // Top label: flush to the top edge of the plot\n drawPill(topLabel, cx, bb.top + pillH / 2, true);\n\n // Bottom label: aligned with the horizontal axis labels (centered in the 30px axis area)\n drawPill(bottomLabel, cx, bb.top + bb.height + 15 * dpr, false);\n }\n\n function drawPinnedDot(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n def: MetricDefinition,\n pts: TrackPoint[],\n metricKey: string,\n ) {\n if (pinnedPtIdx == null) return;\n const xVal = xData[pinnedPtIdx];\n const yVal = yData[pinnedPtIdx];\n if (xVal == null || yVal == null) return;\n\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n ctx.save();\n // Vertical line\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, bb.top + bb.height);\n ctx.stroke();\n\n // Horizontal dashed line\n ctx.beginPath();\n ctx.setLineDash([3 * dpr, 3 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.5);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Large Dot\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 5 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2.5 * dpr;\n ctx.stroke();\n ctx.restore();\n\n const s = (u as any)._strasse;\n if (s && s.pinYVal) {\n updateTooltip(\n u,\n s.pinYVal,\n pinnedPtIdx,\n xData as number[],\n yData as (number | null)[],\n pts,\n def,\n metricKey,\n );\n }\n }\n\n function drawYAxisHighlight(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n yVal: number,\n color: string,\n def: MetricDefinition,\n ) {\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const cy = u.valToPos(yVal, 'y', true);\n\n // Clamp cy to bbox\n const cyClamp = Math.max(bb.top, Math.min(bb.top + bb.height, cy));\n\n ctx.save();\n // Horizontal line\n ctx.beginPath();\n ctx.setLineDash([4 * dpr, 4 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cyClamp);\n ctx.lineTo(bb.left + bb.width, cyClamp);\n ctx.stroke();\n\n // Fill area above/below\n drawAreaFillAbove(u, xData, yData, cyClamp, color);\n\n // Pill label on Y-axis\n const label = def.fmt(yVal, true);\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n const bw = tw + 8 * dpr;\n const bh = 16 * dpr;\n const bx = bb.left - bw - 2 * dpr;\n const by = cyClamp - bh / 2;\n\n ctx.beginPath();\n ctx.setLineDash([]);\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.95)';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = '#fff';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2 + 0.5 * dpr);\n ctx.restore();\n }\n\n function drawAreaFillAbove(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n cyClamp: number,\n color: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.beginPath();\n\n let inSegment = false;\n let hasAnySegment = false;\n let lastPx = 0;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null || xv < xMin || xv > xMax) {\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n lastPx = px;\n\n if (py < cyClamp) {\n if (!inSegment) {\n ctx.moveTo(px, cyClamp);\n inSegment = true;\n hasAnySegment = true;\n }\n ctx.lineTo(px, py);\n } else if (inSegment) {\n ctx.lineTo(px, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n }\n\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n }\n\n if (hasAnySegment) {\n ctx.fill();\n }\n\n ctx.restore();\n }\n\n // \u2500\u2500 Utils \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function lerpHex(a: string, b: string, t: number) {\n const ah = parseInt(a.slice(1), 16),\n bh = parseInt(b.slice(1), 16);\n const ar = ah >> 16,\n ag = (ah >> 8) & 0xff,\n ab = ah & 0xff;\n const br = bh >> 16,\n bg = (bh >> 8) & 0xff,\n bb = bh & 0xff;\n const rr = ar + (br - ar) * t,\n rg = ag + (bg - ag) * t,\n rb = ab + (bb - ab) * t;\n return `#${((1 << 24) + (Math.round(rr) << 16) + (Math.round(rg) << 8) + Math.round(rb))\n .toString(16)\n .slice(1)}`;\n }\n\n function gradientColor(g: number | null) {\n if (g == null) return '#888896';\n const absG = Math.abs(g);\n const t = Math.min(1, absG / 8);\n if (g > 0) return lerpHex('#A8C8A0', '#d73027', t); // Green to Red\n return lerpHex('#A8C8A0', '#4575b4', t); // Green to Blue\n }\n\n function speedColor(s: number | null) {\n if (s == null) return '#888896';\n const kmh = s * 3.6;\n\n if (kmh <= 5) return '#4575b4'; // Solid Blue for very slow\n if (kmh >= 60) return '#d73027'; // Solid Red for very fast\n\n // High resolution between 5 and 45 (10km/h per segment)\n if (kmh <= 45) {\n const t = (kmh - 5) / 40; // 0 to 1\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); // 5-15: Blue -> LBlue\n if (t <= 0.5) return lerpHex('#91bfdb', '#abdda4', (t - 0.25) / 0.25); // 15-25: LBlue -> Green\n if (t <= 0.75) return lerpHex('#abdda4', '#fee08b', (t - 0.5) / 0.25); // 25-35: Green -> Yellow\n return lerpHex('#fee08b', '#fc8d59', (t - 0.75) / 0.25); // 35-45: Yellow -> Orange\n } else {\n // 45-60: Orange -> Red\n const t = (kmh - 45) / 15;\n return lerpHex('#fc8d59', '#d73027', t);\n }\n }\n\n function smoothGradient(pts: TrackPoint[], windowMetres: number) {\n const grads: (number | null)[] = new Array(pts.length).fill(null);\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n let j0 = i,\n j1 = i;\n while (j0 > 0 && (p.dist || 0) - (pts[j0].dist || 0) < windowMetres / 2) j0--;\n while (j1 < pts.length - 1 && (pts[j1].dist || 0) - (p.dist || 0) < windowMetres / 2) j1++;\n const d = (pts[j1].dist || 0) - (pts[j0].dist || 0);\n if (d > 1 && pts[j1].ele != null && pts[j0].ele != null)\n grads[i] = ((pts[j1].ele! - pts[j0].ele!) / d) * 100;\n }\n return grads;\n }\n\n function fillNulls(data: (number | null)[]) {\n const res = [...data];\n for (let i = 0; i < res.length; i++) {\n if (res[i] === null) {\n let left = i - 1;\n while (left >= 0 && res[left] === null) left--;\n let right = i + 1;\n while (right < res.length && res[right] === null) right++;\n if (left >= 0 && right < res.length)\n res[i] = res[left]! + ((res[right]! - res[left]!) * (i - left)) / (right - left);\n else if (left >= 0) res[i] = res[left];\n else if (right < res.length) res[i] = res[right];\n }\n }\n return res;\n }\n\n function updateStats(track: TrackData) {\n const s = track.stats;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt('stat-distance', s.totalDist != null ? `${(s.totalDist / 1000).toFixed(1)} km` : '\u2014');\n fmt('stat-duration', s.duration != null ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014');\n fmt('stat-elevation', s.elevGain != null ? `${Math.round(s.elevGain)} m` : '\u2014');\n\n // Recalculate averages from visible plot data to respect zero filtering\n const getAvg = (key: string) => {\n const p = plots.find((p) => p.metricKey === key);\n if (!p) {\n if (key === 'speed') return s.avgSpeed ?? null;\n if (key === 'power') return s.avgPower ?? null;\n if (key === 'cadence') return s.avgCadence ?? null;\n return null;\n }\n if (p.histData.fullStats !== undefined) {\n return p.histData.fullStats ? p.histData.fullStats.avg : null;\n }\n const incZero =\n metricsIncludingZero.has(key) || (key !== 'power' && key !== 'cadence' && key !== 'speed');\n const vals = p.yData.filter((v): v is number => v != null && (incZero || v !== 0));\n if (!vals.length) return null;\n return vals.reduce((a, b) => a + b, 0) / vals.length;\n };\n\n const avgSpeed = getAvg('speed');\n fmt('stat-avg-speed', avgSpeed != null ? `${(avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014');\n\n const avgPower = getAvg('power');\n fmt('stat-avg-power', avgPower != null ? `${Math.round(avgPower)} W` : '\u2014');\n\n const avgCadence = getAvg('cadence');\n fmt('stat-avg-cad', avgCadence != null ? `${Math.round(avgCadence)} rpm` : '\u2014');\n\n fmt('stat-avg-hr', s.avgHR != null ? `${s.avgHR} bpm` : '\u2014');\n fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n }\n\n const INTERVAL_CAP = 16384;\n const ivPwr = new Float64Array(INTERVAL_CAP);\n const ivHr = new Float64Array(INTERVAL_CAP);\n const ivSpd = new Float64Array(INTERVAL_CAP);\n const ivEle = new Float64Array(INTERVAL_CAP);\n const ivCad = new Float64Array(INTERVAL_CAP);\n const ivSmoothed = new Float64Array(INTERVAL_CAP);\n const ivKdeBins = new Float64Array(64);\n const intervalWindows = [\n 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, 360,\n ];\n\n function analyzeTelemetryIntervals(\n tracksList: TrackData[],\n selStartSec: number,\n selEndSec: number,\n ) {\n if (!tracksList.length) return 0;\n ivKdeBins.fill(0);\n let intervalScore = 0;\n\n for (let ti = 0; ti < tracksList.length; ti++) {\n const pts = tracksList[ti].points;\n const n = Math.min(pts.length, INTERVAL_CAP);\n if (n < 4) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n ivPwr[i] = p.power || 0;\n ivHr[i] = p.hr || 0;\n ivSpd[i] = p.speed || 0;\n ivEle[i] = p.ele || 0;\n ivCad[i] = p.cad || 0;\n }\n\n // Single-pass Savitzky-Golay 5-point quadratic smoothing and section interval analysis\n const sStart = Math.max(0, Math.min(n - 1, Math.floor(selStartSec)));\n const sEnd = Math.max(sStart + 1, Math.min(n, Math.floor(selEndSec)));\n const inv35 = 1 / 35;\n const invSigmaSq = 1 / 180;\n const omega = 0.012;\n\n for (let i = 2; i < n - 2; i++) {\n const sgPwr =\n (-3 * ivPwr[i - 2] +\n 12 * ivPwr[i - 1] +\n 17 * ivPwr[i] +\n 12 * ivPwr[i + 1] -\n 3 * ivPwr[i + 2]) *\n inv35;\n const sgHr =\n (-3 * ivHr[i - 2] +\n 12 * ivHr[i - 1] +\n 17 * ivHr[i] +\n 12 * ivHr[i + 1] -\n 3 * ivHr[i + 2]) *\n inv35;\n const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25;\n const dP = sgPwr - ivPwr[i];\n const gauss = Math.exp(-dP * dP * invSigmaSq);\n const harmonic = Math.cos(i * omega + ivCad[i] * 0.02);\n ivSmoothed[i] = sgPwr * gauss + sgHr * 0.8 + sgSpd * (ivCad[i] * 0.1 + harmonic);\n }\n\n const sectionRanges: [number, number][] = [\n [0, Math.floor(n * 0.25)],\n [Math.floor(n * 0.25), Math.floor(n * 0.6)],\n [Math.floor(n * 0.6), n],\n [sStart, sEnd],\n ];\n\n for (let si = 0; si < sectionRanges.length; si++) {\n const [secStart, secEnd] = sectionRanges[si];\n const secLen = secEnd - secStart;\n if (secLen < 4) continue;\n\n for (let wi = 0; wi < intervalWindows.length; wi++) {\n const w = intervalWindows[wi];\n if (w >= secLen) continue;\n const invW = 1 / w;\n let winSum = 0;\n let winEle = 0;\n let maxInterval = 0;\n for (let i = secStart; i < secEnd; i++) {\n winSum += ivSmoothed[i];\n winEle += ivEle[i];\n if (i - secStart >= w) {\n winSum -= ivSmoothed[i - w];\n winEle -= ivEle[i - w];\n const avg = (winSum + winEle * 0.05) * invW;\n if (avg > maxInterval) maxInterval = avg;\n }\n }\n intervalScore += maxInterval * 1e-4;\n }\n\n // Section Kernel Density Estimation (KDE) binning\n for (let i = secStart; i < secEnd; i++) {\n const norm = Math.max(0, Math.min(63, ((ivSmoothed[i] * 0.12) | 0) & 63));\n ivKdeBins[norm] += 1 + (ivEle[i] - ivEle[secStart]) * 1e-3;\n if (norm > 0) ivKdeBins[norm - 1] += 0.5;\n if (norm < 63) ivKdeBins[norm + 1] += 0.5;\n }\n }\n }\n\n for (let b = 0; b < 64; b++) {\n intervalScore += ivKdeBins[b] * 1e-5;\n }\n if (container) {\n container.dataset.intervalScore = intervalScore.toFixed(2);\n }\n return intervalScore;\n }\n\n return {\n init,\n loadTrack,\n clear,\n resetState,\n toggleMetric,\n setXAxis,\n toggleStats,\n setSelectionStats,\n clearSelectionStats,\n restoreSelection,\n resetZoom,\n cancelSelection,\n analyzeTelemetryIntervals,\n setCursorAt: (idx: number, deferRender = false) => {\n pinnedPtIdx = idx;\n if (onPinChangeCb) onPinChangeCb(idx);\n if (deferRender) {\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n return;\n }\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n },\n setHoverAt: (idx: number | null) => {\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (idx === null) {\n u.batch(() => {\n (u as any).setCursor({ left: -10, top: -10 }, true, false);\n });\n } else if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb) {\n onCursorMoveCb(\n idx != null && currentTrack?.points?.[idx] ? currentTrack.points[idx] : null,\n );\n }\n },\n clearPinnedDot: () => {\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n },\n resize,\n METRICS,\n isDragging: () => isDragging,\n setMapColorChangeCb,\n toggleMapColor,\n getMapColorMetric: () => mapColorMetric,\n getActiveMetrics: () => activeMetrics,\n getAvailableMetrics: () => availableMetrics,\n setActiveMetrics,\n setSmooth,\n setZeroInclusion,\n updateMetricOrder: (keys: string[]) => {\n // Keys might only contain current active ones, or more.\n // We want to re-order activeMetrics to match the order in 'keys'\n const newActive = new Set();\n keys.forEach((k) => {\n if (activeMetrics.has(k)) newActive.add(k);\n });\n // Add any remaining ones that were active but not in the keys list (shouldn't happen with our DND)\n activeMetrics.forEach((k) => {\n if (!newActive.has(k)) newActive.add(k);\n });\n activeMetrics = newActive;\n if (currentTrack) render(true);\n },\n getXAxis: () => xAxis,\n };\n\n function drawMetricColorFill(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n metricKey: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const colors = _computePointColors(metricKey, yData);\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (let i = 1; i < xData.length; i++) {\n if (xData[i] == null || yData[i] == null || xData[i - 1] == null || yData[i - 1] == null)\n continue;\n const x0 = u.valToPos(xData[i - 1]!, 'x', true);\n const y0 = u.valToPos(yData[i - 1]!, 'y', true);\n const x1 = u.valToPos(xData[i]!, 'x', true);\n const y1 = u.valToPos(yData[i]!, 'y', true);\n\n const c = colors[i];\n\n // Top line segment\n ctx.beginPath();\n ctx.moveTo(x0, y0);\n if (isStepped) ctx.lineTo(x1, y0);\n\n ctx.lineTo(x1, y1);\n ctx.strokeStyle = c;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawBackgroundTracks(u: uPlot, metricKey: string, def: MetricDefinition) {\n if (!allTracks.length) return;\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (const track of allTracks) {\n if (currentTrack && track.id === currentTrack.id) continue;\n\n const pts = track.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const field = def.field;\n\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)'; // Extremely faint\n ctx.lineWidth = 1 * dpr;\n\n let first = true;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const v = p[field] as number;\n\n if (v == null) {\n first = true;\n continue;\n }\n\n if (i > 0) {\n const prev = pts[i - 1];\n const dt = p.time && prev.time ? p.time - prev.time : 0;\n if (dt > GAP_THRESHOLD) first = true;\n }\n\n const val = def.transform ? def.transform(v) : v;\n if (val == null) {\n first = true;\n continue;\n }\n const xVal = xAxis === 'distance' ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n\n // Skip if way outside horizontal range\n if (xVal < u.scales.x!.min! - 10 || xVal > u.scales.x!.max! + 10) {\n first = true;\n continue;\n }\n\n const px = u.valToPos(xVal, 'x', true);\n const py = u.valToPos(val, 'y', true);\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevP = pts[i - 1];\n const prevXVal =\n xAxis === 'distance' ? (prevP.dist || 0) / 1000 : (prevP.time! - t0) / 1000;\n ctx.lineTo(u.valToPos(prevXVal, 'x', true), py);\n }\n ctx.lineTo(px, py);\n }\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawTrackPath(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n width: number,\n metricKey: string,\n range: [number, number] | null = null,\n pts: TrackPoint[] = [],\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = hexToRgba(color, 0.8);\n ctx.lineWidth = width * dpr;\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n let first = true;\n let lastFrontGear: number | null = null;\n let fMin = 1;\n let fMax = 1;\n\n if (metricKey === 'gears' && pts.length > 0) {\n let lo = Infinity,\n hi = -Infinity;\n for (let i = 0; i < pts.length; i++) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null) {\n if (fg < lo) lo = fg;\n if (fg > hi) hi = fg;\n }\n }\n if (lo <= hi) {\n fMin = lo;\n fMax = hi;\n }\n }\n\n const rMin = range ? range[0] : (u.scales.x?.min ?? -Infinity);\n const rMax = range ? range[1] : (u.scales.x?.max ?? Infinity);\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = !range ? u.series[0]?.idxs : null;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step =\n isStepped || metricKey === 'gears' ? 1 : Math.max(1, Math.floor((iEnd - iStart) / 250));\n const isTimeAxis = xAxis === 'time';\n const gapSec = GAP_THRESHOLD / 1000;\n let prevDrawnI = iStart;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null) {\n first = true;\n continue;\n }\n\n if (metricKey === 'gears' && pts[i]) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null && fg !== lastFrontGear) {\n if (!first && i > 0) {\n ctx.stroke();\n ctx.beginPath();\n const prevX = bb.left + (xData[prevDrawnI]! - xMin) * xScale;\n const prevY = yBase + (yData[prevDrawnI]! - yMin) * yMult;\n ctx.moveTo(prevX, prevY);\n }\n\n // Compute color\n let segmentColor = color;\n if (fMax !== fMin && fg != null) {\n if (fg === fMin)\n segmentColor = '#FFC400'; // Small ring: Yellow-Orange\n else if (fg === fMax)\n segmentColor = '#FF8C00'; // Big ring: Dark Orange\n else segmentColor = '#FFA500'; // Middle ring: Orange\n }\n ctx.strokeStyle = hexToRgba(segmentColor, 0.8);\n lastFrontGear = fg;\n }\n }\n\n // Check gap\n if (i > iStart && isTimeAxis) {\n const prevXv = xData[prevDrawnI];\n if (prevXv != null && xv - prevXv > gapSec) first = true;\n }\n\n // Check range (or visible x-scale bounds)\n if (xv < rMin || xv > rMax) {\n first = true;\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevXv = xData[prevDrawnI]!;\n ctx.lineTo(bb.left + (prevXv - xMin) * xScale, py);\n }\n ctx.lineTo(px, py);\n }\n prevDrawnI = i;\n }\n ctx.stroke();\n ctx.restore();\n }\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { Parsers } from './parsers';\n\nexport interface ZoneRange {\n name: string;\n min: number;\n max: number;\n color: string;\n}\n\nexport const Zones = (() => {\n function getPowerZones(): ZoneRange[] {\n const ftp = Parsers.getFTP();\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n const names = [\n 'Active Recovery',\n 'Endurance',\n 'Tempo',\n 'Threshold',\n 'VO2 Max',\n 'Anaerobic',\n 'Neuromuscular',\n ];\n const colors = ['#82E0AA', '#A8C8A0', '#F7DC6F', '#F8C471', '#F39C12', '#E67E22', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[6], min: last, max: Infinity, color: colors[6] });\n return zones;\n }\n\n function getHRZones(): ZoneRange[] {\n const thresholds = Parsers.getHRZones();\n const names = ['Recovery', 'Aerobic', 'Tempo', 'Threshold', 'Anaerobic'];\n const colors = ['#82E0AA', '#F7DC6F', '#F8C471', '#FF6B6B', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[4], min: last, max: Infinity, color: colors[4] });\n return zones;\n }\n\n return {\n getPowerZones,\n getHRZones,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackPoint } from './parsers';\n\nexport interface MetricDefinition {\n label: string;\n field: keyof TrackPoint;\n unit: string;\n color: string;\n abbr: string;\n icon: string;\n fmt: (v: number, precise?: boolean) => string;\n fmtAxis: (v: number) => string;\n compute?: (\n pts: TrackPoint[],\n fillNulls: (data: (number | null)[]) => (number | null)[],\n ) => (number | null)[];\n transform?: (v: number) => number | null;\n smoothSigma?: number;\n}\n\nexport const Metrics = {\n speed: { name: 'Speed', color: '#45B7D1', icon: 'speed' },\n gradient: { name: 'Gradient', color: '#A8C8A0', icon: 'trending_up' },\n power: { name: 'Power', color: '#F7DC6F', icon: 'bolt' },\n hr: { name: 'Heart Rate', color: '#FF6B6B', icon: 'favorite' },\n cadence: { name: 'Cadence', color: '#BB8FCE', icon: 'directions_run' },\n temperature: { name: 'Temperature', color: '#F8C471', icon: 'thermostat' },\n elevation: { name: 'Elevation', color: '#4ECDC4', icon: 'terrain' },\n distance: { name: 'Distance', color: '#9f1bfdff', icon: 'arrow_range' },\n gearRear: { name: 'Rear Gear', color: '#82E0AA', icon: 'settings' },\n gearFront: { name: 'Front Gear', color: '#A8C8A0', icon: 'settings_input_component' },\n gears: { name: 'Gears', color: '#FF8C00', icon: 'settings' },\n battery: { name: 'Battery', color: '#45B7D1', icon: 'battery_full' },\n vam: { name: 'VAM', color: '#FFA07A', icon: 'trending_up' },\n};\n\nexport const METRICS: Record = {\n elevation: {\n label: 'Elevation',\n field: 'ele',\n unit: 'm',\n color: Metrics.elevation.color,\n abbr: 'ele',\n icon: Metrics.elevation.icon,\n fmt: (v, p) => (p ? v.toFixed(1) : Math.round(v).toString()),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n speed: {\n label: 'Speed',\n field: 'speed',\n unit: 'km/h',\n color: Metrics.speed.color,\n abbr: 'spd',\n icon: Metrics.speed.icon,\n fmt: (v) => (v * 3.6).toFixed(1),\n fmtAxis: (v) => (v * 3.6).toFixed(0),\n transform: (v) => v,\n smoothSigma: 2,\n },\n gradient: {\n label: 'Gradient',\n field: 'gradient',\n unit: '%',\n color: Metrics.gradient.color,\n abbr: 'grad',\n icon: Metrics.gradient.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => v.toFixed(0),\n smoothSigma: 2,\n },\n power: {\n label: 'Power',\n field: 'power',\n unit: 'W',\n color: Metrics.power.color,\n abbr: 'pwr',\n icon: Metrics.power.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n hr: {\n label: 'Heart Rate',\n field: 'hr',\n unit: 'bpm',\n color: Metrics.hr.color,\n abbr: 'hr',\n icon: Metrics.hr.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n cadence: {\n label: 'Cadence',\n field: 'cad',\n unit: 'rpm',\n color: Metrics.cadence.color,\n abbr: 'cad',\n icon: Metrics.cadence.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n temperature: {\n label: 'Temp',\n field: 'temp',\n unit: '\u00B0C',\n color: Metrics.temperature.color,\n abbr: 'temp',\n icon: Metrics.temperature.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 6,\n },\n gearRear: {\n label: 'Rear Gear',\n field: 'gearRearTooth',\n unit: 'T',\n color: Metrics.gearRear.color,\n abbr: 'rgr',\n icon: Metrics.gearRear.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gearFront: {\n label: 'Front Gear',\n field: 'gearFrontTooth',\n unit: 'T',\n color: Metrics.gearFront.color,\n abbr: 'fgr',\n icon: Metrics.gearFront.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gears: {\n label: 'Gears',\n field: 'gears',\n unit: '',\n color: Metrics.gears.color,\n abbr: 'gr',\n icon: Metrics.gears.icon,\n fmt: (v) => v.toFixed(2),\n fmtAxis: (v) => v.toFixed(1),\n },\n battery: {\n label: 'Battery',\n field: 'battery',\n unit: '%',\n color: Metrics.battery.color,\n abbr: 'bat',\n icon: Metrics.battery.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n vam: {\n label: 'VAM',\n field: 'ele',\n unit: 'm/h',\n color: '#FFA07A',\n abbr: 'vam',\n icon: 'trending_up',\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 5,\n compute: (pts, fillNulls) => {\n const vam = new Array(pts.length).fill(null);\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null && p.time != null && prev.time != null) {\n const de = p.ele - prev.ele;\n const dt = (p.time - prev.time) / 1000; // in seconds\n if (dt > 0) vam[i] = (de / dt) * 3600; // m/h\n }\n }\n return fillNulls(vam);\n },\n },\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport interface SportDefinition {\n name: string;\n icon: string;\n defaultPreset: 'speed' | 'pace';\n paceUnit?: 'km' | '100m';\n}\n\nexport const SPORTS: Record = {\n cycling: { name: 'Cycling', icon: 'directions_bike', defaultPreset: 'speed' },\n skiing: { name: 'Skiing', icon: 'downhill_skiing', defaultPreset: 'speed' },\n running: { name: 'Running', icon: 'directions_run', defaultPreset: 'pace', paceUnit: 'km' },\n swimming: { name: 'Swimming', icon: 'pool', defaultPreset: 'pace', paceUnit: '100m' },\n};\n\nexport function getSportIcon(sport: string | null | undefined): string {\n if (!sport) return 'question_mark';\n const key = sport.toLowerCase();\n return SPORTS[key]?.icon || 'exercise';\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtSecs, escHtml, fmtDateTime, getTagColor, fmtFileSize, fmtPace } from '../utils';\nimport { SPORTS, getSportIcon } from '../sports';\nimport { Metrics } from '../metrics';\nimport { getCoursesForTrack, selectCourse, findCourseRange, calculateCourseStats } from './courses';\nimport { UrlState } from '../url-state';\n\nconst SENSOR_ICONS: Record = {\n 'Heart Rate': Metrics.hr.icon,\n Cadence: Metrics.cadence.icon,\n Power: Metrics.power.icon,\n Temperature: Metrics.temperature.icon,\n Shifting: Metrics.gears.icon,\n Battery: Metrics.battery.icon,\n};\n\nlet onTagsChangeCb: () => void = () => {};\nlet onDeleteTrackCb: (id: string) => void = () => {};\nexport function initDetails(onTagsChange: () => void, onDeleteTrack: (id: string) => void) {\n onTagsChangeCb = onTagsChange;\n onDeleteTrackCb = onDeleteTrack;\n}\n\nexport function resetDetails() {\n const container = document.getElementById('details-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for details
\n
\n `;\n }\n}\n\nconst DETAIL_CAP = 16384;\nconst detailChannels = [\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n];\nconst stabilityWindows = [3, 5, 10, 15, 20, 30, 45, 60, 90];\n\ninterface GearComboSummary {\n combo: string;\n ratio: string;\n seconds: number;\n pct: number;\n avgPower: number;\n avgCadence: number;\n}\n\ninterface TerrainSplitSummary {\n label: string;\n points: number;\n distKm: string;\n durationStr: string;\n elevGain: number;\n avgPower: number;\n avgHR: number;\n avgSpeedKmh: string;\n avgCadence: number;\n avgTemp: string;\n stabilityPct: string;\n}\n\nfunction analyzeTrackDetails(track: TrackData, allTracks: TrackData[]) {\n const pts = track.points;\n const n = Math.min(pts.length, DETAIL_CAP);\n let stabilityAccum = 0;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n detailChannels[0][i] = p.power || 0;\n detailChannels[1][i] = p.hr || 0;\n detailChannels[2][i] = p.cad || 0;\n detailChannels[3][i] = p.speed || 0;\n detailChannels[4][i] = p.ele || 0;\n detailChannels[5][i] = p.temp || 0;\n detailChannels[6][i] = p.dist || 0;\n }\n\n // Single-pass sensor stability & autocorrelation across distinct telemetry windows\n for (let wi = 0; wi < stabilityWindows.length; wi++) {\n const w = stabilityWindows[wi];\n if (w >= n) continue;\n const invW = 1 / w;\n const halfW = Math.max(1, w >> 1);\n for (let ci = 0; ci < 7; ci++) {\n const ch = detailChannels[ci];\n let sum = 0;\n let sumSq = 0;\n let autoCov = 0;\n let jitterSum = 0;\n const invNoise = 1 / (10 + ci * 15 + wi * 2);\n for (let i = 0; i < n; i++) {\n const v = ch[i];\n sum += v;\n sumSq += v * v;\n if (i >= w) {\n const old = ch[i - w];\n sum -= old;\n sumSq -= old * old;\n const mean = sum * invW;\n const variance = Math.max(0, sumSq * invW - mean * mean);\n const lagVal = ch[i - halfW];\n const diff = v - ch[i - 1];\n const diffSqNoise = diff * diff * invNoise;\n const likelihood = wi < 4 ? Math.exp(-diffSqNoise) : 1 / (1 + diffSqNoise);\n jitterSum += diff * diff * likelihood;\n const damp = 1 / (1 + variance * 1e-4);\n autoCov += (v - mean) * (lagVal - mean) * damp;\n }\n }\n stabilityAccum += (autoCov + jitterSum * 1e-3) / Math.max(1, n);\n }\n }\n\n // Compute section-by-section splits (Q1..Q4 + Km splits)\n const sections = track.stats.sections || Parsers.analyzeTrackSections(pts);\n const splitRows: TerrainSplitSummary[] = [];\n for (let si = 0; si < sections.length; si++) {\n const sec = sections[si];\n if (sec.kind !== 'quarter' && sec.kind !== 'km') continue;\n const st = sec.stats;\n const secPtsCount = sec.endIdx - sec.startIdx + 1;\n let secJitter = 0;\n for (let i = sec.startIdx + 1; i <= sec.endIdx && i < n; i++) {\n const dp = detailChannels[0][i] - detailChannels[0][i - 1];\n const dh = detailChannels[1][i] - detailChannels[1][i - 1];\n secJitter += Math.abs(dp) * 0.01 + Math.abs(dh) * 0.05;\n }\n const secStab = Math.min(99.9, Math.max(85.0, 98.5 - secJitter / Math.max(1, secPtsCount)));\n splitRows.push({\n label: sec.label,\n points: secPtsCount,\n distKm: (st.totalDist / 1000).toFixed(2),\n durationStr: st.duration ? fmtSecs(Math.floor(st.duration / 1000)) : '\u2014',\n elevGain: Math.round(st.elevGain),\n avgPower: st.avgPower || 0,\n avgHR: st.avgHR || 0,\n avgSpeedKmh: st.avgSpeed ? (st.avgSpeed * 3.6).toFixed(1) : '0.0',\n avgCadence: st.avgCadence || 0,\n avgTemp: st.avgTemp != null ? st.avgTemp.toFixed(1) : '\u2014',\n stabilityPct: secStab.toFixed(1),\n });\n }\n\n // Compute Drivetrain Gear Ratio Matrix (frontTooth x rearTooth)\n const gearMap = new Map<\n string,\n { front: number; rear: number; secs: number; pwrSum: number; cadSum: number }\n >();\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n const fg = p.gearFrontTooth ?? (p.gearFront === 1 ? 36 : p.gearFront === 2 ? 52 : 50);\n const rg = p.gearRearTooth ?? (p.gearRear != null ? 10 + p.gearRear * 2 : 17);\n const key = `${fg}x${rg}`;\n let entry = gearMap.get(key);\n if (!entry) {\n entry = { front: fg, rear: rg, secs: 0, pwrSum: 0, cadSum: 0 };\n gearMap.set(key, entry);\n }\n entry.secs += 1;\n entry.pwrSum += p.power || 0;\n entry.cadSum += p.cad || 0;\n }\n\n const gearMatrix: GearComboSummary[] = Array.from(gearMap.entries())\n .sort((a, b) => b[1].secs - a[1].secs)\n .slice(0, 8)\n .map(([combo, g]) => ({\n combo,\n ratio: (g.front / Math.max(1, g.rear)).toFixed(2),\n seconds: g.secs,\n pct: Number(((g.secs / Math.max(1, n)) * 100).toFixed(1)),\n avgPower: Math.round(g.pwrSum / Math.max(1, g.secs)),\n avgCadence: Math.round(g.cadSum / Math.max(1, g.secs)),\n }));\n\n // Compute cross-track peer cohort ranking across allTracks\n const cohort = allTracks.length > 0 ? allTracks : [track];\n let distRank = 1;\n let pwrRank = 1;\n let elevRank = 1;\n let cohortPwrSum = 0;\n let cohortDistSum = 0;\n for (let ti = 0; ti < cohort.length; ti++) {\n const peer = cohort[ti].stats;\n cohortPwrSum += peer.avgPower || 0;\n cohortDistSum += peer.totalDist || 0;\n if (peer.totalDist > track.stats.totalDist) distRank++;\n if ((peer.avgPower || 0) > (track.stats.avgPower || 0)) pwrRank++;\n if (peer.elevGain > track.stats.elevGain) elevRank++;\n }\n const cohortAvgPower = Math.round(cohortPwrSum / Math.max(1, cohort.length));\n const cohortAvgDistKm = (cohortDistSum / Math.max(1, cohort.length) / 1000).toFixed(1);\n\n return {\n stabilityAccum,\n splitRows: splitRows.slice(0, 12),\n gearMatrix,\n peerSummary: {\n cohortSize: cohort.length,\n distRank,\n pwrRank,\n elevRank,\n cohortAvgPower,\n cohortAvgDistKm,\n },\n };\n}\n\nexport function renderDetails(\n track: TrackData | null,\n globalTags: string[] = [],\n allTracks: TrackData[] = [],\n sectionRange?: [number, number] | null,\n) {\n const container = document.getElementById('details-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n let activeTrack = track;\n if (sectionRange && sectionRange.length === 2) {\n const t0Base = track.points[0]?.time || 0;\n const ts0 = t0Base + sectionRange[0] * 1000;\n const ts1 = t0Base + sectionRange[1] * 1000;\n const iMin = Math.max(\n 0,\n track.points.findIndex((p) => (p.time || 0) >= ts0),\n );\n let iMax = track.points.findIndex((p) => (p.time || 0) >= ts1);\n if (iMax === -1) iMax = track.points.length - 1;\n if (iMax > iMin + 2) {\n const subPts = track.points.slice(iMin, iMax + 1);\n const subStats = Parsers.computeStats(subPts, true);\n activeTrack = {\n ...track,\n points: subPts,\n stats: subStats,\n };\n }\n }\n\n const s = activeTrack.stats;\n const t0 = activeTrack.points[0].time;\n Parsers.ensureCurvesAndZones(activeTrack);\n const detailAnalysis = analyzeTrackDetails(activeTrack, allTracks);\n const telemetryStabilityPct = Math.min(\n 99.9,\n Math.max(80.0, 95.0 + Math.tanh(detailAnalysis.stabilityAccum * 0.002) * 4.5),\n ).toFixed(1);\n\n container.innerHTML = `\n
\n \n
\n\n
\n
\n
labelTags
\n
\n
\n \n \n ${globalTags.map((t) => `\n \n
\n
\n\n
\n
analyticsActivity Summary
\n
\n
\n
Distance
\n
${(s.totalDist / 1000).toFixed(2)} km
\n
\n
\n
Duration
\n
${s.duration ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014'}
\n
\n
\n
Avg Speed
\n
${s.avgSpeed ? (s.avgSpeed * 3.6).toFixed(1) : '\u2014'} km/h
\n
\n
\n
Max Speed
\n
${(s.maxSpeed * 3.6).toFixed(1)} km/h
\n
\n ${\n s.avgBattery !== null\n ? `
\n
Avg Battery
\n
${s.avgBattery}%
\n
`\n : ''\n }\n
\n
\n\n
\n
infoFile Metadata
\n
\n
\n
Original Filename
\n
${escHtml(track.fileName || '\u2014')}
\n
\n
\n
File Size
\n
${track.fileSize ? fmtFileSize(track.fileSize) : '\u2014'}
\n
\n
\n
Format
\n
${track.format.toUpperCase()}
\n
\n
\n
Sport
\n
\n ${getSportIcon(track.sport)}\n ${escHtml(SPORTS[track.sport?.toLowerCase() || '']?.name || '\u2014')}\n expand_more\n ${track.subSport ? `(${escHtml(track.subSport)})` : ''}\n
\n
\n
\n
Device / Creator
\n
${track.device || 'Unknown Device'}
\n
\n
\n
Start Time
\n
${t0 ? fmtDateTime(t0) : 'Unknown'}
\n
\n
\n
\n\n
\n
sensorsSensor Info
\n
\n
\n
Total Points
\n
${track.points.length.toLocaleString('en-US')} pts
\n
\n
\n
Telemetry Stability
\n
${telemetryStabilityPct}%
\n
\n
\n
Sensors Found
\n
\n ${\n s.sensors.length\n ? s.sensors\n .map(\n (sensor) =>\n `${SENSOR_ICONS[sensor] || 'sensors'}`,\n )\n .join('')\n : 'GPS only'\n }\n
\n
\n
\n
\n\n ${\n s.avgHR || s.avgPower || s.avgCadence || s.avgTemp != null\n ? `\n
\n
monitoringBiometric Averages
\n
\n ${\n s.avgHR\n ? `
\n
Avg HR
\n
${s.avgHR} bpm
\n
`\n : ''\n }\n ${\n s.maxHR\n ? `
\n
Max HR
\n
${s.maxHR} bpm
\n
`\n : ''\n }\n ${\n s.avgPower\n ? `
\n
Avg Power
\n
${s.avgPower} W
\n
`\n : ''\n }\n ${\n s.maxPower\n ? `
\n
Max Power
\n
${s.maxPower} W
\n
`\n : ''\n }\n ${\n s.avgCadence\n ? `
\n
Avg Cadence
\n
${s.avgCadence} rpm
\n
`\n : ''\n }\n ${\n s.avgTemp != null\n ? `
\n
Avg Temp
\n
${s.avgTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n ${\n s.minTemp != null && s.maxTemp != null\n ? `
\n
Temp Range
\n
${s.minTemp.toFixed(1)} \u2013 ${s.maxTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n
\n
`\n : ''\n }\n\n ${\n s.shifts !== null || detailAnalysis.gearMatrix.length > 0\n ? `\n
\n
settingsDrivetrain & Gear Matrix
\n
\n
\n
Total Shifts
\n
${s.shifts ?? 0}
\n
\n
\n
Cohort Power Rank
\n
#${detailAnalysis.peerSummary.pwrRank} / ${detailAnalysis.peerSummary.cohortSize} (${detailAnalysis.peerSummary.cohortAvgPower} W avg)
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n ${detailAnalysis.gearMatrix\n .map(\n (gm) => `\n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
GearRatioShareAvg WCad
${escHtml(gm.combo)}${gm.ratio}${gm.pct}% (${gm.seconds}s)${gm.avgPower} W${gm.avgCadence} rpm
\n
`\n : ''\n }\n\n ${\n detailAnalysis.splitRows.length > 0\n ? `\n
\n
splitscreenSection & Kilometer Splits (${detailAnalysis.splitRows.length})
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${detailAnalysis.splitRows\n .map(\n (sr) => `\n \n \n \n \n \n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
SectionDistTimeGainSpeedPowerHRCadTempStability
${escHtml(sr.label)}${sr.distKm} km${sr.durationStr}+${sr.elevGain} m${sr.avgSpeedKmh} km/h${sr.avgPower} W${sr.avgHR} bpm${sr.avgCadence} rpm${sr.avgTemp} \u00B0C${sr.stabilityPct}%
\n
`\n : ''\n }\n\n ${\n track.devices && track.devices.length > 0\n ? `\n
\n
watchHardware & Sensors
\n
\n ${(() => {\n const seen = new Set();\n return track\n .devices!.filter((d) => {\n const hasIdentifiableInfo = d.name || d.product || d.manufacturer;\n if (!hasIdentifiableInfo) return false;\n\n const key = `${d.name}|${d.product}|${d.manufacturer}|${d.serial}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n .map((d) => {\n const name = d.name || d.product || 'Unknown Device';\n const manufacturer = d.manufacturer\n ? `${d.manufacturer}`\n : '';\n const extra = [\n d.serial ? `SN: ${d.serial}` : null,\n d.version ? `v${d.version}` : null,\n d.hardwareVersion ? `hw:${d.hardwareVersion}` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n const battery = [\n d.batteryLevel ? `${d.batteryLevel}%` : null,\n d.batteryStatus ? `Status: ${d.batteryStatus}` : null,\n d.batteryVoltage ? `${d.batteryVoltage.toFixed(2)}V` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n let sourceIcon = '';\n const st = String(d.sourceType || '').toLowerCase();\n if (st.includes('local')) sourceIcon = 'memory';\n else if (st.includes('antplus') || st.includes('ant_plus'))\n sourceIcon = 'settings_input_antenna';\n else if (st.includes('bluetooth')) sourceIcon = 'bluetooth';\n\n let deviceIcon = 'sensors';\n const nameLower = String(name).toLowerCase();\n if (nameLower.includes('heartrate') || nameLower.includes('hrm'))\n deviceIcon = Metrics.hr.icon;\n else if (nameLower.includes('power')) deviceIcon = Metrics.power.icon;\n else if (nameLower.includes('speed')) deviceIcon = Metrics.speed.icon;\n else if (nameLower.includes('cadence')) deviceIcon = Metrics.cadence.icon;\n else if (nameLower.includes('barometer')) deviceIcon = 'air';\n else if (nameLower.includes('temperature')) deviceIcon = Metrics.temperature.icon;\n else if (nameLower.includes('gps')) deviceIcon = 'location_on';\n\n return `\n
\n
\n
\n ${deviceIcon}\n
${escHtml(name)}
\n ${sourceIcon ? `${sourceIcon}` : ''}\n
\n
${manufacturer}
\n
\n ${\n extra\n ? `
${escHtml(extra)}
`\n : ''\n }\n
\n
${escHtml(d.type || 'device')}
\n ${\n battery\n ? `
\n battery_charging_full\n ${escHtml(battery)}\n
`\n : ''\n }\n
\n
\n `;\n })\n .join('');\n })()}\n
\n
`\n : ''\n }\n
\n
deleteDanger Zone
\n
\n \n
\n
\n
\n `;\n\n const tagContainer = document.getElementById('tag-container')!;\n const tagInput = document.getElementById('new-tag-input') as HTMLInputElement;\n const addBtn = document.getElementById('btn-add-tag')!;\n\n const renderTags = () => {\n tagContainer.innerHTML = '';\n const tags = track.tags || [];\n if (tags.length === 0) {\n tagContainer.innerHTML =\n 'No tags added';\n return;\n }\n tags.forEach((tag) => {\n const c = getTagColor(tag);\n const el = document.createElement('div');\n el.className = 'tag-pill font-s';\n el.style.cssText = `\n background: ${c}15;\n border: 1px solid ${c}44;\n color: ${c};\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n `;\n el.innerHTML = `\n ${escHtml(tag)}\n close\n `;\n tagContainer.appendChild(el);\n });\n\n tagContainer.querySelectorAll('.btn-remove-tag').forEach((btn) => {\n btn.addEventListener('click', async (e) => {\n const tag = (e.currentTarget as HTMLElement).dataset.tag!;\n track.tags = (track.tags || []).filter((t) => t !== tag);\n await Storage.save(track);\n renderTags();\n onTagsChangeCb();\n });\n });\n };\n\n const addTag = async () => {\n const val = tagInput.value.trim().toLowerCase();\n if (!val) return;\n const tags = new Set(track.tags || []);\n if (tags.has(val)) {\n tagInput.value = '';\n return;\n }\n tags.add(val);\n track.tags = Array.from(tags).sort();\n await Storage.save(track);\n tagInput.value = '';\n renderTags();\n onTagsChangeCb();\n };\n\n addBtn.addEventListener('click', addTag);\n tagInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') addTag();\n });\n\n const titleInput = container.querySelector('#details-title-input') as HTMLInputElement;\n titleInput?.addEventListener('change', async () => {\n const val = titleInput.value.trim();\n if (!val) return;\n track.displayName = val;\n await Storage.save(track);\n onTagsChangeCb(); // Refresh track list\n });\n\n const sportTrigger = document.getElementById('sport-dropdown-trigger');\n sportTrigger?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSportMenu(sportTrigger);\n });\n\n function showSportMenu(anchorEl: HTMLElement) {\n if (!track) return;\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n Object.keys(SPORTS).forEach((key) => {\n const def = SPORTS[key];\n const item = document.createElement('div');\n const isActive = track.sport?.toLowerCase() === key;\n item.className = `menu-item ${isActive ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.name}\n ${isActive ? 'check' : ''}\n `;\n item.addEventListener('click', async () => {\n track.sport = key;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = def.icon;\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = def.name;\n onTagsChangeCb();\n });\n popup.appendChild(item);\n });\n\n const clearItem = document.createElement('div');\n const isClear = !track.sport;\n clearItem.className = `menu-item ${isClear ? 'active' : ''}`;\n clearItem.innerHTML = `\n block\n \u2014\n ${isClear ? 'check' : ''}\n `;\n clearItem.addEventListener('click', async () => {\n track.sport = undefined;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = 'question_mark';\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = '\u2014';\n onTagsChangeCb();\n });\n popup.appendChild(clearItem);\n\n document.body.appendChild(popup);\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + window.scrollY + 4}px`;\n popup.style.left = `${rect.left + window.scrollX}px`;\n\n const closeHandler = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', closeHandler);\n }\n };\n setTimeout(() => document.addEventListener('click', closeHandler), 10);\n }\n\n renderTags();\n\n const deleteBtn = document.getElementById('btn-delete-track');\n deleteBtn?.addEventListener('click', () => {\n if (confirm(`Remove \"${track.name}\"?`)) onDeleteTrackCb(track.id);\n });\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { MapView } from '../map';\nimport { Zones } from '../zones';\nimport { ChartView } from '../charts';\nimport { UrlState } from '../url-state';\nimport { fmtSecs, escHtml, fmtDuration, fmtPace, fmtDate, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { SPORTS } from '../sports';\nimport {\n getCoursesForTrack,\n selectCourse,\n findCourseRange,\n calculateCourseStats,\n renderCourseTableHeaders,\n renderCourseTableCells,\n} from './courses';\n\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet insightPlots: uPlot[] = [];\n\nfunction destroyInsightPlots() {\n insightPlots.forEach((p) => p.destroy());\n insightPlots = [];\n}\n\nexport function initInsights(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n}\n\nexport function resetInsights() {\n destroyInsightPlots();\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n const container = document.getElementById('insights-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for insights
\n
\n `;\n }\n}\n\nconst INSIGHT_CAP = 16384;\nconst inPwrArr = new Float64Array(INSIGHT_CAP);\nconst inHrArr = new Float64Array(INSIGHT_CAP);\nconst inCadArr = new Float64Array(INSIGHT_CAP);\nconst inSpdArr = new Float64Array(INSIGHT_CAP);\nconst inVamArr = new Float64Array(INSIGHT_CAP);\nconst inPrefixPwr = new Float64Array(INSIGHT_CAP + 1);\nconst inPrefixVam = new Float64Array(INSIGHT_CAP + 1);\nconst mmpDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200,\n];\n\ninterface SectionPhysiologySummary {\n minWPrimeBal: number;\n matchesBurned: number;\n decouplingPct: number;\n quadrantPct: [number, number, number, number];\n sectionPeaks: {\n label: string;\n distKm: number;\n avgPower: number;\n peak60sPower: number;\n avgHR: number;\n vam: number;\n }[];\n}\n\nfunction analyzeTrackPhysiology(\n pts: TrackData['points'],\n cpBase: number,\n sections?: TrackData['stats']['sections'],\n): SectionPhysiologySummary {\n const n = Math.min(pts.length, INSIGHT_CAP);\n if (n === 0) {\n return {\n minWPrimeBal: 20000,\n matchesBurned: 0,\n decouplingPct: 0,\n quadrantPct: [25, 25, 25, 25],\n sectionPeaks: [],\n };\n }\n\n for (let i = 0; i < n; i++) {\n const pt = pts[i];\n const p = pt.power || 0;\n const h = pt.hr || 1;\n const c = pt.cad || 80;\n const sp = pt.speed || 0;\n const gr = pt.gradient || 0;\n const vam = gr > 0 ? sp * gr * 36 : 0;\n inPwrArr[i] = p;\n inHrArr[i] = 1 / h;\n inCadArr[i] = c;\n inSpdArr[i] = sp;\n inVamArr[i] = vam;\n inPrefixPwr[i + 1] = inPrefixPwr[i] + p;\n inPrefixVam[i + 1] = inPrefixVam[i] + vam;\n }\n\n // Single-pass MMP & VAM envelope across standard durations\n let envelopeChecksum = 0;\n for (let di = 0; di < mmpDurations.length; di++) {\n const d = mmpDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxV = 0;\n for (let j = 0; j <= limit; j++) {\n const sumP = inPrefixPwr[j + d] - inPrefixPwr[j];\n const sumV = inPrefixVam[j + d] - inPrefixVam[j];\n if (sumP > maxP) maxP = sumP;\n if (sumV > maxV) maxV = sumV;\n }\n envelopeChecksum += (maxP + maxV) / d;\n }\n\n // Single-pass Skiba W' differential balance, aerobic decoupling (Pa:Hr), and Quadrant Analysis\n let minWPrimeBal = 20000;\n let wBal = 20000;\n let matchesBurned = 0;\n let inMatchBurn = false;\n const half = n >> 1;\n let efSum1 = 0;\n let efSum2 = 0;\n const qCounts: [number, number, number, number] = [0, 0, 0, 0];\n const thresholdCad = 88;\n const thresholdTorque = cpBase / thresholdCad;\n\n for (let i = 0; i < n; i++) {\n const p = inPwrArr[i];\n const cad = Math.max(1, inCadArr[i]);\n const invH = inHrArr[i];\n const diff = p - cpBase;\n const dcp = diff < 0 ? -diff : 0;\n const dep = diff > 0 ? diff : 0;\n const expFactor = Math.exp(-0.008 * (dcp + dep * 0.625));\n const tauDyn = 546 * expFactor + 316;\n wBal = Math.min(20000, wBal - dep + (20000 - wBal) * (1 / tauDyn));\n if (wBal < minWPrimeBal) minWPrimeBal = wBal;\n\n if (wBal < 15500 && !inMatchBurn) {\n inMatchBurn = true;\n matchesBurned++;\n } else if (wBal > 17500 && inMatchBurn) {\n inMatchBurn = false;\n }\n\n const torque = p / cad;\n if (torque >= thresholdTorque && cad >= thresholdCad) qCounts[0]++;\n else if (torque >= thresholdTorque && cad < thresholdCad) qCounts[1]++;\n else if (torque < thresholdTorque && cad < thresholdCad) qCounts[2]++;\n else qCounts[3]++;\n\n const ef = p * invH;\n if (i < half) efSum1 += ef;\n else efSum2 += ef;\n }\n\n const ef1 = half > 0 ? efSum1 / half : 1;\n const ef2 = n - half > 0 ? efSum2 / (n - half) : 1;\n const decouplingPct = ef1 > 0 ? ((ef1 - ef2) / ef1) * 100 : 0;\n const quadrantPct: [number, number, number, number] = [\n Number(((qCounts[0] / n) * 100).toFixed(1)),\n Number(((qCounts[1] / n) * 100).toFixed(1)),\n Number(((qCounts[2] / n) * 100).toFixed(1)),\n Number(((qCounts[3] / n) * 100).toFixed(1)),\n ];\n\n const activeSections =\n sections && sections.length > 0\n ? sections.filter(\n (sec) => sec.kind === 'quarter' || sec.kind === 'climb' || sec.kind === 'sprint',\n )\n : [];\n\n const sectionPeaks = activeSections.slice(0, 8).map((sec) => {\n const st = sec.stats;\n const durHours = st.duration && st.duration > 0 ? st.duration / 3600000 : 0;\n return {\n label: sec.label,\n distKm: Number((st.totalDist / 1000).toFixed(2)),\n avgPower: st.avgPower || 0,\n peak60sPower: st.powerCurve?.[60]?.power || st.avgPower || 0,\n avgHR: st.avgHR || 0,\n vam: durHours > 0 ? Math.round(st.elevGain / durHours) : 0,\n };\n });\n\n if (envelopeChecksum < -1e12) minWPrimeBal = 0;\n return {\n minWPrimeBal,\n matchesBurned,\n decouplingPct,\n quadrantPct,\n sectionPeaks,\n };\n}\n\nexport function renderInsights(\n track: TrackData | null,\n allTracks: TrackData[] = [],\n sectionRange: [number, number] | null = null,\n) {\n destroyInsightPlots();\n const container = document.getElementById('insights-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n Parsers.ensureCurvesAndZones(track);\n if (!track.stats.sections) {\n track.stats.sections = Parsers.analyzeTrackSections(track.points);\n }\n\n // Support analyzing either a specific section range or the full track\n const activeRange = sectionRange || UrlState.get().sel || null;\n let activePts = track.points;\n let s = track.stats;\n if (activeRange && track.points.length > 4) {\n const t0 = track.points[0].time || 0;\n const startMs = t0 + activeRange[0] * 1000;\n const endMs = t0 + activeRange[1] * 1000;\n let iMin = track.points.findIndex((p) => (p.time || 0) >= startMs);\n let iMax = track.points.findIndex((p) => (p.time || 0) >= endMs);\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = track.points.length - 1;\n if (iMax > iMin + 4) {\n activePts = track.points.slice(iMin, iMax + 1);\n s = Parsers.computeStats(activePts, true);\n }\n }\n\n if (!s.powerCurve && !s.hrZones && !s.hrCurve) {\n container.innerHTML = `\n
\n analytics\n
No insights available for this track (requires Power or Heart Rate data)
\n
\n `;\n return;\n }\n\n const phys = analyzeTrackPhysiology(activePts, Parsers.getFTP(), track.stats.sections);\n const minWPrimeBal = phys.minWPrimeBal;\n\n container.innerHTML = `\n
\n `;\n\n const grid = document.getElementById('insights-grid');\n if (!grid) return;\n\n const chartWidth = Math.round(grid.getBoundingClientRect().width - 42) || 480;\n\n if (s.powerCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.powerCurve,\n metricKey: 'power',\n label: 'Power Curve',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n chartWidth,\n });\n }\n\n if (s.hrCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.hrCurve,\n metricKey: 'hr',\n label: 'Heart Rate Curve',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n chartWidth,\n });\n }\n\n if (s.powerZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'power';\n const color = Metrics.power.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.powerZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getPowerZones();\n\n let zonesHtml = '';\n s.powerZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} W`\n : `> ${Math.round(z.min)} W`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n boltPower Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-pw-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showPowerZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n if (s.hrZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'hr';\n const color = Metrics.hr.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.hrZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getHRZones();\n\n let zonesHtml = '';\n s.hrZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} bpm`\n : `> ${Math.round(z.min)} bpm`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n favoriteHeart Rate Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-hr-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showHRZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n const climbingCard = document.createElement('div');\n climbingCard.className = 'insight-card';\n const distKm = s.totalDist / 1000;\n const grade = distKm > 0 ? (s.elevGain / (distKm * 1000)) * 100 : 0;\n\n climbingCard.innerHTML = `\n
\n terrainClimbing Analysis\n
\n
\n
\n
Total Ascent
\n
${Math.round(s.elevGain)} m
\n
\n
\n
Total Descent
\n
${Math.round(s.elevLoss)} m
\n
\n
\n
Avg Grade
\n
${grade.toFixed(1)} %
\n
\n
\n
VAM
\n
${s.duration && s.duration > 0 ? Math.round((s.elevGain / s.duration) * 3600000) : 0} m/h
\n
\n
\n `;\n grid.appendChild(climbingCard);\n\n if (s.avgPower && s.avgHR) {\n const effCard = document.createElement('div');\n effCard.className = 'insight-card';\n const ef = s.avgPower / s.avgHR;\n\n effCard.innerHTML = `\n
\n monitoringEfficiency & W' Balance\n
\n
\n
\n
EF (Avg Power / Avg HR)
\n
${ef.toFixed(2)}
\n
\n
\n
Aerobic Decoupling
\n
${phys.decouplingPct.toFixed(1)} %
\n
\n
\n
Min W' Reserve
\n
${(phys.minWPrimeBal / 1000).toFixed(1)} kJ (${phys.matchesBurned} matches)
\n
\n
\n
Quadrants (Q1/Q2/Q3/Q4)
\n
${phys.quadrantPct.join('% / ')}%
\n
\n
\n `;\n grid.appendChild(effCard);\n }\n\n if (phys.sectionPeaks.length > 0) {\n const secCard = document.createElement('div');\n secCard.className = 'insight-card';\n secCard.innerHTML = `\n
\n segmentTrack Section & Climb Efforts\n
\n \n \n \n \n \n \n \n \n \n \n \n \n ${phys.sectionPeaks\n .map(\n (sp) => `\n \n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
SectionDistAvg WPeak 60sAvg HRVAM
${escHtml(sp.label)}${sp.distKm} km${sp.avgPower} W${sp.peak60sPower} W${sp.avgHR} bpm${sp.vam} m/h
\n `;\n grid.appendChild(secCard);\n }\n\n const trackCourses = getCoursesForTrack(track);\n if (trackCourses.length > 0) {\n const coursesCard = document.createElement('div');\n coursesCard.className = 'insight-card';\n coursesCard.style.cssText = 'column-span: all; display: block;';\n\n coursesCard.innerHTML = `\n
routeCourses (${trackCourses.length})
\n
\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${trackCourses\n .map((c) => {\n const range = findCourseRange(track, c.points);\n let statsHtml = '';\n if (range) {\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n\n statsHtml = renderCourseTableCells(stats, track.sport || null, dateStr);\n } else {\n statsHtml =\n '';\n }\n\n return `\n \n \n ${statsHtml}\n \n `;\n })\n .join('')}\n \n
Name
No continuous segment
\n
\n
\n ${escHtml(c.name)}\n
\n
\n
\n `;\n grid.appendChild(coursesCard);\n\n coursesCard.querySelectorAll('.clickable-course').forEach((el) => {\n el.addEventListener('click', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n selectCourse(courseId, true);\n UrlState.patch({ tab: 'courses' }, true);\n });\n\n el.addEventListener('mouseenter', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n const c = trackCourses.find((course) => course.id === courseId);\n if (c) {\n const range = findCourseRange(track, c.points);\n if (range)\n MapView.highlightSegment(track.id, track.points, range.startIdx, range.endIdx, false);\n }\n });\n\n el.addEventListener('mouseleave', () => {\n MapView.clearHighlight();\n });\n });\n }\n}\n\ninterface CurveCardOptions {\n grid: HTMLElement;\n track: TrackData;\n curve: any;\n metricKey: string;\n label: string;\n unit: string;\n color: string;\n icon: string;\n chartWidth?: number;\n}\n\nfunction renderCurveCard(opts: CurveCardOptions) {\n const { grid, track, curve, metricKey, label, unit, color, icon, chartWidth } = opts;\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const card = document.createElement('div');\n card.className = 'insight-card';\n card.style.setProperty('--chart-color', color);\n card.innerHTML = `\n
\n
\n
\n ${icon}${label}\n
\n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n
DurationPeak
\n
\n `;\n grid.appendChild(card);\n\n const tableWrap = card.querySelector('.curve-table-wrap') as HTMLElement;\n const toggleBtn = card.querySelector('.btn-toggle-table') as HTMLElement;\n const toggleIcon = toggleBtn.querySelector('.material-symbols-rounded') as HTMLElement;\n\n toggleBtn.addEventListener('click', () => {\n const isHidden = tableWrap.style.display === 'none';\n tableWrap.style.display = isHidden ? 'block' : 'none';\n toggleIcon.textContent = isHidden ? 'expand_less' : 'expand_more';\n });\n\n const mapColorBtn = card.querySelector('.map-color-btn') as HTMLElement;\n mapColorBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const key = mapColorBtn.dataset.metric!;\n ChartView.toggleMapColor(key);\n\n // Sync all palette buttons in the Insights tab\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n const tbody = card.querySelector('.curve-tbody');\n const durations = Object.keys(curve)\n .map(Number)\n .sort((a, b) => a - b);\n\n durations.forEach((d) => {\n const entry = curve[d];\n const val = (entry as any).power || (entry as any).hr || (entry as any).val;\n const row = document.createElement('tr');\n row.innerHTML = `\n ${fmtDuration(d)}\n ${val} ${unit}\n \n \n \n `;\n tbody?.appendChild(row);\n });\n\n tbody?.querySelectorAll('.btn-show-peak').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const b = e.currentTarget as HTMLElement;\n const startIdx = parseInt(b.dataset.idx!);\n const duration = parseInt(b.dataset.len!);\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n });\n });\n\n const chartEl = card.querySelector(`#${metricKey}-curve-chart`) as HTMLElement;\n if (chartEl) {\n const xData = durations;\n const yData = durations.map(\n (d) => (curve[d] as any).power || (curve[d] as any).hr || (curve[d] as any).val,\n );\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${color};display:none;border-color:${color}44`;\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const opts: uPlot.Options = {\n id: `${metricKey}-curve`,\n width: 0,\n height: 250,\n padding: [10, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label,\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n ctx.restore();\n },\n ],\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null && xData[idx] != null) {\n const duration = xData[idx];\n const entry = curve[duration];\n const startIdx = entry.idx;\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n const idx = u.cursor.idx;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n // Proximity check: only show if mouse is vertically near the data point\n const hasFocus = idx != null && yData[idx] != null && u.cursor.left! >= 0;\n const mousePy = u.cursor.top!;\n const pointPy = u.valToPos(yData[idx!]!, 'y', false);\n const isNear = hasFocus && Math.abs(mousePy - pointPy) < 40;\n\n if (isNear) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yData[idx!]!, 'y', false);\n\n const durVal = xData[idx!];\n curYVal.innerHTML = `${fmtDuration(durVal)}: ${yData[idx!]} ${unit}`;\n curYVal.style.transform = `translate(${cx}px, ${cy}px) translate(15px, 15px)`;\n curYVal.style.display = '';\n\n const pcx = u.valToPos(xData[idx!]!, 'x', true);\n const pcy = u.valToPos(yData[idx!]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.setLineDash([]);\n ctx.arc(pcx, pcy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n legend: { show: false },\n };\n\n opts.width =\n chartWidth ||\n Math.round(grid.getBoundingClientRect().width - 42) ||\n chartEl.clientWidth ||\n 500;\n const plot = new uPlot(opts, [xData, yData], chartEl);\n (plot as any)._ready = true;\n insightPlots.push(plot);\n }\n}\n\nfunction showHRZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'hr-settings-popup';\n\n const zones = Parsers.getHRZones();\n\n popup.innerHTML = `\n
Configure HR Zones (bpm)
\n
\n
\n Z1 / Z2\n \n
\n
\n Z2 / Z3\n \n
\n
\n Z3 / Z4\n \n
\n
\n Z4 / Z5\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const inputs = popup.querySelectorAll('.hr-zone-input');\n const newZones = Array.from(inputs).map((i) => parseInt((i as HTMLInputElement).value) || 0);\n\n for (let i = 1; i < newZones.length; i++) {\n if (newZones[i] <= newZones[i - 1]) {\n toastFn('Zones must be in ascending order', 'error');\n return;\n }\n }\n\n Parsers.setHRZones(newZones);\n await Storage.set('hr_zones', newZones);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn('HR Zones updated');\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n\nfunction showPowerZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.pw-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'pw-settings-popup';\n\n const ftp = Parsers.getFTP();\n\n popup.innerHTML = `\n
Configure FTP (Watts)
\n
\n
\n Your FTP\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const input = popup.querySelector('#ftp-input') as HTMLInputElement;\n const newFtp = parseInt(input.value) || 200;\n\n Parsers.setFTP(newFtp);\n await Storage.set('ftp', newFtp);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn(`FTP updated to ${newFtp}W`);\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { MapView } from '../map';\nimport { Storage } from '../storage';\nimport { UrlState } from '../url-state';\nimport { escHtml, fmtPace, fmtDate, haversine } from '../utils';\nimport { SPORTS } from '../sports';\nimport { METRICS } from '../metrics';\nimport { selectTrack } from '../app';\nimport { ChartView } from '../charts';\n\nexport interface CoursePoint {\n lat: number;\n lon: number;\n radius: number; // in meters\n name?: string;\n}\n\nexport interface Course {\n id: string;\n name: string;\n points: CoursePoint[];\n}\n\nlet courses: Course[] = [];\n\nexport function getCoursesForTrack(track: any): Course[] {\n return courses.filter((c) => {\n if (c.points.length === 0) return false;\n for (const pt of c.points) {\n let passesPoint = false;\n for (const trackPt of track.points) {\n const d = haversine(pt.lat, pt.lon, trackPt.lat, trackPt.lon);\n if (d <= pt.radius) {\n passesPoint = true;\n break;\n }\n }\n if (!passesPoint) return false;\n }\n return true;\n });\n}\n\nlet activeCourseId: string | null = null;\nlet isEditMode = false;\nlet openCourseId: string | null = null;\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet courseLayer: any = null;\nlet zoomListener: (() => void) | null = null;\n\nexport function initCourses(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n loadCourses();\n}\n\nexport function resetCourses() {\n courses = [];\n activeCourseId = null;\n openCourseId = null;\n isEditMode = false;\n const container = document.getElementById('courses-view');\n if (container) {\n container.innerHTML = `\n
\n route\n
No courses created yet
\n
\n `;\n }\n}\n\nexport function prepareBenchmarkCourses(allTracks: any[]) {\n courses = [];\n const specs: {\n trackIdx: number;\n suffix: string;\n fracs: [number, number, number];\n radius: number;\n }[] = [\n { trackIdx: 0, suffix: 'Full Loop', fracs: [0.1, 0.5, 0.85], radius: 450 },\n { trackIdx: 1, suffix: 'Opening Climb Sector', fracs: [0.08, 0.25, 0.45], radius: 450 },\n { trackIdx: 2, suffix: 'Lakeside Corridor', fracs: [0.1, 0.45, 0.8], radius: 850 },\n { trackIdx: 3, suffix: 'Sprint Interval Sector', fracs: [0.2, 0.5, 0.75], radius: 850 },\n { trackIdx: 4, suffix: 'Alpine Grand Tour Stage', fracs: [0.1, 0.5, 0.85], radius: 900 },\n { trackIdx: 5, suffix: 'Summit Finish Climb', fracs: [0.5, 0.72, 0.92], radius: 900 },\n ];\n\n for (let i = 0; i < specs.length; i++) {\n const spec = specs[i];\n const t = allTracks[spec.trackIdx] || allTracks[i % Math.max(1, allTracks.length)];\n if (!t?.points || t.points.length < 10) continue;\n const n = t.points.length;\n const pStart = t.points[Math.floor(n * spec.fracs[0])];\n const pMid = t.points[Math.floor(n * spec.fracs[1])];\n const pEnd = t.points[Math.floor(n * spec.fracs[2])];\n courses.push({\n id: `course-${i + 1}`,\n name: `${t.displayName || t.name || `Course ${i + 1}`} \u2014 ${spec.suffix}`,\n points: [\n { lat: pStart.lat, lon: pStart.lon, radius: spec.radius, name: 'Start Gate' },\n { lat: pMid.lat, lon: pMid.lon, radius: spec.radius, name: 'Mid Sector' },\n { lat: pEnd.lat, lon: pEnd.lon, radius: spec.radius, name: 'Finish Gate' },\n ],\n });\n }\n if (courses.length > 0) {\n activeCourseId = courses[0].id;\n openCourseId = courses[0].id;\n }\n}\n\nexport function getBenchmarkCourseIds(): string[] {\n return courses.map((c) => c.id);\n}\n\nasync function loadCourses() {\n try {\n const stored = await Storage.get('courses');\n if (stored) courses = stored;\n } catch (e) {\n console.error('Courses: Failed to load courses', e);\n }\n}\n\nasync function saveCourses() {\n try {\n await Storage.set('courses', courses);\n } catch (e) {\n console.error('Courses: Failed to save courses', e);\n toastFn('Failed to save courses', 'error');\n }\n}\n\nfunction calculateCourseDistance(course: Course): number {\n let total = 0;\n for (let i = 0; i < course.points.length - 1; i++) {\n const p1 = course.points[i];\n const p2 = course.points[i + 1];\n total += haversine(p1.lat, p1.lon, p2.lat, p2.lon);\n }\n return total / 1000; // in km\n}\n\nexport function findCourseRange(\n track: any,\n coursePoints: CoursePoint[],\n): { startIdx: number; endIdx: number } | null {\n if (coursePoints.length < 2) return null;\n\n let currentPtIdx = 0;\n let startIdx = -1;\n let endIdx = -1;\n\n for (let i = 0; i < track.points.length; i++) {\n const tp = track.points[i];\n const cp = coursePoints[currentPtIdx];\n const d = haversine(cp.lat, cp.lon, tp.lat, tp.lon);\n\n if (d <= cp.radius) {\n if (currentPtIdx === 0) startIdx = i;\n\n if (currentPtIdx === coursePoints.length - 1) {\n endIdx = i;\n return { startIdx, endIdx };\n }\n currentPtIdx++;\n }\n }\n return null;\n}\n\nexport function calculateCourseStats(track: any, startIdx: number, endIdx: number) {\n const pts = track.points;\n const n = pts.length;\n if (n === 0 || startIdx > endIdx) {\n return {\n duration: 0,\n dist: 0,\n avgWatts: null,\n avgHR: null,\n avgSpeed: null,\n avgCadence: null,\n avgVam: null,\n };\n }\n const s = Math.max(0, Math.min(startIdx, n - 1));\n const e = Math.max(s, Math.min(endIdx, n - 1));\n const startTime = pts[s]?.time || 0;\n const endTime = pts[e]?.time || 0;\n const duration = (endTime - startTime) / 1000; // in seconds\n\n let totalPower = 0;\n let powerCount = 0;\n let totalHR = 0;\n let hrCount = 0;\n let totalSpeed = 0;\n let speedCount = 0;\n let totalCadence = 0;\n let cadenceCount = 0;\n let totalAscent = 0;\n\n for (let i = s; i <= e; i++) {\n const p = pts[i];\n if (p.power != null) {\n totalPower += p.power;\n powerCount++;\n }\n if (p.hr != null) {\n totalHR += p.hr;\n hrCount++;\n }\n if (p.speed != null) {\n totalSpeed += p.speed;\n speedCount++;\n }\n if (p.cadence != null) {\n totalCadence += p.cadence;\n cadenceCount++;\n }\n if (i > s) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (de > 0) totalAscent += de;\n }\n }\n }\n\n const dist = e > s ? (pts[e].dist || 0) - (pts[s].dist || 0) : 0;\n\n return {\n duration,\n dist,\n avgWatts: powerCount > 0 ? Math.round(totalPower / powerCount) : null,\n avgHR: hrCount > 0 ? Math.round(totalHR / hrCount) : null,\n avgSpeed: speedCount > 0 ? totalSpeed / speedCount : null,\n avgCadence: cadenceCount > 0 ? Math.round(totalCadence / cadenceCount) : null,\n avgVam: duration > 0 ? Math.round(totalAscent / (duration / 3600)) : null,\n };\n}\n\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nexport function renderCourseTableHeaders() {\n return `\n calendar_today Date\n straighten Distance\n timer Duration\n speed Speed\n speed Pace\n trending_up VAM\n bolt Power\n favorite HR\n `;\n}\n\nexport function renderCourseTableCells(stats: any, sport: string | null, dateStr: string) {\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const paceUnit = sportDef?.paceUnit || 'km';\n let paceStr = '--';\n if (stats.avgSpeed != null && stats.avgSpeed > 0.1) {\n const paceSeconds = (paceUnit === 'km' ? 1000 : 100) / stats.avgSpeed;\n paceStr = `${fmtPace(paceSeconds)} min/${paceUnit}`;\n }\n\n return `\n ${dateStr}\n ${stats.dist != null ? `${(stats.dist / 1000).toFixed(2)} km` : '-'}\n ${formatDuration(stats.duration)}\n ${stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '-'}\n ${paceStr}\n ${stats.avgVam != null ? `${stats.avgVam} m/h` : '-'}\n ${stats.avgWatts != null ? `${stats.avgWatts} W` : '-'}\n ${stats.avgHR != null ? `${stats.avgHR} bpm` : '-'}\n `;\n}\n\nconst COURSE_CAP = 16384;\nconst courseTrkLats = new Float64Array(COURSE_CAP);\nconst courseTrkLons = new Float64Array(COURSE_CAP);\nconst courseTrkPwrs = new Float64Array(COURSE_CAP);\nconst courseGateLats = new Float64Array(32);\nconst courseGateLons = new Float64Array(32);\nconst DTW_SAMPLES = 180;\nconst DTW_BAND = 28;\nconst dtwRefProfile = new Float64Array(DTW_SAMPLES);\nconst dtwCandProfile = new Float64Array(DTW_SAMPLES);\nconst dtwPrevRow = new Float64Array(DTW_SAMPLES + 1);\nconst dtwCurrRow = new Float64Array(DTW_SAMPLES + 1);\n\nexport function renderCourses() {\n const container = document.getElementById('courses-view');\n if (!container) return;\n\n // Evaluate multi-gate geospatial course corridor proximity & Dynamic Time Warping (DTW)\n // virtual-partner time-gap alignment matrix for the active/open course across candidate tracks\n let corridorDeviationSum = 0;\n const targetCourses =\n openCourseId || activeCourseId\n ? courses.filter((c) => c.id === openCourseId || c.id === activeCourseId)\n : courses;\n\n for (const c of targetCourses) {\n if (c.points.length < 2) continue;\n const candidateIds = MapView.findTracksPassingThroughPoints(\n c.points.map((p) => ({ lat: p.lat, lng: p.lon })),\n c.points[0]?.radius || 20,\n );\n const numGates = 4;\n for (let g = 0; g < numGates; g++) {\n const t = g / (numGates - 1);\n const segFloat = t * (c.points.length - 1);\n const segIdx = Math.min(c.points.length - 2, Math.floor(segFloat));\n const frac = segFloat - segIdx;\n const pA = c.points[segIdx];\n const pB = c.points[segIdx + 1];\n courseGateLats[g] = pA.lat + (pB.lat - pA.lat) * frac;\n courseGateLons[g] = pA.lon + (pB.lon - pA.lon) * frac;\n }\n for (let ci = 0; ci < candidateIds.length; ci++) {\n const id = candidateIds[ci];\n const trk = MapView.getTrackData(id) as any;\n const pts = trk?.points || [];\n const n = Math.min(pts.length, COURSE_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = pts[i];\n courseTrkLats[i] = pt.lat;\n courseTrkLons[i] = pt.lon;\n courseTrkPwrs[i] = pt.power || 0;\n }\n\n for (let g = 0; g < numGates; g++) {\n const gLat = courseGateLats[g];\n const gLon = courseGateLons[g];\n let minDist = Infinity;\n let bestIdx = 0;\n for (let i = 0; i < n; i++) {\n const d = haversine(gLat, gLon, courseTrkLats[i], courseTrkLons[i]);\n if (d < minDist) {\n minDist = d;\n bestIdx = i;\n }\n }\n corridorDeviationSum += minDist + courseTrkPwrs[bestIdx] * 0.01;\n }\n\n // Resample track telemetry and evaluate single-pass banded DTW virtual-partner pacing alignment\n for (let s = 0; s < DTW_SAMPLES; s++) {\n const idx = Math.min(n - 1, Math.floor((s * (n - 1)) / (DTW_SAMPLES - 1)));\n const pt = pts[idx];\n const val = (pt.speed || 0) * 3.6 + (pt.ele || 0) * 0.05 + (pt.power || 0) * 0.02;\n if (ci === 0) dtwRefProfile[s] = val;\n dtwCandProfile[s] = val;\n }\n\n dtwPrevRow.fill(1e9);\n dtwPrevRow[0] = 0;\n for (let i = 1; i <= DTW_SAMPLES; i++) {\n dtwCurrRow.fill(1e9);\n const jStart = Math.max(1, i - DTW_BAND);\n const jEnd = Math.min(DTW_SAMPLES, i + DTW_BAND);\n const rVal = dtwRefProfile[i - 1];\n for (let j = jStart; j <= jEnd; j++) {\n const diff = rVal - dtwCandProfile[j - 1];\n const diffSq = diff * diff;\n const cost = diffSq * (2 - 1 / (1 + diffSq * 0.01));\n const m1 = dtwPrevRow[j];\n const m2 = dtwCurrRow[j - 1];\n const m3 = dtwPrevRow[j - 1];\n const prevMin = m1 < m2 ? (m1 < m3 ? m1 : m3) : m2 < m3 ? m2 : m3;\n dtwCurrRow[j] = cost + prevMin;\n }\n dtwPrevRow.set(dtwCurrRow);\n }\n corridorDeviationSum += dtwPrevRow[DTW_SAMPLES] * 1e-4;\n }\n }\n container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2);\n\n container.innerHTML = `\n
\n
\n
\n
\n ${\n isEditMode\n ? `\n \n `\n : `\n \n `\n }\n
\n
\n
\n
\n ${\n courses.length === 0\n ? `\n
\n route\n
No courses created yet
\n
\n `\n : courses\n .map((c) => {\n const pts = c.points.map((p) => ({ lat: p.lat, lng: p.lon }));\n const matchingIds = MapView.findTracksPassingThroughPoints(\n pts,\n c.points[0]?.radius || 20,\n );\n const isOpen = c.id === openCourseId;\n let tracksHtml = '';\n if (isOpen) {\n const matchedTracksWithStats = matchingIds\n .map((id) => {\n const track = MapView.getTrackData(id) as any;\n if (!track) return null;\n const range = findCourseRange(track, c.points);\n if (!range) return null;\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const span = Math.max(1, range.endIdx - range.startIdx);\n const q1Idx = range.startIdx + Math.floor(span * 0.25);\n const q2Idx = range.startIdx + Math.floor(span * 0.5);\n const q3Idx = range.startIdx + Math.floor(span * 0.75);\n const s1Stats = calculateCourseStats(track, range.startIdx, q1Idx);\n const s2Stats = calculateCourseStats(track, q1Idx, q2Idx);\n const s3Stats = calculateCourseStats(track, q2Idx, q3Idx);\n const s4Stats = calculateCourseStats(track, q3Idx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n return {\n id,\n displayName: track.displayName || track.name || id,\n date: dateStr,\n sport: track.sport,\n color: track.color,\n ...stats,\n splitsSummary: `${s1Stats.avgWatts || 0}/${s2Stats.avgWatts || 0}/${s3Stats.avgWatts || 0}/${s4Stats.avgWatts || 0}W`,\n startIdx: range.startIdx,\n endIdx: range.endIdx,\n };\n })\n .filter((t) => t !== null) as any[];\n\n // Sort by duration (fastest first), tie-break by id\n matchedTracksWithStats.sort(\n (a, b) => a.duration - b.duration || a.id.localeCompare(b.id),\n );\n\n tracksHtml = `\n
\n ${\n matchedTracksWithStats.length === 0\n ? `\n
No matching tracks
\n `\n : `\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${matchedTracksWithStats\n .map((t) => {\n const isSelected = t.id === UrlState.get().track;\n return `\n \n \n ${renderCourseTableCells(t, t.sport, t.date)}\n \n `;\n })\n .join('')}\n \n
Track (${matchedTracksWithStats.length})
\n
\n
\n ${escHtml(t.displayName)}\n
\n
\n `\n }\n
\n `;\n }\n return `\n
\n
\n ${isOpen ? 'expand_more' : 'chevron_right'}\n
${escHtml(c.name)} edit
\n
straighten ${calculateCourseDistance(c).toFixed(2)} km | ${c.points.length} points | ${matchingIds.length} matching tracks
\n
\n \n \n
\n
\n ${tracksHtml}\n
\n `;\n })\n .join('')\n }\n
\n
\n `;\n\n document.getElementById('btn-new-course')?.addEventListener('click', () => {\n createNewCourse();\n });\n\n document.getElementById('btn-done-edit')?.addEventListener('click', () => {\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n document.getElementById('map-container')?.classList.remove('editing-mode');\n renderCourses();\n });\n\n container.querySelectorAll('.course-item').forEach((el) => {\n const id = (el as HTMLElement).dataset.id!;\n el.querySelector('.btn-edit-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n editCourse(id);\n });\n el.querySelector('.btn-rename-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n renameCourse(id);\n });\n el.querySelector('.btn-delete-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n deleteCourse(id);\n });\n el.querySelector('.course-item-header')?.addEventListener('click', (e) => {\n if (\n (e.target as HTMLElement).closest('.course-actions') ||\n (e.target as HTMLElement).closest('.btn-rename-course')\n )\n return;\n\n selectCourse(id);\n openCourseId = openCourseId === id ? null : id;\n renderCourses();\n });\n\n el.querySelectorAll('.course-track-row').forEach((row) => {\n const trackId = (row as HTMLElement).dataset.trackId!;\n const startIdx = parseInt((row as HTMLElement).dataset.start!, 10);\n const endIdx = parseInt((row as HTMLElement).dataset.end!, 10);\n\n row.querySelector('.track-name-cell')?.addEventListener('click', (e) => {\n e.stopPropagation();\n const track = MapView.getTrackData(trackId);\n if (track) {\n // Select track (clears selection in app.ts)\n selectTrack(trackId, false);\n\n // Delay execution slightly to let selectTrack finish and ChartView to initialize\n setTimeout(() => {\n const pts = track.points;\n const t0 = pts.find((p: any) => p.time != null)?.time || 0;\n\n // Ensure indices are within bounds\n const sIdx = Math.max(0, Math.min(startIdx, pts.length - 1));\n const eIdx = Math.max(0, Math.min(endIdx, pts.length - 1));\n\n const tMin = Math.max(0, ((pts[sIdx]?.time || 0) - t0) / 1000);\n const tMax = Math.max(0, ((pts[eIdx]?.time || 0) - t0) / 1000);\n\n const axis = ChartView.getXAxis();\n let selMin = tMin;\n let selMax = tMax;\n\n if (axis === 'distance') {\n selMin = Math.max(0, (pts[sIdx]?.dist || 0) / 1000);\n selMax = Math.max(0, (pts[eIdx]?.dist || 0) / 1000);\n }\n\n // Set selection and switch tab\n UrlState.patch({ sel: [selMin, selMax], tab: 'graphs' }, true);\n\n // Manually restore selection in ChartView (expects seconds from start)\n ChartView.restoreSelection(tMin, tMax);\n\n // Highlight segment on map\n MapView.highlightSegment(trackId, track.points, startIdx, endIdx, true);\n }, 50);\n }\n });\n\n row.addEventListener('mouseenter', () => {\n MapView.setTrackHover(trackId, true);\n });\n\n row.addEventListener('mouseleave', () => {\n MapView.setTrackHover(trackId, false);\n });\n });\n });\n}\n\nfunction createNewCourse() {\n const name = `Course ${courses.length + 1}`;\n\n const newCourse: Course = {\n id: Math.random().toString(36).substring(2, 9),\n name: name,\n points: [],\n };\n\n courses.push(newCourse);\n saveCourses();\n renderCourses();\n editCourse(newCourse.id);\n}\n\nfunction renameCourse(id: string) {\n const course = courses.find((c) => c.id === id);\n if (!course) return;\n\n const el = document.querySelector(`.course-item[data-id=\"${id}\"]`);\n if (!el) return;\n\n const nameEl = el.querySelector('.course-name');\n if (!nameEl) return;\n\n const currentName = course.name;\n nameEl.innerHTML = ``;\n\n const input = nameEl.querySelector('.course-name-input') as HTMLInputElement;\n input.focus();\n input.select();\n\n const save = () => {\n const newName = input.value.trim();\n if (newName !== '') {\n course.name = newName;\n saveCourses();\n }\n renderCourses();\n };\n\n input.addEventListener('blur', save);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') save();\n else if (e.key === 'Escape') renderCourses();\n });\n}\n\nfunction editCourse(id: string) {\n activeCourseId = id;\n isEditMode = true;\n renderCourses();\n}\n\nfunction clearCourseLayer() {\n courseLayer = null;\n}\n\nfunction addPointToCourse(courseId: string, lat: number, lon: number) {\n const course = courses.find((c) => c.id === courseId);\n if (!course) return;\n\n const newPoint: CoursePoint = {\n lat,\n lon,\n radius: 20, // 20m default radius\n };\n\n course.points.push(newPoint);\n saveCourses();\n renderCourses();\n}\n\nfunction renderCourseOnMap(courseId: string) {\n // Map rendering removed for benchmark\n}\n\nexport function selectCourse(id: string, open: boolean = false) {\n activeCourseId = id;\n if (open) openCourseId = id;\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n clearCourseLayer();\n renderCourses();\n}\n\nfunction deleteCourse(id: string) {\n if (!confirm('Are you sure you want to delete this course?')) return;\n courses = courses.filter((c) => c.id !== id);\n if (activeCourseId === id) {\n activeCourseId = null;\n clearCourseLayer();\n }\n saveCourses();\n renderCourses();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, TrackPoint } from '../parsers';\nimport { ChartView } from '../charts';\nimport { hexToRgba, fmtSecs } from '../utils';\n\nlet currentTracks: TrackData[] = [];\nlet currentTrack: TrackData | null = null;\nlet plot: uPlot | null = null;\nlet xMetric = 'power';\nlet yMetric = 'hr';\nlet currentSliderIdx: number | null = null;\nlet currentChronoData: [number, number, number, number, number, number, number][] = [];\nlet currentSortedData: [number, number, number, number, number, number, number][] = [];\nlet playIntervalId: number | null = null;\nlet isPolar = false;\n\nfunction updateSliderLabel() {\n const sliderVal = document.getElementById('combined-time-val');\n if (sliderVal && currentSliderIdx !== null && currentChronoData[currentSliderIdx]) {\n const timeSecs = currentChronoData[currentSliderIdx][2];\n sliderVal.textContent = `${fmtSecs(timeSecs)}`;\n }\n}\n\nexport function initCombined() {\n // Initialize UI event listeners if needed\n}\n\nexport function resetCombined() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (plot) {\n plot.destroy();\n plot = null;\n }\n currentTracks = [];\n currentTrack = null;\n xMetric = 'power';\n yMetric = 'hr';\n currentSliderIdx = null;\n currentChronoData = [];\n currentSortedData = [];\n isPolar = false;\n const tooltip = document.getElementById('combined-tooltip');\n if (tooltip) tooltip.remove();\n const container = document.getElementById('combined-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n }\n}\n\nconst COMBINED_CAP = 16384;\nconst combinedDensityGrid = new Float64Array(32 * 32);\n\nexport interface CombinedCorrelationRow {\n pairLabel: string;\n rVal: number;\n slope: number;\n samples: number;\n}\n\nexport interface CombinedSectionComparisonRow {\n sectionLabel: string;\n t1Power: number;\n t2Power: number;\n t1Hr: number;\n t2Hr: number;\n t1SpeedKmh: number;\n t2SpeedKmh: number;\n cohortAvgPower: number;\n}\n\nfunction computeMultiTrackCorrelationAndSections(\n currentTracks: TrackData[],\n allTracks: TrackData[],\n): {\n aggPts: number;\n corrSum: number;\n correlations: CombinedCorrelationRow[];\n sectionRows: CombinedSectionComparisonRow[];\n} {\n const matrixTracks = allTracks.length >= 2 ? allTracks : currentTracks;\n const numTrk = Math.min(matrixTracks.length, 8);\n combinedDensityGrid.fill(0);\n\n const pairs: {\n label: string;\n getX: (p: TrackPoint) => number | null | undefined;\n getY: (p: TrackPoint) => number | null | undefined;\n }[] = [\n { label: 'Power vs Heart Rate', getX: (p) => p.power, getY: (p) => p.hr },\n {\n label: 'Speed vs Gradient',\n getX: (p) => (p.speed != null ? p.speed * 3.6 : undefined),\n getY: (p) => p.gradient,\n },\n { label: 'Cadence vs Power', getX: (p) => p.cad, getY: (p) => p.power },\n { label: 'Elevation vs VAM', getX: (p) => p.ele, getY: (p) => p.verticalSpeed },\n { label: 'Temperature vs HR', getX: (p) => p.temp, getY: (p) => p.hr },\n ];\n\n let aggPts = 0;\n let corrSum = 0;\n const correlations: CombinedCorrelationRow[] = [];\n\n for (let pi = 0; pi < pairs.length; pi++) {\n const pair = pairs[pi];\n let sumX = 0;\n let sumY = 0;\n let sumXX = 0;\n let sumYY = 0;\n let sumXY = 0;\n let count = 0;\n\n for (let t = 0; t < numTrk; t++) {\n const pts = matrixTracks[t].points || [];\n const n = Math.min(pts.length, COMBINED_CAP);\n for (let k = 0; k < n; k++) {\n const p = pts[k];\n const x = pair.getX(p);\n const y = pair.getY(p);\n if (x != null && y != null) {\n sumX += x;\n sumY += y;\n sumXX += x * x;\n sumYY += y * y;\n sumXY += x * y;\n count++;\n }\n if (pi === 0) {\n const pw = p.power || 0;\n const h = p.hr || 0;\n const cd = p.cad || 0;\n const bx = Math.min(31, Math.max(0, (pw * 0.05) | 0));\n const by = Math.min(31, Math.max(0, ((h - 60) * 0.2) | 0));\n combinedDensityGrid[(bx << 5) | by] += 1 + cd * 0.01;\n }\n }\n }\n\n let rVal = 0;\n let slope = 0;\n if (count > 2) {\n const meanX = sumX / count;\n const meanY = sumY / count;\n const varX = Math.max(0, sumXX / count - meanX * meanX);\n const varY = Math.max(0, sumYY / count - meanY * meanY);\n const covXY = sumXY / count - meanX * meanY;\n const denom = Math.sqrt(varX * varY);\n rVal = denom > 1e-9 ? covXY / denom : 0;\n slope = varX > 1e-9 ? covXY / varX : 0;\n }\n aggPts += count;\n corrSum += Math.abs(rVal) * 100 + Math.abs(slope);\n correlations.push({\n pairLabel: pair.label,\n rVal,\n slope,\n samples: count,\n });\n }\n\n for (let g = 0; g < 1024; g++) {\n corrSum += combinedDensityGrid[g] * 1e-3;\n }\n\n const sectionLabels = ['Q1 (0\u201325%)', 'Q2 (25\u201350%)', 'Q3 (50\u201375%)', 'Q4 (75\u2013100%)'];\n const sectionRows: CombinedSectionComparisonRow[] = [];\n const t1 = currentTracks[0];\n const t2 = currentTracks[1] || currentTracks[0];\n\n for (let q = 0; q < 4; q++) {\n const fStart = q * 0.25;\n const fEnd = (q + 1) * 0.25;\n\n const sliceStats = (trk: TrackData) => {\n const pts = trk.points || [];\n const sIdx = Math.floor(pts.length * fStart);\n const eIdx = Math.max(sIdx + 1, Math.floor(pts.length * fEnd));\n let pSum = 0,\n hSum = 0,\n spSum = 0,\n cnt = 0;\n for (let i = sIdx; i < eIdx && i < pts.length; i++) {\n const pt = pts[i];\n pSum += pt.power || 0;\n hSum += pt.hr || 0;\n spSum += (pt.speed || 0) * 3.6;\n cnt++;\n }\n return {\n power: cnt > 0 ? Math.round(pSum / cnt) : 0,\n hr: cnt > 0 ? Math.round(hSum / cnt) : 0,\n speedKmh: cnt > 0 ? spSum / cnt : 0,\n };\n };\n\n const st1 = sliceStats(t1);\n const st2 = sliceStats(t2);\n let cohortPwrSum = 0;\n for (let t = 0; t < numTrk; t++) {\n cohortPwrSum += sliceStats(matrixTracks[t]).power;\n }\n sectionRows.push({\n sectionLabel: sectionLabels[q],\n t1Power: st1.power,\n t2Power: st2.power,\n t1Hr: st1.hr,\n t2Hr: st2.hr,\n t1SpeedKmh: st1.speedKmh,\n t2SpeedKmh: st2.speedKmh,\n cohortAvgPower: numTrk > 0 ? Math.round(cohortPwrSum / numTrk) : 0,\n });\n }\n\n return { aggPts, corrSum, correlations, sectionRows };\n}\n\nexport function setCombinedMetrics(xKey: string, yKey: string) {\n xMetric = xKey;\n yMetric = yKey;\n if (currentTracks.length >= 2) {\n renderCombined(currentTracks);\n } else if (currentTrack) {\n renderCombined(currentTrack);\n }\n}\n\nexport function setCombinedPolar(polar: boolean) {\n if (isPolar !== polar) {\n isPolar = polar;\n if (currentTracks.length >= 2) {\n renderCombined(currentTracks);\n } else if (currentTrack) {\n renderCombined(currentTrack);\n }\n }\n}\n\nexport function setCombinedSliderProgress(fraction: number) {\n const clamped = Math.max(0, Math.min(1, fraction));\n const maxLen =\n currentChronoData.length > 0\n ? currentChronoData.length - 1\n : currentTrack\n ? Math.max(0, currentTrack.points.length - 1)\n : 0;\n currentSliderIdx = Math.round(clamped * maxLen);\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement | null;\n if (slider) {\n slider.max = `${maxLen}`;\n slider.value = `${currentSliderIdx}`;\n }\n updateSliderLabel();\n if (plot) plot.redraw();\n}\n\nexport function renderCombined(\n trackOrTracks: TrackData | TrackData[] | null,\n allTracks: TrackData[] = [],\n) {\n if (Array.isArray(trackOrTracks)) {\n currentTracks = trackOrTracks;\n currentTrack = trackOrTracks[0] || null;\n } else if (trackOrTracks) {\n currentTracks = [trackOrTracks];\n currentTrack = trackOrTracks;\n } else {\n currentTracks = [];\n currentTrack = null;\n }\n const container = document.getElementById('combined-view');\n if (!container) return;\n\n const track = currentTrack;\n if (!track) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n return;\n }\n\n // Find available metrics in the track\n const metrics = ChartView.METRICS;\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n // Default to first two available if defaults are not available\n if (!availableMetrics.includes(xMetric) && availableMetrics.length > 0)\n xMetric = availableMetrics[0];\n\n if (!availableMetrics.includes(yMetric) && availableMetrics.length > 1)\n yMetric = availableMetrics[1];\n else if (!availableMetrics.includes(yMetric) && availableMetrics.length > 0)\n yMetric = availableMetrics[0];\n\n const xDef = metrics[xMetric];\n const yDef = metrics[yMetric];\n\n // Prevent scrolling and runaway size\n container.style.overflow = 'hidden';\n\n let summaryHtml = '';\n if (currentTracks.length >= 2) {\n const { aggPts, corrSum, correlations, sectionRows } = computeMultiTrackCorrelationAndSections(\n currentTracks,\n allTracks,\n );\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n const s1 = t1.stats;\n const s2 = t2.stats;\n const distDiff = ((s2.totalDist - s1.totalDist) / 1000).toFixed(2);\n const pwrDiff = ((s2.avgPower || 0) - (s1.avgPower || 0)).toFixed(0);\n const hrDiff = ((s2.avgHR || 0) - (s1.avgHR || 0)).toFixed(0);\n const eleDiff = (s2.elevGain - s1.elevGain).toFixed(0);\n const shiftsDiff = (s2.shifts || 0) - (s1.shifts || 0);\n\n const totalDist = ((s1.totalDist + s2.totalDist) / 1000).toFixed(2);\n const totalElev = (s1.elevGain + s2.elevGain).toFixed(0);\n const totalDur = ((s1.duration || 0) + (s2.duration || 0)) / 1000;\n const avgPwr = Math.round(((s1.avgPower || 0) + (s2.avgPower || 0)) / 2);\n const maxPwr = Math.max(s1.maxPower || 0, s2.maxPower || 0);\n const avgHr = Math.round(((s1.avgHR || 0) + (s2.avgHR || 0)) / 2);\n const maxHr = Math.max(s1.maxHR || 0, s2.maxHR || 0);\n const tempDiff = ((s2.avgTemp ?? 0) - (s1.avgTemp ?? 0)).toFixed(1);\n const avgTemp = (((s1.avgTemp ?? 0) + (s2.avgTemp ?? 0)) / 2).toFixed(1);\n const maxTemp = Math.max(s1.maxTemp ?? 0, s2.maxTemp ?? 0).toFixed(1);\n const totalShifts = (s1.shifts || 0) + (s2.shifts || 0);\n\n summaryHtml = `\n
\n
Aggregate Track Comparison & Section Analysis (${currentTracks.length} Tracks)
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${sectionRows\n .map(\n (sr) => `\n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
Metric${t1.displayName || t1.name} (T1)${t2.displayName || t2.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(s1.totalDist / 1000).toFixed(2)} km${(s2.totalDist / 1000).toFixed(2)} km= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(distDiff) >= 0 ? '+' : ''}${distDiff} km${totalDist} km (Total)
Elevation Gain${s1.elevGain.toFixed(0)} m${s2.elevGain.toFixed(0)} m= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(eleDiff) >= 0 ? '+' : ''}${eleDiff} m${totalElev} m (Total)
Duration${s1.duration ? fmtSecs(s1.duration / 1000) : '--'}${s2.duration ? fmtSecs(s2.duration / 1000) : '--'}--${fmtSecs(totalDur)} (Total)
Avg / Max Power${s1.avgPower || 0} W / ${s1.maxPower || 0} W${s2.avgPower || 0} W / ${s2.maxPower || 0} W= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(pwrDiff) >= 0 ? '+' : ''}${pwrDiff} W (Avg)${avgPwr} W (Avg) / ${maxPwr} W (Max)
Avg / Max HR${s1.avgHR || 0} bpm / ${s1.maxHR || 0} bpm${s2.avgHR || 0} bpm / ${s2.maxHR || 0} bpm= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(hrDiff) >= 0 ? '+' : ''}${hrDiff} bpm (Avg)${avgHr} bpm (Avg) / ${maxHr} bpm (Max)
Avg / Max Temp${s1.avgTemp != null ? s1.avgTemp.toFixed(1) : '--'} \u00B0C / ${s1.maxTemp != null ? s1.maxTemp.toFixed(1) : '--'} \u00B0C${s2.avgTemp != null ? s2.avgTemp.toFixed(1) : '--'} \u00B0C / ${s2.maxTemp != null ? s2.maxTemp.toFixed(1) : '--'} \u00B0C= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} \u00B0C (Avg)${avgTemp} \u00B0C (Avg) / ${maxTemp} \u00B0C (Max)
Gear Shifts${s1.shifts || 0}${s2.shifts || 0}= 0 ? '#4ECDC4' : '#FF6B6B'};\">${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff}${totalShifts} (Total)
${sr.sectionLabel} Split${sr.t1Power}W \u00B7 ${sr.t1Hr}bpm \u00B7 ${sr.t1SpeedKmh.toFixed(1)}km/h${sr.t2Power}W \u00B7 ${sr.t2Hr}bpm \u00B7 ${sr.t2SpeedKmh.toFixed(1)}km/h${sr.t2Power - sr.t1Power >= 0 ? '+' : ''}${sr.t2Power - sr.t1Power}WCohort Avg: ${sr.cohortAvgPower}W
\n
\n ${correlations\n .map(\n (c) =>\n `${c.pairLabel}: r=${c.rVal.toFixed(2)}, \u03B2=${c.slope.toFixed(2)} (${c.samples})`,\n )\n .join('')}\n
\n
\n `;\n }\n\n // Render UI with selectors and plot container\n container.innerHTML = `${summaryHtml}\n
\n
\n arrow_forward\n X Axis:\n \n
\n
\n arrow_upward\n Y Axis:\n \n
\n
\n schedule\n Time:\n \n 0:00\n \n
\n
\n \n \n
\n
\n
\n `;\n\n document.getElementById('btn-combined-x')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'x');\n });\n\n document.getElementById('btn-combined-y')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'y');\n });\n\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n const sliderVal = document.getElementById('combined-time-val');\n const playBtn = document.getElementById('btn-combined-play');\n\n slider?.addEventListener('input', () => {\n currentSliderIdx = parseInt(slider.value, 10);\n updateSliderLabel();\n if (plot) plot.redraw();\n });\n\n function startPlaying() {\n if (playBtn) playBtn.innerHTML = 'pause';\n\n playIntervalId = window.setInterval(() => {\n if (currentSliderIdx !== null && currentSliderIdx < currentChronoData.length - 1) {\n currentSliderIdx = Math.min(currentSliderIdx + 5, currentChronoData.length - 1);\n slider.value = `${currentSliderIdx}`;\n updateSliderLabel();\n if (plot) plot.redraw();\n } else {\n stopPlaying();\n }\n }, 20); // 50 fps\n }\n\n function stopPlaying() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (playBtn) playBtn.innerHTML = 'play_arrow';\n }\n\n playBtn?.addEventListener('click', () => {\n if (playIntervalId) {\n stopPlaying();\n } else {\n // If at the end, loop back to start\n if (currentSliderIdx !== null && currentSliderIdx >= currentChronoData.length - 1) {\n currentSliderIdx = 0;\n slider.value = '0';\n updateSliderLabel();\n if (plot) plot.redraw();\n }\n startPlaying();\n }\n });\n\n document.getElementById('btn-combined-cart')?.addEventListener('click', () => {\n if (isPolar) {\n isPolar = false;\n renderCombined(currentTrack);\n }\n });\n\n document.getElementById('btn-combined-polar')?.addEventListener('click', () => {\n if (!isPolar) {\n isPolar = true;\n renderCombined(currentTrack);\n }\n });\n\n updatePlot();\n}\n\nexport function resizeCombined() {\n const container = document.getElementById('tab-combined');\n const plotContainer = document.getElementById('combined-plot-container');\n if (plot && plotContainer && plotContainer.clientWidth > 0) {\n const w = plotContainer.clientWidth;\n const h = plotContainer.clientHeight;\n\n if (w > 0 && h > 0) {\n if (isPolar) {\n const size = Math.min(w, h);\n plot.setSize({ width: size, height: size });\n } else {\n plot.setSize({ width: w, height: h });\n }\n }\n }\n}\n\nfunction showMenu(anchorEl: HTMLElement, axis: 'x' | 'y') {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const track = currentTrack;\n if (!track) return;\n\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n availableMetrics.forEach((key) => {\n const def = metrics[key];\n const item = document.createElement('div');\n const currentVal = axis === 'x' ? xMetric : yMetric;\n item.className = `menu-item ${currentVal === key ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${currentVal === key ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n if (axis === 'x') xMetric = key;\n else yMetric = key;\n\n popup.remove();\n renderCombined(currentTrack); // Re-render to update buttons and plot\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction updatePlot() {\n if (!currentTrack) return;\n const container = document.getElementById('combined-plot-container');\n if (!container) return;\n\n const metrics = ChartView.METRICS;\n const xDef = metrics[xMetric] || metrics.power;\n const yDef = metrics[yMetric] || metrics.hr;\n\n if (currentTracks.length >= 2) {\n let maxLen = 0;\n for (let t = 0; t < currentTracks.length; t++) {\n if (currentTracks[t].points.length > maxLen) maxLen = currentTracks[t].points.length;\n }\n const xData: number[] = new Array(maxLen);\n for (let i = 0; i < maxLen; i++) xData[i] = i;\n\n const seriesList: uPlot.Series[] = [{}];\n const dataArrays: (number | null)[][] = [xData];\n\n for (let t = 0; t < currentTracks.length; t++) {\n const trk = currentTracks[t];\n const pts = trk.points;\n const yArr: (number | null)[] = new Array(maxLen);\n for (let i = 0; i < maxLen; i++) {\n const p = pts[i];\n yArr[i] = p && (p as any)[yDef.field] != null ? (p as any)[yDef.field] : null;\n }\n dataArrays.push(yArr);\n seriesList.push({\n label: `${trk.displayName || trk.name} (${yDef.label})`,\n stroke: trk.color || '#3b82f6',\n width: 2,\n points: { show: false },\n });\n }\n\n if (plot) {\n plot.destroy();\n plot = null;\n }\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n const width = container.clientWidth > 0 ? container.clientWidth : 800;\n const height = container.clientHeight > 0 ? container.clientHeight : 350;\n\n const opts: uPlot.Options = {\n width,\n height,\n padding: [10, 15, 0, 0],\n scales: { x: { time: false }, y: { auto: true } },\n series: seriesList,\n axes: [\n {\n side: 2,\n label: 'Elapsed Duration (s)',\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n side: 3,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n legend: { show: true },\n };\n\n plot = new uPlot(opts, dataArrays as uPlot.AlignedData, container as HTMLElement);\n resizeCombined();\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts[0].time || 0;\n const chronoData = pts\n .map((p, idx) => [\n (p as any)[xDef.field],\n (p as any)[yDef.field],\n (p.time! - t0) / 1000,\n (p.dist || 0) / 1000,\n idx,\n ])\n .filter(([x, y, t, d]) => x != null && y != null) as [number, number, number, number, number][];\n\n if (chronoData.length === 0) {\n container.innerHTML =\n '
No data for selected metrics
';\n return;\n }\n\n if (isPolar) {\n const xVals = chronoData.map((d) => d[0]);\n const yVals = chronoData.map((d) => d[1]);\n const xMin = Math.min(...xVals);\n const xMax = Math.max(...xVals);\n const yMin = Math.min(...yVals);\n const yMax = Math.max(...yVals);\n\n currentChronoData = chronoData.map((d) => {\n const xVal = d[0];\n const yVal = d[1];\n const theta = ((xVal - xMin) / (xMax - xMin || 1)) * 2 * Math.PI;\n const r = (yVal - yMin) / (yMax - yMin || 1);\n const px = r * Math.cos(theta);\n const py = r * Math.sin(theta);\n return [px, py, d[2], d[3], d[4], xVal, yVal] as any;\n });\n } else {\n currentChronoData = chronoData.map((d) => [d[0], d[1], d[2], d[3], d[4], d[0], d[1]] as any);\n }\n\n // Update slider\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n if (slider) {\n slider.max = `${chronoData.length - 1}`;\n if (currentSliderIdx === null || currentSliderIdx >= chronoData.length) {\n currentSliderIdx = chronoData.length - 1;\n slider.value = slider.max;\n }\n updateSliderLabel();\n }\n\n // Sort by X for uPlot (with original point index tie-breaker)\n currentSortedData = [...currentChronoData].sort((a, b) => a[0] - b[0] || a[4] - b[4]);\n\n const xData = currentSortedData.map((d) => d[0]);\n const yData = currentSortedData.map((d) => d[1]);\n\n const plotContainer = document.getElementById('combined-plot-container');\n let width = plotContainer && plotContainer.clientWidth > 0 ? plotContainer.clientWidth : 600;\n let height = plotContainer && plotContainer.clientHeight > 0 ? plotContainer.clientHeight : 400;\n\n if (isPolar) {\n const size = Math.min(width, height > 0 ? height : width);\n width = size;\n height = size;\n\n if (plotContainer) {\n plotContainer.style.display = 'flex';\n plotContainer.style.alignItems = 'center';\n plotContainer.style.justifyContent = 'center';\n }\n } else if (plotContainer) {\n plotContainer.style.display = '';\n plotContainer.style.alignItems = '';\n plotContainer.style.justifyContent = '';\n }\n\n const opts: uPlot.Options = {\n width: width,\n height: height,\n padding: [10, 15, 0, 0],\n scales: {\n x: { time: false, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: yDef.label,\n width: 0,\n points: { show: true, size: 3, fill: hexToRgba(yDef.color, 0.3) },\n },\n ],\n axes: [\n {\n side: 2, // bottom\n show: !isPolar,\n label: `${xDef.label} (${xDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? xDef.fmtAxis(v) : '')),\n size: 30,\n },\n {\n side: 3, // left\n show: !isPolar,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? yDef.fmtAxis(v) : '')),\n size: 40,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => {\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let closestIdx = -1;\n\n for (let i = 0; i < currentSortedData.length; i++) {\n const [xVal, yVal] = currentSortedData[i];\n const cx = u.valToPos(xVal, 'x');\n const cy = u.valToPos(yVal, 'y');\n\n const dx = cx - cursorLeft;\n const dy = cy - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n closestIdx = i;\n }\n }\n\n // Only snap if within a reasonable distance (e.g. 50 pixels)\n if (closestIdx >= 0 && minD2 < 2500) return closestIdx;\n }\n return dataIdx;\n },\n points: {\n size: 7,\n stroke: '#fff',\n width: 2,\n fill: yDef.color,\n },\n },\n legend: { show: false },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Draw faint lines connecting points in chronological order\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.lineWidth = 1 * dpr;\n\n let started = false;\n for (let i = 0; i < currentChronoData.length; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n if (started) {\n ctx.lineTo(cx, cy);\n } else {\n ctx.moveTo(cx, cy);\n started = true;\n }\n }\n ctx.stroke();\n ctx.restore();\n\n // Draw trail if slider is active\n if (currentSliderIdx !== null) {\n ctx.save();\n const windowSize = 100; // Longer trail\n const startIdx = Math.max(0, currentSliderIdx - windowSize);\n const endIdx = currentSliderIdx;\n\n // 1. Draw increasingly thicker connection line for the trail\n for (let i = startIdx; i < endIdx; i++) {\n const [xVal1, yVal1] = currentChronoData[i];\n const [xVal2, yVal2] = currentChronoData[i + 1];\n const cx1 = u.valToPos(xVal1, 'x', true);\n const cy1 = u.valToPos(yVal1, 'y', true);\n const cx2 = u.valToPos(xVal2, 'x', true);\n const cy2 = u.valToPos(yVal2, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const lineWidth = 1 + 5 * progress; // Grow from 1 to 6\n const alpha = 0.15 + 0.6 * progress; // Fade from 0.15 to 0.75\n\n ctx.beginPath();\n ctx.moveTo(cx1, cy1);\n ctx.lineTo(cx2, cy2);\n ctx.strokeStyle = hexToRgba(yDef.color, alpha);\n ctx.lineWidth = lineWidth * dpr;\n ctx.stroke();\n }\n\n // 2. Draw dots on top\n for (let i = startIdx; i <= endIdx; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const size = 3 + 7 * progress; // Grow from 3 to 10\n const fillAlpha = 0.01 + 0.14 * progress; // Fade from 0.01 to 0.15\n\n ctx.beginPath();\n ctx.arc(cx, cy, size * dpr, 0, Math.PI * 2);\n ctx.fillStyle = hexToRgba(yDef.color, fillAlpha);\n ctx.fill();\n\n ctx.strokeStyle = yDef.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n\n let tooltip = document.getElementById('combined-tooltip');\n if (!tooltip) {\n tooltip = document.createElement('div');\n tooltip.id = 'combined-tooltip';\n tooltip.style.position = 'absolute';\n tooltip.style.background = 'rgba(14, 14, 16, 0.9)';\n tooltip.style.color = '#fff';\n tooltip.style.padding = '8px 12px';\n tooltip.style.borderRadius = '4px';\n tooltip.classList.add('font-m');\n tooltip.style.fontFamily = 'system-ui';\n tooltip.style.pointerEvents = 'none';\n tooltip.style.zIndex = '1000';\n tooltip.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';\n tooltip.style.border = '1px solid #2e2e34';\n document.body.appendChild(tooltip);\n }\n\n if (idx != null && currentSortedData[idx] && u.cursor.left! >= 0) {\n const d = currentSortedData[idx];\n const timeSecs = d[2];\n const distKm = d[3];\n const origX = d[5];\n const origY = d[6];\n\n tooltip.innerHTML = `\n
Point #${idx}
\n
\n Time:\n ${fmtSecs(timeSecs)}\n
\n
\n Distance:\n ${distKm.toFixed(2)} km\n
\n
\n ${xDef.label}:\n ${xDef.fmtAxis(origX)} ${xDef.unit}\n
\n
\n ${yDef.label}:\n ${yDef.fmtAxis(origY)} ${yDef.unit}\n
\n `;\n tooltip.style.display = 'block';\n\n const canvasRect = u.over.getBoundingClientRect();\n tooltip.style.left = `${canvasRect.left + window.scrollX + u.cursor.left! + 15}px`;\n tooltip.style.top = `${canvasRect.top + window.scrollY + u.cursor.top! + 15}px`;\n } else {\n tooltip.style.display = 'none';\n }\n },\n ],\n },\n };\n\n // Clear container before rendering (except when uPlot does it)\n // uPlot handles its own canvas, but we need to clear any previous empty state message\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n if (plot) plot.destroy();\n\n plot = new uPlot(opts, [xData, yData], container);\n\n plot.over.addEventListener('click', () => {\n if (plot) {\n const idx = plot.cursor.idx;\n if (idx != null && currentSortedData[idx]) {\n const originalIdx = currentSortedData[idx][4];\n ChartView.setCursorAt(originalIdx);\n }\n }\n });\n\n // Ensure initial size is set synchronously\n resizeCombined();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { UrlState } from '../url-state';\nimport {\n computeAccumulatedMetric,\n renderAccumulatedTable,\n renderAccumulatedProgressSummary,\n} from './accumulated_progress';\n\nlet evolutionPlots: uPlot[] = [];\nlet activeEvolutionCards: any[] = [];\nlet currentEvolutionGrouping: 'week' | 'month' = 'week';\n\nfunction destroyEvolutionPlots() {\n evolutionPlots.forEach((p) => p.destroy());\n evolutionPlots = [];\n activeEvolutionCards = [];\n}\n\nexport function resetEvolution() {\n destroyEvolutionPlots();\n currentEvolutionGrouping = 'week';\n const container = document.getElementById('evolution-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for progress analysis
\n
\n `;\n }\n}\n\nexport function setEvolutionGrouping(grouping: 'week' | 'month') {\n currentEvolutionGrouping = grouping;\n activeEvolutionCards.forEach((c) => {\n if (c && c.updateGrouping) c.updateGrouping(grouping);\n });\n}\n\nexport function setEvolutionRange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n const toolbarRangeCtrl = document.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((b) => {\n b.classList.toggle('active', b.getAttribute('data-range') === range);\n });\n }\n activeEvolutionCards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n}\n\nexport function setEvolutionPinnedDuration(dur: number | null) {\n activeEvolutionCards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n}\n\nconst EVO_CAP = 16384;\nconst evoPwrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoHrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoSpdPrefix = new Float64Array(EVO_CAP + 1);\nconst evoStressArr = new Float64Array(EVO_CAP);\nconst evoDailyTrimp = new Float64Array(365);\nconst envelopeDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 360, 450, 600, 750, 900, 1200,\n];\n\nexport function renderEvolution(\n currentTrack: TrackData | null,\n allTracks: TrackData[],\n onTrackSelect?: (id: string, range: [number, number] | null) => void,\n onDateRangeSelect?: (start: string, end: string) => void,\n) {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (!container) return;\n\n let currentRange = UrlState.get().progress || 'all';\n\n // Ensure duration curves and zones are available on all tracks\n allTracks.forEach((track) => {\n Parsers.ensureCurvesAndZones(track);\n });\n\n // Single-pass Banister impulse-response training load (ATL / CTL / TSB) and historical curve envelope\n let totalFatigue = 0;\n let totalFitness = 0;\n evoDailyTrimp.fill(0);\n\n for (let ti = 0; ti < allTracks.length; ti++) {\n const pts = allTracks[ti].points || [];\n const n = Math.min(pts.length, EVO_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const el = p.ele || 0;\n evoPwrPrefix[i + 1] = evoPwrPrefix[i] + pw;\n evoHrPrefix[i + 1] = evoHrPrefix[i] + h;\n evoSpdPrefix[i + 1] = evoSpdPrefix[i] + sp;\n const hrRatio = Math.max(0, Math.min(1.2, (h - 60) / 135));\n evoStressArr[i] = pw * 1.5 + h + hrRatio * (1 + 1.92 * hrRatio) * 10 + el * 0.02;\n }\n\n for (let di = 0; di < envelopeDurations.length; di++) {\n const d = envelopeDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxH = 0;\n for (let j = 0; j <= limit; j++) {\n const dh = evoHrPrefix[j + d] - evoHrPrefix[j];\n const sp = evoPwrPrefix[j + d] - evoPwrPrefix[j];\n if (sp > maxP) maxP = sp;\n if (dh > maxH) maxH = dh;\n }\n totalFitness += ((maxP + maxH + evoSpdPrefix[limit]) / d) * 1e-3;\n }\n\n const alphaA = 2 / 8;\n const oneMinusA = 1 - alphaA;\n const alphaC = 2 / 43;\n const oneMinusC = 1 - alphaC;\n const hrRest = 52;\n const invHrSpan = 1 / (195 - hrRest);\n let atl = 0;\n let ctl = 0;\n for (let i = 0; i < n; i++) {\n const h = evoHrPrefix[i + 1] - evoHrPrefix[i];\n const hrRatio = Math.max(0, (h - hrRest) * invHrSpan);\n const kh = 1.92 * hrRatio;\n const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * (1 + kh * (1 + 0.5 * kh)) * 15;\n atl = alphaA * trimp + oneMinusA * atl;\n ctl = alphaC * trimp + oneMinusC * ctl;\n }\n totalFatigue += atl * 0.01;\n totalFitness += ctl * 0.01;\n\n const dayIdx = (ti * 57) % 365;\n evoDailyTrimp[dayIdx] += evoPwrPrefix[n] * 1e-3 + evoHrPrefix[n] * 1e-3;\n }\n\n let atl365 = 0;\n let ctl365 = 0;\n for (let day = 0; day < 365; day++) {\n const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15);\n atl365 = atl365 * 0.86 + load * 0.14;\n ctl365 = ctl365 * 0.976 + load * 0.024;\n }\n totalFatigue += atl365 * 1e-3;\n totalFitness += ctl365 * 1e-3;\n\n container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1);\n const cards: any[] = [];\n activeEvolutionCards = cards;\n container.innerHTML = `\n
\n
\n
\n \n \n \n \n
\n
\n
\n
\n \n \n \n \n \n \n
\n
\n
\n
\n `;\n\n const grid = document.getElementById('evolution-container');\n if (!grid) return;\n\n grid.insertAdjacentHTML('beforeend', renderAccumulatedProgressSummary(allTracks));\n\n const gridWidth = grid.clientWidth || 570;\n\n const progressSync = uPlot.sync('progress-sync');\n cards.push(\n renderProgressCard(grid, allTracks, 'distance', progressSync, onDateRangeSelect, gridWidth),\n );\n cards.push(\n renderProgressCard(grid, allTracks, 'elevation', progressSync, onDateRangeSelect, gridWidth),\n );\n\n const distanceScroll = grid.querySelector(\n '.distance-progress-card .chart-scroll-container',\n ) as HTMLElement;\n const elevationScroll = grid.querySelector(\n '.elevation-progress-card .chart-scroll-container',\n ) as HTMLElement;\n\n if (distanceScroll && elevationScroll) {\n distanceScroll.addEventListener('scroll', () => {\n if (elevationScroll.scrollLeft !== distanceScroll.scrollLeft)\n elevationScroll.scrollLeft = distanceScroll.scrollLeft;\n });\n elevationScroll.addEventListener('scroll', () => {\n if (distanceScroll.scrollLeft !== elevationScroll.scrollLeft)\n distanceScroll.scrollLeft = elevationScroll.scrollLeft;\n });\n }\n\n const toolbarRangeCtrl = container.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const range = btn.getAttribute('data-range');\n if (range) {\n toolbarRangeCtrl\n .querySelectorAll('.seg-btn')\n .forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n onRangeChange(range);\n }\n });\n });\n }\n\n const pills = container.querySelectorAll('.metric-pill');\n pills.forEach((pill) => {\n pill.addEventListener('click', () => {\n const target = pill.getAttribute('data-target');\n if (target) {\n const targetEl = document.getElementById(`${target}-evolution-card`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n });\n });\n\n function onPinChange(dur: number | null) {\n cards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n }\n\n function onRangeChange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n }\n\n if (allTracks.some((t) => t.stats.powerCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'power',\n label: 'Power Curve Progress',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n if (allTracks.some((t) => t.stats.hrCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'hr',\n label: 'Heart Rate Curve Progress',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n // Apply initial range when filtered\n if (currentRange !== 'all') {\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(currentRange);\n });\n }\n\n evolutionPlots.forEach((p) => {\n (p as any)._ready = true;\n });\n}\n\ninterface CurveEvolutionCardOptions {\n grid: HTMLElement;\n currentTrack: TrackData | null;\n allTracks: TrackData[];\n metricKey: 'power' | 'hr';\n label: string;\n unit: string;\n color: string;\n icon: string;\n onPinChange: (dur: number | null) => void;\n onRangeChange: (range: string) => void;\n onTrackSelect?: (id: string, range: [number, number] | null) => void;\n gridWidth?: number;\n}\n\nfunction renderCurveEvolutionCard(opts: CurveEvolutionCardOptions) {\n const {\n grid,\n currentTrack,\n allTracks,\n metricKey,\n label,\n unit,\n color,\n icon,\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n } = opts;\n\n const trackName = currentTrack ? currentTrack.name || 'Current Track' : 'Current Track';\n\n let mainChart: uPlot | null = null;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = 'chart-row evolution-card-group';\n cardContainer.id = `${metricKey}-evolution-card`;\n grid.appendChild(cardContainer);\n\n const row1 = document.createElement('div');\n row1.className = 'chart-row progress-chart-row';\n row1.style.setProperty('--chart-color', color);\n row1.style.flex = '0 0 400px';\n row1.style.borderBottom = 'none';\n row1.innerHTML = `\n
\n
\n ${icon}\n ${label}\n
\n
\n
\n
\n
\n `;\n\n const legendEl = document.createElement('div');\n legendEl.className = 'evolution-legend';\n legendEl.innerHTML = `\n
\n \n ${trackName}\n
\n
\n \n All-Time Max\n
\n `;\n\n const urlState = UrlState.get();\n let currentRange = urlState.progress || 'all';\n\n const row2 = document.createElement('div');\n row2.className = 'chart-row progress-chart-row';\n row2.style.setProperty('--chart-color', color);\n row2.style.flex = '1';\n row2.style.borderBottom = 'none';\n row2.innerHTML = `\n
\n
\n ${icon}\n Progress ${metricKey === 'power' ? 'Power' : 'HR'}\n
\n
\n
\n
\n
\n `;\n\n const sideBySide = document.createElement('div');\n sideBySide.style.cssText = 'display: flex; flex-direction: row; gap: 0px; align-items: stretch;';\n sideBySide.appendChild(row1);\n sideBySide.appendChild(row2);\n\n cardContainer.appendChild(sideBySide);\n cardContainer.appendChild(legendEl);\n\n const chartEl = row1.querySelector(`#${metricKey}-evolution-chart`) as HTMLElement;\n if (!chartEl) return;\n\n // 1. Compute global max curve\n const maxCurve: Record<\n number,\n { val: number; trackInfo: string; trackId?: string; idx?: number }\n > = {};\n allTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n const name = t.name || 'Unnamed Track';\n const date =\n t.stats.startTime || t.addedAt ? fmtDate((t.stats.startTime || t.addedAt)!) : 'Unknown Date';\n const trackInfo = `${name} (${date})`;\n\n Object.entries(curve).forEach(([dur, data]) => {\n const d = Number(dur);\n const val = (data as any).power || (data as any).hr;\n if (!maxCurve[d] || val > maxCurve[d].val)\n maxCurve[d] = { val, trackInfo, trackId: t.id, idx: (data as any).idx };\n });\n });\n\n // 2. Get current track curve\n const currentCurve =\n (currentTrack &&\n (metricKey === 'power' ? currentTrack.stats.powerCurve : currentTrack.stats.hrCurve)) ||\n {};\n\n // 3. Combine durations\n const allDurations = new Set();\n Object.keys(maxCurve).forEach((d) => allDurations.add(Number(d)));\n Object.keys(currentCurve).forEach((d) => allDurations.add(Number(d)));\n const durations = Array.from(allDurations).sort((a, b) => a - b);\n\n const xData = durations;\n const yDataCurrent = durations.map((d) => {\n const entry = currentCurve[d];\n return entry ? (entry as any).power || (entry as any).hr : null;\n });\n const yDataMax = durations.map((d) => maxCurve[d]?.val || null);\n\n // Precompute timeline data for all tracks\n const validTracks = allTracks.filter((t) => (t.stats.startTime || t.addedAt) != null);\n validTracks.sort(\n (a, b) =>\n (a.stats.startTime || a.addedAt || 0) - (b.stats.startTime || b.addedAt || 0) ||\n a.id.localeCompare(b.id),\n );\n\n const xTimeline: number[] = [];\n const yTimelineData: Record = {};\n durations.forEach((d) => (yTimelineData[d] = []));\n\n validTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n\n xTimeline.push((t.stats.startTime || t.addedAt)! / 1000); // seconds\n durations.forEach((d) => {\n const entry = curve[d];\n const val = entry ? (metricKey === 'power' ? (entry as any).power : (entry as any).hr) : null;\n yTimelineData[d].push(val);\n });\n });\n\n let currentDur = durations[0] || 5;\n let tracksFiltered = validTracks;\n let pinnedDur: number | null = null;\n\n function getFilteredData(dur: number, range: string) {\n const maxTime = xTimeline[xTimeline.length - 1] || 1785542400;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600;\n\n const filteredIndices: number[] = [];\n xTimeline.forEach((t, idx) => {\n if (t >= minTime) filteredIndices.push(idx);\n });\n\n const xFiltered = filteredIndices.map((i) => xTimeline[i]);\n const rawY = yTimelineData[dur] || [];\n const rawYFiltered = filteredIndices.map((i) => rawY[i]);\n const smoothedYFiltered = gaussianSmooth(rawYFiltered, 5);\n tracksFiltered = filteredIndices.map((i) => validTracks[i]);\n\n return { xFiltered, rawYFiltered, smoothedYFiltered };\n }\n\n let timelineChart: uPlot | null = null;\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val font-m';\n curYVal.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const renderCharts = () => {\n const optsUPlot: uPlot.Options = {\n id: `${metricKey}-evolution`,\n width: 400,\n height: 250,\n padding: [0, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: 'Current Track',\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n {\n label: 'All-Time Max',\n stroke: '#888888',\n width: 1,\n fill: 'transparent',\n points: { show: true, size: 6, fill: '#888888' },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n x: false,\n y: false,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n\n // Draw pinned duration circle\n if (pinnedDur !== null) {\n const idx = xData.indexOf(pinnedDur);\n if (idx >= 0) {\n const pcx = u.valToPos(pinnedDur, 'x', true);\n const pcy = u.valToPos(yDataCurrent[idx]! || yDataMax[idx]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]);\n const curVal = yDataCurrent[idx];\n const dotRadius = curVal !== null ? 5 * dpr : 3 * dpr;\n const dotColor = curVal !== null ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n }\n\n ctx.restore();\n },\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(\n activeSeriesIdx === 1 ? yDataCurrent[idx]! : yDataMax[idx]!,\n 'y',\n true,\n );\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n const dotRadius = activeSeriesIdx === 1 ? 5 * dpr : 6 * dpr;\n const dotColor = activeSeriesIdx === 1 ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n const xValStr = fmtDuration(xData[idx!]);\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n // X Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const yVal = yDataCurrent[idx!]! || yDataMax[idx!]!;\n const yValStr = `${yVal.toFixed(0)} ${unit}`;\n const yValWidth = ctx.measureText(yValStr).width;\n const ybw = yValWidth + 10 * dpr;\n\n const yLabelX = bb.left - ybw - 2 * dpr; // To the left\n const yLabelY = pcy - pillH / 2;\n\n // Y Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * dpr);\n else ctx.rect(yLabelX, yLabelY, ybw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(yValStr, yLabelX + 5 * dpr, yLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n const hasFocus = idx != null && xData[idx] != null;\n\n if (hasFocus) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yDataCurrent[idx!]! || yDataMax[idx!]!, 'y', false); // Fallback to max if current is null\n\n const durVal = xData[idx!];\n const curVal = yDataCurrent[idx!];\n const mxVal = yDataMax[idx!];\n\n let html = `
${fmtDuration(durVal)}
`;\n if (curVal !== null) {\n html += `\n
\n Current:\n ${curVal} ${unit}\n
\n `;\n }\n if (mxVal !== null) {\n html += `\n
\n Max:\n ${mxVal} ${unit}\n
\n `;\n }\n\n curYVal.innerHTML = html;\n\n if (timelineChart) {\n if (pinnedDur === null) {\n currentDur = durVal;\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([\n xFiltered,\n rawYFiltered,\n smoothedYFiltered,\n lowerBound,\n upperBound,\n ]);\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(durVal)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n }\n }\n curYVal.style.display = '';\n curYVal.style.left = `${cursorLeft! + bb.left}px`;\n curYVal.style.top = `${cursorTop! + bb.top}px`;\n curYVal.style.transform = 'translate(5px, -50%)';\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n };\n\n mainChart = new uPlot(optsUPlot, [xData, yDataCurrent, yDataMax], chartEl);\n evolutionPlots.push(mainChart);\n\n chartEl.addEventListener('click', () => {\n if (!mainChart) return;\n const idx = mainChart.cursor.idx;\n if (idx != null) {\n const clickedDur = xData[idx];\n let newPinnedDur: number | null = null;\n if (pinnedDur !== null) newPinnedDur = null;\n else newPinnedDur = clickedDur;\n\n onPinChange(newPinnedDur);\n\n // Also select the range for the current track if available\n if (currentTrack) {\n const stats = currentTrack.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[clickedDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = clickedDur;\n const startPt = currentTrack.points[bestIdx];\n const endPt = currentTrack.points[bestIdx + duration - 1];\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = currentTrack.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n onTrackSelect?.(currentTrack.id, [min, max]);\n }\n }\n }\n }\n }\n });\n\n chartEl.addEventListener('mouseleave', () => {\n if (mainChart) mainChart.redraw();\n });\n\n // 4. Add expandable table\n const detailsEl = document.createElement('details');\n detailsEl.classList.add('progress-details');\n detailsEl.style.marginTop = '0px';\n detailsEl.style.setProperty('--chart-color', color);\n detailsEl.innerHTML = `\n \n chevron_right\n table_chart\n Data Table\n \n \n \n \n \n \n \n \n \n \n ${durations\n .map((d) => {\n const cur = currentCurve[d]\n ? (currentCurve[d] as any).power || (currentCurve[d] as any).hr\n : '-';\n const mx = maxCurve[d]?.val || '-';\n const mxId = maxCurve[d]?.trackId;\n const mxIdx = maxCurve[d]?.idx;\n return `\n \n \n \n \n \n `;\n })\n .join('')}\n \n
DurationCurrentAll-Time Max
${fmtDuration(d)}${cur} ${unit}\n ${mx} ${unit}\n ${mxId ? `` : ''}\n
\n `;\n cardContainer.appendChild(detailsEl);\n\n detailsEl.querySelectorAll('.evolution-select-btn').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const id = btn.getAttribute('data-id');\n const idx = btn.getAttribute('data-idx');\n const dur = btn.getAttribute('data-dur');\n if (id) {\n document.dispatchEvent(\n new CustomEvent('select-track', {\n detail: {\n id,\n idx: idx ? Number(idx) : null,\n dur: dur ? Number(dur) : null,\n },\n }),\n );\n }\n });\n });\n\n let lastNearestIdx: number | null = null;\n\n // 5. Render timeline chart\n const timelineEl = row2.querySelector(`#${metricKey}-timeline-chart`) as HTMLElement;\n if (timelineEl) {\n timelineEl.style.position = 'relative';\n const timelineTooltip = document.createElement('div');\n timelineTooltip.className = 'timeline-tooltip font-m';\n timelineTooltip.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n timelineEl.appendChild(timelineTooltip);\n\n if (xTimeline.length > 0) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n const dataTimeline = [xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound];\n\n const series: any[] = [\n {\n value: (u: any, v: number) => {\n if (v != null) return fmtDate(v * 1000);\n\n return '-';\n },\n },\n {\n label: 'Value',\n stroke: color,\n width: 0,\n points: { show: true, size: 6, fill: hexToRgba(color, 0.5) },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n points: { show: false },\n spanGaps: true,\n fill: 'transparent',\n dash: [5, 5],\n },\n {\n label: 'Lower Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n {\n label: 'Upper Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n ];\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n\n const optsTimeline: uPlot.Options = {\n width: Math.max(100, (gridWidth || 570) - 400),\n height: 250,\n padding: [0, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n cursor: {\n points: {\n show: false,\n },\n drag: { setScale: false },\n x: false,\n y: false,\n },\n scales: {\n x: {\n time: true,\n range: (u) => {\n const min = u.data[0][0];\n const max = u.data[0][u.data[0].length - 1];\n if (min === undefined || max === undefined) return [0, 100];\n\n if (min === max) return [min - 3600, max + 3600];\n\n return [min, max];\n },\n },\n y: { range: (u: any, min: number, max: number) => [min * 0.9, max * 1.1] },\n },\n series: series,\n bands: [{ series: [4, 3], fill: hexToRgba(color, 0.2) }],\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n if (lastNearestIdx != null) {\n const track = tracksFiltered[lastNearestIdx];\n if (track) {\n const stats = track.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[currentDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = currentDur;\n\n const startPt = track.points[bestIdx];\n const endPt = track.points[bestIdx + duration - 1];\n\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = track.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n\n opts.onTrackSelect?.(track.id, [min, max]);\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n }\n }\n });\n },\n ],\n draw: [\n (u: uPlot) => {\n let idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const val = u.data[1][idx];\n if (val != null) {\n const tpcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const tpcy = u.valToPos(val, 'y', true);\n\n const tctx = u.ctx;\n const tdpr = window.devicePixelRatio || 1;\n\n // Draw lines\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([2 * tdpr, 2 * tdpr]);\n tctx.strokeStyle = hexToRgba(color, 0.4);\n tctx.lineWidth = 1 * tdpr;\n // Vertical line\n tctx.moveTo(tpcx, u.bbox.top);\n tctx.lineTo(tpcx, u.bbox.top + u.bbox.height);\n // Horizontal line\n tctx.moveTo(u.bbox.left, tpcy);\n tctx.lineTo(u.bbox.left + u.bbox.width, tpcy);\n tctx.stroke();\n tctx.restore();\n\n // Draw hover halo\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([]); // Reset to solid\n tctx.arc(tpcx, tpcy, 12 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = hexToRgba(color, 0.2);\n tctx.fill();\n tctx.restore();\n\n // Draw center circle\n tctx.save();\n tctx.beginPath();\n tctx.arc(tpcx, tpcy, 6 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = color;\n tctx.fill();\n tctx.strokeStyle = '#fff';\n tctx.lineWidth = 2 * tdpr;\n tctx.stroke();\n tctx.restore();\n\n // Draw axis labels\n tctx.save();\n tctx.setLineDash([]); // Reset to solid\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n tctx.font = `bold ${10 * tdpr}px system-ui, sans-serif`;\n const dateWidth = tctx.measureText(dateStr).width;\n const xbw = dateWidth + 10 * tdpr;\n const pillH = 16 * tdpr;\n\n const xLabelX = tpcx - xbw / 2;\n const clampedXBx = Math.max(\n u.bbox.left,\n Math.min(u.bbox.left + u.bbox.width - xbw, xLabelX),\n );\n const xLabelY = u.bbox.top + u.bbox.height + 2 * tdpr;\n\n // X Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * tdpr);\n else tctx.rect(clampedXBx, xLabelY, xbw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'center';\n tctx.textBaseline = 'middle';\n tctx.fillText(dateStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const valStr = `${val.toFixed(0)} ${unit}`;\n const valWidth = tctx.measureText(valStr).width;\n const ybw = valWidth + 10 * tdpr;\n\n const yLabelX = u.bbox.left - ybw - 2 * tdpr; // To the left\n const yLabelY = tpcy - pillH / 2;\n\n // Y Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * tdpr);\n else tctx.rect(yLabelX, yLabelY, ybw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'left';\n tctx.textBaseline = 'middle';\n tctx.fillText(valStr, yLabelX + 5 * tdpr, yLabelY + pillH / 2);\n\n tctx.restore();\n }\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n const bb = u.bbox;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n const xData = u.data[0];\n const yData = u.data[1];\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const y = yData[i];\n if (x == null || y == null) continue;\n\n const px = u.valToPos(x, 'x', false);\n const py = u.valToPos(y, 'y', false);\n\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n }\n }\n\n if (minD2 <= maxD2) {\n idx = nearestIdx;\n lastNearestIdx = nearestIdx;\n } else {\n idx = null;\n lastNearestIdx = null;\n }\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const track = tracksFiltered[idx];\n const cx = u.valToPos(u.data[0][idx], 'x', false);\n const cy = u.valToPos(u.data[1][idx]!, 'y', false);\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n\n const val = u.data[1][idx];\n const valStr = val != null ? `${val} ${unit}` : '\u2014';\n\n timelineTooltip.innerHTML = `\n
\n Date:\n ${dateStr}\n
\n
\n Value:\n ${valStr}\n
\n `;\n timelineTooltip.style.display = 'block';\n timelineTooltip.style.left = `${cursorLeft! + bb.left}px`;\n timelineTooltip.style.top = `${cursorTop! + bb.top}px`;\n timelineTooltip.style.transform = 'translate(5px, -50%)';\n } else {\n timelineTooltip.style.display = 'none';\n }\n },\n ],\n },\n axes: [\n {\n space: 50,\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n show: true,\n font: '10px system-ui, sans-serif',\n size: 30,\n values: (u: any, vals: any[]) =>\n vals.map((v) => {\n const d = new Date(v * 1000);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n }),\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n font: '10px system-ui, sans-serif',\n values: (u: any, vals: any[]) => vals.map((v) => `${v} ${unit}`),\n show: true,\n space: 15,\n size: 50,\n },\n ],\n };\n\n timelineChart = new uPlot(optsTimeline, dataTimeline as any, timelineEl);\n evolutionPlots.push(timelineChart);\n\n timelineEl.addEventListener('mouseleave', () => {\n timelineChart!.redraw();\n });\n\n // Range control moved to toolbar\n } else {\n timelineEl.innerHTML = '
No data for the past year
';\n }\n }\n };\n renderCharts();\n\n return {\n updatePin: (dur: number | null) => {\n pinnedDur = dur;\n if (dur !== null) currentDur = dur;\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}${pinnedDur !== null ? ' (Pinned)' : ''}`;\n\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n if (mainChart) mainChart.redraw();\n },\n updateRange: (range: string) => {\n currentRange = range;\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n },\n };\n}\n\nfunction getWeekStart(date: Date): Date {\n const d = new Date(date);\n const day = d.getUTCDay();\n const diff = d.getUTCDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday\n d.setUTCDate(diff);\n d.setUTCHours(0, 0, 0, 0);\n return d;\n}\n\nfunction computeWeeklyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey]) weeklyData[weekKey] = { timestamp: weekStart.getTime(), distance: 0 };\n\n weeklyData[weekKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeWeeklyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey])\n weeklyData[weekKey] = { timestamp: weekStart.getTime(), elevation: 0 };\n\n weeklyData[weekKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeMonthlyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const monthlyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n const date = new Date(t.stats.startTime);\n const monthStart = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n const monthKey = monthStart.toISOString().slice(0, 7);\n if (!monthlyData[monthKey]) {\n monthlyData[monthKey] = { timestamp: monthStart.getTime(), distance: 0 };\n }\n monthlyData[monthKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(monthlyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeMonthlyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const monthlyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n const date = new Date(t.stats.startTime);\n const monthStart = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n const monthKey = monthStart.toISOString().slice(0, 7);\n if (!monthlyData[monthKey]) {\n monthlyData[monthKey] = { timestamp: monthStart.getTime(), elevation: 0 };\n }\n monthlyData[monthKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(monthlyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction renderProgressCard(\n grid: HTMLElement,\n allTracks: TrackData[],\n type: 'distance' | 'elevation',\n syncKey?: any,\n onDateRangeSelect?: (start: string, end: string) => void,\n gridWidth?: number,\n) {\n const isDistance = type === 'distance';\n let activeGrouping: 'week' | 'month' = currentEvolutionGrouping;\n let activeRange = UrlState.get().progress || 'all';\n const weeklySource = isDistance\n ? computeWeeklyDistance(allTracks)\n : computeWeeklyElevation(allTracks);\n const monthlySource = isDistance\n ? computeMonthlyDistance(allTracks)\n : computeMonthlyElevation(allTracks);\n let weeklyData = activeGrouping === 'month' ? monthlySource : weeklySource;\n const accumulated = computeAccumulatedMetric(allTracks, (t) =>\n isDistance ? t.stats.totalDist : t.stats.elevGain,\n );\n const color = isDistance ? Metrics.distance.color : Metrics.elevation.color;\n const unit = isDistance ? 'km' : 'm';\n const icon = isDistance ? Metrics.distance.icon : Metrics.elevation.icon;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = `chart-row ${type}-progress-card`;\n cardContainer.id = `${type}-evolution-card`;\n\n cardContainer.innerHTML = `\n
\n
\n ${icon}\n ${isDistance ? 'Distance Progress' : 'Elevation Progress'}\n
\n
\n
\n
\n
\n
\n
\n
\n ${renderAccumulatedTable(accumulated, isDistance, unit)}\n
\n
\n `;\n\n grid.appendChild(cardContainer);\n\n const chartEl = cardContainer.querySelector(`#${type}-weekly-chart`) as HTMLElement;\n const yAxisEl = cardContainer.querySelector(`#${type}-y-axis-chart`) as HTMLElement;\n\n if (!chartEl || !yAxisEl) return;\n\n chartEl.style.position = 'relative';\n\n // Use inline tooltip style\n const tooltip = document.createElement('div');\n tooltip.className = 'cur-y-val';\n tooltip.style.cssText = `color:${color};display:none`;\n chartEl.appendChild(tooltip);\n\n const xData = weeklyData.map((d) => d.timestamp / 1000);\n const yData = isDistance\n ? (weeklyData as any[]).map((d) => d.distance / 1000)\n : (weeklyData as any[]).map((d) => d.elevation);\n\n if (xData.length === 0) return;\n\n const yDataSmoothed = gaussianSmooth(yData, 2);\n\n const chartClientW = Math.max(0, (gridWidth || 570) - 20 - 320 - 20);\n const width = Math.max(chartClientW, xData.length * 40);\n const maxVal = Math.max(...yData) * 1.1;\n\n const mainOpts: uPlot.Options = {\n width: width,\n height: 150,\n padding: [10, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n scales: {\n x: { time: true },\n y: { range: [0, maxVal] },\n },\n series: [\n {},\n {\n label: isDistance ? 'Distance' : 'Elevation',\n stroke: color,\n fill: hexToRgba(color, 0.1),\n width: 2,\n points: { show: true, size: 4 },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n dash: [5, 5],\n points: { show: false },\n },\n ],\n cursor: {\n sync: syncKey ? { key: syncKey.key } : undefined,\n drag: { x: false, y: false },\n points: { show: false },\n x: false,\n y: false,\n },\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null) {\n const item = weeklyData[idx];\n if (item) {\n const start = new Date(item.timestamp);\n const end = new Date(item.timestamp + 7 * 24 * 60 * 60 * 1000); // End of week\n const startStr = start.toISOString().split('T')[0];\n const endStr = end.toISOString().split('T')[0];\n onDateRangeSelect?.(startStr, endStr);\n }\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n const idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (\n idx != null &&\n cursorLeft != null &&\n cursorTop != null &&\n cursorLeft >= 0 &&\n cursorTop >= 0\n ) {\n const val = u.data[1][idx];\n const valStr =\n val != null ? (isDistance ? `${val.toFixed(1)} km` : `${val.toFixed(0)} m`) : '\u2014';\n\n tooltip.innerHTML = valStr;\n tooltip.style.display = 'block';\n tooltip.style.left = `${u.valToPos(u.data[0][idx]!, 'x', false)}px`;\n tooltip.style.top = `${u.valToPos(u.data[1][idx]!, 'y', false)}px`;\n tooltip.style.transform = 'translate(6px, -50%)';\n } else {\n tooltip.style.display = 'none';\n }\n\n u.redraw(false);\n },\n ],\n draw: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(u.data[1][idx]!, 'y', true);\n const dpr = window.devicePixelRatio || 1;\n const ctx = u.ctx;\n const bb = u.bbox;\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n ctx.arc(pcx, pcy, 6 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n // X Label Pill\n const d = new Date(u.data[0][idx]! * 1000);\n const xValStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n },\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n space: 40,\n values: (self, splits) =>\n splits.map((s) => {\n const d = new Date(s * 1000);\n return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`;\n }),\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: (self, splits) => splits.map((s) => `${s.toFixed(0)} ${unit}`),\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n };\n\n const mainChart = new uPlot(mainOpts, [xData, yData, yDataSmoothed], chartEl);\n evolutionPlots.push(mainChart);\n\n const scrollContainer = cardContainer.querySelector('.chart-scroll-container') as HTMLElement;\n if (scrollContainer && xData.length * 40 > width)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n\n function applySeriesData() {\n weeklyData = activeGrouping === 'month' ? monthlySource : weeklySource;\n const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000;\n let minTime = 0;\n\n if (activeRange === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000;\n else if (activeRange === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000;\n else if (activeRange === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000;\n else if (activeRange === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000;\n else if (activeRange === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000;\n\n const filteredData = weeklyData.filter((d) => d.timestamp >= minTime);\n\n const newXData = filteredData.map((d) => d.timestamp / 1000);\n const newYData = isDistance\n ? (filteredData as any[]).map((d) => d.distance / 1000)\n : (filteredData as any[]).map((d) => d.elevation);\n const newYDataSmoothed = gaussianSmooth(newYData, 2);\n\n const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40);\n const newMaxVal = Math.max(1, ...newYData) * 1.1;\n\n mainChart.setSize({ width: newWidth, height: 150 });\n mainChart.setScale('y', { min: 0, max: newMaxVal });\n mainChart.setData([newXData, newYData, newYDataSmoothed]);\n\n if (scrollContainer)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n }\n\n return {\n updateRange: (range: string) => {\n activeRange = range;\n applySeriesData();\n },\n updateGrouping: (grouping: 'week' | 'month') => {\n activeGrouping = grouping;\n applySeriesData();\n },\n };\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData } from '../parsers';\n\nexport interface AccumulatedData {\n currentYear: number;\n pastYear: number;\n past6m: number;\n past1m: number;\n total: number;\n currentYearAvg: number;\n pastYearAvg: number;\n past6mAvg: number;\n past1mAvg: number;\n totalAvg: number;\n}\n\nexport function computeAccumulatedMetric(\n allTracks: TrackData[],\n extractor: (t: TrackData) => number | undefined,\n): AccumulatedData {\n // Derive deterministic reference timestamp from tracks (or fixed UTC fallback)\n let refTs = 0;\n for (let i = 0; i < allTracks.length; i++) {\n const st = allTracks[i].stats?.startTime;\n if (st && st > refTs) refTs = st;\n }\n if (!refTs) refTs = Date.UTC(2026, 7, 1);\n\n const now = new Date(refTs);\n const currentYear = now.getUTCFullYear();\n\n const oneYearAgoMs = Date.UTC(\n currentYear - 1,\n now.getUTCMonth(),\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const sixMonthsAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 6,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const oneMonthAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 1,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n\n let currentYearVal = 0;\n let pastYearVal = 0;\n let past6mVal = 0;\n let past1mVal = 0;\n let totalVal = 0;\n\n let minTime = refTs;\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime) return;\n const val = extractor(t);\n if (val === undefined) return;\n\n totalVal += val;\n\n const time = t.stats.startTime;\n if (time < minTime) minTime = time;\n\n const date = new Date(time);\n\n if (date.getUTCFullYear() === currentYear) currentYearVal += val;\n\n if (time >= oneYearAgoMs) pastYearVal += val;\n\n if (time >= sixMonthsAgoMs) past6mVal += val;\n\n if (time >= oneMonthAgoMs) past1mVal += val;\n });\n\n const msecPerWeek = 7 * 24 * 60 * 60 * 1000;\n const currentYearStart = Date.UTC(currentYear, 0, 1);\n\n const currentYearWeeks = Math.max(0.1, (refTs - currentYearStart) / msecPerWeek);\n const pastYearWeeks = Math.max(0.1, (refTs - oneYearAgoMs) / msecPerWeek);\n const past6mWeeks = Math.max(0.1, (refTs - sixMonthsAgoMs) / msecPerWeek);\n const past1mWeeks = Math.max(0.1, (refTs - oneMonthAgoMs) / msecPerWeek);\n const totalWeeks = Math.max(0.1, (refTs - minTime) / msecPerWeek);\n\n return {\n currentYear: currentYearVal,\n pastYear: pastYearVal,\n past6m: past6mVal,\n past1m: past1mVal,\n total: totalVal,\n currentYearAvg: currentYearVal / currentYearWeeks,\n pastYearAvg: pastYearVal / pastYearWeeks,\n past6mAvg: past6mVal / past6mWeeks,\n past1mAvg: past1mVal / past1mWeeks,\n totalAvg: totalVal / totalWeeks,\n };\n}\n\nexport function renderAccumulatedTable(\n accumulated: AccumulatedData,\n isDistance: boolean,\n unit: string,\n): string {\n const factor = isDistance ? 1000 : 1;\n const format = (val: number) => {\n const formattedVal = isDistance ? val / factor : val;\n return formattedVal.toLocaleString('en-US', {\n minimumFractionDigits: isDistance ? 1 : 0,\n maximumFractionDigits: isDistance ? 1 : 0,\n });\n };\n\n return `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Period${isDistance ? 'Distance' : 'Elevation'}${isDistance ? 'Distance/Week' : 'Elevation/Week'}
Current Year${format(accumulated.currentYear)} ${unit}${format(accumulated.currentYearAvg)} ${unit}
Past Year${format(accumulated.pastYear)} ${unit}${format(accumulated.pastYearAvg)} ${unit}
Past 6 Months${format(accumulated.past6m)} ${unit}${format(accumulated.past6mAvg)} ${unit}
Past 1 Month${format(accumulated.past1m)} ${unit}${format(accumulated.past1mAvg)} ${unit}
Total${format(accumulated.total)} ${unit}${format(accumulated.totalAvg)} ${unit}
\n `;\n}\n\nexport interface MultiMetricAccumulatedSummary {\n distance: AccumulatedData;\n elevation: AccumulatedData;\n durationHours: AccumulatedData;\n tss: AccumulatedData;\n workKj: AccumulatedData;\n climbCount: AccumulatedData;\n}\n\nexport function computeMultiMetricAccumulated(\n allTracks: TrackData[],\n): MultiMetricAccumulatedSummary {\n const distance = computeAccumulatedMetric(allTracks, (t) => t.stats.totalDist);\n const elevation = computeAccumulatedMetric(allTracks, (t) => t.stats.elevGain);\n const durationHours = computeAccumulatedMetric(allTracks, (t) =>\n t.stats.duration ? t.stats.duration / 3600000 : 0,\n );\n const tss = computeAccumulatedMetric(allTracks, (t) => {\n const durSec = (t.stats.duration || 0) / 1000;\n const avgPwr = t.stats.avgPower || 150;\n const ftp = 200;\n const intensityFactor = avgPwr / ftp;\n return ((durSec * avgPwr * intensityFactor) / (ftp * 3600)) * 100;\n });\n const workKj = computeAccumulatedMetric(allTracks, (t) => {\n const durSec = (t.stats.duration || 0) / 1000;\n const avgPwr = t.stats.avgPower || 0;\n return (durSec * avgPwr) / 1000;\n });\n const climbCount = computeAccumulatedMetric(allTracks, (t) => {\n const secs = t.stats.sections || [];\n return secs.filter((s) => s.kind === 'climb').length;\n });\n\n return {\n distance,\n elevation,\n durationHours,\n tss,\n workKj,\n climbCount,\n };\n}\n\nexport function renderAccumulatedProgressSummary(allTracks: TrackData[]): string {\n const summary = computeMultiMetricAccumulated(allTracks);\n const fmt = (v: number, digits = 1) =>\n v.toLocaleString('en-US', {\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n });\n\n const rows: {\n label: string;\n unit: string;\n data: AccumulatedData;\n scale: number;\n digits: number;\n }[] = [\n { label: 'Distance', unit: 'km', data: summary.distance, scale: 0.001, digits: 1 },\n { label: 'Elevation Gain', unit: 'm', data: summary.elevation, scale: 1, digits: 0 },\n { label: 'Moving Duration', unit: 'h', data: summary.durationHours, scale: 1, digits: 1 },\n { label: 'Training Stress (TSS)', unit: 'TSS', data: summary.tss, scale: 1, digits: 0 },\n { label: 'Mechanical Work', unit: 'kJ', data: summary.workKj, scale: 1, digits: 0 },\n { label: 'Categorized Climbs', unit: 'climbs', data: summary.climbCount, scale: 1, digits: 0 },\n ];\n\n return `\n
\n
\n
\n monitoring\n Accumulated Longitudinal Progress Summary\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n ${rows\n .map(\n (r) => `\n \n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
MetricPast 1MPast 6MPast YearCurrent YearTotalWeekly Avg
${r.label}${fmt(r.data.past1m * r.scale, r.digits)} ${r.unit}${fmt(r.data.past6m * r.scale, r.digits)} ${r.unit}${fmt(r.data.pastYear * r.scale, r.digits)} ${r.unit}${fmt(r.data.currentYear * r.scale, r.digits)} ${r.unit}${fmt(r.data.total * r.scale, r.digits)} ${r.unit}${fmt(r.data.totalAvg * r.scale, r.digits)} ${r.unit}/wk
\n
\n `;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 Main Application \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { Storage } from './storage';\nimport { UrlState, AppState } from './url-state';\nimport { Parsers, TrackData, TrackPoint, calculateBounds, simplifyTrack } from './parsers';\nimport { MapView } from './map';\nimport { ChartView } from './charts';\nimport { renderDetails, initDetails, resetDetails } from './tabs/details';\nimport { renderInsights, initInsights, resetInsights } from './tabs/insights';\nimport {\n renderCombined,\n initCombined,\n resizeCombined,\n resetCombined,\n setCombinedMetrics,\n setCombinedPolar,\n setCombinedSliderProgress,\n} from './tabs/combined';\nimport {\n renderEvolution,\n resetEvolution,\n setEvolutionGrouping,\n setEvolutionRange,\n setEvolutionPinnedDuration,\n} from './tabs/progress';\nimport {\n renderCourses,\n initCourses,\n prepareBenchmarkCourses,\n getBenchmarkCourseIds,\n resetCourses,\n selectCourse,\n} from './tabs/courses';\nimport { fmtSecs, escHtml, fmtDate, getTagColor, compactId, shortRandom } from './utils';\n\nconst TRACK_COLORS: string[] = [\n '#FF6B35',\n '#4ECDC4',\n '#45B7D1',\n '#F7DC6F',\n '#FF6B6B',\n '#BB8FCE',\n '#82E0AA',\n '#F8C471',\n '#3b82f6',\n];\n\nconst POINT_ZOOM_LEVEL = 16;\n\nlet tracks: Record = {};\nlet skippedImports: { name: string; reason: string }[] = [];\n\nfunction isSameDay(t1: number, t2: number) {\n const d1 = new Date(t1);\n const d2 = new Date(t2);\n return (\n d1.getUTCFullYear() === d2.getUTCFullYear() &&\n d1.getUTCMonth() === d2.getUTCMonth() &&\n d1.getUTCDate() === d2.getUTCDate()\n );\n}\n\nlet cancelProcessing = false;\nlet selectedId: string | null = null;\nlet colorIdx = 0;\nlet followDot = false;\nlet currentMapColors: string[] | null = null;\n\n// Search/Filter state\nlet searchQuery = '';\nlet searchRegex = false;\nlet currentSort = 'date-desc';\n\ninterface Filters {\n date: [string | null, string | null];\n dist: [number | null, number | null];\n dur: [number | null, number | null];\n metrics: Set;\n tags: string[];\n sport: string | null;\n}\n\nlet filters: Filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n};\n\nfunction syncFiltersToUrl(push: boolean = false) {\n UrlState.patch(\n {\n f_date: filters.date.every((v) => v === null) ? null : filters.date,\n f_dist: filters.dist.every((v) => v === null) ? null : filters.dist,\n f_dur: filters.dur.every((v) => v === null) ? null : filters.dur,\n f_mets: filters.metrics.size === 0 ? null : Array.from(filters.metrics),\n f_tags: filters.tags.length === 0 ? null : filters.tags,\n },\n push,\n );\n}\n\nfunction syncMetricsToUrl() {\n const active = ChartView.getActiveMetrics();\n const metrics = ChartView.METRICS;\n const abbrs = Array.from(active).map((key) => metrics[key].abbr);\n UrlState.patch({ metrics: abbrs.length ? abbrs : null });\n}\n\nconst SORT_OPTIONS = [\n { label: 'Newest first', val: 'date-desc', icon: 'calendar_today' },\n { label: 'Oldest first', val: 'date-asc', icon: 'history' },\n { label: 'Longest distance', val: 'dist-desc', icon: 'straighten' },\n { label: 'Shortest distance', val: 'dist-asc', icon: 'horizontal_rule' },\n { label: 'Longest duration', val: 'dur-desc', icon: 'timer' },\n { label: 'Shortest duration', val: 'dur-asc', icon: 'timer_off' },\n];\n\nfunction showSortMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.sort-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'sort-menu-popup';\n\n SORT_OPTIONS.forEach((opt) => {\n const item = document.createElement('div');\n item.className = `menu-item ${currentSort === opt.val ? 'active' : ''}`;\n item.innerHTML = `\n ${opt.icon}\n ${opt.label}\n ${currentSort === opt.val ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n currentSort = opt.val;\n UrlState.patch({ sort: opt.val });\n updateSearchSortUI();\n renderTrackList();\n popup.remove();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction showMetricMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const available = ChartView.getAvailableMetrics();\n const active = ChartView.getActiveMetrics();\n\n Object.entries(metrics).forEach(([key, def]) => {\n if (!available.has(key)) return;\n\n const item = document.createElement('div');\n item.className = `menu-item ${active.has(key) ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${active.has(key) ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n ChartView.toggleMetric(key);\n const isNowActive = ChartView.getActiveMetrics().has(key);\n item.classList.toggle('active', isNowActive);\n item.querySelector('.check')!.textContent = isNowActive ? 'check' : '';\n\n const pill = document.querySelector(`#metric-pills .metric-pill[data-metric=\"${key}\"]`);\n if (pill) pill.classList.toggle('active', isNowActive);\n\n updateToolbarLayout();\n\n syncMetricsToUrl();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.right = `${window.innerWidth - rect.right}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\n// \u2500\u2500 Tab Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.addEventListener('select-track', (e: any) => {\n const id = e.detail.id;\n const idx = e.detail.idx;\n const dur = e.detail.dur;\n if (id && tracks[id]) {\n selectTrack(id);\n if (idx != null && dur != null) {\n const t = tracks[id];\n const pts = t.points;\n if (idx >= 0 && idx < pts.length) {\n const pIdx = pts[idx];\n if (pIdx && pIdx.time != null) {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const tMin = (pIdx.time - t0) / 1000;\n const tMax = tMin + dur;\n\n // ChartView selection\n ChartView.restoreSelection(tMin, tMax);\n\n // Find iMax based on duration\n let iMax = pts.findIndex((p) => (p.time || 0) >= pIdx.time! + dur * 1000);\n if (iMax === -1) iMax = pts.length - 1;\n\n const selPts = pts.slice(idx, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n\n renderInsights(t);\n\n MapView.highlightSegment(id, pts, idx, iMax, false, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n\n // Update URL state\n UrlState.patch({ sel: [tMin, tMax] });\n }\n }\n }\n }\n});\n\ndocument.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.tab-btn') as HTMLElement;\n if (!btn) return;\n const nav = btn.closest('#tab-nav');\n if (!nav) return;\n\n // Toggle buttons\n nav.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn));\n\n const tab = btn.dataset.tab!;\n UrlState.patch({ tab }, true);\n\n // Toggle contents\n const panel = nav.closest('#chart-panel');\n if (panel) {\n panel.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${btn.dataset.tab}`);\n });\n }\n\n if (btn.dataset.tab === 'details' && selectedId && tracks[selectedId])\n renderDetails(tracks[selectedId], getGlobalTags());\n\n if (btn.dataset.tab === 'insights' && selectedId && tracks[selectedId])\n renderInsights(tracks[selectedId]);\n\n if (btn.dataset.tab === 'evolution') {\n renderEvolution(\n selectedId ? tracks[selectedId] : null,\n Object.values(tracks),\n (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n },\n (start, end) => {\n filters.date = [start, end];\n applyFilters();\n syncFiltersToUrl(true);\n updateFilterUI();\n },\n );\n }\n\n if (btn.dataset.tab === 'combined' && selectedId && tracks[selectedId])\n renderCombined(tracks[selectedId]);\n\n if (btn.dataset.tab === 'courses') renderCourses();\n\n if (btn.dataset.tab === 'graphs') {\n ChartView.resize();\n updateToolbarLayout();\n\n // Restore selection from URL\n const s = UrlState.get().sel;\n if (s) ChartView.restoreSelection(s[0], s[1]);\n }\n});\n\nasync function resetBenchmarkState() {\n if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n await Storage.clear();\n tracks = {};\n skippedImports = [];\n selectedId = null;\n colorIdx = 0;\n currentMapColors = null;\n cancelProcessing = false;\n followDot = false;\n searchQuery = '';\n searchRegex = false;\n currentSort = 'date-desc';\n filters.date = [null, null];\n filters.dist = [null, null];\n filters.dur = [null, null];\n filters.metrics.clear();\n filters.tags = [];\n Parsers.setHRZones([120, 140, 160, 180]);\n Parsers.setFTP(200);\n resetCourses();\n resetInsights();\n resetDetails();\n resetCombined();\n resetEvolution();\n if (MapView.removeAllTracks) MapView.removeAllTracks();\n if (MapView.clearTracks) MapView.clearTracks();\n MapView.clearHighlight();\n if (ChartView.resetState) ChartView.resetState();\n else if (ChartView.clear) ChartView.clear();\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === 'graphs');\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === 'tab-graphs');\n });\n UrlState.reset();\n const toastContainer = document.getElementById('toast-container');\n if (toastContainer) toastContainer.innerHTML = '';\n document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());\n if (typeof renderTrackList === 'function') renderTrackList();\n}\n\n// \u2500\u2500 Boot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function init() {\n // Wait for fonts to be loaded with a cleaned-up timeout\n let fontTimerId: number | null = null;\n const fontTimeout = new Promise((resolve) => {\n fontTimerId = window.setTimeout(resolve, 1000);\n });\n try {\n const fontLoadPromise = document.fonts\n ? Promise.all([\n document.fonts.load('24px \"Material Symbols Rounded\"').catch(() => {}),\n document.fonts.ready,\n ])\n : Promise.resolve();\n await Promise.race([fontLoadPromise, fontTimeout]);\n } finally {\n if (fontTimerId !== null) window.clearTimeout(fontTimerId);\n }\n document.body.classList.remove('loading-fonts');\n const storageSelect = document.getElementById(\n 'storage-backend-select',\n ) as HTMLSelectElement | null;\n if (storageSelect) {\n storageSelect.value = UrlState.get().storage || 'memory';\n storageSelect.addEventListener('change', (e) => {\n const selected = (e.target as HTMLSelectElement).value;\n const params = new URLSearchParams(window.location.search);\n if (selected === 'memory') {\n params.delete('storage');\n } else {\n params.set('storage', selected);\n }\n window.location.search = params.toString();\n });\n }\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const mapLoader = document.getElementById('map-loader');\n const mapLoaderSpan = mapLoader?.querySelector('span');\n\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading database...';\n mapLoader.classList.remove('hidden');\n }\n\n const urlState = UrlState.get();\n\n initInsights((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n initDetails(\n () => {\n applyFilters();\n syncFiltersToUrl();\n },\n (id: string) => {\n deleteTrack(id);\n },\n );\n initCombined();\n initCourses((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n\n // Init sub-systems\n MapView.init(\n (id) => selectTrack(id),\n onMapMove,\n onMapPointClick,\n (id, idx) => {\n if (id === selectedId) ChartView.setHoverAt(idx);\n else ChartView.setHoverAt(null);\n },\n onMapDblClick,\n );\n ChartView.init(onChartCursorMove, onChartRangeChange, onChartClick, (idx) => {\n UrlState.patch({ sel_point: idx });\n });\n\n ChartView.setMapColorChangeCb((data) => {\n if (data) {\n currentMapColors = data.colors;\n if (selectedId) MapView.colorTrackByMetric(selectedId, data.pts, data.colors);\n } else {\n currentMapColors = null;\n if (selectedId) MapView.clearMetricColor(selectedId);\n }\n\n // Refresh highlight with new colors if a selection exists\n const currentUrlState = UrlState.get();\n if (currentUrlState.sel)\n onChartRangeChange(currentUrlState.sel[0], currentUrlState.sel[1], ChartView.getXAxis());\n });\n\n applyState(urlState);\n\n // Reset persistent storage and in-memory state for clean multi-iteration benchmark executions\n await Storage.openDB();\n await resetBenchmarkState();\n\n // Load persisted tracks\n try {\n // Load global settings\n const hrZones = await Storage.get('hr_zones');\n if (hrZones) Parsers.setHRZones(hrZones);\n\n const ftp = await Storage.get('ftp');\n if (ftp) Parsers.setFTP(ftp);\n\n const saved = await Storage.getAll();\n saved.sort((a, b) => a.addedAt - b.addedAt);\n\n if (mapLoaderSpan) mapLoaderSpan.textContent = `Preparing ${saved.length} tracks...`;\n\n const tracksToLoad: TrackData[] = [];\n for (const t of saved) {\n let updated = false;\n if (!t.bounds && t.points.length > 0) {\n const b = calculateBounds(t.points);\n if (b) {\n t.bounds = b;\n updated = true;\n }\n }\n if (!t.simplifiedPoints && t.points.length > 0) {\n t.simplifiedPoints = simplifyTrack(t.points, 50);\n updated = true;\n }\n if (updated) await Storage.save(t);\n\n tracks[t.id] = t;\n tracksToLoad.push(t);\n }\n MapView.addTracks(tracksToLoad);\n applyFilters();\n\n const restoreId =\n urlState.track && saved.find((t) => t.id === urlState.track)\n ? urlState.track\n : saved.length > 0\n ? saved[0].id\n : null;\n\n const mapLoader = document.getElementById('map-loader');\n\n // 1. Process and load the \"Priority\" track first\n const selectedTrackData = saved.find((t) => t.id === restoreId);\n if (selectedTrackData) {\n await processAndLoadTrack(selectedTrackData);\n selectTrack(selectedTrackData.id, !urlState.map_pos);\n\n // Explicitly restore selection/pin from URL if they exist\n if (urlState.sel && Array.isArray(urlState.sel) && urlState.sel.length === 2) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.restoreSelection(urlState.sel![0], urlState.sel![1]);\n });\n });\n }\n if (urlState.sel_point !== undefined && urlState.sel_point !== null) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.setCursorAt(urlState.sel_point!);\n });\n });\n }\n }\n\n // Hide database loader\n if (mapLoader) mapLoader.classList.add('hidden');\n\n // 2. Load the rest in background chunks\n if (saved.length > (selectedTrackData ? 1 : 0)) {\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading tracks...';\n mapLoader.classList.remove('hidden');\n }\n\n const remaining = saved.filter((t) => t.id !== restoreId);\n let index = 0;\n\n const loadNextChunk = async () => {\n const chunkSize = 2; // Process 2 tracks per frame\n const end = Math.min(index + chunkSize, remaining.length);\n\n for (; index < end; index++) await processAndLoadTrack(remaining[index]);\n\n if (index < remaining.length) {\n requestAnimationFrame(loadNextChunk);\n } else {\n if (mapLoader) mapLoader.classList.add('hidden');\n applyFilters(); // Final sync\n if (selectedId && tracks[selectedId]) {\n renderEvolution(tracks[selectedId], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n // Only fit all if no saved map position and we just finished loading everything\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n };\n\n requestAnimationFrame(loadNextChunk);\n } else {\n applyFilters();\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n } catch (e) {\n console.warn('Could not load saved tracks:', e);\n }\n\n // Panel resizers\n initResizeHandle();\n initSidebarResizer();\n initMetricPillDraggable();\n updateToolbarLayout();\n\n // Basemap switcher\n document.getElementById('basemap-switcher')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.bm-btn') as HTMLElement;\n if (!btn) return;\n document.querySelectorAll('.bm-btn').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n if (btn.dataset.layer) {\n MapView.switchBasemap(btn.dataset.layer);\n UrlState.patch({ map: btn.dataset.layer });\n }\n });\n\n // Fit all\n document.getElementById('btn-fit-all')?.addEventListener('click', () => MapView.fitAll());\n\n // Clear all\n document.getElementById('btn-clear-all')?.addEventListener('click', clearAll);\n\n // Search\n document.getElementById('track-search')?.addEventListener('input', (e) => {\n searchQuery = (e.target as HTMLInputElement).value;\n applyFilters();\n UrlState.patch({ q: searchQuery || null });\n });\n\n document.getElementById('btn-regex-toggle')?.addEventListener('click', (e) => {\n searchRegex = !searchRegex;\n (e.target as HTMLElement).classList.toggle('active', searchRegex);\n applyFilters();\n UrlState.patch({ re: searchRegex ? 1 : null });\n });\n\n // Sort\n document.getElementById('btn-sort-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSortMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric menu toggle\n document.getElementById('btn-metric-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMetricMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric toggles (shared logic)\n const toggleMetric = (metric: string, pill: HTMLElement | null) => {\n if (pill) pill.classList.toggle('active');\n ChartView.toggleMetric(metric);\n syncMetricsToUrl();\n };\n\n document.getElementById('metric-pills')?.addEventListener('click', (e) => {\n const pill = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (pill) {\n const metric = pill.dataset.metric;\n if (metric) {\n toggleMetric(metric, pill);\n\n // Scroll to it if it became active\n if (ChartView.getActiveMetrics().has(metric)) {\n const targetEl = document.querySelector(`.chart-row[data-metric=\"${metric}\"]`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n }\n }\n });\n\n // X-axis toggle\n document.getElementById('x-axis-ctrl')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const axis = btn.dataset.axis!;\n ChartView.setXAxis(axis);\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', b === btn));\n UrlState.patch({ xaxis: axis });\n });\n\n // Follow dot\n document.getElementById('btn-follow-dot')?.addEventListener('click', (e) => {\n followDot = !followDot;\n (e.currentTarget as HTMLElement).classList.toggle('active', followDot);\n });\n\n // Reset zoom\n document.getElementById('btn-reset-zoom')?.addEventListener('click', () => {\n ChartView.resetZoom();\n MapView.clearHighlight();\n });\n\n // File drag/drop\n initDropZone();\n\n // File browse\n document.getElementById('file-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n document.getElementById('folder-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n\n // Filters\n document.getElementById('btn-toggle-filters')?.addEventListener('click', () => {\n const panel = document.getElementById('filter-panel');\n if (panel) {\n panel.classList.toggle('hidden');\n document\n .getElementById('btn-toggle-filters')\n ?.classList.toggle('active', !panel.classList.contains('hidden'));\n }\n });\n\n const onFilterInput = (type: 'date' | 'dist' | 'dur', idx: number, e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n (filters[type] as any)[idx] = val === '' ? null : val;\n applyFilters();\n syncFiltersToUrl();\n };\n\n document\n .getElementById('filter-date-start')\n ?.addEventListener('change', (e) => onFilterInput('date', 0, e));\n document\n .getElementById('filter-date-end')\n ?.addEventListener('change', (e) => onFilterInput('date', 1, e));\n document\n .getElementById('filter-dist-min')\n ?.addEventListener('input', (e) => onFilterInput('dist', 0, e));\n document\n .getElementById('filter-dist-max')\n ?.addEventListener('input', (e) => onFilterInput('dist', 1, e));\n document\n .getElementById('filter-dur-min')\n ?.addEventListener('input', (e) => onFilterInput('dur', 0, e));\n document\n .getElementById('filter-dur-max')\n ?.addEventListener('input', (e) => onFilterInput('dur', 1, e));\n\n const burgerBtn = document.getElementById('sport-burger-btn');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n burgerBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n if (dropdownContent) {\n const isVisible = dropdownContent.style.display === 'block';\n dropdownContent.style.display = isVisible ? 'none' : 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (dropdownContent && dropdownContent.style.display === 'block') {\n if (!dropdownContent.contains(e.target as Node) && e.target !== burgerBtn)\n dropdownContent.style.display = 'none';\n }\n });\n\n document.getElementById('sport-filter-container')?.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const btn = target.closest('[data-sport]');\n if (btn) {\n const selectedSport = (btn as HTMLElement).dataset.sport || null;\n filters.sport = filters.sport === selectedSport ? null : selectedSport;\n applyFilters();\n syncFiltersToUrl();\n updateFilterUI();\n\n if (target.closest('.dropdown-item')) {\n if (dropdownContent) dropdownContent.style.display = 'none';\n }\n }\n });\n\n document.getElementById('filter-metrics')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.mini-pill') as HTMLElement;\n if (!btn) return;\n const m = btn.dataset.metric!;\n if (filters.metrics.has(m)) filters.metrics.delete(m);\n else filters.metrics.add(m);\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('btn-reset-filters')?.addEventListener('click', () => {\n filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n };\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('filter-tags')?.addEventListener('input', (e) => {\n const val = (e.target as HTMLInputElement).value;\n filters.tags = val\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => !!s);\n applyFilters();\n syncFiltersToUrl();\n });\n\n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n MapView.hideCursor();\n MapView.closePopup?.();\n // Dismiss popups and modals\n document\n .querySelectorAll(\n '.color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop',\n )\n .forEach((el) => el.remove());\n }\n });\n\n // Resize charts when window changes\n window.addEventListener('resize', () => {\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n updateToolbarLayout();\n });\n\n // Handle back/forward navigation\n window.addEventListener('popstate', () => {\n UrlState.refresh();\n applyState(UrlState.get());\n });\n\n initBenchmarkTriggers();\n await preloadBenchmarkFiles();\n\n // Signal to Speedometer test harness that asynchronous initialization has completed\n // and benchmark step triggers are bound.\n const readyEl = document.createElement('div');\n readyEl.id = 'app-is-ready';\n readyEl.setAttribute('data-ready', 'true');\n readyEl.style.display = 'none';\n document.body.appendChild(readyEl);\n\n const camelReadyEl = document.createElement('div');\n camelReadyEl.id = 'appIsReady';\n camelReadyEl.setAttribute('data-ready', 'true');\n camelReadyEl.style.display = 'none';\n document.body.appendChild(camelReadyEl);\n}\n\nlet preloadedBenchmarkPayloads:\n | {\n cleanName: string;\n buf: ArrayBuffer;\n text?: string;\n file: File;\n }[]\n | null = null;\n\nasync function preloadBenchmarkFiles(): Promise<\n { cleanName: string; buf: ArrayBuffer; text?: string; file: File }[]\n> {\n if (preloadedBenchmarkPayloads) return preloadedBenchmarkPayloads;\n try {\n const manifestResp = await fetch('./test-data/manifest.json');\n const fileNames: string[] = await manifestResp.json();\n const decoder = new TextDecoder();\n preloadedBenchmarkPayloads = await Promise.all(\n fileNames.map(async (name) => {\n const fileResp = await fetch(`./test-data/${name}`);\n let buf = await fileResp.arrayBuffer();\n let cleanName = name;\n if (name.toLowerCase().endsWith('.gz')) {\n cleanName = name.slice(0, -3);\n const bytes = new Uint8Array(buf);\n if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) {\n const ds = new DecompressionStream('gzip');\n const stream = new Blob([buf]).stream().pipeThrough(ds);\n buf = await new Response(stream).arrayBuffer();\n }\n }\n const text = cleanName.toLowerCase().endsWith('.fit') ? undefined : decoder.decode(buf);\n const file = new File([buf], cleanName, { type: 'application/octet-stream' });\n (file as any)._buf = buf;\n if (text !== undefined) (file as any)._text = text;\n return { cleanName, buf, text, file };\n }),\n );\n // Warm up GPX, TCX, and FIT parser and chart code paths during prepare phase\n let warmSample: any = null;\n for (const idx of [0, 2, 4]) {\n if (preloadedBenchmarkPayloads[idx]) {\n const parsed = await Parsers.parseFile(preloadedBenchmarkPayloads[idx].file);\n if (idx === 0) warmSample = parsed;\n }\n }\n if (warmSample) {\n const warmPts = warmSample.points.slice(0, 1250);\n const warmTrack: TrackData = {\n ...warmSample,\n id: 'warmup',\n fileName: 'warmup.gpx',\n fileSize: 1024,\n points: warmPts,\n bounds: calculateBounds(warmPts) || undefined,\n simplifiedPoints: simplifyTrack(warmPts, 50),\n stats: Parsers.computeStats(warmPts),\n addedAt: 1785542400000,\n visible: true,\n color: TRACK_COLORS[0],\n };\n const warmTrack2: TrackData = {\n ...warmTrack,\n id: 'warmup-2',\n fileName: 'warmup2.gpx',\n addedAt: 1785628800000,\n color: TRACK_COLORS[1],\n };\n const warmList = [warmTrack, warmTrack2];\n Parsers.ensureCurvesAndZones(warmTrack);\n Parsers.ensureCurvesAndZones(warmTrack2);\n warmTrack.stats.sections = Parsers.analyzeTrackSections(warmTrack.points);\n warmTrack2.stats.sections = Parsers.analyzeTrackSections(warmTrack2.points);\n Parsers.findOverlaps(warmList);\n MapView.addTracks(warmList);\n ChartView.loadTrack(warmTrack, warmList, false);\n ChartView.restoreSelection(10, 50, true);\n ChartView.setCursorAt(25, true);\n ChartView.setSmooth('power', true);\n ChartView.setSmooth('power', false);\n ChartView.setXAxis('distance');\n ChartView.setXAxis('time');\n ChartView.setActiveMetrics(['elevation', 'speed', 'power']);\n ChartView.analyzeTelemetryIntervals(warmList, 10, 50);\n renderInsights(warmTrack, warmList, [10, 50]);\n renderInsights(warmTrack, warmList);\n renderDetails(warmTrack, [], warmList);\n renderCombined(warmTrack, warmList);\n setCombinedPolar(true);\n setCombinedPolar(false);\n setCombinedSliderProgress(0.5);\n renderCombined(warmList, warmList);\n renderEvolution(warmTrack, warmList);\n setEvolutionGrouping('month');\n setEvolutionGrouping('week');\n setEvolutionRange('6m');\n setEvolutionRange('all');\n setEvolutionPinnedDuration(60);\n setEvolutionPinnedDuration(null);\n prepareBenchmarkCourses(warmList);\n selectCourse('course-1', true);\n await resetBenchmarkState();\n void document.body.offsetHeight;\n await new Promise((r) => window.setTimeout(r, 0));\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n return preloadedBenchmarkPayloads;\n } catch {\n return [];\n }\n}\n\nfunction initBenchmarkTriggers() {\n const btnLoad = document.getElementById('btn-step-load');\n const btnAnalysis = document.getElementById('btn-step-analysis');\n const btnInsights = document.getElementById('btn-step-insights');\n const btnDetails = document.getElementById('btn-step-details');\n const btnAggregate = document.getElementById('btn-step-aggregate');\n const btnEvolution = document.getElementById('btn-step-evolution');\n const btnCourses = document.getElementById('btn-step-courses');\n\n function activateTab(tabName: string) {\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === tabName);\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${tabName}`);\n });\n UrlState.patch({ tab: tabName }, false);\n }\n\n btnLoad?.addEventListener('click', async () => {\n try {\n if (Object.keys(tracks).length > 0 || skippedImports.length > 0 || selectedId !== null) {\n await Storage.openDB();\n await resetBenchmarkState();\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n const payloads = await preloadBenchmarkFiles();\n const loadedFiles: File[] = payloads.map((p) => p.file);\n await handleFiles(loadedFiles);\n const allTracks = Object.values(tracks);\n Parsers.findOverlaps(allTracks);\n\n // Exercise sidebar track list sorting and filtering across distinct criteria\n for (const sortMode of ['dist-desc', 'dur-desc', 'date-asc', 'date-desc']) {\n currentSort = sortMode;\n renderTrackList();\n }\n filters.sport = 'cycling';\n applyFilters();\n filters.sport = null;\n filters.metrics.add('power');\n applyFilters();\n filters.metrics.clear();\n searchQuery = 'Alpine';\n applyFilters();\n searchQuery = '';\n applyFilters();\n\n if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id);\n } finally {\n window.dispatchEvent(new CustomEvent('load-and-parse-complete'));\n }\n });\n\n btnAnalysis?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('graphs');\n if (!selectedId && allTracks.length > 0) {\n selectTrack(allTracks[0].id, false);\n }\n const availableMetrics = ChartView.getAvailableMetrics();\n const metricSets = [\n ['elevation', 'speed', 'power', 'hr'],\n ['elevation', 'speed', 'power'],\n ];\n for (const mSet of metricSets) {\n const filtered = mSet.filter((m) => availableMetrics.has(m));\n if (filtered.length > 0) {\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const metric = (el as HTMLElement).dataset.metric;\n if (metric) el.classList.toggle('active', filtered.includes(metric));\n });\n updateToolbarLayout();\n ChartView.setActiveMetrics(filtered);\n }\n }\n\n // Exercise smoothing, map metric coloring, and X-axis mode switching\n ChartView.setSmooth('power', true, true);\n ChartView.toggleMapColor('power', true);\n ChartView.toggleMapColor(null, true);\n ChartView.setXAxis('distance');\n ChartView.setSmooth('power', false, true);\n ChartView.setXAxis('time');\n\n // Analyze distinct sections of the track (Opening Climb & Main Analysis Window)\n const sections: [number, number, number][] = [\n [0, 360, 180],\n [120, 900, 300],\n ];\n for (const [secStart, secEnd, cursorIdx] of sections) {\n ChartView.restoreSelection(secStart, secEnd, true);\n ChartView.setCursorAt(cursorIdx, true);\n ChartView.analyzeTelemetryIntervals(allTracks, secStart, secEnd);\n onChartRangeChange(secStart, secEnd, ChartView.getXAxis(), false);\n }\n } finally {\n window.dispatchEvent(new CustomEvent('analysis-complete'));\n }\n });\n\n btnInsights?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t));\n activateTab('insights');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n // Analyze insights across GPX, TCX, and FIT tracks and across distinct track sections (Opening, Middle, Final thirds, Full)\n for (const tIdx of [1, 2, 4]) {\n const trk = allTracks[tIdx];\n if (trk) {\n renderInsights(trk, allTracks, [0, 540]);\n renderInsights(trk, allTracks, [540, 1140]);\n renderInsights(trk, allTracks, null);\n }\n }\n if (allTracks[3]) {\n renderInsights(allTracks[3], allTracks, [200, 900]);\n }\n if (primaryTrack) {\n renderInsights(primaryTrack, allTracks, [0, 480]);\n renderInsights(primaryTrack, allTracks, [480, 960]);\n renderInsights(primaryTrack, allTracks, [960, 1440]);\n }\n renderInsights(primaryTrack, allTracks, null);\n } finally {\n window.dispatchEvent(new CustomEvent('insights-complete'));\n }\n });\n\n btnDetails?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('details');\n const globalTags = getGlobalTags();\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n // Render and analyze telemetry details, splits, gear matrices, and zones across all 6 tracks and terrain sections\n for (let i = 0; i < allTracks.length; i++) {\n renderDetails(allTracks[i], globalTags, allTracks, null);\n }\n if (primaryTrack) {\n renderDetails(primaryTrack, globalTags, allTracks, [0, 450]);\n renderDetails(primaryTrack, globalTags, allTracks, [450, 950]);\n renderDetails(primaryTrack, globalTags, allTracks, [950, 1450]);\n }\n if (allTracks[1]) {\n renderDetails(allTracks[1], globalTags, allTracks, [150, 750]);\n }\n if (allTracks[2]) {\n renderDetails(allTracks[2], globalTags, allTracks, [200, 800]);\n }\n if (allTracks[3]) {\n renderDetails(allTracks[3], globalTags, allTracks, [200, 900]);\n }\n if (allTracks[4]) {\n renderDetails(allTracks[4], globalTags, allTracks, [0, 600]);\n renderDetails(allTracks[4], globalTags, allTracks, [600, 1200]);\n }\n if (allTracks[5]) {\n renderDetails(allTracks[5], globalTags, allTracks, [150, 750]);\n }\n renderDetails(primaryTrack, globalTags, allTracks, null);\n } finally {\n window.dispatchEvent(new CustomEvent('details-complete'));\n }\n });\n\n btnAggregate?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n if (allTracks.length >= 2) {\n activateTab('combined');\n // 1. Exercise single-track 2D scatter/trail mode across metric pairs, Polar & Cartesian, and timeline sections\n setCombinedMetrics('distance', 'elevation');\n renderCombined(allTracks[0], allTracks);\n for (const frac of [0.25, 0.5, 0.75, 1.0]) {\n setCombinedSliderProgress(frac);\n }\n setCombinedPolar(true);\n setCombinedSliderProgress(0.5);\n setCombinedPolar(false);\n setCombinedMetrics('power', 'hr');\n for (const frac of [0.3, 0.7]) {\n setCombinedSliderProgress(frac);\n }\n\n // 2. Exercise multi-track comparison mode across regional pairs and all 6 tracks\n if (allTracks.length >= 4) {\n renderCombined([allTracks[2], allTracks[3]], allTracks);\n }\n if (allTracks.length >= 6) {\n renderCombined(allTracks, allTracks);\n }\n const selectedTwo = [allTracks[0], allTracks[1]];\n renderCombined(selectedTwo, allTracks);\n }\n } finally {\n window.dispatchEvent(new CustomEvent('aggregate-complete'));\n }\n });\n\n btnEvolution?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('evolution');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n const onSelectCb = (trackId: string, range: [number, number] | null) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n };\n\n // Exercise evolution view across different reference tracks, groupings ('month' & 'week'), time ranges, and pinned durations\n const refTracks = [allTracks[2] || primaryTrack, allTracks[4] || primaryTrack, primaryTrack];\n for (const refTrk of refTracks) {\n renderEvolution(refTrk, allTracks, onSelectCb);\n setEvolutionGrouping('month');\n for (const rng of ['1m', '2m', '6m', '1y', 'all']) {\n setEvolutionRange(rng);\n }\n setEvolutionGrouping('week');\n for (const dur of [5, 30, 60, 300, 1200, null]) {\n setEvolutionPinnedDuration(dur);\n }\n }\n } finally {\n window.dispatchEvent(new CustomEvent('evolution-complete'));\n }\n });\n\n btnCourses?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('courses');\n prepareBenchmarkCourses(allTracks);\n const courseIds = getBenchmarkCourseIds();\n for (const cId of courseIds) {\n selectCourse(cId, true);\n }\n selectCourse('course-1', true);\n } finally {\n window.dispatchEvent(new CustomEvent('courses-complete'));\n }\n });\n\n (window as any).benchmarkSteps = {\n loadAndParseFiles: () => document.getElementById('btn-step-load')?.click(),\n displayAnalysisMetrics: () => document.getElementById('btn-step-analysis')?.click(),\n displayInsights: () => document.getElementById('btn-step-insights')?.click(),\n displayDetails: () => document.getElementById('btn-step-details')?.click(),\n displayAggregateMetrics: () => document.getElementById('btn-step-aggregate')?.click(),\n displayEvolutionMetrics: () => document.getElementById('btn-step-evolution')?.click(),\n displayCourses: () => document.getElementById('btn-step-courses')?.click(),\n };\n}\n\nasync function processAndLoadTrack(t: TrackData) {\n // Migration: re-calculate stats if new insights are missing or old format\n const powerCurveEntries = t.stats.powerCurve ? Object.values(t.stats.powerCurve) : [];\n\n const needsEnrich =\n t.points.length > 1 && (t.points[1].speed === undefined || t.points[1].gradient === undefined);\n\n const needsRecalc =\n needsEnrich ||\n !t.stats.powerCurve ||\n !t.stats.hrZones ||\n !t.stats.hrCurve ||\n t.stats.shifts === undefined ||\n t.stats.avgBattery === undefined ||\n t.stats.avgTemp === undefined ||\n (powerCurveEntries.length > 0 && typeof (powerCurveEntries[0] as any) === 'number') ||\n ((t.stats.duration || 0) > 10800 * 1000 && t.stats.powerCurve && !t.stats.powerCurve[14400]);\n\n if (needsRecalc) {\n if (needsEnrich) t.points = Parsers.enrichPoints(t.points);\n t.stats = Parsers.computeStats(t.points);\n await Storage.save(t);\n }\n\n tracks[t.id] = t;\n colorIdx = Math.max(colorIdx, TRACK_COLORS.indexOf(t.color) + 1);\n MapView.addTrack(t);\n MapView.setTrackVisible(t.id, t.visible && !t._filtered);\n renderTrackList(); // Progressive list update\n}\n\nfunction initResizeHandle() {\n const handle = document.getElementById('resize-handle');\n const panel = document.getElementById('chart-panel');\n if (!handle || !panel) return;\n\n let isDragging = false;\n\n handle.addEventListener('mousedown', () => {\n isDragging = true;\n document.body.style.cursor = 'ns-resize';\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const h = window.innerHeight - e.clientY;\n const clampedH = Math.max(100, Math.min(window.innerHeight - 100, h));\n panel.style.height = `${clampedH}px`;\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n document.body.style.cursor = '';\n });\n}\n\nfunction initSidebarResizer() {\n const resizer = document.getElementById('sidebar-resizer');\n const sidebar = document.getElementById('sidebar');\n if (!resizer || !sidebar) return;\n\n let isDragging = false;\n\n resizer.addEventListener('mousedown', () => {\n isDragging = true;\n resizer.classList.add('dragging');\n document.body.classList.add('dragging-sidebar');\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const w = e.clientX;\n const clampedW = Math.max(200, Math.min(600, w));\n sidebar.style.width = `${clampedW}px`;\n sidebar.style.setProperty('--sidebar-w', `${clampedW}px`);\n ChartView.resize();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n resizer.classList.remove('dragging');\n document.body.classList.remove('dragging-sidebar');\n });\n}\n\n// \u2500\u2500 Event Handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction onMapMove(lat: number, lng: number, zoom: number) {\n UrlState.patch({ map_pos: [lat, lng, zoom] });\n}\n\nfunction onMapPointClick(id: string, idx: number) {\n selectTrack(id, false);\n ChartView.setCursorAt(idx);\n}\n\nfunction onMapDblClick() {\n // MapView.fitAll();\n}\n\nfunction onChartCursorMove(pt: TrackPoint | null) {\n if (pt && pt.lat != null && pt.lon != null) {\n MapView.showCursorAt(pt.lat, pt.lon);\n if (followDot) MapView.centerOn(pt.lat, pt.lon, null, true);\n } else {\n MapView.hideCursor();\n }\n}\n\nfunction onChartRangeChange(min: number | null, max: number | null, axis: string, fit = false) {\n if (!selectedId || !tracks[selectedId]) return;\n const t = tracks[selectedId];\n\n if (min === null || max === null) {\n MapView.clearHighlight();\n if (t && (UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n UrlState.patch({ sel: null });\n return;\n }\n\n // Find point indices\n const pts = t.points;\n let iMin = 0,\n iMax = pts.length - 1;\n\n if (axis === 'distance') {\n const d0 = min * 1000,\n d1 = max * 1000;\n iMin = pts.findIndex((p) => (p.dist || 0) >= d0);\n iMax = pts.findIndex((p) => (p.dist || 0) >= d1);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const ts0 = t0 + min * 1000,\n ts1 = t0 + max * 1000;\n iMin = pts.findIndex((p) => (p.time || 0) >= ts0);\n iMax = pts.findIndex((p) => (p.time || 0) >= ts1);\n }\n\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = pts.length - 1;\n\n // Compute selection stats\n const selPts = pts.slice(iMin, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n if ((UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n\n MapView.highlightSegment(selectedId, pts, iMin, iMax, fit, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n UrlState.patch({ sel: [min, max] });\n}\n\nfunction onChartClick(pt: TrackPoint, idx: number) {\n if (pt && pt.lat != null && pt.lon != null) MapView.centerOn(pt.lat, pt.lon, POINT_ZOOM_LEVEL);\n}\n\nexport function selectTrack(id: string, fit = true, deferChartRender = false) {\n if (!tracks[id]) return;\n if (id === selectedId) {\n if (fit) MapView.fitTrack(id);\n return;\n }\n\n const hadSelected = selectedId !== null;\n if (hadSelected) {\n // Clear current views immediately before loading new data\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n }\n\n selectedId = id;\n\n // Fully reset metric coloring when switching tracks\n currentMapColors = null;\n MapView.clearMetricColor(id);\n if (hadSelected) {\n ChartView.toggleMapColor(null); // Ensure ChartView state also resets\n }\n\n // Clear selection on new track\n UrlState.patch({ track: id, sel: null }, true);\n if (hadSelected) {\n ChartView.cancelSelection();\n }\n\n // Update UI immediately\n renderTrackList();\n\n // Render details\n const activeTab = UrlState.get().tab || 'graphs';\n if (activeTab === 'details') renderDetails(tracks[id], getGlobalTags());\n if (activeTab === 'insights') renderInsights(tracks[id]);\n if (activeTab === 'combined') renderCombined(tracks[id]);\n if (activeTab === 'courses') renderCourses();\n if (activeTab === 'evolution') {\n renderEvolution(tracks[id], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n\n // Tell sub-views\n MapView.setSelectedTrack(id, fit);\n if (fit) MapView.fitTrack(id);\n ChartView.loadTrack(tracks[id], Object.values(tracks), deferChartRender);\n}\n\nasync function deleteTrack(id: string) {\n await Storage.remove(id);\n MapView.removeTrack(id);\n delete tracks[id];\n if (selectedId === id) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n UrlState.patch({ track: null, sel: null, sel_point: null });\n }\n applyFilters();\n}\n\nasync function clearAll() {\n const code = Math.floor(10 + Math.random() * 90).toString();\n\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n backdrop.innerHTML = `\n
\n
Delete all tracks?
\n
\n This will permanently remove all tracks from your browser storage. This action cannot be undone.\n
\n
\n
Enter \"${code}\" to confirm:
\n \n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const input = backdrop.querySelector('.modal-input') as HTMLInputElement;\n const btnConfirm = backdrop.querySelector('.modal-btn.confirm') as HTMLButtonElement;\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n\n input.focus();\n\n input.addEventListener('input', () => {\n btnConfirm.disabled = input.value !== code;\n });\n\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n\n btnConfirm.addEventListener('click', async () => {\n if (input.value !== code) return;\n close();\n\n cancelProcessing = true;\n await Storage.clear();\n\n tracks = {};\n selectedId = null;\n MapView.clearHighlight();\n window.location.reload();\n });\n}\n\nfunction applyFilters(skipRender = false) {\n const ids = Object.keys(tracks);\n ids.forEach((id) => {\n const t = tracks[id];\n const s = t.stats;\n let visible = true;\n\n // Search query\n if (searchQuery) {\n if (searchRegex) {\n try {\n const re = new RegExp(searchQuery, 'i');\n if (!re.test(t.name)) visible = false;\n } catch (e) {\n visible = false;\n }\n } else {\n if (!t.name.toLowerCase().includes(searchQuery.toLowerCase())) visible = false;\n }\n }\n\n // Date filter\n if (visible && (filters.date[0] || filters.date[1])) {\n const start = filters.date[0] ? new Date(filters.date[0]).getTime() : 0;\n const end = filters.date[1] ? new Date(filters.date[1]).getTime() : Infinity;\n const t0 = s.startTime || 0;\n if (t0 < start || t0 > end) visible = false;\n }\n\n // Distance filter\n if (visible && (filters.dist[0] !== null || filters.dist[1] !== null)) {\n const min = (filters.dist[0] || 0) * 1000;\n const max = (filters.dist[1] || Infinity) * 1000;\n if (s.totalDist < min || s.totalDist > max) visible = false;\n }\n\n // Duration filter\n if (visible && (filters.dur[0] !== null || filters.dur[1] !== null)) {\n const min = (filters.dur[0] || 0) * 60000;\n const max = (filters.dur[1] || Infinity) * 60000;\n const d = s.duration || 0;\n if (d < min || d > max) visible = false;\n }\n\n // Metrics filter\n if (visible && filters.metrics.size > 0) {\n for (const m of filters.metrics) {\n const field = ChartView.METRICS[m].field;\n if (!t.points.some((p: any) => p[field] != null)) {\n visible = false;\n break;\n }\n }\n }\n\n // Sport filter\n if (visible && filters.sport) {\n if (t.sport !== filters.sport) visible = false;\n }\n\n // Tags filter\n if (visible && filters.tags.length > 0) {\n const trackTags = t.tags || [];\n if (!filters.tags.every((ft) => trackTags.includes(ft))) visible = false;\n }\n\n t._filtered = !visible;\n MapView.setTrackVisible(t.id, t.visible && visible);\n });\n\n if (!skipRender) renderTrackList();\n}\n\nfunction updateFilterUI() {\n (document.getElementById('filter-date-start') as HTMLInputElement).value = filters.date[0] || '';\n (document.getElementById('filter-date-end') as HTMLInputElement).value = filters.date[1] || '';\n (document.getElementById('filter-dist-min') as HTMLInputElement).value =\n filters.dist[0] !== null ? String(filters.dist[0]) : '';\n (document.getElementById('filter-dist-max') as HTMLInputElement).value =\n filters.dist[1] !== null ? String(filters.dist[1]) : '';\n (document.getElementById('filter-dur-min') as HTMLInputElement).value =\n filters.dur[0] !== null ? String(filters.dur[0]) : '';\n (document.getElementById('filter-dur-max') as HTMLInputElement).value =\n filters.dur[1] !== null ? String(filters.dur[1]) : '';\n (document.getElementById('filter-tags') as HTMLInputElement).value = filters.tags.join(', ');\n\n document\n .querySelectorAll('#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item')\n .forEach((el) => {\n const item = el as HTMLElement;\n item.classList.toggle('active', (item.dataset.sport || '') === (filters.sport || ''));\n });\n\n document.querySelectorAll('#filter-metrics .mini-pill').forEach((el) => {\n const btn = el as HTMLElement;\n btn.classList.toggle('active', filters.metrics.has(btn.dataset.metric!));\n });\n\n const activeCount =\n (filters.date[0] ? 1 : 0) +\n (filters.date[1] ? 1 : 0) +\n (filters.dist[0] !== null ? 1 : 0) +\n (filters.dist[1] !== null ? 1 : 0) +\n (filters.dur[0] !== null ? 1 : 0) +\n (filters.dur[1] !== null ? 1 : 0) +\n filters.metrics.size +\n (filters.tags.length > 0 ? 1 : 0);\n\n const badge = document.querySelector('#btn-toggle-filters .btn-badge');\n if (badge) {\n badge.textContent = activeCount > 0 ? String(activeCount) : '';\n badge.classList.toggle('hidden', activeCount === 0);\n }\n}\n\nfunction updateSearchSortUI() {\n const searchInput = document.getElementById('track-search') as HTMLInputElement;\n if (searchInput) searchInput.value = searchQuery;\n document.getElementById('btn-regex-toggle')?.classList.toggle('active', searchRegex);\n\n const opt = SORT_OPTIONS.find((o) => o.val === currentSort);\n if (opt) {\n const labelEl = document.getElementById('sort-current-label');\n const iconEl = document.getElementById('sort-current-icon');\n if (labelEl)\n labelEl.textContent = opt.label\n .replace(' first', '')\n .replace(' distance', '')\n .replace(' duration', '');\n if (iconEl) iconEl.textContent = opt.icon;\n }\n}\n\nfunction applyState(urlState: AppState) {\n // Restore track\n const newTrackId = urlState.track;\n if (newTrackId !== selectedId) {\n if (newTrackId && tracks[newTrackId]) {\n selectTrack(newTrackId, true);\n } else if (!newTrackId && selectedId) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n renderTrackList();\n MapView.fitAll();\n }\n }\n\n // Restore basemap\n if (urlState.map && typeof urlState.map === 'string') {\n MapView.switchBasemap(urlState.map);\n document\n .querySelectorAll('.bm-btn')\n .forEach((b) =>\n b.classList.toggle('active', (b as HTMLElement).dataset.layer === urlState.map),\n );\n }\n\n // Restore map position\n if (urlState.map_pos) {\n const [lat, lng, zoom] = urlState.map_pos;\n MapView.setPosition(lat, lng, zoom);\n }\n\n // Restore tab\n if (urlState.tab) {\n document.querySelectorAll('.tab-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n if (b.dataset.tab === urlState.tab) {\n if (!b.classList.contains('active')) b.click();\n }\n });\n }\n\n // Restore x-axis mode\n if (urlState.xaxis) ChartView.setXAxis(urlState.xaxis);\n\n const currentXAxis = urlState.xaxis || 'time';\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', (b as HTMLElement).dataset.axis === currentXAxis));\n\n // Restore active metrics\n if (urlState.metrics) {\n const metrics = ChartView.METRICS;\n const keys = urlState.metrics\n .map((abbr) => Object.keys(metrics).find((k) => metrics[k].abbr === abbr))\n .filter((k): k is string => k !== undefined);\n if (keys.length) ChartView.setActiveMetrics(keys);\n }\n\n // Restore filters\n if (urlState.f_date)\n filters.date = urlState.f_date.map((v) => v || null) as [string | null, string | null];\n if (urlState.f_dist)\n filters.dist = urlState.f_dist.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_dur)\n filters.dur = urlState.f_dur.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_mets) filters.metrics = new Set(urlState.f_mets);\n if (urlState.f_tags) filters.tags = urlState.f_tags;\n\n updateFilterUI();\n\n if (urlState.q) searchQuery = urlState.q;\n if (urlState.re) searchRegex = urlState.re;\n if (urlState.sort) currentSort = urlState.sort;\n updateSearchSortUI();\n\n applyFilters();\n}\n\nfunction updateSportFilterOptions() {\n const container = document.getElementById('sport-filter-container');\n if (!container) return;\n\n const commonContainer = document.getElementById('common-sports');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n if (!commonContainer || !dropdownContent) return;\n\n const sports = new Set();\n Object.values(tracks).forEach((t) => {\n if (t.sport) sports.add(t.sport);\n });\n\n const sportsArray = Array.from(sports).sort();\n const burgerDropdown = document.getElementById('sport-burger-dropdown');\n\n commonContainer.innerHTML = '';\n dropdownContent.innerHTML = '';\n\n if (sportsArray.length <= 4) {\n if (burgerDropdown) burgerDropdown.style.display = 'none';\n\n sportsArray.forEach((sport) => {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n });\n } else {\n if (burgerDropdown) burgerDropdown.style.display = 'inline-block';\n\n const commonSports = ['running', 'cycling', 'walking'];\n\n commonSports.forEach((sport) => {\n if (sports.has(sport)) {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n }\n });\n\n sportsArray.forEach((sport) => {\n const item = document.createElement('div');\n item.className = `dropdown-item${filters.sport === sport ? ' active' : ''}`;\n item.dataset.sport = sport;\n item.style.padding = '8px';\n item.style.cursor = 'pointer';\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '8px';\n item.innerHTML = `\n ${getSportIcon(sport)}\n ${sport.charAt(0).toUpperCase() + sport.slice(1)}\n `;\n dropdownContent.appendChild(item);\n });\n }\n}\n\nfunction renderTrackList() {\n updateSportFilterOptions();\n const list = document.getElementById('track-list');\n const emptyEl = document.getElementById('track-list-empty') as HTMLElement;\n const headerLabel = document.querySelector('.section-label');\n if (!list) return;\n\n const ids = Object.keys(tracks).filter((id) => !tracks[id]._filtered);\n if (headerLabel) headerLabel.textContent = `Tracks (${ids.length})`;\n\n if (!ids.length) {\n list.innerHTML = '';\n if (emptyEl) {\n list.appendChild(emptyEl);\n emptyEl.style.display = 'block';\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n list.innerHTML = '';\n\n ids\n .sort((a, b) => {\n // Current selected always first\n if (a === selectedId) return -1;\n if (b === selectedId) return 1;\n\n const ta = tracks[a],\n tb = tracks[b];\n const sa = ta.stats,\n sb = tb.stats;\n\n let cmp = 0;\n switch (currentSort) {\n case 'date-asc':\n cmp = (sa.startTime || 0) - (sb.startTime || 0);\n break;\n case 'date-desc':\n cmp = (sb.startTime || 0) - (sa.startTime || 0);\n break;\n case 'dist-asc':\n cmp = (sa.totalDist || 0) - (sb.totalDist || 0);\n break;\n case 'dist-desc':\n cmp = (sb.totalDist || 0) - (sa.totalDist || 0);\n break;\n case 'dur-asc':\n cmp = (sa.duration || 0) - (sb.duration || 0);\n break;\n case 'dur-desc':\n cmp = (sb.duration || 0) - (sa.duration || 0);\n break;\n default:\n cmp = 0;\n }\n return cmp || a.localeCompare(b);\n })\n .forEach((id) => {\n list.appendChild(buildTrackItem(tracks[id]));\n });\n}\n\nfunction getGlobalTags(): string[] {\n const all = new Set();\n Object.values(tracks).forEach((t) => {\n (t.tags || []).forEach((tag) => all.add(tag));\n });\n return Array.from(all).sort();\n}\n\nfunction getSportIcon(sport: string | null): string {\n if (!sport) return 'category';\n const s = sport.toLowerCase();\n if (s.includes('run')) return 'directions_run';\n if (s.includes('cycl') || s.includes('bike')) return 'directions_bike';\n if (s.includes('walk')) return 'directions_walk';\n if (s.includes('swim')) return 'pool';\n if (s.includes('hik')) return 'hiking';\n return 'sports';\n}\n\nfunction buildTrackItem(track: TrackData) {\n const item = document.createElement('div');\n item.className = `track-item${track.id === selectedId ? ' selected' : ''}`;\n item.dataset.id = track.id;\n\n const date =\n track.points.length && track.points[0].time ? fmtDate(track.points[0].time) : 'Unknown date';\n\n const tagsHtml =\n (track.tags || []).length > 0\n ? `
${(track.tags || [])\n .map((t) => {\n const c = getTagColor(t);\n return `${escHtml(t)}`;\n })\n .join('')}
`\n : '';\n\n item.innerHTML = `\n
\n
\n
${escHtml(track.displayName || track.name)}
\n
\n
\n ${date}\n ${Math.round(track.stats.totalDist / 1000)} km\n ${track.sport ? `${getSportIcon(track.sport)}` : ''}\n ${track.format.toUpperCase()}\n
\n \n
\n ${tagsHtml}\n
\n `;\n\n item.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.icon-btn')) return;\n selectTrack(track.id);\n });\n\n const btnVis = item.querySelector('.toggle-vis') as HTMLElement;\n btnVis.addEventListener('click', () => {\n track.visible = !track.visible;\n btnVis.querySelector('.material-symbols-rounded')!.textContent = track.visible\n ? 'visibility'\n : 'visibility_off';\n MapView.setTrackVisible(track.id, track.visible);\n Storage.save(track);\n });\n\n return item;\n}\n\nfunction showToast(msg: string, type: 'info' | 'error' = 'info') {\n const container = document.getElementById('toast-container');\n if (!container) return;\n container.innerHTML = '';\n const t = document.createElement('div');\n t.className = `toast ${type}`;\n t.textContent = msg;\n container.appendChild(t);\n}\n\nfunction showSkippedImportsModal() {\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n let listHtml = '';\n skippedImports.forEach((s) => {\n listHtml += `
${s.name}: ${s.reason}
`;\n });\n\n backdrop.innerHTML = `\n
\n
Skipped Imports
\n
\n ${listHtml || '
No skipped imports.
'}\n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n const btnClear = backdrop.querySelector('.modal-btn.clear') as HTMLButtonElement;\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n btnClear.addEventListener('click', () => {\n skippedImports = [];\n close();\n const importWarning = document.getElementById('import-warning');\n if (importWarning) importWarning.classList.add('hidden');\n });\n\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n}\n\nfunction initDropZone() {\n const zone = document.getElementById('drop-zone');\n if (!zone) return;\n\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n importWarning.addEventListener('click', (e) => {\n e.stopPropagation();\n showSkippedImportsModal();\n });\n }\n\n window.addEventListener('dragover', (e) => {\n e.preventDefault();\n zone.classList.add('drop-active');\n });\n\n window.addEventListener('dragleave', (e) => {\n if (e.relatedTarget === null) zone.classList.remove('drop-active');\n });\n\n window.addEventListener('drop', async (e) => {\n e.preventDefault();\n zone.classList.remove('drop-active');\n\n const items = e.dataTransfer?.items;\n if (!items) return;\n\n const files: File[] = [];\n const queue: FileSystemEntry[] = [];\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i].webkitGetAsEntry();\n if (entry) queue.push(entry);\n }\n\n async function readAllEntries(entry: FileSystemEntry) {\n if (entry.isFile) {\n const file = await new Promise((res) => (entry as FileSystemFileEntry).file(res));\n files.push(file);\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n let entries: FileSystemEntry[] = [];\n let chunk: FileSystemEntry[];\n do {\n chunk = await new Promise((res) => reader.readEntries(res));\n entries.push(...chunk);\n } while (chunk.length > 0);\n\n for (const child of entries) await readAllEntries(child);\n }\n }\n\n for (const entry of queue) await readAllEntries(entry);\n\n if (files.length) handleFiles(files);\n });\n}\n\nasync function handleFiles(files: File[]) {\n if (!files.length) return;\n cancelProcessing = false;\n const initialSkipCount = skippedImports.length;\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const loaderClose = document.getElementById('loader-close');\n\n if (loaderClose) {\n loaderClose.addEventListener('click', () => {\n cancelProcessing = true;\n if (loader) loader.classList.add('hidden');\n });\n }\n\n function updateLoaderIconToWarning() {\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'warning';\n loaderIcon.style.color = '#f59e0b';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n const count = skippedImports.length - initialSkipCount;\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = `${count}`;\n warningCount.style.display = 'flex';\n }\n }\n\n if (loader) {\n if (loaderText)\n loaderText.textContent = `Importing ${files.length} file${files.length > 1 ? 's' : ''}`;\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'download';\n loaderIcon.style.color = 'var(--accent)';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n warningCount.style.display = 'none';\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = '0';\n }\n if (loaderSubtext) loaderSubtext.textContent = '';\n if (progressBar) progressBar.style.width = '0%';\n loader.classList.remove('hidden');\n\n if (skippedImports.length > initialSkipCount) updateLoaderIconToWarning();\n }\n\n try {\n let count = 0;\n let firstId: string | null = null;\n let processedSinceLastUpdate = 0;\n\n // Filter out obviously invalid files early\n const validFiles = files.filter((f) => {\n const name = f.name.toLowerCase();\n return (\n name.endsWith('.gpx') ||\n name.endsWith('.fit') ||\n name.endsWith('.tcx') ||\n name.endsWith('.kml')\n );\n });\n\n const invalidFiles = files.filter((f) => !validFiles.includes(f));\n invalidFiles.forEach((f) => {\n skippedImports.push({ name: f.name, reason: 'Unsupported file format' });\n });\n\n if (validFiles.length === 0) {\n if (files.length > 0) {\n showToast('No valid GPS files found', 'error');\n // Still update warning icon if there were invalid files!\n const importWarning = document.getElementById('import-warning');\n if (importWarning && skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n }\n }\n return;\n }\n\n const loaderFilename = document.getElementById('loader-filename');\n let progressIdxEl: HTMLElement | null = null;\n if (loaderSubtext) {\n loaderSubtext.innerHTML =\n '';\n progressIdxEl = loaderSubtext.querySelector('.progress-index') as HTMLElement | null;\n const totalEl = loaderSubtext.querySelector('.progress-total');\n if (totalEl) totalEl.textContent = validFiles.length.toString();\n }\n\n for (let i = 0; i < validFiles.length; i++) {\n if (cancelProcessing) break;\n const f = validFiles[i];\n if (loaderFilename) loaderFilename.textContent = f.name;\n if (progressIdxEl) progressIdxEl.textContent = (i + 1).toString();\n if (progressBar) progressBar.style.width = `${(i / validFiles.length) * 100}%`;\n\n try {\n const data = await Parsers.parseFile(f);\n\n // Duplicate checks\n const existingTracks = Object.values(tracks);\n\n // Rule 1: Same file and same size\n const sameFile = existingTracks.find((t) => t.fileName === f.name && t.fileSize === f.size);\n if (sameFile) {\n skippedImports.push({ name: f.name, reason: 'Same File' });\n updateLoaderIconToWarning();\n continue;\n }\n\n // Rule 2 & 3: Same start day checks\n const newStart = data.stats.startTime;\n const newDuration = data.stats.duration;\n\n if (newStart != null && newDuration != null) {\n const newEnd = newStart + newDuration;\n const sameDayTracks = existingTracks.filter(\n (t) => t.stats.startTime != null && isSameDay(newStart, t.stats.startTime!),\n );\n\n let discarded = false;\n for (const ext of sameDayTracks) {\n const extStart = ext.stats.startTime!;\n const extDuration = ext.stats.duration!;\n const extEnd = extStart + extDuration;\n\n // Rule 2: Fully contained\n if (newStart >= extStart && newEnd <= extEnd) {\n skippedImports.push({ name: f.name, reason: 'Fully contained in another track' });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n\n // Rule 3: Overlaps for > 10 mins\n const overlap = Math.min(newEnd, extEnd) - Math.max(newStart, extStart);\n if (overlap > 600000) {\n // 10 mins in ms\n skippedImports.push({\n name: f.name,\n reason: 'Overlaps with an existing track for more than 10 mins',\n });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n }\n if (discarded) continue;\n }\n\n const fallbackTime = 1785542400000;\n let id = compactId(data.stats.startTime || fallbackTime);\n if (tracks[id]) id += `-${shortRandom()}`;\n\n // Use filename as activity name if internal name is generic\n let trackName = data.name;\n if (trackName.startsWith('Unnamed') || trackName.startsWith('Fit Activity'))\n trackName = f.name;\n\n // Generate a nice display name\n let displayName = trackName;\n const t0 = data.points[0]?.time;\n const sport = data.sport\n ? data.sport.charAt(0).toUpperCase() + data.sport.slice(1)\n : 'Activity';\n if (t0) {\n const d = new Date(t0);\n displayName = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')} ${sport}`;\n } else {\n displayName = trackName.replace(/\\.[^/.]+$/, '').replace(/_/g, ' '); // Remove extension and replace underscores\n }\n\n const track: TrackData = {\n ...data,\n id,\n name: trackName,\n displayName,\n fileName: f.name,\n fileSize: f.size,\n bounds: calculateBounds(data.points) || undefined,\n simplifiedPoints: simplifyTrack(data.points, 50), // 50m resolution\n addedAt: data.stats.startTime || fallbackTime,\n visible: true,\n color: TRACK_COLORS[colorIdx % TRACK_COLORS.length],\n };\n colorIdx++;\n if (cancelProcessing) break;\n\n await Storage.save(track);\n tracks[id] = track;\n MapView.addTrack(track);\n if (!firstId) firstId = id;\n count++;\n processedSinceLastUpdate++;\n\n if (processedSinceLastUpdate >= 5) {\n processedSinceLastUpdate = 0;\n }\n } catch (err) {\n skippedImports.push({\n name: f.name,\n reason: `Parse error: ${err instanceof Error ? err.message : String(err)}`,\n });\n updateLoaderIconToWarning();\n }\n }\n\n // Update warning icon\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n if (skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n } else {\n importWarning.classList.add('hidden');\n }\n }\n\n const newWarnings = skippedImports.length > initialSkipCount;\n if (!newWarnings && loader) {\n loader.classList.add('hidden');\n }\n\n if (count > 0) {\n showToast(`Imported ${count} track${count > 1 ? 's' : ''}`);\n applyFilters(!!firstId && firstId !== selectedId);\n if (firstId) selectTrack(firstId);\n }\n\n if (newWarnings) {\n const loaderIcon = document.querySelector('.loader-icon-wrap span');\n if (loaderIcon) loaderIcon.textContent = 'warning';\n // Delay hiding loader to let user see the alert icon\n await new Promise((r) => setTimeout(r, 1500));\n }\n } finally {\n if (loader) loader.classList.add('hidden');\n }\n}\n\nfunction initMetricPillDraggable() {\n const container = document.getElementById('metric-pills');\n if (!container) return;\n\n let draggedEl: HTMLElement | null = null;\n\n container.addEventListener('dragstart', (e) => {\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (!target) return;\n draggedEl = target;\n e.dataTransfer!.effectAllowed = 'move';\n target.classList.add('dragging-pill');\n // For transparent background in ghost image\n setTimeout(() => (target.style.opacity = '0.4'), 0);\n });\n\n container.addEventListener('dragover', (e) => {\n e.preventDefault();\n e.dataTransfer!.dropEffect = 'move';\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (target && target !== draggedEl) {\n const rect = target.getBoundingClientRect();\n const next = e.clientX - rect.left > rect.width / 2;\n container.insertBefore(draggedEl!, next ? target.nextSibling : target);\n }\n });\n\n container.addEventListener('dragend', () => {\n if (!draggedEl) return;\n draggedEl.classList.remove('dragging-pill');\n draggedEl.style.opacity = '';\n draggedEl = null;\n\n // Update Chart order\n const keys = Array.from(container.querySelectorAll('.metric-pill')).map(\n (el) => (el as HTMLElement).dataset.metric!,\n );\n ChartView.updateMetricOrder(keys);\n syncMetricsToUrl();\n });\n}\n\nfunction updateToolbarLayout() {\n const toolbar = document.getElementById('chart-toolbar');\n const pills = document.getElementById('metric-pills');\n if (!toolbar || !pills) return;\n\n toolbar.classList.remove('collapsed');\n const availableW = Math.max(0, toolbar.clientWidth - 280);\n let totalW = 0;\n let hidden = false;\n\n Array.from(pills.children).forEach((el) => {\n const htmlEl = el as HTMLElement;\n if (htmlEl.id === 'pill-overflow') return;\n\n htmlEl.classList.remove('overflow-hidden');\n if (!htmlEl.classList.contains('active')) return;\n const metricKey = htmlEl.dataset.metric || '';\n const deterministicPillWidth = 36 + metricKey.length * 6;\n totalW += deterministicPillWidth + 6;\n\n if (totalW > availableW) {\n hidden = true;\n htmlEl.classList.add('overflow-hidden');\n }\n });\n\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.toggle('hidden', !hidden);\n\n if (hidden) toolbar.classList.add('collapsed');\n}\n\ndocument.addEventListener('DOMContentLoaded', init);\n"], + "mappings": "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", + "names": ["UrlState", "_state", "_lastSearch", "_syncTimeout", "_shouldPush", "read", "p", "s", "metricsRaw", "v", "isDesc", "field", "parts", "_sync", "dir", "search", "val", "url", "get", "patch", "partial", "push", "k", "key", "refresh", "reset", "InMemoryStorage", "track", "id", "key", "value", "IndexedDBStorage", "resolve", "reject", "req", "db", "name", "mode", "res", "rej", "tx", "activeDriver", "Storage", "UrlState", "k", "v", "FitParser", "haversine", "lat1", "lon1", "lat2", "lon2", "phi1", "phi2", "deltaPhi", "deltaLambda", "a", "compactId", "timestamp", "buf", "shortRandom", "fmtDuration", "s", "fmtSecs", "h", "m", "fmtPace", "seconds", "mins", "secs", "fmtDate", "ts", "d", "fmtDateTime", "iso", "fmtFileSize", "bytes", "k", "sizes", "i", "escHtml", "str", "getTagColor", "name", "hash", "gaussianSmooth", "data", "sigma", "size", "kernel", "half", "sum", "x", "result", "val", "weightSum", "idx", "hexToRgba", "hex", "alpha", "r", "g", "b", "calculateBounds", "pts", "minLat", "maxLat", "minLon", "maxLon", "p", "SIMPLIFY_CAP", "simplifyLats", "simplifyLons", "simplifyEles", "simplifyDists", "enrichEleBuf", "enrichPwrBuf", "enrichSpdBuf", "simplifyTrack", "minDistanceMeters", "n", "lats", "lons", "eles", "dists", "i", "tolerances", "errChecksum", "degToRad", "ti", "tolDegSq", "anchor", "cosLat", "dx", "dy", "dz", "mid", "mx", "my", "result", "lastPoint", "tolBias", "haversine", "Parsers", "enrichPoints", "totalDist", "prev", "d", "dt", "de", "eleBuf", "pwrBuf", "spdBuf", "gradeWindows", "npAccum", "scaleH", "wi", "w", "invW", "pSum", "sSum", "pAvg", "airDensity", "slopeAngle", "smoothBias", "hrZoneThresholds", "ftp", "computeStats", "includeCurves", "stats", "powerSum", "powerN", "hrSum", "hrN", "cadSum", "cadN", "speedSum", "speedN", "batterySum", "batteryN", "tempSum", "tempN", "hasTemp", "shifts", "hasGears", "diff", "t0", "t1", "calculateHRZones", "calculateHRCurve", "calculatePowerCurve", "calculatePowerZones", "ensureCurvesAndZones", "track", "s", "analyzeTrackSections", "sections", "quarterLabels", "q", "sIdx", "eIdx", "subPts", "thirdLabels", "t", "kmStartIdx", "nextKmMeters", "kmIndex", "kmPts", "win", "inClimb", "climbStart", "climbIdx", "inSprint", "sprintStart", "sprintIdx", "sprintThreshold", "dEle", "dDist", "rollingGrade", "segPts", "pwr", "findOverlaps", "tracksList", "overlaps", "ta", "ptsA", "stepA", "j", "tb", "ptsB", "stepB", "shared", "minCorridor", "a", "pa", "nearest", "b", "pb", "STANDARD_CURVE_DURATIONS", "calculateSlidingMax", "data", "durations", "len", "prefix", "curve", "hasAny", "di", "maxSum", "bestIdx", "limit", "currentSum", "powerData", "nonZero", "v", "hrData", "zones", "thresholds", "pw", "z", "setFTP", "val", "getFTP", "hr", "setHRZones", "getHRZones", "extractXmlTag", "block", "openTag", "closeTag", "start", "extractXmlAttr", "tagOpen", "attrPrefix", "cachedDateKey", "cachedDayMs", "parseIntSlice", "text", "end", "neg", "c0", "digits", "c", "parseFloatSlice", "intPart", "fracPart", "fracDiv", "inFrac", "res", "fastParseTimeSlice", "y", "m", "key", "hh", "mm", "ss", "ms", "extractAttrFloat", "vStart", "parseGPX", "buf", "predecodedText", "firstTrkpt", "header", "trkIdx", "name", "gpxOpenEnd", "device", "points", "pos", "trkStart", "openEnd", "trkEnd", "lat", "lon", "ele", "time", "cad", "power", "temp", "speed", "gearFront", "gearRear", "gearFrontTooth", "gearRearTooth", "battery", "lt", "gt", "c1", "tagLen", "nextLt", "vEnd", "expectedCloseGt", "closeGt", "gears", "parseTCX", "firstTp", "creatorBlock", "tpStart", "tpEnd", "fastDecodeFitData", "dv", "headerSize", "dataSize", "endOffset", "GARMIN_EPOCH_SEC", "SEMICIRCLE_TO_DEG", "defs", "file_ids", "sessions", "records", "events", "device_infos", "offset", "hdr", "localNum", "littleEndian", "globalMsgNum", "numFields", "fields", "recordSize", "num", "size", "type", "def", "le", "gNum", "ts", "rawLat", "rawLon", "rawAlt", "rawDist", "rawSpd", "msg", "fOff", "f", "bType", "sportMap", "evName", "parseFIT", "resolve", "reject", "handleParsedFitData", "error", "devices", "sport", "subSport", "getDeviceName", "fid", "antId", "existing", "statusReports", "idx", "gearEvents", "e", "front", "rear", "frontTooth", "rearTooth", "ft", "fg", "rt", "rg", "lastBattery", "statusIdx", "lastFrontGear", "lastRearGear", "lastFrontTooth", "lastRearTooth", "gearIdx", "validPoints", "ri", "r", "ex", "fastData", "FitParser", "parseKML", "doc", "nameEl", "coordEls", "el", "line", "parts", "parseFile", "file", "ext", "MapView", "trackData", "customClickHandler", "init", "onSelectCb", "onMoveCb", "onPointClickCb", "onPointHoverCb", "onDblClickCb", "switchBasemap", "layer", "addTrack", "t", "addTracks", "ts", "removeTrack", "id", "clearTracks", "removeAllTracks", "setTrackVisible", "visible", "setSelectedTrack", "fit", "fitAll", "fitTrack", "showCursorAt", "lat", "lon", "hideCursor", "highlightSegment", "pts", "start", "end", "colors", "clearHighlight", "setTrackHover", "hover", "ensureVisible", "centerOn", "zoom", "force", "closePopup", "invalidateSize", "getPosition", "setPosition", "lng", "colorTrackByMetric", "clearMetricColor", "findTracksPassingThroughPoints", "points", "radius", "handler", "uPlot", "Zones", "getPowerZones", "ftp", "Parsers", "thresholds", "t", "names", "colors", "zones", "last", "i", "getHRZones", "Metrics", "METRICS", "v", "p", "pts", "fillNulls", "vam", "i", "prev", "de", "dt", "SPORTS", "getSportIcon", "sport", "key", "ChartView", "plots", "renderedTrack", "renderedXAxis", "renderedSpeedMode", "renderedMapColorMetric", "syncKey", "scaleSyncing", "cursorSyncing", "activeMetrics", "availableMetrics", "smoothedMetrics", "metricsIncludingZero", "xAxis", "currentTrack", "allTracks", "selAnchorVal", "selEndVal", "isDragging", "updatingRange", "pinnedPtIdx", "lastMouseXVal", "lastHistMouseEvent", "hoveredHistData", "hoveredHistCanvas", "currentXRange", "targetXRange", "animId", "onCursorMoveCb", "onRangeChangeCb", "onClickCb", "onPinChangeCb", "HIST_W", "ROW_BODY_PADDING", "HIST_GAP", "statsVisible", "histTooltipEl", "container", "emptyEl", "selStatsEl", "resetSelBtn", "mapColorMetric", "onMapColorChangeCb", "init", "onCursorMove", "onRangeChange", "onClick", "onPinChange", "updateHistTooltip", "uPlot", "cancelSelection", "navKeys", "activeNavKeys", "e", "key", "u", "min", "max", "moveStep", "zoomFactor", "newMin", "newMax", "center", "factor", "xFull", "d", "setVisibleRange", "animate", "startMin", "startMax", "lerp", "a", "b", "t", "step", "tMin", "tMax", "cMin", "cMax", "loadTrack", "track", "others", "deferRender", "METRICS", "def", "p", "m", "el", "pill", "metric", "isAvailable", "updateStats", "render", "clear", "destroyPlots", "chartStats", "clearSelectionStats", "resetState", "overflowEl", "toolbar", "toggleMetric", "setSmooth", "metricKey", "enabled", "skipRender", "has", "setZeroInclusion", "includeZero", "setActiveMetrics", "keys", "setXAxis", "axis", "pts", "t0", "convert", "val", "idx", "dTarget", "tTarget", "newRange", "r0", "r1", "toggleStats", "histCol", "resize", "setMapColorChangeCb", "cb", "toggleMapColor", "_updateMapColorBtns", "_fireMapColorCb", "plot", "colors", "_computePointColors", "yData", "vals", "v", "sport", "sportDef", "SPORTS", "defaultMode", "speedMode", "UrlState", "paceUnit", "gradientColor", "speed", "speedColor", "lerpHex", "resetZoom", "updateSelOverlay", "redrawHistograms", "xData", "setSelectionStats", "stats", "fmt", "id", "fmtSecs", "restoreSelection", "totalDuration", "tOffset", "xMin", "xMax", "updateAnchorLines", "w", "anyResized", "histCanvas", "histData", "drawHistogram", "keepState", "savedRange", "savedScroll", "available", "containerW", "canReuse", "lastValidX", "existingByKey", "availSet", "isSmoothed", "isIncZero", "nextSiblingRows", "nextExisting", "i", "ex", "reused", "uplot", "s", "prevSync", "initHoverBinI", "buildHistBins", "span", "transform", "fmtAxis", "unit", "label", "fmtPace", "fillNulls", "gaussianSmooth", "createChart", "initialRange", "insertBeforeEl", "gradData", "smoothGradient", "row", "header", "labelEl", "smoothBtn", "mapColorBtn", "zeroBtn", "incZero", "statsTotalEl", "statsSelEl", "statsContainer", "actionsEl", "rightActionsEl", "paceToggle", "btn", "mode", "isDefault", "rowBody", "plotEl", "fixedMinLabel", "fixedMaxLabel", "isDistAxis", "formatX", "range", "dec", "absV", "h", "hh", "mm", "ss", "incZeroDefault", "gMin", "gMax", "allSum", "allCount", "filtMin", "filtMax", "filtSum", "filtCount", "fullStatsAll", "fullStatsFiltered", "gPad", "fixedYRange", "statsTotalInitialized", "updateHeaderStats", "visibleMin", "visibleMax", "getHtml", "isFull", "rangeStats", "es", "elevationRangeStats", "initializingScale", "uOpts", "_si", "_u", "mn", "mx", "axisIdx", "scaleMin", "scaleMax", "targetLabels", "idealIncr", "incrs", "incr", "splits", "precision", "pos", "top", "drawTrackPath", "drawElevationGradient", "drawGradientChart", "drawMetricColorFill", "drawPinnedDot", "drawYAxisHighlight", "hIdx", "hasPinned", "hasHover", "cy", "drawVerticalLineOnly", "hexToRgba", "ctx", "dpr", "bb", "ax", "fontSize", "fontStr", "tw", "visibleL", "visibleR", "padH", "padV", "bw", "bh", "bx", "by", "drawXAxisLabels", "showHover", "updateTooltip", "binI", "other", "left", "width", "overlay", "selFill", "anchorLine", "anchorLabel", "anchorHandle", "anchorMarker", "endLine", "endLabel", "endHandle", "endMarker", "curYVal", "pinYVal", "self", "attachHandleDrag", "mousedownX", "rect", "attachHistTooltip", "aX", "eX", "overW", "overH", "plotBottom", "isAnchorVisible", "isEndVisible", "fillL", "fillR", "aText", "fmtXVal", "aLabelW", "aIcon", "eText", "eLabelW", "eIcon", "handleEl", "isAnchor", "startX", "startVal", "pxPerUnit", "onMove", "me", "dx", "newVal", "onUp", "BINS", "lo", "hi", "cnt", "bins", "binAccum", "k", "bi", "prev", "next", "canvas", "chartH", "hoverBinI", "hasSel", "selBins", "selBinAccum", "x", "W", "H", "peak", "pad", "plotW", "plotH", "binY", "binH", "baseAlpha", "total", "pts2", "cumSum", "my", "cp", "font9", "avgY", "minLabelY", "maxLabelY", "labelHeight", "countLower", "countHigher", "pLower", "pHigher", "font8", "textY", "fontB10", "midX", "getBinAt", "lineEl", "relY", "rawI", "count", "pct", "low", "high", "zoneHtml", "mid", "zones", "Zones", "zIdx", "z", "finalZIdx", "totalAccum", "totalPct", "html", "stotalAccum", "stotalPct", "ttH", "ttW", "binCenterY", "sum", "n", "gain", "loss", "prevEle", "isDist", "diff", "cx", "gColor", "g", "p0", "p1", "content", "front", "rear", "color44", "gradientColorRgbaCache", "gradientColorRgba", "c", "yMin", "yMax", "xScale", "yScale", "yBase", "idxs", "iStart", "iEnd", "byColor", "prevIdx", "xv1", "xv0", "x0", "y0", "x1", "y1", "color", "segs", "j", "drawHoverLine", "xVal", "opacity", "skipLine", "distVal", "timeVal", "bottomLabel", "topLabel", "drawPill", "text", "y", "isTop", "rx", "clampedRx", "ry", "pillH", "yVal", "cyClamp", "drawAreaFillAbove", "yDir", "yMult", "inSegment", "hasAnySegment", "lastPx", "xv", "yv", "px", "py", "ah", "ar", "ag", "ab", "br", "bg", "rr", "rg", "rb", "absG", "kmh", "windowMetres", "grads", "j0", "j1", "data", "res", "right", "getAvg", "avgSpeed", "avgPower", "avgCadence", "INTERVAL_CAP", "ivPwr", "ivHr", "ivSpd", "ivEle", "ivCad", "ivSmoothed", "ivKdeBins", "intervalWindows", "analyzeTelemetryIntervals", "tracksList", "selStartSec", "selEndSec", "intervalScore", "ti", "sStart", "sEnd", "inv35", "invSigmaSq", "omega", "sgPwr", "sgHr", "sgSpd", "dP", "gauss", "harmonic", "sectionRanges", "si", "secStart", "secEnd", "secLen", "wi", "invW", "winSum", "winEle", "maxInterval", "avg", "norm", "newActive", "isStepped", "drawBackgroundTracks", "GAP_THRESHOLD", "field", "first", "prevP", "prevXVal", "lastFrontGear", "fMin", "fMax", "fg", "rMin", "rMax", "isTimeAxis", "gapSec", "prevDrawnI", "prevX", "prevY", "segmentColor", "prevXv", "SENSOR_ICONS", "Metrics", "onTagsChangeCb", "onDeleteTrackCb", "initDetails", "onTagsChange", "onDeleteTrack", "resetDetails", "container", "DETAIL_CAP", "detailChannels", "stabilityWindows", "analyzeTrackDetails", "track", "allTracks", "pts", "n", "stabilityAccum", "i", "p", "wi", "w", "invW", "halfW", "ci", "ch", "sum", "sumSq", "autoCov", "jitterSum", "invNoise", "v", "old", "mean", "variance", "lagVal", "diff", "diffSqNoise", "likelihood", "damp", "sections", "Parsers", "splitRows", "si", "sec", "st", "secPtsCount", "secJitter", "dp", "dh", "secStab", "fmtSecs", "gearMap", "fg", "rg", "key", "entry", "gearMatrix", "a", "b", "combo", "g", "cohort", "distRank", "pwrRank", "elevRank", "cohortPwrSum", "cohortDistSum", "ti", "peer", "cohortAvgPower", "cohortAvgDistKm", "renderDetails", "globalTags", "sectionRange", "activeTrack", "t0Base", "ts0", "ts1", "iMin", "iMax", "subPts", "subStats", "s", "t0", "detailAnalysis", "telemetryStabilityPct", "escHtml", "t", "fmtFileSize", "getSportIcon", "SPORTS", "fmtDateTime", "sensor", "gm", "sr", "seen", "d", "name", "manufacturer", "extra", "battery", "sourceIcon", "deviceIcon", "nameLower", "tagContainer", "tagInput", "addBtn", "renderTags", "tags", "tag", "c", "getTagColor", "el", "btn", "e", "Storage", "addTag", "val", "titleInput", "sportTrigger", "showSportMenu", "anchorEl", "popup", "def", "item", "isActive", "iconEl", "nameEl", "clearItem", "isClear", "rect", "closeHandler", "uPlot", "courses", "getCoursesForTrack", "track", "c", "pt", "passesPoint", "trackPt", "haversine", "activeCourseId", "isEditMode", "openCourseId", "toastFn", "courseLayer", "initCourses", "showToast", "toastFn", "loadCourses", "resetCourses", "courses", "activeCourseId", "openCourseId", "isEditMode", "container", "prepareBenchmarkCourses", "allTracks", "specs", "i", "spec", "t", "n", "pStart", "pMid", "pEnd", "getBenchmarkCourseIds", "c", "stored", "Storage", "e", "saveCourses", "calculateCourseDistance", "course", "total", "p1", "p2", "haversine", "findCourseRange", "track", "coursePoints", "currentPtIdx", "startIdx", "endIdx", "tp", "cp", "calculateCourseStats", "pts", "s", "startTime", "duration", "totalPower", "powerCount", "totalHR", "hrCount", "totalSpeed", "speedCount", "totalCadence", "cadenceCount", "totalAscent", "prev", "de", "dist", "formatDuration", "seconds", "h", "m", "renderCourseTableHeaders", "METRICS", "renderCourseTableCells", "stats", "sport", "dateStr", "paceUnit", "SPORTS", "paceStr", "paceSeconds", "fmtPace", "COURSE_CAP", "courseTrkLats", "courseTrkLons", "courseTrkPwrs", "courseGateLats", "courseGateLons", "DTW_SAMPLES", "DTW_BAND", "dtwRefProfile", "dtwCandProfile", "dtwPrevRow", "dtwCurrRow", "renderCourses", "corridorDeviationSum", "targetCourses", "candidateIds", "MapView", "p", "numGates", "g", "segFloat", "segIdx", "frac", "pA", "pB", "ci", "id", "pt", "gLat", "gLon", "minDist", "bestIdx", "d", "idx", "val", "jStart", "jEnd", "rVal", "j", "diff", "diffSq", "cost", "m1", "m2", "m3", "prevMin", "matchingIds", "isOpen", "tracksHtml", "matchedTracksWithStats", "range", "span", "q1Idx", "q2Idx", "q3Idx", "s1Stats", "s2Stats", "s3Stats", "s4Stats", "fmtDate", "a", "b", "UrlState", "escHtml", "createNewCourse", "el", "editCourse", "renameCourse", "deleteCourse", "selectCourse", "row", "trackId", "selectTrack", "t0", "sIdx", "eIdx", "tMin", "tMax", "axis", "ChartView", "selMin", "selMax", "name", "newCourse", "nameEl", "currentName", "input", "save", "newName", "clearCourseLayer", "courseLayer", "selectCourse", "id", "open", "activeCourseId", "openCourseId", "isEditMode", "MapView", "clearCourseLayer", "renderCourses", "deleteCourse", "courses", "c", "saveCourses", "toastFn", "insightPlots", "destroyInsightPlots", "p", "initInsights", "showToast", "resetInsights", "el", "container", "INSIGHT_CAP", "inPwrArr", "inHrArr", "inCadArr", "inSpdArr", "inVamArr", "inPrefixPwr", "inPrefixVam", "mmpDurations", "analyzeTrackPhysiology", "pts", "cpBase", "sections", "n", "i", "pt", "h", "c", "sp", "gr", "vam", "envelopeChecksum", "di", "d", "limit", "maxP", "maxV", "j", "sumP", "sumV", "minWPrimeBal", "wBal", "matchesBurned", "inMatchBurn", "half", "efSum1", "efSum2", "qCounts", "thresholdCad", "thresholdTorque", "cad", "invH", "diff", "dcp", "dep", "tauDyn", "torque", "ef", "ef1", "ef2", "decouplingPct", "quadrantPct", "sectionPeaks", "sec", "st", "durHours", "renderInsights", "track", "allTracks", "sectionRange", "Parsers", "activeRange", "UrlState", "activePts", "s", "t0", "startMs", "endMs", "iMin", "iMax", "phys", "grid", "chartWidth", "renderCurveCard", "Metrics", "card", "metricKey", "color", "isMapColored", "ChartView", "totalTime", "a", "b", "zones", "Zones", "zonesHtml", "time", "z", "pct", "rangeText", "fmtSecs", "e", "current", "btn", "showPowerZoneSettings", "showHRZoneSettings", "climbingCard", "distKm", "grade", "effCard", "secCard", "escHtml", "trackCourses", "getCoursesForTrack", "coursesCard", "renderCourseTableHeaders", "range", "findCourseRange", "statsHtml", "stats", "calculateCourseStats", "startTime", "dateStr", "fmtDate", "renderCourseTableCells", "courseId", "selectCourse", "course", "MapView", "opts", "curve", "label", "unit", "icon", "tableWrap", "toggleBtn", "toggleIcon", "isHidden", "mapColorBtn", "key", "tbody", "durations", "entry", "val", "row", "fmtDuration", "startIdx", "duration", "endIdx", "tMin", "tMax", "chartEl", "xData", "yData", "curYVal", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "idx", "hasFocus", "mousePy", "pointPy", "cx", "cy", "durVal", "pcx", "pcy", "plot", "uPlot", "anchorEl", "popup", "rect", "inputs", "newZones", "Storage", "dismiss", "ftp", "input", "newFtp", "uPlot", "currentTracks", "currentTrack", "plot", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "playIntervalId", "isPolar", "updateSliderLabel", "sliderVal", "timeSecs", "fmtSecs", "resetCombined", "playIntervalId", "plot", "currentTracks", "currentTrack", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "isPolar", "tooltip", "container", "COMBINED_CAP", "combinedDensityGrid", "computeMultiTrackCorrelationAndSections", "allTracks", "matrixTracks", "numTrk", "pairs", "p", "aggPts", "corrSum", "correlations", "pi", "pair", "sumX", "sumY", "sumXX", "sumYY", "sumXY", "count", "t", "pts", "n", "k", "x", "y", "pw", "h", "cd", "bx", "by", "rVal", "slope", "meanX", "meanY", "varX", "varY", "covXY", "denom", "g", "sectionLabels", "sectionRows", "t1", "t2", "q", "fStart", "fEnd", "sliceStats", "trk", "sIdx", "eIdx", "pSum", "hSum", "spSum", "cnt", "i", "pt", "st1", "st2", "cohortPwrSum", "setCombinedMetrics", "xKey", "yKey", "renderCombined", "setCombinedPolar", "polar", "setCombinedSliderProgress", "fraction", "clamped", "maxLen", "slider", "updateSliderLabel", "trackOrTracks", "track", "metrics", "ChartView", "availableMetrics", "key", "def", "xDef", "yDef", "summaryHtml", "s1", "s2", "distDiff", "pwrDiff", "hrDiff", "eleDiff", "shiftsDiff", "totalDist", "totalElev", "totalDur", "avgPwr", "maxPwr", "avgHr", "maxHr", "tempDiff", "avgTemp", "maxTemp", "totalShifts", "fmtSecs", "sr", "c", "e", "showMenu", "sliderVal", "playBtn", "startPlaying", "stopPlaying", "updatePlot", "resizeCombined", "plotContainer", "w", "size", "anchorEl", "axis", "el", "popup", "item", "currentVal", "rect", "close", "xData", "seriesList", "dataArrays", "yArr", "width", "height", "opts", "uPlot", "t0", "chronoData", "idx", "d", "xVals", "yVals", "xMin", "xMax", "yMin", "yMax", "xVal", "yVal", "theta", "r", "px", "py", "a", "b", "yData", "hexToRgba", "u", "vals", "v", "seriesIdx", "dataIdx", "cursorLeft", "cursorTop", "minD2", "closestIdx", "cx", "cy", "dx", "dy", "d2", "ctx", "dpr", "started", "startIdx", "endIdx", "xVal1", "yVal1", "xVal2", "yVal2", "cx1", "cy1", "cx2", "cy2", "progress", "lineWidth", "alpha", "fillAlpha", "timeSecs", "distKm", "origX", "origY", "canvasRect", "originalIdx", "uPlot", "computeAccumulatedMetric", "allTracks", "extractor", "refTs", "i", "st", "now", "currentYear", "oneYearAgoMs", "sixMonthsAgoMs", "oneMonthAgoMs", "currentYearVal", "pastYearVal", "past6mVal", "past1mVal", "totalVal", "minTime", "t", "val", "time", "msecPerWeek", "currentYearStart", "currentYearWeeks", "pastYearWeeks", "past6mWeeks", "past1mWeeks", "totalWeeks", "renderAccumulatedTable", "accumulated", "isDistance", "unit", "factor", "format", "computeMultiMetricAccumulated", "distance", "elevation", "durationHours", "tss", "durSec", "avgPwr", "ftp", "intensityFactor", "workKj", "climbCount", "s", "renderAccumulatedProgressSummary", "summary", "fmt", "v", "digits", "r", "evolutionPlots", "activeEvolutionCards", "currentEvolutionGrouping", "destroyEvolutionPlots", "p", "resetEvolution", "container", "setEvolutionGrouping", "grouping", "c", "setEvolutionRange", "range", "UrlState", "toolbarRangeCtrl", "b", "setEvolutionPinnedDuration", "dur", "EVO_CAP", "evoPwrPrefix", "evoHrPrefix", "evoSpdPrefix", "evoStressArr", "evoDailyTrimp", "envelopeDurations", "renderEvolution", "currentTrack", "allTracks", "onTrackSelect", "onDateRangeSelect", "currentRange", "track", "Parsers", "totalFatigue", "totalFitness", "ti", "pts", "n", "i", "pw", "h", "sp", "el", "hrRatio", "di", "d", "limit", "maxP", "maxH", "j", "dh", "alphaA", "oneMinusA", "alphaC", "oneMinusC", "hrRest", "invHrSpan", "atl", "ctl", "kh", "trimp", "dayIdx", "atl365", "ctl365", "day", "load", "cards", "Metrics", "grid", "renderAccumulatedProgressSummary", "gridWidth", "progressSync", "uPlot", "renderProgressCard", "distanceScroll", "elevationScroll", "btn", "onRangeChange", "pill", "target", "onPinChange", "t", "card", "renderCurveEvolutionCard", "opts", "metricKey", "label", "unit", "color", "icon", "trackName", "mainChart", "cardContainer", "row1", "legendEl", "row2", "sideBySide", "chartEl", "maxCurve", "curve", "name", "date", "fmtDate", "trackInfo", "data", "val", "currentCurve", "allDurations", "durations", "a", "xData", "yDataCurrent", "entry", "yDataMax", "validTracks", "xTimeline", "yTimelineData", "currentDur", "tracksFiltered", "pinnedDur", "getFilteredData", "maxTime", "minTime", "filteredIndices", "idx", "xFiltered", "rawY", "rawYFiltered", "smoothedYFiltered", "gaussianSmooth", "timelineChart", "curYVal", "optsUPlot", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "fmtDuration", "pcx", "pcy", "curVal", "dotRadius", "dotColor", "activeSeriesIdx", "cursorLeft", "cursorTop", "minD2", "nearestIdx", "radius", "maxD2", "yCur", "yMax", "px", "py", "dx", "dy", "d2", "xValStr", "xbw", "pillH", "xLabelX", "clampedXBx", "xLabelY", "yValStr", "ybw", "yLabelX", "yLabelY", "cx", "cy", "durVal", "mxVal", "html", "lowerBound", "upperBound", "labelEl", "clickedDur", "newPinnedDur", "stats", "bestIdx", "duration", "startPt", "endPt", "trackStart", "min", "max", "detailsEl", "cur", "mx", "mxId", "mxIdx", "e", "id", "lastNearestIdx", "timelineEl", "timelineTooltip", "dataTimeline", "series", "optsTimeline", "ts", "tpcx", "tpcy", "tctx", "tdpr", "dateStr", "valStr", "yData", "y", "getWeekStart", "diff", "computeWeeklyDistance", "weeklyData", "weekStart", "weekKey", "week", "computeWeeklyElevation", "computeMonthlyDistance", "monthlyData", "monthStart", "monthKey", "computeMonthlyElevation", "type", "syncKey", "isDistance", "activeGrouping", "activeRange", "weeklySource", "monthlySource", "accumulated", "computeAccumulatedMetric", "renderAccumulatedTable", "yAxisEl", "tooltip", "yDataSmoothed", "chartClientW", "width", "maxVal", "mainOpts", "item", "start", "end", "startStr", "endStr", "self", "splits", "s", "scrollContainer", "applySeriesData", "filteredData", "newXData", "newYData", "newYDataSmoothed", "newWidth", "newMaxVal", "TRACK_COLORS", "POINT_ZOOM_LEVEL", "tracks", "skippedImports", "isSameDay", "t1", "t2", "d1", "d2", "cancelProcessing", "selectedId", "colorIdx", "followDot", "currentMapColors", "searchQuery", "searchRegex", "currentSort", "filters", "syncFiltersToUrl", "push", "UrlState", "v", "syncMetricsToUrl", "active", "ChartView", "metrics", "abbrs", "key", "SORT_OPTIONS", "showSortMenu", "anchorEl", "el", "popup", "opt", "item", "updateSearchSortUI", "renderTrackList", "rect", "close", "e", "showMetricMenu", "available", "def", "isNowActive", "pill", "updateToolbarLayout", "id", "idx", "dur", "selectTrack", "t", "pts", "pIdx", "t0", "p", "tMin", "tMax", "iMax", "selPts", "stats", "Parsers", "renderInsights", "MapView", "btn", "nav", "b", "tab", "panel", "c", "renderDetails", "getGlobalTags", "renderEvolution", "trackId", "range", "onChartRangeChange", "start", "end", "applyFilters", "updateFilterUI", "renderCombined", "renderCourses", "s", "resetBenchmarkState", "Storage", "resetCourses", "resetInsights", "resetDetails", "resetCombined", "resetEvolution", "toastContainer", "init", "fontTimerId", "fontTimeout", "resolve", "fontLoadPromise", "storageSelect", "selected", "params", "loader", "loaderText", "loaderSubtext", "progressBar", "mapLoader", "mapLoaderSpan", "urlState", "initInsights", "msg", "type", "showToast", "initDetails", "deleteTrack", "initCourses", "onMapMove", "onMapPointClick", "onMapDblClick", "onChartCursorMove", "onChartClick", "data", "currentUrlState", "applyState", "hrZones", "ftp", "saved", "a", "tracksToLoad", "updated", "calculateBounds", "simplifyTrack", "restoreId", "selectedTrackData", "processAndLoadTrack", "remaining", "index", "loadNextChunk", "initResizeHandle", "initSidebarResizer", "initMetricPillDraggable", "clearAll", "toggleMetric", "metric", "axis", "initDropZone", "handleFiles", "onFilterInput", "val", "burgerBtn", "dropdownContent", "isVisible", "target", "selectedSport", "m", "resizeCombined", "initBenchmarkTriggers", "preloadBenchmarkFiles", "readyEl", "camelReadyEl", "preloadedBenchmarkPayloads", "fileNames", "decoder", "name", "buf", "cleanName", "bytes", "ds", "stream", "text", "file", "warmSample", "parsed", "warmPts", "warmTrack", "warmTrack2", "warmList", "setCombinedPolar", "setCombinedSliderProgress", "setEvolutionGrouping", "setEvolutionRange", "setEvolutionPinnedDuration", "prepareBenchmarkCourses", "selectCourse", "r", "btnLoad", "btnAnalysis", "btnInsights", "btnDetails", "btnAggregate", "btnEvolution", "btnCourses", "activateTab", "tabName", "loadedFiles", "allTracks", "sortMode", "availableMetrics", "metricSets", "mSet", "filtered", "sections", "secStart", "secEnd", "cursorIdx", "primaryTrack", "tIdx", "trk", "globalTags", "i", "setCombinedMetrics", "frac", "selectedTwo", "onSelectCb", "refTracks", "refTrk", "rng", "courseIds", "getBenchmarkCourseIds", "cId", "powerCurveEntries", "needsEnrich", "handle", "isDragging", "h", "clampedH", "resizer", "sidebar", "w", "clampedW", "lat", "lng", "zoom", "pt", "min", "max", "fit", "iMin", "d0", "ts0", "ts1", "deferChartRender", "hadSelected", "activeTab", "code", "backdrop", "input", "btnConfirm", "btnCancel", "skipRender", "visible", "field", "trackTags", "ft", "activeCount", "badge", "searchInput", "o", "labelEl", "iconEl", "newTrackId", "currentXAxis", "keys", "abbr", "k", "updateSportFilterOptions", "commonContainer", "sports", "sportsArray", "burgerDropdown", "sport", "getSportIcon", "list", "emptyEl", "headerLabel", "ids", "ta", "tb", "sa", "sb", "cmp", "buildTrackItem", "all", "tag", "track", "date", "fmtDate", "tagsHtml", "getTagColor", "escHtml", "btnVis", "container", "showSkippedImportsModal", "listHtml", "btnClear", "importWarning", "zone", "items", "files", "queue", "entry", "readAllEntries", "res", "reader", "entries", "chunk", "child", "initialSkipCount", "loaderClose", "updateLoaderIconToWarning", "loaderIcon", "warningCount", "count", "countSpan", "firstId", "processedSinceLastUpdate", "validFiles", "f", "loaderFilename", "progressIdxEl", "totalEl", "existingTracks", "newStart", "newDuration", "newEnd", "sameDayTracks", "discarded", "ext", "extStart", "extDuration", "extEnd", "fallbackTime", "compactId", "shortRandom", "trackName", "displayName", "d", "err", "newWarnings", "draggedEl", "next", "toolbar", "pills", "availableW", "totalW", "hidden", "htmlEl", "deterministicPillWidth", "overflowEl"] } diff --git a/suites-experimental/tools-gps-tracks/src/app.ts b/suites-experimental/tools-gps-tracks/src/app.ts index 4c2de8a86c..c7fd2f1913 100644 --- a/suites-experimental/tools-gps-tracks/src/app.ts +++ b/suites-experimental/tools-gps-tracks/src/app.ts @@ -13,12 +13,27 @@ import { MapView } from './map'; import { ChartView } from './charts'; import { renderDetails, initDetails, resetDetails } from './tabs/details'; import { renderInsights, initInsights, resetInsights } from './tabs/insights'; -import { renderCombined, initCombined, resizeCombined, resetCombined } from './tabs/combined'; -import { renderEvolution, resetEvolution } from './tabs/progress'; +import { + renderCombined, + initCombined, + resizeCombined, + resetCombined, + setCombinedMetrics, + setCombinedPolar, + setCombinedSliderProgress, +} from './tabs/combined'; +import { + renderEvolution, + resetEvolution, + setEvolutionGrouping, + setEvolutionRange, + setEvolutionPinnedDuration, +} from './tabs/progress'; import { renderCourses, initCourses, prepareBenchmarkCourses, + getBenchmarkCourseIds, resetCourses, selectCourse, } from './tabs/courses'; @@ -890,16 +905,34 @@ async function preloadBenchmarkFiles(): Promise< const warmList = [warmTrack, warmTrack2]; Parsers.ensureCurvesAndZones(warmTrack); Parsers.ensureCurvesAndZones(warmTrack2); + warmTrack.stats.sections = Parsers.analyzeTrackSections(warmTrack.points); + warmTrack2.stats.sections = Parsers.analyzeTrackSections(warmTrack2.points); + Parsers.findOverlaps(warmList); MapView.addTracks(warmList); ChartView.loadTrack(warmTrack, warmList, false); ChartView.restoreSelection(10, 50, true); ChartView.setCursorAt(25, true); + ChartView.setSmooth('power', true); + ChartView.setSmooth('power', false); + ChartView.setXAxis('distance'); + ChartView.setXAxis('time'); ChartView.setActiveMetrics(['elevation', 'speed', 'power']); ChartView.analyzeTelemetryIntervals(warmList, 10, 50); + renderInsights(warmTrack, warmList, [10, 50]); renderInsights(warmTrack, warmList); renderDetails(warmTrack, [], warmList); + renderCombined(warmTrack, warmList); + setCombinedPolar(true); + setCombinedPolar(false); + setCombinedSliderProgress(0.5); renderCombined(warmList, warmList); renderEvolution(warmTrack, warmList); + setEvolutionGrouping('month'); + setEvolutionGrouping('week'); + setEvolutionRange('6m'); + setEvolutionRange('all'); + setEvolutionPinnedDuration(60); + setEvolutionPinnedDuration(null); prepareBenchmarkCourses(warmList); selectCourse('course-1', true); await resetBenchmarkState(); @@ -945,6 +978,24 @@ function initBenchmarkTriggers() { const loadedFiles: File[] = payloads.map((p) => p.file); await handleFiles(loadedFiles); const allTracks = Object.values(tracks); + Parsers.findOverlaps(allTracks); + + // Exercise sidebar track list sorting and filtering across distinct criteria + for (const sortMode of ['dist-desc', 'dur-desc', 'date-asc', 'date-desc']) { + currentSort = sortMode; + renderTrackList(); + } + filters.sport = 'cycling'; + applyFilters(); + filters.sport = null; + filters.metrics.add('power'); + applyFilters(); + filters.metrics.clear(); + searchQuery = 'Alpine'; + applyFilters(); + searchQuery = ''; + applyFilters(); + if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id); } finally { window.dispatchEvent(new CustomEvent('load-and-parse-complete')); @@ -956,26 +1007,44 @@ function initBenchmarkTriggers() { const allTracks = Object.values(tracks); activateTab('graphs'); if (!selectedId && allTracks.length > 0) { - selectTrack(allTracks[0].id); + selectTrack(allTracks[0].id, false); } - ChartView.restoreSelection(120, 900, true); - ChartView.setCursorAt(300, true); const availableMetrics = ChartView.getAvailableMetrics(); - const analysisMetrics = ['elevation', 'speed', 'power'].filter((m) => - availableMetrics.has(m), - ); - if (analysisMetrics.length > 0) { - document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => { - const metric = (el as HTMLElement).dataset.metric; - if (metric) el.classList.toggle('active', analysisMetrics.includes(metric)); - }); - updateToolbarLayout(); - ChartView.setActiveMetrics(analysisMetrics); - } else { - updateToolbarLayout(); + const metricSets = [ + ['elevation', 'speed', 'power', 'hr'], + ['elevation', 'speed', 'power'], + ]; + for (const mSet of metricSets) { + const filtered = mSet.filter((m) => availableMetrics.has(m)); + if (filtered.length > 0) { + document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => { + const metric = (el as HTMLElement).dataset.metric; + if (metric) el.classList.toggle('active', filtered.includes(metric)); + }); + updateToolbarLayout(); + ChartView.setActiveMetrics(filtered); + } + } + + // Exercise smoothing, map metric coloring, and X-axis mode switching + ChartView.setSmooth('power', true, true); + ChartView.toggleMapColor('power', true); + ChartView.toggleMapColor(null, true); + ChartView.setXAxis('distance'); + ChartView.setSmooth('power', false, true); + ChartView.setXAxis('time'); + + // Analyze distinct sections of the track (Opening Climb & Main Analysis Window) + const sections: [number, number, number][] = [ + [0, 360, 180], + [120, 900, 300], + ]; + for (const [secStart, secEnd, cursorIdx] of sections) { + ChartView.restoreSelection(secStart, secEnd, true); + ChartView.setCursorAt(cursorIdx, true); + ChartView.analyzeTelemetryIntervals(allTracks, secStart, secEnd); + onChartRangeChange(secStart, secEnd, ChartView.getXAxis(), false); } - ChartView.analyzeTelemetryIntervals(allTracks, 120, 900); - onChartRangeChange(120, 900, ChartView.getXAxis(), false); } finally { window.dispatchEvent(new CustomEvent('analysis-complete')); } @@ -987,7 +1056,24 @@ function initBenchmarkTriggers() { allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t)); activateTab('insights'); const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null; - renderInsights(primaryTrack, allTracks); + // Analyze insights across GPX, TCX, and FIT tracks and across distinct track sections (Opening, Middle, Final thirds, Full) + for (const tIdx of [1, 2, 4]) { + const trk = allTracks[tIdx]; + if (trk) { + renderInsights(trk, allTracks, [0, 540]); + renderInsights(trk, allTracks, [540, 1140]); + renderInsights(trk, allTracks, null); + } + } + if (allTracks[3]) { + renderInsights(allTracks[3], allTracks, [200, 900]); + } + if (primaryTrack) { + renderInsights(primaryTrack, allTracks, [0, 480]); + renderInsights(primaryTrack, allTracks, [480, 960]); + renderInsights(primaryTrack, allTracks, [960, 1440]); + } + renderInsights(primaryTrack, allTracks, null); } finally { window.dispatchEvent(new CustomEvent('insights-complete')); } @@ -997,8 +1083,34 @@ function initBenchmarkTriggers() { try { const allTracks = Object.values(tracks); activateTab('details'); + const globalTags = getGlobalTags(); const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null; - renderDetails(primaryTrack, getGlobalTags(), allTracks); + // Render and analyze telemetry details, splits, gear matrices, and zones across all 6 tracks and terrain sections + for (let i = 0; i < allTracks.length; i++) { + renderDetails(allTracks[i], globalTags, allTracks, null); + } + if (primaryTrack) { + renderDetails(primaryTrack, globalTags, allTracks, [0, 450]); + renderDetails(primaryTrack, globalTags, allTracks, [450, 950]); + renderDetails(primaryTrack, globalTags, allTracks, [950, 1450]); + } + if (allTracks[1]) { + renderDetails(allTracks[1], globalTags, allTracks, [150, 750]); + } + if (allTracks[2]) { + renderDetails(allTracks[2], globalTags, allTracks, [200, 800]); + } + if (allTracks[3]) { + renderDetails(allTracks[3], globalTags, allTracks, [200, 900]); + } + if (allTracks[4]) { + renderDetails(allTracks[4], globalTags, allTracks, [0, 600]); + renderDetails(allTracks[4], globalTags, allTracks, [600, 1200]); + } + if (allTracks[5]) { + renderDetails(allTracks[5], globalTags, allTracks, [150, 750]); + } + renderDetails(primaryTrack, globalTags, allTracks, null); } finally { window.dispatchEvent(new CustomEvent('details-complete')); } @@ -1008,8 +1120,29 @@ function initBenchmarkTriggers() { try { const allTracks = Object.values(tracks); if (allTracks.length >= 2) { - const selectedTwo = [allTracks[0], allTracks[1]]; activateTab('combined'); + // 1. Exercise single-track 2D scatter/trail mode across metric pairs, Polar & Cartesian, and timeline sections + setCombinedMetrics('distance', 'elevation'); + renderCombined(allTracks[0], allTracks); + for (const frac of [0.25, 0.5, 0.75, 1.0]) { + setCombinedSliderProgress(frac); + } + setCombinedPolar(true); + setCombinedSliderProgress(0.5); + setCombinedPolar(false); + setCombinedMetrics('power', 'hr'); + for (const frac of [0.3, 0.7]) { + setCombinedSliderProgress(frac); + } + + // 2. Exercise multi-track comparison mode across regional pairs and all 6 tracks + if (allTracks.length >= 4) { + renderCombined([allTracks[2], allTracks[3]], allTracks); + } + if (allTracks.length >= 6) { + renderCombined(allTracks, allTracks); + } + const selectedTwo = [allTracks[0], allTracks[1]]; renderCombined(selectedTwo, allTracks); } } finally { @@ -1022,13 +1155,27 @@ function initBenchmarkTriggers() { const allTracks = Object.values(tracks); activateTab('evolution'); const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null; - renderEvolution(primaryTrack, allTracks, (trackId, range) => { + const onSelectCb = (trackId: string, range: [number, number] | null) => { selectTrack(trackId, true); if (range) { ChartView.restoreSelection(range[0], range[1]); onChartRangeChange(range[0], range[1], 'time', true); } - }); + }; + + // Exercise evolution view across different reference tracks, groupings ('month' & 'week'), time ranges, and pinned durations + const refTracks = [allTracks[2] || primaryTrack, allTracks[4] || primaryTrack, primaryTrack]; + for (const refTrk of refTracks) { + renderEvolution(refTrk, allTracks, onSelectCb); + setEvolutionGrouping('month'); + for (const rng of ['1m', '2m', '6m', '1y', 'all']) { + setEvolutionRange(rng); + } + setEvolutionGrouping('week'); + for (const dur of [5, 30, 60, 300, 1200, null]) { + setEvolutionPinnedDuration(dur); + } + } } finally { window.dispatchEvent(new CustomEvent('evolution-complete')); } @@ -1039,6 +1186,10 @@ function initBenchmarkTriggers() { const allTracks = Object.values(tracks); activateTab('courses'); prepareBenchmarkCourses(allTracks); + const courseIds = getBenchmarkCourseIds(); + for (const cId of courseIds) { + selectCourse(cId, true); + } selectCourse('course-1', true); } finally { window.dispatchEvent(new CustomEvent('courses-complete')); diff --git a/suites-experimental/tools-gps-tracks/src/charts.ts b/suites-experimental/tools-gps-tracks/src/charts.ts index f8834a206e..d9a1540683 100644 --- a/suites-experimental/tools-gps-tracks/src/charts.ts +++ b/suites-experimental/tools-gps-tracks/src/charts.ts @@ -346,6 +346,28 @@ export const ChartView = (() => { if (currentTrack) render(true); } + function setSmooth(metricKey: string, enabled: boolean, skipRender = false) { + const has = smoothedMetrics.has(metricKey); + if (enabled && !has) { + smoothedMetrics.add(metricKey); + if (currentTrack && !skipRender) render(true); + } else if (!enabled && has) { + smoothedMetrics.delete(metricKey); + if (currentTrack && !skipRender) render(true); + } + } + + function setZeroInclusion(metricKey: string, includeZero: boolean) { + const has = metricsIncludingZero.has(metricKey); + if (includeZero && !has) { + metricsIncludingZero.add(metricKey); + if (currentTrack) render(true); + } else if (!includeZero && has) { + metricsIncludingZero.delete(metricKey); + if (currentTrack) render(true); + } + } + function setActiveMetrics(keys: string[]) { activeMetrics = new Set(keys); if (currentTrack) render(true); @@ -420,7 +442,7 @@ export const ChartView = (() => { onMapColorChangeCb = cb; } - function toggleMapColor(key: string | null) { + function toggleMapColor(key: string | null, skipRender = false) { if (mapColorMetric === key || key === null) { mapColorMetric = null; _updateMapColorBtns(); @@ -431,7 +453,7 @@ export const ChartView = (() => { _fireMapColorCb(); } // Re-render to show/hide colored fills on the graphs - if (currentTrack) render(true); + if (currentTrack && !skipRender) render(true); } function _updateMapColorBtns() { @@ -3063,56 +3085,58 @@ export const ChartView = (() => { ivCad[i] = p.cad || 0; } - // Multi-band Savitzky-Golay 5-point quadratic smoothing, Gaussian kernel density, - // and spectral cadence-HR harmonic analysis + // Single-pass Savitzky-Golay 5-point quadratic smoothing and section interval analysis const sStart = Math.max(0, Math.min(n - 1, Math.floor(selStartSec))); const sEnd = Math.max(sStart + 1, Math.min(n, Math.floor(selEndSec))); const inv35 = 1 / 35; - - const maxSPass = ti < 1 ? 4 : 3; - for (let sPass = 0; sPass < maxSPass; sPass++) { - const weightPwr = 1.0 + sPass * 0.02; - const weightHr = 0.8 + sPass * 0.015; - const invSigmaSq = 1 / (180 + sPass * 25); - const omega = 0.012 + sPass * 0.0015; - for (let i = 2; i < n - 2; i++) { - const sgPwr = - (-3 * ivPwr[i - 2] + - 12 * ivPwr[i - 1] + - 17 * ivPwr[i] + - 12 * ivPwr[i + 1] - - 3 * ivPwr[i + 2]) * - inv35; - const sgHr = - (-3 * ivHr[i - 2] + - 12 * ivHr[i - 1] + - 17 * ivHr[i] + - 12 * ivHr[i + 1] - - 3 * ivHr[i + 2]) * - inv35; - const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25; - const dP = sgPwr - ivPwr[i]; - const gauss = Math.exp(-dP * dP * invSigmaSq); - const harmonic = - sPass < 2 ? Math.cos(i * omega + ivCad[i] * 0.02) : ((i * omega) % 1) - 0.5; - ivSmoothed[i] = - sgPwr * weightPwr * gauss + sgHr * weightHr + sgSpd * (ivCad[i] * 0.1 + harmonic); - } + const invSigmaSq = 1 / 180; + const omega = 0.012; + + for (let i = 2; i < n - 2; i++) { + const sgPwr = + (-3 * ivPwr[i - 2] + + 12 * ivPwr[i - 1] + + 17 * ivPwr[i] + + 12 * ivPwr[i + 1] - + 3 * ivPwr[i + 2]) * + inv35; + const sgHr = + (-3 * ivHr[i - 2] + + 12 * ivHr[i - 1] + + 17 * ivHr[i] + + 12 * ivHr[i + 1] - + 3 * ivHr[i + 2]) * + inv35; + const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25; + const dP = sgPwr - ivPwr[i]; + const gauss = Math.exp(-dP * dP * invSigmaSq); + const harmonic = Math.cos(i * omega + ivCad[i] * 0.02); + ivSmoothed[i] = sgPwr * gauss + sgHr * 0.8 + sgSpd * (ivCad[i] * 0.1 + harmonic); } - for (let pass = 0; pass < 34; pass++) { - const passScale = 1 + pass * 0.005; + const sectionRanges: [number, number][] = [ + [0, Math.floor(n * 0.25)], + [Math.floor(n * 0.25), Math.floor(n * 0.6)], + [Math.floor(n * 0.6), n], + [sStart, sEnd], + ]; + + for (let si = 0; si < sectionRanges.length; si++) { + const [secStart, secEnd] = sectionRanges[si]; + const secLen = secEnd - secStart; + if (secLen < 4) continue; + for (let wi = 0; wi < intervalWindows.length; wi++) { const w = intervalWindows[wi]; - if (w >= n) continue; - const invW = passScale / w; + if (w >= secLen) continue; + const invW = 1 / w; let winSum = 0; let winEle = 0; let maxInterval = 0; - for (let i = 0; i < n; i++) { + for (let i = secStart; i < secEnd; i++) { winSum += ivSmoothed[i]; winEle += ivEle[i]; - if (i >= w) { + if (i - secStart >= w) { winSum -= ivSmoothed[i - w]; winEle -= ivEle[i - w]; const avg = (winSum + winEle * 0.05) * invW; @@ -3122,10 +3146,10 @@ export const ChartView = (() => { intervalScore += maxInterval * 1e-4; } - // Range-selection Kernel Density Estimation (KDE) binning - for (let i = sStart; i < sEnd; i++) { + // Section Kernel Density Estimation (KDE) binning + for (let i = secStart; i < secEnd; i++) { const norm = Math.max(0, Math.min(63, ((ivSmoothed[i] * 0.12) | 0) & 63)); - ivKdeBins[norm] += 1 + (ivEle[i] - ivEle[sStart]) * 1e-3; + ivKdeBins[norm] += 1 + (ivEle[i] - ivEle[secStart]) * 1e-3; if (norm > 0) ivKdeBins[norm - 1] += 0.5; if (norm < 63) ivKdeBins[norm + 1] += 0.5; } @@ -3225,6 +3249,8 @@ export const ChartView = (() => { getActiveMetrics: () => activeMetrics, getAvailableMetrics: () => availableMetrics, setActiveMetrics, + setSmooth, + setZeroInclusion, updateMetricOrder: (keys: string[]) => { // Keys might only contain current active ones, or more. // We want to re-order activeMetrics to match the order in 'keys' diff --git a/suites-experimental/tools-gps-tracks/src/parsers.ts b/suites-experimental/tools-gps-tracks/src/parsers.ts index 80f4e36768..4ea6ca30dc 100644 --- a/suites-experimental/tools-gps-tracks/src/parsers.ts +++ b/suites-experimental/tools-gps-tracks/src/parsers.ts @@ -25,6 +25,25 @@ export interface TrackPoint { gears: number | null; dist?: number; gradient?: number | null; + verticalSpeed?: number | null; +} + +export interface TrackSectionSummary { + id: string; + label: string; + kind: 'quarter' | 'third' | 'km' | 'climb' | 'descent' | 'sprint'; + startIdx: number; + endIdx: number; + stats: TrackStats; +} + +export interface TrackOverlapSummary { + trackAId: string; + trackBId: string; + sharedPoints: number; + minCorridorMeters: number; + powerDelta: number; + speedDelta: number; } export interface TrackStats { @@ -50,6 +69,7 @@ export interface TrackStats { powerZones?: number[] | null; // Time in seconds for each zone shifts?: number | null; // Total number of shifts detected avgBattery?: number | null; + sections?: TrackSectionSummary[]; } export interface DeviceInfo { @@ -130,27 +150,24 @@ export function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): Tra dists[i] = p.dist || 0; } - const tolerances = [2, 4, 6, 9, 13, 18, 24, 32, 42, 55, 70, 88, 108, 130]; + const tolerances = [2, 4, 8, 15, 25, 40, 65, 100]; let errChecksum = 0; const degToRad = 0.017453292519943295; - for (let pass = 0; pass < 5; pass++) { - const tiLimit = pass < 4 ? tolerances.length : 13; - for (let ti = 0; ti < tiLimit; ti++) { - const tolDegSq = (tolerances[ti] * 1e-5 * (1 + pass * 0.05)) ** 2; - let anchor = 0; - for (let i = 1; i < n - 1; i++) { - const cosLat = Math.cos(lats[i] * degToRad); - const dx = (lons[i] - lons[anchor]) * cosLat; - const dy = lats[i] - lats[anchor]; - const dz = (eles[i] - eles[anchor]) * 1e-5; - const dSq = dx * dx + dy * dy + dz * dz; - if (dSq >= tolDegSq) { - const mid = (anchor + i) >> 1; - const mx = (lons[mid] - (lons[anchor] + lons[i]) * 0.5) * cosLat; - const my = lats[mid] - (lats[anchor] + lats[i]) * 0.5; - errChecksum += Math.sqrt(mx * mx + my * my) + (dists[i] - dists[anchor]) * 1e-6; - anchor = i; - } + for (let ti = 0; ti < tolerances.length; ti++) { + const tolDegSq = (tolerances[ti] * 1e-5) ** 2; + let anchor = 0; + for (let i = 1; i < n - 1; i++) { + const cosLat = Math.cos(lats[i] * degToRad); + const dx = (lons[i] - lons[anchor]) * cosLat; + const dy = lats[i] - lats[anchor]; + const dz = (eles[i] - eles[anchor]) * 1e-5; + const dSq = dx * dx + dy * dy + dz * dz; + if (dSq >= tolDegSq) { + const mid = (anchor + i) >> 1; + const mx = (lons[mid] - (lons[anchor] + lons[i]) * 0.5) * cosLat; + const my = lats[mid] - (lats[anchor] + lats[i]) * 0.5; + errChecksum += Math.sqrt(mx * mx + my * my) + (dists[i] - dists[anchor]) * 1e-6; + anchor = i; } } } @@ -218,27 +235,25 @@ export const Parsers = (() => { pwrBuf[i] = pts[i].power ?? 0; spdBuf[i] = pts[i].speed ?? 0; } - const gradeWindows = [3, 5, 8, 12, 18, 25, 30, 45, 60, 75, 90]; + const gradeWindows = [3, 5, 10, 15, 20, 30, 45, 60]; let npAccum = 0; - for (let pass = 0; pass < 4; pass++) { - const scaleH = 1 / (8400 + pass * 150); - for (let wi = 0; wi < gradeWindows.length; wi++) { - const w = gradeWindows[wi]; - const invW = 1 / w; - let pSum = 0; - let sSum = 0; - for (let i = 0; i < n; i++) { - pSum += pwrBuf[i]; - sSum += spdBuf[i]; - if (i >= w) { - pSum -= pwrBuf[i - w]; - sSum -= spdBuf[i - w]; - const pAvg = pSum * invW; - const de = eleBuf[i] - eleBuf[i - w]; - const airDensity = 1.225 * Math.exp(-eleBuf[i] * scaleH); - const slopeAngle = Math.atan2(de, (sSum + 1) * 0.5); - npAccum += pAvg * pAvg * airDensity * 1e-4 + slopeAngle * (sSum * invW) * 1e-2; - } + const scaleH = 1 / 8400; + for (let wi = 0; wi < gradeWindows.length; wi++) { + const w = gradeWindows[wi]; + const invW = 1 / w; + let pSum = 0; + let sSum = 0; + for (let i = 0; i < n; i++) { + pSum += pwrBuf[i]; + sSum += spdBuf[i]; + if (i >= w) { + pSum -= pwrBuf[i - w]; + sSum -= spdBuf[i - w]; + const pAvg = pSum * invW; + const de = eleBuf[i] - eleBuf[i - w]; + const airDensity = 1.225 * Math.exp(-eleBuf[i] * scaleH); + const slopeAngle = Math.atan2(de, (sSum + 1) * 0.5); + npAccum += pAvg * pAvg * airDensity * 1e-4 + slopeAngle * (sSum * invW) * 1e-2; } } } @@ -393,6 +408,170 @@ export const Parsers = (() => { } } + function analyzeTrackSections(pts: TrackPoint[]): TrackSectionSummary[] { + const n = pts.length; + if (n < 8) return []; + const sections: TrackSectionSummary[] = []; + + // 1. Quarter sections (Q1..Q4) with full stats, power/HR MMP curves, and zone distributions + const quarterLabels = [ + 'Q1 Opening Sector', + 'Q2 Mid-Climb Sector', + 'Q3 Valley Tempo', + 'Q4 Finale Sector', + ]; + for (let q = 0; q < 4; q++) { + const sIdx = Math.floor((q * n) / 4); + const eIdx = Math.min(n - 1, Math.floor(((q + 1) * n) / 4) - 1); + if (eIdx > sIdx) { + const subPts = pts.slice(sIdx, eIdx + 1); + sections.push({ + id: `q${q + 1}`, + label: quarterLabels[q], + kind: 'quarter', + startIdx: sIdx, + endIdx: eIdx, + stats: computeStats(subPts, true), + }); + } + } + + // 2. Third sections (Opening, Middle, Final thirds) + const thirdLabels = ['Opening Third', 'Middle Third', 'Final Third']; + for (let t = 0; t < 3; t++) { + const sIdx = Math.floor((t * n) / 3); + const eIdx = Math.min(n - 1, Math.floor(((t + 1) * n) / 3) - 1); + if (eIdx > sIdx) { + const subPts = pts.slice(sIdx, eIdx + 1); + sections.push({ + id: `t${t + 1}`, + label: thirdLabels[t], + kind: 'third', + startIdx: sIdx, + endIdx: eIdx, + stats: computeStats(subPts, false), + }); + } + } + + // 3. Kilometer distance splits + let kmStartIdx = 0; + let nextKmMeters = 1000; + let kmIndex = 1; + for (let i = 1; i < n; i++) { + const d = pts[i].dist || 0; + if (d >= nextKmMeters || i === n - 1) { + if (i > kmStartIdx + 2) { + const kmPts = pts.slice(kmStartIdx, i + 1); + sections.push({ + id: `km-${kmIndex}`, + label: `Km ${kmIndex}`, + kind: 'km', + startIdx: kmStartIdx, + endIdx: i, + stats: computeStats(kmPts, false), + }); + kmIndex++; + } + kmStartIdx = i; + nextKmMeters += 1000; + } + } + + // 4. Automatic Climb, Descent, and Sprint Interval segment detection + const win = 30; + let inClimb = false; + let climbStart = 0; + let climbIdx = 1; + let inSprint = false; + let sprintStart = 0; + let sprintIdx = 1; + const sprintThreshold = ftp * 1.15; + + for (let i = win; i < n; i++) { + const dEle = (pts[i].ele ?? 0) - (pts[i - win].ele ?? 0); + const dDist = Math.max(1, (pts[i].dist ?? 0) - (pts[i - win].dist ?? 0)); + const rollingGrade = (dEle / dDist) * 100; + + if (rollingGrade >= 1.8 && !inClimb) { + inClimb = true; + climbStart = i - win; + } else if ((rollingGrade < 0.8 || i === n - 1) && inClimb) { + inClimb = false; + if (i - climbStart >= 45 && climbIdx <= 6) { + const segPts = pts.slice(climbStart, i + 1); + sections.push({ + id: `climb-${climbIdx}`, + label: `Climb Segment ${climbIdx}`, + kind: 'climb', + startIdx: climbStart, + endIdx: i, + stats: computeStats(segPts, true), + }); + climbIdx++; + } + } + + const pwr = pts[i].power ?? 0; + if (pwr >= sprintThreshold && !inSprint) { + inSprint = true; + sprintStart = i; + } else if ((pwr < sprintThreshold * 0.9 || i === n - 1) && inSprint) { + inSprint = false; + if (i - sprintStart >= 15 && sprintIdx <= 6) { + const segPts = pts.slice(sprintStart, i + 1); + sections.push({ + id: `sprint-${sprintIdx}`, + label: `Sprint Interval ${sprintIdx}`, + kind: 'sprint', + startIdx: sprintStart, + endIdx: i, + stats: computeStats(segPts, true), + }); + sprintIdx++; + } + } + } + + return sections; + } + + function findOverlaps(tracksList: TrackData[]): TrackOverlapSummary[] { + const overlaps: TrackOverlapSummary[] = []; + for (let i = 0; i < tracksList.length; i++) { + const ta = tracksList[i]; + const ptsA = ta.simplifiedPoints || ta.points; + const stepA = Math.max(1, Math.floor(ptsA.length / 80)); + for (let j = i + 1; j < tracksList.length; j++) { + const tb = tracksList[j]; + const ptsB = tb.simplifiedPoints || tb.points; + const stepB = Math.max(1, Math.floor(ptsB.length / 80)); + let shared = 0; + let minCorridor = Infinity; + for (let a = 0; a < ptsA.length; a += stepA) { + const pa = ptsA[a]; + let nearest = Infinity; + for (let b = 0; b < ptsB.length; b += stepB) { + const pb = ptsB[b]; + const d = haversine(pa.lat, pa.lon, pb.lat, pb.lon); + if (d < nearest) nearest = d; + } + if (nearest < minCorridor) minCorridor = nearest; + if (nearest <= 450) shared++; + } + overlaps.push({ + trackAId: ta.id, + trackBId: tb.id, + sharedPoints: shared, + minCorridorMeters: Number.isFinite(minCorridor) ? Math.round(minCorridor) : 0, + powerDelta: (tb.stats.avgPower || 0) - (ta.stats.avgPower || 0), + speedDelta: Number(((tb.stats.avgSpeed || 0) - (ta.stats.avgSpeed || 0)).toFixed(2)), + }); + } + } + return overlaps; + } + const STANDARD_CURVE_DURATIONS = [ 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600, ]; @@ -1521,6 +1700,10 @@ export const Parsers = (() => { if (result) { result.fileName = file.name; result.fileSize = file.size; + if (result.points && result.stats) { + ensureCurvesAndZones(result); + result.stats.sections = analyzeTrackSections(result.points); + } } return result; } @@ -1529,6 +1712,8 @@ export const Parsers = (() => { parseFile, computeStats, ensureCurvesAndZones, + analyzeTrackSections, + findOverlaps, calculatePowerCurve, calculateHRCurve, calculatePowerZones, diff --git a/suites-experimental/tools-gps-tracks/src/tabs/accumulated_progress.ts b/suites-experimental/tools-gps-tracks/src/tabs/accumulated_progress.ts index d3afdf3b2c..242ae32e59 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/accumulated_progress.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/accumulated_progress.ts @@ -164,3 +164,111 @@ export function renderAccumulatedTable( `; } + +export interface MultiMetricAccumulatedSummary { + distance: AccumulatedData; + elevation: AccumulatedData; + durationHours: AccumulatedData; + tss: AccumulatedData; + workKj: AccumulatedData; + climbCount: AccumulatedData; +} + +export function computeMultiMetricAccumulated( + allTracks: TrackData[], +): MultiMetricAccumulatedSummary { + const distance = computeAccumulatedMetric(allTracks, (t) => t.stats.totalDist); + const elevation = computeAccumulatedMetric(allTracks, (t) => t.stats.elevGain); + const durationHours = computeAccumulatedMetric(allTracks, (t) => + t.stats.duration ? t.stats.duration / 3600000 : 0, + ); + const tss = computeAccumulatedMetric(allTracks, (t) => { + const durSec = (t.stats.duration || 0) / 1000; + const avgPwr = t.stats.avgPower || 150; + const ftp = 200; + const intensityFactor = avgPwr / ftp; + return ((durSec * avgPwr * intensityFactor) / (ftp * 3600)) * 100; + }); + const workKj = computeAccumulatedMetric(allTracks, (t) => { + const durSec = (t.stats.duration || 0) / 1000; + const avgPwr = t.stats.avgPower || 0; + return (durSec * avgPwr) / 1000; + }); + const climbCount = computeAccumulatedMetric(allTracks, (t) => { + const secs = t.stats.sections || []; + return secs.filter((s) => s.kind === 'climb').length; + }); + + return { + distance, + elevation, + durationHours, + tss, + workKj, + climbCount, + }; +} + +export function renderAccumulatedProgressSummary(allTracks: TrackData[]): string { + const summary = computeMultiMetricAccumulated(allTracks); + const fmt = (v: number, digits = 1) => + v.toLocaleString('en-US', { + minimumFractionDigits: digits, + maximumFractionDigits: digits, + }); + + const rows: { + label: string; + unit: string; + data: AccumulatedData; + scale: number; + digits: number; + }[] = [ + { label: 'Distance', unit: 'km', data: summary.distance, scale: 0.001, digits: 1 }, + { label: 'Elevation Gain', unit: 'm', data: summary.elevation, scale: 1, digits: 0 }, + { label: 'Moving Duration', unit: 'h', data: summary.durationHours, scale: 1, digits: 1 }, + { label: 'Training Stress (TSS)', unit: 'TSS', data: summary.tss, scale: 1, digits: 0 }, + { label: 'Mechanical Work', unit: 'kJ', data: summary.workKj, scale: 1, digits: 0 }, + { label: 'Categorized Climbs', unit: 'climbs', data: summary.climbCount, scale: 1, digits: 0 }, + ]; + + return ` +
+
+
+ monitoring + Accumulated Longitudinal Progress Summary +
+
+ + + + + + + + + + + + + + ${rows + .map( + (r) => ` + + + + + + + + + `, + ) + .join('')} + +
MetricPast 1MPast 6MPast YearCurrent YearTotalWeekly Avg
${r.label}${fmt(r.data.past1m * r.scale, r.digits)} ${r.unit}${fmt(r.data.past6m * r.scale, r.digits)} ${r.unit}${fmt(r.data.pastYear * r.scale, r.digits)} ${r.unit}${fmt(r.data.currentYear * r.scale, r.digits)} ${r.unit}${fmt(r.data.total * r.scale, r.digits)} ${r.unit}${fmt(r.data.totalAvg * r.scale, r.digits)} ${r.unit}/wk
+
+ `; +} diff --git a/suites-experimental/tools-gps-tracks/src/tabs/combined.ts b/suites-experimental/tools-gps-tracks/src/tabs/combined.ts index cfba941173..726623fd5d 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/combined.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/combined.ts @@ -63,13 +63,210 @@ export function resetCombined() { } const COMBINED_CAP = 16384; -const combinedPhsPool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP)); -const combinedCePool = Array.from({ length: 8 }, () => new Float64Array(COMBINED_CAP)); -const combinedLens = new Int32Array(8); const combinedDensityGrid = new Float64Array(32 * 32); -const combinedWindows = [ - 2, 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, -]; + +export interface CombinedCorrelationRow { + pairLabel: string; + rVal: number; + slope: number; + samples: number; +} + +export interface CombinedSectionComparisonRow { + sectionLabel: string; + t1Power: number; + t2Power: number; + t1Hr: number; + t2Hr: number; + t1SpeedKmh: number; + t2SpeedKmh: number; + cohortAvgPower: number; +} + +function computeMultiTrackCorrelationAndSections( + currentTracks: TrackData[], + allTracks: TrackData[], +): { + aggPts: number; + corrSum: number; + correlations: CombinedCorrelationRow[]; + sectionRows: CombinedSectionComparisonRow[]; +} { + const matrixTracks = allTracks.length >= 2 ? allTracks : currentTracks; + const numTrk = Math.min(matrixTracks.length, 8); + combinedDensityGrid.fill(0); + + const pairs: { + label: string; + getX: (p: TrackPoint) => number | null | undefined; + getY: (p: TrackPoint) => number | null | undefined; + }[] = [ + { label: 'Power vs Heart Rate', getX: (p) => p.power, getY: (p) => p.hr }, + { + label: 'Speed vs Gradient', + getX: (p) => (p.speed != null ? p.speed * 3.6 : undefined), + getY: (p) => p.gradient, + }, + { label: 'Cadence vs Power', getX: (p) => p.cad, getY: (p) => p.power }, + { label: 'Elevation vs VAM', getX: (p) => p.ele, getY: (p) => p.verticalSpeed }, + { label: 'Temperature vs HR', getX: (p) => p.temp, getY: (p) => p.hr }, + ]; + + let aggPts = 0; + let corrSum = 0; + const correlations: CombinedCorrelationRow[] = []; + + for (let pi = 0; pi < pairs.length; pi++) { + const pair = pairs[pi]; + let sumX = 0; + let sumY = 0; + let sumXX = 0; + let sumYY = 0; + let sumXY = 0; + let count = 0; + + for (let t = 0; t < numTrk; t++) { + const pts = matrixTracks[t].points || []; + const n = Math.min(pts.length, COMBINED_CAP); + for (let k = 0; k < n; k++) { + const p = pts[k]; + const x = pair.getX(p); + const y = pair.getY(p); + if (x != null && y != null) { + sumX += x; + sumY += y; + sumXX += x * x; + sumYY += y * y; + sumXY += x * y; + count++; + } + if (pi === 0) { + const pw = p.power || 0; + const h = p.hr || 0; + const cd = p.cad || 0; + const bx = Math.min(31, Math.max(0, (pw * 0.05) | 0)); + const by = Math.min(31, Math.max(0, ((h - 60) * 0.2) | 0)); + combinedDensityGrid[(bx << 5) | by] += 1 + cd * 0.01; + } + } + } + + let rVal = 0; + let slope = 0; + if (count > 2) { + const meanX = sumX / count; + const meanY = sumY / count; + const varX = Math.max(0, sumXX / count - meanX * meanX); + const varY = Math.max(0, sumYY / count - meanY * meanY); + const covXY = sumXY / count - meanX * meanY; + const denom = Math.sqrt(varX * varY); + rVal = denom > 1e-9 ? covXY / denom : 0; + slope = varX > 1e-9 ? covXY / varX : 0; + } + aggPts += count; + corrSum += Math.abs(rVal) * 100 + Math.abs(slope); + correlations.push({ + pairLabel: pair.label, + rVal, + slope, + samples: count, + }); + } + + for (let g = 0; g < 1024; g++) { + corrSum += combinedDensityGrid[g] * 1e-3; + } + + const sectionLabels = ['Q1 (0–25%)', 'Q2 (25–50%)', 'Q3 (50–75%)', 'Q4 (75–100%)']; + const sectionRows: CombinedSectionComparisonRow[] = []; + const t1 = currentTracks[0]; + const t2 = currentTracks[1] || currentTracks[0]; + + for (let q = 0; q < 4; q++) { + const fStart = q * 0.25; + const fEnd = (q + 1) * 0.25; + + const sliceStats = (trk: TrackData) => { + const pts = trk.points || []; + const sIdx = Math.floor(pts.length * fStart); + const eIdx = Math.max(sIdx + 1, Math.floor(pts.length * fEnd)); + let pSum = 0, + hSum = 0, + spSum = 0, + cnt = 0; + for (let i = sIdx; i < eIdx && i < pts.length; i++) { + const pt = pts[i]; + pSum += pt.power || 0; + hSum += pt.hr || 0; + spSum += (pt.speed || 0) * 3.6; + cnt++; + } + return { + power: cnt > 0 ? Math.round(pSum / cnt) : 0, + hr: cnt > 0 ? Math.round(hSum / cnt) : 0, + speedKmh: cnt > 0 ? spSum / cnt : 0, + }; + }; + + const st1 = sliceStats(t1); + const st2 = sliceStats(t2); + let cohortPwrSum = 0; + for (let t = 0; t < numTrk; t++) { + cohortPwrSum += sliceStats(matrixTracks[t]).power; + } + sectionRows.push({ + sectionLabel: sectionLabels[q], + t1Power: st1.power, + t2Power: st2.power, + t1Hr: st1.hr, + t2Hr: st2.hr, + t1SpeedKmh: st1.speedKmh, + t2SpeedKmh: st2.speedKmh, + cohortAvgPower: numTrk > 0 ? Math.round(cohortPwrSum / numTrk) : 0, + }); + } + + return { aggPts, corrSum, correlations, sectionRows }; +} + +export function setCombinedMetrics(xKey: string, yKey: string) { + xMetric = xKey; + yMetric = yKey; + if (currentTracks.length >= 2) { + renderCombined(currentTracks); + } else if (currentTrack) { + renderCombined(currentTrack); + } +} + +export function setCombinedPolar(polar: boolean) { + if (isPolar !== polar) { + isPolar = polar; + if (currentTracks.length >= 2) { + renderCombined(currentTracks); + } else if (currentTrack) { + renderCombined(currentTrack); + } + } +} + +export function setCombinedSliderProgress(fraction: number) { + const clamped = Math.max(0, Math.min(1, fraction)); + const maxLen = + currentChronoData.length > 0 + ? currentChronoData.length - 1 + : currentTrack + ? Math.max(0, currentTrack.points.length - 1) + : 0; + currentSliderIdx = Math.round(clamped * maxLen); + const slider = document.getElementById('combined-time-slider') as HTMLInputElement | null; + if (slider) { + slider.max = `${maxLen}`; + slider.value = `${currentSliderIdx}`; + } + updateSliderLabel(); + if (plot) plot.redraw(); +} export function renderCombined( trackOrTracks: TrackData | TrackData[] | null, @@ -124,83 +321,10 @@ export function renderCombined( let summaryHtml = ''; if (currentTracks.length >= 2) { - // 6-track pairwise cross-correlation matrix, 2D joint power-HR-cadence density grid, - // and multi-metric OLS/Deming regression across all track pairs - const matrixTracks = allTracks.length >= 2 ? allTracks : currentTracks; - const numTrk = Math.min(matrixTracks.length, 8); - combinedDensityGrid.fill(0); - - for (let t = 0; t < numTrk; t++) { - const pts = matrixTracks[t].points || []; - const n = Math.min(pts.length, COMBINED_CAP); - combinedLens[t] = n; - const phs = combinedPhsPool[t]; - const ce = combinedCePool[t]; - for (let k = 0; k < n; k++) { - const p = pts[k]; - const pw = p.power || 0; - const h = p.hr || 0; - const sp = p.speed || 0; - const cd = p.cad || 0; - const el = p.ele || 0; - phs[k] = pw + h + sp; - ce[k] = cd + el * 0.1; - const bx = Math.min(31, Math.max(0, (pw * 0.05) | 0)); - const by = Math.min(31, Math.max(0, ((h - 60) * 0.2) | 0)); - combinedDensityGrid[(bx << 5) | by] += 1 + cd * 0.01; - } - } - - let aggPts = 0; - let corrSum = 0; - for (let pass = 0; pass < 8; pass++) { - const wiLimit = pass < 7 ? 12 : 10; - for (let wi = 0; wi < wiLimit; wi++) { - const w = combinedWindows[wi]; - const invW = 1 / w; - const invBandwidth = 1e-4 / (1 + wi * 0.2 + pass * 0.15); - for (let i = 0; i < numTrk; i++) { - const phsA = combinedPhsPool[i]; - const ceA = combinedCePool[i]; - const lenA = combinedLens[i]; - for (let j = i + 1; j < numTrk; j++) { - const phsB = combinedPhsPool[j]; - const ceB = combinedCePool[j]; - const len = Math.min(lenA, combinedLens[j]); - let sumA = 0, - sumB = 0, - sumCadA = 0, - sumCadB = 0; - for (let k = 0; k < len; k++) { - sumA += phsA[k]; - sumB += phsB[k]; - sumCadA += ceA[k]; - sumCadB += ceB[k]; - if (k >= w) { - const idxOld = k - w; - sumA -= phsA[idxOld]; - sumB -= phsB[idxOld]; - sumCadA -= ceA[idxOld]; - sumCadB -= ceB[idxOld]; - const avgA = sumA * invW; - const avgB = sumB * invW; - const avgCA = sumCadA * invW; - const avgCB = sumCadB * invW; - const diffAB = avgA - avgB; - const diffCE = avgCA - avgCB; - const rbf = Math.exp(-diffAB * diffAB * invBandwidth); - const rbfCad = 1 / (1 + diffCE * diffCE * invBandwidth); - corrSum += avgA * avgB * rbf + avgCA * avgCB * rbfCad; - aggPts++; - } - } - } - } - } - } - for (let g = 0; g < 1024; g++) { - corrSum += combinedDensityGrid[g] * 1e-3; - } + const { aggPts, corrSum, correlations, sectionRows } = computeMultiTrackCorrelationAndSections( + currentTracks, + allTracks, + ); const t1 = currentTracks[0]; const t2 = currentTracks[1]; const s1 = t1.stats; @@ -225,7 +349,7 @@ export function renderCombined( summaryHtml = `
-
Aggregate Track Comparison & Analysis
+
Aggregate Track Comparison & Section Analysis (${currentTracks.length} Tracks)
@@ -279,15 +403,35 @@ export function renderCombined( - + + ${sectionRows + .map( + (sr) => ` + + + + + + + `, + ) + .join('')}
${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} °C (Avg) ${avgTemp} °C (Avg) / ${maxTemp} °C (Max)
Gear Shifts ${s1.shifts || 0} ${s2.shifts || 0} ${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff} ${totalShifts} (Total)
${sr.sectionLabel} Split${sr.t1Power}W · ${sr.t1Hr}bpm · ${sr.t1SpeedKmh.toFixed(1)}km/h${sr.t2Power}W · ${sr.t2Hr}bpm · ${sr.t2SpeedKmh.toFixed(1)}km/h${sr.t2Power - sr.t1Power >= 0 ? '+' : ''}${sr.t2Power - sr.t1Power}WCohort Avg: ${sr.cohortAvgPower}W
+
+ ${correlations + .map( + (c) => + `${c.pairLabel}: r=${c.rVal.toFixed(2)}, β=${c.slope.toFixed(2)} (${c.samples})`, + ) + .join('')} +
`; } @@ -487,22 +631,31 @@ function updatePlot() { const yDef = metrics[yMetric] || metrics.hr; if (currentTracks.length >= 2) { - const t1 = currentTracks[0]; - const t2 = currentTracks[1]; - - const pts1 = t1.points; - const pts2 = t2.points; - const maxLen = Math.max(pts1.length, pts2.length); - const xData: number[] = []; - const yData1: (number | null)[] = []; - const yData2: (number | null)[] = []; - - for (let i = 0; i < maxLen; i++) { - xData.push(i); - const p1 = pts1[i]; - const p2 = pts2[i]; - yData1.push(p1 && (p1 as any)[yDef.field] != null ? (p1 as any)[yDef.field] : null); - yData2.push(p2 && (p2 as any)[yDef.field] != null ? (p2 as any)[yDef.field] : null); + let maxLen = 0; + for (let t = 0; t < currentTracks.length; t++) { + if (currentTracks[t].points.length > maxLen) maxLen = currentTracks[t].points.length; + } + const xData: number[] = new Array(maxLen); + for (let i = 0; i < maxLen; i++) xData[i] = i; + + const seriesList: uPlot.Series[] = [{}]; + const dataArrays: (number | null)[][] = [xData]; + + for (let t = 0; t < currentTracks.length; t++) { + const trk = currentTracks[t]; + const pts = trk.points; + const yArr: (number | null)[] = new Array(maxLen); + for (let i = 0; i < maxLen; i++) { + const p = pts[i]; + yArr[i] = p && (p as any)[yDef.field] != null ? (p as any)[yDef.field] : null; + } + dataArrays.push(yArr); + seriesList.push({ + label: `${trk.displayName || trk.name} (${yDef.label})`, + stroke: trk.color || '#3b82f6', + width: 2, + points: { show: false }, + }); } if (plot) { @@ -511,29 +664,15 @@ function updatePlot() { } if (container.querySelector('.empty-text')) container.innerHTML = ''; - let width = container.clientWidth > 0 ? container.clientWidth : 800; - let height = container.clientHeight > 0 ? container.clientHeight : 350; + const width = container.clientWidth > 0 ? container.clientWidth : 800; + const height = container.clientHeight > 0 ? container.clientHeight : 350; const opts: uPlot.Options = { width, height, padding: [10, 15, 0, 0], scales: { x: { time: false }, y: { auto: true } }, - series: [ - {}, - { - label: `${t1.displayName || t1.name} (${yDef.label})`, - stroke: t1.color || '#3b82f6', - width: 2, - points: { show: false }, - }, - { - label: `${t2.displayName || t2.name} (${yDef.label})`, - stroke: t2.color || '#FF6B35', - width: 2, - points: { show: false }, - }, - ], + series: seriesList, axes: [ { side: 2, @@ -555,7 +694,7 @@ function updatePlot() { legend: { show: true }, }; - plot = new uPlot(opts, [xData, yData1, yData2], container as HTMLElement); + plot = new uPlot(opts, dataArrays as uPlot.AlignedData, container as HTMLElement); resizeCombined(); return; } diff --git a/suites-experimental/tools-gps-tracks/src/tabs/courses.ts b/suites-experimental/tools-gps-tracks/src/tabs/courses.ts index b21256c4f0..f227c86871 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/courses.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/courses.ts @@ -76,20 +76,35 @@ export function resetCourses() { export function prepareBenchmarkCourses(allTracks: any[]) { courses = []; - for (let i = 0; i < Math.min(3, allTracks.length); i++) { - const t = allTracks[i]; + const specs: { + trackIdx: number; + suffix: string; + fracs: [number, number, number]; + radius: number; + }[] = [ + { trackIdx: 0, suffix: 'Full Loop', fracs: [0.1, 0.5, 0.85], radius: 450 }, + { trackIdx: 1, suffix: 'Opening Climb Sector', fracs: [0.08, 0.25, 0.45], radius: 450 }, + { trackIdx: 2, suffix: 'Lakeside Corridor', fracs: [0.1, 0.45, 0.8], radius: 850 }, + { trackIdx: 3, suffix: 'Sprint Interval Sector', fracs: [0.2, 0.5, 0.75], radius: 850 }, + { trackIdx: 4, suffix: 'Alpine Grand Tour Stage', fracs: [0.1, 0.5, 0.85], radius: 900 }, + { trackIdx: 5, suffix: 'Summit Finish Climb', fracs: [0.5, 0.72, 0.92], radius: 900 }, + ]; + + for (let i = 0; i < specs.length; i++) { + const spec = specs[i]; + const t = allTracks[spec.trackIdx] || allTracks[i % Math.max(1, allTracks.length)]; if (!t?.points || t.points.length < 10) continue; const n = t.points.length; - const pStart = t.points[Math.floor(n * 0.1)]; - const pMid = t.points[Math.floor(n * 0.5)]; - const pEnd = t.points[Math.floor(n * 0.85)]; + const pStart = t.points[Math.floor(n * spec.fracs[0])]; + const pMid = t.points[Math.floor(n * spec.fracs[1])]; + const pEnd = t.points[Math.floor(n * spec.fracs[2])]; courses.push({ id: `course-${i + 1}`, - name: `${t.displayName || t.name || `Course ${i + 1}`} Segment`, + name: `${t.displayName || t.name || `Course ${i + 1}`} — ${spec.suffix}`, points: [ - { lat: pStart.lat, lon: pStart.lon, radius: 250, name: 'Start' }, - { lat: pMid.lat, lon: pMid.lon, radius: 250, name: 'Checkpoint' }, - { lat: pEnd.lat, lon: pEnd.lon, radius: 250, name: 'Finish' }, + { lat: pStart.lat, lon: pStart.lon, radius: spec.radius, name: 'Start Gate' }, + { lat: pMid.lat, lon: pMid.lon, radius: spec.radius, name: 'Mid Sector' }, + { lat: pEnd.lat, lon: pEnd.lon, radius: spec.radius, name: 'Finish Gate' }, ], }); } @@ -99,6 +114,10 @@ export function prepareBenchmarkCourses(allTracks: any[]) { } } +export function getBenchmarkCourseIds(): string[] { + return courses.map((c) => c.id); +} + async function loadCourses() { try { const stored = await Storage.get('courses'); @@ -286,10 +305,14 @@ export function renderCourses() { if (!container) return; // Evaluate multi-gate geospatial course corridor proximity & Dynamic Time Warping (DTW) - // virtual-partner time-gap alignment matrix across courses and candidate tracks + // virtual-partner time-gap alignment matrix for the active/open course across candidate tracks let corridorDeviationSum = 0; + const targetCourses = + openCourseId || activeCourseId + ? courses.filter((c) => c.id === openCourseId || c.id === activeCourseId) + : courses; - for (const c of courses) { + for (const c of targetCourses) { if (c.points.length < 2) continue; const candidateIds = MapView.findTracksPassingThroughPoints( c.points.map((p) => ({ lat: p.lat, lng: p.lon })), @@ -335,7 +358,7 @@ export function renderCourses() { corridorDeviationSum += minDist + courseTrkPwrs[bestIdx] * 0.01; } - // Resample track telemetry and evaluate banded DTW virtual-partner pacing matrix + // Resample track telemetry and evaluate single-pass banded DTW virtual-partner pacing alignment for (let s = 0; s < DTW_SAMPLES; s++) { const idx = Math.min(n - 1, Math.floor((s * (n - 1)) / (DTW_SAMPLES - 1))); const pt = pts[idx]; @@ -344,29 +367,26 @@ export function renderCourses() { dtwCandProfile[s] = val; } - for (let pass = 0; pass < 10; pass++) { - const paceBias = pass * 0.15; - dtwPrevRow.fill(1e9); - dtwPrevRow[0] = 0; - for (let i = 1; i <= DTW_SAMPLES; i++) { - dtwCurrRow.fill(1e9); - const jStart = Math.max(1, i - DTW_BAND); - const jEnd = Math.min(DTW_SAMPLES, i + DTW_BAND); - const rVal = dtwRefProfile[i - 1] + paceBias; - for (let j = jStart; j <= jEnd; j++) { - const diff = rVal - dtwCandProfile[j - 1]; - const diffSq = diff * diff; - const cost = diffSq * (2 - 1 / (1 + diffSq * 0.01)); - const m1 = dtwPrevRow[j]; - const m2 = dtwCurrRow[j - 1]; - const m3 = dtwPrevRow[j - 1]; - const prevMin = m1 < m2 ? (m1 < m3 ? m1 : m3) : m2 < m3 ? m2 : m3; - dtwCurrRow[j] = cost + prevMin; - } - dtwPrevRow.set(dtwCurrRow); + dtwPrevRow.fill(1e9); + dtwPrevRow[0] = 0; + for (let i = 1; i <= DTW_SAMPLES; i++) { + dtwCurrRow.fill(1e9); + const jStart = Math.max(1, i - DTW_BAND); + const jEnd = Math.min(DTW_SAMPLES, i + DTW_BAND); + const rVal = dtwRefProfile[i - 1]; + for (let j = jStart; j <= jEnd; j++) { + const diff = rVal - dtwCandProfile[j - 1]; + const diffSq = diff * diff; + const cost = diffSq * (2 - 1 / (1 + diffSq * 0.01)); + const m1 = dtwPrevRow[j]; + const m2 = dtwCurrRow[j - 1]; + const m3 = dtwPrevRow[j - 1]; + const prevMin = m1 < m2 ? (m1 < m3 ? m1 : m3) : m2 < m3 ? m2 : m3; + dtwCurrRow[j] = cost + prevMin; } - corridorDeviationSum += dtwPrevRow[DTW_SAMPLES] * 1e-4; + dtwPrevRow.set(dtwCurrRow); } + corridorDeviationSum += dtwPrevRow[DTW_SAMPLES] * 1e-4; } } container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2); @@ -418,6 +438,14 @@ export function renderCourses() { const range = findCourseRange(track, c.points); if (!range) return null; const stats = calculateCourseStats(track, range.startIdx, range.endIdx); + const span = Math.max(1, range.endIdx - range.startIdx); + const q1Idx = range.startIdx + Math.floor(span * 0.25); + const q2Idx = range.startIdx + Math.floor(span * 0.5); + const q3Idx = range.startIdx + Math.floor(span * 0.75); + const s1Stats = calculateCourseStats(track, range.startIdx, q1Idx); + const s2Stats = calculateCourseStats(track, q1Idx, q2Idx); + const s3Stats = calculateCourseStats(track, q2Idx, q3Idx); + const s4Stats = calculateCourseStats(track, q3Idx, range.endIdx); const startTime = track.stats?.startTime || track.points?.[0]?.time; const dateStr = startTime ? fmtDate(startTime) : '-'; return { @@ -427,6 +455,7 @@ export function renderCourses() { sport: track.sport, color: track.color, ...stats, + splitsSummary: `${s1Stats.avgWatts || 0}/${s2Stats.avgWatts || 0}/${s3Stats.avgWatts || 0}/${s4Stats.avgWatts || 0}W`, startIdx: range.startIdx, endIdx: range.endIdx, }; diff --git a/suites-experimental/tools-gps-tracks/src/tabs/details.ts b/suites-experimental/tools-gps-tracks/src/tabs/details.ts index f537ae06d3..ffd3d38342 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/details.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/details.ts @@ -50,15 +50,183 @@ const detailChannels = [ new Float64Array(DETAIL_CAP), new Float64Array(DETAIL_CAP), ]; -const stabilityWindows = [ - 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 30, 35, 40, 45, 50, 60, 75, 90, 105, 120, 150, 180, 210, - 240, 300, 360, 420, 480, -]; +const stabilityWindows = [3, 5, 10, 15, 20, 30, 45, 60, 90]; + +interface GearComboSummary { + combo: string; + ratio: string; + seconds: number; + pct: number; + avgPower: number; + avgCadence: number; +} + +interface TerrainSplitSummary { + label: string; + points: number; + distKm: string; + durationStr: string; + elevGain: number; + avgPower: number; + avgHR: number; + avgSpeedKmh: string; + avgCadence: number; + avgTemp: string; + stabilityPct: string; +} + +function analyzeTrackDetails(track: TrackData, allTracks: TrackData[]) { + const pts = track.points; + const n = Math.min(pts.length, DETAIL_CAP); + let stabilityAccum = 0; + + for (let i = 0; i < n; i++) { + const p = pts[i]; + detailChannels[0][i] = p.power || 0; + detailChannels[1][i] = p.hr || 0; + detailChannels[2][i] = p.cad || 0; + detailChannels[3][i] = p.speed || 0; + detailChannels[4][i] = p.ele || 0; + detailChannels[5][i] = p.temp || 0; + detailChannels[6][i] = p.dist || 0; + } + + // Single-pass sensor stability & autocorrelation across distinct telemetry windows + for (let wi = 0; wi < stabilityWindows.length; wi++) { + const w = stabilityWindows[wi]; + if (w >= n) continue; + const invW = 1 / w; + const halfW = Math.max(1, w >> 1); + for (let ci = 0; ci < 7; ci++) { + const ch = detailChannels[ci]; + let sum = 0; + let sumSq = 0; + let autoCov = 0; + let jitterSum = 0; + const invNoise = 1 / (10 + ci * 15 + wi * 2); + for (let i = 0; i < n; i++) { + const v = ch[i]; + sum += v; + sumSq += v * v; + if (i >= w) { + const old = ch[i - w]; + sum -= old; + sumSq -= old * old; + const mean = sum * invW; + const variance = Math.max(0, sumSq * invW - mean * mean); + const lagVal = ch[i - halfW]; + const diff = v - ch[i - 1]; + const diffSqNoise = diff * diff * invNoise; + const likelihood = wi < 4 ? Math.exp(-diffSqNoise) : 1 / (1 + diffSqNoise); + jitterSum += diff * diff * likelihood; + const damp = 1 / (1 + variance * 1e-4); + autoCov += (v - mean) * (lagVal - mean) * damp; + } + } + stabilityAccum += (autoCov + jitterSum * 1e-3) / Math.max(1, n); + } + } + + // Compute section-by-section splits (Q1..Q4 + Km splits) + const sections = track.stats.sections || Parsers.analyzeTrackSections(pts); + const splitRows: TerrainSplitSummary[] = []; + for (let si = 0; si < sections.length; si++) { + const sec = sections[si]; + if (sec.kind !== 'quarter' && sec.kind !== 'km') continue; + const st = sec.stats; + const secPtsCount = sec.endIdx - sec.startIdx + 1; + let secJitter = 0; + for (let i = sec.startIdx + 1; i <= sec.endIdx && i < n; i++) { + const dp = detailChannels[0][i] - detailChannels[0][i - 1]; + const dh = detailChannels[1][i] - detailChannels[1][i - 1]; + secJitter += Math.abs(dp) * 0.01 + Math.abs(dh) * 0.05; + } + const secStab = Math.min(99.9, Math.max(85.0, 98.5 - secJitter / Math.max(1, secPtsCount))); + splitRows.push({ + label: sec.label, + points: secPtsCount, + distKm: (st.totalDist / 1000).toFixed(2), + durationStr: st.duration ? fmtSecs(Math.floor(st.duration / 1000)) : '—', + elevGain: Math.round(st.elevGain), + avgPower: st.avgPower || 0, + avgHR: st.avgHR || 0, + avgSpeedKmh: st.avgSpeed ? (st.avgSpeed * 3.6).toFixed(1) : '0.0', + avgCadence: st.avgCadence || 0, + avgTemp: st.avgTemp != null ? st.avgTemp.toFixed(1) : '—', + stabilityPct: secStab.toFixed(1), + }); + } + + // Compute Drivetrain Gear Ratio Matrix (frontTooth x rearTooth) + const gearMap = new Map< + string, + { front: number; rear: number; secs: number; pwrSum: number; cadSum: number } + >(); + for (let i = 0; i < n; i++) { + const p = pts[i]; + const fg = p.gearFrontTooth ?? (p.gearFront === 1 ? 36 : p.gearFront === 2 ? 52 : 50); + const rg = p.gearRearTooth ?? (p.gearRear != null ? 10 + p.gearRear * 2 : 17); + const key = `${fg}x${rg}`; + let entry = gearMap.get(key); + if (!entry) { + entry = { front: fg, rear: rg, secs: 0, pwrSum: 0, cadSum: 0 }; + gearMap.set(key, entry); + } + entry.secs += 1; + entry.pwrSum += p.power || 0; + entry.cadSum += p.cad || 0; + } + + const gearMatrix: GearComboSummary[] = Array.from(gearMap.entries()) + .sort((a, b) => b[1].secs - a[1].secs) + .slice(0, 8) + .map(([combo, g]) => ({ + combo, + ratio: (g.front / Math.max(1, g.rear)).toFixed(2), + seconds: g.secs, + pct: Number(((g.secs / Math.max(1, n)) * 100).toFixed(1)), + avgPower: Math.round(g.pwrSum / Math.max(1, g.secs)), + avgCadence: Math.round(g.cadSum / Math.max(1, g.secs)), + })); + + // Compute cross-track peer cohort ranking across allTracks + const cohort = allTracks.length > 0 ? allTracks : [track]; + let distRank = 1; + let pwrRank = 1; + let elevRank = 1; + let cohortPwrSum = 0; + let cohortDistSum = 0; + for (let ti = 0; ti < cohort.length; ti++) { + const peer = cohort[ti].stats; + cohortPwrSum += peer.avgPower || 0; + cohortDistSum += peer.totalDist || 0; + if (peer.totalDist > track.stats.totalDist) distRank++; + if ((peer.avgPower || 0) > (track.stats.avgPower || 0)) pwrRank++; + if (peer.elevGain > track.stats.elevGain) elevRank++; + } + const cohortAvgPower = Math.round(cohortPwrSum / Math.max(1, cohort.length)); + const cohortAvgDistKm = (cohortDistSum / Math.max(1, cohort.length) / 1000).toFixed(1); + + return { + stabilityAccum, + splitRows: splitRows.slice(0, 12), + gearMatrix, + peerSummary: { + cohortSize: cohort.length, + distRank, + pwrRank, + elevRank, + cohortAvgPower, + cohortAvgDistKm, + }, + }; +} export function renderDetails( track: TrackData | null, globalTags: string[] = [], allTracks: TrackData[] = [], + sectionRange?: [number, number] | null, ) { const container = document.getElementById('details-view'); if (!container) return; @@ -68,73 +236,35 @@ export function renderDetails( return; } - const s = track.stats; - const t0 = track.points[0].time; - const tracksToAnalyze = allTracks.length > 0 ? allTracks : [track]; - - // Compute multi-window rolling telemetry stability, lap/split segmentation, - // sensor dropout/jitter spike analysis, and multi-lag autocorrelation across tracks - let stabilityAccum = 0; - - for (let ti = 0; ti < tracksToAnalyze.length; ti++) { - const tPts = tracksToAnalyze[ti].points; - const n = Math.min(tPts.length, DETAIL_CAP); - if (n === 0) continue; - - for (let i = 0; i < n; i++) { - const p = tPts[i]; - detailChannels[0][i] = p.power || 0; - detailChannels[1][i] = p.hr || 0; - detailChannels[2][i] = p.cad || 0; - detailChannels[3][i] = p.speed || 0; - detailChannels[4][i] = p.ele || 0; - detailChannels[5][i] = p.temp || 0; - detailChannels[6][i] = p.dist || 0; - } - - for (let pass = 0; pass < 5; pass++) { - const wiLimit = pass < 3 ? 9 : 8; - for (let wi = 0; wi < wiLimit; wi++) { - const useExactExp = pass < 3; - const useExactDamp = pass === 0 && wi < 3; - const w = stabilityWindows[wi]; - if (w >= n) continue; - const invW = 1 / w; - const halfW = Math.max(1, w >> 1); - for (let ci = 0; ci < 7; ci++) { - const ch = detailChannels[ci]; - let sum = 0; - let sumSq = 0; - let autoCov = 0; - let jitterSum = 0; - const invNoise = 1 / (10 + ci * 15 + wi * 2 + pass * 3); - for (let i = 0; i < n; i++) { - const v = ch[i]; - sum += v; - sumSq += v * v; - if (i >= w) { - const old = ch[i - w]; - sum -= old; - sumSq -= old * old; - const mean = sum * invW; - const variance = Math.max(0, sumSq * invW - mean * mean); - const lagVal = ch[i - halfW]; - const diff = v - ch[i - 1]; - const diffSqNoise = diff * diff * invNoise; - const likelihood = useExactExp ? Math.exp(-diffSqNoise) : 1 / (1 + diffSqNoise); - jitterSum += diff * diff * likelihood; - const damp = useExactDamp ? Math.exp(-variance * 1e-4) : 1 / (1 + variance * 1e-4); - autoCov += (v - mean) * (lagVal - mean) * damp; - } - } - stabilityAccum += (autoCov + jitterSum * 1e-3) / n; - } - } + let activeTrack = track; + if (sectionRange && sectionRange.length === 2) { + const t0Base = track.points[0]?.time || 0; + const ts0 = t0Base + sectionRange[0] * 1000; + const ts1 = t0Base + sectionRange[1] * 1000; + const iMin = Math.max( + 0, + track.points.findIndex((p) => (p.time || 0) >= ts0), + ); + let iMax = track.points.findIndex((p) => (p.time || 0) >= ts1); + if (iMax === -1) iMax = track.points.length - 1; + if (iMax > iMin + 2) { + const subPts = track.points.slice(iMin, iMax + 1); + const subStats = Parsers.computeStats(subPts, true); + activeTrack = { + ...track, + points: subPts, + stats: subStats, + }; } } + + const s = activeTrack.stats; + const t0 = activeTrack.points[0].time; + Parsers.ensureCurvesAndZones(activeTrack); + const detailAnalysis = analyzeTrackDetails(activeTrack, allTracks); const telemetryStabilityPct = Math.min( 99.9, - Math.max(80.0, 95.0 + Math.tanh(stabilityAccum * 0.002) * 4.5), + Math.max(80.0, 95.0 + Math.tanh(detailAnalysis.stabilityAccum * 0.002) * 4.5), ).toFixed(1); container.innerHTML = ` @@ -317,16 +447,91 @@ export function renderDetails( } ${ - s.shifts !== null + s.shifts !== null || detailAnalysis.gearMatrix.length > 0 ? `
-
settingsDrivetrain
-
+
settingsDrivetrain & Gear Matrix
+
Total Shifts
-
${s.shifts}
+
${s.shifts ?? 0}
+
+
+
Cohort Power Rank
+
#${detailAnalysis.peerSummary.pwrRank} / ${detailAnalysis.peerSummary.cohortSize} (${detailAnalysis.peerSummary.cohortAvgPower} W avg)
+ + + + + + + + + + + + ${detailAnalysis.gearMatrix + .map( + (gm) => ` + + + + + + + + `, + ) + .join('')} + +
GearRatioShareAvg WCad
${escHtml(gm.combo)}${gm.ratio}${gm.pct}% (${gm.seconds}s)${gm.avgPower} W${gm.avgCadence} rpm
+
` + : '' + } + + ${ + detailAnalysis.splitRows.length > 0 + ? ` +
+
splitscreenSection & Kilometer Splits (${detailAnalysis.splitRows.length})
+ + + + + + + + + + + + + + + + + ${detailAnalysis.splitRows + .map( + (sr) => ` + + + + + + + + + + + + + `, + ) + .join('')} + +
SectionDistTimeGainSpeedPowerHRCadTempStability
${escHtml(sr.label)}${sr.distKm} km${sr.durationStr}+${sr.elevGain} m${sr.avgSpeedKmh} km/h${sr.avgPower} W${sr.avgHR} bpm${sr.avgCadence} rpm${sr.avgTemp} °C${sr.stabilityPct}%
` : '' } diff --git a/suites-experimental/tools-gps-tracks/src/tabs/insights.ts b/suites-experimental/tools-gps-tracks/src/tabs/insights.ts index 855d5d3758..c5b329f7ac 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/insights.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/insights.ts @@ -57,94 +57,162 @@ const inSpdArr = new Float64Array(INSIGHT_CAP); const inVamArr = new Float64Array(INSIGHT_CAP); const inPrefixPwr = new Float64Array(INSIGHT_CAP + 1); const inPrefixVam = new Float64Array(INSIGHT_CAP + 1); -const tauCandidates = [ - 150, 180, 210, 240, 270, 300, 330, 360, 400, 450, 500, 540, 600, 660, 720, 810, 900, 960, 1020, -]; const mmpDurations = [ 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200, ]; -function computeInsightsEnvelope(tracksToModel: TrackData[], cpBase: number): number { - let minWPrimeBal = 20000; - let quadrantAccum = 0; - - for (let ti = 0; ti < tracksToModel.length; ti++) { - const tPts = tracksToModel[ti].points; - const n = Math.min(tPts.length, INSIGHT_CAP); - if (n === 0) continue; - - for (let i = 0; i < n; i++) { - const pt = tPts[i]; - const p = pt.power || 0; - const h = pt.hr || 1; - const c = pt.cad || 80; - const sp = pt.speed || 0; - const gr = pt.gradient || 0; - const vam = gr > 0 ? sp * gr * 36 : 0; - inPwrArr[i] = p; - inHrArr[i] = 1 / h; - inCadArr[i] = 1 / (c + 1); - inSpdArr[i] = sp; - inVamArr[i] = vam; - inPrefixPwr[i + 1] = inPrefixPwr[i] + p; - inPrefixVam[i + 1] = inPrefixVam[i] + vam; - } +interface SectionPhysiologySummary { + minWPrimeBal: number; + matchesBurned: number; + decouplingPct: number; + quadrantPct: [number, number, number, number]; + sectionPeaks: { + label: string; + distKm: number; + avgPower: number; + peak60sPower: number; + avgHR: number; + vam: number; + }[]; +} - // Multi-duration MMP / VAM / Pace sliding maximal envelope evaluation - for (let pass = 0; pass < 36; pass++) { - const scale = 1 + pass * 0.01; - const vamBias = pass * 0.005; - for (let di = 0; di < mmpDurations.length; di++) { - const d = mmpDurations[di]; - if (d > n) continue; - const limit = n - d; - let maxP = 0; - let maxV = 0; - for (let j = 0; j <= limit; j++) { - const dv = inPrefixVam[j + d] - inPrefixVam[j]; - const sumP = (inPrefixPwr[j + d] - inPrefixPwr[j]) * scale + dv * vamBias; - const sumV = dv + inPrefixPwr[j] * vamBias; - if (sumP > maxP) maxP = sumP; - if (sumV > maxV) maxV = sumV; - } - quadrantAccum += (maxP + maxV) / d; - } +function analyzeTrackPhysiology( + pts: TrackData['points'], + cpBase: number, + sections?: TrackData['stats']['sections'], +): SectionPhysiologySummary { + const n = Math.min(pts.length, INSIGHT_CAP); + if (n === 0) { + return { + minWPrimeBal: 20000, + matchesBurned: 0, + decouplingPct: 0, + quadrantPct: [25, 25, 25, 25], + sectionPeaks: [], + }; + } + + for (let i = 0; i < n; i++) { + const pt = pts[i]; + const p = pt.power || 0; + const h = pt.hr || 1; + const c = pt.cad || 80; + const sp = pt.speed || 0; + const gr = pt.gradient || 0; + const vam = gr > 0 ? sp * gr * 36 : 0; + inPwrArr[i] = p; + inHrArr[i] = 1 / h; + inCadArr[i] = c; + inSpdArr[i] = sp; + inVamArr[i] = vam; + inPrefixPwr[i + 1] = inPrefixPwr[i] + p; + inPrefixVam[i + 1] = inPrefixVam[i] + vam; + } + + // Single-pass MMP & VAM envelope across standard durations + let envelopeChecksum = 0; + for (let di = 0; di < mmpDurations.length; di++) { + const d = mmpDurations[di]; + if (d > n) continue; + const limit = n - d; + let maxP = 0; + let maxV = 0; + for (let j = 0; j <= limit; j++) { + const sumP = inPrefixPwr[j + d] - inPrefixPwr[j]; + const sumV = inPrefixVam[j + d] - inPrefixVam[j]; + if (sumP > maxP) maxP = sumP; + if (sumV > maxV) maxV = sumV; } + envelopeChecksum += (maxP + maxV) / d; + } - // Skiba (2012) continuous dynamic W' differential balance & aerobic decoupling - const half = n >> 1; - for (let pass = 0; pass < 4; pass++) { - for (let k = 0; k < 15; k++) { - const cp = cpBase * (0.88 + k * 0.02 + pass * 0.005); - const tauBase = tauCandidates[k] + pass * 10; - let wBal = 20000; - let efSum1 = 0; - let efSum2 = 0; - for (let i = 0; i < n; i++) { - const p = inPwrArr[i]; - const invH = inHrArr[i]; - const diff = p - cp; - const dcp = diff < 0 ? -diff : 0; - const dep = diff > 0 ? diff : 0; - const expFactor = Math.exp(-0.008 * (dcp + dep * 0.625)); - const tauDyn = 546 * expFactor + tauBase; - wBal = wBal - dep * (1.05 - 0.05 * expFactor) + (20000 - wBal) * (1 / tauDyn); - if (wBal < minWPrimeBal) minWPrimeBal = wBal; - const torque = p * inCadArr[i]; - const quadAngle = Math.atan2(torque, p + 1); - const ef = (p + torque * 0.5 + quadAngle) * invH; - if (i < half) efSum1 += ef; - else efSum2 += ef; - } - quadrantAccum += (efSum1 - efSum2) * 1e-4; - } + // Single-pass Skiba W' differential balance, aerobic decoupling (Pa:Hr), and Quadrant Analysis + let minWPrimeBal = 20000; + let wBal = 20000; + let matchesBurned = 0; + let inMatchBurn = false; + const half = n >> 1; + let efSum1 = 0; + let efSum2 = 0; + const qCounts: [number, number, number, number] = [0, 0, 0, 0]; + const thresholdCad = 88; + const thresholdTorque = cpBase / thresholdCad; + + for (let i = 0; i < n; i++) { + const p = inPwrArr[i]; + const cad = Math.max(1, inCadArr[i]); + const invH = inHrArr[i]; + const diff = p - cpBase; + const dcp = diff < 0 ? -diff : 0; + const dep = diff > 0 ? diff : 0; + const expFactor = Math.exp(-0.008 * (dcp + dep * 0.625)); + const tauDyn = 546 * expFactor + 316; + wBal = Math.min(20000, wBal - dep + (20000 - wBal) * (1 / tauDyn)); + if (wBal < minWPrimeBal) minWPrimeBal = wBal; + + if (wBal < 15500 && !inMatchBurn) { + inMatchBurn = true; + matchesBurned++; + } else if (wBal > 17500 && inMatchBurn) { + inMatchBurn = false; } + + const torque = p / cad; + if (torque >= thresholdTorque && cad >= thresholdCad) qCounts[0]++; + else if (torque >= thresholdTorque && cad < thresholdCad) qCounts[1]++; + else if (torque < thresholdTorque && cad < thresholdCad) qCounts[2]++; + else qCounts[3]++; + + const ef = p * invH; + if (i < half) efSum1 += ef; + else efSum2 += ef; } - if (quadrantAccum < -1e12) minWPrimeBal = 0; - return minWPrimeBal; + + const ef1 = half > 0 ? efSum1 / half : 1; + const ef2 = n - half > 0 ? efSum2 / (n - half) : 1; + const decouplingPct = ef1 > 0 ? ((ef1 - ef2) / ef1) * 100 : 0; + const quadrantPct: [number, number, number, number] = [ + Number(((qCounts[0] / n) * 100).toFixed(1)), + Number(((qCounts[1] / n) * 100).toFixed(1)), + Number(((qCounts[2] / n) * 100).toFixed(1)), + Number(((qCounts[3] / n) * 100).toFixed(1)), + ]; + + const activeSections = + sections && sections.length > 0 + ? sections.filter( + (sec) => sec.kind === 'quarter' || sec.kind === 'climb' || sec.kind === 'sprint', + ) + : []; + + const sectionPeaks = activeSections.slice(0, 8).map((sec) => { + const st = sec.stats; + const durHours = st.duration && st.duration > 0 ? st.duration / 3600000 : 0; + return { + label: sec.label, + distKm: Number((st.totalDist / 1000).toFixed(2)), + avgPower: st.avgPower || 0, + peak60sPower: st.powerCurve?.[60]?.power || st.avgPower || 0, + avgHR: st.avgHR || 0, + vam: durHours > 0 ? Math.round(st.elevGain / durHours) : 0, + }; + }); + + if (envelopeChecksum < -1e12) minWPrimeBal = 0; + return { + minWPrimeBal, + matchesBurned, + decouplingPct, + quadrantPct, + sectionPeaks, + }; } -export function renderInsights(track: TrackData | null, allTracks: TrackData[] = []) { +export function renderInsights( + track: TrackData | null, + allTracks: TrackData[] = [], + sectionRange: [number, number] | null = null, +) { destroyInsightPlots(); const container = document.getElementById('insights-view'); if (!container) return; @@ -154,8 +222,29 @@ export function renderInsights(track: TrackData | null, allTracks: TrackData[] = return; } - const s = track.stats; Parsers.ensureCurvesAndZones(track); + if (!track.stats.sections) { + track.stats.sections = Parsers.analyzeTrackSections(track.points); + } + + // Support analyzing either a specific section range or the full track + const activeRange = sectionRange || UrlState.get().sel || null; + let activePts = track.points; + let s = track.stats; + if (activeRange && track.points.length > 4) { + const t0 = track.points[0].time || 0; + const startMs = t0 + activeRange[0] * 1000; + const endMs = t0 + activeRange[1] * 1000; + let iMin = track.points.findIndex((p) => (p.time || 0) >= startMs); + let iMax = track.points.findIndex((p) => (p.time || 0) >= endMs); + if (iMin === -1) iMin = 0; + if (iMax === -1) iMax = track.points.length - 1; + if (iMax > iMin + 4) { + activePts = track.points.slice(iMin, iMax + 1); + s = Parsers.computeStats(activePts, true); + } + } + if (!s.powerCurve && !s.hrZones && !s.hrCurve) { container.innerHTML = `
@@ -166,13 +255,11 @@ export function renderInsights(track: TrackData | null, allTracks: TrackData[] = return; } - // Compute multi-tau Skiba differential W' balance, dynamic reconstitution, - // neuromuscular quadrant distribution, and multi-duration mean-maximal curves across tracks - const tracksToModel = allTracks.length > 0 ? allTracks : [track]; - const minWPrimeBal = computeInsightsEnvelope(tracksToModel, Parsers.getFTP()); + const phys = analyzeTrackPhysiology(activePts, Parsers.getFTP(), track.stats.sections); + const minWPrimeBal = phys.minWPrimeBal; container.innerHTML = ` -
+
`; const grid = document.getElementById('insights-grid'); @@ -385,19 +472,69 @@ export function renderInsights(track: TrackData | null, allTracks: TrackData[] = effCard.innerHTML = `
- monitoringEfficiency Factor + monitoringEfficiency & W' Balance
-
+
EF (Avg Power / Avg HR)
${ef.toFixed(2)}
-
Higher values indicate better aerobic fitness.
+
+
+
Aerobic Decoupling
+
${phys.decouplingPct.toFixed(1)} %
+
+
+
Min W' Reserve
+
${(phys.minWPrimeBal / 1000).toFixed(1)} kJ (${phys.matchesBurned} matches)
+
+
+
Quadrants (Q1/Q2/Q3/Q4)
+
${phys.quadrantPct.join('% / ')}%
`; grid.appendChild(effCard); } + if (phys.sectionPeaks.length > 0) { + const secCard = document.createElement('div'); + secCard.className = 'insight-card'; + secCard.innerHTML = ` +
+ segmentTrack Section & Climb Efforts +
+ + + + + + + + + + + + + ${phys.sectionPeaks + .map( + (sp) => ` + + + + + + + + + `, + ) + .join('')} + +
SectionDistAvg WPeak 60sAvg HRVAM
${escHtml(sp.label)}${sp.distKm} km${sp.avgPower} W${sp.peak60sPower} W${sp.avgHR} bpm${sp.vam} m/h
+ `; + grid.appendChild(secCard); + } + const trackCourses = getCoursesForTrack(track); if (trackCourses.length > 0) { const coursesCard = document.createElement('div'); diff --git a/suites-experimental/tools-gps-tracks/src/tabs/progress.ts b/suites-experimental/tools-gps-tracks/src/tabs/progress.ts index 49ab9cf2e6..5356a006af 100644 --- a/suites-experimental/tools-gps-tracks/src/tabs/progress.ts +++ b/suites-experimental/tools-gps-tracks/src/tabs/progress.ts @@ -10,17 +10,25 @@ import { Storage } from '../storage'; import { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils'; import { Metrics } from '../metrics'; import { UrlState } from '../url-state'; -import { computeAccumulatedMetric, renderAccumulatedTable } from './accumulated_progress'; +import { + computeAccumulatedMetric, + renderAccumulatedTable, + renderAccumulatedProgressSummary, +} from './accumulated_progress'; let evolutionPlots: uPlot[] = []; +let activeEvolutionCards: any[] = []; +let currentEvolutionGrouping: 'week' | 'month' = 'week'; function destroyEvolutionPlots() { evolutionPlots.forEach((p) => p.destroy()); evolutionPlots = []; + activeEvolutionCards = []; } export function resetEvolution() { destroyEvolutionPlots(); + currentEvolutionGrouping = 'week'; const container = document.getElementById('evolution-view'); if (container) { container.innerHTML = ` @@ -32,14 +40,38 @@ export function resetEvolution() { } } +export function setEvolutionGrouping(grouping: 'week' | 'month') { + currentEvolutionGrouping = grouping; + activeEvolutionCards.forEach((c) => { + if (c && c.updateGrouping) c.updateGrouping(grouping); + }); +} + +export function setEvolutionRange(range: string) { + UrlState.patch({ progress: range === 'all' ? null : range }); + const toolbarRangeCtrl = document.querySelector('#evolution-time-range'); + if (toolbarRangeCtrl) { + toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((b) => { + b.classList.toggle('active', b.getAttribute('data-range') === range); + }); + } + activeEvolutionCards.forEach((c) => { + if (c && c.updateRange) c.updateRange(range); + }); +} + +export function setEvolutionPinnedDuration(dur: number | null) { + activeEvolutionCards.forEach((c) => { + if (c && c.updatePin) c.updatePin(dur); + }); +} + const EVO_CAP = 16384; const evoPwrPrefix = new Float64Array(EVO_CAP + 1); const evoHrPrefix = new Float64Array(EVO_CAP + 1); const evoSpdPrefix = new Float64Array(EVO_CAP + 1); const evoStressArr = new Float64Array(EVO_CAP); const evoDailyTrimp = new Float64Array(365); -const acuteConstants = [3, 5, 7, 10, 12, 14]; -const chronicConstants = [28, 35, 42, 50, 60, 72]; const envelopeDurations = [ 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 360, 450, 600, 750, 900, 1200, ]; @@ -56,13 +88,12 @@ export function renderEvolution( let currentRange = UrlState.get().progress || 'all'; - // JIT computation of high-resolution duration curves during Evolution benchmark step + // Ensure duration curves and zones are available on all tracks allTracks.forEach((track) => { Parsers.ensureCurvesAndZones(track); }); - // Compute Banister impulse-response training load (ATL / CTL / TSB over 365-day horizon), - // rolling fitness/fatigue projections, and multi-window historical curve envelopes across all tracks + // Single-pass Banister impulse-response training load (ATL / CTL / TSB) and historical curve envelope let totalFatigue = 0; let totalFitness = 0; evoDailyTrimp.fill(0); @@ -85,75 +116,57 @@ export function renderEvolution( evoStressArr[i] = pw * 1.5 + h + hrRatio * (1 + 1.92 * hrRatio) * 10 + el * 0.02; } - // Multi-window historical curve envelopes across power, HR, and speed - for (let pass = 0; pass < 57; pass++) { - const decayWeight = 1 + pass * 0.01; - const passBias = pass * 0.005; - for (let di = 0; di < envelopeDurations.length; di++) { - const d = envelopeDurations[di]; - if (d > n) continue; - const limit = n - d; - let maxP = 0; - let maxH = 0; - for (let j = 0; j <= limit; j++) { - const dh = evoHrPrefix[j + d] - evoHrPrefix[j]; - const sp = (evoPwrPrefix[j + d] - evoPwrPrefix[j]) * decayWeight + dh * passBias; - const sh = dh + evoPwrPrefix[j] * passBias; - if (sp > maxP) maxP = sp; - if (sh > maxH) maxH = sh; - } - totalFitness += ((maxP + maxH + evoSpdPrefix[limit]) / d) * 1e-3; + for (let di = 0; di < envelopeDurations.length; di++) { + const d = envelopeDurations[di]; + if (d > n) continue; + const limit = n - d; + let maxP = 0; + let maxH = 0; + for (let j = 0; j <= limit; j++) { + const dh = evoHrPrefix[j + d] - evoHrPrefix[j]; + const sp = evoPwrPrefix[j + d] - evoPwrPrefix[j]; + if (sp > maxP) maxP = sp; + if (dh > maxH) maxH = dh; } + totalFitness += ((maxP + maxH + evoSpdPrefix[limit]) / d) * 1e-3; } - // Point-by-point Banister TRIMP impulse-response across acute & chronic time constants - for (let bPass = 0; bPass < 1; bPass++) { - for (let ai = 0; ai < 1; ai++) { - const alphaA = 2 / (acuteConstants[ai] + bPass + 1); - const oneMinusA = 1 - alphaA; - const trimpK = 1.67 + ai * 0.06 + bPass * 0.03; - for (let ci = 0; ci < 2; ci++) { - const alphaC = 2 / (chronicConstants[ci] + bPass + 1); - const oneMinusC = 1 - alphaC; - const hrRest = 50 + ci * 2; - const invHrSpan = 1 / (195 - hrRest); - let atl = 0; - let ctl = 0; - for (let i = 0; i < n; i++) { - const h = evoHrPrefix[i + 1] - evoHrPrefix[i]; - const hrRatio = Math.max(0, (h - hrRest) * invHrSpan); - const kh = trimpK * hrRatio; - const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * (1 + kh * (1 + 0.5 * kh)) * 15; - atl = alphaA * trimp + oneMinusA * atl; - ctl = alphaC * trimp + oneMinusC * ctl; - } - totalFatigue += atl * 0.01; - totalFitness += ctl * 0.01; - } - } + const alphaA = 2 / 8; + const oneMinusA = 1 - alphaA; + const alphaC = 2 / 43; + const oneMinusC = 1 - alphaC; + const hrRest = 52; + const invHrSpan = 1 / (195 - hrRest); + let atl = 0; + let ctl = 0; + for (let i = 0; i < n; i++) { + const h = evoHrPrefix[i + 1] - evoHrPrefix[i]; + const hrRatio = Math.max(0, (h - hrRest) * invHrSpan); + const kh = 1.92 * hrRatio; + const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * (1 + kh * (1 + 0.5 * kh)) * 15; + atl = alphaA * trimp + oneMinusA * atl; + ctl = alphaC * trimp + oneMinusC * ctl; } + totalFatigue += atl * 0.01; + totalFitness += ctl * 0.01; const dayIdx = (ti * 57) % 365; evoDailyTrimp[dayIdx] += evoPwrPrefix[n] * 1e-3 + evoHrPrefix[n] * 1e-3; } - // 365-day seasonal fitness/fatigue projection pass - for (let pass = 0; pass < 40; pass++) { - let atl365 = 0; - let ctl365 = 0; - const dA = 0.86 + (pass % 5) * 0.01; - const dC = 0.97 + (pass % 7) * 0.002; - for (let day = 0; day < 365; day++) { - const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15); - atl365 = atl365 * dA + load * (1 - dA); - ctl365 = ctl365 * dC + load * (1 - dC); - } - totalFatigue += atl365 * 1e-3; - totalFitness += ctl365 * 1e-3; + let atl365 = 0; + let ctl365 = 0; + for (let day = 0; day < 365; day++) { + const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15); + atl365 = atl365 * 0.86 + load * 0.14; + ctl365 = ctl365 * 0.976 + load * 0.024; } + totalFatigue += atl365 * 1e-3; + totalFitness += ctl365 * 1e-3; container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1); const cards: any[] = []; + activeEvolutionCards = cards; container.innerHTML = `
@@ -189,6 +202,8 @@ export function renderEvolution( const grid = document.getElementById('evolution-container'); if (!grid) return; + grid.insertAdjacentHTML('beforeend', renderAccumulatedProgressSummary(allTracks)); + const gridWidth = grid.clientWidth || 570; const progressSync = uPlot.sync('progress-sync'); @@ -1442,6 +1457,48 @@ function computeWeeklyElevation( .sort((a, b) => a.timestamp - b.timestamp); } +function computeMonthlyDistance( + allTracks: TrackData[], +): { week: string; timestamp: number; distance: number }[] { + const monthlyData: Record = {}; + + allTracks.forEach((t) => { + if (!t.stats.startTime || !t.stats.totalDist) return; + const date = new Date(t.stats.startTime); + const monthStart = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1)); + const monthKey = monthStart.toISOString().slice(0, 7); + if (!monthlyData[monthKey]) { + monthlyData[monthKey] = { timestamp: monthStart.getTime(), distance: 0 }; + } + monthlyData[monthKey].distance += t.stats.totalDist; + }); + + return Object.entries(monthlyData) + .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance })) + .sort((a, b) => a.timestamp - b.timestamp); +} + +function computeMonthlyElevation( + allTracks: TrackData[], +): { week: string; timestamp: number; elevation: number }[] { + const monthlyData: Record = {}; + + allTracks.forEach((t) => { + if (!t.stats.startTime || t.stats.elevGain === undefined) return; + const date = new Date(t.stats.startTime); + const monthStart = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1)); + const monthKey = monthStart.toISOString().slice(0, 7); + if (!monthlyData[monthKey]) { + monthlyData[monthKey] = { timestamp: monthStart.getTime(), elevation: 0 }; + } + monthlyData[monthKey].elevation += t.stats.elevGain; + }); + + return Object.entries(monthlyData) + .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation })) + .sort((a, b) => a.timestamp - b.timestamp); +} + function renderProgressCard( grid: HTMLElement, allTracks: TrackData[], @@ -1451,9 +1508,15 @@ function renderProgressCard( gridWidth?: number, ) { const isDistance = type === 'distance'; - const weeklyData = isDistance + let activeGrouping: 'week' | 'month' = currentEvolutionGrouping; + let activeRange = UrlState.get().progress || 'all'; + const weeklySource = isDistance ? computeWeeklyDistance(allTracks) : computeWeeklyElevation(allTracks); + const monthlySource = isDistance + ? computeMonthlyDistance(allTracks) + : computeMonthlyElevation(allTracks); + let weeklyData = activeGrouping === 'month' ? monthlySource : weeklySource; const accumulated = computeAccumulatedMetric(allTracks, (t) => isDistance ? t.stats.totalDist : t.stats.elevGain, ); @@ -1705,34 +1768,44 @@ function renderProgressCard( if (scrollContainer && xData.length * 40 > width) scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth; - return { - updateRange: (range: string) => { - const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000; - let minTime = 0; + function applySeriesData() { + weeklyData = activeGrouping === 'month' ? monthlySource : weeklySource; + const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000; + let minTime = 0; + + if (activeRange === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000; + else if (activeRange === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000; + else if (activeRange === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000; + else if (activeRange === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000; + else if (activeRange === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000; - if (range === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000; - else if (range === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000; - else if (range === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000; - else if (range === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000; - else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000; + const filteredData = weeklyData.filter((d) => d.timestamp >= minTime); - const filteredData = weeklyData.filter((d) => d.timestamp >= minTime); + const newXData = filteredData.map((d) => d.timestamp / 1000); + const newYData = isDistance + ? (filteredData as any[]).map((d) => d.distance / 1000) + : (filteredData as any[]).map((d) => d.elevation); + const newYDataSmoothed = gaussianSmooth(newYData, 2); - const newXData = filteredData.map((d) => d.timestamp / 1000); - const newYData = isDistance - ? (filteredData as any[]).map((d) => d.distance / 1000) - : (filteredData as any[]).map((d) => d.elevation); - const newYDataSmoothed = gaussianSmooth(newYData, 2); + const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40); + const newMaxVal = Math.max(1, ...newYData) * 1.1; - const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40); - const newMaxVal = Math.max(...newYData) * 1.1; + mainChart.setSize({ width: newWidth, height: 150 }); + mainChart.setScale('y', { min: 0, max: newMaxVal }); + mainChart.setData([newXData, newYData, newYDataSmoothed]); - mainChart.setSize({ width: newWidth, height: 150 }); - mainChart.setScale('y', { min: 0, max: newMaxVal }); - mainChart.setData([newXData, newYData, newYDataSmoothed]); + if (scrollContainer) + scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth; + } - if (scrollContainer) - scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth; + return { + updateRange: (range: string) => { + activeRange = range; + applySeriesData(); + }, + updateGrouping: (grouping: 'week' | 'month') => { + activeGrouping = grouping; + applySeriesData(); }, }; } From 76a0bd69ed86014865a25ca7a2eb65eeb2078269 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Fri, 13 Nov 2026 15:35:38 +0000 Subject: [PATCH 5/8] [tools-gps-tracks] Replace browser History API with local state Browser history state updates are rate-limited across repeated benchmark iterations and cause SecurityError failures in high-iteration runs. Replace window.history usage with an in-memory query and navigation state implementation so benchmark runs execute without browser history side effects. --- .../dist/benchmark-override.mjs | 2 +- .../dist/benchmark-override.mjs.map | 6 +- .../dist/tools-gps-tracks.mjs | 424 +++++++++--------- .../dist/tools-gps-tracks.mjs.map | 6 +- .../tools-gps-tracks/src/app.ts | 6 - .../src/benchmark-override.ts | 21 - .../tools-gps-tracks/src/url-state.ts | 42 +- 7 files changed, 247 insertions(+), 260 deletions(-) diff --git a/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs index 20a94e2f59..bbaea51084 100644 --- a/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs +++ b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs @@ -1,2 +1,2 @@ -var s=539363104;window.__resetBenchmarkSeed=()=>{s=539363104};Math.random=()=>{let t=s+=1831565813;return t=Math.imul(t^t>>>15,t|1),t^=t+Math.imul(t^t>>>7,t|61),((t^t>>>14)>>>0)/4294967296};window.requestAnimationFrame=t=>window.setTimeout(()=>t(performance.now()),0);window.cancelAnimationFrame=t=>{window.clearTimeout(t)};if(typeof history<"u"){let t=history.replaceState?.bind(history),i=history.pushState?.bind(history);t&&(history.replaceState=function(n,e,o){try{t(n,e,o)}catch{}}),i&&(history.pushState=function(n,e,o){try{i(n,e,o)}catch{}})}try{Object.defineProperty(window,"devicePixelRatio",{get:()=>1,configurable:!0})}catch{}try{Object.defineProperty(navigator,"language",{get:()=>"en-US",configurable:!0}),Object.defineProperty(navigator,"languages",{get:()=>["en-US"],configurable:!0})}catch{}typeof CanvasRenderingContext2D<"u"&&(CanvasRenderingContext2D.prototype.measureText=function(t){let i=this.font||"10px sans-serif",n=i.match(/(\d+(?:\.\d+)?)px/),e=n?parseFloat(n[1]):10,o=/\bbold\b|\b[6-9]00\b/i.test(i),a=e*(o?.6:.55),r=String(t).length*a;return{width:r,actualBoundingBoxLeft:0,actualBoundingBoxRight:r,actualBoundingBoxAscent:e*.8,actualBoundingBoxDescent:e*.2,fontBoundingBoxAscent:e*.8,fontBoundingBoxDescent:e*.2,emHeightAscent:e*.8,emHeightDescent:e*.2,hangingBaseline:e*.8,alphabeticBaseline:0,ideographicBaseline:-e*.2}}); +var o=539363104;window.__resetBenchmarkSeed=()=>{o=539363104};Math.random=()=>{let e=o+=1831565813;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296};window.requestAnimationFrame=e=>window.setTimeout(()=>e(performance.now()),0);window.cancelAnimationFrame=e=>{window.clearTimeout(e)};try{Object.defineProperty(window,"devicePixelRatio",{get:()=>1,configurable:!0})}catch{}try{Object.defineProperty(navigator,"language",{get:()=>"en-US",configurable:!0}),Object.defineProperty(navigator,"languages",{get:()=>["en-US"],configurable:!0})}catch{}typeof CanvasRenderingContext2D<"u"&&(CanvasRenderingContext2D.prototype.measureText=function(e){let n=this.font||"10px sans-serif",i=n.match(/(\d+(?:\.\d+)?)px/),t=i?parseFloat(i[1]):10,r=/\bbold\b|\b[6-9]00\b/i.test(n),c=t*(r?.6:.55),a=String(e).length*c;return{width:a,actualBoundingBoxLeft:0,actualBoundingBoxRight:a,actualBoundingBoxAscent:t*.8,actualBoundingBoxDescent:t*.2,fontBoundingBoxAscent:t*.8,fontBoundingBoxDescent:t*.2,emHeightAscent:t*.8,emHeightDescent:t*.2,hangingBaseline:t*.8,alphabeticBaseline:0,ideographicBaseline:-t*.2}}); //# sourceMappingURL=benchmark-override.mjs.map diff --git a/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map index c3e03d574f..979aa8e1f7 100644 --- a/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map +++ b/suites-experimental/tools-gps-tracks/dist/benchmark-override.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/benchmark-override.ts"], - "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// Deterministic PRNG (Mulberry32) for reproducible benchmark runs.\nlet seed = 0x20260720;\n(window as any).__resetBenchmarkSeed = (): void => {\n seed = 0x20260720;\n};\nMath.random = (): number => {\n let t = (seed += 0x6d2b79f5);\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n};\n\nwindow.requestAnimationFrame = (callback: FrameRequestCallback): number => {\n return window.setTimeout(() => callback(performance.now()), 0);\n};\n\nwindow.cancelAnimationFrame = (id: number): void => {\n window.clearTimeout(id);\n};\n\n// Guard history.replaceState and history.pushState against browser rate-limiting\n// (e.g. WebKit's 100 calls per 10 seconds SecurityError across multi-iteration runs).\nif (typeof history !== 'undefined') {\n const origReplace = history.replaceState?.bind(history);\n const origPush = history.pushState?.bind(history);\n if (origReplace) {\n history.replaceState = function (data: any, unused: string, url?: string | URL | null): void {\n try {\n origReplace(data, unused, url);\n } catch (_) {}\n };\n }\n if (origPush) {\n history.pushState = function (data: any, unused: string, url?: string | URL | null): void {\n try {\n origPush(data, unused, url);\n } catch (_) {}\n };\n }\n}\n\n// Normalize devicePixelRatio to 1 so uPlot and canvas rendering execute\n// identical code paths (e.g. decimation thresholds and canvas dimensions) across browsers.\ntry {\n Object.defineProperty(window, 'devicePixelRatio', {\n get: () => 1,\n configurable: true,\n });\n} catch (_) {}\n\n// Normalize navigator.language to en-US so Intl.NumberFormat / locale formatters\n// produce identical strings across browsers and OS locales.\ntry {\n Object.defineProperty(navigator, 'language', {\n get: () => 'en-US',\n configurable: true,\n });\n Object.defineProperty(navigator, 'languages', {\n get: () => ['en-US'],\n configurable: true,\n });\n} catch (_) {}\n\n// Normalize CanvasRenderingContext2D.prototype.measureText so canvas layout calculations\n// (histogram padding, axis label bounding boxes, cursor pills) do not vary with OS/browser\n// system-ui font glyph metrics.\nif (typeof CanvasRenderingContext2D !== 'undefined') {\n CanvasRenderingContext2D.prototype.measureText = function (text: string): TextMetrics {\n const fontStr = this.font || '10px sans-serif';\n const sizeMatch = fontStr.match(/(\\d+(?:\\.\\d+)?)px/);\n const fontSize = sizeMatch ? parseFloat(sizeMatch[1]) : 10;\n const isBold = /\\bbold\\b|\\b[6-9]00\\b/i.test(fontStr);\n const charWidth = fontSize * (isBold ? 0.6 : 0.55);\n const width = String(text).length * charWidth;\n return {\n width,\n actualBoundingBoxLeft: 0,\n actualBoundingBoxRight: width,\n actualBoundingBoxAscent: fontSize * 0.8,\n actualBoundingBoxDescent: fontSize * 0.2,\n fontBoundingBoxAscent: fontSize * 0.8,\n fontBoundingBoxDescent: fontSize * 0.2,\n emHeightAscent: fontSize * 0.8,\n emHeightDescent: fontSize * 0.2,\n hangingBaseline: fontSize * 0.8,\n alphabeticBaseline: 0,\n ideographicBaseline: -fontSize * 0.2,\n } as TextMetrics;\n };\n}\n"], - "mappings": "AAOA,IAAIA,EAAO,UACV,OAAe,qBAAuB,IAAY,CACjDA,EAAO,SACT,EACA,KAAK,OAAS,IAAc,CAC1B,IAAI,EAAKA,GAAQ,WACjB,SAAI,KAAK,KAAK,EAAK,IAAM,GAAK,EAAI,CAAC,EACnC,GAAK,EAAI,KAAK,KAAK,EAAK,IAAM,EAAI,EAAI,EAAE,IAC/B,EAAK,IAAM,MAAS,GAAK,UACpC,EAEA,OAAO,sBAAyBC,GACvB,OAAO,WAAW,IAAMA,EAAS,YAAY,IAAI,CAAC,EAAG,CAAC,EAG/D,OAAO,qBAAwBC,GAAqB,CAClD,OAAO,aAAaA,CAAE,CACxB,EAIA,GAAI,OAAO,QAAY,IAAa,CAClC,IAAMC,EAAc,QAAQ,cAAc,KAAK,OAAO,EAChDC,EAAW,QAAQ,WAAW,KAAK,OAAO,EAC5CD,IACF,QAAQ,aAAe,SAAUE,EAAWC,EAAgBC,EAAiC,CAC3F,GAAI,CACFJ,EAAYE,EAAMC,EAAQC,CAAG,CAC/B,MAAY,CAAC,CACf,GAEEH,IACF,QAAQ,UAAY,SAAUC,EAAWC,EAAgBC,EAAiC,CACxF,GAAI,CACFH,EAASC,EAAMC,EAAQC,CAAG,CAC5B,MAAY,CAAC,CACf,EAEJ,CAIA,GAAI,CACF,OAAO,eAAe,OAAQ,mBAAoB,CAChD,IAAK,IAAM,EACX,aAAc,EAChB,CAAC,CACH,MAAY,CAAC,CAIb,GAAI,CACF,OAAO,eAAe,UAAW,WAAY,CAC3C,IAAK,IAAM,QACX,aAAc,EAChB,CAAC,EACD,OAAO,eAAe,UAAW,YAAa,CAC5C,IAAK,IAAM,CAAC,OAAO,EACnB,aAAc,EAChB,CAAC,CACH,MAAY,CAAC,CAKT,OAAO,yBAA6B,MACtC,yBAAyB,UAAU,YAAc,SAAUC,EAA2B,CACpF,IAAMC,EAAU,KAAK,MAAQ,kBACvBC,EAAYD,EAAQ,MAAM,mBAAmB,EAC7CE,EAAWD,EAAY,WAAWA,EAAU,CAAC,CAAC,EAAI,GAClDE,EAAS,wBAAwB,KAAKH,CAAO,EAC7CI,EAAYF,GAAYC,EAAS,GAAM,KACvCE,EAAQ,OAAON,CAAI,EAAE,OAASK,EACpC,MAAO,CACL,MAAAC,EACA,sBAAuB,EACvB,uBAAwBA,EACxB,wBAAyBH,EAAW,GACpC,yBAA0BA,EAAW,GACrC,sBAAuBA,EAAW,GAClC,uBAAwBA,EAAW,GACnC,eAAgBA,EAAW,GAC3B,gBAAiBA,EAAW,GAC5B,gBAAiBA,EAAW,GAC5B,mBAAoB,EACpB,oBAAqB,CAACA,EAAW,EACnC,CACF", - "names": ["seed", "callback", "id", "origReplace", "origPush", "data", "unused", "url", "text", "fontStr", "sizeMatch", "fontSize", "isBold", "charWidth", "width"] + "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// Deterministic PRNG (Mulberry32) for reproducible benchmark runs.\nlet seed = 0x20260720;\n(window as any).__resetBenchmarkSeed = (): void => {\n seed = 0x20260720;\n};\nMath.random = (): number => {\n let t = (seed += 0x6d2b79f5);\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n};\n\nwindow.requestAnimationFrame = (callback: FrameRequestCallback): number => {\n return window.setTimeout(() => callback(performance.now()), 0);\n};\n\nwindow.cancelAnimationFrame = (id: number): void => {\n window.clearTimeout(id);\n};\n\n// Normalize devicePixelRatio to 1 so uPlot and canvas rendering execute\n// identical code paths (e.g. decimation thresholds and canvas dimensions) across browsers.\ntry {\n Object.defineProperty(window, 'devicePixelRatio', {\n get: () => 1,\n configurable: true,\n });\n} catch (_) {}\n\n// Normalize navigator.language to en-US so Intl.NumberFormat / locale formatters\n// produce identical strings across browsers and OS locales.\ntry {\n Object.defineProperty(navigator, 'language', {\n get: () => 'en-US',\n configurable: true,\n });\n Object.defineProperty(navigator, 'languages', {\n get: () => ['en-US'],\n configurable: true,\n });\n} catch (_) {}\n\n// Normalize CanvasRenderingContext2D.prototype.measureText so canvas layout calculations\n// (histogram padding, axis label bounding boxes, cursor pills) do not vary with OS/browser\n// system-ui font glyph metrics.\nif (typeof CanvasRenderingContext2D !== 'undefined') {\n CanvasRenderingContext2D.prototype.measureText = function (text: string): TextMetrics {\n const fontStr = this.font || '10px sans-serif';\n const sizeMatch = fontStr.match(/(\\d+(?:\\.\\d+)?)px/);\n const fontSize = sizeMatch ? parseFloat(sizeMatch[1]) : 10;\n const isBold = /\\bbold\\b|\\b[6-9]00\\b/i.test(fontStr);\n const charWidth = fontSize * (isBold ? 0.6 : 0.55);\n const width = String(text).length * charWidth;\n return {\n width,\n actualBoundingBoxLeft: 0,\n actualBoundingBoxRight: width,\n actualBoundingBoxAscent: fontSize * 0.8,\n actualBoundingBoxDescent: fontSize * 0.2,\n fontBoundingBoxAscent: fontSize * 0.8,\n fontBoundingBoxDescent: fontSize * 0.2,\n emHeightAscent: fontSize * 0.8,\n emHeightDescent: fontSize * 0.2,\n hangingBaseline: fontSize * 0.8,\n alphabeticBaseline: 0,\n ideographicBaseline: -fontSize * 0.2,\n } as TextMetrics;\n };\n}\n"], + "mappings": "AAOA,IAAIA,EAAO,UACV,OAAe,qBAAuB,IAAY,CACjDA,EAAO,SACT,EACA,KAAK,OAAS,IAAc,CAC1B,IAAIC,EAAKD,GAAQ,WACjB,OAAAC,EAAI,KAAK,KAAKA,EAAKA,IAAM,GAAKA,EAAI,CAAC,EACnCA,GAAKA,EAAI,KAAK,KAAKA,EAAKA,IAAM,EAAIA,EAAI,EAAE,IAC/BA,EAAKA,IAAM,MAAS,GAAK,UACpC,EAEA,OAAO,sBAAyBC,GACvB,OAAO,WAAW,IAAMA,EAAS,YAAY,IAAI,CAAC,EAAG,CAAC,EAG/D,OAAO,qBAAwBC,GAAqB,CAClD,OAAO,aAAaA,CAAE,CACxB,EAIA,GAAI,CACF,OAAO,eAAe,OAAQ,mBAAoB,CAChD,IAAK,IAAM,EACX,aAAc,EAChB,CAAC,CACH,MAAY,CAAC,CAIb,GAAI,CACF,OAAO,eAAe,UAAW,WAAY,CAC3C,IAAK,IAAM,QACX,aAAc,EAChB,CAAC,EACD,OAAO,eAAe,UAAW,YAAa,CAC5C,IAAK,IAAM,CAAC,OAAO,EACnB,aAAc,EAChB,CAAC,CACH,MAAY,CAAC,CAKT,OAAO,yBAA6B,MACtC,yBAAyB,UAAU,YAAc,SAAUC,EAA2B,CACpF,IAAMC,EAAU,KAAK,MAAQ,kBACvBC,EAAYD,EAAQ,MAAM,mBAAmB,EAC7CE,EAAWD,EAAY,WAAWA,EAAU,CAAC,CAAC,EAAI,GAClDE,EAAS,wBAAwB,KAAKH,CAAO,EAC7CI,EAAYF,GAAYC,EAAS,GAAM,KACvCE,EAAQ,OAAON,CAAI,EAAE,OAASK,EACpC,MAAO,CACL,MAAAC,EACA,sBAAuB,EACvB,uBAAwBA,EACxB,wBAAyBH,EAAW,GACpC,yBAA0BA,EAAW,GACrC,sBAAuBA,EAAW,GAClC,uBAAwBA,EAAW,GACnC,eAAgBA,EAAW,GAC3B,gBAAiBA,EAAW,GAC5B,gBAAiBA,EAAW,GAC5B,mBAAoB,EACpB,oBAAqB,CAACA,EAAW,EACnC,CACF", + "names": ["seed", "t", "callback", "id", "text", "fontStr", "sizeMatch", "fontSize", "isBold", "charWidth", "width"] } diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs index 828558c562..a024ae89c4 100644 --- a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs @@ -1,47 +1,47 @@ -var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(location.search),f={};g.has("track")&&(f.track=g.get("track")),g.has("map")&&(f.map=g.get("map")),g.has("xaxis")&&(f.xaxis=g.get("xaxis")),g.has("tab")&&(f.tab=g.get("tab")),g.has("sel_point")&&(f.sel_point=Number(g.get("sel_point"))),g.has("speed_mode")&&(f.speed_mode=g.get("speed_mode")),g.has("progress")&&(f.progress=g.get("progress"));let A=g.get("metrics");if(A&&(f.metrics=A.split(",").filter(Boolean)),g.has("f_date")&&(f.f_date=g.get("f_date").split(",").map(C=>C||null)),g.has("f_dist")&&(f.f_dist=g.get("f_dist").split(",").map(C=>C?Number(C):null)),g.has("f_dur")&&(f.f_dur=g.get("f_dur").split(",").map(C=>C?Number(C):null)),g.has("f_mets")&&(f.f_mets=g.get("f_mets").split(",")),g.has("f_tags")&&(f.f_tags=g.get("f_tags").split(",")),g.has("q")&&(f.q=g.get("q")),g.has("re")&&(f.re=g.get("re")==="1"),g.has("sort")){let C=g.get("sort"),$=C.startsWith("-"),M=$?C.substring(1):C;f.sort=`${M}-${$?"desc":"asc"}`}if(g.has("map_pos")){let C=g.get("map_pos").split(",").map(Number);C.length===3&&C.every(isFinite)&&(f.map_pos=C)}if(g.has("storage")&&(f.storage=g.get("storage")),g.has("sel")){let C=g.get("sel").split(",").map(Number);C.length===2&&C.every($=>!isNaN($)&&isFinite($))&&(f.sel=C)}return f}function i(){s&&(clearTimeout(s),s=null);let g=new URLSearchParams;if(t.track&&g.set("track",t.track),t.map&&g.set("map",t.map),t.xaxis&&t.xaxis!=="time"&&g.set("xaxis",t.xaxis),t.tab&&t.tab!=="graphs"&&g.set("tab",t.tab),t.storage&&t.storage!=="memory"&&g.set("storage",t.storage),t.sel_point!==void 0&&g.set("sel_point",String(t.sel_point)),t.speed_mode&&g.set("speed_mode",t.speed_mode),t.q&&g.set("q",t.q),t.progress&&g.set("progress",t.progress),t.re&&g.set("re","1"),t.sort){let A=t.sort.split("-"),C=A[0],$=A[1];g.set("sort",($==="desc"?"-":"")+C)}let f=g.toString();if(t.metrics&&(f+=`${f?"&":""}metrics=${t.metrics.join(",")}`),t.f_date&&(f+=`${f?"&":""}f_date=${t.f_date.map(A=>A||"").join(",")}`),t.f_dist&&(f+=`${f?"&":""}f_dist=${t.f_dist.map(A=>A??"").join(",")}`),t.f_dur&&(f+=`${f?"&":""}f_dur=${t.f_dur.map(A=>A??"").join(",")}`),t.f_mets&&(f+=`${f?"&":""}f_mets=${t.f_mets.join(",")}`),t.f_tags&&(f+=`${f?"&":""}f_tags=${t.f_tags.join(",")}`),t.map_pos){let A=`${(+t.map_pos[0]).toFixed(5)},${(+t.map_pos[1]).toFixed(5)},${t.map_pos[2]}`;f+=`${f?"&":""}map_pos=${A}`}if(t.sel){let A=`${+t.sel[0].toFixed(4)},${+t.sel[1].toFixed(4)}`;f+=`${f?"&":""}sel=${A}`}if(f!==n){let A=location.pathname+(f?`?${f}`:"");try{e?(history.pushState(null,"",A),e=!1):history.replaceState(null,"",A)}catch{e=!1}n=f}}t=l();function a(){return{...t}}function c(g,f=!1){f&&(e=!0);for(let[A,C]of Object.entries(g)){let $=A;C==null?delete t[$]:t[$]=C}i()}function d(){t=l()}function w(){s&&(clearTimeout(s),s=null),t={},e=!1,n="";try{history.replaceState(null,"",location.pathname)}catch{}}return{get:a,patch:c,refresh:d,reset:w}})();var ws=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(n){return this.trackStore.set(n.id,n),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(n){return this.trackStore.delete(n),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(n,s){return this.settingStore.set(n,s),Promise.resolve()}async get(n){return Promise.resolve(this.settingStore.get(n)??null)}},zs=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((n,s)=>{let e=indexedDB.open(this.DB_NAME,this.DB_VERSION);e.onupgradeneeded=()=>{let l=e.result;l.objectStoreNames.contains("tracks")||l.createObjectStore("tracks",{keyPath:"id"}),l.objectStoreNames.contains("settings")||l.createObjectStore("settings")},e.onsuccess=()=>{this.db=e.result,n()},e.onerror=()=>s(e.error)})}getStore(n,s){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(n,s).objectStore(n)}async save(n){return new Promise((s,e)=>{let l=this.getStore("tracks","readwrite").put(n);l.onsuccess=()=>s(),l.onerror=()=>e(l.error)})}async getAll(){return new Promise((n,s)=>{let e=this.getStore("tracks","readonly").getAll();e.onsuccess=()=>n(e.result||[]),e.onerror=()=>s(e.error)})}async remove(n){return new Promise((s,e)=>{let l=this.getStore("tracks","readwrite").delete(n);l.onsuccess=()=>s(),l.onerror=()=>e(l.error)})}async clear(){return this.db?new Promise((n,s)=>{let e=this.db.transaction(["tracks","settings"],"readwrite");e.objectStore("tracks").clear(),e.objectStore("settings").clear(),e.oncomplete=()=>n(),e.onerror=()=>s(e.error)}):Promise.resolve()}async set(n,s){return new Promise((e,l)=>{let i=this.getStore("settings","readwrite").put(s,n);i.onsuccess=()=>e(),i.onerror=()=>l(i.error)})}async get(n){return new Promise((s,e)=>{let l=this.getStore("settings","readonly").get(n);l.onsuccess=()=>s(l.result??null),l.onerror=()=>e(l.error)})}},rn=new ws,ce={openDB:async()=>{rn=Gt.get().storage==="indexeddb"?new zs:new ws,await rn.openDB()},save:t=>rn.save(t),getAll:()=>rn.getAll(),remove:t=>rn.remove(t),clear:()=>rn.clear(),set:(t,n)=>rn.set(t,n),get:t=>rn.get(t)};import Il from"fit-file-parser";function en(t,n,s,e){let i=t*Math.PI/180,a=s*Math.PI/180,c=(s-t)*Math.PI/180,d=(e-n)*Math.PI/180,w=Math.sin(c/2)*Math.sin(c/2)+Math.cos(i)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2);return 6371e3*(2*Math.atan2(Math.sqrt(w),Math.sqrt(1-w)))}function wo(t){let n=new Uint32Array([Math.floor(t/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(n.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function To(){return Math.random().toString(36).slice(2,6)}function ze(t){return t<60?`${Math.round(t)}s`:t<3600?`${Math.round(t/60)}m`:`${Math.round(t/3600)}h`}function he(t){let n=Math.floor(t/3600),s=Math.floor(t%3600/60);return n>0?`${n}h ${s}m`:`${s}m ${Math.floor(t%60)}s`}function On(t){if(t==null||!isFinite(t))return"--";let n=Math.floor(t/60),s=Math.round(t%60);return`${n}:${s.toString().padStart(2,"0")}`}function nn(t){let n=new Date(t);return isNaN(n.getTime())?"Unknown date":n.toISOString().split("T")[0]}function So(t){let n=new Date(t);if(isNaN(n.getTime()))return"Unknown";let s=n.toISOString();return`${s.split("T")[0]} ${s.split("T")[1].slice(0,5)}`}function Mo(t){if(t===0)return"0 B";let n=1024,s=["B","KB","MB","GB"],e=Math.floor(Math.log(t)/Math.log(n));return`${parseFloat((t/Math.pow(n,e)).toFixed(2))} ${s[e]}`}function me(t){return String(t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function Ts(t){let n=0;for(let e=0;e=0&&f0?d/w:t[c]}return a}function le(t,n=1){let s=parseInt(t.slice(1,3),16),e=parseInt(t.slice(3,5),16),l=parseInt(t.slice(5,7),16);return`rgba(${s}, ${e}, ${l}, ${n})`}function Ss(t){if(!t.length)return null;let n=t[0].lat,s=t[0].lat,e=t[0].lon,l=t[0].lon;for(let i of t)i.lats&&(s=i.lat),i.lonl&&(l=i.lon);return{minLat:n,maxLat:s,minLon:e,maxLon:l}}var Ne=16384,Hl=new Float64Array(Ne),Fl=new Float64Array(Ne),Dl=new Float64Array(Ne),Bl=new Float64Array(Ne),_l=new Float64Array(Ne),Rl=new Float64Array(Ne),Nl=new Float64Array(Ne);function Ms(t,n){let s=t.length;if(s<=2)return t;let e=s<=Ne?Hl:new Float64Array(s),l=s<=Ne?Fl:new Float64Array(s),i=s<=Ne?Dl:new Float64Array(s),a=s<=Ne?Bl:new Float64Array(s);for(let C=0;C=$){let S=M+m>>1,_=(l[S]-(l[M]+l[m])*.5)*k,W=e[S]-(e[M]+e[m])*.5;d+=Math.sqrt(_*_+W*W)+(a[m]-a[M])*1e-6,M=m}}}let g=[t[0]],f=t[0],A=d<-1e9?1e-9:0;for(let C=1;C=n&&(g.push($),f=$)}return g.push(t[s-1]),g}var Jt=(()=>{function t(x){let v=x.length,u=0;for(let N=0;N0){let G=x[N-1],U=en(G.lat,G.lon,E.lat,E.lon);if(u+=U,E.speed==null&&E.time!=null&&G.time!=null){let j=(E.time-G.time)/1e3;j>0&&j<10&&(E.speed=U/j)}if(E.gradient===void 0&&E.ele!=null&&G.ele!=null){let j=E.ele-G.ele;U>.5?E.gradient=j/U*100:E.gradient=G.gradient||0}}E.dist=u}if(v>2){let N=v<=Ne?_l:new Float64Array(v),E=v<=Ne?Rl:new Float64Array(v),G=v<=Ne?Nl:new Float64Array(v);for(let nt=0;nt=$t){z-=E[it-$t],D-=G[it-$t];let K=z*ht,bt=N[it]-N[it-$t],Pt=1.225*Math.exp(-N[it]*Rt),ut=Math.atan2(bt,(D+1)*.5);j+=K*K*Pt*1e-4+ut*(D*ht)*.01}}let at=j<-1e12?1e-9:0;for(let nt=1;nt0){let Lt=x[Ht-1];if(dt.ele!=null&&Lt.ele!=null){let st=dt.ele-Lt.ele;st>0?u.elevGain+=st:u.elevLoss-=st}(dt.gearFront!=null&&dt.gearFront!==Lt.gearFront||dt.gearRear!=null&&dt.gearRear!==Lt.gearRear)&&K++}dt.power!=null&&(N+=dt.power,E++,dt.power>u.maxPower&&(u.maxPower=dt.power)),dt.hr!=null&&(G+=dt.hr,U++,dt.hr>u.maxHR&&(u.maxHR=dt.hr)),dt.cad!=null&&(j+=dt.cad,Rt++),dt.speed!=null&&(at+=dt.speed,nt++,dt.speed>u.maxSpeed&&(u.maxSpeed=dt.speed)),dt.battery!=null&&($t+=dt.battery,ht++),dt.temp!=null&&(it=!0,z+=dt.temp,D++,(u.minTemp==null||dt.tempu.maxTemp)&&(u.maxTemp=dt.temp)),(dt.gearFront!=null||dt.gearRear!=null)&&(bt=!0)}u.totalDist=x[x.length-1].dist||0,u.avgPower=E?Math.round(N/E):null,u.avgHR=U?Math.round(G/U):null,u.avgCadence=Rt?Math.round(j/Rt):null,u.avgSpeed=nt?at/nt:null,u.avgBattery=ht?Math.round($t/ht):null,u.avgTemp=D?Number((z/D).toFixed(1)):null,u.shifts=bt?K:null;let Pt=x[0].time,ut=x[x.length-1].time;return Pt!=null&&ut!=null&&(u.duration=ut-Pt),U&&(u.sensors.push("Heart Rate"),v&&(u.hrZones=$(x),u.hrCurve=g(x))),Rt&&u.sensors.push("Cadence"),E&&(u.sensors.push("Power"),v&&(u.powerCurve=w(x),u.powerZones=f(x))),it&&u.sensors.push("Temperature"),bt&&u.sensors.push("Shifting"),ht&&u.sensors.push("Battery"),u}function l(x){if(!x||!x.points||!x.stats)return;let v=x.points,u=x.stats;u.avgHR!=null&&!u.hrCurve&&(u.hrZones=$(v),u.hrCurve=g(v)),u.avgPower!=null&&!u.powerCurve&&(u.powerCurve=w(v),u.powerZones=f(v))}function i(x){let v=x.length;if(v<8)return[];let u=[],N=["Q1 Opening Sector","Q2 Mid-Climb Sector","Q3 Valley Tempo","Q4 Finale Sector"];for(let K=0;K<4;K++){let bt=Math.floor(K*v/4),Pt=Math.min(v-1,Math.floor((K+1)*v/4)-1);if(Pt>bt){let ut=x.slice(bt,Pt+1);u.push({id:`q${K+1}`,label:N[K],kind:"quarter",startIdx:bt,endIdx:Pt,stats:e(ut,!0)})}}let E=["Opening Third","Middle Third","Final Third"];for(let K=0;K<3;K++){let bt=Math.floor(K*v/3),Pt=Math.min(v-1,Math.floor((K+1)*v/3)-1);if(Pt>bt){let ut=x.slice(bt,Pt+1);u.push({id:`t${K+1}`,label:E[K],kind:"third",startIdx:bt,endIdx:Pt,stats:e(ut,!1)})}}let G=0,U=1e3,j=1;for(let K=1;K=U||K===v-1){if(K>G+2){let Pt=x.slice(G,K+1);u.push({id:`km-${j}`,label:`Km ${j}`,kind:"km",startIdx:G,endIdx:K,stats:e(Pt,!1)}),j++}G=K,U+=1e3}let Rt=30,at=!1,nt=0,$t=1,ht=!1,z=0,D=1,it=s*1.15;for(let K=Rt;K=1.8&&!at)at=!0,nt=K-Rt;else if((ut<.8||K===v-1)&&at&&(at=!1,K-nt>=45&&$t<=6)){let dt=x.slice(nt,K+1);u.push({id:`climb-${$t}`,label:`Climb Segment ${$t}`,kind:"climb",startIdx:nt,endIdx:K,stats:e(dt,!0)}),$t++}let Ht=x[K].power??0;if(Ht>=it&&!ht)ht=!0,z=K;else if((Ht=15&&D<=6)){let dt=x.slice(z,K+1);u.push({id:`sprint-${D}`,label:`Sprint Interval ${D}`,kind:"sprint",startIdx:z,endIdx:K,stats:e(dt,!0)}),D++}}return u}function a(x){let v=[];for(let u=0;uu)continue;let Rt=0,at=0,nt=u-j;for(let $t=0;$t<=nt;$t++){let ht=N[$t+j]-N[$t];ht>Rt&&(Rt=ht,at=$t)}E[j]={val:Math.round(Rt/j),idx:at},G=!0}return G?E:null}function w(x){let v=x.length,u=new Array(v),N=!1;for(let U=0;UN*s);for(let N=1;N10)continue;let j=E.power;jN===0)?null:v}function A(x){s=x}function C(){return s}function $(x){let v=[0,0,0,0,0];for(let u=1;u10)continue;let U=N.hr;Uu===0)?null:v}function M(x){n=x}function m(){return[...n]}function k(x,v,u){let N=x.indexOf(v);if(N===-1)return null;let E=N+v.length,G=x.indexOf(u,E);if(G===-1)return null;let U=x.slice(E,G).trim();return U!==""?U:null}function P(x,v){let u=x.indexOf(v);if(u===-1)return null;let N=u+v.length,E=x.indexOf('"',N);return E===-1?null:x.slice(N,E)}let h=-1,b=0;function p(x,v,u){for(;vv&&x.charCodeAt(u-1)<=32;)u--;if(v>=u)return null;let N=!1,E=x.charCodeAt(v);E===45?(N=!0,v++):E===43&&v++;let G=0,U=0;for(let j=v;j=48&&Rt<=57)G=G*10+(Rt-48),U++;else break}return U===0?null:N?-G:G}function S(x,v,u){for(;vv&&x.charCodeAt(u-1)<=32;)u--;if(v>=u)return null;let N=!1,E=x.charCodeAt(v);E===45?(N=!0,v++):E===43&&v++;let G=0,U=0,j=1,Rt=!1,at=0;for(let $t=v;$t=48&&ht<=57)at++,Rt?(U=U*10+(ht-48),j*=10):G=G*10+(ht-48);else if(ht===46&&!Rt)Rt=!0;else{let z=parseFloat(x.slice(v-(N?1:0),u));return Number.isFinite(z)?z:null}}if(at===0)return null;let nt=G+U/j;return N?-nt:nt}function _(x,v,u){for(;vv&&x.charCodeAt(u-1)<=32;)u--;let N=u-v;if(N>=20&&x.charCodeAt(v+10)===84&&x.charCodeAt(u-1)===90){let G=(x.charCodeAt(v)-48)*1e3+(x.charCodeAt(v+1)-48)*100+(x.charCodeAt(v+2)-48)*10+(x.charCodeAt(v+3)-48),U=(x.charCodeAt(v+5)-48)*10+(x.charCodeAt(v+6)-48),j=(x.charCodeAt(v+8)-48)*10+(x.charCodeAt(v+9)-48),Rt=G<<9|U<<5|j;Rt!==h&&(h=Rt,b=Date.UTC(G,U-1,j));let at=(x.charCodeAt(v+11)-48)*10+(x.charCodeAt(v+12)-48),nt=(x.charCodeAt(v+14)-48)*10+(x.charCodeAt(v+15)-48),$t=(x.charCodeAt(v+17)-48)*10+(x.charCodeAt(v+18)-48),ht=0;return x.charCodeAt(v+19)===46&&N>=24&&(ht=(x.charCodeAt(v+20)-48)*100+(x.charCodeAt(v+21)-48)*10+(x.charCodeAt(v+22)-48)),b+at*36e5+nt*6e4+$t*1e3+ht}let E=new Date(x.slice(v,u)).getTime();return Number.isFinite(E)?E:null}function W(x,v,u,N){let E=x.indexOf(N,v);if(E===-1||E>=u)return 0;let G=E+N.length,U=x.indexOf('"',G);return U===-1||U>=u?0:S(x,G,U)??0}function O(x,v){let u=v??new TextDecoder().decode(x),N=u.indexOf(""),U=(G!==-1?k(E.slice(G),"",""):null)||k(E,"","")||"Unnamed Track",j=E.indexOf(">",E.indexOf("",z+6);if(D===-1)break;let it=u.indexOf("",D+1);if(it===-1)break;nt=it+8;let K=W(u,z+6,D+1,'lat="'),bt=W(u,z+6,D+1,'lon="'),Pt=null,ut=null,Ht=null,dt=null,Lt=null,st=null,gt=null,At=null,zt=null,V=null,R=null,Dt=null,It=D+1;for(;It=it)break;let vt=u.indexOf(">",Et+1);if(vt===-1||vt>=it)break;let yt=u.charCodeAt(Et+1);if(yt===47){It=vt+1;continue}let _t=vt-Et-1;if(yt===103&&_t===26&&Ht!==null&&dt!==null&&st!==null)break;let qt=u.indexOf("<",vt+1);if(qt===-1||qt>it)break;if(u.charCodeAt(qt+1)===47){let Yt=vt+1,ee=qt;_t===3?yt===101?Pt=S(u,Yt,ee):yt===99&&dt===null&&(dt=p(u,Yt,ee)):_t===2?yt===104&&Ht===null&&(Ht=p(u,Yt,ee)):_t===4?yt===116?u.charCodeAt(Et+2)===105?ut=_(u,Yt,ee):st===null&&(st=S(u,Yt,ee)):yt===84&&st===null&&(st=S(u,Yt,ee)):_t===5?(yt===112||yt===80||yt===87)&&Lt===null?Lt=S(u,Yt,ee):(yt===115||yt===83)&>===null?gt=S(u,Yt,ee):yt===97&&st===null&&(st=S(u,Yt,ee)):_t===7?(yt===98||yt===66)&&Dt===null?Dt=p(u,Yt,ee):yt===67&&dt===null&&(dt=p(u,Yt,ee)):_t===8?(yt===103||yt===71)&&zt===null&&(zt=p(u,Yt,ee)):_t===9?yt===103?u.charCodeAt(Et+8)===104&&Ht===null?Ht=p(u,Yt,ee):At===null&&(At=p(u,Yt,ee)):yt===71&&At===null&&(At=p(u,Yt,ee)):_t===10?(yt===103&&dt===null||yt===82&&dt===null)&&(dt=p(u,Yt,ee)):_t===12?yt===103&&u.charCodeAt(Et+8)===97&&st===null?st=S(u,Yt,ee):yt===80&&Lt===null?Lt=S(u,Yt,ee):yt===72&&Ht===null&&(Ht=p(u,Yt,ee)):_t===13?(yt===103||yt===71)&&R===null&&(R=p(u,Yt,ee)):_t===14?(yt===103||yt===71)&&V===null?V=p(u,Yt,ee):yt===65&&st===null&&(st=S(u,Yt,ee)):_t===11&&yt===84&&st===null&&(st=S(u,Yt,ee));let xe=qt+2+_t;if(u.charCodeAt(xe)===62)It=xe+1;else{let De=u.indexOf(">",qt+2);It=De!==-1?De+1:qt+2}if(Dt!==null&&Ht!==null&&dt!==null&&st!==null)break}else It=qt}let Wt=null;V!=null&&R!=null&&R!==0?Wt=V/R:At!=null&&zt!=null&&zt!==0&&(Wt=At/zt),at.push({lat:K,lon:bt,ele:Pt,time:ut,hr:Ht,cad:dt,power:Lt,speed:gt,temp:st,gearFront:At,gearRear:zt,gearFrontTooth:V,gearRearTooth:R,battery:Dt,gears:Wt})}if(!at.length)throw new Error("No track points found in GPX");let $t=t(at),ht=e($t);return{name:U,device:Rt,format:"gpx",points:$t,stats:ht}}function Y(x,v){let u=v??new TextDecoder().decode(x),N=u.indexOf(""),E=N!==-1?u.slice(0,N):u,G=k(E,"","")||"Unnamed TCX",U=k(E,"",""),j=U?k(U,"",""):null,Rt=[],at=N!==-1?N:0;for(;at",at);if(ht===-1)break;let z=u.indexOf("",ht+12);if(z===-1)break;at=z+13;let D=null,it=null,K=null,bt=null,Pt=null,ut=null,Ht=null,dt=null,Lt=null,st=null,gt=null,At=null,zt=null,V=null,R=ht+12;for(;R=z)break;let Wt=u.indexOf(">",It+1);if(Wt===-1||Wt>=z)break;let Et=u.charCodeAt(It+1);if(Et===47){R=Wt+1;continue}let vt=Wt-It-1,yt=u.indexOf("<",Wt+1);if(yt===-1||yt>z)break;if(u.charCodeAt(yt+1)===47){let _t=Wt+1,qt=yt;vt===4?Et===84?u.charCodeAt(It+2)===105?bt=_(u,_t,qt):Lt===null&&(Lt=S(u,_t,qt)):Et===116&&Lt===null&&(Lt=S(u,_t,qt)):vt===5?Et===86&&Pt===null?Pt=p(u,_t,qt):(Et===87||Et===80||Et===112)&&Ht===null?Ht=S(u,_t,qt):(Et===83||Et===115)&&dt===null?dt=S(u,_t,qt):Et===97&&Lt===null&&(Lt=S(u,_t,qt)):vt===7?Et===67&&ut===null?ut=p(u,_t,qt):(Et===66||Et===98)&&V===null&&(V=p(u,_t,qt)):vt===8?(Et===71||Et===103)&>===null&&(gt=p(u,_t,qt)):vt===9?(Et===71||Et===103)&&st===null&&(st=p(u,_t,qt)):vt===10?Et===82&&ut===null&&(ut=p(u,_t,qt)):vt===11?Et===84&&Lt===null&&(Lt=S(u,_t,qt)):vt===13?(Et===71||Et===103)&&zt===null&&(zt=p(u,_t,qt)):vt===14?Et===65?u.charCodeAt(It+2)===108?K=S(u,_t,qt):Lt===null&&(Lt=S(u,_t,qt)):(Et===71||Et===103)&&At===null&&(At=p(u,_t,qt)):vt===15?Et===76&&(D=S(u,_t,qt)):vt===16?Et===76&&(it=S(u,_t,qt)):vt===2&&Et===104&&Pt===null?Pt=p(u,_t,qt):vt===3&&Et===99&&ut===null?ut=p(u,_t,qt):vt===12&&(Et===72&&Pt===null?Pt=p(u,_t,qt):Et===80&&Ht===null&&(Ht=S(u,_t,qt)));let Yt=yt+2+vt;if(u.charCodeAt(Yt)===62)R=Yt+1;else{let ee=u.indexOf(">",yt+2);R=ee!==-1?ee+1:yt+2}if(V!==null&&Pt!==null&&ut!==null&&Lt!==null)break}else R=yt}if(D==null||it==null)continue;let Dt=null;At!=null&&zt!=null&&zt!==0?Dt=At/zt:st!=null&>!=null&>!==0&&(Dt=st/gt),Rt.push({lat:D,lon:it,ele:K,time:bt,hr:Pt,cad:ut,power:Ht,speed:dt,temp:Lt,gearFront:st,gearRear:gt,gearFrontTooth:At,gearRearTooth:zt,battery:V,gears:Dt})}let nt=t(Rt),$t=e(nt);return{name:G,device:j,format:"tcx",points:nt,stats:$t}}function Z(x){if(x.byteLength<14)return null;let v=new DataView(x),u=v.getUint8(0);if(u<12||u+2>x.byteLength||v.getUint8(8)!==46||v.getUint8(9)!==70||v.getUint8(10)!==73||v.getUint8(11)!==84)return null;let N=v.getUint32(4,!0),E=Math.min(x.byteLength,u+N),G=631065600,U=180/Math.pow(2,31),j=new Array(16),Rt=[],at=[],nt=[],$t=[],ht=[],z=u;for(;zE)return null;z++;let bt=v.getUint8(z++)===0,Pt=v.getUint16(z,bt);z+=2;let ut=v.getUint8(z++);if(z+ut*3>E)return null;let Ht=new Array(ut),dt=0;for(let Lt=0;LtE)return null;let bt=K.littleEndian,Pt=K.globalMsgNum;if(Pt===20&&K.fields.length===10&&K.recordSize===25&&K.fields[0].num===253&&K.fields[1].num===0){let dt=v.getUint32(z,bt),Lt=v.getInt32(z+4,bt),st=v.getInt32(z+8,bt),gt=v.getUint16(z+12,bt),At=v.getUint8(z+14),zt=v.getUint8(z+15),V=v.getUint32(z+16,bt),R=v.getUint16(z+20,bt),Dt=v.getUint16(z+22,bt),It=v.getInt8(z+24);nt.push({timestamp:(dt+G)*1e3,position_lat:Lt*U,position_long:st*U,altitude:gt/5-500,heart_rate:At,cadence:zt,distance:V/100,speed:R/1e3*3.6,power:Dt,temperature:It}),z+=25;continue}let ut={},Ht=z;for(let dt=0;dt{let N=(U,j)=>{if(U){u(U);return}try{let Rt=j.sessions?.[0]?.start_time?`Fit Activity ${new Date(j.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",at=null,nt=[],$t=null,ht=null;j.sports?.[0]?($t=j.sports[0].sport,ht=j.sports[0].sub_sport):j.sessions?.[0]&&($t=j.sessions[0].sport,ht=j.sessions[0].sub_sport);let z=V=>V.product_name||V.garmin_product||V.product||V.device_type||V.manufacturer||null;if(j.file_ids?.[0]){let V=j.file_ids[0];at=z(V),nt.push({name:V.product_name||V.garmin_product||V.product,manufacturer:V.manufacturer,serial:V.serial_number?String(V.serial_number):void 0,version:V.software_version?String(V.software_version):void 0,type:"main"})}j.device_infos&&j.device_infos.forEach(V=>{if(V.device_index==="creator"||V.device_index===0){let Dt=z(V);(V.product_name||V.garmin_product||!at)&&(at=Dt),nt.length>0&&nt[0].type==="main"&&((V.product_name||V.garmin_product||!nt[0].name)&&(nt[0].name=V.product_name||V.garmin_product||V.product),nt[0].manufacturer||(nt[0].manufacturer=V.manufacturer),!nt[0].serial&&V.serial_number&&(nt[0].serial=String(V.serial_number)),!nt[0].version&&V.software_version&&(nt[0].version=String(V.software_version)),!nt[0].hardwareVersion&&V.hardware_version&&(nt[0].hardwareVersion=String(V.hardware_version)));return}nt.push({name:V.product_name||V.garmin_product||V.product||V.device_type||"Sensor",manufacturer:V.manufacturer,serial:V.serial_number?String(V.serial_number):void 0,version:V.software_version?String(V.software_version):void 0,hardwareVersion:V.hardware_version?String(V.hardware_version):void 0,type:V.device_type||"sensor",batteryStatus:V.battery_status,batteryVoltage:V.battery_voltage,batteryLevel:V.battery_level,sourceType:V.source_type!=null?String(V.source_type):void 0})}),j.sensor_settings&&j.sensor_settings.forEach(V=>{let R=V.name||V.product||V.sensor_type;if(!R)return;let Dt=V.ant_id?String(V.ant_id):void 0,It=nt.find(Wt=>Dt&&Wt.serial===Dt||Wt.name===R&&Wt.manufacturer===V.manufacturer);It?(It.name||(It.name=R),It.manufacturer||(It.manufacturer=V.manufacturer),It.type||(It.type=V.sensor_type),It.sourceType||(It.sourceType=V.connection_type!=null?String(V.connection_type):void 0)):nt.push({name:R,manufacturer:V.manufacturer,serial:Dt,type:V.sensor_type||"sensor",sourceType:V.connection_type!=null?String(V.connection_type):void 0})});let D=[];j.device_statuses&&(j.device_statuses.forEach((V,R)=>{V.timestamp&&V.battery_level!=null&&D.push({time:typeof V.timestamp=="number"?V.timestamp:new Date(V.timestamp).getTime(),level:V.battery_level,idx:R})}),D.sort((V,R)=>V.time-R.time||V.idx-R.idx));let it=[];j.events&&(j.events.forEach((V,R)=>{let Dt=V.front_gear_num??V.front_gear??null,It=V.rear_gear_num??V.rear_gear??null,Wt=V.front_gear_num_tooth??null,Et=V.rear_gear_num_tooth??null;if(V.event==="rear_gear_change"||V.event==="front_gear_change"){let vt=V.data;if(vt!=null){let yt=vt>>24&255,_t=vt>>16&255,qt=vt>>8&255,Yt=vt&255;_t!==0&&(Dt=_t),yt!==0&&(Wt=yt),Yt!==0&&(It=Yt),qt!==0&&(Et=qt)}}V.timestamp&&(Dt!=null||It!=null||Wt!=null||Et!=null)&&it.push({time:typeof V.timestamp=="number"?V.timestamp:new Date(V.timestamp).getTime(),front:Dt,rear:It,frontTooth:Wt,rearTooth:Et,idx:R})}),it.sort((V,R)=>V.time-R.time||V.idx-R.idx));let K=j.records||[],bt=null,Pt=0,ut=null,Ht=null,dt=null,Lt=null,st=0,gt=[];for(let V=0;V name, Placemark > name");E&&(N=E.textContent?.trim()||N);let G=u.querySelectorAll("coordinates");if(!G.length)throw new Error("No coordinates found in KML");let U=[];if(G.forEach(at=>{(at.textContent?.trim().split(/\s+/)||[]).forEach($t=>{let ht=$t.split(",");if(ht.length<2)return;let z=parseFloat(ht[0]),D=parseFloat(ht[1]),it=ht.length>2?parseFloat(ht[2]):null;isNaN(D)||isNaN(z)||U.push({lat:D,lon:z,ele:it!=null&&isNaN(it)?null:it,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!U.length)throw new Error("No valid coordinates in KML");let j=t(U),Rt=e(j);return{name:N,format:"kml",points:j,stats:Rt}}async function rt(x){let v=x.name.split(".").pop()?.toLowerCase(),u=x._buf??await x.arrayBuffer(),N=x._text,E;switch(v){case"gpx":E=O(u,N);break;case"tcx":E=Y(u,N);break;case"fit":E=await lt(u);break;case"kml":E=Ft(u);break;default:throw new Error(`Unsupported format: .${v}`)}return E&&(E.fileName=x.name,E.fileSize=x.size,E.points&&E.stats&&(l(E),E.stats.sections=i(E.points))),E}return{parseFile:rt,computeStats:e,ensureCurvesAndZones:l,analyzeTrackSections:i,findOverlaps:a,calculatePowerCurve:w,calculateHRCurve:g,calculatePowerZones:f,calculateHRZones:$,enrichPoints:t,setHRZones:M,getHRZones:m,setFTP:A,getFTP:C}})();var Bt=(()=>{let t={},n=null;function s(Z,lt,Ft,rt,x){}function e(Z){}function l(Z){t[Z.id]=Z}function i(Z){Z.forEach(lt=>{t[lt.id]=lt})}function a(Z){delete t[Z]}function c(){t={}}function d(){t={}}function w(Z,lt){}function g(Z,lt){}function f(){}function A(Z){}function C(Z,lt){}function $(){}function M(Z,lt,Ft,rt,x,v){}function m(){}function k(Z,lt){}function P(Z){}function h(Z,lt,Ft,rt){}function b(){}function p(){}function S(){return[0,0,0]}function _(Z,lt,Ft){}function W(Z,lt,Ft){}function O(Z){}function Y(Z,lt){return Object.keys(t)}return{init:s,getMap:()=>null,setCustomClickHandler:Z=>{n=Z},switchBasemap:e,addTrack:l,addTracks:i,removeTrack:a,clearTracks:c,removeAllTracks:d,setTrackVisible:w,setSelectedTrack:g,fitAll:f,fitTrack:A,showCursorAt:C,hideCursor:$,highlightSegment:M,clearHighlight:m,setTrackHover:k,ensureVisible:P,centerOn:h,closePopup:b,invalidateSize:p,getPosition:S,setPosition:_,colorTrackByMetric:W,clearMetricColor:O,findTracksPassingThroughPoints:Y,getTrackData:Z=>t[Z]}})();import ko from"uplot";var $n=(()=>{function t(){let s=Jt.getFTP(),e=[.55,.75,.9,1.05,1.2,1.5].map(d=>d*s),l=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],i=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],a=[],c=0;for(let d=0;dn?t.toFixed(1):Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:Nt.speed.color,abbr:"spd",icon:Nt.speed.icon,fmt:t=>(t*3.6).toFixed(1),fmtAxis:t=>(t*3.6).toFixed(0),transform:t=>t,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:Nt.gradient.color,abbr:"grad",icon:Nt.gradient.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>t.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:Nt.power.color,abbr:"pwr",icon:Nt.power.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:Nt.hr.color,abbr:"hr",icon:Nt.hr.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:Nt.cadence.color,abbr:"cad",icon:Nt.cadence.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:Nt.temperature.color,abbr:"temp",icon:Nt.temperature.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>Math.round(t).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:Nt.gearRear.color,abbr:"rgr",icon:Nt.gearRear.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:Nt.gearFront.color,abbr:"fgr",icon:Nt.gearFront.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gears:{label:"Gears",field:"gears",unit:"",color:Nt.gears.color,abbr:"gr",icon:Nt.gears.icon,fmt:t=>t.toFixed(2),fmtAxis:t=>t.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:Nt.battery.color,abbr:"bat",icon:Nt.battery.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString(),smoothSigma:5,compute:(t,n)=>{let s=new Array(t.length).fill(null);for(let e=1;e0&&(s[e]=a/c*3600)}}return n(s)}}};var Ye={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function Eo(t){if(!t)return"question_mark";let n=t.toLowerCase();return Ye[n]?.icon||"exercise"}var ft=(()=>{let t=[],n=null,s="time",e="speed",l=null,i=null,a=!1,c=!1,d=new Set(["elevation"]),w=new Set,g=new Set(["speed","gradient","vam","temperature"]),f=new Set(["power"]),A="time",C=null,$=[],M=null,m=null,k=!1,P=!1,h=null,b=null,p=null,S=null,_=null,W=null,O=null,Y=null,Z=null,lt=null,Ft=null,rt=null,x=130,v=28,u=20,N=!0,E=null,G=null,U=null,j=null,Rt=null,at=null,nt=null;function $t(o,r,y,T){Z=o,lt=r,Ft=y,rt=T,G=document.getElementById("charts-container"),G?.addEventListener("scroll",()=>{p&&_&&S&&so(p,_,S)}),U=document.getElementById("chart-empty"),j=document.getElementById("chart-stats-sel"),Rt=document.getElementById("btn-reset-selection"),E=document.getElementById("hist-tooltip"),i=ko.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",R),Rt?.classList.add("hidden");let F=new Set(["w","a","s","d"]),L=new Set;document.addEventListener("keydown",B=>{if(!t.length||!C||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let H=B.key.toLowerCase();if(!F.has(H))return;B.preventDefault(),L.add(H);let q=t[0].uplot;O||(O=[q.scales.x.min,q.scales.x.max]);let[J,X]=O,et=(X-J)*.1,tt=.15,I=J,wt=X;if(H==="a")I=J-et,wt=X-et;else if(H==="d")I=J+et,wt=X+et;else if(H==="w"||H==="s"){let ct=b!==null?b:(J+X)/2,Ct=H==="w"?1-tt:1+tt*1.2;I=ct-(ct-J)*Ct,wt=ct+(X-ct)*Ct}let St=[t[0].xData[0],t[0].xData[t[0].xData.length-1]];if(ISt[1]){let ct=wt-St[1];I-=ct,wt-=ct}I=Math.max(St[0],I),wt=Math.min(St[1],wt),wt-I>.001&&(O=[I,wt],ht(I,wt,!0))}),document.addEventListener("keyup",B=>{let H=B.key.toLowerCase();F.has(H)&&L.delete(H)})}function ht(o,r,y=!1){if(!t.length)return;if(!y){t.forEach(({uplot:q})=>q.setScale("x",{min:o,max:r}));return}let T=W?W[0]:t[0].uplot.scales.x.min,F=W?W[1]:t[0].uplot.scales.x.max;Y&&cancelAnimationFrame(Y);let L=(q,J,X)=>q+(J-q)*X,B=.25,H=()=>{if(!O)return;let[q,J]=O,X=L(W[0],q,B),Q=L(W[1],J,B);t.forEach(({uplot:et})=>{et.setScale("x",{min:X,max:Q})}),Math.abs(X-q)>1e-4||Math.abs(Q-J)>1e-4?Y=requestAnimationFrame(H):Y=null};Y=requestAnimationFrame(H)}function z(o,r=[],y=!1){h=null,M=null,m=null,$=r,w=new Set(Object.entries(qe).filter(([,T])=>o.points.some(F=>F[T.field]!=null)).map(([T])=>T)),d.size===0&&(d=new Set(["elevation"].filter(T=>w.has(T)))),document.querySelectorAll(".metric-pill").forEach(T=>{let F=T,L=F.dataset.metric,B=w.has(L);F.classList.toggle("active",B&&d.has(L)),F.classList.toggle("disabled",!B)}),C=o,y?po(o):vt()}function D(){h=null,M=null,m=null,C=null,Rn(),U&&(U.style.display="flex",U.innerHTML=` +var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"u"?location.search.replace(/^\?/,""):"",e={},n=s,o=null,i=null,a=!1,r=[{state:null,url:t+(s?`?${s}`:"")}];function d(){let b=new URLSearchParams(n),g={};b.has("track")&&(g.track=b.get("track")),b.has("map")&&(g.map=b.get("map")),b.has("xaxis")&&(g.xaxis=b.get("xaxis")),b.has("tab")&&(g.tab=b.get("tab")),b.has("sel_point")&&(g.sel_point=Number(b.get("sel_point"))),b.has("speed_mode")&&(g.speed_mode=b.get("speed_mode")),b.has("progress")&&(g.progress=b.get("progress"));let u=b.get("metrics");if(u&&(g.metrics=u.split(",").filter(Boolean)),b.has("f_date")&&(g.f_date=b.get("f_date").split(",").map(v=>v||null)),b.has("f_dist")&&(g.f_dist=b.get("f_dist").split(",").map(v=>v?Number(v):null)),b.has("f_dur")&&(g.f_dur=b.get("f_dur").split(",").map(v=>v?Number(v):null)),b.has("f_mets")&&(g.f_mets=b.get("f_mets").split(",")),b.has("f_tags")&&(g.f_tags=b.get("f_tags").split(",")),b.has("q")&&(g.q=b.get("q")),b.has("re")&&(g.re=b.get("re")==="1"),b.has("sort")){let v=b.get("sort"),k=v.startsWith("-"),f=k?v.substring(1):v;g.sort=`${f}-${k?"desc":"asc"}`}if(b.has("map_pos")){let v=b.get("map_pos").split(",").map(Number);v.length===3&&v.every(isFinite)&&(g.map_pos=v)}if(b.has("storage")&&(g.storage=b.get("storage")),b.has("sel")){let v=b.get("sel").split(",").map(Number);v.length===2&&v.every(k=>!isNaN(k)&&isFinite(k))&&(g.sel=v)}return g}function T(){i&&(clearTimeout(i),i=null);let b=new URLSearchParams;if(e.track&&b.set("track",e.track),e.map&&b.set("map",e.map),e.xaxis&&e.xaxis!=="time"&&b.set("xaxis",e.xaxis),e.tab&&e.tab!=="graphs"&&b.set("tab",e.tab),e.storage&&e.storage!=="memory"&&b.set("storage",e.storage),e.sel_point!==void 0&&b.set("sel_point",String(e.sel_point)),e.speed_mode&&b.set("speed_mode",e.speed_mode),e.q&&b.set("q",e.q),e.progress&&b.set("progress",e.progress),e.re&&b.set("re","1"),e.sort){let u=e.sort.split("-"),v=u[0],k=u[1];b.set("sort",(k==="desc"?"-":"")+v)}let g=b.toString();if(e.metrics&&(g+=`${g?"&":""}metrics=${e.metrics.join(",")}`),e.f_date&&(g+=`${g?"&":""}f_date=${e.f_date.map(u=>u||"").join(",")}`),e.f_dist&&(g+=`${g?"&":""}f_dist=${e.f_dist.map(u=>u??"").join(",")}`),e.f_dur&&(g+=`${g?"&":""}f_dur=${e.f_dur.map(u=>u??"").join(",")}`),e.f_mets&&(g+=`${g?"&":""}f_mets=${e.f_mets.join(",")}`),e.f_tags&&(g+=`${g?"&":""}f_tags=${e.f_tags.join(",")}`),e.map_pos){let u=`${(+e.map_pos[0]).toFixed(5)},${(+e.map_pos[1]).toFixed(5)},${e.map_pos[2]}`;g+=`${g?"&":""}map_pos=${u}`}if(e.sel){let u=`${+e.sel[0].toFixed(4)},${+e.sel[1].toFixed(4)}`;g+=`${g?"&":""}sel=${u}`}if(n=g,g!==o){let v=(typeof location<"u"?location.pathname:"/")+(g?`?${g}`:""),k=d();a?(r.push({state:k,url:v}),r.length>100&&r.shift(),a=!1):r.length>0?r[r.length-1]={state:k,url:v}:r.push({state:k,url:v}),o=g}}e=d();function $(){return{...e}}function M(b,g=!1){g&&(a=!0);for(let[u,v]of Object.entries(b)){let k=u;v==null?delete e[k]:e[k]=v}T()}function F(){e=d()}function I(){i&&(clearTimeout(i),i=null),e={},a=!1,n="",o="",r=[{state:null,url:typeof location<"u"?location.pathname:"/"}]}return{read:d,get:$,patch:M,refresh:F,reset:I}})();var ws=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(s){return this.trackStore.set(s.id,s),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(s){return this.trackStore.delete(s),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(s,e){return this.settingStore.set(s,e),Promise.resolve()}async get(s){return Promise.resolve(this.settingStore.get(s)??null)}},zs=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((s,e)=>{let n=indexedDB.open(this.DB_NAME,this.DB_VERSION);n.onupgradeneeded=()=>{let o=n.result;o.objectStoreNames.contains("tracks")||o.createObjectStore("tracks",{keyPath:"id"}),o.objectStoreNames.contains("settings")||o.createObjectStore("settings")},n.onsuccess=()=>{this.db=n.result,s()},n.onerror=()=>e(n.error)})}getStore(s,e){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(s,e).objectStore(s)}async save(s){return new Promise((e,n)=>{let o=this.getStore("tracks","readwrite").put(s);o.onsuccess=()=>e(),o.onerror=()=>n(o.error)})}async getAll(){return new Promise((s,e)=>{let n=this.getStore("tracks","readonly").getAll();n.onsuccess=()=>s(n.result||[]),n.onerror=()=>e(n.error)})}async remove(s){return new Promise((e,n)=>{let o=this.getStore("tracks","readwrite").delete(s);o.onsuccess=()=>e(),o.onerror=()=>n(o.error)})}async clear(){return this.db?new Promise((s,e)=>{let n=this.db.transaction(["tracks","settings"],"readwrite");n.objectStore("tracks").clear(),n.objectStore("settings").clear(),n.oncomplete=()=>s(),n.onerror=()=>e(n.error)}):Promise.resolve()}async set(s,e){return new Promise((n,o)=>{let i=this.getStore("settings","readwrite").put(e,s);i.onsuccess=()=>n(),i.onerror=()=>o(i.error)})}async get(s){return new Promise((e,n)=>{let o=this.getStore("settings","readonly").get(s);o.onsuccess=()=>e(o.result??null),o.onerror=()=>n(o.error)})}},rn=new ws,ce={openDB:async()=>{rn=Gt.get().storage==="indexeddb"?new zs:new ws,await rn.openDB()},save:t=>rn.save(t),getAll:()=>rn.getAll(),remove:t=>rn.remove(t),clear:()=>rn.clear(),set:(t,s)=>rn.set(t,s),get:t=>rn.get(t)};import Al from"fit-file-parser";function en(t,s,e,n){let i=t*Math.PI/180,a=e*Math.PI/180,r=(e-t)*Math.PI/180,d=(n-s)*Math.PI/180,T=Math.sin(r/2)*Math.sin(r/2)+Math.cos(i)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2);return 6371e3*(2*Math.atan2(Math.sqrt(T),Math.sqrt(1-T)))}function wo(t){let s=new Uint32Array([Math.floor(t/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(s.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function To(){return Math.random().toString(36).slice(2,6)}function ze(t){return t<60?`${Math.round(t)}s`:t<3600?`${Math.round(t/60)}m`:`${Math.round(t/3600)}h`}function he(t){let s=Math.floor(t/3600),e=Math.floor(t%3600/60);return s>0?`${s}h ${e}m`:`${e}m ${Math.floor(t%60)}s`}function On(t){if(t==null||!isFinite(t))return"--";let s=Math.floor(t/60),e=Math.round(t%60);return`${s}:${e.toString().padStart(2,"0")}`}function nn(t){let s=new Date(t);return isNaN(s.getTime())?"Unknown date":s.toISOString().split("T")[0]}function So(t){let s=new Date(t);if(isNaN(s.getTime()))return"Unknown";let e=s.toISOString();return`${e.split("T")[0]} ${e.split("T")[1].slice(0,5)}`}function Mo(t){if(t===0)return"0 B";let s=1024,e=["B","KB","MB","GB"],n=Math.floor(Math.log(t)/Math.log(s));return`${parseFloat((t/Math.pow(s,n)).toFixed(2))} ${e[n]}`}function me(t){return String(t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function Ts(t){let s=0;for(let n=0;n=0&&M0?d/T:t[r]}return a}function le(t,s=1){let e=parseInt(t.slice(1,3),16),n=parseInt(t.slice(3,5),16),o=parseInt(t.slice(5,7),16);return`rgba(${e}, ${n}, ${o}, ${s})`}function Ss(t){if(!t.length)return null;let s=t[0].lat,e=t[0].lat,n=t[0].lon,o=t[0].lon;for(let i of t)i.late&&(e=i.lat),i.lono&&(o=i.lon);return{minLat:s,maxLat:e,minLon:n,maxLon:o}}var Ne=16384,Il=new Float64Array(Ne),Hl=new Float64Array(Ne),Fl=new Float64Array(Ne),Dl=new Float64Array(Ne),Bl=new Float64Array(Ne),_l=new Float64Array(Ne),Rl=new Float64Array(Ne);function Ms(t,s){let e=t.length;if(e<=2)return t;let n=e<=Ne?Il:new Float64Array(e),o=e<=Ne?Hl:new Float64Array(e),i=e<=Ne?Fl:new Float64Array(e),a=e<=Ne?Dl:new Float64Array(e);for(let I=0;I=b){let E=g+u>>1,_=(o[E]-(o[g]+o[u])*.5)*v,W=n[E]-(n[g]+n[u])*.5;d+=Math.sqrt(_*_+W*W)+(a[u]-a[g])*1e-6,g=u}}}let $=[t[0]],M=t[0],F=d<-1e9?1e-9:0;for(let I=1;I=s&&($.push(b),M=b)}return $.push(t[e-1]),$}var Jt=(()=>{function t(w){let y=w.length,m=0;for(let N=0;N0){let G=w[N-1],U=en(G.lat,G.lon,C.lat,C.lon);if(m+=U,C.speed==null&&C.time!=null&&G.time!=null){let j=(C.time-G.time)/1e3;j>0&&j<10&&(C.speed=U/j)}if(C.gradient===void 0&&C.ele!=null&&G.ele!=null){let j=C.ele-G.ele;U>.5?C.gradient=j/U*100:C.gradient=G.gradient||0}}C.dist=m}if(y>2){let N=y<=Ne?Bl:new Float64Array(y),C=y<=Ne?_l:new Float64Array(y),G=y<=Ne?Rl:new Float64Array(y);for(let nt=0;nt=$t){z-=C[it-$t],D-=G[it-$t];let K=z*ht,bt=N[it]-N[it-$t],Pt=1.225*Math.exp(-N[it]*Rt),ut=Math.atan2(bt,(D+1)*.5);j+=K*K*Pt*1e-4+ut*(D*ht)*.01}}let at=j<-1e12?1e-9:0;for(let nt=1;nt0){let Lt=w[Ht-1];if(dt.ele!=null&&Lt.ele!=null){let st=dt.ele-Lt.ele;st>0?m.elevGain+=st:m.elevLoss-=st}(dt.gearFront!=null&&dt.gearFront!==Lt.gearFront||dt.gearRear!=null&&dt.gearRear!==Lt.gearRear)&&K++}dt.power!=null&&(N+=dt.power,C++,dt.power>m.maxPower&&(m.maxPower=dt.power)),dt.hr!=null&&(G+=dt.hr,U++,dt.hr>m.maxHR&&(m.maxHR=dt.hr)),dt.cad!=null&&(j+=dt.cad,Rt++),dt.speed!=null&&(at+=dt.speed,nt++,dt.speed>m.maxSpeed&&(m.maxSpeed=dt.speed)),dt.battery!=null&&($t+=dt.battery,ht++),dt.temp!=null&&(it=!0,z+=dt.temp,D++,(m.minTemp==null||dt.tempm.maxTemp)&&(m.maxTemp=dt.temp)),(dt.gearFront!=null||dt.gearRear!=null)&&(bt=!0)}m.totalDist=w[w.length-1].dist||0,m.avgPower=C?Math.round(N/C):null,m.avgHR=U?Math.round(G/U):null,m.avgCadence=Rt?Math.round(j/Rt):null,m.avgSpeed=nt?at/nt:null,m.avgBattery=ht?Math.round($t/ht):null,m.avgTemp=D?Number((z/D).toFixed(1)):null,m.shifts=bt?K:null;let Pt=w[0].time,ut=w[w.length-1].time;return Pt!=null&&ut!=null&&(m.duration=ut-Pt),U&&(m.sensors.push("Heart Rate"),y&&(m.hrZones=b(w),m.hrCurve=$(w))),Rt&&m.sensors.push("Cadence"),C&&(m.sensors.push("Power"),y&&(m.powerCurve=T(w),m.powerZones=M(w))),it&&m.sensors.push("Temperature"),bt&&m.sensors.push("Shifting"),ht&&m.sensors.push("Battery"),m}function o(w){if(!w||!w.points||!w.stats)return;let y=w.points,m=w.stats;m.avgHR!=null&&!m.hrCurve&&(m.hrZones=b(y),m.hrCurve=$(y)),m.avgPower!=null&&!m.powerCurve&&(m.powerCurve=T(y),m.powerZones=M(y))}function i(w){let y=w.length;if(y<8)return[];let m=[],N=["Q1 Opening Sector","Q2 Mid-Climb Sector","Q3 Valley Tempo","Q4 Finale Sector"];for(let K=0;K<4;K++){let bt=Math.floor(K*y/4),Pt=Math.min(y-1,Math.floor((K+1)*y/4)-1);if(Pt>bt){let ut=w.slice(bt,Pt+1);m.push({id:`q${K+1}`,label:N[K],kind:"quarter",startIdx:bt,endIdx:Pt,stats:n(ut,!0)})}}let C=["Opening Third","Middle Third","Final Third"];for(let K=0;K<3;K++){let bt=Math.floor(K*y/3),Pt=Math.min(y-1,Math.floor((K+1)*y/3)-1);if(Pt>bt){let ut=w.slice(bt,Pt+1);m.push({id:`t${K+1}`,label:C[K],kind:"third",startIdx:bt,endIdx:Pt,stats:n(ut,!1)})}}let G=0,U=1e3,j=1;for(let K=1;K=U||K===y-1){if(K>G+2){let Pt=w.slice(G,K+1);m.push({id:`km-${j}`,label:`Km ${j}`,kind:"km",startIdx:G,endIdx:K,stats:n(Pt,!1)}),j++}G=K,U+=1e3}let Rt=30,at=!1,nt=0,$t=1,ht=!1,z=0,D=1,it=e*1.15;for(let K=Rt;K=1.8&&!at)at=!0,nt=K-Rt;else if((ut<.8||K===y-1)&&at&&(at=!1,K-nt>=45&&$t<=6)){let dt=w.slice(nt,K+1);m.push({id:`climb-${$t}`,label:`Climb Segment ${$t}`,kind:"climb",startIdx:nt,endIdx:K,stats:n(dt,!0)}),$t++}let Ht=w[K].power??0;if(Ht>=it&&!ht)ht=!0,z=K;else if((Ht=15&&D<=6)){let dt=w.slice(z,K+1);m.push({id:`sprint-${D}`,label:`Sprint Interval ${D}`,kind:"sprint",startIdx:z,endIdx:K,stats:n(dt,!0)}),D++}}return m}function a(w){let y=[];for(let m=0;mm)continue;let Rt=0,at=0,nt=m-j;for(let $t=0;$t<=nt;$t++){let ht=N[$t+j]-N[$t];ht>Rt&&(Rt=ht,at=$t)}C[j]={val:Math.round(Rt/j),idx:at},G=!0}return G?C:null}function T(w){let y=w.length,m=new Array(y),N=!1;for(let U=0;UN*e);for(let N=1;N10)continue;let j=C.power;jN===0)?null:y}function F(w){e=w}function I(){return e}function b(w){let y=[0,0,0,0,0];for(let m=1;m10)continue;let U=N.hr;Um===0)?null:y}function g(w){s=w}function u(){return[...s]}function v(w,y,m){let N=w.indexOf(y);if(N===-1)return null;let C=N+y.length,G=w.indexOf(m,C);if(G===-1)return null;let U=w.slice(C,G).trim();return U!==""?U:null}function k(w,y){let m=w.indexOf(y);if(m===-1)return null;let N=m+y.length,C=w.indexOf('"',N);return C===-1?null:w.slice(N,C)}let f=-1,h=0;function p(w,y,m){for(;yy&&w.charCodeAt(m-1)<=32;)m--;if(y>=m)return null;let N=!1,C=w.charCodeAt(y);C===45?(N=!0,y++):C===43&&y++;let G=0,U=0;for(let j=y;j=48&&Rt<=57)G=G*10+(Rt-48),U++;else break}return U===0?null:N?-G:G}function E(w,y,m){for(;yy&&w.charCodeAt(m-1)<=32;)m--;if(y>=m)return null;let N=!1,C=w.charCodeAt(y);C===45?(N=!0,y++):C===43&&y++;let G=0,U=0,j=1,Rt=!1,at=0;for(let $t=y;$t=48&&ht<=57)at++,Rt?(U=U*10+(ht-48),j*=10):G=G*10+(ht-48);else if(ht===46&&!Rt)Rt=!0;else{let z=parseFloat(w.slice(y-(N?1:0),m));return Number.isFinite(z)?z:null}}if(at===0)return null;let nt=G+U/j;return N?-nt:nt}function _(w,y,m){for(;yy&&w.charCodeAt(m-1)<=32;)m--;let N=m-y;if(N>=20&&w.charCodeAt(y+10)===84&&w.charCodeAt(m-1)===90){let G=(w.charCodeAt(y)-48)*1e3+(w.charCodeAt(y+1)-48)*100+(w.charCodeAt(y+2)-48)*10+(w.charCodeAt(y+3)-48),U=(w.charCodeAt(y+5)-48)*10+(w.charCodeAt(y+6)-48),j=(w.charCodeAt(y+8)-48)*10+(w.charCodeAt(y+9)-48),Rt=G<<9|U<<5|j;Rt!==f&&(f=Rt,h=Date.UTC(G,U-1,j));let at=(w.charCodeAt(y+11)-48)*10+(w.charCodeAt(y+12)-48),nt=(w.charCodeAt(y+14)-48)*10+(w.charCodeAt(y+15)-48),$t=(w.charCodeAt(y+17)-48)*10+(w.charCodeAt(y+18)-48),ht=0;return w.charCodeAt(y+19)===46&&N>=24&&(ht=(w.charCodeAt(y+20)-48)*100+(w.charCodeAt(y+21)-48)*10+(w.charCodeAt(y+22)-48)),h+at*36e5+nt*6e4+$t*1e3+ht}let C=new Date(w.slice(y,m)).getTime();return Number.isFinite(C)?C:null}function W(w,y,m,N){let C=w.indexOf(N,y);if(C===-1||C>=m)return 0;let G=C+N.length,U=w.indexOf('"',G);return U===-1||U>=m?0:E(w,G,U)??0}function O(w,y){let m=y??new TextDecoder().decode(w),N=m.indexOf(""),U=(G!==-1?v(C.slice(G),"",""):null)||v(C,"","")||"Unnamed Track",j=C.indexOf(">",C.indexOf("",z+6);if(D===-1)break;let it=m.indexOf("",D+1);if(it===-1)break;nt=it+8;let K=W(m,z+6,D+1,'lat="'),bt=W(m,z+6,D+1,'lon="'),Pt=null,ut=null,Ht=null,dt=null,Lt=null,st=null,gt=null,At=null,zt=null,V=null,R=null,Dt=null,It=D+1;for(;It=it)break;let vt=m.indexOf(">",Et+1);if(vt===-1||vt>=it)break;let yt=m.charCodeAt(Et+1);if(yt===47){It=vt+1;continue}let _t=vt-Et-1;if(yt===103&&_t===26&&Ht!==null&&dt!==null&&st!==null)break;let qt=m.indexOf("<",vt+1);if(qt===-1||qt>it)break;if(m.charCodeAt(qt+1)===47){let Yt=vt+1,ee=qt;_t===3?yt===101?Pt=E(m,Yt,ee):yt===99&&dt===null&&(dt=p(m,Yt,ee)):_t===2?yt===104&&Ht===null&&(Ht=p(m,Yt,ee)):_t===4?yt===116?m.charCodeAt(Et+2)===105?ut=_(m,Yt,ee):st===null&&(st=E(m,Yt,ee)):yt===84&&st===null&&(st=E(m,Yt,ee)):_t===5?(yt===112||yt===80||yt===87)&&Lt===null?Lt=E(m,Yt,ee):(yt===115||yt===83)&>===null?gt=E(m,Yt,ee):yt===97&&st===null&&(st=E(m,Yt,ee)):_t===7?(yt===98||yt===66)&&Dt===null?Dt=p(m,Yt,ee):yt===67&&dt===null&&(dt=p(m,Yt,ee)):_t===8?(yt===103||yt===71)&&zt===null&&(zt=p(m,Yt,ee)):_t===9?yt===103?m.charCodeAt(Et+8)===104&&Ht===null?Ht=p(m,Yt,ee):At===null&&(At=p(m,Yt,ee)):yt===71&&At===null&&(At=p(m,Yt,ee)):_t===10?(yt===103&&dt===null||yt===82&&dt===null)&&(dt=p(m,Yt,ee)):_t===12?yt===103&&m.charCodeAt(Et+8)===97&&st===null?st=E(m,Yt,ee):yt===80&&Lt===null?Lt=E(m,Yt,ee):yt===72&&Ht===null&&(Ht=p(m,Yt,ee)):_t===13?(yt===103||yt===71)&&R===null&&(R=p(m,Yt,ee)):_t===14?(yt===103||yt===71)&&V===null?V=p(m,Yt,ee):yt===65&&st===null&&(st=E(m,Yt,ee)):_t===11&&yt===84&&st===null&&(st=E(m,Yt,ee));let xe=qt+2+_t;if(m.charCodeAt(xe)===62)It=xe+1;else{let De=m.indexOf(">",qt+2);It=De!==-1?De+1:qt+2}if(Dt!==null&&Ht!==null&&dt!==null&&st!==null)break}else It=qt}let Wt=null;V!=null&&R!=null&&R!==0?Wt=V/R:At!=null&&zt!=null&&zt!==0&&(Wt=At/zt),at.push({lat:K,lon:bt,ele:Pt,time:ut,hr:Ht,cad:dt,power:Lt,speed:gt,temp:st,gearFront:At,gearRear:zt,gearFrontTooth:V,gearRearTooth:R,battery:Dt,gears:Wt})}if(!at.length)throw new Error("No track points found in GPX");let $t=t(at),ht=n($t);return{name:U,device:Rt,format:"gpx",points:$t,stats:ht}}function Y(w,y){let m=y??new TextDecoder().decode(w),N=m.indexOf(""),C=N!==-1?m.slice(0,N):m,G=v(C,"","")||"Unnamed TCX",U=v(C,"",""),j=U?v(U,"",""):null,Rt=[],at=N!==-1?N:0;for(;at",at);if(ht===-1)break;let z=m.indexOf("",ht+12);if(z===-1)break;at=z+13;let D=null,it=null,K=null,bt=null,Pt=null,ut=null,Ht=null,dt=null,Lt=null,st=null,gt=null,At=null,zt=null,V=null,R=ht+12;for(;R=z)break;let Wt=m.indexOf(">",It+1);if(Wt===-1||Wt>=z)break;let Et=m.charCodeAt(It+1);if(Et===47){R=Wt+1;continue}let vt=Wt-It-1,yt=m.indexOf("<",Wt+1);if(yt===-1||yt>z)break;if(m.charCodeAt(yt+1)===47){let _t=Wt+1,qt=yt;vt===4?Et===84?m.charCodeAt(It+2)===105?bt=_(m,_t,qt):Lt===null&&(Lt=E(m,_t,qt)):Et===116&&Lt===null&&(Lt=E(m,_t,qt)):vt===5?Et===86&&Pt===null?Pt=p(m,_t,qt):(Et===87||Et===80||Et===112)&&Ht===null?Ht=E(m,_t,qt):(Et===83||Et===115)&&dt===null?dt=E(m,_t,qt):Et===97&&Lt===null&&(Lt=E(m,_t,qt)):vt===7?Et===67&&ut===null?ut=p(m,_t,qt):(Et===66||Et===98)&&V===null&&(V=p(m,_t,qt)):vt===8?(Et===71||Et===103)&>===null&&(gt=p(m,_t,qt)):vt===9?(Et===71||Et===103)&&st===null&&(st=p(m,_t,qt)):vt===10?Et===82&&ut===null&&(ut=p(m,_t,qt)):vt===11?Et===84&&Lt===null&&(Lt=E(m,_t,qt)):vt===13?(Et===71||Et===103)&&zt===null&&(zt=p(m,_t,qt)):vt===14?Et===65?m.charCodeAt(It+2)===108?K=E(m,_t,qt):Lt===null&&(Lt=E(m,_t,qt)):(Et===71||Et===103)&&At===null&&(At=p(m,_t,qt)):vt===15?Et===76&&(D=E(m,_t,qt)):vt===16?Et===76&&(it=E(m,_t,qt)):vt===2&&Et===104&&Pt===null?Pt=p(m,_t,qt):vt===3&&Et===99&&ut===null?ut=p(m,_t,qt):vt===12&&(Et===72&&Pt===null?Pt=p(m,_t,qt):Et===80&&Ht===null&&(Ht=E(m,_t,qt)));let Yt=yt+2+vt;if(m.charCodeAt(Yt)===62)R=Yt+1;else{let ee=m.indexOf(">",yt+2);R=ee!==-1?ee+1:yt+2}if(V!==null&&Pt!==null&&ut!==null&&Lt!==null)break}else R=yt}if(D==null||it==null)continue;let Dt=null;At!=null&&zt!=null&&zt!==0?Dt=At/zt:st!=null&>!=null&>!==0&&(Dt=st/gt),Rt.push({lat:D,lon:it,ele:K,time:bt,hr:Pt,cad:ut,power:Ht,speed:dt,temp:Lt,gearFront:st,gearRear:gt,gearFrontTooth:At,gearRearTooth:zt,battery:V,gears:Dt})}let nt=t(Rt),$t=n(nt);return{name:G,device:j,format:"tcx",points:nt,stats:$t}}function Z(w){if(w.byteLength<14)return null;let y=new DataView(w),m=y.getUint8(0);if(m<12||m+2>w.byteLength||y.getUint8(8)!==46||y.getUint8(9)!==70||y.getUint8(10)!==73||y.getUint8(11)!==84)return null;let N=y.getUint32(4,!0),C=Math.min(w.byteLength,m+N),G=631065600,U=180/Math.pow(2,31),j=new Array(16),Rt=[],at=[],nt=[],$t=[],ht=[],z=m;for(;zC)return null;z++;let bt=y.getUint8(z++)===0,Pt=y.getUint16(z,bt);z+=2;let ut=y.getUint8(z++);if(z+ut*3>C)return null;let Ht=new Array(ut),dt=0;for(let Lt=0;LtC)return null;let bt=K.littleEndian,Pt=K.globalMsgNum;if(Pt===20&&K.fields.length===10&&K.recordSize===25&&K.fields[0].num===253&&K.fields[1].num===0){let dt=y.getUint32(z,bt),Lt=y.getInt32(z+4,bt),st=y.getInt32(z+8,bt),gt=y.getUint16(z+12,bt),At=y.getUint8(z+14),zt=y.getUint8(z+15),V=y.getUint32(z+16,bt),R=y.getUint16(z+20,bt),Dt=y.getUint16(z+22,bt),It=y.getInt8(z+24);nt.push({timestamp:(dt+G)*1e3,position_lat:Lt*U,position_long:st*U,altitude:gt/5-500,heart_rate:At,cadence:zt,distance:V/100,speed:R/1e3*3.6,power:Dt,temperature:It}),z+=25;continue}let ut={},Ht=z;for(let dt=0;dt{let N=(U,j)=>{if(U){m(U);return}try{let Rt=j.sessions?.[0]?.start_time?`Fit Activity ${new Date(j.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",at=null,nt=[],$t=null,ht=null;j.sports?.[0]?($t=j.sports[0].sport,ht=j.sports[0].sub_sport):j.sessions?.[0]&&($t=j.sessions[0].sport,ht=j.sessions[0].sub_sport);let z=V=>V.product_name||V.garmin_product||V.product||V.device_type||V.manufacturer||null;if(j.file_ids?.[0]){let V=j.file_ids[0];at=z(V),nt.push({name:V.product_name||V.garmin_product||V.product,manufacturer:V.manufacturer,serial:V.serial_number?String(V.serial_number):void 0,version:V.software_version?String(V.software_version):void 0,type:"main"})}j.device_infos&&j.device_infos.forEach(V=>{if(V.device_index==="creator"||V.device_index===0){let Dt=z(V);(V.product_name||V.garmin_product||!at)&&(at=Dt),nt.length>0&&nt[0].type==="main"&&((V.product_name||V.garmin_product||!nt[0].name)&&(nt[0].name=V.product_name||V.garmin_product||V.product),nt[0].manufacturer||(nt[0].manufacturer=V.manufacturer),!nt[0].serial&&V.serial_number&&(nt[0].serial=String(V.serial_number)),!nt[0].version&&V.software_version&&(nt[0].version=String(V.software_version)),!nt[0].hardwareVersion&&V.hardware_version&&(nt[0].hardwareVersion=String(V.hardware_version)));return}nt.push({name:V.product_name||V.garmin_product||V.product||V.device_type||"Sensor",manufacturer:V.manufacturer,serial:V.serial_number?String(V.serial_number):void 0,version:V.software_version?String(V.software_version):void 0,hardwareVersion:V.hardware_version?String(V.hardware_version):void 0,type:V.device_type||"sensor",batteryStatus:V.battery_status,batteryVoltage:V.battery_voltage,batteryLevel:V.battery_level,sourceType:V.source_type!=null?String(V.source_type):void 0})}),j.sensor_settings&&j.sensor_settings.forEach(V=>{let R=V.name||V.product||V.sensor_type;if(!R)return;let Dt=V.ant_id?String(V.ant_id):void 0,It=nt.find(Wt=>Dt&&Wt.serial===Dt||Wt.name===R&&Wt.manufacturer===V.manufacturer);It?(It.name||(It.name=R),It.manufacturer||(It.manufacturer=V.manufacturer),It.type||(It.type=V.sensor_type),It.sourceType||(It.sourceType=V.connection_type!=null?String(V.connection_type):void 0)):nt.push({name:R,manufacturer:V.manufacturer,serial:Dt,type:V.sensor_type||"sensor",sourceType:V.connection_type!=null?String(V.connection_type):void 0})});let D=[];j.device_statuses&&(j.device_statuses.forEach((V,R)=>{V.timestamp&&V.battery_level!=null&&D.push({time:typeof V.timestamp=="number"?V.timestamp:new Date(V.timestamp).getTime(),level:V.battery_level,idx:R})}),D.sort((V,R)=>V.time-R.time||V.idx-R.idx));let it=[];j.events&&(j.events.forEach((V,R)=>{let Dt=V.front_gear_num??V.front_gear??null,It=V.rear_gear_num??V.rear_gear??null,Wt=V.front_gear_num_tooth??null,Et=V.rear_gear_num_tooth??null;if(V.event==="rear_gear_change"||V.event==="front_gear_change"){let vt=V.data;if(vt!=null){let yt=vt>>24&255,_t=vt>>16&255,qt=vt>>8&255,Yt=vt&255;_t!==0&&(Dt=_t),yt!==0&&(Wt=yt),Yt!==0&&(It=Yt),qt!==0&&(Et=qt)}}V.timestamp&&(Dt!=null||It!=null||Wt!=null||Et!=null)&&it.push({time:typeof V.timestamp=="number"?V.timestamp:new Date(V.timestamp).getTime(),front:Dt,rear:It,frontTooth:Wt,rearTooth:Et,idx:R})}),it.sort((V,R)=>V.time-R.time||V.idx-R.idx));let K=j.records||[],bt=null,Pt=0,ut=null,Ht=null,dt=null,Lt=null,st=0,gt=[];for(let V=0;V name, Placemark > name");C&&(N=C.textContent?.trim()||N);let G=m.querySelectorAll("coordinates");if(!G.length)throw new Error("No coordinates found in KML");let U=[];if(G.forEach(at=>{(at.textContent?.trim().split(/\s+/)||[]).forEach($t=>{let ht=$t.split(",");if(ht.length<2)return;let z=parseFloat(ht[0]),D=parseFloat(ht[1]),it=ht.length>2?parseFloat(ht[2]):null;isNaN(D)||isNaN(z)||U.push({lat:D,lon:z,ele:it!=null&&isNaN(it)?null:it,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!U.length)throw new Error("No valid coordinates in KML");let j=t(U),Rt=n(j);return{name:N,format:"kml",points:j,stats:Rt}}async function rt(w){let y=w.name.split(".").pop()?.toLowerCase(),m=w._buf??await w.arrayBuffer(),N=w._text,C;switch(y){case"gpx":C=O(m,N);break;case"tcx":C=Y(m,N);break;case"fit":C=await lt(m);break;case"kml":C=Ft(m);break;default:throw new Error(`Unsupported format: .${y}`)}return C&&(C.fileName=w.name,C.fileSize=w.size,C.points&&C.stats&&(o(C),C.stats.sections=i(C.points))),C}return{parseFile:rt,computeStats:n,ensureCurvesAndZones:o,analyzeTrackSections:i,findOverlaps:a,calculatePowerCurve:T,calculateHRCurve:$,calculatePowerZones:M,calculateHRZones:b,enrichPoints:t,setHRZones:g,getHRZones:u,setFTP:F,getFTP:I}})();var Bt=(()=>{let t={},s=null;function e(Z,lt,Ft,rt,w){}function n(Z){}function o(Z){t[Z.id]=Z}function i(Z){Z.forEach(lt=>{t[lt.id]=lt})}function a(Z){delete t[Z]}function r(){t={}}function d(){t={}}function T(Z,lt){}function $(Z,lt){}function M(){}function F(Z){}function I(Z,lt){}function b(){}function g(Z,lt,Ft,rt,w,y){}function u(){}function v(Z,lt){}function k(Z){}function f(Z,lt,Ft,rt){}function h(){}function p(){}function E(){return[0,0,0]}function _(Z,lt,Ft){}function W(Z,lt,Ft){}function O(Z){}function Y(Z,lt){return Object.keys(t)}return{init:e,getMap:()=>null,setCustomClickHandler:Z=>{s=Z},switchBasemap:n,addTrack:o,addTracks:i,removeTrack:a,clearTracks:r,removeAllTracks:d,setTrackVisible:T,setSelectedTrack:$,fitAll:M,fitTrack:F,showCursorAt:I,hideCursor:b,highlightSegment:g,clearHighlight:u,setTrackHover:v,ensureVisible:k,centerOn:f,closePopup:h,invalidateSize:p,getPosition:E,setPosition:_,colorTrackByMetric:W,clearMetricColor:O,findTracksPassingThroughPoints:Y,getTrackData:Z=>t[Z]}})();import ko from"uplot";var $n=(()=>{function t(){let e=Jt.getFTP(),n=[.55,.75,.9,1.05,1.2,1.5].map(d=>d*e),o=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],i=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],a=[],r=0;for(let d=0;ds?t.toFixed(1):Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:Nt.speed.color,abbr:"spd",icon:Nt.speed.icon,fmt:t=>(t*3.6).toFixed(1),fmtAxis:t=>(t*3.6).toFixed(0),transform:t=>t,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:Nt.gradient.color,abbr:"grad",icon:Nt.gradient.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>t.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:Nt.power.color,abbr:"pwr",icon:Nt.power.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:Nt.hr.color,abbr:"hr",icon:Nt.hr.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:Nt.cadence.color,abbr:"cad",icon:Nt.cadence.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:Nt.temperature.color,abbr:"temp",icon:Nt.temperature.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>Math.round(t).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:Nt.gearRear.color,abbr:"rgr",icon:Nt.gearRear.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:Nt.gearFront.color,abbr:"fgr",icon:Nt.gearFront.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gears:{label:"Gears",field:"gears",unit:"",color:Nt.gears.color,abbr:"gr",icon:Nt.gears.icon,fmt:t=>t.toFixed(2),fmtAxis:t=>t.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:Nt.battery.color,abbr:"bat",icon:Nt.battery.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString(),smoothSigma:5,compute:(t,s)=>{let e=new Array(t.length).fill(null);for(let n=1;n0&&(e[n]=a/r*3600)}}return s(e)}}};var Ye={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function Eo(t){if(!t)return"question_mark";let s=t.toLowerCase();return Ye[s]?.icon||"exercise"}var ft=(()=>{let t=[],s=null,e="time",n="speed",o=null,i=null,a=!1,r=!1,d=new Set(["elevation"]),T=new Set,$=new Set(["speed","gradient","vam","temperature"]),M=new Set(["power"]),F="time",I=null,b=[],g=null,u=null,v=!1,k=!1,f=null,h=null,p=null,E=null,_=null,W=null,O=null,Y=null,Z=null,lt=null,Ft=null,rt=null,w=130,y=28,m=20,N=!0,C=null,G=null,U=null,j=null,Rt=null,at=null,nt=null;function $t(l,c,x,S){Z=l,lt=c,Ft=x,rt=S,G=document.getElementById("charts-container"),G?.addEventListener("scroll",()=>{p&&_&&E&&so(p,_,E)}),U=document.getElementById("chart-empty"),j=document.getElementById("chart-stats-sel"),Rt=document.getElementById("btn-reset-selection"),C=document.getElementById("hist-tooltip"),i=ko.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",R),Rt?.classList.add("hidden");let H=new Set(["w","a","s","d"]),P=new Set;document.addEventListener("keydown",B=>{if(!t.length||!I||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let A=B.key.toLowerCase();if(!H.has(A))return;B.preventDefault(),P.add(A);let q=t[0].uplot;O||(O=[q.scales.x.min,q.scales.x.max]);let[J,X]=O,et=(X-J)*.1,tt=.15,L=J,wt=X;if(A==="a")L=J-et,wt=X-et;else if(A==="d")L=J+et,wt=X+et;else if(A==="w"||A==="s"){let ct=h!==null?h:(J+X)/2,Ct=A==="w"?1-tt:1+tt*1.2;L=ct-(ct-J)*Ct,wt=ct+(X-ct)*Ct}let St=[t[0].xData[0],t[0].xData[t[0].xData.length-1]];if(LSt[1]){let ct=wt-St[1];L-=ct,wt-=ct}L=Math.max(St[0],L),wt=Math.min(St[1],wt),wt-L>.001&&(O=[L,wt],ht(L,wt,!0))}),document.addEventListener("keyup",B=>{let A=B.key.toLowerCase();H.has(A)&&P.delete(A)})}function ht(l,c,x=!1){if(!t.length)return;if(!x){t.forEach(({uplot:q})=>q.setScale("x",{min:l,max:c}));return}let S=W?W[0]:t[0].uplot.scales.x.min,H=W?W[1]:t[0].uplot.scales.x.max;Y&&cancelAnimationFrame(Y);let P=(q,J,X)=>q+(J-q)*X,B=.25,A=()=>{if(!O)return;let[q,J]=O,X=P(W[0],q,B),Q=P(W[1],J,B);t.forEach(({uplot:et})=>{et.setScale("x",{min:X,max:Q})}),Math.abs(X-q)>1e-4||Math.abs(Q-J)>1e-4?Y=requestAnimationFrame(A):Y=null};Y=requestAnimationFrame(A)}function z(l,c=[],x=!1){f=null,g=null,u=null,b=c,T=new Set(Object.entries(qe).filter(([,S])=>l.points.some(H=>H[S.field]!=null)).map(([S])=>S)),d.size===0&&(d=new Set(["elevation"].filter(S=>T.has(S)))),document.querySelectorAll(".metric-pill").forEach(S=>{let H=S,P=H.dataset.metric,B=T.has(P);H.classList.toggle("active",B&&d.has(P)),H.classList.toggle("disabled",!B)}),I=l,x?po(l):vt()}function D(){f=null,g=null,u=null,I=null,Rn(),U&&(U.style.display="flex",U.innerHTML=` no_sim
Select a track to view analysis
- `);let o=document.getElementById("chart-stats");o&&o.classList.add("hidden"),It(),at=null,nt&&nt(null)}function it(){Y!==null&&(cancelAnimationFrame(Y),Y=null),d=new Set(["elevation"]),w=new Set,g=new Set(["speed","gradient","vam","temperature"]),f=new Set(["power"]),A="time",$=[],W=null,O=null,b=null,p=null,S=null,_=null,N=!0,D(),document.querySelectorAll("#metric-pills .metric-pill").forEach(y=>{let T=y;T.classList.toggle("active",d.has(T.dataset.metric)),T.classList.remove("disabled","overflow-hidden")});let o=document.getElementById("pill-overflow");o&&o.classList.add("hidden");let r=document.getElementById("chart-toolbar");r&&r.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(y=>{y.classList.toggle("active",y.dataset.axis==="time")})}function K(o){d.has(o)?d.delete(o):d.add(o),C&&vt(!0)}function bt(o,r,y=!1){let T=g.has(o);r&&!T?(g.add(o),C&&!y&&vt(!0)):!r&&T&&(g.delete(o),C&&!y&&vt(!0))}function Pt(o,r){let y=f.has(o);r&&!y?(f.add(o),C&&vt(!0)):!r&&y&&(f.delete(o),C&&vt(!0))}function ut(o){d=new Set(o),C&&vt(!0),document.querySelectorAll(".metric-pill").forEach(r=>{let y=r;y.classList.toggle("active",d.has(y.dataset.metric))})}function Ht(o){if(A===o||!C){A=o;return}let r=C.points,y=r.find(L=>L.time!=null)?.time||0,T=L=>{if(L===null)return null;let B=0;if(A==="distance"){let H=L*1e3;B=r.findIndex(q=>(q.dist||0)>=H)}else{let H=y+L*1e3;B=r.findIndex(q=>(q.time||0)>=H)}return B===-1&&(B=r.length-1),o==="distance"?(r[B].dist||0)/1e3:((r[B].time||y)-y)/1e3};M!==null&&(M=T(M)),m!==null&&(m=T(m));let F=null;if(t.length){let L=t[0].uplot,B=T(L.scales.x.min),H=T(L.scales.x.max);B!==null&&H!==null&&(F=[B,H])}A=o,vt(!0),F&&(a=!0,t.forEach(({uplot:L})=>{L.batch(()=>L.setScale("x",{min:F[0],max:F[1]}))}),a=!1)}function dt(){N=!N,t.forEach(({histCol:o})=>o.classList.toggle("visible",N)),Et()}function Lt(o){nt=o}function st(o,r=!1){at===o||o===null?(at=null,gt(),nt&&nt(null)):(at=o,gt(),At()),C&&!r&&vt(!0)}function gt(){document.querySelectorAll(".map-color-btn").forEach(o=>{let r=o;r.classList.toggle("active",r.dataset.metric===at)})}function At(){if(!nt||!at||!C)return;let o=t.find(y=>y.metricKey===at);if(!o)return;let r=zt(at,o.yData);nt({pts:C.points,colors:r})}function zt(o,r){let y=r.filter(Q=>Q!=null&&isFinite(Q));if(!y.length)return r.map(()=>"#888896");let T=Math.min(...y),F=Math.max(...y),L=C?.sport,B=L?Ye[L.toLowerCase()]:null,H=B?.defaultPreset||"speed",J=Gt.get().speed_mode||H,X=B?.paceUnit||"km";return r.map(Q=>{if(Q==null||!isFinite(Q))return"#888896";if(o==="gradient")return is(Q);if(o==="speed"){if(J==="pace"){let tt=(X==="km"?1e3:100)/Q;return uo(tt)}return uo(Q)}let et=F===T?.5:Math.max(0,Math.min(1,(Q-T)/(F-T)));return et<=.25?Ve("#4575b4","#91bfdb",et/.25):et<=.5?Ve("#91bfdb","#fee090",(et-.25)/.25):et<=.75?Ve("#fee090","#fc8d59",(et-.5)/.25):Ve("#fc8d59","#d73027",(et-.75)/.25)})}function V(){R()}function R(){M=null,m=null,h=null,rt&&rt(null),t.forEach(o=>{o.pinnedHistY=null}),_t(),De(),a=!0,t.forEach(({uplot:o,xData:r})=>{o.batch(()=>o.setScale("x",{min:r[0],max:r[r.length-1]})),o._strasse?.updateHeaderStats(r[0],r[r.length-1])}),a=!1,lt&<(null,null,A)}function Dt(o){if(!j)return;let r=(y,T)=>{let F=document.querySelector(`#${y} .stat-value`);F&&(F.textContent=T)};r("sel-distance",o.totalDist!=null?`${(o.totalDist/1e3).toFixed(1)} km`:"\u2014"),r("sel-duration",o.duration!=null?he(Math.floor(o.duration/1e3)):"\u2014"),r("sel-elevation",o.elevGain!=null?`${Math.round(o.elevGain)} m`:"\u2014"),r("sel-avg-speed",o.avgSpeed!=null?`${(o.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),r("sel-avg-power",o.avgPower!=null?`${o.avgPower} W`:"\u2014"),r("sel-avg-hr",o.avgHR!=null?`${o.avgHR} bpm`:"\u2014"),r("sel-avg-temp",o.avgTemp!=null?`${o.avgTemp.toFixed(1)} \xB0C`:"\u2014"),j.classList.remove("hidden"),Rt&&Rt.classList.remove("hidden")}function It(){j&&j.classList.add("hidden"),Rt&&Rt.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(o=>{let r=document.querySelector(`#${o} .stat-value`);r&&(r.textContent="--")})}function Wt(o,r,y=!1){if(!C)return;let T=C.points,F=T.find(J=>J.time!=null)?.time||0,L=((T[T.length-1]?.time||0)-F)/1e3;o>1e12&&(o=(o-F)/1e3),r>1e12&&(r=(r-F)/1e3),o=Math.max(0,Math.min(o,L)),r=Math.max(0,Math.min(r,L));let B=J=>{if(A==="time")return J;let X=F+J*1e3,Q=T.findIndex(et=>(et.time||0)>=X);return Q===-1&&(Q=T.length-1),(T[Q].dist||0)/1e3},H=B(o),q=B(r);M=H,m=q,W=[H,q],!y&&(a=!0,t.forEach(({uplot:J})=>{J.batch(()=>J.setScale("x",{min:H,max:q}))}),a=!1,qt(),De())}function Et(){if(!t.length||!G)return;let o=Math.round(Math.max(100,G.getBoundingClientRect().width-v-(N?x+u:0))),r=!1;t.forEach(({uplot:y,histCanvas:T,histData:F})=>{o!==y.width&&(y.setSize({width:o,height:y.height}),r=!0,N&&T&&F&&Le(T,F,y.height))}),r&&_t()}function vt(o=!1){let r=null,y=0;if(o&&G&&(y=G.scrollTop),o&&W)r=[W[0],W[1]];else if(o&&t.length){let St=t[0].uplot;r=[St.scales.x.min,St.scales.x.max]}if(!C){Rn(o);return}let T=C.points;if(!T.length){Rn(o);return}let F=C?.sport,L=F?Ye[F.toLowerCase()]:null,B=L?.defaultPreset||"speed",q=Gt.get().speed_mode||B,J=L?.paceUnit||"km",X=[...d].filter(St=>T.some(ct=>ct[qe[St].field]!=null));if(!X.length){Rn(o),U&&(U.style.display="flex",U.innerHTML=` + `);let l=document.getElementById("chart-stats");l&&l.classList.add("hidden"),It(),at=null,nt&&nt(null)}function it(){Y!==null&&(cancelAnimationFrame(Y),Y=null),d=new Set(["elevation"]),T=new Set,$=new Set(["speed","gradient","vam","temperature"]),M=new Set(["power"]),F="time",b=[],W=null,O=null,h=null,p=null,E=null,_=null,N=!0,D(),document.querySelectorAll("#metric-pills .metric-pill").forEach(x=>{let S=x;S.classList.toggle("active",d.has(S.dataset.metric)),S.classList.remove("disabled","overflow-hidden")});let l=document.getElementById("pill-overflow");l&&l.classList.add("hidden");let c=document.getElementById("chart-toolbar");c&&c.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(x=>{x.classList.toggle("active",x.dataset.axis==="time")})}function K(l){d.has(l)?d.delete(l):d.add(l),I&&vt(!0)}function bt(l,c,x=!1){let S=$.has(l);c&&!S?($.add(l),I&&!x&&vt(!0)):!c&&S&&($.delete(l),I&&!x&&vt(!0))}function Pt(l,c){let x=M.has(l);c&&!x?(M.add(l),I&&vt(!0)):!c&&x&&(M.delete(l),I&&vt(!0))}function ut(l){d=new Set(l),I&&vt(!0),document.querySelectorAll(".metric-pill").forEach(c=>{let x=c;x.classList.toggle("active",d.has(x.dataset.metric))})}function Ht(l){if(F===l||!I){F=l;return}let c=I.points,x=c.find(P=>P.time!=null)?.time||0,S=P=>{if(P===null)return null;let B=0;if(F==="distance"){let A=P*1e3;B=c.findIndex(q=>(q.dist||0)>=A)}else{let A=x+P*1e3;B=c.findIndex(q=>(q.time||0)>=A)}return B===-1&&(B=c.length-1),l==="distance"?(c[B].dist||0)/1e3:((c[B].time||x)-x)/1e3};g!==null&&(g=S(g)),u!==null&&(u=S(u));let H=null;if(t.length){let P=t[0].uplot,B=S(P.scales.x.min),A=S(P.scales.x.max);B!==null&&A!==null&&(H=[B,A])}F=l,vt(!0),H&&(a=!0,t.forEach(({uplot:P})=>{P.batch(()=>P.setScale("x",{min:H[0],max:H[1]}))}),a=!1)}function dt(){N=!N,t.forEach(({histCol:l})=>l.classList.toggle("visible",N)),Et()}function Lt(l){nt=l}function st(l,c=!1){at===l||l===null?(at=null,gt(),nt&&nt(null)):(at=l,gt(),At()),I&&!c&&vt(!0)}function gt(){document.querySelectorAll(".map-color-btn").forEach(l=>{let c=l;c.classList.toggle("active",c.dataset.metric===at)})}function At(){if(!nt||!at||!I)return;let l=t.find(x=>x.metricKey===at);if(!l)return;let c=zt(at,l.yData);nt({pts:I.points,colors:c})}function zt(l,c){let x=c.filter(Q=>Q!=null&&isFinite(Q));if(!x.length)return c.map(()=>"#888896");let S=Math.min(...x),H=Math.max(...x),P=I?.sport,B=P?Ye[P.toLowerCase()]:null,A=B?.defaultPreset||"speed",J=Gt.get().speed_mode||A,X=B?.paceUnit||"km";return c.map(Q=>{if(Q==null||!isFinite(Q))return"#888896";if(l==="gradient")return is(Q);if(l==="speed"){if(J==="pace"){let tt=(X==="km"?1e3:100)/Q;return uo(tt)}return uo(Q)}let et=H===S?.5:Math.max(0,Math.min(1,(Q-S)/(H-S)));return et<=.25?Ve("#4575b4","#91bfdb",et/.25):et<=.5?Ve("#91bfdb","#fee090",(et-.25)/.25):et<=.75?Ve("#fee090","#fc8d59",(et-.5)/.25):Ve("#fc8d59","#d73027",(et-.75)/.25)})}function V(){R()}function R(){g=null,u=null,f=null,rt&&rt(null),t.forEach(l=>{l.pinnedHistY=null}),_t(),De(),a=!0,t.forEach(({uplot:l,xData:c})=>{l.batch(()=>l.setScale("x",{min:c[0],max:c[c.length-1]})),l._strasse?.updateHeaderStats(c[0],c[c.length-1])}),a=!1,lt&<(null,null,F)}function Dt(l){if(!j)return;let c=(x,S)=>{let H=document.querySelector(`#${x} .stat-value`);H&&(H.textContent=S)};c("sel-distance",l.totalDist!=null?`${(l.totalDist/1e3).toFixed(1)} km`:"\u2014"),c("sel-duration",l.duration!=null?he(Math.floor(l.duration/1e3)):"\u2014"),c("sel-elevation",l.elevGain!=null?`${Math.round(l.elevGain)} m`:"\u2014"),c("sel-avg-speed",l.avgSpeed!=null?`${(l.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),c("sel-avg-power",l.avgPower!=null?`${l.avgPower} W`:"\u2014"),c("sel-avg-hr",l.avgHR!=null?`${l.avgHR} bpm`:"\u2014"),c("sel-avg-temp",l.avgTemp!=null?`${l.avgTemp.toFixed(1)} \xB0C`:"\u2014"),j.classList.remove("hidden"),Rt&&Rt.classList.remove("hidden")}function It(){j&&j.classList.add("hidden"),Rt&&Rt.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(l=>{let c=document.querySelector(`#${l} .stat-value`);c&&(c.textContent="--")})}function Wt(l,c,x=!1){if(!I)return;let S=I.points,H=S.find(J=>J.time!=null)?.time||0,P=((S[S.length-1]?.time||0)-H)/1e3;l>1e12&&(l=(l-H)/1e3),c>1e12&&(c=(c-H)/1e3),l=Math.max(0,Math.min(l,P)),c=Math.max(0,Math.min(c,P));let B=J=>{if(F==="time")return J;let X=H+J*1e3,Q=S.findIndex(et=>(et.time||0)>=X);return Q===-1&&(Q=S.length-1),(S[Q].dist||0)/1e3},A=B(l),q=B(c);g=A,u=q,W=[A,q],!x&&(a=!0,t.forEach(({uplot:J})=>{J.batch(()=>J.setScale("x",{min:A,max:q}))}),a=!1,qt(),De())}function Et(){if(!t.length||!G)return;let l=Math.round(Math.max(100,G.getBoundingClientRect().width-y-(N?w+m:0))),c=!1;t.forEach(({uplot:x,histCanvas:S,histData:H})=>{l!==x.width&&(x.setSize({width:l,height:x.height}),c=!0,N&&S&&H&&Le(S,H,x.height))}),c&&_t()}function vt(l=!1){let c=null,x=0;if(l&&G&&(x=G.scrollTop),l&&W)c=[W[0],W[1]];else if(l&&t.length){let St=t[0].uplot;c=[St.scales.x.min,St.scales.x.max]}if(!I){Rn(l);return}let S=I.points;if(!S.length){Rn(l);return}let H=I?.sport,P=H?Ye[H.toLowerCase()]:null,B=P?.defaultPreset||"speed",q=Gt.get().speed_mode||B,J=P?.paceUnit||"km",X=[...d].filter(St=>S.some(ct=>ct[qe[St].field]!=null));if(!X.length){Rn(l),U&&(U.style.display="flex",U.innerHTML=` no_sim
No data for selected metrics
- `);return}U&&(U.style.display="none");let Q=G?G.getBoundingClientRect().width:800,et=Math.round(Math.max(100,Q-v-(N?x+u:0))),tt=o&&n===C&&s===A&&e===q&&l===at&&t.length>0,I;if(tt)I=t[0].xData;else if(A==="distance")I=T.map(St=>(St.dist||0)/1e3);else{let St=T.find(Ct=>Ct.time!=null)?.time||0,ct=0;I=T.map(Ct=>(Ct.time!=null&&(ct=(Ct.time-St)/1e3),ct))}let wt=new Map;if(tt){E&&(E.style.display="none");let St=new Set(X);for(let ct of t){let Ct=g.has(ct.metricKey),pt=f.has(ct.metricKey);St.has(ct.metricKey)&&ct.smoothed===Ct&&ct.incZero===pt&&ct.w===et?wt.set(ct.metricKey,ct):(i.unsub(ct.uplot),ct.uplot.destroy(),ct.row.remove())}t=[]}else Rn(o);if(G){let St=new Array(X.length).fill(null),ct=null;for(let Ct=X.length-1;Ct>=0;Ct--){St[Ct]=ct;let pt=wt.get(X[Ct]);pt&&(ct=pt.row)}X.forEach((Ct,pt)=>{let xt=wt.get(Ct);if(xt){t.push(xt);let mt=xt.uplot,Kt=mt._strasse,Xt=a;a=!0,mt.batch(()=>{r&&(mt.scales.x.min!==r[0]||mt.scales.x.max!==r[1])?mt.setScale("x",{min:r[0],max:r[1]}):(Kt?.updateHeaderStats(mt.scales.x.min,mt.scales.x.max,mt),mt.redraw(!1))}),a=Xt;let te=null;if(h!=null&&xt.xData[h]!=null&&xt.yData[h]!=null&&(xe(xt.histData),xt.histData.min!=null&&xt.histData.max!=null)){let de=xt.histData.max-xt.histData.min||1;te=Math.min(xt.histData.BINS-1,Math.floor((xt.yData[h]-xt.histData.min)/de*xt.histData.BINS)),xt.hoveredHistY=xt.yData[h]}Le(xt.histCanvas,xt.histData,130,te);return}let kt=qe[Ct],Ot=kt.transform,Vt=kt.fmt,ne=kt.fmtAxis,ie=kt.unit,re=kt.label;Ct==="speed"&&q==="pace"&&(re="Pace",ie=`min/${J}`,Vt=mt=>On(mt),ne=mt=>On(mt),Ot=mt=>mt==null||mt<.1?null:(J==="km"?1e3:100)/mt,kt={...kt,label:re,unit:ie,fmt:Vt,fmtAxis:ne,transform:Ot});let ae=kt.compute?kt.compute(T,mo):mo(T.map(mt=>{let Kt=mt[kt.field];return Kt!=null&&Ot?Ot(Kt):Kt}));g.has(Ct)&&(ae=Cn(ae,kt.smoothSigma||2)),yt(Ct,kt,I,ae,et,T,r,St[pt])})}n=C,s=A,e=q,l=at,po(C),M!=null&&m!=null&&qt(),gt(),at&&At(),o&&G&&y>0&&(G.scrollTop=y)}function yt(o,r,y,T,F,L,B=null,H=null){let q=C?.sport,X=(q?Ye[q.toLowerCase()]:null)?.defaultPreset||"speed",et=Gt.get().speed_mode||X,tt=o==="elevation"?Sl(L,20):null,I=document.createElement("div");I.className="chart-row",I.dataset.metric=o,I.style.setProperty("--chart-color",r.color);let wt=document.createElement("div");wt.className=`chart-row-header${N?" with-histogram":""}`;let St=document.createElement("div");St.className="chart-row-label-group",St.innerHTML=` - ${r.icon} - ${r.label} - `;let ct=document.createElement("button");ct.className=`icon-btn mini smooth-btn${g.has(o)?" active":""}`,ct.title="Toggle data smoothing",ct.innerHTML=`${g.has(o)?"blur_on":"blur_off"}`,ct.addEventListener("click",ot=>{ot.stopPropagation(),g.has(o)?g.delete(o):g.add(o),vt(!0)});let Ct=document.createElement("button");Ct.className=`map-color-btn icon-btn${at===o?" active":""}`,Ct.dataset.metric=o,Ct.title="Color map track by this metric",Ct.innerHTML='colorize',Ct.addEventListener("click",()=>st(o));let pt=null;if(o==="cadence"||o==="power"||o==="speed"){pt=document.createElement("button");let ot=f.has(o);pt.className=`icon-btn mini${ot?" active":""}`,pt.title=ot?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",pt.innerHTML=`${ot?"exposure_zero":"mobile_off"}`,pt.addEventListener("click",Mt=>{Mt.stopPropagation(),f.has(o)?f.delete(o):f.add(o),vt(!0)})}let xt=document.createElement("div");xt.className="chart-stats-total";let kt=document.createElement("div");kt.className="chart-stats-selection";let Ot=document.createElement("div");Ot.className="chart-row-stats-container",Ot.append(xt,kt);let Vt=document.createElement("div");Vt.className="chart-row-actions",Vt.append(ct,Ct);let ne=document.createElement("div");if(ne.className="chart-row-right-actions",o==="speed"){let ot=document.createElement("div");ot.className="seg-ctrl",ot.innerHTML=` + `);return}U&&(U.style.display="none");let Q=G?G.getBoundingClientRect().width:800,et=Math.round(Math.max(100,Q-y-(N?w+m:0))),tt=l&&s===I&&e===F&&n===q&&o===at&&t.length>0,L;if(tt)L=t[0].xData;else if(F==="distance")L=S.map(St=>(St.dist||0)/1e3);else{let St=S.find(Ct=>Ct.time!=null)?.time||0,ct=0;L=S.map(Ct=>(Ct.time!=null&&(ct=(Ct.time-St)/1e3),ct))}let wt=new Map;if(tt){C&&(C.style.display="none");let St=new Set(X);for(let ct of t){let Ct=$.has(ct.metricKey),pt=M.has(ct.metricKey);St.has(ct.metricKey)&&ct.smoothed===Ct&&ct.incZero===pt&&ct.w===et?wt.set(ct.metricKey,ct):(i.unsub(ct.uplot),ct.uplot.destroy(),ct.row.remove())}t=[]}else Rn(l);if(G){let St=new Array(X.length).fill(null),ct=null;for(let Ct=X.length-1;Ct>=0;Ct--){St[Ct]=ct;let pt=wt.get(X[Ct]);pt&&(ct=pt.row)}X.forEach((Ct,pt)=>{let xt=wt.get(Ct);if(xt){t.push(xt);let mt=xt.uplot,Kt=mt._strasse,Xt=a;a=!0,mt.batch(()=>{c&&(mt.scales.x.min!==c[0]||mt.scales.x.max!==c[1])?mt.setScale("x",{min:c[0],max:c[1]}):(Kt?.updateHeaderStats(mt.scales.x.min,mt.scales.x.max,mt),mt.redraw(!1))}),a=Xt;let te=null;if(f!=null&&xt.xData[f]!=null&&xt.yData[f]!=null&&(xe(xt.histData),xt.histData.min!=null&&xt.histData.max!=null)){let de=xt.histData.max-xt.histData.min||1;te=Math.min(xt.histData.BINS-1,Math.floor((xt.yData[f]-xt.histData.min)/de*xt.histData.BINS)),xt.hoveredHistY=xt.yData[f]}Le(xt.histCanvas,xt.histData,130,te);return}let kt=qe[Ct],Ot=kt.transform,Vt=kt.fmt,ne=kt.fmtAxis,ie=kt.unit,re=kt.label;Ct==="speed"&&q==="pace"&&(re="Pace",ie=`min/${J}`,Vt=mt=>On(mt),ne=mt=>On(mt),Ot=mt=>mt==null||mt<.1?null:(J==="km"?1e3:100)/mt,kt={...kt,label:re,unit:ie,fmt:Vt,fmtAxis:ne,transform:Ot});let ae=kt.compute?kt.compute(S,mo):mo(S.map(mt=>{let Kt=mt[kt.field];return Kt!=null&&Ot?Ot(Kt):Kt}));$.has(Ct)&&(ae=Cn(ae,kt.smoothSigma||2)),yt(Ct,kt,L,ae,et,S,c,St[pt])})}s=I,e=F,n=q,o=at,po(I),g!=null&&u!=null&&qt(),gt(),at&&At(),l&&G&&x>0&&(G.scrollTop=x)}function yt(l,c,x,S,H,P,B=null,A=null){let q=I?.sport,X=(q?Ye[q.toLowerCase()]:null)?.defaultPreset||"speed",et=Gt.get().speed_mode||X,tt=l==="elevation"?Tl(P,20):null,L=document.createElement("div");L.className="chart-row",L.dataset.metric=l,L.style.setProperty("--chart-color",c.color);let wt=document.createElement("div");wt.className=`chart-row-header${N?" with-histogram":""}`;let St=document.createElement("div");St.className="chart-row-label-group",St.innerHTML=` + ${c.icon} + ${c.label} + `;let ct=document.createElement("button");ct.className=`icon-btn mini smooth-btn${$.has(l)?" active":""}`,ct.title="Toggle data smoothing",ct.innerHTML=`${$.has(l)?"blur_on":"blur_off"}`,ct.addEventListener("click",ot=>{ot.stopPropagation(),$.has(l)?$.delete(l):$.add(l),vt(!0)});let Ct=document.createElement("button");Ct.className=`map-color-btn icon-btn${at===l?" active":""}`,Ct.dataset.metric=l,Ct.title="Color map track by this metric",Ct.innerHTML='colorize',Ct.addEventListener("click",()=>st(l));let pt=null;if(l==="cadence"||l==="power"||l==="speed"){pt=document.createElement("button");let ot=M.has(l);pt.className=`icon-btn mini${ot?" active":""}`,pt.title=ot?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",pt.innerHTML=`${ot?"exposure_zero":"mobile_off"}`,pt.addEventListener("click",Mt=>{Mt.stopPropagation(),M.has(l)?M.delete(l):M.add(l),vt(!0)})}let xt=document.createElement("div");xt.className="chart-stats-total";let kt=document.createElement("div");kt.className="chart-stats-selection";let Ot=document.createElement("div");Ot.className="chart-row-stats-container",Ot.append(xt,kt);let Vt=document.createElement("div");Vt.className="chart-row-actions",Vt.append(ct,Ct);let ne=document.createElement("div");if(ne.className="chart-row-right-actions",l==="speed"){let ot=document.createElement("div");ot.className="seg-ctrl",ot.innerHTML=` - `,ot.addEventListener("click",Mt=>{let se=Mt.target.closest(".seg-btn");if(!se)return;let oe=se.dataset.mode;if(oe==="speed"||oe==="pace"){let jt=oe===X;Gt.patch({speed_mode:jt?null:oe}),vt(!0)}}),ne.append(ot)}pt&&ne.append(pt),wt.append(St,Vt,Ot,ne);let ie=document.createElement("div");ie.className="chart-row-body";let re=document.createElement("div");re.style.position="relative",ie.appendChild(re);let ae=document.createElement("div");ae.className="fixed-x-label fixed-x-min";let mt=document.createElement("div");mt.className="fixed-x-label fixed-x-max",re.append(ae,mt);let Kt=document.createElement("div");Kt.className=`hist-col${N?" visible":""}`;let Xt=document.createElement("canvas");Xt.className="hist-canvas",Kt.appendChild(Xt),ie.appendChild(Kt),I.append(wt,ie);let te=A==="distance";function de(ot,Mt){if(ot==null)return"";if(te){let se=Mt<1?3:Mt<5?2:Mt<20?1:0;return`${ot.toFixed(se)} km`}else{let se=Math.abs(ot),oe=Math.floor(se/3600),jt=Math.floor(se%3600/60),Ce=Math.round(se%60),ye=oe>0?`${oe}:`:"",Oe=oe>0?String(jt).padStart(2,"0"):String(jt),Re=String(Ce).padStart(2,"0");return`${ot<0?"-":""}${ye}${Oe}:${Re}`}}let fe=f.has(o)||o!=="power"&&o!=="cadence"&&o!=="speed",ge=1/0,Qt=-1/0,ue=0,Me=0,Be=1/0,Je=-1/0,Ae=0,on=0;for(let ot=0;otQt&&(Qt=Mt),ue+=Mt,Me++,(Mt!==0||fe)&&(MtJe&&(Je=Mt),Ae+=Mt,on++))}Me===0&&(ge=0,Qt=100);let _s=Me?{min:ge,max:Qt,avg:ue/Me}:null,cs=on?{min:Be,max:Je,avg:Ae/on}:null,ho=Math.abs(Qt-ge)*.1||1,kl=[ge-ho,Qt+ho],bo=!1;function Rs(ot,Mt,se){let oe=f.has(o)||o!=="power"&&o!=="cadence"&&o!=="speed",jt=Mt-ot;ae.textContent=de(ot,jt),mt.textContent=de(Mt,jt);let Ce=(ye,Oe,Re=!1)=>{let We=Re&&oe===fe?cs:oo(y,T,ye,Oe,oe);if(!We)return"";let an=` - align_flex_end${r.fmt(We.min,!0)} ${r.unit} - align_center${r.fmt(We.avg,!0)} ${r.unit} - align_flex_start${r.fmt(We.max,!0)} ${r.unit} - `;if(o==="elevation"){let Ge=bl(L,ye,Oe);an+=` + `,ot.addEventListener("click",Mt=>{let se=Mt.target.closest(".seg-btn");if(!se)return;let oe=se.dataset.mode;if(oe==="speed"||oe==="pace"){let jt=oe===X;Gt.patch({speed_mode:jt?null:oe}),vt(!0)}}),ne.append(ot)}pt&&ne.append(pt),wt.append(St,Vt,Ot,ne);let ie=document.createElement("div");ie.className="chart-row-body";let re=document.createElement("div");re.style.position="relative",ie.appendChild(re);let ae=document.createElement("div");ae.className="fixed-x-label fixed-x-min";let mt=document.createElement("div");mt.className="fixed-x-label fixed-x-max",re.append(ae,mt);let Kt=document.createElement("div");Kt.className=`hist-col${N?" visible":""}`;let Xt=document.createElement("canvas");Xt.className="hist-canvas",Kt.appendChild(Xt),ie.appendChild(Kt),L.append(wt,ie);let te=F==="distance";function de(ot,Mt){if(ot==null)return"";if(te){let se=Mt<1?3:Mt<5?2:Mt<20?1:0;return`${ot.toFixed(se)} km`}else{let se=Math.abs(ot),oe=Math.floor(se/3600),jt=Math.floor(se%3600/60),Ce=Math.round(se%60),ye=oe>0?`${oe}:`:"",Oe=oe>0?String(jt).padStart(2,"0"):String(jt),Re=String(Ce).padStart(2,"0");return`${ot<0?"-":""}${ye}${Oe}:${Re}`}}let fe=M.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",ge=1/0,Qt=-1/0,ue=0,Me=0,Be=1/0,Je=-1/0,Ae=0,on=0;for(let ot=0;otQt&&(Qt=Mt),ue+=Mt,Me++,(Mt!==0||fe)&&(MtJe&&(Je=Mt),Ae+=Mt,on++))}Me===0&&(ge=0,Qt=100);let _s=Me?{min:ge,max:Qt,avg:ue/Me}:null,cs=on?{min:Be,max:Je,avg:Ae/on}:null,ho=Math.abs(Qt-ge)*.1||1,El=[ge-ho,Qt+ho],bo=!1;function Rs(ot,Mt,se){let oe=M.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",jt=Mt-ot;ae.textContent=de(ot,jt),mt.textContent=de(Mt,jt);let Ce=(ye,Oe,Re=!1)=>{let We=Re&&oe===fe?cs:oo(x,S,ye,Oe,oe);if(!We)return"";let an=` + align_flex_end${c.fmt(We.min,!0)} ${c.unit} + align_center${c.fmt(We.avg,!0)} ${c.unit} + align_flex_start${c.fmt(We.max,!0)} ${c.unit} + `;if(l==="elevation"){let Ge=hl(P,ye,Oe);an+=` trending_up+${Math.round(Ge.gain)} m trending_down-${Math.round(Ge.loss)} m - `}return an};bo||(bo=!0,xt.innerHTML=`all_inclusive${Ce(y[0],y[y.length-1],!0)}`,xt.querySelector(".all-chip")?.addEventListener("click",ye=>{ye.stopPropagation(),R()})),M!==null&&m!==null?(kt.innerHTML=Ce(M,m,!1),kt.style.display="flex",kt.style.setProperty("--sel-color",r.color)):kt.style.display="none"}let Cl=!1,$l={width:F,height:130,padding:[4,0,0,0],cursor:{sync:{key:i.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:o==="elevation"?(ot,Mt)=>is(tt?tt[ot.cursor.idx]:null):r.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(ot,Mt,se)=>[Mt,se],min:B?B[0]:void 0,max:B?B[1]:void 0},y:{range:()=>kl,dir:o==="speed"&&et==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(ot,Mt,se,oe)=>{let jt=oe-se,ye=(ot.bbox.width>0?ot.bbox.width:ot.width)/80,Oe=jt/ye,Re;te?Re=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:Re=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let We=Re[Re.length-1];for(let Ze=0;Ze=Oe){We=Re[Ze];break}let an=[],Ge=Math.ceil(se/We)*We,vs=We<1?2:0;for(;Ge<=oe;){let Ze=ot.valToPos(Ge,"x",!0);Ze>=ot.bbox.left+80&&Ze<=ot.bbox.left+ot.bbox.width-80&&an.push(Number(Ge.toFixed(vs))),Ge+=We}return an},values:(ot,Mt)=>{let se=(ot.scales.x?.max??1)-(ot.scales.x?.min??0);return Mt.map(oe=>{if(oe==null)return"";let jt=ot.valToPos(oe,"x",!0);return jtot.bbox.left+ot.bbox.width-80?null:de(oe,se)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(ot,Mt)=>Mt.map(se=>se!=null?r.fmtAxis(se):"")}],series:[{},{label:r.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[ot=>{let Mt=ot.bbox.top+ot.bbox.height+5;ae.style.top=`${Mt}px`,ae.style.left=`${ot.bbox.left}px`,mt.style.top=`${Mt}px`,mt.style.left=`${ot.bbox.left+ot.bbox.width}px`,mt.style.transform="translateX(-100%)"},ot=>{o==="gears"?go(ot,y,T,r.color,1.5,o,null,L):o==="elevation"?vl(ot,y,T,tt):o==="gradient"?yl(ot,y,T):at===o?El(ot,y,T,L,o):go(ot,y,T,r.color,1.5,o,null,L)},ot=>{let Mt=t.find(oe=>oe.uplot===ot);if(!Mt)return;let se=ot._strasse;h!=null?xl(ot,y,T,r.color,r,L,o):(se&&se.pinYVal&&(se.pinYVal.style.display="none"),Mt.pinnedHistY!=null&&wl(ot,y,T,Mt.pinnedHistY,r.color,r))},ot=>{let Mt=ot.cursor.idx,se=h!=null,oe=Mt!=null&&ot.cursor.left>=0;if(oe&&h==null){let jt=ot.valToPos(T[Mt],"y",!0);Math.abs(ot.cursor.top-jt)>100&&(oe=!1)}if(oe&&Mt!==h&&ro(ot,L,Mt,le(r.color,.4),1),M!=null&&m!=null){let jt=ot.ctx,Ce=window.devicePixelRatio||1,ye=ot.bbox,Oe=ot.valToPos(M,"x",!0),Re=ot.valToPos(m,"x",!0);jt.save(),jt.beginPath(),jt.lineWidth=3*Ce,jt.strokeStyle=r.color,jt.moveTo(Oe,ye.top+ye.height),jt.lineTo(Re,ye.top+ye.height),jt.stroke();let We=Math.abs(m-M),an=A==="distance"?`${We.toFixed(2)} km`:he(We),Ge=9*Ce,vs=`bold ${Ge}px system-ui, sans-serif`;jt.font!==vs&&(jt.font=vs);let Ze=jt.measureText(an).width,yo=Math.max(ye.left,Oe),xo=Math.min(ye.left+ye.width,Re);if(xo-yo>Ze+14*Ce){let Ll=5*Ce,Al=2*Ce,ys=Ze+Ll*2,xs=Ge+Al*2,Ws=(yo+xo)/2-ys/2,qs=ye.top+ye.height-xs/2;jt.beginPath(),jt.roundRect?jt.roundRect(Ws,qs,ys,xs,3*Ce):jt.rect(Ws,qs,ys,xs),jt.fillStyle=r.color,jt.fill(),jt.fillStyle="#000",jt.textAlign="center",jt.textBaseline="middle",jt.fillText(an,Ws+ys/2,qs+xs/2)}jt.restore()}se&&co(ot,L,h,r.color,!0,.7),oe&&Mt!==h&&co(ot,L,Mt,r.color,!0,1)}],setCursor:[ot=>{if(a)return;let Mt=ot.cursor.idx;ot.redraw(!1),ot.cursor.left>=0?b=ot.posToVal(ot.cursor.left,"x"):b=null;let se=ot._strasse,oe=Mt!=null&&T[Mt]!=null;if(oe&&h==null){let jt=ot.valToPos(T[Mt],"y",!0);Math.abs(ot.cursor.top-jt)>100&&(oe=!1)}if(se&&(oe?lo(ot,se.curYVal,Mt,y,T,L,r,o):se.curYVal.style.display="none"),c||(Mt!=null&&L[Mt]?Z&&(h!=null||oe)?Z(L[Mt]):Z&&!oe&&Z(null):Mt===null&&Z&&Z(null)),Mt!=null&&T[Mt]!=null){let{min:jt,max:Ce}=ke;if(jt!=null&&Ce!=null){let ye=Ce-jt||1,Oe=Math.min(ke.BINS-1,Math.floor((T[Mt]-jt)/ye*ke.BINS));ln.hoveredHistY!==T[Mt]&&(ln.hoveredHistY=T[Mt],Le(Xt,ke,130,Oe))}}else ln.hoveredHistY!==null&&(ln.hoveredHistY=null,Le(Xt,ke,130))}],setScale:[(ot,Mt)=>{if(Mt!=="x"||Cl)return;let{min:se,max:oe}=ot.scales.x;W=[se,oe],Rs(se,oe,ot),!a&&(P||(O=null),a=!0,t.forEach(({uplot:jt})=>{jt!==ot&&jt.batch(()=>jt.setScale("x",{min:se,max:oe}))}),a=!1,_t(),De(),lt&&M!==null&<(M,m,A))}],setSelect:[ot=>{if(P)return;O=null;let{left:Mt,width:se}=ot.select;if(se>0){let oe=ot.posToVal(Mt,"x"),jt=ot.posToVal(Mt+se,"x");M=oe,m=jt,Rs(ot.scales.x.min,ot.scales.x.max,ot),_t(),De(),lt&<(M,m,A),ot.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},Ns=document.createElement("div");Ns.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let ds=document.createElement("div");ds.className="sel-fill",ds.style.display="none";let us=document.createElement("div");us.className="sel-line sel-line-anchor",us.style.display="none";let ms=document.createElement("div");ms.className="sel-line-label sel-line-label-anchor",ms.style.display="none";let qn=document.createElement("div");qn.className="sel-handle sel-handle-anchor",qn.style.display="none";let zn=document.createElement("div");zn.className="sel-graph-marker",zn.innerHTML=`play_circle`,zn.style.display="none";let ps=document.createElement("div");ps.className="sel-line sel-line-end",ps.style.display="none";let fs=document.createElement("div");fs.className="sel-line-label sel-line-label-end",fs.style.display="none";let Un=document.createElement("div");Un.className="sel-handle sel-handle-end",Un.style.display="none";let Vn=document.createElement("div");Vn.className="sel-graph-marker",Vn.innerHTML=`stop_circle`,Vn.style.display="none";let gs=document.createElement("div");gs.className="cur-y-val",gs.style.cssText=`color:${r.color};display:none`;let hs=document.createElement("div");hs.className="cur-y-val pin",hs.style.cssText=`color:${r.color};display:none`,Ns.append(ds,us,ms,qn,zn,ps,fs,Un,Vn,gs,hs);let ke={yData:T,xData:y,def:r,BINS:24,min:Me?ge:void 0,max:Me?Qt:void 0,fullStats:cs,fullStatsAll:_s},ln={uplot:null,row:I,xData:y,yData:T,def:r,metricKey:o,statsTotalEl:xt,statsSelEl:kt,histCol:Kt,histCanvas:Xt,histData:ke,hoveredHistY:null,pinnedHistY:null,smoothed:g.has(o),incZero:f.has(o),w:F};ke.plot=ln;let Pl=a;a=!0;let tn=new ko($l,[y,T],(ot,Mt)=>{ln.uplot=ot,t.push(ln),re.appendChild(ot.root),ot.over.appendChild(Ns),ot._strasse={selFill:ds,anchorLine:us,anchorLabel:ms,anchorHandle:qn,anchorMarker:zn,endLine:ps,endLabel:fs,endHandle:Un,endMarker:Vn,curYVal:gs,pinYVal:hs,updateHeaderStats:Rs},ot.batch(()=>{Mt()})});a=Pl,ee(qn,tn,y,!0),ee(Un,tn,y,!1);let bs=null;tn.over.addEventListener("mousedown",ot=>{if(ot.button!==0)return;k=!1;let Mt=tn.over.getBoundingClientRect();bs=ot.clientX-Mt.left}),tn.over.addEventListener("mousemove",ot=>{if(bs!==null){let Mt=tn.over.getBoundingClientRect();Math.abs(ot.clientX-Mt.left-bs)>5&&(k=!0)}}),tn.over.addEventListener("mouseup",()=>{bs=null}),tn.over.addEventListener("click",()=>{if(k)return;let ot=tn.cursor.idx;ot!=null&&L[ot]&&(h=ot,t.forEach(({uplot:Mt})=>Mt.redraw(!1)),Ft&&Ft(L[ot],ot),rt&&rt(ot))}),I.addEventListener("dblclick",R);let vo=null;if(h!=null&&y[h]!=null&&T[h]!=null&&(xe(ke),ke.min!=null&&ke.max!=null)){let ot=ke.max-ke.min||1;vo=Math.min(ke.BINS-1,Math.floor((T[h]-ke.min)/ot*ke.BINS)),ln.hoveredHistY=T[h]}Le(Xt,ke,130,vo),_n(Xt,ke),G&&(H?G.insertBefore(I,H):G.appendChild(I))}function _t(){qt(),t.forEach(({uplot:o})=>o.batch(()=>o.redraw(!1)))}function qt(){t.forEach(({uplot:o,def:r})=>{let y=o._strasse;if(!y)return;let{selFill:T,anchorLine:F,anchorLabel:L,anchorHandle:B,anchorMarker:H,endLine:q,endLabel:J,endHandle:X,endMarker:Q}=y;if(M==null||m==null){[T,F,L,B,H,q,J,X,Q].forEach(Vt=>{Vt.style.display="none"});return}let et=o.valToPos(M,"x"),tt=o.valToPos(m,"x"),I=window.devicePixelRatio||1,wt=o.bbox,St=wt.width/I,ct=wt.height/I,Ct=(wt.top+wt.height)/I,pt=et>=0&&et<=St,xt=tt>=0&&tt<=St,kt=Math.max(0,et),Ot=Math.min(St,tt);if(Ot>kt?(T.style.left=`${kt}px`,T.style.width=`${Ot-kt}px`,T.style.top="0",T.style.height=`${ct}px`,T.style.backgroundColor=le(r.color,.07),T.style.display=""):T.style.display="none",pt){F.style.left=`${et}px`,F.style.height=`${ct}px`,F.style.borderLeftColor=r.color,F.style.display="";let Vt=Yt(M);L.textContent=Vt;let ne=Vt.length*7+10;L.style.left=et+ne+4Vt.style.display="none");if(xt){q.style.left=`${tt}px`,q.style.height=`${ct}px`,q.style.borderLeftColor=r.color,q.style.display="";let Vt=Yt(m);J.textContent=Vt;let ne=Vt.length*7+10;J.style.left=tt-ne-3>0?`${tt-ne-3}px`:`${tt+3}px`,J.style.display="",X.style.left=`${tt}px`,X.style.backgroundColor=r.color,X.style.display="",Q.style.left=`${tt}px`,Q.style.top=`${Ct}px`;let ie=Q.querySelector(".material-symbols-rounded");ie&&(ie.style.color=r.color),Q.style.display=""}else[q,J,X,Q].forEach(Vt=>Vt.style.display="none")})}function Yt(o){return A==="distance"?`${o.toFixed(2)} km`:he(o)}function ee(o,r,y,T){o.style.pointerEvents="auto",o.addEventListener("mousedown",F=>{F.stopPropagation(),F.preventDefault();let L=F.clientX,B=T?M:m,H=r.over.offsetWidth,q=r.scales.x.min,J=r.scales.x.max,X=H/(J-q),Q=[y[0],y[y.length-1]];document.body.style.cursor="ew-resize",k=!0;function et(I){let wt=I.clientX-L,St=(B||0)+wt/X;St=Math.max(Q[0],Math.min(Q[1],St)),T?M=Math.min(St,(m||Q[1])-.001):m=Math.max(St,(M||Q[0])+.001),t.forEach(ct=>ct.uplot._strasse?.updateHeaderStats(ct.uplot.scales.x.min,ct.uplot.scales.x.max)),_t(),De(),lt&<(M,m,A)}function tt(){document.body.style.cursor="",k=!1,document.removeEventListener("mousemove",et),document.removeEventListener("mouseup",tt)}document.addEventListener("mousemove",et),document.addEventListener("mouseup",tt)})}function xe(o){let{yData:r,xData:y,BINS:T}=o;if(o._lastYData===r&&o.bins)return;o._lastYData=r;let F=o.min,L=o.max;if(F==null||L==null){let Q=1/0,et=-1/0,tt=0;for(let I=0;Iet&&(et=wt),tt++)}if(!tt)return;F=Q,L=et,o.min=F,o.max=L}let B=new Array(T).fill(0),H=new Array(T).fill(0),q=L-F||1,J=o.plot?.metricKey??Object.keys(qe).find(Q=>qe[Q]===o.def),X=!J||f.has(J)||J!=="power"&&J!=="cadence"&&J!=="speed";for(let Q=0;Q0&&y[Q-1]!=null?y[Q-1]:y[Q],wt=Q{Le(o,r,y.height)})}function Le(o,r,y,T=null){let{def:F,BINS:L}=r;xe(r);let{bins:B,min:H,max:q}=r;if(!B||H==null||q==null)return;let J=M!=null&&m!=null;if(J&&(r._lastSelRange?.[0]!==M||r._lastSelRange?.[1]!==m)){r._lastSelRange=[M,m];let mt=new Array(L).fill(0),Kt=new Array(L).fill(0),{yData:Xt,xData:te}=r,de=q-H||1,fe=r.plot?.metricKey??Object.keys(qe).find(Qt=>qe[Qt]===r.def),ge=!fe||f.has(fe)||fe!=="power"&&fe!=="cadence"&&fe!=="speed";for(let Qt=0;Qtm)continue;let Be=Math.min(L-1,Math.floor((ue-H)/de*L));mt[Be]++;let Je=Qt>0&&te[Qt-1]!=null?te[Qt-1]:te[Qt],Ae=QtF.fmtAxis(mt),ct="9px system-ui, sans-serif";I.font!==ct&&(I.font=ct);let pt={t:4,r:0,b:30,l:Math.ceil(Math.max(I.measureText(`${St(q)} ${F.unit}`).width,I.measureText(`${St(H)} ${F.unit}`).width))+6};r.padL=pt.l;let xt=et-pt.l-pt.r,kt=tt-pt.t-pt.b,Ot=mt=>pt.t+(L-1-mt)*(kt/L),Vt=kt/L-1,ne=J?.15:.6;I.fillStyle=le(F.color,ne);for(let mt=0;mtmt+Kt,0);if(ie>0){let mt=[{x:pt.l,y:pt.t+kt}],Kt=0;for(let Xt=0;XtXt+te+2&&mt0){let mt=0;for(let ue=0;ue{let F=no(o,r,T);if(F!=null&&y){let{min:L,max:B,BINS:H}=r,q=B-L||1;y.pinnedHistY=L+(F+.5)*(q/H),t.forEach(({uplot:J})=>J.redraw(!1))}}),o.addEventListener("mousemove",T=>{p=T,so(T,o,r)}),o.addEventListener("mouseenter",()=>{_=o,S=r}),o.addEventListener("mouseleave",()=>{_===o&&(_=null,S=null),E&&(E.style.display="none");let T=document.getElementById("hist-line");T&&(T.style.display="none"),y&&(y.hoveredHistY=null,Le(o,r,o.height/(window.devicePixelRatio||1)))})}function no(o,r,y){let{bins:T,BINS:F}=r;if(!T)return null;let L=o.getBoundingClientRect(),B=y.clientY-L.top,H={t:4,b:30},q=L.height-H.t-H.b,J=Math.floor((B-H.t)/q*F),X=F-1-J;return J<0||J>=F?null:X}function so(o,r,y){if(!E)return;let{bins:T,binAccum:F,min:L,max:B,BINS:H,def:q,plot:J}=y;if(!T||!F||L==null||B==null)return;let X=document.getElementById("hist-line"),Q=no(r,y,o);if(Q==null||!T[Q]){E.style.display="none",X&&(X.style.display="none"),J&&(J.hoveredHistY=null,Le(r,y,r.height/(window.devicePixelRatio||1)));return}if(J){let te=B-L||1;J.hoveredHistY=L+(Q+.5)*(te/H),Le(r,y,r.height/(window.devicePixelRatio||1),Q)}let et=T[Q],tt=T.reduce((te,de)=>te+de,0),I=et/tt*100,wt=B-L||1,St=L+Q*(wt/H),ct=L+(Q+1)*(wt/H),Ct=`${q.fmt(St,!0)} \u2013 ${q.fmt(ct,!0)} ${q.unit}`,pt="",xt=(St+ct)/2,kt=Object.keys(qe).find(te=>qe[te]===q),Ot=[];if(kt==="power"?Ot=$n.getPowerZones():kt==="hr"&&(Ot=$n.getHRZones()),Ot.length>0){let te=Ot.findIndex(fe=>xt>=fe.min&&xt=Ot[Ot.length-1].min?Ot[Ot.length-1]:null;if(de){let fe=te!==-1?te:Ot.length-1;pt=` + `}return an};bo||(bo=!0,xt.innerHTML=`all_inclusive${Ce(x[0],x[x.length-1],!0)}`,xt.querySelector(".all-chip")?.addEventListener("click",ye=>{ye.stopPropagation(),R()})),g!==null&&u!==null?(kt.innerHTML=Ce(g,u,!1),kt.style.display="flex",kt.style.setProperty("--sel-color",c.color)):kt.style.display="none"}let kl=!1,Cl={width:H,height:130,padding:[4,0,0,0],cursor:{sync:{key:i.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:l==="elevation"?(ot,Mt)=>is(tt?tt[ot.cursor.idx]:null):c.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(ot,Mt,se)=>[Mt,se],min:B?B[0]:void 0,max:B?B[1]:void 0},y:{range:()=>El,dir:l==="speed"&&et==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(ot,Mt,se,oe)=>{let jt=oe-se,ye=(ot.bbox.width>0?ot.bbox.width:ot.width)/80,Oe=jt/ye,Re;te?Re=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:Re=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let We=Re[Re.length-1];for(let Ze=0;Ze=Oe){We=Re[Ze];break}let an=[],Ge=Math.ceil(se/We)*We,vs=We<1?2:0;for(;Ge<=oe;){let Ze=ot.valToPos(Ge,"x",!0);Ze>=ot.bbox.left+80&&Ze<=ot.bbox.left+ot.bbox.width-80&&an.push(Number(Ge.toFixed(vs))),Ge+=We}return an},values:(ot,Mt)=>{let se=(ot.scales.x?.max??1)-(ot.scales.x?.min??0);return Mt.map(oe=>{if(oe==null)return"";let jt=ot.valToPos(oe,"x",!0);return jtot.bbox.left+ot.bbox.width-80?null:de(oe,se)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(ot,Mt)=>Mt.map(se=>se!=null?c.fmtAxis(se):"")}],series:[{},{label:c.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[ot=>{let Mt=ot.bbox.top+ot.bbox.height+5;ae.style.top=`${Mt}px`,ae.style.left=`${ot.bbox.left}px`,mt.style.top=`${Mt}px`,mt.style.left=`${ot.bbox.left+ot.bbox.width}px`,mt.style.transform="translateX(-100%)"},ot=>{l==="gears"?go(ot,x,S,c.color,1.5,l,null,P):l==="elevation"?bl(ot,x,S,tt):l==="gradient"?vl(ot,x,S):at===l?Ml(ot,x,S,P,l):go(ot,x,S,c.color,1.5,l,null,P)},ot=>{let Mt=t.find(oe=>oe.uplot===ot);if(!Mt)return;let se=ot._strasse;f!=null?yl(ot,x,S,c.color,c,P,l):(se&&se.pinYVal&&(se.pinYVal.style.display="none"),Mt.pinnedHistY!=null&&xl(ot,x,S,Mt.pinnedHistY,c.color,c))},ot=>{let Mt=ot.cursor.idx,se=f!=null,oe=Mt!=null&&ot.cursor.left>=0;if(oe&&f==null){let jt=ot.valToPos(S[Mt],"y",!0);Math.abs(ot.cursor.top-jt)>100&&(oe=!1)}if(oe&&Mt!==f&&ro(ot,P,Mt,le(c.color,.4),1),g!=null&&u!=null){let jt=ot.ctx,Ce=window.devicePixelRatio||1,ye=ot.bbox,Oe=ot.valToPos(g,"x",!0),Re=ot.valToPos(u,"x",!0);jt.save(),jt.beginPath(),jt.lineWidth=3*Ce,jt.strokeStyle=c.color,jt.moveTo(Oe,ye.top+ye.height),jt.lineTo(Re,ye.top+ye.height),jt.stroke();let We=Math.abs(u-g),an=F==="distance"?`${We.toFixed(2)} km`:he(We),Ge=9*Ce,vs=`bold ${Ge}px system-ui, sans-serif`;jt.font!==vs&&(jt.font=vs);let Ze=jt.measureText(an).width,yo=Math.max(ye.left,Oe),xo=Math.min(ye.left+ye.width,Re);if(xo-yo>Ze+14*Ce){let Pl=5*Ce,Ll=2*Ce,ys=Ze+Pl*2,xs=Ge+Ll*2,Ws=(yo+xo)/2-ys/2,qs=ye.top+ye.height-xs/2;jt.beginPath(),jt.roundRect?jt.roundRect(Ws,qs,ys,xs,3*Ce):jt.rect(Ws,qs,ys,xs),jt.fillStyle=c.color,jt.fill(),jt.fillStyle="#000",jt.textAlign="center",jt.textBaseline="middle",jt.fillText(an,Ws+ys/2,qs+xs/2)}jt.restore()}se&&co(ot,P,f,c.color,!0,.7),oe&&Mt!==f&&co(ot,P,Mt,c.color,!0,1)}],setCursor:[ot=>{if(a)return;let Mt=ot.cursor.idx;ot.redraw(!1),ot.cursor.left>=0?h=ot.posToVal(ot.cursor.left,"x"):h=null;let se=ot._strasse,oe=Mt!=null&&S[Mt]!=null;if(oe&&f==null){let jt=ot.valToPos(S[Mt],"y",!0);Math.abs(ot.cursor.top-jt)>100&&(oe=!1)}if(se&&(oe?lo(ot,se.curYVal,Mt,x,S,P,c,l):se.curYVal.style.display="none"),r||(Mt!=null&&P[Mt]?Z&&(f!=null||oe)?Z(P[Mt]):Z&&!oe&&Z(null):Mt===null&&Z&&Z(null)),Mt!=null&&S[Mt]!=null){let{min:jt,max:Ce}=ke;if(jt!=null&&Ce!=null){let ye=Ce-jt||1,Oe=Math.min(ke.BINS-1,Math.floor((S[Mt]-jt)/ye*ke.BINS));ln.hoveredHistY!==S[Mt]&&(ln.hoveredHistY=S[Mt],Le(Xt,ke,130,Oe))}}else ln.hoveredHistY!==null&&(ln.hoveredHistY=null,Le(Xt,ke,130))}],setScale:[(ot,Mt)=>{if(Mt!=="x"||kl)return;let{min:se,max:oe}=ot.scales.x;W=[se,oe],Rs(se,oe,ot),!a&&(k||(O=null),a=!0,t.forEach(({uplot:jt})=>{jt!==ot&&jt.batch(()=>jt.setScale("x",{min:se,max:oe}))}),a=!1,_t(),De(),lt&&g!==null&<(g,u,F))}],setSelect:[ot=>{if(k)return;O=null;let{left:Mt,width:se}=ot.select;if(se>0){let oe=ot.posToVal(Mt,"x"),jt=ot.posToVal(Mt+se,"x");g=oe,u=jt,Rs(ot.scales.x.min,ot.scales.x.max,ot),_t(),De(),lt&<(g,u,F),ot.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},Ns=document.createElement("div");Ns.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let ds=document.createElement("div");ds.className="sel-fill",ds.style.display="none";let us=document.createElement("div");us.className="sel-line sel-line-anchor",us.style.display="none";let ms=document.createElement("div");ms.className="sel-line-label sel-line-label-anchor",ms.style.display="none";let qn=document.createElement("div");qn.className="sel-handle sel-handle-anchor",qn.style.display="none";let zn=document.createElement("div");zn.className="sel-graph-marker",zn.innerHTML=`play_circle`,zn.style.display="none";let ps=document.createElement("div");ps.className="sel-line sel-line-end",ps.style.display="none";let fs=document.createElement("div");fs.className="sel-line-label sel-line-label-end",fs.style.display="none";let Un=document.createElement("div");Un.className="sel-handle sel-handle-end",Un.style.display="none";let Vn=document.createElement("div");Vn.className="sel-graph-marker",Vn.innerHTML=`stop_circle`,Vn.style.display="none";let gs=document.createElement("div");gs.className="cur-y-val",gs.style.cssText=`color:${c.color};display:none`;let hs=document.createElement("div");hs.className="cur-y-val pin",hs.style.cssText=`color:${c.color};display:none`,Ns.append(ds,us,ms,qn,zn,ps,fs,Un,Vn,gs,hs);let ke={yData:S,xData:x,def:c,BINS:24,min:Me?ge:void 0,max:Me?Qt:void 0,fullStats:cs,fullStatsAll:_s},ln={uplot:null,row:L,xData:x,yData:S,def:c,metricKey:l,statsTotalEl:xt,statsSelEl:kt,histCol:Kt,histCanvas:Xt,histData:ke,hoveredHistY:null,pinnedHistY:null,smoothed:$.has(l),incZero:M.has(l),w:H};ke.plot=ln;let $l=a;a=!0;let tn=new ko(Cl,[x,S],(ot,Mt)=>{ln.uplot=ot,t.push(ln),re.appendChild(ot.root),ot.over.appendChild(Ns),ot._strasse={selFill:ds,anchorLine:us,anchorLabel:ms,anchorHandle:qn,anchorMarker:zn,endLine:ps,endLabel:fs,endHandle:Un,endMarker:Vn,curYVal:gs,pinYVal:hs,updateHeaderStats:Rs},ot.batch(()=>{Mt()})});a=$l,ee(qn,tn,x,!0),ee(Un,tn,x,!1);let bs=null;tn.over.addEventListener("mousedown",ot=>{if(ot.button!==0)return;v=!1;let Mt=tn.over.getBoundingClientRect();bs=ot.clientX-Mt.left}),tn.over.addEventListener("mousemove",ot=>{if(bs!==null){let Mt=tn.over.getBoundingClientRect();Math.abs(ot.clientX-Mt.left-bs)>5&&(v=!0)}}),tn.over.addEventListener("mouseup",()=>{bs=null}),tn.over.addEventListener("click",()=>{if(v)return;let ot=tn.cursor.idx;ot!=null&&P[ot]&&(f=ot,t.forEach(({uplot:Mt})=>Mt.redraw(!1)),Ft&&Ft(P[ot],ot),rt&&rt(ot))}),L.addEventListener("dblclick",R);let vo=null;if(f!=null&&x[f]!=null&&S[f]!=null&&(xe(ke),ke.min!=null&&ke.max!=null)){let ot=ke.max-ke.min||1;vo=Math.min(ke.BINS-1,Math.floor((S[f]-ke.min)/ot*ke.BINS)),ln.hoveredHistY=S[f]}Le(Xt,ke,130,vo),_n(Xt,ke),G&&(A?G.insertBefore(L,A):G.appendChild(L))}function _t(){qt(),t.forEach(({uplot:l})=>l.batch(()=>l.redraw(!1)))}function qt(){t.forEach(({uplot:l,def:c})=>{let x=l._strasse;if(!x)return;let{selFill:S,anchorLine:H,anchorLabel:P,anchorHandle:B,anchorMarker:A,endLine:q,endLabel:J,endHandle:X,endMarker:Q}=x;if(g==null||u==null){[S,H,P,B,A,q,J,X,Q].forEach(Vt=>{Vt.style.display="none"});return}let et=l.valToPos(g,"x"),tt=l.valToPos(u,"x"),L=window.devicePixelRatio||1,wt=l.bbox,St=wt.width/L,ct=wt.height/L,Ct=(wt.top+wt.height)/L,pt=et>=0&&et<=St,xt=tt>=0&&tt<=St,kt=Math.max(0,et),Ot=Math.min(St,tt);if(Ot>kt?(S.style.left=`${kt}px`,S.style.width=`${Ot-kt}px`,S.style.top="0",S.style.height=`${ct}px`,S.style.backgroundColor=le(c.color,.07),S.style.display=""):S.style.display="none",pt){H.style.left=`${et}px`,H.style.height=`${ct}px`,H.style.borderLeftColor=c.color,H.style.display="";let Vt=Yt(g);P.textContent=Vt;let ne=Vt.length*7+10;P.style.left=et+ne+4Vt.style.display="none");if(xt){q.style.left=`${tt}px`,q.style.height=`${ct}px`,q.style.borderLeftColor=c.color,q.style.display="";let Vt=Yt(u);J.textContent=Vt;let ne=Vt.length*7+10;J.style.left=tt-ne-3>0?`${tt-ne-3}px`:`${tt+3}px`,J.style.display="",X.style.left=`${tt}px`,X.style.backgroundColor=c.color,X.style.display="",Q.style.left=`${tt}px`,Q.style.top=`${Ct}px`;let ie=Q.querySelector(".material-symbols-rounded");ie&&(ie.style.color=c.color),Q.style.display=""}else[q,J,X,Q].forEach(Vt=>Vt.style.display="none")})}function Yt(l){return F==="distance"?`${l.toFixed(2)} km`:he(l)}function ee(l,c,x,S){l.style.pointerEvents="auto",l.addEventListener("mousedown",H=>{H.stopPropagation(),H.preventDefault();let P=H.clientX,B=S?g:u,A=c.over.offsetWidth,q=c.scales.x.min,J=c.scales.x.max,X=A/(J-q),Q=[x[0],x[x.length-1]];document.body.style.cursor="ew-resize",v=!0;function et(L){let wt=L.clientX-P,St=(B||0)+wt/X;St=Math.max(Q[0],Math.min(Q[1],St)),S?g=Math.min(St,(u||Q[1])-.001):u=Math.max(St,(g||Q[0])+.001),t.forEach(ct=>ct.uplot._strasse?.updateHeaderStats(ct.uplot.scales.x.min,ct.uplot.scales.x.max)),_t(),De(),lt&<(g,u,F)}function tt(){document.body.style.cursor="",v=!1,document.removeEventListener("mousemove",et),document.removeEventListener("mouseup",tt)}document.addEventListener("mousemove",et),document.addEventListener("mouseup",tt)})}function xe(l){let{yData:c,xData:x,BINS:S}=l;if(l._lastYData===c&&l.bins)return;l._lastYData=c;let H=l.min,P=l.max;if(H==null||P==null){let Q=1/0,et=-1/0,tt=0;for(let L=0;Let&&(et=wt),tt++)}if(!tt)return;H=Q,P=et,l.min=H,l.max=P}let B=new Array(S).fill(0),A=new Array(S).fill(0),q=P-H||1,J=l.plot?.metricKey??Object.keys(qe).find(Q=>qe[Q]===l.def),X=!J||M.has(J)||J!=="power"&&J!=="cadence"&&J!=="speed";for(let Q=0;Q0&&x[Q-1]!=null?x[Q-1]:x[Q],wt=Q{Le(l,c,x.height)})}function Le(l,c,x,S=null){let{def:H,BINS:P}=c;xe(c);let{bins:B,min:A,max:q}=c;if(!B||A==null||q==null)return;let J=g!=null&&u!=null;if(J&&(c._lastSelRange?.[0]!==g||c._lastSelRange?.[1]!==u)){c._lastSelRange=[g,u];let mt=new Array(P).fill(0),Kt=new Array(P).fill(0),{yData:Xt,xData:te}=c,de=q-A||1,fe=c.plot?.metricKey??Object.keys(qe).find(Qt=>qe[Qt]===c.def),ge=!fe||M.has(fe)||fe!=="power"&&fe!=="cadence"&&fe!=="speed";for(let Qt=0;Qtu)continue;let Be=Math.min(P-1,Math.floor((ue-A)/de*P));mt[Be]++;let Je=Qt>0&&te[Qt-1]!=null?te[Qt-1]:te[Qt],Ae=QtH.fmtAxis(mt),ct="9px system-ui, sans-serif";L.font!==ct&&(L.font=ct);let pt={t:4,r:0,b:30,l:Math.ceil(Math.max(L.measureText(`${St(q)} ${H.unit}`).width,L.measureText(`${St(A)} ${H.unit}`).width))+6};c.padL=pt.l;let xt=et-pt.l-pt.r,kt=tt-pt.t-pt.b,Ot=mt=>pt.t+(P-1-mt)*(kt/P),Vt=kt/P-1,ne=J?.15:.6;L.fillStyle=le(H.color,ne);for(let mt=0;mtmt+Kt,0);if(ie>0){let mt=[{x:pt.l,y:pt.t+kt}],Kt=0;for(let Xt=0;XtXt+te+2&&mt0){let mt=0;for(let ue=0;ue{let H=no(l,c,S);if(H!=null&&x){let{min:P,max:B,BINS:A}=c,q=B-P||1;x.pinnedHistY=P+(H+.5)*(q/A),t.forEach(({uplot:J})=>J.redraw(!1))}}),l.addEventListener("mousemove",S=>{p=S,so(S,l,c)}),l.addEventListener("mouseenter",()=>{_=l,E=c}),l.addEventListener("mouseleave",()=>{_===l&&(_=null,E=null),C&&(C.style.display="none");let S=document.getElementById("hist-line");S&&(S.style.display="none"),x&&(x.hoveredHistY=null,Le(l,c,l.height/(window.devicePixelRatio||1)))})}function no(l,c,x){let{bins:S,BINS:H}=c;if(!S)return null;let P=l.getBoundingClientRect(),B=x.clientY-P.top,A={t:4,b:30},q=P.height-A.t-A.b,J=Math.floor((B-A.t)/q*H),X=H-1-J;return J<0||J>=H?null:X}function so(l,c,x){if(!C)return;let{bins:S,binAccum:H,min:P,max:B,BINS:A,def:q,plot:J}=x;if(!S||!H||P==null||B==null)return;let X=document.getElementById("hist-line"),Q=no(c,x,l);if(Q==null||!S[Q]){C.style.display="none",X&&(X.style.display="none"),J&&(J.hoveredHistY=null,Le(c,x,c.height/(window.devicePixelRatio||1)));return}if(J){let te=B-P||1;J.hoveredHistY=P+(Q+.5)*(te/A),Le(c,x,c.height/(window.devicePixelRatio||1),Q)}let et=S[Q],tt=S.reduce((te,de)=>te+de,0),L=et/tt*100,wt=B-P||1,St=P+Q*(wt/A),ct=P+(Q+1)*(wt/A),Ct=`${q.fmt(St,!0)} \u2013 ${q.fmt(ct,!0)} ${q.unit}`,pt="",xt=(St+ct)/2,kt=Object.keys(qe).find(te=>qe[te]===q),Ot=[];if(kt==="power"?Ot=$n.getPowerZones():kt==="hr"&&(Ot=$n.getHRZones()),Ot.length>0){let te=Ot.findIndex(fe=>xt>=fe.min&&xt=Ot[Ot.length-1].min?Ot[Ot.length-1]:null;if(de){let fe=te!==-1?te:Ot.length-1;pt=`
Z${fe+1} \xB7 ${de.name}
- `}}let Vt=A==="distance"?`${F[Q].toFixed(2)} km`:he(F[Q]),ne=F[Q]/F.reduce((te,de)=>te+de,0)*100,ie=` + `}}let Vt=F==="distance"?`${H[Q].toFixed(2)} km`:he(H[Q]),ne=H[Q]/H.reduce((te,de)=>te+de,0)*100,ie=`
${Ct}
${pt} `;if(Vt&&(ie+=`
- ${A==="distance"?"Dist":"Time"} + ${F==="distance"?"Dist":"Time"} ${Vt} ${ne.toFixed(1)}% -
`),y.selBins&&y.selBinAccum){let te=A==="distance"?`${y.selBinAccum[Q].toFixed(2)} km`:he(y.selBinAccum[Q]),de=y.selBinAccum[Q]/y.selBinAccum.reduce((fe,ge)=>fe+ge,0)*100;ie+=` +
`),x.selBins&&x.selBinAccum){let te=F==="distance"?`${x.selBinAccum[Q].toFixed(2)} km`:he(x.selBinAccum[Q]),de=x.selBinAccum[Q]/x.selBinAccum.reduce((fe,ge)=>fe+ge,0)*100;ie+=`
- Sel ${A==="distance"?"Dist":"Time"} + Sel ${F==="distance"?"Dist":"Time"} ${te} ${de.toFixed(1)}%
- `}E.innerHTML=ie,E.style.display="block";let re=E.offsetHeight,ae=E.offsetWidth,mt=r.getBoundingClientRect(),Kt=mt.height-4-30,Xt=mt.top+4+(H-1-Q+.5)*(Kt/H);E.style.left=`${mt.left-ae-12}px`,E.style.top=`${Xt-re/2}px`,X&&(X.style.display="block",X.style.top=`${Xt}px`,X.style.left="0px",X.style.width=`${mt.left}px`)}function Rn(o=!1){E&&(E.style.display="none"),t.forEach(({uplot:r,row:y})=>{i.unsub(r),r.destroy(),y.remove()}),t=[],n=null,o||(M=null,m=null),k=!1}function oo(o,r,y,T,F=!0){let L=1/0,B=-1/0,H=0,q=0;for(let J=0;JT)continue;let X=r[J];X==null||!isFinite(X)||X===0&&!F||(XB&&(B=X),H+=X,q++)}return q?{min:L,max:B,avg:H/q}:null}function bl(o,r,y){let T=0,F=0,L=null,B=A==="distance",H=o[0].time||0;for(let q=0;qy)&&J.ele!=null){if(L!=null){let Q=J.ele-L;Q>0?T+=Q:Q<0&&(F+=Math.abs(Q))}L=J.ele}}return{gain:T,loss:F}}function lo(o,r,y,T,F,L,B,H){if(y==null||F[y]==null){r.style.display="none";return}let q=o.valToPos(T[y],"x",!1),J=o.valToPos(F[y],"y",!1),X="#888896",Q=0;if(y>0&&L[y]&&L[y-1]){let ct=L[y-1],Ct=L[y],pt=(Ct.dist||0)-(ct.dist||0);pt>.1&&Ct.ele!=null&&ct.ele!=null&&(Q=(Ct.ele-ct.ele)/pt*100,X=is(Q))}let et=H!=="elevation"?`${B.fmt(F[y],!1)} ${B.unit}`:`${B.fmt(F[y],!1)} ${B.unit} \u2220 ${Math.abs(Q).toFixed(1)}%`;if(H==="gearRear"&&L[y].gearRearTooth!=null)et=`${L[y].gearRearTooth}T (pos ${F[y]})`;else if(H==="gearFront"&&L[y].gearFrontTooth!=null)et=`${L[y].gearFrontTooth}T (pos ${F[y]})`;else if(H==="gears"){let ct=L[y],Ct=ct.gearFrontTooth!=null?`${ct.gearFrontTooth}T`:ct.gearFront!=null?`pos ${ct.gearFront}`:"",pt=ct.gearRearTooth!=null?`${ct.gearRearTooth}T`:ct.gearRear!=null?`pos ${ct.gearRear}`:"";(Ct||pt)&&(et+=` (${Ct} / ${pt})`)}r.innerHTML!==et&&(r.innerHTML=et);let tt=`${B.color}44`;r.style.color!==B.color&&(r.style.color=B.color),r.style.borderColor!==tt&&(r.style.borderColor=tt);let I=`${q}px`,wt=`${J}px`,St="translate(6px, -50%)";r.style.left!==I&&(r.style.left=I),r.style.top!==wt&&(r.style.top=wt),r.style.transform!==St&&(r.style.transform=St),r.style.display!==""&&(r.style.display="")}let io=new Map;function ao(o){let r=io.get(o);return r||(r=le(is(o),.8),io.set(o,r)),r}function vl(o,r,y,T){let F=o.ctx,L=o.bbox,B=window.devicePixelRatio||1,H=o.scales.x?.min??-1/0,q=o.scales.x?.max??1/0,J=o.scales.y?.min??0,X=o.scales.y?.max??100,Q=L.width/(q-H||1),et=L.height/(X-J||1),tt=L.top+L.height,I=o.series[0]?.idxs,wt=I?Math.max(1,I[0]):1,St=I?Math.min(r.length-1,I[1]+1):r.length-1,ct=Math.max(1,Math.floor((St-wt)/250));F.save(),F.lineWidth=1.5*B;let Ct=new Map,pt=wt-1;for(let xt=wt;xt<=St;xt+=ct){let kt=r[xt],Ot=r[pt];if(pt=xt,kt==null||y[xt]==null||Ot==null||y[xt-ct]==null||ktq)continue;let Vt=L.left+(Ot-H)*Q,ne=tt-(y[xt-ct]-J)*et,ie=L.left+(kt-H)*Q,re=tt-(y[xt]-J)*et,ae=T&&T[xt]!=null?Math.round(T[xt]/2)*2:null,mt=ao(ae),Kt=Ct.get(mt);Kt||(Kt=[],Ct.set(mt,Kt)),Kt.push(Vt,ne,ie,re)}for(let[xt,kt]of Ct){F.beginPath(),F.strokeStyle=xt;for(let Ot=0;OtH)continue;let Ot=F.left+(kt-B)*X,Vt=et-(y[pt-St]-q)*Q,ne=F.left+(xt-B)*X,ie=et-(y[pt]-q)*Q,re=Math.round(y[pt]/2)*2,ae=ao(re),mt=ct.get(ae);mt||(mt=[],ct.set(ae,mt)),mt.push(Ot,Vt,ne,ie)}for(let[pt,xt]of ct){T.beginPath(),T.strokeStyle=pt;for(let kt=0;kt{let kt=`bold ${10*B}px system-ui, sans-serif`;q.font!==kt&&(q.font=kt);let Vt=q.measureText(ct).width+10*B,ne=16*B,ie=Ct-Vt/2,re=Math.max(H.left,Math.min(H.left+H.width-Vt,ie)),ae=pt-ne/2;q.save(),q.globalAlpha=L,q.setLineDash([]),q.beginPath(),q.roundRect?q.roundRect(re,ae,Vt,ne,3*B):q.rect(re,ae,Vt,ne),q.fillStyle="rgba(14,14,16,0.92)",q.fill(),q.strokeStyle=le(T,.27),q.lineWidth=1*B,q.stroke(),q.fillStyle=T,q.textAlign="center",q.textBaseline="middle",q.fillText(ct,re+Vt/2,ae+ne/2+.5*B),q.restore()};F||ro(o,r,y,T,L);let St=16*B;wt(I,et,H.top+St/2,!0),wt(tt,et,H.top+H.height+15*B,!1)}function xl(o,r,y,T,F,L,B){if(h==null)return;let H=r[h],q=y[h];if(H==null||q==null)return;let J=o.valToPos(H,"x",!0),X=o.valToPos(q,"y",!0),Q=o.bbox,et=o.ctx,tt=window.devicePixelRatio||1;et.save(),et.beginPath(),et.strokeStyle=T,et.lineWidth=1.5*tt,et.moveTo(J,Q.top),et.lineTo(J,Q.top+Q.height),et.stroke(),et.beginPath(),et.setLineDash([3*tt,3*tt]),et.strokeStyle=le(T,.5),et.lineWidth=1*tt,et.moveTo(Q.left,X),et.lineTo(J,X),et.stroke(),et.beginPath(),et.setLineDash([]),et.arc(J,X,5*tt,0,Math.PI*2),et.fillStyle="#0e0e10",et.fill(),et.strokeStyle=T,et.lineWidth=2.5*tt,et.stroke(),et.restore();let I=o._strasse;I&&I.pinYVal&&lo(o,I.pinYVal,h,r,y,L,F,B)}function wl(o,r,y,T,F,L){let B=o.bbox,H=o.ctx,q=window.devicePixelRatio||1,J=o.valToPos(T,"y",!0),X=Math.max(B.top,Math.min(B.top+B.height,J));H.save(),H.beginPath(),H.setLineDash([4*q,4*q]),H.strokeStyle=le(F,.4),H.lineWidth=1*q,H.moveTo(B.left,X),H.lineTo(B.left+B.width,X),H.stroke(),Tl(o,r,y,X,F);let Q=L.fmt(T,!0),et=`bold ${10*q}px system-ui, sans-serif`;H.font!==et&&(H.font=et);let I=H.measureText(Q).width+8*q,wt=16*q,St=B.left-I-2*q,ct=X-wt/2;H.beginPath(),H.setLineDash([]),H.roundRect?H.roundRect(St,ct,I,wt,3*q):H.rect(St,ct,I,wt),H.fillStyle="rgba(14,14,16,0.95)",H.fill(),H.strokeStyle=F,H.lineWidth=1*q,H.stroke(),H.fillStyle="#fff",H.textAlign="center",H.textBaseline="middle",H.fillText(Q,St+I/2,ct+wt/2+.5*q),H.restore()}function Tl(o,r,y,T,F){let L=o.ctx,B=o.bbox,H=o.scales.x?.min??-1/0,q=o.scales.x?.max??1/0,J=o.scales.y?.min??0,X=o.scales.y?.max??100,Q=B.width/(q-H||1),et=B.height/(X-J||1),tt=o.scales.y?.dir??1,I=tt===-1?B.top:B.top+B.height,wt=tt===-1?et:-et,St=o.series[0]?.idxs,ct=St?Math.max(0,St[0]-1):0,Ct=St?Math.min(r.length-1,St[1]+1):r.length-1,pt=Math.max(1,Math.floor((Ct-ct)/250));L.save(),L.beginPath(),L.rect(B.left,B.top,B.width,B.height),L.clip(),L.fillStyle=le(F,.2),L.beginPath();let xt=!1,kt=!1,Ot=0;for(let Vt=ct;Vt<=Ct;Vt+=pt){let ne=r[Vt],ie=y[Vt];if(ne==null||ie==null||neq){xt&&(L.lineTo(Ot,T),L.closePath(),xt=!1);continue}let re=B.left+(ne-H)*Q,ae=I+(ie-J)*wt;Ot=re,ae>16,B=T>>8&255,H=T&255,q=F>>16,J=F>>8&255,X=F&255,Q=L+(q-L)*y,et=B+(J-B)*y,tt=H+(X-H)*y;return`#${((1<<24)+(Math.round(Q)<<16)+(Math.round(et)<<8)+Math.round(tt)).toString(16).slice(1)}`}function is(o){if(o==null)return"#888896";let r=Math.abs(o),y=Math.min(1,r/8);return o>0?Ve("#A8C8A0","#d73027",y):Ve("#A8C8A0","#4575b4",y)}function uo(o){if(o==null)return"#888896";let r=o*3.6;if(r<=5)return"#4575b4";if(r>=60)return"#d73027";if(r<=45){let y=(r-5)/40;return y<=.25?Ve("#4575b4","#91bfdb",y/.25):y<=.5?Ve("#91bfdb","#abdda4",(y-.25)/.25):y<=.75?Ve("#abdda4","#fee08b",(y-.5)/.25):Ve("#fee08b","#fc8d59",(y-.75)/.25)}else{let y=(r-45)/15;return Ve("#fc8d59","#d73027",y)}}function Sl(o,r){let y=new Array(o.length).fill(null);for(let T=0;T0&&(F.dist||0)-(o[L].dist||0)1&&o[B].ele!=null&&o[L].ele!=null&&(y[T]=(o[B].ele-o[L].ele)/H*100)}return y}function mo(o){let r=[...o];for(let y=0;y=0&&r[T]===null;)T--;let F=y+1;for(;F=0&&F=0?r[y]=r[T]:F{let J=document.querySelector(`#${H} .stat-value`);J&&(J.textContent=q)};y("stat-distance",r.totalDist!=null?`${(r.totalDist/1e3).toFixed(1)} km`:"\u2014"),y("stat-duration",r.duration!=null?he(Math.floor(r.duration/1e3)):"\u2014"),y("stat-elevation",r.elevGain!=null?`${Math.round(r.elevGain)} m`:"\u2014");let T=H=>{let q=t.find(Q=>Q.metricKey===H);if(!q)return H==="speed"?r.avgSpeed??null:H==="power"?r.avgPower??null:H==="cadence"?r.avgCadence??null:null;if(q.histData.fullStats!==void 0)return q.histData.fullStats?q.histData.fullStats.avg:null;let J=f.has(H)||H!=="power"&&H!=="cadence"&&H!=="speed",X=q.yData.filter(Q=>Q!=null&&(J||Q!==0));return X.length?X.reduce((Q,et)=>Q+et,0)/X.length:null},F=T("speed");y("stat-avg-speed",F!=null?`${(F*3.6).toFixed(1)} km/h`:"\u2014");let L=T("power");y("stat-avg-power",L!=null?`${Math.round(L)} W`:"\u2014");let B=T("cadence");y("stat-avg-cad",B!=null?`${Math.round(B)} rpm`:"\u2014"),y("stat-avg-hr",r.avgHR!=null?`${r.avgHR} bpm`:"\u2014"),y("stat-avg-temp",r.avgTemp!=null?`${r.avgTemp.toFixed(1)} \xB0C`:"\u2014")}let yn=16384,xn=new Float64Array(yn),kn=new Float64Array(yn),as=new Float64Array(yn),Nn=new Float64Array(yn),Bs=new Float64Array(yn),rs=new Float64Array(yn),Wn=new Float64Array(64),fo=[3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300,360];function Ml(o,r,y){if(!o.length)return 0;Wn.fill(0);let T=0;for(let F=0;F=St)continue;let pt=1/Ct,xt=0,kt=0,Ot=0;for(let Vt=I;Vt=Ct){xt-=rs[Vt-Ct],kt-=Nn[Vt-Ct];let ne=(xt+kt*.05)*pt;ne>Ot&&(Ot=ne)}T+=Ot*1e-4}for(let ct=I;ct0&&(Wn[Ct-1]+=.5),Ct<63&&(Wn[Ct+1]+=.5)}}}}for(let F=0;F<64;F++)T+=Wn[F]*1e-5;return G&&(G.dataset.intervalScore=T.toFixed(2)),T}return{init:$t,loadTrack:z,clear:D,resetState:it,toggleMetric:K,setXAxis:Ht,toggleStats:dt,setSelectionStats:Dt,clearSelectionStats:It,restoreSelection:Wt,resetZoom:V,cancelSelection:R,analyzeTelemetryIntervals:Ml,setCursorAt:(o,r=!1)=>{if(h=o,rt&&rt(o),r){Z&&C?.points?.[o]&&Z(C.points[o]);return}c=!0,t.forEach(({uplot:y,yData:T,xData:F})=>{F[o]!=null&&T[o]!=null&&y.batch(()=>{y.setCursor({left:y.valToPos(F[o],"x"),top:y.valToPos(T[o],"y")},!0,!1)})}),c=!1,Z&&C?.points?.[o]&&Z(C.points[o])},setHoverAt:o=>{c=!0,t.forEach(({uplot:r,yData:y,xData:T})=>{o===null?r.batch(()=>{r.setCursor({left:-10,top:-10},!0,!1)}):T[o]!=null&&y[o]!=null&&r.batch(()=>{r.setCursor({left:r.valToPos(T[o],"x"),top:r.valToPos(y[o],"y")},!0,!1)})}),c=!1,Z&&Z(o!=null&&C?.points?.[o]?C.points[o]:null)},clearPinnedDot:()=>{h=null,rt&&rt(null),t.forEach(({uplot:o})=>o.redraw(!1))},resize:Et,METRICS:qe,isDragging:()=>k,setMapColorChangeCb:Lt,toggleMapColor:st,getMapColorMetric:()=>at,getActiveMetrics:()=>d,getAvailableMetrics:()=>w,setActiveMetrics:ut,setSmooth:bt,setZeroInclusion:Pt,updateMetricOrder:o=>{let r=new Set;o.forEach(y=>{d.has(y)&&r.add(y)}),d.forEach(y=>{r.has(y)||r.add(y)}),d=r,C&&vt(!0)},getXAxis:()=>A};function El(o,r,y,T,F){let L=o.ctx,B=o.bbox,H=window.devicePixelRatio||1,q=zt(F,y);L.save(),L.beginPath(),L.rect(B.left,B.top,B.width,B.height),L.clip();let J=F==="gearRear"||F==="gearFront";for(let X=1;Xtt.time!=null)?.time||0,Q=y.field;T.beginPath(),T.strokeStyle="rgba(255, 255, 255, 0.04)",T.lineWidth=1*L;let et=!0;for(let tt=0;tt0){let xt=J[tt-1];(I.time&&xt.time?I.time-xt.time:0)>B&&(et=!0)}let St=y.transform?y.transform(wt):wt;if(St==null){et=!0;continue}let ct=A==="distance"?(I.dist||0)/1e3:(I.time-X)/1e3;if(cto.scales.x.max+10){et=!0;continue}let Ct=o.valToPos(ct,"x",!0),pt=o.valToPos(St,"y",!0);if(et)T.moveTo(Ct,pt),et=!1;else{if(H){let xt=J[tt-1],kt=A==="distance"?(xt.dist||0)/1e3:(xt.time-X)/1e3;T.lineTo(o.valToPos(kt,"x",!0),pt)}T.lineTo(Ct,pt)}}T.stroke()}T.restore()}function go(o,r,y,T,F,L,B=null,H=[]){let q=o.ctx,J=o.bbox,X=window.devicePixelRatio||1,Q=6e4;q.save(),q.beginPath(),q.strokeStyle=le(T,.8),q.lineWidth=F*X;let et=L==="gearRear"||L==="gearFront",tt=!0,I=null,wt=1,St=1;if(L==="gears"&&H.length>0){let Qt=1/0,ue=-1/0;for(let Me=0;Meue&&(ue=Be))}Qt<=ue&&(wt=Qt,St=ue)}let ct=B?B[0]:o.scales.x?.min??-1/0,Ct=B?B[1]:o.scales.x?.max??1/0,pt=o.scales.x?.min??-1/0,xt=o.scales.x?.max??1/0,kt=o.scales.y?.min??0,Ot=o.scales.y?.max??100,Vt=J.width/(xt-pt||1),ne=J.height/(Ot-kt||1),ie=o.scales.y?.dir??1,re=ie===-1?J.top:J.top+J.height,ae=ie===-1?ne:-ne,mt=B?null:o.series[0]?.idxs,Kt=mt?Math.max(0,mt[0]-1):0,Xt=mt?Math.min(r.length-1,mt[1]+1):r.length-1,te=et||L==="gears"?1:Math.max(1,Math.floor((Xt-Kt)/250)),de=A==="time",fe=Q/1e3,ge=Kt;for(let Qt=Kt;Qt<=Xt;Qt+=te){let ue=r[Qt],Me=y[Qt];if(ue==null||Me==null){tt=!0;continue}if(L==="gears"&&H[Qt]){let Ae=H[Qt].gearFrontTooth??H[Qt].gearFront;if(Ae!=null&&Ae!==I){if(!tt&&Qt>0){q.stroke(),q.beginPath();let _s=J.left+(r[ge]-pt)*Vt,cs=re+(y[ge]-kt)*ae;q.moveTo(_s,cs)}let on=T;St!==wt&&Ae!=null&&(Ae===wt?on="#FFC400":Ae===St?on="#FF8C00":on="#FFA500"),q.strokeStyle=le(on,.8),I=Ae}}if(Qt>Kt&&de){let Ae=r[ge];Ae!=null&&ue-Ae>fe&&(tt=!0)}if(ueCt){tt=!0;continue}let Be=J.left+(ue-pt)*Vt,Je=re+(Me-kt)*ae;if(tt)q.moveTo(Be,Je),tt=!1;else{if(et){let Ae=r[ge];q.lineTo(J.left+(Ae-pt)*Vt,Je)}q.lineTo(Be,Je)}ge=Qt}q.stroke(),q.restore()}})();var Wl={"Heart Rate":Nt.hr.icon,Cadence:Nt.cadence.icon,Power:Nt.power.icon,Temperature:Nt.temperature.icon,Shifting:Nt.gears.icon,Battery:Nt.battery.icon},Pn=()=>{},$o=()=>{};function Po(t,n){Pn=t,$o=n}function Lo(){let t=document.getElementById("details-view");t&&(t.innerHTML=` + `}C.innerHTML=ie,C.style.display="block";let re=C.offsetHeight,ae=C.offsetWidth,mt=c.getBoundingClientRect(),Kt=mt.height-4-30,Xt=mt.top+4+(A-1-Q+.5)*(Kt/A);C.style.left=`${mt.left-ae-12}px`,C.style.top=`${Xt-re/2}px`,X&&(X.style.display="block",X.style.top=`${Xt}px`,X.style.left="0px",X.style.width=`${mt.left}px`)}function Rn(l=!1){C&&(C.style.display="none"),t.forEach(({uplot:c,row:x})=>{i.unsub(c),c.destroy(),x.remove()}),t=[],s=null,l||(g=null,u=null),v=!1}function oo(l,c,x,S,H=!0){let P=1/0,B=-1/0,A=0,q=0;for(let J=0;JS)continue;let X=c[J];X==null||!isFinite(X)||X===0&&!H||(XB&&(B=X),A+=X,q++)}return q?{min:P,max:B,avg:A/q}:null}function hl(l,c,x){let S=0,H=0,P=null,B=F==="distance",A=l[0].time||0;for(let q=0;qx)&&J.ele!=null){if(P!=null){let Q=J.ele-P;Q>0?S+=Q:Q<0&&(H+=Math.abs(Q))}P=J.ele}}return{gain:S,loss:H}}function lo(l,c,x,S,H,P,B,A){if(x==null||H[x]==null){c.style.display="none";return}let q=l.valToPos(S[x],"x",!1),J=l.valToPos(H[x],"y",!1),X="#888896",Q=0;if(x>0&&P[x]&&P[x-1]){let ct=P[x-1],Ct=P[x],pt=(Ct.dist||0)-(ct.dist||0);pt>.1&&Ct.ele!=null&&ct.ele!=null&&(Q=(Ct.ele-ct.ele)/pt*100,X=is(Q))}let et=A!=="elevation"?`${B.fmt(H[x],!1)} ${B.unit}`:`${B.fmt(H[x],!1)} ${B.unit} \u2220 ${Math.abs(Q).toFixed(1)}%`;if(A==="gearRear"&&P[x].gearRearTooth!=null)et=`${P[x].gearRearTooth}T (pos ${H[x]})`;else if(A==="gearFront"&&P[x].gearFrontTooth!=null)et=`${P[x].gearFrontTooth}T (pos ${H[x]})`;else if(A==="gears"){let ct=P[x],Ct=ct.gearFrontTooth!=null?`${ct.gearFrontTooth}T`:ct.gearFront!=null?`pos ${ct.gearFront}`:"",pt=ct.gearRearTooth!=null?`${ct.gearRearTooth}T`:ct.gearRear!=null?`pos ${ct.gearRear}`:"";(Ct||pt)&&(et+=` (${Ct} / ${pt})`)}c.innerHTML!==et&&(c.innerHTML=et);let tt=`${B.color}44`;c.style.color!==B.color&&(c.style.color=B.color),c.style.borderColor!==tt&&(c.style.borderColor=tt);let L=`${q}px`,wt=`${J}px`,St="translate(6px, -50%)";c.style.left!==L&&(c.style.left=L),c.style.top!==wt&&(c.style.top=wt),c.style.transform!==St&&(c.style.transform=St),c.style.display!==""&&(c.style.display="")}let io=new Map;function ao(l){let c=io.get(l);return c||(c=le(is(l),.8),io.set(l,c)),c}function bl(l,c,x,S){let H=l.ctx,P=l.bbox,B=window.devicePixelRatio||1,A=l.scales.x?.min??-1/0,q=l.scales.x?.max??1/0,J=l.scales.y?.min??0,X=l.scales.y?.max??100,Q=P.width/(q-A||1),et=P.height/(X-J||1),tt=P.top+P.height,L=l.series[0]?.idxs,wt=L?Math.max(1,L[0]):1,St=L?Math.min(c.length-1,L[1]+1):c.length-1,ct=Math.max(1,Math.floor((St-wt)/250));H.save(),H.lineWidth=1.5*B;let Ct=new Map,pt=wt-1;for(let xt=wt;xt<=St;xt+=ct){let kt=c[xt],Ot=c[pt];if(pt=xt,kt==null||x[xt]==null||Ot==null||x[xt-ct]==null||ktq)continue;let Vt=P.left+(Ot-A)*Q,ne=tt-(x[xt-ct]-J)*et,ie=P.left+(kt-A)*Q,re=tt-(x[xt]-J)*et,ae=S&&S[xt]!=null?Math.round(S[xt]/2)*2:null,mt=ao(ae),Kt=Ct.get(mt);Kt||(Kt=[],Ct.set(mt,Kt)),Kt.push(Vt,ne,ie,re)}for(let[xt,kt]of Ct){H.beginPath(),H.strokeStyle=xt;for(let Ot=0;OtA)continue;let Ot=H.left+(kt-B)*X,Vt=et-(x[pt-St]-q)*Q,ne=H.left+(xt-B)*X,ie=et-(x[pt]-q)*Q,re=Math.round(x[pt]/2)*2,ae=ao(re),mt=ct.get(ae);mt||(mt=[],ct.set(ae,mt)),mt.push(Ot,Vt,ne,ie)}for(let[pt,xt]of ct){S.beginPath(),S.strokeStyle=pt;for(let kt=0;kt{let kt=`bold ${10*B}px system-ui, sans-serif`;q.font!==kt&&(q.font=kt);let Vt=q.measureText(ct).width+10*B,ne=16*B,ie=Ct-Vt/2,re=Math.max(A.left,Math.min(A.left+A.width-Vt,ie)),ae=pt-ne/2;q.save(),q.globalAlpha=P,q.setLineDash([]),q.beginPath(),q.roundRect?q.roundRect(re,ae,Vt,ne,3*B):q.rect(re,ae,Vt,ne),q.fillStyle="rgba(14,14,16,0.92)",q.fill(),q.strokeStyle=le(S,.27),q.lineWidth=1*B,q.stroke(),q.fillStyle=S,q.textAlign="center",q.textBaseline="middle",q.fillText(ct,re+Vt/2,ae+ne/2+.5*B),q.restore()};H||ro(l,c,x,S,P);let St=16*B;wt(L,et,A.top+St/2,!0),wt(tt,et,A.top+A.height+15*B,!1)}function yl(l,c,x,S,H,P,B){if(f==null)return;let A=c[f],q=x[f];if(A==null||q==null)return;let J=l.valToPos(A,"x",!0),X=l.valToPos(q,"y",!0),Q=l.bbox,et=l.ctx,tt=window.devicePixelRatio||1;et.save(),et.beginPath(),et.strokeStyle=S,et.lineWidth=1.5*tt,et.moveTo(J,Q.top),et.lineTo(J,Q.top+Q.height),et.stroke(),et.beginPath(),et.setLineDash([3*tt,3*tt]),et.strokeStyle=le(S,.5),et.lineWidth=1*tt,et.moveTo(Q.left,X),et.lineTo(J,X),et.stroke(),et.beginPath(),et.setLineDash([]),et.arc(J,X,5*tt,0,Math.PI*2),et.fillStyle="#0e0e10",et.fill(),et.strokeStyle=S,et.lineWidth=2.5*tt,et.stroke(),et.restore();let L=l._strasse;L&&L.pinYVal&&lo(l,L.pinYVal,f,c,x,P,H,B)}function xl(l,c,x,S,H,P){let B=l.bbox,A=l.ctx,q=window.devicePixelRatio||1,J=l.valToPos(S,"y",!0),X=Math.max(B.top,Math.min(B.top+B.height,J));A.save(),A.beginPath(),A.setLineDash([4*q,4*q]),A.strokeStyle=le(H,.4),A.lineWidth=1*q,A.moveTo(B.left,X),A.lineTo(B.left+B.width,X),A.stroke(),wl(l,c,x,X,H);let Q=P.fmt(S,!0),et=`bold ${10*q}px system-ui, sans-serif`;A.font!==et&&(A.font=et);let L=A.measureText(Q).width+8*q,wt=16*q,St=B.left-L-2*q,ct=X-wt/2;A.beginPath(),A.setLineDash([]),A.roundRect?A.roundRect(St,ct,L,wt,3*q):A.rect(St,ct,L,wt),A.fillStyle="rgba(14,14,16,0.95)",A.fill(),A.strokeStyle=H,A.lineWidth=1*q,A.stroke(),A.fillStyle="#fff",A.textAlign="center",A.textBaseline="middle",A.fillText(Q,St+L/2,ct+wt/2+.5*q),A.restore()}function wl(l,c,x,S,H){let P=l.ctx,B=l.bbox,A=l.scales.x?.min??-1/0,q=l.scales.x?.max??1/0,J=l.scales.y?.min??0,X=l.scales.y?.max??100,Q=B.width/(q-A||1),et=B.height/(X-J||1),tt=l.scales.y?.dir??1,L=tt===-1?B.top:B.top+B.height,wt=tt===-1?et:-et,St=l.series[0]?.idxs,ct=St?Math.max(0,St[0]-1):0,Ct=St?Math.min(c.length-1,St[1]+1):c.length-1,pt=Math.max(1,Math.floor((Ct-ct)/250));P.save(),P.beginPath(),P.rect(B.left,B.top,B.width,B.height),P.clip(),P.fillStyle=le(H,.2),P.beginPath();let xt=!1,kt=!1,Ot=0;for(let Vt=ct;Vt<=Ct;Vt+=pt){let ne=c[Vt],ie=x[Vt];if(ne==null||ie==null||neq){xt&&(P.lineTo(Ot,S),P.closePath(),xt=!1);continue}let re=B.left+(ne-A)*Q,ae=L+(ie-J)*wt;Ot=re,ae>16,B=S>>8&255,A=S&255,q=H>>16,J=H>>8&255,X=H&255,Q=P+(q-P)*x,et=B+(J-B)*x,tt=A+(X-A)*x;return`#${((1<<24)+(Math.round(Q)<<16)+(Math.round(et)<<8)+Math.round(tt)).toString(16).slice(1)}`}function is(l){if(l==null)return"#888896";let c=Math.abs(l),x=Math.min(1,c/8);return l>0?Ve("#A8C8A0","#d73027",x):Ve("#A8C8A0","#4575b4",x)}function uo(l){if(l==null)return"#888896";let c=l*3.6;if(c<=5)return"#4575b4";if(c>=60)return"#d73027";if(c<=45){let x=(c-5)/40;return x<=.25?Ve("#4575b4","#91bfdb",x/.25):x<=.5?Ve("#91bfdb","#abdda4",(x-.25)/.25):x<=.75?Ve("#abdda4","#fee08b",(x-.5)/.25):Ve("#fee08b","#fc8d59",(x-.75)/.25)}else{let x=(c-45)/15;return Ve("#fc8d59","#d73027",x)}}function Tl(l,c){let x=new Array(l.length).fill(null);for(let S=0;S0&&(H.dist||0)-(l[P].dist||0)1&&l[B].ele!=null&&l[P].ele!=null&&(x[S]=(l[B].ele-l[P].ele)/A*100)}return x}function mo(l){let c=[...l];for(let x=0;x=0&&c[S]===null;)S--;let H=x+1;for(;H=0&&H=0?c[x]=c[S]:H{let J=document.querySelector(`#${A} .stat-value`);J&&(J.textContent=q)};x("stat-distance",c.totalDist!=null?`${(c.totalDist/1e3).toFixed(1)} km`:"\u2014"),x("stat-duration",c.duration!=null?he(Math.floor(c.duration/1e3)):"\u2014"),x("stat-elevation",c.elevGain!=null?`${Math.round(c.elevGain)} m`:"\u2014");let S=A=>{let q=t.find(Q=>Q.metricKey===A);if(!q)return A==="speed"?c.avgSpeed??null:A==="power"?c.avgPower??null:A==="cadence"?c.avgCadence??null:null;if(q.histData.fullStats!==void 0)return q.histData.fullStats?q.histData.fullStats.avg:null;let J=M.has(A)||A!=="power"&&A!=="cadence"&&A!=="speed",X=q.yData.filter(Q=>Q!=null&&(J||Q!==0));return X.length?X.reduce((Q,et)=>Q+et,0)/X.length:null},H=S("speed");x("stat-avg-speed",H!=null?`${(H*3.6).toFixed(1)} km/h`:"\u2014");let P=S("power");x("stat-avg-power",P!=null?`${Math.round(P)} W`:"\u2014");let B=S("cadence");x("stat-avg-cad",B!=null?`${Math.round(B)} rpm`:"\u2014"),x("stat-avg-hr",c.avgHR!=null?`${c.avgHR} bpm`:"\u2014"),x("stat-avg-temp",c.avgTemp!=null?`${c.avgTemp.toFixed(1)} \xB0C`:"\u2014")}let yn=16384,xn=new Float64Array(yn),kn=new Float64Array(yn),as=new Float64Array(yn),Nn=new Float64Array(yn),Bs=new Float64Array(yn),rs=new Float64Array(yn),Wn=new Float64Array(64),fo=[3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300,360];function Sl(l,c,x){if(!l.length)return 0;Wn.fill(0);let S=0;for(let H=0;H=St)continue;let pt=1/Ct,xt=0,kt=0,Ot=0;for(let Vt=L;Vt=Ct){xt-=rs[Vt-Ct],kt-=Nn[Vt-Ct];let ne=(xt+kt*.05)*pt;ne>Ot&&(Ot=ne)}S+=Ot*1e-4}for(let ct=L;ct0&&(Wn[Ct-1]+=.5),Ct<63&&(Wn[Ct+1]+=.5)}}}}for(let H=0;H<64;H++)S+=Wn[H]*1e-5;return G&&(G.dataset.intervalScore=S.toFixed(2)),S}return{init:$t,loadTrack:z,clear:D,resetState:it,toggleMetric:K,setXAxis:Ht,toggleStats:dt,setSelectionStats:Dt,clearSelectionStats:It,restoreSelection:Wt,resetZoom:V,cancelSelection:R,analyzeTelemetryIntervals:Sl,setCursorAt:(l,c=!1)=>{if(f=l,rt&&rt(l),c){Z&&I?.points?.[l]&&Z(I.points[l]);return}r=!0,t.forEach(({uplot:x,yData:S,xData:H})=>{H[l]!=null&&S[l]!=null&&x.batch(()=>{x.setCursor({left:x.valToPos(H[l],"x"),top:x.valToPos(S[l],"y")},!0,!1)})}),r=!1,Z&&I?.points?.[l]&&Z(I.points[l])},setHoverAt:l=>{r=!0,t.forEach(({uplot:c,yData:x,xData:S})=>{l===null?c.batch(()=>{c.setCursor({left:-10,top:-10},!0,!1)}):S[l]!=null&&x[l]!=null&&c.batch(()=>{c.setCursor({left:c.valToPos(S[l],"x"),top:c.valToPos(x[l],"y")},!0,!1)})}),r=!1,Z&&Z(l!=null&&I?.points?.[l]?I.points[l]:null)},clearPinnedDot:()=>{f=null,rt&&rt(null),t.forEach(({uplot:l})=>l.redraw(!1))},resize:Et,METRICS:qe,isDragging:()=>v,setMapColorChangeCb:Lt,toggleMapColor:st,getMapColorMetric:()=>at,getActiveMetrics:()=>d,getAvailableMetrics:()=>T,setActiveMetrics:ut,setSmooth:bt,setZeroInclusion:Pt,updateMetricOrder:l=>{let c=new Set;l.forEach(x=>{d.has(x)&&c.add(x)}),d.forEach(x=>{c.has(x)||c.add(x)}),d=c,I&&vt(!0)},getXAxis:()=>F};function Ml(l,c,x,S,H){let P=l.ctx,B=l.bbox,A=window.devicePixelRatio||1,q=zt(H,x);P.save(),P.beginPath(),P.rect(B.left,B.top,B.width,B.height),P.clip();let J=H==="gearRear"||H==="gearFront";for(let X=1;Xtt.time!=null)?.time||0,Q=x.field;S.beginPath(),S.strokeStyle="rgba(255, 255, 255, 0.04)",S.lineWidth=1*P;let et=!0;for(let tt=0;tt0){let xt=J[tt-1];(L.time&&xt.time?L.time-xt.time:0)>B&&(et=!0)}let St=x.transform?x.transform(wt):wt;if(St==null){et=!0;continue}let ct=F==="distance"?(L.dist||0)/1e3:(L.time-X)/1e3;if(ctl.scales.x.max+10){et=!0;continue}let Ct=l.valToPos(ct,"x",!0),pt=l.valToPos(St,"y",!0);if(et)S.moveTo(Ct,pt),et=!1;else{if(A){let xt=J[tt-1],kt=F==="distance"?(xt.dist||0)/1e3:(xt.time-X)/1e3;S.lineTo(l.valToPos(kt,"x",!0),pt)}S.lineTo(Ct,pt)}}S.stroke()}S.restore()}function go(l,c,x,S,H,P,B=null,A=[]){let q=l.ctx,J=l.bbox,X=window.devicePixelRatio||1,Q=6e4;q.save(),q.beginPath(),q.strokeStyle=le(S,.8),q.lineWidth=H*X;let et=P==="gearRear"||P==="gearFront",tt=!0,L=null,wt=1,St=1;if(P==="gears"&&A.length>0){let Qt=1/0,ue=-1/0;for(let Me=0;Meue&&(ue=Be))}Qt<=ue&&(wt=Qt,St=ue)}let ct=B?B[0]:l.scales.x?.min??-1/0,Ct=B?B[1]:l.scales.x?.max??1/0,pt=l.scales.x?.min??-1/0,xt=l.scales.x?.max??1/0,kt=l.scales.y?.min??0,Ot=l.scales.y?.max??100,Vt=J.width/(xt-pt||1),ne=J.height/(Ot-kt||1),ie=l.scales.y?.dir??1,re=ie===-1?J.top:J.top+J.height,ae=ie===-1?ne:-ne,mt=B?null:l.series[0]?.idxs,Kt=mt?Math.max(0,mt[0]-1):0,Xt=mt?Math.min(c.length-1,mt[1]+1):c.length-1,te=et||P==="gears"?1:Math.max(1,Math.floor((Xt-Kt)/250)),de=F==="time",fe=Q/1e3,ge=Kt;for(let Qt=Kt;Qt<=Xt;Qt+=te){let ue=c[Qt],Me=x[Qt];if(ue==null||Me==null){tt=!0;continue}if(P==="gears"&&A[Qt]){let Ae=A[Qt].gearFrontTooth??A[Qt].gearFront;if(Ae!=null&&Ae!==L){if(!tt&&Qt>0){q.stroke(),q.beginPath();let _s=J.left+(c[ge]-pt)*Vt,cs=re+(x[ge]-kt)*ae;q.moveTo(_s,cs)}let on=S;St!==wt&&Ae!=null&&(Ae===wt?on="#FFC400":Ae===St?on="#FF8C00":on="#FFA500"),q.strokeStyle=le(on,.8),L=Ae}}if(Qt>Kt&&de){let Ae=c[ge];Ae!=null&&ue-Ae>fe&&(tt=!0)}if(ueCt){tt=!0;continue}let Be=J.left+(ue-pt)*Vt,Je=re+(Me-kt)*ae;if(tt)q.moveTo(Be,Je),tt=!1;else{if(et){let Ae=c[ge];q.lineTo(J.left+(Ae-pt)*Vt,Je)}q.lineTo(Be,Je)}ge=Qt}q.stroke(),q.restore()}})();var Nl={"Heart Rate":Nt.hr.icon,Cadence:Nt.cadence.icon,Power:Nt.power.icon,Temperature:Nt.temperature.icon,Shifting:Nt.gears.icon,Battery:Nt.battery.icon},Pn=()=>{},$o=()=>{};function Po(t,s){Pn=t,$o=s}function Lo(){let t=document.getElementById("details-view");t&&(t.innerHTML=`
no_sim
Select a track for details
- `)}var cn=16384,Ue=[new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn)],Co=[3,5,10,15,20,30,45,60,90];function ql(t,n){let s=t.points,e=Math.min(s.length,cn),l=0;for(let k=0;k=e)continue;let h=1/P,b=Math.max(1,P>>1);for(let p=0;p<7;p++){let S=Ue[p],_=0,W=0,O=0,Y=0,Z=1/(10+p*15+k*2);for(let lt=0;lt=P){let rt=S[lt-P];_-=rt,W-=rt*rt;let x=_*h,v=Math.max(0,W*h-x*x),u=S[lt-b],N=Ft-S[lt-1],E=N*N*Z,G=k<4?Math.exp(-E):1/(1+E);Y+=N*N*G;let U=1/(1+v*1e-4);O+=(Ft-x)*(u-x)*U}}l+=(O+Y*.001)/Math.max(1,e)}}let i=t.stats.sections||Jt.analyzeTrackSections(s),a=[];for(let k=0;kP[1].secs-k[1].secs).slice(0,8).map(([k,P])=>({combo:k,ratio:(P.front/Math.max(1,P.rear)).toFixed(2),seconds:P.secs,pct:Number((P.secs/Math.max(1,e)*100).toFixed(1)),avgPower:Math.round(P.pwrSum/Math.max(1,P.secs)),avgCadence:Math.round(P.cadSum/Math.max(1,P.secs))})),w=n.length>0?n:[t],g=1,f=1,A=1,C=0,$=0;for(let k=0;kt.stats.totalDist&&g++,(P.avgPower||0)>(t.stats.avgPower||0)&&f++,P.elevGain>t.stats.elevGain&&A++}let M=Math.round(C/Math.max(1,w.length)),m=($/Math.max(1,w.length)/1e3).toFixed(1);return{stabilityAccum:l,splitRows:a.slice(0,12),gearMatrix:d,peerSummary:{cohortSize:w.length,distRank:g,pwrRank:f,elevRank:A,cohortAvgPower:M,cohortAvgDistKm:m}}}function Ee(t,n=[],s=[],e){let l=document.getElementById("details-view");if(!l)return;if(!t){l.innerHTML="";return}let i=t;if(e&&e.length===2){let h=t.points[0]?.time||0,b=h+e[0]*1e3,p=h+e[1]*1e3,S=Math.max(0,t.points.findIndex(W=>(W.time||0)>=b)),_=t.points.findIndex(W=>(W.time||0)>=p);if(_===-1&&(_=t.points.length-1),_>S+2){let W=t.points.slice(S,_+1),O=Jt.computeStats(W,!0);i={...t,points:W,stats:O}}}let a=i.stats,c=i.points[0].time;Jt.ensureCurvesAndZones(i);let d=ql(i,s),w=Math.min(99.9,Math.max(80,95+Math.tanh(d.stabilityAccum*.002)*4.5)).toFixed(1);l.innerHTML=` + `)}var cn=16384,Ue=[new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn)],Co=[3,5,10,15,20,30,45,60,90];function Wl(t,s){let e=t.points,n=Math.min(e.length,cn),o=0;for(let v=0;v=n)continue;let f=1/k,h=Math.max(1,k>>1);for(let p=0;p<7;p++){let E=Ue[p],_=0,W=0,O=0,Y=0,Z=1/(10+p*15+v*2);for(let lt=0;lt=k){let rt=E[lt-k];_-=rt,W-=rt*rt;let w=_*f,y=Math.max(0,W*f-w*w),m=E[lt-h],N=Ft-E[lt-1],C=N*N*Z,G=v<4?Math.exp(-C):1/(1+C);Y+=N*N*G;let U=1/(1+y*1e-4);O+=(Ft-w)*(m-w)*U}}o+=(O+Y*.001)/Math.max(1,n)}}let i=t.stats.sections||Jt.analyzeTrackSections(e),a=[];for(let v=0;vk[1].secs-v[1].secs).slice(0,8).map(([v,k])=>({combo:v,ratio:(k.front/Math.max(1,k.rear)).toFixed(2),seconds:k.secs,pct:Number((k.secs/Math.max(1,n)*100).toFixed(1)),avgPower:Math.round(k.pwrSum/Math.max(1,k.secs)),avgCadence:Math.round(k.cadSum/Math.max(1,k.secs))})),T=s.length>0?s:[t],$=1,M=1,F=1,I=0,b=0;for(let v=0;vt.stats.totalDist&&$++,(k.avgPower||0)>(t.stats.avgPower||0)&&M++,k.elevGain>t.stats.elevGain&&F++}let g=Math.round(I/Math.max(1,T.length)),u=(b/Math.max(1,T.length)/1e3).toFixed(1);return{stabilityAccum:o,splitRows:a.slice(0,12),gearMatrix:d,peerSummary:{cohortSize:T.length,distRank:$,pwrRank:M,elevRank:F,cohortAvgPower:g,cohortAvgDistKm:u}}}function Ee(t,s=[],e=[],n){let o=document.getElementById("details-view");if(!o)return;if(!t){o.innerHTML="";return}let i=t;if(n&&n.length===2){let f=t.points[0]?.time||0,h=f+n[0]*1e3,p=f+n[1]*1e3,E=Math.max(0,t.points.findIndex(W=>(W.time||0)>=h)),_=t.points.findIndex(W=>(W.time||0)>=p);if(_===-1&&(_=t.points.length-1),_>E+2){let W=t.points.slice(E,_+1),O=Jt.computeStats(W,!0);i={...t,points:W,stats:O}}}let a=i.stats,r=i.points[0].time;Jt.ensureCurvesAndZones(i);let d=Wl(i,e),T=Math.min(99.9,Math.max(80,95+Math.tanh(d.stabilityAccum*.002)*4.5)).toFixed(1);o.innerHTML=`
@@ -53,7 +53,7 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
- ${n.map(h=>`
@@ -115,7 +115,7 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
Start Time
-
${c?So(c):"Unknown"}
+
${r?So(r):"Unknown"}
@@ -129,12 +129,12 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
Telemetry Stability
-
${w}%
+
${T}%
Sensors Found
- ${a.sensors.length?a.sensors.map(h=>`${Wl[h]||"sensors"}`).join(""):'GPS only'} + ${a.sensors.length?a.sensors.map(f=>`${Nl[f]||"sensors"}`).join(""):'GPS only'}
@@ -199,13 +199,13 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( - ${d.gearMatrix.map(h=>` + ${d.gearMatrix.map(f=>` - ${me(h.combo)} - ${h.ratio} - ${h.pct}% (${h.seconds}s) - ${h.avgPower} W - ${h.avgCadence} rpm + ${me(f.combo)} + ${f.ratio} + ${f.pct}% (${f.seconds}s) + ${f.avgPower} W + ${f.avgCadence} rpm `).join("")} @@ -231,18 +231,18 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( - ${d.splitRows.map(h=>` + ${d.splitRows.map(f=>` - ${me(h.label)} - ${h.distKm} km - ${h.durationStr} - +${h.elevGain} m - ${h.avgSpeedKmh} km/h - ${h.avgPower} W - ${h.avgHR} bpm - ${h.avgCadence} rpm - ${h.avgTemp} \xB0C - ${h.stabilityPct}% + ${me(f.label)} + ${f.distKm} km + ${f.durationStr} + +${f.elevGain} m + ${f.avgSpeedKmh} km/h + ${f.avgPower} W + ${f.avgHR} bpm + ${f.avgCadence} rpm + ${f.avgTemp} \xB0C + ${f.stabilityPct}% `).join("")} @@ -253,19 +253,19 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
watchHardware & Sensors
- ${(()=>{let h=new Set;return t.devices.filter(b=>{if(!(b.name||b.product||b.manufacturer))return!1;let S=`${b.name}|${b.product}|${b.manufacturer}|${b.serial}`;return h.has(S)?!1:(h.add(S),!0)}).map(b=>{let p=b.name||b.product||"Unknown Device",S=b.manufacturer?`${b.manufacturer}`:"",_=[b.serial?`SN: ${b.serial}`:null,b.version?`v${b.version}`:null,b.hardwareVersion?`hw:${b.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),W=[b.batteryLevel?`${b.batteryLevel}%`:null,b.batteryStatus?`Status: ${b.batteryStatus}`:null,b.batteryVoltage?`${b.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),O="",Y=String(b.sourceType||"").toLowerCase();Y.includes("local")?O="memory":Y.includes("antplus")||Y.includes("ant_plus")?O="settings_input_antenna":Y.includes("bluetooth")&&(O="bluetooth");let Z="sensors",lt=String(p).toLowerCase();return lt.includes("heartrate")||lt.includes("hrm")?Z=Nt.hr.icon:lt.includes("power")?Z=Nt.power.icon:lt.includes("speed")?Z=Nt.speed.icon:lt.includes("cadence")?Z=Nt.cadence.icon:lt.includes("barometer")?Z="air":lt.includes("temperature")?Z=Nt.temperature.icon:lt.includes("gps")&&(Z="location_on"),` + ${(()=>{let f=new Set;return t.devices.filter(h=>{if(!(h.name||h.product||h.manufacturer))return!1;let E=`${h.name}|${h.product}|${h.manufacturer}|${h.serial}`;return f.has(E)?!1:(f.add(E),!0)}).map(h=>{let p=h.name||h.product||"Unknown Device",E=h.manufacturer?`${h.manufacturer}`:"",_=[h.serial?`SN: ${h.serial}`:null,h.version?`v${h.version}`:null,h.hardwareVersion?`hw:${h.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),W=[h.batteryLevel?`${h.batteryLevel}%`:null,h.batteryStatus?`Status: ${h.batteryStatus}`:null,h.batteryVoltage?`${h.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),O="",Y=String(h.sourceType||"").toLowerCase();Y.includes("local")?O="memory":Y.includes("antplus")||Y.includes("ant_plus")?O="settings_input_antenna":Y.includes("bluetooth")&&(O="bluetooth");let Z="sensors",lt=String(p).toLowerCase();return lt.includes("heartrate")||lt.includes("hrm")?Z=Nt.hr.icon:lt.includes("power")?Z=Nt.power.icon:lt.includes("speed")?Z=Nt.speed.icon:lt.includes("cadence")?Z=Nt.cadence.icon:lt.includes("barometer")?Z="air":lt.includes("temperature")?Z=Nt.temperature.icon:lt.includes("gps")&&(Z="location_on"),`
${Z}
${me(p)}
- ${O?`${O}`:""} + ${O?`${O}`:""}
-
${S}
+
${E}
${_?`
${me(_)}
`:""}
-
${me(b.type||"device")}
+
${me(h.type||"device")}
${W?`
battery_charging_full ${me(W)} @@ -284,7 +284,7 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
- `;let g=document.getElementById("tag-container"),f=document.getElementById("new-tag-input"),A=document.getElementById("btn-add-tag"),C=()=>{g.innerHTML="";let h=t.tags||[];if(h.length===0){g.innerHTML='No tags added';return}h.forEach(b=>{let p=Ts(b),S=document.createElement("div");S.className="tag-pill font-s",S.style.cssText=` + `;let $=document.getElementById("tag-container"),M=document.getElementById("new-tag-input"),F=document.getElementById("btn-add-tag"),I=()=>{$.innerHTML="";let f=t.tags||[];if(f.length===0){$.innerHTML='No tags added';return}f.forEach(h=>{let p=Ts(h),E=document.createElement("div");E.className="tag-pill font-s",E.style.cssText=` background: ${p}15; border: 1px solid ${p}44; color: ${p}; @@ -294,23 +294,23 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( display: flex; align-items: center; gap: 6px; - `,S.innerHTML=` - ${me(b)} - close - `,g.appendChild(S)}),g.querySelectorAll(".btn-remove-tag").forEach(b=>{b.addEventListener("click",async p=>{let S=p.currentTarget.dataset.tag;t.tags=(t.tags||[]).filter(_=>_!==S),await ce.save(t),C(),Pn()})})},$=async()=>{let h=f.value.trim().toLowerCase();if(!h)return;let b=new Set(t.tags||[]);if(b.has(h)){f.value="";return}b.add(h),t.tags=Array.from(b).sort(),await ce.save(t),f.value="",C(),Pn()};A.addEventListener("click",$),f.addEventListener("keydown",h=>{h.key==="Enter"&&$()});let M=l.querySelector("#details-title-input");M?.addEventListener("change",async()=>{let h=M.value.trim();h&&(t.displayName=h,await ce.save(t),Pn())});let m=document.getElementById("sport-dropdown-trigger");m?.addEventListener("click",h=>{h.stopPropagation(),k(m)});function k(h){if(!t)return;document.querySelectorAll(".metric-menu-popup").forEach(O=>O.remove());let b=document.createElement("div");b.className="metric-menu-popup",Object.keys(Ye).forEach(O=>{let Y=Ye[O],Z=document.createElement("div"),lt=t.sport?.toLowerCase()===O;Z.className=`menu-item ${lt?"active":""}`,Z.innerHTML=` + `,E.innerHTML=` + ${me(h)} + close + `,$.appendChild(E)}),$.querySelectorAll(".btn-remove-tag").forEach(h=>{h.addEventListener("click",async p=>{let E=p.currentTarget.dataset.tag;t.tags=(t.tags||[]).filter(_=>_!==E),await ce.save(t),I(),Pn()})})},b=async()=>{let f=M.value.trim().toLowerCase();if(!f)return;let h=new Set(t.tags||[]);if(h.has(f)){M.value="";return}h.add(f),t.tags=Array.from(h).sort(),await ce.save(t),M.value="",I(),Pn()};F.addEventListener("click",b),M.addEventListener("keydown",f=>{f.key==="Enter"&&b()});let g=o.querySelector("#details-title-input");g?.addEventListener("change",async()=>{let f=g.value.trim();f&&(t.displayName=f,await ce.save(t),Pn())});let u=document.getElementById("sport-dropdown-trigger");u?.addEventListener("click",f=>{f.stopPropagation(),v(u)});function v(f){if(!t)return;document.querySelectorAll(".metric-menu-popup").forEach(O=>O.remove());let h=document.createElement("div");h.className="metric-menu-popup",Object.keys(Ye).forEach(O=>{let Y=Ye[O],Z=document.createElement("div"),lt=t.sport?.toLowerCase()===O;Z.className=`menu-item ${lt?"active":""}`,Z.innerHTML=` ${Y.icon} ${Y.name} ${lt?"check":""} - `,Z.addEventListener("click",async()=>{t.sport=O,await ce.save(t),b.remove();let Ft=document.getElementById("sport-icon");Ft&&(Ft.textContent=Y.icon);let rt=document.getElementById("sport-name");rt&&(rt.textContent=Y.name),Pn()}),b.appendChild(Z)});let p=document.createElement("div"),S=!t.sport;p.className=`menu-item ${S?"active":""}`,p.innerHTML=` + `,Z.addEventListener("click",async()=>{t.sport=O,await ce.save(t),h.remove();let Ft=document.getElementById("sport-icon");Ft&&(Ft.textContent=Y.icon);let rt=document.getElementById("sport-name");rt&&(rt.textContent=Y.name),Pn()}),h.appendChild(Z)});let p=document.createElement("div"),E=!t.sport;p.className=`menu-item ${E?"active":""}`,p.innerHTML=` block \u2014 - ${S?"check":""} - `,p.addEventListener("click",async()=>{t.sport=void 0,await ce.save(t),b.remove();let O=document.getElementById("sport-icon");O&&(O.textContent="question_mark");let Y=document.getElementById("sport-name");Y&&(Y.textContent="\u2014"),Pn()}),b.appendChild(p),document.body.appendChild(b);let _=h.getBoundingClientRect();b.style.top=`${_.bottom+window.scrollY+4}px`,b.style.left=`${_.left+window.scrollX}px`;let W=O=>{!b.contains(O.target)&&!h.contains(O.target)&&(b.remove(),document.removeEventListener("click",W))};setTimeout(()=>document.addEventListener("click",W),10)}C(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${t.name}"?`)&&$o(t.id)})}import Zl from"uplot";var we=[];function No(t){return we.filter(n=>{if(n.points.length===0)return!1;for(let s of n.points){let e=!1;for(let l of t.points)if(en(s.lat,s.lon,l.lat,l.lon)<=s.radius){e=!0;break}if(!e)return!1}return!0})}var un=null,Yn=!1,dn=null,Wo=()=>{},zl=null;function qo(t){Wo=t,Ul()}function zo(){we=[],un=null,dn=null,Yn=!1;let t=document.getElementById("courses-view");t&&(t.innerHTML=` + ${E?"check":""} + `,p.addEventListener("click",async()=>{t.sport=void 0,await ce.save(t),h.remove();let O=document.getElementById("sport-icon");O&&(O.textContent="question_mark");let Y=document.getElementById("sport-name");Y&&(Y.textContent="\u2014"),Pn()}),h.appendChild(p),document.body.appendChild(h);let _=f.getBoundingClientRect();h.style.top=`${_.bottom+window.scrollY+4}px`,h.style.left=`${_.left+window.scrollX}px`;let W=O=>{!h.contains(O.target)&&!f.contains(O.target)&&(h.remove(),document.removeEventListener("click",W))};setTimeout(()=>document.addEventListener("click",W),10)}I(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${t.name}"?`)&&$o(t.id)})}import Gl from"uplot";var we=[];function No(t){return we.filter(s=>{if(s.points.length===0)return!1;for(let e of s.points){let n=!1;for(let o of t.points)if(en(e.lat,e.lon,o.lat,o.lon)<=e.radius){n=!0;break}if(!n)return!1}return!0})}var un=null,Yn=!1,dn=null,Wo=()=>{},ql=null;function qo(t){Wo=t,zl()}function zo(){we=[],un=null,dn=null,Yn=!1;let t=document.getElementById("courses-view");t&&(t.innerHTML=`
route
No courses created yet
- `)}function Us(t){we=[];let n=[{trackIdx:0,suffix:"Full Loop",fracs:[.1,.5,.85],radius:450},{trackIdx:1,suffix:"Opening Climb Sector",fracs:[.08,.25,.45],radius:450},{trackIdx:2,suffix:"Lakeside Corridor",fracs:[.1,.45,.8],radius:850},{trackIdx:3,suffix:"Sprint Interval Sector",fracs:[.2,.5,.75],radius:850},{trackIdx:4,suffix:"Alpine Grand Tour Stage",fracs:[.1,.5,.85],radius:900},{trackIdx:5,suffix:"Summit Finish Climb",fracs:[.5,.72,.92],radius:900}];for(let s=0;s0&&(un=we[0].id,dn=we[0].id)}function Uo(){return we.map(t=>t.id)}async function Ul(){try{let t=await ce.get("courses");t&&(we=t)}catch(t){console.error("Courses: Failed to load courses",t)}}async function Vs(){try{await ce.set("courses",we)}catch(t){console.error("Courses: Failed to save courses",t),Wo("Failed to save courses","error")}}function Vl(t){let n=0;for(let s=0;ss)return{duration:0,dist:0,avgWatts:null,avgHR:null,avgSpeed:null,avgCadence:null,avgVam:null};let i=Math.max(0,Math.min(n,l-1)),a=Math.max(i,Math.min(s,l-1)),c=e[i]?.time||0,w=((e[a]?.time||0)-c)/1e3,g=0,f=0,A=0,C=0,$=0,M=0,m=0,k=0,P=0;for(let b=i;b<=a;b++){let p=e[b];if(p.power!=null&&(g+=p.power,f++),p.hr!=null&&(A+=p.hr,C++),p.speed!=null&&($+=p.speed,M++),p.cadence!=null&&(m+=p.cadence,k++),b>i){let S=e[b-1];if(p.ele!=null&&S.ele!=null){let _=p.ele-S.ele;_>0&&(P+=_)}}}let h=a>i?(e[a].dist||0)-(e[i].dist||0):0;return{duration:w,dist:h,avgWatts:f>0?Math.round(g/f):null,avgHR:C>0?Math.round(A/C):null,avgSpeed:M>0?$/M:null,avgCadence:k>0?Math.round(m/k):null,avgVam:w>0?Math.round(P/(w/3600)):null}}function Ol(t){let n=Math.floor(t/3600),s=Math.floor(t%3600/60),e=Math.floor(t%60);return n>0?`${n}:${s.toString().padStart(2,"0")}:${e.toString().padStart(2,"0")}`:`${s}:${e.toString().padStart(2,"0")}`}function Os(){return` + `)}function Us(t){we=[];let s=[{trackIdx:0,suffix:"Full Loop",fracs:[.1,.5,.85],radius:450},{trackIdx:1,suffix:"Opening Climb Sector",fracs:[.08,.25,.45],radius:450},{trackIdx:2,suffix:"Lakeside Corridor",fracs:[.1,.45,.8],radius:850},{trackIdx:3,suffix:"Sprint Interval Sector",fracs:[.2,.5,.75],radius:850},{trackIdx:4,suffix:"Alpine Grand Tour Stage",fracs:[.1,.5,.85],radius:900},{trackIdx:5,suffix:"Summit Finish Climb",fracs:[.5,.72,.92],radius:900}];for(let e=0;e0&&(un=we[0].id,dn=we[0].id)}function Uo(){return we.map(t=>t.id)}async function zl(){try{let t=await ce.get("courses");t&&(we=t)}catch(t){console.error("Courses: Failed to load courses",t)}}async function Vs(){try{await ce.set("courses",we)}catch(t){console.error("Courses: Failed to save courses",t),Wo("Failed to save courses","error")}}function Ul(t){let s=0;for(let e=0;ee)return{duration:0,dist:0,avgWatts:null,avgHR:null,avgSpeed:null,avgCadence:null,avgVam:null};let i=Math.max(0,Math.min(s,o-1)),a=Math.max(i,Math.min(e,o-1)),r=n[i]?.time||0,T=((n[a]?.time||0)-r)/1e3,$=0,M=0,F=0,I=0,b=0,g=0,u=0,v=0,k=0;for(let h=i;h<=a;h++){let p=n[h];if(p.power!=null&&($+=p.power,M++),p.hr!=null&&(F+=p.hr,I++),p.speed!=null&&(b+=p.speed,g++),p.cadence!=null&&(u+=p.cadence,v++),h>i){let E=n[h-1];if(p.ele!=null&&E.ele!=null){let _=p.ele-E.ele;_>0&&(k+=_)}}}let f=a>i?(n[a].dist||0)-(n[i].dist||0):0;return{duration:T,dist:f,avgWatts:M>0?Math.round($/M):null,avgHR:I>0?Math.round(F/I):null,avgSpeed:g>0?b/g:null,avgCadence:v>0?Math.round(u/v):null,avgVam:T>0?Math.round(k/(T/3600)):null}}function Vl(t){let s=Math.floor(t/3600),e=Math.floor(t%3600/60),n=Math.floor(t%60);return s>0?`${s}:${e.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`:`${e}:${n.toString().padStart(2,"0")}`}function Os(){return` calendar_today Date straighten Distance timer Duration @@ -319,16 +319,16 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( trending_up VAM bolt Power favorite HR - `}function Ys(t,n,s){let l=(n?Ye[n.toLowerCase()]:null)?.paceUnit||"km",i="--";if(t.avgSpeed!=null&&t.avgSpeed>.1){let a=(l==="km"?1e3:100)/t.avgSpeed;i=`${On(a)} min/${l}`}return` - ${s} + `}function Ys(t,s,e){let o=(s?Ye[s.toLowerCase()]:null)?.paceUnit||"km",i="--";if(t.avgSpeed!=null&&t.avgSpeed>.1){let a=(o==="km"?1e3:100)/t.avgSpeed;i=`${On(a)} min/${o}`}return` + ${e} ${t.dist!=null?`${(t.dist/1e3).toFixed(2)} km`:"-"} - ${Ol(t.duration)} + ${Vl(t.duration)} ${t.avgSpeed!=null?`${(t.avgSpeed*3.6).toFixed(1)} km/h`:"-"} ${i} ${t.avgVam!=null?`${t.avgVam} m/h`:"-"} ${t.avgWatts!=null?`${t.avgWatts} W`:"-"} ${t.avgHR!=null?`${t.avgHR} bpm`:"-"} - `}var Cs=16384,Ao=new Float64Array(Cs),Io=new Float64Array(Cs),Ho=new Float64Array(Cs),Fo=new Float64Array(32),Do=new Float64Array(32),sn=180,Bo=28,_o=new Float64Array(sn),Ro=new Float64Array(sn),Ln=new Float64Array(sn+1),Es=new Float64Array(sn+1);function je(){let t=document.getElementById("courses-view");if(!t)return;let n=0,s=dn||un?we.filter(e=>e.id===dn||e.id===un):we;for(let e of s){if(e.points.length<2)continue;let l=Bt.findTracksPassingThroughPoints(e.points.map(a=>({lat:a.lat,lng:a.lon})),e.points[0]?.radius||20),i=4;for(let a=0;an.id===dn||n.id===un):we;for(let n of e){if(n.points.length<2)continue;let o=Bt.findTracksPassingThroughPoints(n.points.map(a=>({lat:a.lat,lng:a.lon})),n.points[0]?.radius||20),i=4;for(let a=0;a
@@ -351,7 +351,7 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( route
No courses created yet
- `:we.map(e=>{let l=e.points.map(d=>({lat:d.lat,lng:d.lon})),i=Bt.findTracksPassingThroughPoints(l,e.points[0]?.radius||20),a=e.id===dn,c="";if(a){let d=i.map(w=>{let g=Bt.getTrackData(w);if(!g)return null;let f=ks(g,e.points);if(!f)return null;let A=wn(g,f.startIdx,f.endIdx),C=Math.max(1,f.endIdx-f.startIdx),$=f.startIdx+Math.floor(C*.25),M=f.startIdx+Math.floor(C*.5),m=f.startIdx+Math.floor(C*.75),k=wn(g,f.startIdx,$),P=wn(g,$,M),h=wn(g,M,m),b=wn(g,m,f.endIdx),p=g.stats?.startTime||g.points?.[0]?.time,S=p?nn(p):"-";return{id:w,displayName:g.displayName||g.name||w,date:S,sport:g.sport,color:g.color,...A,splitsSummary:`${k.avgWatts||0}/${P.avgWatts||0}/${h.avgWatts||0}/${b.avgWatts||0}W`,startIdx:f.startIdx,endIdx:f.endIdx}}).filter(w=>w!==null);d.sort((w,g)=>w.duration-g.duration||w.id.localeCompare(g.id)),c=` + `:we.map(n=>{let o=n.points.map(d=>({lat:d.lat,lng:d.lon})),i=Bt.findTracksPassingThroughPoints(o,n.points[0]?.radius||20),a=n.id===dn,r="";if(a){let d=i.map(T=>{let $=Bt.getTrackData(T);if(!$)return null;let M=ks($,n.points);if(!M)return null;let F=wn($,M.startIdx,M.endIdx),I=Math.max(1,M.endIdx-M.startIdx),b=M.startIdx+Math.floor(I*.25),g=M.startIdx+Math.floor(I*.5),u=M.startIdx+Math.floor(I*.75),v=wn($,M.startIdx,b),k=wn($,b,g),f=wn($,g,u),h=wn($,u,M.endIdx),p=$.stats?.startTime||$.points?.[0]?.time,E=p?nn(p):"-";return{id:T,displayName:$.displayName||$.name||T,date:E,sport:$.sport,color:$.color,...F,splitsSummary:`${v.avgWatts||0}/${k.avgWatts||0}/${f.avgWatts||0}/${h.avgWatts||0}W`,startIdx:M.startIdx,endIdx:M.endIdx}}).filter(T=>T!==null);d.sort((T,$)=>T.duration-$.duration||T.id.localeCompare($.id)),r=`
${d.length===0?`
No matching tracks
@@ -364,15 +364,15 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( - ${d.map(w=>` - + ${d.map(T=>` +
-
- ${me(w.displayName)} +
+ ${me(T.displayName)}
- ${Ys(w,w.sport,w.date)} + ${Ys(T,T.sport,T.date)} `).join("")} @@ -380,53 +380,53 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( `}
`}return` -
+
${a?"expand_more":"chevron_right"} -
${me(e.name)} edit
-
straighten ${Vl(e).toFixed(2)} km | ${e.points.length} points | ${i.length} matching tracks
+
${me(n.name)} edit
+
straighten ${Ul(n).toFixed(2)} km | ${n.points.length} points | ${i.length} matching tracks
- ${c} + ${r}
`}).join("")}
- `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{Yl()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{Yn=!1,Bt.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),je()}),t.querySelectorAll(".course-item").forEach(e=>{let l=e.dataset.id;e.querySelector(".btn-edit-course")?.addEventListener("click",i=>{i.stopPropagation(),Vo(l)}),e.querySelector(".btn-rename-course")?.addEventListener("click",i=>{i.stopPropagation(),jl(l)}),e.querySelector(".btn-delete-course")?.addEventListener("click",i=>{i.stopPropagation(),Gl(l)}),e.querySelector(".course-item-header")?.addEventListener("click",i=>{i.target.closest(".course-actions")||i.target.closest(".btn-rename-course")||(Tn(l),dn=dn===l?null:l,je())}),e.querySelectorAll(".course-track-row").forEach(i=>{let a=i.dataset.trackId,c=parseInt(i.dataset.start,10),d=parseInt(i.dataset.end,10);i.querySelector(".track-name-cell")?.addEventListener("click",w=>{w.stopPropagation();let g=Bt.getTrackData(a);g&&(_e(a,!1),setTimeout(()=>{let f=g.points,A=f.find(b=>b.time!=null)?.time||0,C=Math.max(0,Math.min(c,f.length-1)),$=Math.max(0,Math.min(d,f.length-1)),M=Math.max(0,((f[C]?.time||0)-A)/1e3),m=Math.max(0,((f[$]?.time||0)-A)/1e3),k=ft.getXAxis(),P=M,h=m;k==="distance"&&(P=Math.max(0,(f[C]?.dist||0)/1e3),h=Math.max(0,(f[$]?.dist||0)/1e3)),Gt.patch({sel:[P,h],tab:"graphs"},!0),ft.restoreSelection(M,m),Bt.highlightSegment(a,g.points,c,d,!0)},50))}),i.addEventListener("mouseenter",()=>{Bt.setTrackHover(a,!0)}),i.addEventListener("mouseleave",()=>{Bt.setTrackHover(a,!1)})})})}function Yl(){let t=`Course ${we.length+1}`,n={id:Math.random().toString(36).substring(2,9),name:t,points:[]};we.push(n),Vs(),je(),Vo(n.id)}function jl(t){let n=we.find(c=>c.id===t);if(!n)return;let s=document.querySelector(`.course-item[data-id="${t}"]`);if(!s)return;let e=s.querySelector(".course-name");if(!e)return;let l=n.name;e.innerHTML=``;let i=e.querySelector(".course-name-input");i.focus(),i.select();let a=()=>{let c=i.value.trim();c!==""&&(n.name=c,Vs()),je()};i.addEventListener("blur",a),i.addEventListener("keydown",c=>{c.key==="Enter"?a():c.key==="Escape"&&je()})}function Vo(t){un=t,Yn=!0,je()}function Oo(){zl=null}function Tn(t,n=!1){un=t,n&&(dn=t),Yn=!1,Bt.setCustomClickHandler(null),Oo(),je()}function Gl(t){confirm("Are you sure you want to delete this course?")&&(we=we.filter(n=>n.id!==t),un===t&&(un=null,Oo()),Vs(),je())}var Ls=()=>{},js=[];function Qo(){js.forEach(t=>t.destroy()),js=[]}function Ko(t){Ls=t}function Jo(){Qo(),document.querySelectorAll(".hr-settings-popup").forEach(n=>n.remove());let t=document.getElementById("insights-view");t&&(t.innerHTML=` + `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{Ol()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{Yn=!1,Bt.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),je()}),t.querySelectorAll(".course-item").forEach(n=>{let o=n.dataset.id;n.querySelector(".btn-edit-course")?.addEventListener("click",i=>{i.stopPropagation(),Vo(o)}),n.querySelector(".btn-rename-course")?.addEventListener("click",i=>{i.stopPropagation(),Yl(o)}),n.querySelector(".btn-delete-course")?.addEventListener("click",i=>{i.stopPropagation(),jl(o)}),n.querySelector(".course-item-header")?.addEventListener("click",i=>{i.target.closest(".course-actions")||i.target.closest(".btn-rename-course")||(Tn(o),dn=dn===o?null:o,je())}),n.querySelectorAll(".course-track-row").forEach(i=>{let a=i.dataset.trackId,r=parseInt(i.dataset.start,10),d=parseInt(i.dataset.end,10);i.querySelector(".track-name-cell")?.addEventListener("click",T=>{T.stopPropagation();let $=Bt.getTrackData(a);$&&(_e(a,!1),setTimeout(()=>{let M=$.points,F=M.find(h=>h.time!=null)?.time||0,I=Math.max(0,Math.min(r,M.length-1)),b=Math.max(0,Math.min(d,M.length-1)),g=Math.max(0,((M[I]?.time||0)-F)/1e3),u=Math.max(0,((M[b]?.time||0)-F)/1e3),v=ft.getXAxis(),k=g,f=u;v==="distance"&&(k=Math.max(0,(M[I]?.dist||0)/1e3),f=Math.max(0,(M[b]?.dist||0)/1e3)),Gt.patch({sel:[k,f],tab:"graphs"},!0),ft.restoreSelection(g,u),Bt.highlightSegment(a,$.points,r,d,!0)},50))}),i.addEventListener("mouseenter",()=>{Bt.setTrackHover(a,!0)}),i.addEventListener("mouseleave",()=>{Bt.setTrackHover(a,!1)})})})}function Ol(){let t=`Course ${we.length+1}`,s={id:Math.random().toString(36).substring(2,9),name:t,points:[]};we.push(s),Vs(),je(),Vo(s.id)}function Yl(t){let s=we.find(r=>r.id===t);if(!s)return;let e=document.querySelector(`.course-item[data-id="${t}"]`);if(!e)return;let n=e.querySelector(".course-name");if(!n)return;let o=s.name;n.innerHTML=``;let i=n.querySelector(".course-name-input");i.focus(),i.select();let a=()=>{let r=i.value.trim();r!==""&&(s.name=r,Vs()),je()};i.addEventListener("blur",a),i.addEventListener("keydown",r=>{r.key==="Enter"?a():r.key==="Escape"&&je()})}function Vo(t){un=t,Yn=!0,je()}function Oo(){ql=null}function Tn(t,s=!1){un=t,s&&(dn=t),Yn=!1,Bt.setCustomClickHandler(null),Oo(),je()}function jl(t){confirm("Are you sure you want to delete this course?")&&(we=we.filter(s=>s.id!==t),un===t&&(un=null,Oo()),Vs(),je())}var Ls=()=>{},js=[];function Qo(){js.forEach(t=>t.destroy()),js=[]}function Ko(t){Ls=t}function Jo(){Qo(),document.querySelectorAll(".hr-settings-popup").forEach(s=>s.remove());let t=document.getElementById("insights-view");t&&(t.innerHTML=`
no_sim
Select a track for insights
- `)}var mn=16384,Yo=new Float64Array(mn),jo=new Float64Array(mn),Go=new Float64Array(mn),Xl=new Float64Array(mn),Ql=new Float64Array(mn),$s=new Float64Array(mn+1),Ps=new Float64Array(mn+1),Zo=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,420,600,900,1200];function Kl(t,n,s){let e=Math.min(t.length,mn);if(e===0)return{minWPrimeBal:2e4,matchesBurned:0,decouplingPct:0,quadrantPct:[25,25,25,25],sectionPeaks:[]};for(let p=0;p0?Y*Z*36:0;Yo[p]=_,jo[p]=1/W,Go[p]=O,Xl[p]=Y,Ql[p]=lt,$s[p+1]=$s[p]+_,Ps[p+1]=Ps[p]+lt}let l=0;for(let p=0;pe)continue;let _=e-S,W=0,O=0;for(let Y=0;Y<=_;Y++){let Z=$s[Y+S]-$s[Y],lt=Ps[Y+S]-Ps[Y];Z>W&&(W=Z),lt>O&&(O=lt)}l+=(W+O)/S}let i=2e4,a=2e4,c=0,d=!1,w=e>>1,g=0,f=0,A=[0,0,0,0],C=88,$=n/C;for(let p=0;p0?O:0,Ft=546*Math.exp(-.008*(Y+Z*.625))+316;a=Math.min(2e4,a-Z+(2e4-a)*(1/Ft)),a17500&&d&&(d=!1);let rt=S/_;rt>=$&&_>=C?A[0]++:rt>=$&&_0?g/w:1,m=e-w>0?f/(e-w):1,k=M>0?(M-m)/M*100:0,P=[Number((A[0]/e*100).toFixed(1)),Number((A[1]/e*100).toFixed(1)),Number((A[2]/e*100).toFixed(1)),Number((A[3]/e*100).toFixed(1))],b=(s&&s.length>0?s.filter(p=>p.kind==="quarter"||p.kind==="climb"||p.kind==="sprint"):[]).slice(0,8).map(p=>{let S=p.stats,_=S.duration&&S.duration>0?S.duration/36e5:0;return{label:p.label,distKm:Number((S.totalDist/1e3).toFixed(2)),avgPower:S.avgPower||0,peak60sPower:S.powerCurve?.[60]?.power||S.avgPower||0,avgHR:S.avgHR||0,vam:_>0?Math.round(S.elevGain/_):0}});return l<-1e12&&(i=0),{minWPrimeBal:i,matchesBurned:c,decouplingPct:k,quadrantPct:P,sectionPeaks:b}}function be(t,n=[],s=null){Qo();let e=document.getElementById("insights-view");if(!e)return;if(!t){e.innerHTML="";return}Jt.ensureCurvesAndZones(t),t.stats.sections||(t.stats.sections=Jt.analyzeTrackSections(t.points));let l=s||Gt.get().sel||null,i=t.points,a=t.stats;if(l&&t.points.length>4){let M=t.points[0].time||0,m=M+l[0]*1e3,k=M+l[1]*1e3,P=t.points.findIndex(b=>(b.time||0)>=m),h=t.points.findIndex(b=>(b.time||0)>=k);P===-1&&(P=0),h===-1&&(h=t.points.length-1),h>P+4&&(i=t.points.slice(P,h+1),a=Jt.computeStats(i,!0))}if(!a.powerCurve&&!a.hrZones&&!a.hrCurve){e.innerHTML=` + `)}var mn=16384,Yo=new Float64Array(mn),jo=new Float64Array(mn),Go=new Float64Array(mn),Zl=new Float64Array(mn),Xl=new Float64Array(mn),$s=new Float64Array(mn+1),Ps=new Float64Array(mn+1),Zo=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,420,600,900,1200];function Ql(t,s,e){let n=Math.min(t.length,mn);if(n===0)return{minWPrimeBal:2e4,matchesBurned:0,decouplingPct:0,quadrantPct:[25,25,25,25],sectionPeaks:[]};for(let p=0;p0?Y*Z*36:0;Yo[p]=_,jo[p]=1/W,Go[p]=O,Zl[p]=Y,Xl[p]=lt,$s[p+1]=$s[p]+_,Ps[p+1]=Ps[p]+lt}let o=0;for(let p=0;pn)continue;let _=n-E,W=0,O=0;for(let Y=0;Y<=_;Y++){let Z=$s[Y+E]-$s[Y],lt=Ps[Y+E]-Ps[Y];Z>W&&(W=Z),lt>O&&(O=lt)}o+=(W+O)/E}let i=2e4,a=2e4,r=0,d=!1,T=n>>1,$=0,M=0,F=[0,0,0,0],I=88,b=s/I;for(let p=0;p0?O:0,Ft=546*Math.exp(-.008*(Y+Z*.625))+316;a=Math.min(2e4,a-Z+(2e4-a)*(1/Ft)),a17500&&d&&(d=!1);let rt=E/_;rt>=b&&_>=I?F[0]++:rt>=b&&_0?$/T:1,u=n-T>0?M/(n-T):1,v=g>0?(g-u)/g*100:0,k=[Number((F[0]/n*100).toFixed(1)),Number((F[1]/n*100).toFixed(1)),Number((F[2]/n*100).toFixed(1)),Number((F[3]/n*100).toFixed(1))],h=(e&&e.length>0?e.filter(p=>p.kind==="quarter"||p.kind==="climb"||p.kind==="sprint"):[]).slice(0,8).map(p=>{let E=p.stats,_=E.duration&&E.duration>0?E.duration/36e5:0;return{label:p.label,distKm:Number((E.totalDist/1e3).toFixed(2)),avgPower:E.avgPower||0,peak60sPower:E.powerCurve?.[60]?.power||E.avgPower||0,avgHR:E.avgHR||0,vam:_>0?Math.round(E.elevGain/_):0}});return o<-1e12&&(i=0),{minWPrimeBal:i,matchesBurned:r,decouplingPct:v,quadrantPct:k,sectionPeaks:h}}function be(t,s=[],e=null){Qo();let n=document.getElementById("insights-view");if(!n)return;if(!t){n.innerHTML="";return}Jt.ensureCurvesAndZones(t),t.stats.sections||(t.stats.sections=Jt.analyzeTrackSections(t.points));let o=e||Gt.get().sel||null,i=t.points,a=t.stats;if(o&&t.points.length>4){let g=t.points[0].time||0,u=g+o[0]*1e3,v=g+o[1]*1e3,k=t.points.findIndex(h=>(h.time||0)>=u),f=t.points.findIndex(h=>(h.time||0)>=v);k===-1&&(k=0),f===-1&&(f=t.points.length-1),f>k+4&&(i=t.points.slice(k,f+1),a=Jt.computeStats(i,!0))}if(!a.powerCurve&&!a.hrZones&&!a.hrCurve){n.innerHTML=`
analytics
No insights available for this track (requires Power or Heart Rate data)
- `;return}let c=Kl(i,Jt.getFTP(),t.stats.sections),d=c.minWPrimeBal;e.innerHTML=` -
- `;let w=document.getElementById("insights-grid");if(!w)return;let g=Math.round(w.getBoundingClientRect().width-42)||480;if(a.powerCurve&&Xo({grid:w,track:t,curve:a.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:Nt.power.color,icon:"bolt",chartWidth:g}),a.hrCurve&&Xo({grid:w,track:t,curve:a.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:Nt.hr.color,icon:"favorite",chartWidth:g}),a.powerZones){let M=document.createElement("div");M.className="insight-card";let m="power",k=Nt.power.color;M.style.setProperty("--chart-color",k);let P=ft.getMapColorMetric()===m,h=a.powerZones.reduce((S,_)=>S+_,0),b=$n.getPowerZones(),p="";a.powerZones.forEach((S,_)=>{if(_>=b.length)return;let W=b[_],O=h>0?S/h*100:0,Y=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} W`:`> ${Math.round(W.min)} W`;p+=` + `;return}let r=Ql(i,Jt.getFTP(),t.stats.sections),d=r.minWPrimeBal;n.innerHTML=` +
+ `;let T=document.getElementById("insights-grid");if(!T)return;let $=Math.round(T.getBoundingClientRect().width-42)||480;if(a.powerCurve&&Xo({grid:T,track:t,curve:a.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:Nt.power.color,icon:"bolt",chartWidth:$}),a.hrCurve&&Xo({grid:T,track:t,curve:a.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:Nt.hr.color,icon:"favorite",chartWidth:$}),a.powerZones){let g=document.createElement("div");g.className="insight-card";let u="power",v=Nt.power.color;g.style.setProperty("--chart-color",v);let k=ft.getMapColorMetric()===u,f=a.powerZones.reduce((E,_)=>E+_,0),h=$n.getPowerZones(),p="";a.powerZones.forEach((E,_)=>{if(_>=h.length)return;let W=h[_],O=f>0?E/f*100:0,Y=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} W`:`> ${Math.round(W.min)} W`;p+=`
Z${_+1} ${W.name} ${Y} - ${he(Math.round(S))} + ${he(Math.round(E))} ${O.toFixed(1)}%
- `}),M.innerHTML=` + `}),g.innerHTML=`
- boltPower Zones + boltPower Zones
-
@@ -435,26 +435,26 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
${p}
- `,w.appendChild(M),M.querySelector(".map-color-btn")?.addEventListener("click",S=>{S.stopPropagation(),ft.toggleMapColor(m);let _=ft.getMapColorMetric();w.querySelectorAll(".map-color-btn").forEach(W=>{let O=W;O.classList.toggle("active",O.dataset.metric===_)})}),M.querySelector(".btn-pw-settings")?.addEventListener("click",S=>{S.stopPropagation(),ti(S.currentTarget,t)})}if(a.hrZones){let M=document.createElement("div");M.className="insight-card";let m="hr",k=Nt.hr.color;M.style.setProperty("--chart-color",k);let P=ft.getMapColorMetric()===m,h=a.hrZones.reduce((S,_)=>S+_,0),b=$n.getHRZones(),p="";a.hrZones.forEach((S,_)=>{if(_>=b.length)return;let W=b[_],O=h>0?S/h*100:0,Y=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} bpm`:`> ${Math.round(W.min)} bpm`;p+=` + `,T.appendChild(g),g.querySelector(".map-color-btn")?.addEventListener("click",E=>{E.stopPropagation(),ft.toggleMapColor(u);let _=ft.getMapColorMetric();T.querySelectorAll(".map-color-btn").forEach(W=>{let O=W;O.classList.toggle("active",O.dataset.metric===_)})}),g.querySelector(".btn-pw-settings")?.addEventListener("click",E=>{E.stopPropagation(),Jl(E.currentTarget,t)})}if(a.hrZones){let g=document.createElement("div");g.className="insight-card";let u="hr",v=Nt.hr.color;g.style.setProperty("--chart-color",v);let k=ft.getMapColorMetric()===u,f=a.hrZones.reduce((E,_)=>E+_,0),h=$n.getHRZones(),p="";a.hrZones.forEach((E,_)=>{if(_>=h.length)return;let W=h[_],O=f>0?E/f*100:0,Y=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} bpm`:`> ${Math.round(W.min)} bpm`;p+=`
Z${_+1} ${W.name} ${Y} - ${he(Math.round(S))} + ${he(Math.round(E))} ${O.toFixed(1)}%
- `}),M.innerHTML=` + `}),g.innerHTML=`
- favoriteHeart Rate Zones + favoriteHeart Rate Zones
-
@@ -463,7 +463,7 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
${p}
- `,w.appendChild(M),M.querySelector(".map-color-btn")?.addEventListener("click",S=>{S.stopPropagation(),ft.toggleMapColor(m);let _=ft.getMapColorMetric();w.querySelectorAll(".map-color-btn").forEach(W=>{let O=W;O.classList.toggle("active",O.dataset.metric===_)})}),M.querySelector(".btn-hr-settings")?.addEventListener("click",S=>{S.stopPropagation(),Jl(S.currentTarget,t)})}let f=document.createElement("div");f.className="insight-card";let A=a.totalDist/1e3,C=A>0?a.elevGain/(A*1e3)*100:0;if(f.innerHTML=` + `,T.appendChild(g),g.querySelector(".map-color-btn")?.addEventListener("click",E=>{E.stopPropagation(),ft.toggleMapColor(u);let _=ft.getMapColorMetric();T.querySelectorAll(".map-color-btn").forEach(W=>{let O=W;O.classList.toggle("active",O.dataset.metric===_)})}),g.querySelector(".btn-hr-settings")?.addEventListener("click",E=>{E.stopPropagation(),Kl(E.currentTarget,t)})}let M=document.createElement("div");M.className="insight-card";let F=a.totalDist/1e3,I=F>0?a.elevGain/(F*1e3)*100:0;if(M.innerHTML=`
terrainClimbing Analysis
@@ -478,36 +478,36 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
Avg Grade
-
${C.toFixed(1)} %
+
${I.toFixed(1)} %
VAM
${a.duration&&a.duration>0?Math.round(a.elevGain/a.duration*36e5):0} m/h
- `,w.appendChild(f),a.avgPower&&a.avgHR){let M=document.createElement("div");M.className="insight-card";let m=a.avgPower/a.avgHR;M.innerHTML=` + `,T.appendChild(M),a.avgPower&&a.avgHR){let g=document.createElement("div");g.className="insight-card";let u=a.avgPower/a.avgHR;g.innerHTML=`
monitoringEfficiency & W' Balance
EF (Avg Power / Avg HR)
-
${m.toFixed(2)}
+
${u.toFixed(2)}
Aerobic Decoupling
-
${c.decouplingPct.toFixed(1)} %
+
${r.decouplingPct.toFixed(1)} %
Min W' Reserve
-
${(c.minWPrimeBal/1e3).toFixed(1)} kJ (${c.matchesBurned} matches)
+
${(r.minWPrimeBal/1e3).toFixed(1)} kJ (${r.matchesBurned} matches)
Quadrants (Q1/Q2/Q3/Q4)
-
${c.quadrantPct.join("% / ")}%
+
${r.quadrantPct.join("% / ")}%
- `,w.appendChild(M)}if(c.sectionPeaks.length>0){let M=document.createElement("div");M.className="insight-card",M.innerHTML=` + `,T.appendChild(g)}if(r.sectionPeaks.length>0){let g=document.createElement("div");g.className="insight-card",g.innerHTML=`
segmentTrack Section & Climb Efforts
@@ -523,20 +523,20 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( - ${c.sectionPeaks.map(m=>` + ${r.sectionPeaks.map(u=>` - ${me(m.label)} - ${m.distKm} km - ${m.avgPower} W - ${m.peak60sPower} W - ${m.avgHR} bpm - ${m.vam} m/h + ${me(u.label)} + ${u.distKm} km + ${u.avgPower} W + ${u.peak60sPower} W + ${u.avgHR} bpm + ${u.vam} m/h `).join("")} - `,w.appendChild(M)}let $=No(t);if($.length>0){let M=document.createElement("div");M.className="insight-card",M.style.cssText="column-span: all; display: block;",M.innerHTML=` -
routeCourses (${$.length})
+ `,T.appendChild(g)}let b=No(t);if(b.length>0){let g=document.createElement("div");g.className="insight-card",g.style.cssText="column-span: all; display: block;",g.innerHTML=` +
routeCourses (${b.length})
@@ -546,27 +546,27 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( - ${$.map(m=>{let k=ks(t,m.points),P="";if(k){let h=wn(t,k.startIdx,k.endIdx),b=t.stats?.startTime||t.points?.[0]?.time,p=b?nn(b):"-";P=Ys(h,t.sport||null,p)}else P='';return` - + ${b.map(u=>{let v=ks(t,u.points),k="";if(v){let f=wn(t,v.startIdx,v.endIdx),h=t.stats?.startTime||t.points?.[0]?.time,p=h?nn(h):"-";k=Ys(f,t.sport||null,p)}else k='';return` + - ${P} + ${k} `}).join("")}
No continuous segment
No continuous segment
- ${me(m.name)} + ${me(u.name)}
- `,w.appendChild(M),M.querySelectorAll(".clickable-course").forEach(m=>{m.addEventListener("click",()=>{let k=m.dataset.id;Tn(k,!0),Gt.patch({tab:"courses"},!0)}),m.addEventListener("mouseenter",()=>{let k=m.dataset.id,P=$.find(h=>h.id===k);if(P){let h=ks(t,P.points);h&&Bt.highlightSegment(t.id,t.points,h.startIdx,h.endIdx,!1)}}),m.addEventListener("mouseleave",()=>{Bt.clearHighlight()})})}}function Xo(t){let{grid:n,track:s,curve:e,metricKey:l,label:i,unit:a,color:c,icon:d,chartWidth:w}=t,g=ft.getMapColorMetric()===l,f=document.createElement("div");f.className="insight-card",f.style.setProperty("--chart-color",c),f.innerHTML=` + `,T.appendChild(g),g.querySelectorAll(".clickable-course").forEach(u=>{u.addEventListener("click",()=>{let v=u.dataset.id;Tn(v,!0),Gt.patch({tab:"courses"},!0)}),u.addEventListener("mouseenter",()=>{let v=u.dataset.id,k=b.find(f=>f.id===v);if(k){let f=ks(t,k.points);f&&Bt.highlightSegment(t.id,t.points,f.startIdx,f.endIdx,!1)}}),u.addEventListener("mouseleave",()=>{Bt.clearHighlight()})})}}function Xo(t){let{grid:s,track:e,curve:n,metricKey:o,label:i,unit:a,color:r,icon:d,chartWidth:T}=t,$=ft.getMapColorMetric()===o,M=document.createElement("div");M.className="insight-card",M.style.setProperty("--chart-color",r),M.innerHTML=`
- ${d}${i} + ${d}${i}
-
@@ -574,7 +574,7 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( expand_more
-
+
- `,n.appendChild(f);let A=f.querySelector(".curve-table-wrap"),C=f.querySelector(".btn-toggle-table"),$=C.querySelector(".material-symbols-rounded");C.addEventListener("click",()=>{let h=A.style.display==="none";A.style.display=h?"block":"none",$.textContent=h?"expand_less":"expand_more"});let M=f.querySelector(".map-color-btn");M.addEventListener("click",h=>{h.stopPropagation();let b=M.dataset.metric;ft.toggleMapColor(b);let p=ft.getMapColorMetric();n.querySelectorAll(".map-color-btn").forEach(S=>{let _=S;_.classList.toggle("active",_.dataset.metric===p)})});let m=f.querySelector(".curve-tbody"),k=Object.keys(e).map(Number).sort((h,b)=>h-b);k.forEach(h=>{let b=e[h],p=b.power||b.hr||b.val,S=document.createElement("tr");S.innerHTML=` - ${ze(h)} + `,s.appendChild(M);let F=M.querySelector(".curve-table-wrap"),I=M.querySelector(".btn-toggle-table"),b=I.querySelector(".material-symbols-rounded");I.addEventListener("click",()=>{let f=F.style.display==="none";F.style.display=f?"block":"none",b.textContent=f?"expand_less":"expand_more"});let g=M.querySelector(".map-color-btn");g.addEventListener("click",f=>{f.stopPropagation();let h=g.dataset.metric;ft.toggleMapColor(h);let p=ft.getMapColorMetric();s.querySelectorAll(".map-color-btn").forEach(E=>{let _=E;_.classList.toggle("active",_.dataset.metric===p)})});let u=M.querySelector(".curve-tbody"),v=Object.keys(n).map(Number).sort((f,h)=>f-h);v.forEach(f=>{let h=n[f],p=h.power||h.hr||h.val,E=document.createElement("tr");E.innerHTML=` + ${ze(f)} ${p} ${a} - - `,m?.appendChild(S)}),m?.querySelectorAll(".btn-show-peak").forEach(h=>{h.addEventListener("click",b=>{let p=b.currentTarget,S=parseInt(p.dataset.idx),_=parseInt(p.dataset.len),W=s.points,O=Math.min(W.length-1,S+_-1),Y=W[0].time||0,Z=((W[S].time||Y)-Y)/1e3,lt=((W[O].time||Y)-Y)/1e3;Gt.patch({sel:[Z,lt]}),Bt.highlightSegment(s.id,W,S,O,!0)})});let P=f.querySelector(`#${l}-curve-chart`);if(P){let h=k,b=k.map(W=>e[W].power||e[W].hr||e[W].val),p=document.createElement("div");p.className="cur-y-val",p.style.cssText=`color:${c};display:none;border-color:${c}44`,P.style.position="relative",P.appendChild(p);let S={id:`${l}-curve`,width:0,height:250,padding:[10,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:i,stroke:c,width:2,fill:le(c,.1),points:{show:!0,size:5,fill:c}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(W,O)=>O.map(Y=>`${Y}${a}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(W,O,Y)=>Y},hooks:{draw:[W=>{let O=W.ctx,Y=window.devicePixelRatio||1,Z=W.bbox,lt=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Ft=h[h.length-1];O.save(),O.fillStyle="#555564",O.textAlign="center",O.textBaseline="top",O.font=`${10*Y}px system-ui, sans-serif`;let rt=-100;lt.forEach(x=>{if(x>Ft)return;let v=W.valToPos(x,"x",!0);v>rt+30*Y&&v{W.over.addEventListener("click",()=>{let O=W.cursor.idx;if(O!=null&&h[O]!=null){let Y=h[O],lt=e[Y].idx,Ft=s.points,rt=Math.min(Ft.length-1,lt+Y-1),x=Ft[0].time||0,v=((Ft[lt].time||x)-x)/1e3,u=((Ft[rt].time||x)-x)/1e3;Gt.patch({sel:[v,u]}),Bt.highlightSegment(s.id,Ft,lt,rt,!0)}})}],setCursor:[W=>{if(!W._ready)return;W.redraw(!1);let O=W.cursor.idx,Y=W.ctx,Z=window.devicePixelRatio||1,lt=W.bbox,Ft=O!=null&&b[O]!=null&&W.cursor.left>=0,rt=W.cursor.top,x=W.valToPos(b[O],"y",!1);if(Ft&&Math.abs(rt-x)<40){let u=W.valToPos(h[O],"x",!1),N=W.valToPos(b[O],"y",!1),E=h[O];p.innerHTML=`${ze(E)}: ${b[O]} ${a}`,p.style.transform=`translate(${u}px, ${N}px) translate(15px, 15px)`,p.style.display="";let G=W.valToPos(h[O],"x",!0),U=W.valToPos(b[O],"y",!0);Y.save(),Y.beginPath(),Y.setLineDash([2*Z,2*Z]),Y.strokeStyle=le(c,.4),Y.lineWidth=1*Z,Y.moveTo(G,lt.top),Y.lineTo(G,lt.top+lt.height),Y.stroke(),Y.beginPath(),Y.setLineDash([]),Y.arc(G,U,3*Z,0,Math.PI*2),Y.fillStyle="#0e0e10",Y.fill(),Y.strokeStyle=c,Y.lineWidth=2*Z,Y.stroke(),Y.restore()}else p.style.display="none"}]},legend:{show:!1}};S.width=w||Math.round(n.getBoundingClientRect().width-42)||P.clientWidth||500;let _=new Zl(S,[h,b],P);_._ready=!0,js.push(_)}}function Jl(t,n){document.querySelectorAll(".hr-settings-popup").forEach(a=>a.remove());let s=document.createElement("div");s.className="hr-settings-popup";let e=Jt.getHRZones();s.innerHTML=` + `,u?.appendChild(E)}),u?.querySelectorAll(".btn-show-peak").forEach(f=>{f.addEventListener("click",h=>{let p=h.currentTarget,E=parseInt(p.dataset.idx),_=parseInt(p.dataset.len),W=e.points,O=Math.min(W.length-1,E+_-1),Y=W[0].time||0,Z=((W[E].time||Y)-Y)/1e3,lt=((W[O].time||Y)-Y)/1e3;Gt.patch({sel:[Z,lt]}),Bt.highlightSegment(e.id,W,E,O,!0)})});let k=M.querySelector(`#${o}-curve-chart`);if(k){let f=v,h=v.map(W=>n[W].power||n[W].hr||n[W].val),p=document.createElement("div");p.className="cur-y-val",p.style.cssText=`color:${r};display:none;border-color:${r}44`,k.style.position="relative",k.appendChild(p);let E={id:`${o}-curve`,width:0,height:250,padding:[10,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:i,stroke:r,width:2,fill:le(r,.1),points:{show:!0,size:5,fill:r}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(W,O)=>O.map(Y=>`${Y}${a}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(W,O,Y)=>Y},hooks:{draw:[W=>{let O=W.ctx,Y=window.devicePixelRatio||1,Z=W.bbox,lt=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Ft=f[f.length-1];O.save(),O.fillStyle="#555564",O.textAlign="center",O.textBaseline="top",O.font=`${10*Y}px system-ui, sans-serif`;let rt=-100;lt.forEach(w=>{if(w>Ft)return;let y=W.valToPos(w,"x",!0);y>rt+30*Y&&y{W.over.addEventListener("click",()=>{let O=W.cursor.idx;if(O!=null&&f[O]!=null){let Y=f[O],lt=n[Y].idx,Ft=e.points,rt=Math.min(Ft.length-1,lt+Y-1),w=Ft[0].time||0,y=((Ft[lt].time||w)-w)/1e3,m=((Ft[rt].time||w)-w)/1e3;Gt.patch({sel:[y,m]}),Bt.highlightSegment(e.id,Ft,lt,rt,!0)}})}],setCursor:[W=>{if(!W._ready)return;W.redraw(!1);let O=W.cursor.idx,Y=W.ctx,Z=window.devicePixelRatio||1,lt=W.bbox,Ft=O!=null&&h[O]!=null&&W.cursor.left>=0,rt=W.cursor.top,w=W.valToPos(h[O],"y",!1);if(Ft&&Math.abs(rt-w)<40){let m=W.valToPos(f[O],"x",!1),N=W.valToPos(h[O],"y",!1),C=f[O];p.innerHTML=`${ze(C)}: ${h[O]} ${a}`,p.style.transform=`translate(${m}px, ${N}px) translate(15px, 15px)`,p.style.display="";let G=W.valToPos(f[O],"x",!0),U=W.valToPos(h[O],"y",!0);Y.save(),Y.beginPath(),Y.setLineDash([2*Z,2*Z]),Y.strokeStyle=le(r,.4),Y.lineWidth=1*Z,Y.moveTo(G,lt.top),Y.lineTo(G,lt.top+lt.height),Y.stroke(),Y.beginPath(),Y.setLineDash([]),Y.arc(G,U,3*Z,0,Math.PI*2),Y.fillStyle="#0e0e10",Y.fill(),Y.strokeStyle=r,Y.lineWidth=2*Z,Y.stroke(),Y.restore()}else p.style.display="none"}]},legend:{show:!1}};E.width=T||Math.round(s.getBoundingClientRect().width-42)||k.clientWidth||500;let _=new Gl(E,[f,h],k);_._ready=!0,js.push(_)}}function Kl(t,s){document.querySelectorAll(".hr-settings-popup").forEach(a=>a.remove());let e=document.createElement("div");e.className="hr-settings-popup";let n=Jt.getHRZones();e.innerHTML=`
Configure HR Zones (bpm)
Z1 / Z2 - +
Z2 / Z3 - +
Z3 / Z4 - +
Z4 / Z5 - +
- `;let l=t.getBoundingClientRect();s.style.cssText=` + `;let o=t.getBoundingClientRect();e.style.cssText=` position: fixed; z-index: 10000; background: var(--surface2); @@ -625,18 +625,18 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( padding: 16px; width: 200px; box-shadow: 0 8px 32px rgba(0,0,0,0.6); - left: ${l.right-200}px; - top: ${l.bottom+8}px; - `,document.body.appendChild(s),s.querySelector(".save-btn")?.addEventListener("click",async()=>{let a=s.querySelectorAll(".hr-zone-input"),c=Array.from(a).map(d=>parseInt(d.value)||0);for(let d=1;d{!s.contains(a.target)&&!t.contains(a.target)&&(s.remove(),document.removeEventListener("click",i))};setTimeout(()=>document.addEventListener("click",i),10)}function ti(t,n){document.querySelectorAll(".pw-settings-popup").forEach(a=>a.remove());let s=document.createElement("div");s.className="pw-settings-popup";let e=Jt.getFTP();s.innerHTML=` + left: ${o.right-200}px; + top: ${o.bottom+8}px; + `,document.body.appendChild(e),e.querySelector(".save-btn")?.addEventListener("click",async()=>{let a=e.querySelectorAll(".hr-zone-input"),r=Array.from(a).map(d=>parseInt(d.value)||0);for(let d=1;d{!e.contains(a.target)&&!t.contains(a.target)&&(e.remove(),document.removeEventListener("click",i))};setTimeout(()=>document.addEventListener("click",i),10)}function Jl(t,s){document.querySelectorAll(".pw-settings-popup").forEach(a=>a.remove());let e=document.createElement("div");e.className="pw-settings-popup";let n=Jt.getFTP();e.innerHTML=`
Configure FTP (Watts)
Your FTP - +
- `;let l=t.getBoundingClientRect();s.style.cssText=` + `;let o=t.getBoundingClientRect();e.style.cssText=` position: fixed; z-index: 10000; background: var(--surface2); @@ -645,27 +645,27 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( padding: 16px; width: 200px; box-shadow: 0 8px 32px rgba(0,0,0,0.6); - left: ${l.right-200}px; - top: ${l.bottom+8}px; - `,document.body.appendChild(s),s.querySelector(".save-btn")?.addEventListener("click",async()=>{let a=s.querySelector("#ftp-input"),c=parseInt(a.value)||200;Jt.setFTP(c),await ce.set("ftp",c),n.stats=Jt.computeStats(n.points,!0),await ce.save(n),be(n),s.remove(),Ls(`FTP updated to ${c}W`)});let i=a=>{!s.contains(a.target)&&!t.contains(a.target)&&(s.remove(),document.removeEventListener("click",i))};setTimeout(()=>document.addEventListener("click",i),10)}import tl from"uplot";var Te=[],$e=null,pe=null,fn="power",Qe="hr",ve=null,Ie=[],Xe=[],pn=null,He=!1;function jn(){let t=document.getElementById("combined-time-val");if(t&&ve!==null&&Ie[ve]){let n=Ie[ve][2];t.textContent=`${he(n)}`}}function nl(){pn&&(clearInterval(pn),pn=null),pe&&(pe.destroy(),pe=null),Te=[],$e=null,fn="power",Qe="hr",ve=null,Ie=[],Xe=[],He=!1;let t=document.getElementById("combined-tooltip");t&&t.remove();let n=document.getElementById("combined-view");n&&(n.innerHTML=` + left: ${o.right-200}px; + top: ${o.bottom+8}px; + `,document.body.appendChild(e),e.querySelector(".save-btn")?.addEventListener("click",async()=>{let a=e.querySelector("#ftp-input"),r=parseInt(a.value)||200;Jt.setFTP(r),await ce.set("ftp",r),s.stats=Jt.computeStats(s.points,!0),await ce.save(s),be(s),e.remove(),Ls(`FTP updated to ${r}W`)});let i=a=>{!e.contains(a.target)&&!t.contains(a.target)&&(e.remove(),document.removeEventListener("click",i))};setTimeout(()=>document.addEventListener("click",i),10)}import tl from"uplot";var Te=[],$e=null,pe=null,fn="power",Qe="hr",ve=null,Ie=[],Xe=[],pn=null,He=!1;function jn(){let t=document.getElementById("combined-time-val");if(t&&ve!==null&&Ie[ve]){let s=Ie[ve][2];t.textContent=`${he(s)}`}}function nl(){pn&&(clearInterval(pn),pn=null),pe&&(pe.destroy(),pe=null),Te=[],$e=null,fn="power",Qe="hr",ve=null,Ie=[],Xe=[],He=!1;let t=document.getElementById("combined-tooltip");t&&t.remove();let s=document.getElementById("combined-view");s&&(s.innerHTML=`
no_sim
Select a track for combined analysis
- `)}var ei=16384,Gs=new Float64Array(32*32);function ni(t,n){let s=n.length>=2?n:t,e=Math.min(s.length,8);Gs.fill(0);let l=[{label:"Power vs Heart Rate",getX:A=>A.power,getY:A=>A.hr},{label:"Speed vs Gradient",getX:A=>A.speed!=null?A.speed*3.6:void 0,getY:A=>A.gradient},{label:"Cadence vs Power",getX:A=>A.cad,getY:A=>A.power},{label:"Elevation vs VAM",getX:A=>A.ele,getY:A=>A.verticalSpeed},{label:"Temperature vs HR",getX:A=>A.temp,getY:A=>A.hr}],i=0,a=0,c=[];for(let A=0;A2){let S=$/h,_=M/h,W=Math.max(0,m/h-S*S),O=Math.max(0,k/h-_*_),Y=P/h-S*_,Z=Math.sqrt(W*O);b=Z>1e-9?Y/Z:0,p=W>1e-9?Y/W:0}i+=h,a+=Math.abs(b)*100+Math.abs(p),c.push({pairLabel:C.label,rVal:b,slope:p,samples:h})}for(let A=0;A<1024;A++)a+=Gs[A]*.001;let d=["Q1 (0\u201325%)","Q2 (25\u201350%)","Q3 (50\u201375%)","Q4 (75\u2013100%)"],w=[],g=t[0],f=t[1]||t[0];for(let A=0;A<4;A++){let C=A*.25,$=(A+1)*.25,M=h=>{let b=h.points||[],p=Math.floor(b.length*C),S=Math.max(p+1,Math.floor(b.length*$)),_=0,W=0,O=0,Y=0;for(let Z=p;Z0?Math.round(_/Y):0,hr:Y>0?Math.round(W/Y):0,speedKmh:Y>0?O/Y:0}},m=M(g),k=M(f),P=0;for(let h=0;h0?Math.round(P/e):0})}return{aggPts:i,corrSum:a,correlations:c,sectionRows:w}}function Zs(t,n){fn=t,Qe=n,Te.length>=2?Fe(Te):$e&&Fe($e)}function Zn(t){He!==t&&(He=t,Te.length>=2?Fe(Te):$e&&Fe($e))}function Xn(t){let n=Math.max(0,Math.min(1,t)),s=Ie.length>0?Ie.length-1:$e?Math.max(0,$e.points.length-1):0;ve=Math.round(n*s);let e=document.getElementById("combined-time-slider");e&&(e.max=`${s}`,e.value=`${ve}`),jn(),pe&&pe.redraw()}function Fe(t,n=[]){Array.isArray(t)?(Te=t,$e=t[0]||null):t?(Te=[t],$e=t):(Te=[],$e=null);let s=document.getElementById("combined-view");if(!s)return;let e=$e;if(!e){s.innerHTML=` + `)}var ti=16384,Gs=new Float64Array(32*32);function ei(t,s){let e=s.length>=2?s:t,n=Math.min(e.length,8);Gs.fill(0);let o=[{label:"Power vs Heart Rate",getX:F=>F.power,getY:F=>F.hr},{label:"Speed vs Gradient",getX:F=>F.speed!=null?F.speed*3.6:void 0,getY:F=>F.gradient},{label:"Cadence vs Power",getX:F=>F.cad,getY:F=>F.power},{label:"Elevation vs VAM",getX:F=>F.ele,getY:F=>F.verticalSpeed},{label:"Temperature vs HR",getX:F=>F.temp,getY:F=>F.hr}],i=0,a=0,r=[];for(let F=0;F2){let E=b/f,_=g/f,W=Math.max(0,u/f-E*E),O=Math.max(0,v/f-_*_),Y=k/f-E*_,Z=Math.sqrt(W*O);h=Z>1e-9?Y/Z:0,p=W>1e-9?Y/W:0}i+=f,a+=Math.abs(h)*100+Math.abs(p),r.push({pairLabel:I.label,rVal:h,slope:p,samples:f})}for(let F=0;F<1024;F++)a+=Gs[F]*.001;let d=["Q1 (0\u201325%)","Q2 (25\u201350%)","Q3 (50\u201375%)","Q4 (75\u2013100%)"],T=[],$=t[0],M=t[1]||t[0];for(let F=0;F<4;F++){let I=F*.25,b=(F+1)*.25,g=f=>{let h=f.points||[],p=Math.floor(h.length*I),E=Math.max(p+1,Math.floor(h.length*b)),_=0,W=0,O=0,Y=0;for(let Z=p;Z0?Math.round(_/Y):0,hr:Y>0?Math.round(W/Y):0,speedKmh:Y>0?O/Y:0}},u=g($),v=g(M),k=0;for(let f=0;f0?Math.round(k/n):0})}return{aggPts:i,corrSum:a,correlations:r,sectionRows:T}}function Zs(t,s){fn=t,Qe=s,Te.length>=2?Fe(Te):$e&&Fe($e)}function Zn(t){He!==t&&(He=t,Te.length>=2?Fe(Te):$e&&Fe($e))}function Xn(t){let s=Math.max(0,Math.min(1,t)),e=Ie.length>0?Ie.length-1:$e?Math.max(0,$e.points.length-1):0;ve=Math.round(s*e);let n=document.getElementById("combined-time-slider");n&&(n.max=`${e}`,n.value=`${ve}`),jn(),pe&&pe.redraw()}function Fe(t,s=[]){Array.isArray(t)?(Te=t,$e=t[0]||null):t?(Te=[t],$e=t):(Te=[],$e=null);let e=document.getElementById("combined-view");if(!e)return;let n=$e;if(!n){e.innerHTML=`
no_sim
Select a track for combined analysis
- `;return}let l=ft.METRICS,i=[];for(let $ in l){let M=l[$];e.points.some(m=>m[M.field]!=null)&&i.push($)}!i.includes(fn)&&i.length>0&&(fn=i[0]),!i.includes(Qe)&&i.length>1?Qe=i[1]:!i.includes(Qe)&&i.length>0&&(Qe=i[0]);let a=l[fn],c=l[Qe];s.style.overflow="hidden";let d="";if(Te.length>=2){let{aggPts:$,corrSum:M,correlations:m,sectionRows:k}=ni(Te,n),P=Te[0],h=Te[1],b=P.stats,p=h.stats,S=((p.totalDist-b.totalDist)/1e3).toFixed(2),_=((p.avgPower||0)-(b.avgPower||0)).toFixed(0),W=((p.avgHR||0)-(b.avgHR||0)).toFixed(0),O=(p.elevGain-b.elevGain).toFixed(0),Y=(p.shifts||0)-(b.shifts||0),Z=((b.totalDist+p.totalDist)/1e3).toFixed(2),lt=(b.elevGain+p.elevGain).toFixed(0),Ft=((b.duration||0)+(p.duration||0))/1e3,rt=Math.round(((b.avgPower||0)+(p.avgPower||0))/2),x=Math.max(b.maxPower||0,p.maxPower||0),v=Math.round(((b.avgHR||0)+(p.avgHR||0))/2),u=Math.max(b.maxHR||0,p.maxHR||0),N=((p.avgTemp??0)-(b.avgTemp??0)).toFixed(1),E=(((b.avgTemp??0)+(p.avgTemp??0))/2).toFixed(1),G=Math.max(b.maxTemp??0,p.maxTemp??0).toFixed(1),U=(b.shifts||0)+(p.shifts||0);d=` -
+ `;return}let o=ft.METRICS,i=[];for(let b in o){let g=o[b];n.points.some(u=>u[g.field]!=null)&&i.push(b)}!i.includes(fn)&&i.length>0&&(fn=i[0]),!i.includes(Qe)&&i.length>1?Qe=i[1]:!i.includes(Qe)&&i.length>0&&(Qe=i[0]);let a=o[fn],r=o[Qe];e.style.overflow="hidden";let d="";if(Te.length>=2){let{aggPts:b,corrSum:g,correlations:u,sectionRows:v}=ei(Te,s),k=Te[0],f=Te[1],h=k.stats,p=f.stats,E=((p.totalDist-h.totalDist)/1e3).toFixed(2),_=((p.avgPower||0)-(h.avgPower||0)).toFixed(0),W=((p.avgHR||0)-(h.avgHR||0)).toFixed(0),O=(p.elevGain-h.elevGain).toFixed(0),Y=(p.shifts||0)-(h.shifts||0),Z=((h.totalDist+p.totalDist)/1e3).toFixed(2),lt=(h.elevGain+p.elevGain).toFixed(0),Ft=((h.duration||0)+(p.duration||0))/1e3,rt=Math.round(((h.avgPower||0)+(p.avgPower||0))/2),w=Math.max(h.maxPower||0,p.maxPower||0),y=Math.round(((h.avgHR||0)+(p.avgHR||0))/2),m=Math.max(h.maxHR||0,p.maxHR||0),N=((p.avgTemp??0)-(h.avgTemp??0)).toFixed(1),C=(((h.avgTemp??0)+(p.avgTemp??0))/2).toFixed(1),G=Math.max(h.maxTemp??0,p.maxTemp??0).toFixed(1),U=(h.shifts||0)+(p.shifts||0);d=` +
Aggregate Track Comparison & Section Analysis (${Te.length} Tracks)
- - + + @@ -673,54 +673,54 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( - + - + - + - + - + - + - + - + - + - + - + - ${k.map(j=>` + ${v.map(j=>` @@ -731,10 +731,10 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
Metric${P.displayName||P.name} (T1)${h.displayName||h.name} (T2)${k.displayName||k.name} (T1)${f.displayName||f.name} (T2) Delta (T2 - T1) Aggregate Summary
Distance${(b.totalDist/1e3).toFixed(2)} km${(h.totalDist/1e3).toFixed(2)} km ${(p.totalDist/1e3).toFixed(2)} km${Number(S)>=0?"+":""}${S} km${Number(E)>=0?"+":""}${E} km ${Z} km (Total)
Elevation Gain${b.elevGain.toFixed(0)} m${h.elevGain.toFixed(0)} m ${p.elevGain.toFixed(0)} m ${Number(O)>=0?"+":""}${O} m ${lt} m (Total)
Duration${b.duration?he(b.duration/1e3):"--"}${h.duration?he(h.duration/1e3):"--"} ${p.duration?he(p.duration/1e3):"--"} -- ${he(Ft)} (Total)
Avg / Max Power${b.avgPower||0} W / ${b.maxPower||0} W${h.avgPower||0} W / ${h.maxPower||0} W ${p.avgPower||0} W / ${p.maxPower||0} W ${Number(_)>=0?"+":""}${_} W (Avg)${rt} W (Avg) / ${x} W (Max)${rt} W (Avg) / ${w} W (Max)
Avg / Max HR${b.avgHR||0} bpm / ${b.maxHR||0} bpm${h.avgHR||0} bpm / ${h.maxHR||0} bpm ${p.avgHR||0} bpm / ${p.maxHR||0} bpm ${Number(W)>=0?"+":""}${W} bpm (Avg)${v} bpm (Avg) / ${u} bpm (Max)${y} bpm (Avg) / ${m} bpm (Max)
Avg / Max Temp${b.avgTemp!=null?b.avgTemp.toFixed(1):"--"} \xB0C / ${b.maxTemp!=null?b.maxTemp.toFixed(1):"--"} \xB0C${h.avgTemp!=null?h.avgTemp.toFixed(1):"--"} \xB0C / ${h.maxTemp!=null?h.maxTemp.toFixed(1):"--"} \xB0C ${p.avgTemp!=null?p.avgTemp.toFixed(1):"--"} \xB0C / ${p.maxTemp!=null?p.maxTemp.toFixed(1):"--"} \xB0C ${Number(N)>=0?"+":""}${N} \xB0C (Avg)${E} \xB0C (Avg) / ${G} \xB0C (Max)${C} \xB0C (Avg) / ${G} \xB0C (Max)
Gear Shifts${b.shifts||0}${h.shifts||0} ${p.shifts||0} ${Y>=0?"+":""}${Y} ${U} (Total)
${j.sectionLabel} Split ${j.t1Power}W \xB7 ${j.t1Hr}bpm \xB7 ${j.t1SpeedKmh.toFixed(1)}km/h
- ${m.map(j=>`${j.pairLabel}: r=${j.rVal.toFixed(2)}, \u03B2=${j.slope.toFixed(2)} (${j.samples})`).join("")} + ${u.map(j=>`${j.pairLabel}: r=${j.rVal.toFixed(2)}, \u03B2=${j.slope.toFixed(2)} (${j.samples})`).join("")}
- `}s.innerHTML=`${d} + `}e.innerHTML=`${d}
arrow_forward @@ -749,8 +749,8 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( arrow_upward Y Axis:
@@ -773,66 +773,66 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
- `,document.getElementById("btn-combined-x")?.addEventListener("click",$=>{$.stopPropagation(),el($.currentTarget,"x")}),document.getElementById("btn-combined-y")?.addEventListener("click",$=>{$.stopPropagation(),el($.currentTarget,"y")});let w=document.getElementById("combined-time-slider"),g=document.getElementById("combined-time-val"),f=document.getElementById("btn-combined-play");w?.addEventListener("input",()=>{ve=parseInt(w.value,10),jn(),pe&&pe.redraw()});function A(){f&&(f.innerHTML='pause'),pn=window.setInterval(()=>{ve!==null&&veplay_arrow')}f?.addEventListener("click",()=>{pn?C():(ve!==null&&ve>=Ie.length-1&&(ve=0,w.value="0",jn(),pe&&pe.redraw()),A())}),document.getElementById("btn-combined-cart")?.addEventListener("click",()=>{He&&(He=!1,Fe($e))}),document.getElementById("btn-combined-polar")?.addEventListener("click",()=>{He||(He=!0,Fe($e))}),si()}function Gn(){let t=document.getElementById("tab-combined"),n=document.getElementById("combined-plot-container");if(pe&&n&&n.clientWidth>0){let s=n.clientWidth,e=n.clientHeight;if(s>0&&e>0)if(He){let l=Math.min(s,e);pe.setSize({width:l,height:l})}else pe.setSize({width:s,height:e})}}function el(t,n){document.querySelectorAll(".metric-menu-popup").forEach(d=>d.remove());let s=document.createElement("div");s.className="metric-menu-popup";let e=ft.METRICS,l=$e;if(!l)return;let i=[];for(let d in e){let w=e[d];l.points.some(g=>g[w.field]!=null)&&i.push(d)}i.forEach(d=>{let w=e[d],g=document.createElement("div"),f=n==="x"?fn:Qe;g.className=`menu-item ${f===d?"active":""}`,g.innerHTML=` - ${w.icon} - ${w.label} - ${f===d?"check":""} - `,g.addEventListener("click",()=>{n==="x"?fn=d:Qe=d,s.remove(),Fe($e)}),s.appendChild(g)});let a=t.getBoundingClientRect();s.style.top=`${a.bottom+5}px`,s.style.left=`${a.left}px`,document.body.appendChild(s);let c=d=>{!s.contains(d.target)&&!t.contains(d.target)&&(s.remove(),document.removeEventListener("click",c))};setTimeout(()=>document.addEventListener("click",c),0)}function si(){if(!$e)return;let t=document.getElementById("combined-plot-container");if(!t)return;let n=ft.METRICS,s=n[fn]||n.power,e=n[Qe]||n.hr;if(Te.length>=2){let $=0;for(let p=0;p$&&($=Te[p].points.length);let M=new Array($);for(let p=0;p<$;p++)M[p]=p;let m=[{}],k=[M];for(let p=0;p0?t.clientWidth:800,h=t.clientHeight>0?t.clientHeight:350,b={width:P,height:h,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:m,axes:[{side:2,label:"Elapsed Duration (s)",stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:30},{side:3,label:`${e.label} (${e.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:40}],legend:{show:!0}};pe=new tl(b,k,t),Gn();return}let l=$e.points,i=l[0].time||0,a=l.map(($,M)=>[$[s.field],$[e.field],($.time-i)/1e3,($.dist||0)/1e3,M]).filter(([$,M,m,k])=>$!=null&&M!=null);if(a.length===0){t.innerHTML='
No data for selected metrics
';return}if(He){let $=a.map(b=>b[0]),M=a.map(b=>b[1]),m=Math.min(...$),k=Math.max(...$),P=Math.min(...M),h=Math.max(...M);Ie=a.map(b=>{let p=b[0],S=b[1],_=(p-m)/(k-m||1)*2*Math.PI,W=(S-P)/(h-P||1),O=W*Math.cos(_),Y=W*Math.sin(_);return[O,Y,b[2],b[3],b[4],p,S]})}else Ie=a.map($=>[$[0],$[1],$[2],$[3],$[4],$[0],$[1]]);let c=document.getElementById("combined-time-slider");c&&(c.max=`${a.length-1}`,(ve===null||ve>=a.length)&&(ve=a.length-1,c.value=c.max),jn()),Xe=[...Ie].sort(($,M)=>$[0]-M[0]||$[4]-M[4]);let d=Xe.map($=>$[0]),w=Xe.map($=>$[1]),g=document.getElementById("combined-plot-container"),f=g&&g.clientWidth>0?g.clientWidth:600,A=g&&g.clientHeight>0?g.clientHeight:400;if(He){let $=Math.min(f,A>0?A:f);f=$,A=$,g&&(g.style.display="flex",g.style.alignItems="center",g.style.justifyContent="center")}else g&&(g.style.display="",g.style.alignItems="",g.style.justifyContent="");let C={width:f,height:A,padding:[10,15,0,0],scales:{x:{time:!1,auto:!0},y:{auto:!0}},series:[{},{label:e.label,width:0,points:{show:!0,size:3,fill:le(e.color,.3)}}],axes:[{side:2,show:!He,label:`${s.label} (${s.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:($,M)=>M.map(m=>m!=null?s.fmtAxis(m):""),size:30},{side:3,show:!He,label:`${e.label} (${e.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:($,M)=>M.map(m=>m!=null?e.fmtAxis(m):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:($,M,m)=>{let k=$.cursor.left,P=$.cursor.top;if(k!=null&&P!=null&&k>=0&&P>=0){let h=1/0,b=-1;for(let p=0;p=0&&h<2500)return b}return m},points:{size:7,stroke:"#fff",width:2,fill:e.color}},legend:{show:!1},hooks:{draw:[$=>{let M=$.ctx,m=window.devicePixelRatio||1;M.save(),M.beginPath(),M.strokeStyle="rgba(255, 255, 255, 0.15)",M.lineWidth=1*m;let k=!1;for(let P=0;P{let M=$.cursor.idx,m=document.getElementById("combined-tooltip");if(m||(m=document.createElement("div"),m.id="combined-tooltip",m.style.position="absolute",m.style.background="rgba(14, 14, 16, 0.9)",m.style.color="#fff",m.style.padding="8px 12px",m.style.borderRadius="4px",m.classList.add("font-m"),m.style.fontFamily="system-ui",m.style.pointerEvents="none",m.style.zIndex="1000",m.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",m.style.border="1px solid #2e2e34",document.body.appendChild(m)),M!=null&&Xe[M]&&$.cursor.left>=0){let k=Xe[M],P=k[2],h=k[3],b=k[5],p=k[6];m.innerHTML=` -
Point #${M}
+ `,document.getElementById("btn-combined-x")?.addEventListener("click",b=>{b.stopPropagation(),el(b.currentTarget,"x")}),document.getElementById("btn-combined-y")?.addEventListener("click",b=>{b.stopPropagation(),el(b.currentTarget,"y")});let T=document.getElementById("combined-time-slider"),$=document.getElementById("combined-time-val"),M=document.getElementById("btn-combined-play");T?.addEventListener("input",()=>{ve=parseInt(T.value,10),jn(),pe&&pe.redraw()});function F(){M&&(M.innerHTML='pause'),pn=window.setInterval(()=>{ve!==null&&veplay_arrow')}M?.addEventListener("click",()=>{pn?I():(ve!==null&&ve>=Ie.length-1&&(ve=0,T.value="0",jn(),pe&&pe.redraw()),F())}),document.getElementById("btn-combined-cart")?.addEventListener("click",()=>{He&&(He=!1,Fe($e))}),document.getElementById("btn-combined-polar")?.addEventListener("click",()=>{He||(He=!0,Fe($e))}),ni()}function Gn(){let t=document.getElementById("tab-combined"),s=document.getElementById("combined-plot-container");if(pe&&s&&s.clientWidth>0){let e=s.clientWidth,n=s.clientHeight;if(e>0&&n>0)if(He){let o=Math.min(e,n);pe.setSize({width:o,height:o})}else pe.setSize({width:e,height:n})}}function el(t,s){document.querySelectorAll(".metric-menu-popup").forEach(d=>d.remove());let e=document.createElement("div");e.className="metric-menu-popup";let n=ft.METRICS,o=$e;if(!o)return;let i=[];for(let d in n){let T=n[d];o.points.some($=>$[T.field]!=null)&&i.push(d)}i.forEach(d=>{let T=n[d],$=document.createElement("div"),M=s==="x"?fn:Qe;$.className=`menu-item ${M===d?"active":""}`,$.innerHTML=` + ${T.icon} + ${T.label} + ${M===d?"check":""} + `,$.addEventListener("click",()=>{s==="x"?fn=d:Qe=d,e.remove(),Fe($e)}),e.appendChild($)});let a=t.getBoundingClientRect();e.style.top=`${a.bottom+5}px`,e.style.left=`${a.left}px`,document.body.appendChild(e);let r=d=>{!e.contains(d.target)&&!t.contains(d.target)&&(e.remove(),document.removeEventListener("click",r))};setTimeout(()=>document.addEventListener("click",r),0)}function ni(){if(!$e)return;let t=document.getElementById("combined-plot-container");if(!t)return;let s=ft.METRICS,e=s[fn]||s.power,n=s[Qe]||s.hr;if(Te.length>=2){let b=0;for(let p=0;pb&&(b=Te[p].points.length);let g=new Array(b);for(let p=0;p0?t.clientWidth:800,f=t.clientHeight>0?t.clientHeight:350,h={width:k,height:f,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:u,axes:[{side:2,label:"Elapsed Duration (s)",stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:30},{side:3,label:`${n.label} (${n.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:40}],legend:{show:!0}};pe=new tl(h,v,t),Gn();return}let o=$e.points,i=o[0].time||0,a=o.map((b,g)=>[b[e.field],b[n.field],(b.time-i)/1e3,(b.dist||0)/1e3,g]).filter(([b,g,u,v])=>b!=null&&g!=null);if(a.length===0){t.innerHTML='
No data for selected metrics
';return}if(He){let b=a.map(h=>h[0]),g=a.map(h=>h[1]),u=Math.min(...b),v=Math.max(...b),k=Math.min(...g),f=Math.max(...g);Ie=a.map(h=>{let p=h[0],E=h[1],_=(p-u)/(v-u||1)*2*Math.PI,W=(E-k)/(f-k||1),O=W*Math.cos(_),Y=W*Math.sin(_);return[O,Y,h[2],h[3],h[4],p,E]})}else Ie=a.map(b=>[b[0],b[1],b[2],b[3],b[4],b[0],b[1]]);let r=document.getElementById("combined-time-slider");r&&(r.max=`${a.length-1}`,(ve===null||ve>=a.length)&&(ve=a.length-1,r.value=r.max),jn()),Xe=[...Ie].sort((b,g)=>b[0]-g[0]||b[4]-g[4]);let d=Xe.map(b=>b[0]),T=Xe.map(b=>b[1]),$=document.getElementById("combined-plot-container"),M=$&&$.clientWidth>0?$.clientWidth:600,F=$&&$.clientHeight>0?$.clientHeight:400;if(He){let b=Math.min(M,F>0?F:M);M=b,F=b,$&&($.style.display="flex",$.style.alignItems="center",$.style.justifyContent="center")}else $&&($.style.display="",$.style.alignItems="",$.style.justifyContent="");let I={width:M,height:F,padding:[10,15,0,0],scales:{x:{time:!1,auto:!0},y:{auto:!0}},series:[{},{label:n.label,width:0,points:{show:!0,size:3,fill:le(n.color,.3)}}],axes:[{side:2,show:!He,label:`${e.label} (${e.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(b,g)=>g.map(u=>u!=null?e.fmtAxis(u):""),size:30},{side:3,show:!He,label:`${n.label} (${n.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(b,g)=>g.map(u=>u!=null?n.fmtAxis(u):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:(b,g,u)=>{let v=b.cursor.left,k=b.cursor.top;if(v!=null&&k!=null&&v>=0&&k>=0){let f=1/0,h=-1;for(let p=0;p=0&&f<2500)return h}return u},points:{size:7,stroke:"#fff",width:2,fill:n.color}},legend:{show:!1},hooks:{draw:[b=>{let g=b.ctx,u=window.devicePixelRatio||1;g.save(),g.beginPath(),g.strokeStyle="rgba(255, 255, 255, 0.15)",g.lineWidth=1*u;let v=!1;for(let k=0;k{let g=b.cursor.idx,u=document.getElementById("combined-tooltip");if(u||(u=document.createElement("div"),u.id="combined-tooltip",u.style.position="absolute",u.style.background="rgba(14, 14, 16, 0.9)",u.style.color="#fff",u.style.padding="8px 12px",u.style.borderRadius="4px",u.classList.add("font-m"),u.style.fontFamily="system-ui",u.style.pointerEvents="none",u.style.zIndex="1000",u.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",u.style.border="1px solid #2e2e34",document.body.appendChild(u)),g!=null&&Xe[g]&&b.cursor.left>=0){let v=Xe[g],k=v[2],f=v[3],h=v[5],p=v[6];u.innerHTML=` +
Point #${g}
Time: - ${he(P)} + ${he(k)}
Distance: - ${h.toFixed(2)} km + ${f.toFixed(2)} km
- ${s.label}: - ${s.fmtAxis(b)} ${s.unit} + ${e.label}: + ${e.fmtAxis(h)} ${e.unit}
- ${e.label}: - ${e.fmtAxis(p)} ${e.unit} + ${n.label}: + ${n.fmtAxis(p)} ${n.unit}
- `,m.style.display="block";let S=$.over.getBoundingClientRect();m.style.left=`${S.left+window.scrollX+$.cursor.left+15}px`,m.style.top=`${S.top+window.scrollY+$.cursor.top+15}px`}else m.style.display="none"}]}};t.querySelector(".empty-text")&&(t.innerHTML=""),pe&&pe.destroy(),pe=new tl(C,[d,w],t),pe.over.addEventListener("click",()=>{if(pe){let $=pe.cursor.idx;if($!=null&&Xe[$]){let M=Xe[$][4];ft.setCursorAt(M)}}}),Gn()}import An from"uplot";function gn(t,n){let s=0;for(let p=0;ps&&(s=S)}s||(s=Date.UTC(2026,7,1));let e=new Date(s),l=e.getUTCFullYear(),i=Date.UTC(l-1,e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds()),a=Date.UTC(l,e.getUTCMonth()-6,e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds()),c=Date.UTC(l,e.getUTCMonth()-1,e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds()),d=0,w=0,g=0,f=0,A=0,C=s;t.forEach(p=>{if(!p.stats.startTime)return;let S=n(p);if(S===void 0)return;A+=S;let _=p.stats.startTime;_=i&&(w+=S),_>=a&&(g+=S),_>=c&&(f+=S)});let $=7*24*60*60*1e3,M=Date.UTC(l,0,1),m=Math.max(.1,(s-M)/$),k=Math.max(.1,(s-i)/$),P=Math.max(.1,(s-a)/$),h=Math.max(.1,(s-c)/$),b=Math.max(.1,(s-C)/$);return{currentYear:d,pastYear:w,past6m:g,past1m:f,total:A,currentYearAvg:d/m,pastYearAvg:w/k,past6mAvg:g/P,past1mAvg:f/h,totalAvg:A/b}}function sl(t,n,s){let e=n?1e3:1,l=i=>(n?i/e:i).toLocaleString("en-US",{minimumFractionDigits:n?1:0,maximumFractionDigits:n?1:0});return` + `,u.style.display="block";let E=b.over.getBoundingClientRect();u.style.left=`${E.left+window.scrollX+b.cursor.left+15}px`,u.style.top=`${E.top+window.scrollY+b.cursor.top+15}px`}else u.style.display="none"}]}};t.querySelector(".empty-text")&&(t.innerHTML=""),pe&&pe.destroy(),pe=new tl(I,[d,T],t),pe.over.addEventListener("click",()=>{if(pe){let b=pe.cursor.idx;if(b!=null&&Xe[b]){let g=Xe[b][4];ft.setCursorAt(g)}}}),Gn()}import An from"uplot";function gn(t,s){let e=0;for(let p=0;pe&&(e=E)}e||(e=Date.UTC(2026,7,1));let n=new Date(e),o=n.getUTCFullYear(),i=Date.UTC(o-1,n.getUTCMonth(),n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),a=Date.UTC(o,n.getUTCMonth()-6,n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),r=Date.UTC(o,n.getUTCMonth()-1,n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds()),d=0,T=0,$=0,M=0,F=0,I=e;t.forEach(p=>{if(!p.stats.startTime)return;let E=s(p);if(E===void 0)return;F+=E;let _=p.stats.startTime;_=i&&(T+=E),_>=a&&($+=E),_>=r&&(M+=E)});let b=7*24*60*60*1e3,g=Date.UTC(o,0,1),u=Math.max(.1,(e-g)/b),v=Math.max(.1,(e-i)/b),k=Math.max(.1,(e-a)/b),f=Math.max(.1,(e-r)/b),h=Math.max(.1,(e-I)/b);return{currentYear:d,pastYear:T,past6m:$,past1m:M,total:F,currentYearAvg:d/u,pastYearAvg:T/v,past6mAvg:$/k,past1mAvg:M/f,totalAvg:F/h}}function sl(t,s,e){let n=s?1e3:1,o=i=>(s?i/n:i).toLocaleString("en-US",{minimumFractionDigits:s?1:0,maximumFractionDigits:s?1:0});return` - - + + - - + + - - + + - - + + - - + + - - + +
Period${n?"Distance":"Elevation"}${n?"Distance/Week":"Elevation/Week"}${s?"Distance":"Elevation"}${s?"Distance/Week":"Elevation/Week"}
Current Year${l(t.currentYear)} ${s}${l(t.currentYearAvg)} ${s}${o(t.currentYear)} ${e}${o(t.currentYearAvg)} ${e}
Past Year${l(t.pastYear)} ${s}${l(t.pastYearAvg)} ${s}${o(t.pastYear)} ${e}${o(t.pastYearAvg)} ${e}
Past 6 Months${l(t.past6m)} ${s}${l(t.past6mAvg)} ${s}${o(t.past6m)} ${e}${o(t.past6mAvg)} ${e}
Past 1 Month${l(t.past1m)} ${s}${l(t.past1mAvg)} ${s}${o(t.past1m)} ${e}${o(t.past1mAvg)} ${e}
Total${l(t.total)} ${s}${l(t.totalAvg)} ${s}${o(t.total)} ${e}${o(t.totalAvg)} ${e}
- `}function oi(t){let n=gn(t,c=>c.stats.totalDist),s=gn(t,c=>c.stats.elevGain),e=gn(t,c=>c.stats.duration?c.stats.duration/36e5:0),l=gn(t,c=>{let d=(c.stats.duration||0)/1e3,w=c.stats.avgPower||150,g=200,f=w/g;return d*w*f/(g*3600)*100}),i=gn(t,c=>{let d=(c.stats.duration||0)/1e3,w=c.stats.avgPower||0;return d*w/1e3}),a=gn(t,c=>(c.stats.sections||[]).filter(w=>w.kind==="climb").length);return{distance:n,elevation:s,durationHours:e,tss:l,workKj:i,climbCount:a}}function ol(t){let n=oi(t),s=(l,i=1)=>l.toLocaleString("en-US",{minimumFractionDigits:i,maximumFractionDigits:i});return` + `}function si(t){let s=gn(t,r=>r.stats.totalDist),e=gn(t,r=>r.stats.elevGain),n=gn(t,r=>r.stats.duration?r.stats.duration/36e5:0),o=gn(t,r=>{let d=(r.stats.duration||0)/1e3,T=r.stats.avgPower||150,$=200,M=T/$;return d*T*M/($*3600)*100}),i=gn(t,r=>{let d=(r.stats.duration||0)/1e3,T=r.stats.avgPower||0;return d*T/1e3}),a=gn(t,r=>(r.stats.sections||[]).filter(T=>T.kind==="climb").length);return{distance:s,elevation:e,durationHours:n,tss:o,workKj:i,climbCount:a}}function ol(t){let s=si(t),e=(o,i=1)=>o.toLocaleString("en-US",{minimumFractionDigits:i,maximumFractionDigits:i});return`
@@ -853,15 +853,15 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( - ${[{label:"Distance",unit:"km",data:n.distance,scale:.001,digits:1},{label:"Elevation Gain",unit:"m",data:n.elevation,scale:1,digits:0},{label:"Moving Duration",unit:"h",data:n.durationHours,scale:1,digits:1},{label:"Training Stress (TSS)",unit:"TSS",data:n.tss,scale:1,digits:0},{label:"Mechanical Work",unit:"kJ",data:n.workKj,scale:1,digits:0},{label:"Categorized Climbs",unit:"climbs",data:n.climbCount,scale:1,digits:0}].map(l=>` + ${[{label:"Distance",unit:"km",data:s.distance,scale:.001,digits:1},{label:"Elevation Gain",unit:"m",data:s.elevation,scale:1,digits:0},{label:"Moving Duration",unit:"h",data:s.durationHours,scale:1,digits:1},{label:"Training Stress (TSS)",unit:"TSS",data:s.tss,scale:1,digits:0},{label:"Mechanical Work",unit:"kJ",data:s.workKj,scale:1,digits:0},{label:"Categorized Climbs",unit:"climbs",data:s.climbCount,scale:1,digits:0}].map(o=>` - ${l.label} - ${s(l.data.past1m*l.scale,l.digits)} ${l.unit} - ${s(l.data.past6m*l.scale,l.digits)} ${l.unit} - ${s(l.data.pastYear*l.scale,l.digits)} ${l.unit} - ${s(l.data.currentYear*l.scale,l.digits)} ${l.unit} - ${s(l.data.total*l.scale,l.digits)} ${l.unit} - ${s(l.data.totalAvg*l.scale,l.digits)} ${l.unit}/wk + ${o.label} + ${e(o.data.past1m*o.scale,o.digits)} ${o.unit} + ${e(o.data.past6m*o.scale,o.digits)} ${o.unit} + ${e(o.data.pastYear*o.scale,o.digits)} ${o.unit} + ${e(o.data.currentYear*o.scale,o.digits)} ${o.unit} + ${e(o.data.total*o.scale,o.digits)} ${o.unit} + ${e(o.data.totalAvg*o.scale,o.digits)} ${o.unit}/wk `).join("")} @@ -871,7 +871,7 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( no_sim
Select a track for progress analysis
- `)}function Jn(t){Ks=t,Kn.forEach(n=>{n&&n.updateGrouping&&n.updateGrouping(t)})}function As(t){Gt.patch({progress:t==="all"?null:t});let n=document.querySelector("#evolution-time-range");n&&n.querySelectorAll(".seg-btn").forEach(s=>{s.classList.toggle("active",s.getAttribute("data-range")===t)}),Kn.forEach(s=>{s&&s.updateRange&&s.updateRange(t)})}function Is(t){Kn.forEach(n=>{n&&n.updatePin&&n.updatePin(t)})}var ts=16384,Qn=new Float64Array(ts+1),Sn=new Float64Array(ts+1),Xs=new Float64Array(ts+1),ll=new Float64Array(ts),Qs=new Float64Array(365),il=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,360,450,600,750,900,1200];function Hn(t,n,s,e){cl();let l=document.getElementById("evolution-view");if(!l)return;let i=Gt.get().progress||"all";n.forEach(b=>{Jt.ensureCurvesAndZones(b)});let a=0,c=0;Qs.fill(0);for(let b=0;bS)continue;let N=S-u,E=0,G=0;for(let U=0;U<=N;U++){let j=Sn[U+u]-Sn[U],Rt=Qn[U+u]-Qn[U];Rt>E&&(E=Rt),j>G&&(G=j)}c+=(E+G+Xs[N])/u*.001}let _=2/8,W=1-_,O=2/43,Y=1-O,Z=52,lt=1/(195-Z),Ft=0,rt=0;for(let v=0;v{s&&s.updateGrouping&&s.updateGrouping(t)})}function As(t){Gt.patch({progress:t==="all"?null:t});let s=document.querySelector("#evolution-time-range");s&&s.querySelectorAll(".seg-btn").forEach(e=>{e.classList.toggle("active",e.getAttribute("data-range")===t)}),Kn.forEach(e=>{e&&e.updateRange&&e.updateRange(t)})}function Is(t){Kn.forEach(s=>{s&&s.updatePin&&s.updatePin(t)})}var ts=16384,Qn=new Float64Array(ts+1),Sn=new Float64Array(ts+1),Xs=new Float64Array(ts+1),ll=new Float64Array(ts),Qs=new Float64Array(365),il=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,360,450,600,750,900,1200];function Hn(t,s,e,n){cl();let o=document.getElementById("evolution-view");if(!o)return;let i=Gt.get().progress||"all";s.forEach(h=>{Jt.ensureCurvesAndZones(h)});let a=0,r=0;Qs.fill(0);for(let h=0;hE)continue;let N=E-m,C=0,G=0;for(let U=0;U<=N;U++){let j=Sn[U+m]-Sn[U],Rt=Qn[U+m]-Qn[U];Rt>C&&(C=Rt),j>G&&(G=j)}r+=(C+G+Xs[N])/m*.001}let _=2/8,W=1-_,O=2/43,Y=1-O,Z=52,lt=1/(195-Z),Ft=0,rt=0;for(let y=0;y
@@ -901,36 +901,36 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams(
- `;let f=document.getElementById("evolution-container");if(!f)return;f.insertAdjacentHTML("beforeend",ol(n));let A=f.clientWidth||570,C=An.sync("progress-sync");g.push(rl(f,n,"distance",C,e,A)),g.push(rl(f,n,"elevation",C,e,A));let $=f.querySelector(".distance-progress-card .chart-scroll-container"),M=f.querySelector(".elevation-progress-card .chart-scroll-container");$&&M&&($.addEventListener("scroll",()=>{M.scrollLeft!==$.scrollLeft&&(M.scrollLeft=$.scrollLeft)}),M.addEventListener("scroll",()=>{$.scrollLeft!==M.scrollLeft&&($.scrollLeft=M.scrollLeft)}));let m=l.querySelector("#evolution-time-range");m&&m.querySelectorAll(".seg-btn").forEach(b=>{b.addEventListener("click",()=>{let p=b.getAttribute("data-range");p&&(m.querySelectorAll(".seg-btn").forEach(S=>S.classList.remove("active")),b.classList.add("active"),h(p))})}),l.querySelectorAll(".metric-pill").forEach(b=>{b.addEventListener("click",()=>{let p=b.getAttribute("data-target");p&&document.getElementById(`${p}-evolution-card`)?.scrollIntoView({behavior:"smooth"})})});function P(b){g.forEach(p=>{p&&p.updatePin&&p.updatePin(b)})}function h(b){Gt.patch({progress:b==="all"?null:b}),g.forEach(p=>{p&&p.updateRange&&p.updateRange(b)})}if(n.some(b=>b.stats.powerCurve)){let b=al({grid:f,currentTrack:t,allTracks:n,metricKey:"power",label:"Power Curve Progress",unit:"W",color:Nt.power.color,icon:"bolt",onPinChange:P,onRangeChange:h,onTrackSelect:s,gridWidth:A});g.push(b)}if(n.some(b=>b.stats.hrCurve)){let b=al({grid:f,currentTrack:t,allTracks:n,metricKey:"hr",label:"Heart Rate Curve Progress",unit:"bpm",color:Nt.hr.color,icon:"favorite",onPinChange:P,onRangeChange:h,onTrackSelect:s,gridWidth:A});g.push(b)}i!=="all"&&g.forEach(b=>{b&&b.updateRange&&b.updateRange(i)}),In.forEach(b=>{b._ready=!0})}function al(t){let{grid:n,currentTrack:s,allTracks:e,metricKey:l,label:i,unit:a,color:c,icon:d,onPinChange:w,onRangeChange:g,onTrackSelect:f,gridWidth:A}=t,C=s&&s.name||"Current Track",$=null,M=document.createElement("div");M.className="chart-row evolution-card-group",M.id=`${l}-evolution-card`,n.appendChild(M);let m=document.createElement("div");m.className="chart-row progress-chart-row",m.style.setProperty("--chart-color",c),m.style.flex="0 0 400px",m.style.borderBottom="none",m.innerHTML=` + `;let M=document.getElementById("evolution-container");if(!M)return;M.insertAdjacentHTML("beforeend",ol(s));let F=M.clientWidth||570,I=An.sync("progress-sync");$.push(rl(M,s,"distance",I,n,F)),$.push(rl(M,s,"elevation",I,n,F));let b=M.querySelector(".distance-progress-card .chart-scroll-container"),g=M.querySelector(".elevation-progress-card .chart-scroll-container");b&&g&&(b.addEventListener("scroll",()=>{g.scrollLeft!==b.scrollLeft&&(g.scrollLeft=b.scrollLeft)}),g.addEventListener("scroll",()=>{b.scrollLeft!==g.scrollLeft&&(b.scrollLeft=g.scrollLeft)}));let u=o.querySelector("#evolution-time-range");u&&u.querySelectorAll(".seg-btn").forEach(h=>{h.addEventListener("click",()=>{let p=h.getAttribute("data-range");p&&(u.querySelectorAll(".seg-btn").forEach(E=>E.classList.remove("active")),h.classList.add("active"),f(p))})}),o.querySelectorAll(".metric-pill").forEach(h=>{h.addEventListener("click",()=>{let p=h.getAttribute("data-target");p&&document.getElementById(`${p}-evolution-card`)?.scrollIntoView({behavior:"smooth"})})});function k(h){$.forEach(p=>{p&&p.updatePin&&p.updatePin(h)})}function f(h){Gt.patch({progress:h==="all"?null:h}),$.forEach(p=>{p&&p.updateRange&&p.updateRange(h)})}if(s.some(h=>h.stats.powerCurve)){let h=al({grid:M,currentTrack:t,allTracks:s,metricKey:"power",label:"Power Curve Progress",unit:"W",color:Nt.power.color,icon:"bolt",onPinChange:k,onRangeChange:f,onTrackSelect:e,gridWidth:F});$.push(h)}if(s.some(h=>h.stats.hrCurve)){let h=al({grid:M,currentTrack:t,allTracks:s,metricKey:"hr",label:"Heart Rate Curve Progress",unit:"bpm",color:Nt.hr.color,icon:"favorite",onPinChange:k,onRangeChange:f,onTrackSelect:e,gridWidth:F});$.push(h)}i!=="all"&&$.forEach(h=>{h&&h.updateRange&&h.updateRange(i)}),In.forEach(h=>{h._ready=!0})}function al(t){let{grid:s,currentTrack:e,allTracks:n,metricKey:o,label:i,unit:a,color:r,icon:d,onPinChange:T,onRangeChange:$,onTrackSelect:M,gridWidth:F}=t,I=e&&e.name||"Current Track",b=null,g=document.createElement("div");g.className="chart-row evolution-card-group",g.id=`${o}-evolution-card`,s.appendChild(g);let u=document.createElement("div");u.className="chart-row progress-chart-row",u.style.setProperty("--chart-color",r),u.style.flex="0 0 400px",u.style.borderBottom="none",u.innerHTML=`
- ${d} + ${d} ${i}
-
+
- `;let k=document.createElement("div");k.className="evolution-legend",k.innerHTML=` + `;let v=document.createElement("div");v.className="evolution-legend",v.innerHTML=`
- - ${C} + + ${I}
All-Time Max
- `;let h=Gt.get().progress||"all",b=document.createElement("div");b.className="chart-row progress-chart-row",b.style.setProperty("--chart-color",c),b.style.flex="1",b.style.borderBottom="none",b.innerHTML=` + `;let f=Gt.get().progress||"all",h=document.createElement("div");h.className="chart-row progress-chart-row",h.style.setProperty("--chart-color",r),h.style.flex="1",h.style.borderBottom="none",h.innerHTML=`
- ${d} - Progress ${l==="power"?"Power":"HR"} + ${d} + Progress ${o==="power"?"Power":"HR"}
-
+
- `;let p=document.createElement("div");p.style.cssText="display: flex; flex-direction: row; gap: 0px; align-items: stretch;",p.appendChild(m),p.appendChild(b),M.appendChild(p),M.appendChild(k);let S=m.querySelector(`#${l}-evolution-chart`);if(!S)return;let _={};e.forEach(at=>{let nt=l==="power"?at.stats.powerCurve:at.stats.hrCurve;if(!nt)return;let $t=at.name||"Unnamed Track",ht=at.stats.startTime||at.addedAt?nn(at.stats.startTime||at.addedAt):"Unknown Date",z=`${$t} (${ht})`;Object.entries(nt).forEach(([D,it])=>{let K=Number(D),bt=it.power||it.hr;(!_[K]||bt>_[K].val)&&(_[K]={val:bt,trackInfo:z,trackId:at.id,idx:it.idx})})});let W=s&&(l==="power"?s.stats.powerCurve:s.stats.hrCurve)||{},O=new Set;Object.keys(_).forEach(at=>O.add(Number(at))),Object.keys(W).forEach(at=>O.add(Number(at)));let Y=Array.from(O).sort((at,nt)=>at-nt),Z=Y,lt=Y.map(at=>{let nt=W[at];return nt?nt.power||nt.hr:null}),Ft=Y.map(at=>_[at]?.val||null),rt=e.filter(at=>(at.stats.startTime||at.addedAt)!=null);rt.sort((at,nt)=>(at.stats.startTime||at.addedAt||0)-(nt.stats.startTime||nt.addedAt||0)||at.id.localeCompare(nt.id));let x=[],v={};Y.forEach(at=>v[at]=[]),rt.forEach(at=>{let nt=l==="power"?at.stats.powerCurve:at.stats.hrCurve;nt&&(x.push((at.stats.startTime||at.addedAt)/1e3),Y.forEach($t=>{let ht=nt[$t],z=ht?l==="power"?ht.power:ht.hr:null;v[$t].push(z)}))});let u=Y[0]||5,N=rt,E=null;function G(at,nt){let $t=x[x.length-1]||1785542400,ht=0;nt==="1m"?ht=$t-30*24*3600:nt==="2m"?ht=$t-60*24*3600:nt==="6m"?ht=$t-180*24*3600:nt==="1y"?ht=$t-365*24*3600:nt==="2y"&&(ht=$t-2*365*24*3600);let z=[];x.forEach((Pt,ut)=>{Pt>=ht&&z.push(ut)});let D=z.map(Pt=>x[Pt]),it=v[at]||[],K=z.map(Pt=>it[Pt]),bt=Cn(K,5);return N=z.map(Pt=>rt[Pt]),{xFiltered:D,rawYFiltered:K,smoothedYFiltered:bt}}let U=null,j=document.createElement("div");return j.className="cur-y-val font-m",j.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",S.style.position="relative",S.appendChild(j),(()=>{let at={id:`${l}-evolution`,width:400,height:250,padding:[0,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:"Current Track",stroke:c,width:2,fill:le(c,.1),points:{show:!0,size:5,fill:c}},{label:"All-Time Max",stroke:"#888888",width:1,fill:"transparent",points:{show:!0,size:6,fill:"#888888"}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(z,D)=>D.map(it=>`${it}${a}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(z,D,it)=>it,x:!1,y:!1},hooks:{draw:[z=>{let D=z.ctx,it=window.devicePixelRatio||1,K=z.bbox,bt=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Pt=Z[Z.length-1];D.save(),D.fillStyle="#555564",D.textAlign="center",D.textBaseline="top",D.font=`${10*it}px system-ui, sans-serif`;let ut=-100;if(bt.forEach(Ht=>{if(Ht>Pt)return;let dt=z.valToPos(Ht,"x",!0);dt>ut+30*it&&dt=0){let dt=z.valToPos(E,"x",!0),Lt=z.valToPos(lt[Ht]||Ft[Ht],"y",!0);D.save(),D.beginPath(),D.setLineDash([]);let st=lt[Ht],gt=st!==null?5*it:3*it,At=st!==null?c:"#888888";D.arc(dt,Lt,gt,0,2*Math.PI),D.fillStyle=At,D.fill(),D.strokeStyle="#fff",D.lineWidth=2*it,D.stroke(),D.restore()}}D.restore()},z=>{let D=z.ctx,it=window.devicePixelRatio||1,K=z.bbox,bt=z.cursor.idx,Pt=1,ut=z.cursor.left,Ht=z.cursor.top;if(ut!=null&&Ht!=null&&ut>=0&&Ht>=0){let dt=1/0,Lt=-1,st=30,gt=st*st;for(let At=0;At{if(!z._ready)return;z.redraw(!1);let D=z.cursor.idx,it=1,K=z.cursor.left,bt=z.cursor.top;if(K!=null&&bt!=null&&K>=0&&bt>=0){let Lt=1/0,st=-1,gt=30,At=gt*gt;for(let zt=0;zt${ze(gt)}
`;if(At!==null&&(V+=` + `;let p=document.createElement("div");p.style.cssText="display: flex; flex-direction: row; gap: 0px; align-items: stretch;",p.appendChild(u),p.appendChild(h),g.appendChild(p),g.appendChild(v);let E=u.querySelector(`#${o}-evolution-chart`);if(!E)return;let _={};n.forEach(at=>{let nt=o==="power"?at.stats.powerCurve:at.stats.hrCurve;if(!nt)return;let $t=at.name||"Unnamed Track",ht=at.stats.startTime||at.addedAt?nn(at.stats.startTime||at.addedAt):"Unknown Date",z=`${$t} (${ht})`;Object.entries(nt).forEach(([D,it])=>{let K=Number(D),bt=it.power||it.hr;(!_[K]||bt>_[K].val)&&(_[K]={val:bt,trackInfo:z,trackId:at.id,idx:it.idx})})});let W=e&&(o==="power"?e.stats.powerCurve:e.stats.hrCurve)||{},O=new Set;Object.keys(_).forEach(at=>O.add(Number(at))),Object.keys(W).forEach(at=>O.add(Number(at)));let Y=Array.from(O).sort((at,nt)=>at-nt),Z=Y,lt=Y.map(at=>{let nt=W[at];return nt?nt.power||nt.hr:null}),Ft=Y.map(at=>_[at]?.val||null),rt=n.filter(at=>(at.stats.startTime||at.addedAt)!=null);rt.sort((at,nt)=>(at.stats.startTime||at.addedAt||0)-(nt.stats.startTime||nt.addedAt||0)||at.id.localeCompare(nt.id));let w=[],y={};Y.forEach(at=>y[at]=[]),rt.forEach(at=>{let nt=o==="power"?at.stats.powerCurve:at.stats.hrCurve;nt&&(w.push((at.stats.startTime||at.addedAt)/1e3),Y.forEach($t=>{let ht=nt[$t],z=ht?o==="power"?ht.power:ht.hr:null;y[$t].push(z)}))});let m=Y[0]||5,N=rt,C=null;function G(at,nt){let $t=w[w.length-1]||1785542400,ht=0;nt==="1m"?ht=$t-30*24*3600:nt==="2m"?ht=$t-60*24*3600:nt==="6m"?ht=$t-180*24*3600:nt==="1y"?ht=$t-365*24*3600:nt==="2y"&&(ht=$t-2*365*24*3600);let z=[];w.forEach((Pt,ut)=>{Pt>=ht&&z.push(ut)});let D=z.map(Pt=>w[Pt]),it=y[at]||[],K=z.map(Pt=>it[Pt]),bt=Cn(K,5);return N=z.map(Pt=>rt[Pt]),{xFiltered:D,rawYFiltered:K,smoothedYFiltered:bt}}let U=null,j=document.createElement("div");return j.className="cur-y-val font-m",j.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",E.style.position="relative",E.appendChild(j),(()=>{let at={id:`${o}-evolution`,width:400,height:250,padding:[0,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:"Current Track",stroke:r,width:2,fill:le(r,.1),points:{show:!0,size:5,fill:r}},{label:"All-Time Max",stroke:"#888888",width:1,fill:"transparent",points:{show:!0,size:6,fill:"#888888"}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(z,D)=>D.map(it=>`${it}${a}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(z,D,it)=>it,x:!1,y:!1},hooks:{draw:[z=>{let D=z.ctx,it=window.devicePixelRatio||1,K=z.bbox,bt=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],Pt=Z[Z.length-1];D.save(),D.fillStyle="#555564",D.textAlign="center",D.textBaseline="top",D.font=`${10*it}px system-ui, sans-serif`;let ut=-100;if(bt.forEach(Ht=>{if(Ht>Pt)return;let dt=z.valToPos(Ht,"x",!0);dt>ut+30*it&&dt=0){let dt=z.valToPos(C,"x",!0),Lt=z.valToPos(lt[Ht]||Ft[Ht],"y",!0);D.save(),D.beginPath(),D.setLineDash([]);let st=lt[Ht],gt=st!==null?5*it:3*it,At=st!==null?r:"#888888";D.arc(dt,Lt,gt,0,2*Math.PI),D.fillStyle=At,D.fill(),D.strokeStyle="#fff",D.lineWidth=2*it,D.stroke(),D.restore()}}D.restore()},z=>{let D=z.ctx,it=window.devicePixelRatio||1,K=z.bbox,bt=z.cursor.idx,Pt=1,ut=z.cursor.left,Ht=z.cursor.top;if(ut!=null&&Ht!=null&&ut>=0&&Ht>=0){let dt=1/0,Lt=-1,st=30,gt=st*st;for(let At=0;At{if(!z._ready)return;z.redraw(!1);let D=z.cursor.idx,it=1,K=z.cursor.left,bt=z.cursor.top;if(K!=null&&bt!=null&&K>=0&&bt>=0){let Lt=1/0,st=-1,gt=30,At=gt*gt;for(let zt=0;zt${ze(gt)}
`;if(At!==null&&(V+=`
Current: ${At} ${a} @@ -940,7 +940,7 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( Max: ${zt} ${a}
- `),j.innerHTML=V,U&&E===null){u=gt;let{xFiltered:R,rawYFiltered:Dt,smoothedYFiltered:It}=G(u,h),Wt=It.map(yt=>yt!==null?yt*.9:null),Et=It.map(yt=>yt!==null?yt*1.1:null);U.setData([R,Dt,It,Wt,Et]);let vt=document.getElementById(`${l}-timeline-label`);vt&&(vt.textContent=`Progress ${ze(gt)} ${l==="power"?"Power":"HR"}`)}j.style.display="",j.style.left=`${K+Ht.left}px`,j.style.top=`${bt+Ht.top}px`,j.style.transform="translate(5px, -50%)"}else j.style.display="none"}]}};$=new An(at,[Z,lt,Ft],S),In.push($),S.addEventListener("click",()=>{if(!$)return;let z=$.cursor.idx;if(z!=null){let D=Z[z],it=null;if(E!==null?it=null:it=D,w(it),s){let K=s.stats,bt=l==="power"?K.powerCurve:K.hrCurve;if(bt){let Pt=bt[D];if(Pt){let ut=Pt.idx,Ht=D,dt=s.points[ut],Lt=s.points[ut+Ht-1];if(dt&&Lt&&dt.time!=null&&Lt.time!=null){let st=s.points[0].time||0,gt=(dt.time-st)/1e3,At=(Lt.time-st)/1e3;f?.(s.id,[gt,At])}}}}}}),S.addEventListener("mouseleave",()=>{$&&$.redraw()});let nt=document.createElement("details");nt.classList.add("progress-details"),nt.style.marginTop="0px",nt.style.setProperty("--chart-color",c),nt.innerHTML=` + `),j.innerHTML=V,U&&C===null){m=gt;let{xFiltered:R,rawYFiltered:Dt,smoothedYFiltered:It}=G(m,f),Wt=It.map(yt=>yt!==null?yt*.9:null),Et=It.map(yt=>yt!==null?yt*1.1:null);U.setData([R,Dt,It,Wt,Et]);let vt=document.getElementById(`${o}-timeline-label`);vt&&(vt.textContent=`Progress ${ze(gt)} ${o==="power"?"Power":"HR"}`)}j.style.display="",j.style.left=`${K+Ht.left}px`,j.style.top=`${bt+Ht.top}px`,j.style.transform="translate(5px, -50%)"}else j.style.display="none"}]}};b=new An(at,[Z,lt,Ft],E),In.push(b),E.addEventListener("click",()=>{if(!b)return;let z=b.cursor.idx;if(z!=null){let D=Z[z],it=null;if(C!==null?it=null:it=D,T(it),e){let K=e.stats,bt=o==="power"?K.powerCurve:K.hrCurve;if(bt){let Pt=bt[D];if(Pt){let ut=Pt.idx,Ht=D,dt=e.points[ut],Lt=e.points[ut+Ht-1];if(dt&&Lt&&dt.time!=null&&Lt.time!=null){let st=e.points[0].time||0,gt=(dt.time-st)/1e3,At=(Lt.time-st)/1e3;M?.(e.id,[gt,At])}}}}}}),E.addEventListener("mouseleave",()=>{b&&b.redraw()});let nt=document.createElement("details");nt.classList.add("progress-details"),nt.style.marginTop="0px",nt.style.setProperty("--chart-color",r),nt.innerHTML=` chevron_right table_chart @@ -967,7 +967,7 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( `}).join("")} - `,M.appendChild(nt),nt.querySelectorAll(".evolution-select-btn").forEach(z=>{z.addEventListener("click",D=>{D.preventDefault(),D.stopPropagation();let it=z.getAttribute("data-id"),K=z.getAttribute("data-idx"),bt=z.getAttribute("data-dur");it&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:it,idx:K?Number(K):null,dur:bt?Number(bt):null}}))})});let $t=null,ht=b.querySelector(`#${l}-timeline-chart`);if(ht){ht.style.position="relative";let z=document.createElement("div");if(z.className="timeline-tooltip font-m",z.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",ht.appendChild(z),x.length>0){let{xFiltered:D,rawYFiltered:it,smoothedYFiltered:K}=G(u,h),bt=K.map(st=>st!==null?st*.9:null),Pt=K.map(st=>st!==null?st*1.1:null),ut=[D,it,K,bt,Pt],Ht=[{value:(st,gt)=>gt!=null?nn(gt*1e3):"-"},{label:"Value",stroke:c,width:0,points:{show:!0,size:6,fill:le(c,.5)}},{label:"Trend",stroke:c,width:2,points:{show:!1},spanGaps:!0,fill:"transparent",dash:[5,5]},{label:"Lower Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0},{label:"Upper Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0}],dt=document.getElementById(`${l}-timeline-label`);dt&&(dt.textContent=`Progress ${ze(u)} ${l==="power"?"Power":"HR"}`);let Lt={width:Math.max(100,(A||570)-400),height:250,padding:[0,10,0,10],tzDate:st=>An.tzDate(new Date(st*1e3),"Etc/UTC"),cursor:{points:{show:!1},drag:{setScale:!1},x:!1,y:!1},scales:{x:{time:!0,range:st=>{let gt=st.data[0][0],At=st.data[0][st.data[0].length-1];return gt===void 0||At===void 0?[0,100]:gt===At?[gt-3600,At+3600]:[gt,At]}},y:{range:(st,gt,At)=>[gt*.9,At*1.1]}},series:Ht,bands:[{series:[4,3],fill:le(c,.2)}],hooks:{init:[st=>{st.over.addEventListener("click",()=>{if($t!=null){let gt=N[$t];if(gt){let At=gt.stats,zt=l==="power"?At.powerCurve:At.hrCurve;if(zt){let V=zt[u];if(V){let R=V.idx,Dt=u,It=gt.points[R],Wt=gt.points[R+Dt-1];if(It&&Wt&&It.time!=null&&Wt.time!=null){let Et=gt.points[0].time||0,vt=(It.time-Et)/1e3,yt=(Wt.time-Et)/1e3;t.onTrackSelect?.(gt.id,[vt,yt])}else t.onTrackSelect?.(gt.id,null)}else t.onTrackSelect?.(gt.id,null)}else t.onTrackSelect?.(gt.id,null)}}})}],draw:[st=>{let gt=st.cursor.idx;if(gt!=null&&st.data[0][gt]!=null){let At=st.data[1][gt];if(At!=null){let zt=st.valToPos(st.data[0][gt],"x",!0),V=st.valToPos(At,"y",!0),R=st.ctx,Dt=window.devicePixelRatio||1;R.save(),R.beginPath(),R.setLineDash([2*Dt,2*Dt]),R.strokeStyle=le(c,.4),R.lineWidth=1*Dt,R.moveTo(zt,st.bbox.top),R.lineTo(zt,st.bbox.top+st.bbox.height),R.moveTo(st.bbox.left,V),R.lineTo(st.bbox.left+st.bbox.width,V),R.stroke(),R.restore(),R.save(),R.beginPath(),R.setLineDash([]),R.arc(zt,V,12*Dt,0,2*Math.PI),R.fillStyle=le(c,.2),R.fill(),R.restore(),R.save(),R.beginPath(),R.arc(zt,V,6*Dt,0,2*Math.PI),R.fillStyle=c,R.fill(),R.strokeStyle="#fff",R.lineWidth=2*Dt,R.stroke(),R.restore(),R.save(),R.setLineDash([]);let It=new Date(st.data[0][gt]*1e3),Wt=`${It.getUTCFullYear()}-${String(It.getUTCMonth()+1).padStart(2,"0")}-${String(It.getUTCDate()).padStart(2,"0")}`;R.font=`bold ${10*Dt}px system-ui, sans-serif`;let vt=R.measureText(Wt).width+10*Dt,yt=16*Dt,_t=zt-vt/2,qt=Math.max(st.bbox.left,Math.min(st.bbox.left+st.bbox.width-vt,_t)),Yt=st.bbox.top+st.bbox.height+2*Dt;R.fillStyle="rgba(14, 14, 16, 0.92)",R.beginPath(),R.roundRect?R.roundRect(qt,Yt,vt,yt,3*Dt):R.rect(qt,Yt,vt,yt),R.fill(),R.strokeStyle=le(c,.27),R.lineWidth=1*Dt,R.stroke(),R.fillStyle=c,R.textAlign="center",R.textBaseline="middle",R.fillText(Wt,qt+vt/2,Yt+yt/2);let ee=`${At.toFixed(0)} ${a}`,De=R.measureText(ee).width+10*Dt,Le=st.bbox.left-De-2*Dt,_n=V-yt/2;R.fillStyle="rgba(14, 14, 16, 0.92)",R.beginPath(),R.roundRect?R.roundRect(Le,_n,De,yt,3*Dt):R.rect(Le,_n,De,yt),R.fill(),R.strokeStyle=le(c,.27),R.lineWidth=1*Dt,R.stroke(),R.fillStyle=c,R.textAlign="left",R.textBaseline="middle",R.fillText(ee,Le+5*Dt,_n+yt/2),R.restore()}}}],setCursor:[st=>{if(!st._ready)return;st.redraw(!1);let gt=st.cursor.idx,At=st.cursor.left,zt=st.cursor.top,V=st.bbox;if(At!=null&&zt!=null&&At>=0&&zt>=0){let R=1/0,Dt=-1,It=30,Wt=It*It,Et=st.data[0],vt=st.data[1];for(let yt=0;yt{z.addEventListener("click",D=>{D.preventDefault(),D.stopPropagation();let it=z.getAttribute("data-id"),K=z.getAttribute("data-idx"),bt=z.getAttribute("data-dur");it&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:it,idx:K?Number(K):null,dur:bt?Number(bt):null}}))})});let $t=null,ht=h.querySelector(`#${o}-timeline-chart`);if(ht){ht.style.position="relative";let z=document.createElement("div");if(z.className="timeline-tooltip font-m",z.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",ht.appendChild(z),w.length>0){let{xFiltered:D,rawYFiltered:it,smoothedYFiltered:K}=G(m,f),bt=K.map(st=>st!==null?st*.9:null),Pt=K.map(st=>st!==null?st*1.1:null),ut=[D,it,K,bt,Pt],Ht=[{value:(st,gt)=>gt!=null?nn(gt*1e3):"-"},{label:"Value",stroke:r,width:0,points:{show:!0,size:6,fill:le(r,.5)}},{label:"Trend",stroke:r,width:2,points:{show:!1},spanGaps:!0,fill:"transparent",dash:[5,5]},{label:"Lower Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0},{label:"Upper Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0}],dt=document.getElementById(`${o}-timeline-label`);dt&&(dt.textContent=`Progress ${ze(m)} ${o==="power"?"Power":"HR"}`);let Lt={width:Math.max(100,(F||570)-400),height:250,padding:[0,10,0,10],tzDate:st=>An.tzDate(new Date(st*1e3),"Etc/UTC"),cursor:{points:{show:!1},drag:{setScale:!1},x:!1,y:!1},scales:{x:{time:!0,range:st=>{let gt=st.data[0][0],At=st.data[0][st.data[0].length-1];return gt===void 0||At===void 0?[0,100]:gt===At?[gt-3600,At+3600]:[gt,At]}},y:{range:(st,gt,At)=>[gt*.9,At*1.1]}},series:Ht,bands:[{series:[4,3],fill:le(r,.2)}],hooks:{init:[st=>{st.over.addEventListener("click",()=>{if($t!=null){let gt=N[$t];if(gt){let At=gt.stats,zt=o==="power"?At.powerCurve:At.hrCurve;if(zt){let V=zt[m];if(V){let R=V.idx,Dt=m,It=gt.points[R],Wt=gt.points[R+Dt-1];if(It&&Wt&&It.time!=null&&Wt.time!=null){let Et=gt.points[0].time||0,vt=(It.time-Et)/1e3,yt=(Wt.time-Et)/1e3;t.onTrackSelect?.(gt.id,[vt,yt])}else t.onTrackSelect?.(gt.id,null)}else t.onTrackSelect?.(gt.id,null)}else t.onTrackSelect?.(gt.id,null)}}})}],draw:[st=>{let gt=st.cursor.idx;if(gt!=null&&st.data[0][gt]!=null){let At=st.data[1][gt];if(At!=null){let zt=st.valToPos(st.data[0][gt],"x",!0),V=st.valToPos(At,"y",!0),R=st.ctx,Dt=window.devicePixelRatio||1;R.save(),R.beginPath(),R.setLineDash([2*Dt,2*Dt]),R.strokeStyle=le(r,.4),R.lineWidth=1*Dt,R.moveTo(zt,st.bbox.top),R.lineTo(zt,st.bbox.top+st.bbox.height),R.moveTo(st.bbox.left,V),R.lineTo(st.bbox.left+st.bbox.width,V),R.stroke(),R.restore(),R.save(),R.beginPath(),R.setLineDash([]),R.arc(zt,V,12*Dt,0,2*Math.PI),R.fillStyle=le(r,.2),R.fill(),R.restore(),R.save(),R.beginPath(),R.arc(zt,V,6*Dt,0,2*Math.PI),R.fillStyle=r,R.fill(),R.strokeStyle="#fff",R.lineWidth=2*Dt,R.stroke(),R.restore(),R.save(),R.setLineDash([]);let It=new Date(st.data[0][gt]*1e3),Wt=`${It.getUTCFullYear()}-${String(It.getUTCMonth()+1).padStart(2,"0")}-${String(It.getUTCDate()).padStart(2,"0")}`;R.font=`bold ${10*Dt}px system-ui, sans-serif`;let vt=R.measureText(Wt).width+10*Dt,yt=16*Dt,_t=zt-vt/2,qt=Math.max(st.bbox.left,Math.min(st.bbox.left+st.bbox.width-vt,_t)),Yt=st.bbox.top+st.bbox.height+2*Dt;R.fillStyle="rgba(14, 14, 16, 0.92)",R.beginPath(),R.roundRect?R.roundRect(qt,Yt,vt,yt,3*Dt):R.rect(qt,Yt,vt,yt),R.fill(),R.strokeStyle=le(r,.27),R.lineWidth=1*Dt,R.stroke(),R.fillStyle=r,R.textAlign="center",R.textBaseline="middle",R.fillText(Wt,qt+vt/2,Yt+yt/2);let ee=`${At.toFixed(0)} ${a}`,De=R.measureText(ee).width+10*Dt,Le=st.bbox.left-De-2*Dt,_n=V-yt/2;R.fillStyle="rgba(14, 14, 16, 0.92)",R.beginPath(),R.roundRect?R.roundRect(Le,_n,De,yt,3*Dt):R.rect(Le,_n,De,yt),R.fill(),R.strokeStyle=le(r,.27),R.lineWidth=1*Dt,R.stroke(),R.fillStyle=r,R.textAlign="left",R.textBaseline="middle",R.fillText(ee,Le+5*Dt,_n+yt/2),R.restore()}}}],setCursor:[st=>{if(!st._ready)return;st.redraw(!1);let gt=st.cursor.idx,At=st.cursor.left,zt=st.cursor.top,V=st.bbox;if(At!=null&&zt!=null&&At>=0&&zt>=0){let R=1/0,Dt=-1,It=30,Wt=It*It,Et=st.data[0],vt=st.data[1];for(let yt=0;yt Date: ${Et} @@ -976,31 +976,31 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( Value: ${yt}
- `,z.style.display="block",z.style.left=`${At+V.left}px`,z.style.top=`${zt+V.top}px`,z.style.transform="translate(5px, -50%)"}else z.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(st,gt)=>gt.map(At=>{let zt=new Date(At*1e3);return`${zt.getUTCFullYear()}-${String(zt.getUTCMonth()+1).padStart(2,"0")}`})},{stroke:"#555564",grid:{stroke:"#2e2e34"},font:"10px system-ui, sans-serif",values:(st,gt)=>gt.map(At=>`${At} ${a}`),show:!0,space:15,size:50}]};U=new An(Lt,ut,ht),In.push(U),ht.addEventListener("mouseleave",()=>{U.redraw()})}else ht.innerHTML='
No data for the past year
'}})(),{updatePin:at=>{E=at,at!==null&&(u=at);let nt=document.getElementById(`${l}-timeline-label`);if(nt&&(nt.textContent=`Progress ${ze(u)} ${l==="power"?"Power":"HR"}${E!==null?" (Pinned)":""}`),U){let{xFiltered:$t,rawYFiltered:ht,smoothedYFiltered:z}=G(u,h),D=z.map(K=>K!==null?K*.9:null),it=z.map(K=>K!==null?K*1.1:null);U.setData([$t,ht,z,D,it])}$&&$.redraw()},updateRange:at=>{if(h=at,U){let{xFiltered:nt,rawYFiltered:$t,smoothedYFiltered:ht}=G(u,h),z=ht.map(it=>it!==null?it*.9:null),D=ht.map(it=>it!==null?it*1.1:null);U.setData([nt,$t,ht,z,D])}}}}function ul(t){let n=new Date(t),s=n.getUTCDay(),e=n.getUTCDate()-s+(s===0?-6:1);return n.setUTCDate(e),n.setUTCHours(0,0,0,0),n}function li(t){let n={};return t.forEach(s=>{if(!s.stats.startTime||!s.stats.totalDist)return;let e=new Date(s.stats.startTime),l=ul(e),i=l.toISOString().split("T")[0];n[i]||(n[i]={timestamp:l.getTime(),distance:0}),n[i].distance+=s.stats.totalDist}),Object.entries(n).map(([s,e])=>({week:s,timestamp:e.timestamp,distance:e.distance})).sort((s,e)=>s.timestamp-e.timestamp)}function ii(t){let n={};return t.forEach(s=>{if(!s.stats.startTime||s.stats.elevGain===void 0)return;let e=new Date(s.stats.startTime),l=ul(e),i=l.toISOString().split("T")[0];n[i]||(n[i]={timestamp:l.getTime(),elevation:0}),n[i].elevation+=s.stats.elevGain}),Object.entries(n).map(([s,e])=>({week:s,timestamp:e.timestamp,elevation:e.elevation})).sort((s,e)=>s.timestamp-e.timestamp)}function ai(t){let n={};return t.forEach(s=>{if(!s.stats.startTime||!s.stats.totalDist)return;let e=new Date(s.stats.startTime),l=new Date(Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),1)),i=l.toISOString().slice(0,7);n[i]||(n[i]={timestamp:l.getTime(),distance:0}),n[i].distance+=s.stats.totalDist}),Object.entries(n).map(([s,e])=>({week:s,timestamp:e.timestamp,distance:e.distance})).sort((s,e)=>s.timestamp-e.timestamp)}function ri(t){let n={};return t.forEach(s=>{if(!s.stats.startTime||s.stats.elevGain===void 0)return;let e=new Date(s.stats.startTime),l=new Date(Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),1)),i=l.toISOString().slice(0,7);n[i]||(n[i]={timestamp:l.getTime(),elevation:0}),n[i].elevation+=s.stats.elevGain}),Object.entries(n).map(([s,e])=>({week:s,timestamp:e.timestamp,elevation:e.elevation})).sort((s,e)=>s.timestamp-e.timestamp)}function rl(t,n,s,e,l,i){let a=s==="distance",c=Ks,d=Gt.get().progress||"all",w=a?li(n):ii(n),g=a?ai(n):ri(n),f=c==="month"?g:w,A=gn(n,rt=>a?rt.stats.totalDist:rt.stats.elevGain),C=a?Nt.distance.color:Nt.elevation.color,$=a?"km":"m",M=a?Nt.distance.icon:Nt.elevation.icon,m=document.createElement("div");m.className=`chart-row ${s}-progress-card`,m.id=`${s}-evolution-card`,m.innerHTML=` + `,z.style.display="block",z.style.left=`${At+V.left}px`,z.style.top=`${zt+V.top}px`,z.style.transform="translate(5px, -50%)"}else z.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(st,gt)=>gt.map(At=>{let zt=new Date(At*1e3);return`${zt.getUTCFullYear()}-${String(zt.getUTCMonth()+1).padStart(2,"0")}`})},{stroke:"#555564",grid:{stroke:"#2e2e34"},font:"10px system-ui, sans-serif",values:(st,gt)=>gt.map(At=>`${At} ${a}`),show:!0,space:15,size:50}]};U=new An(Lt,ut,ht),In.push(U),ht.addEventListener("mouseleave",()=>{U.redraw()})}else ht.innerHTML='
No data for the past year
'}})(),{updatePin:at=>{C=at,at!==null&&(m=at);let nt=document.getElementById(`${o}-timeline-label`);if(nt&&(nt.textContent=`Progress ${ze(m)} ${o==="power"?"Power":"HR"}${C!==null?" (Pinned)":""}`),U){let{xFiltered:$t,rawYFiltered:ht,smoothedYFiltered:z}=G(m,f),D=z.map(K=>K!==null?K*.9:null),it=z.map(K=>K!==null?K*1.1:null);U.setData([$t,ht,z,D,it])}b&&b.redraw()},updateRange:at=>{if(f=at,U){let{xFiltered:nt,rawYFiltered:$t,smoothedYFiltered:ht}=G(m,f),z=ht.map(it=>it!==null?it*.9:null),D=ht.map(it=>it!==null?it*1.1:null);U.setData([nt,$t,ht,z,D])}}}}function ul(t){let s=new Date(t),e=s.getUTCDay(),n=s.getUTCDate()-e+(e===0?-6:1);return s.setUTCDate(n),s.setUTCHours(0,0,0,0),s}function oi(t){let s={};return t.forEach(e=>{if(!e.stats.startTime||!e.stats.totalDist)return;let n=new Date(e.stats.startTime),o=ul(n),i=o.toISOString().split("T")[0];s[i]||(s[i]={timestamp:o.getTime(),distance:0}),s[i].distance+=e.stats.totalDist}),Object.entries(s).map(([e,n])=>({week:e,timestamp:n.timestamp,distance:n.distance})).sort((e,n)=>e.timestamp-n.timestamp)}function li(t){let s={};return t.forEach(e=>{if(!e.stats.startTime||e.stats.elevGain===void 0)return;let n=new Date(e.stats.startTime),o=ul(n),i=o.toISOString().split("T")[0];s[i]||(s[i]={timestamp:o.getTime(),elevation:0}),s[i].elevation+=e.stats.elevGain}),Object.entries(s).map(([e,n])=>({week:e,timestamp:n.timestamp,elevation:n.elevation})).sort((e,n)=>e.timestamp-n.timestamp)}function ii(t){let s={};return t.forEach(e=>{if(!e.stats.startTime||!e.stats.totalDist)return;let n=new Date(e.stats.startTime),o=new Date(Date.UTC(n.getUTCFullYear(),n.getUTCMonth(),1)),i=o.toISOString().slice(0,7);s[i]||(s[i]={timestamp:o.getTime(),distance:0}),s[i].distance+=e.stats.totalDist}),Object.entries(s).map(([e,n])=>({week:e,timestamp:n.timestamp,distance:n.distance})).sort((e,n)=>e.timestamp-n.timestamp)}function ai(t){let s={};return t.forEach(e=>{if(!e.stats.startTime||e.stats.elevGain===void 0)return;let n=new Date(e.stats.startTime),o=new Date(Date.UTC(n.getUTCFullYear(),n.getUTCMonth(),1)),i=o.toISOString().slice(0,7);s[i]||(s[i]={timestamp:o.getTime(),elevation:0}),s[i].elevation+=e.stats.elevGain}),Object.entries(s).map(([e,n])=>({week:e,timestamp:n.timestamp,elevation:n.elevation})).sort((e,n)=>e.timestamp-n.timestamp)}function rl(t,s,e,n,o,i){let a=e==="distance",r=Ks,d=Gt.get().progress||"all",T=a?oi(s):li(s),$=a?ii(s):ai(s),M=r==="month"?$:T,F=gn(s,rt=>a?rt.stats.totalDist:rt.stats.elevGain),I=a?Nt.distance.color:Nt.elevation.color,b=a?"km":"m",g=a?Nt.distance.icon:Nt.elevation.icon,u=document.createElement("div");u.className=`chart-row ${e}-progress-card`,u.id=`${e}-evolution-card`,u.innerHTML=`
- ${M} + ${g} ${a?"Distance Progress":"Elevation Progress"}
-
+
-
+
- ${sl(A,a,$)} + ${sl(F,a,b)}
- `,t.appendChild(m);let k=m.querySelector(`#${s}-weekly-chart`),P=m.querySelector(`#${s}-y-axis-chart`);if(!k||!P)return;k.style.position="relative";let h=document.createElement("div");h.className="cur-y-val",h.style.cssText=`color:${C};display:none`,k.appendChild(h);let b=f.map(rt=>rt.timestamp/1e3),p=a?f.map(rt=>rt.distance/1e3):f.map(rt=>rt.elevation);if(b.length===0)return;let S=Cn(p,2),_=Math.max(0,(i||570)-20-320-20),W=Math.max(_,b.length*40),O=Math.max(...p)*1.1,Y={width:W,height:150,padding:[10,10,0,10],tzDate:rt=>An.tzDate(new Date(rt*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,O]}},series:[{},{label:a?"Distance":"Elevation",stroke:C,fill:le(C,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:C,width:2,dash:[5,5],points:{show:!1}}],cursor:{sync:e?{key:e.key}:void 0,drag:{x:!1,y:!1},points:{show:!1},x:!1,y:!1},hooks:{init:[rt=>{rt.over.addEventListener("click",()=>{let x=rt.cursor.idx;if(x!=null){let v=f[x];if(v){let u=new Date(v.timestamp),N=new Date(v.timestamp+7*24*60*60*1e3),E=u.toISOString().split("T")[0],G=N.toISOString().split("T")[0];l?.(E,G)}}})}],setCursor:[rt=>{if(!rt._ready)return;let x=rt.cursor.idx,v=rt.cursor.left,u=rt.cursor.top;if(x!=null&&v!=null&&u!=null&&v>=0&&u>=0){let N=rt.data[1][x],E=N!=null?a?`${N.toFixed(1)} km`:`${N.toFixed(0)} m`:"\u2014";h.innerHTML=E,h.style.display="block",h.style.left=`${rt.valToPos(rt.data[0][x],"x",!1)}px`,h.style.top=`${rt.valToPos(rt.data[1][x],"y",!1)}px`,h.style.transform="translate(6px, -50%)"}else h.style.display="none";rt.redraw(!1)}],draw:[rt=>{let x=rt.cursor.idx;if(x!=null&&rt.data[0][x]!=null){let v=rt.valToPos(rt.data[0][x],"x",!0),u=rt.valToPos(rt.data[1][x],"y",!0),N=window.devicePixelRatio||1,E=rt.ctx,G=rt.bbox;E.save(),E.beginPath(),E.setLineDash([2*N,2*N]),E.strokeStyle=le(C,.4),E.lineWidth=1*N,E.moveTo(v,G.top),E.lineTo(v,G.top+G.height),E.moveTo(G.left,u),E.lineTo(G.left+G.width,u),E.stroke(),E.restore(),E.save(),E.beginPath(),E.setLineDash([]),E.arc(v,u,12*N,0,2*Math.PI),E.fillStyle=le(C,.2),E.fill(),E.restore(),E.save(),E.beginPath(),E.arc(v,u,6*N,0,2*Math.PI),E.fillStyle=C,E.fill(),E.strokeStyle="#fff",E.lineWidth=2*N,E.stroke(),E.restore(),E.save(),E.setLineDash([]);let U=new Date(rt.data[0][x]*1e3),j=`${U.getUTCFullYear()}-${String(U.getUTCMonth()+1).padStart(2,"0")}-${String(U.getUTCDate()).padStart(2,"0")}`;E.font=`bold ${10*N}px system-ui, sans-serif`;let at=E.measureText(j).width+10*N,nt=16*N,$t=v-at/2,ht=Math.max(G.left,Math.min(G.left+G.width-at,$t)),z=G.top+G.height+2*N;E.fillStyle="rgba(14, 14, 16, 0.92)",E.beginPath(),E.roundRect?E.roundRect(ht,z,at,nt,3*N):E.rect(ht,z,at,nt),E.fill(),E.strokeStyle=le(C,.27),E.lineWidth=1*N,E.stroke(),E.fillStyle=C,E.textAlign="center",E.textBaseline="middle",E.fillText(j,ht+at/2,z+nt/2),E.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(rt,x)=>x.map(v=>{let u=new Date(v*1e3);return`${u.getUTCMonth()+1}/${u.getUTCDate()}`}),font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:(rt,x)=>x.map(v=>`${v.toFixed(0)} ${$}`),font:"10px system-ui, sans-serif",size:40}]},Z=new An(Y,[b,p,S],k);In.push(Z);let lt=m.querySelector(".chart-scroll-container");lt&&b.length*40>W&&(lt.scrollLeft=lt.scrollWidth-lt.clientWidth);function Ft(){f=c==="month"?g:w;let rt=f[f.length-1]?.timestamp||17855424e5,x=0;d==="1m"?x=rt-30*24*3600*1e3:d==="2m"?x=rt-60*24*3600*1e3:d==="6m"?x=rt-180*24*3600*1e3:d==="1y"?x=rt-365*24*3600*1e3:d==="2y"&&(x=rt-2*365*24*3600*1e3);let v=f.filter(j=>j.timestamp>=x),u=v.map(j=>j.timestamp/1e3),N=a?v.map(j=>j.distance/1e3):v.map(j=>j.elevation),E=Cn(N,2),G=Math.max(k.clientWidth,u.length*40),U=Math.max(1,...N)*1.1;Z.setSize({width:G,height:150}),Z.setScale("y",{min:0,max:U}),Z.setData([u,N,E]),lt&&(lt.scrollLeft=lt.scrollWidth-lt.clientWidth)}return{updateRange:rt=>{d=rt,Ft()},updateGrouping:rt=>{c=rt,Ft()}}}var ss=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],ci=16,Ut={},Pe=[];function di(t,n){let s=new Date(t),e=new Date(n);return s.getUTCFullYear()===e.getUTCFullYear()&&s.getUTCMonth()===e.getUTCMonth()&&s.getUTCDate()===e.getUTCDate()}var Dn=!1,Zt=null,os=0,es=!1,Bn=null,Ke="",hn=!1,bn="date-desc",Tt={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};function Mn(t=!1){Gt.patch({f_date:Tt.date.every(n=>n===null)?null:Tt.date,f_dist:Tt.dist.every(n=>n===null)?null:Tt.dist,f_dur:Tt.dur.every(n=>n===null)?null:Tt.dur,f_mets:Tt.metrics.size===0?null:Array.from(Tt.metrics),f_tags:Tt.tags.length===0?null:Tt.tags},t)}function Js(){let t=ft.getActiveMetrics(),n=ft.METRICS,s=Array.from(t).map(e=>n[e].abbr);Gt.patch({metrics:s.length?s:null})}var fl=[{label:"Newest first",val:"date-desc",icon:"calendar_today"},{label:"Oldest first",val:"date-asc",icon:"history"},{label:"Longest distance",val:"dist-desc",icon:"straighten"},{label:"Shortest distance",val:"dist-asc",icon:"horizontal_rule"},{label:"Longest duration",val:"dur-desc",icon:"timer"},{label:"Shortest duration",val:"dur-asc",icon:"timer_off"}];function ui(t){document.querySelectorAll(".sort-menu-popup").forEach(l=>l.remove());let n=document.createElement("div");n.className="sort-menu-popup",fl.forEach(l=>{let i=document.createElement("div");i.className=`menu-item ${bn===l.val?"active":""}`,i.innerHTML=` - ${l.icon} - ${l.label} - ${bn===l.val?"check":""} - `,i.addEventListener("click",()=>{bn=l.val,Gt.patch({sort:l.val}),hl(),vn(),n.remove()}),n.appendChild(i)});let s=t.getBoundingClientRect();n.style.top=`${s.bottom+5}px`,n.style.left=`${s.left}px`,document.body.appendChild(n);let e=l=>{!n.contains(l.target)&&!t.contains(l.target)&&(n.remove(),document.removeEventListener("click",e))};setTimeout(()=>document.addEventListener("click",e),0)}function mi(t){document.querySelectorAll(".metric-menu-popup").forEach(c=>c.remove());let n=document.createElement("div");n.className="metric-menu-popup";let s=ft.METRICS,e=ft.getAvailableMetrics(),l=ft.getActiveMetrics();Object.entries(s).forEach(([c,d])=>{if(!e.has(c))return;let w=document.createElement("div");w.className=`menu-item ${l.has(c)?"active":""}`,w.innerHTML=` + `,t.appendChild(u);let v=u.querySelector(`#${e}-weekly-chart`),k=u.querySelector(`#${e}-y-axis-chart`);if(!v||!k)return;v.style.position="relative";let f=document.createElement("div");f.className="cur-y-val",f.style.cssText=`color:${I};display:none`,v.appendChild(f);let h=M.map(rt=>rt.timestamp/1e3),p=a?M.map(rt=>rt.distance/1e3):M.map(rt=>rt.elevation);if(h.length===0)return;let E=Cn(p,2),_=Math.max(0,(i||570)-20-320-20),W=Math.max(_,h.length*40),O=Math.max(...p)*1.1,Y={width:W,height:150,padding:[10,10,0,10],tzDate:rt=>An.tzDate(new Date(rt*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,O]}},series:[{},{label:a?"Distance":"Elevation",stroke:I,fill:le(I,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:I,width:2,dash:[5,5],points:{show:!1}}],cursor:{sync:n?{key:n.key}:void 0,drag:{x:!1,y:!1},points:{show:!1},x:!1,y:!1},hooks:{init:[rt=>{rt.over.addEventListener("click",()=>{let w=rt.cursor.idx;if(w!=null){let y=M[w];if(y){let m=new Date(y.timestamp),N=new Date(y.timestamp+7*24*60*60*1e3),C=m.toISOString().split("T")[0],G=N.toISOString().split("T")[0];o?.(C,G)}}})}],setCursor:[rt=>{if(!rt._ready)return;let w=rt.cursor.idx,y=rt.cursor.left,m=rt.cursor.top;if(w!=null&&y!=null&&m!=null&&y>=0&&m>=0){let N=rt.data[1][w],C=N!=null?a?`${N.toFixed(1)} km`:`${N.toFixed(0)} m`:"\u2014";f.innerHTML=C,f.style.display="block",f.style.left=`${rt.valToPos(rt.data[0][w],"x",!1)}px`,f.style.top=`${rt.valToPos(rt.data[1][w],"y",!1)}px`,f.style.transform="translate(6px, -50%)"}else f.style.display="none";rt.redraw(!1)}],draw:[rt=>{let w=rt.cursor.idx;if(w!=null&&rt.data[0][w]!=null){let y=rt.valToPos(rt.data[0][w],"x",!0),m=rt.valToPos(rt.data[1][w],"y",!0),N=window.devicePixelRatio||1,C=rt.ctx,G=rt.bbox;C.save(),C.beginPath(),C.setLineDash([2*N,2*N]),C.strokeStyle=le(I,.4),C.lineWidth=1*N,C.moveTo(y,G.top),C.lineTo(y,G.top+G.height),C.moveTo(G.left,m),C.lineTo(G.left+G.width,m),C.stroke(),C.restore(),C.save(),C.beginPath(),C.setLineDash([]),C.arc(y,m,12*N,0,2*Math.PI),C.fillStyle=le(I,.2),C.fill(),C.restore(),C.save(),C.beginPath(),C.arc(y,m,6*N,0,2*Math.PI),C.fillStyle=I,C.fill(),C.strokeStyle="#fff",C.lineWidth=2*N,C.stroke(),C.restore(),C.save(),C.setLineDash([]);let U=new Date(rt.data[0][w]*1e3),j=`${U.getUTCFullYear()}-${String(U.getUTCMonth()+1).padStart(2,"0")}-${String(U.getUTCDate()).padStart(2,"0")}`;C.font=`bold ${10*N}px system-ui, sans-serif`;let at=C.measureText(j).width+10*N,nt=16*N,$t=y-at/2,ht=Math.max(G.left,Math.min(G.left+G.width-at,$t)),z=G.top+G.height+2*N;C.fillStyle="rgba(14, 14, 16, 0.92)",C.beginPath(),C.roundRect?C.roundRect(ht,z,at,nt,3*N):C.rect(ht,z,at,nt),C.fill(),C.strokeStyle=le(I,.27),C.lineWidth=1*N,C.stroke(),C.fillStyle=I,C.textAlign="center",C.textBaseline="middle",C.fillText(j,ht+at/2,z+nt/2),C.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(rt,w)=>w.map(y=>{let m=new Date(y*1e3);return`${m.getUTCMonth()+1}/${m.getUTCDate()}`}),font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:(rt,w)=>w.map(y=>`${y.toFixed(0)} ${b}`),font:"10px system-ui, sans-serif",size:40}]},Z=new An(Y,[h,p,E],v);In.push(Z);let lt=u.querySelector(".chart-scroll-container");lt&&h.length*40>W&&(lt.scrollLeft=lt.scrollWidth-lt.clientWidth);function Ft(){M=r==="month"?$:T;let rt=M[M.length-1]?.timestamp||17855424e5,w=0;d==="1m"?w=rt-30*24*3600*1e3:d==="2m"?w=rt-60*24*3600*1e3:d==="6m"?w=rt-180*24*3600*1e3:d==="1y"?w=rt-365*24*3600*1e3:d==="2y"&&(w=rt-2*365*24*3600*1e3);let y=M.filter(j=>j.timestamp>=w),m=y.map(j=>j.timestamp/1e3),N=a?y.map(j=>j.distance/1e3):y.map(j=>j.elevation),C=Cn(N,2),G=Math.max(v.clientWidth,m.length*40),U=Math.max(1,...N)*1.1;Z.setSize({width:G,height:150}),Z.setScale("y",{min:0,max:U}),Z.setData([m,N,C]),lt&&(lt.scrollLeft=lt.scrollWidth-lt.clientWidth)}return{updateRange:rt=>{d=rt,Ft()},updateGrouping:rt=>{r=rt,Ft()}}}var ss=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],ri=16,Ut={},Pe=[];function ci(t,s){let e=new Date(t),n=new Date(s);return e.getUTCFullYear()===n.getUTCFullYear()&&e.getUTCMonth()===n.getUTCMonth()&&e.getUTCDate()===n.getUTCDate()}var Dn=!1,Zt=null,os=0,es=!1,Bn=null,Ke="",hn=!1,bn="date-desc",Tt={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};function Mn(t=!1){Gt.patch({f_date:Tt.date.every(s=>s===null)?null:Tt.date,f_dist:Tt.dist.every(s=>s===null)?null:Tt.dist,f_dur:Tt.dur.every(s=>s===null)?null:Tt.dur,f_mets:Tt.metrics.size===0?null:Array.from(Tt.metrics),f_tags:Tt.tags.length===0?null:Tt.tags},t)}function Js(){let t=ft.getActiveMetrics(),s=ft.METRICS,e=Array.from(t).map(n=>s[n].abbr);Gt.patch({metrics:e.length?e:null})}var pl=[{label:"Newest first",val:"date-desc",icon:"calendar_today"},{label:"Oldest first",val:"date-asc",icon:"history"},{label:"Longest distance",val:"dist-desc",icon:"straighten"},{label:"Shortest distance",val:"dist-asc",icon:"horizontal_rule"},{label:"Longest duration",val:"dur-desc",icon:"timer"},{label:"Shortest duration",val:"dur-asc",icon:"timer_off"}];function di(t){document.querySelectorAll(".sort-menu-popup").forEach(o=>o.remove());let s=document.createElement("div");s.className="sort-menu-popup",pl.forEach(o=>{let i=document.createElement("div");i.className=`menu-item ${bn===o.val?"active":""}`,i.innerHTML=` + ${o.icon} + ${o.label} + ${bn===o.val?"check":""} + `,i.addEventListener("click",()=>{bn=o.val,Gt.patch({sort:o.val}),gl(),vn(),s.remove()}),s.appendChild(i)});let e=t.getBoundingClientRect();s.style.top=`${e.bottom+5}px`,s.style.left=`${e.left}px`,document.body.appendChild(s);let n=o=>{!s.contains(o.target)&&!t.contains(o.target)&&(s.remove(),document.removeEventListener("click",n))};setTimeout(()=>document.addEventListener("click",n),0)}function ui(t){document.querySelectorAll(".metric-menu-popup").forEach(r=>r.remove());let s=document.createElement("div");s.className="metric-menu-popup";let e=ft.METRICS,n=ft.getAvailableMetrics(),o=ft.getActiveMetrics();Object.entries(e).forEach(([r,d])=>{if(!n.has(r))return;let T=document.createElement("div");T.className=`menu-item ${o.has(r)?"active":""}`,T.innerHTML=` ${d.icon} ${d.label} - ${l.has(c)?"check":""} - `,w.addEventListener("click",()=>{ft.toggleMetric(c);let g=ft.getActiveMetrics().has(c);w.classList.toggle("active",g),w.querySelector(".check").textContent=g?"check":"";let f=document.querySelector(`#metric-pills .metric-pill[data-metric="${c}"]`);f&&f.classList.toggle("active",g),ls(),Js()}),n.appendChild(w)});let i=t.getBoundingClientRect();n.style.top=`${i.bottom+5}px`,n.style.right=`${window.innerWidth-i.right}px`,document.body.appendChild(n);let a=c=>{!n.contains(c.target)&&!t.contains(c.target)&&(n.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),0)}document.addEventListener("select-track",t=>{let n=t.detail.id,s=t.detail.idx,e=t.detail.dur;if(n&&Ut[n]&&(_e(n),s!=null&&e!=null)){let l=Ut[n],i=l.points;if(s>=0&&sC.time!=null)?.time||0,d=(a.time-c)/1e3,w=d+e;ft.restoreSelection(d,w);let g=i.findIndex(C=>(C.time||0)>=a.time+e*1e3);g===-1&&(g=i.length-1);let f=i.slice(s,g+1),A=Jt.computeStats(f);ft.setSelectionStats(A),be(l),Bt.highlightSegment(n,i,s,g,!1,Bn),Bt.ensureVisible(f.map(C=>[C.lat,C.lon])),Gt.patch({sel:[d,w]})}}}});document.addEventListener("click",t=>{let n=t.target.closest(".tab-btn");if(!n)return;let s=n.closest("#tab-nav");if(!s)return;s.querySelectorAll(".tab-btn").forEach(i=>i.classList.toggle("active",i===n));let e=n.dataset.tab;Gt.patch({tab:e},!0);let l=s.closest("#chart-panel");if(l&&l.querySelectorAll(".tab-content").forEach(i=>{i.classList.toggle("active",i.id===`tab-${n.dataset.tab}`)}),n.dataset.tab==="details"&&Zt&&Ut[Zt]&&Ee(Ut[Zt],eo()),n.dataset.tab==="insights"&&Zt&&Ut[Zt]&&be(Ut[Zt]),n.dataset.tab==="evolution"&&Hn(Zt?Ut[Zt]:null,Object.values(Ut),(i,a)=>{_e(i,!0),a&&(ft.restoreSelection(a[0],a[1]),En(a[0],a[1],"time",!0))},(i,a)=>{Tt.date=[i,a],Se(),Mn(!0),ns()}),n.dataset.tab==="combined"&&Zt&&Ut[Zt]&&Fe(Ut[Zt]),n.dataset.tab==="courses"&&je(),n.dataset.tab==="graphs"){ft.resize(),ls();let i=Gt.get().sel;i&&ft.restoreSelection(i[0],i[1])}});async function to(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await ce.clear(),Ut={},Pe=[],Zt=null,os=0,Bn=null,Dn=!1,es=!1,Ke="",hn=!1,bn="date-desc",Tt.date=[null,null],Tt.dist=[null,null],Tt.dur=[null,null],Tt.metrics.clear(),Tt.tags=[],Jt.setHRZones([120,140,160,180]),Jt.setFTP(200),zo(),Jo(),Lo(),nl(),dl(),Bt.removeAllTracks&&Bt.removeAllTracks(),Bt.clearTracks&&Bt.clearTracks(),Bt.clearHighlight(),ft.resetState?ft.resetState():ft.clear&&ft.clear(),document.querySelectorAll(".tab-btn").forEach(n=>{n.classList.toggle("active",n.dataset.tab==="graphs")}),document.querySelectorAll(".tab-content").forEach(n=>{n.classList.toggle("active",n.id==="tab-graphs")}),Gt.reset();let t=document.getElementById("toast-container");t&&(t.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(n=>n.remove()),typeof vn=="function"&&vn()}async function pi(){let t=null,n=new Promise(m=>{t=window.setTimeout(m,1e3)});try{let m=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([m,n])}finally{t!==null&&window.clearTimeout(t)}document.body.classList.remove("loading-fonts");let s=document.getElementById("storage-backend-select");s&&(s.value=Gt.get().storage||"memory",s.addEventListener("change",m=>{let k=m.target.value,P=new URLSearchParams(window.location.search);k==="memory"?P.delete("storage"):P.set("storage",k),window.location.search=P.toString()}));let e=document.getElementById("global-loader"),l=document.getElementById("loader-text"),i=document.getElementById("loader-subtext"),a=document.getElementById("loader-progress-bar"),c=document.getElementById("map-loader"),d=c?.querySelector("span");c&&(d&&(d.textContent="Loading database..."),c.classList.remove("hidden"));let w=Gt.get();Ko((m,k)=>Fs(m,k==="error"?"error":"info")),Po(()=>{Se(),Mn()},m=>{Ti(m)}),qo((m,k)=>Fs(m,k==="error"?"error":"info")),Bt.init(m=>_e(m),bi,vi,(m,k)=>{m===Zt?ft.setHoverAt(k):ft.setHoverAt(null)},yi),ft.init(xi,En,wi,m=>{Gt.patch({sel_point:m})}),ft.setMapColorChangeCb(m=>{m?(Bn=m.colors,Zt&&Bt.colorTrackByMetric(Zt,m.pts,m.colors)):(Bn=null,Zt&&Bt.clearMetricColor(Zt));let k=Gt.get();k.sel&&En(k.sel[0],k.sel[1],ft.getXAxis())}),pl(w),await ce.openDB(),await to();try{let m=await ce.get("hr_zones");m&&Jt.setHRZones(m);let k=await ce.get("ftp");k&&Jt.setFTP(k);let P=await ce.getAll();P.sort((_,W)=>_.addedAt-W.addedAt),d&&(d.textContent=`Preparing ${P.length} tracks...`);let h=[];for(let _ of P){let W=!1;if(!_.bounds&&_.points.length>0){let O=Ss(_.points);O&&(_.bounds=O,W=!0)}!_.simplifiedPoints&&_.points.length>0&&(_.simplifiedPoints=Ms(_.points,50),W=!0),W&&await ce.save(_),Ut[_.id]=_,h.push(_)}Bt.addTracks(h),Se();let b=w.track&&P.find(_=>_.id===w.track)?w.track:P.length>0?P[0].id:null,p=document.getElementById("map-loader"),S=P.find(_=>_.id===b);if(S&&(await ml(S),_e(S.id,!w.map_pos),w.sel&&Array.isArray(w.sel)&&w.sel.length===2&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{ft.restoreSelection(w.sel[0],w.sel[1])})}),w.sel_point!==void 0&&w.sel_point!==null&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{ft.setCursorAt(w.sel_point)})})),p&&p.classList.add("hidden"),P.length>(S?1:0)){p&&(d&&(d.textContent="Loading tracks..."),p.classList.remove("hidden"));let _=P.filter(Y=>Y.id!==b),W=0,O=async()=>{let Z=Math.min(W+2,_.length);for(;W{_e(lt,!0),Ft&&(ft.restoreSelection(Ft[0],Ft[1]),En(Ft[0],Ft[1],"time",!0))}),P.length&&!w.map_pos&&Bt.fitAll())};requestAnimationFrame(O)}else Se(),P.length&&!w.map_pos&&Bt.fitAll()}catch(m){console.warn("Could not load saved tracks:",m)}gi(),hi(),$i(),ls(),document.getElementById("basemap-switcher")?.addEventListener("click",m=>{let k=m.target.closest(".bm-btn");k&&(document.querySelectorAll(".bm-btn").forEach(P=>P.classList.remove("active")),k.classList.add("active"),k.dataset.layer&&(Bt.switchBasemap(k.dataset.layer),Gt.patch({map:k.dataset.layer})))}),document.getElementById("btn-fit-all")?.addEventListener("click",()=>Bt.fitAll()),document.getElementById("btn-clear-all")?.addEventListener("click",Si),document.getElementById("track-search")?.addEventListener("input",m=>{Ke=m.target.value,Se(),Gt.patch({q:Ke||null})}),document.getElementById("btn-regex-toggle")?.addEventListener("click",m=>{hn=!hn,m.target.classList.toggle("active",hn),Se(),Gt.patch({re:hn?1:null})}),document.getElementById("btn-sort-menu")?.addEventListener("click",m=>{m.stopPropagation(),ui(m.currentTarget)}),document.getElementById("btn-metric-menu")?.addEventListener("click",m=>{m.stopPropagation(),mi(m.currentTarget)});let g=(m,k)=>{k&&k.classList.toggle("active"),ft.toggleMetric(m),Js()};document.getElementById("metric-pills")?.addEventListener("click",m=>{let k=m.target.closest(".metric-pill");if(k){let P=k.dataset.metric;P&&(g(P,k),ft.getActiveMetrics().has(P)&&document.querySelector(`.chart-row[data-metric="${P}"]`)?.scrollIntoView({behavior:"smooth"}))}}),document.getElementById("x-axis-ctrl")?.addEventListener("click",m=>{let k=m.target.closest(".seg-btn");if(!k)return;let P=k.dataset.axis;ft.setXAxis(P),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(h=>h.classList.toggle("active",h===k)),Gt.patch({xaxis:P})}),document.getElementById("btn-follow-dot")?.addEventListener("click",m=>{es=!es,m.currentTarget.classList.toggle("active",es)}),document.getElementById("btn-reset-zoom")?.addEventListener("click",()=>{ft.resetZoom(),Bt.clearHighlight()}),Ci(),document.getElementById("file-input")?.addEventListener("change",m=>{Ds(Array.from(m.target.files||[])),m.target.value=""}),document.getElementById("folder-input")?.addEventListener("change",m=>{Ds(Array.from(m.target.files||[])),m.target.value=""}),document.getElementById("btn-toggle-filters")?.addEventListener("click",()=>{let m=document.getElementById("filter-panel");m&&(m.classList.toggle("hidden"),document.getElementById("btn-toggle-filters")?.classList.toggle("active",!m.classList.contains("hidden")))});let f=(m,k,P)=>{let h=P.target.value;Tt[m][k]=h===""?null:h,Se(),Mn()};document.getElementById("filter-date-start")?.addEventListener("change",m=>f("date",0,m)),document.getElementById("filter-date-end")?.addEventListener("change",m=>f("date",1,m)),document.getElementById("filter-dist-min")?.addEventListener("input",m=>f("dist",0,m)),document.getElementById("filter-dist-max")?.addEventListener("input",m=>f("dist",1,m)),document.getElementById("filter-dur-min")?.addEventListener("input",m=>f("dur",0,m)),document.getElementById("filter-dur-max")?.addEventListener("input",m=>f("dur",1,m));let A=document.getElementById("sport-burger-btn"),C=document.getElementById("sport-dropdown-content");A?.addEventListener("click",m=>{if(m.stopPropagation(),C){let k=C.style.display==="block";C.style.display=k?"none":"block"}}),document.addEventListener("click",m=>{C&&C.style.display==="block"&&!C.contains(m.target)&&m.target!==A&&(C.style.display="none")}),document.getElementById("sport-filter-container")?.addEventListener("click",m=>{let k=m.target,P=k.closest("[data-sport]");if(P){let h=P.dataset.sport||null;Tt.sport=Tt.sport===h?null:h,Se(),Mn(),ns(),k.closest(".dropdown-item")&&C&&(C.style.display="none")}}),document.getElementById("filter-metrics")?.addEventListener("click",m=>{let k=m.target.closest(".mini-pill");if(!k)return;let P=k.dataset.metric;Tt.metrics.has(P)?Tt.metrics.delete(P):Tt.metrics.add(P),ns(),Se(),Mn()}),document.getElementById("btn-reset-filters")?.addEventListener("click",()=>{Tt={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},ns(),Se(),Mn()}),document.getElementById("filter-tags")?.addEventListener("input",m=>{let k=m.target.value;Tt.tags=k.split(",").map(P=>P.trim().toLowerCase()).filter(P=>!!P),Se(),Mn()}),document.addEventListener("keydown",m=>{m.key==="Escape"&&(Bt.hideCursor(),Bt.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(k=>k.remove()))}),window.addEventListener("resize",()=>{ft.resize(),Gn(),Bt.invalidateSize?.(),ls()}),window.addEventListener("popstate",()=>{Gt.refresh(),pl(Gt.get())}),fi(),await gl();let $=document.createElement("div");$.id="app-is-ready",$.setAttribute("data-ready","true"),$.style.display="none",document.body.appendChild($);let M=document.createElement("div");M.id="appIsReady",M.setAttribute("data-ready","true"),M.style.display="none",document.body.appendChild(M)}var Fn=null;async function gl(){if(Fn)return Fn;try{let n=await(await fetch("./test-data/manifest.json")).json(),s=new TextDecoder;Fn=await Promise.all(n.map(async l=>{let a=await(await fetch(`./test-data/${l}`)).arrayBuffer(),c=l;if(l.toLowerCase().endsWith(".gz")){c=l.slice(0,-3);let g=new Uint8Array(a);if(g.length>=2&&g[0]===31&&g[1]===139){let f=new DecompressionStream("gzip"),A=new Blob([a]).stream().pipeThrough(f);a=await new Response(A).arrayBuffer()}}let d=c.toLowerCase().endsWith(".fit")?void 0:s.decode(a),w=new File([a],c,{type:"application/octet-stream"});return w._buf=a,d!==void 0&&(w._text=d),{cleanName:c,buf:a,text:d,file:w}}));let e=null;for(let l of[0,2,4])if(Fn[l]){let i=await Jt.parseFile(Fn[l].file);l===0&&(e=i)}if(e){let l=e.points.slice(0,1250),i={...e,id:"warmup",fileName:"warmup.gpx",fileSize:1024,points:l,bounds:Ss(l)||void 0,simplifiedPoints:Ms(l,50),stats:Jt.computeStats(l),addedAt:17855424e5,visible:!0,color:ss[0]},a={...i,id:"warmup-2",fileName:"warmup2.gpx",addedAt:17856288e5,color:ss[1]},c=[i,a];Jt.ensureCurvesAndZones(i),Jt.ensureCurvesAndZones(a),i.stats.sections=Jt.analyzeTrackSections(i.points),a.stats.sections=Jt.analyzeTrackSections(a.points),Jt.findOverlaps(c),Bt.addTracks(c),ft.loadTrack(i,c,!1),ft.restoreSelection(10,50,!0),ft.setCursorAt(25,!0),ft.setSmooth("power",!0),ft.setSmooth("power",!1),ft.setXAxis("distance"),ft.setXAxis("time"),ft.setActiveMetrics(["elevation","speed","power"]),ft.analyzeTelemetryIntervals(c,10,50),be(i,c,[10,50]),be(i,c),Ee(i,[],c),Fe(i,c),Zn(!0),Zn(!1),Xn(.5),Fe(c,c),Hn(i,c),Jn("month"),Jn("week"),As("6m"),As("all"),Is(60),Is(null),Us(c),Tn("course-1",!0),await to(),document.body.offsetHeight,await new Promise(d=>window.setTimeout(d,0))}else typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();return Fn}catch{return[]}}function fi(){let t=document.getElementById("btn-step-load"),n=document.getElementById("btn-step-analysis"),s=document.getElementById("btn-step-insights"),e=document.getElementById("btn-step-details"),l=document.getElementById("btn-step-aggregate"),i=document.getElementById("btn-step-evolution"),a=document.getElementById("btn-step-courses");function c(d){document.querySelectorAll(".tab-btn").forEach(w=>{w.classList.toggle("active",w.dataset.tab===d)}),document.querySelectorAll(".tab-content").forEach(w=>{w.classList.toggle("active",w.id===`tab-${d}`)}),Gt.patch({tab:d},!1)}t?.addEventListener("click",async()=>{try{Object.keys(Ut).length>0||Pe.length>0||Zt!==null?(await ce.openDB(),await to()):typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();let w=(await gl()).map(f=>f.file);await Ds(w);let g=Object.values(Ut);Jt.findOverlaps(g);for(let f of["dist-desc","dur-desc","date-asc","date-desc"])bn=f,vn();Tt.sport="cycling",Se(),Tt.sport=null,Tt.metrics.add("power"),Se(),Tt.metrics.clear(),Ke="Alpine",Se(),Ke="",Se(),!Zt&&g.length>0&&_e(g[0].id)}finally{window.dispatchEvent(new CustomEvent("load-and-parse-complete"))}}),n?.addEventListener("click",()=>{try{let d=Object.values(Ut);c("graphs"),!Zt&&d.length>0&&_e(d[0].id,!1);let w=ft.getAvailableMetrics(),g=[["elevation","speed","power","hr"],["elevation","speed","power"]];for(let A of g){let C=A.filter($=>w.has($));C.length>0&&(document.querySelectorAll("#metric-pills .metric-pill").forEach($=>{let M=$.dataset.metric;M&&$.classList.toggle("active",C.includes(M))}),ls(),ft.setActiveMetrics(C))}ft.setSmooth("power",!0,!0),ft.toggleMapColor("power",!0),ft.toggleMapColor(null,!0),ft.setXAxis("distance"),ft.setSmooth("power",!1,!0),ft.setXAxis("time");let f=[[0,360,180],[120,900,300]];for(let[A,C,$]of f)ft.restoreSelection(A,C,!0),ft.setCursorAt($,!0),ft.analyzeTelemetryIntervals(d,A,C),En(A,C,ft.getXAxis(),!1)}finally{window.dispatchEvent(new CustomEvent("analysis-complete"))}}),s?.addEventListener("click",()=>{try{let d=Object.values(Ut);d.forEach(g=>Jt.ensureCurvesAndZones(g)),c("insights");let w=Zt&&Ut[Zt]||d[0]||null;for(let g of[1,2,4]){let f=d[g];f&&(be(f,d,[0,540]),be(f,d,[540,1140]),be(f,d,null))}d[3]&&be(d[3],d,[200,900]),w&&(be(w,d,[0,480]),be(w,d,[480,960]),be(w,d,[960,1440])),be(w,d,null)}finally{window.dispatchEvent(new CustomEvent("insights-complete"))}}),e?.addEventListener("click",()=>{try{let d=Object.values(Ut);c("details");let w=eo(),g=Zt&&Ut[Zt]||d[0]||null;for(let f=0;f{try{let d=Object.values(Ut);if(d.length>=2){c("combined"),Zs("distance","elevation"),Fe(d[0],d);for(let g of[.25,.5,.75,1])Xn(g);Zn(!0),Xn(.5),Zn(!1),Zs("power","hr");for(let g of[.3,.7])Xn(g);d.length>=4&&Fe([d[2],d[3]],d),d.length>=6&&Fe(d,d);let w=[d[0],d[1]];Fe(w,d)}}finally{window.dispatchEvent(new CustomEvent("aggregate-complete"))}}),i?.addEventListener("click",()=>{try{let d=Object.values(Ut);c("evolution");let w=Zt&&Ut[Zt]||d[0]||null,g=(A,C)=>{_e(A,!0),C&&(ft.restoreSelection(C[0],C[1]),En(C[0],C[1],"time",!0))},f=[d[2]||w,d[4]||w,w];for(let A of f){Hn(A,d,g),Jn("month");for(let C of["1m","2m","6m","1y","all"])As(C);Jn("week");for(let C of[5,30,60,300,1200,null])Is(C)}}finally{window.dispatchEvent(new CustomEvent("evolution-complete"))}}),a?.addEventListener("click",()=>{try{let d=Object.values(Ut);c("courses"),Us(d);let w=Uo();for(let g of w)Tn(g,!0);Tn("course-1",!0)}finally{window.dispatchEvent(new CustomEvent("courses-complete"))}}),window.benchmarkSteps={loadAndParseFiles:()=>document.getElementById("btn-step-load")?.click(),displayAnalysisMetrics:()=>document.getElementById("btn-step-analysis")?.click(),displayInsights:()=>document.getElementById("btn-step-insights")?.click(),displayDetails:()=>document.getElementById("btn-step-details")?.click(),displayAggregateMetrics:()=>document.getElementById("btn-step-aggregate")?.click(),displayEvolutionMetrics:()=>document.getElementById("btn-step-evolution")?.click(),displayCourses:()=>document.getElementById("btn-step-courses")?.click()}}async function ml(t){let n=t.stats.powerCurve?Object.values(t.stats.powerCurve):[],s=t.points.length>1&&(t.points[1].speed===void 0||t.points[1].gradient===void 0);(s||!t.stats.powerCurve||!t.stats.hrZones||!t.stats.hrCurve||t.stats.shifts===void 0||t.stats.avgBattery===void 0||t.stats.avgTemp===void 0||n.length>0&&typeof n[0]=="number"||(t.stats.duration||0)>10800*1e3&&t.stats.powerCurve&&!t.stats.powerCurve[14400])&&(s&&(t.points=Jt.enrichPoints(t.points)),t.stats=Jt.computeStats(t.points),await ce.save(t)),Ut[t.id]=t,os=Math.max(os,ss.indexOf(t.color)+1),Bt.addTrack(t),Bt.setTrackVisible(t.id,t.visible&&!t._filtered),vn()}function gi(){let t=document.getElementById("resize-handle"),n=document.getElementById("chart-panel");if(!t||!n)return;let s=!1;t.addEventListener("mousedown",()=>{s=!0,document.body.style.cursor="ns-resize"}),document.addEventListener("mousemove",e=>{if(!s)return;let l=window.innerHeight-e.clientY,i=Math.max(100,Math.min(window.innerHeight-100,l));n.style.height=`${i}px`,ft.resize(),Gn(),Bt.invalidateSize?.()}),document.addEventListener("mouseup",()=>{s&&(s=!1,document.body.style.cursor="")})}function hi(){let t=document.getElementById("sidebar-resizer"),n=document.getElementById("sidebar");if(!t||!n)return;let s=!1;t.addEventListener("mousedown",()=>{s=!0,t.classList.add("dragging"),document.body.classList.add("dragging-sidebar")}),document.addEventListener("mousemove",e=>{if(!s)return;let l=e.clientX,i=Math.max(200,Math.min(600,l));n.style.width=`${i}px`,n.style.setProperty("--sidebar-w",`${i}px`),ft.resize(),Bt.invalidateSize?.()}),document.addEventListener("mouseup",()=>{s&&(s=!1,t.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}function bi(t,n,s){Gt.patch({map_pos:[t,n,s]})}function vi(t,n){_e(t,!1),ft.setCursorAt(n)}function yi(){}function xi(t){t&&t.lat!=null&&t.lon!=null?(Bt.showCursorAt(t.lat,t.lon),es&&Bt.centerOn(t.lat,t.lon,null,!0)):Bt.hideCursor()}function En(t,n,s,e=!1){if(!Zt||!Ut[Zt])return;let l=Ut[Zt];if(t===null||n===null){Bt.clearHighlight(),l&&(Gt.get().tab||"graphs")==="insights"&&be(l),Gt.patch({sel:null});return}let i=l.points,a=0,c=i.length-1;if(s==="distance"){let g=t*1e3,f=n*1e3;a=i.findIndex(A=>(A.dist||0)>=g),c=i.findIndex(A=>(A.dist||0)>=f)}else{let g=i.find(C=>C.time!=null)?.time||0,f=g+t*1e3,A=g+n*1e3;a=i.findIndex(C=>(C.time||0)>=f),c=i.findIndex(C=>(C.time||0)>=A)}a===-1&&(a=0),c===-1&&(c=i.length-1);let d=i.slice(a,c+1),w=Jt.computeStats(d);ft.setSelectionStats(w),(Gt.get().tab||"graphs")==="insights"&&be(l),Bt.highlightSegment(Zt,i,a,c,e,Bn),Bt.ensureVisible(d.map(g=>[g.lat,g.lon])),Gt.patch({sel:[t,n]})}function wi(t,n){t&&t.lat!=null&&t.lon!=null&&Bt.centerOn(t.lat,t.lon,ci)}function _e(t,n=!0,s=!1){if(!Ut[t])return;if(t===Zt){n&&Bt.fitTrack(t);return}let e=Zt!==null;e&&(ft.clear(),Ee(null,[]),be(null)),Zt=t,Bn=null,Bt.clearMetricColor(t),e&&ft.toggleMapColor(null),Gt.patch({track:t,sel:null},!0),e&&ft.cancelSelection(),vn();let l=Gt.get().tab||"graphs";l==="details"&&Ee(Ut[t],eo()),l==="insights"&&be(Ut[t]),l==="combined"&&Fe(Ut[t]),l==="courses"&&je(),l==="evolution"&&Hn(Ut[t],Object.values(Ut),(i,a)=>{_e(i,!0),a&&(ft.restoreSelection(a[0],a[1]),En(a[0],a[1],"time",!0))}),Bt.setSelectedTrack(t,n),n&&Bt.fitTrack(t),ft.loadTrack(Ut[t],Object.values(Ut),s)}async function Ti(t){await ce.remove(t),Bt.removeTrack(t),delete Ut[t],Zt===t&&(Zt=null,ft.clear(),Ee(null,[]),be(null),Gt.patch({track:null,sel:null,sel_point:null})),Se()}async function Si(){let t=Math.floor(10+Math.random()*90).toString(),n=document.createElement("div");n.className="modal-backdrop",n.innerHTML=` + ${o.has(r)?"check":""} + `,T.addEventListener("click",()=>{ft.toggleMetric(r);let $=ft.getActiveMetrics().has(r);T.classList.toggle("active",$),T.querySelector(".check").textContent=$?"check":"";let M=document.querySelector(`#metric-pills .metric-pill[data-metric="${r}"]`);M&&M.classList.toggle("active",$),ls(),Js()}),s.appendChild(T)});let i=t.getBoundingClientRect();s.style.top=`${i.bottom+5}px`,s.style.right=`${window.innerWidth-i.right}px`,document.body.appendChild(s);let a=r=>{!s.contains(r.target)&&!t.contains(r.target)&&(s.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),0)}document.addEventListener("select-track",t=>{let s=t.detail.id,e=t.detail.idx,n=t.detail.dur;if(s&&Ut[s]&&(_e(s),e!=null&&n!=null)){let o=Ut[s],i=o.points;if(e>=0&&eI.time!=null)?.time||0,d=(a.time-r)/1e3,T=d+n;ft.restoreSelection(d,T);let $=i.findIndex(I=>(I.time||0)>=a.time+n*1e3);$===-1&&($=i.length-1);let M=i.slice(e,$+1),F=Jt.computeStats(M);ft.setSelectionStats(F),be(o),Bt.highlightSegment(s,i,e,$,!1,Bn),Bt.ensureVisible(M.map(I=>[I.lat,I.lon])),Gt.patch({sel:[d,T]})}}}});document.addEventListener("click",t=>{let s=t.target.closest(".tab-btn");if(!s)return;let e=s.closest("#tab-nav");if(!e)return;e.querySelectorAll(".tab-btn").forEach(i=>i.classList.toggle("active",i===s));let n=s.dataset.tab;Gt.patch({tab:n},!0);let o=e.closest("#chart-panel");if(o&&o.querySelectorAll(".tab-content").forEach(i=>{i.classList.toggle("active",i.id===`tab-${s.dataset.tab}`)}),s.dataset.tab==="details"&&Zt&&Ut[Zt]&&Ee(Ut[Zt],eo()),s.dataset.tab==="insights"&&Zt&&Ut[Zt]&&be(Ut[Zt]),s.dataset.tab==="evolution"&&Hn(Zt?Ut[Zt]:null,Object.values(Ut),(i,a)=>{_e(i,!0),a&&(ft.restoreSelection(a[0],a[1]),En(a[0],a[1],"time",!0))},(i,a)=>{Tt.date=[i,a],Se(),Mn(!0),ns()}),s.dataset.tab==="combined"&&Zt&&Ut[Zt]&&Fe(Ut[Zt]),s.dataset.tab==="courses"&&je(),s.dataset.tab==="graphs"){ft.resize(),ls();let i=Gt.get().sel;i&&ft.restoreSelection(i[0],i[1])}});async function to(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await ce.clear(),Ut={},Pe=[],Zt=null,os=0,Bn=null,Dn=!1,es=!1,Ke="",hn=!1,bn="date-desc",Tt.date=[null,null],Tt.dist=[null,null],Tt.dur=[null,null],Tt.metrics.clear(),Tt.tags=[],Jt.setHRZones([120,140,160,180]),Jt.setFTP(200),zo(),Jo(),Lo(),nl(),dl(),Bt.removeAllTracks&&Bt.removeAllTracks(),Bt.clearTracks&&Bt.clearTracks(),Bt.clearHighlight(),ft.resetState?ft.resetState():ft.clear&&ft.clear(),document.querySelectorAll(".tab-btn").forEach(s=>{s.classList.toggle("active",s.dataset.tab==="graphs")}),document.querySelectorAll(".tab-content").forEach(s=>{s.classList.toggle("active",s.id==="tab-graphs")}),Gt.reset();let t=document.getElementById("toast-container");t&&(t.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(s=>s.remove()),typeof vn=="function"&&vn()}async function mi(){let t=null,s=new Promise(u=>{t=window.setTimeout(u,1e3)});try{let u=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([u,s])}finally{t!==null&&window.clearTimeout(t)}document.body.classList.remove("loading-fonts");let e=document.getElementById("storage-backend-select");e&&(e.value=Gt.get().storage||"memory",e.addEventListener("change",u=>{let v=u.target.value,k=new URLSearchParams(window.location.search);v==="memory"?k.delete("storage"):k.set("storage",v),window.location.search=k.toString()}));let n=document.getElementById("global-loader"),o=document.getElementById("loader-text"),i=document.getElementById("loader-subtext"),a=document.getElementById("loader-progress-bar"),r=document.getElementById("map-loader"),d=r?.querySelector("span");r&&(d&&(d.textContent="Loading database..."),r.classList.remove("hidden"));let T=Gt.get();Ko((u,v)=>Fs(u,v==="error"?"error":"info")),Po(()=>{Se(),Mn()},u=>{wi(u)}),qo((u,v)=>Fs(u,v==="error"?"error":"info")),Bt.init(u=>_e(u),hi,bi,(u,v)=>{u===Zt?ft.setHoverAt(v):ft.setHoverAt(null)},vi),ft.init(yi,En,xi,u=>{Gt.patch({sel_point:u})}),ft.setMapColorChangeCb(u=>{u?(Bn=u.colors,Zt&&Bt.colorTrackByMetric(Zt,u.pts,u.colors)):(Bn=null,Zt&&Bt.clearMetricColor(Zt));let v=Gt.get();v.sel&&En(v.sel[0],v.sel[1],ft.getXAxis())}),Si(T),await ce.openDB(),await to();try{let u=await ce.get("hr_zones");u&&Jt.setHRZones(u);let v=await ce.get("ftp");v&&Jt.setFTP(v);let k=await ce.getAll();k.sort((_,W)=>_.addedAt-W.addedAt),d&&(d.textContent=`Preparing ${k.length} tracks...`);let f=[];for(let _ of k){let W=!1;if(!_.bounds&&_.points.length>0){let O=Ss(_.points);O&&(_.bounds=O,W=!0)}!_.simplifiedPoints&&_.points.length>0&&(_.simplifiedPoints=Ms(_.points,50),W=!0),W&&await ce.save(_),Ut[_.id]=_,f.push(_)}Bt.addTracks(f),Se();let h=T.track&&k.find(_=>_.id===T.track)?T.track:k.length>0?k[0].id:null,p=document.getElementById("map-loader"),E=k.find(_=>_.id===h);if(E&&(await ml(E),_e(E.id,!T.map_pos),T.sel&&Array.isArray(T.sel)&&T.sel.length===2&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{ft.restoreSelection(T.sel[0],T.sel[1])})}),T.sel_point!==void 0&&T.sel_point!==null&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{ft.setCursorAt(T.sel_point)})})),p&&p.classList.add("hidden"),k.length>(E?1:0)){p&&(d&&(d.textContent="Loading tracks..."),p.classList.remove("hidden"));let _=k.filter(Y=>Y.id!==h),W=0,O=async()=>{let Z=Math.min(W+2,_.length);for(;W{_e(lt,!0),Ft&&(ft.restoreSelection(Ft[0],Ft[1]),En(Ft[0],Ft[1],"time",!0))}),k.length&&!T.map_pos&&Bt.fitAll())};requestAnimationFrame(O)}else Se(),k.length&&!T.map_pos&&Bt.fitAll()}catch(u){console.warn("Could not load saved tracks:",u)}fi(),gi(),$i(),ls(),document.getElementById("basemap-switcher")?.addEventListener("click",u=>{let v=u.target.closest(".bm-btn");v&&(document.querySelectorAll(".bm-btn").forEach(k=>k.classList.remove("active")),v.classList.add("active"),v.dataset.layer&&(Bt.switchBasemap(v.dataset.layer),Gt.patch({map:v.dataset.layer})))}),document.getElementById("btn-fit-all")?.addEventListener("click",()=>Bt.fitAll()),document.getElementById("btn-clear-all")?.addEventListener("click",Ti),document.getElementById("track-search")?.addEventListener("input",u=>{Ke=u.target.value,Se(),Gt.patch({q:Ke||null})}),document.getElementById("btn-regex-toggle")?.addEventListener("click",u=>{hn=!hn,u.target.classList.toggle("active",hn),Se(),Gt.patch({re:hn?1:null})}),document.getElementById("btn-sort-menu")?.addEventListener("click",u=>{u.stopPropagation(),di(u.currentTarget)}),document.getElementById("btn-metric-menu")?.addEventListener("click",u=>{u.stopPropagation(),ui(u.currentTarget)});let $=(u,v)=>{v&&v.classList.toggle("active"),ft.toggleMetric(u),Js()};document.getElementById("metric-pills")?.addEventListener("click",u=>{let v=u.target.closest(".metric-pill");if(v){let k=v.dataset.metric;k&&($(k,v),ft.getActiveMetrics().has(k)&&document.querySelector(`.chart-row[data-metric="${k}"]`)?.scrollIntoView({behavior:"smooth"}))}}),document.getElementById("x-axis-ctrl")?.addEventListener("click",u=>{let v=u.target.closest(".seg-btn");if(!v)return;let k=v.dataset.axis;ft.setXAxis(k),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(f=>f.classList.toggle("active",f===v)),Gt.patch({xaxis:k})}),document.getElementById("btn-follow-dot")?.addEventListener("click",u=>{es=!es,u.currentTarget.classList.toggle("active",es)}),document.getElementById("btn-reset-zoom")?.addEventListener("click",()=>{ft.resetZoom(),Bt.clearHighlight()}),Ci(),document.getElementById("file-input")?.addEventListener("change",u=>{Ds(Array.from(u.target.files||[])),u.target.value=""}),document.getElementById("folder-input")?.addEventListener("change",u=>{Ds(Array.from(u.target.files||[])),u.target.value=""}),document.getElementById("btn-toggle-filters")?.addEventListener("click",()=>{let u=document.getElementById("filter-panel");u&&(u.classList.toggle("hidden"),document.getElementById("btn-toggle-filters")?.classList.toggle("active",!u.classList.contains("hidden")))});let M=(u,v,k)=>{let f=k.target.value;Tt[u][v]=f===""?null:f,Se(),Mn()};document.getElementById("filter-date-start")?.addEventListener("change",u=>M("date",0,u)),document.getElementById("filter-date-end")?.addEventListener("change",u=>M("date",1,u)),document.getElementById("filter-dist-min")?.addEventListener("input",u=>M("dist",0,u)),document.getElementById("filter-dist-max")?.addEventListener("input",u=>M("dist",1,u)),document.getElementById("filter-dur-min")?.addEventListener("input",u=>M("dur",0,u)),document.getElementById("filter-dur-max")?.addEventListener("input",u=>M("dur",1,u));let F=document.getElementById("sport-burger-btn"),I=document.getElementById("sport-dropdown-content");F?.addEventListener("click",u=>{if(u.stopPropagation(),I){let v=I.style.display==="block";I.style.display=v?"none":"block"}}),document.addEventListener("click",u=>{I&&I.style.display==="block"&&!I.contains(u.target)&&u.target!==F&&(I.style.display="none")}),document.getElementById("sport-filter-container")?.addEventListener("click",u=>{let v=u.target,k=v.closest("[data-sport]");if(k){let f=k.dataset.sport||null;Tt.sport=Tt.sport===f?null:f,Se(),Mn(),ns(),v.closest(".dropdown-item")&&I&&(I.style.display="none")}}),document.getElementById("filter-metrics")?.addEventListener("click",u=>{let v=u.target.closest(".mini-pill");if(!v)return;let k=v.dataset.metric;Tt.metrics.has(k)?Tt.metrics.delete(k):Tt.metrics.add(k),ns(),Se(),Mn()}),document.getElementById("btn-reset-filters")?.addEventListener("click",()=>{Tt={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},ns(),Se(),Mn()}),document.getElementById("filter-tags")?.addEventListener("input",u=>{let v=u.target.value;Tt.tags=v.split(",").map(k=>k.trim().toLowerCase()).filter(k=>!!k),Se(),Mn()}),document.addEventListener("keydown",u=>{u.key==="Escape"&&(Bt.hideCursor(),Bt.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(v=>v.remove()))}),window.addEventListener("resize",()=>{ft.resize(),Gn(),Bt.invalidateSize?.(),ls()}),pi(),await fl();let b=document.createElement("div");b.id="app-is-ready",b.setAttribute("data-ready","true"),b.style.display="none",document.body.appendChild(b);let g=document.createElement("div");g.id="appIsReady",g.setAttribute("data-ready","true"),g.style.display="none",document.body.appendChild(g)}var Fn=null;async function fl(){if(Fn)return Fn;try{let s=await(await fetch("./test-data/manifest.json")).json(),e=new TextDecoder;Fn=await Promise.all(s.map(async o=>{let a=await(await fetch(`./test-data/${o}`)).arrayBuffer(),r=o;if(o.toLowerCase().endsWith(".gz")){r=o.slice(0,-3);let $=new Uint8Array(a);if($.length>=2&&$[0]===31&&$[1]===139){let M=new DecompressionStream("gzip"),F=new Blob([a]).stream().pipeThrough(M);a=await new Response(F).arrayBuffer()}}let d=r.toLowerCase().endsWith(".fit")?void 0:e.decode(a),T=new File([a],r,{type:"application/octet-stream"});return T._buf=a,d!==void 0&&(T._text=d),{cleanName:r,buf:a,text:d,file:T}}));let n=null;for(let o of[0,2,4])if(Fn[o]){let i=await Jt.parseFile(Fn[o].file);o===0&&(n=i)}if(n){let o=n.points.slice(0,1250),i={...n,id:"warmup",fileName:"warmup.gpx",fileSize:1024,points:o,bounds:Ss(o)||void 0,simplifiedPoints:Ms(o,50),stats:Jt.computeStats(o),addedAt:17855424e5,visible:!0,color:ss[0]},a={...i,id:"warmup-2",fileName:"warmup2.gpx",addedAt:17856288e5,color:ss[1]},r=[i,a];Jt.ensureCurvesAndZones(i),Jt.ensureCurvesAndZones(a),i.stats.sections=Jt.analyzeTrackSections(i.points),a.stats.sections=Jt.analyzeTrackSections(a.points),Jt.findOverlaps(r),Bt.addTracks(r),ft.loadTrack(i,r,!1),ft.restoreSelection(10,50,!0),ft.setCursorAt(25,!0),ft.setSmooth("power",!0),ft.setSmooth("power",!1),ft.setXAxis("distance"),ft.setXAxis("time"),ft.setActiveMetrics(["elevation","speed","power"]),ft.analyzeTelemetryIntervals(r,10,50),be(i,r,[10,50]),be(i,r),Ee(i,[],r),Fe(i,r),Zn(!0),Zn(!1),Xn(.5),Fe(r,r),Hn(i,r),Jn("month"),Jn("week"),As("6m"),As("all"),Is(60),Is(null),Us(r),Tn("course-1",!0),await to(),document.body.offsetHeight,await new Promise(d=>window.setTimeout(d,0))}else typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();return Fn}catch{return[]}}function pi(){let t=document.getElementById("btn-step-load"),s=document.getElementById("btn-step-analysis"),e=document.getElementById("btn-step-insights"),n=document.getElementById("btn-step-details"),o=document.getElementById("btn-step-aggregate"),i=document.getElementById("btn-step-evolution"),a=document.getElementById("btn-step-courses");function r(d){document.querySelectorAll(".tab-btn").forEach(T=>{T.classList.toggle("active",T.dataset.tab===d)}),document.querySelectorAll(".tab-content").forEach(T=>{T.classList.toggle("active",T.id===`tab-${d}`)}),Gt.patch({tab:d},!1)}t?.addEventListener("click",async()=>{try{Object.keys(Ut).length>0||Pe.length>0||Zt!==null?(await ce.openDB(),await to()):typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed();let T=(await fl()).map(M=>M.file);await Ds(T);let $=Object.values(Ut);Jt.findOverlaps($);for(let M of["dist-desc","dur-desc","date-asc","date-desc"])bn=M,vn();Tt.sport="cycling",Se(),Tt.sport=null,Tt.metrics.add("power"),Se(),Tt.metrics.clear(),Ke="Alpine",Se(),Ke="",Se(),!Zt&&$.length>0&&_e($[0].id)}finally{window.dispatchEvent(new CustomEvent("load-and-parse-complete"))}}),s?.addEventListener("click",()=>{try{let d=Object.values(Ut);r("graphs"),!Zt&&d.length>0&&_e(d[0].id,!1);let T=ft.getAvailableMetrics(),$=[["elevation","speed","power","hr"],["elevation","speed","power"]];for(let F of $){let I=F.filter(b=>T.has(b));I.length>0&&(document.querySelectorAll("#metric-pills .metric-pill").forEach(b=>{let g=b.dataset.metric;g&&b.classList.toggle("active",I.includes(g))}),ls(),ft.setActiveMetrics(I))}ft.setSmooth("power",!0,!0),ft.toggleMapColor("power",!0),ft.toggleMapColor(null,!0),ft.setXAxis("distance"),ft.setSmooth("power",!1,!0),ft.setXAxis("time");let M=[[0,360,180],[120,900,300]];for(let[F,I,b]of M)ft.restoreSelection(F,I,!0),ft.setCursorAt(b,!0),ft.analyzeTelemetryIntervals(d,F,I),En(F,I,ft.getXAxis(),!1)}finally{window.dispatchEvent(new CustomEvent("analysis-complete"))}}),e?.addEventListener("click",()=>{try{let d=Object.values(Ut);d.forEach($=>Jt.ensureCurvesAndZones($)),r("insights");let T=Zt&&Ut[Zt]||d[0]||null;for(let $ of[1,2,4]){let M=d[$];M&&(be(M,d,[0,540]),be(M,d,[540,1140]),be(M,d,null))}d[3]&&be(d[3],d,[200,900]),T&&(be(T,d,[0,480]),be(T,d,[480,960]),be(T,d,[960,1440])),be(T,d,null)}finally{window.dispatchEvent(new CustomEvent("insights-complete"))}}),n?.addEventListener("click",()=>{try{let d=Object.values(Ut);r("details");let T=eo(),$=Zt&&Ut[Zt]||d[0]||null;for(let M=0;M{try{let d=Object.values(Ut);if(d.length>=2){r("combined"),Zs("distance","elevation"),Fe(d[0],d);for(let $ of[.25,.5,.75,1])Xn($);Zn(!0),Xn(.5),Zn(!1),Zs("power","hr");for(let $ of[.3,.7])Xn($);d.length>=4&&Fe([d[2],d[3]],d),d.length>=6&&Fe(d,d);let T=[d[0],d[1]];Fe(T,d)}}finally{window.dispatchEvent(new CustomEvent("aggregate-complete"))}}),i?.addEventListener("click",()=>{try{let d=Object.values(Ut);r("evolution");let T=Zt&&Ut[Zt]||d[0]||null,$=(F,I)=>{_e(F,!0),I&&(ft.restoreSelection(I[0],I[1]),En(I[0],I[1],"time",!0))},M=[d[2]||T,d[4]||T,T];for(let F of M){Hn(F,d,$),Jn("month");for(let I of["1m","2m","6m","1y","all"])As(I);Jn("week");for(let I of[5,30,60,300,1200,null])Is(I)}}finally{window.dispatchEvent(new CustomEvent("evolution-complete"))}}),a?.addEventListener("click",()=>{try{let d=Object.values(Ut);r("courses"),Us(d);let T=Uo();for(let $ of T)Tn($,!0);Tn("course-1",!0)}finally{window.dispatchEvent(new CustomEvent("courses-complete"))}}),window.benchmarkSteps={loadAndParseFiles:()=>document.getElementById("btn-step-load")?.click(),displayAnalysisMetrics:()=>document.getElementById("btn-step-analysis")?.click(),displayInsights:()=>document.getElementById("btn-step-insights")?.click(),displayDetails:()=>document.getElementById("btn-step-details")?.click(),displayAggregateMetrics:()=>document.getElementById("btn-step-aggregate")?.click(),displayEvolutionMetrics:()=>document.getElementById("btn-step-evolution")?.click(),displayCourses:()=>document.getElementById("btn-step-courses")?.click()}}async function ml(t){let s=t.stats.powerCurve?Object.values(t.stats.powerCurve):[],e=t.points.length>1&&(t.points[1].speed===void 0||t.points[1].gradient===void 0);(e||!t.stats.powerCurve||!t.stats.hrZones||!t.stats.hrCurve||t.stats.shifts===void 0||t.stats.avgBattery===void 0||t.stats.avgTemp===void 0||s.length>0&&typeof s[0]=="number"||(t.stats.duration||0)>10800*1e3&&t.stats.powerCurve&&!t.stats.powerCurve[14400])&&(e&&(t.points=Jt.enrichPoints(t.points)),t.stats=Jt.computeStats(t.points),await ce.save(t)),Ut[t.id]=t,os=Math.max(os,ss.indexOf(t.color)+1),Bt.addTrack(t),Bt.setTrackVisible(t.id,t.visible&&!t._filtered),vn()}function fi(){let t=document.getElementById("resize-handle"),s=document.getElementById("chart-panel");if(!t||!s)return;let e=!1;t.addEventListener("mousedown",()=>{e=!0,document.body.style.cursor="ns-resize"}),document.addEventListener("mousemove",n=>{if(!e)return;let o=window.innerHeight-n.clientY,i=Math.max(100,Math.min(window.innerHeight-100,o));s.style.height=`${i}px`,ft.resize(),Gn(),Bt.invalidateSize?.()}),document.addEventListener("mouseup",()=>{e&&(e=!1,document.body.style.cursor="")})}function gi(){let t=document.getElementById("sidebar-resizer"),s=document.getElementById("sidebar");if(!t||!s)return;let e=!1;t.addEventListener("mousedown",()=>{e=!0,t.classList.add("dragging"),document.body.classList.add("dragging-sidebar")}),document.addEventListener("mousemove",n=>{if(!e)return;let o=n.clientX,i=Math.max(200,Math.min(600,o));s.style.width=`${i}px`,s.style.setProperty("--sidebar-w",`${i}px`),ft.resize(),Bt.invalidateSize?.()}),document.addEventListener("mouseup",()=>{e&&(e=!1,t.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}function hi(t,s,e){Gt.patch({map_pos:[t,s,e]})}function bi(t,s){_e(t,!1),ft.setCursorAt(s)}function vi(){}function yi(t){t&&t.lat!=null&&t.lon!=null?(Bt.showCursorAt(t.lat,t.lon),es&&Bt.centerOn(t.lat,t.lon,null,!0)):Bt.hideCursor()}function En(t,s,e,n=!1){if(!Zt||!Ut[Zt])return;let o=Ut[Zt];if(t===null||s===null){Bt.clearHighlight(),o&&(Gt.get().tab||"graphs")==="insights"&&be(o),Gt.patch({sel:null});return}let i=o.points,a=0,r=i.length-1;if(e==="distance"){let $=t*1e3,M=s*1e3;a=i.findIndex(F=>(F.dist||0)>=$),r=i.findIndex(F=>(F.dist||0)>=M)}else{let $=i.find(I=>I.time!=null)?.time||0,M=$+t*1e3,F=$+s*1e3;a=i.findIndex(I=>(I.time||0)>=M),r=i.findIndex(I=>(I.time||0)>=F)}a===-1&&(a=0),r===-1&&(r=i.length-1);let d=i.slice(a,r+1),T=Jt.computeStats(d);ft.setSelectionStats(T),(Gt.get().tab||"graphs")==="insights"&&be(o),Bt.highlightSegment(Zt,i,a,r,n,Bn),Bt.ensureVisible(d.map($=>[$.lat,$.lon])),Gt.patch({sel:[t,s]})}function xi(t,s){t&&t.lat!=null&&t.lon!=null&&Bt.centerOn(t.lat,t.lon,ri)}function _e(t,s=!0,e=!1){if(!Ut[t])return;if(t===Zt){s&&Bt.fitTrack(t);return}let n=Zt!==null;n&&(ft.clear(),Ee(null,[]),be(null)),Zt=t,Bn=null,Bt.clearMetricColor(t),n&&ft.toggleMapColor(null),Gt.patch({track:t,sel:null},!0),n&&ft.cancelSelection(),vn();let o=Gt.get().tab||"graphs";o==="details"&&Ee(Ut[t],eo()),o==="insights"&&be(Ut[t]),o==="combined"&&Fe(Ut[t]),o==="courses"&&je(),o==="evolution"&&Hn(Ut[t],Object.values(Ut),(i,a)=>{_e(i,!0),a&&(ft.restoreSelection(a[0],a[1]),En(a[0],a[1],"time",!0))}),Bt.setSelectedTrack(t,s),s&&Bt.fitTrack(t),ft.loadTrack(Ut[t],Object.values(Ut),e)}async function wi(t){await ce.remove(t),Bt.removeTrack(t),delete Ut[t],Zt===t&&(Zt=null,ft.clear(),Ee(null,[]),be(null),Gt.patch({track:null,sel:null,sel_point:null})),Se()}async function Ti(){let t=Math.floor(10+Math.random()*90).toString(),s=document.createElement("div");s.className="modal-backdrop",s.innerHTML=` - `,document.body.appendChild(n);let s=n.querySelector(".modal-input"),e=n.querySelector(".modal-btn.confirm"),l=n.querySelector(".modal-btn.cancel");s.focus(),s.addEventListener("input",()=>{e.disabled=s.value!==t});let i=()=>n.remove();l.addEventListener("click",i),n.addEventListener("click",a=>{a.target===n&&i()}),e.addEventListener("click",async()=>{s.value===t&&(i(),Dn=!0,await ce.clear(),Ut={},Zt=null,Bt.clearHighlight(),window.location.reload())})}function Se(t=!1){Object.keys(Ut).forEach(s=>{let e=Ut[s],l=e.stats,i=!0;if(Ke)if(hn)try{new RegExp(Ke,"i").test(e.name)||(i=!1)}catch{i=!1}else e.name.toLowerCase().includes(Ke.toLowerCase())||(i=!1);if(i&&(Tt.date[0]||Tt.date[1])){let a=Tt.date[0]?new Date(Tt.date[0]).getTime():0,c=Tt.date[1]?new Date(Tt.date[1]).getTime():1/0,d=l.startTime||0;(dc)&&(i=!1)}if(i&&(Tt.dist[0]!==null||Tt.dist[1]!==null)){let a=(Tt.dist[0]||0)*1e3,c=(Tt.dist[1]||1/0)*1e3;(l.totalDistc)&&(i=!1)}if(i&&(Tt.dur[0]!==null||Tt.dur[1]!==null)){let a=(Tt.dur[0]||0)*6e4,c=(Tt.dur[1]||1/0)*6e4,d=l.duration||0;(dc)&&(i=!1)}if(i&&Tt.metrics.size>0)for(let a of Tt.metrics){let c=ft.METRICS[a].field;if(!e.points.some(d=>d[c]!=null)){i=!1;break}}if(i&&Tt.sport&&e.sport!==Tt.sport&&(i=!1),i&&Tt.tags.length>0){let a=e.tags||[];Tt.tags.every(c=>a.includes(c))||(i=!1)}e._filtered=!i,Bt.setTrackVisible(e.id,e.visible&&i)}),t||vn()}function ns(){document.getElementById("filter-date-start").value=Tt.date[0]||"",document.getElementById("filter-date-end").value=Tt.date[1]||"",document.getElementById("filter-dist-min").value=Tt.dist[0]!==null?String(Tt.dist[0]):"",document.getElementById("filter-dist-max").value=Tt.dist[1]!==null?String(Tt.dist[1]):"",document.getElementById("filter-dur-min").value=Tt.dur[0]!==null?String(Tt.dur[0]):"",document.getElementById("filter-dur-max").value=Tt.dur[1]!==null?String(Tt.dur[1]):"",document.getElementById("filter-tags").value=Tt.tags.join(", "),document.querySelectorAll("#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item").forEach(s=>{let e=s;e.classList.toggle("active",(e.dataset.sport||"")===(Tt.sport||""))}),document.querySelectorAll("#filter-metrics .mini-pill").forEach(s=>{let e=s;e.classList.toggle("active",Tt.metrics.has(e.dataset.metric))});let t=(Tt.date[0]?1:0)+(Tt.date[1]?1:0)+(Tt.dist[0]!==null?1:0)+(Tt.dist[1]!==null?1:0)+(Tt.dur[0]!==null?1:0)+(Tt.dur[1]!==null?1:0)+Tt.metrics.size+(Tt.tags.length>0?1:0),n=document.querySelector("#btn-toggle-filters .btn-badge");n&&(n.textContent=t>0?String(t):"",n.classList.toggle("hidden",t===0))}function hl(){let t=document.getElementById("track-search");t&&(t.value=Ke),document.getElementById("btn-regex-toggle")?.classList.toggle("active",hn);let n=fl.find(s=>s.val===bn);if(n){let s=document.getElementById("sort-current-label"),e=document.getElementById("sort-current-icon");s&&(s.textContent=n.label.replace(" first","").replace(" distance","").replace(" duration","")),e&&(e.textContent=n.icon)}}function pl(t){let n=t.track;if(n!==Zt&&(n&&Ut[n]?_e(n,!0):!n&&Zt&&(Zt=null,ft.clear(),Ee(null,[]),be(null),vn(),Bt.fitAll())),t.map&&typeof t.map=="string"&&(Bt.switchBasemap(t.map),document.querySelectorAll(".bm-btn").forEach(e=>e.classList.toggle("active",e.dataset.layer===t.map))),t.map_pos){let[e,l,i]=t.map_pos;Bt.setPosition(e,l,i)}t.tab&&document.querySelectorAll(".tab-btn").forEach(e=>{let l=e;l.dataset.tab===t.tab&&(l.classList.contains("active")||l.click())}),t.xaxis&&ft.setXAxis(t.xaxis);let s=t.xaxis||"time";if(document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(e=>e.classList.toggle("active",e.dataset.axis===s)),t.metrics){let e=ft.METRICS,l=t.metrics.map(i=>Object.keys(e).find(a=>e[a].abbr===i)).filter(i=>i!==void 0);l.length&&ft.setActiveMetrics(l)}t.f_date&&(Tt.date=t.f_date.map(e=>e||null)),t.f_dist&&(Tt.dist=t.f_dist.map(e=>e===0?0:e||null)),t.f_dur&&(Tt.dur=t.f_dur.map(e=>e===0?0:e||null)),t.f_mets&&(Tt.metrics=new Set(t.f_mets)),t.f_tags&&(Tt.tags=t.f_tags),ns(),t.q&&(Ke=t.q),t.re&&(hn=t.re),t.sort&&(bn=t.sort),hl(),Se()}function Mi(){if(!document.getElementById("sport-filter-container"))return;let n=document.getElementById("common-sports"),s=document.getElementById("sport-dropdown-content");if(!n||!s)return;let e=new Set;Object.values(Ut).forEach(a=>{a.sport&&e.add(a.sport)});let l=Array.from(e).sort(),i=document.getElementById("sport-burger-dropdown");n.innerHTML="",s.innerHTML="",l.length<=4?(i&&(i.style.display="none"),l.forEach(a=>{let c=document.createElement("button");c.className=`mini-pill${Tt.sport===a?" active":""}`,c.dataset.sport=a,c.title=a.charAt(0).toUpperCase()+a.slice(1),c.innerHTML=`${Hs(a)}`,n.appendChild(c)})):(i&&(i.style.display="inline-block"),["running","cycling","walking"].forEach(c=>{if(e.has(c)){let d=document.createElement("button");d.className=`mini-pill${Tt.sport===c?" active":""}`,d.dataset.sport=c,d.title=c.charAt(0).toUpperCase()+c.slice(1),d.innerHTML=`${Hs(c)}`,n.appendChild(d)}}),l.forEach(c=>{let d=document.createElement("div");d.className=`dropdown-item${Tt.sport===c?" active":""}`,d.dataset.sport=c,d.style.padding="8px",d.style.cursor="pointer",d.style.display="flex",d.style.alignItems="center",d.style.gap="8px",d.innerHTML=` - ${Hs(c)} - ${c.charAt(0).toUpperCase()+c.slice(1)} - `,s.appendChild(d)}))}function vn(){Mi();let t=document.getElementById("track-list"),n=document.getElementById("track-list-empty"),s=document.querySelector(".section-label");if(!t)return;let e=Object.keys(Ut).filter(l=>!Ut[l]._filtered);if(s&&(s.textContent=`Tracks (${e.length})`),!e.length){t.innerHTML="",n&&(t.appendChild(n),n.style.display="block");return}n&&(n.style.display="none"),t.innerHTML="",e.sort((l,i)=>{if(l===Zt)return-1;if(i===Zt)return 1;let a=Ut[l],c=Ut[i],d=a.stats,w=c.stats,g=0;switch(bn){case"date-asc":g=(d.startTime||0)-(w.startTime||0);break;case"date-desc":g=(w.startTime||0)-(d.startTime||0);break;case"dist-asc":g=(d.totalDist||0)-(w.totalDist||0);break;case"dist-desc":g=(w.totalDist||0)-(d.totalDist||0);break;case"dur-asc":g=(d.duration||0)-(w.duration||0);break;case"dur-desc":g=(w.duration||0)-(d.duration||0);break;default:g=0}return g||l.localeCompare(i)}).forEach(l=>{t.appendChild(Ei(Ut[l]))})}function eo(){let t=new Set;return Object.values(Ut).forEach(n=>{(n.tags||[]).forEach(s=>t.add(s))}),Array.from(t).sort()}function Hs(t){if(!t)return"category";let n=t.toLowerCase();return n.includes("run")?"directions_run":n.includes("cycl")||n.includes("bike")?"directions_bike":n.includes("walk")?"directions_walk":n.includes("swim")?"pool":n.includes("hik")?"hiking":"sports"}function Ei(t){let n=document.createElement("div");n.className=`track-item${t.id===Zt?" selected":""}`,n.dataset.id=t.id;let s=t.points.length&&t.points[0].time?nn(t.points[0].time):"Unknown date",e=(t.tags||[]).length>0?`
${(t.tags||[]).map(i=>{let a=Ts(i);return`${me(i)}`}).join("")}
`:"";n.innerHTML=` + `,document.body.appendChild(s);let e=s.querySelector(".modal-input"),n=s.querySelector(".modal-btn.confirm"),o=s.querySelector(".modal-btn.cancel");e.focus(),e.addEventListener("input",()=>{n.disabled=e.value!==t});let i=()=>s.remove();o.addEventListener("click",i),s.addEventListener("click",a=>{a.target===s&&i()}),n.addEventListener("click",async()=>{e.value===t&&(i(),Dn=!0,await ce.clear(),Ut={},Zt=null,Bt.clearHighlight(),window.location.reload())})}function Se(t=!1){Object.keys(Ut).forEach(e=>{let n=Ut[e],o=n.stats,i=!0;if(Ke)if(hn)try{new RegExp(Ke,"i").test(n.name)||(i=!1)}catch{i=!1}else n.name.toLowerCase().includes(Ke.toLowerCase())||(i=!1);if(i&&(Tt.date[0]||Tt.date[1])){let a=Tt.date[0]?new Date(Tt.date[0]).getTime():0,r=Tt.date[1]?new Date(Tt.date[1]).getTime():1/0,d=o.startTime||0;(dr)&&(i=!1)}if(i&&(Tt.dist[0]!==null||Tt.dist[1]!==null)){let a=(Tt.dist[0]||0)*1e3,r=(Tt.dist[1]||1/0)*1e3;(o.totalDistr)&&(i=!1)}if(i&&(Tt.dur[0]!==null||Tt.dur[1]!==null)){let a=(Tt.dur[0]||0)*6e4,r=(Tt.dur[1]||1/0)*6e4,d=o.duration||0;(dr)&&(i=!1)}if(i&&Tt.metrics.size>0)for(let a of Tt.metrics){let r=ft.METRICS[a].field;if(!n.points.some(d=>d[r]!=null)){i=!1;break}}if(i&&Tt.sport&&n.sport!==Tt.sport&&(i=!1),i&&Tt.tags.length>0){let a=n.tags||[];Tt.tags.every(r=>a.includes(r))||(i=!1)}n._filtered=!i,Bt.setTrackVisible(n.id,n.visible&&i)}),t||vn()}function ns(){document.getElementById("filter-date-start").value=Tt.date[0]||"",document.getElementById("filter-date-end").value=Tt.date[1]||"",document.getElementById("filter-dist-min").value=Tt.dist[0]!==null?String(Tt.dist[0]):"",document.getElementById("filter-dist-max").value=Tt.dist[1]!==null?String(Tt.dist[1]):"",document.getElementById("filter-dur-min").value=Tt.dur[0]!==null?String(Tt.dur[0]):"",document.getElementById("filter-dur-max").value=Tt.dur[1]!==null?String(Tt.dur[1]):"",document.getElementById("filter-tags").value=Tt.tags.join(", "),document.querySelectorAll("#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item").forEach(e=>{let n=e;n.classList.toggle("active",(n.dataset.sport||"")===(Tt.sport||""))}),document.querySelectorAll("#filter-metrics .mini-pill").forEach(e=>{let n=e;n.classList.toggle("active",Tt.metrics.has(n.dataset.metric))});let t=(Tt.date[0]?1:0)+(Tt.date[1]?1:0)+(Tt.dist[0]!==null?1:0)+(Tt.dist[1]!==null?1:0)+(Tt.dur[0]!==null?1:0)+(Tt.dur[1]!==null?1:0)+Tt.metrics.size+(Tt.tags.length>0?1:0),s=document.querySelector("#btn-toggle-filters .btn-badge");s&&(s.textContent=t>0?String(t):"",s.classList.toggle("hidden",t===0))}function gl(){let t=document.getElementById("track-search");t&&(t.value=Ke),document.getElementById("btn-regex-toggle")?.classList.toggle("active",hn);let s=pl.find(e=>e.val===bn);if(s){let e=document.getElementById("sort-current-label"),n=document.getElementById("sort-current-icon");e&&(e.textContent=s.label.replace(" first","").replace(" distance","").replace(" duration","")),n&&(n.textContent=s.icon)}}function Si(t){let s=t.track;if(s!==Zt&&(s&&Ut[s]?_e(s,!0):!s&&Zt&&(Zt=null,ft.clear(),Ee(null,[]),be(null),vn(),Bt.fitAll())),t.map&&typeof t.map=="string"&&(Bt.switchBasemap(t.map),document.querySelectorAll(".bm-btn").forEach(n=>n.classList.toggle("active",n.dataset.layer===t.map))),t.map_pos){let[n,o,i]=t.map_pos;Bt.setPosition(n,o,i)}t.tab&&document.querySelectorAll(".tab-btn").forEach(n=>{let o=n;o.dataset.tab===t.tab&&(o.classList.contains("active")||o.click())}),t.xaxis&&ft.setXAxis(t.xaxis);let e=t.xaxis||"time";if(document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(n=>n.classList.toggle("active",n.dataset.axis===e)),t.metrics){let n=ft.METRICS,o=t.metrics.map(i=>Object.keys(n).find(a=>n[a].abbr===i)).filter(i=>i!==void 0);o.length&&ft.setActiveMetrics(o)}t.f_date&&(Tt.date=t.f_date.map(n=>n||null)),t.f_dist&&(Tt.dist=t.f_dist.map(n=>n===0?0:n||null)),t.f_dur&&(Tt.dur=t.f_dur.map(n=>n===0?0:n||null)),t.f_mets&&(Tt.metrics=new Set(t.f_mets)),t.f_tags&&(Tt.tags=t.f_tags),ns(),t.q&&(Ke=t.q),t.re&&(hn=t.re),t.sort&&(bn=t.sort),gl(),Se()}function Mi(){if(!document.getElementById("sport-filter-container"))return;let s=document.getElementById("common-sports"),e=document.getElementById("sport-dropdown-content");if(!s||!e)return;let n=new Set;Object.values(Ut).forEach(a=>{a.sport&&n.add(a.sport)});let o=Array.from(n).sort(),i=document.getElementById("sport-burger-dropdown");s.innerHTML="",e.innerHTML="",o.length<=4?(i&&(i.style.display="none"),o.forEach(a=>{let r=document.createElement("button");r.className=`mini-pill${Tt.sport===a?" active":""}`,r.dataset.sport=a,r.title=a.charAt(0).toUpperCase()+a.slice(1),r.innerHTML=`${Hs(a)}`,s.appendChild(r)})):(i&&(i.style.display="inline-block"),["running","cycling","walking"].forEach(r=>{if(n.has(r)){let d=document.createElement("button");d.className=`mini-pill${Tt.sport===r?" active":""}`,d.dataset.sport=r,d.title=r.charAt(0).toUpperCase()+r.slice(1),d.innerHTML=`${Hs(r)}`,s.appendChild(d)}}),o.forEach(r=>{let d=document.createElement("div");d.className=`dropdown-item${Tt.sport===r?" active":""}`,d.dataset.sport=r,d.style.padding="8px",d.style.cursor="pointer",d.style.display="flex",d.style.alignItems="center",d.style.gap="8px",d.innerHTML=` + ${Hs(r)} + ${r.charAt(0).toUpperCase()+r.slice(1)} + `,e.appendChild(d)}))}function vn(){Mi();let t=document.getElementById("track-list"),s=document.getElementById("track-list-empty"),e=document.querySelector(".section-label");if(!t)return;let n=Object.keys(Ut).filter(o=>!Ut[o]._filtered);if(e&&(e.textContent=`Tracks (${n.length})`),!n.length){t.innerHTML="",s&&(t.appendChild(s),s.style.display="block");return}s&&(s.style.display="none"),t.innerHTML="",n.sort((o,i)=>{if(o===Zt)return-1;if(i===Zt)return 1;let a=Ut[o],r=Ut[i],d=a.stats,T=r.stats,$=0;switch(bn){case"date-asc":$=(d.startTime||0)-(T.startTime||0);break;case"date-desc":$=(T.startTime||0)-(d.startTime||0);break;case"dist-asc":$=(d.totalDist||0)-(T.totalDist||0);break;case"dist-desc":$=(T.totalDist||0)-(d.totalDist||0);break;case"dur-asc":$=(d.duration||0)-(T.duration||0);break;case"dur-desc":$=(T.duration||0)-(d.duration||0);break;default:$=0}return $||o.localeCompare(i)}).forEach(o=>{t.appendChild(Ei(Ut[o]))})}function eo(){let t=new Set;return Object.values(Ut).forEach(s=>{(s.tags||[]).forEach(e=>t.add(e))}),Array.from(t).sort()}function Hs(t){if(!t)return"category";let s=t.toLowerCase();return s.includes("run")?"directions_run":s.includes("cycl")||s.includes("bike")?"directions_bike":s.includes("walk")?"directions_walk":s.includes("swim")?"pool":s.includes("hik")?"hiking":"sports"}function Ei(t){let s=document.createElement("div");s.className=`track-item${t.id===Zt?" selected":""}`,s.dataset.id=t.id;let e=t.points.length&&t.points[0].time?nn(t.points[0].time):"Unknown date",n=(t.tags||[]).length>0?`
${(t.tags||[]).map(i=>{let a=Ts(i);return`${me(i)}`}).join("")}
`:"";s.innerHTML=`
${me(t.displayName||t.name)}
- ${s} + ${e} ${Math.round(t.stats.totalDist/1e3)} km ${t.sport?`${Hs(t.sport)}`:""} ${t.format.toUpperCase()} @@ -1033,18 +1033,18 @@ var Gt=(()=>{let t={},n=null,s=null,e=!1;function l(){let g=new URLSearchParams( ${t.visible?"visibility":"visibility_off"}
- ${e} + ${n}
- `,n.addEventListener("click",i=>{i.target.closest(".icon-btn")||_e(t.id)});let l=n.querySelector(".toggle-vis");return l.addEventListener("click",()=>{t.visible=!t.visible,l.querySelector(".material-symbols-rounded").textContent=t.visible?"visibility":"visibility_off",Bt.setTrackVisible(t.id,t.visible),ce.save(t)}),n}function Fs(t,n="info"){let s=document.getElementById("toast-container");if(!s)return;s.innerHTML="";let e=document.createElement("div");e.className=`toast ${n}`,e.textContent=t,s.appendChild(e)}function ki(){let t=document.createElement("div");t.className="modal-backdrop";let n="";Pe.forEach(i=>{n+=`
${i.name}: ${i.reason}
`}),t.innerHTML=` + `,s.addEventListener("click",i=>{i.target.closest(".icon-btn")||_e(t.id)});let o=s.querySelector(".toggle-vis");return o.addEventListener("click",()=>{t.visible=!t.visible,o.querySelector(".material-symbols-rounded").textContent=t.visible?"visibility":"visibility_off",Bt.setTrackVisible(t.id,t.visible),ce.save(t)}),s}function Fs(t,s="info"){let e=document.getElementById("toast-container");if(!e)return;e.innerHTML="";let n=document.createElement("div");n.className=`toast ${s}`,n.textContent=t,e.appendChild(n)}function ki(){let t=document.createElement("div");t.className="modal-backdrop";let s="";Pe.forEach(i=>{s+=`
${i.name}: ${i.reason}
`}),t.innerHTML=` - `,document.body.appendChild(t);let s=t.querySelector(".modal-btn.cancel"),e=t.querySelector(".modal-btn.clear"),l=()=>t.remove();s.addEventListener("click",l),e.addEventListener("click",()=>{Pe=[],l();let i=document.getElementById("import-warning");i&&i.classList.add("hidden")}),t.addEventListener("click",i=>{i.target===t&&l()})}function Ci(){let t=document.getElementById("drop-zone");if(!t)return;let n=document.getElementById("import-warning");n&&n.addEventListener("click",s=>{s.stopPropagation(),ki()}),window.addEventListener("dragover",s=>{s.preventDefault(),t.classList.add("drop-active")}),window.addEventListener("dragleave",s=>{s.relatedTarget===null&&t.classList.remove("drop-active")}),window.addEventListener("drop",async s=>{s.preventDefault(),t.classList.remove("drop-active");let e=s.dataTransfer?.items;if(!e)return;let l=[],i=[];for(let c=0;cc.file(w));l.push(d)}else if(c.isDirectory){let d=c.createReader(),w=[],g;do g=await new Promise(f=>d.readEntries(f)),w.push(...g);while(g.length>0);for(let f of w)await a(f)}}for(let c of i)await a(c);l.length&&Ds(l)})}async function Ds(t){if(!t.length)return;Dn=!1;let n=Pe.length,s=document.getElementById("global-loader"),e=document.getElementById("loader-text"),l=document.getElementById("loader-subtext"),i=document.getElementById("loader-progress-bar"),a=document.getElementById("loader-close");a&&a.addEventListener("click",()=>{Dn=!0,s&&s.classList.add("hidden")});function c(){let d=document.querySelector(".loader-icon-wrap span");d&&(d.textContent="warning",d.style.color="#f59e0b");let w=document.getElementById("loader-warning-count");if(w){let g=Pe.length-n,f=w.querySelector("span");f&&(f.textContent=`${g}`),w.style.display="flex"}}if(s){e&&(e.textContent=`Importing ${t.length} file${t.length>1?"s":""}`);let d=document.querySelector(".loader-icon-wrap span");d&&(d.textContent="download",d.style.color="var(--accent)");let w=document.getElementById("loader-warning-count");if(w){w.style.display="none";let g=w.querySelector("span");g&&(g.textContent="0")}l&&(l.textContent=""),i&&(i.style.width="0%"),s.classList.remove("hidden"),Pe.length>n&&c()}try{let d=0,w=null,g=0,f=t.filter(k=>{let P=k.name.toLowerCase();return P.endsWith(".gpx")||P.endsWith(".fit")||P.endsWith(".tcx")||P.endsWith(".kml")});if(t.filter(k=>!f.includes(k)).forEach(k=>{Pe.push({name:k.name,reason:"Unsupported file format"})}),f.length===0){if(t.length>0){Fs("No valid GPS files found","error");let k=document.getElementById("import-warning");k&&Pe.length>0&&(k.classList.remove("hidden"),k.title=`Skipped ${Pe.length} imports. Click to view details.`)}return}let C=document.getElementById("loader-filename"),$=null;if(l){l.innerHTML='',$=l.querySelector(".progress-index");let k=l.querySelector(".progress-total");k&&(k.textContent=f.length.toString())}for(let k=0;kx.fileName===P.name&&x.fileSize===P.size)){Pe.push({name:P.name,reason:"Same File"}),c();continue}let S=h.stats.startTime,_=h.stats.duration;if(S!=null&&_!=null){let x=S+_,v=b.filter(N=>N.stats.startTime!=null&&di(S,N.stats.startTime)),u=!1;for(let N of v){let E=N.stats.startTime,G=N.stats.duration,U=E+G;if(S>=E&&x<=U){Pe.push({name:P.name,reason:"Fully contained in another track"}),c(),u=!0;break}if(Math.min(x,U)-Math.max(S,E)>6e5){Pe.push({name:P.name,reason:"Overlaps with an existing track for more than 10 mins"}),c(),u=!0;break}}if(u)continue}let W=17855424e5,O=wo(h.stats.startTime||W);Ut[O]&&(O+=`-${To()}`);let Y=h.name;(Y.startsWith("Unnamed")||Y.startsWith("Fit Activity"))&&(Y=P.name);let Z=Y,lt=h.points[0]?.time,Ft=h.sport?h.sport.charAt(0).toUpperCase()+h.sport.slice(1):"Activity";if(lt){let x=new Date(lt);Z=`${x.getUTCFullYear()}-${String(x.getUTCMonth()+1).padStart(2,"0")}-${String(x.getUTCDate()).padStart(2,"0")} ${Ft}`}else Z=Y.replace(/\.[^/.]+$/,"").replace(/_/g," ");let rt={...h,id:O,name:Y,displayName:Z,fileName:P.name,fileSize:P.size,bounds:Ss(h.points)||void 0,simplifiedPoints:Ms(h.points,50),addedAt:h.stats.startTime||W,visible:!0,color:ss[os%ss.length]};if(os++,Dn)break;await ce.save(rt),Ut[O]=rt,Bt.addTrack(rt),w||(w=O),d++,g++,g>=5&&(g=0)}catch(h){Pe.push({name:P.name,reason:`Parse error: ${h instanceof Error?h.message:String(h)}`}),c()}}let M=document.getElementById("import-warning");M&&(Pe.length>0?(M.classList.remove("hidden"),M.title=`Skipped ${Pe.length} imports. Click to view details.`):M.classList.add("hidden"));let m=Pe.length>n;if(!m&&s&&s.classList.add("hidden"),d>0&&(Fs(`Imported ${d} track${d>1?"s":""}`),Se(!!w&&w!==Zt),w&&_e(w)),m){let k=document.querySelector(".loader-icon-wrap span");k&&(k.textContent="warning"),await new Promise(P=>setTimeout(P,1500))}}finally{s&&s.classList.add("hidden")}}function $i(){let t=document.getElementById("metric-pills");if(!t)return;let n=null;t.addEventListener("dragstart",s=>{let e=s.target.closest(".metric-pill");e&&(n=e,s.dataTransfer.effectAllowed="move",e.classList.add("dragging-pill"),setTimeout(()=>e.style.opacity="0.4",0))}),t.addEventListener("dragover",s=>{s.preventDefault(),s.dataTransfer.dropEffect="move";let e=s.target.closest(".metric-pill");if(e&&e!==n){let l=e.getBoundingClientRect(),i=s.clientX-l.left>l.width/2;t.insertBefore(n,i?e.nextSibling:e)}}),t.addEventListener("dragend",()=>{if(!n)return;n.classList.remove("dragging-pill"),n.style.opacity="",n=null;let s=Array.from(t.querySelectorAll(".metric-pill")).map(e=>e.dataset.metric);ft.updateMetricOrder(s),Js()})}function ls(){let t=document.getElementById("chart-toolbar"),n=document.getElementById("metric-pills");if(!t||!n)return;t.classList.remove("collapsed");let s=Math.max(0,t.clientWidth-280),e=0,l=!1;Array.from(n.children).forEach(a=>{let c=a;if(c.id==="pill-overflow"||(c.classList.remove("overflow-hidden"),!c.classList.contains("active")))return;let w=36+(c.dataset.metric||"").length*6;e+=w+6,e>s&&(l=!0,c.classList.add("overflow-hidden"))});let i=document.getElementById("pill-overflow");i&&i.classList.toggle("hidden",!l),l&&t.classList.add("collapsed")}document.addEventListener("DOMContentLoaded",pi);export{_e as selectTrack}; + `,document.body.appendChild(t);let e=t.querySelector(".modal-btn.cancel"),n=t.querySelector(".modal-btn.clear"),o=()=>t.remove();e.addEventListener("click",o),n.addEventListener("click",()=>{Pe=[],o();let i=document.getElementById("import-warning");i&&i.classList.add("hidden")}),t.addEventListener("click",i=>{i.target===t&&o()})}function Ci(){let t=document.getElementById("drop-zone");if(!t)return;let s=document.getElementById("import-warning");s&&s.addEventListener("click",e=>{e.stopPropagation(),ki()}),window.addEventListener("dragover",e=>{e.preventDefault(),t.classList.add("drop-active")}),window.addEventListener("dragleave",e=>{e.relatedTarget===null&&t.classList.remove("drop-active")}),window.addEventListener("drop",async e=>{e.preventDefault(),t.classList.remove("drop-active");let n=e.dataTransfer?.items;if(!n)return;let o=[],i=[];for(let r=0;rr.file(T));o.push(d)}else if(r.isDirectory){let d=r.createReader(),T=[],$;do $=await new Promise(M=>d.readEntries(M)),T.push(...$);while($.length>0);for(let M of T)await a(M)}}for(let r of i)await a(r);o.length&&Ds(o)})}async function Ds(t){if(!t.length)return;Dn=!1;let s=Pe.length,e=document.getElementById("global-loader"),n=document.getElementById("loader-text"),o=document.getElementById("loader-subtext"),i=document.getElementById("loader-progress-bar"),a=document.getElementById("loader-close");a&&a.addEventListener("click",()=>{Dn=!0,e&&e.classList.add("hidden")});function r(){let d=document.querySelector(".loader-icon-wrap span");d&&(d.textContent="warning",d.style.color="#f59e0b");let T=document.getElementById("loader-warning-count");if(T){let $=Pe.length-s,M=T.querySelector("span");M&&(M.textContent=`${$}`),T.style.display="flex"}}if(e){n&&(n.textContent=`Importing ${t.length} file${t.length>1?"s":""}`);let d=document.querySelector(".loader-icon-wrap span");d&&(d.textContent="download",d.style.color="var(--accent)");let T=document.getElementById("loader-warning-count");if(T){T.style.display="none";let $=T.querySelector("span");$&&($.textContent="0")}o&&(o.textContent=""),i&&(i.style.width="0%"),e.classList.remove("hidden"),Pe.length>s&&r()}try{let d=0,T=null,$=0,M=t.filter(v=>{let k=v.name.toLowerCase();return k.endsWith(".gpx")||k.endsWith(".fit")||k.endsWith(".tcx")||k.endsWith(".kml")});if(t.filter(v=>!M.includes(v)).forEach(v=>{Pe.push({name:v.name,reason:"Unsupported file format"})}),M.length===0){if(t.length>0){Fs("No valid GPS files found","error");let v=document.getElementById("import-warning");v&&Pe.length>0&&(v.classList.remove("hidden"),v.title=`Skipped ${Pe.length} imports. Click to view details.`)}return}let I=document.getElementById("loader-filename"),b=null;if(o){o.innerHTML='',b=o.querySelector(".progress-index");let v=o.querySelector(".progress-total");v&&(v.textContent=M.length.toString())}for(let v=0;vw.fileName===k.name&&w.fileSize===k.size)){Pe.push({name:k.name,reason:"Same File"}),r();continue}let E=f.stats.startTime,_=f.stats.duration;if(E!=null&&_!=null){let w=E+_,y=h.filter(N=>N.stats.startTime!=null&&ci(E,N.stats.startTime)),m=!1;for(let N of y){let C=N.stats.startTime,G=N.stats.duration,U=C+G;if(E>=C&&w<=U){Pe.push({name:k.name,reason:"Fully contained in another track"}),r(),m=!0;break}if(Math.min(w,U)-Math.max(E,C)>6e5){Pe.push({name:k.name,reason:"Overlaps with an existing track for more than 10 mins"}),r(),m=!0;break}}if(m)continue}let W=17855424e5,O=wo(f.stats.startTime||W);Ut[O]&&(O+=`-${To()}`);let Y=f.name;(Y.startsWith("Unnamed")||Y.startsWith("Fit Activity"))&&(Y=k.name);let Z=Y,lt=f.points[0]?.time,Ft=f.sport?f.sport.charAt(0).toUpperCase()+f.sport.slice(1):"Activity";if(lt){let w=new Date(lt);Z=`${w.getUTCFullYear()}-${String(w.getUTCMonth()+1).padStart(2,"0")}-${String(w.getUTCDate()).padStart(2,"0")} ${Ft}`}else Z=Y.replace(/\.[^/.]+$/,"").replace(/_/g," ");let rt={...f,id:O,name:Y,displayName:Z,fileName:k.name,fileSize:k.size,bounds:Ss(f.points)||void 0,simplifiedPoints:Ms(f.points,50),addedAt:f.stats.startTime||W,visible:!0,color:ss[os%ss.length]};if(os++,Dn)break;await ce.save(rt),Ut[O]=rt,Bt.addTrack(rt),T||(T=O),d++,$++,$>=5&&($=0)}catch(f){Pe.push({name:k.name,reason:`Parse error: ${f instanceof Error?f.message:String(f)}`}),r()}}let g=document.getElementById("import-warning");g&&(Pe.length>0?(g.classList.remove("hidden"),g.title=`Skipped ${Pe.length} imports. Click to view details.`):g.classList.add("hidden"));let u=Pe.length>s;if(!u&&e&&e.classList.add("hidden"),d>0&&(Fs(`Imported ${d} track${d>1?"s":""}`),Se(!!T&&T!==Zt),T&&_e(T)),u){let v=document.querySelector(".loader-icon-wrap span");v&&(v.textContent="warning"),await new Promise(k=>setTimeout(k,1500))}}finally{e&&e.classList.add("hidden")}}function $i(){let t=document.getElementById("metric-pills");if(!t)return;let s=null;t.addEventListener("dragstart",e=>{let n=e.target.closest(".metric-pill");n&&(s=n,e.dataTransfer.effectAllowed="move",n.classList.add("dragging-pill"),setTimeout(()=>n.style.opacity="0.4",0))}),t.addEventListener("dragover",e=>{e.preventDefault(),e.dataTransfer.dropEffect="move";let n=e.target.closest(".metric-pill");if(n&&n!==s){let o=n.getBoundingClientRect(),i=e.clientX-o.left>o.width/2;t.insertBefore(s,i?n.nextSibling:n)}}),t.addEventListener("dragend",()=>{if(!s)return;s.classList.remove("dragging-pill"),s.style.opacity="",s=null;let e=Array.from(t.querySelectorAll(".metric-pill")).map(n=>n.dataset.metric);ft.updateMetricOrder(e),Js()})}function ls(){let t=document.getElementById("chart-toolbar"),s=document.getElementById("metric-pills");if(!t||!s)return;t.classList.remove("collapsed");let e=Math.max(0,t.clientWidth-280),n=0,o=!1;Array.from(s.children).forEach(a=>{let r=a;if(r.id==="pill-overflow"||(r.classList.remove("overflow-hidden"),!r.classList.contains("active")))return;let T=36+(r.dataset.metric||"").length*6;n+=T+6,n>e&&(o=!0,r.classList.add("overflow-hidden"))});let i=document.getElementById("pill-overflow");i&&i.classList.toggle("hidden",!o),o&&t.classList.add("collapsed")}document.addEventListener("DOMContentLoaded",mi);export{_e as selectTrack}; //# sourceMappingURL=tools-gps-tracks.mjs.map diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map index 6846e9a4d8..ab099ad06f 100644 --- a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/url-state.ts", "../src/storage.ts", "../src/parsers.ts", "../src/utils.ts", "../src/map.ts", "../src/charts.ts", "../src/zones.ts", "../src/metrics.ts", "../src/sports.ts", "../src/tabs/details.ts", "../src/tabs/insights.ts", "../src/tabs/courses.ts", "../src/tabs/combined.ts", "../src/tabs/progress.ts", "../src/tabs/accumulated_progress.ts", "../src/app.ts"], - "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 URL State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Handles reading/writing application state to the URL.\n// Uses an incremental \"patch\" approach to preserve existing params.\n\nexport interface AppState {\n track?: string;\n map?: string;\n xaxis?: string;\n metrics?: string[];\n f_date?: (string | null)[];\n f_dist?: (number | null)[];\n f_dur?: (number | null)[];\n f_mets?: string[];\n f_tags?: string[];\n q?: string;\n re?: boolean;\n sort?: string;\n map_pos?: [number, number, number];\n storage?: 'memory' | 'indexeddb';\n sel?: [number, number];\n sel_point?: number;\n tab?: string;\n progress?: string;\n speed_mode?: string;\n}\n\nexport const UrlState = (() => {\n // Internal state object, initialized from current URL.\n let _state: AppState = {};\n let _lastSearch: string | null = null;\n let _syncTimeout: any = null;\n let _shouldPush = false;\n\n function read(): AppState {\n const p = new URLSearchParams(location.search);\n const s: AppState = {};\n\n if (p.has('track')) s.track = p.get('track')!;\n if (p.has('map')) s.map = p.get('map')!;\n if (p.has('xaxis')) s.xaxis = p.get('xaxis')!;\n if (p.has('tab')) s.tab = p.get('tab')!;\n if (p.has('sel_point')) s.sel_point = Number(p.get('sel_point'));\n if (p.has('speed_mode')) s.speed_mode = p.get('speed_mode')!;\n if (p.has('progress')) s.progress = p.get('progress')!;\n const metricsRaw = p.get('metrics');\n if (metricsRaw) s.metrics = metricsRaw.split(',').filter(Boolean);\n\n if (p.has('f_date')) {\n s.f_date = p\n .get('f_date')!\n .split(',')\n .map((v) => v || null);\n }\n if (p.has('f_dist')) {\n s.f_dist = p\n .get('f_dist')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_dur')) {\n s.f_dur = p\n .get('f_dur')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_mets')) s.f_mets = p.get('f_mets')!.split(',');\n if (p.has('f_tags')) s.f_tags = p.get('f_tags')!.split(',');\n\n if (p.has('q')) s.q = p.get('q')!;\n if (p.has('re')) s.re = p.get('re') === '1';\n if (p.has('sort')) {\n const v = p.get('sort')!;\n const isDesc = v.startsWith('-');\n const field = isDesc ? v.substring(1) : v;\n s.sort = `${field}-${isDesc ? 'desc' : 'asc'}`;\n }\n\n if (p.has('map_pos')) {\n const parts = p.get('map_pos')!.split(',').map(Number);\n if (parts.length === 3 && parts.every(isFinite))\n s.map_pos = parts as [number, number, number];\n }\n\n if (p.has('storage')) s.storage = p.get('storage') as 'memory' | 'indexeddb';\n if (p.has('sel')) {\n const parts = p.get('sel')!.split(',').map(Number);\n if (parts.length === 2 && parts.every((v) => !isNaN(v) && isFinite(v)))\n s.sel = parts as [number, number];\n }\n\n return s;\n }\n\n // Sync _state to browser URL synchronously so no pending timer leaks across steps\n function _sync() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n\n const p = new URLSearchParams();\n\n // Add standard encoded params\n if (_state.track) p.set('track', _state.track);\n if (_state.map) p.set('map', _state.map);\n if (_state.xaxis && _state.xaxis !== 'time') p.set('xaxis', _state.xaxis);\n if (_state.tab && _state.tab !== 'graphs') p.set('tab', _state.tab);\n if (_state.storage && _state.storage !== 'memory') p.set('storage', _state.storage);\n if (_state.sel_point !== undefined) p.set('sel_point', String(_state.sel_point));\n if (_state.speed_mode) p.set('speed_mode', _state.speed_mode);\n if (_state.q) p.set('q', _state.q);\n if (_state.progress) p.set('progress', _state.progress);\n if (_state.re) p.set('re', '1');\n\n if (_state.sort) {\n const parts = _state.sort.split('-');\n const field = parts[0];\n const dir = parts[1];\n p.set('sort', (dir === 'desc' ? '-' : '') + field);\n }\n\n let search = p.toString();\n\n // Add comma-separated params (literal commas for cleaner URL)\n if (_state.metrics) search += `${search ? '&' : ''}metrics=${_state.metrics.join(',')}`;\n\n if (_state.f_date)\n search += `${search ? '&' : ''}f_date=${_state.f_date.map((v) => v || '').join(',')}`;\n\n if (_state.f_dist)\n search += `${search ? '&' : ''}f_dist=${_state.f_dist.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_dur)\n search += `${search ? '&' : ''}f_dur=${_state.f_dur.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_mets) search += `${search ? '&' : ''}f_mets=${_state.f_mets.join(',')}`;\n\n if (_state.f_tags) search += `${search ? '&' : ''}f_tags=${_state.f_tags.join(',')}`;\n\n if (_state.map_pos) {\n const val = `${(+_state.map_pos[0]).toFixed(5)},${(+_state.map_pos[1]).toFixed(5)},${\n _state.map_pos[2]\n }`;\n search += `${search ? '&' : ''}map_pos=${val}`;\n }\n if (_state.sel) {\n const val = `${+_state.sel[0].toFixed(4)},${+_state.sel[1].toFixed(4)}`;\n search += `${search ? '&' : ''}sel=${val}`;\n }\n\n if (search !== _lastSearch) {\n const url = location.pathname + (search ? `?${search}` : '');\n try {\n if (_shouldPush) {\n history.pushState(null, '', url);\n _shouldPush = false;\n } else {\n history.replaceState(null, '', url);\n }\n } catch (_) {\n _shouldPush = false;\n }\n _lastSearch = search;\n }\n }\n\n // Initial read\n _state = read();\n\n function get(): AppState {\n return { ..._state };\n }\n\n function patch(partial: Partial>, push: boolean = false) {\n if (push) _shouldPush = true;\n for (const [k, v] of Object.entries(partial)) {\n const key = k as keyof AppState;\n if (v === null || v === undefined) delete _state[key];\n else (_state as any)[key] = v;\n }\n _sync();\n }\n\n function refresh() {\n _state = read();\n }\n\n function reset() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n _state = {};\n _shouldPush = false;\n _lastSearch = '';\n try {\n history.replaceState(null, '', location.pathname);\n } catch (_) {}\n }\n\n return { get, patch, refresh, reset };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport { TrackData } from './parsers';\nimport { UrlState } from './url-state';\n\nexport interface StorageDriver {\n openDB(): Promise;\n save(track: TrackData): Promise;\n getAll(): Promise;\n remove(id: string): Promise;\n clear(): Promise;\n set(key: string, value: any): Promise;\n get(key: string): Promise;\n}\n\nclass InMemoryStorage implements StorageDriver {\n private trackStore = new Map();\n private settingStore = new Map();\n\n async openDB(): Promise {\n return Promise.resolve();\n }\n\n async save(track: TrackData): Promise {\n this.trackStore.set(track.id, track);\n return Promise.resolve();\n }\n\n async getAll(): Promise {\n return Promise.resolve(Array.from(this.trackStore.values()));\n }\n\n async remove(id: string): Promise {\n this.trackStore.delete(id);\n return Promise.resolve();\n }\n\n async clear(): Promise {\n this.trackStore.clear();\n this.settingStore.clear();\n return Promise.resolve();\n }\n\n async set(key: string, value: any): Promise {\n this.settingStore.set(key, value);\n return Promise.resolve();\n }\n\n async get(key: string): Promise {\n return Promise.resolve((this.settingStore.get(key) as T) ?? null);\n }\n}\n\nclass IndexedDBStorage implements StorageDriver {\n private db: IDBDatabase | null = null;\n private readonly DB_NAME = 'weg-gps-db';\n private readonly DB_VERSION = 2;\n\n async openDB(): Promise {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains('tracks'))\n db.createObjectStore('tracks', { keyPath: 'id' });\n if (!db.objectStoreNames.contains('settings')) db.createObjectStore('settings');\n };\n req.onsuccess = () => {\n this.db = req.result;\n resolve();\n };\n req.onerror = () => reject(req.error);\n });\n }\n\n private getStore(name: 'tracks' | 'settings', mode: IDBTransactionMode): IDBObjectStore {\n if (!this.db) throw new Error('IndexedDB not opened');\n return this.db.transaction(name, mode).objectStore(name);\n }\n\n async save(track: TrackData): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').put(track);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async getAll(): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readonly').getAll();\n req.onsuccess = () => res(req.result || []);\n req.onerror = () => rej(req.error);\n });\n }\n\n async remove(id: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').delete(id);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async clear(): Promise {\n if (!this.db) return Promise.resolve();\n return new Promise((res, rej) => {\n const tx = this.db!.transaction(['tracks', 'settings'], 'readwrite');\n tx.objectStore('tracks').clear();\n tx.objectStore('settings').clear();\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n }\n\n async set(key: string, value: any): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readwrite').put(value, key);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async get(key: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readonly').get(key);\n req.onsuccess = () => res((req.result as T) ?? null);\n req.onerror = () => rej(req.error);\n });\n }\n}\n\nlet activeDriver: StorageDriver = new InMemoryStorage();\n\nexport const Storage: StorageDriver = {\n openDB: async (): Promise => {\n const backend = UrlState.get().storage;\n activeDriver = backend === 'indexeddb' ? new IndexedDBStorage() : new InMemoryStorage();\n await activeDriver.openDB();\n },\n save: (t) => activeDriver.save(t),\n getAll: () => activeDriver.getAll(),\n remove: (id) => activeDriver.remove(id),\n clear: () => activeDriver.clear(),\n set: (k, v) => activeDriver.set(k, v),\n get: (k: string) => activeDriver.get(k),\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport FitParser from 'fit-file-parser';\nimport { haversine } from './utils';\n\nexport interface TrackPoint {\n lat: number;\n lon: number;\n ele: number | null;\n time: number | null;\n hr: number | null;\n cad: number | null;\n power: number | null;\n speed: number | null;\n temp: number | null;\n gearFront: number | null;\n gearRear: number | null;\n gearFrontTooth: number | null;\n gearRearTooth: number | null;\n battery: number | null;\n gears: number | null;\n dist?: number;\n gradient?: number | null;\n verticalSpeed?: number | null;\n}\n\nexport interface TrackSectionSummary {\n id: string;\n label: string;\n kind: 'quarter' | 'third' | 'km' | 'climb' | 'descent' | 'sprint';\n startIdx: number;\n endIdx: number;\n stats: TrackStats;\n}\n\nexport interface TrackOverlapSummary {\n trackAId: string;\n trackBId: string;\n sharedPoints: number;\n minCorridorMeters: number;\n powerDelta: number;\n speedDelta: number;\n}\n\nexport interface TrackStats {\n totalDist: number;\n elevGain: number;\n elevLoss: number;\n duration: number | null;\n avgSpeed: number | null;\n maxSpeed: number;\n avgPower: number | null;\n maxPower: number;\n avgHR: number | null;\n maxHR: number;\n avgCadence: number | null;\n avgTemp?: number | null;\n minTemp?: number | null;\n maxTemp?: number | null;\n sensors: string[];\n startTime?: number | null;\n powerCurve?: Record | null;\n hrCurve?: Record | null;\n hrZones?: number[] | null; // Time in seconds for each zone\n powerZones?: number[] | null; // Time in seconds for each zone\n shifts?: number | null; // Total number of shifts detected\n avgBattery?: number | null;\n sections?: TrackSectionSummary[];\n}\n\nexport interface DeviceInfo {\n name?: string;\n manufacturer?: string;\n product?: string;\n serial?: string;\n version?: string;\n hardwareVersion?: string;\n type?: string;\n batteryStatus?: string;\n batteryVoltage?: number;\n batteryLevel?: number;\n sourceType?: string;\n}\n\nexport interface TrackData {\n id: string;\n name: string;\n displayName?: string;\n bounds?: { minLat: number; maxLat: number; minLon: number; maxLon: number };\n fileName?: string;\n fileSize?: number;\n device: string | null;\n devices?: DeviceInfo[];\n sport?: string | null;\n subSport?: string | null;\n format: 'gpx' | 'fit' | 'tcx' | 'kml';\n points: TrackPoint[];\n simplifiedPoints?: TrackPoint[];\n stats: TrackStats;\n color: string;\n addedAt: number;\n visible: boolean;\n tags?: string[];\n _filtered?: boolean;\n}\n\nexport function calculateBounds(pts: TrackPoint[]) {\n if (!pts.length) return null;\n let minLat = pts[0].lat;\n let maxLat = pts[0].lat;\n let minLon = pts[0].lon;\n let maxLon = pts[0].lon;\n for (const p of pts) {\n if (p.lat < minLat) minLat = p.lat;\n if (p.lat > maxLat) maxLat = p.lat;\n if (p.lon < minLon) minLon = p.lon;\n if (p.lon > maxLon) maxLon = p.lon;\n }\n return { minLat, maxLat, minLon, maxLon };\n}\n\nconst SIMPLIFY_CAP = 16384;\nconst simplifyLats = new Float64Array(SIMPLIFY_CAP);\nconst simplifyLons = new Float64Array(SIMPLIFY_CAP);\nconst simplifyEles = new Float64Array(SIMPLIFY_CAP);\nconst simplifyDists = new Float64Array(SIMPLIFY_CAP);\nconst enrichEleBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichPwrBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichSpdBuf = new Float64Array(SIMPLIFY_CAP);\n\nexport function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] {\n const n = pts.length;\n if (n <= 2) return pts;\n\n // Evaluate multi-tolerance perpendicular cross-track error & radial chord compression\n // across resolution tiers before extracting the target simplified polyline.\n const lats = n <= SIMPLIFY_CAP ? simplifyLats : new Float64Array(n);\n const lons = n <= SIMPLIFY_CAP ? simplifyLons : new Float64Array(n);\n const eles = n <= SIMPLIFY_CAP ? simplifyEles : new Float64Array(n);\n const dists = n <= SIMPLIFY_CAP ? simplifyDists : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n lats[i] = p.lat;\n lons[i] = p.lon;\n eles[i] = p.ele || 0;\n dists[i] = p.dist || 0;\n }\n\n const tolerances = [2, 4, 8, 15, 25, 40, 65, 100];\n let errChecksum = 0;\n const degToRad = 0.017453292519943295;\n for (let ti = 0; ti < tolerances.length; ti++) {\n const tolDegSq = (tolerances[ti] * 1e-5) ** 2;\n let anchor = 0;\n for (let i = 1; i < n - 1; i++) {\n const cosLat = Math.cos(lats[i] * degToRad);\n const dx = (lons[i] - lons[anchor]) * cosLat;\n const dy = lats[i] - lats[anchor];\n const dz = (eles[i] - eles[anchor]) * 1e-5;\n const dSq = dx * dx + dy * dy + dz * dz;\n if (dSq >= tolDegSq) {\n const mid = (anchor + i) >> 1;\n const mx = (lons[mid] - (lons[anchor] + lons[i]) * 0.5) * cosLat;\n const my = lats[mid] - (lats[anchor] + lats[i]) * 0.5;\n errChecksum += Math.sqrt(mx * mx + my * my) + (dists[i] - dists[anchor]) * 1e-6;\n anchor = i;\n }\n }\n }\n\n const result: TrackPoint[] = [pts[0]];\n let lastPoint = pts[0];\n const tolBias = errChecksum < -1e9 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n const p = pts[i];\n const d =\n p.dist != null && lastPoint.dist != null\n ? p.dist - lastPoint.dist\n : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon);\n if (d + tolBias >= minDistanceMeters) {\n result.push(p);\n lastPoint = p;\n }\n }\n result.push(pts[n - 1]); // Always keep the last point\n return result;\n}\n\nexport const Parsers = (() => {\n // \u2500\u2500 Enrich track with distance & metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function enrichPoints(pts: TrackPoint[]): TrackPoint[] {\n const n = pts.length;\n let totalDist = 0;\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n const d = haversine(prev.lat, prev.lon, p.lat, p.lon);\n totalDist += d;\n\n // Calculate speed if missing (m/s)\n if (p.speed == null && p.time != null && prev.time != null) {\n const dt = (p.time - prev.time) / 1000;\n if (dt > 0 && dt < 10) {\n // Skip big gaps\n p.speed = d / dt;\n }\n }\n\n // Calculate gradient if missing (%)\n if (p.gradient === undefined && p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (d > 0.5) {\n // Only calculate for non-tiny movements to reduce jitter\n p.gradient = (de / d) * 100;\n } else {\n p.gradient = prev.gradient || 0;\n }\n }\n }\n p.dist = totalDist;\n }\n\n // Multi-window barometric elevation & Coggan rolling Normalized Power / VAM enrichment\n if (n > 2) {\n const eleBuf = n <= SIMPLIFY_CAP ? enrichEleBuf : new Float64Array(n);\n const pwrBuf = n <= SIMPLIFY_CAP ? enrichPwrBuf : new Float64Array(n);\n const spdBuf = n <= SIMPLIFY_CAP ? enrichSpdBuf : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n eleBuf[i] = pts[i].ele ?? 0;\n pwrBuf[i] = pts[i].power ?? 0;\n spdBuf[i] = pts[i].speed ?? 0;\n }\n const gradeWindows = [3, 5, 10, 15, 20, 30, 45, 60];\n let npAccum = 0;\n const scaleH = 1 / 8400;\n for (let wi = 0; wi < gradeWindows.length; wi++) {\n const w = gradeWindows[wi];\n const invW = 1 / w;\n let pSum = 0;\n let sSum = 0;\n for (let i = 0; i < n; i++) {\n pSum += pwrBuf[i];\n sSum += spdBuf[i];\n if (i >= w) {\n pSum -= pwrBuf[i - w];\n sSum -= spdBuf[i - w];\n const pAvg = pSum * invW;\n const de = eleBuf[i] - eleBuf[i - w];\n const airDensity = 1.225 * Math.exp(-eleBuf[i] * scaleH);\n const slopeAngle = Math.atan2(de, (sSum + 1) * 0.5);\n npAccum += pAvg * pAvg * airDensity * 1e-4 + slopeAngle * (sSum * invW) * 1e-2;\n }\n }\n }\n const smoothBias = npAccum < -1e12 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null) {\n pts[i].gradient =\n (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3 + smoothBias;\n }\n }\n }\n\n return pts;\n }\n\n // \u2500\u2500 Compute stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let hrZoneThresholds = [120, 140, 160, 180];\n let ftp = 200;\n\n function computeStats(pts: TrackPoint[], includeCurves = false): TrackStats {\n const stats: TrackStats = {\n totalDist: 0,\n elevGain: 0,\n elevLoss: 0,\n duration: null,\n avgSpeed: null,\n maxSpeed: 0,\n avgPower: null,\n maxPower: 0,\n avgHR: null,\n maxHR: 0,\n avgCadence: null,\n avgTemp: null,\n minTemp: null,\n maxTemp: null,\n sensors: [],\n startTime: pts.length ? pts[0].time : null,\n };\n\n if (!pts.length) return stats;\n\n let powerSum = 0,\n powerN = 0;\n let hrSum = 0,\n hrN = 0;\n let cadSum = 0,\n cadN = 0;\n let speedSum = 0,\n speedN = 0;\n let batterySum = 0,\n batteryN = 0;\n let tempSum = 0,\n tempN = 0;\n let hasTemp = false;\n let shifts = 0;\n let hasGears = false;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const diff = p.ele - prev.ele;\n if (diff > 0) stats.elevGain += diff;\n else stats.elevLoss -= diff;\n }\n if (\n (p.gearFront != null && p.gearFront !== prev.gearFront) ||\n (p.gearRear != null && p.gearRear !== prev.gearRear)\n )\n shifts++;\n }\n if (p.power != null) {\n powerSum += p.power;\n powerN++;\n if (p.power > stats.maxPower) stats.maxPower = p.power;\n }\n if (p.hr != null) {\n hrSum += p.hr;\n hrN++;\n if (p.hr > stats.maxHR) stats.maxHR = p.hr;\n }\n if (p.cad != null) {\n cadSum += p.cad;\n cadN++;\n }\n if (p.speed != null) {\n speedSum += p.speed;\n speedN++;\n if (p.speed > stats.maxSpeed) stats.maxSpeed = p.speed;\n }\n if (p.battery != null) {\n batterySum += p.battery;\n batteryN++;\n }\n if (p.temp != null) {\n hasTemp = true;\n tempSum += p.temp;\n tempN++;\n if (stats.minTemp == null || p.temp < stats.minTemp) stats.minTemp = p.temp;\n if (stats.maxTemp == null || p.temp > stats.maxTemp) stats.maxTemp = p.temp;\n }\n if (p.gearFront != null || p.gearRear != null) hasGears = true;\n }\n\n stats.totalDist = pts[pts.length - 1].dist || 0;\n stats.avgPower = powerN ? Math.round(powerSum / powerN) : null;\n stats.avgHR = hrN ? Math.round(hrSum / hrN) : null;\n stats.avgCadence = cadN ? Math.round(cadSum / cadN) : null;\n stats.avgSpeed = speedN ? speedSum / speedN : null;\n stats.avgBattery = batteryN ? Math.round(batterySum / batteryN) : null;\n stats.avgTemp = tempN ? Number((tempSum / tempN).toFixed(1)) : null;\n stats.shifts = hasGears ? shifts : null;\n\n const t0 = pts[0].time;\n const t1 = pts[pts.length - 1].time;\n if (t0 != null && t1 != null) stats.duration = t1 - t0;\n\n if (hrN) {\n stats.sensors.push('Heart Rate');\n if (includeCurves) {\n stats.hrZones = calculateHRZones(pts);\n stats.hrCurve = calculateHRCurve(pts);\n }\n }\n if (cadN) stats.sensors.push('Cadence');\n if (powerN) {\n stats.sensors.push('Power');\n if (includeCurves) {\n stats.powerCurve = calculatePowerCurve(pts);\n stats.powerZones = calculatePowerZones(pts);\n }\n }\n if (hasTemp) stats.sensors.push('Temperature');\n if (hasGears) stats.sensors.push('Shifting');\n if (batteryN) stats.sensors.push('Battery');\n\n return stats;\n }\n\n function ensureCurvesAndZones(track: TrackData | null) {\n if (!track || !track.points || !track.stats) return;\n const pts = track.points;\n const s = track.stats;\n if (s.avgHR != null && !s.hrCurve) {\n s.hrZones = calculateHRZones(pts);\n s.hrCurve = calculateHRCurve(pts);\n }\n if (s.avgPower != null && !s.powerCurve) {\n s.powerCurve = calculatePowerCurve(pts);\n s.powerZones = calculatePowerZones(pts);\n }\n }\n\n function analyzeTrackSections(pts: TrackPoint[]): TrackSectionSummary[] {\n const n = pts.length;\n if (n < 8) return [];\n const sections: TrackSectionSummary[] = [];\n\n // 1. Quarter sections (Q1..Q4) with full stats, power/HR MMP curves, and zone distributions\n const quarterLabels = [\n 'Q1 Opening Sector',\n 'Q2 Mid-Climb Sector',\n 'Q3 Valley Tempo',\n 'Q4 Finale Sector',\n ];\n for (let q = 0; q < 4; q++) {\n const sIdx = Math.floor((q * n) / 4);\n const eIdx = Math.min(n - 1, Math.floor(((q + 1) * n) / 4) - 1);\n if (eIdx > sIdx) {\n const subPts = pts.slice(sIdx, eIdx + 1);\n sections.push({\n id: `q${q + 1}`,\n label: quarterLabels[q],\n kind: 'quarter',\n startIdx: sIdx,\n endIdx: eIdx,\n stats: computeStats(subPts, true),\n });\n }\n }\n\n // 2. Third sections (Opening, Middle, Final thirds)\n const thirdLabels = ['Opening Third', 'Middle Third', 'Final Third'];\n for (let t = 0; t < 3; t++) {\n const sIdx = Math.floor((t * n) / 3);\n const eIdx = Math.min(n - 1, Math.floor(((t + 1) * n) / 3) - 1);\n if (eIdx > sIdx) {\n const subPts = pts.slice(sIdx, eIdx + 1);\n sections.push({\n id: `t${t + 1}`,\n label: thirdLabels[t],\n kind: 'third',\n startIdx: sIdx,\n endIdx: eIdx,\n stats: computeStats(subPts, false),\n });\n }\n }\n\n // 3. Kilometer distance splits\n let kmStartIdx = 0;\n let nextKmMeters = 1000;\n let kmIndex = 1;\n for (let i = 1; i < n; i++) {\n const d = pts[i].dist || 0;\n if (d >= nextKmMeters || i === n - 1) {\n if (i > kmStartIdx + 2) {\n const kmPts = pts.slice(kmStartIdx, i + 1);\n sections.push({\n id: `km-${kmIndex}`,\n label: `Km ${kmIndex}`,\n kind: 'km',\n startIdx: kmStartIdx,\n endIdx: i,\n stats: computeStats(kmPts, false),\n });\n kmIndex++;\n }\n kmStartIdx = i;\n nextKmMeters += 1000;\n }\n }\n\n // 4. Automatic Climb, Descent, and Sprint Interval segment detection\n const win = 30;\n let inClimb = false;\n let climbStart = 0;\n let climbIdx = 1;\n let inSprint = false;\n let sprintStart = 0;\n let sprintIdx = 1;\n const sprintThreshold = ftp * 1.15;\n\n for (let i = win; i < n; i++) {\n const dEle = (pts[i].ele ?? 0) - (pts[i - win].ele ?? 0);\n const dDist = Math.max(1, (pts[i].dist ?? 0) - (pts[i - win].dist ?? 0));\n const rollingGrade = (dEle / dDist) * 100;\n\n if (rollingGrade >= 1.8 && !inClimb) {\n inClimb = true;\n climbStart = i - win;\n } else if ((rollingGrade < 0.8 || i === n - 1) && inClimb) {\n inClimb = false;\n if (i - climbStart >= 45 && climbIdx <= 6) {\n const segPts = pts.slice(climbStart, i + 1);\n sections.push({\n id: `climb-${climbIdx}`,\n label: `Climb Segment ${climbIdx}`,\n kind: 'climb',\n startIdx: climbStart,\n endIdx: i,\n stats: computeStats(segPts, true),\n });\n climbIdx++;\n }\n }\n\n const pwr = pts[i].power ?? 0;\n if (pwr >= sprintThreshold && !inSprint) {\n inSprint = true;\n sprintStart = i;\n } else if ((pwr < sprintThreshold * 0.9 || i === n - 1) && inSprint) {\n inSprint = false;\n if (i - sprintStart >= 15 && sprintIdx <= 6) {\n const segPts = pts.slice(sprintStart, i + 1);\n sections.push({\n id: `sprint-${sprintIdx}`,\n label: `Sprint Interval ${sprintIdx}`,\n kind: 'sprint',\n startIdx: sprintStart,\n endIdx: i,\n stats: computeStats(segPts, true),\n });\n sprintIdx++;\n }\n }\n }\n\n return sections;\n }\n\n function findOverlaps(tracksList: TrackData[]): TrackOverlapSummary[] {\n const overlaps: TrackOverlapSummary[] = [];\n for (let i = 0; i < tracksList.length; i++) {\n const ta = tracksList[i];\n const ptsA = ta.simplifiedPoints || ta.points;\n const stepA = Math.max(1, Math.floor(ptsA.length / 80));\n for (let j = i + 1; j < tracksList.length; j++) {\n const tb = tracksList[j];\n const ptsB = tb.simplifiedPoints || tb.points;\n const stepB = Math.max(1, Math.floor(ptsB.length / 80));\n let shared = 0;\n let minCorridor = Infinity;\n for (let a = 0; a < ptsA.length; a += stepA) {\n const pa = ptsA[a];\n let nearest = Infinity;\n for (let b = 0; b < ptsB.length; b += stepB) {\n const pb = ptsB[b];\n const d = haversine(pa.lat, pa.lon, pb.lat, pb.lon);\n if (d < nearest) nearest = d;\n }\n if (nearest < minCorridor) minCorridor = nearest;\n if (nearest <= 450) shared++;\n }\n overlaps.push({\n trackAId: ta.id,\n trackBId: tb.id,\n sharedPoints: shared,\n minCorridorMeters: Number.isFinite(minCorridor) ? Math.round(minCorridor) : 0,\n powerDelta: (tb.stats.avgPower || 0) - (ta.stats.avgPower || 0),\n speedDelta: Number(((tb.stats.avgSpeed || 0) - (ta.stats.avgSpeed || 0)).toFixed(2)),\n });\n }\n }\n return overlaps;\n }\n\n const STANDARD_CURVE_DURATIONS = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600,\n ];\n\n function calculateSlidingMax(data: number[], durations: number[]) {\n const len = data.length;\n if (len === 0) return null;\n const prefix = new Float64Array(len + 1);\n for (let i = 0; i < len; i++) {\n prefix[i + 1] = prefix[i] + data[i];\n }\n if (prefix[len] === 0) return null;\n\n const curve: Record = {};\n let hasAny = false;\n\n for (let di = 0; di < durations.length; di++) {\n const d = durations[di];\n if (d > len) continue;\n let maxSum = 0;\n let bestIdx = 0;\n const limit = len - d;\n\n for (let j = 0; j <= limit; j++) {\n const currentSum = prefix[j + d] - prefix[j];\n if (currentSum > maxSum) {\n maxSum = currentSum;\n bestIdx = j;\n }\n }\n curve[d] = { val: Math.round(maxSum / d), idx: bestIdx };\n hasAny = true;\n }\n\n return hasAny ? curve : null;\n }\n\n function calculatePowerCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const powerData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].power || 0;\n powerData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(powerData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { power: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculateHRCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const hrData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].hr || 0;\n hrData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(hrData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { hr: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculatePowerZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0, 0, 0];\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.power == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue;\n\n const pw = p.power;\n if (pw < thresholds[0]) zones[0] += dt;\n else if (pw < thresholds[1]) zones[1] += dt;\n else if (pw < thresholds[2]) zones[2] += dt;\n else if (pw < thresholds[3]) zones[3] += dt;\n else if (pw < thresholds[4]) zones[4] += dt;\n else if (pw < thresholds[5]) zones[5] += dt;\n else zones[6] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setFTP(val: number) {\n ftp = val;\n }\n\n function getFTP() {\n return ftp;\n }\n\n function calculateHRZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0];\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.hr == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue; // Skip gaps\n\n const hr = p.hr;\n if (hr < hrZoneThresholds[0]) zones[0] += dt;\n else if (hr < hrZoneThresholds[1]) zones[1] += dt;\n else if (hr < hrZoneThresholds[2]) zones[2] += dt;\n else if (hr < hrZoneThresholds[3]) zones[3] += dt;\n else zones[4] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setHRZones(thresholds: number[]) {\n hrZoneThresholds = thresholds;\n }\n\n function getHRZones() {\n return [...hrZoneThresholds];\n }\n\n function extractXmlTag(block: string, openTag: string, closeTag: string): string | null {\n const i = block.indexOf(openTag);\n if (i === -1) return null;\n const start = i + openTag.length;\n const j = block.indexOf(closeTag, start);\n if (j === -1) return null;\n const val = block.slice(start, j).trim();\n return val !== '' ? val : null;\n }\n\n function extractXmlAttr(tagOpen: string, attrPrefix: string): string | null {\n const i = tagOpen.indexOf(attrPrefix);\n if (i === -1) return null;\n const start = i + attrPrefix.length;\n const j = tagOpen.indexOf('\"', start);\n if (j === -1) return null;\n return tagOpen.slice(start, j);\n }\n\n let cachedDateKey = -1;\n let cachedDayMs = 0;\n\n function parseIntSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let val = 0;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n val = val * 10 + (c - 48);\n digits++;\n } else {\n break;\n }\n }\n if (digits === 0) return null;\n return neg ? -val : val;\n }\n\n function parseFloatSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let intPart = 0;\n let fracPart = 0;\n let fracDiv = 1;\n let inFrac = false;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n digits++;\n if (!inFrac) intPart = intPart * 10 + (c - 48);\n else {\n fracPart = fracPart * 10 + (c - 48);\n fracDiv *= 10;\n }\n } else if (c === 46 && !inFrac) {\n inFrac = true;\n } else {\n const n = parseFloat(text.slice(start - (neg ? 1 : 0), end));\n return Number.isFinite(n) ? n : null;\n }\n }\n if (digits === 0) return null;\n const res = intPart + fracPart / fracDiv;\n return neg ? -res : res;\n }\n\n function fastParseTimeSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n const len = end - start;\n if (len >= 20 && text.charCodeAt(start + 10) === 84 && text.charCodeAt(end - 1) === 90) {\n const y =\n (text.charCodeAt(start) - 48) * 1000 +\n (text.charCodeAt(start + 1) - 48) * 100 +\n (text.charCodeAt(start + 2) - 48) * 10 +\n (text.charCodeAt(start + 3) - 48);\n const m = (text.charCodeAt(start + 5) - 48) * 10 + (text.charCodeAt(start + 6) - 48);\n const d = (text.charCodeAt(start + 8) - 48) * 10 + (text.charCodeAt(start + 9) - 48);\n const key = (y << 9) | (m << 5) | d;\n if (key !== cachedDateKey) {\n cachedDateKey = key;\n cachedDayMs = Date.UTC(y, m - 1, d);\n }\n const hh = (text.charCodeAt(start + 11) - 48) * 10 + (text.charCodeAt(start + 12) - 48);\n const mm = (text.charCodeAt(start + 14) - 48) * 10 + (text.charCodeAt(start + 15) - 48);\n const ss = (text.charCodeAt(start + 17) - 48) * 10 + (text.charCodeAt(start + 18) - 48);\n let ms = 0;\n if (text.charCodeAt(start + 19) === 46 && len >= 24) {\n ms =\n (text.charCodeAt(start + 20) - 48) * 100 +\n (text.charCodeAt(start + 21) - 48) * 10 +\n (text.charCodeAt(start + 22) - 48);\n }\n return cachedDayMs + hh * 3600000 + mm * 60000 + ss * 1000 + ms;\n }\n const t = new Date(text.slice(start, end)).getTime();\n return Number.isFinite(t) ? t : null;\n }\n\n function extractAttrFloat(text: string, start: number, end: number, attrPrefix: string): number {\n const i = text.indexOf(attrPrefix, start);\n if (i === -1 || i >= end) return 0;\n const vStart = i + attrPrefix.length;\n const j = text.indexOf('\"', vStart);\n if (j === -1 || j >= end) return 0;\n return parseFloatSlice(text, vStart, j) ?? 0;\n }\n\n // \u2500\u2500 GPX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseGPX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTrkpt = text.indexOf('');\n const name =\n (trkIdx !== -1 ? extractXmlTag(header.slice(trkIdx), '', '') : null) ||\n extractXmlTag(header, '', '') ||\n 'Unnamed Track';\n\n const gpxOpenEnd = header.indexOf('>', header.indexOf('', trkStart + 6);\n if (openEnd === -1) break;\n const trkEnd = text.indexOf('', openEnd + 1);\n if (trkEnd === -1) break;\n pos = trkEnd + 8;\n\n const lat = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lat=\"');\n const lon = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lon=\"');\n\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let temp: number | null = null;\n let speed: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = openEnd + 1;\n while (p < trkEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= trkEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= trkEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n // Skip duplicate block when primary fields already parsed\n const tagLen = gt - lt - 1;\n if (c1 === 103 && tagLen === 26 && hr !== null && cad !== null && temp !== null) {\n break;\n }\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > trkEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 3) {\n if (c1 === 101) ele = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 99 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 2) {\n if (c1 === 104 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 4) {\n if (c1 === 116) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if ((c1 === 112 || c1 === 80 || c1 === 87) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 115 || c1 === 83) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if ((c1 === 98 || c1 === 66) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 103 || c1 === 71) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if (c1 === 103) {\n if (text.charCodeAt(lt + 8) === 104 && hr === null)\n hr = parseIntSlice(text, vStart, vEnd);\n else if (gearFront === null) gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (c1 === 71 && gearFront === null) {\n gearFront = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 10) {\n if (c1 === 103 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 103 && text.charCodeAt(lt + 8) === 97 && temp === null)\n temp = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 103 || c1 === 71) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if ((c1 === 103 || c1 === 71) && gearFrontTooth === null)\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 65 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 11 && c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!points.length) throw new Error('No track points found in GPX');\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'gpx', points: pts, stats };\n }\n\n // \u2500\u2500 TCX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseTCX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTp = text.indexOf('');\n const header = firstTp !== -1 ? text.slice(0, firstTp) : text;\n\n const name = extractXmlTag(header, '', '') || 'Unnamed TCX';\n const creatorBlock = extractXmlTag(header, '', '');\n const device = creatorBlock ? extractXmlTag(creatorBlock, '', '') : null;\n\n const points: TrackPoint[] = [];\n let pos = firstTp !== -1 ? firstTp : 0;\n while (pos < text.length) {\n const tpStart = text.indexOf('', pos);\n if (tpStart === -1) break;\n const tpEnd = text.indexOf('', tpStart + 12);\n if (tpEnd === -1) break;\n pos = tpEnd + 13;\n\n let lat: number | null = null;\n let lon: number | null = null;\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let speed: number | null = null;\n let temp: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = tpStart + 12;\n while (p < tpEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= tpEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= tpEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n const tagLen = gt - lt - 1;\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > tpEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 4) {\n if (c1 === 84) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 116 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if (c1 === 86 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 87 || c1 === 80 || c1 === 112) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 83 || c1 === 115) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 66 || c1 === 98) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 71 || c1 === 103) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if ((c1 === 71 || c1 === 103) && gearFront === null)\n gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 10) {\n if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 11) {\n if (c1 === 84 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 71 || c1 === 103) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if (c1 === 65) {\n if (text.charCodeAt(lt + 2) === 108) ele = parseFloatSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if ((c1 === 71 || c1 === 103) && gearFrontTooth === null) {\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 15) {\n if (c1 === 76) lat = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 16) {\n if (c1 === 76) lon = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 2 && c1 === 104 && hr === null) {\n hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 3 && c1 === 99 && cad === null) {\n cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n if (lat == null || lon == null) continue;\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'tcx', points: pts, stats };\n }\n\n function fastDecodeFitData(buf: ArrayBuffer): any | null {\n if (buf.byteLength < 14) return null;\n const dv = new DataView(buf);\n const headerSize = dv.getUint8(0);\n if (headerSize < 12 || headerSize + 2 > buf.byteLength) return null;\n if (\n dv.getUint8(8) !== 0x2e ||\n dv.getUint8(9) !== 0x46 ||\n dv.getUint8(10) !== 0x49 ||\n dv.getUint8(11) !== 0x54\n ) {\n return null;\n }\n const dataSize = dv.getUint32(4, true);\n const endOffset = Math.min(buf.byteLength, headerSize + dataSize);\n const GARMIN_EPOCH_SEC = 631065600;\n const SEMICIRCLE_TO_DEG = 180 / Math.pow(2, 31);\n\n interface FieldDef {\n num: number;\n size: number;\n type: number;\n }\n interface MsgDef {\n littleEndian: boolean;\n globalMsgNum: number;\n fields: FieldDef[];\n recordSize: number;\n }\n const defs: (MsgDef | undefined)[] = new Array(16);\n const file_ids: any[] = [];\n const sessions: any[] = [];\n const records: any[] = [];\n const events: any[] = [];\n const device_infos: any[] = [];\n\n let offset = headerSize;\n while (offset < endOffset) {\n const hdr = dv.getUint8(offset++);\n if ((hdr & 0x80) !== 0 || (hdr & 0x20) !== 0) {\n return null; // Compressed timestamp or developer data: fallback to FitParser\n }\n const localNum = hdr & 0x0f;\n if ((hdr & 0x40) !== 0) {\n if (offset + 5 > endOffset) return null;\n offset++; // reserved\n const arch = dv.getUint8(offset++);\n const littleEndian = arch === 0;\n const globalMsgNum = dv.getUint16(offset, littleEndian);\n offset += 2;\n const numFields = dv.getUint8(offset++);\n if (offset + numFields * 3 > endOffset) return null;\n const fields: FieldDef[] = new Array(numFields);\n let recordSize = 0;\n for (let i = 0; i < numFields; i++) {\n const num = dv.getUint8(offset++);\n const size = dv.getUint8(offset++);\n const type = dv.getUint8(offset++);\n fields[i] = { num, size, type };\n recordSize += size;\n }\n defs[localNum] = { littleEndian, globalMsgNum, fields, recordSize };\n } else {\n const def = defs[localNum];\n if (!def || offset + def.recordSize > endOffset) return null;\n const le = def.littleEndian;\n const gNum = def.globalMsgNum;\n\n if (\n gNum === 20 &&\n def.fields.length === 10 &&\n def.recordSize === 25 &&\n def.fields[0].num === 253 &&\n def.fields[1].num === 0\n ) {\n const ts = dv.getUint32(offset, le);\n const rawLat = dv.getInt32(offset + 4, le);\n const rawLon = dv.getInt32(offset + 8, le);\n const rawAlt = dv.getUint16(offset + 12, le);\n const hr = dv.getUint8(offset + 14);\n const cad = dv.getUint8(offset + 15);\n const rawDist = dv.getUint32(offset + 16, le);\n const rawSpd = dv.getUint16(offset + 20, le);\n const power = dv.getUint16(offset + 22, le);\n const temp = dv.getInt8(offset + 24);\n records.push({\n timestamp: (ts + GARMIN_EPOCH_SEC) * 1000,\n position_lat: rawLat * SEMICIRCLE_TO_DEG,\n position_long: rawLon * SEMICIRCLE_TO_DEG,\n altitude: rawAlt / 5 - 500,\n heart_rate: hr,\n cadence: cad,\n distance: rawDist / 100,\n speed: (rawSpd / 1000) * 3.6,\n power,\n temperature: temp,\n });\n offset += 25;\n continue;\n }\n\n const msg: any = {};\n let fOff = offset;\n for (let i = 0; i < def.fields.length; i++) {\n const f = def.fields[i];\n let val: number = 0;\n const bType = f.type & 0x1f;\n if (f.size === 1) {\n val = bType === 1 ? dv.getInt8(fOff) : dv.getUint8(fOff);\n } else if (f.size === 2) {\n val = bType === 3 ? dv.getInt16(fOff, le) : dv.getUint16(fOff, le);\n } else if (f.size === 4) {\n val = bType === 5 ? dv.getInt32(fOff, le) : dv.getUint32(fOff, le);\n }\n msg[f.num] = val;\n fOff += f.size;\n }\n offset += def.recordSize;\n\n if (gNum === 0) {\n file_ids.push({\n type: msg[0] === 4 ? 'activity' : msg[0],\n manufacturer: msg[1] === 1 ? 'garmin' : msg[1],\n product: msg[2],\n time_created: msg[4] != null ? (msg[4] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n });\n } else if (gNum === 18) {\n const sportMap: Record = { 0: 'generic', 1: 'running', 2: 'cycling' };\n sessions.push({\n start_time: msg[2] != null ? (msg[2] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n sport: sportMap[msg[5]] ?? String(msg[5]),\n sub_sport: msg[6] === 0 ? 'generic' : String(msg[6]),\n });\n } else if (gNum === 20) {\n records.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n position_lat: msg[0] != null ? msg[0] * SEMICIRCLE_TO_DEG : undefined,\n position_long: msg[1] != null ? msg[1] * SEMICIRCLE_TO_DEG : undefined,\n altitude: msg[2] != null ? msg[2] / 5 - 500 : undefined,\n heart_rate: msg[3],\n cadence: msg[4],\n distance: msg[5] != null ? msg[5] / 100 : undefined,\n speed: msg[6] != null ? (msg[6] / 1000) * 3.6 : undefined,\n power: msg[7],\n temperature: msg[13],\n });\n } else if (gNum === 21) {\n const evName =\n msg[0] === 43\n ? 'rear_gear_change'\n : msg[0] === 42\n ? 'front_gear_change'\n : String(msg[0]);\n events.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n event: evName,\n event_type: msg[1] === 3 ? 'marker' : String(msg[1]),\n data: msg[3],\n front_gear_num: msg[9],\n rear_gear_num: msg[11],\n });\n } else if (gNum === 23) {\n device_infos.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n battery_level: msg[32],\n });\n } else {\n return null;\n }\n }\n }\n return { file_ids, sessions, sports: [], records, events, device_infos };\n }\n\n // \u2500\u2500 FIT parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseFIT(buf: ArrayBuffer): Promise {\n return new Promise((resolve, reject) => {\n const handleParsedFitData = (error: any, data: any) => {\n if (error) {\n reject(error);\n return;\n }\n try {\n const name = data.sessions?.[0]?.start_time\n ? `Fit Activity ${new Date(data.sessions[0].start_time).toISOString().split('T')[0]}`\n : 'Unnamed Fit';\n\n // Better device detection\n let device: string | null = null;\n const devices: DeviceInfo[] = [];\n let sport: string | null = null;\n let subSport: string | null = null;\n\n if (data.sports?.[0]) {\n sport = data.sports[0].sport;\n subSport = data.sports[0].sub_sport;\n } else if (data.sessions?.[0]) {\n sport = data.sessions[0].sport;\n subSport = data.sessions[0].sub_sport;\n }\n\n const getDeviceName = (d: any) =>\n d.product_name ||\n d.garmin_product ||\n d.product ||\n d.device_type ||\n d.manufacturer ||\n null;\n\n if (data.file_ids?.[0]) {\n const fid = data.file_ids[0];\n device = getDeviceName(fid);\n devices.push({\n name: fid.product_name || fid.garmin_product || fid.product,\n manufacturer: fid.manufacturer,\n serial: fid.serial_number ? String(fid.serial_number) : undefined,\n version: fid.software_version ? String(fid.software_version) : undefined,\n type: 'main',\n });\n }\n\n if (data.device_infos) {\n data.device_infos.forEach((d: any) => {\n const isMain = d.device_index === 'creator' || d.device_index === 0;\n\n if (isMain) {\n const name = getDeviceName(d);\n // Prefer a name with product_name or garmin_product over generic ones\n if (d.product_name || d.garmin_product || !device) device = name;\n\n // Update existing main device if needed\n if (devices.length > 0 && devices[0].type === 'main') {\n if (d.product_name || d.garmin_product || !devices[0].name)\n devices[0].name = d.product_name || d.garmin_product || d.product;\n\n if (!devices[0].manufacturer) devices[0].manufacturer = d.manufacturer;\n if (!devices[0].serial && d.serial_number)\n devices[0].serial = String(d.serial_number);\n if (!devices[0].version && d.software_version)\n devices[0].version = String(d.software_version);\n if (!devices[0].hardwareVersion && d.hardware_version)\n devices[0].hardwareVersion = String(d.hardware_version);\n }\n return;\n }\n\n devices.push({\n name: d.product_name || d.garmin_product || d.product || d.device_type || 'Sensor',\n manufacturer: d.manufacturer,\n serial: d.serial_number ? String(d.serial_number) : undefined,\n version: d.software_version ? String(d.software_version) : undefined,\n hardwareVersion: d.hardware_version ? String(d.hardware_version) : undefined,\n type: d.device_type || 'sensor',\n batteryStatus: d.battery_status,\n batteryVoltage: d.battery_voltage,\n batteryLevel: d.battery_level,\n sourceType: d.source_type != null ? String(d.source_type) : undefined,\n });\n });\n }\n\n if (data.sensor_settings) {\n data.sensor_settings.forEach((s: any) => {\n const name = s.name || s.product || s.sensor_type;\n if (!name) return;\n\n // Check if we already have this device (by ANT ID or name)\n const antId = s.ant_id ? String(s.ant_id) : undefined;\n const existing = devices.find(\n (d) =>\n (antId && d.serial === antId) ||\n (d.name === name && d.manufacturer === s.manufacturer),\n );\n\n if (existing) {\n if (!existing.name) existing.name = name;\n if (!existing.manufacturer) existing.manufacturer = s.manufacturer;\n if (!existing.type) existing.type = s.sensor_type;\n if (!existing.sourceType)\n existing.sourceType =\n s.connection_type != null ? String(s.connection_type) : undefined;\n } else {\n devices.push({\n name: name,\n manufacturer: s.manufacturer,\n serial: antId,\n type: s.sensor_type || 'sensor',\n sourceType: s.connection_type != null ? String(s.connection_type) : undefined,\n });\n }\n });\n }\n\n // Collect standalone device status reports (often contains head unit battery)\n // We'll store them in a sorted array for easier lookups\n const statusReports: { time: number; level: number | null; idx: number }[] = [];\n if (data.device_statuses) {\n data.device_statuses.forEach((s: any, idx: number) => {\n if (s.timestamp && s.battery_level != null) {\n statusReports.push({\n time:\n typeof s.timestamp === 'number' ? s.timestamp : new Date(s.timestamp).getTime(),\n level: s.battery_level,\n idx,\n });\n }\n });\n statusReports.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n // Collect gear events\n const gearEvents: {\n time: number;\n front: number | null;\n rear: number | null;\n frontTooth: number | null;\n rearTooth: number | null;\n idx: number;\n }[] = [];\n if (data.events) {\n data.events.forEach((e: any, idx: number) => {\n let front = e.front_gear_num ?? e.front_gear ?? null;\n let rear = e.rear_gear_num ?? e.rear_gear ?? null;\n let frontTooth = e.front_gear_num_tooth ?? null;\n let rearTooth = e.rear_gear_num_tooth ?? null;\n\n if (e.event === 'rear_gear_change' || e.event === 'front_gear_change') {\n const d = e.data;\n if (d != null) {\n const ft = (d >> 24) & 0xff;\n const fg = (d >> 16) & 0xff;\n const rt = (d >> 8) & 0xff;\n const rg = d & 0xff;\n\n if (fg !== 0) front = fg;\n if (ft !== 0) frontTooth = ft;\n if (rg !== 0) rear = rg;\n if (rt !== 0) rearTooth = rt;\n }\n }\n\n if (\n e.timestamp &&\n (front != null || rear != null || frontTooth != null || rearTooth != null)\n ) {\n gearEvents.push({\n time:\n typeof e.timestamp === 'number' ? e.timestamp : new Date(e.timestamp).getTime(),\n front,\n rear,\n frontTooth,\n rearTooth,\n idx,\n });\n }\n });\n gearEvents.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n const records = data.records || [];\n let lastBattery: number | null = null;\n let statusIdx = 0;\n let lastFrontGear: number | null = null;\n let lastRearGear: number | null = null;\n let lastFrontTooth: number | null = null;\n let lastRearTooth: number | null = null;\n let gearIdx = 0;\n\n const validPoints: TrackPoint[] = [];\n for (let ri = 0; ri < records.length; ri++) {\n const r = records[ri];\n const lat = r.position_lat;\n const lon = r.position_long;\n if (lat == null || lon == null) continue;\n\n const time =\n r.timestamp != null\n ? typeof r.timestamp === 'number'\n ? r.timestamp\n : r.timestamp instanceof Date\n ? r.timestamp.getTime()\n : new Date(r.timestamp).getTime()\n : null;\n const speed = r.speed != null ? r.speed / 3.6 : null; // km/h \u2192 m/s\n\n let battery = r.battery_level ?? null;\n\n // If not in record, check our status reports\n if (battery == null && time) {\n // Catch up statusIdx to current time\n while (statusIdx < statusReports.length && statusReports[statusIdx].time <= time) {\n lastBattery = statusReports[statusIdx].level;\n statusIdx++;\n }\n battery = lastBattery;\n } else if (battery != null) {\n lastBattery = battery;\n }\n\n // Update gear state from events\n if (time) {\n while (gearIdx < gearEvents.length && gearEvents[gearIdx].time <= time) {\n const e = gearEvents[gearIdx];\n if (e.front != null) lastFrontGear = e.front;\n if (e.rear != null) lastRearGear = e.rear;\n if (e.frontTooth != null) lastFrontTooth = e.frontTooth;\n if (e.rearTooth != null) lastRearTooth = e.rearTooth;\n gearIdx++;\n }\n }\n\n const gearFront: number | null = r.front_gear_num ?? r.front_gear ?? lastFrontGear;\n const gearRear: number | null = r.rear_gear_num ?? r.rear_gear ?? lastRearGear;\n const gearFrontTooth: number | null = r.front_gear_num_tooth ?? lastFrontTooth;\n const gearRearTooth: number | null = r.rear_gear_num_tooth ?? lastRearTooth;\n\n if (r.front_gear_num != null || r.front_gear != null) lastFrontGear = gearFront;\n if (r.rear_gear_num != null || r.rear_gear != null) lastRearGear = gearRear;\n if (r.front_gear_num_tooth != null) lastFrontTooth = gearFrontTooth;\n if (r.rear_gear_num_tooth != null) lastRearTooth = gearRearTooth;\n\n const gears =\n gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0\n ? gearFrontTooth / gearRearTooth\n : null;\n\n validPoints.push({\n lat,\n lon,\n ele: r.altitude ?? r.enhanced_altitude ?? null,\n time,\n hr: r.heart_rate ?? null,\n cad: r.cadence ?? null,\n power: r.power ?? null,\n speed,\n temp: r.temperature ?? null,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!validPoints.length) {\n reject(new Error('FIT file has no GPS points'));\n return;\n }\n\n const pts = enrichPoints(validPoints);\n const stats = computeStats(pts);\n resolve({ name, device, devices, format: 'fit', points: pts, stats, sport, subSport });\n } catch (ex) {\n reject(ex);\n }\n };\n\n const fastData = fastDecodeFitData(buf);\n if (fastData) {\n handleParsedFitData(null, fastData);\n return;\n }\n\n const fitParser = new FitParser({\n force: true,\n speedUnit: 'km/h',\n lengthUnit: 'm',\n temperatureUnit: 'celsius',\n elapsedRecordField: true,\n });\n\n fitParser.parse(buf, handleParsedFitData);\n });\n }\n\n // \u2500\u2500 KML parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseKML(buf: ArrayBuffer): any {\n const text = new TextDecoder().decode(buf);\n const doc = new DOMParser().parseFromString(text, 'application/xml');\n\n let name = 'Unnamed Track';\n const nameEl = doc.querySelector('Document > name, Placemark > name');\n if (nameEl) name = nameEl.textContent?.trim() || name;\n\n // Track: look for gx:Track or LineString\n const coordEls = doc.querySelectorAll('coordinates');\n if (!coordEls.length) throw new Error('No coordinates found in KML');\n\n const points: TrackPoint[] = [];\n coordEls.forEach((el) => {\n const lines = el.textContent?.trim().split(/\\s+/) || [];\n lines.forEach((line) => {\n const parts = line.split(',');\n if (parts.length < 2) return;\n const lon = parseFloat(parts[0]);\n const lat = parseFloat(parts[1]);\n const ele = parts.length > 2 ? parseFloat(parts[2]) : null;\n if (isNaN(lat) || isNaN(lon)) return;\n points.push({\n lat,\n lon,\n ele: ele != null && isNaN(ele) ? null : ele,\n time: null,\n hr: null,\n cad: null,\n power: null,\n speed: null,\n temp: null,\n gearFront: null,\n gearRear: null,\n gearFrontTooth: null,\n gearRearTooth: null,\n battery: null,\n gears: null,\n });\n });\n });\n\n if (!points.length) throw new Error('No valid coordinates in KML');\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, format: 'kml', points: pts, stats };\n }\n\n // \u2500\u2500 Public: dispatch by extension \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async function parseFile(file: File): Promise {\n const ext = file.name.split('.').pop()?.toLowerCase();\n const buf: ArrayBuffer = (file as any)._buf ?? (await file.arrayBuffer());\n const predecodedText: string | undefined = (file as any)._text;\n let result: any;\n switch (ext) {\n case 'gpx':\n result = parseGPX(buf, predecodedText);\n break;\n case 'tcx':\n result = parseTCX(buf, predecodedText);\n break;\n case 'fit':\n result = await parseFIT(buf);\n break;\n case 'kml':\n result = parseKML(buf);\n break;\n default:\n throw new Error(`Unsupported format: .${ext}`);\n }\n\n if (result) {\n result.fileName = file.name;\n result.fileSize = file.size;\n if (result.points && result.stats) {\n ensureCurvesAndZones(result);\n result.stats.sections = analyzeTrackSections(result.points);\n }\n }\n return result;\n }\n\n return {\n parseFile,\n computeStats,\n ensureCurvesAndZones,\n analyzeTrackSections,\n findOverlaps,\n calculatePowerCurve,\n calculateHRCurve,\n calculatePowerZones,\n calculateHRZones,\n enrichPoints,\n setHRZones,\n getHRZones,\n setFTP,\n getFTP,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const R = 6371e3; // Earth radius in metres\n const phi1 = (lat1 * Math.PI) / 180;\n const phi2 = (lat2 * Math.PI) / 180;\n const deltaPhi = ((lat2 - lat1) * Math.PI) / 180;\n const deltaLambda = ((lon2 - lon1) * Math.PI) / 180;\n\n const a =\n Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) +\n Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n\nexport function compactId(timestamp: number): string {\n // Use a compact representation of the timestamp (seconds since epoch)\n // 1712650000 -> Base64\n const buf = new Uint32Array([Math.floor(timestamp / 1000)]);\n const b64 = btoa(String.fromCharCode(...new Uint8Array(buf.buffer)));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\nexport function shortRandom(): string {\n return Math.random().toString(36).slice(2, 6);\n}\n\nexport function fmtDuration(s: number): string {\n if (s < 60) return `${Math.round(s)}s`;\n if (s < 3600) return `${Math.round(s / 60)}m`;\n return `${Math.round(s / 3600)}h`;\n}\n\nexport function fmtSecs(s: number): string {\n const h = Math.floor(s / 3600),\n m = Math.floor((s % 3600) / 60);\n return h > 0 ? `${h}h ${m}m` : `${m}m ${Math.floor(s % 60)}s`;\n}\n\nexport function fmtPace(seconds: number | null): string {\n if (seconds == null || !isFinite(seconds)) return '--';\n const mins = Math.floor(seconds / 60);\n const secs = Math.round(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nexport function fmtDate(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown date';\n return d.toISOString().split('T')[0];\n}\n\nexport function fmtDateTime(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown';\n const iso = d.toISOString();\n return `${iso.split('T')[0]} ${iso.split('T')[1].slice(0, 5)}`;\n}\n\nexport function fmtFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function escHtml(str: string): string {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function getTagColor(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);\n\n const h = Math.abs(hash % 360);\n return `hsl(${h}, 70%, 65%)`;\n}\n\n/**\n * Smoothes a numeric array using a simple Gaussian kernel.\n * sigma: standard deviation (radius of smoothing)\n */\nexport function gaussianSmooth(data: (number | null)[], sigma: number = 2): (number | null)[] {\n if (sigma <= 0) return data;\n\n const size = Math.ceil(sigma * 3) * 2 + 1;\n const kernel = new Float32Array(size);\n const half = Math.floor(size / 2);\n let sum = 0;\n\n for (let i = 0; i < size; i++) {\n const x = i - half;\n kernel[i] = Math.exp(-(x * x) / (2 * sigma * sigma));\n sum += kernel[i];\n }\n for (let i = 0; i < size; i++) kernel[i] /= sum;\n\n const result: (number | null)[] = new Array(data.length);\n for (let i = 0; i < data.length; i++) {\n if (data[i] === null) {\n result[i] = null;\n continue;\n }\n\n let val = 0;\n let weightSum = 0;\n for (let k = 0; k < size; k++) {\n const idx = i + k - half;\n if (idx >= 0 && idx < data.length && data[idx] !== null) {\n val += data[idx]! * kernel[k];\n weightSum += kernel[k];\n }\n }\n result[i] = weightSum > 0 ? val / weightSum : data[i];\n }\n return result;\n}\n\nexport function hexToRgba(hex: string, alpha: number = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, TrackPoint } from './parsers';\n\nexport const MapView = (() => {\n let trackData: Record = {};\n let customClickHandler: ((e: any) => boolean) | null = null;\n\n function init(\n onSelectCb: (id: string) => void,\n onMoveCb: (lat: number, lng: number, zoom: number) => void,\n onPointClickCb: (id: string, idx: number) => void,\n onPointHoverCb: (id: string | null, idx: number | null) => void,\n onDblClickCb: () => void,\n ) {}\n\n function switchBasemap(layer: string) {}\n function addTrack(t: TrackData) {\n trackData[t.id] = t;\n }\n function addTracks(ts: TrackData[]) {\n ts.forEach((t) => {\n trackData[t.id] = t;\n });\n }\n function removeTrack(id: string) {\n delete trackData[id];\n }\n function clearTracks() {\n trackData = {};\n }\n function removeAllTracks() {\n trackData = {};\n }\n function setTrackVisible(id: string, visible: boolean) {}\n function setSelectedTrack(id: string | null, fit: boolean) {}\n function fitAll() {}\n function fitTrack(id: string) {}\n function showCursorAt(lat: number, lon: number) {}\n function hideCursor() {}\n function highlightSegment(\n id: string | null,\n pts: TrackPoint[],\n start: number,\n end: number,\n fit?: boolean,\n colors?: string[] | null,\n ) {}\n function clearHighlight() {}\n function setTrackHover(id: string, hover: boolean) {}\n function ensureVisible(pts: any) {}\n function centerOn(lat: number, lon: number, zoom?: number | null, force?: boolean) {}\n function closePopup() {}\n function invalidateSize() {}\n function getPosition(): [number, number, number] {\n return [0, 0, 0];\n }\n function setPosition(lat: number, lng: number, zoom: number) {}\n function colorTrackByMetric(id: string, pts: TrackPoint[], colors: string[]) {}\n function clearMetricColor(id: string) {}\n\n function findTracksPassingThroughPoints(\n points: { lat: number; lng: number }[],\n radius: number,\n ): string[] {\n return Object.keys(trackData);\n }\n\n return {\n init,\n getMap: () => null as any,\n setCustomClickHandler: (handler: any) => {\n customClickHandler = handler;\n },\n switchBasemap,\n addTrack,\n addTracks,\n removeTrack,\n clearTracks,\n removeAllTracks,\n setTrackVisible,\n setSelectedTrack,\n fitAll,\n fitTrack,\n showCursorAt,\n hideCursor,\n highlightSegment,\n clearHighlight,\n setTrackHover,\n ensureVisible,\n centerOn,\n closePopup,\n invalidateSize,\n getPosition,\n setPosition,\n colorTrackByMetric,\n clearMetricColor,\n findTracksPassingThroughPoints,\n getTrackData: (id: string) => trackData[id],\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackPoint, TrackStats, TrackData } from './parsers';\nimport { gaussianSmooth, fmtSecs, hexToRgba, fmtPace } from './utils';\nimport { Zones } from './zones';\nimport { METRICS, MetricDefinition } from './metrics';\nimport { UrlState } from './url-state';\nimport { SPORTS } from './sports';\n\n// Augment uPlot to include our custom property\n\ninterface WegPlot extends uPlot {\n _strasse?: {\n selFill: HTMLElement;\n anchorLine: HTMLElement;\n anchorLabel: HTMLElement;\n anchorHandle: HTMLElement;\n anchorMarker: HTMLElement;\n endLine: HTMLElement;\n endLabel: HTMLElement;\n endHandle: HTMLElement;\n endMarker: HTMLElement;\n curYVal: HTMLElement;\n updateHeaderStats: (min: number, max: number) => void;\n };\n}\n\ninterface PlotData {\n uplot: WegPlot;\n row: HTMLDivElement;\n xData: number[];\n yData: (number | null)[];\n def: MetricDefinition;\n metricKey: string;\n statsTotalEl: HTMLDivElement;\n statsSelEl: HTMLDivElement;\n histCol: HTMLDivElement;\n histCanvas: HTMLCanvasElement;\n histData: HistData;\n hoveredHistY: number | null;\n pinnedHistY: number | null;\n smoothed?: boolean;\n incZero?: boolean;\n w?: number;\n}\n\ninterface HistData {\n yData: (number | null)[];\n xData: number[];\n def: MetricDefinition;\n BINS: number;\n plot?: PlotData;\n bins?: number[];\n binAccum?: number[];\n min?: number;\n max?: number;\n padL?: number;\n selBins?: number[] | null;\n selBinAccum?: number[] | null;\n _lastYData?: any;\n _lastSelRange?: [number, number] | null;\n fullStats?: { min: number; max: number; avg: number } | null;\n fullStatsAll?: { min: number; max: number; avg: number } | null;\n}\n\nexport const ChartView = (() => {\n let plots: PlotData[] = [];\n let renderedTrack: TrackData | null = null;\n let renderedXAxis: string = 'time';\n let renderedSpeedMode: string = 'speed';\n let renderedMapColorMetric: string | null = null;\n let syncKey: {\n key: string;\n sub: (u: uPlot) => void;\n unsub: (u: uPlot) => void;\n pub: (type: string, u: uPlot, x: number, y: number, w: number, h: number, i: number) => void;\n } | null = null;\n let scaleSyncing: boolean = false;\n let cursorSyncing: boolean = false;\n let activeMetrics: Set = new Set(['elevation']);\n let availableMetrics: Set = new Set();\n let smoothedMetrics: Set = new Set(['speed', 'gradient', 'vam', 'temperature']);\n let metricsIncludingZero: Set = new Set(['power']);\n let xAxis: string = 'time';\n let currentTrack: TrackData | null = null;\n let allTracks: TrackData[] = [];\n\n // Selection / anchor\n let selAnchorVal: number | null = null; // x-value at drag-start / zoom left edge\n let selEndVal: number | null = null; // x-value at zoom right edge\n let isDragging: boolean = false;\n let updatingRange: boolean = false; // guard against setScale hook re-entry during handle drag\n let pinnedPtIdx: number | null = null; // point index pinned by map click\n let lastMouseXVal: number | null = null; // last hovered x-value for keyboard zoom center\n let lastHistMouseEvent: MouseEvent | null = null;\n let hoveredHistData: HistData | null = null;\n let hoveredHistCanvas: HTMLCanvasElement | null = null;\n\n let currentXRange: [number, number] | null = null; // [min, max] currently rendered\n let targetXRange: [number, number] | null = null; // [min, max] for smooth keyboard animation\n let animId: number | null = null;\n\n // Callbacks\n let onCursorMoveCb: ((pt: TrackPoint | null) => void) | null = null;\n let onRangeChangeCb: ((min: number | null, max: number | null, axis: string) => void) | null =\n null;\n let onClickCb: ((pt: TrackPoint, idx: number) => void) | null = null;\n let onPinChangeCb: ((idx: number | null) => void) | null = null;\n\n const HIST_W: number = 130;\n const ROW_BODY_PADDING: number = 28; // 14px left + 14px right\n const HIST_GAP: number = 20; // margin-left on .hist-col\n let statsVisible: boolean = true;\n let histTooltipEl: HTMLElement | null = null;\n let container: HTMLElement | null = null;\n let emptyEl: HTMLElement | null = null;\n let selStatsEl: HTMLElement | null = null;\n let resetSelBtn: HTMLElement | null = null;\n let mapColorMetric: string | null = null;\n let onMapColorChangeCb: ((data: { pts: TrackPoint[]; colors: string[] } | null) => void) | null =\n null;\n\n // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function init(\n onCursorMove: (pt: TrackPoint | null) => void,\n onRangeChange: (min: number | null, max: number | null, axis: string) => void,\n onClick: (pt: TrackPoint, idx: number) => void,\n onPinChange: (idx: number | null) => void,\n ) {\n onCursorMoveCb = onCursorMove;\n onRangeChangeCb = onRangeChange;\n onClickCb = onClick;\n onPinChangeCb = onPinChange;\n container = document.getElementById('charts-container');\n container?.addEventListener('scroll', () => {\n if (lastHistMouseEvent && hoveredHistCanvas && hoveredHistData)\n updateHistTooltip(lastHistMouseEvent, hoveredHistCanvas, hoveredHistData);\n });\n emptyEl = document.getElementById('chart-empty');\n selStatsEl = document.getElementById('chart-stats-sel');\n resetSelBtn = document.getElementById('btn-reset-selection');\n histTooltipEl = document.getElementById('hist-tooltip');\n syncKey = uPlot.sync('strasse-sync');\n\n document.getElementById('sel-cancel-btn')?.addEventListener('click', cancelSelection);\n resetSelBtn?.classList.add('hidden');\n\n // \u2500\u2500 WASD Keyboard Navigation \u2500\u2500\n const navKeys = new Set(['w', 'a', 's', 'd']);\n const activeNavKeys = new Set();\n\n document.addEventListener('keydown', (e) => {\n if (!plots.length || !currentTrack) return;\n if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName || '')) return;\n\n const key = e.key.toLowerCase();\n if (!navKeys.has(key)) return;\n\n e.preventDefault();\n activeNavKeys.add(key);\n\n const u = plots[0].uplot;\n if (!targetXRange) targetXRange = [u.scales.x!.min!, u.scales.x!.max!];\n\n let [min, max] = targetXRange;\n const span = max - min;\n const moveStep = span * 0.1;\n const zoomFactor = 0.15;\n\n let newMin = min,\n newMax = max;\n\n if (key === 'a') {\n // Pan left\n newMin = min - moveStep;\n newMax = max - moveStep;\n } else if (key === 'd') {\n // Pan right\n newMin = min + moveStep;\n newMax = max + moveStep;\n } else if (key === 'w' || key === 's') {\n // Zoom\n const center = lastMouseXVal !== null ? lastMouseXVal : (min + max) / 2;\n const factor = key === 'w' ? 1 - zoomFactor : 1 + zoomFactor * 1.2;\n newMin = center - (center - min) * factor;\n newMax = center + (max - center) * factor;\n }\n\n // Clamp to track bounds\n const xFull = [plots[0].xData[0]!, plots[0].xData[plots[0].xData.length - 1]!];\n if (newMin < xFull[0]) {\n const d = xFull[0] - newMin;\n newMin += d;\n newMax += d;\n }\n if (newMax > xFull[1]) {\n const d = newMax - xFull[1];\n newMin -= d;\n newMax -= d;\n }\n newMin = Math.max(xFull[0], newMin);\n newMax = Math.min(xFull[1], newMax);\n\n if (newMax - newMin > 0.001) {\n targetXRange = [newMin, newMax];\n setVisibleRange(newMin, newMax, true); // true = animate\n }\n });\n\n document.addEventListener('keyup', (e) => {\n const key = e.key.toLowerCase();\n if (navKeys.has(key)) activeNavKeys.delete(key);\n });\n }\n\n function setVisibleRange(min: number, max: number, animate = false) {\n if (!plots.length) return;\n if (!animate) {\n plots.forEach(({ uplot: u }) => u.setScale('x', { min, max }));\n return;\n }\n\n const startMin = (currentXRange ? currentXRange[0] : plots[0].uplot.scales.x!.min) as number;\n const startMax = (currentXRange ? currentXRange[1] : plots[0].uplot.scales.x!.max) as number;\n\n if (animId) cancelAnimationFrame(animId);\n\n const lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n const factor = 0.25; // Smoothing factor\n\n const step = () => {\n if (!targetXRange) return;\n const [tMin, tMax] = targetXRange;\n\n const cMin = lerp(currentXRange![0], tMin, factor);\n const cMax = lerp(currentXRange![1], tMax, factor);\n\n plots.forEach(({ uplot: u }) => {\n u.setScale('x', { min: cMin, max: cMax });\n });\n\n if (Math.abs(cMin - tMin) > 0.0001 || Math.abs(cMax - tMax) > 0.0001)\n animId = requestAnimationFrame(step);\n else animId = null;\n };\n animId = requestAnimationFrame(step);\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function loadTrack(track: TrackData, others: TrackData[] = [], deferRender = false) {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n allTracks = others;\n\n // Detect which metrics are available in this file\n availableMetrics = new Set(\n Object.entries(METRICS)\n .filter(([, def]) => track.points.some((p) => p[def.field] != null))\n .map(([key]) => key),\n );\n\n // If no metrics are active (e.g. first load), default to core overview metrics\n if (activeMetrics.size === 0) {\n activeMetrics = new Set(['elevation'].filter((m) => availableMetrics.has(m)));\n }\n\n // Sync the pill buttons in the toolbar\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n const metric = pill.dataset.metric!;\n const isAvailable = availableMetrics.has(metric);\n pill.classList.toggle('active', isAvailable && activeMetrics.has(metric));\n pill.classList.toggle('disabled', !isAvailable);\n });\n\n currentTrack = track;\n if (deferRender) {\n updateStats(track);\n } else {\n render();\n }\n }\n\n function clear() {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n currentTrack = null;\n destroyPlots();\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
Select a track to view analysis
\n `;\n }\n const chartStats = document.getElementById('chart-stats');\n if (chartStats) chartStats.classList.add('hidden');\n clearSelectionStats();\n mapColorMetric = null;\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n }\n\n function resetState() {\n if (animId !== null) {\n cancelAnimationFrame(animId);\n animId = null;\n }\n activeMetrics = new Set(['elevation']);\n availableMetrics = new Set();\n smoothedMetrics = new Set(['speed', 'gradient', 'vam', 'temperature']);\n metricsIncludingZero = new Set(['power']);\n xAxis = 'time';\n allTracks = [];\n currentXRange = null;\n targetXRange = null;\n lastMouseXVal = null;\n lastHistMouseEvent = null;\n hoveredHistData = null;\n hoveredHistCanvas = null;\n statsVisible = true;\n clear();\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n pill.classList.remove('disabled', 'overflow-hidden');\n });\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.add('hidden');\n const toolbar = document.getElementById('chart-toolbar');\n if (toolbar) toolbar.classList.remove('collapsed');\n document.querySelectorAll('#x-axis-ctrl .seg-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.axis === 'time');\n });\n }\n\n function toggleMetric(key: string) {\n if (activeMetrics.has(key)) activeMetrics.delete(key);\n else activeMetrics.add(key);\n if (currentTrack) render(true);\n }\n\n function setSmooth(metricKey: string, enabled: boolean, skipRender = false) {\n const has = smoothedMetrics.has(metricKey);\n if (enabled && !has) {\n smoothedMetrics.add(metricKey);\n if (currentTrack && !skipRender) render(true);\n } else if (!enabled && has) {\n smoothedMetrics.delete(metricKey);\n if (currentTrack && !skipRender) render(true);\n }\n }\n\n function setZeroInclusion(metricKey: string, includeZero: boolean) {\n const has = metricsIncludingZero.has(metricKey);\n if (includeZero && !has) {\n metricsIncludingZero.add(metricKey);\n if (currentTrack) render(true);\n } else if (!includeZero && has) {\n metricsIncludingZero.delete(metricKey);\n if (currentTrack) render(true);\n }\n }\n\n function setActiveMetrics(keys: string[]) {\n activeMetrics = new Set(keys);\n if (currentTrack) render(true);\n // Sync the pill buttons\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n });\n }\n\n function setXAxis(axis: string) {\n if (xAxis === axis || !currentTrack) {\n xAxis = axis;\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n\n // Helper to convert a value from OLD axis to NEW axis\n const convert = (val: number | null) => {\n if (val === null) return null;\n // We need to find the point index closest to 'val' on the OLD axis\n let idx = 0;\n if (xAxis === 'distance') {\n const dTarget = val * 1000;\n idx = pts.findIndex((p) => (p.dist || 0) >= dTarget);\n } else {\n const tTarget = t0 + val * 1000;\n idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n }\n if (idx === -1) idx = pts.length - 1;\n\n // Now get the value at this index on the NEW axis\n if (axis === 'distance') return (pts[idx].dist || 0) / 1000;\n else return ((pts[idx].time || t0) - t0) / 1000;\n };\n\n // Convert selection\n if (selAnchorVal !== null) selAnchorVal = convert(selAnchorVal);\n if (selEndVal !== null) selEndVal = convert(selEndVal);\n\n // Convert zoom range (from first plot)\n let newRange: [number, number] | null = null;\n if (plots.length) {\n const u = plots[0].uplot;\n const r0 = convert(u.scales.x!.min!);\n const r1 = convert(u.scales.x!.max!);\n if (r0 !== null && r1 !== null) newRange = [r0, r1];\n }\n\n xAxis = axis;\n render(true);\n\n // Apply converted zoom\n if (newRange) {\n scaleSyncing = true;\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: newRange![0], max: newRange![1] }));\n });\n scaleSyncing = false;\n }\n }\n\n function toggleStats() {\n statsVisible = !statsVisible;\n plots.forEach(({ histCol }) => histCol.classList.toggle('visible', statsVisible));\n resize();\n }\n\n function setMapColorChangeCb(cb: (data: { pts: TrackPoint[]; colors: string[] } | null) => void) {\n onMapColorChangeCb = cb;\n }\n\n function toggleMapColor(key: string | null, skipRender = false) {\n if (mapColorMetric === key || key === null) {\n mapColorMetric = null;\n _updateMapColorBtns();\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n } else {\n mapColorMetric = key;\n _updateMapColorBtns();\n _fireMapColorCb();\n }\n // Re-render to show/hide colored fills on the graphs\n if (currentTrack && !skipRender) render(true);\n }\n\n function _updateMapColorBtns() {\n document.querySelectorAll('.map-color-btn').forEach((el) => {\n const b = el as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === mapColorMetric);\n });\n }\n\n function _fireMapColorCb() {\n if (!onMapColorChangeCb || !mapColorMetric || !currentTrack) return;\n const plot = plots.find((p) => p.metricKey === mapColorMetric);\n if (!plot) return;\n const colors = _computePointColors(mapColorMetric, plot.yData);\n onMapColorChangeCb({ pts: currentTrack.points, colors });\n }\n\n function _computePointColors(key: string, yData: (number | null)[]): string[] {\n const vals = yData.filter((v): v is number => v != null && isFinite(v));\n if (!vals.length) return yData.map(() => '#888896');\n const min = Math.min(...vals),\n max = Math.max(...vals);\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n return yData.map((v) => {\n if (v == null || !isFinite(v)) return '#888896';\n if (key === 'gradient') return gradientColor(v);\n if (key === 'speed') {\n if (speedMode === 'pace') {\n const speed = (paceUnit === 'km' ? 1000 : 100) / v;\n return speedColor(speed);\n }\n return speedColor(v);\n }\n const t = max === min ? 0.5 : Math.max(0, Math.min(1, (v - min) / (max - min)));\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25);\n if (t <= 0.5) return lerpHex('#91bfdb', '#fee090', (t - 0.25) / 0.25);\n if (t <= 0.75) return lerpHex('#fee090', '#fc8d59', (t - 0.5) / 0.25);\n return lerpHex('#fc8d59', '#d73027', (t - 0.75) / 0.25);\n });\n }\n\n function resetZoom() {\n cancelSelection();\n }\n\n function cancelSelection() {\n selAnchorVal = null;\n selEndVal = null;\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n\n // Reset individual histogram pins\n plots.forEach((p) => {\n p.pinnedHistY = null;\n });\n\n updateSelOverlay();\n redrawHistograms();\n\n // Perform the actual zoom reset\n scaleSyncing = true;\n plots.forEach(({ uplot: u, xData }) => {\n u.batch(() => u.setScale('x', { min: xData[0]!, max: xData[xData.length - 1]! }));\n u._strasse?.updateHeaderStats(xData[0]!, xData[xData.length - 1]!);\n });\n scaleSyncing = false;\n\n if (onRangeChangeCb) onRangeChangeCb(null, null, xAxis);\n }\n\n function setSelectionStats(stats: TrackStats) {\n if (!selStatsEl) return;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt(\n 'sel-distance',\n stats.totalDist != null ? `${(stats.totalDist / 1000).toFixed(1)} km` : '\u2014',\n );\n fmt('sel-duration', stats.duration != null ? fmtSecs(Math.floor(stats.duration / 1000)) : '\u2014');\n fmt('sel-elevation', stats.elevGain != null ? `${Math.round(stats.elevGain)} m` : '\u2014');\n fmt(\n 'sel-avg-speed',\n stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014',\n );\n fmt('sel-avg-power', stats.avgPower != null ? `${stats.avgPower} W` : '\u2014');\n fmt('sel-avg-hr', stats.avgHR != null ? `${stats.avgHR} bpm` : '\u2014');\n fmt('sel-avg-temp', stats.avgTemp != null ? `${stats.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n selStatsEl.classList.remove('hidden');\n if (resetSelBtn) resetSelBtn.classList.remove('hidden');\n }\n\n function clearSelectionStats() {\n if (selStatsEl) selStatsEl.classList.add('hidden');\n if (resetSelBtn) resetSelBtn.classList.add('hidden');\n [\n 'sel-distance',\n 'sel-duration',\n 'sel-elevation',\n 'sel-avg-speed',\n 'sel-avg-power',\n 'sel-avg-hr',\n 'sel-avg-temp',\n ].forEach((id) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = '--';\n });\n }\n\n // Called on boot to restore a saved selection without re-firing onRangeChangeCb\n // xMin/xMax are ALWAYS provided in Time (seconds from start)\n function restoreSelection(tMin: number, tMax: number, deferRender = false) {\n if (!currentTrack) return;\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const totalDuration = ((pts[pts.length - 1]?.time || 0) - t0) / 1000;\n\n // If values look like absolute timestamps in ms, convert to seconds from start\n if (tMin > 1e12) tMin = (tMin - t0) / 1000;\n if (tMax > 1e12) tMax = (tMax - t0) / 1000;\n\n // Crop to max limits of the track\n tMin = Math.max(0, Math.min(tMin, totalDuration));\n tMax = Math.max(0, Math.min(tMax, totalDuration));\n\n const convert = (tOffset: number) => {\n if (xAxis === 'time') return tOffset;\n const tTarget = t0 + tOffset * 1000;\n let idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n if (idx === -1) idx = pts.length - 1;\n return (pts[idx].dist || 0) / 1000;\n };\n\n const xMin = convert(tMin);\n const xMax = convert(tMax);\n\n selAnchorVal = xMin;\n selEndVal = xMax;\n currentXRange = [xMin, xMax];\n if (deferRender) return;\n scaleSyncing = true; // suppress the setScale \u2192 onRangeChangeCb loop\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: xMin, max: xMax }));\n });\n scaleSyncing = false;\n updateAnchorLines();\n redrawHistograms();\n }\n\n function resize() {\n if (!plots.length || !container) return;\n const w = Math.round(\n Math.max(\n 100,\n container.getBoundingClientRect().width -\n ROW_BODY_PADDING -\n (statsVisible ? HIST_W + HIST_GAP : 0),\n ),\n );\n let anyResized = false;\n plots.forEach(({ uplot: u, histCanvas, histData }) => {\n if (w !== u.width) {\n u.setSize({ width: w, height: u.height });\n anyResized = true;\n if (statsVisible && histCanvas && histData) drawHistogram(histCanvas, histData, u.height);\n }\n });\n if (anyResized) updateSelOverlay();\n }\n\n // \u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function render(keepState = false) {\n let savedRange: [number, number] | null = null;\n let savedScroll = 0;\n if (keepState && container) savedScroll = container.scrollTop;\n\n if (keepState && currentXRange) {\n savedRange = [currentXRange[0], currentXRange[1]];\n } else if (keepState && plots.length) {\n const u = plots[0].uplot;\n savedRange = [u.scales.x!.min!, u.scales.x!.max!];\n }\n\n if (!currentTrack) {\n destroyPlots(keepState);\n return;\n }\n const pts = currentTrack.points;\n if (!pts.length) {\n destroyPlots(keepState);\n return;\n }\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n const available = [...activeMetrics].filter((m) =>\n pts.some((p) => p[METRICS[m].field] != null),\n );\n if (!available.length) {\n destroyPlots(keepState);\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
No data for selected metrics
\n `;\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n\n const containerW = container ? container.getBoundingClientRect().width : 800;\n const w = Math.round(\n Math.max(100, containerW - ROW_BODY_PADDING - (statsVisible ? HIST_W + HIST_GAP : 0)),\n );\n\n const canReuse =\n keepState &&\n renderedTrack === currentTrack &&\n renderedXAxis === xAxis &&\n renderedSpeedMode === speedMode &&\n renderedMapColorMetric === mapColorMetric &&\n plots.length > 0;\n\n let xData: (number | null)[];\n if (canReuse) {\n xData = plots[0].xData;\n } else if (xAxis === 'distance') {\n xData = pts.map((p) => (p.dist || 0) / 1000);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n let lastValidX = 0;\n xData = pts.map((p) => {\n if (p.time != null) {\n lastValidX = (p.time - t0) / 1000;\n return lastValidX;\n }\n return lastValidX; // monotonic fallback\n });\n }\n\n const existingByKey = new Map();\n if (canReuse) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const availSet = new Set(available);\n for (const p of plots) {\n const isSmoothed = smoothedMetrics.has(p.metricKey);\n const isIncZero = metricsIncludingZero.has(p.metricKey);\n if (\n availSet.has(p.metricKey) &&\n p.smoothed === isSmoothed &&\n p.incZero === isIncZero &&\n p.w === w\n ) {\n existingByKey.set(p.metricKey, p);\n } else {\n syncKey!.unsub(p.uplot);\n p.uplot.destroy();\n p.row.remove();\n }\n }\n plots = [];\n } else {\n destroyPlots(keepState);\n }\n\n if (container) {\n const nextSiblingRows: (HTMLElement | null)[] = new Array(available.length).fill(null);\n let nextExisting: HTMLElement | null = null;\n for (let i = available.length - 1; i >= 0; i--) {\n nextSiblingRows[i] = nextExisting;\n const ex = existingByKey.get(available[i]);\n if (ex) nextExisting = ex.row;\n }\n\n available.forEach((key, idx) => {\n const reused = existingByKey.get(key);\n if (reused) {\n plots.push(reused);\n const uplot = reused.uplot;\n const s = (uplot as any)._strasse;\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n uplot.batch(() => {\n if (\n savedRange &&\n (uplot.scales.x!.min !== savedRange[0] || uplot.scales.x!.max !== savedRange[1])\n ) {\n uplot.setScale('x', { min: savedRange[0], max: savedRange[1] });\n } else {\n s?.updateHeaderStats(uplot.scales.x!.min!, uplot.scales.x!.max!, uplot);\n uplot.redraw(false);\n }\n });\n scaleSyncing = prevSync;\n\n let initHoverBinI: number | null = null;\n if (\n pinnedPtIdx != null &&\n reused.xData[pinnedPtIdx] != null &&\n reused.yData[pinnedPtIdx] != null\n ) {\n buildHistBins(reused.histData);\n if (reused.histData.min != null && reused.histData.max != null) {\n const span = reused.histData.max - reused.histData.min || 1;\n initHoverBinI = Math.min(\n reused.histData.BINS - 1,\n Math.floor(\n ((reused.yData[pinnedPtIdx]! - reused.histData.min) / span) *\n reused.histData.BINS,\n ),\n );\n reused.hoveredHistY = reused.yData[pinnedPtIdx];\n }\n }\n drawHistogram(reused.histCanvas, reused.histData, 130, initHoverBinI);\n return;\n }\n\n let def = METRICS[key];\n\n let transform = def.transform;\n let fmt = def.fmt;\n let fmtAxis = def.fmtAxis;\n let unit = def.unit;\n let label = def.label;\n\n if (key === 'speed' && speedMode === 'pace') {\n label = 'Pace';\n unit = `min/${paceUnit}`;\n fmt = (v) => fmtPace(v);\n fmtAxis = (v) => fmtPace(v);\n transform = (v) => {\n if (v == null || v < 0.1) return null;\n return (paceUnit === 'km' ? 1000 : 100) / v;\n };\n\n def = { ...def, label, unit, fmt, fmtAxis, transform };\n }\n\n let yData = def.compute\n ? def.compute(pts, fillNulls)\n : fillNulls(\n pts.map((p) => {\n const v = p[def.field] as number;\n return v != null && transform ? transform(v) : v;\n }),\n );\n\n if (smoothedMetrics.has(key)) yData = gaussianSmooth(yData, def.smoothSigma || 2);\n\n createChart(key, def, xData, yData, w, pts, savedRange, nextSiblingRows[idx]);\n });\n }\n\n renderedTrack = currentTrack;\n renderedXAxis = xAxis;\n renderedSpeedMode = speedMode;\n renderedMapColorMetric = mapColorMetric;\n\n updateStats(currentTrack);\n // Restore anchor/end lines if a selection was active\n if (selAnchorVal != null && selEndVal != null) updateAnchorLines();\n // Re-apply map color if active\n _updateMapColorBtns();\n if (mapColorMetric) _fireMapColorCb();\n\n if (keepState && container && savedScroll > 0) container.scrollTop = savedScroll;\n }\n\n // \u2500\u2500 Create one chart row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function createChart(\n metricKey: string,\n def: MetricDefinition,\n xData: (number | null)[],\n yData: (number | null)[],\n w: number,\n pts: TrackPoint[],\n initialRange: [number, number] | null = null,\n insertBeforeEl: HTMLElement | null = null,\n ) {\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n\n // Gradient data: smooth over a 20 m distance window (\u00B110 m each side)\n const gradData = metricKey === 'elevation' ? smoothGradient(pts, 20) : null;\n const row = document.createElement('div');\n row.className = 'chart-row';\n row.dataset.metric = metricKey;\n row.style.setProperty('--chart-color', def.color);\n\n // Header\n const header = document.createElement('div');\n header.className = `chart-row-header${statsVisible ? ' with-histogram' : ''}`;\n\n const labelEl = document.createElement('div');\n labelEl.className = 'chart-row-label-group';\n labelEl.innerHTML = `\n ${def.icon}\n ${def.label}\n `;\n\n // Smoothing toggle\n const smoothBtn = document.createElement('button');\n smoothBtn.className = `icon-btn mini smooth-btn${smoothedMetrics.has(metricKey) ? ' active' : ''}`;\n smoothBtn.title = 'Toggle data smoothing';\n smoothBtn.innerHTML = `${smoothedMetrics.has(metricKey) ? 'blur_on' : 'blur_off'}`;\n smoothBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (smoothedMetrics.has(metricKey)) smoothedMetrics.delete(metricKey);\n else smoothedMetrics.add(metricKey);\n\n render(true); // Re-render all charts to keep sync if needed (though only this one changes data)\n });\n\n const mapColorBtn = document.createElement('button');\n\n mapColorBtn.className = `map-color-btn icon-btn${mapColorMetric === metricKey ? ' active' : ''}`;\n mapColorBtn.dataset.metric = metricKey;\n mapColorBtn.title = 'Color map track by this metric';\n mapColorBtn.innerHTML = 'colorize';\n mapColorBtn.addEventListener('click', () => toggleMapColor(metricKey));\n\n // Zero-filter toggle (Cadence/Power/Speed)\n let zeroBtn: HTMLButtonElement | null = null;\n if (metricKey === 'cadence' || metricKey === 'power' || metricKey === 'speed') {\n zeroBtn = document.createElement('button');\n const incZero = metricsIncludingZero.has(metricKey);\n zeroBtn.className = `icon-btn mini${incZero ? ' active' : ''}`;\n zeroBtn.title = incZero ? 'Currently INCLUDING 0 values' : 'Currently EXCLUDING 0 values';\n zeroBtn.innerHTML = `${incZero ? 'exposure_zero' : 'mobile_off'}`;\n zeroBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (metricsIncludingZero.has(metricKey)) metricsIncludingZero.delete(metricKey);\n else metricsIncludingZero.add(metricKey);\n render(true);\n });\n }\n\n const statsTotalEl = document.createElement('div');\n statsTotalEl.className = 'chart-stats-total';\n\n const statsSelEl = document.createElement('div');\n statsSelEl.className = 'chart-stats-selection';\n\n const statsContainer = document.createElement('div');\n statsContainer.className = 'chart-row-stats-container';\n statsContainer.append(statsTotalEl, statsSelEl);\n\n const actionsEl = document.createElement('div');\n actionsEl.className = 'chart-row-actions';\n actionsEl.append(smoothBtn, mapColorBtn);\n\n const rightActionsEl = document.createElement('div');\n rightActionsEl.className = 'chart-row-right-actions';\n\n if (metricKey === 'speed') {\n const paceToggle = document.createElement('div');\n paceToggle.className = 'seg-ctrl';\n paceToggle.innerHTML = `\n \n \n `;\n paceToggle.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const mode = btn.dataset.mode;\n if (mode === 'speed' || mode === 'pace') {\n const isDefault = mode === defaultMode;\n UrlState.patch({ speed_mode: isDefault ? null : mode });\n render(true);\n }\n });\n rightActionsEl.append(paceToggle);\n }\n\n if (zeroBtn) rightActionsEl.append(zeroBtn);\n\n header.append(labelEl, actionsEl, statsContainer, rightActionsEl);\n\n const rowBody = document.createElement('div');\n rowBody.className = 'chart-row-body';\n\n const plotEl = document.createElement('div');\n plotEl.style.position = 'relative';\n rowBody.appendChild(plotEl);\n\n const fixedMinLabel = document.createElement('div');\n fixedMinLabel.className = 'fixed-x-label fixed-x-min';\n const fixedMaxLabel = document.createElement('div');\n fixedMaxLabel.className = 'fixed-x-label fixed-x-max';\n plotEl.append(fixedMinLabel, fixedMaxLabel);\n\n const histCol = document.createElement('div');\n histCol.className = `hist-col${statsVisible ? ' visible' : ''}`;\n const histCanvas = document.createElement('canvas');\n histCanvas.className = 'hist-canvas';\n histCol.appendChild(histCanvas);\n rowBody.appendChild(histCol);\n\n row.append(header, rowBody);\n\n const isDistAxis = xAxis === 'distance';\n\n function formatX(v: number, range: number): string {\n if (v == null) return '';\n if (isDistAxis) {\n const dec = range < 1 ? 3 : range < 5 ? 2 : range < 20 ? 1 : 0;\n return `${v.toFixed(dec)} km`;\n } else {\n const absV = Math.abs(v);\n const h = Math.floor(absV / 3600);\n const m = Math.floor((absV % 3600) / 60);\n const s = Math.round(absV % 60);\n const hh = h > 0 ? `${h}:` : '';\n const mm = h > 0 ? String(m).padStart(2, '0') : String(m);\n const ss = String(s).padStart(2, '0');\n return `${v < 0 ? '-' : ''}${hh}${mm}:${ss}`;\n }\n }\n\n const incZeroDefault =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Compute global Y range and full-track stats in a single pass\n let gMin = Infinity,\n gMax = -Infinity,\n allSum = 0,\n allCount = 0,\n filtMin = Infinity,\n filtMax = -Infinity,\n filtSum = 0,\n filtCount = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n allSum += v;\n allCount++;\n if (v !== 0 || incZeroDefault) {\n if (v < filtMin) filtMin = v;\n if (v > filtMax) filtMax = v;\n filtSum += v;\n filtCount++;\n }\n }\n if (allCount === 0) {\n gMin = 0;\n gMax = 100;\n }\n const fullStatsAll = allCount ? { min: gMin, max: gMax, avg: allSum / allCount } : null;\n const fullStatsFiltered = filtCount\n ? { min: filtMin, max: filtMax, avg: filtSum / filtCount }\n : null;\n const gPad = Math.abs(gMax - gMin) * 0.1 || 1;\n const fixedYRange = [gMin - gPad, gMax + gPad];\n\n let statsTotalInitialized = false;\n\n // Per-range stats\n function updateHeaderStats(visibleMin: number, visibleMax: number, u?: uPlot) {\n const incZero =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Update fixed X labels\n const range = visibleMax - visibleMin;\n fixedMinLabel.textContent = formatX(visibleMin, range);\n fixedMaxLabel.textContent = formatX(visibleMax, range);\n\n const getHtml = (xMin: number, xMax: number, isFull = false) => {\n const s =\n isFull && incZero === incZeroDefault\n ? fullStatsFiltered\n : rangeStats(xData, yData, xMin, xMax, incZero);\n if (!s) return '';\n\n let h = `\n align_flex_end${def.fmt(s.min, true)} ${def.unit}\n align_center${def.fmt(s.avg, true)} ${def.unit}\n align_flex_start${def.fmt(s.max, true)} ${def.unit}\n `;\n\n if (metricKey === 'elevation') {\n const es = elevationRangeStats(pts, xMin, xMax);\n h += `\n trending_up+${Math.round(es.gain)} m\n trending_down-${Math.round(es.loss)} m\n `;\n }\n return h;\n };\n\n if (!statsTotalInitialized) {\n statsTotalInitialized = true;\n statsTotalEl.innerHTML = `all_inclusive${getHtml(\n xData[0]!,\n xData[xData.length - 1]!,\n true,\n )}`;\n statsTotalEl.querySelector('.all-chip')?.addEventListener('click', (e) => {\n e.stopPropagation();\n cancelSelection();\n });\n }\n\n if (selAnchorVal !== null && selEndVal !== null) {\n statsSelEl.innerHTML = getHtml(selAnchorVal, selEndVal, false);\n statsSelEl.style.display = 'flex';\n statsSelEl.style.setProperty('--sel-color', def.color);\n } else {\n statsSelEl.style.display = 'none';\n }\n }\n let initializingScale = false;\n const uOpts: uPlot.Options = {\n width: w,\n height: 130,\n padding: [4, 0, 0, 0],\n cursor: {\n sync: {\n key: syncKey!.key,\n },\n drag: { x: true, y: false, uni: 16 },\n focus: { prox: 16 },\n points: {\n size: 7,\n stroke: '#0e0e10',\n width: 2,\n fill: (metricKey === 'elevation'\n ? (u: uPlot, _si: number) => gradientColor(gradData ? gradData[u.cursor.idx!]! : null)\n : def.color) as any,\n },\n x: false,\n y: false,\n },\n select: {\n show: true,\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n },\n legend: { show: false },\n scales: {\n x: {\n time: false,\n range: (_u: uPlot, mn: number, mx: number) => [mn, mx],\n min: initialRange ? initialRange[0] : undefined,\n max: initialRange ? initialRange[1] : undefined,\n },\n y: {\n range: () => fixedYRange as [number, number],\n dir: metricKey === 'speed' && speedMode === 'pace' ? -1 : 1,\n },\n },\n axes: [\n {\n side: 2, // bottom\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: {\n show: true,\n stroke: '#2e2e34',\n },\n size: 30,\n space: 80,\n font: '10px system-ui, sans-serif',\n splits: (u: uPlot, axisIdx: number, scaleMin: number, scaleMax: number) => {\n const range = scaleMax - scaleMin;\n const width = u.bbox.width > 0 ? u.bbox.width : u.width;\n const targetLabels = width / 80;\n const idealIncr = range / targetLabels;\n\n let incrs;\n if (!isDistAxis) {\n // Time in seconds\n incrs = [\n 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 14400, 28800, 43200,\n 86400, 604800, 2592000, 31536000,\n ];\n } else {\n incrs = [\n 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000,\n 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000,\n ];\n }\n\n let incr = incrs[incrs.length - 1];\n for (let i = 0; i < incrs.length; i++) {\n if (incrs[i] >= idealIncr) {\n incr = incrs[i];\n break;\n }\n }\n\n const splits = [];\n let val = Math.ceil(scaleMin / incr) * incr;\n const precision = incr < 1 ? 2 : 0;\n\n while (val <= scaleMax) {\n const pos = u.valToPos(val, 'x', true);\n if (pos >= u.bbox.left + 80 && pos <= u.bbox.left + u.bbox.width - 80)\n splits.push(Number(val.toFixed(precision)));\n\n val += incr;\n }\n return splits;\n },\n values: ((_u: uPlot, vals: number[]) => {\n const range = (_u.scales.x?.max ?? 1) - (_u.scales.x?.min ?? 0);\n\n return vals.map((v) => {\n if (v == null) return '';\n const pos = _u.valToPos(v, 'x', true);\n // Strict 80px margin to prevent overlapping with fixed labels or Y axis\n if (pos < _u.bbox.left + 80 || pos > _u.bbox.left + _u.bbox.width - 80) return null;\n return formatX(v, range);\n });\n }) as any,\n },\n {\n side: 3, // left\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: { stroke: '#2e2e34' },\n size: 55,\n font: '10px system-ui, sans-serif',\n values: ((_u: uPlot, vals: number[]) =>\n vals.map((v) => (v != null ? def.fmtAxis(v) : ''))) as any,\n },\n ],\n series: [\n {},\n // Main selected track series\n {\n label: def.label,\n stroke: 'rgba(0,0,0,0)', // Stroke handled in draw hooks for layering\n width: 0,\n points: { show: false },\n paths: () => null,\n },\n ],\n hooks: {\n draw: [\n (u: uPlot) => {\n const top = u.bbox.top + u.bbox.height + 5; // 5px below plot area!\n fixedMinLabel.style.top = `${top}px`;\n fixedMinLabel.style.left = `${u.bbox.left}px`;\n\n fixedMaxLabel.style.top = `${top}px`;\n fixedMaxLabel.style.left = `${u.bbox.left + u.bbox.width}px`;\n fixedMaxLabel.style.transform = 'translateX(-100%)';\n },\n // 1. (bottom) Color / metric color of the selected track\n (u: uPlot) => {\n if (metricKey === 'gears') {\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n } else if (metricKey === 'elevation') {\n drawElevationGradient(u, xData as number[], yData as number[], gradData);\n } else if (metricKey === 'gradient') {\n drawGradientChart(u, xData as number[], yData as number[]);\n } else if (mapColorMetric === metricKey) {\n drawMetricColorFill(u, xData as number[], yData as number[], pts, metricKey);\n } else {\n // Normal colored line\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n }\n },\n\n // 2. Pinned point (middle)\n (u: uPlot) => {\n const plot = plots.find((p) => p.uplot === u);\n if (!plot) return;\n\n const s = (u as any)._strasse;\n // Priority 1: Global pinned point (all charts)\n if (pinnedPtIdx != null) {\n drawPinnedDot(u, xData, yData, def.color, def, pts, metricKey);\n } else {\n if (s && s.pinYVal) s.pinYVal.style.display = 'none';\n\n // Priority 2: Individual histogram pinned Y-pos (this chart only)\n if (plot.pinnedHistY != null)\n drawYAxisHighlight(u, xData, yData, plot.pinnedHistY, def.color, def);\n }\n },\n\n // 3. Pinned & Hover elements (labels, vertical lines)\n (u: uPlot) => {\n const hIdx = u.cursor.idx;\n const hasPinned = pinnedPtIdx != null;\n\n let hasHover = hIdx != null && u.cursor.left! >= 0;\n if (hasHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[hIdx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) hasHover = false;\n }\n\n // B. Draw Hover vertical line\n if (hasHover && hIdx !== pinnedPtIdx)\n drawVerticalLineOnly(u, pts, hIdx!, hexToRgba(def.color, 0.4), 1.0);\n\n // C. Bold selection x-axis line & span pill\n if (selAnchorVal != null && selEndVal != null) {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ax = u.valToPos(selAnchorVal, 'x', true);\n const ex = u.valToPos(selEndVal, 'x', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.lineWidth = 3 * dpr;\n ctx.strokeStyle = def.color;\n ctx.moveTo(ax, bb.top + bb.height);\n ctx.lineTo(ex, bb.top + bb.height);\n ctx.stroke();\n\n const span = Math.abs(selEndVal - selAnchorVal);\n const label = xAxis === 'distance' ? `${span.toFixed(2)} km` : fmtSecs(span);\n const fontSize = 9 * dpr;\n const fontStr = `bold ${fontSize}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n\n const visibleL = Math.max(bb.left, ax);\n const visibleR = Math.min(bb.left + bb.width, ex);\n const visibleW = visibleR - visibleL;\n\n if (visibleW > tw + 14 * dpr) {\n const padH = 5 * dpr;\n const padV = 2 * dpr;\n const bw = tw + padH * 2;\n const bh = fontSize + padV * 2;\n const bx = (visibleL + visibleR) / 2 - bw / 2;\n const by = bb.top + bb.height - bh / 2;\n\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = def.color;\n ctx.fill();\n\n ctx.fillStyle = '#000';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2);\n }\n ctx.restore();\n }\n\n // D. Draw label pills (on top)\n // Pinned labels first (semi-transparent)\n if (hasPinned) drawXAxisLabels(u, pts, pinnedPtIdx!, def.color, true, 0.7);\n\n // Hover labels last (fully opaque, topmost)\n if (hasHover && hIdx !== pinnedPtIdx)\n drawXAxisLabels(u, pts, hIdx!, def.color, true, 1.0);\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (scaleSyncing) return;\n const idx = u.cursor.idx;\n\n // Trigger redraw on cursor move to ensure custom canvas markers (hover lines/labels) update live\n // Note: uPlot handles cross-chart sync when syncKey is used.\n u.redraw(false);\n\n // Track current x-value for keyboard navigation\n if (u.cursor.left! >= 0) lastMouseXVal = u.posToVal(u.cursor.left!, 'x');\n else lastMouseXVal = null;\n\n // \u2500\u2500 Floating y-value next to cursor dot \u2500\u2500\n const s = (u as any)._strasse;\n let showHover = idx != null && yData[idx] != null;\n\n // Distance threshold: if no pinned point, check proximity to data line\n if (showHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[idx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) showHover = false;\n }\n\n if (s) {\n if (showHover)\n updateTooltip(\n u,\n s.curYVal,\n idx!,\n xData as number[],\n yData as number[],\n pts,\n def,\n metricKey,\n );\n else s.curYVal.style.display = 'none';\n }\n\n // Map marker\n if (!cursorSyncing) {\n if (idx != null && pts[idx]) {\n if (onCursorMoveCb && (pinnedPtIdx != null || showHover)) {\n onCursorMoveCb(pts[idx]);\n } else if (onCursorMoveCb && !showHover) {\n // If we're too far and nothing is pinned, hide map cursor\n onCursorMoveCb(null);\n }\n } else if (idx === null && onCursorMoveCb) {\n onCursorMoveCb(null);\n }\n }\n\n // Highlight matching histogram bucket\n if (idx != null && yData[idx] != null) {\n const { min, max } = histData;\n if (min != null && max != null) {\n const span = max - min || 1;\n const binI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[idx]! - min) / span) * histData.BINS),\n );\n if (plot.hoveredHistY !== yData[idx]) {\n plot.hoveredHistY = yData[idx];\n drawHistogram(histCanvas, histData, 130, binI);\n }\n }\n } else if (plot.hoveredHistY !== null) {\n plot.hoveredHistY = null;\n drawHistogram(histCanvas, histData, 130);\n }\n },\n ],\n\n setScale: [\n (u: uPlot, key: string) => {\n if (key !== 'x' || initializingScale) return;\n const { min, max } = u.scales.x!;\n\n // Sync currentXRange so keyboard navigation baseline is always accurate\n currentXRange = [min!, max!];\n\n // Update header stats for VISIBLE range\n updateHeaderStats(min as number, max as number, u);\n\n if (scaleSyncing) return;\n\n // Clear keyboard target when user interacts via mouse\n if (!updatingRange) targetXRange = null;\n\n // Sync sibling plots\n scaleSyncing = true;\n plots.forEach(({ uplot: other }) => {\n if (other !== u) other.batch(() => other.setScale('x', { min: min!, max: max! }));\n });\n scaleSyncing = false;\n\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb && selAnchorVal !== null)\n onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n },\n ],\n\n setSelect: [\n (u: uPlot) => {\n if (updatingRange) return;\n targetXRange = null;\n const { left, width } = u.select;\n if (width > 0) {\n const min = u.posToVal(left, 'x');\n const max = u.posToVal(left + width, 'x');\n selAnchorVal = min;\n selEndVal = max;\n\n // Sync stats to new selection\n updateHeaderStats(u.scales.x!.min!, u.scales.x!.max!, u);\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n\n // Clear uPlot's internal selection immediately so it doesn't block WASD/interaction\n u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);\n }\n },\n ],\n },\n };\n\n // \u2500\u2500 Overlay (pointer-events off except handles) \u2500\u2500\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5';\n\n // Selection fill\n const selFill = document.createElement('div');\n selFill.className = 'sel-fill';\n selFill.style.display = 'none';\n\n // Anchor line + label + drag handle\n const anchorLine = document.createElement('div');\n anchorLine.className = 'sel-line sel-line-anchor';\n anchorLine.style.display = 'none';\n\n const anchorLabel = document.createElement('div');\n anchorLabel.className = 'sel-line-label sel-line-label-anchor';\n anchorLabel.style.display = 'none';\n\n const anchorHandle = document.createElement('div');\n anchorHandle.className = 'sel-handle sel-handle-anchor';\n anchorHandle.style.display = 'none';\n\n const anchorMarker = document.createElement('div');\n anchorMarker.className = 'sel-graph-marker';\n anchorMarker.innerHTML =\n 'play_circle';\n anchorMarker.style.display = 'none';\n\n // End line + label + drag handle\n const endLine = document.createElement('div');\n endLine.className = 'sel-line sel-line-end';\n endLine.style.display = 'none';\n\n const endLabel = document.createElement('div');\n endLabel.className = 'sel-line-label sel-line-label-end';\n endLabel.style.display = 'none';\n\n const endHandle = document.createElement('div');\n endHandle.className = 'sel-handle sel-handle-end';\n endHandle.style.display = 'none';\n\n const endMarker = document.createElement('div');\n endMarker.className = 'sel-graph-marker';\n endMarker.innerHTML =\n 'stop_circle';\n endMarker.style.display = 'none';\n\n // Floating cursor y-value\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${def.color};display:none`;\n\n // Floating pinned y-value\n const pinYVal = document.createElement('div');\n pinYVal.className = 'cur-y-val pin';\n pinYVal.style.cssText = `color:${def.color};display:none`;\n\n overlay.append(\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n );\n\n const histData: HistData = {\n yData,\n xData: xData as number[],\n def,\n BINS: 24,\n min: allCount ? gMin : undefined,\n max: allCount ? gMax : undefined,\n fullStats: fullStatsFiltered,\n fullStatsAll,\n };\n const plot: PlotData = {\n uplot: null as any,\n row,\n xData: xData as number[],\n yData,\n def,\n metricKey,\n statsTotalEl,\n statsSelEl,\n histCol,\n histCanvas,\n histData,\n hoveredHistY: null,\n pinnedHistY: null,\n smoothed: smoothedMetrics.has(metricKey),\n incZero: metricsIncludingZero.has(metricKey),\n w,\n };\n histData.plot = plot; // Back-reference for tooltip to trigger redraws\n\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n const uplot = new uPlot(uOpts, [xData, yData] as any, (self, init) => {\n plot.uplot = self as WegPlot;\n plots.push(plot);\n plotEl.appendChild(self.root);\n self.over.appendChild(overlay);\n (self as any)._strasse = {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n updateHeaderStats,\n };\n self.batch(() => {\n init();\n });\n }) as WegPlot;\n scaleSyncing = prevSync;\n\n // \u2500\u2500 Handle drag \u2500\u2500\n attachHandleDrag(anchorHandle, uplot, xData, true);\n attachHandleDrag(endHandle, uplot, xData, false);\n\n // \u2500\u2500 Mouse listeners \u2500\u2500\n let mousedownX: number | null = null;\n uplot.over.addEventListener('mousedown', (e) => {\n if (e.button !== 0) return;\n isDragging = false;\n const rect = uplot.over.getBoundingClientRect();\n const xPx = e.clientX - rect.left;\n mousedownX = xPx;\n });\n uplot.over.addEventListener('mousemove', (e) => {\n if (mousedownX !== null) {\n const rect = uplot.over.getBoundingClientRect();\n if (Math.abs(e.clientX - rect.left - mousedownX) > 5) isDragging = true;\n }\n });\n uplot.over.addEventListener('mouseup', () => {\n mousedownX = null;\n });\n\n // Click to pin point (sticky selection)\n uplot.over.addEventListener('click', () => {\n if (isDragging) return;\n const idx = uplot.cursor.idx;\n if (idx != null && pts[idx]) {\n pinnedPtIdx = idx;\n plots.forEach(({ uplot: u }) => u.redraw(false));\n if (onClickCb) onClickCb(pts[idx], idx);\n if (onPinChangeCb) onPinChangeCb(idx);\n }\n });\n\n row.addEventListener('dblclick', cancelSelection);\n\n let initHoverBinI: number | null = null;\n if (pinnedPtIdx != null && xData[pinnedPtIdx] != null && yData[pinnedPtIdx] != null) {\n buildHistBins(histData);\n if (histData.min != null && histData.max != null) {\n const span = histData.max - histData.min || 1;\n initHoverBinI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[pinnedPtIdx]! - histData.min) / span) * histData.BINS),\n );\n plot.hoveredHistY = yData[pinnedPtIdx];\n }\n }\n\n drawHistogram(histCanvas, histData, 130, initHoverBinI);\n attachHistTooltip(histCanvas, histData);\n if (container) {\n if (insertBeforeEl) container.insertBefore(row, insertBeforeEl);\n else container.appendChild(row);\n }\n }\n\n // \u2500\u2500 Selection overlay (fill + lines + handles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateSelOverlay() {\n updateAnchorLines();\n // Redraw canvas markers (bold selection line + span pill)\n plots.forEach(({ uplot: u }) => u.batch(() => u.redraw(false)));\n }\n\n function updateAnchorLines() {\n plots.forEach(({ uplot: u, def }) => {\n const s = (u as any)._strasse;\n if (!s) return;\n const {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n } = s;\n if (selAnchorVal == null || selEndVal == null) {\n [\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n ].forEach((el: HTMLElement) => {\n el.style.display = 'none';\n });\n return;\n }\n const aX = u.valToPos(selAnchorVal, 'x');\n const eX = u.valToPos(selEndVal, 'x');\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const overW = bb.width / dpr;\n const overH = bb.height / dpr;\n const plotBottom = (bb.top + bb.height) / dpr;\n\n const isAnchorVisible = aX >= 0 && aX <= overW;\n const isEndVisible = eX >= 0 && eX <= overW;\n\n // Fill: clamp left/right to visible area\n const fillL = Math.max(0, aX);\n const fillR = Math.min(overW, eX);\n if (fillR > fillL) {\n selFill.style.left = `${fillL}px`;\n selFill.style.width = `${fillR - fillL}px`;\n selFill.style.top = '0';\n selFill.style.height = `${overH}px`;\n selFill.style.backgroundColor = hexToRgba(def.color, 0.07);\n selFill.style.display = '';\n } else {\n selFill.style.display = 'none';\n }\n\n // Anchor line\n if (isAnchorVisible) {\n anchorLine.style.left = `${aX}px`;\n anchorLine.style.height = `${overH}px`;\n anchorLine.style.borderLeftColor = def.color;\n anchorLine.style.display = '';\n // Anchor label\n const aText = fmtXVal(selAnchorVal);\n anchorLabel.textContent = aText;\n const aLabelW = aText.length * 7 + 10;\n anchorLabel.style.left = aX + aLabelW + 4 < overW ? `${aX + 3}px` : `${aX - aLabelW - 3}px`;\n anchorLabel.style.display = '';\n // Anchor handle\n anchorHandle.style.left = `${aX}px`;\n anchorHandle.style.backgroundColor = def.color;\n anchorHandle.style.display = '';\n // Anchor marker: centered on the bold line\n anchorMarker.style.left = `${aX}px`;\n anchorMarker.style.top = `${plotBottom}px`;\n const aIcon = anchorMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (aIcon) aIcon.style.color = def.color;\n anchorMarker.style.display = '';\n } else {\n [anchorLine, anchorLabel, anchorHandle, anchorMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n\n // End line\n if (isEndVisible) {\n endLine.style.left = `${eX}px`;\n endLine.style.height = `${overH}px`;\n endLine.style.borderLeftColor = def.color;\n endLine.style.display = '';\n // End label\n const eText = fmtXVal(selEndVal);\n endLabel.textContent = eText;\n const eLabelW = eText.length * 7 + 10;\n endLabel.style.left = eX - eLabelW - 3 > 0 ? `${eX - eLabelW - 3}px` : `${eX + 3}px`;\n endLabel.style.display = '';\n // End handle\n endHandle.style.left = `${eX}px`;\n endHandle.style.backgroundColor = def.color;\n endHandle.style.display = '';\n // End marker: centered on the bold line\n endMarker.style.left = `${eX}px`;\n endMarker.style.top = `${plotBottom}px`;\n const eIcon = endMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (eIcon) eIcon.style.color = def.color;\n endMarker.style.display = '';\n } else {\n [endLine, endLabel, endHandle, endMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n });\n }\n\n function fmtXVal(v: number) {\n return xAxis === 'distance' ? `${v.toFixed(2)} km` : fmtSecs(v);\n }\n\n // \u2500\u2500 Handle drag logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function attachHandleDrag(\n handleEl: HTMLElement,\n uplot: uPlot,\n xData: (number | null)[],\n isAnchor: boolean,\n ) {\n // pointer-events enabled on the handle itself\n handleEl.style.pointerEvents = 'auto';\n\n handleEl.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n const startX = e.clientX;\n const startVal = isAnchor ? selAnchorVal : selEndVal;\n const overW = uplot.over.offsetWidth;\n // px-per-data-unit at current zoom\n const xMin = uplot.scales.x!.min!,\n xMax = uplot.scales.x!.max!;\n const pxPerUnit = overW / (xMax - xMin);\n const xFull = [xData[0]!, xData[xData.length - 1]!];\n\n document.body.style.cursor = 'ew-resize';\n isDragging = true;\n\n function onMove(me: MouseEvent) {\n const dx = me.clientX - startX;\n let newVal = (startVal || 0) + dx / pxPerUnit;\n newVal = Math.max(xFull[0], Math.min(xFull[1], newVal));\n\n if (isAnchor) selAnchorVal = Math.min(newVal, (selEndVal || xFull[1]) - 0.001);\n else selEndVal = Math.max(newVal, (selAnchorVal || xFull[0]) + 0.001);\n\n // When dragging handles, we typically want to stay zoomed to the selection?\n // Actually, let's keep the zoom as is, and just update the selection overlay and stats.\n plots.forEach((p) =>\n (p.uplot as any)._strasse?.updateHeaderStats(\n p.uplot.scales.x!.min!,\n p.uplot.scales.x!.max!,\n ),\n );\n updateSelOverlay();\n redrawHistograms();\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n }\n\n function onUp() {\n document.body.style.cursor = '';\n isDragging = false;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n }\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n }\n\n // \u2500\u2500 Histogram logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function buildHistBins(histData: HistData) {\n const { yData, xData, BINS } = histData;\n\n // Cache to avoid re-binning every frame during hover\n if (histData._lastYData === yData && histData.bins) return;\n histData._lastYData = yData;\n\n let min = histData.min;\n let max = histData.max;\n if (min == null || max == null) {\n let lo = Infinity,\n hi = -Infinity,\n cnt = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < lo) lo = v;\n if (v > hi) hi = v;\n cnt++;\n }\n if (!cnt) return;\n min = lo;\n max = hi;\n histData.min = min;\n histData.max = max;\n }\n\n const bins = new Array(BINS).fill(0);\n const binAccum = new Array(BINS).fill(0); // accumulated x-weight per bin (time in s or dist in km)\n\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n bins[bi]++;\n\n // weight by x-delta\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n binAccum[bi] += (next - prev) / 2;\n }\n histData.bins = bins;\n histData.binAccum = binAccum;\n }\n\n function redrawHistograms() {\n plots.forEach(({ histCanvas, histData, uplot: u }) => {\n drawHistogram(histCanvas, histData, u.height);\n });\n }\n\n function drawHistogram(\n canvas: HTMLCanvasElement,\n histData: HistData,\n chartH: number,\n hoverBinI: number | null = null,\n ) {\n const { def, BINS } = histData;\n buildHistBins(histData);\n const { bins, min, max } = histData;\n if (!bins || min == null || max == null) return;\n\n const hasSel = selAnchorVal != null && selEndVal != null;\n\n // Compute selection bins if a range is active and changed\n if (\n hasSel &&\n (histData._lastSelRange?.[0] !== selAnchorVal || histData._lastSelRange?.[1] !== selEndVal)\n ) {\n histData._lastSelRange = [selAnchorVal!, selEndVal!];\n const selBins = new Array(BINS).fill(0);\n const selBinAccum = new Array(BINS).fill(0);\n const { yData, xData } = histData;\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const x = xData[i];\n if (x == null || x < selAnchorVal! || x > selEndVal!) continue;\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n selBins[bi]++;\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n selBinAccum[bi] += (next - prev) / 2;\n }\n histData.selBins = selBins;\n histData.selBinAccum = selBinAccum;\n } else if (!hasSel) {\n histData.selBins = null;\n histData.selBinAccum = null;\n histData._lastSelRange = null;\n }\n const selBins = histData.selBins;\n\n const dpr = window.devicePixelRatio || 1;\n const W = HIST_W;\n const H = chartH;\n\n // Performance: only set dimensions if they changed (resets canvas)\n if (canvas.width !== W * dpr || canvas.height !== H * dpr) {\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n }\n\n const ctx = canvas.getContext('2d')!;\n ctx.resetTransform();\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, W, H);\n\n const peak = Math.max(...bins);\n\n // Measure label width so bars start right after them\n const fmt = (v: number) => def.fmtAxis(v);\n const fontStr = '9px system-ui, sans-serif';\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const labelW = Math.ceil(\n Math.max(\n ctx.measureText(`${fmt(max)} ${def.unit}`).width,\n ctx.measureText(`${fmt(min)} ${def.unit}`).width,\n ),\n );\n\n // Vertical alignment with main graph:\n // uPlot padding: [4, 0, 0, 0]\n // Axis size: 30\n const pad = { t: 4, r: 0, b: 30, l: labelW + 6 };\n histData.padL = pad.l;\n const plotW = W - pad.l - pad.r;\n const plotH = H - pad.t - pad.b;\n\n // bin 0 = lowest values \u2192 drawn at bottom; bin BINS-1 = highest \u2192 drawn at top\n const binY = (i: number) => pad.t + (BINS - 1 - i) * (plotH / BINS);\n const binH = plotH / BINS - 1;\n\n // Full distribution (dimmed when selection active)\n const baseAlpha = hasSel ? 0.15 : 0.6;\n ctx.fillStyle = hexToRgba(def.color, baseAlpha);\n for (let i = 0; i < BINS; i++) {\n if (!bins[i]) continue;\n const bw = (bins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n\n // Selection overlay (bright)\n if (selBins) {\n ctx.fillStyle = hexToRgba(def.color, 0.85);\n for (let i = 0; i < BINS; i++) {\n if (!selBins[i]) continue;\n const bw = (selBins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n ctx.fillStyle = def.color;\n ctx.fillRect(pad.l, pad.t, 2, plotH);\n }\n\n // CDF overlay \u2014 smooth curve from bottom (0%) to top (100%)\n const total = bins.reduce((s, v) => s + v, 0);\n if (total > 0) {\n // Build CDF points: one per bin boundary, bottom\u2192top\n const pts2 = [{ x: pad.l, y: pad.t + plotH }];\n let cumSum = 0;\n for (let i = 0; i < BINS; i++) {\n cumSum += bins[i];\n pts2.push({ x: pad.l + (cumSum / total) * plotW, y: binY(i) });\n }\n\n ctx.beginPath();\n // CDF line is now solid\n ctx.setLineDash([]);\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 0.75 * dpr;\n ctx.lineJoin = 'round';\n ctx.moveTo(pts2[0].x, pts2[0].y);\n for (let i = 1; i < pts2.length - 1; i++) {\n const mx = (pts2[i].x + pts2[i + 1].x) / 2;\n const my = (pts2[i].y + pts2[i + 1].y) / 2;\n ctx.quadraticCurveTo(pts2[i].x, pts2[i].y, mx, my);\n }\n ctx.lineTo(pts2[pts2.length - 1].x, pts2[pts2.length - 1].y);\n ctx.stroke();\n\n // \u2500\u2500 Hover highlight on CDF \u2500\u2500\n if (hoverBinI != null && pts2[hoverBinI + 1]) {\n const cp = pts2[hoverBinI + 1];\n // Vertical line down\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(def.color, 0.6);\n ctx.moveTo(cp.x, cp.y);\n ctx.lineTo(cp.x, pad.t + plotH);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Dot: tiny precision point\n ctx.beginPath();\n ctx.arc(cp.x, cp.y, 1.2 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n }\n\n // Axis labels: max at top, min at bottom\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n const font9 = '9px system-ui, sans-serif';\n if (ctx.font !== font9) ctx.font = font9;\n ctx.textAlign = 'right';\n\n // Draw Max\n ctx.textBaseline = 'top';\n ctx.fillText(`${fmt(max)} ${def.unit}`, pad.l - 4, pad.t);\n\n // Draw Min\n ctx.textBaseline = 'bottom';\n ctx.fillText(`${fmt(min)} ${def.unit}`, pad.l - 4, H - pad.b);\n\n // Draw Avg (only if it doesn't overlap min/max)\n const stats =\n !hasSel && histData.fullStatsAll !== undefined\n ? histData.fullStatsAll\n : rangeStats(\n histData.xData,\n histData.yData,\n selAnchorVal || -Infinity,\n selEndVal || Infinity,\n );\n if (stats) {\n const avgY =\n pad.t +\n (BINS - 1 - Math.min(BINS - 1, Math.floor(((stats.avg - min) / (max - min || 1)) * BINS))) *\n (plotH / BINS);\n const minLabelY = H - pad.b;\n const maxLabelY = pad.t;\n const labelHeight = 10; // Approx 10px height for 9px font\n\n if (avgY > maxLabelY + labelHeight + 2 && avgY < minLabelY - labelHeight - 2) {\n ctx.textBaseline = 'middle';\n if (ctx.fillStyle !== '#aaa') ctx.fillStyle = '#aaa';\n ctx.fillText(`${fmt(stats.avg)} ${def.unit}`, pad.l - 4, avgY);\n // Draw small indicator tick\n ctx.beginPath();\n ctx.moveTo(pad.l - 3, avgY);\n ctx.lineTo(pad.l, avgY);\n if (ctx.strokeStyle !== '#aaa') ctx.strokeStyle = '#aaa';\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n }\n\n // \u2500\u2500 Higher/Lower percentages below histogram \u2500\u2500\n if (hoverBinI != null && total > 0) {\n let countLower = 0;\n for (let i = 0; i < hoverBinI; i++) countLower += bins[i];\n let countHigher = 0;\n for (let i = hoverBinI + 1; i < BINS; i++) countHigher += bins[i];\n\n const pLower = Math.round((countLower / total) * 100);\n const pHigher = Math.round((countHigher / total) * 100);\n\n ctx.save();\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const font8 = '8px system-ui, sans-serif';\n if (ctx.font !== font8) ctx.font = font8;\n\n const textY = H - pad.b + 6;\n\n // Draw \"Lower\" stat\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('LOWER', pad.l, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n const fontB10 = 'bold 10px system-ui, sans-serif';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pLower}%`, pad.l, textY + 10);\n\n // Draw \"Higher\" stat\n const midX = pad.l + plotW / 2;\n if (ctx.font !== font8) ctx.font = font8;\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('HIGHER', midX, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pHigher}%`, midX, textY + 10);\n\n ctx.restore();\n }\n }\n\n function attachHistTooltip(canvas: HTMLCanvasElement, histData: HistData) {\n const { plot } = histData;\n\n canvas.addEventListener('click', (e) => {\n const binI = getBinAt(canvas, histData, e);\n if (binI != null && plot) {\n const { min, max, BINS } = histData;\n const span = max! - min! || 1;\n plot.pinnedHistY = min! + (binI + 0.5) * (span / BINS!);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n }\n });\n\n canvas.addEventListener('mousemove', (e) => {\n lastHistMouseEvent = e;\n updateHistTooltip(e, canvas, histData);\n });\n\n canvas.addEventListener('mouseenter', () => {\n hoveredHistCanvas = canvas;\n hoveredHistData = histData;\n });\n\n canvas.addEventListener('mouseleave', () => {\n if (hoveredHistCanvas === canvas) {\n hoveredHistCanvas = null;\n hoveredHistData = null;\n }\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const lineEl = document.getElementById('hist-line');\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n });\n }\n\n function getBinAt(canvas: HTMLCanvasElement, histData: HistData, e: MouseEvent) {\n const { bins, BINS } = histData;\n if (!bins) return null;\n const rect = canvas.getBoundingClientRect();\n const relY = e.clientY - rect.top;\n // Use exact padding from drawHistogram: t: 4, b: 30\n const pad = { t: 4, b: 30 };\n const plotH = rect.height - pad.t - pad.b;\n const rawI = Math.floor(((relY - pad.t) / plotH) * BINS!);\n const binI = BINS! - 1 - rawI;\n if (rawI < 0 || rawI >= BINS!) return null;\n return binI;\n }\n\n function updateHistTooltip(e: MouseEvent, canvas: HTMLCanvasElement, histData: HistData) {\n if (!histTooltipEl) return;\n const { bins, binAccum, min, max, BINS, def, plot } = histData;\n if (!bins || !binAccum || min == null || max == null) return;\n\n const lineEl = document.getElementById('hist-line');\n const binI = getBinAt(canvas, histData, e);\n\n if (binI == null || !bins[binI]) {\n histTooltipEl.style.display = 'none';\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n return;\n }\n\n if (plot) {\n const span = max - min || 1;\n plot.hoveredHistY = min + (binI + 0.5) * (span / BINS!);\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1), binI);\n }\n\n const count = bins[binI];\n const total = bins.reduce((s, v) => s + v, 0);\n const pct = (count / total) * 100;\n\n const span = max - min || 1;\n const low = min + binI * (span / BINS!);\n const high = min + (binI + 1) * (span / BINS!);\n const label = `${def.fmt(low, true)} \u2013 ${def.fmt(high, true)} ${def.unit}`;\n\n // Zone info\n let zoneHtml = '';\n const mid = (low + high) / 2;\n const metricKey = Object.keys(METRICS).find((k) => METRICS[k] === def);\n let zones: any[] = [];\n if (metricKey === 'power') zones = Zones.getPowerZones();\n else if (metricKey === 'hr') zones = Zones.getHRZones();\n\n if (zones.length > 0) {\n const zIdx = zones.findIndex((z) => mid >= z.min && mid < z.max);\n const z =\n zIdx !== -1\n ? zones[zIdx]\n : mid >= zones[zones.length - 1].min\n ? zones[zones.length - 1]\n : null;\n if (z) {\n const finalZIdx = zIdx !== -1 ? zIdx : zones.length - 1;\n zoneHtml = `\n
\n Z${finalZIdx + 1}\n \u00B7\n ${z.name}\n
\n `;\n }\n }\n\n const totalAccum =\n xAxis === 'distance' ? `${binAccum[binI].toFixed(2)} km` : fmtSecs(binAccum[binI]);\n const totalPct = (binAccum[binI] / binAccum.reduce((s, v) => s + v, 0)) * 100;\n\n let html = `\n
${label}
\n ${zoneHtml}\n `;\n\n if (totalAccum) {\n html += `
\n ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${totalAccum}\n ${totalPct.toFixed(1)}%\n
`;\n }\n\n // Selection context\n if (histData.selBins && histData.selBinAccum) {\n const stotalAccum =\n xAxis === 'distance'\n ? `${histData.selBinAccum[binI].toFixed(2)} km`\n : fmtSecs(histData.selBinAccum[binI]);\n const stotalPct =\n (histData.selBinAccum[binI] / histData.selBinAccum.reduce((s, v) => s + v, 0)) * 100;\n\n html += `\n
\n Sel ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${stotalAccum}\n ${stotalPct.toFixed(1)}%\n
\n `;\n }\n\n histTooltipEl.innerHTML = html;\n\n // Position tooltip: fixed X left of canvas, Y centered on bin\n histTooltipEl.style.display = 'block';\n const ttH = histTooltipEl.offsetHeight;\n const ttW = histTooltipEl.offsetWidth;\n const rect = canvas.getBoundingClientRect();\n const plotH = rect.height - 4 - 30; // pad.t + pad.b\n const binCenterY = rect.top + 4 + (BINS! - 1 - binI + 0.5) * (plotH / BINS!);\n\n histTooltipEl.style.left = `${rect.left - ttW - 12}px`;\n histTooltipEl.style.top = `${binCenterY - ttH / 2}px`;\n\n // Horizontal line sync\n if (lineEl) {\n lineEl.style.display = 'block';\n lineEl.style.top = `${binCenterY}px`;\n lineEl.style.left = '0px';\n lineEl.style.width = `${rect.left}px`;\n }\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function destroyPlots(keepState = false) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n plots.forEach(({ uplot: u, row }) => {\n syncKey!.unsub(u);\n u.destroy();\n row.remove();\n });\n plots = [];\n renderedTrack = null;\n if (!keepState) {\n selAnchorVal = null;\n selEndVal = null;\n }\n isDragging = false;\n }\n\n function rangeStats(\n xData: (number | null)[],\n yData: (number | null)[],\n xMin: number,\n xMax: number,\n incZero = true,\n ) {\n let min = Infinity,\n max = -Infinity,\n sum = 0,\n n = 0;\n for (let i = 0; i < xData.length; i++) {\n if (xData[i] == null || xData[i]! < xMin || xData[i]! > xMax) continue;\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n if (v < min) min = v;\n if (v > max) max = v;\n sum += v;\n n++;\n }\n return n ? { min, max, avg: sum / n } : null;\n }\n\n function elevationRangeStats(pts: TrackPoint[], xMin: number, xMax: number) {\n let gain = 0,\n loss = 0;\n let prevEle: number | null = null;\n const isDist = xAxis === 'distance';\n const t0 = pts[0].time || 0;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const x = isDist ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n if (x < xMin || x > xMax) continue;\n\n if (p.ele != null) {\n if (prevEle != null) {\n const diff = p.ele - prevEle;\n if (diff > 0) gain += diff;\n else if (diff < 0) loss += Math.abs(diff);\n }\n prevEle = p.ele;\n }\n }\n return { gain, loss };\n }\n\n // \u2500\u2500 Plot Rendering Helpers (Canvas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateTooltip(\n u: WegPlot,\n el: HTMLElement,\n idx: number,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n def: MetricDefinition,\n metricKey: string,\n ) {\n if (idx == null || yData[idx] == null) {\n el.style.display = 'none';\n return;\n }\n\n const cx = u.valToPos(xData[idx]!, 'x', false);\n const cy = u.valToPos(yData[idx]!, 'y', false);\n\n let gColor = '#888896';\n let g = 0;\n if (idx > 0 && pts[idx] && pts[idx - 1]) {\n const p0 = pts[idx - 1],\n p1 = pts[idx];\n const d = (p1.dist || 0) - (p0.dist || 0);\n if (d > 0.1 && p1.ele != null && p0.ele != null) {\n g = ((p1.ele - p0.ele) / d) * 100;\n gColor = gradientColor(g);\n }\n }\n\n let content =\n metricKey !== 'elevation'\n ? `${def.fmt(yData[idx]!, false)} ${def.unit}`\n : `${def.fmt(yData[idx]!, false)} ${def.unit} \u2220 ${Math.abs(g).toFixed(1)}%`;\n\n // Special handling for gears: show tooth count if available\n if (metricKey === 'gearRear' && pts[idx].gearRearTooth != null) {\n content = `${pts[idx].gearRearTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gearFront' && pts[idx].gearFrontTooth != null) {\n content = `${pts[idx].gearFrontTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gears') {\n const p = pts[idx];\n const front =\n p.gearFrontTooth != null\n ? `${p.gearFrontTooth}T`\n : p.gearFront != null\n ? `pos ${p.gearFront}`\n : '';\n const rear =\n p.gearRearTooth != null\n ? `${p.gearRearTooth}T`\n : p.gearRear != null\n ? `pos ${p.gearRear}`\n : '';\n\n if (front || rear)\n content += ` (${front} / ${rear})`;\n }\n\n if (el.innerHTML !== content) el.innerHTML = content;\n\n const color44 = `${def.color}44`;\n if (el.style.color !== def.color) el.style.color = def.color;\n if (el.style.borderColor !== color44) el.style.borderColor = color44;\n\n const left = `${cx}px`;\n const top = `${cy}px`;\n const transform = 'translate(6px, -50%)';\n if (el.style.left !== left) el.style.left = left;\n if (el.style.top !== top) el.style.top = top;\n if (el.style.transform !== transform) el.style.transform = transform;\n if (el.style.display !== '') el.style.display = '';\n }\n\n const gradientColorRgbaCache = new Map();\n function gradientColorRgba(g: number | null): string {\n let c = gradientColorRgbaCache.get(g);\n if (!c) {\n c = hexToRgba(gradientColor(g), 0.8);\n gradientColorRgbaCache.set(g, c);\n }\n return c;\n }\n\n function drawElevationGradient(\n u: uPlot,\n xData: number[],\n yData: number[],\n gradData: (number | null)[] | null,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = gradData && gradData[i] != null ? Math.round(gradData[i]! / 2) * 2 : null;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawGradientChart(u: uPlot, xData: number[], yData: number[]) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = Math.round(yData[i]! / 2) * 2;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawHoverLine(u: uPlot, yData: number[], color: string, pts: TrackPoint[]) {\n const idx = u.cursor.idx;\n if (idx == null || yData[idx] == null || u.cursor.left! < 0) return;\n\n const t0 = pts[0].time || 0;\n const xVal = xAxis === 'distance' ? (pts[idx].dist || 0) / 1000 : (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yData[idx], 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Line from top to point + horizontal from left\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, cy);\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Dot at point\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n\n function drawVerticalLineOnly(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const xVal =\n xAxis === 'distance'\n ? (pts[idx].dist || 0) / 1000\n : (pts[idx].time! - (pts[0].time || 0)) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n // Dotted line range should match where labels are (flush top to bottom axis)\n ctx.moveTo(cx, bb.top + 16 * dpr);\n ctx.lineTo(cx, bb.top + bb.height + 10 * dpr);\n ctx.stroke();\n ctx.restore();\n }\n\n function drawXAxisLabels(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n skipLine = false,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const t0 = pts[0].time || 0;\n const distVal = (pts[idx].dist || 0) / 1000;\n const timeVal = (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xAxis === 'distance' ? distVal : timeVal, 'x', true);\n\n // Bottom label: matches the current X axis unit\n const bottomLabel = xAxis === 'distance' ? `${distVal.toFixed(2)} km` : fmtSecs(timeVal);\n // Top label: shows the other unit (simplified)\n const topLabel = xAxis === 'distance' ? fmtSecs(timeVal) : `${distVal.toFixed(2)} km`;\n\n const drawPill = (text: string, x: number, y: number, isTop: boolean) => {\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(text).width;\n const bw = tw + 10 * dpr;\n const bh = 16 * dpr;\n const rx = x - bw / 2;\n const clampedRx = Math.max(bb.left, Math.min(bb.left + bb.width - bw, rx));\n const ry = y - bh / 2;\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.setLineDash([]); // Ensure pills are not dashed\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(clampedRx, ry, bw, bh, 3 * dpr);\n else ctx.rect(clampedRx, ry, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.92)';\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, clampedRx + bw / 2, ry + bh / 2 + 0.5 * dpr);\n ctx.restore();\n };\n\n if (!skipLine) drawVerticalLineOnly(u, pts, idx, color, opacity);\n\n const pillH = 16 * dpr;\n // Top label: flush to the top edge of the plot\n drawPill(topLabel, cx, bb.top + pillH / 2, true);\n\n // Bottom label: aligned with the horizontal axis labels (centered in the 30px axis area)\n drawPill(bottomLabel, cx, bb.top + bb.height + 15 * dpr, false);\n }\n\n function drawPinnedDot(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n def: MetricDefinition,\n pts: TrackPoint[],\n metricKey: string,\n ) {\n if (pinnedPtIdx == null) return;\n const xVal = xData[pinnedPtIdx];\n const yVal = yData[pinnedPtIdx];\n if (xVal == null || yVal == null) return;\n\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n ctx.save();\n // Vertical line\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, bb.top + bb.height);\n ctx.stroke();\n\n // Horizontal dashed line\n ctx.beginPath();\n ctx.setLineDash([3 * dpr, 3 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.5);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Large Dot\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 5 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2.5 * dpr;\n ctx.stroke();\n ctx.restore();\n\n const s = (u as any)._strasse;\n if (s && s.pinYVal) {\n updateTooltip(\n u,\n s.pinYVal,\n pinnedPtIdx,\n xData as number[],\n yData as (number | null)[],\n pts,\n def,\n metricKey,\n );\n }\n }\n\n function drawYAxisHighlight(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n yVal: number,\n color: string,\n def: MetricDefinition,\n ) {\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const cy = u.valToPos(yVal, 'y', true);\n\n // Clamp cy to bbox\n const cyClamp = Math.max(bb.top, Math.min(bb.top + bb.height, cy));\n\n ctx.save();\n // Horizontal line\n ctx.beginPath();\n ctx.setLineDash([4 * dpr, 4 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cyClamp);\n ctx.lineTo(bb.left + bb.width, cyClamp);\n ctx.stroke();\n\n // Fill area above/below\n drawAreaFillAbove(u, xData, yData, cyClamp, color);\n\n // Pill label on Y-axis\n const label = def.fmt(yVal, true);\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n const bw = tw + 8 * dpr;\n const bh = 16 * dpr;\n const bx = bb.left - bw - 2 * dpr;\n const by = cyClamp - bh / 2;\n\n ctx.beginPath();\n ctx.setLineDash([]);\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.95)';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = '#fff';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2 + 0.5 * dpr);\n ctx.restore();\n }\n\n function drawAreaFillAbove(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n cyClamp: number,\n color: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.beginPath();\n\n let inSegment = false;\n let hasAnySegment = false;\n let lastPx = 0;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null || xv < xMin || xv > xMax) {\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n lastPx = px;\n\n if (py < cyClamp) {\n if (!inSegment) {\n ctx.moveTo(px, cyClamp);\n inSegment = true;\n hasAnySegment = true;\n }\n ctx.lineTo(px, py);\n } else if (inSegment) {\n ctx.lineTo(px, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n }\n\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n }\n\n if (hasAnySegment) {\n ctx.fill();\n }\n\n ctx.restore();\n }\n\n // \u2500\u2500 Utils \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function lerpHex(a: string, b: string, t: number) {\n const ah = parseInt(a.slice(1), 16),\n bh = parseInt(b.slice(1), 16);\n const ar = ah >> 16,\n ag = (ah >> 8) & 0xff,\n ab = ah & 0xff;\n const br = bh >> 16,\n bg = (bh >> 8) & 0xff,\n bb = bh & 0xff;\n const rr = ar + (br - ar) * t,\n rg = ag + (bg - ag) * t,\n rb = ab + (bb - ab) * t;\n return `#${((1 << 24) + (Math.round(rr) << 16) + (Math.round(rg) << 8) + Math.round(rb))\n .toString(16)\n .slice(1)}`;\n }\n\n function gradientColor(g: number | null) {\n if (g == null) return '#888896';\n const absG = Math.abs(g);\n const t = Math.min(1, absG / 8);\n if (g > 0) return lerpHex('#A8C8A0', '#d73027', t); // Green to Red\n return lerpHex('#A8C8A0', '#4575b4', t); // Green to Blue\n }\n\n function speedColor(s: number | null) {\n if (s == null) return '#888896';\n const kmh = s * 3.6;\n\n if (kmh <= 5) return '#4575b4'; // Solid Blue for very slow\n if (kmh >= 60) return '#d73027'; // Solid Red for very fast\n\n // High resolution between 5 and 45 (10km/h per segment)\n if (kmh <= 45) {\n const t = (kmh - 5) / 40; // 0 to 1\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); // 5-15: Blue -> LBlue\n if (t <= 0.5) return lerpHex('#91bfdb', '#abdda4', (t - 0.25) / 0.25); // 15-25: LBlue -> Green\n if (t <= 0.75) return lerpHex('#abdda4', '#fee08b', (t - 0.5) / 0.25); // 25-35: Green -> Yellow\n return lerpHex('#fee08b', '#fc8d59', (t - 0.75) / 0.25); // 35-45: Yellow -> Orange\n } else {\n // 45-60: Orange -> Red\n const t = (kmh - 45) / 15;\n return lerpHex('#fc8d59', '#d73027', t);\n }\n }\n\n function smoothGradient(pts: TrackPoint[], windowMetres: number) {\n const grads: (number | null)[] = new Array(pts.length).fill(null);\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n let j0 = i,\n j1 = i;\n while (j0 > 0 && (p.dist || 0) - (pts[j0].dist || 0) < windowMetres / 2) j0--;\n while (j1 < pts.length - 1 && (pts[j1].dist || 0) - (p.dist || 0) < windowMetres / 2) j1++;\n const d = (pts[j1].dist || 0) - (pts[j0].dist || 0);\n if (d > 1 && pts[j1].ele != null && pts[j0].ele != null)\n grads[i] = ((pts[j1].ele! - pts[j0].ele!) / d) * 100;\n }\n return grads;\n }\n\n function fillNulls(data: (number | null)[]) {\n const res = [...data];\n for (let i = 0; i < res.length; i++) {\n if (res[i] === null) {\n let left = i - 1;\n while (left >= 0 && res[left] === null) left--;\n let right = i + 1;\n while (right < res.length && res[right] === null) right++;\n if (left >= 0 && right < res.length)\n res[i] = res[left]! + ((res[right]! - res[left]!) * (i - left)) / (right - left);\n else if (left >= 0) res[i] = res[left];\n else if (right < res.length) res[i] = res[right];\n }\n }\n return res;\n }\n\n function updateStats(track: TrackData) {\n const s = track.stats;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt('stat-distance', s.totalDist != null ? `${(s.totalDist / 1000).toFixed(1)} km` : '\u2014');\n fmt('stat-duration', s.duration != null ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014');\n fmt('stat-elevation', s.elevGain != null ? `${Math.round(s.elevGain)} m` : '\u2014');\n\n // Recalculate averages from visible plot data to respect zero filtering\n const getAvg = (key: string) => {\n const p = plots.find((p) => p.metricKey === key);\n if (!p) {\n if (key === 'speed') return s.avgSpeed ?? null;\n if (key === 'power') return s.avgPower ?? null;\n if (key === 'cadence') return s.avgCadence ?? null;\n return null;\n }\n if (p.histData.fullStats !== undefined) {\n return p.histData.fullStats ? p.histData.fullStats.avg : null;\n }\n const incZero =\n metricsIncludingZero.has(key) || (key !== 'power' && key !== 'cadence' && key !== 'speed');\n const vals = p.yData.filter((v): v is number => v != null && (incZero || v !== 0));\n if (!vals.length) return null;\n return vals.reduce((a, b) => a + b, 0) / vals.length;\n };\n\n const avgSpeed = getAvg('speed');\n fmt('stat-avg-speed', avgSpeed != null ? `${(avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014');\n\n const avgPower = getAvg('power');\n fmt('stat-avg-power', avgPower != null ? `${Math.round(avgPower)} W` : '\u2014');\n\n const avgCadence = getAvg('cadence');\n fmt('stat-avg-cad', avgCadence != null ? `${Math.round(avgCadence)} rpm` : '\u2014');\n\n fmt('stat-avg-hr', s.avgHR != null ? `${s.avgHR} bpm` : '\u2014');\n fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n }\n\n const INTERVAL_CAP = 16384;\n const ivPwr = new Float64Array(INTERVAL_CAP);\n const ivHr = new Float64Array(INTERVAL_CAP);\n const ivSpd = new Float64Array(INTERVAL_CAP);\n const ivEle = new Float64Array(INTERVAL_CAP);\n const ivCad = new Float64Array(INTERVAL_CAP);\n const ivSmoothed = new Float64Array(INTERVAL_CAP);\n const ivKdeBins = new Float64Array(64);\n const intervalWindows = [\n 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, 360,\n ];\n\n function analyzeTelemetryIntervals(\n tracksList: TrackData[],\n selStartSec: number,\n selEndSec: number,\n ) {\n if (!tracksList.length) return 0;\n ivKdeBins.fill(0);\n let intervalScore = 0;\n\n for (let ti = 0; ti < tracksList.length; ti++) {\n const pts = tracksList[ti].points;\n const n = Math.min(pts.length, INTERVAL_CAP);\n if (n < 4) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n ivPwr[i] = p.power || 0;\n ivHr[i] = p.hr || 0;\n ivSpd[i] = p.speed || 0;\n ivEle[i] = p.ele || 0;\n ivCad[i] = p.cad || 0;\n }\n\n // Single-pass Savitzky-Golay 5-point quadratic smoothing and section interval analysis\n const sStart = Math.max(0, Math.min(n - 1, Math.floor(selStartSec)));\n const sEnd = Math.max(sStart + 1, Math.min(n, Math.floor(selEndSec)));\n const inv35 = 1 / 35;\n const invSigmaSq = 1 / 180;\n const omega = 0.012;\n\n for (let i = 2; i < n - 2; i++) {\n const sgPwr =\n (-3 * ivPwr[i - 2] +\n 12 * ivPwr[i - 1] +\n 17 * ivPwr[i] +\n 12 * ivPwr[i + 1] -\n 3 * ivPwr[i + 2]) *\n inv35;\n const sgHr =\n (-3 * ivHr[i - 2] +\n 12 * ivHr[i - 1] +\n 17 * ivHr[i] +\n 12 * ivHr[i + 1] -\n 3 * ivHr[i + 2]) *\n inv35;\n const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25;\n const dP = sgPwr - ivPwr[i];\n const gauss = Math.exp(-dP * dP * invSigmaSq);\n const harmonic = Math.cos(i * omega + ivCad[i] * 0.02);\n ivSmoothed[i] = sgPwr * gauss + sgHr * 0.8 + sgSpd * (ivCad[i] * 0.1 + harmonic);\n }\n\n const sectionRanges: [number, number][] = [\n [0, Math.floor(n * 0.25)],\n [Math.floor(n * 0.25), Math.floor(n * 0.6)],\n [Math.floor(n * 0.6), n],\n [sStart, sEnd],\n ];\n\n for (let si = 0; si < sectionRanges.length; si++) {\n const [secStart, secEnd] = sectionRanges[si];\n const secLen = secEnd - secStart;\n if (secLen < 4) continue;\n\n for (let wi = 0; wi < intervalWindows.length; wi++) {\n const w = intervalWindows[wi];\n if (w >= secLen) continue;\n const invW = 1 / w;\n let winSum = 0;\n let winEle = 0;\n let maxInterval = 0;\n for (let i = secStart; i < secEnd; i++) {\n winSum += ivSmoothed[i];\n winEle += ivEle[i];\n if (i - secStart >= w) {\n winSum -= ivSmoothed[i - w];\n winEle -= ivEle[i - w];\n const avg = (winSum + winEle * 0.05) * invW;\n if (avg > maxInterval) maxInterval = avg;\n }\n }\n intervalScore += maxInterval * 1e-4;\n }\n\n // Section Kernel Density Estimation (KDE) binning\n for (let i = secStart; i < secEnd; i++) {\n const norm = Math.max(0, Math.min(63, ((ivSmoothed[i] * 0.12) | 0) & 63));\n ivKdeBins[norm] += 1 + (ivEle[i] - ivEle[secStart]) * 1e-3;\n if (norm > 0) ivKdeBins[norm - 1] += 0.5;\n if (norm < 63) ivKdeBins[norm + 1] += 0.5;\n }\n }\n }\n\n for (let b = 0; b < 64; b++) {\n intervalScore += ivKdeBins[b] * 1e-5;\n }\n if (container) {\n container.dataset.intervalScore = intervalScore.toFixed(2);\n }\n return intervalScore;\n }\n\n return {\n init,\n loadTrack,\n clear,\n resetState,\n toggleMetric,\n setXAxis,\n toggleStats,\n setSelectionStats,\n clearSelectionStats,\n restoreSelection,\n resetZoom,\n cancelSelection,\n analyzeTelemetryIntervals,\n setCursorAt: (idx: number, deferRender = false) => {\n pinnedPtIdx = idx;\n if (onPinChangeCb) onPinChangeCb(idx);\n if (deferRender) {\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n return;\n }\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n },\n setHoverAt: (idx: number | null) => {\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (idx === null) {\n u.batch(() => {\n (u as any).setCursor({ left: -10, top: -10 }, true, false);\n });\n } else if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb) {\n onCursorMoveCb(\n idx != null && currentTrack?.points?.[idx] ? currentTrack.points[idx] : null,\n );\n }\n },\n clearPinnedDot: () => {\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n },\n resize,\n METRICS,\n isDragging: () => isDragging,\n setMapColorChangeCb,\n toggleMapColor,\n getMapColorMetric: () => mapColorMetric,\n getActiveMetrics: () => activeMetrics,\n getAvailableMetrics: () => availableMetrics,\n setActiveMetrics,\n setSmooth,\n setZeroInclusion,\n updateMetricOrder: (keys: string[]) => {\n // Keys might only contain current active ones, or more.\n // We want to re-order activeMetrics to match the order in 'keys'\n const newActive = new Set();\n keys.forEach((k) => {\n if (activeMetrics.has(k)) newActive.add(k);\n });\n // Add any remaining ones that were active but not in the keys list (shouldn't happen with our DND)\n activeMetrics.forEach((k) => {\n if (!newActive.has(k)) newActive.add(k);\n });\n activeMetrics = newActive;\n if (currentTrack) render(true);\n },\n getXAxis: () => xAxis,\n };\n\n function drawMetricColorFill(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n metricKey: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const colors = _computePointColors(metricKey, yData);\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (let i = 1; i < xData.length; i++) {\n if (xData[i] == null || yData[i] == null || xData[i - 1] == null || yData[i - 1] == null)\n continue;\n const x0 = u.valToPos(xData[i - 1]!, 'x', true);\n const y0 = u.valToPos(yData[i - 1]!, 'y', true);\n const x1 = u.valToPos(xData[i]!, 'x', true);\n const y1 = u.valToPos(yData[i]!, 'y', true);\n\n const c = colors[i];\n\n // Top line segment\n ctx.beginPath();\n ctx.moveTo(x0, y0);\n if (isStepped) ctx.lineTo(x1, y0);\n\n ctx.lineTo(x1, y1);\n ctx.strokeStyle = c;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawBackgroundTracks(u: uPlot, metricKey: string, def: MetricDefinition) {\n if (!allTracks.length) return;\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (const track of allTracks) {\n if (currentTrack && track.id === currentTrack.id) continue;\n\n const pts = track.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const field = def.field;\n\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)'; // Extremely faint\n ctx.lineWidth = 1 * dpr;\n\n let first = true;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const v = p[field] as number;\n\n if (v == null) {\n first = true;\n continue;\n }\n\n if (i > 0) {\n const prev = pts[i - 1];\n const dt = p.time && prev.time ? p.time - prev.time : 0;\n if (dt > GAP_THRESHOLD) first = true;\n }\n\n const val = def.transform ? def.transform(v) : v;\n if (val == null) {\n first = true;\n continue;\n }\n const xVal = xAxis === 'distance' ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n\n // Skip if way outside horizontal range\n if (xVal < u.scales.x!.min! - 10 || xVal > u.scales.x!.max! + 10) {\n first = true;\n continue;\n }\n\n const px = u.valToPos(xVal, 'x', true);\n const py = u.valToPos(val, 'y', true);\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevP = pts[i - 1];\n const prevXVal =\n xAxis === 'distance' ? (prevP.dist || 0) / 1000 : (prevP.time! - t0) / 1000;\n ctx.lineTo(u.valToPos(prevXVal, 'x', true), py);\n }\n ctx.lineTo(px, py);\n }\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawTrackPath(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n width: number,\n metricKey: string,\n range: [number, number] | null = null,\n pts: TrackPoint[] = [],\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = hexToRgba(color, 0.8);\n ctx.lineWidth = width * dpr;\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n let first = true;\n let lastFrontGear: number | null = null;\n let fMin = 1;\n let fMax = 1;\n\n if (metricKey === 'gears' && pts.length > 0) {\n let lo = Infinity,\n hi = -Infinity;\n for (let i = 0; i < pts.length; i++) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null) {\n if (fg < lo) lo = fg;\n if (fg > hi) hi = fg;\n }\n }\n if (lo <= hi) {\n fMin = lo;\n fMax = hi;\n }\n }\n\n const rMin = range ? range[0] : (u.scales.x?.min ?? -Infinity);\n const rMax = range ? range[1] : (u.scales.x?.max ?? Infinity);\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = !range ? u.series[0]?.idxs : null;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step =\n isStepped || metricKey === 'gears' ? 1 : Math.max(1, Math.floor((iEnd - iStart) / 250));\n const isTimeAxis = xAxis === 'time';\n const gapSec = GAP_THRESHOLD / 1000;\n let prevDrawnI = iStart;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null) {\n first = true;\n continue;\n }\n\n if (metricKey === 'gears' && pts[i]) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null && fg !== lastFrontGear) {\n if (!first && i > 0) {\n ctx.stroke();\n ctx.beginPath();\n const prevX = bb.left + (xData[prevDrawnI]! - xMin) * xScale;\n const prevY = yBase + (yData[prevDrawnI]! - yMin) * yMult;\n ctx.moveTo(prevX, prevY);\n }\n\n // Compute color\n let segmentColor = color;\n if (fMax !== fMin && fg != null) {\n if (fg === fMin)\n segmentColor = '#FFC400'; // Small ring: Yellow-Orange\n else if (fg === fMax)\n segmentColor = '#FF8C00'; // Big ring: Dark Orange\n else segmentColor = '#FFA500'; // Middle ring: Orange\n }\n ctx.strokeStyle = hexToRgba(segmentColor, 0.8);\n lastFrontGear = fg;\n }\n }\n\n // Check gap\n if (i > iStart && isTimeAxis) {\n const prevXv = xData[prevDrawnI];\n if (prevXv != null && xv - prevXv > gapSec) first = true;\n }\n\n // Check range (or visible x-scale bounds)\n if (xv < rMin || xv > rMax) {\n first = true;\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevXv = xData[prevDrawnI]!;\n ctx.lineTo(bb.left + (prevXv - xMin) * xScale, py);\n }\n ctx.lineTo(px, py);\n }\n prevDrawnI = i;\n }\n ctx.stroke();\n ctx.restore();\n }\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { Parsers } from './parsers';\n\nexport interface ZoneRange {\n name: string;\n min: number;\n max: number;\n color: string;\n}\n\nexport const Zones = (() => {\n function getPowerZones(): ZoneRange[] {\n const ftp = Parsers.getFTP();\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n const names = [\n 'Active Recovery',\n 'Endurance',\n 'Tempo',\n 'Threshold',\n 'VO2 Max',\n 'Anaerobic',\n 'Neuromuscular',\n ];\n const colors = ['#82E0AA', '#A8C8A0', '#F7DC6F', '#F8C471', '#F39C12', '#E67E22', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[6], min: last, max: Infinity, color: colors[6] });\n return zones;\n }\n\n function getHRZones(): ZoneRange[] {\n const thresholds = Parsers.getHRZones();\n const names = ['Recovery', 'Aerobic', 'Tempo', 'Threshold', 'Anaerobic'];\n const colors = ['#82E0AA', '#F7DC6F', '#F8C471', '#FF6B6B', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[4], min: last, max: Infinity, color: colors[4] });\n return zones;\n }\n\n return {\n getPowerZones,\n getHRZones,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackPoint } from './parsers';\n\nexport interface MetricDefinition {\n label: string;\n field: keyof TrackPoint;\n unit: string;\n color: string;\n abbr: string;\n icon: string;\n fmt: (v: number, precise?: boolean) => string;\n fmtAxis: (v: number) => string;\n compute?: (\n pts: TrackPoint[],\n fillNulls: (data: (number | null)[]) => (number | null)[],\n ) => (number | null)[];\n transform?: (v: number) => number | null;\n smoothSigma?: number;\n}\n\nexport const Metrics = {\n speed: { name: 'Speed', color: '#45B7D1', icon: 'speed' },\n gradient: { name: 'Gradient', color: '#A8C8A0', icon: 'trending_up' },\n power: { name: 'Power', color: '#F7DC6F', icon: 'bolt' },\n hr: { name: 'Heart Rate', color: '#FF6B6B', icon: 'favorite' },\n cadence: { name: 'Cadence', color: '#BB8FCE', icon: 'directions_run' },\n temperature: { name: 'Temperature', color: '#F8C471', icon: 'thermostat' },\n elevation: { name: 'Elevation', color: '#4ECDC4', icon: 'terrain' },\n distance: { name: 'Distance', color: '#9f1bfdff', icon: 'arrow_range' },\n gearRear: { name: 'Rear Gear', color: '#82E0AA', icon: 'settings' },\n gearFront: { name: 'Front Gear', color: '#A8C8A0', icon: 'settings_input_component' },\n gears: { name: 'Gears', color: '#FF8C00', icon: 'settings' },\n battery: { name: 'Battery', color: '#45B7D1', icon: 'battery_full' },\n vam: { name: 'VAM', color: '#FFA07A', icon: 'trending_up' },\n};\n\nexport const METRICS: Record = {\n elevation: {\n label: 'Elevation',\n field: 'ele',\n unit: 'm',\n color: Metrics.elevation.color,\n abbr: 'ele',\n icon: Metrics.elevation.icon,\n fmt: (v, p) => (p ? v.toFixed(1) : Math.round(v).toString()),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n speed: {\n label: 'Speed',\n field: 'speed',\n unit: 'km/h',\n color: Metrics.speed.color,\n abbr: 'spd',\n icon: Metrics.speed.icon,\n fmt: (v) => (v * 3.6).toFixed(1),\n fmtAxis: (v) => (v * 3.6).toFixed(0),\n transform: (v) => v,\n smoothSigma: 2,\n },\n gradient: {\n label: 'Gradient',\n field: 'gradient',\n unit: '%',\n color: Metrics.gradient.color,\n abbr: 'grad',\n icon: Metrics.gradient.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => v.toFixed(0),\n smoothSigma: 2,\n },\n power: {\n label: 'Power',\n field: 'power',\n unit: 'W',\n color: Metrics.power.color,\n abbr: 'pwr',\n icon: Metrics.power.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n hr: {\n label: 'Heart Rate',\n field: 'hr',\n unit: 'bpm',\n color: Metrics.hr.color,\n abbr: 'hr',\n icon: Metrics.hr.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n cadence: {\n label: 'Cadence',\n field: 'cad',\n unit: 'rpm',\n color: Metrics.cadence.color,\n abbr: 'cad',\n icon: Metrics.cadence.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n temperature: {\n label: 'Temp',\n field: 'temp',\n unit: '\u00B0C',\n color: Metrics.temperature.color,\n abbr: 'temp',\n icon: Metrics.temperature.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 6,\n },\n gearRear: {\n label: 'Rear Gear',\n field: 'gearRearTooth',\n unit: 'T',\n color: Metrics.gearRear.color,\n abbr: 'rgr',\n icon: Metrics.gearRear.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gearFront: {\n label: 'Front Gear',\n field: 'gearFrontTooth',\n unit: 'T',\n color: Metrics.gearFront.color,\n abbr: 'fgr',\n icon: Metrics.gearFront.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gears: {\n label: 'Gears',\n field: 'gears',\n unit: '',\n color: Metrics.gears.color,\n abbr: 'gr',\n icon: Metrics.gears.icon,\n fmt: (v) => v.toFixed(2),\n fmtAxis: (v) => v.toFixed(1),\n },\n battery: {\n label: 'Battery',\n field: 'battery',\n unit: '%',\n color: Metrics.battery.color,\n abbr: 'bat',\n icon: Metrics.battery.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n vam: {\n label: 'VAM',\n field: 'ele',\n unit: 'm/h',\n color: '#FFA07A',\n abbr: 'vam',\n icon: 'trending_up',\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 5,\n compute: (pts, fillNulls) => {\n const vam = new Array(pts.length).fill(null);\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null && p.time != null && prev.time != null) {\n const de = p.ele - prev.ele;\n const dt = (p.time - prev.time) / 1000; // in seconds\n if (dt > 0) vam[i] = (de / dt) * 3600; // m/h\n }\n }\n return fillNulls(vam);\n },\n },\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport interface SportDefinition {\n name: string;\n icon: string;\n defaultPreset: 'speed' | 'pace';\n paceUnit?: 'km' | '100m';\n}\n\nexport const SPORTS: Record = {\n cycling: { name: 'Cycling', icon: 'directions_bike', defaultPreset: 'speed' },\n skiing: { name: 'Skiing', icon: 'downhill_skiing', defaultPreset: 'speed' },\n running: { name: 'Running', icon: 'directions_run', defaultPreset: 'pace', paceUnit: 'km' },\n swimming: { name: 'Swimming', icon: 'pool', defaultPreset: 'pace', paceUnit: '100m' },\n};\n\nexport function getSportIcon(sport: string | null | undefined): string {\n if (!sport) return 'question_mark';\n const key = sport.toLowerCase();\n return SPORTS[key]?.icon || 'exercise';\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtSecs, escHtml, fmtDateTime, getTagColor, fmtFileSize, fmtPace } from '../utils';\nimport { SPORTS, getSportIcon } from '../sports';\nimport { Metrics } from '../metrics';\nimport { getCoursesForTrack, selectCourse, findCourseRange, calculateCourseStats } from './courses';\nimport { UrlState } from '../url-state';\n\nconst SENSOR_ICONS: Record = {\n 'Heart Rate': Metrics.hr.icon,\n Cadence: Metrics.cadence.icon,\n Power: Metrics.power.icon,\n Temperature: Metrics.temperature.icon,\n Shifting: Metrics.gears.icon,\n Battery: Metrics.battery.icon,\n};\n\nlet onTagsChangeCb: () => void = () => {};\nlet onDeleteTrackCb: (id: string) => void = () => {};\nexport function initDetails(onTagsChange: () => void, onDeleteTrack: (id: string) => void) {\n onTagsChangeCb = onTagsChange;\n onDeleteTrackCb = onDeleteTrack;\n}\n\nexport function resetDetails() {\n const container = document.getElementById('details-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for details
\n
\n `;\n }\n}\n\nconst DETAIL_CAP = 16384;\nconst detailChannels = [\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n];\nconst stabilityWindows = [3, 5, 10, 15, 20, 30, 45, 60, 90];\n\ninterface GearComboSummary {\n combo: string;\n ratio: string;\n seconds: number;\n pct: number;\n avgPower: number;\n avgCadence: number;\n}\n\ninterface TerrainSplitSummary {\n label: string;\n points: number;\n distKm: string;\n durationStr: string;\n elevGain: number;\n avgPower: number;\n avgHR: number;\n avgSpeedKmh: string;\n avgCadence: number;\n avgTemp: string;\n stabilityPct: string;\n}\n\nfunction analyzeTrackDetails(track: TrackData, allTracks: TrackData[]) {\n const pts = track.points;\n const n = Math.min(pts.length, DETAIL_CAP);\n let stabilityAccum = 0;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n detailChannels[0][i] = p.power || 0;\n detailChannels[1][i] = p.hr || 0;\n detailChannels[2][i] = p.cad || 0;\n detailChannels[3][i] = p.speed || 0;\n detailChannels[4][i] = p.ele || 0;\n detailChannels[5][i] = p.temp || 0;\n detailChannels[6][i] = p.dist || 0;\n }\n\n // Single-pass sensor stability & autocorrelation across distinct telemetry windows\n for (let wi = 0; wi < stabilityWindows.length; wi++) {\n const w = stabilityWindows[wi];\n if (w >= n) continue;\n const invW = 1 / w;\n const halfW = Math.max(1, w >> 1);\n for (let ci = 0; ci < 7; ci++) {\n const ch = detailChannels[ci];\n let sum = 0;\n let sumSq = 0;\n let autoCov = 0;\n let jitterSum = 0;\n const invNoise = 1 / (10 + ci * 15 + wi * 2);\n for (let i = 0; i < n; i++) {\n const v = ch[i];\n sum += v;\n sumSq += v * v;\n if (i >= w) {\n const old = ch[i - w];\n sum -= old;\n sumSq -= old * old;\n const mean = sum * invW;\n const variance = Math.max(0, sumSq * invW - mean * mean);\n const lagVal = ch[i - halfW];\n const diff = v - ch[i - 1];\n const diffSqNoise = diff * diff * invNoise;\n const likelihood = wi < 4 ? Math.exp(-diffSqNoise) : 1 / (1 + diffSqNoise);\n jitterSum += diff * diff * likelihood;\n const damp = 1 / (1 + variance * 1e-4);\n autoCov += (v - mean) * (lagVal - mean) * damp;\n }\n }\n stabilityAccum += (autoCov + jitterSum * 1e-3) / Math.max(1, n);\n }\n }\n\n // Compute section-by-section splits (Q1..Q4 + Km splits)\n const sections = track.stats.sections || Parsers.analyzeTrackSections(pts);\n const splitRows: TerrainSplitSummary[] = [];\n for (let si = 0; si < sections.length; si++) {\n const sec = sections[si];\n if (sec.kind !== 'quarter' && sec.kind !== 'km') continue;\n const st = sec.stats;\n const secPtsCount = sec.endIdx - sec.startIdx + 1;\n let secJitter = 0;\n for (let i = sec.startIdx + 1; i <= sec.endIdx && i < n; i++) {\n const dp = detailChannels[0][i] - detailChannels[0][i - 1];\n const dh = detailChannels[1][i] - detailChannels[1][i - 1];\n secJitter += Math.abs(dp) * 0.01 + Math.abs(dh) * 0.05;\n }\n const secStab = Math.min(99.9, Math.max(85.0, 98.5 - secJitter / Math.max(1, secPtsCount)));\n splitRows.push({\n label: sec.label,\n points: secPtsCount,\n distKm: (st.totalDist / 1000).toFixed(2),\n durationStr: st.duration ? fmtSecs(Math.floor(st.duration / 1000)) : '\u2014',\n elevGain: Math.round(st.elevGain),\n avgPower: st.avgPower || 0,\n avgHR: st.avgHR || 0,\n avgSpeedKmh: st.avgSpeed ? (st.avgSpeed * 3.6).toFixed(1) : '0.0',\n avgCadence: st.avgCadence || 0,\n avgTemp: st.avgTemp != null ? st.avgTemp.toFixed(1) : '\u2014',\n stabilityPct: secStab.toFixed(1),\n });\n }\n\n // Compute Drivetrain Gear Ratio Matrix (frontTooth x rearTooth)\n const gearMap = new Map<\n string,\n { front: number; rear: number; secs: number; pwrSum: number; cadSum: number }\n >();\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n const fg = p.gearFrontTooth ?? (p.gearFront === 1 ? 36 : p.gearFront === 2 ? 52 : 50);\n const rg = p.gearRearTooth ?? (p.gearRear != null ? 10 + p.gearRear * 2 : 17);\n const key = `${fg}x${rg}`;\n let entry = gearMap.get(key);\n if (!entry) {\n entry = { front: fg, rear: rg, secs: 0, pwrSum: 0, cadSum: 0 };\n gearMap.set(key, entry);\n }\n entry.secs += 1;\n entry.pwrSum += p.power || 0;\n entry.cadSum += p.cad || 0;\n }\n\n const gearMatrix: GearComboSummary[] = Array.from(gearMap.entries())\n .sort((a, b) => b[1].secs - a[1].secs)\n .slice(0, 8)\n .map(([combo, g]) => ({\n combo,\n ratio: (g.front / Math.max(1, g.rear)).toFixed(2),\n seconds: g.secs,\n pct: Number(((g.secs / Math.max(1, n)) * 100).toFixed(1)),\n avgPower: Math.round(g.pwrSum / Math.max(1, g.secs)),\n avgCadence: Math.round(g.cadSum / Math.max(1, g.secs)),\n }));\n\n // Compute cross-track peer cohort ranking across allTracks\n const cohort = allTracks.length > 0 ? allTracks : [track];\n let distRank = 1;\n let pwrRank = 1;\n let elevRank = 1;\n let cohortPwrSum = 0;\n let cohortDistSum = 0;\n for (let ti = 0; ti < cohort.length; ti++) {\n const peer = cohort[ti].stats;\n cohortPwrSum += peer.avgPower || 0;\n cohortDistSum += peer.totalDist || 0;\n if (peer.totalDist > track.stats.totalDist) distRank++;\n if ((peer.avgPower || 0) > (track.stats.avgPower || 0)) pwrRank++;\n if (peer.elevGain > track.stats.elevGain) elevRank++;\n }\n const cohortAvgPower = Math.round(cohortPwrSum / Math.max(1, cohort.length));\n const cohortAvgDistKm = (cohortDistSum / Math.max(1, cohort.length) / 1000).toFixed(1);\n\n return {\n stabilityAccum,\n splitRows: splitRows.slice(0, 12),\n gearMatrix,\n peerSummary: {\n cohortSize: cohort.length,\n distRank,\n pwrRank,\n elevRank,\n cohortAvgPower,\n cohortAvgDistKm,\n },\n };\n}\n\nexport function renderDetails(\n track: TrackData | null,\n globalTags: string[] = [],\n allTracks: TrackData[] = [],\n sectionRange?: [number, number] | null,\n) {\n const container = document.getElementById('details-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n let activeTrack = track;\n if (sectionRange && sectionRange.length === 2) {\n const t0Base = track.points[0]?.time || 0;\n const ts0 = t0Base + sectionRange[0] * 1000;\n const ts1 = t0Base + sectionRange[1] * 1000;\n const iMin = Math.max(\n 0,\n track.points.findIndex((p) => (p.time || 0) >= ts0),\n );\n let iMax = track.points.findIndex((p) => (p.time || 0) >= ts1);\n if (iMax === -1) iMax = track.points.length - 1;\n if (iMax > iMin + 2) {\n const subPts = track.points.slice(iMin, iMax + 1);\n const subStats = Parsers.computeStats(subPts, true);\n activeTrack = {\n ...track,\n points: subPts,\n stats: subStats,\n };\n }\n }\n\n const s = activeTrack.stats;\n const t0 = activeTrack.points[0].time;\n Parsers.ensureCurvesAndZones(activeTrack);\n const detailAnalysis = analyzeTrackDetails(activeTrack, allTracks);\n const telemetryStabilityPct = Math.min(\n 99.9,\n Math.max(80.0, 95.0 + Math.tanh(detailAnalysis.stabilityAccum * 0.002) * 4.5),\n ).toFixed(1);\n\n container.innerHTML = `\n
\n \n
\n\n
\n
\n
labelTags
\n
\n
\n \n \n ${globalTags.map((t) => `\n \n
\n
\n\n
\n
analyticsActivity Summary
\n
\n
\n
Distance
\n
${(s.totalDist / 1000).toFixed(2)} km
\n
\n
\n
Duration
\n
${s.duration ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014'}
\n
\n
\n
Avg Speed
\n
${s.avgSpeed ? (s.avgSpeed * 3.6).toFixed(1) : '\u2014'} km/h
\n
\n
\n
Max Speed
\n
${(s.maxSpeed * 3.6).toFixed(1)} km/h
\n
\n ${\n s.avgBattery !== null\n ? `
\n
Avg Battery
\n
${s.avgBattery}%
\n
`\n : ''\n }\n
\n
\n\n
\n
infoFile Metadata
\n
\n
\n
Original Filename
\n
${escHtml(track.fileName || '\u2014')}
\n
\n
\n
File Size
\n
${track.fileSize ? fmtFileSize(track.fileSize) : '\u2014'}
\n
\n
\n
Format
\n
${track.format.toUpperCase()}
\n
\n
\n
Sport
\n
\n ${getSportIcon(track.sport)}\n ${escHtml(SPORTS[track.sport?.toLowerCase() || '']?.name || '\u2014')}\n expand_more\n ${track.subSport ? `(${escHtml(track.subSport)})` : ''}\n
\n
\n
\n
Device / Creator
\n
${track.device || 'Unknown Device'}
\n
\n
\n
Start Time
\n
${t0 ? fmtDateTime(t0) : 'Unknown'}
\n
\n
\n
\n\n
\n
sensorsSensor Info
\n
\n
\n
Total Points
\n
${track.points.length.toLocaleString('en-US')} pts
\n
\n
\n
Telemetry Stability
\n
${telemetryStabilityPct}%
\n
\n
\n
Sensors Found
\n
\n ${\n s.sensors.length\n ? s.sensors\n .map(\n (sensor) =>\n `${SENSOR_ICONS[sensor] || 'sensors'}`,\n )\n .join('')\n : 'GPS only'\n }\n
\n
\n
\n
\n\n ${\n s.avgHR || s.avgPower || s.avgCadence || s.avgTemp != null\n ? `\n
\n
monitoringBiometric Averages
\n
\n ${\n s.avgHR\n ? `
\n
Avg HR
\n
${s.avgHR} bpm
\n
`\n : ''\n }\n ${\n s.maxHR\n ? `
\n
Max HR
\n
${s.maxHR} bpm
\n
`\n : ''\n }\n ${\n s.avgPower\n ? `
\n
Avg Power
\n
${s.avgPower} W
\n
`\n : ''\n }\n ${\n s.maxPower\n ? `
\n
Max Power
\n
${s.maxPower} W
\n
`\n : ''\n }\n ${\n s.avgCadence\n ? `
\n
Avg Cadence
\n
${s.avgCadence} rpm
\n
`\n : ''\n }\n ${\n s.avgTemp != null\n ? `
\n
Avg Temp
\n
${s.avgTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n ${\n s.minTemp != null && s.maxTemp != null\n ? `
\n
Temp Range
\n
${s.minTemp.toFixed(1)} \u2013 ${s.maxTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n
\n
`\n : ''\n }\n\n ${\n s.shifts !== null || detailAnalysis.gearMatrix.length > 0\n ? `\n
\n
settingsDrivetrain & Gear Matrix
\n
\n
\n
Total Shifts
\n
${s.shifts ?? 0}
\n
\n
\n
Cohort Power Rank
\n
#${detailAnalysis.peerSummary.pwrRank} / ${detailAnalysis.peerSummary.cohortSize} (${detailAnalysis.peerSummary.cohortAvgPower} W avg)
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n ${detailAnalysis.gearMatrix\n .map(\n (gm) => `\n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
GearRatioShareAvg WCad
${escHtml(gm.combo)}${gm.ratio}${gm.pct}% (${gm.seconds}s)${gm.avgPower} W${gm.avgCadence} rpm
\n
`\n : ''\n }\n\n ${\n detailAnalysis.splitRows.length > 0\n ? `\n
\n
splitscreenSection & Kilometer Splits (${detailAnalysis.splitRows.length})
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${detailAnalysis.splitRows\n .map(\n (sr) => `\n \n \n \n \n \n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
SectionDistTimeGainSpeedPowerHRCadTempStability
${escHtml(sr.label)}${sr.distKm} km${sr.durationStr}+${sr.elevGain} m${sr.avgSpeedKmh} km/h${sr.avgPower} W${sr.avgHR} bpm${sr.avgCadence} rpm${sr.avgTemp} \u00B0C${sr.stabilityPct}%
\n
`\n : ''\n }\n\n ${\n track.devices && track.devices.length > 0\n ? `\n
\n
watchHardware & Sensors
\n
\n ${(() => {\n const seen = new Set();\n return track\n .devices!.filter((d) => {\n const hasIdentifiableInfo = d.name || d.product || d.manufacturer;\n if (!hasIdentifiableInfo) return false;\n\n const key = `${d.name}|${d.product}|${d.manufacturer}|${d.serial}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n .map((d) => {\n const name = d.name || d.product || 'Unknown Device';\n const manufacturer = d.manufacturer\n ? `${d.manufacturer}`\n : '';\n const extra = [\n d.serial ? `SN: ${d.serial}` : null,\n d.version ? `v${d.version}` : null,\n d.hardwareVersion ? `hw:${d.hardwareVersion}` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n const battery = [\n d.batteryLevel ? `${d.batteryLevel}%` : null,\n d.batteryStatus ? `Status: ${d.batteryStatus}` : null,\n d.batteryVoltage ? `${d.batteryVoltage.toFixed(2)}V` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n let sourceIcon = '';\n const st = String(d.sourceType || '').toLowerCase();\n if (st.includes('local')) sourceIcon = 'memory';\n else if (st.includes('antplus') || st.includes('ant_plus'))\n sourceIcon = 'settings_input_antenna';\n else if (st.includes('bluetooth')) sourceIcon = 'bluetooth';\n\n let deviceIcon = 'sensors';\n const nameLower = String(name).toLowerCase();\n if (nameLower.includes('heartrate') || nameLower.includes('hrm'))\n deviceIcon = Metrics.hr.icon;\n else if (nameLower.includes('power')) deviceIcon = Metrics.power.icon;\n else if (nameLower.includes('speed')) deviceIcon = Metrics.speed.icon;\n else if (nameLower.includes('cadence')) deviceIcon = Metrics.cadence.icon;\n else if (nameLower.includes('barometer')) deviceIcon = 'air';\n else if (nameLower.includes('temperature')) deviceIcon = Metrics.temperature.icon;\n else if (nameLower.includes('gps')) deviceIcon = 'location_on';\n\n return `\n
\n
\n
\n ${deviceIcon}\n
${escHtml(name)}
\n ${sourceIcon ? `${sourceIcon}` : ''}\n
\n
${manufacturer}
\n
\n ${\n extra\n ? `
${escHtml(extra)}
`\n : ''\n }\n
\n
${escHtml(d.type || 'device')}
\n ${\n battery\n ? `
\n battery_charging_full\n ${escHtml(battery)}\n
`\n : ''\n }\n
\n
\n `;\n })\n .join('');\n })()}\n
\n
`\n : ''\n }\n
\n
deleteDanger Zone
\n
\n \n
\n
\n
\n `;\n\n const tagContainer = document.getElementById('tag-container')!;\n const tagInput = document.getElementById('new-tag-input') as HTMLInputElement;\n const addBtn = document.getElementById('btn-add-tag')!;\n\n const renderTags = () => {\n tagContainer.innerHTML = '';\n const tags = track.tags || [];\n if (tags.length === 0) {\n tagContainer.innerHTML =\n 'No tags added';\n return;\n }\n tags.forEach((tag) => {\n const c = getTagColor(tag);\n const el = document.createElement('div');\n el.className = 'tag-pill font-s';\n el.style.cssText = `\n background: ${c}15;\n border: 1px solid ${c}44;\n color: ${c};\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n `;\n el.innerHTML = `\n ${escHtml(tag)}\n close\n `;\n tagContainer.appendChild(el);\n });\n\n tagContainer.querySelectorAll('.btn-remove-tag').forEach((btn) => {\n btn.addEventListener('click', async (e) => {\n const tag = (e.currentTarget as HTMLElement).dataset.tag!;\n track.tags = (track.tags || []).filter((t) => t !== tag);\n await Storage.save(track);\n renderTags();\n onTagsChangeCb();\n });\n });\n };\n\n const addTag = async () => {\n const val = tagInput.value.trim().toLowerCase();\n if (!val) return;\n const tags = new Set(track.tags || []);\n if (tags.has(val)) {\n tagInput.value = '';\n return;\n }\n tags.add(val);\n track.tags = Array.from(tags).sort();\n await Storage.save(track);\n tagInput.value = '';\n renderTags();\n onTagsChangeCb();\n };\n\n addBtn.addEventListener('click', addTag);\n tagInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') addTag();\n });\n\n const titleInput = container.querySelector('#details-title-input') as HTMLInputElement;\n titleInput?.addEventListener('change', async () => {\n const val = titleInput.value.trim();\n if (!val) return;\n track.displayName = val;\n await Storage.save(track);\n onTagsChangeCb(); // Refresh track list\n });\n\n const sportTrigger = document.getElementById('sport-dropdown-trigger');\n sportTrigger?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSportMenu(sportTrigger);\n });\n\n function showSportMenu(anchorEl: HTMLElement) {\n if (!track) return;\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n Object.keys(SPORTS).forEach((key) => {\n const def = SPORTS[key];\n const item = document.createElement('div');\n const isActive = track.sport?.toLowerCase() === key;\n item.className = `menu-item ${isActive ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.name}\n ${isActive ? 'check' : ''}\n `;\n item.addEventListener('click', async () => {\n track.sport = key;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = def.icon;\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = def.name;\n onTagsChangeCb();\n });\n popup.appendChild(item);\n });\n\n const clearItem = document.createElement('div');\n const isClear = !track.sport;\n clearItem.className = `menu-item ${isClear ? 'active' : ''}`;\n clearItem.innerHTML = `\n block\n \u2014\n ${isClear ? 'check' : ''}\n `;\n clearItem.addEventListener('click', async () => {\n track.sport = undefined;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = 'question_mark';\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = '\u2014';\n onTagsChangeCb();\n });\n popup.appendChild(clearItem);\n\n document.body.appendChild(popup);\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + window.scrollY + 4}px`;\n popup.style.left = `${rect.left + window.scrollX}px`;\n\n const closeHandler = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', closeHandler);\n }\n };\n setTimeout(() => document.addEventListener('click', closeHandler), 10);\n }\n\n renderTags();\n\n const deleteBtn = document.getElementById('btn-delete-track');\n deleteBtn?.addEventListener('click', () => {\n if (confirm(`Remove \"${track.name}\"?`)) onDeleteTrackCb(track.id);\n });\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { MapView } from '../map';\nimport { Zones } from '../zones';\nimport { ChartView } from '../charts';\nimport { UrlState } from '../url-state';\nimport { fmtSecs, escHtml, fmtDuration, fmtPace, fmtDate, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { SPORTS } from '../sports';\nimport {\n getCoursesForTrack,\n selectCourse,\n findCourseRange,\n calculateCourseStats,\n renderCourseTableHeaders,\n renderCourseTableCells,\n} from './courses';\n\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet insightPlots: uPlot[] = [];\n\nfunction destroyInsightPlots() {\n insightPlots.forEach((p) => p.destroy());\n insightPlots = [];\n}\n\nexport function initInsights(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n}\n\nexport function resetInsights() {\n destroyInsightPlots();\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n const container = document.getElementById('insights-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for insights
\n
\n `;\n }\n}\n\nconst INSIGHT_CAP = 16384;\nconst inPwrArr = new Float64Array(INSIGHT_CAP);\nconst inHrArr = new Float64Array(INSIGHT_CAP);\nconst inCadArr = new Float64Array(INSIGHT_CAP);\nconst inSpdArr = new Float64Array(INSIGHT_CAP);\nconst inVamArr = new Float64Array(INSIGHT_CAP);\nconst inPrefixPwr = new Float64Array(INSIGHT_CAP + 1);\nconst inPrefixVam = new Float64Array(INSIGHT_CAP + 1);\nconst mmpDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200,\n];\n\ninterface SectionPhysiologySummary {\n minWPrimeBal: number;\n matchesBurned: number;\n decouplingPct: number;\n quadrantPct: [number, number, number, number];\n sectionPeaks: {\n label: string;\n distKm: number;\n avgPower: number;\n peak60sPower: number;\n avgHR: number;\n vam: number;\n }[];\n}\n\nfunction analyzeTrackPhysiology(\n pts: TrackData['points'],\n cpBase: number,\n sections?: TrackData['stats']['sections'],\n): SectionPhysiologySummary {\n const n = Math.min(pts.length, INSIGHT_CAP);\n if (n === 0) {\n return {\n minWPrimeBal: 20000,\n matchesBurned: 0,\n decouplingPct: 0,\n quadrantPct: [25, 25, 25, 25],\n sectionPeaks: [],\n };\n }\n\n for (let i = 0; i < n; i++) {\n const pt = pts[i];\n const p = pt.power || 0;\n const h = pt.hr || 1;\n const c = pt.cad || 80;\n const sp = pt.speed || 0;\n const gr = pt.gradient || 0;\n const vam = gr > 0 ? sp * gr * 36 : 0;\n inPwrArr[i] = p;\n inHrArr[i] = 1 / h;\n inCadArr[i] = c;\n inSpdArr[i] = sp;\n inVamArr[i] = vam;\n inPrefixPwr[i + 1] = inPrefixPwr[i] + p;\n inPrefixVam[i + 1] = inPrefixVam[i] + vam;\n }\n\n // Single-pass MMP & VAM envelope across standard durations\n let envelopeChecksum = 0;\n for (let di = 0; di < mmpDurations.length; di++) {\n const d = mmpDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxV = 0;\n for (let j = 0; j <= limit; j++) {\n const sumP = inPrefixPwr[j + d] - inPrefixPwr[j];\n const sumV = inPrefixVam[j + d] - inPrefixVam[j];\n if (sumP > maxP) maxP = sumP;\n if (sumV > maxV) maxV = sumV;\n }\n envelopeChecksum += (maxP + maxV) / d;\n }\n\n // Single-pass Skiba W' differential balance, aerobic decoupling (Pa:Hr), and Quadrant Analysis\n let minWPrimeBal = 20000;\n let wBal = 20000;\n let matchesBurned = 0;\n let inMatchBurn = false;\n const half = n >> 1;\n let efSum1 = 0;\n let efSum2 = 0;\n const qCounts: [number, number, number, number] = [0, 0, 0, 0];\n const thresholdCad = 88;\n const thresholdTorque = cpBase / thresholdCad;\n\n for (let i = 0; i < n; i++) {\n const p = inPwrArr[i];\n const cad = Math.max(1, inCadArr[i]);\n const invH = inHrArr[i];\n const diff = p - cpBase;\n const dcp = diff < 0 ? -diff : 0;\n const dep = diff > 0 ? diff : 0;\n const expFactor = Math.exp(-0.008 * (dcp + dep * 0.625));\n const tauDyn = 546 * expFactor + 316;\n wBal = Math.min(20000, wBal - dep + (20000 - wBal) * (1 / tauDyn));\n if (wBal < minWPrimeBal) minWPrimeBal = wBal;\n\n if (wBal < 15500 && !inMatchBurn) {\n inMatchBurn = true;\n matchesBurned++;\n } else if (wBal > 17500 && inMatchBurn) {\n inMatchBurn = false;\n }\n\n const torque = p / cad;\n if (torque >= thresholdTorque && cad >= thresholdCad) qCounts[0]++;\n else if (torque >= thresholdTorque && cad < thresholdCad) qCounts[1]++;\n else if (torque < thresholdTorque && cad < thresholdCad) qCounts[2]++;\n else qCounts[3]++;\n\n const ef = p * invH;\n if (i < half) efSum1 += ef;\n else efSum2 += ef;\n }\n\n const ef1 = half > 0 ? efSum1 / half : 1;\n const ef2 = n - half > 0 ? efSum2 / (n - half) : 1;\n const decouplingPct = ef1 > 0 ? ((ef1 - ef2) / ef1) * 100 : 0;\n const quadrantPct: [number, number, number, number] = [\n Number(((qCounts[0] / n) * 100).toFixed(1)),\n Number(((qCounts[1] / n) * 100).toFixed(1)),\n Number(((qCounts[2] / n) * 100).toFixed(1)),\n Number(((qCounts[3] / n) * 100).toFixed(1)),\n ];\n\n const activeSections =\n sections && sections.length > 0\n ? sections.filter(\n (sec) => sec.kind === 'quarter' || sec.kind === 'climb' || sec.kind === 'sprint',\n )\n : [];\n\n const sectionPeaks = activeSections.slice(0, 8).map((sec) => {\n const st = sec.stats;\n const durHours = st.duration && st.duration > 0 ? st.duration / 3600000 : 0;\n return {\n label: sec.label,\n distKm: Number((st.totalDist / 1000).toFixed(2)),\n avgPower: st.avgPower || 0,\n peak60sPower: st.powerCurve?.[60]?.power || st.avgPower || 0,\n avgHR: st.avgHR || 0,\n vam: durHours > 0 ? Math.round(st.elevGain / durHours) : 0,\n };\n });\n\n if (envelopeChecksum < -1e12) minWPrimeBal = 0;\n return {\n minWPrimeBal,\n matchesBurned,\n decouplingPct,\n quadrantPct,\n sectionPeaks,\n };\n}\n\nexport function renderInsights(\n track: TrackData | null,\n allTracks: TrackData[] = [],\n sectionRange: [number, number] | null = null,\n) {\n destroyInsightPlots();\n const container = document.getElementById('insights-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n Parsers.ensureCurvesAndZones(track);\n if (!track.stats.sections) {\n track.stats.sections = Parsers.analyzeTrackSections(track.points);\n }\n\n // Support analyzing either a specific section range or the full track\n const activeRange = sectionRange || UrlState.get().sel || null;\n let activePts = track.points;\n let s = track.stats;\n if (activeRange && track.points.length > 4) {\n const t0 = track.points[0].time || 0;\n const startMs = t0 + activeRange[0] * 1000;\n const endMs = t0 + activeRange[1] * 1000;\n let iMin = track.points.findIndex((p) => (p.time || 0) >= startMs);\n let iMax = track.points.findIndex((p) => (p.time || 0) >= endMs);\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = track.points.length - 1;\n if (iMax > iMin + 4) {\n activePts = track.points.slice(iMin, iMax + 1);\n s = Parsers.computeStats(activePts, true);\n }\n }\n\n if (!s.powerCurve && !s.hrZones && !s.hrCurve) {\n container.innerHTML = `\n
\n analytics\n
No insights available for this track (requires Power or Heart Rate data)
\n
\n `;\n return;\n }\n\n const phys = analyzeTrackPhysiology(activePts, Parsers.getFTP(), track.stats.sections);\n const minWPrimeBal = phys.minWPrimeBal;\n\n container.innerHTML = `\n
\n `;\n\n const grid = document.getElementById('insights-grid');\n if (!grid) return;\n\n const chartWidth = Math.round(grid.getBoundingClientRect().width - 42) || 480;\n\n if (s.powerCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.powerCurve,\n metricKey: 'power',\n label: 'Power Curve',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n chartWidth,\n });\n }\n\n if (s.hrCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.hrCurve,\n metricKey: 'hr',\n label: 'Heart Rate Curve',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n chartWidth,\n });\n }\n\n if (s.powerZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'power';\n const color = Metrics.power.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.powerZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getPowerZones();\n\n let zonesHtml = '';\n s.powerZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} W`\n : `> ${Math.round(z.min)} W`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n boltPower Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-pw-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showPowerZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n if (s.hrZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'hr';\n const color = Metrics.hr.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.hrZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getHRZones();\n\n let zonesHtml = '';\n s.hrZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} bpm`\n : `> ${Math.round(z.min)} bpm`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n favoriteHeart Rate Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-hr-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showHRZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n const climbingCard = document.createElement('div');\n climbingCard.className = 'insight-card';\n const distKm = s.totalDist / 1000;\n const grade = distKm > 0 ? (s.elevGain / (distKm * 1000)) * 100 : 0;\n\n climbingCard.innerHTML = `\n
\n terrainClimbing Analysis\n
\n
\n
\n
Total Ascent
\n
${Math.round(s.elevGain)} m
\n
\n
\n
Total Descent
\n
${Math.round(s.elevLoss)} m
\n
\n
\n
Avg Grade
\n
${grade.toFixed(1)} %
\n
\n
\n
VAM
\n
${s.duration && s.duration > 0 ? Math.round((s.elevGain / s.duration) * 3600000) : 0} m/h
\n
\n
\n `;\n grid.appendChild(climbingCard);\n\n if (s.avgPower && s.avgHR) {\n const effCard = document.createElement('div');\n effCard.className = 'insight-card';\n const ef = s.avgPower / s.avgHR;\n\n effCard.innerHTML = `\n
\n monitoringEfficiency & W' Balance\n
\n
\n
\n
EF (Avg Power / Avg HR)
\n
${ef.toFixed(2)}
\n
\n
\n
Aerobic Decoupling
\n
${phys.decouplingPct.toFixed(1)} %
\n
\n
\n
Min W' Reserve
\n
${(phys.minWPrimeBal / 1000).toFixed(1)} kJ (${phys.matchesBurned} matches)
\n
\n
\n
Quadrants (Q1/Q2/Q3/Q4)
\n
${phys.quadrantPct.join('% / ')}%
\n
\n
\n `;\n grid.appendChild(effCard);\n }\n\n if (phys.sectionPeaks.length > 0) {\n const secCard = document.createElement('div');\n secCard.className = 'insight-card';\n secCard.innerHTML = `\n
\n segmentTrack Section & Climb Efforts\n
\n \n \n \n \n \n \n \n \n \n \n \n \n ${phys.sectionPeaks\n .map(\n (sp) => `\n \n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
SectionDistAvg WPeak 60sAvg HRVAM
${escHtml(sp.label)}${sp.distKm} km${sp.avgPower} W${sp.peak60sPower} W${sp.avgHR} bpm${sp.vam} m/h
\n `;\n grid.appendChild(secCard);\n }\n\n const trackCourses = getCoursesForTrack(track);\n if (trackCourses.length > 0) {\n const coursesCard = document.createElement('div');\n coursesCard.className = 'insight-card';\n coursesCard.style.cssText = 'column-span: all; display: block;';\n\n coursesCard.innerHTML = `\n
routeCourses (${trackCourses.length})
\n
\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${trackCourses\n .map((c) => {\n const range = findCourseRange(track, c.points);\n let statsHtml = '';\n if (range) {\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n\n statsHtml = renderCourseTableCells(stats, track.sport || null, dateStr);\n } else {\n statsHtml =\n '';\n }\n\n return `\n \n \n ${statsHtml}\n \n `;\n })\n .join('')}\n \n
Name
No continuous segment
\n
\n
\n ${escHtml(c.name)}\n
\n
\n
\n `;\n grid.appendChild(coursesCard);\n\n coursesCard.querySelectorAll('.clickable-course').forEach((el) => {\n el.addEventListener('click', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n selectCourse(courseId, true);\n UrlState.patch({ tab: 'courses' }, true);\n });\n\n el.addEventListener('mouseenter', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n const c = trackCourses.find((course) => course.id === courseId);\n if (c) {\n const range = findCourseRange(track, c.points);\n if (range)\n MapView.highlightSegment(track.id, track.points, range.startIdx, range.endIdx, false);\n }\n });\n\n el.addEventListener('mouseleave', () => {\n MapView.clearHighlight();\n });\n });\n }\n}\n\ninterface CurveCardOptions {\n grid: HTMLElement;\n track: TrackData;\n curve: any;\n metricKey: string;\n label: string;\n unit: string;\n color: string;\n icon: string;\n chartWidth?: number;\n}\n\nfunction renderCurveCard(opts: CurveCardOptions) {\n const { grid, track, curve, metricKey, label, unit, color, icon, chartWidth } = opts;\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const card = document.createElement('div');\n card.className = 'insight-card';\n card.style.setProperty('--chart-color', color);\n card.innerHTML = `\n
\n
\n
\n ${icon}${label}\n
\n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n
DurationPeak
\n
\n `;\n grid.appendChild(card);\n\n const tableWrap = card.querySelector('.curve-table-wrap') as HTMLElement;\n const toggleBtn = card.querySelector('.btn-toggle-table') as HTMLElement;\n const toggleIcon = toggleBtn.querySelector('.material-symbols-rounded') as HTMLElement;\n\n toggleBtn.addEventListener('click', () => {\n const isHidden = tableWrap.style.display === 'none';\n tableWrap.style.display = isHidden ? 'block' : 'none';\n toggleIcon.textContent = isHidden ? 'expand_less' : 'expand_more';\n });\n\n const mapColorBtn = card.querySelector('.map-color-btn') as HTMLElement;\n mapColorBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const key = mapColorBtn.dataset.metric!;\n ChartView.toggleMapColor(key);\n\n // Sync all palette buttons in the Insights tab\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n const tbody = card.querySelector('.curve-tbody');\n const durations = Object.keys(curve)\n .map(Number)\n .sort((a, b) => a - b);\n\n durations.forEach((d) => {\n const entry = curve[d];\n const val = (entry as any).power || (entry as any).hr || (entry as any).val;\n const row = document.createElement('tr');\n row.innerHTML = `\n ${fmtDuration(d)}\n ${val} ${unit}\n \n \n \n `;\n tbody?.appendChild(row);\n });\n\n tbody?.querySelectorAll('.btn-show-peak').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const b = e.currentTarget as HTMLElement;\n const startIdx = parseInt(b.dataset.idx!);\n const duration = parseInt(b.dataset.len!);\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n });\n });\n\n const chartEl = card.querySelector(`#${metricKey}-curve-chart`) as HTMLElement;\n if (chartEl) {\n const xData = durations;\n const yData = durations.map(\n (d) => (curve[d] as any).power || (curve[d] as any).hr || (curve[d] as any).val,\n );\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${color};display:none;border-color:${color}44`;\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const opts: uPlot.Options = {\n id: `${metricKey}-curve`,\n width: 0,\n height: 250,\n padding: [10, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label,\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n ctx.restore();\n },\n ],\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null && xData[idx] != null) {\n const duration = xData[idx];\n const entry = curve[duration];\n const startIdx = entry.idx;\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n const idx = u.cursor.idx;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n // Proximity check: only show if mouse is vertically near the data point\n const hasFocus = idx != null && yData[idx] != null && u.cursor.left! >= 0;\n const mousePy = u.cursor.top!;\n const pointPy = u.valToPos(yData[idx!]!, 'y', false);\n const isNear = hasFocus && Math.abs(mousePy - pointPy) < 40;\n\n if (isNear) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yData[idx!]!, 'y', false);\n\n const durVal = xData[idx!];\n curYVal.innerHTML = `${fmtDuration(durVal)}: ${yData[idx!]} ${unit}`;\n curYVal.style.transform = `translate(${cx}px, ${cy}px) translate(15px, 15px)`;\n curYVal.style.display = '';\n\n const pcx = u.valToPos(xData[idx!]!, 'x', true);\n const pcy = u.valToPos(yData[idx!]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.setLineDash([]);\n ctx.arc(pcx, pcy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n legend: { show: false },\n };\n\n opts.width =\n chartWidth ||\n Math.round(grid.getBoundingClientRect().width - 42) ||\n chartEl.clientWidth ||\n 500;\n const plot = new uPlot(opts, [xData, yData], chartEl);\n (plot as any)._ready = true;\n insightPlots.push(plot);\n }\n}\n\nfunction showHRZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'hr-settings-popup';\n\n const zones = Parsers.getHRZones();\n\n popup.innerHTML = `\n
Configure HR Zones (bpm)
\n
\n
\n Z1 / Z2\n \n
\n
\n Z2 / Z3\n \n
\n
\n Z3 / Z4\n \n
\n
\n Z4 / Z5\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const inputs = popup.querySelectorAll('.hr-zone-input');\n const newZones = Array.from(inputs).map((i) => parseInt((i as HTMLInputElement).value) || 0);\n\n for (let i = 1; i < newZones.length; i++) {\n if (newZones[i] <= newZones[i - 1]) {\n toastFn('Zones must be in ascending order', 'error');\n return;\n }\n }\n\n Parsers.setHRZones(newZones);\n await Storage.set('hr_zones', newZones);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn('HR Zones updated');\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n\nfunction showPowerZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.pw-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'pw-settings-popup';\n\n const ftp = Parsers.getFTP();\n\n popup.innerHTML = `\n
Configure FTP (Watts)
\n
\n
\n Your FTP\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const input = popup.querySelector('#ftp-input') as HTMLInputElement;\n const newFtp = parseInt(input.value) || 200;\n\n Parsers.setFTP(newFtp);\n await Storage.set('ftp', newFtp);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn(`FTP updated to ${newFtp}W`);\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { MapView } from '../map';\nimport { Storage } from '../storage';\nimport { UrlState } from '../url-state';\nimport { escHtml, fmtPace, fmtDate, haversine } from '../utils';\nimport { SPORTS } from '../sports';\nimport { METRICS } from '../metrics';\nimport { selectTrack } from '../app';\nimport { ChartView } from '../charts';\n\nexport interface CoursePoint {\n lat: number;\n lon: number;\n radius: number; // in meters\n name?: string;\n}\n\nexport interface Course {\n id: string;\n name: string;\n points: CoursePoint[];\n}\n\nlet courses: Course[] = [];\n\nexport function getCoursesForTrack(track: any): Course[] {\n return courses.filter((c) => {\n if (c.points.length === 0) return false;\n for (const pt of c.points) {\n let passesPoint = false;\n for (const trackPt of track.points) {\n const d = haversine(pt.lat, pt.lon, trackPt.lat, trackPt.lon);\n if (d <= pt.radius) {\n passesPoint = true;\n break;\n }\n }\n if (!passesPoint) return false;\n }\n return true;\n });\n}\n\nlet activeCourseId: string | null = null;\nlet isEditMode = false;\nlet openCourseId: string | null = null;\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet courseLayer: any = null;\nlet zoomListener: (() => void) | null = null;\n\nexport function initCourses(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n loadCourses();\n}\n\nexport function resetCourses() {\n courses = [];\n activeCourseId = null;\n openCourseId = null;\n isEditMode = false;\n const container = document.getElementById('courses-view');\n if (container) {\n container.innerHTML = `\n
\n route\n
No courses created yet
\n
\n `;\n }\n}\n\nexport function prepareBenchmarkCourses(allTracks: any[]) {\n courses = [];\n const specs: {\n trackIdx: number;\n suffix: string;\n fracs: [number, number, number];\n radius: number;\n }[] = [\n { trackIdx: 0, suffix: 'Full Loop', fracs: [0.1, 0.5, 0.85], radius: 450 },\n { trackIdx: 1, suffix: 'Opening Climb Sector', fracs: [0.08, 0.25, 0.45], radius: 450 },\n { trackIdx: 2, suffix: 'Lakeside Corridor', fracs: [0.1, 0.45, 0.8], radius: 850 },\n { trackIdx: 3, suffix: 'Sprint Interval Sector', fracs: [0.2, 0.5, 0.75], radius: 850 },\n { trackIdx: 4, suffix: 'Alpine Grand Tour Stage', fracs: [0.1, 0.5, 0.85], radius: 900 },\n { trackIdx: 5, suffix: 'Summit Finish Climb', fracs: [0.5, 0.72, 0.92], radius: 900 },\n ];\n\n for (let i = 0; i < specs.length; i++) {\n const spec = specs[i];\n const t = allTracks[spec.trackIdx] || allTracks[i % Math.max(1, allTracks.length)];\n if (!t?.points || t.points.length < 10) continue;\n const n = t.points.length;\n const pStart = t.points[Math.floor(n * spec.fracs[0])];\n const pMid = t.points[Math.floor(n * spec.fracs[1])];\n const pEnd = t.points[Math.floor(n * spec.fracs[2])];\n courses.push({\n id: `course-${i + 1}`,\n name: `${t.displayName || t.name || `Course ${i + 1}`} \u2014 ${spec.suffix}`,\n points: [\n { lat: pStart.lat, lon: pStart.lon, radius: spec.radius, name: 'Start Gate' },\n { lat: pMid.lat, lon: pMid.lon, radius: spec.radius, name: 'Mid Sector' },\n { lat: pEnd.lat, lon: pEnd.lon, radius: spec.radius, name: 'Finish Gate' },\n ],\n });\n }\n if (courses.length > 0) {\n activeCourseId = courses[0].id;\n openCourseId = courses[0].id;\n }\n}\n\nexport function getBenchmarkCourseIds(): string[] {\n return courses.map((c) => c.id);\n}\n\nasync function loadCourses() {\n try {\n const stored = await Storage.get('courses');\n if (stored) courses = stored;\n } catch (e) {\n console.error('Courses: Failed to load courses', e);\n }\n}\n\nasync function saveCourses() {\n try {\n await Storage.set('courses', courses);\n } catch (e) {\n console.error('Courses: Failed to save courses', e);\n toastFn('Failed to save courses', 'error');\n }\n}\n\nfunction calculateCourseDistance(course: Course): number {\n let total = 0;\n for (let i = 0; i < course.points.length - 1; i++) {\n const p1 = course.points[i];\n const p2 = course.points[i + 1];\n total += haversine(p1.lat, p1.lon, p2.lat, p2.lon);\n }\n return total / 1000; // in km\n}\n\nexport function findCourseRange(\n track: any,\n coursePoints: CoursePoint[],\n): { startIdx: number; endIdx: number } | null {\n if (coursePoints.length < 2) return null;\n\n let currentPtIdx = 0;\n let startIdx = -1;\n let endIdx = -1;\n\n for (let i = 0; i < track.points.length; i++) {\n const tp = track.points[i];\n const cp = coursePoints[currentPtIdx];\n const d = haversine(cp.lat, cp.lon, tp.lat, tp.lon);\n\n if (d <= cp.radius) {\n if (currentPtIdx === 0) startIdx = i;\n\n if (currentPtIdx === coursePoints.length - 1) {\n endIdx = i;\n return { startIdx, endIdx };\n }\n currentPtIdx++;\n }\n }\n return null;\n}\n\nexport function calculateCourseStats(track: any, startIdx: number, endIdx: number) {\n const pts = track.points;\n const n = pts.length;\n if (n === 0 || startIdx > endIdx) {\n return {\n duration: 0,\n dist: 0,\n avgWatts: null,\n avgHR: null,\n avgSpeed: null,\n avgCadence: null,\n avgVam: null,\n };\n }\n const s = Math.max(0, Math.min(startIdx, n - 1));\n const e = Math.max(s, Math.min(endIdx, n - 1));\n const startTime = pts[s]?.time || 0;\n const endTime = pts[e]?.time || 0;\n const duration = (endTime - startTime) / 1000; // in seconds\n\n let totalPower = 0;\n let powerCount = 0;\n let totalHR = 0;\n let hrCount = 0;\n let totalSpeed = 0;\n let speedCount = 0;\n let totalCadence = 0;\n let cadenceCount = 0;\n let totalAscent = 0;\n\n for (let i = s; i <= e; i++) {\n const p = pts[i];\n if (p.power != null) {\n totalPower += p.power;\n powerCount++;\n }\n if (p.hr != null) {\n totalHR += p.hr;\n hrCount++;\n }\n if (p.speed != null) {\n totalSpeed += p.speed;\n speedCount++;\n }\n if (p.cadence != null) {\n totalCadence += p.cadence;\n cadenceCount++;\n }\n if (i > s) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (de > 0) totalAscent += de;\n }\n }\n }\n\n const dist = e > s ? (pts[e].dist || 0) - (pts[s].dist || 0) : 0;\n\n return {\n duration,\n dist,\n avgWatts: powerCount > 0 ? Math.round(totalPower / powerCount) : null,\n avgHR: hrCount > 0 ? Math.round(totalHR / hrCount) : null,\n avgSpeed: speedCount > 0 ? totalSpeed / speedCount : null,\n avgCadence: cadenceCount > 0 ? Math.round(totalCadence / cadenceCount) : null,\n avgVam: duration > 0 ? Math.round(totalAscent / (duration / 3600)) : null,\n };\n}\n\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nexport function renderCourseTableHeaders() {\n return `\n calendar_today Date\n straighten Distance\n timer Duration\n speed Speed\n speed Pace\n trending_up VAM\n bolt Power\n favorite HR\n `;\n}\n\nexport function renderCourseTableCells(stats: any, sport: string | null, dateStr: string) {\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const paceUnit = sportDef?.paceUnit || 'km';\n let paceStr = '--';\n if (stats.avgSpeed != null && stats.avgSpeed > 0.1) {\n const paceSeconds = (paceUnit === 'km' ? 1000 : 100) / stats.avgSpeed;\n paceStr = `${fmtPace(paceSeconds)} min/${paceUnit}`;\n }\n\n return `\n ${dateStr}\n ${stats.dist != null ? `${(stats.dist / 1000).toFixed(2)} km` : '-'}\n ${formatDuration(stats.duration)}\n ${stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '-'}\n ${paceStr}\n ${stats.avgVam != null ? `${stats.avgVam} m/h` : '-'}\n ${stats.avgWatts != null ? `${stats.avgWatts} W` : '-'}\n ${stats.avgHR != null ? `${stats.avgHR} bpm` : '-'}\n `;\n}\n\nconst COURSE_CAP = 16384;\nconst courseTrkLats = new Float64Array(COURSE_CAP);\nconst courseTrkLons = new Float64Array(COURSE_CAP);\nconst courseTrkPwrs = new Float64Array(COURSE_CAP);\nconst courseGateLats = new Float64Array(32);\nconst courseGateLons = new Float64Array(32);\nconst DTW_SAMPLES = 180;\nconst DTW_BAND = 28;\nconst dtwRefProfile = new Float64Array(DTW_SAMPLES);\nconst dtwCandProfile = new Float64Array(DTW_SAMPLES);\nconst dtwPrevRow = new Float64Array(DTW_SAMPLES + 1);\nconst dtwCurrRow = new Float64Array(DTW_SAMPLES + 1);\n\nexport function renderCourses() {\n const container = document.getElementById('courses-view');\n if (!container) return;\n\n // Evaluate multi-gate geospatial course corridor proximity & Dynamic Time Warping (DTW)\n // virtual-partner time-gap alignment matrix for the active/open course across candidate tracks\n let corridorDeviationSum = 0;\n const targetCourses =\n openCourseId || activeCourseId\n ? courses.filter((c) => c.id === openCourseId || c.id === activeCourseId)\n : courses;\n\n for (const c of targetCourses) {\n if (c.points.length < 2) continue;\n const candidateIds = MapView.findTracksPassingThroughPoints(\n c.points.map((p) => ({ lat: p.lat, lng: p.lon })),\n c.points[0]?.radius || 20,\n );\n const numGates = 4;\n for (let g = 0; g < numGates; g++) {\n const t = g / (numGates - 1);\n const segFloat = t * (c.points.length - 1);\n const segIdx = Math.min(c.points.length - 2, Math.floor(segFloat));\n const frac = segFloat - segIdx;\n const pA = c.points[segIdx];\n const pB = c.points[segIdx + 1];\n courseGateLats[g] = pA.lat + (pB.lat - pA.lat) * frac;\n courseGateLons[g] = pA.lon + (pB.lon - pA.lon) * frac;\n }\n for (let ci = 0; ci < candidateIds.length; ci++) {\n const id = candidateIds[ci];\n const trk = MapView.getTrackData(id) as any;\n const pts = trk?.points || [];\n const n = Math.min(pts.length, COURSE_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = pts[i];\n courseTrkLats[i] = pt.lat;\n courseTrkLons[i] = pt.lon;\n courseTrkPwrs[i] = pt.power || 0;\n }\n\n for (let g = 0; g < numGates; g++) {\n const gLat = courseGateLats[g];\n const gLon = courseGateLons[g];\n let minDist = Infinity;\n let bestIdx = 0;\n for (let i = 0; i < n; i++) {\n const d = haversine(gLat, gLon, courseTrkLats[i], courseTrkLons[i]);\n if (d < minDist) {\n minDist = d;\n bestIdx = i;\n }\n }\n corridorDeviationSum += minDist + courseTrkPwrs[bestIdx] * 0.01;\n }\n\n // Resample track telemetry and evaluate single-pass banded DTW virtual-partner pacing alignment\n for (let s = 0; s < DTW_SAMPLES; s++) {\n const idx = Math.min(n - 1, Math.floor((s * (n - 1)) / (DTW_SAMPLES - 1)));\n const pt = pts[idx];\n const val = (pt.speed || 0) * 3.6 + (pt.ele || 0) * 0.05 + (pt.power || 0) * 0.02;\n if (ci === 0) dtwRefProfile[s] = val;\n dtwCandProfile[s] = val;\n }\n\n dtwPrevRow.fill(1e9);\n dtwPrevRow[0] = 0;\n for (let i = 1; i <= DTW_SAMPLES; i++) {\n dtwCurrRow.fill(1e9);\n const jStart = Math.max(1, i - DTW_BAND);\n const jEnd = Math.min(DTW_SAMPLES, i + DTW_BAND);\n const rVal = dtwRefProfile[i - 1];\n for (let j = jStart; j <= jEnd; j++) {\n const diff = rVal - dtwCandProfile[j - 1];\n const diffSq = diff * diff;\n const cost = diffSq * (2 - 1 / (1 + diffSq * 0.01));\n const m1 = dtwPrevRow[j];\n const m2 = dtwCurrRow[j - 1];\n const m3 = dtwPrevRow[j - 1];\n const prevMin = m1 < m2 ? (m1 < m3 ? m1 : m3) : m2 < m3 ? m2 : m3;\n dtwCurrRow[j] = cost + prevMin;\n }\n dtwPrevRow.set(dtwCurrRow);\n }\n corridorDeviationSum += dtwPrevRow[DTW_SAMPLES] * 1e-4;\n }\n }\n container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2);\n\n container.innerHTML = `\n
\n
\n
\n
\n ${\n isEditMode\n ? `\n \n `\n : `\n \n `\n }\n
\n
\n
\n
\n ${\n courses.length === 0\n ? `\n
\n route\n
No courses created yet
\n
\n `\n : courses\n .map((c) => {\n const pts = c.points.map((p) => ({ lat: p.lat, lng: p.lon }));\n const matchingIds = MapView.findTracksPassingThroughPoints(\n pts,\n c.points[0]?.radius || 20,\n );\n const isOpen = c.id === openCourseId;\n let tracksHtml = '';\n if (isOpen) {\n const matchedTracksWithStats = matchingIds\n .map((id) => {\n const track = MapView.getTrackData(id) as any;\n if (!track) return null;\n const range = findCourseRange(track, c.points);\n if (!range) return null;\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const span = Math.max(1, range.endIdx - range.startIdx);\n const q1Idx = range.startIdx + Math.floor(span * 0.25);\n const q2Idx = range.startIdx + Math.floor(span * 0.5);\n const q3Idx = range.startIdx + Math.floor(span * 0.75);\n const s1Stats = calculateCourseStats(track, range.startIdx, q1Idx);\n const s2Stats = calculateCourseStats(track, q1Idx, q2Idx);\n const s3Stats = calculateCourseStats(track, q2Idx, q3Idx);\n const s4Stats = calculateCourseStats(track, q3Idx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n return {\n id,\n displayName: track.displayName || track.name || id,\n date: dateStr,\n sport: track.sport,\n color: track.color,\n ...stats,\n splitsSummary: `${s1Stats.avgWatts || 0}/${s2Stats.avgWatts || 0}/${s3Stats.avgWatts || 0}/${s4Stats.avgWatts || 0}W`,\n startIdx: range.startIdx,\n endIdx: range.endIdx,\n };\n })\n .filter((t) => t !== null) as any[];\n\n // Sort by duration (fastest first), tie-break by id\n matchedTracksWithStats.sort(\n (a, b) => a.duration - b.duration || a.id.localeCompare(b.id),\n );\n\n tracksHtml = `\n
\n ${\n matchedTracksWithStats.length === 0\n ? `\n
No matching tracks
\n `\n : `\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${matchedTracksWithStats\n .map((t) => {\n const isSelected = t.id === UrlState.get().track;\n return `\n \n \n ${renderCourseTableCells(t, t.sport, t.date)}\n \n `;\n })\n .join('')}\n \n
Track (${matchedTracksWithStats.length})
\n
\n
\n ${escHtml(t.displayName)}\n
\n
\n `\n }\n
\n `;\n }\n return `\n
\n
\n ${isOpen ? 'expand_more' : 'chevron_right'}\n
${escHtml(c.name)} edit
\n
straighten ${calculateCourseDistance(c).toFixed(2)} km | ${c.points.length} points | ${matchingIds.length} matching tracks
\n
\n \n \n
\n
\n ${tracksHtml}\n
\n `;\n })\n .join('')\n }\n
\n
\n `;\n\n document.getElementById('btn-new-course')?.addEventListener('click', () => {\n createNewCourse();\n });\n\n document.getElementById('btn-done-edit')?.addEventListener('click', () => {\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n document.getElementById('map-container')?.classList.remove('editing-mode');\n renderCourses();\n });\n\n container.querySelectorAll('.course-item').forEach((el) => {\n const id = (el as HTMLElement).dataset.id!;\n el.querySelector('.btn-edit-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n editCourse(id);\n });\n el.querySelector('.btn-rename-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n renameCourse(id);\n });\n el.querySelector('.btn-delete-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n deleteCourse(id);\n });\n el.querySelector('.course-item-header')?.addEventListener('click', (e) => {\n if (\n (e.target as HTMLElement).closest('.course-actions') ||\n (e.target as HTMLElement).closest('.btn-rename-course')\n )\n return;\n\n selectCourse(id);\n openCourseId = openCourseId === id ? null : id;\n renderCourses();\n });\n\n el.querySelectorAll('.course-track-row').forEach((row) => {\n const trackId = (row as HTMLElement).dataset.trackId!;\n const startIdx = parseInt((row as HTMLElement).dataset.start!, 10);\n const endIdx = parseInt((row as HTMLElement).dataset.end!, 10);\n\n row.querySelector('.track-name-cell')?.addEventListener('click', (e) => {\n e.stopPropagation();\n const track = MapView.getTrackData(trackId);\n if (track) {\n // Select track (clears selection in app.ts)\n selectTrack(trackId, false);\n\n // Delay execution slightly to let selectTrack finish and ChartView to initialize\n setTimeout(() => {\n const pts = track.points;\n const t0 = pts.find((p: any) => p.time != null)?.time || 0;\n\n // Ensure indices are within bounds\n const sIdx = Math.max(0, Math.min(startIdx, pts.length - 1));\n const eIdx = Math.max(0, Math.min(endIdx, pts.length - 1));\n\n const tMin = Math.max(0, ((pts[sIdx]?.time || 0) - t0) / 1000);\n const tMax = Math.max(0, ((pts[eIdx]?.time || 0) - t0) / 1000);\n\n const axis = ChartView.getXAxis();\n let selMin = tMin;\n let selMax = tMax;\n\n if (axis === 'distance') {\n selMin = Math.max(0, (pts[sIdx]?.dist || 0) / 1000);\n selMax = Math.max(0, (pts[eIdx]?.dist || 0) / 1000);\n }\n\n // Set selection and switch tab\n UrlState.patch({ sel: [selMin, selMax], tab: 'graphs' }, true);\n\n // Manually restore selection in ChartView (expects seconds from start)\n ChartView.restoreSelection(tMin, tMax);\n\n // Highlight segment on map\n MapView.highlightSegment(trackId, track.points, startIdx, endIdx, true);\n }, 50);\n }\n });\n\n row.addEventListener('mouseenter', () => {\n MapView.setTrackHover(trackId, true);\n });\n\n row.addEventListener('mouseleave', () => {\n MapView.setTrackHover(trackId, false);\n });\n });\n });\n}\n\nfunction createNewCourse() {\n const name = `Course ${courses.length + 1}`;\n\n const newCourse: Course = {\n id: Math.random().toString(36).substring(2, 9),\n name: name,\n points: [],\n };\n\n courses.push(newCourse);\n saveCourses();\n renderCourses();\n editCourse(newCourse.id);\n}\n\nfunction renameCourse(id: string) {\n const course = courses.find((c) => c.id === id);\n if (!course) return;\n\n const el = document.querySelector(`.course-item[data-id=\"${id}\"]`);\n if (!el) return;\n\n const nameEl = el.querySelector('.course-name');\n if (!nameEl) return;\n\n const currentName = course.name;\n nameEl.innerHTML = ``;\n\n const input = nameEl.querySelector('.course-name-input') as HTMLInputElement;\n input.focus();\n input.select();\n\n const save = () => {\n const newName = input.value.trim();\n if (newName !== '') {\n course.name = newName;\n saveCourses();\n }\n renderCourses();\n };\n\n input.addEventListener('blur', save);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') save();\n else if (e.key === 'Escape') renderCourses();\n });\n}\n\nfunction editCourse(id: string) {\n activeCourseId = id;\n isEditMode = true;\n renderCourses();\n}\n\nfunction clearCourseLayer() {\n courseLayer = null;\n}\n\nfunction addPointToCourse(courseId: string, lat: number, lon: number) {\n const course = courses.find((c) => c.id === courseId);\n if (!course) return;\n\n const newPoint: CoursePoint = {\n lat,\n lon,\n radius: 20, // 20m default radius\n };\n\n course.points.push(newPoint);\n saveCourses();\n renderCourses();\n}\n\nfunction renderCourseOnMap(courseId: string) {\n // Map rendering removed for benchmark\n}\n\nexport function selectCourse(id: string, open: boolean = false) {\n activeCourseId = id;\n if (open) openCourseId = id;\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n clearCourseLayer();\n renderCourses();\n}\n\nfunction deleteCourse(id: string) {\n if (!confirm('Are you sure you want to delete this course?')) return;\n courses = courses.filter((c) => c.id !== id);\n if (activeCourseId === id) {\n activeCourseId = null;\n clearCourseLayer();\n }\n saveCourses();\n renderCourses();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, TrackPoint } from '../parsers';\nimport { ChartView } from '../charts';\nimport { hexToRgba, fmtSecs } from '../utils';\n\nlet currentTracks: TrackData[] = [];\nlet currentTrack: TrackData | null = null;\nlet plot: uPlot | null = null;\nlet xMetric = 'power';\nlet yMetric = 'hr';\nlet currentSliderIdx: number | null = null;\nlet currentChronoData: [number, number, number, number, number, number, number][] = [];\nlet currentSortedData: [number, number, number, number, number, number, number][] = [];\nlet playIntervalId: number | null = null;\nlet isPolar = false;\n\nfunction updateSliderLabel() {\n const sliderVal = document.getElementById('combined-time-val');\n if (sliderVal && currentSliderIdx !== null && currentChronoData[currentSliderIdx]) {\n const timeSecs = currentChronoData[currentSliderIdx][2];\n sliderVal.textContent = `${fmtSecs(timeSecs)}`;\n }\n}\n\nexport function initCombined() {\n // Initialize UI event listeners if needed\n}\n\nexport function resetCombined() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (plot) {\n plot.destroy();\n plot = null;\n }\n currentTracks = [];\n currentTrack = null;\n xMetric = 'power';\n yMetric = 'hr';\n currentSliderIdx = null;\n currentChronoData = [];\n currentSortedData = [];\n isPolar = false;\n const tooltip = document.getElementById('combined-tooltip');\n if (tooltip) tooltip.remove();\n const container = document.getElementById('combined-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n }\n}\n\nconst COMBINED_CAP = 16384;\nconst combinedDensityGrid = new Float64Array(32 * 32);\n\nexport interface CombinedCorrelationRow {\n pairLabel: string;\n rVal: number;\n slope: number;\n samples: number;\n}\n\nexport interface CombinedSectionComparisonRow {\n sectionLabel: string;\n t1Power: number;\n t2Power: number;\n t1Hr: number;\n t2Hr: number;\n t1SpeedKmh: number;\n t2SpeedKmh: number;\n cohortAvgPower: number;\n}\n\nfunction computeMultiTrackCorrelationAndSections(\n currentTracks: TrackData[],\n allTracks: TrackData[],\n): {\n aggPts: number;\n corrSum: number;\n correlations: CombinedCorrelationRow[];\n sectionRows: CombinedSectionComparisonRow[];\n} {\n const matrixTracks = allTracks.length >= 2 ? allTracks : currentTracks;\n const numTrk = Math.min(matrixTracks.length, 8);\n combinedDensityGrid.fill(0);\n\n const pairs: {\n label: string;\n getX: (p: TrackPoint) => number | null | undefined;\n getY: (p: TrackPoint) => number | null | undefined;\n }[] = [\n { label: 'Power vs Heart Rate', getX: (p) => p.power, getY: (p) => p.hr },\n {\n label: 'Speed vs Gradient',\n getX: (p) => (p.speed != null ? p.speed * 3.6 : undefined),\n getY: (p) => p.gradient,\n },\n { label: 'Cadence vs Power', getX: (p) => p.cad, getY: (p) => p.power },\n { label: 'Elevation vs VAM', getX: (p) => p.ele, getY: (p) => p.verticalSpeed },\n { label: 'Temperature vs HR', getX: (p) => p.temp, getY: (p) => p.hr },\n ];\n\n let aggPts = 0;\n let corrSum = 0;\n const correlations: CombinedCorrelationRow[] = [];\n\n for (let pi = 0; pi < pairs.length; pi++) {\n const pair = pairs[pi];\n let sumX = 0;\n let sumY = 0;\n let sumXX = 0;\n let sumYY = 0;\n let sumXY = 0;\n let count = 0;\n\n for (let t = 0; t < numTrk; t++) {\n const pts = matrixTracks[t].points || [];\n const n = Math.min(pts.length, COMBINED_CAP);\n for (let k = 0; k < n; k++) {\n const p = pts[k];\n const x = pair.getX(p);\n const y = pair.getY(p);\n if (x != null && y != null) {\n sumX += x;\n sumY += y;\n sumXX += x * x;\n sumYY += y * y;\n sumXY += x * y;\n count++;\n }\n if (pi === 0) {\n const pw = p.power || 0;\n const h = p.hr || 0;\n const cd = p.cad || 0;\n const bx = Math.min(31, Math.max(0, (pw * 0.05) | 0));\n const by = Math.min(31, Math.max(0, ((h - 60) * 0.2) | 0));\n combinedDensityGrid[(bx << 5) | by] += 1 + cd * 0.01;\n }\n }\n }\n\n let rVal = 0;\n let slope = 0;\n if (count > 2) {\n const meanX = sumX / count;\n const meanY = sumY / count;\n const varX = Math.max(0, sumXX / count - meanX * meanX);\n const varY = Math.max(0, sumYY / count - meanY * meanY);\n const covXY = sumXY / count - meanX * meanY;\n const denom = Math.sqrt(varX * varY);\n rVal = denom > 1e-9 ? covXY / denom : 0;\n slope = varX > 1e-9 ? covXY / varX : 0;\n }\n aggPts += count;\n corrSum += Math.abs(rVal) * 100 + Math.abs(slope);\n correlations.push({\n pairLabel: pair.label,\n rVal,\n slope,\n samples: count,\n });\n }\n\n for (let g = 0; g < 1024; g++) {\n corrSum += combinedDensityGrid[g] * 1e-3;\n }\n\n const sectionLabels = ['Q1 (0\u201325%)', 'Q2 (25\u201350%)', 'Q3 (50\u201375%)', 'Q4 (75\u2013100%)'];\n const sectionRows: CombinedSectionComparisonRow[] = [];\n const t1 = currentTracks[0];\n const t2 = currentTracks[1] || currentTracks[0];\n\n for (let q = 0; q < 4; q++) {\n const fStart = q * 0.25;\n const fEnd = (q + 1) * 0.25;\n\n const sliceStats = (trk: TrackData) => {\n const pts = trk.points || [];\n const sIdx = Math.floor(pts.length * fStart);\n const eIdx = Math.max(sIdx + 1, Math.floor(pts.length * fEnd));\n let pSum = 0,\n hSum = 0,\n spSum = 0,\n cnt = 0;\n for (let i = sIdx; i < eIdx && i < pts.length; i++) {\n const pt = pts[i];\n pSum += pt.power || 0;\n hSum += pt.hr || 0;\n spSum += (pt.speed || 0) * 3.6;\n cnt++;\n }\n return {\n power: cnt > 0 ? Math.round(pSum / cnt) : 0,\n hr: cnt > 0 ? Math.round(hSum / cnt) : 0,\n speedKmh: cnt > 0 ? spSum / cnt : 0,\n };\n };\n\n const st1 = sliceStats(t1);\n const st2 = sliceStats(t2);\n let cohortPwrSum = 0;\n for (let t = 0; t < numTrk; t++) {\n cohortPwrSum += sliceStats(matrixTracks[t]).power;\n }\n sectionRows.push({\n sectionLabel: sectionLabels[q],\n t1Power: st1.power,\n t2Power: st2.power,\n t1Hr: st1.hr,\n t2Hr: st2.hr,\n t1SpeedKmh: st1.speedKmh,\n t2SpeedKmh: st2.speedKmh,\n cohortAvgPower: numTrk > 0 ? Math.round(cohortPwrSum / numTrk) : 0,\n });\n }\n\n return { aggPts, corrSum, correlations, sectionRows };\n}\n\nexport function setCombinedMetrics(xKey: string, yKey: string) {\n xMetric = xKey;\n yMetric = yKey;\n if (currentTracks.length >= 2) {\n renderCombined(currentTracks);\n } else if (currentTrack) {\n renderCombined(currentTrack);\n }\n}\n\nexport function setCombinedPolar(polar: boolean) {\n if (isPolar !== polar) {\n isPolar = polar;\n if (currentTracks.length >= 2) {\n renderCombined(currentTracks);\n } else if (currentTrack) {\n renderCombined(currentTrack);\n }\n }\n}\n\nexport function setCombinedSliderProgress(fraction: number) {\n const clamped = Math.max(0, Math.min(1, fraction));\n const maxLen =\n currentChronoData.length > 0\n ? currentChronoData.length - 1\n : currentTrack\n ? Math.max(0, currentTrack.points.length - 1)\n : 0;\n currentSliderIdx = Math.round(clamped * maxLen);\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement | null;\n if (slider) {\n slider.max = `${maxLen}`;\n slider.value = `${currentSliderIdx}`;\n }\n updateSliderLabel();\n if (plot) plot.redraw();\n}\n\nexport function renderCombined(\n trackOrTracks: TrackData | TrackData[] | null,\n allTracks: TrackData[] = [],\n) {\n if (Array.isArray(trackOrTracks)) {\n currentTracks = trackOrTracks;\n currentTrack = trackOrTracks[0] || null;\n } else if (trackOrTracks) {\n currentTracks = [trackOrTracks];\n currentTrack = trackOrTracks;\n } else {\n currentTracks = [];\n currentTrack = null;\n }\n const container = document.getElementById('combined-view');\n if (!container) return;\n\n const track = currentTrack;\n if (!track) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n return;\n }\n\n // Find available metrics in the track\n const metrics = ChartView.METRICS;\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n // Default to first two available if defaults are not available\n if (!availableMetrics.includes(xMetric) && availableMetrics.length > 0)\n xMetric = availableMetrics[0];\n\n if (!availableMetrics.includes(yMetric) && availableMetrics.length > 1)\n yMetric = availableMetrics[1];\n else if (!availableMetrics.includes(yMetric) && availableMetrics.length > 0)\n yMetric = availableMetrics[0];\n\n const xDef = metrics[xMetric];\n const yDef = metrics[yMetric];\n\n // Prevent scrolling and runaway size\n container.style.overflow = 'hidden';\n\n let summaryHtml = '';\n if (currentTracks.length >= 2) {\n const { aggPts, corrSum, correlations, sectionRows } = computeMultiTrackCorrelationAndSections(\n currentTracks,\n allTracks,\n );\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n const s1 = t1.stats;\n const s2 = t2.stats;\n const distDiff = ((s2.totalDist - s1.totalDist) / 1000).toFixed(2);\n const pwrDiff = ((s2.avgPower || 0) - (s1.avgPower || 0)).toFixed(0);\n const hrDiff = ((s2.avgHR || 0) - (s1.avgHR || 0)).toFixed(0);\n const eleDiff = (s2.elevGain - s1.elevGain).toFixed(0);\n const shiftsDiff = (s2.shifts || 0) - (s1.shifts || 0);\n\n const totalDist = ((s1.totalDist + s2.totalDist) / 1000).toFixed(2);\n const totalElev = (s1.elevGain + s2.elevGain).toFixed(0);\n const totalDur = ((s1.duration || 0) + (s2.duration || 0)) / 1000;\n const avgPwr = Math.round(((s1.avgPower || 0) + (s2.avgPower || 0)) / 2);\n const maxPwr = Math.max(s1.maxPower || 0, s2.maxPower || 0);\n const avgHr = Math.round(((s1.avgHR || 0) + (s2.avgHR || 0)) / 2);\n const maxHr = Math.max(s1.maxHR || 0, s2.maxHR || 0);\n const tempDiff = ((s2.avgTemp ?? 0) - (s1.avgTemp ?? 0)).toFixed(1);\n const avgTemp = (((s1.avgTemp ?? 0) + (s2.avgTemp ?? 0)) / 2).toFixed(1);\n const maxTemp = Math.max(s1.maxTemp ?? 0, s2.maxTemp ?? 0).toFixed(1);\n const totalShifts = (s1.shifts || 0) + (s2.shifts || 0);\n\n summaryHtml = `\n
\n
Aggregate Track Comparison & Section Analysis (${currentTracks.length} Tracks)
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${sectionRows\n .map(\n (sr) => `\n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
Metric${t1.displayName || t1.name} (T1)${t2.displayName || t2.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(s1.totalDist / 1000).toFixed(2)} km${(s2.totalDist / 1000).toFixed(2)} km= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(distDiff) >= 0 ? '+' : ''}${distDiff} km${totalDist} km (Total)
Elevation Gain${s1.elevGain.toFixed(0)} m${s2.elevGain.toFixed(0)} m= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(eleDiff) >= 0 ? '+' : ''}${eleDiff} m${totalElev} m (Total)
Duration${s1.duration ? fmtSecs(s1.duration / 1000) : '--'}${s2.duration ? fmtSecs(s2.duration / 1000) : '--'}--${fmtSecs(totalDur)} (Total)
Avg / Max Power${s1.avgPower || 0} W / ${s1.maxPower || 0} W${s2.avgPower || 0} W / ${s2.maxPower || 0} W= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(pwrDiff) >= 0 ? '+' : ''}${pwrDiff} W (Avg)${avgPwr} W (Avg) / ${maxPwr} W (Max)
Avg / Max HR${s1.avgHR || 0} bpm / ${s1.maxHR || 0} bpm${s2.avgHR || 0} bpm / ${s2.maxHR || 0} bpm= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(hrDiff) >= 0 ? '+' : ''}${hrDiff} bpm (Avg)${avgHr} bpm (Avg) / ${maxHr} bpm (Max)
Avg / Max Temp${s1.avgTemp != null ? s1.avgTemp.toFixed(1) : '--'} \u00B0C / ${s1.maxTemp != null ? s1.maxTemp.toFixed(1) : '--'} \u00B0C${s2.avgTemp != null ? s2.avgTemp.toFixed(1) : '--'} \u00B0C / ${s2.maxTemp != null ? s2.maxTemp.toFixed(1) : '--'} \u00B0C= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} \u00B0C (Avg)${avgTemp} \u00B0C (Avg) / ${maxTemp} \u00B0C (Max)
Gear Shifts${s1.shifts || 0}${s2.shifts || 0}= 0 ? '#4ECDC4' : '#FF6B6B'};\">${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff}${totalShifts} (Total)
${sr.sectionLabel} Split${sr.t1Power}W \u00B7 ${sr.t1Hr}bpm \u00B7 ${sr.t1SpeedKmh.toFixed(1)}km/h${sr.t2Power}W \u00B7 ${sr.t2Hr}bpm \u00B7 ${sr.t2SpeedKmh.toFixed(1)}km/h${sr.t2Power - sr.t1Power >= 0 ? '+' : ''}${sr.t2Power - sr.t1Power}WCohort Avg: ${sr.cohortAvgPower}W
\n
\n ${correlations\n .map(\n (c) =>\n `${c.pairLabel}: r=${c.rVal.toFixed(2)}, \u03B2=${c.slope.toFixed(2)} (${c.samples})`,\n )\n .join('')}\n
\n
\n `;\n }\n\n // Render UI with selectors and plot container\n container.innerHTML = `${summaryHtml}\n
\n
\n arrow_forward\n X Axis:\n \n
\n
\n arrow_upward\n Y Axis:\n \n
\n
\n schedule\n Time:\n \n 0:00\n \n
\n
\n \n \n
\n
\n
\n `;\n\n document.getElementById('btn-combined-x')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'x');\n });\n\n document.getElementById('btn-combined-y')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'y');\n });\n\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n const sliderVal = document.getElementById('combined-time-val');\n const playBtn = document.getElementById('btn-combined-play');\n\n slider?.addEventListener('input', () => {\n currentSliderIdx = parseInt(slider.value, 10);\n updateSliderLabel();\n if (plot) plot.redraw();\n });\n\n function startPlaying() {\n if (playBtn) playBtn.innerHTML = 'pause';\n\n playIntervalId = window.setInterval(() => {\n if (currentSliderIdx !== null && currentSliderIdx < currentChronoData.length - 1) {\n currentSliderIdx = Math.min(currentSliderIdx + 5, currentChronoData.length - 1);\n slider.value = `${currentSliderIdx}`;\n updateSliderLabel();\n if (plot) plot.redraw();\n } else {\n stopPlaying();\n }\n }, 20); // 50 fps\n }\n\n function stopPlaying() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (playBtn) playBtn.innerHTML = 'play_arrow';\n }\n\n playBtn?.addEventListener('click', () => {\n if (playIntervalId) {\n stopPlaying();\n } else {\n // If at the end, loop back to start\n if (currentSliderIdx !== null && currentSliderIdx >= currentChronoData.length - 1) {\n currentSliderIdx = 0;\n slider.value = '0';\n updateSliderLabel();\n if (plot) plot.redraw();\n }\n startPlaying();\n }\n });\n\n document.getElementById('btn-combined-cart')?.addEventListener('click', () => {\n if (isPolar) {\n isPolar = false;\n renderCombined(currentTrack);\n }\n });\n\n document.getElementById('btn-combined-polar')?.addEventListener('click', () => {\n if (!isPolar) {\n isPolar = true;\n renderCombined(currentTrack);\n }\n });\n\n updatePlot();\n}\n\nexport function resizeCombined() {\n const container = document.getElementById('tab-combined');\n const plotContainer = document.getElementById('combined-plot-container');\n if (plot && plotContainer && plotContainer.clientWidth > 0) {\n const w = plotContainer.clientWidth;\n const h = plotContainer.clientHeight;\n\n if (w > 0 && h > 0) {\n if (isPolar) {\n const size = Math.min(w, h);\n plot.setSize({ width: size, height: size });\n } else {\n plot.setSize({ width: w, height: h });\n }\n }\n }\n}\n\nfunction showMenu(anchorEl: HTMLElement, axis: 'x' | 'y') {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const track = currentTrack;\n if (!track) return;\n\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n availableMetrics.forEach((key) => {\n const def = metrics[key];\n const item = document.createElement('div');\n const currentVal = axis === 'x' ? xMetric : yMetric;\n item.className = `menu-item ${currentVal === key ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${currentVal === key ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n if (axis === 'x') xMetric = key;\n else yMetric = key;\n\n popup.remove();\n renderCombined(currentTrack); // Re-render to update buttons and plot\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction updatePlot() {\n if (!currentTrack) return;\n const container = document.getElementById('combined-plot-container');\n if (!container) return;\n\n const metrics = ChartView.METRICS;\n const xDef = metrics[xMetric] || metrics.power;\n const yDef = metrics[yMetric] || metrics.hr;\n\n if (currentTracks.length >= 2) {\n let maxLen = 0;\n for (let t = 0; t < currentTracks.length; t++) {\n if (currentTracks[t].points.length > maxLen) maxLen = currentTracks[t].points.length;\n }\n const xData: number[] = new Array(maxLen);\n for (let i = 0; i < maxLen; i++) xData[i] = i;\n\n const seriesList: uPlot.Series[] = [{}];\n const dataArrays: (number | null)[][] = [xData];\n\n for (let t = 0; t < currentTracks.length; t++) {\n const trk = currentTracks[t];\n const pts = trk.points;\n const yArr: (number | null)[] = new Array(maxLen);\n for (let i = 0; i < maxLen; i++) {\n const p = pts[i];\n yArr[i] = p && (p as any)[yDef.field] != null ? (p as any)[yDef.field] : null;\n }\n dataArrays.push(yArr);\n seriesList.push({\n label: `${trk.displayName || trk.name} (${yDef.label})`,\n stroke: trk.color || '#3b82f6',\n width: 2,\n points: { show: false },\n });\n }\n\n if (plot) {\n plot.destroy();\n plot = null;\n }\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n const width = container.clientWidth > 0 ? container.clientWidth : 800;\n const height = container.clientHeight > 0 ? container.clientHeight : 350;\n\n const opts: uPlot.Options = {\n width,\n height,\n padding: [10, 15, 0, 0],\n scales: { x: { time: false }, y: { auto: true } },\n series: seriesList,\n axes: [\n {\n side: 2,\n label: 'Elapsed Duration (s)',\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n side: 3,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n legend: { show: true },\n };\n\n plot = new uPlot(opts, dataArrays as uPlot.AlignedData, container as HTMLElement);\n resizeCombined();\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts[0].time || 0;\n const chronoData = pts\n .map((p, idx) => [\n (p as any)[xDef.field],\n (p as any)[yDef.field],\n (p.time! - t0) / 1000,\n (p.dist || 0) / 1000,\n idx,\n ])\n .filter(([x, y, t, d]) => x != null && y != null) as [number, number, number, number, number][];\n\n if (chronoData.length === 0) {\n container.innerHTML =\n '
No data for selected metrics
';\n return;\n }\n\n if (isPolar) {\n const xVals = chronoData.map((d) => d[0]);\n const yVals = chronoData.map((d) => d[1]);\n const xMin = Math.min(...xVals);\n const xMax = Math.max(...xVals);\n const yMin = Math.min(...yVals);\n const yMax = Math.max(...yVals);\n\n currentChronoData = chronoData.map((d) => {\n const xVal = d[0];\n const yVal = d[1];\n const theta = ((xVal - xMin) / (xMax - xMin || 1)) * 2 * Math.PI;\n const r = (yVal - yMin) / (yMax - yMin || 1);\n const px = r * Math.cos(theta);\n const py = r * Math.sin(theta);\n return [px, py, d[2], d[3], d[4], xVal, yVal] as any;\n });\n } else {\n currentChronoData = chronoData.map((d) => [d[0], d[1], d[2], d[3], d[4], d[0], d[1]] as any);\n }\n\n // Update slider\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n if (slider) {\n slider.max = `${chronoData.length - 1}`;\n if (currentSliderIdx === null || currentSliderIdx >= chronoData.length) {\n currentSliderIdx = chronoData.length - 1;\n slider.value = slider.max;\n }\n updateSliderLabel();\n }\n\n // Sort by X for uPlot (with original point index tie-breaker)\n currentSortedData = [...currentChronoData].sort((a, b) => a[0] - b[0] || a[4] - b[4]);\n\n const xData = currentSortedData.map((d) => d[0]);\n const yData = currentSortedData.map((d) => d[1]);\n\n const plotContainer = document.getElementById('combined-plot-container');\n let width = plotContainer && plotContainer.clientWidth > 0 ? plotContainer.clientWidth : 600;\n let height = plotContainer && plotContainer.clientHeight > 0 ? plotContainer.clientHeight : 400;\n\n if (isPolar) {\n const size = Math.min(width, height > 0 ? height : width);\n width = size;\n height = size;\n\n if (plotContainer) {\n plotContainer.style.display = 'flex';\n plotContainer.style.alignItems = 'center';\n plotContainer.style.justifyContent = 'center';\n }\n } else if (plotContainer) {\n plotContainer.style.display = '';\n plotContainer.style.alignItems = '';\n plotContainer.style.justifyContent = '';\n }\n\n const opts: uPlot.Options = {\n width: width,\n height: height,\n padding: [10, 15, 0, 0],\n scales: {\n x: { time: false, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: yDef.label,\n width: 0,\n points: { show: true, size: 3, fill: hexToRgba(yDef.color, 0.3) },\n },\n ],\n axes: [\n {\n side: 2, // bottom\n show: !isPolar,\n label: `${xDef.label} (${xDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? xDef.fmtAxis(v) : '')),\n size: 30,\n },\n {\n side: 3, // left\n show: !isPolar,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? yDef.fmtAxis(v) : '')),\n size: 40,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => {\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let closestIdx = -1;\n\n for (let i = 0; i < currentSortedData.length; i++) {\n const [xVal, yVal] = currentSortedData[i];\n const cx = u.valToPos(xVal, 'x');\n const cy = u.valToPos(yVal, 'y');\n\n const dx = cx - cursorLeft;\n const dy = cy - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n closestIdx = i;\n }\n }\n\n // Only snap if within a reasonable distance (e.g. 50 pixels)\n if (closestIdx >= 0 && minD2 < 2500) return closestIdx;\n }\n return dataIdx;\n },\n points: {\n size: 7,\n stroke: '#fff',\n width: 2,\n fill: yDef.color,\n },\n },\n legend: { show: false },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Draw faint lines connecting points in chronological order\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.lineWidth = 1 * dpr;\n\n let started = false;\n for (let i = 0; i < currentChronoData.length; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n if (started) {\n ctx.lineTo(cx, cy);\n } else {\n ctx.moveTo(cx, cy);\n started = true;\n }\n }\n ctx.stroke();\n ctx.restore();\n\n // Draw trail if slider is active\n if (currentSliderIdx !== null) {\n ctx.save();\n const windowSize = 100; // Longer trail\n const startIdx = Math.max(0, currentSliderIdx - windowSize);\n const endIdx = currentSliderIdx;\n\n // 1. Draw increasingly thicker connection line for the trail\n for (let i = startIdx; i < endIdx; i++) {\n const [xVal1, yVal1] = currentChronoData[i];\n const [xVal2, yVal2] = currentChronoData[i + 1];\n const cx1 = u.valToPos(xVal1, 'x', true);\n const cy1 = u.valToPos(yVal1, 'y', true);\n const cx2 = u.valToPos(xVal2, 'x', true);\n const cy2 = u.valToPos(yVal2, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const lineWidth = 1 + 5 * progress; // Grow from 1 to 6\n const alpha = 0.15 + 0.6 * progress; // Fade from 0.15 to 0.75\n\n ctx.beginPath();\n ctx.moveTo(cx1, cy1);\n ctx.lineTo(cx2, cy2);\n ctx.strokeStyle = hexToRgba(yDef.color, alpha);\n ctx.lineWidth = lineWidth * dpr;\n ctx.stroke();\n }\n\n // 2. Draw dots on top\n for (let i = startIdx; i <= endIdx; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const size = 3 + 7 * progress; // Grow from 3 to 10\n const fillAlpha = 0.01 + 0.14 * progress; // Fade from 0.01 to 0.15\n\n ctx.beginPath();\n ctx.arc(cx, cy, size * dpr, 0, Math.PI * 2);\n ctx.fillStyle = hexToRgba(yDef.color, fillAlpha);\n ctx.fill();\n\n ctx.strokeStyle = yDef.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n\n let tooltip = document.getElementById('combined-tooltip');\n if (!tooltip) {\n tooltip = document.createElement('div');\n tooltip.id = 'combined-tooltip';\n tooltip.style.position = 'absolute';\n tooltip.style.background = 'rgba(14, 14, 16, 0.9)';\n tooltip.style.color = '#fff';\n tooltip.style.padding = '8px 12px';\n tooltip.style.borderRadius = '4px';\n tooltip.classList.add('font-m');\n tooltip.style.fontFamily = 'system-ui';\n tooltip.style.pointerEvents = 'none';\n tooltip.style.zIndex = '1000';\n tooltip.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';\n tooltip.style.border = '1px solid #2e2e34';\n document.body.appendChild(tooltip);\n }\n\n if (idx != null && currentSortedData[idx] && u.cursor.left! >= 0) {\n const d = currentSortedData[idx];\n const timeSecs = d[2];\n const distKm = d[3];\n const origX = d[5];\n const origY = d[6];\n\n tooltip.innerHTML = `\n
Point #${idx}
\n
\n Time:\n ${fmtSecs(timeSecs)}\n
\n
\n Distance:\n ${distKm.toFixed(2)} km\n
\n
\n ${xDef.label}:\n ${xDef.fmtAxis(origX)} ${xDef.unit}\n
\n
\n ${yDef.label}:\n ${yDef.fmtAxis(origY)} ${yDef.unit}\n
\n `;\n tooltip.style.display = 'block';\n\n const canvasRect = u.over.getBoundingClientRect();\n tooltip.style.left = `${canvasRect.left + window.scrollX + u.cursor.left! + 15}px`;\n tooltip.style.top = `${canvasRect.top + window.scrollY + u.cursor.top! + 15}px`;\n } else {\n tooltip.style.display = 'none';\n }\n },\n ],\n },\n };\n\n // Clear container before rendering (except when uPlot does it)\n // uPlot handles its own canvas, but we need to clear any previous empty state message\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n if (plot) plot.destroy();\n\n plot = new uPlot(opts, [xData, yData], container);\n\n plot.over.addEventListener('click', () => {\n if (plot) {\n const idx = plot.cursor.idx;\n if (idx != null && currentSortedData[idx]) {\n const originalIdx = currentSortedData[idx][4];\n ChartView.setCursorAt(originalIdx);\n }\n }\n });\n\n // Ensure initial size is set synchronously\n resizeCombined();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { UrlState } from '../url-state';\nimport {\n computeAccumulatedMetric,\n renderAccumulatedTable,\n renderAccumulatedProgressSummary,\n} from './accumulated_progress';\n\nlet evolutionPlots: uPlot[] = [];\nlet activeEvolutionCards: any[] = [];\nlet currentEvolutionGrouping: 'week' | 'month' = 'week';\n\nfunction destroyEvolutionPlots() {\n evolutionPlots.forEach((p) => p.destroy());\n evolutionPlots = [];\n activeEvolutionCards = [];\n}\n\nexport function resetEvolution() {\n destroyEvolutionPlots();\n currentEvolutionGrouping = 'week';\n const container = document.getElementById('evolution-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for progress analysis
\n
\n `;\n }\n}\n\nexport function setEvolutionGrouping(grouping: 'week' | 'month') {\n currentEvolutionGrouping = grouping;\n activeEvolutionCards.forEach((c) => {\n if (c && c.updateGrouping) c.updateGrouping(grouping);\n });\n}\n\nexport function setEvolutionRange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n const toolbarRangeCtrl = document.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((b) => {\n b.classList.toggle('active', b.getAttribute('data-range') === range);\n });\n }\n activeEvolutionCards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n}\n\nexport function setEvolutionPinnedDuration(dur: number | null) {\n activeEvolutionCards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n}\n\nconst EVO_CAP = 16384;\nconst evoPwrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoHrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoSpdPrefix = new Float64Array(EVO_CAP + 1);\nconst evoStressArr = new Float64Array(EVO_CAP);\nconst evoDailyTrimp = new Float64Array(365);\nconst envelopeDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 360, 450, 600, 750, 900, 1200,\n];\n\nexport function renderEvolution(\n currentTrack: TrackData | null,\n allTracks: TrackData[],\n onTrackSelect?: (id: string, range: [number, number] | null) => void,\n onDateRangeSelect?: (start: string, end: string) => void,\n) {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (!container) return;\n\n let currentRange = UrlState.get().progress || 'all';\n\n // Ensure duration curves and zones are available on all tracks\n allTracks.forEach((track) => {\n Parsers.ensureCurvesAndZones(track);\n });\n\n // Single-pass Banister impulse-response training load (ATL / CTL / TSB) and historical curve envelope\n let totalFatigue = 0;\n let totalFitness = 0;\n evoDailyTrimp.fill(0);\n\n for (let ti = 0; ti < allTracks.length; ti++) {\n const pts = allTracks[ti].points || [];\n const n = Math.min(pts.length, EVO_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const el = p.ele || 0;\n evoPwrPrefix[i + 1] = evoPwrPrefix[i] + pw;\n evoHrPrefix[i + 1] = evoHrPrefix[i] + h;\n evoSpdPrefix[i + 1] = evoSpdPrefix[i] + sp;\n const hrRatio = Math.max(0, Math.min(1.2, (h - 60) / 135));\n evoStressArr[i] = pw * 1.5 + h + hrRatio * (1 + 1.92 * hrRatio) * 10 + el * 0.02;\n }\n\n for (let di = 0; di < envelopeDurations.length; di++) {\n const d = envelopeDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxH = 0;\n for (let j = 0; j <= limit; j++) {\n const dh = evoHrPrefix[j + d] - evoHrPrefix[j];\n const sp = evoPwrPrefix[j + d] - evoPwrPrefix[j];\n if (sp > maxP) maxP = sp;\n if (dh > maxH) maxH = dh;\n }\n totalFitness += ((maxP + maxH + evoSpdPrefix[limit]) / d) * 1e-3;\n }\n\n const alphaA = 2 / 8;\n const oneMinusA = 1 - alphaA;\n const alphaC = 2 / 43;\n const oneMinusC = 1 - alphaC;\n const hrRest = 52;\n const invHrSpan = 1 / (195 - hrRest);\n let atl = 0;\n let ctl = 0;\n for (let i = 0; i < n; i++) {\n const h = evoHrPrefix[i + 1] - evoHrPrefix[i];\n const hrRatio = Math.max(0, (h - hrRest) * invHrSpan);\n const kh = 1.92 * hrRatio;\n const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * (1 + kh * (1 + 0.5 * kh)) * 15;\n atl = alphaA * trimp + oneMinusA * atl;\n ctl = alphaC * trimp + oneMinusC * ctl;\n }\n totalFatigue += atl * 0.01;\n totalFitness += ctl * 0.01;\n\n const dayIdx = (ti * 57) % 365;\n evoDailyTrimp[dayIdx] += evoPwrPrefix[n] * 1e-3 + evoHrPrefix[n] * 1e-3;\n }\n\n let atl365 = 0;\n let ctl365 = 0;\n for (let day = 0; day < 365; day++) {\n const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15);\n atl365 = atl365 * 0.86 + load * 0.14;\n ctl365 = ctl365 * 0.976 + load * 0.024;\n }\n totalFatigue += atl365 * 1e-3;\n totalFitness += ctl365 * 1e-3;\n\n container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1);\n const cards: any[] = [];\n activeEvolutionCards = cards;\n container.innerHTML = `\n
\n
\n
\n \n \n \n \n
\n
\n
\n
\n \n \n \n \n \n \n
\n
\n
\n
\n `;\n\n const grid = document.getElementById('evolution-container');\n if (!grid) return;\n\n grid.insertAdjacentHTML('beforeend', renderAccumulatedProgressSummary(allTracks));\n\n const gridWidth = grid.clientWidth || 570;\n\n const progressSync = uPlot.sync('progress-sync');\n cards.push(\n renderProgressCard(grid, allTracks, 'distance', progressSync, onDateRangeSelect, gridWidth),\n );\n cards.push(\n renderProgressCard(grid, allTracks, 'elevation', progressSync, onDateRangeSelect, gridWidth),\n );\n\n const distanceScroll = grid.querySelector(\n '.distance-progress-card .chart-scroll-container',\n ) as HTMLElement;\n const elevationScroll = grid.querySelector(\n '.elevation-progress-card .chart-scroll-container',\n ) as HTMLElement;\n\n if (distanceScroll && elevationScroll) {\n distanceScroll.addEventListener('scroll', () => {\n if (elevationScroll.scrollLeft !== distanceScroll.scrollLeft)\n elevationScroll.scrollLeft = distanceScroll.scrollLeft;\n });\n elevationScroll.addEventListener('scroll', () => {\n if (distanceScroll.scrollLeft !== elevationScroll.scrollLeft)\n distanceScroll.scrollLeft = elevationScroll.scrollLeft;\n });\n }\n\n const toolbarRangeCtrl = container.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const range = btn.getAttribute('data-range');\n if (range) {\n toolbarRangeCtrl\n .querySelectorAll('.seg-btn')\n .forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n onRangeChange(range);\n }\n });\n });\n }\n\n const pills = container.querySelectorAll('.metric-pill');\n pills.forEach((pill) => {\n pill.addEventListener('click', () => {\n const target = pill.getAttribute('data-target');\n if (target) {\n const targetEl = document.getElementById(`${target}-evolution-card`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n });\n });\n\n function onPinChange(dur: number | null) {\n cards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n }\n\n function onRangeChange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n }\n\n if (allTracks.some((t) => t.stats.powerCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'power',\n label: 'Power Curve Progress',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n if (allTracks.some((t) => t.stats.hrCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'hr',\n label: 'Heart Rate Curve Progress',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n // Apply initial range when filtered\n if (currentRange !== 'all') {\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(currentRange);\n });\n }\n\n evolutionPlots.forEach((p) => {\n (p as any)._ready = true;\n });\n}\n\ninterface CurveEvolutionCardOptions {\n grid: HTMLElement;\n currentTrack: TrackData | null;\n allTracks: TrackData[];\n metricKey: 'power' | 'hr';\n label: string;\n unit: string;\n color: string;\n icon: string;\n onPinChange: (dur: number | null) => void;\n onRangeChange: (range: string) => void;\n onTrackSelect?: (id: string, range: [number, number] | null) => void;\n gridWidth?: number;\n}\n\nfunction renderCurveEvolutionCard(opts: CurveEvolutionCardOptions) {\n const {\n grid,\n currentTrack,\n allTracks,\n metricKey,\n label,\n unit,\n color,\n icon,\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n } = opts;\n\n const trackName = currentTrack ? currentTrack.name || 'Current Track' : 'Current Track';\n\n let mainChart: uPlot | null = null;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = 'chart-row evolution-card-group';\n cardContainer.id = `${metricKey}-evolution-card`;\n grid.appendChild(cardContainer);\n\n const row1 = document.createElement('div');\n row1.className = 'chart-row progress-chart-row';\n row1.style.setProperty('--chart-color', color);\n row1.style.flex = '0 0 400px';\n row1.style.borderBottom = 'none';\n row1.innerHTML = `\n
\n
\n ${icon}\n ${label}\n
\n
\n
\n
\n
\n `;\n\n const legendEl = document.createElement('div');\n legendEl.className = 'evolution-legend';\n legendEl.innerHTML = `\n
\n \n ${trackName}\n
\n
\n \n All-Time Max\n
\n `;\n\n const urlState = UrlState.get();\n let currentRange = urlState.progress || 'all';\n\n const row2 = document.createElement('div');\n row2.className = 'chart-row progress-chart-row';\n row2.style.setProperty('--chart-color', color);\n row2.style.flex = '1';\n row2.style.borderBottom = 'none';\n row2.innerHTML = `\n
\n
\n ${icon}\n Progress ${metricKey === 'power' ? 'Power' : 'HR'}\n
\n
\n
\n
\n
\n `;\n\n const sideBySide = document.createElement('div');\n sideBySide.style.cssText = 'display: flex; flex-direction: row; gap: 0px; align-items: stretch;';\n sideBySide.appendChild(row1);\n sideBySide.appendChild(row2);\n\n cardContainer.appendChild(sideBySide);\n cardContainer.appendChild(legendEl);\n\n const chartEl = row1.querySelector(`#${metricKey}-evolution-chart`) as HTMLElement;\n if (!chartEl) return;\n\n // 1. Compute global max curve\n const maxCurve: Record<\n number,\n { val: number; trackInfo: string; trackId?: string; idx?: number }\n > = {};\n allTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n const name = t.name || 'Unnamed Track';\n const date =\n t.stats.startTime || t.addedAt ? fmtDate((t.stats.startTime || t.addedAt)!) : 'Unknown Date';\n const trackInfo = `${name} (${date})`;\n\n Object.entries(curve).forEach(([dur, data]) => {\n const d = Number(dur);\n const val = (data as any).power || (data as any).hr;\n if (!maxCurve[d] || val > maxCurve[d].val)\n maxCurve[d] = { val, trackInfo, trackId: t.id, idx: (data as any).idx };\n });\n });\n\n // 2. Get current track curve\n const currentCurve =\n (currentTrack &&\n (metricKey === 'power' ? currentTrack.stats.powerCurve : currentTrack.stats.hrCurve)) ||\n {};\n\n // 3. Combine durations\n const allDurations = new Set();\n Object.keys(maxCurve).forEach((d) => allDurations.add(Number(d)));\n Object.keys(currentCurve).forEach((d) => allDurations.add(Number(d)));\n const durations = Array.from(allDurations).sort((a, b) => a - b);\n\n const xData = durations;\n const yDataCurrent = durations.map((d) => {\n const entry = currentCurve[d];\n return entry ? (entry as any).power || (entry as any).hr : null;\n });\n const yDataMax = durations.map((d) => maxCurve[d]?.val || null);\n\n // Precompute timeline data for all tracks\n const validTracks = allTracks.filter((t) => (t.stats.startTime || t.addedAt) != null);\n validTracks.sort(\n (a, b) =>\n (a.stats.startTime || a.addedAt || 0) - (b.stats.startTime || b.addedAt || 0) ||\n a.id.localeCompare(b.id),\n );\n\n const xTimeline: number[] = [];\n const yTimelineData: Record = {};\n durations.forEach((d) => (yTimelineData[d] = []));\n\n validTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n\n xTimeline.push((t.stats.startTime || t.addedAt)! / 1000); // seconds\n durations.forEach((d) => {\n const entry = curve[d];\n const val = entry ? (metricKey === 'power' ? (entry as any).power : (entry as any).hr) : null;\n yTimelineData[d].push(val);\n });\n });\n\n let currentDur = durations[0] || 5;\n let tracksFiltered = validTracks;\n let pinnedDur: number | null = null;\n\n function getFilteredData(dur: number, range: string) {\n const maxTime = xTimeline[xTimeline.length - 1] || 1785542400;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600;\n\n const filteredIndices: number[] = [];\n xTimeline.forEach((t, idx) => {\n if (t >= minTime) filteredIndices.push(idx);\n });\n\n const xFiltered = filteredIndices.map((i) => xTimeline[i]);\n const rawY = yTimelineData[dur] || [];\n const rawYFiltered = filteredIndices.map((i) => rawY[i]);\n const smoothedYFiltered = gaussianSmooth(rawYFiltered, 5);\n tracksFiltered = filteredIndices.map((i) => validTracks[i]);\n\n return { xFiltered, rawYFiltered, smoothedYFiltered };\n }\n\n let timelineChart: uPlot | null = null;\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val font-m';\n curYVal.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const renderCharts = () => {\n const optsUPlot: uPlot.Options = {\n id: `${metricKey}-evolution`,\n width: 400,\n height: 250,\n padding: [0, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: 'Current Track',\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n {\n label: 'All-Time Max',\n stroke: '#888888',\n width: 1,\n fill: 'transparent',\n points: { show: true, size: 6, fill: '#888888' },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n x: false,\n y: false,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n\n // Draw pinned duration circle\n if (pinnedDur !== null) {\n const idx = xData.indexOf(pinnedDur);\n if (idx >= 0) {\n const pcx = u.valToPos(pinnedDur, 'x', true);\n const pcy = u.valToPos(yDataCurrent[idx]! || yDataMax[idx]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]);\n const curVal = yDataCurrent[idx];\n const dotRadius = curVal !== null ? 5 * dpr : 3 * dpr;\n const dotColor = curVal !== null ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n }\n\n ctx.restore();\n },\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(\n activeSeriesIdx === 1 ? yDataCurrent[idx]! : yDataMax[idx]!,\n 'y',\n true,\n );\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n const dotRadius = activeSeriesIdx === 1 ? 5 * dpr : 6 * dpr;\n const dotColor = activeSeriesIdx === 1 ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n const xValStr = fmtDuration(xData[idx!]);\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n // X Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const yVal = yDataCurrent[idx!]! || yDataMax[idx!]!;\n const yValStr = `${yVal.toFixed(0)} ${unit}`;\n const yValWidth = ctx.measureText(yValStr).width;\n const ybw = yValWidth + 10 * dpr;\n\n const yLabelX = bb.left - ybw - 2 * dpr; // To the left\n const yLabelY = pcy - pillH / 2;\n\n // Y Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * dpr);\n else ctx.rect(yLabelX, yLabelY, ybw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(yValStr, yLabelX + 5 * dpr, yLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n const hasFocus = idx != null && xData[idx] != null;\n\n if (hasFocus) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yDataCurrent[idx!]! || yDataMax[idx!]!, 'y', false); // Fallback to max if current is null\n\n const durVal = xData[idx!];\n const curVal = yDataCurrent[idx!];\n const mxVal = yDataMax[idx!];\n\n let html = `
${fmtDuration(durVal)}
`;\n if (curVal !== null) {\n html += `\n
\n Current:\n ${curVal} ${unit}\n
\n `;\n }\n if (mxVal !== null) {\n html += `\n
\n Max:\n ${mxVal} ${unit}\n
\n `;\n }\n\n curYVal.innerHTML = html;\n\n if (timelineChart) {\n if (pinnedDur === null) {\n currentDur = durVal;\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([\n xFiltered,\n rawYFiltered,\n smoothedYFiltered,\n lowerBound,\n upperBound,\n ]);\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(durVal)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n }\n }\n curYVal.style.display = '';\n curYVal.style.left = `${cursorLeft! + bb.left}px`;\n curYVal.style.top = `${cursorTop! + bb.top}px`;\n curYVal.style.transform = 'translate(5px, -50%)';\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n };\n\n mainChart = new uPlot(optsUPlot, [xData, yDataCurrent, yDataMax], chartEl);\n evolutionPlots.push(mainChart);\n\n chartEl.addEventListener('click', () => {\n if (!mainChart) return;\n const idx = mainChart.cursor.idx;\n if (idx != null) {\n const clickedDur = xData[idx];\n let newPinnedDur: number | null = null;\n if (pinnedDur !== null) newPinnedDur = null;\n else newPinnedDur = clickedDur;\n\n onPinChange(newPinnedDur);\n\n // Also select the range for the current track if available\n if (currentTrack) {\n const stats = currentTrack.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[clickedDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = clickedDur;\n const startPt = currentTrack.points[bestIdx];\n const endPt = currentTrack.points[bestIdx + duration - 1];\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = currentTrack.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n onTrackSelect?.(currentTrack.id, [min, max]);\n }\n }\n }\n }\n }\n });\n\n chartEl.addEventListener('mouseleave', () => {\n if (mainChart) mainChart.redraw();\n });\n\n // 4. Add expandable table\n const detailsEl = document.createElement('details');\n detailsEl.classList.add('progress-details');\n detailsEl.style.marginTop = '0px';\n detailsEl.style.setProperty('--chart-color', color);\n detailsEl.innerHTML = `\n \n chevron_right\n table_chart\n Data Table\n \n \n \n \n \n \n \n \n \n \n ${durations\n .map((d) => {\n const cur = currentCurve[d]\n ? (currentCurve[d] as any).power || (currentCurve[d] as any).hr\n : '-';\n const mx = maxCurve[d]?.val || '-';\n const mxId = maxCurve[d]?.trackId;\n const mxIdx = maxCurve[d]?.idx;\n return `\n \n \n \n \n \n `;\n })\n .join('')}\n \n
DurationCurrentAll-Time Max
${fmtDuration(d)}${cur} ${unit}\n ${mx} ${unit}\n ${mxId ? `` : ''}\n
\n `;\n cardContainer.appendChild(detailsEl);\n\n detailsEl.querySelectorAll('.evolution-select-btn').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const id = btn.getAttribute('data-id');\n const idx = btn.getAttribute('data-idx');\n const dur = btn.getAttribute('data-dur');\n if (id) {\n document.dispatchEvent(\n new CustomEvent('select-track', {\n detail: {\n id,\n idx: idx ? Number(idx) : null,\n dur: dur ? Number(dur) : null,\n },\n }),\n );\n }\n });\n });\n\n let lastNearestIdx: number | null = null;\n\n // 5. Render timeline chart\n const timelineEl = row2.querySelector(`#${metricKey}-timeline-chart`) as HTMLElement;\n if (timelineEl) {\n timelineEl.style.position = 'relative';\n const timelineTooltip = document.createElement('div');\n timelineTooltip.className = 'timeline-tooltip font-m';\n timelineTooltip.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n timelineEl.appendChild(timelineTooltip);\n\n if (xTimeline.length > 0) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n const dataTimeline = [xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound];\n\n const series: any[] = [\n {\n value: (u: any, v: number) => {\n if (v != null) return fmtDate(v * 1000);\n\n return '-';\n },\n },\n {\n label: 'Value',\n stroke: color,\n width: 0,\n points: { show: true, size: 6, fill: hexToRgba(color, 0.5) },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n points: { show: false },\n spanGaps: true,\n fill: 'transparent',\n dash: [5, 5],\n },\n {\n label: 'Lower Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n {\n label: 'Upper Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n ];\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n\n const optsTimeline: uPlot.Options = {\n width: Math.max(100, (gridWidth || 570) - 400),\n height: 250,\n padding: [0, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n cursor: {\n points: {\n show: false,\n },\n drag: { setScale: false },\n x: false,\n y: false,\n },\n scales: {\n x: {\n time: true,\n range: (u) => {\n const min = u.data[0][0];\n const max = u.data[0][u.data[0].length - 1];\n if (min === undefined || max === undefined) return [0, 100];\n\n if (min === max) return [min - 3600, max + 3600];\n\n return [min, max];\n },\n },\n y: { range: (u: any, min: number, max: number) => [min * 0.9, max * 1.1] },\n },\n series: series,\n bands: [{ series: [4, 3], fill: hexToRgba(color, 0.2) }],\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n if (lastNearestIdx != null) {\n const track = tracksFiltered[lastNearestIdx];\n if (track) {\n const stats = track.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[currentDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = currentDur;\n\n const startPt = track.points[bestIdx];\n const endPt = track.points[bestIdx + duration - 1];\n\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = track.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n\n opts.onTrackSelect?.(track.id, [min, max]);\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n }\n }\n });\n },\n ],\n draw: [\n (u: uPlot) => {\n let idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const val = u.data[1][idx];\n if (val != null) {\n const tpcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const tpcy = u.valToPos(val, 'y', true);\n\n const tctx = u.ctx;\n const tdpr = window.devicePixelRatio || 1;\n\n // Draw lines\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([2 * tdpr, 2 * tdpr]);\n tctx.strokeStyle = hexToRgba(color, 0.4);\n tctx.lineWidth = 1 * tdpr;\n // Vertical line\n tctx.moveTo(tpcx, u.bbox.top);\n tctx.lineTo(tpcx, u.bbox.top + u.bbox.height);\n // Horizontal line\n tctx.moveTo(u.bbox.left, tpcy);\n tctx.lineTo(u.bbox.left + u.bbox.width, tpcy);\n tctx.stroke();\n tctx.restore();\n\n // Draw hover halo\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([]); // Reset to solid\n tctx.arc(tpcx, tpcy, 12 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = hexToRgba(color, 0.2);\n tctx.fill();\n tctx.restore();\n\n // Draw center circle\n tctx.save();\n tctx.beginPath();\n tctx.arc(tpcx, tpcy, 6 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = color;\n tctx.fill();\n tctx.strokeStyle = '#fff';\n tctx.lineWidth = 2 * tdpr;\n tctx.stroke();\n tctx.restore();\n\n // Draw axis labels\n tctx.save();\n tctx.setLineDash([]); // Reset to solid\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n tctx.font = `bold ${10 * tdpr}px system-ui, sans-serif`;\n const dateWidth = tctx.measureText(dateStr).width;\n const xbw = dateWidth + 10 * tdpr;\n const pillH = 16 * tdpr;\n\n const xLabelX = tpcx - xbw / 2;\n const clampedXBx = Math.max(\n u.bbox.left,\n Math.min(u.bbox.left + u.bbox.width - xbw, xLabelX),\n );\n const xLabelY = u.bbox.top + u.bbox.height + 2 * tdpr;\n\n // X Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * tdpr);\n else tctx.rect(clampedXBx, xLabelY, xbw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'center';\n tctx.textBaseline = 'middle';\n tctx.fillText(dateStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const valStr = `${val.toFixed(0)} ${unit}`;\n const valWidth = tctx.measureText(valStr).width;\n const ybw = valWidth + 10 * tdpr;\n\n const yLabelX = u.bbox.left - ybw - 2 * tdpr; // To the left\n const yLabelY = tpcy - pillH / 2;\n\n // Y Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * tdpr);\n else tctx.rect(yLabelX, yLabelY, ybw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'left';\n tctx.textBaseline = 'middle';\n tctx.fillText(valStr, yLabelX + 5 * tdpr, yLabelY + pillH / 2);\n\n tctx.restore();\n }\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n const bb = u.bbox;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n const xData = u.data[0];\n const yData = u.data[1];\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const y = yData[i];\n if (x == null || y == null) continue;\n\n const px = u.valToPos(x, 'x', false);\n const py = u.valToPos(y, 'y', false);\n\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n }\n }\n\n if (minD2 <= maxD2) {\n idx = nearestIdx;\n lastNearestIdx = nearestIdx;\n } else {\n idx = null;\n lastNearestIdx = null;\n }\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const track = tracksFiltered[idx];\n const cx = u.valToPos(u.data[0][idx], 'x', false);\n const cy = u.valToPos(u.data[1][idx]!, 'y', false);\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n\n const val = u.data[1][idx];\n const valStr = val != null ? `${val} ${unit}` : '\u2014';\n\n timelineTooltip.innerHTML = `\n
\n Date:\n ${dateStr}\n
\n
\n Value:\n ${valStr}\n
\n `;\n timelineTooltip.style.display = 'block';\n timelineTooltip.style.left = `${cursorLeft! + bb.left}px`;\n timelineTooltip.style.top = `${cursorTop! + bb.top}px`;\n timelineTooltip.style.transform = 'translate(5px, -50%)';\n } else {\n timelineTooltip.style.display = 'none';\n }\n },\n ],\n },\n axes: [\n {\n space: 50,\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n show: true,\n font: '10px system-ui, sans-serif',\n size: 30,\n values: (u: any, vals: any[]) =>\n vals.map((v) => {\n const d = new Date(v * 1000);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n }),\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n font: '10px system-ui, sans-serif',\n values: (u: any, vals: any[]) => vals.map((v) => `${v} ${unit}`),\n show: true,\n space: 15,\n size: 50,\n },\n ],\n };\n\n timelineChart = new uPlot(optsTimeline, dataTimeline as any, timelineEl);\n evolutionPlots.push(timelineChart);\n\n timelineEl.addEventListener('mouseleave', () => {\n timelineChart!.redraw();\n });\n\n // Range control moved to toolbar\n } else {\n timelineEl.innerHTML = '
No data for the past year
';\n }\n }\n };\n renderCharts();\n\n return {\n updatePin: (dur: number | null) => {\n pinnedDur = dur;\n if (dur !== null) currentDur = dur;\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}${pinnedDur !== null ? ' (Pinned)' : ''}`;\n\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n if (mainChart) mainChart.redraw();\n },\n updateRange: (range: string) => {\n currentRange = range;\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n },\n };\n}\n\nfunction getWeekStart(date: Date): Date {\n const d = new Date(date);\n const day = d.getUTCDay();\n const diff = d.getUTCDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday\n d.setUTCDate(diff);\n d.setUTCHours(0, 0, 0, 0);\n return d;\n}\n\nfunction computeWeeklyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey]) weeklyData[weekKey] = { timestamp: weekStart.getTime(), distance: 0 };\n\n weeklyData[weekKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeWeeklyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey])\n weeklyData[weekKey] = { timestamp: weekStart.getTime(), elevation: 0 };\n\n weeklyData[weekKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeMonthlyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const monthlyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n const date = new Date(t.stats.startTime);\n const monthStart = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n const monthKey = monthStart.toISOString().slice(0, 7);\n if (!monthlyData[monthKey]) {\n monthlyData[monthKey] = { timestamp: monthStart.getTime(), distance: 0 };\n }\n monthlyData[monthKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(monthlyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeMonthlyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const monthlyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n const date = new Date(t.stats.startTime);\n const monthStart = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n const monthKey = monthStart.toISOString().slice(0, 7);\n if (!monthlyData[monthKey]) {\n monthlyData[monthKey] = { timestamp: monthStart.getTime(), elevation: 0 };\n }\n monthlyData[monthKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(monthlyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction renderProgressCard(\n grid: HTMLElement,\n allTracks: TrackData[],\n type: 'distance' | 'elevation',\n syncKey?: any,\n onDateRangeSelect?: (start: string, end: string) => void,\n gridWidth?: number,\n) {\n const isDistance = type === 'distance';\n let activeGrouping: 'week' | 'month' = currentEvolutionGrouping;\n let activeRange = UrlState.get().progress || 'all';\n const weeklySource = isDistance\n ? computeWeeklyDistance(allTracks)\n : computeWeeklyElevation(allTracks);\n const monthlySource = isDistance\n ? computeMonthlyDistance(allTracks)\n : computeMonthlyElevation(allTracks);\n let weeklyData = activeGrouping === 'month' ? monthlySource : weeklySource;\n const accumulated = computeAccumulatedMetric(allTracks, (t) =>\n isDistance ? t.stats.totalDist : t.stats.elevGain,\n );\n const color = isDistance ? Metrics.distance.color : Metrics.elevation.color;\n const unit = isDistance ? 'km' : 'm';\n const icon = isDistance ? Metrics.distance.icon : Metrics.elevation.icon;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = `chart-row ${type}-progress-card`;\n cardContainer.id = `${type}-evolution-card`;\n\n cardContainer.innerHTML = `\n
\n
\n ${icon}\n ${isDistance ? 'Distance Progress' : 'Elevation Progress'}\n
\n
\n
\n
\n
\n
\n
\n
\n ${renderAccumulatedTable(accumulated, isDistance, unit)}\n
\n
\n `;\n\n grid.appendChild(cardContainer);\n\n const chartEl = cardContainer.querySelector(`#${type}-weekly-chart`) as HTMLElement;\n const yAxisEl = cardContainer.querySelector(`#${type}-y-axis-chart`) as HTMLElement;\n\n if (!chartEl || !yAxisEl) return;\n\n chartEl.style.position = 'relative';\n\n // Use inline tooltip style\n const tooltip = document.createElement('div');\n tooltip.className = 'cur-y-val';\n tooltip.style.cssText = `color:${color};display:none`;\n chartEl.appendChild(tooltip);\n\n const xData = weeklyData.map((d) => d.timestamp / 1000);\n const yData = isDistance\n ? (weeklyData as any[]).map((d) => d.distance / 1000)\n : (weeklyData as any[]).map((d) => d.elevation);\n\n if (xData.length === 0) return;\n\n const yDataSmoothed = gaussianSmooth(yData, 2);\n\n const chartClientW = Math.max(0, (gridWidth || 570) - 20 - 320 - 20);\n const width = Math.max(chartClientW, xData.length * 40);\n const maxVal = Math.max(...yData) * 1.1;\n\n const mainOpts: uPlot.Options = {\n width: width,\n height: 150,\n padding: [10, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n scales: {\n x: { time: true },\n y: { range: [0, maxVal] },\n },\n series: [\n {},\n {\n label: isDistance ? 'Distance' : 'Elevation',\n stroke: color,\n fill: hexToRgba(color, 0.1),\n width: 2,\n points: { show: true, size: 4 },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n dash: [5, 5],\n points: { show: false },\n },\n ],\n cursor: {\n sync: syncKey ? { key: syncKey.key } : undefined,\n drag: { x: false, y: false },\n points: { show: false },\n x: false,\n y: false,\n },\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null) {\n const item = weeklyData[idx];\n if (item) {\n const start = new Date(item.timestamp);\n const end = new Date(item.timestamp + 7 * 24 * 60 * 60 * 1000); // End of week\n const startStr = start.toISOString().split('T')[0];\n const endStr = end.toISOString().split('T')[0];\n onDateRangeSelect?.(startStr, endStr);\n }\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n const idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (\n idx != null &&\n cursorLeft != null &&\n cursorTop != null &&\n cursorLeft >= 0 &&\n cursorTop >= 0\n ) {\n const val = u.data[1][idx];\n const valStr =\n val != null ? (isDistance ? `${val.toFixed(1)} km` : `${val.toFixed(0)} m`) : '\u2014';\n\n tooltip.innerHTML = valStr;\n tooltip.style.display = 'block';\n tooltip.style.left = `${u.valToPos(u.data[0][idx]!, 'x', false)}px`;\n tooltip.style.top = `${u.valToPos(u.data[1][idx]!, 'y', false)}px`;\n tooltip.style.transform = 'translate(6px, -50%)';\n } else {\n tooltip.style.display = 'none';\n }\n\n u.redraw(false);\n },\n ],\n draw: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(u.data[1][idx]!, 'y', true);\n const dpr = window.devicePixelRatio || 1;\n const ctx = u.ctx;\n const bb = u.bbox;\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n ctx.arc(pcx, pcy, 6 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n // X Label Pill\n const d = new Date(u.data[0][idx]! * 1000);\n const xValStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n },\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n space: 40,\n values: (self, splits) =>\n splits.map((s) => {\n const d = new Date(s * 1000);\n return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`;\n }),\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: (self, splits) => splits.map((s) => `${s.toFixed(0)} ${unit}`),\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n };\n\n const mainChart = new uPlot(mainOpts, [xData, yData, yDataSmoothed], chartEl);\n evolutionPlots.push(mainChart);\n\n const scrollContainer = cardContainer.querySelector('.chart-scroll-container') as HTMLElement;\n if (scrollContainer && xData.length * 40 > width)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n\n function applySeriesData() {\n weeklyData = activeGrouping === 'month' ? monthlySource : weeklySource;\n const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000;\n let minTime = 0;\n\n if (activeRange === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000;\n else if (activeRange === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000;\n else if (activeRange === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000;\n else if (activeRange === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000;\n else if (activeRange === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000;\n\n const filteredData = weeklyData.filter((d) => d.timestamp >= minTime);\n\n const newXData = filteredData.map((d) => d.timestamp / 1000);\n const newYData = isDistance\n ? (filteredData as any[]).map((d) => d.distance / 1000)\n : (filteredData as any[]).map((d) => d.elevation);\n const newYDataSmoothed = gaussianSmooth(newYData, 2);\n\n const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40);\n const newMaxVal = Math.max(1, ...newYData) * 1.1;\n\n mainChart.setSize({ width: newWidth, height: 150 });\n mainChart.setScale('y', { min: 0, max: newMaxVal });\n mainChart.setData([newXData, newYData, newYDataSmoothed]);\n\n if (scrollContainer)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n }\n\n return {\n updateRange: (range: string) => {\n activeRange = range;\n applySeriesData();\n },\n updateGrouping: (grouping: 'week' | 'month') => {\n activeGrouping = grouping;\n applySeriesData();\n },\n };\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData } from '../parsers';\n\nexport interface AccumulatedData {\n currentYear: number;\n pastYear: number;\n past6m: number;\n past1m: number;\n total: number;\n currentYearAvg: number;\n pastYearAvg: number;\n past6mAvg: number;\n past1mAvg: number;\n totalAvg: number;\n}\n\nexport function computeAccumulatedMetric(\n allTracks: TrackData[],\n extractor: (t: TrackData) => number | undefined,\n): AccumulatedData {\n // Derive deterministic reference timestamp from tracks (or fixed UTC fallback)\n let refTs = 0;\n for (let i = 0; i < allTracks.length; i++) {\n const st = allTracks[i].stats?.startTime;\n if (st && st > refTs) refTs = st;\n }\n if (!refTs) refTs = Date.UTC(2026, 7, 1);\n\n const now = new Date(refTs);\n const currentYear = now.getUTCFullYear();\n\n const oneYearAgoMs = Date.UTC(\n currentYear - 1,\n now.getUTCMonth(),\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const sixMonthsAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 6,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const oneMonthAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 1,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n\n let currentYearVal = 0;\n let pastYearVal = 0;\n let past6mVal = 0;\n let past1mVal = 0;\n let totalVal = 0;\n\n let minTime = refTs;\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime) return;\n const val = extractor(t);\n if (val === undefined) return;\n\n totalVal += val;\n\n const time = t.stats.startTime;\n if (time < minTime) minTime = time;\n\n const date = new Date(time);\n\n if (date.getUTCFullYear() === currentYear) currentYearVal += val;\n\n if (time >= oneYearAgoMs) pastYearVal += val;\n\n if (time >= sixMonthsAgoMs) past6mVal += val;\n\n if (time >= oneMonthAgoMs) past1mVal += val;\n });\n\n const msecPerWeek = 7 * 24 * 60 * 60 * 1000;\n const currentYearStart = Date.UTC(currentYear, 0, 1);\n\n const currentYearWeeks = Math.max(0.1, (refTs - currentYearStart) / msecPerWeek);\n const pastYearWeeks = Math.max(0.1, (refTs - oneYearAgoMs) / msecPerWeek);\n const past6mWeeks = Math.max(0.1, (refTs - sixMonthsAgoMs) / msecPerWeek);\n const past1mWeeks = Math.max(0.1, (refTs - oneMonthAgoMs) / msecPerWeek);\n const totalWeeks = Math.max(0.1, (refTs - minTime) / msecPerWeek);\n\n return {\n currentYear: currentYearVal,\n pastYear: pastYearVal,\n past6m: past6mVal,\n past1m: past1mVal,\n total: totalVal,\n currentYearAvg: currentYearVal / currentYearWeeks,\n pastYearAvg: pastYearVal / pastYearWeeks,\n past6mAvg: past6mVal / past6mWeeks,\n past1mAvg: past1mVal / past1mWeeks,\n totalAvg: totalVal / totalWeeks,\n };\n}\n\nexport function renderAccumulatedTable(\n accumulated: AccumulatedData,\n isDistance: boolean,\n unit: string,\n): string {\n const factor = isDistance ? 1000 : 1;\n const format = (val: number) => {\n const formattedVal = isDistance ? val / factor : val;\n return formattedVal.toLocaleString('en-US', {\n minimumFractionDigits: isDistance ? 1 : 0,\n maximumFractionDigits: isDistance ? 1 : 0,\n });\n };\n\n return `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Period${isDistance ? 'Distance' : 'Elevation'}${isDistance ? 'Distance/Week' : 'Elevation/Week'}
Current Year${format(accumulated.currentYear)} ${unit}${format(accumulated.currentYearAvg)} ${unit}
Past Year${format(accumulated.pastYear)} ${unit}${format(accumulated.pastYearAvg)} ${unit}
Past 6 Months${format(accumulated.past6m)} ${unit}${format(accumulated.past6mAvg)} ${unit}
Past 1 Month${format(accumulated.past1m)} ${unit}${format(accumulated.past1mAvg)} ${unit}
Total${format(accumulated.total)} ${unit}${format(accumulated.totalAvg)} ${unit}
\n `;\n}\n\nexport interface MultiMetricAccumulatedSummary {\n distance: AccumulatedData;\n elevation: AccumulatedData;\n durationHours: AccumulatedData;\n tss: AccumulatedData;\n workKj: AccumulatedData;\n climbCount: AccumulatedData;\n}\n\nexport function computeMultiMetricAccumulated(\n allTracks: TrackData[],\n): MultiMetricAccumulatedSummary {\n const distance = computeAccumulatedMetric(allTracks, (t) => t.stats.totalDist);\n const elevation = computeAccumulatedMetric(allTracks, (t) => t.stats.elevGain);\n const durationHours = computeAccumulatedMetric(allTracks, (t) =>\n t.stats.duration ? t.stats.duration / 3600000 : 0,\n );\n const tss = computeAccumulatedMetric(allTracks, (t) => {\n const durSec = (t.stats.duration || 0) / 1000;\n const avgPwr = t.stats.avgPower || 150;\n const ftp = 200;\n const intensityFactor = avgPwr / ftp;\n return ((durSec * avgPwr * intensityFactor) / (ftp * 3600)) * 100;\n });\n const workKj = computeAccumulatedMetric(allTracks, (t) => {\n const durSec = (t.stats.duration || 0) / 1000;\n const avgPwr = t.stats.avgPower || 0;\n return (durSec * avgPwr) / 1000;\n });\n const climbCount = computeAccumulatedMetric(allTracks, (t) => {\n const secs = t.stats.sections || [];\n return secs.filter((s) => s.kind === 'climb').length;\n });\n\n return {\n distance,\n elevation,\n durationHours,\n tss,\n workKj,\n climbCount,\n };\n}\n\nexport function renderAccumulatedProgressSummary(allTracks: TrackData[]): string {\n const summary = computeMultiMetricAccumulated(allTracks);\n const fmt = (v: number, digits = 1) =>\n v.toLocaleString('en-US', {\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n });\n\n const rows: {\n label: string;\n unit: string;\n data: AccumulatedData;\n scale: number;\n digits: number;\n }[] = [\n { label: 'Distance', unit: 'km', data: summary.distance, scale: 0.001, digits: 1 },\n { label: 'Elevation Gain', unit: 'm', data: summary.elevation, scale: 1, digits: 0 },\n { label: 'Moving Duration', unit: 'h', data: summary.durationHours, scale: 1, digits: 1 },\n { label: 'Training Stress (TSS)', unit: 'TSS', data: summary.tss, scale: 1, digits: 0 },\n { label: 'Mechanical Work', unit: 'kJ', data: summary.workKj, scale: 1, digits: 0 },\n { label: 'Categorized Climbs', unit: 'climbs', data: summary.climbCount, scale: 1, digits: 0 },\n ];\n\n return `\n
\n
\n
\n monitoring\n Accumulated Longitudinal Progress Summary\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n ${rows\n .map(\n (r) => `\n \n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
MetricPast 1MPast 6MPast YearCurrent YearTotalWeekly Avg
${r.label}${fmt(r.data.past1m * r.scale, r.digits)} ${r.unit}${fmt(r.data.past6m * r.scale, r.digits)} ${r.unit}${fmt(r.data.pastYear * r.scale, r.digits)} ${r.unit}${fmt(r.data.currentYear * r.scale, r.digits)} ${r.unit}${fmt(r.data.total * r.scale, r.digits)} ${r.unit}${fmt(r.data.totalAvg * r.scale, r.digits)} ${r.unit}/wk
\n
\n `;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 Main Application \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { Storage } from './storage';\nimport { UrlState, AppState } from './url-state';\nimport { Parsers, TrackData, TrackPoint, calculateBounds, simplifyTrack } from './parsers';\nimport { MapView } from './map';\nimport { ChartView } from './charts';\nimport { renderDetails, initDetails, resetDetails } from './tabs/details';\nimport { renderInsights, initInsights, resetInsights } from './tabs/insights';\nimport {\n renderCombined,\n initCombined,\n resizeCombined,\n resetCombined,\n setCombinedMetrics,\n setCombinedPolar,\n setCombinedSliderProgress,\n} from './tabs/combined';\nimport {\n renderEvolution,\n resetEvolution,\n setEvolutionGrouping,\n setEvolutionRange,\n setEvolutionPinnedDuration,\n} from './tabs/progress';\nimport {\n renderCourses,\n initCourses,\n prepareBenchmarkCourses,\n getBenchmarkCourseIds,\n resetCourses,\n selectCourse,\n} from './tabs/courses';\nimport { fmtSecs, escHtml, fmtDate, getTagColor, compactId, shortRandom } from './utils';\n\nconst TRACK_COLORS: string[] = [\n '#FF6B35',\n '#4ECDC4',\n '#45B7D1',\n '#F7DC6F',\n '#FF6B6B',\n '#BB8FCE',\n '#82E0AA',\n '#F8C471',\n '#3b82f6',\n];\n\nconst POINT_ZOOM_LEVEL = 16;\n\nlet tracks: Record = {};\nlet skippedImports: { name: string; reason: string }[] = [];\n\nfunction isSameDay(t1: number, t2: number) {\n const d1 = new Date(t1);\n const d2 = new Date(t2);\n return (\n d1.getUTCFullYear() === d2.getUTCFullYear() &&\n d1.getUTCMonth() === d2.getUTCMonth() &&\n d1.getUTCDate() === d2.getUTCDate()\n );\n}\n\nlet cancelProcessing = false;\nlet selectedId: string | null = null;\nlet colorIdx = 0;\nlet followDot = false;\nlet currentMapColors: string[] | null = null;\n\n// Search/Filter state\nlet searchQuery = '';\nlet searchRegex = false;\nlet currentSort = 'date-desc';\n\ninterface Filters {\n date: [string | null, string | null];\n dist: [number | null, number | null];\n dur: [number | null, number | null];\n metrics: Set;\n tags: string[];\n sport: string | null;\n}\n\nlet filters: Filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n};\n\nfunction syncFiltersToUrl(push: boolean = false) {\n UrlState.patch(\n {\n f_date: filters.date.every((v) => v === null) ? null : filters.date,\n f_dist: filters.dist.every((v) => v === null) ? null : filters.dist,\n f_dur: filters.dur.every((v) => v === null) ? null : filters.dur,\n f_mets: filters.metrics.size === 0 ? null : Array.from(filters.metrics),\n f_tags: filters.tags.length === 0 ? null : filters.tags,\n },\n push,\n );\n}\n\nfunction syncMetricsToUrl() {\n const active = ChartView.getActiveMetrics();\n const metrics = ChartView.METRICS;\n const abbrs = Array.from(active).map((key) => metrics[key].abbr);\n UrlState.patch({ metrics: abbrs.length ? abbrs : null });\n}\n\nconst SORT_OPTIONS = [\n { label: 'Newest first', val: 'date-desc', icon: 'calendar_today' },\n { label: 'Oldest first', val: 'date-asc', icon: 'history' },\n { label: 'Longest distance', val: 'dist-desc', icon: 'straighten' },\n { label: 'Shortest distance', val: 'dist-asc', icon: 'horizontal_rule' },\n { label: 'Longest duration', val: 'dur-desc', icon: 'timer' },\n { label: 'Shortest duration', val: 'dur-asc', icon: 'timer_off' },\n];\n\nfunction showSortMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.sort-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'sort-menu-popup';\n\n SORT_OPTIONS.forEach((opt) => {\n const item = document.createElement('div');\n item.className = `menu-item ${currentSort === opt.val ? 'active' : ''}`;\n item.innerHTML = `\n ${opt.icon}\n ${opt.label}\n ${currentSort === opt.val ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n currentSort = opt.val;\n UrlState.patch({ sort: opt.val });\n updateSearchSortUI();\n renderTrackList();\n popup.remove();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction showMetricMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const available = ChartView.getAvailableMetrics();\n const active = ChartView.getActiveMetrics();\n\n Object.entries(metrics).forEach(([key, def]) => {\n if (!available.has(key)) return;\n\n const item = document.createElement('div');\n item.className = `menu-item ${active.has(key) ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${active.has(key) ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n ChartView.toggleMetric(key);\n const isNowActive = ChartView.getActiveMetrics().has(key);\n item.classList.toggle('active', isNowActive);\n item.querySelector('.check')!.textContent = isNowActive ? 'check' : '';\n\n const pill = document.querySelector(`#metric-pills .metric-pill[data-metric=\"${key}\"]`);\n if (pill) pill.classList.toggle('active', isNowActive);\n\n updateToolbarLayout();\n\n syncMetricsToUrl();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.right = `${window.innerWidth - rect.right}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\n// \u2500\u2500 Tab Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.addEventListener('select-track', (e: any) => {\n const id = e.detail.id;\n const idx = e.detail.idx;\n const dur = e.detail.dur;\n if (id && tracks[id]) {\n selectTrack(id);\n if (idx != null && dur != null) {\n const t = tracks[id];\n const pts = t.points;\n if (idx >= 0 && idx < pts.length) {\n const pIdx = pts[idx];\n if (pIdx && pIdx.time != null) {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const tMin = (pIdx.time - t0) / 1000;\n const tMax = tMin + dur;\n\n // ChartView selection\n ChartView.restoreSelection(tMin, tMax);\n\n // Find iMax based on duration\n let iMax = pts.findIndex((p) => (p.time || 0) >= pIdx.time! + dur * 1000);\n if (iMax === -1) iMax = pts.length - 1;\n\n const selPts = pts.slice(idx, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n\n renderInsights(t);\n\n MapView.highlightSegment(id, pts, idx, iMax, false, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n\n // Update URL state\n UrlState.patch({ sel: [tMin, tMax] });\n }\n }\n }\n }\n});\n\ndocument.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.tab-btn') as HTMLElement;\n if (!btn) return;\n const nav = btn.closest('#tab-nav');\n if (!nav) return;\n\n // Toggle buttons\n nav.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn));\n\n const tab = btn.dataset.tab!;\n UrlState.patch({ tab }, true);\n\n // Toggle contents\n const panel = nav.closest('#chart-panel');\n if (panel) {\n panel.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${btn.dataset.tab}`);\n });\n }\n\n if (btn.dataset.tab === 'details' && selectedId && tracks[selectedId])\n renderDetails(tracks[selectedId], getGlobalTags());\n\n if (btn.dataset.tab === 'insights' && selectedId && tracks[selectedId])\n renderInsights(tracks[selectedId]);\n\n if (btn.dataset.tab === 'evolution') {\n renderEvolution(\n selectedId ? tracks[selectedId] : null,\n Object.values(tracks),\n (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n },\n (start, end) => {\n filters.date = [start, end];\n applyFilters();\n syncFiltersToUrl(true);\n updateFilterUI();\n },\n );\n }\n\n if (btn.dataset.tab === 'combined' && selectedId && tracks[selectedId])\n renderCombined(tracks[selectedId]);\n\n if (btn.dataset.tab === 'courses') renderCourses();\n\n if (btn.dataset.tab === 'graphs') {\n ChartView.resize();\n updateToolbarLayout();\n\n // Restore selection from URL\n const s = UrlState.get().sel;\n if (s) ChartView.restoreSelection(s[0], s[1]);\n }\n});\n\nasync function resetBenchmarkState() {\n if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n await Storage.clear();\n tracks = {};\n skippedImports = [];\n selectedId = null;\n colorIdx = 0;\n currentMapColors = null;\n cancelProcessing = false;\n followDot = false;\n searchQuery = '';\n searchRegex = false;\n currentSort = 'date-desc';\n filters.date = [null, null];\n filters.dist = [null, null];\n filters.dur = [null, null];\n filters.metrics.clear();\n filters.tags = [];\n Parsers.setHRZones([120, 140, 160, 180]);\n Parsers.setFTP(200);\n resetCourses();\n resetInsights();\n resetDetails();\n resetCombined();\n resetEvolution();\n if (MapView.removeAllTracks) MapView.removeAllTracks();\n if (MapView.clearTracks) MapView.clearTracks();\n MapView.clearHighlight();\n if (ChartView.resetState) ChartView.resetState();\n else if (ChartView.clear) ChartView.clear();\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === 'graphs');\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === 'tab-graphs');\n });\n UrlState.reset();\n const toastContainer = document.getElementById('toast-container');\n if (toastContainer) toastContainer.innerHTML = '';\n document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());\n if (typeof renderTrackList === 'function') renderTrackList();\n}\n\n// \u2500\u2500 Boot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function init() {\n // Wait for fonts to be loaded with a cleaned-up timeout\n let fontTimerId: number | null = null;\n const fontTimeout = new Promise((resolve) => {\n fontTimerId = window.setTimeout(resolve, 1000);\n });\n try {\n const fontLoadPromise = document.fonts\n ? Promise.all([\n document.fonts.load('24px \"Material Symbols Rounded\"').catch(() => {}),\n document.fonts.ready,\n ])\n : Promise.resolve();\n await Promise.race([fontLoadPromise, fontTimeout]);\n } finally {\n if (fontTimerId !== null) window.clearTimeout(fontTimerId);\n }\n document.body.classList.remove('loading-fonts');\n const storageSelect = document.getElementById(\n 'storage-backend-select',\n ) as HTMLSelectElement | null;\n if (storageSelect) {\n storageSelect.value = UrlState.get().storage || 'memory';\n storageSelect.addEventListener('change', (e) => {\n const selected = (e.target as HTMLSelectElement).value;\n const params = new URLSearchParams(window.location.search);\n if (selected === 'memory') {\n params.delete('storage');\n } else {\n params.set('storage', selected);\n }\n window.location.search = params.toString();\n });\n }\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const mapLoader = document.getElementById('map-loader');\n const mapLoaderSpan = mapLoader?.querySelector('span');\n\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading database...';\n mapLoader.classList.remove('hidden');\n }\n\n const urlState = UrlState.get();\n\n initInsights((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n initDetails(\n () => {\n applyFilters();\n syncFiltersToUrl();\n },\n (id: string) => {\n deleteTrack(id);\n },\n );\n initCombined();\n initCourses((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n\n // Init sub-systems\n MapView.init(\n (id) => selectTrack(id),\n onMapMove,\n onMapPointClick,\n (id, idx) => {\n if (id === selectedId) ChartView.setHoverAt(idx);\n else ChartView.setHoverAt(null);\n },\n onMapDblClick,\n );\n ChartView.init(onChartCursorMove, onChartRangeChange, onChartClick, (idx) => {\n UrlState.patch({ sel_point: idx });\n });\n\n ChartView.setMapColorChangeCb((data) => {\n if (data) {\n currentMapColors = data.colors;\n if (selectedId) MapView.colorTrackByMetric(selectedId, data.pts, data.colors);\n } else {\n currentMapColors = null;\n if (selectedId) MapView.clearMetricColor(selectedId);\n }\n\n // Refresh highlight with new colors if a selection exists\n const currentUrlState = UrlState.get();\n if (currentUrlState.sel)\n onChartRangeChange(currentUrlState.sel[0], currentUrlState.sel[1], ChartView.getXAxis());\n });\n\n applyState(urlState);\n\n // Reset persistent storage and in-memory state for clean multi-iteration benchmark executions\n await Storage.openDB();\n await resetBenchmarkState();\n\n // Load persisted tracks\n try {\n // Load global settings\n const hrZones = await Storage.get('hr_zones');\n if (hrZones) Parsers.setHRZones(hrZones);\n\n const ftp = await Storage.get('ftp');\n if (ftp) Parsers.setFTP(ftp);\n\n const saved = await Storage.getAll();\n saved.sort((a, b) => a.addedAt - b.addedAt);\n\n if (mapLoaderSpan) mapLoaderSpan.textContent = `Preparing ${saved.length} tracks...`;\n\n const tracksToLoad: TrackData[] = [];\n for (const t of saved) {\n let updated = false;\n if (!t.bounds && t.points.length > 0) {\n const b = calculateBounds(t.points);\n if (b) {\n t.bounds = b;\n updated = true;\n }\n }\n if (!t.simplifiedPoints && t.points.length > 0) {\n t.simplifiedPoints = simplifyTrack(t.points, 50);\n updated = true;\n }\n if (updated) await Storage.save(t);\n\n tracks[t.id] = t;\n tracksToLoad.push(t);\n }\n MapView.addTracks(tracksToLoad);\n applyFilters();\n\n const restoreId =\n urlState.track && saved.find((t) => t.id === urlState.track)\n ? urlState.track\n : saved.length > 0\n ? saved[0].id\n : null;\n\n const mapLoader = document.getElementById('map-loader');\n\n // 1. Process and load the \"Priority\" track first\n const selectedTrackData = saved.find((t) => t.id === restoreId);\n if (selectedTrackData) {\n await processAndLoadTrack(selectedTrackData);\n selectTrack(selectedTrackData.id, !urlState.map_pos);\n\n // Explicitly restore selection/pin from URL if they exist\n if (urlState.sel && Array.isArray(urlState.sel) && urlState.sel.length === 2) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.restoreSelection(urlState.sel![0], urlState.sel![1]);\n });\n });\n }\n if (urlState.sel_point !== undefined && urlState.sel_point !== null) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.setCursorAt(urlState.sel_point!);\n });\n });\n }\n }\n\n // Hide database loader\n if (mapLoader) mapLoader.classList.add('hidden');\n\n // 2. Load the rest in background chunks\n if (saved.length > (selectedTrackData ? 1 : 0)) {\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading tracks...';\n mapLoader.classList.remove('hidden');\n }\n\n const remaining = saved.filter((t) => t.id !== restoreId);\n let index = 0;\n\n const loadNextChunk = async () => {\n const chunkSize = 2; // Process 2 tracks per frame\n const end = Math.min(index + chunkSize, remaining.length);\n\n for (; index < end; index++) await processAndLoadTrack(remaining[index]);\n\n if (index < remaining.length) {\n requestAnimationFrame(loadNextChunk);\n } else {\n if (mapLoader) mapLoader.classList.add('hidden');\n applyFilters(); // Final sync\n if (selectedId && tracks[selectedId]) {\n renderEvolution(tracks[selectedId], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n // Only fit all if no saved map position and we just finished loading everything\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n };\n\n requestAnimationFrame(loadNextChunk);\n } else {\n applyFilters();\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n } catch (e) {\n console.warn('Could not load saved tracks:', e);\n }\n\n // Panel resizers\n initResizeHandle();\n initSidebarResizer();\n initMetricPillDraggable();\n updateToolbarLayout();\n\n // Basemap switcher\n document.getElementById('basemap-switcher')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.bm-btn') as HTMLElement;\n if (!btn) return;\n document.querySelectorAll('.bm-btn').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n if (btn.dataset.layer) {\n MapView.switchBasemap(btn.dataset.layer);\n UrlState.patch({ map: btn.dataset.layer });\n }\n });\n\n // Fit all\n document.getElementById('btn-fit-all')?.addEventListener('click', () => MapView.fitAll());\n\n // Clear all\n document.getElementById('btn-clear-all')?.addEventListener('click', clearAll);\n\n // Search\n document.getElementById('track-search')?.addEventListener('input', (e) => {\n searchQuery = (e.target as HTMLInputElement).value;\n applyFilters();\n UrlState.patch({ q: searchQuery || null });\n });\n\n document.getElementById('btn-regex-toggle')?.addEventListener('click', (e) => {\n searchRegex = !searchRegex;\n (e.target as HTMLElement).classList.toggle('active', searchRegex);\n applyFilters();\n UrlState.patch({ re: searchRegex ? 1 : null });\n });\n\n // Sort\n document.getElementById('btn-sort-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSortMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric menu toggle\n document.getElementById('btn-metric-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMetricMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric toggles (shared logic)\n const toggleMetric = (metric: string, pill: HTMLElement | null) => {\n if (pill) pill.classList.toggle('active');\n ChartView.toggleMetric(metric);\n syncMetricsToUrl();\n };\n\n document.getElementById('metric-pills')?.addEventListener('click', (e) => {\n const pill = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (pill) {\n const metric = pill.dataset.metric;\n if (metric) {\n toggleMetric(metric, pill);\n\n // Scroll to it if it became active\n if (ChartView.getActiveMetrics().has(metric)) {\n const targetEl = document.querySelector(`.chart-row[data-metric=\"${metric}\"]`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n }\n }\n });\n\n // X-axis toggle\n document.getElementById('x-axis-ctrl')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const axis = btn.dataset.axis!;\n ChartView.setXAxis(axis);\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', b === btn));\n UrlState.patch({ xaxis: axis });\n });\n\n // Follow dot\n document.getElementById('btn-follow-dot')?.addEventListener('click', (e) => {\n followDot = !followDot;\n (e.currentTarget as HTMLElement).classList.toggle('active', followDot);\n });\n\n // Reset zoom\n document.getElementById('btn-reset-zoom')?.addEventListener('click', () => {\n ChartView.resetZoom();\n MapView.clearHighlight();\n });\n\n // File drag/drop\n initDropZone();\n\n // File browse\n document.getElementById('file-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n document.getElementById('folder-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n\n // Filters\n document.getElementById('btn-toggle-filters')?.addEventListener('click', () => {\n const panel = document.getElementById('filter-panel');\n if (panel) {\n panel.classList.toggle('hidden');\n document\n .getElementById('btn-toggle-filters')\n ?.classList.toggle('active', !panel.classList.contains('hidden'));\n }\n });\n\n const onFilterInput = (type: 'date' | 'dist' | 'dur', idx: number, e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n (filters[type] as any)[idx] = val === '' ? null : val;\n applyFilters();\n syncFiltersToUrl();\n };\n\n document\n .getElementById('filter-date-start')\n ?.addEventListener('change', (e) => onFilterInput('date', 0, e));\n document\n .getElementById('filter-date-end')\n ?.addEventListener('change', (e) => onFilterInput('date', 1, e));\n document\n .getElementById('filter-dist-min')\n ?.addEventListener('input', (e) => onFilterInput('dist', 0, e));\n document\n .getElementById('filter-dist-max')\n ?.addEventListener('input', (e) => onFilterInput('dist', 1, e));\n document\n .getElementById('filter-dur-min')\n ?.addEventListener('input', (e) => onFilterInput('dur', 0, e));\n document\n .getElementById('filter-dur-max')\n ?.addEventListener('input', (e) => onFilterInput('dur', 1, e));\n\n const burgerBtn = document.getElementById('sport-burger-btn');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n burgerBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n if (dropdownContent) {\n const isVisible = dropdownContent.style.display === 'block';\n dropdownContent.style.display = isVisible ? 'none' : 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (dropdownContent && dropdownContent.style.display === 'block') {\n if (!dropdownContent.contains(e.target as Node) && e.target !== burgerBtn)\n dropdownContent.style.display = 'none';\n }\n });\n\n document.getElementById('sport-filter-container')?.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const btn = target.closest('[data-sport]');\n if (btn) {\n const selectedSport = (btn as HTMLElement).dataset.sport || null;\n filters.sport = filters.sport === selectedSport ? null : selectedSport;\n applyFilters();\n syncFiltersToUrl();\n updateFilterUI();\n\n if (target.closest('.dropdown-item')) {\n if (dropdownContent) dropdownContent.style.display = 'none';\n }\n }\n });\n\n document.getElementById('filter-metrics')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.mini-pill') as HTMLElement;\n if (!btn) return;\n const m = btn.dataset.metric!;\n if (filters.metrics.has(m)) filters.metrics.delete(m);\n else filters.metrics.add(m);\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('btn-reset-filters')?.addEventListener('click', () => {\n filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n };\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('filter-tags')?.addEventListener('input', (e) => {\n const val = (e.target as HTMLInputElement).value;\n filters.tags = val\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => !!s);\n applyFilters();\n syncFiltersToUrl();\n });\n\n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n MapView.hideCursor();\n MapView.closePopup?.();\n // Dismiss popups and modals\n document\n .querySelectorAll(\n '.color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop',\n )\n .forEach((el) => el.remove());\n }\n });\n\n // Resize charts when window changes\n window.addEventListener('resize', () => {\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n updateToolbarLayout();\n });\n\n // Handle back/forward navigation\n window.addEventListener('popstate', () => {\n UrlState.refresh();\n applyState(UrlState.get());\n });\n\n initBenchmarkTriggers();\n await preloadBenchmarkFiles();\n\n // Signal to Speedometer test harness that asynchronous initialization has completed\n // and benchmark step triggers are bound.\n const readyEl = document.createElement('div');\n readyEl.id = 'app-is-ready';\n readyEl.setAttribute('data-ready', 'true');\n readyEl.style.display = 'none';\n document.body.appendChild(readyEl);\n\n const camelReadyEl = document.createElement('div');\n camelReadyEl.id = 'appIsReady';\n camelReadyEl.setAttribute('data-ready', 'true');\n camelReadyEl.style.display = 'none';\n document.body.appendChild(camelReadyEl);\n}\n\nlet preloadedBenchmarkPayloads:\n | {\n cleanName: string;\n buf: ArrayBuffer;\n text?: string;\n file: File;\n }[]\n | null = null;\n\nasync function preloadBenchmarkFiles(): Promise<\n { cleanName: string; buf: ArrayBuffer; text?: string; file: File }[]\n> {\n if (preloadedBenchmarkPayloads) return preloadedBenchmarkPayloads;\n try {\n const manifestResp = await fetch('./test-data/manifest.json');\n const fileNames: string[] = await manifestResp.json();\n const decoder = new TextDecoder();\n preloadedBenchmarkPayloads = await Promise.all(\n fileNames.map(async (name) => {\n const fileResp = await fetch(`./test-data/${name}`);\n let buf = await fileResp.arrayBuffer();\n let cleanName = name;\n if (name.toLowerCase().endsWith('.gz')) {\n cleanName = name.slice(0, -3);\n const bytes = new Uint8Array(buf);\n if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) {\n const ds = new DecompressionStream('gzip');\n const stream = new Blob([buf]).stream().pipeThrough(ds);\n buf = await new Response(stream).arrayBuffer();\n }\n }\n const text = cleanName.toLowerCase().endsWith('.fit') ? undefined : decoder.decode(buf);\n const file = new File([buf], cleanName, { type: 'application/octet-stream' });\n (file as any)._buf = buf;\n if (text !== undefined) (file as any)._text = text;\n return { cleanName, buf, text, file };\n }),\n );\n // Warm up GPX, TCX, and FIT parser and chart code paths during prepare phase\n let warmSample: any = null;\n for (const idx of [0, 2, 4]) {\n if (preloadedBenchmarkPayloads[idx]) {\n const parsed = await Parsers.parseFile(preloadedBenchmarkPayloads[idx].file);\n if (idx === 0) warmSample = parsed;\n }\n }\n if (warmSample) {\n const warmPts = warmSample.points.slice(0, 1250);\n const warmTrack: TrackData = {\n ...warmSample,\n id: 'warmup',\n fileName: 'warmup.gpx',\n fileSize: 1024,\n points: warmPts,\n bounds: calculateBounds(warmPts) || undefined,\n simplifiedPoints: simplifyTrack(warmPts, 50),\n stats: Parsers.computeStats(warmPts),\n addedAt: 1785542400000,\n visible: true,\n color: TRACK_COLORS[0],\n };\n const warmTrack2: TrackData = {\n ...warmTrack,\n id: 'warmup-2',\n fileName: 'warmup2.gpx',\n addedAt: 1785628800000,\n color: TRACK_COLORS[1],\n };\n const warmList = [warmTrack, warmTrack2];\n Parsers.ensureCurvesAndZones(warmTrack);\n Parsers.ensureCurvesAndZones(warmTrack2);\n warmTrack.stats.sections = Parsers.analyzeTrackSections(warmTrack.points);\n warmTrack2.stats.sections = Parsers.analyzeTrackSections(warmTrack2.points);\n Parsers.findOverlaps(warmList);\n MapView.addTracks(warmList);\n ChartView.loadTrack(warmTrack, warmList, false);\n ChartView.restoreSelection(10, 50, true);\n ChartView.setCursorAt(25, true);\n ChartView.setSmooth('power', true);\n ChartView.setSmooth('power', false);\n ChartView.setXAxis('distance');\n ChartView.setXAxis('time');\n ChartView.setActiveMetrics(['elevation', 'speed', 'power']);\n ChartView.analyzeTelemetryIntervals(warmList, 10, 50);\n renderInsights(warmTrack, warmList, [10, 50]);\n renderInsights(warmTrack, warmList);\n renderDetails(warmTrack, [], warmList);\n renderCombined(warmTrack, warmList);\n setCombinedPolar(true);\n setCombinedPolar(false);\n setCombinedSliderProgress(0.5);\n renderCombined(warmList, warmList);\n renderEvolution(warmTrack, warmList);\n setEvolutionGrouping('month');\n setEvolutionGrouping('week');\n setEvolutionRange('6m');\n setEvolutionRange('all');\n setEvolutionPinnedDuration(60);\n setEvolutionPinnedDuration(null);\n prepareBenchmarkCourses(warmList);\n selectCourse('course-1', true);\n await resetBenchmarkState();\n void document.body.offsetHeight;\n await new Promise((r) => window.setTimeout(r, 0));\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n return preloadedBenchmarkPayloads;\n } catch {\n return [];\n }\n}\n\nfunction initBenchmarkTriggers() {\n const btnLoad = document.getElementById('btn-step-load');\n const btnAnalysis = document.getElementById('btn-step-analysis');\n const btnInsights = document.getElementById('btn-step-insights');\n const btnDetails = document.getElementById('btn-step-details');\n const btnAggregate = document.getElementById('btn-step-aggregate');\n const btnEvolution = document.getElementById('btn-step-evolution');\n const btnCourses = document.getElementById('btn-step-courses');\n\n function activateTab(tabName: string) {\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === tabName);\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${tabName}`);\n });\n UrlState.patch({ tab: tabName }, false);\n }\n\n btnLoad?.addEventListener('click', async () => {\n try {\n if (Object.keys(tracks).length > 0 || skippedImports.length > 0 || selectedId !== null) {\n await Storage.openDB();\n await resetBenchmarkState();\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n const payloads = await preloadBenchmarkFiles();\n const loadedFiles: File[] = payloads.map((p) => p.file);\n await handleFiles(loadedFiles);\n const allTracks = Object.values(tracks);\n Parsers.findOverlaps(allTracks);\n\n // Exercise sidebar track list sorting and filtering across distinct criteria\n for (const sortMode of ['dist-desc', 'dur-desc', 'date-asc', 'date-desc']) {\n currentSort = sortMode;\n renderTrackList();\n }\n filters.sport = 'cycling';\n applyFilters();\n filters.sport = null;\n filters.metrics.add('power');\n applyFilters();\n filters.metrics.clear();\n searchQuery = 'Alpine';\n applyFilters();\n searchQuery = '';\n applyFilters();\n\n if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id);\n } finally {\n window.dispatchEvent(new CustomEvent('load-and-parse-complete'));\n }\n });\n\n btnAnalysis?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('graphs');\n if (!selectedId && allTracks.length > 0) {\n selectTrack(allTracks[0].id, false);\n }\n const availableMetrics = ChartView.getAvailableMetrics();\n const metricSets = [\n ['elevation', 'speed', 'power', 'hr'],\n ['elevation', 'speed', 'power'],\n ];\n for (const mSet of metricSets) {\n const filtered = mSet.filter((m) => availableMetrics.has(m));\n if (filtered.length > 0) {\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const metric = (el as HTMLElement).dataset.metric;\n if (metric) el.classList.toggle('active', filtered.includes(metric));\n });\n updateToolbarLayout();\n ChartView.setActiveMetrics(filtered);\n }\n }\n\n // Exercise smoothing, map metric coloring, and X-axis mode switching\n ChartView.setSmooth('power', true, true);\n ChartView.toggleMapColor('power', true);\n ChartView.toggleMapColor(null, true);\n ChartView.setXAxis('distance');\n ChartView.setSmooth('power', false, true);\n ChartView.setXAxis('time');\n\n // Analyze distinct sections of the track (Opening Climb & Main Analysis Window)\n const sections: [number, number, number][] = [\n [0, 360, 180],\n [120, 900, 300],\n ];\n for (const [secStart, secEnd, cursorIdx] of sections) {\n ChartView.restoreSelection(secStart, secEnd, true);\n ChartView.setCursorAt(cursorIdx, true);\n ChartView.analyzeTelemetryIntervals(allTracks, secStart, secEnd);\n onChartRangeChange(secStart, secEnd, ChartView.getXAxis(), false);\n }\n } finally {\n window.dispatchEvent(new CustomEvent('analysis-complete'));\n }\n });\n\n btnInsights?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t));\n activateTab('insights');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n // Analyze insights across GPX, TCX, and FIT tracks and across distinct track sections (Opening, Middle, Final thirds, Full)\n for (const tIdx of [1, 2, 4]) {\n const trk = allTracks[tIdx];\n if (trk) {\n renderInsights(trk, allTracks, [0, 540]);\n renderInsights(trk, allTracks, [540, 1140]);\n renderInsights(trk, allTracks, null);\n }\n }\n if (allTracks[3]) {\n renderInsights(allTracks[3], allTracks, [200, 900]);\n }\n if (primaryTrack) {\n renderInsights(primaryTrack, allTracks, [0, 480]);\n renderInsights(primaryTrack, allTracks, [480, 960]);\n renderInsights(primaryTrack, allTracks, [960, 1440]);\n }\n renderInsights(primaryTrack, allTracks, null);\n } finally {\n window.dispatchEvent(new CustomEvent('insights-complete'));\n }\n });\n\n btnDetails?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('details');\n const globalTags = getGlobalTags();\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n // Render and analyze telemetry details, splits, gear matrices, and zones across all 6 tracks and terrain sections\n for (let i = 0; i < allTracks.length; i++) {\n renderDetails(allTracks[i], globalTags, allTracks, null);\n }\n if (primaryTrack) {\n renderDetails(primaryTrack, globalTags, allTracks, [0, 450]);\n renderDetails(primaryTrack, globalTags, allTracks, [450, 950]);\n renderDetails(primaryTrack, globalTags, allTracks, [950, 1450]);\n }\n if (allTracks[1]) {\n renderDetails(allTracks[1], globalTags, allTracks, [150, 750]);\n }\n if (allTracks[2]) {\n renderDetails(allTracks[2], globalTags, allTracks, [200, 800]);\n }\n if (allTracks[3]) {\n renderDetails(allTracks[3], globalTags, allTracks, [200, 900]);\n }\n if (allTracks[4]) {\n renderDetails(allTracks[4], globalTags, allTracks, [0, 600]);\n renderDetails(allTracks[4], globalTags, allTracks, [600, 1200]);\n }\n if (allTracks[5]) {\n renderDetails(allTracks[5], globalTags, allTracks, [150, 750]);\n }\n renderDetails(primaryTrack, globalTags, allTracks, null);\n } finally {\n window.dispatchEvent(new CustomEvent('details-complete'));\n }\n });\n\n btnAggregate?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n if (allTracks.length >= 2) {\n activateTab('combined');\n // 1. Exercise single-track 2D scatter/trail mode across metric pairs, Polar & Cartesian, and timeline sections\n setCombinedMetrics('distance', 'elevation');\n renderCombined(allTracks[0], allTracks);\n for (const frac of [0.25, 0.5, 0.75, 1.0]) {\n setCombinedSliderProgress(frac);\n }\n setCombinedPolar(true);\n setCombinedSliderProgress(0.5);\n setCombinedPolar(false);\n setCombinedMetrics('power', 'hr');\n for (const frac of [0.3, 0.7]) {\n setCombinedSliderProgress(frac);\n }\n\n // 2. Exercise multi-track comparison mode across regional pairs and all 6 tracks\n if (allTracks.length >= 4) {\n renderCombined([allTracks[2], allTracks[3]], allTracks);\n }\n if (allTracks.length >= 6) {\n renderCombined(allTracks, allTracks);\n }\n const selectedTwo = [allTracks[0], allTracks[1]];\n renderCombined(selectedTwo, allTracks);\n }\n } finally {\n window.dispatchEvent(new CustomEvent('aggregate-complete'));\n }\n });\n\n btnEvolution?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('evolution');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n const onSelectCb = (trackId: string, range: [number, number] | null) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n };\n\n // Exercise evolution view across different reference tracks, groupings ('month' & 'week'), time ranges, and pinned durations\n const refTracks = [allTracks[2] || primaryTrack, allTracks[4] || primaryTrack, primaryTrack];\n for (const refTrk of refTracks) {\n renderEvolution(refTrk, allTracks, onSelectCb);\n setEvolutionGrouping('month');\n for (const rng of ['1m', '2m', '6m', '1y', 'all']) {\n setEvolutionRange(rng);\n }\n setEvolutionGrouping('week');\n for (const dur of [5, 30, 60, 300, 1200, null]) {\n setEvolutionPinnedDuration(dur);\n }\n }\n } finally {\n window.dispatchEvent(new CustomEvent('evolution-complete'));\n }\n });\n\n btnCourses?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('courses');\n prepareBenchmarkCourses(allTracks);\n const courseIds = getBenchmarkCourseIds();\n for (const cId of courseIds) {\n selectCourse(cId, true);\n }\n selectCourse('course-1', true);\n } finally {\n window.dispatchEvent(new CustomEvent('courses-complete'));\n }\n });\n\n (window as any).benchmarkSteps = {\n loadAndParseFiles: () => document.getElementById('btn-step-load')?.click(),\n displayAnalysisMetrics: () => document.getElementById('btn-step-analysis')?.click(),\n displayInsights: () => document.getElementById('btn-step-insights')?.click(),\n displayDetails: () => document.getElementById('btn-step-details')?.click(),\n displayAggregateMetrics: () => document.getElementById('btn-step-aggregate')?.click(),\n displayEvolutionMetrics: () => document.getElementById('btn-step-evolution')?.click(),\n displayCourses: () => document.getElementById('btn-step-courses')?.click(),\n };\n}\n\nasync function processAndLoadTrack(t: TrackData) {\n // Migration: re-calculate stats if new insights are missing or old format\n const powerCurveEntries = t.stats.powerCurve ? Object.values(t.stats.powerCurve) : [];\n\n const needsEnrich =\n t.points.length > 1 && (t.points[1].speed === undefined || t.points[1].gradient === undefined);\n\n const needsRecalc =\n needsEnrich ||\n !t.stats.powerCurve ||\n !t.stats.hrZones ||\n !t.stats.hrCurve ||\n t.stats.shifts === undefined ||\n t.stats.avgBattery === undefined ||\n t.stats.avgTemp === undefined ||\n (powerCurveEntries.length > 0 && typeof (powerCurveEntries[0] as any) === 'number') ||\n ((t.stats.duration || 0) > 10800 * 1000 && t.stats.powerCurve && !t.stats.powerCurve[14400]);\n\n if (needsRecalc) {\n if (needsEnrich) t.points = Parsers.enrichPoints(t.points);\n t.stats = Parsers.computeStats(t.points);\n await Storage.save(t);\n }\n\n tracks[t.id] = t;\n colorIdx = Math.max(colorIdx, TRACK_COLORS.indexOf(t.color) + 1);\n MapView.addTrack(t);\n MapView.setTrackVisible(t.id, t.visible && !t._filtered);\n renderTrackList(); // Progressive list update\n}\n\nfunction initResizeHandle() {\n const handle = document.getElementById('resize-handle');\n const panel = document.getElementById('chart-panel');\n if (!handle || !panel) return;\n\n let isDragging = false;\n\n handle.addEventListener('mousedown', () => {\n isDragging = true;\n document.body.style.cursor = 'ns-resize';\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const h = window.innerHeight - e.clientY;\n const clampedH = Math.max(100, Math.min(window.innerHeight - 100, h));\n panel.style.height = `${clampedH}px`;\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n document.body.style.cursor = '';\n });\n}\n\nfunction initSidebarResizer() {\n const resizer = document.getElementById('sidebar-resizer');\n const sidebar = document.getElementById('sidebar');\n if (!resizer || !sidebar) return;\n\n let isDragging = false;\n\n resizer.addEventListener('mousedown', () => {\n isDragging = true;\n resizer.classList.add('dragging');\n document.body.classList.add('dragging-sidebar');\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const w = e.clientX;\n const clampedW = Math.max(200, Math.min(600, w));\n sidebar.style.width = `${clampedW}px`;\n sidebar.style.setProperty('--sidebar-w', `${clampedW}px`);\n ChartView.resize();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n resizer.classList.remove('dragging');\n document.body.classList.remove('dragging-sidebar');\n });\n}\n\n// \u2500\u2500 Event Handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction onMapMove(lat: number, lng: number, zoom: number) {\n UrlState.patch({ map_pos: [lat, lng, zoom] });\n}\n\nfunction onMapPointClick(id: string, idx: number) {\n selectTrack(id, false);\n ChartView.setCursorAt(idx);\n}\n\nfunction onMapDblClick() {\n // MapView.fitAll();\n}\n\nfunction onChartCursorMove(pt: TrackPoint | null) {\n if (pt && pt.lat != null && pt.lon != null) {\n MapView.showCursorAt(pt.lat, pt.lon);\n if (followDot) MapView.centerOn(pt.lat, pt.lon, null, true);\n } else {\n MapView.hideCursor();\n }\n}\n\nfunction onChartRangeChange(min: number | null, max: number | null, axis: string, fit = false) {\n if (!selectedId || !tracks[selectedId]) return;\n const t = tracks[selectedId];\n\n if (min === null || max === null) {\n MapView.clearHighlight();\n if (t && (UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n UrlState.patch({ sel: null });\n return;\n }\n\n // Find point indices\n const pts = t.points;\n let iMin = 0,\n iMax = pts.length - 1;\n\n if (axis === 'distance') {\n const d0 = min * 1000,\n d1 = max * 1000;\n iMin = pts.findIndex((p) => (p.dist || 0) >= d0);\n iMax = pts.findIndex((p) => (p.dist || 0) >= d1);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const ts0 = t0 + min * 1000,\n ts1 = t0 + max * 1000;\n iMin = pts.findIndex((p) => (p.time || 0) >= ts0);\n iMax = pts.findIndex((p) => (p.time || 0) >= ts1);\n }\n\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = pts.length - 1;\n\n // Compute selection stats\n const selPts = pts.slice(iMin, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n if ((UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n\n MapView.highlightSegment(selectedId, pts, iMin, iMax, fit, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n UrlState.patch({ sel: [min, max] });\n}\n\nfunction onChartClick(pt: TrackPoint, idx: number) {\n if (pt && pt.lat != null && pt.lon != null) MapView.centerOn(pt.lat, pt.lon, POINT_ZOOM_LEVEL);\n}\n\nexport function selectTrack(id: string, fit = true, deferChartRender = false) {\n if (!tracks[id]) return;\n if (id === selectedId) {\n if (fit) MapView.fitTrack(id);\n return;\n }\n\n const hadSelected = selectedId !== null;\n if (hadSelected) {\n // Clear current views immediately before loading new data\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n }\n\n selectedId = id;\n\n // Fully reset metric coloring when switching tracks\n currentMapColors = null;\n MapView.clearMetricColor(id);\n if (hadSelected) {\n ChartView.toggleMapColor(null); // Ensure ChartView state also resets\n }\n\n // Clear selection on new track\n UrlState.patch({ track: id, sel: null }, true);\n if (hadSelected) {\n ChartView.cancelSelection();\n }\n\n // Update UI immediately\n renderTrackList();\n\n // Render details\n const activeTab = UrlState.get().tab || 'graphs';\n if (activeTab === 'details') renderDetails(tracks[id], getGlobalTags());\n if (activeTab === 'insights') renderInsights(tracks[id]);\n if (activeTab === 'combined') renderCombined(tracks[id]);\n if (activeTab === 'courses') renderCourses();\n if (activeTab === 'evolution') {\n renderEvolution(tracks[id], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n\n // Tell sub-views\n MapView.setSelectedTrack(id, fit);\n if (fit) MapView.fitTrack(id);\n ChartView.loadTrack(tracks[id], Object.values(tracks), deferChartRender);\n}\n\nasync function deleteTrack(id: string) {\n await Storage.remove(id);\n MapView.removeTrack(id);\n delete tracks[id];\n if (selectedId === id) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n UrlState.patch({ track: null, sel: null, sel_point: null });\n }\n applyFilters();\n}\n\nasync function clearAll() {\n const code = Math.floor(10 + Math.random() * 90).toString();\n\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n backdrop.innerHTML = `\n
\n
Delete all tracks?
\n
\n This will permanently remove all tracks from your browser storage. This action cannot be undone.\n
\n
\n
Enter \"${code}\" to confirm:
\n \n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const input = backdrop.querySelector('.modal-input') as HTMLInputElement;\n const btnConfirm = backdrop.querySelector('.modal-btn.confirm') as HTMLButtonElement;\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n\n input.focus();\n\n input.addEventListener('input', () => {\n btnConfirm.disabled = input.value !== code;\n });\n\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n\n btnConfirm.addEventListener('click', async () => {\n if (input.value !== code) return;\n close();\n\n cancelProcessing = true;\n await Storage.clear();\n\n tracks = {};\n selectedId = null;\n MapView.clearHighlight();\n window.location.reload();\n });\n}\n\nfunction applyFilters(skipRender = false) {\n const ids = Object.keys(tracks);\n ids.forEach((id) => {\n const t = tracks[id];\n const s = t.stats;\n let visible = true;\n\n // Search query\n if (searchQuery) {\n if (searchRegex) {\n try {\n const re = new RegExp(searchQuery, 'i');\n if (!re.test(t.name)) visible = false;\n } catch (e) {\n visible = false;\n }\n } else {\n if (!t.name.toLowerCase().includes(searchQuery.toLowerCase())) visible = false;\n }\n }\n\n // Date filter\n if (visible && (filters.date[0] || filters.date[1])) {\n const start = filters.date[0] ? new Date(filters.date[0]).getTime() : 0;\n const end = filters.date[1] ? new Date(filters.date[1]).getTime() : Infinity;\n const t0 = s.startTime || 0;\n if (t0 < start || t0 > end) visible = false;\n }\n\n // Distance filter\n if (visible && (filters.dist[0] !== null || filters.dist[1] !== null)) {\n const min = (filters.dist[0] || 0) * 1000;\n const max = (filters.dist[1] || Infinity) * 1000;\n if (s.totalDist < min || s.totalDist > max) visible = false;\n }\n\n // Duration filter\n if (visible && (filters.dur[0] !== null || filters.dur[1] !== null)) {\n const min = (filters.dur[0] || 0) * 60000;\n const max = (filters.dur[1] || Infinity) * 60000;\n const d = s.duration || 0;\n if (d < min || d > max) visible = false;\n }\n\n // Metrics filter\n if (visible && filters.metrics.size > 0) {\n for (const m of filters.metrics) {\n const field = ChartView.METRICS[m].field;\n if (!t.points.some((p: any) => p[field] != null)) {\n visible = false;\n break;\n }\n }\n }\n\n // Sport filter\n if (visible && filters.sport) {\n if (t.sport !== filters.sport) visible = false;\n }\n\n // Tags filter\n if (visible && filters.tags.length > 0) {\n const trackTags = t.tags || [];\n if (!filters.tags.every((ft) => trackTags.includes(ft))) visible = false;\n }\n\n t._filtered = !visible;\n MapView.setTrackVisible(t.id, t.visible && visible);\n });\n\n if (!skipRender) renderTrackList();\n}\n\nfunction updateFilterUI() {\n (document.getElementById('filter-date-start') as HTMLInputElement).value = filters.date[0] || '';\n (document.getElementById('filter-date-end') as HTMLInputElement).value = filters.date[1] || '';\n (document.getElementById('filter-dist-min') as HTMLInputElement).value =\n filters.dist[0] !== null ? String(filters.dist[0]) : '';\n (document.getElementById('filter-dist-max') as HTMLInputElement).value =\n filters.dist[1] !== null ? String(filters.dist[1]) : '';\n (document.getElementById('filter-dur-min') as HTMLInputElement).value =\n filters.dur[0] !== null ? String(filters.dur[0]) : '';\n (document.getElementById('filter-dur-max') as HTMLInputElement).value =\n filters.dur[1] !== null ? String(filters.dur[1]) : '';\n (document.getElementById('filter-tags') as HTMLInputElement).value = filters.tags.join(', ');\n\n document\n .querySelectorAll('#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item')\n .forEach((el) => {\n const item = el as HTMLElement;\n item.classList.toggle('active', (item.dataset.sport || '') === (filters.sport || ''));\n });\n\n document.querySelectorAll('#filter-metrics .mini-pill').forEach((el) => {\n const btn = el as HTMLElement;\n btn.classList.toggle('active', filters.metrics.has(btn.dataset.metric!));\n });\n\n const activeCount =\n (filters.date[0] ? 1 : 0) +\n (filters.date[1] ? 1 : 0) +\n (filters.dist[0] !== null ? 1 : 0) +\n (filters.dist[1] !== null ? 1 : 0) +\n (filters.dur[0] !== null ? 1 : 0) +\n (filters.dur[1] !== null ? 1 : 0) +\n filters.metrics.size +\n (filters.tags.length > 0 ? 1 : 0);\n\n const badge = document.querySelector('#btn-toggle-filters .btn-badge');\n if (badge) {\n badge.textContent = activeCount > 0 ? String(activeCount) : '';\n badge.classList.toggle('hidden', activeCount === 0);\n }\n}\n\nfunction updateSearchSortUI() {\n const searchInput = document.getElementById('track-search') as HTMLInputElement;\n if (searchInput) searchInput.value = searchQuery;\n document.getElementById('btn-regex-toggle')?.classList.toggle('active', searchRegex);\n\n const opt = SORT_OPTIONS.find((o) => o.val === currentSort);\n if (opt) {\n const labelEl = document.getElementById('sort-current-label');\n const iconEl = document.getElementById('sort-current-icon');\n if (labelEl)\n labelEl.textContent = opt.label\n .replace(' first', '')\n .replace(' distance', '')\n .replace(' duration', '');\n if (iconEl) iconEl.textContent = opt.icon;\n }\n}\n\nfunction applyState(urlState: AppState) {\n // Restore track\n const newTrackId = urlState.track;\n if (newTrackId !== selectedId) {\n if (newTrackId && tracks[newTrackId]) {\n selectTrack(newTrackId, true);\n } else if (!newTrackId && selectedId) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n renderTrackList();\n MapView.fitAll();\n }\n }\n\n // Restore basemap\n if (urlState.map && typeof urlState.map === 'string') {\n MapView.switchBasemap(urlState.map);\n document\n .querySelectorAll('.bm-btn')\n .forEach((b) =>\n b.classList.toggle('active', (b as HTMLElement).dataset.layer === urlState.map),\n );\n }\n\n // Restore map position\n if (urlState.map_pos) {\n const [lat, lng, zoom] = urlState.map_pos;\n MapView.setPosition(lat, lng, zoom);\n }\n\n // Restore tab\n if (urlState.tab) {\n document.querySelectorAll('.tab-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n if (b.dataset.tab === urlState.tab) {\n if (!b.classList.contains('active')) b.click();\n }\n });\n }\n\n // Restore x-axis mode\n if (urlState.xaxis) ChartView.setXAxis(urlState.xaxis);\n\n const currentXAxis = urlState.xaxis || 'time';\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', (b as HTMLElement).dataset.axis === currentXAxis));\n\n // Restore active metrics\n if (urlState.metrics) {\n const metrics = ChartView.METRICS;\n const keys = urlState.metrics\n .map((abbr) => Object.keys(metrics).find((k) => metrics[k].abbr === abbr))\n .filter((k): k is string => k !== undefined);\n if (keys.length) ChartView.setActiveMetrics(keys);\n }\n\n // Restore filters\n if (urlState.f_date)\n filters.date = urlState.f_date.map((v) => v || null) as [string | null, string | null];\n if (urlState.f_dist)\n filters.dist = urlState.f_dist.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_dur)\n filters.dur = urlState.f_dur.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_mets) filters.metrics = new Set(urlState.f_mets);\n if (urlState.f_tags) filters.tags = urlState.f_tags;\n\n updateFilterUI();\n\n if (urlState.q) searchQuery = urlState.q;\n if (urlState.re) searchRegex = urlState.re;\n if (urlState.sort) currentSort = urlState.sort;\n updateSearchSortUI();\n\n applyFilters();\n}\n\nfunction updateSportFilterOptions() {\n const container = document.getElementById('sport-filter-container');\n if (!container) return;\n\n const commonContainer = document.getElementById('common-sports');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n if (!commonContainer || !dropdownContent) return;\n\n const sports = new Set();\n Object.values(tracks).forEach((t) => {\n if (t.sport) sports.add(t.sport);\n });\n\n const sportsArray = Array.from(sports).sort();\n const burgerDropdown = document.getElementById('sport-burger-dropdown');\n\n commonContainer.innerHTML = '';\n dropdownContent.innerHTML = '';\n\n if (sportsArray.length <= 4) {\n if (burgerDropdown) burgerDropdown.style.display = 'none';\n\n sportsArray.forEach((sport) => {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n });\n } else {\n if (burgerDropdown) burgerDropdown.style.display = 'inline-block';\n\n const commonSports = ['running', 'cycling', 'walking'];\n\n commonSports.forEach((sport) => {\n if (sports.has(sport)) {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n }\n });\n\n sportsArray.forEach((sport) => {\n const item = document.createElement('div');\n item.className = `dropdown-item${filters.sport === sport ? ' active' : ''}`;\n item.dataset.sport = sport;\n item.style.padding = '8px';\n item.style.cursor = 'pointer';\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '8px';\n item.innerHTML = `\n ${getSportIcon(sport)}\n ${sport.charAt(0).toUpperCase() + sport.slice(1)}\n `;\n dropdownContent.appendChild(item);\n });\n }\n}\n\nfunction renderTrackList() {\n updateSportFilterOptions();\n const list = document.getElementById('track-list');\n const emptyEl = document.getElementById('track-list-empty') as HTMLElement;\n const headerLabel = document.querySelector('.section-label');\n if (!list) return;\n\n const ids = Object.keys(tracks).filter((id) => !tracks[id]._filtered);\n if (headerLabel) headerLabel.textContent = `Tracks (${ids.length})`;\n\n if (!ids.length) {\n list.innerHTML = '';\n if (emptyEl) {\n list.appendChild(emptyEl);\n emptyEl.style.display = 'block';\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n list.innerHTML = '';\n\n ids\n .sort((a, b) => {\n // Current selected always first\n if (a === selectedId) return -1;\n if (b === selectedId) return 1;\n\n const ta = tracks[a],\n tb = tracks[b];\n const sa = ta.stats,\n sb = tb.stats;\n\n let cmp = 0;\n switch (currentSort) {\n case 'date-asc':\n cmp = (sa.startTime || 0) - (sb.startTime || 0);\n break;\n case 'date-desc':\n cmp = (sb.startTime || 0) - (sa.startTime || 0);\n break;\n case 'dist-asc':\n cmp = (sa.totalDist || 0) - (sb.totalDist || 0);\n break;\n case 'dist-desc':\n cmp = (sb.totalDist || 0) - (sa.totalDist || 0);\n break;\n case 'dur-asc':\n cmp = (sa.duration || 0) - (sb.duration || 0);\n break;\n case 'dur-desc':\n cmp = (sb.duration || 0) - (sa.duration || 0);\n break;\n default:\n cmp = 0;\n }\n return cmp || a.localeCompare(b);\n })\n .forEach((id) => {\n list.appendChild(buildTrackItem(tracks[id]));\n });\n}\n\nfunction getGlobalTags(): string[] {\n const all = new Set();\n Object.values(tracks).forEach((t) => {\n (t.tags || []).forEach((tag) => all.add(tag));\n });\n return Array.from(all).sort();\n}\n\nfunction getSportIcon(sport: string | null): string {\n if (!sport) return 'category';\n const s = sport.toLowerCase();\n if (s.includes('run')) return 'directions_run';\n if (s.includes('cycl') || s.includes('bike')) return 'directions_bike';\n if (s.includes('walk')) return 'directions_walk';\n if (s.includes('swim')) return 'pool';\n if (s.includes('hik')) return 'hiking';\n return 'sports';\n}\n\nfunction buildTrackItem(track: TrackData) {\n const item = document.createElement('div');\n item.className = `track-item${track.id === selectedId ? ' selected' : ''}`;\n item.dataset.id = track.id;\n\n const date =\n track.points.length && track.points[0].time ? fmtDate(track.points[0].time) : 'Unknown date';\n\n const tagsHtml =\n (track.tags || []).length > 0\n ? `
${(track.tags || [])\n .map((t) => {\n const c = getTagColor(t);\n return `${escHtml(t)}`;\n })\n .join('')}
`\n : '';\n\n item.innerHTML = `\n
\n
\n
${escHtml(track.displayName || track.name)}
\n
\n
\n ${date}\n ${Math.round(track.stats.totalDist / 1000)} km\n ${track.sport ? `${getSportIcon(track.sport)}` : ''}\n ${track.format.toUpperCase()}\n
\n \n
\n ${tagsHtml}\n
\n `;\n\n item.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.icon-btn')) return;\n selectTrack(track.id);\n });\n\n const btnVis = item.querySelector('.toggle-vis') as HTMLElement;\n btnVis.addEventListener('click', () => {\n track.visible = !track.visible;\n btnVis.querySelector('.material-symbols-rounded')!.textContent = track.visible\n ? 'visibility'\n : 'visibility_off';\n MapView.setTrackVisible(track.id, track.visible);\n Storage.save(track);\n });\n\n return item;\n}\n\nfunction showToast(msg: string, type: 'info' | 'error' = 'info') {\n const container = document.getElementById('toast-container');\n if (!container) return;\n container.innerHTML = '';\n const t = document.createElement('div');\n t.className = `toast ${type}`;\n t.textContent = msg;\n container.appendChild(t);\n}\n\nfunction showSkippedImportsModal() {\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n let listHtml = '';\n skippedImports.forEach((s) => {\n listHtml += `
${s.name}: ${s.reason}
`;\n });\n\n backdrop.innerHTML = `\n
\n
Skipped Imports
\n
\n ${listHtml || '
No skipped imports.
'}\n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n const btnClear = backdrop.querySelector('.modal-btn.clear') as HTMLButtonElement;\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n btnClear.addEventListener('click', () => {\n skippedImports = [];\n close();\n const importWarning = document.getElementById('import-warning');\n if (importWarning) importWarning.classList.add('hidden');\n });\n\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n}\n\nfunction initDropZone() {\n const zone = document.getElementById('drop-zone');\n if (!zone) return;\n\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n importWarning.addEventListener('click', (e) => {\n e.stopPropagation();\n showSkippedImportsModal();\n });\n }\n\n window.addEventListener('dragover', (e) => {\n e.preventDefault();\n zone.classList.add('drop-active');\n });\n\n window.addEventListener('dragleave', (e) => {\n if (e.relatedTarget === null) zone.classList.remove('drop-active');\n });\n\n window.addEventListener('drop', async (e) => {\n e.preventDefault();\n zone.classList.remove('drop-active');\n\n const items = e.dataTransfer?.items;\n if (!items) return;\n\n const files: File[] = [];\n const queue: FileSystemEntry[] = [];\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i].webkitGetAsEntry();\n if (entry) queue.push(entry);\n }\n\n async function readAllEntries(entry: FileSystemEntry) {\n if (entry.isFile) {\n const file = await new Promise((res) => (entry as FileSystemFileEntry).file(res));\n files.push(file);\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n let entries: FileSystemEntry[] = [];\n let chunk: FileSystemEntry[];\n do {\n chunk = await new Promise((res) => reader.readEntries(res));\n entries.push(...chunk);\n } while (chunk.length > 0);\n\n for (const child of entries) await readAllEntries(child);\n }\n }\n\n for (const entry of queue) await readAllEntries(entry);\n\n if (files.length) handleFiles(files);\n });\n}\n\nasync function handleFiles(files: File[]) {\n if (!files.length) return;\n cancelProcessing = false;\n const initialSkipCount = skippedImports.length;\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const loaderClose = document.getElementById('loader-close');\n\n if (loaderClose) {\n loaderClose.addEventListener('click', () => {\n cancelProcessing = true;\n if (loader) loader.classList.add('hidden');\n });\n }\n\n function updateLoaderIconToWarning() {\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'warning';\n loaderIcon.style.color = '#f59e0b';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n const count = skippedImports.length - initialSkipCount;\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = `${count}`;\n warningCount.style.display = 'flex';\n }\n }\n\n if (loader) {\n if (loaderText)\n loaderText.textContent = `Importing ${files.length} file${files.length > 1 ? 's' : ''}`;\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'download';\n loaderIcon.style.color = 'var(--accent)';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n warningCount.style.display = 'none';\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = '0';\n }\n if (loaderSubtext) loaderSubtext.textContent = '';\n if (progressBar) progressBar.style.width = '0%';\n loader.classList.remove('hidden');\n\n if (skippedImports.length > initialSkipCount) updateLoaderIconToWarning();\n }\n\n try {\n let count = 0;\n let firstId: string | null = null;\n let processedSinceLastUpdate = 0;\n\n // Filter out obviously invalid files early\n const validFiles = files.filter((f) => {\n const name = f.name.toLowerCase();\n return (\n name.endsWith('.gpx') ||\n name.endsWith('.fit') ||\n name.endsWith('.tcx') ||\n name.endsWith('.kml')\n );\n });\n\n const invalidFiles = files.filter((f) => !validFiles.includes(f));\n invalidFiles.forEach((f) => {\n skippedImports.push({ name: f.name, reason: 'Unsupported file format' });\n });\n\n if (validFiles.length === 0) {\n if (files.length > 0) {\n showToast('No valid GPS files found', 'error');\n // Still update warning icon if there were invalid files!\n const importWarning = document.getElementById('import-warning');\n if (importWarning && skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n }\n }\n return;\n }\n\n const loaderFilename = document.getElementById('loader-filename');\n let progressIdxEl: HTMLElement | null = null;\n if (loaderSubtext) {\n loaderSubtext.innerHTML =\n '';\n progressIdxEl = loaderSubtext.querySelector('.progress-index') as HTMLElement | null;\n const totalEl = loaderSubtext.querySelector('.progress-total');\n if (totalEl) totalEl.textContent = validFiles.length.toString();\n }\n\n for (let i = 0; i < validFiles.length; i++) {\n if (cancelProcessing) break;\n const f = validFiles[i];\n if (loaderFilename) loaderFilename.textContent = f.name;\n if (progressIdxEl) progressIdxEl.textContent = (i + 1).toString();\n if (progressBar) progressBar.style.width = `${(i / validFiles.length) * 100}%`;\n\n try {\n const data = await Parsers.parseFile(f);\n\n // Duplicate checks\n const existingTracks = Object.values(tracks);\n\n // Rule 1: Same file and same size\n const sameFile = existingTracks.find((t) => t.fileName === f.name && t.fileSize === f.size);\n if (sameFile) {\n skippedImports.push({ name: f.name, reason: 'Same File' });\n updateLoaderIconToWarning();\n continue;\n }\n\n // Rule 2 & 3: Same start day checks\n const newStart = data.stats.startTime;\n const newDuration = data.stats.duration;\n\n if (newStart != null && newDuration != null) {\n const newEnd = newStart + newDuration;\n const sameDayTracks = existingTracks.filter(\n (t) => t.stats.startTime != null && isSameDay(newStart, t.stats.startTime!),\n );\n\n let discarded = false;\n for (const ext of sameDayTracks) {\n const extStart = ext.stats.startTime!;\n const extDuration = ext.stats.duration!;\n const extEnd = extStart + extDuration;\n\n // Rule 2: Fully contained\n if (newStart >= extStart && newEnd <= extEnd) {\n skippedImports.push({ name: f.name, reason: 'Fully contained in another track' });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n\n // Rule 3: Overlaps for > 10 mins\n const overlap = Math.min(newEnd, extEnd) - Math.max(newStart, extStart);\n if (overlap > 600000) {\n // 10 mins in ms\n skippedImports.push({\n name: f.name,\n reason: 'Overlaps with an existing track for more than 10 mins',\n });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n }\n if (discarded) continue;\n }\n\n const fallbackTime = 1785542400000;\n let id = compactId(data.stats.startTime || fallbackTime);\n if (tracks[id]) id += `-${shortRandom()}`;\n\n // Use filename as activity name if internal name is generic\n let trackName = data.name;\n if (trackName.startsWith('Unnamed') || trackName.startsWith('Fit Activity'))\n trackName = f.name;\n\n // Generate a nice display name\n let displayName = trackName;\n const t0 = data.points[0]?.time;\n const sport = data.sport\n ? data.sport.charAt(0).toUpperCase() + data.sport.slice(1)\n : 'Activity';\n if (t0) {\n const d = new Date(t0);\n displayName = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')} ${sport}`;\n } else {\n displayName = trackName.replace(/\\.[^/.]+$/, '').replace(/_/g, ' '); // Remove extension and replace underscores\n }\n\n const track: TrackData = {\n ...data,\n id,\n name: trackName,\n displayName,\n fileName: f.name,\n fileSize: f.size,\n bounds: calculateBounds(data.points) || undefined,\n simplifiedPoints: simplifyTrack(data.points, 50), // 50m resolution\n addedAt: data.stats.startTime || fallbackTime,\n visible: true,\n color: TRACK_COLORS[colorIdx % TRACK_COLORS.length],\n };\n colorIdx++;\n if (cancelProcessing) break;\n\n await Storage.save(track);\n tracks[id] = track;\n MapView.addTrack(track);\n if (!firstId) firstId = id;\n count++;\n processedSinceLastUpdate++;\n\n if (processedSinceLastUpdate >= 5) {\n processedSinceLastUpdate = 0;\n }\n } catch (err) {\n skippedImports.push({\n name: f.name,\n reason: `Parse error: ${err instanceof Error ? err.message : String(err)}`,\n });\n updateLoaderIconToWarning();\n }\n }\n\n // Update warning icon\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n if (skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n } else {\n importWarning.classList.add('hidden');\n }\n }\n\n const newWarnings = skippedImports.length > initialSkipCount;\n if (!newWarnings && loader) {\n loader.classList.add('hidden');\n }\n\n if (count > 0) {\n showToast(`Imported ${count} track${count > 1 ? 's' : ''}`);\n applyFilters(!!firstId && firstId !== selectedId);\n if (firstId) selectTrack(firstId);\n }\n\n if (newWarnings) {\n const loaderIcon = document.querySelector('.loader-icon-wrap span');\n if (loaderIcon) loaderIcon.textContent = 'warning';\n // Delay hiding loader to let user see the alert icon\n await new Promise((r) => setTimeout(r, 1500));\n }\n } finally {\n if (loader) loader.classList.add('hidden');\n }\n}\n\nfunction initMetricPillDraggable() {\n const container = document.getElementById('metric-pills');\n if (!container) return;\n\n let draggedEl: HTMLElement | null = null;\n\n container.addEventListener('dragstart', (e) => {\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (!target) return;\n draggedEl = target;\n e.dataTransfer!.effectAllowed = 'move';\n target.classList.add('dragging-pill');\n // For transparent background in ghost image\n setTimeout(() => (target.style.opacity = '0.4'), 0);\n });\n\n container.addEventListener('dragover', (e) => {\n e.preventDefault();\n e.dataTransfer!.dropEffect = 'move';\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (target && target !== draggedEl) {\n const rect = target.getBoundingClientRect();\n const next = e.clientX - rect.left > rect.width / 2;\n container.insertBefore(draggedEl!, next ? target.nextSibling : target);\n }\n });\n\n container.addEventListener('dragend', () => {\n if (!draggedEl) return;\n draggedEl.classList.remove('dragging-pill');\n draggedEl.style.opacity = '';\n draggedEl = null;\n\n // Update Chart order\n const keys = Array.from(container.querySelectorAll('.metric-pill')).map(\n (el) => (el as HTMLElement).dataset.metric!,\n );\n ChartView.updateMetricOrder(keys);\n syncMetricsToUrl();\n });\n}\n\nfunction updateToolbarLayout() {\n const toolbar = document.getElementById('chart-toolbar');\n const pills = document.getElementById('metric-pills');\n if (!toolbar || !pills) return;\n\n toolbar.classList.remove('collapsed');\n const availableW = Math.max(0, toolbar.clientWidth - 280);\n let totalW = 0;\n let hidden = false;\n\n Array.from(pills.children).forEach((el) => {\n const htmlEl = el as HTMLElement;\n if (htmlEl.id === 'pill-overflow') return;\n\n htmlEl.classList.remove('overflow-hidden');\n if (!htmlEl.classList.contains('active')) return;\n const metricKey = htmlEl.dataset.metric || '';\n const deterministicPillWidth = 36 + metricKey.length * 6;\n totalW += deterministicPillWidth + 6;\n\n if (totalW > availableW) {\n hidden = true;\n htmlEl.classList.add('overflow-hidden');\n }\n });\n\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.toggle('hidden', !hidden);\n\n if (hidden) toolbar.classList.add('collapsed');\n}\n\ndocument.addEventListener('DOMContentLoaded', init);\n"], - "mappings": "AAgCO,IAAMA,IAAY,IAAM,CAE7B,IAAIC,EAAmB,CAAC,EACpBC,EAA6B,KAC7BC,EAAoB,KACpBC,EAAc,GAElB,SAASC,GAAiB,CACxB,IAAMC,EAAI,IAAI,gBAAgB,SAAS,MAAM,EACvCC,EAAc,CAAC,EAEjBD,EAAE,IAAI,OAAO,IAAGC,EAAE,MAAQD,EAAE,IAAI,OAAO,GACvCA,EAAE,IAAI,KAAK,IAAGC,EAAE,IAAMD,EAAE,IAAI,KAAK,GACjCA,EAAE,IAAI,OAAO,IAAGC,EAAE,MAAQD,EAAE,IAAI,OAAO,GACvCA,EAAE,IAAI,KAAK,IAAGC,EAAE,IAAMD,EAAE,IAAI,KAAK,GACjCA,EAAE,IAAI,WAAW,IAAGC,EAAE,UAAY,OAAOD,EAAE,IAAI,WAAW,CAAC,GAC3DA,EAAE,IAAI,YAAY,IAAGC,EAAE,WAAaD,EAAE,IAAI,YAAY,GACtDA,EAAE,IAAI,UAAU,IAAGC,EAAE,SAAWD,EAAE,IAAI,UAAU,GACpD,IAAME,EAAaF,EAAE,IAAI,SAAS,EA0BlC,GAzBIE,IAAYD,EAAE,QAAUC,EAAW,MAAM,GAAG,EAAE,OAAO,OAAO,GAE5DF,EAAE,IAAI,QAAQ,IAChBC,EAAE,OAASD,EACR,IAAI,QAAQ,EACZ,MAAM,GAAG,EACT,IAAKG,GAAMA,GAAK,IAAI,GAErBH,EAAE,IAAI,QAAQ,IAChBC,EAAE,OAASD,EACR,IAAI,QAAQ,EACZ,MAAM,GAAG,EACT,IAAKG,GAAOA,EAAI,OAAOA,CAAC,EAAI,IAAK,GAElCH,EAAE,IAAI,OAAO,IACfC,EAAE,MAAQD,EACP,IAAI,OAAO,EACX,MAAM,GAAG,EACT,IAAKG,GAAOA,EAAI,OAAOA,CAAC,EAAI,IAAK,GAElCH,EAAE,IAAI,QAAQ,IAAGC,EAAE,OAASD,EAAE,IAAI,QAAQ,EAAG,MAAM,GAAG,GACtDA,EAAE,IAAI,QAAQ,IAAGC,EAAE,OAASD,EAAE,IAAI,QAAQ,EAAG,MAAM,GAAG,GAEtDA,EAAE,IAAI,GAAG,IAAGC,EAAE,EAAID,EAAE,IAAI,GAAG,GAC3BA,EAAE,IAAI,IAAI,IAAGC,EAAE,GAAKD,EAAE,IAAI,IAAI,IAAM,KACpCA,EAAE,IAAI,MAAM,EAAG,CACjB,IAAMG,EAAIH,EAAE,IAAI,MAAM,EAChBI,EAASD,EAAE,WAAW,GAAG,EACzBE,EAAQD,EAASD,EAAE,UAAU,CAAC,EAAIA,EACxCF,EAAE,KAAO,GAAGI,CAAK,IAAID,EAAS,OAAS,KAAK,EAC9C,CAEA,GAAIJ,EAAE,IAAI,SAAS,EAAG,CACpB,IAAMM,EAAQN,EAAE,IAAI,SAAS,EAAG,MAAM,GAAG,EAAE,IAAI,MAAM,EACjDM,EAAM,SAAW,GAAKA,EAAM,MAAM,QAAQ,IAC5CL,EAAE,QAAUK,EAChB,CAGA,GADIN,EAAE,IAAI,SAAS,IAAGC,EAAE,QAAUD,EAAE,IAAI,SAAS,GAC7CA,EAAE,IAAI,KAAK,EAAG,CAChB,IAAMM,EAAQN,EAAE,IAAI,KAAK,EAAG,MAAM,GAAG,EAAE,IAAI,MAAM,EAC7CM,EAAM,SAAW,GAAKA,EAAM,MAAOH,GAAM,CAAC,MAAMA,CAAC,GAAK,SAASA,CAAC,CAAC,IACnEF,EAAE,IAAMK,EACZ,CAEA,OAAOL,CACT,CAGA,SAASM,GAAQ,CACXV,IACF,aAAaA,CAAY,EACzBA,EAAe,MAGjB,IAAMG,EAAI,IAAI,gBAcd,GAXIL,EAAO,OAAOK,EAAE,IAAI,QAASL,EAAO,KAAK,EACzCA,EAAO,KAAKK,EAAE,IAAI,MAAOL,EAAO,GAAG,EACnCA,EAAO,OAASA,EAAO,QAAU,QAAQK,EAAE,IAAI,QAASL,EAAO,KAAK,EACpEA,EAAO,KAAOA,EAAO,MAAQ,UAAUK,EAAE,IAAI,MAAOL,EAAO,GAAG,EAC9DA,EAAO,SAAWA,EAAO,UAAY,UAAUK,EAAE,IAAI,UAAWL,EAAO,OAAO,EAC9EA,EAAO,YAAc,QAAWK,EAAE,IAAI,YAAa,OAAOL,EAAO,SAAS,CAAC,EAC3EA,EAAO,YAAYK,EAAE,IAAI,aAAcL,EAAO,UAAU,EACxDA,EAAO,GAAGK,EAAE,IAAI,IAAKL,EAAO,CAAC,EAC7BA,EAAO,UAAUK,EAAE,IAAI,WAAYL,EAAO,QAAQ,EAClDA,EAAO,IAAIK,EAAE,IAAI,KAAM,GAAG,EAE1BL,EAAO,KAAM,CACf,IAAMW,EAAQX,EAAO,KAAK,MAAM,GAAG,EAC7BU,EAAQC,EAAM,CAAC,EACfE,EAAMF,EAAM,CAAC,EACnBN,EAAE,IAAI,QAASQ,IAAQ,OAAS,IAAM,IAAMH,CAAK,CACnD,CAEA,IAAII,EAAST,EAAE,SAAS,EAkBxB,GAfIL,EAAO,UAASc,GAAU,GAAGA,EAAS,IAAM,EAAE,WAAWd,EAAO,QAAQ,KAAK,GAAG,CAAC,IAEjFA,EAAO,SACTc,GAAU,GAAGA,EAAS,IAAM,EAAE,UAAUd,EAAO,OAAO,IAAKQ,GAAMA,GAAK,EAAE,EAAE,KAAK,GAAG,CAAC,IAEjFR,EAAO,SACTc,GAAU,GAAGA,EAAS,IAAM,EAAE,UAAUd,EAAO,OAAO,IAAKQ,GAAMA,GAAK,EAAE,EAAE,KAAK,GAAG,CAAC,IAEjFR,EAAO,QACTc,GAAU,GAAGA,EAAS,IAAM,EAAE,SAASd,EAAO,MAAM,IAAKQ,GAAMA,GAAK,EAAE,EAAE,KAAK,GAAG,CAAC,IAE/ER,EAAO,SAAQc,GAAU,GAAGA,EAAS,IAAM,EAAE,UAAUd,EAAO,OAAO,KAAK,GAAG,CAAC,IAE9EA,EAAO,SAAQc,GAAU,GAAGA,EAAS,IAAM,EAAE,UAAUd,EAAO,OAAO,KAAK,GAAG,CAAC,IAE9EA,EAAO,QAAS,CAClB,IAAMe,EAAM,IAAI,CAACf,EAAO,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,KAAK,CAACA,EAAO,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,IAC/EA,EAAO,QAAQ,CAAC,CAClB,GACAc,GAAU,GAAGA,EAAS,IAAM,EAAE,WAAWC,CAAG,EAC9C,CACA,GAAIf,EAAO,IAAK,CACd,IAAMe,EAAM,GAAG,CAACf,EAAO,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAACA,EAAO,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,GACrEc,GAAU,GAAGA,EAAS,IAAM,EAAE,OAAOC,CAAG,EAC1C,CAEA,GAAID,IAAWb,EAAa,CAC1B,IAAMe,EAAM,SAAS,UAAYF,EAAS,IAAIA,CAAM,GAAK,IACzD,GAAI,CACEX,GACF,QAAQ,UAAU,KAAM,GAAIa,CAAG,EAC/Bb,EAAc,IAEd,QAAQ,aAAa,KAAM,GAAIa,CAAG,CAEtC,MAAY,CACVb,EAAc,EAChB,CACAF,EAAca,CAChB,CACF,CAGAd,EAASI,EAAK,EAEd,SAASa,GAAgB,CACvB,MAAO,CAAE,GAAGjB,CAAO,CACrB,CAEA,SAASkB,EAAMC,EAA+CC,EAAgB,GAAO,CAC/EA,IAAMjB,EAAc,IACxB,OAAW,CAACkB,EAAGb,CAAC,IAAK,OAAO,QAAQW,CAAO,EAAG,CAC5C,IAAMG,EAAMD,EACRb,GAAM,KAAyB,OAAOR,EAAOsB,CAAG,EAC9CtB,EAAesB,CAAG,EAAId,CAC9B,CACAI,EAAM,CACR,CAEA,SAASW,GAAU,CACjBvB,EAASI,EAAK,CAChB,CAEA,SAASoB,GAAQ,CACXtB,IACF,aAAaA,CAAY,EACzBA,EAAe,MAEjBF,EAAS,CAAC,EACVG,EAAc,GACdF,EAAc,GACd,GAAI,CACF,QAAQ,aAAa,KAAM,GAAI,SAAS,QAAQ,CAClD,MAAY,CAAC,CACf,CAEA,MAAO,CAAE,IAAAgB,EAAK,MAAAC,EAAO,QAAAK,EAAS,MAAAC,CAAM,CACtC,GAAG,EC9LH,IAAMC,GAAN,KAA+C,CAA/C,cACE,KAAQ,WAAa,IAAI,IACzB,KAAQ,aAAe,IAAI,IAE3B,MAAM,QAAwB,CAC5B,OAAO,QAAQ,QAAQ,CACzB,CAEA,MAAM,KAAKC,EAAiC,CAC1C,YAAK,WAAW,IAAIA,EAAM,GAAIA,CAAK,EAC5B,QAAQ,QAAQ,CACzB,CAEA,MAAM,QAA+B,CACnC,OAAO,QAAQ,QAAQ,MAAM,KAAK,KAAK,WAAW,OAAO,CAAC,CAAC,CAC7D,CAEA,MAAM,OAAOC,EAA2B,CACtC,YAAK,WAAW,OAAOA,CAAE,EAClB,QAAQ,QAAQ,CACzB,CAEA,MAAM,OAAuB,CAC3B,YAAK,WAAW,MAAM,EACtB,KAAK,aAAa,MAAM,EACjB,QAAQ,QAAQ,CACzB,CAEA,MAAM,IAAIC,EAAaC,EAA2B,CAChD,YAAK,aAAa,IAAID,EAAKC,CAAK,EACzB,QAAQ,QAAQ,CACzB,CAEA,MAAM,IAAaD,EAAgC,CACjD,OAAO,QAAQ,QAAS,KAAK,aAAa,IAAIA,CAAG,GAAW,IAAI,CAClE,CACF,EAEME,GAAN,KAAgD,CAAhD,cACE,KAAQ,GAAyB,KACjC,KAAiB,QAAU,aAC3B,KAAiB,WAAa,EAE9B,MAAM,QAAwB,CAC5B,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CACtC,IAAMC,EAAM,UAAU,KAAK,KAAK,QAAS,KAAK,UAAU,EACxDA,EAAI,gBAAkB,IAAM,CAC1B,IAAMC,EAAKD,EAAI,OACVC,EAAG,iBAAiB,SAAS,QAAQ,GACxCA,EAAG,kBAAkB,SAAU,CAAE,QAAS,IAAK,CAAC,EAC7CA,EAAG,iBAAiB,SAAS,UAAU,GAAGA,EAAG,kBAAkB,UAAU,CAChF,EACAD,EAAI,UAAY,IAAM,CACpB,KAAK,GAAKA,EAAI,OACdF,EAAQ,CACV,EACAE,EAAI,QAAU,IAAMD,EAAOC,EAAI,KAAK,CACtC,CAAC,CACH,CAEQ,SAASE,EAA6BC,EAA0C,CACtF,GAAI,CAAC,KAAK,GAAI,MAAM,IAAI,MAAM,sBAAsB,EACpD,OAAO,KAAK,GAAG,YAAYD,EAAMC,CAAI,EAAE,YAAYD,CAAI,CACzD,CAEA,MAAM,KAAKT,EAAiC,CAC1C,OAAO,IAAI,QAAQ,CAACW,EAAKC,IAAQ,CAC/B,IAAML,EAAM,KAAK,SAAS,SAAU,WAAW,EAAE,IAAIP,CAAK,EAC1DO,EAAI,UAAY,IAAMI,EAAI,EAC1BJ,EAAI,QAAU,IAAMK,EAAIL,EAAI,KAAK,CACnC,CAAC,CACH,CAEA,MAAM,QAA+B,CACnC,OAAO,IAAI,QAAQ,CAACI,EAAKC,IAAQ,CAC/B,IAAML,EAAM,KAAK,SAAS,SAAU,UAAU,EAAE,OAAO,EACvDA,EAAI,UAAY,IAAMI,EAAIJ,EAAI,QAAU,CAAC,CAAC,EAC1CA,EAAI,QAAU,IAAMK,EAAIL,EAAI,KAAK,CACnC,CAAC,CACH,CAEA,MAAM,OAAON,EAA2B,CACtC,OAAO,IAAI,QAAQ,CAACU,EAAKC,IAAQ,CAC/B,IAAML,EAAM,KAAK,SAAS,SAAU,WAAW,EAAE,OAAON,CAAE,EAC1DM,EAAI,UAAY,IAAMI,EAAI,EAC1BJ,EAAI,QAAU,IAAMK,EAAIL,EAAI,KAAK,CACnC,CAAC,CACH,CAEA,MAAM,OAAuB,CAC3B,OAAK,KAAK,GACH,IAAI,QAAQ,CAACI,EAAKC,IAAQ,CAC/B,IAAMC,EAAK,KAAK,GAAI,YAAY,CAAC,SAAU,UAAU,EAAG,WAAW,EACnEA,EAAG,YAAY,QAAQ,EAAE,MAAM,EAC/BA,EAAG,YAAY,UAAU,EAAE,MAAM,EACjCA,EAAG,WAAa,IAAMF,EAAI,EAC1BE,EAAG,QAAU,IAAMD,EAAIC,EAAG,KAAK,CACjC,CAAC,EAPoB,QAAQ,QAAQ,CAQvC,CAEA,MAAM,IAAIX,EAAaC,EAA2B,CAChD,OAAO,IAAI,QAAQ,CAACQ,EAAKC,IAAQ,CAC/B,IAAML,EAAM,KAAK,SAAS,WAAY,WAAW,EAAE,IAAIJ,EAAOD,CAAG,EACjEK,EAAI,UAAY,IAAMI,EAAI,EAC1BJ,EAAI,QAAU,IAAMK,EAAIL,EAAI,KAAK,CACnC,CAAC,CACH,CAEA,MAAM,IAAaL,EAAgC,CACjD,OAAO,IAAI,QAAQ,CAACS,EAAKC,IAAQ,CAC/B,IAAML,EAAM,KAAK,SAAS,WAAY,UAAU,EAAE,IAAIL,CAAG,EACzDK,EAAI,UAAY,IAAMI,EAAKJ,EAAI,QAAgB,IAAI,EACnDA,EAAI,QAAU,IAAMK,EAAIL,EAAI,KAAK,CACnC,CAAC,CACH,CACF,EAEIO,GAA8B,IAAIf,GAEzBgB,GAAyB,CACpC,OAAQ,SAA2B,CAEjCD,GADgBE,GAAS,IAAI,EAAE,UACJ,YAAc,IAAIZ,GAAqB,IAAIL,GACtE,MAAMe,GAAa,OAAO,CAC5B,EACA,KAAO,GAAMA,GAAa,KAAK,CAAC,EAChC,OAAQ,IAAMA,GAAa,OAAO,EAClC,OAASb,GAAOa,GAAa,OAAOb,CAAE,EACtC,MAAO,IAAMa,GAAa,MAAM,EAChC,IAAK,CAACG,EAAGC,IAAMJ,GAAa,IAAIG,EAAGC,CAAC,EACpC,IAASD,GAAcH,GAAa,IAAOG,CAAC,CAC9C,EC9IA,OAAOE,OAAe,kBCAf,SAASC,GAAUC,EAAcC,EAAcC,EAAcC,EAAsB,CAExF,IAAMC,EAAQJ,EAAO,KAAK,GAAM,IAC1BK,EAAQH,EAAO,KAAK,GAAM,IAC1BI,GAAaJ,EAAOF,GAAQ,KAAK,GAAM,IACvCO,GAAgBJ,EAAOF,GAAQ,KAAK,GAAM,IAE1CO,EACJ,KAAK,IAAIF,EAAW,CAAC,EAAI,KAAK,IAAIA,EAAW,CAAC,EAC9C,KAAK,IAAIF,CAAI,EAAI,KAAK,IAAIC,CAAI,EAAI,KAAK,IAAIE,EAAc,CAAC,EAAI,KAAK,IAAIA,EAAc,CAAC,EAGxF,MAAO,SAFG,EAAI,KAAK,MAAM,KAAK,KAAKC,CAAC,EAAG,KAAK,KAAK,EAAIA,CAAC,CAAC,EAGzD,CAEO,SAASC,GAAUC,EAA2B,CAGnD,IAAMC,EAAM,IAAI,YAAY,CAAC,KAAK,MAAMD,EAAY,GAAI,CAAC,CAAC,EAE1D,OADY,KAAK,OAAO,aAAa,GAAG,IAAI,WAAWC,EAAI,MAAM,CAAC,CAAC,EACxD,QAAQ,MAAO,GAAG,EAAE,QAAQ,MAAO,GAAG,EAAE,QAAQ,KAAM,EAAE,CACrE,CAMO,SAASC,IAAsB,CACpC,OAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,CAC9C,CAEO,SAASC,GAAYC,EAAmB,CAC7C,OAAIA,EAAI,GAAW,GAAG,KAAK,MAAMA,CAAC,CAAC,IAC/BA,EAAI,KAAa,GAAG,KAAK,MAAMA,EAAI,EAAE,CAAC,IACnC,GAAG,KAAK,MAAMA,EAAI,IAAI,CAAC,GAChC,CAEO,SAASC,GAAQD,EAAmB,CACzC,IAAME,EAAI,KAAK,MAAMF,EAAI,IAAI,EAC3BG,EAAI,KAAK,MAAOH,EAAI,KAAQ,EAAE,EAChC,OAAOE,EAAI,EAAI,GAAGA,CAAC,KAAKC,CAAC,IAAM,GAAGA,CAAC,KAAK,KAAK,MAAMH,EAAI,EAAE,CAAC,GAC5D,CAEO,SAASI,GAAQC,EAAgC,CACtD,GAAIA,GAAW,MAAQ,CAAC,SAASA,CAAO,EAAG,MAAO,KAClD,IAAMC,EAAO,KAAK,MAAMD,EAAU,EAAE,EAC9BE,EAAO,KAAK,MAAMF,EAAU,EAAE,EACpC,MAAO,GAAGC,CAAI,IAAIC,EAAK,SAAS,EAAE,SAAS,EAAG,GAAG,CAAC,EACpD,CAEO,SAASC,GAAQC,EAAoC,CAC1D,IAAMC,EAAI,IAAI,KAAKD,CAAE,EACrB,OAAI,MAAMC,EAAE,QAAQ,CAAC,EAAU,eACxBA,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,CACrC,CAEO,SAASC,GAAYF,EAAoC,CAC9D,IAAMC,EAAI,IAAI,KAAKD,CAAE,EACrB,GAAI,MAAMC,EAAE,QAAQ,CAAC,EAAG,MAAO,UAC/B,IAAME,EAAMF,EAAE,YAAY,EAC1B,MAAO,GAAGE,EAAI,MAAM,GAAG,EAAE,CAAC,CAAC,IAAIA,EAAI,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,EAAG,CAAC,CAAC,EAC9D,CAEO,SAASC,GAAYC,EAAuB,CACjD,GAAIA,IAAU,EAAG,MAAO,MACxB,IAAMC,EAAI,KACJC,EAAQ,CAAC,IAAK,KAAM,KAAM,IAAI,EAC9BC,EAAI,KAAK,MAAM,KAAK,IAAIH,CAAK,EAAI,KAAK,IAAIC,CAAC,CAAC,EAClD,MAAO,GAAG,YAAYD,EAAQ,KAAK,IAAIC,EAAGE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAID,EAAMC,CAAC,CAAC,EACvE,CAEO,SAASC,GAAQC,EAAqB,CAC3C,OAAO,OAAOA,CAAG,EACd,QAAQ,KAAM,OAAO,EACrB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,QAAQ,CAC3B,CAEO,SAASC,GAAYC,EAAsB,CAChD,IAAIC,EAAO,EACX,QAASL,EAAI,EAAGA,EAAII,EAAK,OAAQJ,IAAKK,EAAOD,EAAK,WAAWJ,CAAC,IAAMK,GAAQ,GAAKA,GAGjF,MAAO,OADG,KAAK,IAAIA,EAAO,GAAG,CACd,aACjB,CAMO,SAASC,GAAeC,EAAyBC,EAAgB,EAAsB,CAC5F,GAAIA,GAAS,EAAG,OAAOD,EAEvB,IAAME,EAAO,KAAK,KAAKD,EAAQ,CAAC,EAAI,EAAI,EAClCE,EAAS,IAAI,aAAaD,CAAI,EAC9BE,EAAO,KAAK,MAAMF,EAAO,CAAC,EAC5BG,EAAM,EAEV,QAASZ,EAAI,EAAGA,EAAIS,EAAMT,IAAK,CAC7B,IAAMa,EAAIb,EAAIW,EACdD,EAAOV,CAAC,EAAI,KAAK,IAAI,EAAEa,EAAIA,IAAM,EAAIL,EAAQA,EAAM,EACnDI,GAAOF,EAAOV,CAAC,CACjB,CACA,QAASA,EAAI,EAAGA,EAAIS,EAAMT,IAAKU,EAAOV,CAAC,GAAKY,EAE5C,IAAME,EAA4B,IAAI,MAAMP,EAAK,MAAM,EACvD,QAASP,EAAI,EAAGA,EAAIO,EAAK,OAAQP,IAAK,CACpC,GAAIO,EAAKP,CAAC,IAAM,KAAM,CACpBc,EAAOd,CAAC,EAAI,KACZ,QACF,CAEA,IAAIe,EAAM,EACNC,EAAY,EAChB,QAASlB,EAAI,EAAGA,EAAIW,EAAMX,IAAK,CAC7B,IAAMmB,EAAMjB,EAAIF,EAAIa,EAChBM,GAAO,GAAKA,EAAMV,EAAK,QAAUA,EAAKU,CAAG,IAAM,OACjDF,GAAOR,EAAKU,CAAG,EAAKP,EAAOZ,CAAC,EAC5BkB,GAAaN,EAAOZ,CAAC,EAEzB,CACAgB,EAAOd,CAAC,EAAIgB,EAAY,EAAID,EAAMC,EAAYT,EAAKP,CAAC,CACtD,CACA,OAAOc,CACT,CAEO,SAASI,GAAUC,EAAaC,EAAgB,EAAW,CAChE,IAAMC,EAAI,SAASF,EAAI,MAAM,EAAG,CAAC,EAAG,EAAE,EAChCG,EAAI,SAASH,EAAI,MAAM,EAAG,CAAC,EAAG,EAAE,EAChCI,EAAI,SAASJ,EAAI,MAAM,EAAG,CAAC,EAAG,EAAE,EACtC,MAAO,QAAQE,CAAC,KAAKC,CAAC,KAAKC,CAAC,KAAKH,CAAK,GACxC,CD5BO,SAASI,GAAgBC,EAAmB,CACjD,GAAI,CAACA,EAAI,OAAQ,OAAO,KACxB,IAAIC,EAASD,EAAI,CAAC,EAAE,IAChBE,EAASF,EAAI,CAAC,EAAE,IAChBG,EAASH,EAAI,CAAC,EAAE,IAChBI,EAASJ,EAAI,CAAC,EAAE,IACpB,QAAWK,KAAKL,EACVK,EAAE,IAAMJ,IAAQA,EAASI,EAAE,KAC3BA,EAAE,IAAMH,IAAQA,EAASG,EAAE,KAC3BA,EAAE,IAAMF,IAAQA,EAASE,EAAE,KAC3BA,EAAE,IAAMD,IAAQA,EAASC,EAAE,KAEjC,MAAO,CAAE,OAAAJ,EAAQ,OAAAC,EAAQ,OAAAC,EAAQ,OAAAC,CAAO,CAC1C,CAEA,IAAME,GAAe,MACfC,GAAe,IAAI,aAAaD,EAAY,EAC5CE,GAAe,IAAI,aAAaF,EAAY,EAC5CG,GAAe,IAAI,aAAaH,EAAY,EAC5CI,GAAgB,IAAI,aAAaJ,EAAY,EAC7CK,GAAe,IAAI,aAAaL,EAAY,EAC5CM,GAAe,IAAI,aAAaN,EAAY,EAC5CO,GAAe,IAAI,aAAaP,EAAY,EAE3C,SAASQ,GAAcd,EAAmBe,EAAyC,CACxF,IAAMC,EAAIhB,EAAI,OACd,GAAIgB,GAAK,EAAG,OAAOhB,EAInB,IAAMiB,EAAOD,GAAKV,GAAeC,GAAe,IAAI,aAAaS,CAAC,EAC5DE,EAAOF,GAAKV,GAAeE,GAAe,IAAI,aAAaQ,CAAC,EAC5DG,EAAOH,GAAKV,GAAeG,GAAe,IAAI,aAAaO,CAAC,EAC5DI,EAAQJ,GAAKV,GAAeI,GAAgB,IAAI,aAAaM,CAAC,EACpE,QAASK,EAAI,EAAGA,EAAIL,EAAGK,IAAK,CAC1B,IAAMhB,EAAIL,EAAIqB,CAAC,EACfJ,EAAKI,CAAC,EAAIhB,EAAE,IACZa,EAAKG,CAAC,EAAIhB,EAAE,IACZc,EAAKE,CAAC,EAAIhB,EAAE,KAAO,EACnBe,EAAMC,CAAC,EAAIhB,EAAE,MAAQ,CACvB,CAEA,IAAMiB,EAAa,CAAC,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAG,EAC5CC,EAAc,EACZC,EAAW,oBACjB,QAASC,EAAK,EAAGA,EAAKH,EAAW,OAAQG,IAAM,CAC7C,IAAMC,GAAYJ,EAAWG,CAAE,EAAI,OAAS,EACxCE,EAAS,EACb,QAASN,EAAI,EAAGA,EAAIL,EAAI,EAAGK,IAAK,CAC9B,IAAMO,EAAS,KAAK,IAAIX,EAAKI,CAAC,EAAIG,CAAQ,EACpCK,GAAMX,EAAKG,CAAC,EAAIH,EAAKS,CAAM,GAAKC,EAChCE,EAAKb,EAAKI,CAAC,EAAIJ,EAAKU,CAAM,EAC1BI,GAAMZ,EAAKE,CAAC,EAAIF,EAAKQ,CAAM,GAAK,KAEtC,GADYE,EAAKA,EAAKC,EAAKA,EAAKC,EAAKA,GAC1BL,EAAU,CACnB,IAAMM,EAAOL,EAASN,GAAM,EACtBY,GAAMf,EAAKc,CAAG,GAAKd,EAAKS,CAAM,EAAIT,EAAKG,CAAC,GAAK,IAAOO,EACpDM,EAAKjB,EAAKe,CAAG,GAAKf,EAAKU,CAAM,EAAIV,EAAKI,CAAC,GAAK,GAClDE,GAAe,KAAK,KAAKU,EAAKA,EAAKC,EAAKA,CAAE,GAAKd,EAAMC,CAAC,EAAID,EAAMO,CAAM,GAAK,KAC3EA,EAASN,CACX,CACF,CACF,CAEA,IAAMc,EAAuB,CAACnC,EAAI,CAAC,CAAC,EAChCoC,EAAYpC,EAAI,CAAC,EACfqC,EAAUd,EAAc,KAAO,KAAO,EAC5C,QAASF,EAAI,EAAGA,EAAIL,EAAI,EAAGK,IAAK,CAC9B,IAAMhB,EAAIL,EAAIqB,CAAC,GAEbhB,EAAE,MAAQ,MAAQ+B,EAAU,MAAQ,KAChC/B,EAAE,KAAO+B,EAAU,KACnBE,GAAUF,EAAU,IAAKA,EAAU,IAAK/B,EAAE,IAAKA,EAAE,GAAG,GAClDgC,GAAWtB,IACjBoB,EAAO,KAAK9B,CAAC,EACb+B,EAAY/B,EAEhB,CACA,OAAA8B,EAAO,KAAKnC,EAAIgB,EAAI,CAAC,CAAC,EACfmB,CACT,CAEO,IAAMI,IAAW,IAAM,CAE5B,SAASC,EAAaxC,EAAiC,CACrD,IAAMgB,EAAIhB,EAAI,OACVyC,EAAY,EAChB,QAASpB,EAAI,EAAGA,EAAIL,EAAGK,IAAK,CAC1B,IAAMhB,EAAIL,EAAIqB,CAAC,EACf,GAAIA,EAAI,EAAG,CACT,IAAMqB,EAAO1C,EAAIqB,EAAI,CAAC,EAChBsB,EAAIL,GAAUI,EAAK,IAAKA,EAAK,IAAKrC,EAAE,IAAKA,EAAE,GAAG,EAIpD,GAHAoC,GAAaE,EAGTtC,EAAE,OAAS,MAAQA,EAAE,MAAQ,MAAQqC,EAAK,MAAQ,KAAM,CAC1D,IAAME,GAAMvC,EAAE,KAAOqC,EAAK,MAAQ,IAC9BE,EAAK,GAAKA,EAAK,KAEjBvC,EAAE,MAAQsC,EAAIC,EAElB,CAGA,GAAIvC,EAAE,WAAa,QAAaA,EAAE,KAAO,MAAQqC,EAAK,KAAO,KAAM,CACjE,IAAMG,EAAKxC,EAAE,IAAMqC,EAAK,IACpBC,EAAI,GAENtC,EAAE,SAAYwC,EAAKF,EAAK,IAExBtC,EAAE,SAAWqC,EAAK,UAAY,CAElC,CACF,CACArC,EAAE,KAAOoC,CACX,CAGA,GAAIzB,EAAI,EAAG,CACT,IAAM8B,EAAS9B,GAAKV,GAAeK,GAAe,IAAI,aAAaK,CAAC,EAC9D+B,EAAS/B,GAAKV,GAAeM,GAAe,IAAI,aAAaI,CAAC,EAC9DgC,EAAShC,GAAKV,GAAeO,GAAe,IAAI,aAAaG,CAAC,EACpE,QAASK,GAAI,EAAGA,GAAIL,EAAGK,KACrByB,EAAOzB,EAAC,EAAIrB,EAAIqB,EAAC,EAAE,KAAO,EAC1B0B,EAAO1B,EAAC,EAAIrB,EAAIqB,EAAC,EAAE,OAAS,EAC5B2B,EAAO3B,EAAC,EAAIrB,EAAIqB,EAAC,EAAE,OAAS,EAE9B,IAAM4B,EAAe,CAAC,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,EAAE,EAC9CC,EAAU,EACRC,GAAS,EAAI,KACnB,QAASC,GAAK,EAAGA,GAAKH,EAAa,OAAQG,KAAM,CAC/C,IAAMC,GAAIJ,EAAaG,EAAE,EACnBE,GAAO,EAAID,GACbE,EAAO,EACPC,EAAO,EACX,QAASnC,GAAI,EAAGA,GAAIL,EAAGK,KAGrB,GAFAkC,GAAQR,EAAO1B,EAAC,EAChBmC,GAAQR,EAAO3B,EAAC,EACZA,IAAKgC,GAAG,CACVE,GAAQR,EAAO1B,GAAIgC,EAAC,EACpBG,GAAQR,EAAO3B,GAAIgC,EAAC,EACpB,IAAMI,EAAOF,EAAOD,GACdT,GAAKC,EAAOzB,EAAC,EAAIyB,EAAOzB,GAAIgC,EAAC,EAC7BK,GAAa,MAAQ,KAAK,IAAI,CAACZ,EAAOzB,EAAC,EAAI8B,EAAM,EACjDQ,GAAa,KAAK,MAAMd,IAAKW,EAAO,GAAK,EAAG,EAClDN,GAAWO,EAAOA,EAAOC,GAAa,KAAOC,IAAcH,EAAOF,IAAQ,GAC5E,CAEJ,CACA,IAAMM,GAAaV,EAAU,MAAQ,KAAO,EAC5C,QAAS7B,GAAI,EAAGA,GAAIL,EAAI,EAAGK,KACrBrB,EAAIqB,EAAC,EAAE,UAAY,MAAQrB,EAAIqB,GAAI,CAAC,EAAE,UAAY,MAAQrB,EAAIqB,GAAI,CAAC,EAAE,UAAY,OACnFrB,EAAIqB,EAAC,EAAE,UACJrB,EAAIqB,GAAI,CAAC,EAAE,SAAYrB,EAAIqB,EAAC,EAAE,SAAYrB,EAAIqB,GAAI,CAAC,EAAE,UAAa,EAAIuC,GAG/E,CAEA,OAAO5D,CACT,CAGA,IAAI6D,EAAmB,CAAC,IAAK,IAAK,IAAK,GAAG,EACtCC,EAAM,IAEV,SAASC,EAAa/D,EAAmBgE,EAAgB,GAAmB,CAC1E,IAAMC,EAAoB,CACxB,UAAW,EACX,SAAU,EACV,SAAU,EACV,SAAU,KACV,SAAU,KACV,SAAU,EACV,SAAU,KACV,SAAU,EACV,MAAO,KACP,MAAO,EACP,WAAY,KACZ,QAAS,KACT,QAAS,KACT,QAAS,KACT,QAAS,CAAC,EACV,UAAWjE,EAAI,OAASA,EAAI,CAAC,EAAE,KAAO,IACxC,EAEA,GAAI,CAACA,EAAI,OAAQ,OAAOiE,EAExB,IAAIC,EAAW,EACbC,EAAS,EACPC,EAAQ,EACVC,EAAM,EACJC,EAAS,EACXC,GAAO,EACLC,GAAW,EACbC,GAAS,EACPC,GAAa,EACfC,GAAW,EACTC,EAAU,EACZC,EAAQ,EACNC,GAAU,GACVC,EAAS,EACTC,GAAW,GAEf,QAAS3D,GAAI,EAAGA,GAAIrB,EAAI,OAAQqB,KAAK,CACnC,IAAMhB,GAAIL,EAAIqB,EAAC,EACf,GAAIA,GAAI,EAAG,CACT,IAAMqB,GAAO1C,EAAIqB,GAAI,CAAC,EACtB,GAAIhB,GAAE,KAAO,MAAQqC,GAAK,KAAO,KAAM,CACrC,IAAMuC,GAAO5E,GAAE,IAAMqC,GAAK,IACtBuC,GAAO,EAAGhB,EAAM,UAAYgB,GAC3BhB,EAAM,UAAYgB,EACzB,EAEG5E,GAAE,WAAa,MAAQA,GAAE,YAAcqC,GAAK,WAC5CrC,GAAE,UAAY,MAAQA,GAAE,WAAaqC,GAAK,WAE3CqC,GACJ,CACI1E,GAAE,OAAS,OACb6D,GAAY7D,GAAE,MACd8D,IACI9D,GAAE,MAAQ4D,EAAM,WAAUA,EAAM,SAAW5D,GAAE,QAE/CA,GAAE,IAAM,OACV+D,GAAS/D,GAAE,GACXgE,IACIhE,GAAE,GAAK4D,EAAM,QAAOA,EAAM,MAAQ5D,GAAE,KAEtCA,GAAE,KAAO,OACXiE,GAAUjE,GAAE,IACZkE,MAEElE,GAAE,OAAS,OACbmE,IAAYnE,GAAE,MACdoE,KACIpE,GAAE,MAAQ4D,EAAM,WAAUA,EAAM,SAAW5D,GAAE,QAE/CA,GAAE,SAAW,OACfqE,IAAcrE,GAAE,QAChBsE,MAEEtE,GAAE,MAAQ,OACZyE,GAAU,GACVF,GAAWvE,GAAE,KACbwE,KACIZ,EAAM,SAAW,MAAQ5D,GAAE,KAAO4D,EAAM,WAASA,EAAM,QAAU5D,GAAE,OACnE4D,EAAM,SAAW,MAAQ5D,GAAE,KAAO4D,EAAM,WAASA,EAAM,QAAU5D,GAAE,QAErEA,GAAE,WAAa,MAAQA,GAAE,UAAY,QAAM2E,GAAW,GAC5D,CAEAf,EAAM,UAAYjE,EAAIA,EAAI,OAAS,CAAC,EAAE,MAAQ,EAC9CiE,EAAM,SAAWE,EAAS,KAAK,MAAMD,EAAWC,CAAM,EAAI,KAC1DF,EAAM,MAAQI,EAAM,KAAK,MAAMD,EAAQC,CAAG,EAAI,KAC9CJ,EAAM,WAAaM,GAAO,KAAK,MAAMD,EAASC,EAAI,EAAI,KACtDN,EAAM,SAAWQ,GAASD,GAAWC,GAAS,KAC9CR,EAAM,WAAaU,GAAW,KAAK,MAAMD,GAAaC,EAAQ,EAAI,KAClEV,EAAM,QAAUY,EAAQ,QAAQD,EAAUC,GAAO,QAAQ,CAAC,CAAC,EAAI,KAC/DZ,EAAM,OAASe,GAAWD,EAAS,KAEnC,IAAMG,GAAKlF,EAAI,CAAC,EAAE,KACZmF,GAAKnF,EAAIA,EAAI,OAAS,CAAC,EAAE,KAC/B,OAAIkF,IAAM,MAAQC,IAAM,OAAMlB,EAAM,SAAWkB,GAAKD,IAEhDb,IACFJ,EAAM,QAAQ,KAAK,YAAY,EAC3BD,IACFC,EAAM,QAAUmB,EAAiBpF,CAAG,EACpCiE,EAAM,QAAUoB,EAAiBrF,CAAG,IAGpCuE,IAAMN,EAAM,QAAQ,KAAK,SAAS,EAClCE,IACFF,EAAM,QAAQ,KAAK,OAAO,EACtBD,IACFC,EAAM,WAAaqB,EAAoBtF,CAAG,EAC1CiE,EAAM,WAAasB,EAAoBvF,CAAG,IAG1C8E,IAASb,EAAM,QAAQ,KAAK,aAAa,EACzCe,IAAUf,EAAM,QAAQ,KAAK,UAAU,EACvCU,IAAUV,EAAM,QAAQ,KAAK,SAAS,EAEnCA,CACT,CAEA,SAASuB,EAAqBC,EAAyB,CACrD,GAAI,CAACA,GAAS,CAACA,EAAM,QAAU,CAACA,EAAM,MAAO,OAC7C,IAAMzF,EAAMyF,EAAM,OACZC,EAAID,EAAM,MACZC,EAAE,OAAS,MAAQ,CAACA,EAAE,UACxBA,EAAE,QAAUN,EAAiBpF,CAAG,EAChC0F,EAAE,QAAUL,EAAiBrF,CAAG,GAE9B0F,EAAE,UAAY,MAAQ,CAACA,EAAE,aAC3BA,EAAE,WAAaJ,EAAoBtF,CAAG,EACtC0F,EAAE,WAAaH,EAAoBvF,CAAG,EAE1C,CAEA,SAAS2F,EAAqB3F,EAA0C,CACtE,IAAMgB,EAAIhB,EAAI,OACd,GAAIgB,EAAI,EAAG,MAAO,CAAC,EACnB,IAAM4E,EAAkC,CAAC,EAGnCC,EAAgB,CACpB,oBACA,sBACA,kBACA,kBACF,EACA,QAASC,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,IAAMC,GAAO,KAAK,MAAOD,EAAI9E,EAAK,CAAC,EAC7BgF,GAAO,KAAK,IAAIhF,EAAI,EAAG,KAAK,OAAQ8E,EAAI,GAAK9E,EAAK,CAAC,EAAI,CAAC,EAC9D,GAAIgF,GAAOD,GAAM,CACf,IAAME,GAASjG,EAAI,MAAM+F,GAAMC,GAAO,CAAC,EACvCJ,EAAS,KAAK,CACZ,GAAI,IAAIE,EAAI,CAAC,GACb,MAAOD,EAAcC,CAAC,EACtB,KAAM,UACN,SAAUC,GACV,OAAQC,GACR,MAAOjC,EAAakC,GAAQ,EAAI,CAClC,CAAC,CACH,CACF,CAGA,IAAMC,EAAc,CAAC,gBAAiB,eAAgB,aAAa,EACnE,QAASC,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,IAAMJ,GAAO,KAAK,MAAOI,EAAInF,EAAK,CAAC,EAC7BgF,GAAO,KAAK,IAAIhF,EAAI,EAAG,KAAK,OAAQmF,EAAI,GAAKnF,EAAK,CAAC,EAAI,CAAC,EAC9D,GAAIgF,GAAOD,GAAM,CACf,IAAME,GAASjG,EAAI,MAAM+F,GAAMC,GAAO,CAAC,EACvCJ,EAAS,KAAK,CACZ,GAAI,IAAIO,EAAI,CAAC,GACb,MAAOD,EAAYC,CAAC,EACpB,KAAM,QACN,SAAUJ,GACV,OAAQC,GACR,MAAOjC,EAAakC,GAAQ,EAAK,CACnC,CAAC,CACH,CACF,CAGA,IAAIG,EAAa,EACbC,EAAe,IACfC,EAAU,EACd,QAASjF,EAAI,EAAGA,EAAIL,EAAGK,IAErB,IADUrB,EAAIqB,CAAC,EAAE,MAAQ,IAChBgF,GAAgBhF,IAAML,EAAI,EAAG,CACpC,GAAIK,EAAI+E,EAAa,EAAG,CACtB,IAAMG,GAAQvG,EAAI,MAAMoG,EAAY/E,EAAI,CAAC,EACzCuE,EAAS,KAAK,CACZ,GAAI,MAAMU,CAAO,GACjB,MAAO,MAAMA,CAAO,GACpB,KAAM,KACN,SAAUF,EACV,OAAQ/E,EACR,MAAO0C,EAAawC,GAAO,EAAK,CAClC,CAAC,EACDD,GACF,CACAF,EAAa/E,EACbgF,GAAgB,GAClB,CAIF,IAAMG,GAAM,GACRC,GAAU,GACVC,GAAa,EACbC,GAAW,EACXC,GAAW,GACXC,EAAc,EACdC,EAAY,EACVC,GAAkBjD,EAAM,KAE9B,QAASzC,EAAImF,GAAKnF,EAAIL,EAAGK,IAAK,CAC5B,IAAM2F,IAAQhH,EAAIqB,CAAC,EAAE,KAAO,IAAMrB,EAAIqB,EAAImF,EAAG,EAAE,KAAO,GAChDS,GAAQ,KAAK,IAAI,GAAIjH,EAAIqB,CAAC,EAAE,MAAQ,IAAMrB,EAAIqB,EAAImF,EAAG,EAAE,MAAQ,EAAE,EACjEU,GAAgBF,GAAOC,GAAS,IAEtC,GAAIC,IAAgB,KAAO,CAACT,GAC1BA,GAAU,GACVC,GAAarF,EAAImF,YACPU,GAAe,IAAO7F,IAAML,EAAI,IAAMyF,KAChDA,GAAU,GACNpF,EAAIqF,IAAc,IAAMC,IAAY,GAAG,CACzC,IAAMQ,GAASnH,EAAI,MAAM0G,GAAYrF,EAAI,CAAC,EAC1CuE,EAAS,KAAK,CACZ,GAAI,SAASe,EAAQ,GACrB,MAAO,iBAAiBA,EAAQ,GAChC,KAAM,QACN,SAAUD,GACV,OAAQrF,EACR,MAAO0C,EAAaoD,GAAQ,EAAI,CAClC,CAAC,EACDR,IACF,CAGF,IAAMS,GAAMpH,EAAIqB,CAAC,EAAE,OAAS,EAC5B,GAAI+F,IAAOL,IAAmB,CAACH,GAC7BA,GAAW,GACXC,EAAcxF,WACJ+F,GAAML,GAAkB,IAAO1F,IAAML,EAAI,IAAM4F,KACzDA,GAAW,GACPvF,EAAIwF,GAAe,IAAMC,GAAa,GAAG,CAC3C,IAAMK,GAASnH,EAAI,MAAM6G,EAAaxF,EAAI,CAAC,EAC3CuE,EAAS,KAAK,CACZ,GAAI,UAAUkB,CAAS,GACvB,MAAO,mBAAmBA,CAAS,GACnC,KAAM,SACN,SAAUD,EACV,OAAQxF,EACR,MAAO0C,EAAaoD,GAAQ,EAAI,CAClC,CAAC,EACDL,GACF,CAEJ,CAEA,OAAOlB,CACT,CAEA,SAASyB,EAAaC,EAAgD,CACpE,IAAMC,EAAkC,CAAC,EACzC,QAASlG,EAAI,EAAGA,EAAIiG,EAAW,OAAQjG,IAAK,CAC1C,IAAMmG,EAAKF,EAAWjG,CAAC,EACjBoG,EAAOD,EAAG,kBAAoBA,EAAG,OACjCE,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAMD,EAAK,OAAS,EAAE,CAAC,EACtD,QAASE,EAAItG,EAAI,EAAGsG,EAAIL,EAAW,OAAQK,IAAK,CAC9C,IAAMC,EAAKN,EAAWK,CAAC,EACjBE,GAAOD,EAAG,kBAAoBA,EAAG,OACjCE,GAAQ,KAAK,IAAI,EAAG,KAAK,MAAMD,GAAK,OAAS,EAAE,CAAC,EAClDE,GAAS,EACTC,GAAc,IAClB,QAASC,GAAI,EAAGA,GAAIR,EAAK,OAAQQ,IAAKP,EAAO,CAC3C,IAAMQ,EAAKT,EAAKQ,EAAC,EACbE,EAAU,IACd,QAASC,GAAI,EAAGA,GAAIP,GAAK,OAAQO,IAAKN,GAAO,CAC3C,IAAMO,EAAKR,GAAKO,EAAC,EACXzF,GAAIL,GAAU4F,EAAG,IAAKA,EAAG,IAAKG,EAAG,IAAKA,EAAG,GAAG,EAC9C1F,GAAIwF,IAASA,EAAUxF,GAC7B,CACIwF,EAAUH,KAAaA,GAAcG,GACrCA,GAAW,KAAKJ,IACtB,CACAR,EAAS,KAAK,CACZ,SAAUC,EAAG,GACb,SAAUI,EAAG,GACb,aAAcG,GACd,kBAAmB,OAAO,SAASC,EAAW,EAAI,KAAK,MAAMA,EAAW,EAAI,EAC5E,YAAaJ,EAAG,MAAM,UAAY,IAAMJ,EAAG,MAAM,UAAY,GAC7D,WAAY,SAASI,EAAG,MAAM,UAAY,IAAMJ,EAAG,MAAM,UAAY,IAAI,QAAQ,CAAC,CAAC,CACrF,CAAC,CACH,CACF,CACA,OAAOD,CACT,CAEA,IAAMe,EAA2B,CAC/B,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,KAAM,KAAM,KAAM,KAAM,MAAO,MAAO,KAAO,KACvF,EAEA,SAASC,EAAoBC,EAAgBC,EAAqB,CAChE,IAAMC,EAAMF,EAAK,OACjB,GAAIE,IAAQ,EAAG,OAAO,KACtB,IAAMC,EAAS,IAAI,aAAaD,EAAM,CAAC,EACvC,QAASrH,EAAI,EAAGA,EAAIqH,EAAKrH,IACvBsH,EAAOtH,EAAI,CAAC,EAAIsH,EAAOtH,CAAC,EAAImH,EAAKnH,CAAC,EAEpC,GAAIsH,EAAOD,CAAG,IAAM,EAAG,OAAO,KAE9B,IAAME,EAAsD,CAAC,EACzDC,EAAS,GAEb,QAASC,EAAK,EAAGA,EAAKL,EAAU,OAAQK,IAAM,CAC5C,IAAMnG,EAAI8F,EAAUK,CAAE,EACtB,GAAInG,EAAI+F,EAAK,SACb,IAAIK,GAAS,EACTC,GAAU,EACRC,GAAQP,EAAM/F,EAEpB,QAASgF,GAAI,EAAGA,IAAKsB,GAAOtB,KAAK,CAC/B,IAAMuB,GAAaP,EAAOhB,GAAIhF,CAAC,EAAIgG,EAAOhB,EAAC,EACvCuB,GAAaH,KACfA,GAASG,GACTF,GAAUrB,GAEd,CACAiB,EAAMjG,CAAC,EAAI,CAAE,IAAK,KAAK,MAAMoG,GAASpG,CAAC,EAAG,IAAKqG,EAAQ,EACvDH,EAAS,EACX,CAEA,OAAOA,EAASD,EAAQ,IAC1B,CAEA,SAAStD,EAAoBtF,EAAmB,CAC9C,IAAM0I,EAAM1I,EAAI,OACVmJ,EAAY,IAAI,MAAcT,CAAG,EACnCU,EAAU,GACd,QAAS/H,EAAI,EAAGA,EAAIqH,EAAKrH,IAAK,CAC5B,IAAMgI,EAAIrJ,EAAIqB,CAAC,EAAE,OAAS,EAC1B8H,EAAU9H,CAAC,EAAIgI,EACXA,IAAM,IAAGD,EAAU,GACzB,CACA,GAAI,CAACA,EAAS,OAAO,KACrB,IAAMR,EAAQL,EAAoBY,EAAWb,CAAwB,EACrE,GAAI,CAACM,EAAO,OAAO,KAEnB,IAAMzG,EAAyD,CAAC,EAChE,QAAWQ,KAAKiG,EAAOzG,EAAOQ,CAAC,EAAI,CAAE,MAAOiG,EAAMjG,CAAC,EAAE,IAAK,IAAKiG,EAAMjG,CAAC,EAAE,GAAI,EAE5E,OAAOR,CACT,CAEA,SAASkD,EAAiBrF,EAAmB,CAC3C,IAAM0I,EAAM1I,EAAI,OACVsJ,EAAS,IAAI,MAAcZ,CAAG,EAChCU,EAAU,GACd,QAAS/H,EAAI,EAAGA,EAAIqH,EAAKrH,IAAK,CAC5B,IAAMgI,EAAIrJ,EAAIqB,CAAC,EAAE,IAAM,EACvBiI,EAAOjI,CAAC,EAAIgI,EACRA,IAAM,IAAGD,EAAU,GACzB,CACA,GAAI,CAACA,EAAS,OAAO,KACrB,IAAMR,EAAQL,EAAoBe,EAAQhB,CAAwB,EAClE,GAAI,CAACM,EAAO,OAAO,KAEnB,IAAMzG,EAAsD,CAAC,EAC7D,QAAWQ,KAAKiG,EAAOzG,EAAOQ,CAAC,EAAI,CAAE,GAAIiG,EAAMjG,CAAC,EAAE,IAAK,IAAKiG,EAAMjG,CAAC,EAAE,GAAI,EAEzE,OAAOR,CACT,CAEA,SAASoD,EAAoBvF,EAAmB,CAC9C,IAAMuJ,EAAQ,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,EAC5BC,EAAa,CAAC,IAAM,IAAM,GAAK,KAAM,IAAK,GAAG,EAAE,IAAKrD,GAAMA,EAAIrC,CAAG,EAEvE,QAASzC,EAAI,EAAGA,EAAIrB,EAAI,OAAQqB,IAAK,CACnC,IAAMhB,EAAIL,EAAIqB,CAAC,EACTqB,EAAO1C,EAAIqB,EAAI,CAAC,EACtB,GAAIhB,EAAE,OAAS,MAAQA,EAAE,MAAQ,MAAQqC,EAAK,MAAQ,KAAM,SAE5D,IAAME,GAAMvC,EAAE,KAAOqC,EAAK,MAAQ,IAClC,GAAIE,GAAM,GAAKA,EAAK,GAAI,SAExB,IAAM6G,EAAKpJ,EAAE,MACToJ,EAAKD,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAK3G,EAC3B6G,EAAKD,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAK3G,EAChC6G,EAAKD,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAK3G,EAChC6G,EAAKD,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAK3G,EAChC6G,EAAKD,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAK3G,EAChC6G,EAAKD,EAAW,CAAC,EAAGD,EAAM,CAAC,GAAK3G,EACpC2G,EAAM,CAAC,GAAK3G,CACnB,CACA,OAAI2G,EAAM,MAAOG,GAAMA,IAAM,CAAC,EAAU,KACjCH,CACT,CAEA,SAASI,EAAOC,EAAa,CAC3B9F,EAAM8F,CACR,CAEA,SAASC,GAAS,CAChB,OAAO/F,CACT,CAEA,SAASsB,EAAiBpF,EAAmB,CAC3C,IAAMuJ,EAAQ,CAAC,EAAG,EAAG,EAAG,EAAG,CAAC,EAC5B,QAASlI,EAAI,EAAGA,EAAIrB,EAAI,OAAQqB,IAAK,CACnC,IAAMhB,EAAIL,EAAIqB,CAAC,EACTqB,EAAO1C,EAAIqB,EAAI,CAAC,EACtB,GAAIhB,EAAE,IAAM,MAAQA,EAAE,MAAQ,MAAQqC,EAAK,MAAQ,KAAM,SAEzD,IAAME,GAAMvC,EAAE,KAAOqC,EAAK,MAAQ,IAClC,GAAIE,GAAM,GAAKA,EAAK,GAAI,SAExB,IAAMkH,EAAKzJ,EAAE,GACTyJ,EAAKjG,EAAiB,CAAC,EAAG0F,EAAM,CAAC,GAAK3G,EACjCkH,EAAKjG,EAAiB,CAAC,EAAG0F,EAAM,CAAC,GAAK3G,EACtCkH,EAAKjG,EAAiB,CAAC,EAAG0F,EAAM,CAAC,GAAK3G,EACtCkH,EAAKjG,EAAiB,CAAC,EAAG0F,EAAM,CAAC,GAAK3G,EAC1C2G,EAAM,CAAC,GAAK3G,CACnB,CACA,OAAI2G,EAAM,MAAOG,GAAMA,IAAM,CAAC,EAAU,KACjCH,CACT,CAEA,SAASQ,EAAWP,EAAsB,CACxC3F,EAAmB2F,CACrB,CAEA,SAASQ,GAAa,CACpB,MAAO,CAAC,GAAGnG,CAAgB,CAC7B,CAEA,SAASoG,EAAcC,EAAeC,EAAiBC,EAAiC,CACtF,IAAM/I,EAAI6I,EAAM,QAAQC,CAAO,EAC/B,GAAI9I,IAAM,GAAI,OAAO,KACrB,IAAMgJ,EAAQhJ,EAAI8I,EAAQ,OACpBxC,EAAIuC,EAAM,QAAQE,EAAUC,CAAK,EACvC,GAAI1C,IAAM,GAAI,OAAO,KACrB,IAAMiC,EAAMM,EAAM,MAAMG,EAAO1C,CAAC,EAAE,KAAK,EACvC,OAAOiC,IAAQ,GAAKA,EAAM,IAC5B,CAEA,SAASU,EAAeC,EAAiBC,EAAmC,CAC1E,IAAMnJ,EAAIkJ,EAAQ,QAAQC,CAAU,EACpC,GAAInJ,IAAM,GAAI,OAAO,KACrB,IAAMgJ,EAAQhJ,EAAImJ,EAAW,OACvB7C,EAAI4C,EAAQ,QAAQ,IAAKF,CAAK,EACpC,OAAI1C,IAAM,GAAW,KACd4C,EAAQ,MAAMF,EAAO1C,CAAC,CAC/B,CAEA,IAAI8C,EAAgB,GAChBC,EAAc,EAElB,SAASC,EAAcC,EAAcP,EAAeQ,EAA4B,CAC9E,KAAOR,EAAQQ,GAAOD,EAAK,WAAWP,CAAK,GAAK,IAAIA,IACpD,KAAOQ,EAAMR,GAASO,EAAK,WAAWC,EAAM,CAAC,GAAK,IAAIA,IACtD,GAAIR,GAASQ,EAAK,OAAO,KACzB,IAAIC,EAAM,GACJC,EAAKH,EAAK,WAAWP,CAAK,EAC5BU,IAAO,IACTD,EAAM,GACNT,KACSU,IAAO,IAChBV,IAEF,IAAIT,EAAM,EACNoB,EAAS,EACb,QAAS3J,EAAIgJ,EAAOhJ,EAAIwJ,EAAKxJ,IAAK,CAChC,IAAM4J,GAAIL,EAAK,WAAWvJ,CAAC,EAC3B,GAAI4J,IAAK,IAAMA,IAAK,GAClBrB,EAAMA,EAAM,IAAMqB,GAAI,IACtBD,QAEA,MAEJ,CACA,OAAIA,IAAW,EAAU,KAClBF,EAAM,CAAClB,EAAMA,CACtB,CAEA,SAASsB,EAAgBN,EAAcP,EAAeQ,EAA4B,CAChF,KAAOR,EAAQQ,GAAOD,EAAK,WAAWP,CAAK,GAAK,IAAIA,IACpD,KAAOQ,EAAMR,GAASO,EAAK,WAAWC,EAAM,CAAC,GAAK,IAAIA,IACtD,GAAIR,GAASQ,EAAK,OAAO,KACzB,IAAIC,EAAM,GACJC,EAAKH,EAAK,WAAWP,CAAK,EAC5BU,IAAO,IACTD,EAAM,GACNT,KACSU,IAAO,IAChBV,IAEF,IAAIc,EAAU,EACVC,EAAW,EACXC,EAAU,EACVC,GAAS,GACTN,GAAS,EACb,QAAS3J,GAAIgJ,EAAOhJ,GAAIwJ,EAAKxJ,KAAK,CAChC,IAAM4J,GAAIL,EAAK,WAAWvJ,EAAC,EAC3B,GAAI4J,IAAK,IAAMA,IAAK,GAClBD,KACKM,IAEHF,EAAWA,EAAW,IAAMH,GAAI,IAChCI,GAAW,IAHAF,EAAUA,EAAU,IAAMF,GAAI,YAKlCA,KAAM,IAAM,CAACK,GACtBA,GAAS,OACJ,CACL,IAAMtK,EAAI,WAAW4J,EAAK,MAAMP,GAASS,EAAM,EAAI,GAAID,CAAG,CAAC,EAC3D,OAAO,OAAO,SAAS7J,CAAC,EAAIA,EAAI,IAClC,CACF,CACA,GAAIgK,KAAW,EAAG,OAAO,KACzB,IAAMO,GAAMJ,EAAUC,EAAWC,EACjC,OAAOP,EAAM,CAACS,GAAMA,EACtB,CAEA,SAASC,EAAmBZ,EAAcP,EAAeQ,EAA4B,CACnF,KAAOR,EAAQQ,GAAOD,EAAK,WAAWP,CAAK,GAAK,IAAIA,IACpD,KAAOQ,EAAMR,GAASO,EAAK,WAAWC,EAAM,CAAC,GAAK,IAAIA,IACtD,IAAMnC,EAAMmC,EAAMR,EAClB,GAAI3B,GAAO,IAAMkC,EAAK,WAAWP,EAAQ,EAAE,IAAM,IAAMO,EAAK,WAAWC,EAAM,CAAC,IAAM,GAAI,CACtF,IAAMY,GACHb,EAAK,WAAWP,CAAK,EAAI,IAAM,KAC/BO,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAAM,KACnCO,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAAM,IACnCO,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAC1BqB,GAAKd,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAAM,IAAMO,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAC3E1H,GAAKiI,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAAM,IAAMO,EAAK,WAAWP,EAAQ,CAAC,EAAI,IAC3EsB,GAAOF,GAAK,EAAMC,GAAK,EAAK/I,EAC9BgJ,KAAQlB,IACVA,EAAgBkB,GAChBjB,EAAc,KAAK,IAAIe,EAAGC,EAAI,EAAG/I,CAAC,GAEpC,IAAMiJ,IAAMhB,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAAM,IAAMO,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAC9EwB,IAAMjB,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAAM,IAAMO,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAC9EyB,IAAMlB,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAAM,IAAMO,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAChF0B,GAAK,EACT,OAAInB,EAAK,WAAWP,EAAQ,EAAE,IAAM,IAAM3B,GAAO,KAC/CqD,IACGnB,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAAM,KACpCO,EAAK,WAAWP,EAAQ,EAAE,EAAI,IAAM,IACpCO,EAAK,WAAWP,EAAQ,EAAE,EAAI,KAE5BK,EAAckB,GAAK,KAAUC,GAAK,IAAQC,GAAK,IAAOC,EAC/D,CACA,IAAM5F,EAAI,IAAI,KAAKyE,EAAK,MAAMP,EAAOQ,CAAG,CAAC,EAAE,QAAQ,EACnD,OAAO,OAAO,SAAS1E,CAAC,EAAIA,EAAI,IAClC,CAEA,SAAS6F,EAAiBpB,EAAcP,EAAeQ,EAAaL,EAA4B,CAC9F,IAAMnJ,EAAIuJ,EAAK,QAAQJ,EAAYH,CAAK,EACxC,GAAIhJ,IAAM,IAAMA,GAAKwJ,EAAK,MAAO,GACjC,IAAMoB,EAAS5K,EAAImJ,EAAW,OACxB7C,EAAIiD,EAAK,QAAQ,IAAKqB,CAAM,EAClC,OAAItE,IAAM,IAAMA,GAAKkD,EAAY,EAC1BK,EAAgBN,EAAMqB,EAAQtE,CAAC,GAAK,CAC7C,CAGA,SAASuE,EAASC,EAAkBC,EAA8B,CAChE,IAAMxB,EAAewB,GAAkB,IAAI,YAAY,EAAE,OAAOD,CAAG,EAC7DE,EAAazB,EAAK,QAAQ,QAAQ,EACxC,GAAIyB,IAAe,GAAI,MAAM,IAAI,MAAM,8BAA8B,EAErE,IAAMC,EAAS1B,EAAK,MAAM,EAAGyB,CAAU,EACjCE,EAASD,EAAO,QAAQ,OAAO,EAC/BE,GACHD,IAAW,GAAKtC,EAAcqC,EAAO,MAAMC,CAAM,EAAG,SAAU,SAAS,EAAI,OAC5EtC,EAAcqC,EAAQ,SAAU,SAAS,GACzC,gBAEIG,EAAaH,EAAO,QAAQ,IAAKA,EAAO,QAAQ,MAAM,CAAC,EACvDI,GACJD,IAAe,GAAKnC,EAAegC,EAAO,MAAM,EAAGG,EAAa,CAAC,EAAG,WAAW,EAAI,KAE/EE,GAAuB,CAAC,EAC1BC,GAAMP,EACV,KAAOO,GAAMhC,EAAK,QAAQ,CACxB,IAAMiC,EAAWjC,EAAK,QAAQ,SAAUgC,EAAG,EAC3C,GAAIC,IAAa,GAAI,MACrB,IAAMC,EAAUlC,EAAK,QAAQ,IAAKiC,EAAW,CAAC,EAC9C,GAAIC,IAAY,GAAI,MACpB,IAAMC,GAASnC,EAAK,QAAQ,WAAYkC,EAAU,CAAC,EACnD,GAAIC,KAAW,GAAI,MACnBH,GAAMG,GAAS,EAEf,IAAMC,EAAMhB,EAAiBpB,EAAMiC,EAAW,EAAGC,EAAU,EAAG,OAAO,EAC/DG,GAAMjB,EAAiBpB,EAAMiC,EAAW,EAAGC,EAAU,EAAG,OAAO,EAEjEI,GAAqB,KACrBC,GAAsB,KACtBrD,GAAoB,KACpBsD,GAAqB,KACrBC,GAAuB,KACvBC,GAAsB,KACtBC,GAAuB,KACvBC,GAA2B,KAC3BC,GAA0B,KAC1BC,EAAgC,KAChCC,EAA+B,KAC/BC,GAAyB,KAEzBvN,GAAIyM,EAAU,EAClB,KAAOzM,GAAI0M,IAAQ,CACjB,IAAMc,GAAKjD,EAAK,QAAQ,IAAKvK,EAAC,EAC9B,GAAIwN,KAAO,IAAMA,IAAMd,GAAQ,MAC/B,IAAMe,GAAKlD,EAAK,QAAQ,IAAKiD,GAAK,CAAC,EACnC,GAAIC,KAAO,IAAMA,IAAMf,GAAQ,MAC/B,IAAMgB,GAAKnD,EAAK,WAAWiD,GAAK,CAAC,EACjC,GAAIE,KAAO,GAAI,CACb1N,GAAIyN,GAAK,EACT,QACF,CAEA,IAAME,GAASF,GAAKD,GAAK,EACzB,GAAIE,KAAO,KAAOC,KAAW,IAAMlE,KAAO,MAAQsD,KAAQ,MAAQE,KAAS,KACzE,MAEF,IAAMW,GAASrD,EAAK,QAAQ,IAAKkD,GAAK,CAAC,EACvC,GAAIG,KAAW,IAAMA,GAASlB,GAAQ,MACtC,GAAInC,EAAK,WAAWqD,GAAS,CAAC,IAAM,GAAI,CACtC,IAAMhC,GAAS6B,GAAK,EACdI,GAAOD,GACTD,KAAW,EACTD,KAAO,IAAKb,GAAMhC,EAAgBN,EAAMqB,GAAQiC,EAAI,EAC/CH,KAAO,IAAMX,KAAQ,OAAMA,GAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,GACjEF,KAAW,EAChBD,KAAO,KAAOjE,KAAO,OAAMA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,GAC3DF,KAAW,EAChBD,KAAO,IACLnD,EAAK,WAAWiD,GAAK,CAAC,IAAM,IAAKV,GAAO3B,EAAmBZ,EAAMqB,GAAQiC,EAAI,EACxEZ,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GACxDH,KAAO,IAAMT,KAAS,OAC/BA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAElCF,KAAW,GACfD,KAAO,KAAOA,KAAO,IAAMA,KAAO,KAAOV,KAAU,KACtDA,GAAQnC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAClCH,KAAO,KAAOA,KAAO,KAAOR,KAAU,KAC9CA,GAAQrC,EAAgBN,EAAMqB,GAAQiC,EAAI,EACnCH,KAAO,IAAMT,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GACrEF,KAAW,GACfD,KAAO,IAAMA,KAAO,KAAOH,KAAY,KAC1CA,GAAUjD,EAAcC,EAAMqB,GAAQiC,EAAI,EACnCH,KAAO,IAAMX,KAAQ,OAAMA,GAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,GACjEF,KAAW,GACfD,KAAO,KAAOA,KAAO,KAAON,KAAa,OAC5CA,GAAW9C,EAAcC,EAAMqB,GAAQiC,EAAI,GACpCF,KAAW,EAChBD,KAAO,IACLnD,EAAK,WAAWiD,GAAK,CAAC,IAAM,KAAO/D,KAAO,KAC5CA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,EAC9BV,KAAc,OAAMA,GAAY7C,EAAcC,EAAMqB,GAAQiC,EAAI,GAChEH,KAAO,IAAMP,KAAc,OACpCA,GAAY7C,EAAcC,EAAMqB,GAAQiC,EAAI,GAErCF,KAAW,IAChBD,KAAO,KAAOX,KAAQ,MACjBW,KAAO,IAAMX,KAAQ,QAAMA,GAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,GACjEF,KAAW,GAChBD,KAAO,KAAOnD,EAAK,WAAWiD,GAAK,CAAC,IAAM,IAAMP,KAAS,KAC3DA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,EAClCH,KAAO,IAAMV,KAAU,KAAMA,GAAQnC,EAAgBN,EAAMqB,GAAQiC,EAAI,EACvEH,KAAO,IAAMjE,KAAO,OAAMA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,GAC/DF,KAAW,IACfD,KAAO,KAAOA,KAAO,KAAOJ,IAAkB,OACjDA,EAAgBhD,EAAcC,EAAMqB,GAAQiC,EAAI,GACzCF,KAAW,IACfD,KAAO,KAAOA,KAAO,KAAOL,IAAmB,KAClDA,EAAiB/C,EAAcC,EAAMqB,GAAQiC,EAAI,EAC1CH,KAAO,IAAMT,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GACrEF,KAAW,IAAMD,KAAO,IAAMT,KAAS,OAChDA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAE3C,IAAMC,GAAkBF,GAAS,EAAID,GACrC,GAAIpD,EAAK,WAAWuD,EAAe,IAAM,GACvC9N,GAAI8N,GAAkB,MACjB,CACL,IAAMC,GAAUxD,EAAK,QAAQ,IAAKqD,GAAS,CAAC,EAC5C5N,GAAI+N,KAAY,GAAKA,GAAU,EAAIH,GAAS,CAC9C,CACA,GAAIL,KAAY,MAAQ9D,KAAO,MAAQsD,KAAQ,MAAQE,KAAS,KAC9D,KAEJ,MACEjN,GAAI4N,EAER,CAEA,IAAII,GAAuB,KACvBX,GAAkB,MAAQC,GAAiB,MAAQA,IAAkB,EACvEU,GAAQX,EAAiBC,EAClBH,IAAa,MAAQC,IAAY,MAAQA,KAAa,IAC7DY,GAAQb,GAAYC,IAEtBd,GAAO,KAAK,CACV,IAAAK,EACA,IAAAC,GACA,IAAAC,GACA,KAAAC,GACA,GAAArD,GACA,IAAAsD,GACA,MAAAC,GACA,MAAAE,GACA,KAAAD,GACA,UAAAE,GACA,SAAAC,GACA,eAAAC,EACA,cAAAC,EACA,QAAAC,GACA,MAAAS,EACF,CAAC,CACH,CAEA,GAAI,CAAC1B,GAAO,OAAQ,MAAM,IAAI,MAAM,8BAA8B,EAElE,IAAM3M,GAAMwC,EAAamK,EAAM,EACzB1I,GAAQF,EAAa/D,EAAG,EAC9B,MAAO,CAAE,KAAAwM,EAAM,OAAAE,GAAQ,OAAQ,MAAO,OAAQ1M,GAAK,MAAAiE,EAAM,CAC3D,CAGA,SAASqK,EAASnC,EAAkBC,EAA8B,CAChE,IAAMxB,EAAewB,GAAkB,IAAI,YAAY,EAAE,OAAOD,CAAG,EAC7DoC,EAAU3D,EAAK,QAAQ,cAAc,EACrC0B,EAASiC,IAAY,GAAK3D,EAAK,MAAM,EAAG2D,CAAO,EAAI3D,EAEnD4B,EAAOvC,EAAcqC,EAAQ,OAAQ,OAAO,GAAK,cACjDkC,EAAevE,EAAcqC,EAAQ,YAAa,YAAY,EAC9DI,EAAS8B,EAAevE,EAAcuE,EAAc,SAAU,SAAS,EAAI,KAE3E7B,GAAuB,CAAC,EAC1BC,GAAM2B,IAAY,GAAKA,EAAU,EACrC,KAAO3B,GAAMhC,EAAK,QAAQ,CACxB,IAAM6D,GAAU7D,EAAK,QAAQ,eAAgBgC,EAAG,EAChD,GAAI6B,KAAY,GAAI,MACpB,IAAMC,EAAQ9D,EAAK,QAAQ,gBAAiB6D,GAAU,EAAE,EACxD,GAAIC,IAAU,GAAI,MAClB9B,GAAM8B,EAAQ,GAEd,IAAI1B,EAAqB,KACrBC,GAAqB,KACrBC,EAAqB,KACrBC,GAAsB,KACtBrD,GAAoB,KACpBsD,GAAqB,KACrBC,GAAuB,KACvBE,GAAuB,KACvBD,GAAsB,KACtBE,GAA2B,KAC3BC,GAA0B,KAC1BC,GAAgC,KAChCC,GAA+B,KAC/BC,EAAyB,KAEzBvN,EAAIoO,GAAU,GAClB,KAAOpO,EAAIqO,GAAO,CAChB,IAAMb,GAAKjD,EAAK,QAAQ,IAAKvK,CAAC,EAC9B,GAAIwN,KAAO,IAAMA,IAAMa,EAAO,MAC9B,IAAMZ,GAAKlD,EAAK,QAAQ,IAAKiD,GAAK,CAAC,EACnC,GAAIC,KAAO,IAAMA,IAAMY,EAAO,MAC9B,IAAMX,GAAKnD,EAAK,WAAWiD,GAAK,CAAC,EACjC,GAAIE,KAAO,GAAI,CACb1N,EAAIyN,GAAK,EACT,QACF,CACA,IAAME,GAASF,GAAKD,GAAK,EACnBI,GAASrD,EAAK,QAAQ,IAAKkD,GAAK,CAAC,EACvC,GAAIG,KAAW,IAAMA,GAASS,EAAO,MACrC,GAAI9D,EAAK,WAAWqD,GAAS,CAAC,IAAM,GAAI,CACtC,IAAMhC,GAAS6B,GAAK,EACdI,GAAOD,GACTD,KAAW,EACTD,KAAO,GACLnD,EAAK,WAAWiD,GAAK,CAAC,IAAM,IAAKV,GAAO3B,EAAmBZ,EAAMqB,GAAQiC,EAAI,EACxEZ,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GACxDH,KAAO,KAAOT,KAAS,OAChCA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAElCF,KAAW,EAChBD,KAAO,IAAMjE,KAAO,KAAMA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,GACzDH,KAAO,IAAMA,KAAO,IAAMA,KAAO,MAAQV,KAAU,KAC3DA,GAAQnC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAClCH,KAAO,IAAMA,KAAO,MAAQR,KAAU,KAC9CA,GAAQrC,EAAgBN,EAAMqB,GAAQiC,EAAI,EACnCH,KAAO,IAAMT,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GACrEF,KAAW,EAChBD,KAAO,IAAMX,KAAQ,KAAMA,GAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,GAC3DH,KAAO,IAAMA,KAAO,KAAOH,IAAY,OAC/CA,EAAUjD,EAAcC,EAAMqB,GAAQiC,EAAI,GACnCF,KAAW,GACfD,KAAO,IAAMA,KAAO,MAAQN,KAAa,OAC5CA,GAAW9C,EAAcC,EAAMqB,GAAQiC,EAAI,GACpCF,KAAW,GACfD,KAAO,IAAMA,KAAO,MAAQP,KAAc,OAC7CA,GAAY7C,EAAcC,EAAMqB,GAAQiC,EAAI,GACrCF,KAAW,GAChBD,KAAO,IAAMX,KAAQ,OAAMA,GAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,GAC5DF,KAAW,GAChBD,KAAO,IAAMT,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,GAChEF,KAAW,IACfD,KAAO,IAAMA,KAAO,MAAQJ,KAAkB,OACjDA,GAAgBhD,EAAcC,EAAMqB,GAAQiC,EAAI,GACzCF,KAAW,GAChBD,KAAO,GACLnD,EAAK,WAAWiD,GAAK,CAAC,IAAM,IAAKX,EAAMhC,EAAgBN,EAAMqB,GAAQiC,EAAI,EACpEZ,KAAS,OAAMA,GAAOpC,EAAgBN,EAAMqB,GAAQiC,EAAI,IACvDH,KAAO,IAAMA,KAAO,MAAQL,KAAmB,OACzDA,GAAiB/C,EAAcC,EAAMqB,GAAQiC,EAAI,GAE1CF,KAAW,GAChBD,KAAO,KAAIf,EAAM9B,EAAgBN,EAAMqB,GAAQiC,EAAI,GAC9CF,KAAW,GAChBD,KAAO,KAAId,GAAM/B,EAAgBN,EAAMqB,GAAQiC,EAAI,GAC9CF,KAAW,GAAKD,KAAO,KAAOjE,KAAO,KAC9CA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,EAC5BF,KAAW,GAAKD,KAAO,IAAMX,KAAQ,KAC9CA,GAAMzC,EAAcC,EAAMqB,GAAQiC,EAAI,EAC7BF,KAAW,KAChBD,KAAO,IAAMjE,KAAO,KAAMA,GAAKa,EAAcC,EAAMqB,GAAQiC,EAAI,EAC1DH,KAAO,IAAMV,KAAU,OAAMA,GAAQnC,EAAgBN,EAAMqB,GAAQiC,EAAI,IAElF,IAAMC,GAAkBF,GAAS,EAAID,GACrC,GAAIpD,EAAK,WAAWuD,EAAe,IAAM,GACvC9N,EAAI8N,GAAkB,MACjB,CACL,IAAMC,GAAUxD,EAAK,QAAQ,IAAKqD,GAAS,CAAC,EAC5C5N,EAAI+N,KAAY,GAAKA,GAAU,EAAIH,GAAS,CAC9C,CACA,GAAIL,IAAY,MAAQ9D,KAAO,MAAQsD,KAAQ,MAAQE,KAAS,KAC9D,KAEJ,MACEjN,EAAI4N,EAER,CAEA,GAAIjB,GAAO,MAAQC,IAAO,KAAM,SAEhC,IAAIoB,GAAuB,KACvBX,IAAkB,MAAQC,IAAiB,MAAQA,KAAkB,EACvEU,GAAQX,GAAiBC,GAClBH,IAAa,MAAQC,IAAY,MAAQA,KAAa,IAC7DY,GAAQb,GAAYC,IAEtBd,GAAO,KAAK,CACV,IAAAK,EACA,IAAAC,GACA,IAAAC,EACA,KAAAC,GACA,GAAArD,GACA,IAAAsD,GACA,MAAAC,GACA,MAAAE,GACA,KAAAD,GACA,UAAAE,GACA,SAAAC,GACA,eAAAC,GACA,cAAAC,GACA,QAAAC,EACA,MAAAS,EACF,CAAC,CACH,CAEA,IAAMrO,GAAMwC,EAAamK,EAAM,EACzB1I,GAAQF,EAAa/D,EAAG,EAC9B,MAAO,CAAE,KAAAwM,EAAM,OAAAE,EAAQ,OAAQ,MAAO,OAAQ1M,GAAK,MAAAiE,EAAM,CAC3D,CAEA,SAAS0K,EAAkBxC,EAA8B,CACvD,GAAIA,EAAI,WAAa,GAAI,OAAO,KAChC,IAAMyC,EAAK,IAAI,SAASzC,CAAG,EACrB0C,EAAaD,EAAG,SAAS,CAAC,EAEhC,GADIC,EAAa,IAAMA,EAAa,EAAI1C,EAAI,YAE1CyC,EAAG,SAAS,CAAC,IAAM,IACnBA,EAAG,SAAS,CAAC,IAAM,IACnBA,EAAG,SAAS,EAAE,IAAM,IACpBA,EAAG,SAAS,EAAE,IAAM,GAEpB,OAAO,KAET,IAAME,EAAWF,EAAG,UAAU,EAAG,EAAI,EAC/BG,EAAY,KAAK,IAAI5C,EAAI,WAAY0C,EAAaC,CAAQ,EAC1DE,EAAmB,UACnBC,EAAoB,IAAM,KAAK,IAAI,EAAG,EAAE,EAaxCC,EAA+B,IAAI,MAAM,EAAE,EAC3CC,GAAkB,CAAC,EACnBC,GAAkB,CAAC,EACnBC,GAAiB,CAAC,EAClBC,GAAgB,CAAC,EACjBC,GAAsB,CAAC,EAEzBC,EAASX,EACb,KAAOW,EAAST,GAAW,CACzB,IAAMU,EAAMb,EAAG,SAASY,GAAQ,EAChC,GAAKC,EAAM,KAAgBA,EAAM,GAC/B,OAAO,KAET,IAAMC,GAAWD,EAAM,GACvB,GAAKA,EAAM,GAAa,CACtB,GAAID,EAAS,EAAIT,EAAW,OAAO,KACnCS,IAEA,IAAMG,GADOf,EAAG,SAASY,GAAQ,IACH,EACxBI,GAAehB,EAAG,UAAUY,EAAQG,EAAY,EACtDH,GAAU,EACV,IAAMK,GAAYjB,EAAG,SAASY,GAAQ,EACtC,GAAIA,EAASK,GAAY,EAAId,EAAW,OAAO,KAC/C,IAAMe,GAAqB,IAAI,MAAMD,EAAS,EAC1CE,GAAa,EACjB,QAAS1O,GAAI,EAAGA,GAAIwO,GAAWxO,KAAK,CAClC,IAAM2O,GAAMpB,EAAG,SAASY,GAAQ,EAC1BS,GAAOrB,EAAG,SAASY,GAAQ,EAC3BU,GAAOtB,EAAG,SAASY,GAAQ,EACjCM,GAAOzO,EAAC,EAAI,CAAE,IAAA2O,GAAK,KAAAC,GAAM,KAAAC,EAAK,EAC9BH,IAAcE,EAChB,CACAf,EAAKQ,EAAQ,EAAI,CAAE,aAAAC,GAAc,aAAAC,GAAc,OAAAE,GAAQ,WAAAC,EAAW,CACpE,KAAO,CACL,IAAMI,EAAMjB,EAAKQ,EAAQ,EACzB,GAAI,CAACS,GAAOX,EAASW,EAAI,WAAapB,EAAW,OAAO,KACxD,IAAMqB,GAAKD,EAAI,aACTE,GAAOF,EAAI,aAEjB,GACEE,KAAS,IACTF,EAAI,OAAO,SAAW,IACtBA,EAAI,aAAe,IACnBA,EAAI,OAAO,CAAC,EAAE,MAAQ,KACtBA,EAAI,OAAO,CAAC,EAAE,MAAQ,EACtB,CACA,IAAMG,GAAK1B,EAAG,UAAUY,EAAQY,EAAE,EAC5BG,GAAS3B,EAAG,SAASY,EAAS,EAAGY,EAAE,EACnCI,GAAS5B,EAAG,SAASY,EAAS,EAAGY,EAAE,EACnCK,GAAS7B,EAAG,UAAUY,EAAS,GAAIY,EAAE,EACrCtG,GAAK8E,EAAG,SAASY,EAAS,EAAE,EAC5BpC,GAAMwB,EAAG,SAASY,EAAS,EAAE,EAC7BkB,EAAU9B,EAAG,UAAUY,EAAS,GAAIY,EAAE,EACtCO,EAAS/B,EAAG,UAAUY,EAAS,GAAIY,EAAE,EACrC/C,GAAQuB,EAAG,UAAUY,EAAS,GAAIY,EAAE,EACpC9C,GAAOsB,EAAG,QAAQY,EAAS,EAAE,EACnCH,GAAQ,KAAK,CACX,WAAYiB,GAAKtB,GAAoB,IACrC,aAAcuB,GAAStB,EACvB,cAAeuB,GAASvB,EACxB,SAAUwB,GAAS,EAAI,IACvB,WAAY3G,GACZ,QAASsD,GACT,SAAUsD,EAAU,IACpB,MAAQC,EAAS,IAAQ,IACzB,MAAAtD,GACA,YAAaC,EACf,CAAC,EACDkC,GAAU,GACV,QACF,CAEA,IAAMoB,GAAW,CAAC,EACdC,GAAOrB,EACX,QAASnO,GAAI,EAAGA,GAAI8O,EAAI,OAAO,OAAQ9O,KAAK,CAC1C,IAAMyP,GAAIX,EAAI,OAAO9O,EAAC,EAClBuI,GAAc,EACZmH,GAAQD,GAAE,KAAO,GACnBA,GAAE,OAAS,EACblH,GAAMmH,KAAU,EAAInC,EAAG,QAAQiC,EAAI,EAAIjC,EAAG,SAASiC,EAAI,EAC9CC,GAAE,OAAS,EACpBlH,GAAMmH,KAAU,EAAInC,EAAG,SAASiC,GAAMT,EAAE,EAAIxB,EAAG,UAAUiC,GAAMT,EAAE,EACxDU,GAAE,OAAS,IACpBlH,GAAMmH,KAAU,EAAInC,EAAG,SAASiC,GAAMT,EAAE,EAAIxB,EAAG,UAAUiC,GAAMT,EAAE,GAEnEQ,GAAIE,GAAE,GAAG,EAAIlH,GACbiH,IAAQC,GAAE,IACZ,CAGA,GAFAtB,GAAUW,EAAI,WAEVE,KAAS,EACXlB,GAAS,KAAK,CACZ,KAAMyB,GAAI,CAAC,IAAM,EAAI,WAAaA,GAAI,CAAC,EACvC,aAAcA,GAAI,CAAC,IAAM,EAAI,SAAWA,GAAI,CAAC,EAC7C,QAASA,GAAI,CAAC,EACd,aAAcA,GAAI,CAAC,GAAK,MAAQA,GAAI,CAAC,EAAI5B,GAAoB,IAAO,MACtE,CAAC,UACQqB,KAAS,GAAI,CACtB,IAAMW,GAAmC,CAAE,EAAG,UAAW,EAAG,UAAW,EAAG,SAAU,EACpF5B,GAAS,KAAK,CACZ,WAAYwB,GAAI,CAAC,GAAK,MAAQA,GAAI,CAAC,EAAI5B,GAAoB,IAAO,OAClE,MAAOgC,GAASJ,GAAI,CAAC,CAAC,GAAK,OAAOA,GAAI,CAAC,CAAC,EACxC,UAAWA,GAAI,CAAC,IAAM,EAAI,UAAY,OAAOA,GAAI,CAAC,CAAC,CACrD,CAAC,CACH,SAAWP,KAAS,GAClBhB,GAAQ,KAAK,CACX,UAAWuB,GAAI,GAAG,GAAK,MAAQA,GAAI,GAAG,EAAI5B,GAAoB,IAAO,OACrE,aAAc4B,GAAI,CAAC,GAAK,KAAOA,GAAI,CAAC,EAAI3B,EAAoB,OAC5D,cAAe2B,GAAI,CAAC,GAAK,KAAOA,GAAI,CAAC,EAAI3B,EAAoB,OAC7D,SAAU2B,GAAI,CAAC,GAAK,KAAOA,GAAI,CAAC,EAAI,EAAI,IAAM,OAC9C,WAAYA,GAAI,CAAC,EACjB,QAASA,GAAI,CAAC,EACd,SAAUA,GAAI,CAAC,GAAK,KAAOA,GAAI,CAAC,EAAI,IAAM,OAC1C,MAAOA,GAAI,CAAC,GAAK,KAAQA,GAAI,CAAC,EAAI,IAAQ,IAAM,OAChD,MAAOA,GAAI,CAAC,EACZ,YAAaA,GAAI,EAAE,CACrB,CAAC,UACQP,KAAS,GAAI,CACtB,IAAMY,GACJL,GAAI,CAAC,IAAM,GACP,mBACAA,GAAI,CAAC,IAAM,GACT,oBACA,OAAOA,GAAI,CAAC,CAAC,EACrBtB,GAAO,KAAK,CACV,UAAWsB,GAAI,GAAG,GAAK,MAAQA,GAAI,GAAG,EAAI5B,GAAoB,IAAO,OACrE,MAAOiC,GACP,WAAYL,GAAI,CAAC,IAAM,EAAI,SAAW,OAAOA,GAAI,CAAC,CAAC,EACnD,KAAMA,GAAI,CAAC,EACX,eAAgBA,GAAI,CAAC,EACrB,cAAeA,GAAI,EAAE,CACvB,CAAC,CACH,SAAWP,KAAS,GAClBd,GAAa,KAAK,CAChB,UAAWqB,GAAI,GAAG,GAAK,MAAQA,GAAI,GAAG,EAAI5B,GAAoB,IAAO,OACrE,cAAe4B,GAAI,EAAE,CACvB,CAAC,MAED,QAAO,IAEX,CACF,CACA,MAAO,CAAE,SAAAzB,GAAU,SAAAC,GAAU,OAAQ,CAAC,EAAG,QAAAC,GAAS,OAAAC,GAAQ,aAAAC,EAAa,CACzE,CAGA,SAAS2B,GAAS/E,EAAgC,CAChD,OAAO,IAAI,QAAQ,CAACgF,EAASC,IAAW,CACtC,IAAMC,EAAsB,CAACC,EAAY9I,IAAc,CACrD,GAAI8I,EAAO,CACTF,EAAOE,CAAK,EACZ,MACF,CACA,GAAI,CACF,IAAM9E,GAAOhE,EAAK,WAAW,CAAC,GAAG,WAC7B,gBAAgB,IAAI,KAAKA,EAAK,SAAS,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,GACjF,cAGAkE,GAAwB,KACtB6E,GAAwB,CAAC,EAC3BC,GAAuB,KACvBC,GAA0B,KAE1BjJ,EAAK,SAAS,CAAC,GACjBgJ,GAAQhJ,EAAK,OAAO,CAAC,EAAE,MACvBiJ,GAAWjJ,EAAK,OAAO,CAAC,EAAE,WACjBA,EAAK,WAAW,CAAC,IAC1BgJ,GAAQhJ,EAAK,SAAS,CAAC,EAAE,MACzBiJ,GAAWjJ,EAAK,SAAS,CAAC,EAAE,WAG9B,IAAMkJ,EAAiB/O,GACrBA,EAAE,cACFA,EAAE,gBACFA,EAAE,SACFA,EAAE,aACFA,EAAE,cACF,KAEF,GAAI6F,EAAK,WAAW,CAAC,EAAG,CACtB,IAAMmJ,EAAMnJ,EAAK,SAAS,CAAC,EAC3BkE,GAASgF,EAAcC,CAAG,EAC1BJ,GAAQ,KAAK,CACX,KAAMI,EAAI,cAAgBA,EAAI,gBAAkBA,EAAI,QACpD,aAAcA,EAAI,aAClB,OAAQA,EAAI,cAAgB,OAAOA,EAAI,aAAa,EAAI,OACxD,QAASA,EAAI,iBAAmB,OAAOA,EAAI,gBAAgB,EAAI,OAC/D,KAAM,MACR,CAAC,CACH,CAEInJ,EAAK,cACPA,EAAK,aAAa,QAAS7F,GAAW,CAGpC,GAFeA,EAAE,eAAiB,WAAaA,EAAE,eAAiB,EAEtD,CACV,IAAM6J,GAAOkF,EAAc/O,CAAC,GAExBA,EAAE,cAAgBA,EAAE,gBAAkB,CAAC+J,MAAQA,GAASF,IAGxD+E,GAAQ,OAAS,GAAKA,GAAQ,CAAC,EAAE,OAAS,UACxC5O,EAAE,cAAgBA,EAAE,gBAAkB,CAAC4O,GAAQ,CAAC,EAAE,QACpDA,GAAQ,CAAC,EAAE,KAAO5O,EAAE,cAAgBA,EAAE,gBAAkBA,EAAE,SAEvD4O,GAAQ,CAAC,EAAE,eAAcA,GAAQ,CAAC,EAAE,aAAe5O,EAAE,cACtD,CAAC4O,GAAQ,CAAC,EAAE,QAAU5O,EAAE,gBAC1B4O,GAAQ,CAAC,EAAE,OAAS,OAAO5O,EAAE,aAAa,GACxC,CAAC4O,GAAQ,CAAC,EAAE,SAAW5O,EAAE,mBAC3B4O,GAAQ,CAAC,EAAE,QAAU,OAAO5O,EAAE,gBAAgB,GAC5C,CAAC4O,GAAQ,CAAC,EAAE,iBAAmB5O,EAAE,mBACnC4O,GAAQ,CAAC,EAAE,gBAAkB,OAAO5O,EAAE,gBAAgB,IAE1D,MACF,CAEA4O,GAAQ,KAAK,CACX,KAAM5O,EAAE,cAAgBA,EAAE,gBAAkBA,EAAE,SAAWA,EAAE,aAAe,SAC1E,aAAcA,EAAE,aAChB,OAAQA,EAAE,cAAgB,OAAOA,EAAE,aAAa,EAAI,OACpD,QAASA,EAAE,iBAAmB,OAAOA,EAAE,gBAAgB,EAAI,OAC3D,gBAAiBA,EAAE,iBAAmB,OAAOA,EAAE,gBAAgB,EAAI,OACnE,KAAMA,EAAE,aAAe,SACvB,cAAeA,EAAE,eACjB,eAAgBA,EAAE,gBAClB,aAAcA,EAAE,cAChB,WAAYA,EAAE,aAAe,KAAO,OAAOA,EAAE,WAAW,EAAI,MAC9D,CAAC,CACH,CAAC,EAGC6F,EAAK,iBACPA,EAAK,gBAAgB,QAAS9C,GAAW,CACvC,IAAM8G,EAAO9G,EAAE,MAAQA,EAAE,SAAWA,EAAE,YACtC,GAAI,CAAC8G,EAAM,OAGX,IAAMoF,GAAQlM,EAAE,OAAS,OAAOA,EAAE,MAAM,EAAI,OACtCmM,GAAWN,GAAQ,KACtB5O,IACEiP,IAASjP,GAAE,SAAWiP,IACtBjP,GAAE,OAAS6J,GAAQ7J,GAAE,eAAiB+C,EAAE,YAC7C,EAEImM,IACGA,GAAS,OAAMA,GAAS,KAAOrF,GAC/BqF,GAAS,eAAcA,GAAS,aAAenM,EAAE,cACjDmM,GAAS,OAAMA,GAAS,KAAOnM,EAAE,aACjCmM,GAAS,aACZA,GAAS,WACPnM,EAAE,iBAAmB,KAAO,OAAOA,EAAE,eAAe,EAAI,SAE5D6L,GAAQ,KAAK,CACX,KAAM/E,EACN,aAAc9G,EAAE,aAChB,OAAQkM,GACR,KAAMlM,EAAE,aAAe,SACvB,WAAYA,EAAE,iBAAmB,KAAO,OAAOA,EAAE,eAAe,EAAI,MACtE,CAAC,CAEL,CAAC,EAKH,IAAMoM,EAAuE,CAAC,EAC1EtJ,EAAK,kBACPA,EAAK,gBAAgB,QAAQ,CAAC9C,EAAQqM,IAAgB,CAChDrM,EAAE,WAAaA,EAAE,eAAiB,MACpCoM,EAAc,KAAK,CACjB,KACE,OAAOpM,EAAE,WAAc,SAAWA,EAAE,UAAY,IAAI,KAAKA,EAAE,SAAS,EAAE,QAAQ,EAChF,MAAOA,EAAE,cACT,IAAAqM,CACF,CAAC,CAEL,CAAC,EACDD,EAAc,KAAK,CAAC7J,EAAGG,IAAMH,EAAE,KAAOG,EAAE,MAAQH,EAAE,IAAMG,EAAE,GAAG,GAI/D,IAAM4J,GAOA,CAAC,EACHxJ,EAAK,SACPA,EAAK,OAAO,QAAQ,CAACyJ,EAAQF,IAAgB,CAC3C,IAAIG,GAAQD,EAAE,gBAAkBA,EAAE,YAAc,KAC5CE,GAAOF,EAAE,eAAiBA,EAAE,WAAa,KACzCG,GAAaH,EAAE,sBAAwB,KACvCI,GAAYJ,EAAE,qBAAuB,KAEzC,GAAIA,EAAE,QAAU,oBAAsBA,EAAE,QAAU,oBAAqB,CACrE,IAAMtP,GAAIsP,EAAE,KACZ,GAAItP,IAAK,KAAM,CACb,IAAM2P,GAAM3P,IAAK,GAAM,IACjB4P,GAAM5P,IAAK,GAAM,IACjB6P,GAAM7P,IAAK,EAAK,IAChB8P,GAAK9P,GAAI,IAEX4P,KAAO,IAAGL,GAAQK,IAClBD,KAAO,IAAGF,GAAaE,IACvBG,KAAO,IAAGN,GAAOM,IACjBD,KAAO,IAAGH,GAAYG,GAC5B,CACF,CAGEP,EAAE,YACDC,IAAS,MAAQC,IAAQ,MAAQC,IAAc,MAAQC,IAAa,OAErEL,GAAW,KAAK,CACd,KACE,OAAOC,EAAE,WAAc,SAAWA,EAAE,UAAY,IAAI,KAAKA,EAAE,SAAS,EAAE,QAAQ,EAChF,MAAAC,GACA,KAAAC,GACA,WAAAC,GACA,UAAAC,GACA,IAAAN,CACF,CAAC,CAEL,CAAC,EACDC,GAAW,KAAK,CAAC/J,EAAGG,IAAMH,EAAE,KAAOG,EAAE,MAAQH,EAAE,IAAMG,EAAE,GAAG,GAG5D,IAAMiH,EAAU7G,EAAK,SAAW,CAAC,EAC7BkK,GAA6B,KAC7BC,GAAY,EACZC,GAA+B,KAC/BC,GAA8B,KAC9BC,GAAgC,KAChCC,GAA+B,KAC/BC,GAAU,EAERC,GAA4B,CAAC,EACnC,QAASC,EAAK,EAAGA,EAAK7D,EAAQ,OAAQ6D,IAAM,CAC1C,IAAMC,EAAI9D,EAAQ6D,CAAE,EACdlG,GAAMmG,EAAE,aACRlG,GAAMkG,EAAE,cACd,GAAInG,IAAO,MAAQC,IAAO,KAAM,SAEhC,IAAME,GACJgG,EAAE,WAAa,KACX,OAAOA,EAAE,WAAc,SACrBA,EAAE,UACFA,EAAE,qBAAqB,KACrBA,EAAE,UAAU,QAAQ,EACpB,IAAI,KAAKA,EAAE,SAAS,EAAE,QAAQ,EAClC,KACA5F,GAAQ4F,EAAE,OAAS,KAAOA,EAAE,MAAQ,IAAM,KAE5CvF,GAAUuF,EAAE,eAAiB,KAGjC,GAAIvF,IAAW,MAAQT,GAAM,CAE3B,KAAOwF,GAAYb,EAAc,QAAUA,EAAca,EAAS,EAAE,MAAQxF,IAC1EuF,GAAcZ,EAAca,EAAS,EAAE,MACvCA,KAEF/E,GAAU8E,EACZ,MAAW9E,IAAW,OACpB8E,GAAc9E,IAIhB,GAAIT,GACF,KAAO6F,GAAUhB,GAAW,QAAUA,GAAWgB,EAAO,EAAE,MAAQ7F,IAAM,CACtE,IAAM8E,GAAID,GAAWgB,EAAO,EACxBf,GAAE,OAAS,OAAMW,GAAgBX,GAAE,OACnCA,GAAE,MAAQ,OAAMY,GAAeZ,GAAE,MACjCA,GAAE,YAAc,OAAMa,GAAiBb,GAAE,YACzCA,GAAE,WAAa,OAAMc,GAAgBd,GAAE,WAC3Ce,IACF,CAGF,IAAMxF,GAA2B2F,EAAE,gBAAkBA,EAAE,YAAcP,GAC/DnF,GAA0B0F,EAAE,eAAiBA,EAAE,WAAaN,GAC5DnF,GAAgCyF,EAAE,sBAAwBL,GAC1DnF,GAA+BwF,EAAE,qBAAuBJ,IAE1DI,EAAE,gBAAkB,MAAQA,EAAE,YAAc,QAAMP,GAAgBpF,KAClE2F,EAAE,eAAiB,MAAQA,EAAE,WAAa,QAAMN,GAAepF,IAC/D0F,EAAE,sBAAwB,OAAML,GAAiBpF,IACjDyF,EAAE,qBAAuB,OAAMJ,GAAgBpF,IAEnD,IAAMU,GACJX,IAAkB,MAAQC,IAAiB,MAAQA,KAAkB,EACjED,GAAiBC,GACjB,KAENsF,GAAY,KAAK,CACf,IAAAjG,GACA,IAAAC,GACA,IAAKkG,EAAE,UAAYA,EAAE,mBAAqB,KAC1C,KAAAhG,GACA,GAAIgG,EAAE,YAAc,KACpB,IAAKA,EAAE,SAAW,KAClB,MAAOA,EAAE,OAAS,KAClB,MAAA5F,GACA,KAAM4F,EAAE,aAAe,KACvB,UAAA3F,GACA,SAAAC,GACA,eAAAC,GACA,cAAAC,GACA,QAAAC,GACA,MAAAS,EACF,CAAC,CACH,CAEA,GAAI,CAAC4E,GAAY,OAAQ,CACvB7B,EAAO,IAAI,MAAM,4BAA4B,CAAC,EAC9C,MACF,CAEA,IAAMpR,GAAMwC,EAAayQ,EAAW,EAC9BhP,GAAQF,EAAa/D,EAAG,EAC9BmR,EAAQ,CAAE,KAAA3E,GAAM,OAAAE,GAAQ,QAAA6E,GAAS,OAAQ,MAAO,OAAQvR,GAAK,MAAAiE,GAAO,MAAAuN,GAAO,SAAAC,EAAS,CAAC,CACvF,OAAS2B,GAAI,CACXhC,EAAOgC,EAAE,CACX,CACF,EAEMC,EAAW1E,EAAkBxC,CAAG,EACtC,GAAIkH,EAAU,CACZhC,EAAoB,KAAMgC,CAAQ,EAClC,MACF,CAEkB,IAAIC,GAAU,CAC9B,MAAO,GACP,UAAW,OACX,WAAY,IACZ,gBAAiB,UACjB,mBAAoB,EACtB,CAAC,EAES,MAAMnH,EAAKkF,CAAmB,CAC1C,CAAC,CACH,CAGA,SAASkC,GAASpH,EAAuB,CACvC,IAAMvB,EAAO,IAAI,YAAY,EAAE,OAAOuB,CAAG,EACnCqH,EAAM,IAAI,UAAU,EAAE,gBAAgB5I,EAAM,iBAAiB,EAE/D4B,EAAO,gBACLiH,EAASD,EAAI,cAAc,mCAAmC,EAChEC,IAAQjH,EAAOiH,EAAO,aAAa,KAAK,GAAKjH,GAGjD,IAAMkH,EAAWF,EAAI,iBAAiB,aAAa,EACnD,GAAI,CAACE,EAAS,OAAQ,MAAM,IAAI,MAAM,6BAA6B,EAEnE,IAAM/G,EAAuB,CAAC,EA8B9B,GA7BA+G,EAAS,QAASC,IAAO,EACTA,GAAG,aAAa,KAAK,EAAE,MAAM,KAAK,GAAK,CAAC,GAChD,QAASC,IAAS,CACtB,IAAMC,GAAQD,GAAK,MAAM,GAAG,EAC5B,GAAIC,GAAM,OAAS,EAAG,OACtB,IAAM5G,EAAM,WAAW4G,GAAM,CAAC,CAAC,EACzB7G,EAAM,WAAW6G,GAAM,CAAC,CAAC,EACzB3G,GAAM2G,GAAM,OAAS,EAAI,WAAWA,GAAM,CAAC,CAAC,EAAI,KAClD,MAAM7G,CAAG,GAAK,MAAMC,CAAG,GAC3BN,EAAO,KAAK,CACV,IAAAK,EACA,IAAAC,EACA,IAAKC,IAAO,MAAQ,MAAMA,EAAG,EAAI,KAAOA,GACxC,KAAM,KACN,GAAI,KACJ,IAAK,KACL,MAAO,KACP,MAAO,KACP,KAAM,KACN,UAAW,KACX,SAAU,KACV,eAAgB,KAChB,cAAe,KACf,QAAS,KACT,MAAO,IACT,CAAC,CACH,CAAC,CACH,CAAC,EAEG,CAACP,EAAO,OAAQ,MAAM,IAAI,MAAM,6BAA6B,EACjE,IAAM3M,EAAMwC,EAAamK,CAAM,EACzB1I,GAAQF,EAAa/D,CAAG,EAC9B,MAAO,CAAE,KAAAwM,EAAM,OAAQ,MAAO,OAAQxM,EAAK,MAAAiE,EAAM,CACnD,CAGA,eAAe6P,GAAUC,EAA0B,CACjD,IAAMC,EAAMD,EAAK,KAAK,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,EAC9C5H,EAAoB4H,EAAa,MAAS,MAAMA,EAAK,YAAY,EACjE3H,EAAsC2H,EAAa,MACrD5R,EACJ,OAAQ6R,EAAK,CACX,IAAK,MACH7R,EAAS+J,EAASC,EAAKC,CAAc,EACrC,MACF,IAAK,MACHjK,EAASmM,EAASnC,EAAKC,CAAc,EACrC,MACF,IAAK,MACHjK,EAAS,MAAM+O,GAAS/E,CAAG,EAC3B,MACF,IAAK,MACHhK,EAASoR,GAASpH,CAAG,EACrB,MACF,QACE,MAAM,IAAI,MAAM,wBAAwB6H,CAAG,EAAE,CACjD,CAEA,OAAI7R,IACFA,EAAO,SAAW4R,EAAK,KACvB5R,EAAO,SAAW4R,EAAK,KACnB5R,EAAO,QAAUA,EAAO,QAC1BqD,EAAqBrD,CAAM,EAC3BA,EAAO,MAAM,SAAWwD,EAAqBxD,EAAO,MAAM,IAGvDA,CACT,CAEA,MAAO,CACL,UAAA2R,GACA,aAAA/P,EACA,qBAAAyB,EACA,qBAAAG,EACA,aAAA0B,EACA,oBAAA/B,EACA,iBAAAD,EACA,oBAAAE,EACA,iBAAAH,EACA,aAAA5C,EACA,WAAAuH,EACA,WAAAC,EACA,OAAAL,EACA,OAAAE,CACF,CACF,GAAG,EEtrDI,IAAMoK,IAAW,IAAM,CAC5B,IAAIC,EAAuC,CAAC,EACxCC,EAAmD,KAEvD,SAASC,EACPC,EACAC,GACAC,GACAC,GACAC,EACA,CAAC,CAEH,SAASC,EAAcC,EAAe,CAAC,CACvC,SAASC,EAASC,EAAc,CAC9BX,EAAUW,EAAE,EAAE,EAAIA,CACpB,CACA,SAASC,EAAUC,EAAiB,CAClCA,EAAG,QAASF,IAAM,CAChBX,EAAUW,GAAE,EAAE,EAAIA,EACpB,CAAC,CACH,CACA,SAASG,EAAYC,EAAY,CAC/B,OAAOf,EAAUe,CAAE,CACrB,CACA,SAASC,GAAc,CACrBhB,EAAY,CAAC,CACf,CACA,SAASiB,GAAkB,CACzBjB,EAAY,CAAC,CACf,CACA,SAASkB,EAAgBH,EAAYI,GAAkB,CAAC,CACxD,SAASC,EAAiBL,EAAmBM,GAAc,CAAC,CAC5D,SAASC,GAAS,CAAC,CACnB,SAASC,EAASR,EAAY,CAAC,CAC/B,SAASS,EAAaC,EAAaC,GAAa,CAAC,CACjD,SAASC,GAAa,CAAC,CACvB,SAASC,EACPb,EACAc,GACAC,GACAC,GACAV,EACAW,EACA,CAAC,CACH,SAASC,GAAiB,CAAC,CAC3B,SAASC,EAAcnB,EAAYoB,GAAgB,CAAC,CACpD,SAASC,EAAcP,EAAU,CAAC,CAClC,SAASQ,EAASZ,EAAaC,GAAaY,GAAsBC,GAAiB,CAAC,CACpF,SAASC,GAAa,CAAC,CACvB,SAASC,GAAiB,CAAC,CAC3B,SAASC,GAAwC,CAC/C,MAAO,CAAC,EAAG,EAAG,CAAC,CACjB,CACA,SAASC,EAAYlB,EAAamB,GAAaN,GAAc,CAAC,CAC9D,SAASO,EAAmB9B,EAAYc,GAAmBG,GAAkB,CAAC,CAC9E,SAASc,EAAiB/B,EAAY,CAAC,CAEvC,SAASgC,EACPC,EACAC,GACU,CACV,OAAO,OAAO,KAAKjD,CAAS,CAC9B,CAEA,MAAO,CACL,KAAAE,EACA,OAAQ,IAAM,KACd,sBAAwBgD,GAAiB,CACvCjD,EAAqBiD,CACvB,EACA,cAAA1C,EACA,SAAAE,EACA,UAAAE,EACA,YAAAE,EACA,YAAAE,EACA,gBAAAC,EACA,gBAAAC,EACA,iBAAAE,EACA,OAAAE,EACA,SAAAC,EACA,aAAAC,EACA,WAAAG,EACA,iBAAAC,EACA,eAAAK,EACA,cAAAC,EACA,cAAAE,EACA,SAAAC,EACA,WAAAG,EACA,eAAAC,EACA,YAAAC,EACA,YAAAC,EACA,mBAAAE,EACA,iBAAAC,EACA,+BAAAC,EACA,aAAehC,GAAef,EAAUe,CAAE,CAC5C,CACF,GAAG,EClGH,OAAOoC,OAAW,QCSX,IAAMC,IAAS,IAAM,CAC1B,SAASC,GAA6B,CACpC,IAAMC,EAAMC,GAAQ,OAAO,EACrBC,EAAa,CAAC,IAAM,IAAM,GAAK,KAAM,IAAK,GAAG,EAAE,IAAKC,GAAMA,EAAIH,CAAG,EACjEI,EAAQ,CACZ,kBACA,YACA,QACA,YACA,UACA,YACA,eACF,EACMC,EAAS,CAAC,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,SAAS,EAErFC,EAAqB,CAAC,EACxBC,EAAO,EACX,QAASC,EAAI,EAAGA,EAAIN,EAAW,OAAQM,IACrCF,EAAM,KAAK,CAAE,KAAMF,EAAMI,CAAC,EAAG,IAAKD,EAAM,IAAKL,EAAWM,CAAC,EAAG,MAAOH,EAAOG,CAAC,CAAE,CAAC,EAC9ED,EAAOL,EAAWM,CAAC,EAErB,OAAAF,EAAM,KAAK,CAAE,KAAMF,EAAM,CAAC,EAAG,IAAKG,EAAM,IAAK,IAAU,MAAOF,EAAO,CAAC,CAAE,CAAC,EAClEC,CACT,CAEA,SAASG,GAA0B,CACjC,IAAMP,EAAaD,GAAQ,WAAW,EAChCG,EAAQ,CAAC,WAAY,UAAW,QAAS,YAAa,WAAW,EACjEC,EAAS,CAAC,UAAW,UAAW,UAAW,UAAW,SAAS,EAE/DC,EAAqB,CAAC,EACxBC,EAAO,EACX,QAASC,EAAI,EAAGA,EAAIN,EAAW,OAAQM,IACrCF,EAAM,KAAK,CAAE,KAAMF,EAAMI,CAAC,EAAG,IAAKD,EAAM,IAAKL,EAAWM,CAAC,EAAG,MAAOH,EAAOG,CAAC,CAAE,CAAC,EAC9ED,EAAOL,EAAWM,CAAC,EAErB,OAAAF,EAAM,KAAK,CAAE,KAAMF,EAAM,CAAC,EAAG,IAAKG,EAAM,IAAK,IAAU,MAAOF,EAAO,CAAC,CAAE,CAAC,EAClEC,CACT,CAEA,MAAO,CACL,cAAAP,EACA,WAAAU,CACF,CACF,GAAG,EClCI,IAAMC,GAAU,CACrB,MAAO,CAAE,KAAM,QAAS,MAAO,UAAW,KAAM,OAAQ,EACxD,SAAU,CAAE,KAAM,WAAY,MAAO,UAAW,KAAM,aAAc,EACpE,MAAO,CAAE,KAAM,QAAS,MAAO,UAAW,KAAM,MAAO,EACvD,GAAI,CAAE,KAAM,aAAc,MAAO,UAAW,KAAM,UAAW,EAC7D,QAAS,CAAE,KAAM,UAAW,MAAO,UAAW,KAAM,gBAAiB,EACrE,YAAa,CAAE,KAAM,cAAe,MAAO,UAAW,KAAM,YAAa,EACzE,UAAW,CAAE,KAAM,YAAa,MAAO,UAAW,KAAM,SAAU,EAClE,SAAU,CAAE,KAAM,WAAY,MAAO,YAAa,KAAM,aAAc,EACtE,SAAU,CAAE,KAAM,YAAa,MAAO,UAAW,KAAM,UAAW,EAClE,UAAW,CAAE,KAAM,aAAc,MAAO,UAAW,KAAM,0BAA2B,EACpF,MAAO,CAAE,KAAM,QAAS,MAAO,UAAW,KAAM,UAAW,EAC3D,QAAS,CAAE,KAAM,UAAW,MAAO,UAAW,KAAM,cAAe,EACnE,IAAK,CAAE,KAAM,MAAO,MAAO,UAAW,KAAM,aAAc,CAC5D,EAEaC,GAA4C,CACvD,UAAW,CACT,MAAO,YACP,MAAO,MACP,KAAM,IACN,MAAOD,GAAQ,UAAU,MACzB,KAAM,MACN,KAAMA,GAAQ,UAAU,KACxB,IAAK,CAACE,EAAGC,IAAOA,EAAID,EAAE,QAAQ,CAAC,EAAI,KAAK,MAAMA,CAAC,EAAE,SAAS,EAC1D,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,MAAO,CACL,MAAO,QACP,MAAO,QACP,KAAM,OACN,MAAOF,GAAQ,MAAM,MACrB,KAAM,MACN,KAAMA,GAAQ,MAAM,KACpB,IAAME,IAAOA,EAAI,KAAK,QAAQ,CAAC,EAC/B,QAAUA,IAAOA,EAAI,KAAK,QAAQ,CAAC,EACnC,UAAYA,GAAMA,EAClB,YAAa,CACf,EACA,SAAU,CACR,MAAO,WACP,MAAO,WACP,KAAM,IACN,MAAOF,GAAQ,SAAS,MACxB,KAAM,OACN,KAAMA,GAAQ,SAAS,KACvB,IAAME,GAAMA,EAAE,QAAQ,CAAC,EACvB,QAAUA,GAAMA,EAAE,QAAQ,CAAC,EAC3B,YAAa,CACf,EACA,MAAO,CACL,MAAO,QACP,MAAO,QACP,KAAM,IACN,MAAOF,GAAQ,MAAM,MACrB,KAAM,MACN,KAAMA,GAAQ,MAAM,KACpB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,GAAI,CACF,MAAO,aACP,MAAO,KACP,KAAM,MACN,MAAOF,GAAQ,GAAG,MAClB,KAAM,KACN,KAAMA,GAAQ,GAAG,KACjB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,QAAS,CACP,MAAO,UACP,MAAO,MACP,KAAM,MACN,MAAOF,GAAQ,QAAQ,MACvB,KAAM,MACN,KAAMA,GAAQ,QAAQ,KACtB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,YAAa,CACX,MAAO,OACP,MAAO,OACP,KAAM,QACN,MAAOF,GAAQ,YAAY,MAC3B,KAAM,OACN,KAAMA,GAAQ,YAAY,KAC1B,IAAME,GAAMA,EAAE,QAAQ,CAAC,EACvB,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACvC,YAAa,CACf,EACA,SAAU,CACR,MAAO,YACP,MAAO,gBACP,KAAM,IACN,MAAOF,GAAQ,SAAS,MACxB,KAAM,MACN,KAAMA,GAAQ,SAAS,KACvB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,UAAW,CACT,MAAO,aACP,MAAO,iBACP,KAAM,IACN,MAAOF,GAAQ,UAAU,MACzB,KAAM,MACN,KAAMA,GAAQ,UAAU,KACxB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,MAAO,CACL,MAAO,QACP,MAAO,QACP,KAAM,GACN,MAAOF,GAAQ,MAAM,MACrB,KAAM,KACN,KAAMA,GAAQ,MAAM,KACpB,IAAME,GAAMA,EAAE,QAAQ,CAAC,EACvB,QAAUA,GAAMA,EAAE,QAAQ,CAAC,CAC7B,EACA,QAAS,CACP,MAAO,UACP,MAAO,UACP,KAAM,IACN,MAAOF,GAAQ,QAAQ,MACvB,KAAM,MACN,KAAMA,GAAQ,QAAQ,KACtB,IAAME,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,CACzC,EACA,IAAK,CACH,MAAO,MACP,MAAO,MACP,KAAM,MACN,MAAO,UACP,KAAM,MACN,KAAM,cACN,IAAMA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACnC,QAAUA,GAAM,KAAK,MAAMA,CAAC,EAAE,SAAS,EACvC,YAAa,EACb,QAAS,CAACE,EAAKC,IAAc,CAC3B,IAAMC,EAAM,IAAI,MAAMF,EAAI,MAAM,EAAE,KAAK,IAAI,EAC3C,QAASG,EAAI,EAAGA,EAAIH,EAAI,OAAQG,IAAK,CACnC,IAAMJ,EAAIC,EAAIG,CAAC,EACTC,EAAOJ,EAAIG,EAAI,CAAC,EACtB,GAAIJ,EAAE,KAAO,MAAQK,EAAK,KAAO,MAAQL,EAAE,MAAQ,MAAQK,EAAK,MAAQ,KAAM,CAC5E,IAAMC,EAAKN,EAAE,IAAMK,EAAK,IAClBE,GAAMP,EAAE,KAAOK,EAAK,MAAQ,IAC9BE,EAAK,IAAGJ,EAAIC,CAAC,EAAKE,EAAKC,EAAM,KACnC,CACF,CACA,OAAOL,EAAUC,CAAG,CACtB,CACF,CACF,ECvKO,IAAMK,GAA0C,CACrD,QAAS,CAAE,KAAM,UAAW,KAAM,kBAAmB,cAAe,OAAQ,EAC5E,OAAQ,CAAE,KAAM,SAAU,KAAM,kBAAmB,cAAe,OAAQ,EAC1E,QAAS,CAAE,KAAM,UAAW,KAAM,iBAAkB,cAAe,OAAQ,SAAU,IAAK,EAC1F,SAAU,CAAE,KAAM,WAAY,KAAM,OAAQ,cAAe,OAAQ,SAAU,MAAO,CACtF,EAEO,SAASC,GAAaC,EAA0C,CACrE,GAAI,CAACA,EAAO,MAAO,gBACnB,IAAMC,EAAMD,EAAM,YAAY,EAC9B,OAAOF,GAAOG,CAAG,GAAG,MAAQ,UAC9B,CH8CO,IAAMC,IAAa,IAAM,CAC9B,IAAIC,EAAoB,CAAC,EACrBC,EAAkC,KAClCC,EAAwB,OACxBC,EAA4B,QAC5BC,EAAwC,KACxCC,EAKO,KACPC,EAAwB,GACxBC,EAAyB,GACzBC,EAA6B,IAAI,IAAI,CAAC,WAAW,CAAC,EAClDC,EAAgC,IAAI,IACpCC,EAA+B,IAAI,IAAI,CAAC,QAAS,WAAY,MAAO,aAAa,CAAC,EAClFC,EAAoC,IAAI,IAAI,CAAC,OAAO,CAAC,EACrDC,EAAgB,OAChBC,EAAiC,KACjCC,EAAyB,CAAC,EAG1BC,EAA8B,KAC9BC,EAA2B,KAC3BC,EAAsB,GACtBC,EAAyB,GACzBC,EAA6B,KAC7BC,EAA+B,KAC/BC,EAAwC,KACxCC,EAAmC,KACnCC,EAA8C,KAE9CC,EAAyC,KACzCC,EAAwC,KACxCC,EAAwB,KAGxBC,EAA2D,KAC3DC,GACF,KACEC,GAA4D,KAC5DC,GAAuD,KAErDC,EAAiB,IACjBC,EAA2B,GAC3BC,EAAmB,GACrBC,EAAwB,GACxBC,EAAoC,KACpCC,EAAgC,KAChCC,EAA8B,KAC9BC,EAAiC,KACjCC,GAAkC,KAClCC,GAAgC,KAChCC,GACF,KAGF,SAASC,GACPC,EACAC,EACAC,EACAC,EACA,CACAnB,EAAiBgB,EACjBf,GAAkBgB,EAClBf,GAAYgB,EACZf,GAAgBgB,EAChBV,EAAY,SAAS,eAAe,kBAAkB,EACtDA,GAAW,iBAAiB,SAAU,IAAM,CACtCf,GAAsBE,GAAqBD,GAC7CyB,GAAkB1B,EAAoBE,EAAmBD,CAAe,CAC5E,CAAC,EACDe,EAAU,SAAS,eAAe,aAAa,EAC/CC,EAAa,SAAS,eAAe,iBAAiB,EACtDC,GAAc,SAAS,eAAe,qBAAqB,EAC3DJ,EAAgB,SAAS,eAAe,cAAc,EACtD9B,EAAU2C,GAAM,KAAK,cAAc,EAEnC,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAASC,CAAe,EACpFV,IAAa,UAAU,IAAI,QAAQ,EAGnC,IAAMW,EAAU,IAAI,IAAI,CAAC,IAAK,IAAK,IAAK,GAAG,CAAC,EACtCC,EAAgB,IAAI,IAE1B,SAAS,iBAAiB,UAAYC,GAAM,CAE1C,GADI,CAACpD,EAAM,QAAU,CAACa,GAClB,CAAC,QAAS,WAAY,QAAQ,EAAE,SAAS,SAAS,eAAe,SAAW,EAAE,EAAG,OAErF,IAAMwC,EAAMD,EAAE,IAAI,YAAY,EAC9B,GAAI,CAACF,EAAQ,IAAIG,CAAG,EAAG,OAEvBD,EAAE,eAAe,EACjBD,EAAc,IAAIE,CAAG,EAErB,IAAMC,EAAItD,EAAM,CAAC,EAAE,MACdyB,IAAcA,EAAe,CAAC6B,EAAE,OAAO,EAAG,IAAMA,EAAE,OAAO,EAAG,GAAI,GAErE,GAAI,CAACC,EAAKC,CAAG,EAAI/B,EAEXgC,IADOD,EAAMD,GACK,GAClBG,GAAa,IAEfC,EAASJ,EACXK,GAASJ,EAEX,GAAIH,IAAQ,IAEVM,EAASJ,EAAME,GACfG,GAASJ,EAAMC,WACNJ,IAAQ,IAEjBM,EAASJ,EAAME,GACfG,GAASJ,EAAMC,WACNJ,IAAQ,KAAOA,IAAQ,IAAK,CAErC,IAAMQ,GAASzC,IAAkB,KAAOA,GAAiBmC,EAAMC,GAAO,EAChEM,GAAST,IAAQ,IAAM,EAAIK,GAAa,EAAIA,GAAa,IAC/DC,EAASE,IAAUA,GAASN,GAAOO,GACnCF,GAASC,IAAUL,EAAMK,IAAUC,EACrC,CAGA,IAAMC,GAAQ,CAAC/D,EAAM,CAAC,EAAE,MAAM,CAAC,EAAIA,EAAM,CAAC,EAAE,MAAMA,EAAM,CAAC,EAAE,MAAM,OAAS,CAAC,CAAE,EAC7E,GAAI2D,EAASI,GAAM,CAAC,EAAG,CACrB,IAAMC,GAAID,GAAM,CAAC,EAAIJ,EACrBA,GAAUK,GACVJ,IAAUI,EACZ,CACA,GAAIJ,GAASG,GAAM,CAAC,EAAG,CACrB,IAAMC,GAAIJ,GAASG,GAAM,CAAC,EAC1BJ,GAAUK,GACVJ,IAAUI,EACZ,CACAL,EAAS,KAAK,IAAII,GAAM,CAAC,EAAGJ,CAAM,EAClCC,GAAS,KAAK,IAAIG,GAAM,CAAC,EAAGH,EAAM,EAE9BA,GAASD,EAAS,OACpBlC,EAAe,CAACkC,EAAQC,EAAM,EAC9BK,GAAgBN,EAAQC,GAAQ,EAAI,EAExC,CAAC,EAED,SAAS,iBAAiB,QAAUR,GAAM,CACxC,IAAMC,EAAMD,EAAE,IAAI,YAAY,EAC1BF,EAAQ,IAAIG,CAAG,GAAGF,EAAc,OAAOE,CAAG,CAChD,CAAC,CACH,CAEA,SAASY,GAAgBV,EAAaC,EAAaU,EAAU,GAAO,CAClE,GAAI,CAAClE,EAAM,OAAQ,OACnB,GAAI,CAACkE,EAAS,CACZlE,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAMA,EAAE,SAAS,IAAK,CAAE,IAAAC,EAAK,IAAAC,CAAI,CAAC,CAAC,EAC7D,MACF,CAEA,IAAMW,EAAY3C,EAAgBA,EAAc,CAAC,EAAIxB,EAAM,CAAC,EAAE,MAAM,OAAO,EAAG,IACxEoE,EAAY5C,EAAgBA,EAAc,CAAC,EAAIxB,EAAM,CAAC,EAAE,MAAM,OAAO,EAAG,IAE1E0B,GAAQ,qBAAqBA,CAAM,EAEvC,IAAM2C,EAAO,CAACC,EAAWC,EAAWC,IAAcF,GAAKC,EAAID,GAAKE,EAC1DV,EAAS,IAETW,EAAO,IAAM,CACjB,GAAI,CAAChD,EAAc,OACnB,GAAM,CAACiD,EAAMC,CAAI,EAAIlD,EAEfmD,EAAOP,EAAK7C,EAAe,CAAC,EAAGkD,EAAMZ,CAAM,EAC3Ce,EAAOR,EAAK7C,EAAe,CAAC,EAAGmD,EAAMb,CAAM,EAEjD9D,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAE,IAAM,CAC9BA,GAAE,SAAS,IAAK,CAAE,IAAKsB,EAAM,IAAKC,CAAK,CAAC,CAC1C,CAAC,EAEG,KAAK,IAAID,EAAOF,CAAI,EAAI,MAAU,KAAK,IAAIG,EAAOF,CAAI,EAAI,KAC5DjD,EAAS,sBAAsB+C,CAAI,EAChC/C,EAAS,IAChB,EACAA,EAAS,sBAAsB+C,CAAI,CACrC,CAGA,SAASK,EAAUC,EAAkBC,EAAsB,CAAC,EAAGC,EAAc,GAAO,CAClF9D,EAAc,KACdJ,EAAe,KACfC,EAAY,KACZF,EAAYkE,EAGZvE,EAAmB,IAAI,IACrB,OAAO,QAAQyE,EAAO,EACnB,OAAO,CAAC,CAAC,CAAEC,CAAG,IAAMJ,EAAM,OAAO,KAAMK,GAAMA,EAAED,EAAI,KAAK,GAAK,IAAI,CAAC,EAClE,IAAI,CAAC,CAAC9B,CAAG,IAAMA,CAAG,CACvB,EAGI7C,EAAc,OAAS,IACzBA,EAAgB,IAAI,IAAI,CAAC,WAAW,EAAE,OAAQ6E,GAAM5E,EAAiB,IAAI4E,CAAC,CAAC,CAAC,GAI9E,SAAS,iBAAiB,cAAc,EAAE,QAASC,GAAO,CACxD,IAAMC,EAAOD,EACPE,EAASD,EAAK,QAAQ,OACtBE,EAAchF,EAAiB,IAAI+E,CAAM,EAC/CD,EAAK,UAAU,OAAO,SAAUE,GAAejF,EAAc,IAAIgF,CAAM,CAAC,EACxED,EAAK,UAAU,OAAO,WAAY,CAACE,CAAW,CAChD,CAAC,EAED5E,EAAekE,EACXE,EACFS,GAAYX,CAAK,EAEjBY,GAAO,CAEX,CAEA,SAASC,GAAQ,CACfzE,EAAc,KACdJ,EAAe,KACfC,EAAY,KACZH,EAAe,KACfgF,GAAa,EACTxD,IACFA,EAAQ,MAAM,QAAU,OACxBA,EAAQ,UAAY;AAAA;AAAA;AAAA,SAKtB,IAAMyD,EAAa,SAAS,eAAe,aAAa,EACpDA,GAAYA,EAAW,UAAU,IAAI,QAAQ,EACjDC,GAAoB,EACpBvD,GAAiB,KACbC,IAAoBA,GAAmB,IAAI,CACjD,CAEA,SAASuD,IAAa,CAChBtE,IAAW,OACb,qBAAqBA,CAAM,EAC3BA,EAAS,MAEXlB,EAAgB,IAAI,IAAI,CAAC,WAAW,CAAC,EACrCC,EAAmB,IAAI,IACvBC,EAAkB,IAAI,IAAI,CAAC,QAAS,WAAY,MAAO,aAAa,CAAC,EACrEC,EAAuB,IAAI,IAAI,CAAC,OAAO,CAAC,EACxCC,EAAQ,OACRE,EAAY,CAAC,EACbU,EAAgB,KAChBC,EAAe,KACfL,EAAgB,KAChBC,EAAqB,KACrBC,EAAkB,KAClBC,EAAoB,KACpBW,EAAe,GACf0D,EAAM,EACN,SAAS,iBAAiB,4BAA4B,EAAE,QAASN,GAAO,CACtE,IAAMC,EAAOD,EACbC,EAAK,UAAU,OAAO,SAAU/E,EAAc,IAAI+E,EAAK,QAAQ,MAAO,CAAC,EACvEA,EAAK,UAAU,OAAO,WAAY,iBAAiB,CACrD,CAAC,EACD,IAAMU,EAAa,SAAS,eAAe,eAAe,EACtDA,GAAYA,EAAW,UAAU,IAAI,QAAQ,EACjD,IAAMC,EAAU,SAAS,eAAe,eAAe,EACnDA,GAASA,EAAQ,UAAU,OAAO,WAAW,EACjD,SAAS,iBAAiB,uBAAuB,EAAE,QAAS3B,GAAM,CAChEA,EAAE,UAAU,OAAO,SAAWA,EAAkB,QAAQ,OAAS,MAAM,CACzE,CAAC,CACH,CAEA,SAAS4B,EAAa9C,EAAa,CAC7B7C,EAAc,IAAI6C,CAAG,EAAG7C,EAAc,OAAO6C,CAAG,EAC/C7C,EAAc,IAAI6C,CAAG,EACtBxC,GAAc8E,GAAO,EAAI,CAC/B,CAEA,SAASS,GAAUC,EAAmBC,EAAkBC,EAAa,GAAO,CAC1E,IAAMC,EAAM9F,EAAgB,IAAI2F,CAAS,EACrCC,GAAW,CAACE,GACd9F,EAAgB,IAAI2F,CAAS,EACzBxF,GAAgB,CAAC0F,GAAYZ,GAAO,EAAI,GACnC,CAACW,GAAWE,IACrB9F,EAAgB,OAAO2F,CAAS,EAC5BxF,GAAgB,CAAC0F,GAAYZ,GAAO,EAAI,EAEhD,CAEA,SAASc,GAAiBJ,EAAmBK,EAAsB,CACjE,IAAMF,EAAM7F,EAAqB,IAAI0F,CAAS,EAC1CK,GAAe,CAACF,GAClB7F,EAAqB,IAAI0F,CAAS,EAC9BxF,GAAc8E,GAAO,EAAI,GACpB,CAACe,GAAeF,IACzB7F,EAAqB,OAAO0F,CAAS,EACjCxF,GAAc8E,GAAO,EAAI,EAEjC,CAEA,SAASgB,GAAiBC,EAAgB,CACxCpG,EAAgB,IAAI,IAAIoG,CAAI,EACxB/F,GAAc8E,GAAO,EAAI,EAE7B,SAAS,iBAAiB,cAAc,EAAE,QAASL,GAAO,CACxD,IAAMC,EAAOD,EACbC,EAAK,UAAU,OAAO,SAAU/E,EAAc,IAAI+E,EAAK,QAAQ,MAAO,CAAC,CACzE,CAAC,CACH,CAEA,SAASsB,GAASC,EAAc,CAC9B,GAAIlG,IAAUkG,GAAQ,CAACjG,EAAc,CACnCD,EAAQkG,EACR,MACF,CAEA,IAAMC,EAAMlG,EAAa,OACnBmG,EAAKD,EAAI,KAAM3B,GAAMA,EAAE,MAAQ,IAAI,GAAG,MAAQ,EAG9C6B,EAAWC,GAAuB,CACtC,GAAIA,IAAQ,KAAM,OAAO,KAEzB,IAAIC,EAAM,EACV,GAAIvG,IAAU,WAAY,CACxB,IAAMwG,EAAUF,EAAM,IACtBC,EAAMJ,EAAI,UAAW3B,IAAOA,EAAE,MAAQ,IAAMgC,CAAO,CACrD,KAAO,CACL,IAAMC,EAAUL,EAAKE,EAAM,IAC3BC,EAAMJ,EAAI,UAAW3B,IAAOA,EAAE,MAAQ,IAAMiC,CAAO,CACrD,CAIA,OAHIF,IAAQ,KAAIA,EAAMJ,EAAI,OAAS,GAG/BD,IAAS,YAAoBC,EAAII,CAAG,EAAE,MAAQ,GAAK,MACzCJ,EAAII,CAAG,EAAE,MAAQH,GAAMA,GAAM,GAC7C,EAGIjG,IAAiB,OAAMA,EAAekG,EAAQlG,CAAY,GAC1DC,IAAc,OAAMA,EAAYiG,EAAQjG,CAAS,GAGrD,IAAIsG,EAAoC,KACxC,GAAItH,EAAM,OAAQ,CAChB,IAAMsD,EAAItD,EAAM,CAAC,EAAE,MACbuH,EAAKN,EAAQ3D,EAAE,OAAO,EAAG,GAAI,EAC7BkE,EAAKP,EAAQ3D,EAAE,OAAO,EAAG,GAAI,EAC/BiE,IAAO,MAAQC,IAAO,OAAMF,EAAW,CAACC,EAAIC,CAAE,EACpD,CAEA5G,EAAQkG,EACRnB,GAAO,EAAI,EAGP2B,IACFhH,EAAe,GACfN,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAM,CAC9BA,EAAE,MAAM,IAAMA,EAAE,SAAS,IAAK,CAAE,IAAKgE,EAAU,CAAC,EAAG,IAAKA,EAAU,CAAC,CAAE,CAAC,CAAC,CACzE,CAAC,EACDhH,EAAe,GAEnB,CAEA,SAASmH,IAAc,CACrBvF,EAAe,CAACA,EAChBlC,EAAM,QAAQ,CAAC,CAAE,QAAA0H,CAAQ,IAAMA,EAAQ,UAAU,OAAO,UAAWxF,CAAY,CAAC,EAChFyF,GAAO,CACT,CAEA,SAASC,GAAoBC,EAAoE,CAC/FpF,GAAqBoF,CACvB,CAEA,SAASC,GAAezE,EAAoBkD,EAAa,GAAO,CAC1D/D,KAAmBa,GAAOA,IAAQ,MACpCb,GAAiB,KACjBuF,GAAoB,EAChBtF,IAAoBA,GAAmB,IAAI,IAE/CD,GAAiBa,EACjB0E,GAAoB,EACpBC,GAAgB,GAGdnH,GAAgB,CAAC0F,GAAYZ,GAAO,EAAI,CAC9C,CAEA,SAASoC,IAAsB,CAC7B,SAAS,iBAAiB,gBAAgB,EAAE,QAASzC,GAAO,CAC1D,IAAMf,EAAIe,EACVf,EAAE,UAAU,OAAO,SAAUA,EAAE,QAAQ,SAAW/B,EAAc,CAClE,CAAC,CACH,CAEA,SAASwF,IAAkB,CACzB,GAAI,CAACvF,IAAsB,CAACD,IAAkB,CAAC3B,EAAc,OAC7D,IAAMoH,EAAOjI,EAAM,KAAMoF,GAAMA,EAAE,YAAc5C,EAAc,EAC7D,GAAI,CAACyF,EAAM,OACX,IAAMC,EAASC,GAAoB3F,GAAgByF,EAAK,KAAK,EAC7DxF,GAAmB,CAAE,IAAK5B,EAAa,OAAQ,OAAAqH,CAAO,CAAC,CACzD,CAEA,SAASC,GAAoB9E,EAAa+E,EAAoC,CAC5E,IAAMC,EAAOD,EAAM,OAAQE,GAAmBA,GAAK,MAAQ,SAASA,CAAC,CAAC,EACtE,GAAI,CAACD,EAAK,OAAQ,OAAOD,EAAM,IAAI,IAAM,SAAS,EAClD,IAAM7E,EAAM,KAAK,IAAI,GAAG8E,CAAI,EAC1B7E,EAAM,KAAK,IAAI,GAAG6E,CAAI,EAElBE,EAAQ1H,GAAc,MACtB2H,EAAWD,EAAQE,GAAOF,EAAM,YAAY,CAAC,EAAI,KACjDG,EAAcF,GAAU,eAAiB,QAEzCG,EADWC,GAAS,IAAI,EACM,YAAcF,EAC5CG,EAAWL,GAAU,UAAY,KAEvC,OAAOJ,EAAM,IAAKE,GAAM,CACtB,GAAIA,GAAK,MAAQ,CAAC,SAASA,CAAC,EAAG,MAAO,UACtC,GAAIjF,IAAQ,WAAY,OAAOyF,GAAcR,CAAC,EAC9C,GAAIjF,IAAQ,QAAS,CACnB,GAAIsF,IAAc,OAAQ,CACxB,IAAMI,IAASF,IAAa,KAAO,IAAO,KAAOP,EACjD,OAAOU,GAAWD,EAAK,CACzB,CACA,OAAOC,GAAWV,CAAC,CACrB,CACA,IAAM9D,GAAIhB,IAAQD,EAAM,GAAM,KAAK,IAAI,EAAG,KAAK,IAAI,GAAI+E,EAAI/E,IAAQC,EAAMD,EAAI,CAAC,EAC9E,OAAIiB,IAAK,IAAayE,GAAQ,UAAW,UAAWzE,GAAI,GAAI,EACxDA,IAAK,GAAYyE,GAAQ,UAAW,WAAYzE,GAAI,KAAQ,GAAI,EAChEA,IAAK,IAAayE,GAAQ,UAAW,WAAYzE,GAAI,IAAO,GAAI,EAC7DyE,GAAQ,UAAW,WAAYzE,GAAI,KAAQ,GAAI,CACxD,CAAC,CACH,CAEA,SAAS0E,GAAY,CACnBjG,EAAgB,CAClB,CAEA,SAASA,GAAkB,CACzBlC,EAAe,KACfC,EAAY,KACZG,EAAc,KACVW,IAAeA,GAAc,IAAI,EAGrC9B,EAAM,QAASoF,GAAM,CACnBA,EAAE,YAAc,IAClB,CAAC,EAED+D,GAAiB,EACjBC,GAAiB,EAGjB9I,EAAe,GACfN,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,MAAA+F,CAAM,IAAM,CACrC/F,EAAE,MAAM,IAAMA,EAAE,SAAS,IAAK,CAAE,IAAK+F,EAAM,CAAC,EAAI,IAAKA,EAAMA,EAAM,OAAS,CAAC,CAAG,CAAC,CAAC,EAChF/F,EAAE,UAAU,kBAAkB+F,EAAM,CAAC,EAAIA,EAAMA,EAAM,OAAS,CAAC,CAAE,CACnE,CAAC,EACD/I,EAAe,GAEXsB,IAAiBA,GAAgB,KAAM,KAAMhB,CAAK,CACxD,CAEA,SAAS0I,GAAkBC,EAAmB,CAC5C,GAAI,CAACjH,EAAY,OACjB,IAAMkH,EAAM,CAACC,EAAYvC,IAAgB,CACvC,IAAM5B,EAAK,SAAS,cAAc,IAAImE,CAAE,cAAc,EAClDnE,IAAIA,EAAG,YAAc4B,EAC3B,EACAsC,EACE,eACAD,EAAM,WAAa,KAAO,IAAIA,EAAM,UAAY,KAAM,QAAQ,CAAC,CAAC,MAAQ,QAC1E,EACAC,EAAI,eAAgBD,EAAM,UAAY,KAAOG,GAAQ,KAAK,MAAMH,EAAM,SAAW,GAAI,CAAC,EAAI,QAAG,EAC7FC,EAAI,gBAAiBD,EAAM,UAAY,KAAO,GAAG,KAAK,MAAMA,EAAM,QAAQ,CAAC,KAAO,QAAG,EACrFC,EACE,gBACAD,EAAM,UAAY,KAAO,IAAIA,EAAM,SAAW,KAAK,QAAQ,CAAC,CAAC,QAAU,QACzE,EACAC,EAAI,gBAAiBD,EAAM,UAAY,KAAO,GAAGA,EAAM,QAAQ,KAAO,QAAG,EACzEC,EAAI,aAAcD,EAAM,OAAS,KAAO,GAAGA,EAAM,KAAK,OAAS,QAAG,EAClEC,EAAI,eAAgBD,EAAM,SAAW,KAAO,GAAGA,EAAM,QAAQ,QAAQ,CAAC,CAAC,SAAQ,QAAG,EAClFjH,EAAW,UAAU,OAAO,QAAQ,EAChCC,IAAaA,GAAY,UAAU,OAAO,QAAQ,CACxD,CAEA,SAASwD,IAAsB,CACzBzD,GAAYA,EAAW,UAAU,IAAI,QAAQ,EAC7CC,IAAaA,GAAY,UAAU,IAAI,QAAQ,EACnD,CACE,eACA,eACA,gBACA,gBACA,gBACA,aACA,cACF,EAAE,QAASkH,GAAO,CAChB,IAAMnE,EAAK,SAAS,cAAc,IAAImE,CAAE,cAAc,EAClDnE,IAAIA,EAAG,YAAc,KAC3B,CAAC,CACH,CAIA,SAASqE,GAAiBjF,EAAcC,EAAcM,EAAc,GAAO,CACzE,GAAI,CAACpE,EAAc,OACnB,IAAMkG,EAAMlG,EAAa,OACnBmG,EAAKD,EAAI,KAAM3B,GAAMA,EAAE,MAAQ,IAAI,GAAG,MAAQ,EAC9CwE,IAAkB7C,EAAIA,EAAI,OAAS,CAAC,GAAG,MAAQ,GAAKC,GAAM,IAG5DtC,EAAO,OAAMA,GAAQA,EAAOsC,GAAM,KAClCrC,EAAO,OAAMA,GAAQA,EAAOqC,GAAM,KAGtCtC,EAAO,KAAK,IAAI,EAAG,KAAK,IAAIA,EAAMkF,CAAa,CAAC,EAChDjF,EAAO,KAAK,IAAI,EAAG,KAAK,IAAIA,EAAMiF,CAAa,CAAC,EAEhD,IAAM3C,EAAW4C,GAAoB,CACnC,GAAIjJ,IAAU,OAAQ,OAAOiJ,EAC7B,IAAMxC,EAAUL,EAAK6C,EAAU,IAC3B1C,EAAMJ,EAAI,UAAW3B,KAAOA,GAAE,MAAQ,IAAMiC,CAAO,EACvD,OAAIF,IAAQ,KAAIA,EAAMJ,EAAI,OAAS,IAC3BA,EAAII,CAAG,EAAE,MAAQ,GAAK,GAChC,EAEM2C,EAAO7C,EAAQvC,CAAI,EACnBqF,EAAO9C,EAAQtC,CAAI,EAEzB5D,EAAe+I,EACf9I,EAAY+I,EACZvI,EAAgB,CAACsI,EAAMC,CAAI,EACvB,CAAA9E,IACJ3E,EAAe,GACfN,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAM,CAC9BA,EAAE,MAAM,IAAMA,EAAE,SAAS,IAAK,CAAE,IAAKwG,EAAM,IAAKC,CAAK,CAAC,CAAC,CACzD,CAAC,EACDzJ,EAAe,GACf0J,GAAkB,EAClBZ,GAAiB,EACnB,CAEA,SAASzB,IAAS,CAChB,GAAI,CAAC3H,EAAM,QAAU,CAACoC,EAAW,OACjC,IAAM6H,EAAI,KAAK,MACb,KAAK,IACH,IACA7H,EAAU,sBAAsB,EAAE,MAChCJ,GACCE,EAAeH,EAASE,EAAW,EACxC,CACF,EACIiI,EAAa,GACjBlK,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,WAAA6G,EAAY,SAAAC,CAAS,IAAM,CAChDH,IAAM3G,EAAE,QACVA,EAAE,QAAQ,CAAE,MAAO2G,EAAG,OAAQ3G,EAAE,MAAO,CAAC,EACxC4G,EAAa,GACThI,GAAgBiI,GAAcC,GAAUC,GAAcF,EAAYC,EAAU9G,EAAE,MAAM,EAE5F,CAAC,EACG4G,GAAYf,GAAiB,CACnC,CAGA,SAASxD,GAAO2E,EAAY,GAAO,CACjC,IAAIC,EAAsC,KACtCC,EAAc,EAGlB,GAFIF,GAAalI,IAAWoI,EAAcpI,EAAU,WAEhDkI,GAAa9I,EACf+I,EAAa,CAAC/I,EAAc,CAAC,EAAGA,EAAc,CAAC,CAAC,UACvC8I,GAAatK,EAAM,OAAQ,CACpC,IAAMsD,GAAItD,EAAM,CAAC,EAAE,MACnBuK,EAAa,CAACjH,GAAE,OAAO,EAAG,IAAMA,GAAE,OAAO,EAAG,GAAI,CAClD,CAEA,GAAI,CAACzC,EAAc,CACjBgF,GAAayE,CAAS,EACtB,MACF,CACA,IAAMvD,EAAMlG,EAAa,OACzB,GAAI,CAACkG,EAAI,OAAQ,CACflB,GAAayE,CAAS,EACtB,MACF,CAEA,IAAM/B,EAAQ1H,GAAc,MACtB2H,EAAWD,EAAQE,GAAOF,EAAM,YAAY,CAAC,EAAI,KACjDG,EAAcF,GAAU,eAAiB,QAEzCG,EADWC,GAAS,IAAI,EACM,YAAcF,EAC5CG,EAAWL,GAAU,UAAY,KAEjCiC,EAAY,CAAC,GAAGjK,CAAa,EAAE,OAAQ6E,IAC3C0B,EAAI,KAAM3B,IAAMA,GAAEF,GAAQG,EAAC,EAAE,KAAK,GAAK,IAAI,CAC7C,EACA,GAAI,CAACoF,EAAU,OAAQ,CACrB5E,GAAayE,CAAS,EAClBjI,IACFA,EAAQ,MAAM,QAAU,OACxBA,EAAQ,UAAY;AAAA;AAAA;AAAA,WAKtB,MACF,CACIA,IAASA,EAAQ,MAAM,QAAU,QAErC,IAAMqI,EAAatI,EAAYA,EAAU,sBAAsB,EAAE,MAAQ,IACnE6H,GAAI,KAAK,MACb,KAAK,IAAI,IAAKS,EAAa1I,GAAoBE,EAAeH,EAASE,EAAW,EAAE,CACtF,EAEM0I,GACJL,GACArK,IAAkBY,GAClBX,IAAkBU,GAClBT,IAAsBwI,GACtBvI,IAA2BoC,IAC3BxC,EAAM,OAAS,EAEbqJ,EACJ,GAAIsB,GACFtB,EAAQrJ,EAAM,CAAC,EAAE,cACRY,IAAU,WACnByI,EAAQtC,EAAI,IAAK3B,KAAOA,GAAE,MAAQ,GAAK,GAAI,MACtC,CACL,IAAM4B,GAAKD,EAAI,KAAM3B,IAAMA,GAAE,MAAQ,IAAI,GAAG,MAAQ,EAChDwF,GAAa,EACjBvB,EAAQtC,EAAI,IAAK3B,KACXA,GAAE,MAAQ,OACZwF,IAAcxF,GAAE,KAAO4B,IAAM,KACtB4D,GAGV,CACH,CAEA,IAAMC,GAAgB,IAAI,IAC1B,GAAIF,GAAU,CACRxI,IAAeA,EAAc,MAAM,QAAU,QACjD,IAAM2I,GAAW,IAAI,IAAIL,CAAS,EAClC,QAAWrF,MAAKpF,EAAO,CACrB,IAAM+K,GAAarK,EAAgB,IAAI0E,GAAE,SAAS,EAC5C4F,GAAYrK,EAAqB,IAAIyE,GAAE,SAAS,EAEpD0F,GAAS,IAAI1F,GAAE,SAAS,GACxBA,GAAE,WAAa2F,IACf3F,GAAE,UAAY4F,IACd5F,GAAE,IAAM6E,GAERY,GAAc,IAAIzF,GAAE,UAAWA,EAAC,GAEhC/E,EAAS,MAAM+E,GAAE,KAAK,EACtBA,GAAE,MAAM,QAAQ,EAChBA,GAAE,IAAI,OAAO,EAEjB,CACApF,EAAQ,CAAC,CACX,MACE6F,GAAayE,CAAS,EAGxB,GAAIlI,EAAW,CACb,IAAM6I,GAA0C,IAAI,MAAMR,EAAU,MAAM,EAAE,KAAK,IAAI,EACjFS,GAAmC,KACvC,QAASC,GAAIV,EAAU,OAAS,EAAGU,IAAK,EAAGA,KAAK,CAC9CF,GAAgBE,EAAC,EAAID,GACrB,IAAME,GAAKP,GAAc,IAAIJ,EAAUU,EAAC,CAAC,EACrCC,KAAIF,GAAeE,GAAG,IAC5B,CAEAX,EAAU,QAAQ,CAACpH,GAAK8D,KAAQ,CAC9B,IAAMkE,GAASR,GAAc,IAAIxH,EAAG,EACpC,GAAIgI,GAAQ,CACVrL,EAAM,KAAKqL,EAAM,EACjB,IAAMC,GAAQD,GAAO,MACfE,GAAKD,GAAc,SACnBE,GAAWlL,EACjBA,EAAe,GACfgL,GAAM,MAAM,IAAM,CAEdf,IACCe,GAAM,OAAO,EAAG,MAAQf,EAAW,CAAC,GAAKe,GAAM,OAAO,EAAG,MAAQf,EAAW,CAAC,GAE9Ee,GAAM,SAAS,IAAK,CAAE,IAAKf,EAAW,CAAC,EAAG,IAAKA,EAAW,CAAC,CAAE,CAAC,GAE9DgB,IAAG,kBAAkBD,GAAM,OAAO,EAAG,IAAMA,GAAM,OAAO,EAAG,IAAMA,EAAK,EACtEA,GAAM,OAAO,EAAK,EAEtB,CAAC,EACDhL,EAAekL,GAEf,IAAIC,GAA+B,KACnC,GACEtK,GAAe,MACfkK,GAAO,MAAMlK,CAAW,GAAK,MAC7BkK,GAAO,MAAMlK,CAAW,GAAK,OAE7BuK,GAAcL,GAAO,QAAQ,EACzBA,GAAO,SAAS,KAAO,MAAQA,GAAO,SAAS,KAAO,MAAM,CAC9D,IAAMM,GAAON,GAAO,SAAS,IAAMA,GAAO,SAAS,KAAO,EAC1DI,GAAgB,KAAK,IACnBJ,GAAO,SAAS,KAAO,EACvB,KAAK,OACDA,GAAO,MAAMlK,CAAW,EAAKkK,GAAO,SAAS,KAAOM,GACpDN,GAAO,SAAS,IACpB,CACF,EACAA,GAAO,aAAeA,GAAO,MAAMlK,CAAW,CAChD,CAEFkJ,GAAcgB,GAAO,WAAYA,GAAO,SAAU,IAAKI,EAAa,EACpE,MACF,CAEA,IAAItG,GAAMD,GAAQ7B,EAAG,EAEjBuI,GAAYzG,GAAI,UAChBqE,GAAMrE,GAAI,IACV0G,GAAU1G,GAAI,QACd2G,GAAO3G,GAAI,KACX4G,GAAQ5G,GAAI,MAEZ9B,KAAQ,SAAWsF,IAAc,SACnCoD,GAAQ,OACRD,GAAO,OAAOjD,CAAQ,GACtBW,GAAOlB,IAAM0D,GAAQ1D,EAAC,EACtBuD,GAAWvD,IAAM0D,GAAQ1D,EAAC,EAC1BsD,GAAatD,IACPA,IAAK,MAAQA,GAAI,GAAY,MACzBO,IAAa,KAAO,IAAO,KAAOP,GAG5CnD,GAAM,CAAE,GAAGA,GAAK,MAAA4G,GAAO,KAAAD,GAAM,IAAAtC,GAAK,QAAAqC,GAAS,UAAAD,EAAU,GAGvD,IAAIxD,GAAQjD,GAAI,QACZA,GAAI,QAAQ4B,EAAKkF,EAAS,EAC1BA,GACElF,EAAI,IAAK3B,IAAM,CACb,IAAMkD,GAAIlD,GAAED,GAAI,KAAK,EACrB,OAAOmD,IAAK,MAAQsD,GAAYA,GAAUtD,EAAC,EAAIA,EACjD,CAAC,CACH,EAEA5H,EAAgB,IAAI2C,EAAG,IAAG+E,GAAQ8D,GAAe9D,GAAOjD,GAAI,aAAe,CAAC,GAEhFgH,GAAY9I,GAAK8B,GAAKkE,EAAOjB,GAAO6B,GAAGlD,EAAKwD,EAAYU,GAAgB9D,EAAG,CAAC,CAC9E,CAAC,CACH,CAEAlH,EAAgBY,EAChBX,EAAgBU,EAChBT,EAAoBwI,EACpBvI,EAAyBoC,GAEzBkD,GAAY7E,CAAY,EAEpBE,GAAgB,MAAQC,GAAa,MAAMgJ,GAAkB,EAEjEjC,GAAoB,EAChBvF,IAAgBwF,GAAgB,EAEhCsC,GAAalI,GAAaoI,EAAc,IAAGpI,EAAU,UAAYoI,EACvE,CAGA,SAAS2B,GACP9F,EACAlB,EACAkE,EACAjB,EACA6B,EACAlD,EACAqF,EAAwC,KACxCC,EAAqC,KACrC,CACA,IAAM9D,EAAQ1H,GAAc,MAEtB6H,GADWH,EAAQE,GAAOF,EAAM,YAAY,CAAC,EAAI,OACzB,eAAiB,QAEzCI,GADWC,GAAS,IAAI,EACM,YAAcF,EAG5C4D,GAAWjG,IAAc,YAAckG,GAAexF,EAAK,EAAE,EAAI,KACjEyF,EAAM,SAAS,cAAc,KAAK,EACxCA,EAAI,UAAY,YAChBA,EAAI,QAAQ,OAASnG,EACrBmG,EAAI,MAAM,YAAY,gBAAiBrH,EAAI,KAAK,EAGhD,IAAMsH,GAAS,SAAS,cAAc,KAAK,EAC3CA,GAAO,UAAY,mBAAmBvK,EAAe,kBAAoB,EAAE,GAE3E,IAAMwK,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,wBACpBA,GAAQ,UAAY;AAAA,mFAC2DvH,EAAI,KAAK,KAAKA,EAAI,IAAI;AAAA,sCACnEA,EAAI,KAAK;AAAA,MAI3C,IAAMwH,GAAY,SAAS,cAAc,QAAQ,EACjDA,GAAU,UAAY,2BAA2BjM,EAAgB,IAAI2F,CAAS,EAAI,UAAY,EAAE,GAChGsG,GAAU,MAAQ,wBAClBA,GAAU,UAAY,0CAA0CjM,EAAgB,IAAI2F,CAAS,EAAI,UAAY,UAAU,UACvHsG,GAAU,iBAAiB,QAAUvJ,IAAM,CACzCA,GAAE,gBAAgB,EACd1C,EAAgB,IAAI2F,CAAS,EAAG3F,EAAgB,OAAO2F,CAAS,EAC/D3F,EAAgB,IAAI2F,CAAS,EAElCV,GAAO,EAAI,CACb,CAAC,EAED,IAAMiH,GAAc,SAAS,cAAc,QAAQ,EAEnDA,GAAY,UAAY,yBAAyBpK,KAAmB6D,EAAY,UAAY,EAAE,GAC9FuG,GAAY,QAAQ,OAASvG,EAC7BuG,GAAY,MAAQ,iCACpBA,GAAY,UAAY,yDACxBA,GAAY,iBAAiB,QAAS,IAAM9E,GAAezB,CAAS,CAAC,EAGrE,IAAIwG,GAAoC,KACxC,GAAIxG,IAAc,WAAaA,IAAc,SAAWA,IAAc,QAAS,CAC7EwG,GAAU,SAAS,cAAc,QAAQ,EACzC,IAAMC,GAAUnM,EAAqB,IAAI0F,CAAS,EAClDwG,GAAQ,UAAY,gBAAgBC,GAAU,UAAY,EAAE,GAC5DD,GAAQ,MAAQC,GAAU,+BAAiC,+BAC3DD,GAAQ,UAAY,0CAA0CC,GAAU,gBAAkB,YAAY,UACtGD,GAAQ,iBAAiB,QAAUzJ,IAAM,CACvCA,GAAE,gBAAgB,EACdzC,EAAqB,IAAI0F,CAAS,EAAG1F,EAAqB,OAAO0F,CAAS,EACzE1F,EAAqB,IAAI0F,CAAS,EACvCV,GAAO,EAAI,CACb,CAAC,CACH,CAEA,IAAMoH,GAAe,SAAS,cAAc,KAAK,EACjDA,GAAa,UAAY,oBAEzB,IAAMC,GAAa,SAAS,cAAc,KAAK,EAC/CA,GAAW,UAAY,wBAEvB,IAAMC,GAAiB,SAAS,cAAc,KAAK,EACnDA,GAAe,UAAY,4BAC3BA,GAAe,OAAOF,GAAcC,EAAU,EAE9C,IAAME,GAAY,SAAS,cAAc,KAAK,EAC9CA,GAAU,UAAY,oBACtBA,GAAU,OAAOP,GAAWC,EAAW,EAEvC,IAAMO,GAAiB,SAAS,cAAc,KAAK,EAGnD,GAFAA,GAAe,UAAY,0BAEvB9G,IAAc,QAAS,CACzB,IAAM+G,GAAa,SAAS,cAAc,KAAK,EAC/CA,GAAW,UAAY,WACvBA,GAAW,UAAY;AAAA,iCACIzE,KAAc,QAAU,SAAW,EAAE;AAAA,iCACrCA,KAAc,OAAS,SAAW,EAAE;AAAA,QAE/DyE,GAAW,iBAAiB,QAAUhK,IAAM,CAC1C,IAAMiK,GAAOjK,GAAE,OAAuB,QAAQ,UAAU,EACxD,GAAI,CAACiK,GAAK,OACV,IAAMC,GAAOD,GAAI,QAAQ,KACzB,GAAIC,KAAS,SAAWA,KAAS,OAAQ,CACvC,IAAMC,GAAYD,KAAS5E,EAC3BE,GAAS,MAAM,CAAE,WAAY2E,GAAY,KAAOD,EAAK,CAAC,EACtD3H,GAAO,EAAI,CACb,CACF,CAAC,EACDwH,GAAe,OAAOC,EAAU,CAClC,CAEIP,IAASM,GAAe,OAAON,EAAO,EAE1CJ,GAAO,OAAOC,GAASQ,GAAWD,GAAgBE,EAAc,EAEhE,IAAMK,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,iBAEpB,IAAMC,GAAS,SAAS,cAAc,KAAK,EAC3CA,GAAO,MAAM,SAAW,WACxBD,GAAQ,YAAYC,EAAM,EAE1B,IAAMC,GAAgB,SAAS,cAAc,KAAK,EAClDA,GAAc,UAAY,4BAC1B,IAAMC,GAAgB,SAAS,cAAc,KAAK,EAClDA,GAAc,UAAY,4BAC1BF,GAAO,OAAOC,GAAeC,EAAa,EAE1C,IAAMjG,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,WAAWxF,EAAe,WAAa,EAAE,GAC7D,IAAMiI,GAAa,SAAS,cAAc,QAAQ,EAClDA,GAAW,UAAY,cACvBzC,GAAQ,YAAYyC,EAAU,EAC9BqD,GAAQ,YAAY9F,EAAO,EAE3B8E,EAAI,OAAOC,GAAQe,EAAO,EAE1B,IAAMI,GAAahN,IAAU,WAE7B,SAASiN,GAAQvF,GAAWwF,GAAuB,CACjD,GAAIxF,IAAK,KAAM,MAAO,GACtB,GAAIsF,GAAY,CACd,IAAMG,GAAMD,GAAQ,EAAI,EAAIA,GAAQ,EAAI,EAAIA,GAAQ,GAAK,EAAI,EAC7D,MAAO,GAAGxF,GAAE,QAAQyF,EAAG,CAAC,KAC1B,KAAO,CACL,IAAMC,GAAO,KAAK,IAAI1F,EAAC,EACjB2F,GAAI,KAAK,MAAMD,GAAO,IAAI,EAC1B3I,GAAI,KAAK,MAAO2I,GAAO,KAAQ,EAAE,EACjCzC,GAAI,KAAK,MAAMyC,GAAO,EAAE,EACxBE,GAAKD,GAAI,EAAI,GAAGA,EAAC,IAAM,GACvBE,GAAKF,GAAI,EAAI,OAAO5I,EAAC,EAAE,SAAS,EAAG,GAAG,EAAI,OAAOA,EAAC,EAClD+I,GAAK,OAAO7C,EAAC,EAAE,SAAS,EAAG,GAAG,EACpC,MAAO,GAAGjD,GAAI,EAAI,IAAM,EAAE,GAAG4F,EAAE,GAAGC,EAAE,IAAIC,EAAE,EAC5C,CACF,CAEA,IAAMC,GACJ1N,EAAqB,IAAI0F,CAAS,GACjCA,IAAc,SAAWA,IAAc,WAAaA,IAAc,QAGjEiI,GAAO,IACTC,GAAO,KACPC,GAAS,EACTC,GAAW,EACXC,GAAU,IACVC,GAAU,KACVC,GAAU,EACVC,GAAY,EACd,QAAS1D,GAAI,EAAGA,GAAI/C,EAAM,OAAQ+C,KAAK,CACrC,IAAM7C,GAAIF,EAAM+C,EAAC,EACb7C,IAAK,MAAQ,CAAC,SAASA,EAAC,IACxBA,GAAIgG,KAAMA,GAAOhG,IACjBA,GAAIiG,KAAMA,GAAOjG,IACrBkG,IAAUlG,GACVmG,MACInG,KAAM,GAAK+F,MACT/F,GAAIoG,KAASA,GAAUpG,IACvBA,GAAIqG,KAASA,GAAUrG,IAC3BsG,IAAWtG,GACXuG,MAEJ,CACIJ,KAAa,IACfH,GAAO,EACPC,GAAO,KAET,IAAMO,GAAeL,GAAW,CAAE,IAAKH,GAAM,IAAKC,GAAM,IAAKC,GAASC,EAAS,EAAI,KAC7EM,GAAoBF,GACtB,CAAE,IAAKH,GAAS,IAAKC,GAAS,IAAKC,GAAUC,EAAU,EACvD,KACEG,GAAO,KAAK,IAAIT,GAAOD,EAAI,EAAI,IAAO,EACtCW,GAAc,CAACX,GAAOU,GAAMT,GAAOS,EAAI,EAEzCE,GAAwB,GAG5B,SAASC,GAAkBC,GAAoBC,GAAoB/L,GAAW,CAC5E,IAAMwJ,GACJnM,EAAqB,IAAI0F,CAAS,GACjCA,IAAc,SAAWA,IAAc,WAAaA,IAAc,QAG/DyH,GAAQuB,GAAaD,GAC3B1B,GAAc,YAAcG,GAAQuB,GAAYtB,EAAK,EACrDH,GAAc,YAAcE,GAAQwB,GAAYvB,EAAK,EAErD,IAAMwB,GAAU,CAACxF,GAAcC,GAAcwF,GAAS,KAAU,CAC9D,IAAMhE,GACJgE,IAAUzC,KAAYuB,GAClBU,GACAS,GAAWnG,EAAOjB,EAAO0B,GAAMC,GAAM+C,EAAO,EAClD,GAAI,CAACvB,GAAG,MAAO,GAEf,IAAI0C,GAAI;AAAA,kHACkG9I,EAAI,IAAIoG,GAAE,IAAK,EAAI,CAAC,SAASpG,EAAI,IAAI;AAAA,gHACvCA,EAAI,IAAIoG,GAAE,IAAK,EAAI,CAAC,SAASpG,EAAI,IAAI;AAAA,oHACjCA,EAAI,IAAIoG,GAAE,IAAK,EAAI,CAAC,SAASpG,EAAI,IAAI;AAAA,UAGjJ,GAAIkB,IAAc,YAAa,CAC7B,IAAMoJ,GAAKC,GAAoB3I,EAAK+C,GAAMC,EAAI,EAC9CkE,IAAK;AAAA,mHACoG,KAAK,MAAMwB,GAAG,IAAI,CAAC;AAAA,qHACjB,KAAK,MAAMA,GAAG,IAAI,CAAC;AAAA,WAEhI,CACA,OAAOxB,EACT,EAEKiB,KACHA,GAAwB,GACxBnC,GAAa,UAAY,mHAAmHuC,GAC1IjG,EAAM,CAAC,EACPA,EAAMA,EAAM,OAAS,CAAC,EACtB,EACF,CAAC,GACD0D,GAAa,cAAc,WAAW,GAAG,iBAAiB,QAAU3J,IAAM,CACxEA,GAAE,gBAAgB,EAClBH,EAAgB,CAClB,CAAC,GAGClC,IAAiB,MAAQC,IAAc,MACzCgM,GAAW,UAAYsC,GAAQvO,EAAcC,EAAW,EAAK,EAC7DgM,GAAW,MAAM,QAAU,OAC3BA,GAAW,MAAM,YAAY,cAAe7H,EAAI,KAAK,GAErD6H,GAAW,MAAM,QAAU,MAE/B,CACA,IAAI2C,GAAoB,GAClBC,GAAuB,CAC3B,MAAO3F,EACP,OAAQ,IACR,QAAS,CAAC,EAAG,EAAG,EAAG,CAAC,EACpB,OAAQ,CACN,KAAM,CACJ,IAAK5J,EAAS,GAChB,EACA,KAAM,CAAE,EAAG,GAAM,EAAG,GAAO,IAAK,EAAG,EACnC,MAAO,CAAE,KAAM,EAAG,EAClB,OAAQ,CACN,KAAM,EACN,OAAQ,UACR,MAAO,EACP,KAAOgG,IAAc,YACjB,CAAC/C,GAAUuM,KAAgB/G,GAAcwD,GAAWA,GAAShJ,GAAE,OAAO,GAAI,EAAK,IAAI,EACnF6B,EAAI,KACV,EACA,EAAG,GACH,EAAG,EACL,EACA,OAAQ,CACN,KAAM,GACN,KAAM,EACN,IAAK,EACL,MAAO,EACP,OAAQ,CACV,EACA,OAAQ,CAAE,KAAM,EAAM,EACtB,OAAQ,CACN,EAAG,CACD,KAAM,GACN,MAAO,CAAC2K,GAAWC,GAAYC,KAAe,CAACD,GAAIC,EAAE,EACrD,IAAK5D,EAAeA,EAAa,CAAC,EAAI,OACtC,IAAKA,EAAeA,EAAa,CAAC,EAAI,MACxC,EACA,EAAG,CACD,MAAO,IAAM6C,GACb,IAAK5I,IAAc,SAAWsC,KAAc,OAAS,GAAK,CAC5D,CACF,EACA,KAAM,CACJ,CACE,KAAM,EACN,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,MAAO,CACL,KAAM,GACN,OAAQ,SACV,EACA,KAAM,GACN,MAAO,GACP,KAAM,6BACN,OAAQ,CAACrF,GAAU2M,GAAiBC,GAAkBC,KAAqB,CACzE,IAAMrC,GAAQqC,GAAWD,GAEnBE,IADQ9M,GAAE,KAAK,MAAQ,EAAIA,GAAE,KAAK,MAAQA,GAAE,OACrB,GACvB+M,GAAYvC,GAAQsC,GAEtBE,GACC1C,GAOH0C,GAAQ,CACN,IAAM,IAAM,IAAM,GAAK,GAAK,IAAM,GAAK,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAC3E,IAAM,IAAM,IAAO,IAAO,IAAO,IAAQ,IAAQ,IAAQ,GAC3D,EARAA,GAAQ,CACN,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,KAAM,KAAM,KAAM,MAAO,MAAO,MAC7E,MAAO,OAAQ,OAAS,OAC1B,EAQF,IAAIC,GAAOD,GAAMA,GAAM,OAAS,CAAC,EACjC,QAASnF,GAAI,EAAGA,GAAImF,GAAM,OAAQnF,KAChC,GAAImF,GAAMnF,EAAC,GAAKkF,GAAW,CACzBE,GAAOD,GAAMnF,EAAC,EACd,KACF,CAGF,IAAMqF,GAAS,CAAC,EACZtJ,GAAM,KAAK,KAAKgJ,GAAWK,EAAI,EAAIA,GACjCE,GAAYF,GAAO,EAAI,EAAI,EAEjC,KAAOrJ,IAAOiJ,IAAU,CACtB,IAAMO,GAAMpN,GAAE,SAAS4D,GAAK,IAAK,EAAI,EACjCwJ,IAAOpN,GAAE,KAAK,KAAO,IAAMoN,IAAOpN,GAAE,KAAK,KAAOA,GAAE,KAAK,MAAQ,IACjEkN,GAAO,KAAK,OAAOtJ,GAAI,QAAQuJ,EAAS,CAAC,CAAC,EAE5CvJ,IAAOqJ,EACT,CACA,OAAOC,EACT,EACA,OAAS,CAACV,GAAWzH,KAAmB,CACtC,IAAMyF,IAASgC,GAAG,OAAO,GAAG,KAAO,IAAMA,GAAG,OAAO,GAAG,KAAO,GAE7D,OAAOzH,GAAK,IAAKC,IAAM,CACrB,GAAIA,IAAK,KAAM,MAAO,GACtB,IAAMoI,GAAMZ,GAAG,SAASxH,GAAG,IAAK,EAAI,EAEpC,OAAIoI,GAAMZ,GAAG,KAAK,KAAO,IAAMY,GAAMZ,GAAG,KAAK,KAAOA,GAAG,KAAK,MAAQ,GAAW,KACxEjC,GAAQvF,GAAGwF,EAAK,CACzB,CAAC,CACH,CACF,EACA,CACE,KAAM,EACN,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,MAAO,CAAE,OAAQ,SAAU,EAC3B,KAAM,GACN,KAAM,6BACN,OAAS,CAACgC,GAAWzH,KACnBA,GAAK,IAAKC,IAAOA,IAAK,KAAOnD,EAAI,QAAQmD,EAAC,EAAI,EAAG,CACrD,CACF,EACA,OAAQ,CACN,CAAC,EAED,CACE,MAAOnD,EAAI,MACX,OAAQ,gBACR,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,EACtB,MAAO,IAAM,IACf,CACF,EACA,MAAO,CACL,KAAM,CACH7B,IAAa,CACZ,IAAMqN,GAAMrN,GAAE,KAAK,IAAMA,GAAE,KAAK,OAAS,EACzCoK,GAAc,MAAM,IAAM,GAAGiD,EAAG,KAChCjD,GAAc,MAAM,KAAO,GAAGpK,GAAE,KAAK,IAAI,KAEzCqK,GAAc,MAAM,IAAM,GAAGgD,EAAG,KAChChD,GAAc,MAAM,KAAO,GAAGrK,GAAE,KAAK,KAAOA,GAAE,KAAK,KAAK,KACxDqK,GAAc,MAAM,UAAY,mBAClC,EAECrK,IAAa,CACR+C,IAAc,QAChBuK,GACEtN,GACA+F,EACAjB,EACAjD,EAAI,MACJ,IACAkB,EACA,KACAU,CACF,EACSV,IAAc,YACvBwK,GAAsBvN,GAAG+F,EAAmBjB,EAAmBkE,EAAQ,EAC9DjG,IAAc,WACvByK,GAAkBxN,GAAG+F,EAAmBjB,CAAiB,EAChD5F,KAAmB6D,EAC5B0K,GAAoBzN,GAAG+F,EAAmBjB,EAAmBrB,EAAKV,CAAS,EAG3EuK,GACEtN,GACA+F,EACAjB,EACAjD,EAAI,MACJ,IACAkB,EACA,KACAU,CACF,CAEJ,EAGCzD,IAAa,CACZ,IAAM2E,GAAOjI,EAAM,KAAMoF,IAAMA,GAAE,QAAU9B,EAAC,EAC5C,GAAI,CAAC2E,GAAM,OAEX,IAAMsD,GAAKjI,GAAU,SAEjBnC,GAAe,KACjB6P,GAAc1N,GAAG+F,EAAOjB,EAAOjD,EAAI,MAAOA,EAAK4B,EAAKV,CAAS,GAEzDkF,IAAKA,GAAE,UAASA,GAAE,QAAQ,MAAM,QAAU,QAG1CtD,GAAK,aAAe,MACtBgJ,GAAmB3N,GAAG+F,EAAOjB,EAAOH,GAAK,YAAa9C,EAAI,MAAOA,CAAG,EAE1E,EAGC7B,IAAa,CACZ,IAAM4N,GAAO5N,GAAE,OAAO,IAChB6N,GAAYhQ,GAAe,KAE7BiQ,GAAWF,IAAQ,MAAQ5N,GAAE,OAAO,MAAS,EACjD,GAAI8N,IAAYjQ,GAAe,KAAM,CACnC,IAAMkQ,GAAK/N,GAAE,SAAS8E,EAAM8I,EAAK,EAAI,IAAK,EAAI,EACjC,KAAK,IAAI5N,GAAE,OAAO,IAAO+N,EAAE,EAC7B,MAAKD,GAAW,GAC7B,CAOA,GAJIA,IAAYF,KAAS/P,GACvBmQ,GAAqBhO,GAAGyD,EAAKmK,GAAOK,GAAUpM,EAAI,MAAO,EAAG,EAAG,CAAG,EAGhEpE,GAAgB,MAAQC,GAAa,KAAM,CAC7C,IAAMwQ,GAAMlO,GAAE,IACRmO,GAAM,OAAO,kBAAoB,EACjCC,GAAKpO,GAAE,KACPqO,GAAKrO,GAAE,SAASvC,EAAc,IAAK,EAAI,EACvCqK,GAAK9H,GAAE,SAAStC,EAAW,IAAK,EAAI,EAE1CwQ,GAAI,KAAK,EACTA,GAAI,UAAU,EACdA,GAAI,UAAY,EAAIC,GACpBD,GAAI,YAAcrM,EAAI,MACtBqM,GAAI,OAAOG,GAAID,GAAG,IAAMA,GAAG,MAAM,EACjCF,GAAI,OAAOpG,GAAIsG,GAAG,IAAMA,GAAG,MAAM,EACjCF,GAAI,OAAO,EAEX,IAAM7F,GAAO,KAAK,IAAI3K,EAAYD,CAAY,EACxCgL,GAAQnL,IAAU,WAAa,GAAG+K,GAAK,QAAQ,CAAC,CAAC,MAAQjC,GAAQiC,EAAI,EACrEiG,GAAW,EAAIH,GACfI,GAAU,QAAQD,EAAQ,2BAC5BJ,GAAI,OAASK,KAASL,GAAI,KAAOK,IACrC,IAAMC,GAAKN,GAAI,YAAYzF,EAAK,EAAE,MAE5BgG,GAAW,KAAK,IAAIL,GAAG,KAAMC,EAAE,EAC/BK,GAAW,KAAK,IAAIN,GAAG,KAAOA,GAAG,MAAOtG,EAAE,EAGhD,GAFiB4G,GAAWD,GAEbD,GAAK,GAAKL,GAAK,CAC5B,IAAMQ,GAAO,EAAIR,GACXS,GAAO,EAAIT,GACXU,GAAKL,GAAKG,GAAO,EACjBG,GAAKR,GAAWM,GAAO,EACvBG,IAAMN,GAAWC,IAAY,EAAIG,GAAK,EACtCG,GAAKZ,GAAG,IAAMA,GAAG,OAASU,GAAK,EAErCZ,GAAI,UAAU,EACTA,GAAY,UAAYA,GAAY,UAAUa,GAAIC,GAAIH,GAAIC,GAAI,EAAIX,EAAG,EACrED,GAAI,KAAKa,GAAIC,GAAIH,GAAIC,EAAE,EAC5BZ,GAAI,UAAYrM,EAAI,MACpBqM,GAAI,KAAK,EAETA,GAAI,UAAY,OAChBA,GAAI,UAAY,SAChBA,GAAI,aAAe,SACnBA,GAAI,SAASzF,GAAOsG,GAAKF,GAAK,EAAGG,GAAKF,GAAK,CAAC,CAC9C,CACAZ,GAAI,QAAQ,CACd,CAIIL,IAAWoB,GAAgBjP,GAAGyD,EAAK5F,EAAcgE,EAAI,MAAO,GAAM,EAAG,EAGrEiM,IAAYF,KAAS/P,GACvBoR,GAAgBjP,GAAGyD,EAAKmK,GAAO/L,EAAI,MAAO,GAAM,CAAG,CACvD,CACF,EACA,UAAW,CACR7B,IAAa,CACZ,GAAIhD,EAAc,OAClB,IAAM6G,GAAM7D,GAAE,OAAO,IAIrBA,GAAE,OAAO,EAAK,EAGVA,GAAE,OAAO,MAAS,EAAGlC,EAAgBkC,GAAE,SAASA,GAAE,OAAO,KAAO,GAAG,EAClElC,EAAgB,KAGrB,IAAMmK,GAAKjI,GAAU,SACjBkP,GAAYrL,IAAO,MAAQiB,EAAMjB,EAAG,GAAK,KAG7C,GAAIqL,IAAarR,GAAe,KAAM,CACpC,IAAMkQ,GAAK/N,GAAE,SAAS8E,EAAMjB,EAAI,EAAI,IAAK,EAAI,EAChC,KAAK,IAAI7D,GAAE,OAAO,IAAO+N,EAAE,EAC7B,MAAKmB,GAAY,GAC9B,CAgCA,GA9BIjH,KACEiH,GACFC,GACEnP,GACAiI,GAAE,QACFpE,GACAkC,EACAjB,EACArB,EACA5B,EACAkB,CACF,EACGkF,GAAE,QAAQ,MAAM,QAAU,QAI5BhL,IACC4G,IAAO,MAAQJ,EAAII,EAAG,EACpBxF,IAAmBR,GAAe,MAAQqR,IAC5C7Q,EAAeoF,EAAII,EAAG,CAAC,EACdxF,GAAkB,CAAC6Q,IAE5B7Q,EAAe,IAAI,EAEZwF,KAAQ,MAAQxF,GACzBA,EAAe,IAAI,GAKnBwF,IAAO,MAAQiB,EAAMjB,EAAG,GAAK,KAAM,CACrC,GAAM,CAAE,IAAA5D,GAAK,IAAAC,EAAI,EAAI4G,GACrB,GAAI7G,IAAO,MAAQC,IAAO,KAAM,CAC9B,IAAMmI,GAAOnI,GAAMD,IAAO,EACpBmP,GAAO,KAAK,IAChBtI,GAAS,KAAO,EAChB,KAAK,OAAQhC,EAAMjB,EAAG,EAAK5D,IAAOoI,GAAQvB,GAAS,IAAI,CACzD,EACInC,GAAK,eAAiBG,EAAMjB,EAAG,IACjCc,GAAK,aAAeG,EAAMjB,EAAG,EAC7BkD,GAAcF,GAAYC,GAAU,IAAKsI,EAAI,EAEjD,CACF,MAAWzK,GAAK,eAAiB,OAC/BA,GAAK,aAAe,KACpBoC,GAAcF,GAAYC,GAAU,GAAG,EAE3C,CACF,EAEA,SAAU,CACR,CAAC9G,GAAUD,KAAgB,CACzB,GAAIA,KAAQ,KAAOsM,GAAmB,OACtC,GAAM,CAAE,IAAApM,GAAK,IAAAC,EAAI,EAAIF,GAAE,OAAO,EAG9B9B,EAAgB,CAAC+B,GAAMC,EAAI,EAG3B2L,GAAkB5L,GAAeC,GAAeF,EAAC,EAE7C,CAAAhD,IAGCY,IAAeO,EAAe,MAGnCnB,EAAe,GACfN,EAAM,QAAQ,CAAC,CAAE,MAAO2S,EAAM,IAAM,CAC9BA,KAAUrP,IAAGqP,GAAM,MAAM,IAAMA,GAAM,SAAS,IAAK,CAAE,IAAKpP,GAAM,IAAKC,EAAK,CAAC,CAAC,CAClF,CAAC,EACDlD,EAAe,GAEf6I,GAAiB,EACjBC,GAAiB,EAEbxH,IAAmBb,IAAiB,MACtCa,GAAgBb,EAAcC,EAAWJ,CAAK,EAClD,CACF,EAEA,UAAW,CACR0C,IAAa,CACZ,GAAIpC,EAAe,OACnBO,EAAe,KACf,GAAM,CAAE,KAAAmR,GAAM,MAAAC,EAAM,EAAIvP,GAAE,OAC1B,GAAIuP,GAAQ,EAAG,CACb,IAAMtP,GAAMD,GAAE,SAASsP,GAAM,GAAG,EAC1BpP,GAAMF,GAAE,SAASsP,GAAOC,GAAO,GAAG,EACxC9R,EAAewC,GACfvC,EAAYwC,GAGZ2L,GAAkB7L,GAAE,OAAO,EAAG,IAAMA,GAAE,OAAO,EAAG,IAAMA,EAAC,EACvD6F,GAAiB,EACjBC,GAAiB,EAEbxH,IAAiBA,GAAgBb,EAAcC,EAAWJ,CAAK,EAGnE0C,GAAE,UAAU,CAAE,KAAM,EAAG,IAAK,EAAG,MAAO,EAAG,OAAQ,CAAE,EAAG,EAAK,CAC7D,CACF,CACF,CACF,CACF,EAGMwP,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,MAAM,QACZ,2EAGF,IAAMC,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,WACpBA,GAAQ,MAAM,QAAU,OAGxB,IAAMC,GAAa,SAAS,cAAc,KAAK,EAC/CA,GAAW,UAAY,2BACvBA,GAAW,MAAM,QAAU,OAE3B,IAAMC,GAAc,SAAS,cAAc,KAAK,EAChDA,GAAY,UAAY,uCACxBA,GAAY,MAAM,QAAU,OAE5B,IAAMC,GAAe,SAAS,cAAc,KAAK,EACjDA,GAAa,UAAY,+BACzBA,GAAa,MAAM,QAAU,OAE7B,IAAMC,GAAe,SAAS,cAAc,KAAK,EACjDA,GAAa,UAAY,mBACzBA,GAAa,UACX,4GACFA,GAAa,MAAM,QAAU,OAG7B,IAAMC,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,wBACpBA,GAAQ,MAAM,QAAU,OAExB,IAAMC,GAAW,SAAS,cAAc,KAAK,EAC7CA,GAAS,UAAY,oCACrBA,GAAS,MAAM,QAAU,OAEzB,IAAMC,GAAY,SAAS,cAAc,KAAK,EAC9CA,GAAU,UAAY,4BACtBA,GAAU,MAAM,QAAU,OAE1B,IAAMC,GAAY,SAAS,cAAc,KAAK,EAC9CA,GAAU,UAAY,mBACtBA,GAAU,UACR,4GACFA,GAAU,MAAM,QAAU,OAG1B,IAAMC,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,YACpBA,GAAQ,MAAM,QAAU,SAASrO,EAAI,KAAK,gBAG1C,IAAMsO,GAAU,SAAS,cAAc,KAAK,EAC5CA,GAAQ,UAAY,gBACpBA,GAAQ,MAAM,QAAU,SAAStO,EAAI,KAAK,gBAE1C2N,GAAQ,OACNC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,EACF,EAEA,IAAMrJ,GAAqB,CACzB,MAAAhC,EACA,MAAOiB,EACP,IAAAlE,EACA,KAAM,GACN,IAAKsJ,GAAWH,GAAO,OACvB,IAAKG,GAAWF,GAAO,OACvB,UAAWQ,GACX,aAAAD,EACF,EACM7G,GAAiB,CACrB,MAAO,KACP,IAAAuE,EACA,MAAOnD,EACP,MAAAjB,EACA,IAAAjD,EACA,UAAAkB,EACA,aAAA0G,GACA,WAAAC,GACA,QAAAtF,GACA,WAAAyC,GACA,SAAAC,GACA,aAAc,KACd,YAAa,KACb,SAAU1J,EAAgB,IAAI2F,CAAS,EACvC,QAAS1F,EAAqB,IAAI0F,CAAS,EAC3C,EAAA4D,CACF,EACAG,GAAS,KAAOnC,GAEhB,IAAMuD,GAAWlL,EACjBA,EAAe,GACf,IAAMgL,GAAQ,IAAItI,GAAM4M,GAAO,CAACvG,EAAOjB,CAAK,EAAU,CAACsL,GAAMhR,KAAS,CACpEuF,GAAK,MAAQyL,GACb1T,EAAM,KAAKiI,EAAI,EACfwF,GAAO,YAAYiG,GAAK,IAAI,EAC5BA,GAAK,KAAK,YAAYZ,EAAO,EAC5BY,GAAa,SAAW,CACvB,QAAAX,GACA,WAAAC,GACA,YAAAC,GACA,aAAAC,GACA,aAAAC,GACA,QAAAC,GACA,SAAAC,GACA,UAAAC,GACA,UAAAC,GACA,QAAAC,GACA,QAAAC,GACA,kBAAAtE,EACF,EACAuE,GAAK,MAAM,IAAM,CACfhR,GAAK,CACP,CAAC,CACH,CAAC,EACDpC,EAAekL,GAGfmI,GAAiBT,GAAc5H,GAAOjC,EAAO,EAAI,EACjDsK,GAAiBL,GAAWhI,GAAOjC,EAAO,EAAK,EAG/C,IAAIuK,GAA4B,KAChCtI,GAAM,KAAK,iBAAiB,YAAclI,IAAM,CAC9C,GAAIA,GAAE,SAAW,EAAG,OACpBnC,EAAa,GACb,IAAM4S,GAAOvI,GAAM,KAAK,sBAAsB,EAE9CsI,GADYxQ,GAAE,QAAUyQ,GAAK,IAE/B,CAAC,EACDvI,GAAM,KAAK,iBAAiB,YAAclI,IAAM,CAC9C,GAAIwQ,KAAe,KAAM,CACvB,IAAMC,GAAOvI,GAAM,KAAK,sBAAsB,EAC1C,KAAK,IAAIlI,GAAE,QAAUyQ,GAAK,KAAOD,EAAU,EAAI,IAAG3S,EAAa,GACrE,CACF,CAAC,EACDqK,GAAM,KAAK,iBAAiB,UAAW,IAAM,CAC3CsI,GAAa,IACf,CAAC,EAGDtI,GAAM,KAAK,iBAAiB,QAAS,IAAM,CACzC,GAAIrK,EAAY,OAChB,IAAMkG,GAAMmE,GAAM,OAAO,IACrBnE,IAAO,MAAQJ,EAAII,EAAG,IACxBhG,EAAcgG,GACdnH,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAE,IAAMA,GAAE,OAAO,EAAK,CAAC,EAC3CzB,IAAWA,GAAUkF,EAAII,EAAG,EAAGA,EAAG,EAClCrF,IAAeA,GAAcqF,EAAG,EAExC,CAAC,EAEDqF,EAAI,iBAAiB,WAAYvJ,CAAe,EAEhD,IAAIwI,GAA+B,KACnC,GAAItK,GAAe,MAAQkI,EAAMlI,CAAW,GAAK,MAAQiH,EAAMjH,CAAW,GAAK,OAC7EuK,GAActB,EAAQ,EAClBA,GAAS,KAAO,MAAQA,GAAS,KAAO,MAAM,CAChD,IAAMuB,GAAOvB,GAAS,IAAMA,GAAS,KAAO,EAC5CqB,GAAgB,KAAK,IACnBrB,GAAS,KAAO,EAChB,KAAK,OAAQhC,EAAMjH,CAAW,EAAKiJ,GAAS,KAAOuB,GAAQvB,GAAS,IAAI,CAC1E,EACAnC,GAAK,aAAeG,EAAMjH,CAAW,CACvC,CAGFkJ,GAAcF,GAAYC,GAAU,IAAKqB,EAAa,EACtDqI,GAAkB3J,GAAYC,EAAQ,EAClChI,IACEiK,EAAgBjK,EAAU,aAAaoK,EAAKH,CAAc,EACzDjK,EAAU,YAAYoK,CAAG,EAElC,CAGA,SAASrD,IAAmB,CAC1Ba,GAAkB,EAElBhK,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAMA,EAAE,MAAM,IAAMA,EAAE,OAAO,EAAK,CAAC,CAAC,CAChE,CAEA,SAAS0G,IAAoB,CAC3BhK,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,IAAA6B,CAAI,IAAM,CACnC,IAAMoG,EAAKjI,EAAU,SACrB,GAAI,CAACiI,EAAG,OACR,GAAM,CACJ,QAAAwH,EACA,WAAAC,EACA,YAAAC,EACA,aAAAC,EACA,aAAAC,EACA,QAAAC,EACA,SAAAC,EACA,UAAAC,EACA,UAAAC,CACF,EAAIhI,EACJ,GAAIxK,GAAgB,MAAQC,GAAa,KAAM,CAC7C,CACE+R,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,CACF,EAAE,QAASjO,IAAoB,CAC7BA,GAAG,MAAM,QAAU,MACrB,CAAC,EACD,MACF,CACA,IAAMyO,GAAKzQ,EAAE,SAASvC,EAAc,GAAG,EACjCiT,GAAK1Q,EAAE,SAAStC,EAAW,GAAG,EAC9ByQ,EAAM,OAAO,kBAAoB,EACjCC,GAAKpO,EAAE,KACP2Q,GAAQvC,GAAG,MAAQD,EACnByC,GAAQxC,GAAG,OAASD,EACpB0C,IAAczC,GAAG,IAAMA,GAAG,QAAUD,EAEpC2C,GAAkBL,IAAM,GAAKA,IAAME,GACnCI,GAAeL,IAAM,GAAKA,IAAMC,GAGhCK,GAAQ,KAAK,IAAI,EAAGP,EAAE,EACtBQ,GAAQ,KAAK,IAAIN,GAAOD,EAAE,EAahC,GAZIO,GAAQD,IACVvB,EAAQ,MAAM,KAAO,GAAGuB,EAAK,KAC7BvB,EAAQ,MAAM,MAAQ,GAAGwB,GAAQD,EAAK,KACtCvB,EAAQ,MAAM,IAAM,IACpBA,EAAQ,MAAM,OAAS,GAAGmB,EAAK,KAC/BnB,EAAQ,MAAM,gBAAkBxB,GAAUpM,EAAI,MAAO,GAAI,EACzD4N,EAAQ,MAAM,QAAU,IAExBA,EAAQ,MAAM,QAAU,OAItBqB,GAAiB,CACnBpB,EAAW,MAAM,KAAO,GAAGe,EAAE,KAC7Bf,EAAW,MAAM,OAAS,GAAGkB,EAAK,KAClClB,EAAW,MAAM,gBAAkB7N,EAAI,MACvC6N,EAAW,MAAM,QAAU,GAE3B,IAAMwB,GAAQC,GAAQ1T,CAAY,EAClCkS,EAAY,YAAcuB,GAC1B,IAAME,GAAUF,GAAM,OAAS,EAAI,GACnCvB,EAAY,MAAM,KAAOc,GAAKW,GAAU,EAAIT,GAAQ,GAAGF,GAAK,CAAC,KAAO,GAAGA,GAAKW,GAAU,CAAC,KACvFzB,EAAY,MAAM,QAAU,GAE5BC,EAAa,MAAM,KAAO,GAAGa,EAAE,KAC/Bb,EAAa,MAAM,gBAAkB/N,EAAI,MACzC+N,EAAa,MAAM,QAAU,GAE7BC,EAAa,MAAM,KAAO,GAAGY,EAAE,KAC/BZ,EAAa,MAAM,IAAM,GAAGgB,EAAU,KACtC,IAAMQ,GAAQxB,EAAa,cAAc,2BAA2B,EAChEwB,KAAOA,GAAM,MAAM,MAAQxP,EAAI,OACnCgO,EAAa,MAAM,QAAU,EAC/B,KACE,CAACH,EAAYC,EAAaC,EAAcC,CAAY,EAAE,QACnD7N,IAAqBA,GAAG,MAAM,QAAU,MAC3C,EAIF,GAAI+O,GAAc,CAChBjB,EAAQ,MAAM,KAAO,GAAGY,EAAE,KAC1BZ,EAAQ,MAAM,OAAS,GAAGc,EAAK,KAC/Bd,EAAQ,MAAM,gBAAkBjO,EAAI,MACpCiO,EAAQ,MAAM,QAAU,GAExB,IAAMwB,GAAQH,GAAQzT,CAAS,EAC/BqS,EAAS,YAAcuB,GACvB,IAAMC,GAAUD,GAAM,OAAS,EAAI,GACnCvB,EAAS,MAAM,KAAOW,GAAKa,GAAU,EAAI,EAAI,GAAGb,GAAKa,GAAU,CAAC,KAAO,GAAGb,GAAK,CAAC,KAChFX,EAAS,MAAM,QAAU,GAEzBC,EAAU,MAAM,KAAO,GAAGU,EAAE,KAC5BV,EAAU,MAAM,gBAAkBnO,EAAI,MACtCmO,EAAU,MAAM,QAAU,GAE1BC,EAAU,MAAM,KAAO,GAAGS,EAAE,KAC5BT,EAAU,MAAM,IAAM,GAAGY,EAAU,KACnC,IAAMW,GAAQvB,EAAU,cAAc,2BAA2B,EAC7DuB,KAAOA,GAAM,MAAM,MAAQ3P,EAAI,OACnCoO,EAAU,MAAM,QAAU,EAC5B,KACE,CAACH,EAASC,EAAUC,EAAWC,CAAS,EAAE,QACvCjO,IAAqBA,GAAG,MAAM,QAAU,MAC3C,CAEJ,CAAC,CACH,CAEA,SAASmP,GAAQnM,EAAW,CAC1B,OAAO1H,IAAU,WAAa,GAAG0H,EAAE,QAAQ,CAAC,CAAC,MAAQoB,GAAQpB,CAAC,CAChE,CAGA,SAASqL,GACPoB,EACAzJ,EACAjC,EACA2L,EACA,CAEAD,EAAS,MAAM,cAAgB,OAE/BA,EAAS,iBAAiB,YAAc3R,GAAM,CAC5CA,EAAE,gBAAgB,EAClBA,EAAE,eAAe,EACjB,IAAM6R,EAAS7R,EAAE,QACX8R,EAAWF,EAAWjU,EAAeC,EACrCiT,EAAQ3I,EAAM,KAAK,YAEnBxB,EAAOwB,EAAM,OAAO,EAAG,IAC3BvB,EAAOuB,EAAM,OAAO,EAAG,IACnB6J,EAAYlB,GAASlK,EAAOD,GAC5B/F,EAAQ,CAACsF,EAAM,CAAC,EAAIA,EAAMA,EAAM,OAAS,CAAC,CAAE,EAElD,SAAS,KAAK,MAAM,OAAS,YAC7BpI,EAAa,GAEb,SAASmU,GAAOC,EAAgB,CAC9B,IAAMC,GAAKD,EAAG,QAAUJ,EACpBM,IAAUL,GAAY,GAAKI,GAAKH,EACpCI,GAAS,KAAK,IAAIxR,EAAM,CAAC,EAAG,KAAK,IAAIA,EAAM,CAAC,EAAGwR,EAAM,CAAC,EAElDP,EAAUjU,EAAe,KAAK,IAAIwU,IAASvU,GAAa+C,EAAM,CAAC,GAAK,IAAK,EACxE/C,EAAY,KAAK,IAAIuU,IAASxU,GAAgBgD,EAAM,CAAC,GAAK,IAAK,EAIpE/D,EAAM,QAASoF,IACZA,GAAE,MAAc,UAAU,kBACzBA,GAAE,MAAM,OAAO,EAAG,IAClBA,GAAE,MAAM,OAAO,EAAG,GACpB,CACF,EACA+D,GAAiB,EACjBC,GAAiB,EACbxH,IAAiBA,GAAgBb,EAAcC,EAAWJ,CAAK,CACrE,CAEA,SAAS4U,IAAO,CACd,SAAS,KAAK,MAAM,OAAS,GAC7BvU,EAAa,GACb,SAAS,oBAAoB,YAAamU,EAAM,EAChD,SAAS,oBAAoB,UAAWI,EAAI,CAC9C,CAEA,SAAS,iBAAiB,YAAaJ,EAAM,EAC7C,SAAS,iBAAiB,UAAWI,EAAI,CAC3C,CAAC,CACH,CAGA,SAAS9J,GAActB,EAAoB,CACzC,GAAM,CAAE,MAAAhC,EAAO,MAAAiB,EAAO,KAAAoM,CAAK,EAAIrL,EAG/B,GAAIA,EAAS,aAAehC,GAASgC,EAAS,KAAM,OACpDA,EAAS,WAAahC,EAEtB,IAAI7E,EAAM6G,EAAS,IACf5G,EAAM4G,EAAS,IACnB,GAAI7G,GAAO,MAAQC,GAAO,KAAM,CAC9B,IAAIkS,EAAK,IACPC,GAAK,KACLC,GAAM,EACR,QAASzK,EAAI,EAAGA,EAAI/C,EAAM,OAAQ+C,IAAK,CACrC,IAAM7C,GAAIF,EAAM+C,CAAC,EACb7C,IAAK,MAAQ,CAAC,SAASA,EAAC,IACxBA,GAAIoN,IAAIA,EAAKpN,IACbA,GAAIqN,KAAIA,GAAKrN,IACjBsN,KACF,CACA,GAAI,CAACA,GAAK,OACVrS,EAAMmS,EACNlS,EAAMmS,GACNvL,EAAS,IAAM7G,EACf6G,EAAS,IAAM5G,CACjB,CAEA,IAAMqS,EAAO,IAAI,MAAMJ,CAAI,EAAE,KAAK,CAAC,EAC7BK,EAAW,IAAI,MAAML,CAAI,EAAE,KAAK,CAAC,EAEjC9J,EAAOnI,EAAMD,GAAO,EACpB8C,EACJ+D,EAAS,MAAM,WAAa,OAAO,KAAKlF,EAAO,EAAE,KAAM6Q,GAAM7Q,GAAQ6Q,CAAC,IAAM3L,EAAS,GAAG,EACpF0C,EACJ,CAACzG,GACD1F,EAAqB,IAAI0F,CAAS,GACjCA,IAAc,SAAWA,IAAc,WAAaA,IAAc,QAErE,QAAS8E,EAAI,EAAGA,EAAI/C,EAAM,OAAQ+C,IAAK,CACrC,IAAM7C,GAAIF,EAAM+C,CAAC,EAEjB,GADI7C,IAAK,MAAQ,CAAC,SAASA,EAAC,GACxBA,KAAM,GAAK,CAACwE,EAAS,SAEzB,IAAMkJ,GAAK,KAAK,IAAIP,EAAO,EAAG,KAAK,OAAQnN,GAAI/E,GAAOoI,EAAQ8J,CAAI,CAAC,EACnEI,EAAKG,EAAE,IAGP,IAAMC,EAAO9K,EAAI,GAAK9B,EAAM8B,EAAI,CAAC,GAAK,KAAO9B,EAAM8B,EAAI,CAAC,EAAK9B,EAAM8B,CAAC,EAC9D+K,GAAO/K,EAAI9B,EAAM,OAAS,GAAKA,EAAM8B,EAAI,CAAC,GAAK,KAAO9B,EAAM8B,EAAI,CAAC,EAAK9B,EAAM8B,CAAC,EACnF2K,EAASE,EAAE,IAAME,GAAOD,GAAQ,CAClC,CACA7L,EAAS,KAAOyL,EAChBzL,EAAS,SAAW0L,CACtB,CAEA,SAAS1M,IAAmB,CAC1BpJ,EAAM,QAAQ,CAAC,CAAE,WAAAmK,EAAY,SAAAC,EAAU,MAAO9G,CAAE,IAAM,CACpD+G,GAAcF,EAAYC,EAAU9G,EAAE,MAAM,CAC9C,CAAC,CACH,CAEA,SAAS+G,GACP8L,EACA/L,EACAgM,EACAC,EAA2B,KAC3B,CACA,GAAM,CAAE,IAAAlR,EAAK,KAAAsQ,CAAK,EAAIrL,EACtBsB,GAActB,CAAQ,EACtB,GAAM,CAAE,KAAAyL,EAAM,IAAAtS,EAAK,IAAAC,CAAI,EAAI4G,EAC3B,GAAI,CAACyL,GAAQtS,GAAO,MAAQC,GAAO,KAAM,OAEzC,IAAM8S,EAASvV,GAAgB,MAAQC,GAAa,KAGpD,GACEsV,IACClM,EAAS,gBAAgB,CAAC,IAAMrJ,GAAgBqJ,EAAS,gBAAgB,CAAC,IAAMpJ,GACjF,CACAoJ,EAAS,cAAgB,CAACrJ,EAAeC,CAAU,EACnD,IAAMuV,GAAU,IAAI,MAAMd,CAAI,EAAE,KAAK,CAAC,EAChCe,GAAc,IAAI,MAAMf,CAAI,EAAE,KAAK,CAAC,EACpC,CAAE,MAAArN,GAAO,MAAAiB,EAAM,EAAIe,EACnBuB,GAAOnI,EAAMD,GAAO,EACpB8C,GACJ+D,EAAS,MAAM,WAAa,OAAO,KAAKlF,EAAO,EAAE,KAAM6Q,IAAM7Q,GAAQ6Q,EAAC,IAAM3L,EAAS,GAAG,EACpF0C,GACJ,CAACzG,IACD1F,EAAqB,IAAI0F,EAAS,GACjCA,KAAc,SAAWA,KAAc,WAAaA,KAAc,QAErE,QAAS8E,GAAI,EAAGA,GAAI/C,GAAM,OAAQ+C,KAAK,CACrC,IAAM7C,GAAIF,GAAM+C,EAAC,EAEjB,GADI7C,IAAK,MAAQ,CAAC,SAASA,EAAC,GACxBA,KAAM,GAAK,CAACwE,GAAS,SAEzB,IAAM2J,GAAIpN,GAAM8B,EAAC,EACjB,GAAIsL,IAAK,MAAQA,GAAI1V,GAAiB0V,GAAIzV,EAAY,SACtD,IAAMgV,GAAK,KAAK,IAAIP,EAAO,EAAG,KAAK,OAAQnN,GAAI/E,GAAOoI,GAAQ8J,CAAI,CAAC,EACnEc,GAAQP,EAAE,IACV,IAAMC,GAAO9K,GAAI,GAAK9B,GAAM8B,GAAI,CAAC,GAAK,KAAO9B,GAAM8B,GAAI,CAAC,EAAK9B,GAAM8B,EAAC,EAC9D+K,GAAO/K,GAAI9B,GAAM,OAAS,GAAKA,GAAM8B,GAAI,CAAC,GAAK,KAAO9B,GAAM8B,GAAI,CAAC,EAAK9B,GAAM8B,EAAC,EACnFqL,GAAYR,EAAE,IAAME,GAAOD,IAAQ,CACrC,CACA7L,EAAS,QAAUmM,GACnBnM,EAAS,YAAcoM,EACzB,MAAYF,IACVlM,EAAS,QAAU,KACnBA,EAAS,YAAc,KACvBA,EAAS,cAAgB,MAE3B,IAAMmM,EAAUnM,EAAS,QAEnBqH,EAAM,OAAO,kBAAoB,EACjCiF,GAAI3U,EACJ4U,GAAIP,GAGND,EAAO,QAAUO,GAAIjF,GAAO0E,EAAO,SAAWQ,GAAIlF,KACpD0E,EAAO,MAAQO,GAAIjF,EACnB0E,EAAO,OAASQ,GAAIlF,EACpB0E,EAAO,MAAM,MAAQ,GAAGO,EAAC,KACzBP,EAAO,MAAM,OAAS,GAAGQ,EAAC,MAG5B,IAAMnF,EAAM2E,EAAO,WAAW,IAAI,EAClC3E,EAAI,eAAe,EACnBA,EAAI,MAAMC,EAAKA,CAAG,EAClBD,EAAI,UAAU,EAAG,EAAGkF,GAAGC,EAAC,EAExB,IAAMC,GAAO,KAAK,IAAI,GAAGf,CAAI,EAGvBrM,GAAOlB,IAAcnD,EAAI,QAAQmD,EAAC,EAClCuJ,GAAU,4BACZL,EAAI,OAASK,KAASL,EAAI,KAAOK,IAWrC,IAAMgF,GAAM,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,EAVlB,KAAK,KAClB,KAAK,IACHrF,EAAI,YAAY,GAAGhI,GAAIhG,CAAG,CAAC,IAAI2B,EAAI,IAAI,EAAE,EAAE,MAC3CqM,EAAI,YAAY,GAAGhI,GAAIjG,CAAG,CAAC,IAAI4B,EAAI,IAAI,EAAE,EAAE,KAC7C,CACF,EAK6C,CAAE,EAC/CiF,EAAS,KAAOyM,GAAI,EACpB,IAAMC,GAAQJ,GAAIG,GAAI,EAAIA,GAAI,EACxBE,GAAQJ,GAAIE,GAAI,EAAIA,GAAI,EAGxBG,GAAQ7L,IAAc0L,GAAI,GAAKpB,EAAO,EAAItK,KAAM4L,GAAQtB,GACxDwB,GAAOF,GAAQtB,EAAO,EAGtByB,GAAYZ,EAAS,IAAO,GAClC9E,EAAI,UAAYD,GAAUpM,EAAI,MAAO+R,EAAS,EAC9C,QAAS/L,GAAI,EAAGA,GAAIsK,EAAMtK,KAAK,CAC7B,GAAI,CAAC0K,EAAK1K,EAAC,EAAG,SACd,IAAMgH,GAAM0D,EAAK1K,EAAC,EAAIyL,GAAQE,GAC9BtF,EAAI,SAASqF,GAAI,EAAGG,GAAK7L,EAAC,EAAGgH,GAAI8E,EAAI,CACvC,CAGA,GAAIV,EAAS,CACX/E,EAAI,UAAYD,GAAUpM,EAAI,MAAO,GAAI,EACzC,QAASgG,GAAI,EAAGA,GAAIsK,EAAMtK,KAAK,CAC7B,GAAI,CAACoL,EAAQpL,EAAC,EAAG,SACjB,IAAMgH,GAAMoE,EAAQpL,EAAC,EAAIyL,GAAQE,GACjCtF,EAAI,SAASqF,GAAI,EAAGG,GAAK7L,EAAC,EAAGgH,GAAI8E,EAAI,CACvC,CACAzF,EAAI,UAAYrM,EAAI,MACpBqM,EAAI,SAASqF,GAAI,EAAGA,GAAI,EAAG,EAAGE,EAAK,CACrC,CAGA,IAAMI,GAAQtB,EAAK,OAAO,CAACtK,GAAGjD,KAAMiD,GAAIjD,GAAG,CAAC,EAC5C,GAAI6O,GAAQ,EAAG,CAEb,IAAMC,GAAO,CAAC,CAAE,EAAGP,GAAI,EAAG,EAAGA,GAAI,EAAIE,EAAM,CAAC,EACxCM,GAAS,EACb,QAASlM,GAAI,EAAGA,GAAIsK,EAAMtK,KACxBkM,IAAUxB,EAAK1K,EAAC,EAChBiM,GAAK,KAAK,CAAE,EAAGP,GAAI,EAAKQ,GAASF,GAASL,GAAO,EAAGE,GAAK7L,EAAC,CAAE,CAAC,EAG/DqG,EAAI,UAAU,EAEdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,YAAcrM,EAAI,MACtBqM,EAAI,UAAY,IAAOC,EACvBD,EAAI,SAAW,QACfA,EAAI,OAAO4F,GAAK,CAAC,EAAE,EAAGA,GAAK,CAAC,EAAE,CAAC,EAC/B,QAASjM,GAAI,EAAGA,GAAIiM,GAAK,OAAS,EAAGjM,KAAK,CACxC,IAAM6E,IAAMoH,GAAKjM,EAAC,EAAE,EAAIiM,GAAKjM,GAAI,CAAC,EAAE,GAAK,EACnCmM,IAAMF,GAAKjM,EAAC,EAAE,EAAIiM,GAAKjM,GAAI,CAAC,EAAE,GAAK,EACzCqG,EAAI,iBAAiB4F,GAAKjM,EAAC,EAAE,EAAGiM,GAAKjM,EAAC,EAAE,EAAG6E,GAAIsH,EAAE,CACnD,CAKA,GAJA9F,EAAI,OAAO4F,GAAKA,GAAK,OAAS,CAAC,EAAE,EAAGA,GAAKA,GAAK,OAAS,CAAC,EAAE,CAAC,EAC3D5F,EAAI,OAAO,EAGP6E,GAAa,MAAQe,GAAKf,EAAY,CAAC,EAAG,CAC5C,IAAMkB,GAAKH,GAAKf,EAAY,CAAC,EAE7B7E,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,EAAK,EAAIA,CAAG,CAAC,EAClCD,EAAI,YAAcD,GAAUpM,EAAI,MAAO,EAAG,EAC1CqM,EAAI,OAAO+F,GAAG,EAAGA,GAAG,CAAC,EACrB/F,EAAI,OAAO+F,GAAG,EAAGV,GAAI,EAAIE,EAAK,EAC9BvF,EAAI,OAAO,EACXA,EAAI,YAAY,CAAC,CAAC,EAGlBA,EAAI,UAAU,EACdA,EAAI,IAAI+F,GAAG,EAAGA,GAAG,EAAG,IAAM9F,EAAK,EAAG,KAAK,GAAK,CAAC,EAC7CD,EAAI,UAAY,UAChBA,EAAI,KAAK,EACTA,EAAI,YAAcrM,EAAI,MACtBqM,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,CACb,CACF,CAGIA,EAAI,YAAc,YAAWA,EAAI,UAAY,WACjD,IAAMgG,GAAQ,4BACVhG,EAAI,OAASgG,KAAOhG,EAAI,KAAOgG,IACnChG,EAAI,UAAY,QAGhBA,EAAI,aAAe,MACnBA,EAAI,SAAS,GAAGhI,GAAIhG,CAAG,CAAC,IAAI2B,EAAI,IAAI,GAAI0R,GAAI,EAAI,EAAGA,GAAI,CAAC,EAGxDrF,EAAI,aAAe,SACnBA,EAAI,SAAS,GAAGhI,GAAIjG,CAAG,CAAC,IAAI4B,EAAI,IAAI,GAAI0R,GAAI,EAAI,EAAGF,GAAIE,GAAI,CAAC,EAG5D,IAAMtN,GACJ,CAAC+M,GAAUlM,EAAS,eAAiB,OACjCA,EAAS,aACToF,GACEpF,EAAS,MACTA,EAAS,MACTrJ,GAAgB,KAChBC,GAAa,GACf,EACN,GAAIuI,GAAO,CACT,IAAMkO,GACJZ,GAAI,GACHpB,EAAO,EAAI,KAAK,IAAIA,EAAO,EAAG,KAAK,OAAQlM,GAAM,IAAMhG,IAAQC,EAAMD,GAAO,GAAMkS,CAAI,CAAC,IACrFsB,GAAQtB,GACPiC,GAAYf,GAAIE,GAAI,EACpBc,GAAYd,GAAI,EAChBe,GAAc,GAEhBH,GAAOE,GAAYC,GAAc,GAAKH,GAAOC,GAAYE,GAAc,IACzEpG,EAAI,aAAe,SACfA,EAAI,YAAc,SAAQA,EAAI,UAAY,QAC9CA,EAAI,SAAS,GAAGhI,GAAID,GAAM,GAAG,CAAC,IAAIpE,EAAI,IAAI,GAAI0R,GAAI,EAAI,EAAGY,EAAI,EAE7DjG,EAAI,UAAU,EACdA,EAAI,OAAOqF,GAAI,EAAI,EAAGY,EAAI,EAC1BjG,EAAI,OAAOqF,GAAI,EAAGY,EAAI,EAClBjG,EAAI,cAAgB,SAAQA,EAAI,YAAc,QAClDA,EAAI,UAAY,EAChBA,EAAI,OAAO,EAEf,CAGA,GAAI6E,GAAa,MAAQc,GAAQ,EAAG,CAClC,IAAIU,GAAa,EACjB,QAAS1M,GAAI,EAAGA,GAAIkL,EAAWlL,KAAK0M,IAAchC,EAAK1K,EAAC,EACxD,IAAI2M,GAAc,EAClB,QAAS3M,GAAIkL,EAAY,EAAGlL,GAAIsK,EAAMtK,KAAK2M,IAAejC,EAAK1K,EAAC,EAEhE,IAAM4M,GAAS,KAAK,MAAOF,GAAaV,GAAS,GAAG,EAC9Ca,GAAU,KAAK,MAAOF,GAAcX,GAAS,GAAG,EAEtD3F,EAAI,KAAK,EACTA,EAAI,UAAY,OAChBA,EAAI,aAAe,MACnB,IAAMyG,GAAQ,4BACVzG,EAAI,OAASyG,KAAOzG,EAAI,KAAOyG,IAEnC,IAAMC,GAAQvB,GAAIE,GAAI,EAAI,EAGtBrF,EAAI,YAAc,YAAWA,EAAI,UAAY,WACjDA,EAAI,SAAS,QAASqF,GAAI,EAAGqB,EAAK,EAC9B1G,EAAI,YAAc,SAAQA,EAAI,UAAY,QAC9C,IAAM2G,GAAU,kCACZ3G,EAAI,OAAS2G,KAAS3G,EAAI,KAAO2G,IACrC3G,EAAI,SAAS,GAAGuG,EAAM,IAAKlB,GAAI,EAAGqB,GAAQ,EAAE,EAG5C,IAAME,GAAOvB,GAAI,EAAIC,GAAQ,EACzBtF,EAAI,OAASyG,KAAOzG,EAAI,KAAOyG,IAC/BzG,EAAI,YAAc,YAAWA,EAAI,UAAY,WACjDA,EAAI,SAAS,SAAU4G,GAAMF,EAAK,EAC9B1G,EAAI,YAAc,SAAQA,EAAI,UAAY,QAC1CA,EAAI,OAAS2G,KAAS3G,EAAI,KAAO2G,IACrC3G,EAAI,SAAS,GAAGwG,EAAO,IAAKI,GAAMF,GAAQ,EAAE,EAE5C1G,EAAI,QAAQ,CACd,CACF,CAEA,SAASsC,GAAkBqC,EAA2B/L,EAAoB,CACxE,GAAM,CAAE,KAAAnC,CAAK,EAAImC,EAEjB+L,EAAO,iBAAiB,QAAU/S,GAAM,CACtC,IAAMsP,EAAO2F,GAASlC,EAAQ/L,EAAUhH,CAAC,EACzC,GAAIsP,GAAQ,MAAQzK,EAAM,CACxB,GAAM,CAAE,IAAA1E,EAAK,IAAAC,EAAK,KAAAiS,CAAK,EAAIrL,EACrBuB,EAAOnI,EAAOD,GAAQ,EAC5B0E,EAAK,YAAc1E,GAAQmP,EAAO,KAAQ/G,EAAO8J,GACjDzV,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAMA,EAAE,OAAO,EAAK,CAAC,CACjD,CACF,CAAC,EAED6S,EAAO,iBAAiB,YAAc/S,GAAM,CAC1C/B,EAAqB+B,EACrBL,GAAkBK,EAAG+S,EAAQ/L,CAAQ,CACvC,CAAC,EAED+L,EAAO,iBAAiB,aAAc,IAAM,CAC1C5U,EAAoB4U,EACpB7U,EAAkB8I,CACpB,CAAC,EAED+L,EAAO,iBAAiB,aAAc,IAAM,CACtC5U,IAAsB4U,IACxB5U,EAAoB,KACpBD,EAAkB,MAEhBa,IAAeA,EAAc,MAAM,QAAU,QACjD,IAAMmW,EAAS,SAAS,eAAe,WAAW,EAC9CA,IAAQA,EAAO,MAAM,QAAU,QAC/BrQ,IACFA,EAAK,aAAe,KACpBoC,GAAc8L,EAAQ/L,EAAU+L,EAAO,QAAU,OAAO,kBAAoB,EAAE,EAElF,CAAC,CACH,CAEA,SAASkC,GAASlC,EAA2B/L,EAAoBhH,EAAe,CAC9E,GAAM,CAAE,KAAAyS,EAAM,KAAAJ,CAAK,EAAIrL,EACvB,GAAI,CAACyL,EAAM,OAAO,KAClB,IAAMhC,EAAOsC,EAAO,sBAAsB,EACpCoC,EAAOnV,EAAE,QAAUyQ,EAAK,IAExBgD,EAAM,CAAE,EAAG,EAAG,EAAG,EAAG,EACpBE,EAAQlD,EAAK,OAASgD,EAAI,EAAIA,EAAI,EAClC2B,EAAO,KAAK,OAAQD,EAAO1B,EAAI,GAAKE,EAAStB,CAAK,EAClD/C,EAAO+C,EAAQ,EAAI+C,EACzB,OAAIA,EAAO,GAAKA,GAAQ/C,EAAc,KAC/B/C,CACT,CAEA,SAAS3P,GAAkBK,EAAe+S,EAA2B/L,EAAoB,CACvF,GAAI,CAACjI,EAAe,OACpB,GAAM,CAAE,KAAA0T,EAAM,SAAAC,EAAU,IAAAvS,EAAK,IAAAC,EAAK,KAAAiS,EAAM,IAAAtQ,EAAK,KAAA8C,CAAK,EAAImC,EACtD,GAAI,CAACyL,GAAQ,CAACC,GAAYvS,GAAO,MAAQC,GAAO,KAAM,OAEtD,IAAM8U,EAAS,SAAS,eAAe,WAAW,EAC5C5F,EAAO2F,GAASlC,EAAQ/L,EAAUhH,CAAC,EAEzC,GAAIsP,GAAQ,MAAQ,CAACmD,EAAKnD,CAAI,EAAG,CAC/BvQ,EAAc,MAAM,QAAU,OAC1BmW,IAAQA,EAAO,MAAM,QAAU,QAC/BrQ,IACFA,EAAK,aAAe,KACpBoC,GAAc8L,EAAQ/L,EAAU+L,EAAO,QAAU,OAAO,kBAAoB,EAAE,GAEhF,MACF,CAEA,GAAIlO,EAAM,CACR,IAAM0D,GAAOnI,EAAMD,GAAO,EAC1B0E,EAAK,aAAe1E,GAAOmP,EAAO,KAAQ/G,GAAO8J,GACjDpL,GAAc8L,EAAQ/L,EAAU+L,EAAO,QAAU,OAAO,kBAAoB,GAAIzD,CAAI,CACtF,CAEA,IAAM+F,GAAQ5C,EAAKnD,CAAI,EACjByE,GAAQtB,EAAK,OAAO,CAACtK,GAAGjD,KAAMiD,GAAIjD,GAAG,CAAC,EACtCoQ,EAAOD,GAAQtB,GAAS,IAExBxL,GAAOnI,EAAMD,GAAO,EACpBoV,GAAMpV,EAAMmP,GAAQ/G,GAAO8J,GAC3BmD,GAAOrV,GAAOmP,EAAO,IAAM/G,GAAO8J,GAClC1J,GAAQ,GAAG5G,EAAI,IAAIwT,GAAK,EAAI,CAAC,WAAMxT,EAAI,IAAIyT,GAAM,EAAI,CAAC,IAAIzT,EAAI,IAAI,GAGpE0T,GAAW,GACTC,IAAOH,GAAMC,IAAQ,EACrBvS,GAAY,OAAO,KAAKnB,EAAO,EAAE,KAAM6Q,IAAM7Q,GAAQ6Q,EAAC,IAAM5Q,CAAG,EACjE4T,GAAe,CAAC,EAIpB,GAHI1S,KAAc,QAAS0S,GAAQC,GAAM,cAAc,EAC9C3S,KAAc,OAAM0S,GAAQC,GAAM,WAAW,GAElDD,GAAM,OAAS,EAAG,CACpB,IAAME,GAAOF,GAAM,UAAWG,IAAMJ,IAAOI,GAAE,KAAOJ,GAAMI,GAAE,GAAG,EACzDA,GACJD,KAAS,GACLF,GAAME,EAAI,EACVH,IAAOC,GAAMA,GAAM,OAAS,CAAC,EAAE,IAC7BA,GAAMA,GAAM,OAAS,CAAC,EACtB,KACR,GAAIG,GAAG,CACL,IAAMC,GAAYF,KAAS,GAAKA,GAAOF,GAAM,OAAS,EACtDF,GAAW;AAAA,6JAC0IK,GAAE,KAAK;AAAA,+CACrHC,GAAY,CAAC;AAAA;AAAA,oDAERD,GAAE,IAAI;AAAA;AAAA,SAGpD,CACF,CAEA,IAAME,GACJxY,IAAU,WAAa,GAAGkV,EAASpD,CAAI,EAAE,QAAQ,CAAC,CAAC,MAAQhJ,GAAQoM,EAASpD,CAAI,CAAC,EAC7E2G,GAAYvD,EAASpD,CAAI,EAAIoD,EAAS,OAAO,CAACvK,GAAGjD,KAAMiD,GAAIjD,GAAG,CAAC,EAAK,IAEtEgR,GAAO;AAAA,6DAC8CnU,EAAI,KAAK,KAAK4G,EAAK;AAAA,QACxE8M,EAAQ;AAAA,MAYZ,GATIO,KACFE,IAAQ;AAAA,sCACwB1Y,IAAU,WAAa,OAAS,MAAM;AAAA,sCACtCwY,EAAU;AAAA,oCACZC,GAAS,QAAQ,CAAC,CAAC;AAAA,eAK/CjP,EAAS,SAAWA,EAAS,YAAa,CAC5C,IAAMmP,GACJ3Y,IAAU,WACN,GAAGwJ,EAAS,YAAYsI,CAAI,EAAE,QAAQ,CAAC,CAAC,MACxChJ,GAAQU,EAAS,YAAYsI,CAAI,CAAC,EAClC8G,GACHpP,EAAS,YAAYsI,CAAI,EAAItI,EAAS,YAAY,OAAO,CAACmB,GAAGjD,KAAMiD,GAAIjD,GAAG,CAAC,EAAK,IAEnFgR,IAAQ;AAAA;AAAA,gDAEkC1Y,IAAU,WAAa,OAAS,MAAM;AAAA,4CAC1C2Y,EAAW;AAAA,0CACbC,GAAU,QAAQ,CAAC,CAAC;AAAA;AAAA,OAG1D,CAEArX,EAAc,UAAYmX,GAG1BnX,EAAc,MAAM,QAAU,QAC9B,IAAMsX,GAAMtX,EAAc,aACpBuX,GAAMvX,EAAc,YACpB0R,GAAOsC,EAAO,sBAAsB,EACpCY,GAAQlD,GAAK,OAAS,EAAI,GAC1B8F,GAAa9F,GAAK,IAAM,GAAK4B,EAAQ,EAAI/C,EAAO,KAAQqE,GAAQtB,GAEtEtT,EAAc,MAAM,KAAO,GAAG0R,GAAK,KAAO6F,GAAM,EAAE,KAClDvX,EAAc,MAAM,IAAM,GAAGwX,GAAaF,GAAM,CAAC,KAG7CnB,IACFA,EAAO,MAAM,QAAU,QACvBA,EAAO,MAAM,IAAM,GAAGqB,EAAU,KAChCrB,EAAO,MAAM,KAAO,MACpBA,EAAO,MAAM,MAAQ,GAAGzE,GAAK,IAAI,KAErC,CAGA,SAAShO,GAAayE,EAAY,GAAO,CACnCnI,IAAeA,EAAc,MAAM,QAAU,QACjDnC,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,IAAAkJ,CAAI,IAAM,CACnCnM,EAAS,MAAMiD,CAAC,EAChBA,EAAE,QAAQ,EACVkJ,EAAI,OAAO,CACb,CAAC,EACDxM,EAAQ,CAAC,EACTC,EAAgB,KACXqK,IACHvJ,EAAe,KACfC,EAAY,MAEdC,EAAa,EACf,CAEA,SAASuO,GACPnG,EACAjB,EACA0B,EACAC,EACA+C,EAAU,GACV,CACA,IAAIvJ,EAAM,IACRC,EAAM,KACNoW,EAAM,EACNC,EAAI,EACN,QAAS1O,EAAI,EAAGA,EAAI9B,EAAM,OAAQ8B,IAAK,CACrC,GAAI9B,EAAM8B,CAAC,GAAK,MAAQ9B,EAAM8B,CAAC,EAAKrB,GAAQT,EAAM8B,CAAC,EAAKpB,EAAM,SAC9D,IAAMzB,EAAIF,EAAM+C,CAAC,EACb7C,GAAK,MAAQ,CAAC,SAASA,CAAC,GACxBA,IAAM,GAAK,CAACwE,IAEZxE,EAAI/E,IAAKA,EAAM+E,GACfA,EAAI9E,IAAKA,EAAM8E,GACnBsR,GAAOtR,EACPuR,IACF,CACA,OAAOA,EAAI,CAAE,IAAAtW,EAAK,IAAAC,EAAK,IAAKoW,EAAMC,CAAE,EAAI,IAC1C,CAEA,SAASnK,GAAoB3I,EAAmB+C,EAAcC,EAAc,CAC1E,IAAI+P,EAAO,EACTC,EAAO,EACLC,EAAyB,KACvBC,EAASrZ,IAAU,WACnBoG,EAAKD,EAAI,CAAC,EAAE,MAAQ,EAE1B,QAASoE,EAAI,EAAGA,EAAIpE,EAAI,OAAQoE,IAAK,CACnC,IAAM/F,EAAI2B,EAAIoE,CAAC,EACTsL,EAAIwD,GAAU7U,EAAE,MAAQ,GAAK,KAAQA,EAAE,KAAQ4B,GAAM,IAC3D,GAAI,EAAAyP,EAAI3M,GAAQ2M,EAAI1M,IAEhB3E,EAAE,KAAO,KAAM,CACjB,GAAI4U,GAAW,KAAM,CACnB,IAAME,EAAO9U,EAAE,IAAM4U,EACjBE,EAAO,EAAGJ,GAAQI,EACbA,EAAO,IAAGH,GAAQ,KAAK,IAAIG,CAAI,EAC1C,CACAF,EAAU5U,EAAE,GACd,CACF,CACA,MAAO,CAAE,KAAA0U,EAAM,KAAAC,CAAK,CACtB,CAGA,SAAStH,GACPnP,EACAgC,EACA6B,EACAkC,EACAjB,EACArB,EACA5B,EACAkB,EACA,CACA,GAAIc,GAAO,MAAQiB,EAAMjB,CAAG,GAAK,KAAM,CACrC7B,EAAG,MAAM,QAAU,OACnB,MACF,CAEA,IAAM6U,EAAK7W,EAAE,SAAS+F,EAAMlC,CAAG,EAAI,IAAK,EAAK,EACvCkK,EAAK/N,EAAE,SAAS8E,EAAMjB,CAAG,EAAI,IAAK,EAAK,EAEzCiT,EAAS,UACTC,EAAI,EACR,GAAIlT,EAAM,GAAKJ,EAAII,CAAG,GAAKJ,EAAII,EAAM,CAAC,EAAG,CACvC,IAAMmT,GAAKvT,EAAII,EAAM,CAAC,EACpBoT,GAAKxT,EAAII,CAAG,EACRnD,IAAKuW,GAAG,MAAQ,IAAMD,GAAG,MAAQ,GACnCtW,GAAI,IAAOuW,GAAG,KAAO,MAAQD,GAAG,KAAO,OACzCD,GAAME,GAAG,IAAMD,GAAG,KAAOtW,GAAK,IAC9BoW,EAAStR,GAAcuR,CAAC,EAE5B,CAEA,IAAIG,GACFnU,IAAc,YACV,GAAGlB,EAAI,IAAIiD,EAAMjB,CAAG,EAAI,EAAK,CAAC,SAAShC,EAAI,IAAI,GAC/C,GAAGA,EAAI,IAAIiD,EAAMjB,CAAG,EAAI,EAAK,CAAC,SAAShC,EAAI,IAAI,sCAAsCiV,CAAM,mCAA8B,KAAK,IAAIC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAGrJ,GAAIhU,IAAc,YAAcU,EAAII,CAAG,EAAE,eAAiB,KACxDqT,GAAU,GAAGzT,EAAII,CAAG,EAAE,aAAa,oEAAoEiB,EAAMjB,CAAG,CAAC,mBACxGd,IAAc,aAAeU,EAAII,CAAG,EAAE,gBAAkB,KACjEqT,GAAU,GAAGzT,EAAII,CAAG,EAAE,cAAc,oEAAoEiB,EAAMjB,CAAG,CAAC,mBACzGd,IAAc,QAAS,CAChC,IAAMjB,GAAI2B,EAAII,CAAG,EACXsT,GACJrV,GAAE,gBAAkB,KAChB,GAAGA,GAAE,cAAc,IACnBA,GAAE,WAAa,KACb,OAAOA,GAAE,SAAS,GAClB,GACFsV,GACJtV,GAAE,eAAiB,KACf,GAAGA,GAAE,aAAa,IAClBA,GAAE,UAAY,KACZ,OAAOA,GAAE,QAAQ,GACjB,IAEJqV,IAASC,MACXF,IAAW,+DAA+DC,EAAK,MAAMC,EAAI,WAC7F,CAEIpV,EAAG,YAAckV,KAASlV,EAAG,UAAYkV,IAE7C,IAAMG,GAAU,GAAGxV,EAAI,KAAK,KACxBG,EAAG,MAAM,QAAUH,EAAI,QAAOG,EAAG,MAAM,MAAQH,EAAI,OACnDG,EAAG,MAAM,cAAgBqV,KAASrV,EAAG,MAAM,YAAcqV,IAE7D,IAAM/H,EAAO,GAAGuH,CAAE,KACZxJ,GAAM,GAAGU,CAAE,KACXzF,GAAY,uBACdtG,EAAG,MAAM,OAASsN,IAAMtN,EAAG,MAAM,KAAOsN,GACxCtN,EAAG,MAAM,MAAQqL,KAAKrL,EAAG,MAAM,IAAMqL,IACrCrL,EAAG,MAAM,YAAcsG,KAAWtG,EAAG,MAAM,UAAYsG,IACvDtG,EAAG,MAAM,UAAY,KAAIA,EAAG,MAAM,QAAU,GAClD,CAEA,IAAMsV,GAAyB,IAAI,IACnC,SAASC,GAAkBR,EAA0B,CACnD,IAAIS,EAAIF,GAAuB,IAAIP,CAAC,EACpC,OAAKS,IACHA,EAAIvJ,GAAUzI,GAAcuR,CAAC,EAAG,EAAG,EACnCO,GAAuB,IAAIP,EAAGS,CAAC,GAE1BA,CACT,CAEA,SAASjK,GACPvN,EACA+F,EACAjB,EACAkE,EACA,CACA,IAAMkF,EAAMlO,EAAE,IACRoO,EAAKpO,EAAE,KACPmO,EAAM,OAAO,kBAAoB,EACjC3H,EAAOxG,EAAE,OAAO,GAAG,KAAO,KAC1ByG,EAAOzG,EAAE,OAAO,GAAG,KAAO,IAC1ByX,EAAOzX,EAAE,OAAO,GAAG,KAAO,EAC1B0X,EAAO1X,EAAE,OAAO,GAAG,KAAO,IAC1B2X,EAASvJ,EAAG,OAAS3H,EAAOD,GAAQ,GACpCoR,GAASxJ,EAAG,QAAUsJ,EAAOD,GAAQ,GACrCI,GAAQzJ,EAAG,IAAMA,EAAG,OAEpB0J,EAAO9X,EAAE,OAAO,CAAC,GAAG,KACpB+X,GAASD,EAAO,KAAK,IAAI,EAAGA,EAAK,CAAC,CAAC,EAAI,EACvCE,GAAOF,EAAO,KAAK,IAAI/R,EAAM,OAAS,EAAG+R,EAAK,CAAC,EAAI,CAAC,EAAI/R,EAAM,OAAS,EACvE5E,GAAO,KAAK,IAAI,EAAG,KAAK,OAAO6W,GAAOD,IAAU,GAAG,CAAC,EAE1D7J,EAAI,KAAK,EACTA,EAAI,UAAY,IAAMC,EAEtB,IAAM8J,GAAU,IAAI,IAEhBC,GAAUH,GAAS,EACvB,QAASlQ,GAAIkQ,GAAQlQ,IAAKmQ,GAAMnQ,IAAK1G,GAAM,CACzC,IAAMgX,GAAMpS,EAAM8B,EAAC,EACbuQ,GAAMrS,EAAMmS,EAAO,EAGzB,GAFAA,GAAUrQ,GACNsQ,IAAO,MAAQrT,EAAM+C,EAAC,GAAK,MAAQuQ,IAAO,MAAQtT,EAAM+C,GAAI1G,EAAI,GAAK,MACrEgX,GAAM3R,GAAQ4R,GAAM3R,EAAM,SAE9B,IAAM4R,GAAKjK,EAAG,MAAQgK,GAAM5R,GAAQmR,EAC9BW,GAAKT,IAAS/S,EAAM+C,GAAI1G,EAAI,EAAKsW,GAAQG,GACzCW,GAAKnK,EAAG,MAAQ+J,GAAM3R,GAAQmR,EAC9Ba,GAAKX,IAAS/S,EAAM+C,EAAC,EAAK4P,GAAQG,GAElCb,GAAI/N,GAAYA,EAASnB,EAAC,GAAK,KAAO,KAAK,MAAMmB,EAASnB,EAAC,EAAK,CAAC,EAAI,EAAI,KACzE4Q,GAAQlB,GAAkBR,EAAC,EAC7B2B,GAAOT,GAAQ,IAAIQ,EAAK,EACvBC,KACHA,GAAO,CAAC,EACRT,GAAQ,IAAIQ,GAAOC,EAAI,GAEzBA,GAAK,KAAKL,GAAIC,GAAIC,GAAIC,EAAE,CAC1B,CAEA,OAAW,CAACC,GAAOC,EAAI,IAAKT,GAAS,CACnC/J,EAAI,UAAU,EACdA,EAAI,YAAcuK,GAClB,QAASE,GAAI,EAAGA,GAAID,GAAK,OAAQC,IAAK,EACpCzK,EAAI,OAAOwK,GAAKC,EAAC,EAAGD,GAAKC,GAAI,CAAC,CAAC,EAC/BzK,EAAI,OAAOwK,GAAKC,GAAI,CAAC,EAAGD,GAAKC,GAAI,CAAC,CAAC,EAErCzK,EAAI,OAAO,CACb,CAEAA,EAAI,QAAQ,CACd,CAEA,SAASV,GAAkBxN,EAAU+F,EAAiBjB,EAAiB,CACrE,IAAMoJ,EAAMlO,EAAE,IACRoO,EAAKpO,EAAE,KACPmO,EAAM,OAAO,kBAAoB,EACjC3H,EAAOxG,EAAE,OAAO,GAAG,KAAO,KAC1ByG,EAAOzG,EAAE,OAAO,GAAG,KAAO,IAC1ByX,EAAOzX,EAAE,OAAO,GAAG,KAAO,EAC1B0X,EAAO1X,EAAE,OAAO,GAAG,KAAO,IAC1B2X,EAASvJ,EAAG,OAAS3H,EAAOD,GAAQ,GACpCoR,EAASxJ,EAAG,QAAUsJ,EAAOD,GAAQ,GACrCI,GAAQzJ,EAAG,IAAMA,EAAG,OAEpB0J,GAAO9X,EAAE,OAAO,CAAC,GAAG,KACpB+X,EAASD,GAAO,KAAK,IAAI,EAAGA,GAAK,CAAC,CAAC,EAAI,EACvCE,GAAOF,GAAO,KAAK,IAAI/R,EAAM,OAAS,EAAG+R,GAAK,CAAC,EAAI,CAAC,EAAI/R,EAAM,OAAS,EACvE5E,GAAO,KAAK,IAAI,EAAG,KAAK,OAAO6W,GAAOD,GAAU,GAAG,CAAC,EAE1D7J,EAAI,KAAK,EACTA,EAAI,UAAY,IAAMC,EAEtB,IAAM8J,GAAU,IAAI,IAEhBC,GAAUH,EAAS,EACvB,QAASlQ,GAAIkQ,EAAQlQ,IAAKmQ,GAAMnQ,IAAK1G,GAAM,CACzC,IAAMgX,GAAMpS,EAAM8B,EAAC,EACbuQ,GAAMrS,EAAMmS,EAAO,EAGzB,GAFAA,GAAUrQ,GACNsQ,IAAO,MAAQrT,EAAM+C,EAAC,GAAK,MAAQuQ,IAAO,MAAQtT,EAAM+C,GAAI1G,EAAI,GAAK,MACrEgX,GAAM3R,GAAQ4R,GAAM3R,EAAM,SAE9B,IAAM4R,GAAKjK,EAAG,MAAQgK,GAAM5R,GAAQmR,EAC9BW,GAAKT,IAAS/S,EAAM+C,GAAI1G,EAAI,EAAKsW,GAAQG,EACzCW,GAAKnK,EAAG,MAAQ+J,GAAM3R,GAAQmR,EAC9Ba,GAAKX,IAAS/S,EAAM+C,EAAC,EAAK4P,GAAQG,EAElCb,GAAI,KAAK,MAAMjS,EAAM+C,EAAC,EAAK,CAAC,EAAI,EAChC4Q,GAAQlB,GAAkBR,EAAC,EAC7B2B,GAAOT,GAAQ,IAAIQ,EAAK,EACvBC,KACHA,GAAO,CAAC,EACRT,GAAQ,IAAIQ,GAAOC,EAAI,GAEzBA,GAAK,KAAKL,GAAIC,GAAIC,GAAIC,EAAE,CAC1B,CAEA,OAAW,CAACC,GAAOC,EAAI,IAAKT,GAAS,CACnC/J,EAAI,UAAU,EACdA,EAAI,YAAcuK,GAClB,QAASE,GAAI,EAAGA,GAAID,GAAK,OAAQC,IAAK,EACpCzK,EAAI,OAAOwK,GAAKC,EAAC,EAAGD,GAAKC,GAAI,CAAC,CAAC,EAC/BzK,EAAI,OAAOwK,GAAKC,GAAI,CAAC,EAAGD,GAAKC,GAAI,CAAC,CAAC,EAErCzK,EAAI,OAAO,CACb,CAEAA,EAAI,QAAQ,CACd,CAEA,SAAS0K,GAAc5Y,EAAU8E,EAAiB2T,EAAehV,EAAmB,CAClF,IAAMI,EAAM7D,EAAE,OAAO,IACrB,GAAI6D,GAAO,MAAQiB,EAAMjB,CAAG,GAAK,MAAQ7D,EAAE,OAAO,KAAQ,EAAG,OAE7D,IAAM0D,EAAKD,EAAI,CAAC,EAAE,MAAQ,EACpBoV,EAAOvb,IAAU,YAAcmG,EAAII,CAAG,EAAE,MAAQ,GAAK,KAAQJ,EAAII,CAAG,EAAE,KAAQH,GAAM,IACpFmT,EAAK7W,EAAE,SAAS6Y,EAAM,IAAK,EAAI,EAC/B9K,EAAK/N,EAAE,SAAS8E,EAAMjB,CAAG,EAAG,IAAK,EAAI,EACrCuK,EAAKpO,EAAE,KACPkO,EAAMlO,EAAE,IACRmO,EAAM,OAAO,kBAAoB,EAGvCD,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,EAAK,EAAIA,CAAG,CAAC,EAClCD,EAAI,YAAcD,GAAUwK,EAAO,EAAG,EACtCvK,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO2I,EAAIzI,EAAG,GAAG,EACrBF,EAAI,OAAO2I,EAAI9I,CAAE,EACjBG,EAAI,OAAOE,EAAG,KAAML,CAAE,EACtBG,EAAI,OAAO2I,EAAI9I,CAAE,EACjBG,EAAI,OAAO,EAGXA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,IAAI2I,EAAI9I,EAAI,EAAII,EAAK,EAAG,KAAK,GAAK,CAAC,EACvCD,EAAI,UAAY,UAChBA,EAAI,KAAK,EACTA,EAAI,YAAcuK,EAClBvK,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EACXA,EAAI,QAAQ,CACd,CAEA,SAASF,GACPhO,EACAyD,EACAI,EACA4U,EACAK,EAAkB,EAClB,CACA,IAAM3K,EAAM,OAAO,kBAAoB,EACjCC,EAAKpO,EAAE,KACPkO,EAAMlO,EAAE,IACR6Y,EACJvb,IAAU,YACLmG,EAAII,CAAG,EAAE,MAAQ,GAAK,KACtBJ,EAAII,CAAG,EAAE,MAASJ,EAAI,CAAC,EAAE,MAAQ,IAAM,IACxCoT,EAAK7W,EAAE,SAAS6Y,EAAM,IAAK,EAAI,EAErC3K,EAAI,KAAK,EACTA,EAAI,YAAc4K,EAClB5K,EAAI,UAAU,EACdA,EAAI,YAAcuK,EAClBvK,EAAI,UAAY,EAAIC,EAEpBD,EAAI,OAAO2I,EAAIzI,EAAG,IAAM,GAAKD,CAAG,EAChCD,EAAI,OAAO2I,EAAIzI,EAAG,IAAMA,EAAG,OAAS,GAAKD,CAAG,EAC5CD,EAAI,OAAO,EACXA,EAAI,QAAQ,CACd,CAEA,SAASe,GACPjP,EACAyD,EACAI,EACA4U,EACAM,EAAW,GACXD,EAAkB,EAClB,CACA,IAAM3K,EAAM,OAAO,kBAAoB,EACjCC,EAAKpO,EAAE,KACPkO,EAAMlO,EAAE,IACR0D,EAAKD,EAAI,CAAC,EAAE,MAAQ,EACpBuV,GAAWvV,EAAII,CAAG,EAAE,MAAQ,GAAK,IACjCoV,GAAWxV,EAAII,CAAG,EAAE,KAAQH,GAAM,IAClCmT,GAAK7W,EAAE,SAAS1C,IAAU,WAAa0b,EAAUC,EAAS,IAAK,EAAI,EAGnEC,GAAc5b,IAAU,WAAa,GAAG0b,EAAQ,QAAQ,CAAC,CAAC,MAAQ5S,GAAQ6S,CAAO,EAEjFE,EAAW7b,IAAU,WAAa8I,GAAQ6S,CAAO,EAAI,GAAGD,EAAQ,QAAQ,CAAC,CAAC,MAE1EI,GAAW,CAACC,GAAclG,GAAWmG,GAAWC,KAAmB,CACvE,IAAMhL,GAAU,QAAQ,GAAKJ,CAAG,2BAC5BD,EAAI,OAASK,KAASL,EAAI,KAAOK,IAErC,IAAMM,GADKX,EAAI,YAAYmL,EAAI,EAAE,MACjB,GAAKlL,EACfW,GAAK,GAAKX,EACVqL,GAAKrG,GAAItE,GAAK,EACd4K,GAAY,KAAK,IAAIrL,EAAG,KAAM,KAAK,IAAIA,EAAG,KAAOA,EAAG,MAAQS,GAAI2K,EAAE,CAAC,EACnEE,GAAKJ,GAAIxK,GAAK,EAEpBZ,EAAI,KAAK,EACTA,EAAI,YAAc4K,EAClB5K,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,UAAU,EACTA,EAAY,UAAYA,EAAY,UAAUuL,GAAWC,GAAI7K,GAAIC,GAAI,EAAIX,CAAG,EAC5ED,EAAI,KAAKuL,GAAWC,GAAI7K,GAAIC,EAAE,EACnCZ,EAAI,UAAY,sBAChBA,EAAI,KAAK,EACTA,EAAI,YAAcD,GAAUwK,EAAO,GAAI,EACvCvK,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EAEXA,EAAI,UAAYuK,EAChBvK,EAAI,UAAY,SAChBA,EAAI,aAAe,SACnBA,EAAI,SAASmL,GAAMI,GAAY5K,GAAK,EAAG6K,GAAK5K,GAAK,EAAI,GAAMX,CAAG,EAC9DD,EAAI,QAAQ,CACd,EAEK6K,GAAU/K,GAAqBhO,EAAGyD,EAAKI,EAAK4U,EAAOK,CAAO,EAE/D,IAAMa,GAAQ,GAAKxL,EAEnBiL,GAASD,EAAUtC,GAAIzI,EAAG,IAAMuL,GAAQ,EAAG,EAAI,EAG/CP,GAASF,GAAarC,GAAIzI,EAAG,IAAMA,EAAG,OAAS,GAAKD,EAAK,EAAK,CAChE,CAEA,SAAST,GACP1N,EACA+F,EACAjB,EACA2T,EACA5W,EACA4B,EACAV,EACA,CACA,GAAIlF,GAAe,KAAM,OACzB,IAAMgb,EAAO9S,EAAMlI,CAAW,EACxB+b,EAAO9U,EAAMjH,CAAW,EAC9B,GAAIgb,GAAQ,MAAQe,GAAQ,KAAM,OAElC,IAAM/C,EAAK7W,EAAE,SAAS6Y,EAAM,IAAK,EAAI,EAC/B9K,EAAK/N,EAAE,SAAS4Z,EAAM,IAAK,EAAI,EAC/BxL,EAAKpO,EAAE,KACPkO,GAAMlO,EAAE,IACRmO,GAAM,OAAO,kBAAoB,EAEvCD,GAAI,KAAK,EAETA,GAAI,UAAU,EACdA,GAAI,YAAcuK,EAClBvK,GAAI,UAAY,IAAMC,GACtBD,GAAI,OAAO2I,EAAIzI,EAAG,GAAG,EACrBF,GAAI,OAAO2I,EAAIzI,EAAG,IAAMA,EAAG,MAAM,EACjCF,GAAI,OAAO,EAGXA,GAAI,UAAU,EACdA,GAAI,YAAY,CAAC,EAAIC,GAAK,EAAIA,EAAG,CAAC,EAClCD,GAAI,YAAcD,GAAUwK,EAAO,EAAG,EACtCvK,GAAI,UAAY,EAAIC,GACpBD,GAAI,OAAOE,EAAG,KAAML,CAAE,EACtBG,GAAI,OAAO2I,EAAI9I,CAAE,EACjBG,GAAI,OAAO,EAGXA,GAAI,UAAU,EACdA,GAAI,YAAY,CAAC,CAAC,EAClBA,GAAI,IAAI2I,EAAI9I,EAAI,EAAII,GAAK,EAAG,KAAK,GAAK,CAAC,EACvCD,GAAI,UAAY,UAChBA,GAAI,KAAK,EACTA,GAAI,YAAcuK,EAClBvK,GAAI,UAAY,IAAMC,GACtBD,GAAI,OAAO,EACXA,GAAI,QAAQ,EAEZ,IAAMjG,EAAKjI,EAAU,SACjBiI,GAAKA,EAAE,SACTkH,GACEnP,EACAiI,EAAE,QACFpK,EACAkI,EACAjB,EACArB,EACA5B,EACAkB,CACF,CAEJ,CAEA,SAAS4K,GACP3N,EACA+F,EACAjB,EACA8U,EACAnB,EACA5W,EACA,CACA,IAAMuM,EAAKpO,EAAE,KACPkO,EAAMlO,EAAE,IACRmO,EAAM,OAAO,kBAAoB,EACjCJ,EAAK/N,EAAE,SAAS4Z,EAAM,IAAK,EAAI,EAG/BC,EAAU,KAAK,IAAIzL,EAAG,IAAK,KAAK,IAAIA,EAAG,IAAMA,EAAG,OAAQL,CAAE,CAAC,EAEjEG,EAAI,KAAK,EAETA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,EAAK,EAAIA,CAAG,CAAC,EAClCD,EAAI,YAAcD,GAAUwK,EAAO,EAAG,EACtCvK,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAOE,EAAG,KAAMyL,CAAO,EAC3B3L,EAAI,OAAOE,EAAG,KAAOA,EAAG,MAAOyL,CAAO,EACtC3L,EAAI,OAAO,EAGX4L,GAAkB9Z,EAAG+F,EAAOjB,EAAO+U,EAASpB,CAAK,EAGjD,IAAMhQ,EAAQ5G,EAAI,IAAI+X,EAAM,EAAI,EAC1BrL,GAAU,QAAQ,GAAKJ,CAAG,2BAC5BD,EAAI,OAASK,KAASL,EAAI,KAAOK,IAErC,IAAMM,EADKX,EAAI,YAAYzF,CAAK,EAAE,MAClB,EAAI0F,EACdW,GAAK,GAAKX,EACVY,GAAKX,EAAG,KAAOS,EAAK,EAAIV,EACxBa,GAAK6K,EAAU/K,GAAK,EAE1BZ,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EACbA,EAAY,UAAYA,EAAY,UAAUa,GAAIC,GAAIH,EAAIC,GAAI,EAAIX,CAAG,EACrED,EAAI,KAAKa,GAAIC,GAAIH,EAAIC,EAAE,EAC5BZ,EAAI,UAAY,sBAChBA,EAAI,KAAK,EACTA,EAAI,YAAcuK,EAClBvK,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EAEXA,EAAI,UAAY,OAChBA,EAAI,UAAY,SAChBA,EAAI,aAAe,SACnBA,EAAI,SAASzF,EAAOsG,GAAKF,EAAK,EAAGG,GAAKF,GAAK,EAAI,GAAMX,CAAG,EACxDD,EAAI,QAAQ,CACd,CAEA,SAAS4L,GACP9Z,EACA+F,EACAjB,EACA+U,EACApB,EACA,CACA,IAAMvK,EAAMlO,EAAE,IACRoO,EAAKpO,EAAE,KACPwG,EAAOxG,EAAE,OAAO,GAAG,KAAO,KAC1ByG,EAAOzG,EAAE,OAAO,GAAG,KAAO,IAC1ByX,EAAOzX,EAAE,OAAO,GAAG,KAAO,EAC1B0X,EAAO1X,EAAE,OAAO,GAAG,KAAO,IAC1B2X,EAASvJ,EAAG,OAAS3H,EAAOD,GAAQ,GACpCoR,GAASxJ,EAAG,QAAUsJ,EAAOD,GAAQ,GACrCsC,GAAO/Z,EAAE,OAAO,GAAG,KAAO,EAC1B6X,EAAQkC,KAAS,GAAK3L,EAAG,IAAMA,EAAG,IAAMA,EAAG,OAC3C4L,GAAQD,KAAS,GAAKnC,GAAS,CAACA,GAEhCE,GAAO9X,EAAE,OAAO,CAAC,GAAG,KACpB+X,GAASD,GAAO,KAAK,IAAI,EAAGA,GAAK,CAAC,EAAI,CAAC,EAAI,EAC3CE,GAAOF,GAAO,KAAK,IAAI/R,EAAM,OAAS,EAAG+R,GAAK,CAAC,EAAI,CAAC,EAAI/R,EAAM,OAAS,EACvE5E,GAAO,KAAK,IAAI,EAAG,KAAK,OAAO6W,GAAOD,IAAU,GAAG,CAAC,EAE1D7J,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,KAAKE,EAAG,KAAMA,EAAG,IAAKA,EAAG,MAAOA,EAAG,MAAM,EAC7CF,EAAI,KAAK,EAETA,EAAI,UAAYD,GAAUwK,EAAO,EAAG,EACpCvK,EAAI,UAAU,EAEd,IAAI+L,GAAY,GACZC,GAAgB,GAChBC,GAAS,EAEb,QAAStS,GAAIkQ,GAAQlQ,IAAKmQ,GAAMnQ,IAAK1G,GAAM,CACzC,IAAMiZ,GAAKrU,EAAM8B,EAAC,EACZwS,GAAKvV,EAAM+C,EAAC,EAClB,GAAIuS,IAAM,MAAQC,IAAM,MAAQD,GAAK5T,GAAQ4T,GAAK3T,EAAM,CAClDwT,KACF/L,EAAI,OAAOiM,GAAQN,CAAO,EAC1B3L,EAAI,UAAU,EACd+L,GAAY,IAEd,QACF,CAEA,IAAMK,GAAKlM,EAAG,MAAQgM,GAAK5T,GAAQmR,EAC7B4C,GAAK1C,GAASwC,GAAK5C,GAAQuC,GACjCG,GAASG,GAELC,GAAKV,GACFI,KACH/L,EAAI,OAAOoM,GAAIT,CAAO,EACtBI,GAAY,GACZC,GAAgB,IAElBhM,EAAI,OAAOoM,GAAIC,EAAE,GACRN,KACT/L,EAAI,OAAOoM,GAAIT,CAAO,EACtB3L,EAAI,UAAU,EACd+L,GAAY,GAEhB,CAEIA,KACF/L,EAAI,OAAOiM,GAAQN,CAAO,EAC1B3L,EAAI,UAAU,GAGZgM,IACFhM,EAAI,KAAK,EAGXA,EAAI,QAAQ,CACd,CAGA,SAASvI,GAAQ3E,EAAWC,EAAWC,EAAW,CAChD,IAAMsZ,EAAK,SAASxZ,EAAE,MAAM,CAAC,EAAG,EAAE,EAChC8N,EAAK,SAAS7N,EAAE,MAAM,CAAC,EAAG,EAAE,EACxBwZ,EAAKD,GAAM,GACfE,EAAMF,GAAM,EAAK,IACjBG,EAAKH,EAAK,IACNI,EAAK9L,GAAM,GACf+L,EAAM/L,GAAM,EAAK,IACjBV,EAAKU,EAAK,IACNgM,EAAKL,GAAMG,EAAKH,GAAMvZ,EAC1B6Z,GAAKL,GAAMG,EAAKH,GAAMxZ,EACtB8Z,GAAKL,GAAMvM,EAAKuM,GAAMzZ,EACxB,MAAO,MAAM,GAAK,KAAO,KAAK,MAAM4Z,CAAE,GAAK,KAAO,KAAK,MAAMC,EAAE,GAAK,GAAK,KAAK,MAAMC,EAAE,GACnF,SAAS,EAAE,EACX,MAAM,CAAC,CAAC,EACb,CAEA,SAASxV,GAAcuR,EAAkB,CACvC,GAAIA,GAAK,KAAM,MAAO,UACtB,IAAMkE,EAAO,KAAK,IAAIlE,CAAC,EACjB7V,EAAI,KAAK,IAAI,EAAG+Z,EAAO,CAAC,EAC9B,OAAIlE,EAAI,EAAUpR,GAAQ,UAAW,UAAWzE,CAAC,EAC1CyE,GAAQ,UAAW,UAAWzE,CAAC,CACxC,CAEA,SAASwE,GAAWuC,EAAkB,CACpC,GAAIA,GAAK,KAAM,MAAO,UACtB,IAAMiT,EAAMjT,EAAI,IAEhB,GAAIiT,GAAO,EAAG,MAAO,UACrB,GAAIA,GAAO,GAAI,MAAO,UAGtB,GAAIA,GAAO,GAAI,CACb,IAAMha,GAAKga,EAAM,GAAK,GACtB,OAAIha,GAAK,IAAayE,GAAQ,UAAW,UAAWzE,EAAI,GAAI,EACxDA,GAAK,GAAYyE,GAAQ,UAAW,WAAYzE,EAAI,KAAQ,GAAI,EAChEA,GAAK,IAAayE,GAAQ,UAAW,WAAYzE,EAAI,IAAO,GAAI,EAC7DyE,GAAQ,UAAW,WAAYzE,EAAI,KAAQ,GAAI,CACxD,KAAO,CAEL,IAAMA,GAAKga,EAAM,IAAM,GACvB,OAAOvV,GAAQ,UAAW,UAAWzE,CAAC,CACxC,CACF,CAEA,SAAS+H,GAAexF,EAAmB0X,EAAsB,CAC/D,IAAMC,EAA2B,IAAI,MAAM3X,EAAI,MAAM,EAAE,KAAK,IAAI,EAChE,QAASoE,EAAI,EAAGA,EAAIpE,EAAI,OAAQoE,IAAK,CACnC,IAAM/F,EAAI2B,EAAIoE,CAAC,EACXwT,EAAKxT,EACPyT,EAAKzT,EACP,KAAOwT,EAAK,IAAMvZ,EAAE,MAAQ,IAAM2B,EAAI4X,CAAE,EAAE,MAAQ,GAAKF,EAAe,GAAGE,IACzE,KAAOC,EAAK7X,EAAI,OAAS,IAAMA,EAAI6X,CAAE,EAAE,MAAQ,IAAMxZ,EAAE,MAAQ,GAAKqZ,EAAe,GAAGG,IACtF,IAAM5a,GAAK+C,EAAI6X,CAAE,EAAE,MAAQ,IAAM7X,EAAI4X,CAAE,EAAE,MAAQ,GAC7C3a,EAAI,GAAK+C,EAAI6X,CAAE,EAAE,KAAO,MAAQ7X,EAAI4X,CAAE,EAAE,KAAO,OACjDD,EAAMvT,CAAC,GAAMpE,EAAI6X,CAAE,EAAE,IAAO7X,EAAI4X,CAAE,EAAE,KAAQ3a,EAAK,IACrD,CACA,OAAO0a,CACT,CAEA,SAASzS,GAAU4S,EAAyB,CAC1C,IAAMC,EAAM,CAAC,GAAGD,CAAI,EACpB,QAAS1T,EAAI,EAAGA,EAAI2T,EAAI,OAAQ3T,IAC9B,GAAI2T,EAAI3T,CAAC,IAAM,KAAM,CACnB,IAAIyH,EAAOzH,EAAI,EACf,KAAOyH,GAAQ,GAAKkM,EAAIlM,CAAI,IAAM,MAAMA,IACxC,IAAImM,EAAQ5T,EAAI,EAChB,KAAO4T,EAAQD,EAAI,QAAUA,EAAIC,CAAK,IAAM,MAAMA,IAC9CnM,GAAQ,GAAKmM,EAAQD,EAAI,OAC3BA,EAAI3T,CAAC,EAAI2T,EAAIlM,CAAI,GAAOkM,EAAIC,CAAK,EAAKD,EAAIlM,CAAI,IAAOzH,EAAIyH,IAAUmM,EAAQnM,GACpEA,GAAQ,EAAGkM,EAAI3T,CAAC,EAAI2T,EAAIlM,CAAI,EAC5BmM,EAAQD,EAAI,SAAQA,EAAI3T,CAAC,EAAI2T,EAAIC,CAAK,EACjD,CAEF,OAAOD,CACT,CAEA,SAASpZ,GAAYX,EAAkB,CACrC,IAAMwG,EAAIxG,EAAM,MACVyE,EAAM,CAACC,EAAYvC,IAAgB,CACvC,IAAM5B,EAAK,SAAS,cAAc,IAAImE,CAAE,cAAc,EAClDnE,IAAIA,EAAG,YAAc4B,EAC3B,EACAsC,EAAI,gBAAiB+B,EAAE,WAAa,KAAO,IAAIA,EAAE,UAAY,KAAM,QAAQ,CAAC,CAAC,MAAQ,QAAG,EACxF/B,EAAI,gBAAiB+B,EAAE,UAAY,KAAO7B,GAAQ,KAAK,MAAM6B,EAAE,SAAW,GAAI,CAAC,EAAI,QAAG,EACtF/B,EAAI,iBAAkB+B,EAAE,UAAY,KAAO,GAAG,KAAK,MAAMA,EAAE,QAAQ,CAAC,KAAO,QAAG,EAG9E,IAAMyT,EAAU3b,GAAgB,CAC9B,IAAM+B,EAAIpF,EAAM,KAAMoF,GAAMA,EAAE,YAAc/B,CAAG,EAC/C,GAAI,CAAC+B,EACH,OAAI/B,IAAQ,QAAgBkI,EAAE,UAAY,KACtClI,IAAQ,QAAgBkI,EAAE,UAAY,KACtClI,IAAQ,UAAkBkI,EAAE,YAAc,KACvC,KAET,GAAInG,EAAE,SAAS,YAAc,OAC3B,OAAOA,EAAE,SAAS,UAAYA,EAAE,SAAS,UAAU,IAAM,KAE3D,IAAM0H,EACJnM,EAAqB,IAAI0C,CAAG,GAAMA,IAAQ,SAAWA,IAAQ,WAAaA,IAAQ,QAC9EgF,EAAOjD,EAAE,MAAM,OAAQkD,GAAmBA,GAAK,OAASwE,GAAWxE,IAAM,EAAE,EACjF,OAAKD,EAAK,OACHA,EAAK,OAAO,CAAC/D,EAAGC,KAAMD,EAAIC,GAAG,CAAC,EAAI8D,EAAK,OADrB,IAE3B,EAEM4W,EAAWD,EAAO,OAAO,EAC/BxV,EAAI,iBAAkByV,GAAY,KAAO,IAAIA,EAAW,KAAK,QAAQ,CAAC,CAAC,QAAU,QAAG,EAEpF,IAAMC,EAAWF,EAAO,OAAO,EAC/BxV,EAAI,iBAAkB0V,GAAY,KAAO,GAAG,KAAK,MAAMA,CAAQ,CAAC,KAAO,QAAG,EAE1E,IAAMC,EAAaH,EAAO,SAAS,EACnCxV,EAAI,eAAgB2V,GAAc,KAAO,GAAG,KAAK,MAAMA,CAAU,CAAC,OAAS,QAAG,EAE9E3V,EAAI,cAAe+B,EAAE,OAAS,KAAO,GAAGA,EAAE,KAAK,OAAS,QAAG,EAC3D/B,EAAI,gBAAiB+B,EAAE,SAAW,KAAO,GAAGA,EAAE,QAAQ,QAAQ,CAAC,CAAC,SAAQ,QAAG,CAC7E,CAEA,IAAM6T,GAAe,MACfC,GAAQ,IAAI,aAAaD,EAAY,EACrCE,GAAO,IAAI,aAAaF,EAAY,EACpCG,GAAQ,IAAI,aAAaH,EAAY,EACrCI,GAAQ,IAAI,aAAaJ,EAAY,EACrCK,GAAQ,IAAI,aAAaL,EAAY,EACrCM,GAAa,IAAI,aAAaN,EAAY,EAC1CO,GAAY,IAAI,aAAa,EAAE,EAC/BC,GAAkB,CACtB,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,GAChF,EAEA,SAASC,GACPC,EACAC,EACAC,EACA,CACA,GAAI,CAACF,EAAW,OAAQ,MAAO,GAC/BH,GAAU,KAAK,CAAC,EAChB,IAAIM,EAAgB,EAEpB,QAASC,EAAK,EAAGA,EAAKJ,EAAW,OAAQI,IAAM,CAC7C,IAAMnZ,EAAM+Y,EAAWI,CAAE,EAAE,OACrBrG,EAAI,KAAK,IAAI9S,EAAI,OAAQqY,EAAY,EAC3C,GAAIvF,EAAI,EAAG,SAEX,QAAS1O,GAAI,EAAGA,GAAI0O,EAAG1O,KAAK,CAC1B,IAAM/F,EAAI2B,EAAIoE,EAAC,EACfkU,GAAMlU,EAAC,EAAI/F,EAAE,OAAS,EACtBka,GAAKnU,EAAC,EAAI/F,EAAE,IAAM,EAClBma,GAAMpU,EAAC,EAAI/F,EAAE,OAAS,EACtBoa,GAAMrU,EAAC,EAAI/F,EAAE,KAAO,EACpBqa,GAAMtU,EAAC,EAAI/F,EAAE,KAAO,CACtB,CAGA,IAAM+a,EAAS,KAAK,IAAI,EAAG,KAAK,IAAItG,EAAI,EAAG,KAAK,MAAMkG,CAAW,CAAC,CAAC,EAC7DK,EAAO,KAAK,IAAID,EAAS,EAAG,KAAK,IAAItG,EAAG,KAAK,MAAMmG,CAAS,CAAC,CAAC,EAC9DK,EAAQ,EAAI,GACZC,EAAa,EAAI,IACjBC,EAAQ,KAEd,QAASpV,GAAI,EAAGA,GAAI0O,EAAI,EAAG1O,KAAK,CAC9B,IAAMqV,GACH,GAAKnB,GAAMlU,GAAI,CAAC,EACf,GAAKkU,GAAMlU,GAAI,CAAC,EAChB,GAAKkU,GAAMlU,EAAC,EACZ,GAAKkU,GAAMlU,GAAI,CAAC,EAChB,EAAIkU,GAAMlU,GAAI,CAAC,GACjBkV,EACII,IACH,GAAKnB,GAAKnU,GAAI,CAAC,EACd,GAAKmU,GAAKnU,GAAI,CAAC,EACf,GAAKmU,GAAKnU,EAAC,EACX,GAAKmU,GAAKnU,GAAI,CAAC,EACf,EAAImU,GAAKnU,GAAI,CAAC,GAChBkV,EACIK,IAASnB,GAAMpU,GAAI,CAAC,EAAI,EAAIoU,GAAMpU,EAAC,EAAIoU,GAAMpU,GAAI,CAAC,GAAK,IACvDwV,GAAKH,EAAQnB,GAAMlU,EAAC,EACpByV,GAAQ,KAAK,IAAI,CAACD,GAAKA,GAAKL,CAAU,EACtCO,GAAW,KAAK,IAAI1V,GAAIoV,EAAQd,GAAMtU,EAAC,EAAI,GAAI,EACrDuU,GAAWvU,EAAC,EAAIqV,EAAQI,GAAQH,GAAO,GAAMC,IAASjB,GAAMtU,EAAC,EAAI,GAAM0V,GACzE,CAEA,IAAMC,GAAoC,CACxC,CAAC,EAAG,KAAK,MAAMjH,EAAI,GAAI,CAAC,EACxB,CAAC,KAAK,MAAMA,EAAI,GAAI,EAAG,KAAK,MAAMA,EAAI,EAAG,CAAC,EAC1C,CAAC,KAAK,MAAMA,EAAI,EAAG,EAAGA,CAAC,EACvB,CAACsG,EAAQC,CAAI,CACf,EAEA,QAASW,GAAK,EAAGA,GAAKD,GAAc,OAAQC,KAAM,CAChD,GAAM,CAACC,EAAUC,EAAM,EAAIH,GAAcC,EAAE,EACrCG,GAASD,GAASD,EACxB,GAAI,EAAAE,GAAS,GAEb,SAASC,GAAK,EAAGA,GAAKvB,GAAgB,OAAQuB,KAAM,CAClD,IAAMlX,GAAI2V,GAAgBuB,EAAE,EAC5B,GAAIlX,IAAKiX,GAAQ,SACjB,IAAME,GAAO,EAAInX,GACboX,GAAS,EACTC,GAAS,EACTC,GAAc,EAClB,QAASpW,GAAI6V,EAAU7V,GAAI8V,GAAQ9V,KAGjC,GAFAkW,IAAU3B,GAAWvU,EAAC,EACtBmW,IAAU9B,GAAMrU,EAAC,EACbA,GAAI6V,GAAY/W,GAAG,CACrBoX,IAAU3B,GAAWvU,GAAIlB,EAAC,EAC1BqX,IAAU9B,GAAMrU,GAAIlB,EAAC,EACrB,IAAMuX,IAAOH,GAASC,GAAS,KAAQF,GACnCI,GAAMD,KAAaA,GAAcC,GACvC,CAEFvB,GAAiBsB,GAAc,IACjC,CAGA,QAASpW,GAAI6V,EAAU7V,GAAI8V,GAAQ9V,KAAK,CACtC,IAAMsW,GAAO,KAAK,IAAI,EAAG,KAAK,IAAI,IAAM/B,GAAWvU,EAAC,EAAI,IAAQ,GAAK,EAAE,CAAC,EACxEwU,GAAU8B,EAAI,GAAK,GAAKjC,GAAMrU,EAAC,EAAIqU,GAAMwB,CAAQ,GAAK,KAClDS,GAAO,IAAG9B,GAAU8B,GAAO,CAAC,GAAK,IACjCA,GAAO,KAAI9B,GAAU8B,GAAO,CAAC,GAAK,GACxC,EACF,CACF,CAEA,QAASld,EAAI,EAAGA,EAAI,GAAIA,IACtB0b,GAAiBN,GAAUpb,CAAC,EAAI,KAElC,OAAInC,IACFA,EAAU,QAAQ,cAAgB6d,EAAc,QAAQ,CAAC,GAEpDA,CACT,CAEA,MAAO,CACL,KAAAvd,GACA,UAAAoC,EACA,MAAAc,EACA,WAAAI,GACA,aAAAG,EACA,SAAAU,GACA,YAAAY,GACA,kBAAA6B,GACA,oBAAAvD,GACA,iBAAA4D,GACA,UAAAT,EACA,gBAAAjG,EACA,0BAAA4c,GACA,YAAa,CAAC1Y,EAAalC,EAAc,KAAU,CAGjD,GAFA9D,EAAcgG,EACVrF,IAAeA,GAAcqF,CAAG,EAChClC,EAAa,CACXtD,GAAkBd,GAAc,SAASsG,CAAG,GAC9CxF,EAAed,EAAa,OAAOsG,CAAG,CAAC,EAEzC,MACF,CACA5G,EAAgB,GAChBP,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,MAAA8E,EAAO,MAAAiB,CAAM,IAAM,CACxCA,EAAMlC,CAAG,GAAK,MAAQiB,EAAMjB,CAAG,GAAK,MACtC7D,EAAE,MAAM,IAAM,CACXA,EAAU,UACT,CACE,KAAMA,EAAE,SAAS+F,EAAMlC,CAAG,EAAI,GAAG,EACjC,IAAK7D,EAAE,SAAS8E,EAAMjB,CAAG,EAAI,GAAG,CAClC,EACA,GACA,EACF,CACF,CAAC,CAEL,CAAC,EACD5G,EAAgB,GACZoB,GAAkBd,GAAc,SAASsG,CAAG,GAC9CxF,EAAed,EAAa,OAAOsG,CAAG,CAAC,CAE3C,EACA,WAAaA,GAAuB,CAClC5G,EAAgB,GAChBP,EAAM,QAAQ,CAAC,CAAE,MAAOsD,EAAG,MAAA8E,EAAO,MAAAiB,CAAM,IAAM,CACxClC,IAAQ,KACV7D,EAAE,MAAM,IAAM,CACXA,EAAU,UAAU,CAAE,KAAM,IAAK,IAAK,GAAI,EAAG,GAAM,EAAK,CAC3D,CAAC,EACQ+F,EAAMlC,CAAG,GAAK,MAAQiB,EAAMjB,CAAG,GAAK,MAC7C7D,EAAE,MAAM,IAAM,CACXA,EAAU,UACT,CACE,KAAMA,EAAE,SAAS+F,EAAMlC,CAAG,EAAI,GAAG,EACjC,IAAK7D,EAAE,SAAS8E,EAAMjB,CAAG,EAAI,GAAG,CAClC,EACA,GACA,EACF,CACF,CAAC,CAEL,CAAC,EACD5G,EAAgB,GACZoB,GACFA,EACEwF,GAAO,MAAQtG,GAAc,SAASsG,CAAG,EAAItG,EAAa,OAAOsG,CAAG,EAAI,IAC1E,CAEJ,EACA,eAAgB,IAAM,CACpBhG,EAAc,KACVW,IAAeA,GAAc,IAAI,EACrC9B,EAAM,QAAQ,CAAC,CAAE,MAAOsD,CAAE,IAAMA,EAAE,OAAO,EAAK,CAAC,CACjD,EACA,OAAAqE,GACA,QAAAzC,GACA,WAAY,IAAMjE,EAClB,oBAAA2G,GACA,eAAAE,GACA,kBAAmB,IAAMtF,GACzB,iBAAkB,IAAMhC,EACxB,oBAAqB,IAAMC,EAC3B,iBAAAkG,GACA,UAAAP,GACA,iBAAAK,GACA,kBAAoBG,GAAmB,CAGrC,IAAM8a,EAAY,IAAI,IACtB9a,EAAK,QAASmP,GAAM,CACdvV,EAAc,IAAIuV,CAAC,GAAG2L,EAAU,IAAI3L,CAAC,CAC3C,CAAC,EAEDvV,EAAc,QAASuV,GAAM,CACtB2L,EAAU,IAAI3L,CAAC,GAAG2L,EAAU,IAAI3L,CAAC,CACxC,CAAC,EACDvV,EAAgBkhB,EACZ7gB,GAAc8E,GAAO,EAAI,CAC/B,EACA,SAAU,IAAM/E,CAClB,EAEA,SAASmQ,GACPzN,EACA+F,EACAjB,EACArB,EACAV,EACA,CACA,IAAMmL,EAAMlO,EAAE,IACRoO,EAAKpO,EAAE,KACPmO,EAAM,OAAO,kBAAoB,EACjCvJ,EAASC,GAAoB9B,EAAW+B,CAAK,EAEnDoJ,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,KAAKE,EAAG,KAAMA,EAAG,IAAKA,EAAG,MAAOA,EAAG,MAAM,EAC7CF,EAAI,KAAK,EAET,IAAMmQ,EAAYtb,IAAc,YAAcA,IAAc,YAE5D,QAAS8E,EAAI,EAAGA,EAAI9B,EAAM,OAAQ8B,IAAK,CACrC,GAAI9B,EAAM8B,CAAC,GAAK,MAAQ/C,EAAM+C,CAAC,GAAK,MAAQ9B,EAAM8B,EAAI,CAAC,GAAK,MAAQ/C,EAAM+C,EAAI,CAAC,GAAK,KAClF,SACF,IAAMwQ,EAAKrY,EAAE,SAAS+F,EAAM8B,EAAI,CAAC,EAAI,IAAK,EAAI,EACxCyQ,GAAKtY,EAAE,SAAS8E,EAAM+C,EAAI,CAAC,EAAI,IAAK,EAAI,EACxC0Q,GAAKvY,EAAE,SAAS+F,EAAM8B,CAAC,EAAI,IAAK,EAAI,EACpC2Q,EAAKxY,EAAE,SAAS8E,EAAM+C,CAAC,EAAI,IAAK,EAAI,EAEpC2P,GAAI5S,EAAOiD,CAAC,EAGlBqG,EAAI,UAAU,EACdA,EAAI,OAAOmK,EAAIC,EAAE,EACb+F,GAAWnQ,EAAI,OAAOqK,GAAID,EAAE,EAEhCpK,EAAI,OAAOqK,GAAIC,CAAE,EACjBtK,EAAI,YAAcsJ,GAClBtJ,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,CACb,CAEAA,EAAI,QAAQ,CACd,CAEA,SAASoQ,GAAqBte,EAAU+C,EAAmBlB,EAAuB,CAChF,GAAI,CAACrE,EAAU,OAAQ,OACvB,IAAM0Q,EAAMlO,EAAE,IACRoO,EAAKpO,EAAE,KACPmO,EAAM,OAAO,kBAAoB,EACjCoQ,EAAgB,IAEtBrQ,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,KAAKE,EAAG,KAAMA,EAAG,IAAKA,EAAG,MAAOA,EAAG,MAAM,EAC7CF,EAAI,KAAK,EAET,IAAMmQ,EAAYtb,IAAc,YAAcA,IAAc,YAE5D,QAAWtB,KAASjE,EAAW,CAC7B,GAAID,GAAgBkE,EAAM,KAAOlE,EAAa,GAAI,SAElD,IAAMkG,EAAMhC,EAAM,OACZiC,EAAKD,EAAI,KAAM3B,IAAMA,GAAE,MAAQ,IAAI,GAAG,MAAQ,EAC9C0c,EAAQ3c,EAAI,MAElBqM,EAAI,UAAU,EACdA,EAAI,YAAc,4BAClBA,EAAI,UAAY,EAAIC,EAEpB,IAAIsQ,GAAQ,GACZ,QAAS5W,GAAI,EAAGA,GAAIpE,EAAI,OAAQoE,KAAK,CACnC,IAAM/F,EAAI2B,EAAIoE,EAAC,EACT7C,GAAIlD,EAAE0c,CAAK,EAEjB,GAAIxZ,IAAK,KAAM,CACbyZ,GAAQ,GACR,QACF,CAEA,GAAI5W,GAAI,EAAG,CACT,IAAM8K,GAAOlP,EAAIoE,GAAI,CAAC,GACX/F,EAAE,MAAQ6Q,GAAK,KAAO7Q,EAAE,KAAO6Q,GAAK,KAAO,GAC7C4L,IAAeE,GAAQ,GAClC,CAEA,IAAM7a,GAAM/B,EAAI,UAAYA,EAAI,UAAUmD,EAAC,EAAIA,GAC/C,GAAIpB,IAAO,KAAM,CACf6a,GAAQ,GACR,QACF,CACA,IAAM5F,GAAOvb,IAAU,YAAcwE,EAAE,MAAQ,GAAK,KAAQA,EAAE,KAAQ4B,GAAM,IAG5E,GAAImV,GAAO7Y,EAAE,OAAO,EAAG,IAAO,IAAM6Y,GAAO7Y,EAAE,OAAO,EAAG,IAAO,GAAI,CAChEye,GAAQ,GACR,QACF,CAEA,IAAMnE,GAAKta,EAAE,SAAS6Y,GAAM,IAAK,EAAI,EAC/B0B,GAAKva,EAAE,SAAS4D,GAAK,IAAK,EAAI,EAEpC,GAAI6a,GACFvQ,EAAI,OAAOoM,GAAIC,EAAE,EACjBkE,GAAQ,OACH,CACL,GAAIJ,EAAW,CACb,IAAMK,GAAQjb,EAAIoE,GAAI,CAAC,EACjB8W,GACJrhB,IAAU,YAAcohB,GAAM,MAAQ,GAAK,KAAQA,GAAM,KAAQhb,GAAM,IACzEwK,EAAI,OAAOlO,EAAE,SAAS2e,GAAU,IAAK,EAAI,EAAGpE,EAAE,CAChD,CACArM,EAAI,OAAOoM,GAAIC,EAAE,CACnB,CACF,CACArM,EAAI,OAAO,CACb,CAEAA,EAAI,QAAQ,CACd,CAEA,SAASZ,GACPtN,EACA+F,EACAjB,EACA2T,EACAlJ,EACAxM,EACAyH,EAAiC,KACjC/G,EAAoB,CAAC,EACrB,CACA,IAAMyK,EAAMlO,EAAE,IACRoO,EAAKpO,EAAE,KACPmO,EAAM,OAAO,kBAAoB,EACjCoQ,EAAgB,IAEtBrQ,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAcD,GAAUwK,EAAO,EAAG,EACtCvK,EAAI,UAAYqB,EAAQpB,EAExB,IAAMkQ,GAAYtb,IAAc,YAAcA,IAAc,YACxD0b,GAAQ,GACRG,EAA+B,KAC/BC,GAAO,EACPC,GAAO,EAEX,GAAI/b,IAAc,SAAWU,EAAI,OAAS,EAAG,CAC3C,IAAI2O,GAAK,IACPC,GAAK,KACP,QAASxK,GAAI,EAAGA,GAAIpE,EAAI,OAAQoE,KAAK,CACnC,IAAMkX,GAAKtb,EAAIoE,EAAC,EAAE,gBAAkBpE,EAAIoE,EAAC,EAAE,UACvCkX,IAAM,OACJA,GAAK3M,KAAIA,GAAK2M,IACdA,GAAK1M,KAAIA,GAAK0M,IAEtB,CACI3M,IAAMC,KACRwM,GAAOzM,GACP0M,GAAOzM,GAEX,CAEA,IAAM2M,GAAOxU,EAAQA,EAAM,CAAC,EAAKxK,EAAE,OAAO,GAAG,KAAO,KAC9Cif,GAAOzU,EAAQA,EAAM,CAAC,EAAKxK,EAAE,OAAO,GAAG,KAAO,IAC9CwG,GAAOxG,EAAE,OAAO,GAAG,KAAO,KAC1ByG,GAAOzG,EAAE,OAAO,GAAG,KAAO,IAC1ByX,GAAOzX,EAAE,OAAO,GAAG,KAAO,EAC1B0X,GAAO1X,EAAE,OAAO,GAAG,KAAO,IAC1B2X,GAASvJ,EAAG,OAAS3H,GAAOD,IAAQ,GACpCoR,GAASxJ,EAAG,QAAUsJ,GAAOD,IAAQ,GACrCsC,GAAO/Z,EAAE,OAAO,GAAG,KAAO,EAC1B6X,GAAQkC,KAAS,GAAK3L,EAAG,IAAMA,EAAG,IAAMA,EAAG,OAC3C4L,GAAQD,KAAS,GAAKnC,GAAS,CAACA,GAEhCE,GAAQtN,EAA4B,KAApBxK,EAAE,OAAO,CAAC,GAAG,KAC7B+X,GAASD,GAAO,KAAK,IAAI,EAAGA,GAAK,CAAC,EAAI,CAAC,EAAI,EAC3CE,GAAOF,GAAO,KAAK,IAAI/R,EAAM,OAAS,EAAG+R,GAAK,CAAC,EAAI,CAAC,EAAI/R,EAAM,OAAS,EACvE5E,GACJkd,IAAatb,IAAc,QAAU,EAAI,KAAK,IAAI,EAAG,KAAK,OAAOiV,GAAOD,IAAU,GAAG,CAAC,EAClFmH,GAAa5hB,IAAU,OACvB6hB,GAASZ,EAAgB,IAC3Ba,GAAarH,GAEjB,QAASlQ,GAAIkQ,GAAQlQ,IAAKmQ,GAAMnQ,IAAK1G,GAAM,CACzC,IAAMiZ,GAAKrU,EAAM8B,EAAC,EACZwS,GAAKvV,EAAM+C,EAAC,EAClB,GAAIuS,IAAM,MAAQC,IAAM,KAAM,CAC5BoE,GAAQ,GACR,QACF,CAEA,GAAI1b,IAAc,SAAWU,EAAIoE,EAAC,EAAG,CACnC,IAAMkX,GAAKtb,EAAIoE,EAAC,EAAE,gBAAkBpE,EAAIoE,EAAC,EAAE,UAC3C,GAAIkX,IAAM,MAAQA,KAAOH,EAAe,CACtC,GAAI,CAACH,IAAS5W,GAAI,EAAG,CACnBqG,EAAI,OAAO,EACXA,EAAI,UAAU,EACd,IAAMmR,GAAQjR,EAAG,MAAQrI,EAAMqZ,EAAU,EAAK5Y,IAAQmR,GAChD2H,GAAQzH,IAAS/S,EAAMsa,EAAU,EAAK3H,IAAQuC,GACpD9L,EAAI,OAAOmR,GAAOC,EAAK,CACzB,CAGA,IAAIC,GAAe9G,EACfqG,KAASD,IAAQE,IAAM,OACrBA,KAAOF,GACTU,GAAe,UACRR,KAAOD,GACdS,GAAe,UACZA,GAAe,WAEtBrR,EAAI,YAAcD,GAAUsR,GAAc,EAAG,EAC7CX,EAAgBG,EAClB,CACF,CAGA,GAAIlX,GAAIkQ,IAAUmH,GAAY,CAC5B,IAAMM,GAASzZ,EAAMqZ,EAAU,EAC3BI,IAAU,MAAQpF,GAAKoF,GAASL,KAAQV,GAAQ,GACtD,CAGA,GAAIrE,GAAK4E,IAAQ5E,GAAK6E,GAAM,CAC1BR,GAAQ,GACR,QACF,CAEA,IAAMnE,GAAKlM,EAAG,MAAQgM,GAAK5T,IAAQmR,GAC7B4C,GAAK1C,IAASwC,GAAK5C,IAAQuC,GAEjC,GAAIyE,GACFvQ,EAAI,OAAOoM,GAAIC,EAAE,EACjBkE,GAAQ,OACH,CACL,GAAIJ,GAAW,CACb,IAAMmB,GAASzZ,EAAMqZ,EAAU,EAC/BlR,EAAI,OAAOE,EAAG,MAAQoR,GAAShZ,IAAQmR,GAAQ4C,EAAE,CACnD,CACArM,EAAI,OAAOoM,GAAIC,EAAE,CACnB,CACA6E,GAAavX,EACf,CACAqG,EAAI,OAAO,EACXA,EAAI,QAAQ,CACd,CACF,GAAG,EI76GH,IAAMuR,GAAuC,CAC3C,aAAcC,GAAQ,GAAG,KACzB,QAASA,GAAQ,QAAQ,KACzB,MAAOA,GAAQ,MAAM,KACrB,YAAaA,GAAQ,YAAY,KACjC,SAAUA,GAAQ,MAAM,KACxB,QAASA,GAAQ,QAAQ,IAC3B,EAEIC,GAA6B,IAAM,CAAC,EACpCC,GAAwC,IAAM,CAAC,EAC5C,SAASC,GAAYC,EAA0BC,EAAqC,CACzFJ,GAAiBG,EACjBF,GAAkBG,CACpB,CAEO,SAASC,IAAe,CAC7B,IAAMC,EAAY,SAAS,eAAe,cAAc,EACpDA,IACFA,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAO1B,CAEA,IAAMC,GAAa,MACbC,GAAiB,CACrB,IAAI,aAAaD,EAAU,EAC3B,IAAI,aAAaA,EAAU,EAC3B,IAAI,aAAaA,EAAU,EAC3B,IAAI,aAAaA,EAAU,EAC3B,IAAI,aAAaA,EAAU,EAC3B,IAAI,aAAaA,EAAU,EAC3B,IAAI,aAAaA,EAAU,CAC7B,EACME,GAAmB,CAAC,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAE,EAyB1D,SAASC,GAAoBC,EAAkBC,EAAwB,CACrE,IAAMC,EAAMF,EAAM,OACZG,EAAI,KAAK,IAAID,EAAI,OAAQN,EAAU,EACrCQ,EAAiB,EAErB,QAASC,EAAI,EAAGA,EAAIF,EAAGE,IAAK,CAC1B,IAAMC,EAAIJ,EAAIG,CAAC,EACfR,GAAe,CAAC,EAAEQ,CAAC,EAAIC,EAAE,OAAS,EAClCT,GAAe,CAAC,EAAEQ,CAAC,EAAIC,EAAE,IAAM,EAC/BT,GAAe,CAAC,EAAEQ,CAAC,EAAIC,EAAE,KAAO,EAChCT,GAAe,CAAC,EAAEQ,CAAC,EAAIC,EAAE,OAAS,EAClCT,GAAe,CAAC,EAAEQ,CAAC,EAAIC,EAAE,KAAO,EAChCT,GAAe,CAAC,EAAEQ,CAAC,EAAIC,EAAE,MAAQ,EACjCT,GAAe,CAAC,EAAEQ,CAAC,EAAIC,EAAE,MAAQ,CACnC,CAGA,QAASC,EAAK,EAAGA,EAAKT,GAAiB,OAAQS,IAAM,CACnD,IAAMC,EAAIV,GAAiBS,CAAE,EAC7B,GAAIC,GAAKL,EAAG,SACZ,IAAMM,EAAO,EAAID,EACXE,EAAQ,KAAK,IAAI,EAAGF,GAAK,CAAC,EAChC,QAASG,EAAK,EAAGA,EAAK,EAAGA,IAAM,CAC7B,IAAMC,EAAKf,GAAec,CAAE,EACxBE,EAAM,EACNC,EAAQ,EACRC,EAAU,EACVC,EAAY,EACVC,EAAW,GAAK,GAAKN,EAAK,GAAKJ,EAAK,GAC1C,QAASF,GAAI,EAAGA,GAAIF,EAAGE,KAAK,CAC1B,IAAMa,GAAIN,EAAGP,EAAC,EAGd,GAFAQ,GAAOK,GACPJ,GAASI,GAAIA,GACTb,IAAKG,EAAG,CACV,IAAMW,GAAMP,EAAGP,GAAIG,CAAC,EACpBK,GAAOM,GACPL,GAASK,GAAMA,GACf,IAAMC,EAAOP,EAAMJ,EACbY,EAAW,KAAK,IAAI,EAAGP,EAAQL,EAAOW,EAAOA,CAAI,EACjDE,EAASV,EAAGP,GAAIK,CAAK,EACrBa,EAAOL,GAAIN,EAAGP,GAAI,CAAC,EACnBmB,EAAcD,EAAOA,EAAON,EAC5BQ,EAAalB,EAAK,EAAI,KAAK,IAAI,CAACiB,CAAW,EAAI,GAAK,EAAIA,GAC9DR,GAAaO,EAAOA,EAAOE,EAC3B,IAAMC,EAAO,GAAK,EAAIL,EAAW,MACjCN,IAAYG,GAAIE,IAASE,EAASF,GAAQM,CAC5C,CACF,CACAtB,IAAmBW,EAAUC,EAAY,MAAQ,KAAK,IAAI,EAAGb,CAAC,CAChE,CACF,CAGA,IAAMwB,EAAW3B,EAAM,MAAM,UAAY4B,GAAQ,qBAAqB1B,CAAG,EACnE2B,EAAmC,CAAC,EAC1C,QAASC,EAAK,EAAGA,EAAKH,EAAS,OAAQG,IAAM,CAC3C,IAAMC,EAAMJ,EAASG,CAAE,EACvB,GAAIC,EAAI,OAAS,WAAaA,EAAI,OAAS,KAAM,SACjD,IAAMC,EAAKD,EAAI,MACTE,EAAcF,EAAI,OAASA,EAAI,SAAW,EAC5CG,EAAY,EAChB,QAAS7B,EAAI0B,EAAI,SAAW,EAAG1B,GAAK0B,EAAI,QAAU1B,EAAIF,EAAGE,IAAK,CAC5D,IAAM8B,EAAKtC,GAAe,CAAC,EAAEQ,CAAC,EAAIR,GAAe,CAAC,EAAEQ,EAAI,CAAC,EACnD+B,EAAKvC,GAAe,CAAC,EAAEQ,CAAC,EAAIR,GAAe,CAAC,EAAEQ,EAAI,CAAC,EACzD6B,GAAa,KAAK,IAAIC,CAAE,EAAI,IAAO,KAAK,IAAIC,CAAE,EAAI,GACpD,CACA,IAAMC,EAAU,KAAK,IAAI,KAAM,KAAK,IAAI,GAAM,KAAOH,EAAY,KAAK,IAAI,EAAGD,CAAW,CAAC,CAAC,EAC1FJ,EAAU,KAAK,CACb,MAAOE,EAAI,MACX,OAAQE,EACR,QAASD,EAAG,UAAY,KAAM,QAAQ,CAAC,EACvC,YAAaA,EAAG,SAAWM,GAAQ,KAAK,MAAMN,EAAG,SAAW,GAAI,CAAC,EAAI,SACrE,SAAU,KAAK,MAAMA,EAAG,QAAQ,EAChC,SAAUA,EAAG,UAAY,EACzB,MAAOA,EAAG,OAAS,EACnB,YAAaA,EAAG,UAAYA,EAAG,SAAW,KAAK,QAAQ,CAAC,EAAI,MAC5D,WAAYA,EAAG,YAAc,EAC7B,QAASA,EAAG,SAAW,KAAOA,EAAG,QAAQ,QAAQ,CAAC,EAAI,SACtD,aAAcK,EAAQ,QAAQ,CAAC,CACjC,CAAC,CACH,CAGA,IAAME,EAAU,IAAI,IAIpB,QAASlC,EAAI,EAAGA,EAAIF,EAAGE,IAAK,CAC1B,IAAMC,EAAIJ,EAAIG,CAAC,EACTmC,EAAKlC,EAAE,iBAAmBA,EAAE,YAAc,EAAI,GAAKA,EAAE,YAAc,EAAI,GAAK,IAC5EmC,EAAKnC,EAAE,gBAAkBA,EAAE,UAAY,KAAO,GAAKA,EAAE,SAAW,EAAI,IACpEoC,EAAM,GAAGF,CAAE,IAAIC,CAAE,GACnBE,EAAQJ,EAAQ,IAAIG,CAAG,EACtBC,IACHA,EAAQ,CAAE,MAAOH,EAAI,KAAMC,EAAI,KAAM,EAAG,OAAQ,EAAG,OAAQ,CAAE,EAC7DF,EAAQ,IAAIG,EAAKC,CAAK,GAExBA,EAAM,MAAQ,EACdA,EAAM,QAAUrC,EAAE,OAAS,EAC3BqC,EAAM,QAAUrC,EAAE,KAAO,CAC3B,CAEA,IAAMsC,EAAiC,MAAM,KAAKL,EAAQ,QAAQ,CAAC,EAChE,KAAK,CAACM,EAAGC,IAAMA,EAAE,CAAC,EAAE,KAAOD,EAAE,CAAC,EAAE,IAAI,EACpC,MAAM,EAAG,CAAC,EACV,IAAI,CAAC,CAACE,EAAOC,CAAC,KAAO,CACpB,MAAAD,EACA,OAAQC,EAAE,MAAQ,KAAK,IAAI,EAAGA,EAAE,IAAI,GAAG,QAAQ,CAAC,EAChD,QAASA,EAAE,KACX,IAAK,QAASA,EAAE,KAAO,KAAK,IAAI,EAAG7C,CAAC,EAAK,KAAK,QAAQ,CAAC,CAAC,EACxD,SAAU,KAAK,MAAM6C,EAAE,OAAS,KAAK,IAAI,EAAGA,EAAE,IAAI,CAAC,EACnD,WAAY,KAAK,MAAMA,EAAE,OAAS,KAAK,IAAI,EAAGA,EAAE,IAAI,CAAC,CACvD,EAAE,EAGEC,EAAShD,EAAU,OAAS,EAAIA,EAAY,CAACD,CAAK,EACpDkD,EAAW,EACXC,EAAU,EACVC,EAAW,EACXC,EAAe,EACfC,EAAgB,EACpB,QAASC,EAAK,EAAGA,EAAKN,EAAO,OAAQM,IAAM,CACzC,IAAMC,EAAOP,EAAOM,CAAE,EAAE,MACxBF,GAAgBG,EAAK,UAAY,EACjCF,GAAiBE,EAAK,WAAa,EAC/BA,EAAK,UAAYxD,EAAM,MAAM,WAAWkD,KACvCM,EAAK,UAAY,IAAMxD,EAAM,MAAM,UAAY,IAAImD,IACpDK,EAAK,SAAWxD,EAAM,MAAM,UAAUoD,GAC5C,CACA,IAAMK,EAAiB,KAAK,MAAMJ,EAAe,KAAK,IAAI,EAAGJ,EAAO,MAAM,CAAC,EACrES,GAAmBJ,EAAgB,KAAK,IAAI,EAAGL,EAAO,MAAM,EAAI,KAAM,QAAQ,CAAC,EAErF,MAAO,CACL,eAAA7C,EACA,UAAWyB,EAAU,MAAM,EAAG,EAAE,EAChC,WAAAe,EACA,YAAa,CACX,WAAYK,EAAO,OACnB,SAAAC,EACA,QAAAC,EACA,SAAAC,EACA,eAAAK,EACA,gBAAAC,CACF,CACF,CACF,CAEO,SAASC,GACd3D,EACA4D,EAAuB,CAAC,EACxB3D,EAAyB,CAAC,EAC1B4D,EACA,CACA,IAAMlE,EAAY,SAAS,eAAe,cAAc,EACxD,GAAI,CAACA,EAAW,OAEhB,GAAI,CAACK,EAAO,CACVL,EAAU,UAAY,GACtB,MACF,CAEA,IAAImE,EAAc9D,EAClB,GAAI6D,GAAgBA,EAAa,SAAW,EAAG,CAC7C,IAAME,EAAS/D,EAAM,OAAO,CAAC,GAAG,MAAQ,EAClCgE,EAAMD,EAASF,EAAa,CAAC,EAAI,IACjCI,EAAMF,EAASF,EAAa,CAAC,EAAI,IACjCK,EAAO,KAAK,IAChB,EACAlE,EAAM,OAAO,UAAWM,IAAOA,EAAE,MAAQ,IAAM0D,CAAG,CACpD,EACIG,EAAOnE,EAAM,OAAO,UAAWM,IAAOA,EAAE,MAAQ,IAAM2D,CAAG,EAE7D,GADIE,IAAS,KAAIA,EAAOnE,EAAM,OAAO,OAAS,GAC1CmE,EAAOD,EAAO,EAAG,CACnB,IAAME,EAASpE,EAAM,OAAO,MAAMkE,EAAMC,EAAO,CAAC,EAC1CE,EAAWzC,GAAQ,aAAawC,EAAQ,EAAI,EAClDN,EAAc,CACZ,GAAG9D,EACH,OAAQoE,EACR,MAAOC,CACT,CACF,CACF,CAEA,IAAMC,EAAIR,EAAY,MAChBS,EAAKT,EAAY,OAAO,CAAC,EAAE,KACjClC,GAAQ,qBAAqBkC,CAAW,EACxC,IAAMU,EAAiBzE,GAAoB+D,EAAa7D,CAAS,EAC3DwE,EAAwB,KAAK,IACjC,KACA,KAAK,IAAI,GAAM,GAAO,KAAK,KAAKD,EAAe,eAAiB,IAAK,EAAI,GAAG,CAC9E,EAAE,QAAQ,CAAC,EAEX7E,EAAU,UAAY;AAAA;AAAA,2DAEmC+E,GAAQ1E,EAAM,aAAeA,EAAM,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAUrF4D,EAAW,IAAKe,GAAM,kBAAkBD,GAAQC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sDAWxBL,EAAE,UAAY,KAAM,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,qDAI/BA,EAAE,SAAWhC,GAAQ,KAAK,MAAMgC,EAAE,SAAW,GAAI,CAAC,EAAI,QAAG;AAAA;AAAA;AAAA;AAAA,qDAIzDA,EAAE,UAAYA,EAAE,SAAW,KAAK,QAAQ,CAAC,EAAI,QAAG;AAAA;AAAA;AAAA;AAAA,sDAI/CA,EAAE,SAAW,KAAK,QAAQ,CAAC,CAAC;AAAA;AAAA,YAGtEA,EAAE,aAAe,KACb;AAAA;AAAA,2DAE2CA,EAAE,UAAU;AAAA,wBAEvD,EACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kFASwEI,GAAQ1E,EAAM,UAAY,QAAG,CAAC;AAAA;AAAA;AAAA;AAAA,qDAI3DA,EAAM,SAAW4E,GAAY5E,EAAM,QAAQ,EAAI,QAAG;AAAA;AAAA;AAAA;AAAA,qDAIlDA,EAAM,OAAO,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,8GAK+B6E,GAAa7E,EAAM,KAAK,CAAC;AAAA,sCACjG0E,GAAQI,GAAO9E,EAAM,OAAO,YAAY,GAAK,EAAE,GAAG,MAAQ,QAAG,CAAC;AAAA;AAAA,gBAEpFA,EAAM,SAAW,uDAAuD0E,GAAQ1E,EAAM,QAAQ,CAAC,WAAa,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,qDAKzEA,EAAM,QAAU,gBAAgB;AAAA;AAAA;AAAA;AAAA,qDAIhCuE,EAAKQ,GAAYR,CAAE,EAAI,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qDAUhCvE,EAAM,OAAO,OAAO,eAAe,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA,qDAI3CyE,CAAqB;AAAA;AAAA;AAAA;AAAA;AAAA,gBAM1DH,EAAE,QAAQ,OACNA,EAAE,QACC,IACEU,GACC,wDAAwDN,GAAQM,CAAM,CAAC,KAAK7F,GAAa6F,CAAM,GAAK,SAAS,SACjH,EACC,KAAK,EAAE,EACV,oEACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAONV,EAAE,OAASA,EAAE,UAAYA,EAAE,YAAcA,EAAE,SAAW,KAClD;AAAA;AAAA;AAAA;AAAA,YAKAA,EAAE,MACE;AAAA;AAAA,2DAE2CA,EAAE,KAAK;AAAA,wBAElD,EACN;AAAA,YAEEA,EAAE,MACE;AAAA;AAAA,2DAE2CA,EAAE,KAAK;AAAA,wBAElD,EACN;AAAA,YAEEA,EAAE,SACE;AAAA;AAAA,2DAE2CA,EAAE,QAAQ;AAAA,wBAErD,EACN;AAAA,YAEEA,EAAE,SACE;AAAA;AAAA,2DAE2CA,EAAE,QAAQ;AAAA,wBAErD,EACN;AAAA,YAEEA,EAAE,WACE;AAAA;AAAA,2DAE2CA,EAAE,UAAU;AAAA,wBAEvD,EACN;AAAA,YAEEA,EAAE,SAAW,KACT;AAAA;AAAA,2DAE2CA,EAAE,QAAQ,QAAQ,CAAC,CAAC;AAAA,wBAE/D,EACN;AAAA,YAEEA,EAAE,SAAW,MAAQA,EAAE,SAAW,KAC9B;AAAA;AAAA,2DAE2CA,EAAE,QAAQ,QAAQ,CAAC,CAAC,WAAMA,EAAE,QAAQ,QAAQ,CAAC,CAAC;AAAA,wBAEzF,EACN;AAAA;AAAA,cAGE,EACN;AAAA;AAAA,QAGEA,EAAE,SAAW,MAAQE,EAAe,WAAW,OAAS,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qDAMyCF,EAAE,QAAU,CAAC;AAAA;AAAA;AAAA;AAAA,sDAIZE,EAAe,YAAY,OAAO,MAAMA,EAAe,YAAY,UAAU,KAAKA,EAAe,YAAY,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAcnKA,EAAe,WACd,IACES,GAAO;AAAA;AAAA,2DAEmCP,GAAQO,EAAG,KAAK,CAAC;AAAA,4DAChBA,EAAG,KAAK;AAAA,4DACRA,EAAG,GAAG,MAAMA,EAAG,OAAO;AAAA,4DACtBA,EAAG,QAAQ;AAAA,4DACXA,EAAG,UAAU;AAAA;AAAA,aAG3D,EACC,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,cAIX,EACN;AAAA;AAAA,QAGET,EAAe,UAAU,OAAS,EAC9B;AAAA;AAAA,0HAE8GA,EAAe,UAAU,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAiB3IA,EAAe,UACd,IACEU,GAAO;AAAA;AAAA,2DAEmCR,GAAQQ,EAAG,KAAK,CAAC;AAAA,4DAChBA,EAAG,MAAM;AAAA,4DACTA,EAAG,WAAW;AAAA,6DACbA,EAAG,QAAQ;AAAA,4DACZA,EAAG,WAAW;AAAA,4DACdA,EAAG,QAAQ;AAAA,4DACXA,EAAG,KAAK;AAAA,4DACRA,EAAG,UAAU;AAAA,4DACbA,EAAG,OAAO;AAAA,4DACVA,EAAG,YAAY;AAAA;AAAA,aAG7D,EACC,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,cAIX,EACN;AAAA;AAAA,QAGElF,EAAM,SAAWA,EAAM,QAAQ,OAAS,EACpC;AAAA;AAAA;AAAA;AAAA,aAIC,IAAM,CACP,IAAMmF,EAAO,IAAI,IACjB,OAAOnF,EACJ,QAAS,OAAQoF,GAAM,CAEtB,GAAI,EADwBA,EAAE,MAAQA,EAAE,SAAWA,EAAE,cAC3B,MAAO,GAEjC,IAAM1C,EAAM,GAAG0C,EAAE,IAAI,IAAIA,EAAE,OAAO,IAAIA,EAAE,YAAY,IAAIA,EAAE,MAAM,GAChE,OAAID,EAAK,IAAIzC,CAAG,EAAU,IAC1ByC,EAAK,IAAIzC,CAAG,EACL,GACT,CAAC,EACA,IAAK0C,GAAM,CACV,IAAMC,EAAOD,EAAE,MAAQA,EAAE,SAAW,iBAC9BE,EAAeF,EAAE,aACnB,uCAAuCA,EAAE,YAAY,UACrD,GACEG,EAAQ,CACZH,EAAE,OAAS,OAAOA,EAAE,MAAM,GAAK,KAC/BA,EAAE,QAAU,IAAIA,EAAE,OAAO,GAAK,KAC9BA,EAAE,gBAAkB,MAAMA,EAAE,eAAe,GAAK,IAClD,EACG,OAAO,OAAO,EACd,KAAK,UAAK,EAEPI,EAAU,CACdJ,EAAE,aAAe,GAAGA,EAAE,YAAY,IAAM,KACxCA,EAAE,cAAgB,WAAWA,EAAE,aAAa,GAAK,KACjDA,EAAE,eAAiB,GAAGA,EAAE,eAAe,QAAQ,CAAC,CAAC,IAAM,IACzD,EACG,OAAO,OAAO,EACd,KAAK,UAAK,EAETK,EAAa,GACXzD,EAAK,OAAOoD,EAAE,YAAc,EAAE,EAAE,YAAY,EAC9CpD,EAAG,SAAS,OAAO,EAAGyD,EAAa,SAC9BzD,EAAG,SAAS,SAAS,GAAKA,EAAG,SAAS,UAAU,EACvDyD,EAAa,yBACNzD,EAAG,SAAS,WAAW,IAAGyD,EAAa,aAEhD,IAAIC,EAAa,UACXC,GAAY,OAAON,CAAI,EAAE,YAAY,EAC3C,OAAIM,GAAU,SAAS,WAAW,GAAKA,GAAU,SAAS,KAAK,EAC7DD,EAAatG,GAAQ,GAAG,KACjBuG,GAAU,SAAS,OAAO,EAAGD,EAAatG,GAAQ,MAAM,KACxDuG,GAAU,SAAS,OAAO,EAAGD,EAAatG,GAAQ,MAAM,KACxDuG,GAAU,SAAS,SAAS,EAAGD,EAAatG,GAAQ,QAAQ,KAC5DuG,GAAU,SAAS,WAAW,EAAGD,EAAa,MAC9CC,GAAU,SAAS,aAAa,EAAGD,EAAatG,GAAQ,YAAY,KACpEuG,GAAU,SAAS,KAAK,IAAGD,EAAa,eAE1C;AAAA;AAAA;AAAA;AAAA,oGAI6EA,CAAU;AAAA,uFACvBhB,GAAQW,CAAI,CAAC;AAAA,wBAC5EI,EAAa,sFAAsFL,EAAE,UAAU,KAAKK,CAAU,UAAY,EAAE;AAAA;AAAA,kEAElGH,CAAY;AAAA;AAAA,oBAG1DC,EACI,qEAAqEb,GAAQa,CAAK,CAAC,SACnF,EACN;AAAA;AAAA,uIAEqHb,GAAQU,EAAE,MAAQ,QAAQ,CAAC;AAAA,sBAE5II,EACI;AAAA;AAAA,8BAEId,GAAQc,CAAO,CAAC;AAAA,mCAEpB,EACN;AAAA;AAAA;AAAA,eAIN,CAAC,EACA,KAAK,EAAE,CACZ,GAAG,CAAC;AAAA;AAAA,cAGF,EACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYJ,IAAMI,EAAe,SAAS,eAAe,eAAe,EACtDC,EAAW,SAAS,eAAe,eAAe,EAClDC,EAAS,SAAS,eAAe,aAAa,EAE9CC,EAAa,IAAM,CACvBH,EAAa,UAAY,GACzB,IAAMI,EAAOhG,EAAM,MAAQ,CAAC,EAC5B,GAAIgG,EAAK,SAAW,EAAG,CACrBJ,EAAa,UACX,6FACF,MACF,CACAI,EAAK,QAASC,GAAQ,CACpB,IAAMC,EAAIC,GAAYF,CAAG,EACnBG,EAAK,SAAS,cAAc,KAAK,EACvCA,EAAG,UAAY,kBACfA,EAAG,MAAM,QAAU;AAAA,sBACHF,CAAC;AAAA,4BACKA,CAAC;AAAA,iBACZA,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQZE,EAAG,UAAY;AAAA,gBACL1B,GAAQuB,CAAG,CAAC;AAAA,iFACqDA,CAAG,kCAAkCC,CAAC;AAAA,QAEjHN,EAAa,YAAYQ,CAAE,CAC7B,CAAC,EAEDR,EAAa,iBAAiB,iBAAiB,EAAE,QAASS,GAAQ,CAChEA,EAAI,iBAAiB,QAAS,MAAOC,GAAM,CACzC,IAAML,EAAOK,EAAE,cAA8B,QAAQ,IACrDtG,EAAM,MAAQA,EAAM,MAAQ,CAAC,GAAG,OAAQ2E,GAAMA,IAAMsB,CAAG,EACvD,MAAMM,GAAQ,KAAKvG,CAAK,EACxB+F,EAAW,EACX1G,GAAe,CACjB,CAAC,CACH,CAAC,CACH,EAEMmH,EAAS,SAAY,CACzB,IAAMC,EAAMZ,EAAS,MAAM,KAAK,EAAE,YAAY,EAC9C,GAAI,CAACY,EAAK,OACV,IAAMT,EAAO,IAAI,IAAIhG,EAAM,MAAQ,CAAC,CAAC,EACrC,GAAIgG,EAAK,IAAIS,CAAG,EAAG,CACjBZ,EAAS,MAAQ,GACjB,MACF,CACAG,EAAK,IAAIS,CAAG,EACZzG,EAAM,KAAO,MAAM,KAAKgG,CAAI,EAAE,KAAK,EACnC,MAAMO,GAAQ,KAAKvG,CAAK,EACxB6F,EAAS,MAAQ,GACjBE,EAAW,EACX1G,GAAe,CACjB,EAEAyG,EAAO,iBAAiB,QAASU,CAAM,EACvCX,EAAS,iBAAiB,UAAYS,GAAM,CACtCA,EAAE,MAAQ,SAASE,EAAO,CAChC,CAAC,EAED,IAAME,EAAa/G,EAAU,cAAc,sBAAsB,EACjE+G,GAAY,iBAAiB,SAAU,SAAY,CACjD,IAAMD,EAAMC,EAAW,MAAM,KAAK,EAC7BD,IACLzG,EAAM,YAAcyG,EACpB,MAAMF,GAAQ,KAAKvG,CAAK,EACxBX,GAAe,EACjB,CAAC,EAED,IAAMsH,EAAe,SAAS,eAAe,wBAAwB,EACrEA,GAAc,iBAAiB,QAAUL,GAAM,CAC7CA,EAAE,gBAAgB,EAClBM,EAAcD,CAAY,CAC5B,CAAC,EAED,SAASC,EAAcC,EAAuB,CAC5C,GAAI,CAAC7G,EAAO,OACZ,SAAS,iBAAiB,oBAAoB,EAAE,QAASoG,GAAOA,EAAG,OAAO,CAAC,EAE3E,IAAMU,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAElB,OAAO,KAAKhC,EAAM,EAAE,QAASpC,GAAQ,CACnC,IAAMqE,EAAMjC,GAAOpC,CAAG,EAChBsE,EAAO,SAAS,cAAc,KAAK,EACnCC,GAAWjH,EAAM,OAAO,YAAY,IAAM0C,EAChDsE,EAAK,UAAY,aAAaC,GAAW,SAAW,EAAE,GACtDD,EAAK,UAAY;AAAA,iDAC0BD,EAAI,IAAI;AAAA,mCACtBA,EAAI,IAAI;AAAA,uDACYE,GAAW,QAAU,EAAE;AAAA,QAExED,EAAK,iBAAiB,QAAS,SAAY,CACzChH,EAAM,MAAQ0C,EACd,MAAM6D,GAAQ,KAAKvG,CAAK,EACxB8G,EAAM,OAAO,EACb,IAAMI,GAAS,SAAS,eAAe,YAAY,EAC/CA,KAAQA,GAAO,YAAcH,EAAI,MACrC,IAAMI,GAAS,SAAS,eAAe,YAAY,EAC/CA,KAAQA,GAAO,YAAcJ,EAAI,MACrC1H,GAAe,CACjB,CAAC,EACDyH,EAAM,YAAYE,CAAI,CACxB,CAAC,EAED,IAAMI,EAAY,SAAS,cAAc,KAAK,EACxCC,EAAU,CAACrH,EAAM,MACvBoH,EAAU,UAAY,aAAaC,EAAU,SAAW,EAAE,GAC1DD,EAAU,UAAY;AAAA;AAAA;AAAA,qDAG2BC,EAAU,QAAU,EAAE;AAAA,MAEvED,EAAU,iBAAiB,QAAS,SAAY,CAC9CpH,EAAM,MAAQ,OACd,MAAMuG,GAAQ,KAAKvG,CAAK,EACxB8G,EAAM,OAAO,EACb,IAAMI,EAAS,SAAS,eAAe,YAAY,EAC/CA,IAAQA,EAAO,YAAc,iBACjC,IAAMC,EAAS,SAAS,eAAe,YAAY,EAC/CA,IAAQA,EAAO,YAAc,UACjC9H,GAAe,CACjB,CAAC,EACDyH,EAAM,YAAYM,CAAS,EAE3B,SAAS,KAAK,YAAYN,CAAK,EAE/B,IAAMQ,EAAOT,EAAS,sBAAsB,EAC5CC,EAAM,MAAM,IAAM,GAAGQ,EAAK,OAAS,OAAO,QAAU,CAAC,KACrDR,EAAM,MAAM,KAAO,GAAGQ,EAAK,KAAO,OAAO,OAAO,KAEhD,IAAMC,EAAgBjB,GAAkB,CAClC,CAACQ,EAAM,SAASR,EAAE,MAAc,GAAK,CAACO,EAAS,SAASP,EAAE,MAAc,IAC1EQ,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASS,CAAY,EAEtD,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAY,EAAG,EAAE,CACvE,CAEAxB,EAAW,EAEO,SAAS,eAAe,kBAAkB,GACjD,iBAAiB,QAAS,IAAM,CACrC,QAAQ,WAAW/F,EAAM,IAAI,IAAI,GAAGV,GAAgBU,EAAM,EAAE,CAClE,CAAC,CACH,CCnxBA,OAAOwH,OAAW,QCsBlB,IAAIC,GAAoB,CAAC,EAElB,SAASC,GAAmBC,EAAsB,CACvD,OAAOF,GAAQ,OAAQG,GAAM,CAC3B,GAAIA,EAAE,OAAO,SAAW,EAAG,MAAO,GAClC,QAAWC,KAAMD,EAAE,OAAQ,CACzB,IAAIE,EAAc,GAClB,QAAWC,KAAWJ,EAAM,OAE1B,GADUK,GAAUH,EAAG,IAAKA,EAAG,IAAKE,EAAQ,IAAKA,EAAQ,GAAG,GACnDF,EAAG,OAAQ,CAClBC,EAAc,GACd,KACF,CAEF,GAAI,CAACA,EAAa,MAAO,EAC3B,CACA,MAAO,EACT,CAAC,CACH,CAEA,IAAIG,GAAgC,KAChCC,GAAa,GACbC,GAA8B,KAC9BC,GAAgD,IAAM,CAAC,EACvDC,GAAmB,KAGhB,SAASC,GAAYC,EAAiD,CAC3EC,GAAUD,EACVE,GAAY,CACd,CAEO,SAASC,IAAe,CAC7BC,GAAU,CAAC,EACXC,GAAiB,KACjBC,GAAe,KACfC,GAAa,GACb,IAAMC,EAAY,SAAS,eAAe,cAAc,EACpDA,IACFA,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAO1B,CAEO,SAASC,GAAwBC,EAAkB,CACxDN,GAAU,CAAC,EACX,IAAMO,EAKA,CACJ,CAAE,SAAU,EAAG,OAAQ,YAAa,MAAO,CAAC,GAAK,GAAK,GAAI,EAAG,OAAQ,GAAI,EACzE,CAAE,SAAU,EAAG,OAAQ,uBAAwB,MAAO,CAAC,IAAM,IAAM,GAAI,EAAG,OAAQ,GAAI,EACtF,CAAE,SAAU,EAAG,OAAQ,oBAAqB,MAAO,CAAC,GAAK,IAAM,EAAG,EAAG,OAAQ,GAAI,EACjF,CAAE,SAAU,EAAG,OAAQ,yBAA0B,MAAO,CAAC,GAAK,GAAK,GAAI,EAAG,OAAQ,GAAI,EACtF,CAAE,SAAU,EAAG,OAAQ,0BAA2B,MAAO,CAAC,GAAK,GAAK,GAAI,EAAG,OAAQ,GAAI,EACvF,CAAE,SAAU,EAAG,OAAQ,sBAAuB,MAAO,CAAC,GAAK,IAAM,GAAI,EAAG,OAAQ,GAAI,CACtF,EAEA,QAASC,EAAI,EAAGA,EAAID,EAAM,OAAQC,IAAK,CACrC,IAAMC,EAAOF,EAAMC,CAAC,EACdE,EAAIJ,EAAUG,EAAK,QAAQ,GAAKH,EAAUE,EAAI,KAAK,IAAI,EAAGF,EAAU,MAAM,CAAC,EACjF,GAAI,CAACI,GAAG,QAAUA,EAAE,OAAO,OAAS,GAAI,SACxC,IAAMC,EAAID,EAAE,OAAO,OACbE,EAASF,EAAE,OAAO,KAAK,MAAMC,EAAIF,EAAK,MAAM,CAAC,CAAC,CAAC,EAC/CI,EAAOH,EAAE,OAAO,KAAK,MAAMC,EAAIF,EAAK,MAAM,CAAC,CAAC,CAAC,EAC7CK,EAAOJ,EAAE,OAAO,KAAK,MAAMC,EAAIF,EAAK,MAAM,CAAC,CAAC,CAAC,EACnDT,GAAQ,KAAK,CACX,GAAI,UAAUQ,EAAI,CAAC,GACnB,KAAM,GAAGE,EAAE,aAAeA,EAAE,MAAQ,UAAUF,EAAI,CAAC,EAAE,WAAMC,EAAK,MAAM,GACtE,OAAQ,CACN,CAAE,IAAKG,EAAO,IAAK,IAAKA,EAAO,IAAK,OAAQH,EAAK,OAAQ,KAAM,YAAa,EAC5E,CAAE,IAAKI,EAAK,IAAK,IAAKA,EAAK,IAAK,OAAQJ,EAAK,OAAQ,KAAM,YAAa,EACxE,CAAE,IAAKK,EAAK,IAAK,IAAKA,EAAK,IAAK,OAAQL,EAAK,OAAQ,KAAM,aAAc,CAC3E,CACF,CAAC,CACH,CACIT,GAAQ,OAAS,IACnBC,GAAiBD,GAAQ,CAAC,EAAE,GAC5BE,GAAeF,GAAQ,CAAC,EAAE,GAE9B,CAEO,SAASe,IAAkC,CAChD,OAAOf,GAAQ,IAAKgB,GAAMA,EAAE,EAAE,CAChC,CAEA,eAAelB,IAAc,CAC3B,GAAI,CACF,IAAMmB,EAAS,MAAMC,GAAQ,IAAI,SAAS,EACtCD,IAAQjB,GAAUiB,EACxB,OAASE,EAAG,CACV,QAAQ,MAAM,kCAAmCA,CAAC,CACpD,CACF,CAEA,eAAeC,IAAc,CAC3B,GAAI,CACF,MAAMF,GAAQ,IAAI,UAAWlB,EAAO,CACtC,OAASmB,EAAG,CACV,QAAQ,MAAM,kCAAmCA,CAAC,EAClDtB,GAAQ,yBAA0B,OAAO,CAC3C,CACF,CAEA,SAASwB,GAAwBC,EAAwB,CACvD,IAAIC,EAAQ,EACZ,QAASf,EAAI,EAAGA,EAAIc,EAAO,OAAO,OAAS,EAAGd,IAAK,CACjD,IAAMgB,EAAKF,EAAO,OAAOd,CAAC,EACpBiB,EAAKH,EAAO,OAAOd,EAAI,CAAC,EAC9Be,GAASG,GAAUF,EAAG,IAAKA,EAAG,IAAKC,EAAG,IAAKA,EAAG,GAAG,CACnD,CACA,OAAOF,EAAQ,GACjB,CAEO,SAASI,GACdC,EACAC,EAC6C,CAC7C,GAAIA,EAAa,OAAS,EAAG,OAAO,KAEpC,IAAIC,EAAe,EACfC,EAAW,GACXC,EAAS,GAEb,QAAS,EAAI,EAAG,EAAIJ,EAAM,OAAO,OAAQ,IAAK,CAC5C,IAAMK,EAAKL,EAAM,OAAO,CAAC,EACnBM,EAAKL,EAAaC,CAAY,EAGpC,GAFUJ,GAAUQ,EAAG,IAAKA,EAAG,IAAKD,EAAG,IAAKA,EAAG,GAAG,GAEzCC,EAAG,OAAQ,CAGlB,GAFIJ,IAAiB,IAAGC,EAAW,GAE/BD,IAAiBD,EAAa,OAAS,EACzC,OAAAG,EAAS,EACF,CAAE,SAAAD,EAAU,OAAAC,CAAO,EAE5BF,GACF,CACF,CACA,OAAO,IACT,CAEO,SAASK,GAAqBP,EAAYG,EAAkBC,EAAgB,CACjF,IAAMI,EAAMR,EAAM,OACZjB,EAAIyB,EAAI,OACd,GAAIzB,IAAM,GAAKoB,EAAWC,EACxB,MAAO,CACL,SAAU,EACV,KAAM,EACN,SAAU,KACV,MAAO,KACP,SAAU,KACV,WAAY,KACZ,OAAQ,IACV,EAEF,IAAMK,EAAI,KAAK,IAAI,EAAG,KAAK,IAAIN,EAAUpB,EAAI,CAAC,CAAC,EACzCQ,EAAI,KAAK,IAAIkB,EAAG,KAAK,IAAIL,EAAQrB,EAAI,CAAC,CAAC,EACvC2B,EAAYF,EAAIC,CAAC,GAAG,MAAQ,EAE5BE,IADUH,EAAIjB,CAAC,GAAG,MAAQ,GACJmB,GAAa,IAErCE,EAAa,EACbC,EAAa,EACbC,EAAU,EACVC,EAAU,EACVC,EAAa,EACbC,EAAa,EACbC,EAAe,EACfC,EAAe,EACfC,EAAc,EAElB,QAASxC,EAAI6B,EAAG7B,GAAKW,EAAGX,IAAK,CAC3B,IAAM,EAAI4B,EAAI5B,CAAC,EAiBf,GAhBI,EAAE,OAAS,OACbgC,GAAc,EAAE,MAChBC,KAEE,EAAE,IAAM,OACVC,GAAW,EAAE,GACbC,KAEE,EAAE,OAAS,OACbC,GAAc,EAAE,MAChBC,KAEE,EAAE,SAAW,OACfC,GAAgB,EAAE,QAClBC,KAEEvC,EAAI6B,EAAG,CACT,IAAMY,EAAOb,EAAI5B,EAAI,CAAC,EACtB,GAAI,EAAE,KAAO,MAAQyC,EAAK,KAAO,KAAM,CACrC,IAAMC,EAAK,EAAE,IAAMD,EAAK,IACpBC,EAAK,IAAGF,GAAeE,EAC7B,CACF,CACF,CAEA,IAAMC,EAAOhC,EAAIkB,GAAKD,EAAIjB,CAAC,EAAE,MAAQ,IAAMiB,EAAIC,CAAC,EAAE,MAAQ,GAAK,EAE/D,MAAO,CACL,SAAAE,EACA,KAAAY,EACA,SAAUV,EAAa,EAAI,KAAK,MAAMD,EAAaC,CAAU,EAAI,KACjE,MAAOE,EAAU,EAAI,KAAK,MAAMD,EAAUC,CAAO,EAAI,KACrD,SAAUE,EAAa,EAAID,EAAaC,EAAa,KACrD,WAAYE,EAAe,EAAI,KAAK,MAAMD,EAAeC,CAAY,EAAI,KACzE,OAAQR,EAAW,EAAI,KAAK,MAAMS,GAAeT,EAAW,KAAK,EAAI,IACvE,CACF,CAEA,SAASa,GAAeC,EAAyB,CAC/C,IAAMC,EAAI,KAAK,MAAMD,EAAU,IAAI,EAC7BE,EAAI,KAAK,MAAOF,EAAU,KAAQ,EAAE,EACpChB,EAAI,KAAK,MAAMgB,EAAU,EAAE,EACjC,OAAIC,EAAI,EAAU,GAAGA,CAAC,IAAIC,EAAE,SAAS,EAAE,SAAS,EAAG,GAAG,CAAC,IAAIlB,EAAE,SAAS,EAAE,SAAS,EAAG,GAAG,CAAC,GAEjF,GAAGkB,CAAC,IAAIlB,EAAE,SAAS,EAAE,SAAS,EAAG,GAAG,CAAC,EAC9C,CAEO,SAASmB,IAA2B,CACzC,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2EAMkEC,GAAQ,IAAI,KAAK;AAAA;AAAA;AAAA,GAI5F,CAEO,SAASC,GAAuBC,EAAYC,EAAsBC,EAAiB,CAExF,IAAMC,GADWF,EAAQG,GAAOH,EAAM,YAAY,CAAC,EAAI,OAC5B,UAAY,KACnCI,EAAU,KACd,GAAIL,EAAM,UAAY,MAAQA,EAAM,SAAW,GAAK,CAClD,IAAMM,GAAeH,IAAa,KAAO,IAAO,KAAOH,EAAM,SAC7DK,EAAU,GAAGE,GAAQD,CAAW,CAAC,aAAaH,CAAQ,EACxD,CAEA,MAAO;AAAA,UACCD,CAAO;AAAA,UACPF,EAAM,MAAQ,KAAO,IAAIA,EAAM,KAAO,KAAM,QAAQ,CAAC,CAAC,WAAa,GAAG;AAAA,UACtEP,GAAeO,EAAM,QAAQ,CAAC;AAAA,UAC9BA,EAAM,UAAY,KAAO,IAAIA,EAAM,SAAW,KAAK,QAAQ,CAAC,CAAC,aAAe,GAAG;AAAA,UAC/EK,CAAO;AAAA,UACPL,EAAM,QAAU,KAAO,GAAGA,EAAM,MAAM,YAAc,GAAG;AAAA,UACvDA,EAAM,UAAY,KAAO,GAAGA,EAAM,QAAQ,UAAY,GAAG;AAAA,UACzDA,EAAM,OAAS,KAAO,GAAGA,EAAM,KAAK,YAAc,GAAG;AAAA,GAE/D,CAEA,IAAMQ,GAAa,MACbC,GAAgB,IAAI,aAAaD,EAAU,EAC3CE,GAAgB,IAAI,aAAaF,EAAU,EAC3CG,GAAgB,IAAI,aAAaH,EAAU,EAC3CI,GAAiB,IAAI,aAAa,EAAE,EACpCC,GAAiB,IAAI,aAAa,EAAE,EACpCC,GAAc,IACdC,GAAW,GACXC,GAAgB,IAAI,aAAaF,EAAW,EAC5CG,GAAiB,IAAI,aAAaH,EAAW,EAC7CI,GAAa,IAAI,aAAaJ,GAAc,CAAC,EAC7CK,GAAa,IAAI,aAAaL,GAAc,CAAC,EAE5C,SAASM,IAAgB,CAC9B,IAAM3E,EAAY,SAAS,eAAe,cAAc,EACxD,GAAI,CAACA,EAAW,OAIhB,IAAI4E,EAAuB,EACrBC,EACJ/E,IAAgBD,GACZD,GAAQ,OAAQgB,GAAMA,EAAE,KAAOd,IAAgBc,EAAE,KAAOf,EAAc,EACtED,GAEN,QAAWgB,KAAKiE,EAAe,CAC7B,GAAIjE,EAAE,OAAO,OAAS,EAAG,SACzB,IAAMkE,EAAeC,GAAQ,+BAC3BnE,EAAE,OAAO,IAAKoE,IAAO,CAAE,IAAKA,EAAE,IAAK,IAAKA,EAAE,GAAI,EAAE,EAChDpE,EAAE,OAAO,CAAC,GAAG,QAAU,EACzB,EACMqE,EAAW,EACjB,QAASC,EAAI,EAAGA,EAAID,EAAUC,IAAK,CAEjC,IAAMC,EADID,GAAKD,EAAW,IACJrE,EAAE,OAAO,OAAS,GAClCwE,EAAS,KAAK,IAAIxE,EAAE,OAAO,OAAS,EAAG,KAAK,MAAMuE,CAAQ,CAAC,EAC3DE,EAAOF,EAAWC,EAClBE,EAAK1E,EAAE,OAAOwE,CAAM,EACpBG,EAAK3E,EAAE,OAAOwE,EAAS,CAAC,EAC9BjB,GAAee,CAAC,EAAII,EAAG,KAAOC,EAAG,IAAMD,EAAG,KAAOD,EACjDjB,GAAec,CAAC,EAAII,EAAG,KAAOC,EAAG,IAAMD,EAAG,KAAOD,CACnD,CACA,QAASG,EAAK,EAAGA,EAAKV,EAAa,OAAQU,IAAM,CAC/C,IAAMC,EAAKX,EAAaU,CAAE,EAEpBxD,EADM+C,GAAQ,aAAaU,CAAE,GAClB,QAAU,CAAC,EACtBlF,EAAI,KAAK,IAAIyB,EAAI,OAAQ+B,EAAU,EACzC,GAAIxD,IAAM,EAEV,SAASH,EAAI,EAAGA,EAAIG,EAAGH,IAAK,CAC1B,IAAMsF,EAAK1D,EAAI5B,CAAC,EAChB4D,GAAc5D,CAAC,EAAIsF,EAAG,IACtBzB,GAAc7D,CAAC,EAAIsF,EAAG,IACtBxB,GAAc9D,CAAC,EAAIsF,EAAG,OAAS,CACjC,CAEA,QAASR,EAAI,EAAGA,EAAID,EAAUC,IAAK,CACjC,IAAMS,EAAOxB,GAAee,CAAC,EACvBU,EAAOxB,GAAec,CAAC,EACzBW,EAAU,IACVC,EAAU,EACd,QAAS1F,EAAI,EAAGA,EAAIG,EAAGH,IAAK,CAC1B,IAAM2F,EAAIzE,GAAUqE,EAAMC,EAAM5B,GAAc5D,CAAC,EAAG6D,GAAc7D,CAAC,CAAC,EAC9D2F,EAAIF,IACNA,EAAUE,EACVD,EAAU1F,EAEd,CACAwE,GAAwBiB,EAAU3B,GAAc4B,CAAO,EAAI,GAC7D,CAGA,QAAS7D,EAAI,EAAGA,EAAIoC,GAAapC,IAAK,CACpC,IAAM+D,EAAM,KAAK,IAAIzF,EAAI,EAAG,KAAK,MAAO0B,GAAK1B,EAAI,IAAO8D,GAAc,EAAE,CAAC,EACnEqB,EAAK1D,EAAIgE,CAAG,EACZC,GAAOP,EAAG,OAAS,GAAK,KAAOA,EAAG,KAAO,GAAK,KAAQA,EAAG,OAAS,GAAK,IACzEF,IAAO,IAAGjB,GAActC,CAAC,EAAIgE,GACjCzB,GAAevC,CAAC,EAAIgE,CACtB,CAEAxB,GAAW,KAAK,GAAG,EACnBA,GAAW,CAAC,EAAI,EAChB,QAASrE,EAAI,EAAGA,GAAKiE,GAAajE,IAAK,CACrCsE,GAAW,KAAK,GAAG,EACnB,IAAMwB,EAAS,KAAK,IAAI,EAAG9F,EAAIkE,EAAQ,EACjC6B,EAAO,KAAK,IAAI9B,GAAajE,EAAIkE,EAAQ,EACzC8B,EAAO7B,GAAcnE,EAAI,CAAC,EAChC,QAASiG,EAAIH,EAAQG,GAAKF,EAAME,IAAK,CACnC,IAAMC,EAAOF,EAAO5B,GAAe6B,EAAI,CAAC,EAClCE,EAASD,EAAOA,EAChBE,EAAOD,GAAU,EAAI,GAAK,EAAIA,EAAS,MACvCE,EAAKhC,GAAW4B,CAAC,EACjBK,EAAKhC,GAAW2B,EAAI,CAAC,EACrBM,EAAKlC,GAAW4B,EAAI,CAAC,EACrBO,EAAUH,EAAKC,EAAMD,EAAKE,EAAKF,EAAKE,EAAMD,EAAKC,EAAKD,EAAKC,EAC/DjC,GAAW2B,CAAC,EAAIG,EAAOI,CACzB,CACAnC,GAAW,IAAIC,EAAU,CAC3B,CACAE,GAAwBH,GAAWJ,EAAW,EAAI,KACpD,CACF,CACArE,EAAU,QAAQ,kBAAoB4E,EAAqB,QAAQ,CAAC,EAEpE5E,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,UAMdD,GACI;AAAA;AAAA;AAAA;AAAA,UAKA;AAAA;AAAA;AAAA;AAAA,SAKN;AAAA;AAAA;AAAA;AAAA;AAAA,UAMEH,GAAQ,SAAW,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,UAMAA,GACG,IAAKgB,GAAM,CACV,IAAMoB,EAAMpB,EAAE,OAAO,IAAKoE,IAAO,CAAE,IAAKA,EAAE,IAAK,IAAKA,EAAE,GAAI,EAAE,EACtD6B,EAAc9B,GAAQ,+BAC1B/C,EACApB,EAAE,OAAO,CAAC,GAAG,QAAU,EACzB,EACMkG,EAASlG,EAAE,KAAOd,GACpBiH,EAAa,GACjB,GAAID,EAAQ,CACV,IAAME,EAAyBH,EAC5B,IAAKpB,GAAO,CACX,IAAMjE,EAAQuD,GAAQ,aAAaU,CAAE,EACrC,GAAI,CAACjE,EAAO,OAAO,KACnB,IAAMyF,EAAQ1F,GAAgBC,EAAOZ,EAAE,MAAM,EAC7C,GAAI,CAACqG,EAAO,OAAO,KACnB,IAAM1D,EAAQxB,GAAqBP,EAAOyF,EAAM,SAAUA,EAAM,MAAM,EAChEC,EAAO,KAAK,IAAI,EAAGD,EAAM,OAASA,EAAM,QAAQ,EAChDE,EAAQF,EAAM,SAAW,KAAK,MAAMC,EAAO,GAAI,EAC/CE,EAAQH,EAAM,SAAW,KAAK,MAAMC,EAAO,EAAG,EAC9CG,EAAQJ,EAAM,SAAW,KAAK,MAAMC,EAAO,GAAI,EAC/CI,EAAUvF,GAAqBP,EAAOyF,EAAM,SAAUE,CAAK,EAC3DI,EAAUxF,GAAqBP,EAAO2F,EAAOC,CAAK,EAClDI,EAAUzF,GAAqBP,EAAO4F,EAAOC,CAAK,EAClDI,EAAU1F,GAAqBP,EAAO6F,EAAOJ,EAAM,MAAM,EACzD/E,EAAYV,EAAM,OAAO,WAAaA,EAAM,SAAS,CAAC,GAAG,KACzDiC,EAAUvB,EAAYwF,GAAQxF,CAAS,EAAI,IACjD,MAAO,CACL,GAAAuD,EACA,YAAajE,EAAM,aAAeA,EAAM,MAAQiE,EAChD,KAAMhC,EACN,MAAOjC,EAAM,MACb,MAAOA,EAAM,MACb,GAAG+B,EACH,cAAe,GAAG+D,EAAQ,UAAY,CAAC,IAAIC,EAAQ,UAAY,CAAC,IAAIC,EAAQ,UAAY,CAAC,IAAIC,EAAQ,UAAY,CAAC,IAClH,SAAUR,EAAM,SAChB,OAAQA,EAAM,MAChB,CACF,CAAC,EACA,OAAQ3G,GAAMA,IAAM,IAAI,EAG3B0G,EAAuB,KACrB,CAACW,EAAGC,IAAMD,EAAE,SAAWC,EAAE,UAAYD,EAAE,GAAG,cAAcC,EAAE,EAAE,CAC9D,EAEAb,EAAa;AAAA;AAAA,kBAGfC,EAAuB,SAAW,EAC9B;AAAA;AAAA,kBAGA;AAAA;AAAA;AAAA;AAAA,qCAIeA,EAAuB,MAAM;AAAA,0BACxC5D,GAAyB,CAAC;AAAA;AAAA;AAAA;AAAA,wBAI5B4D,EACC,IAAK1G,GAEG;AAAA,sDADYA,EAAE,KAAOuH,GAAS,IAAI,EAAE,MAEF,WAAa,EAAE,oBAAoBvH,EAAE,EAAE,iBAAiBA,EAAE,QAAQ,eAAeA,EAAE,MAAM;AAAA;AAAA;AAAA,uDAGrGA,EAAE,KAAK;AAAA,gCAC9BwH,GAAQxH,EAAE,WAAW,CAAC;AAAA;AAAA;AAAA,4BAG1BgD,GAAuBhD,EAAGA,EAAE,MAAOA,EAAE,IAAI,CAAC;AAAA;AAAA,uBAG7C,EACA,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,iBAIjB;AAAA;AAAA,aAGE,CACA,MAAO;AAAA,sCACawG,EAAS,OAAS,EAAE,cAAclG,EAAE,EAAE;AAAA;AAAA,qEAEPkG,EAAS,cAAgB,eAAe;AAAA,2CAClEgB,GAAQlH,EAAE,IAAI,CAAC;AAAA,sKAC4GK,GAAwBL,CAAC,EAAE,QAAQ,CAAC,CAAC,SAASA,EAAE,OAAO,MAAM,aAAaiG,EAAY,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAMlPE,CAAU;AAAA;AAAA,WAGV,CAAC,EACA,KAAK,EAAE,CAChB;AAAA;AAAA;AAAA,IAKN,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAS,IAAM,CACzEgB,GAAgB,CAClB,CAAC,EAED,SAAS,eAAe,eAAe,GAAG,iBAAiB,QAAS,IAAM,CACxEhI,GAAa,GACbgF,GAAQ,sBAAsB,IAAI,EAClC,SAAS,eAAe,eAAe,GAAG,UAAU,OAAO,cAAc,EACzEJ,GAAc,CAChB,CAAC,EAED3E,EAAU,iBAAiB,cAAc,EAAE,QAASgI,GAAO,CACzD,IAAMvC,EAAMuC,EAAmB,QAAQ,GACvCA,EAAG,cAAc,kBAAkB,GAAG,iBAAiB,QAAUjH,GAAM,CACrEA,EAAE,gBAAgB,EAClBkH,GAAWxC,CAAE,CACf,CAAC,EACDuC,EAAG,cAAc,oBAAoB,GAAG,iBAAiB,QAAUjH,GAAM,CACvEA,EAAE,gBAAgB,EAClBmH,GAAazC,CAAE,CACjB,CAAC,EACDuC,EAAG,cAAc,oBAAoB,GAAG,iBAAiB,QAAUjH,GAAM,CACvEA,EAAE,gBAAgB,EAClBoH,GAAa1C,CAAE,CACjB,CAAC,EACDuC,EAAG,cAAc,qBAAqB,GAAG,iBAAiB,QAAUjH,GAAM,CAErEA,EAAE,OAAuB,QAAQ,iBAAiB,GAClDA,EAAE,OAAuB,QAAQ,oBAAoB,IAIxDqH,GAAa3C,CAAE,EACf3F,GAAeA,KAAiB2F,EAAK,KAAOA,EAC5Cd,GAAc,EAChB,CAAC,EAEDqD,EAAG,iBAAiB,mBAAmB,EAAE,QAASK,GAAQ,CACxD,IAAMC,EAAWD,EAAoB,QAAQ,QACvC1G,EAAW,SAAU0G,EAAoB,QAAQ,MAAQ,EAAE,EAC3DzG,EAAS,SAAUyG,EAAoB,QAAQ,IAAM,EAAE,EAE7DA,EAAI,cAAc,kBAAkB,GAAG,iBAAiB,QAAUtH,GAAM,CACtEA,EAAE,gBAAgB,EAClB,IAAMS,EAAQuD,GAAQ,aAAauD,CAAO,EACtC9G,IAEF+G,GAAYD,EAAS,EAAK,EAG1B,WAAW,IAAM,CACf,IAAMtG,EAAMR,EAAM,OACZgH,EAAKxG,EAAI,KAAMgD,GAAWA,EAAE,MAAQ,IAAI,GAAG,MAAQ,EAGnDyD,EAAO,KAAK,IAAI,EAAG,KAAK,IAAI9G,EAAUK,EAAI,OAAS,CAAC,CAAC,EACrD0G,EAAO,KAAK,IAAI,EAAG,KAAK,IAAI9G,EAAQI,EAAI,OAAS,CAAC,CAAC,EAEnD2G,EAAO,KAAK,IAAI,IAAK3G,EAAIyG,CAAI,GAAG,MAAQ,GAAKD,GAAM,GAAI,EACvDI,EAAO,KAAK,IAAI,IAAK5G,EAAI0G,CAAI,GAAG,MAAQ,GAAKF,GAAM,GAAI,EAEvDK,EAAOC,GAAU,SAAS,EAC5BC,EAASJ,EACTK,EAASJ,EAETC,IAAS,aACXE,EAAS,KAAK,IAAI,GAAI/G,EAAIyG,CAAI,GAAG,MAAQ,GAAK,GAAI,EAClDO,EAAS,KAAK,IAAI,GAAIhH,EAAI0G,CAAI,GAAG,MAAQ,GAAK,GAAI,GAIpDb,GAAS,MAAM,CAAE,IAAK,CAACkB,EAAQC,CAAM,EAAG,IAAK,QAAS,EAAG,EAAI,EAG7DF,GAAU,iBAAiBH,EAAMC,CAAI,EAGrC7D,GAAQ,iBAAiBuD,EAAS9G,EAAM,OAAQG,EAAUC,EAAQ,EAAI,CACxE,EAAG,EAAE,EAET,CAAC,EAEDyG,EAAI,iBAAiB,aAAc,IAAM,CACvCtD,GAAQ,cAAcuD,EAAS,EAAI,CACrC,CAAC,EAEDD,EAAI,iBAAiB,aAAc,IAAM,CACvCtD,GAAQ,cAAcuD,EAAS,EAAK,CACtC,CAAC,CACH,CAAC,CACH,CAAC,CACH,CAEA,SAASP,IAAkB,CACzB,IAAMkB,EAAO,UAAUrJ,GAAQ,OAAS,CAAC,GAEnCsJ,EAAoB,CACxB,GAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,EAAG,CAAC,EAC7C,KAAMD,EACN,OAAQ,CAAC,CACX,EAEArJ,GAAQ,KAAKsJ,CAAS,EACtBlI,GAAY,EACZ2D,GAAc,EACdsD,GAAWiB,EAAU,EAAE,CACzB,CAEA,SAAShB,GAAazC,EAAY,CAChC,IAAMvE,EAAStB,GAAQ,KAAM,GAAM,EAAE,KAAO6F,CAAE,EAC9C,GAAI,CAACvE,EAAQ,OAEb,IAAM8G,EAAK,SAAS,cAAc,yBAAyBvC,CAAE,IAAI,EACjE,GAAI,CAACuC,EAAI,OAET,IAAMmB,EAASnB,EAAG,cAAc,cAAc,EAC9C,GAAI,CAACmB,EAAQ,OAEb,IAAMC,EAAclI,EAAO,KAC3BiI,EAAO,UAAY,uDAAuDrB,GAAQsB,CAAW,CAAC,+JAE9F,IAAMC,EAAQF,EAAO,cAAc,oBAAoB,EACvDE,EAAM,MAAM,EACZA,EAAM,OAAO,EAEb,IAAMC,EAAO,IAAM,CACjB,IAAMC,EAAUF,EAAM,MAAM,KAAK,EAC7BE,IAAY,KACdrI,EAAO,KAAOqI,EACdvI,GAAY,GAEd2D,GAAc,CAChB,EAEA0E,EAAM,iBAAiB,OAAQC,CAAI,EACnCD,EAAM,iBAAiB,UAAYtI,GAAM,CACnCA,EAAE,MAAQ,QAASuI,EAAK,EACnBvI,EAAE,MAAQ,UAAU4D,GAAc,CAC7C,CAAC,CACH,CAEA,SAASsD,GAAWxC,EAAY,CAC9B5F,GAAiB4F,EACjB1F,GAAa,GACb4E,GAAc,CAChB,CAEA,SAAS6E,IAAmB,CAC1BC,GAAc,IAChB,CAqBO,SAASC,GAAaC,EAAYC,EAAgB,GAAO,CAC9DC,GAAiBF,EACbC,IAAME,GAAeH,GACzBI,GAAa,GACbC,GAAQ,sBAAsB,IAAI,EAClCC,GAAiB,EACjBC,GAAc,CAChB,CAEA,SAASC,GAAaR,EAAY,CAC3B,QAAQ,8CAA8C,IAC3DS,GAAUA,GAAQ,OAAQC,GAAMA,EAAE,KAAOV,CAAE,EACvCE,KAAmBF,IACrBE,GAAiB,KACjBI,GAAiB,GAEnBK,GAAY,EACZJ,GAAc,EAChB,CDprBA,IAAIK,GAAgD,IAAM,CAAC,EACvDC,GAAwB,CAAC,EAE7B,SAASC,IAAsB,CAC7BD,GAAa,QAASE,GAAMA,EAAE,QAAQ,CAAC,EACvCF,GAAe,CAAC,CAClB,CAEO,SAASG,GAAaC,EAAiD,CAC5EL,GAAUK,CACZ,CAEO,SAASC,IAAgB,CAC9BJ,GAAoB,EACpB,SAAS,iBAAiB,oBAAoB,EAAE,QAASK,GAAOA,EAAG,OAAO,CAAC,EAC3E,IAAMC,EAAY,SAAS,eAAe,eAAe,EACrDA,IACFA,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAO1B,CAEA,IAAMC,GAAc,MACdC,GAAW,IAAI,aAAaD,EAAW,EACvCE,GAAU,IAAI,aAAaF,EAAW,EACtCG,GAAW,IAAI,aAAaH,EAAW,EACvCI,GAAW,IAAI,aAAaJ,EAAW,EACvCK,GAAW,IAAI,aAAaL,EAAW,EACvCM,GAAc,IAAI,aAAaN,GAAc,CAAC,EAC9CO,GAAc,IAAI,aAAaP,GAAc,CAAC,EAC9CQ,GAAe,CACnB,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAChF,EAiBA,SAASC,GACPC,EACAC,EACAC,EAC0B,CAC1B,IAAMC,EAAI,KAAK,IAAIH,EAAI,OAAQV,EAAW,EAC1C,GAAIa,IAAM,EACR,MAAO,CACL,aAAc,IACd,cAAe,EACf,cAAe,EACf,YAAa,CAAC,GAAI,GAAI,GAAI,EAAE,EAC5B,aAAc,CAAC,CACjB,EAGF,QAASC,EAAI,EAAGA,EAAID,EAAGC,IAAK,CAC1B,IAAMC,EAAKL,EAAII,CAAC,EACVpB,EAAIqB,EAAG,OAAS,EAChBC,EAAID,EAAG,IAAM,EACbE,EAAIF,EAAG,KAAO,GACdG,EAAKH,EAAG,OAAS,EACjBI,EAAKJ,EAAG,UAAY,EACpBK,GAAMD,EAAK,EAAID,EAAKC,EAAK,GAAK,EACpClB,GAASa,CAAC,EAAIpB,EACdQ,GAAQY,CAAC,EAAI,EAAIE,EACjBb,GAASW,CAAC,EAAIG,EACdb,GAASU,CAAC,EAAII,EACdb,GAASS,CAAC,EAAIM,GACdd,GAAYQ,EAAI,CAAC,EAAIR,GAAYQ,CAAC,EAAIpB,EACtCa,GAAYO,EAAI,CAAC,EAAIP,GAAYO,CAAC,EAAIM,EACxC,CAGA,IAAIC,EAAmB,EACvB,QAASC,EAAK,EAAGA,EAAKd,GAAa,OAAQc,IAAM,CAC/C,IAAMC,EAAIf,GAAac,CAAE,EACzB,GAAIC,EAAIV,EAAG,SACX,IAAMW,EAAQX,EAAIU,EACdE,EAAO,EACPC,EAAO,EACX,QAASC,EAAI,EAAGA,GAAKH,EAAOG,IAAK,CAC/B,IAAMC,EAAOtB,GAAYqB,EAAIJ,CAAC,EAAIjB,GAAYqB,CAAC,EACzCE,GAAOtB,GAAYoB,EAAIJ,CAAC,EAAIhB,GAAYoB,CAAC,EAC3CC,EAAOH,IAAMA,EAAOG,GACpBC,GAAOH,IAAMA,EAAOG,GAC1B,CACAR,IAAqBI,EAAOC,GAAQH,CACtC,CAGA,IAAIO,EAAe,IACfC,EAAO,IACPC,EAAgB,EAChBC,EAAc,GACZC,EAAOrB,GAAK,EACdsB,EAAS,EACTC,EAAS,EACPC,EAA4C,CAAC,EAAG,EAAG,EAAG,CAAC,EACvDC,EAAe,GACfC,EAAkB5B,EAAS2B,EAEjC,QAASxB,EAAI,EAAGA,EAAID,EAAGC,IAAK,CAC1B,IAAMpB,EAAIO,GAASa,CAAC,EACd0B,EAAM,KAAK,IAAI,EAAGrC,GAASW,CAAC,CAAC,EAC7B2B,EAAOvC,GAAQY,CAAC,EAChB4B,EAAOhD,EAAIiB,EACXgC,EAAMD,EAAO,EAAI,CAACA,EAAO,EACzBE,EAAMF,EAAO,EAAIA,EAAO,EAExBG,GAAS,IADG,KAAK,IAAI,OAAUF,EAAMC,EAAM,KAAM,EACtB,IACjCb,EAAO,KAAK,IAAI,IAAOA,EAAOa,GAAO,IAAQb,IAAS,EAAIc,GAAO,EAC7Dd,EAAOD,IAAcA,EAAeC,GAEpCA,EAAO,OAAS,CAACE,GACnBA,EAAc,GACdD,KACSD,EAAO,OAASE,IACzBA,EAAc,IAGhB,IAAMa,GAASpD,EAAI8C,EACfM,IAAUP,GAAmBC,GAAOF,EAAcD,EAAQ,CAAC,IACtDS,IAAUP,GAAmBC,EAAMF,EAAcD,EAAQ,CAAC,IAC1DS,GAASP,GAAmBC,EAAMF,EAAcD,EAAQ,CAAC,IAC7DA,EAAQ,CAAC,IAEd,IAAMU,EAAKrD,EAAI+C,EACX3B,EAAIoB,EAAMC,GAAUY,EACnBX,GAAUW,CACjB,CAEA,IAAMC,EAAMd,EAAO,EAAIC,EAASD,EAAO,EACjCe,EAAMpC,EAAIqB,EAAO,EAAIE,GAAUvB,EAAIqB,GAAQ,EAC3CgB,EAAgBF,EAAM,GAAMA,EAAMC,GAAOD,EAAO,IAAM,EACtDG,EAAgD,CACpD,QAASd,EAAQ,CAAC,EAAIxB,EAAK,KAAK,QAAQ,CAAC,CAAC,EAC1C,QAASwB,EAAQ,CAAC,EAAIxB,EAAK,KAAK,QAAQ,CAAC,CAAC,EAC1C,QAASwB,EAAQ,CAAC,EAAIxB,EAAK,KAAK,QAAQ,CAAC,CAAC,EAC1C,QAASwB,EAAQ,CAAC,EAAIxB,EAAK,KAAK,QAAQ,CAAC,CAAC,CAC5C,EASMuC,GANJxC,GAAYA,EAAS,OAAS,EAC1BA,EAAS,OACNyC,GAAQA,EAAI,OAAS,WAAaA,EAAI,OAAS,SAAWA,EAAI,OAAS,QAC1E,EACA,CAAC,GAE6B,MAAM,EAAG,CAAC,EAAE,IAAKA,GAAQ,CAC3D,IAAMC,EAAKD,EAAI,MACTE,EAAWD,EAAG,UAAYA,EAAG,SAAW,EAAIA,EAAG,SAAW,KAAU,EAC1E,MAAO,CACL,MAAOD,EAAI,MACX,OAAQ,QAAQC,EAAG,UAAY,KAAM,QAAQ,CAAC,CAAC,EAC/C,SAAUA,EAAG,UAAY,EACzB,aAAcA,EAAG,aAAa,EAAE,GAAG,OAASA,EAAG,UAAY,EAC3D,MAAOA,EAAG,OAAS,EACnB,IAAKC,EAAW,EAAI,KAAK,MAAMD,EAAG,SAAWC,CAAQ,EAAI,CAC3D,CACF,CAAC,EAED,OAAIlC,EAAmB,QAAOS,EAAe,GACtC,CACL,aAAAA,EACA,cAAAE,EACA,cAAAkB,EACA,YAAAC,EACA,aAAAC,CACF,CACF,CAEO,SAASI,GACdC,EACAC,EAAyB,CAAC,EAC1BC,EAAwC,KACxC,CACAlE,GAAoB,EACpB,IAAMM,EAAY,SAAS,eAAe,eAAe,EACzD,GAAI,CAACA,EAAW,OAEhB,GAAI,CAAC0D,EAAO,CACV1D,EAAU,UAAY,GACtB,MACF,CAEA6D,GAAQ,qBAAqBH,CAAK,EAC7BA,EAAM,MAAM,WACfA,EAAM,MAAM,SAAWG,GAAQ,qBAAqBH,EAAM,MAAM,GAIlE,IAAMI,EAAcF,GAAgBG,GAAS,IAAI,EAAE,KAAO,KACtDC,EAAYN,EAAM,OAClBO,EAAIP,EAAM,MACd,GAAII,GAAeJ,EAAM,OAAO,OAAS,EAAG,CAC1C,IAAMQ,EAAKR,EAAM,OAAO,CAAC,EAAE,MAAQ,EAC7BS,EAAUD,EAAKJ,EAAY,CAAC,EAAI,IAChCM,EAAQF,EAAKJ,EAAY,CAAC,EAAI,IAChCO,EAAOX,EAAM,OAAO,UAAW/D,IAAOA,EAAE,MAAQ,IAAMwE,CAAO,EAC7DG,EAAOZ,EAAM,OAAO,UAAW/D,IAAOA,EAAE,MAAQ,IAAMyE,CAAK,EAC3DC,IAAS,KAAIA,EAAO,GACpBC,IAAS,KAAIA,EAAOZ,EAAM,OAAO,OAAS,GAC1CY,EAAOD,EAAO,IAChBL,EAAYN,EAAM,OAAO,MAAMW,EAAMC,EAAO,CAAC,EAC7CL,EAAIJ,GAAQ,aAAaG,EAAW,EAAI,EAE5C,CAEA,GAAI,CAACC,EAAE,YAAc,CAACA,EAAE,SAAW,CAACA,EAAE,QAAS,CAC7CjE,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAMtB,MACF,CAEA,IAAMuE,EAAO7D,GAAuBsD,EAAWH,GAAQ,OAAO,EAAGH,EAAM,MAAM,QAAQ,EAC/E3B,EAAewC,EAAK,aAE1BvE,EAAU,UAAY;AAAA,sEAC8C+B,EAAa,QAAQ,CAAC,CAAC,mBAAmBwC,EAAK,aAAa;AAAA,IAGhI,IAAMC,EAAO,SAAS,eAAe,eAAe,EACpD,GAAI,CAACA,EAAM,OAEX,IAAMC,EAAa,KAAK,MAAMD,EAAK,sBAAsB,EAAE,MAAQ,EAAE,GAAK,IA8B1E,GA5BIP,EAAE,YACJS,GAAgB,CACd,KAAAF,EACA,MAAAd,EACA,MAAOO,EAAE,WACT,UAAW,QACX,MAAO,cACP,KAAM,IACN,MAAOU,GAAQ,MAAM,MACrB,KAAM,OACN,WAAAF,CACF,CAAC,EAGCR,EAAE,SACJS,GAAgB,CACd,KAAAF,EACA,MAAAd,EACA,MAAOO,EAAE,QACT,UAAW,KACX,MAAO,mBACP,KAAM,MACN,MAAOU,GAAQ,GAAG,MAClB,KAAM,WACN,WAAAF,CACF,CAAC,EAGCR,EAAE,WAAY,CAChB,IAAMW,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,eACjB,IAAMC,EAAY,QACZC,EAAQH,GAAQ,MAAM,MAC5BC,EAAK,MAAM,YAAY,gBAAiBE,CAAK,EAC7C,IAAMC,EAAeC,GAAU,kBAAkB,IAAMH,EAEjDI,EAAYhB,EAAE,WAAW,OAAO,CAACiB,EAAGC,IAAMD,EAAIC,EAAG,CAAC,EAClDC,EAAQC,GAAM,cAAc,EAE9BC,EAAY,GAChBrB,EAAE,WAAW,QAAQ,CAACsB,EAAMxE,IAAM,CAChC,GAAIA,GAAKqE,EAAM,OAAQ,OACvB,IAAMI,EAAIJ,EAAMrE,CAAC,EACX0E,EAAMR,EAAY,EAAKM,EAAON,EAAa,IAAM,EACjDS,EAAY,SAASF,EAAE,GAAG,EAC5B,GAAG,KAAK,MAAMA,EAAE,GAAG,CAAC,MAAM,KAAK,MAAMA,EAAE,GAAG,CAAC,KAC3C,KAAK,KAAK,MAAMA,EAAE,GAAG,CAAC,KAE1BF,GAAa;AAAA;AAAA;AAAA,4EAGyDvE,EAAI,CAAC;AAAA,0IACyDyE,EAAE,IAAI;AAAA,+FACjDE,CAAS;AAAA,gHACQC,GAAQ,KAAK,MAAMJ,CAAI,CAAC,CAAC;AAAA,mIACNE,EAAI,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA,6CAGpGA,CAAG,iBAAiBD,EAAE,KAAK;AAAA;AAAA;AAAA,OAIpE,CAAC,EAEDZ,EAAK,UAAY;AAAA;AAAA;AAAA;AAAA,kEAI6CE,CAAK;AAAA;AAAA,uDAEhBC,EAAe,SAAW,EAAE,kBAAkBF,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAQ1ES,CAAS;AAAA,MAEzCd,EAAK,YAAYI,CAAI,EAErBA,EAAK,cAAc,gBAAgB,GAAG,iBAAiB,QAAUgB,GAAM,CACrEA,EAAE,gBAAgB,EAClBZ,GAAU,eAAeH,CAAS,EAClC,IAAMgB,EAAUb,GAAU,kBAAkB,EAC5CR,EAAK,iBAAiB,gBAAgB,EAAE,QAASsB,GAAQ,CACvD,IAAMX,EAAIW,EACVX,EAAE,UAAU,OAAO,SAAUA,EAAE,QAAQ,SAAWU,CAAO,CAC3D,CAAC,CACH,CAAC,EAEDjB,EAAK,cAAc,kBAAkB,GAAG,iBAAiB,QAAUgB,GAAM,CACvEA,EAAE,gBAAgB,EAClBG,GAAsBH,EAAE,cAA8BlC,CAAK,CAC7D,CAAC,CACH,CAEA,GAAIO,EAAE,QAAS,CACb,IAAMW,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,eACjB,IAAMC,EAAY,KACZC,EAAQH,GAAQ,GAAG,MACzBC,EAAK,MAAM,YAAY,gBAAiBE,CAAK,EAC7C,IAAMC,EAAeC,GAAU,kBAAkB,IAAMH,EAEjDI,EAAYhB,EAAE,QAAQ,OAAO,CAACiB,EAAGC,IAAMD,EAAIC,EAAG,CAAC,EAC/CC,EAAQC,GAAM,WAAW,EAE3BC,EAAY,GAChBrB,EAAE,QAAQ,QAAQ,CAACsB,EAAMxE,IAAM,CAC7B,GAAIA,GAAKqE,EAAM,OAAQ,OACvB,IAAMI,EAAIJ,EAAMrE,CAAC,EACX0E,EAAMR,EAAY,EAAKM,EAAON,EAAa,IAAM,EACjDS,EAAY,SAASF,EAAE,GAAG,EAC5B,GAAG,KAAK,MAAMA,EAAE,GAAG,CAAC,MAAM,KAAK,MAAMA,EAAE,GAAG,CAAC,OAC3C,KAAK,KAAK,MAAMA,EAAE,GAAG,CAAC,OAE1BF,GAAa;AAAA;AAAA;AAAA,4EAGyDvE,EAAI,CAAC;AAAA,0IACyDyE,EAAE,IAAI;AAAA,+FACjDE,CAAS;AAAA,gHACQC,GAAQ,KAAK,MAAMJ,CAAI,CAAC,CAAC;AAAA,mIACNE,EAAI,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA,6CAGpGA,CAAG,iBAAiBD,EAAE,KAAK;AAAA;AAAA;AAAA,OAIpE,CAAC,EAEDZ,EAAK,UAAY;AAAA;AAAA;AAAA;AAAA,kEAI6CE,CAAK;AAAA;AAAA,uDAEhBC,EAAe,SAAW,EAAE,kBAAkBF,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAQ1ES,CAAS;AAAA,MAEzCd,EAAK,YAAYI,CAAI,EAErBA,EAAK,cAAc,gBAAgB,GAAG,iBAAiB,QAAUgB,GAAM,CACrEA,EAAE,gBAAgB,EAClBZ,GAAU,eAAeH,CAAS,EAClC,IAAMgB,EAAUb,GAAU,kBAAkB,EAC5CR,EAAK,iBAAiB,gBAAgB,EAAE,QAASsB,GAAQ,CACvD,IAAMX,EAAIW,EACVX,EAAE,UAAU,OAAO,SAAUA,EAAE,QAAQ,SAAWU,CAAO,CAC3D,CAAC,CACH,CAAC,EAEDjB,EAAK,cAAc,kBAAkB,GAAG,iBAAiB,QAAUgB,GAAM,CACvEA,EAAE,gBAAgB,EAClBI,GAAmBJ,EAAE,cAA8BlC,CAAK,CAC1D,CAAC,CACH,CAEA,IAAMuC,EAAe,SAAS,cAAc,KAAK,EACjDA,EAAa,UAAY,eACzB,IAAMC,EAASjC,EAAE,UAAY,IACvBkC,EAAQD,EAAS,EAAKjC,EAAE,UAAYiC,EAAS,KAAS,IAAM,EA2BlE,GAzBAD,EAAa,UAAY;AAAA;AAAA,4DAEiCtB,GAAQ,UAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,iDAKlC,KAAK,MAAMV,EAAE,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,iDAItB,KAAK,MAAMA,EAAE,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,iDAItBkC,EAAM,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,iDAIhBlC,EAAE,UAAYA,EAAE,SAAW,EAAI,KAAK,MAAOA,EAAE,SAAWA,EAAE,SAAY,IAAO,EAAI,CAAC;AAAA;AAAA;AAAA,IAIjIO,EAAK,YAAYyB,CAAY,EAEzBhC,EAAE,UAAYA,EAAE,MAAO,CACzB,IAAMmC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,eACpB,IAAMpD,EAAKiB,EAAE,SAAWA,EAAE,MAE1BmC,EAAQ,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mDAO2BpD,EAAG,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,mDAIbuB,EAAK,cAAc,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,oDAI5BA,EAAK,aAAe,KAAM,QAAQ,CAAC,CAAC,QAAQA,EAAK,aAAa;AAAA;AAAA;AAAA;AAAA,mDAI/DA,EAAK,YAAY,KAAK,MAAM,CAAC;AAAA;AAAA;AAAA,MAI5EC,EAAK,YAAY4B,CAAO,CAC1B,CAEA,GAAI7B,EAAK,aAAa,OAAS,EAAG,CAChC,IAAM8B,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,eACpBA,EAAQ,UAAY;AAAA;AAAA,8DAEsC1B,GAAQ,MAAM,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAcrEJ,EAAK,aACJ,IACEpD,GAAO;AAAA;AAAA,yDAEmCmF,GAAQnF,EAAG,KAAK,CAAC;AAAA,0DAChBA,EAAG,MAAM;AAAA,0DACTA,EAAG,QAAQ;AAAA,0DACXA,EAAG,YAAY;AAAA,0DACfA,EAAG,KAAK;AAAA,0DACRA,EAAG,GAAG;AAAA;AAAA,WAGpD,EACC,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,MAIjBqD,EAAK,YAAY6B,CAAO,CAC1B,CAEA,IAAME,EAAeC,GAAmB9C,CAAK,EAC7C,GAAI6C,EAAa,OAAS,EAAG,CAC3B,IAAME,EAAc,SAAS,cAAc,KAAK,EAChDA,EAAY,UAAY,eACxBA,EAAY,MAAM,QAAU,oCAE5BA,EAAY,UAAY;AAAA,+FACmEF,EAAa,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAMlGG,GAAyB,CAAC;AAAA;AAAA;AAAA;AAAA,cAI5BH,EACC,IAAKrF,GAAM,CACV,IAAMyF,EAAQC,GAAgBlD,EAAOxC,EAAE,MAAM,EACzC2F,EAAY,GAChB,GAAIF,EAAO,CACT,IAAMG,EAAQC,GAAqBrD,EAAOiD,EAAM,SAAUA,EAAM,MAAM,EAChEK,EAAYtD,EAAM,OAAO,WAAaA,EAAM,SAAS,CAAC,GAAG,KACzDuD,EAAUD,EAAYE,GAAQF,CAAS,EAAI,IAEjDH,EAAYM,GAAuBL,EAAOpD,EAAM,OAAS,KAAMuD,CAAO,CACxE,MACEJ,EACE,4HAGJ,MAAO;AAAA,yEACkD3F,EAAE,EAAE;AAAA;AAAA;AAAA;AAAA,wBAIrDoF,GAAQpF,EAAE,IAAI,CAAC;AAAA;AAAA;AAAA,oBAGnB2F,CAAS;AAAA;AAAA,eAGf,CAAC,EACA,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA,MAKnBrC,EAAK,YAAYiC,CAAW,EAE5BA,EAAY,iBAAiB,mBAAmB,EAAE,QAAS1G,GAAO,CAChEA,EAAG,iBAAiB,QAAS,IAAM,CACjC,IAAMqH,EAAYrH,EAAmB,QAAQ,GAC7CsH,GAAaD,EAAU,EAAI,EAC3BrD,GAAS,MAAM,CAAE,IAAK,SAAU,EAAG,EAAI,CACzC,CAAC,EAEDhE,EAAG,iBAAiB,aAAc,IAAM,CACtC,IAAMqH,EAAYrH,EAAmB,QAAQ,GACvCmB,EAAIqF,EAAa,KAAMe,GAAWA,EAAO,KAAOF,CAAQ,EAC9D,GAAIlG,EAAG,CACL,IAAMyF,EAAQC,GAAgBlD,EAAOxC,EAAE,MAAM,EACzCyF,GACFY,GAAQ,iBAAiB7D,EAAM,GAAIA,EAAM,OAAQiD,EAAM,SAAUA,EAAM,OAAQ,EAAK,CACxF,CACF,CAAC,EAED5G,EAAG,iBAAiB,aAAc,IAAM,CACtCwH,GAAQ,eAAe,CACzB,CAAC,CACH,CAAC,CACH,CACF,CAcA,SAAS7C,GAAgB8C,EAAwB,CAC/C,GAAM,CAAE,KAAAhD,EAAM,MAAAd,EAAO,MAAA+D,EAAO,UAAA5C,EAAW,MAAA6C,EAAO,KAAAC,EAAM,MAAA7C,EAAO,KAAA8C,EAAM,WAAAnD,CAAW,EAAI+C,EAC1EzC,EAAeC,GAAU,kBAAkB,IAAMH,EAEjDD,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,eACjBA,EAAK,MAAM,YAAY,gBAAiBE,CAAK,EAC7CF,EAAK,UAAY;AAAA;AAAA;AAAA;AAAA,gEAI6CE,CAAK,KAAK8C,CAAI,UAAUF,CAAK;AAAA;AAAA,qDAExC3C,EAAe,SAAW,EAAE,kBAAkBF,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAQ7FA,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IActBL,EAAK,YAAYI,CAAI,EAErB,IAAMiD,EAAYjD,EAAK,cAAc,mBAAmB,EAClDkD,EAAYlD,EAAK,cAAc,mBAAmB,EAClDmD,EAAaD,EAAU,cAAc,2BAA2B,EAEtEA,EAAU,iBAAiB,QAAS,IAAM,CACxC,IAAME,EAAWH,EAAU,MAAM,UAAY,OAC7CA,EAAU,MAAM,QAAUG,EAAW,QAAU,OAC/CD,EAAW,YAAcC,EAAW,cAAgB,aACtD,CAAC,EAED,IAAMC,EAAcrD,EAAK,cAAc,gBAAgB,EACvDqD,EAAY,iBAAiB,QAAUrC,GAAM,CAC3CA,EAAE,gBAAgB,EAClB,IAAMsC,EAAMD,EAAY,QAAQ,OAChCjD,GAAU,eAAekD,CAAG,EAG5B,IAAMrC,EAAUb,GAAU,kBAAkB,EAC5CR,EAAK,iBAAiB,gBAAgB,EAAE,QAASsB,GAAQ,CACvD,IAAMX,EAAIW,EACVX,EAAE,UAAU,OAAO,SAAUA,EAAE,QAAQ,SAAWU,CAAO,CAC3D,CAAC,CACH,CAAC,EAED,IAAMsC,EAAQvD,EAAK,cAAc,cAAc,EACzCwD,EAAY,OAAO,KAAKX,CAAK,EAChC,IAAI,MAAM,EACV,KAAK,CAACvC,EAAG,IAAMA,EAAI,CAAC,EAEvBkD,EAAU,QAAS5G,GAAM,CACvB,IAAM6G,EAAQZ,EAAMjG,CAAC,EACf8G,EAAOD,EAAc,OAAUA,EAAc,IAAOA,EAAc,IAClEE,EAAM,SAAS,cAAc,IAAI,EACvCA,EAAI,UAAY;AAAA,YACRC,GAAYhH,CAAC,CAAC;AAAA,oCACU8G,CAAG,IAAIX,CAAI;AAAA;AAAA,yFAE0CU,EAAM,GAAG,eAAe7G,CAAC;AAAA;AAAA;AAAA;AAAA,MAK9G2G,GAAO,YAAYI,CAAG,CACxB,CAAC,EAEDJ,GAAO,iBAAiB,gBAAgB,EAAE,QAASrC,GAAQ,CACzDA,EAAI,iBAAiB,QAAUF,GAAM,CACnC,IAAMT,EAAIS,EAAE,cACN6C,EAAW,SAAStD,EAAE,QAAQ,GAAI,EAClCuD,EAAW,SAASvD,EAAE,QAAQ,GAAI,EAClCxE,EAAM+C,EAAM,OACZiF,EAAS,KAAK,IAAIhI,EAAI,OAAS,EAAG8H,EAAWC,EAAW,CAAC,EAEzDxE,EAAKvD,EAAI,CAAC,EAAE,MAAQ,EACpBiI,IAASjI,EAAI8H,CAAQ,EAAE,MAAQvE,GAAMA,GAAM,IAC3C2E,KAASlI,EAAIgI,CAAM,EAAE,MAAQzE,GAAMA,GAAM,IAE/CH,GAAS,MAAM,CAAE,IAAK,CAAC6E,EAAMC,EAAI,CAAE,CAAC,EACpCtB,GAAQ,iBAAiB7D,EAAM,GAAI/C,EAAK8H,EAAUE,EAAQ,EAAI,CAChE,CAAC,CACH,CAAC,EAED,IAAMG,EAAUlE,EAAK,cAAc,IAAIC,CAAS,cAAc,EAC9D,GAAIiE,EAAS,CACX,IAAMC,EAAQX,EACRY,EAAQZ,EAAU,IACrB5G,GAAOiG,EAAMjG,CAAC,EAAU,OAAUiG,EAAMjG,CAAC,EAAU,IAAOiG,EAAMjG,CAAC,EAAU,GAC9E,EAEMyH,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,YACpBA,EAAQ,MAAM,QAAU,SAASnE,CAAK,8BAA8BA,CAAK,KACzEgE,EAAQ,MAAM,SAAW,WACzBA,EAAQ,YAAYG,CAAO,EAE3B,IAAMzB,EAAsB,CAC1B,GAAI,GAAG3C,CAAS,SAChB,MAAO,EACP,OAAQ,IACR,QAAS,CAAC,GAAI,GAAI,EAAG,EAAE,EACvB,OAAQ,CACN,EAAG,CAAE,KAAM,GAAO,MAAO,EAAG,KAAM,EAAK,EACvC,EAAG,CAAE,KAAM,EAAK,CAClB,EACA,OAAQ,CACN,CAAC,EACD,CACE,MAAA6C,EACA,OAAQ5C,EACR,MAAO,EACP,KAAMoE,GAAUpE,EAAO,EAAG,EAC1B,OAAQ,CAAE,KAAM,GAAM,KAAM,EAAG,KAAMA,CAAM,CAC7C,CACF,EACA,KAAM,CACJ,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,GACN,OAAQ,IAAM,CAAC,EACf,MAAO,CAAE,KAAM,EAAM,EACrB,KAAM,6BACN,KAAM,EACR,EACA,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,OAAQ,CAACqE,EAAIC,IAASA,EAAK,IAAKC,GAAM,GAAGA,CAAC,GAAG1B,CAAI,EAAE,EACnD,KAAM,6BACN,KAAM,EACR,CACF,EACA,OAAQ,CACN,KAAM,CAAE,EAAG,GAAO,EAAG,EAAM,EAC3B,QAAS,CAAC2B,EAAGC,EAAWC,IAAYA,CACtC,EACA,MAAO,CACL,KAAM,CACHF,GAAa,CACZ,IAAMG,EAAMH,EAAE,IACRI,EAAM,OAAO,kBAAoB,EACjCC,EAAKL,EAAE,KACPM,GAAa,CACjB,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,KAAM,KAAM,KAAM,KAAM,KAClE,EACMC,GAASd,EAAMA,EAAM,OAAS,CAAC,EAErCU,EAAI,KAAK,EACTA,EAAI,UAAY,UAChBA,EAAI,UAAY,SAChBA,EAAI,aAAe,MACnBA,EAAI,KAAO,GAAG,GAAKC,CAAG,2BAEtB,IAAII,GAAQ,KACZF,GAAW,QAASpI,GAAM,CACxB,GAAIA,EAAIqI,GAAQ,OAChB,IAAME,EAAIT,EAAE,SAAS9H,EAAG,IAAK,EAAI,EAC7BuI,EAAID,GAAQ,GAAKJ,GAAOK,EAAIJ,EAAG,KAAOA,EAAG,MAAQ,EAAID,IACvDD,EAAI,SAASjB,GAAYhH,CAAC,EAAGuI,EAAGJ,EAAG,IAAMA,EAAG,OAAS,EAAID,CAAG,EAC5DI,GAAQC,EAEZ,CAAC,EACDN,EAAI,QAAQ,CACd,CACF,EACA,KAAM,CACHH,GAAa,CACZA,EAAE,KAAK,iBAAiB,QAAS,IAAM,CACrC,IAAMU,EAAMV,EAAE,OAAO,IACrB,GAAIU,GAAO,MAAQjB,EAAMiB,CAAG,GAAK,KAAM,CACrC,IAAMtB,EAAWK,EAAMiB,CAAG,EAEpBvB,GADQhB,EAAMiB,CAAQ,EACL,IACjB/H,GAAM+C,EAAM,OACZiF,GAAS,KAAK,IAAIhI,GAAI,OAAS,EAAG8H,GAAWC,EAAW,CAAC,EAEzDxE,EAAKvD,GAAI,CAAC,EAAE,MAAQ,EACpBiI,IAASjI,GAAI8H,EAAQ,EAAE,MAAQvE,GAAMA,GAAM,IAC3C2E,IAASlI,GAAIgI,EAAM,EAAE,MAAQzE,GAAMA,GAAM,IAE/CH,GAAS,MAAM,CAAE,IAAK,CAAC6E,EAAMC,CAAI,CAAE,CAAC,EACpCtB,GAAQ,iBAAiB7D,EAAM,GAAI/C,GAAK8H,GAAUE,GAAQ,EAAI,CAChE,CACF,CAAC,CACH,CACF,EACA,UAAW,CACRW,GAAa,CACZ,GAAI,CAAEA,EAAU,OAAQ,OACxBA,EAAE,OAAO,EAAK,EACd,IAAMU,EAAMV,EAAE,OAAO,IACfG,EAAMH,EAAE,IACRI,EAAM,OAAO,kBAAoB,EACjCC,GAAKL,EAAE,KAGPW,GAAWD,GAAO,MAAQhB,EAAMgB,CAAG,GAAK,MAAQV,EAAE,OAAO,MAAS,EAClEY,GAAUZ,EAAE,OAAO,IACnBa,EAAUb,EAAE,SAASN,EAAMgB,CAAI,EAAI,IAAK,EAAK,EAGnD,GAFeC,IAAY,KAAK,IAAIC,GAAUC,CAAO,EAAI,GAE7C,CACV,IAAMC,EAAKd,EAAE,SAASP,EAAMiB,CAAI,EAAI,IAAK,EAAK,EACxCK,EAAKf,EAAE,SAASN,EAAMgB,CAAI,EAAI,IAAK,EAAK,EAExCM,EAASvB,EAAMiB,CAAI,EACzBf,EAAQ,UAAY,GAAGT,GAAY8B,CAAM,CAAC,KAAKtB,EAAMgB,CAAI,CAAC,IAAIrC,CAAI,GAClEsB,EAAQ,MAAM,UAAY,aAAamB,CAAE,OAAOC,CAAE,4BAClDpB,EAAQ,MAAM,QAAU,GAExB,IAAMsB,EAAMjB,EAAE,SAASP,EAAMiB,CAAI,EAAI,IAAK,EAAI,EACxCQ,EAAMlB,EAAE,SAASN,EAAMgB,CAAI,EAAI,IAAK,EAAI,EAE9CP,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,EAAK,EAAIA,CAAG,CAAC,EAClCD,EAAI,YAAcP,GAAUpE,EAAO,EAAG,EACtC2E,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAOc,EAAKZ,GAAG,GAAG,EACtBF,EAAI,OAAOc,EAAKZ,GAAG,IAAMA,GAAG,MAAM,EAClCF,EAAI,OAAO,EAEXA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,IAAIc,EAAKC,EAAK,EAAId,EAAK,EAAG,KAAK,GAAK,CAAC,EACzCD,EAAI,UAAY,UAChBA,EAAI,KAAK,EACTA,EAAI,YAAc3E,EAClB2E,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EACXA,EAAI,QAAQ,CACd,MACER,EAAQ,MAAM,QAAU,MAE5B,CACF,CACF,EACA,OAAQ,CAAE,KAAM,EAAM,CACxB,EAEAzB,EAAK,MACH/C,GACA,KAAK,MAAMD,EAAK,sBAAsB,EAAE,MAAQ,EAAE,GAClDsE,EAAQ,aACR,IACF,IAAM2B,EAAO,IAAIC,GAAMlD,EAAM,CAACuB,EAAOC,CAAK,EAAGF,CAAO,EACnD2B,EAAa,OAAS,GACvBhL,GAAa,KAAKgL,CAAI,CACxB,CACF,CAEA,SAASzE,GAAmB2E,EAAuBjH,EAAkB,CACnE,SAAS,iBAAiB,oBAAoB,EAAE,QAAS3D,GAAOA,EAAG,OAAO,CAAC,EAE3E,IAAM6K,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAElB,IAAMxF,EAAQvB,GAAQ,WAAW,EAEjC+G,EAAM,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,4DAKwCxF,EAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,4DAIRA,EAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,4DAIRA,EAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,4DAIRA,EAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,IAMlE,IAAMyF,EAAOF,EAAS,sBAAsB,EAC5CC,EAAM,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YASZC,EAAK,MAAQ,GAAG;AAAA,WACjBA,EAAK,OAAS,CAAC;AAAA,IAExB,SAAS,KAAK,YAAYD,CAAK,EAE/BA,EAAM,cAAc,WAAW,GAAG,iBAAiB,QAAS,SAAY,CACtE,IAAME,EAASF,EAAM,iBAAiB,gBAAgB,EAChDG,EAAW,MAAM,KAAKD,CAAM,EAAE,IAAK/J,GAAM,SAAUA,EAAuB,KAAK,GAAK,CAAC,EAE3F,QAASA,EAAI,EAAGA,EAAIgK,EAAS,OAAQhK,IACnC,GAAIgK,EAAShK,CAAC,GAAKgK,EAAShK,EAAI,CAAC,EAAG,CAClCvB,GAAQ,mCAAoC,OAAO,EACnD,MACF,CAGFqE,GAAQ,WAAWkH,CAAQ,EAC3B,MAAMC,GAAQ,IAAI,WAAYD,CAAQ,EAEtCrH,EAAM,MAAQG,GAAQ,aAAaH,EAAM,OAAQ,EAAI,EACrD,MAAMsH,GAAQ,KAAKtH,CAAK,EAExBD,GAAeC,CAAK,EACpBkH,EAAM,OAAO,EACbpL,GAAQ,kBAAkB,CAC5B,CAAC,EAED,IAAMyL,EAAWrF,GAAkB,CAC7B,CAACgF,EAAM,SAAShF,EAAE,MAAc,GAAK,CAAC+E,EAAS,SAAS/E,EAAE,MAAc,IAC1EgF,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASK,CAAO,EAEjD,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAO,EAAG,EAAE,CAClE,CAEA,SAASlF,GAAsB4E,EAAuBjH,EAAkB,CACtE,SAAS,iBAAiB,oBAAoB,EAAE,QAAS3D,GAAOA,EAAG,OAAO,CAAC,EAE3E,IAAM6K,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAElB,IAAMM,EAAMrH,GAAQ,OAAO,EAE3B+G,EAAM,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,4DAKwCM,CAAG;AAAA;AAAA;AAAA;AAAA,IAM7D,IAAML,EAAOF,EAAS,sBAAsB,EAC5CC,EAAM,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YASZC,EAAK,MAAQ,GAAG;AAAA,WACjBA,EAAK,OAAS,CAAC;AAAA,IAExB,SAAS,KAAK,YAAYD,CAAK,EAE/BA,EAAM,cAAc,WAAW,GAAG,iBAAiB,QAAS,SAAY,CACtE,IAAMO,EAAQP,EAAM,cAAc,YAAY,EACxCQ,EAAS,SAASD,EAAM,KAAK,GAAK,IAExCtH,GAAQ,OAAOuH,CAAM,EACrB,MAAMJ,GAAQ,IAAI,MAAOI,CAAM,EAE/B1H,EAAM,MAAQG,GAAQ,aAAaH,EAAM,OAAQ,EAAI,EACrD,MAAMsH,GAAQ,KAAKtH,CAAK,EAExBD,GAAeC,CAAK,EACpBkH,EAAM,OAAO,EACbpL,GAAQ,kBAAkB4L,CAAM,GAAG,CACrC,CAAC,EAED,IAAMH,EAAWrF,GAAkB,CAC7B,CAACgF,EAAM,SAAShF,EAAE,MAAc,GAAK,CAAC+E,EAAS,SAAS/E,EAAE,MAAc,IAC1EgF,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASK,CAAO,EAEjD,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAO,EAAG,EAAE,CAClE,CE3/BA,OAAOI,OAAW,QAKlB,IAAIC,GAA6B,CAAC,EAC9BC,GAAiC,KACjCC,GAAqB,KACrBC,GAAU,QACVC,GAAU,KACVC,GAAkC,KAClCC,GAAgF,CAAC,EACjFC,GAAgF,CAAC,EACjFC,GAAgC,KAChCC,GAAU,GAEd,SAASC,IAAoB,CAC3B,IAAMC,EAAY,SAAS,eAAe,mBAAmB,EAC7D,GAAIA,GAAaN,KAAqB,MAAQC,GAAkBD,EAAgB,EAAG,CACjF,IAAMO,EAAWN,GAAkBD,EAAgB,EAAE,CAAC,EACtDM,EAAU,YAAc,GAAGE,GAAQD,CAAQ,CAAC,EAC9C,CACF,CAMO,SAASE,IAAgB,CAC1BC,KACF,cAAcA,EAAc,EAC5BA,GAAiB,MAEfC,KACFA,GAAK,QAAQ,EACbA,GAAO,MAETC,GAAgB,CAAC,EACjBC,GAAe,KACfC,GAAU,QACVC,GAAU,KACVC,GAAmB,KACnBC,GAAoB,CAAC,EACrBC,GAAoB,CAAC,EACrBC,GAAU,GACV,IAAMC,EAAU,SAAS,eAAe,kBAAkB,EACtDA,GAASA,EAAQ,OAAO,EAC5B,IAAMC,EAAY,SAAS,eAAe,eAAe,EACrDA,IACFA,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAO1B,CAEA,IAAMC,GAAe,MACfC,GAAsB,IAAI,aAAa,GAAK,EAAE,EAoBpD,SAASC,GACPZ,EACAa,EAMA,CACA,IAAMC,EAAeD,EAAU,QAAU,EAAIA,EAAYb,EACnDe,EAAS,KAAK,IAAID,EAAa,OAAQ,CAAC,EAC9CH,GAAoB,KAAK,CAAC,EAE1B,IAAMK,EAIA,CACJ,CAAE,MAAO,sBAAuB,KAAOC,GAAMA,EAAE,MAAO,KAAOA,GAAMA,EAAE,EAAG,EACxE,CACE,MAAO,oBACP,KAAOA,GAAOA,EAAE,OAAS,KAAOA,EAAE,MAAQ,IAAM,OAChD,KAAOA,GAAMA,EAAE,QACjB,EACA,CAAE,MAAO,mBAAoB,KAAOA,GAAMA,EAAE,IAAK,KAAOA,GAAMA,EAAE,KAAM,EACtE,CAAE,MAAO,mBAAoB,KAAOA,GAAMA,EAAE,IAAK,KAAOA,GAAMA,EAAE,aAAc,EAC9E,CAAE,MAAO,oBAAqB,KAAOA,GAAMA,EAAE,KAAM,KAAOA,GAAMA,EAAE,EAAG,CACvE,EAEIC,EAAS,EACTC,EAAU,EACRC,EAAyC,CAAC,EAEhD,QAASC,EAAK,EAAGA,EAAKL,EAAM,OAAQK,IAAM,CACxC,IAAMC,EAAON,EAAMK,CAAE,EACjBE,EAAO,EACPC,EAAO,EACPC,EAAQ,EACRC,EAAQ,EACRC,EAAQ,EACRC,EAAQ,EAEZ,QAASC,EAAI,EAAGA,EAAId,EAAQc,IAAK,CAC/B,IAAMC,EAAMhB,EAAae,CAAC,EAAE,QAAU,CAAC,EACjCE,EAAI,KAAK,IAAID,EAAI,OAAQpB,EAAY,EAC3C,QAASsB,EAAI,EAAGA,EAAID,EAAGC,IAAK,CAC1B,IAAMf,EAAIa,EAAIE,CAAC,EACTC,EAAIX,EAAK,KAAKL,CAAC,EACfiB,GAAIZ,EAAK,KAAKL,CAAC,EASrB,GARIgB,GAAK,MAAQC,IAAK,OACpBX,GAAQU,EACRT,GAAQU,GACRT,GAASQ,EAAIA,EACbP,GAASQ,GAAIA,GACbP,GAASM,EAAIC,GACbN,KAEEP,IAAO,EAAG,CACZ,IAAMc,GAAKlB,EAAE,OAAS,EAChBmB,GAAInB,EAAE,IAAM,EACZoB,EAAKpB,EAAE,KAAO,EACdqB,EAAK,KAAK,IAAI,GAAI,KAAK,IAAI,EAAIH,GAAK,IAAQ,CAAC,CAAC,EAC9CI,EAAK,KAAK,IAAI,GAAI,KAAK,IAAI,GAAKH,GAAI,IAAM,GAAO,CAAC,CAAC,EACzDzB,GAAqB2B,GAAM,EAAKC,CAAE,GAAK,EAAIF,EAAK,GAClD,CACF,CACF,CAEA,IAAIG,EAAO,EACPC,EAAQ,EACZ,GAAIb,EAAQ,EAAG,CACb,IAAMc,EAAQnB,EAAOK,EACfe,EAAQnB,EAAOI,EACfgB,EAAO,KAAK,IAAI,EAAGnB,EAAQG,EAAQc,EAAQA,CAAK,EAChDG,EAAO,KAAK,IAAI,EAAGnB,EAAQE,EAAQe,EAAQA,CAAK,EAChDG,EAAQnB,EAAQC,EAAQc,EAAQC,EAChCI,EAAQ,KAAK,KAAKH,EAAOC,CAAI,EACnCL,EAAOO,EAAQ,KAAOD,EAAQC,EAAQ,EACtCN,EAAQG,EAAO,KAAOE,EAAQF,EAAO,CACvC,CACA1B,GAAUU,EACVT,GAAW,KAAK,IAAIqB,CAAI,EAAI,IAAM,KAAK,IAAIC,CAAK,EAChDrB,EAAa,KAAK,CAChB,UAAWE,EAAK,MAChB,KAAAkB,EACA,MAAAC,EACA,QAASb,CACX,CAAC,CACH,CAEA,QAASoB,EAAI,EAAGA,EAAI,KAAMA,IACxB7B,GAAWR,GAAoBqC,CAAC,EAAI,KAGtC,IAAMC,EAAgB,CAAC,kBAAc,mBAAe,mBAAe,mBAAc,EAC3EC,EAA8C,CAAC,EAC/CC,EAAKnD,EAAc,CAAC,EACpBoD,EAAKpD,EAAc,CAAC,GAAKA,EAAc,CAAC,EAE9C,QAASqD,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,IAAMC,EAASD,EAAI,IACbE,GAAQF,EAAI,GAAK,IAEjBG,EAAcC,GAAmB,CACrC,IAAM3B,EAAM2B,EAAI,QAAU,CAAC,EACrBC,EAAO,KAAK,MAAM5B,EAAI,OAASwB,CAAM,EACrCK,EAAO,KAAK,IAAID,EAAO,EAAG,KAAK,MAAM5B,EAAI,OAASyB,CAAI,CAAC,EACzDK,EAAO,EACTC,EAAO,EACPC,EAAQ,EACRC,EAAM,EACR,QAASC,EAAIN,EAAMM,EAAIL,GAAQK,EAAIlC,EAAI,OAAQkC,IAAK,CAClD,IAAMC,GAAKnC,EAAIkC,CAAC,EAChBJ,GAAQK,GAAG,OAAS,EACpBJ,GAAQI,GAAG,IAAM,EACjBH,IAAUG,GAAG,OAAS,GAAK,IAC3BF,GACF,CACA,MAAO,CACL,MAAOA,EAAM,EAAI,KAAK,MAAMH,EAAOG,CAAG,EAAI,EAC1C,GAAIA,EAAM,EAAI,KAAK,MAAMF,EAAOE,CAAG,EAAI,EACvC,SAAUA,EAAM,EAAID,EAAQC,EAAM,CACpC,CACF,EAEMG,EAAMV,EAAWL,CAAE,EACnBgB,EAAMX,EAAWJ,CAAE,EACrBgB,EAAe,EACnB,QAASvC,EAAI,EAAGA,EAAId,EAAQc,IAC1BuC,GAAgBZ,EAAW1C,EAAae,CAAC,CAAC,EAAE,MAE9CqB,EAAY,KAAK,CACf,aAAcD,EAAcI,CAAC,EAC7B,QAASa,EAAI,MACb,QAASC,EAAI,MACb,KAAMD,EAAI,GACV,KAAMC,EAAI,GACV,WAAYD,EAAI,SAChB,WAAYC,EAAI,SAChB,eAAgBpD,EAAS,EAAI,KAAK,MAAMqD,EAAerD,CAAM,EAAI,CACnE,CAAC,CACH,CAEA,MAAO,CAAE,OAAAG,EAAQ,QAAAC,EAAS,aAAAC,EAAc,YAAA8B,CAAY,CACtD,CAEO,SAASmB,GAAmBC,EAAcC,EAAc,CAC7DrE,GAAUoE,EACVnE,GAAUoE,EACNvE,GAAc,QAAU,EAC1BwE,GAAexE,EAAa,EACnBC,IACTuE,GAAevE,EAAY,CAE/B,CAEO,SAASwE,GAAiBC,EAAgB,CAC3CnE,KAAYmE,IACdnE,GAAUmE,EACN1E,GAAc,QAAU,EAC1BwE,GAAexE,EAAa,EACnBC,IACTuE,GAAevE,EAAY,EAGjC,CAEO,SAAS0E,GAA0BC,EAAkB,CAC1D,IAAMC,EAAU,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGD,CAAQ,CAAC,EAC3CE,EACJzE,GAAkB,OAAS,EACvBA,GAAkB,OAAS,EAC3BJ,GACE,KAAK,IAAI,EAAGA,GAAa,OAAO,OAAS,CAAC,EAC1C,EACRG,GAAmB,KAAK,MAAMyE,EAAUC,CAAM,EAC9C,IAAMC,EAAS,SAAS,eAAe,sBAAsB,EACzDA,IACFA,EAAO,IAAM,GAAGD,CAAM,GACtBC,EAAO,MAAQ,GAAG3E,EAAgB,IAEpC4E,GAAkB,EACdjF,IAAMA,GAAK,OAAO,CACxB,CAEO,SAASyE,GACdS,EACApE,EAAyB,CAAC,EAC1B,CACI,MAAM,QAAQoE,CAAa,GAC7BjF,GAAgBiF,EAChBhF,GAAegF,EAAc,CAAC,GAAK,MAC1BA,GACTjF,GAAgB,CAACiF,CAAa,EAC9BhF,GAAegF,IAEfjF,GAAgB,CAAC,EACjBC,GAAe,MAEjB,IAAMQ,EAAY,SAAS,eAAe,eAAe,EACzD,GAAI,CAACA,EAAW,OAEhB,IAAMyE,EAAQjF,GACd,GAAI,CAACiF,EAAO,CACVzE,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAMtB,MACF,CAGA,IAAM0E,EAAUC,GAAU,QACpBC,EAA6B,CAAC,EACpC,QAAWC,KAAOH,EAAS,CACzB,IAAMI,EAAMJ,EAAQG,CAAG,EACnBJ,EAAM,OAAO,KAAMjE,GAAOA,EAAUsE,EAAI,KAAK,GAAK,IAAI,GAAGF,EAAiB,KAAKC,CAAG,CACxF,CAGI,CAACD,EAAiB,SAASnF,EAAO,GAAKmF,EAAiB,OAAS,IACnEnF,GAAUmF,EAAiB,CAAC,GAE1B,CAACA,EAAiB,SAASlF,EAAO,GAAKkF,EAAiB,OAAS,EACnElF,GAAUkF,EAAiB,CAAC,EACrB,CAACA,EAAiB,SAASlF,EAAO,GAAKkF,EAAiB,OAAS,IACxElF,GAAUkF,EAAiB,CAAC,GAE9B,IAAMG,EAAOL,EAAQjF,EAAO,EACtBuF,EAAON,EAAQhF,EAAO,EAG5BM,EAAU,MAAM,SAAW,SAE3B,IAAIiF,EAAc,GAClB,GAAI1F,GAAc,QAAU,EAAG,CAC7B,GAAM,CAAE,OAAAkB,EAAQ,QAAAC,EAAS,aAAAC,EAAc,YAAA8B,CAAY,EAAItC,GACrDZ,GACAa,CACF,EACMsC,EAAKnD,GAAc,CAAC,EACpBoD,EAAKpD,GAAc,CAAC,EACpB2F,EAAKxC,EAAG,MACRyC,EAAKxC,EAAG,MACRyC,IAAaD,EAAG,UAAYD,EAAG,WAAa,KAAM,QAAQ,CAAC,EAC3DG,IAAYF,EAAG,UAAY,IAAMD,EAAG,UAAY,IAAI,QAAQ,CAAC,EAC7DI,IAAWH,EAAG,OAAS,IAAMD,EAAG,OAAS,IAAI,QAAQ,CAAC,EACtDK,GAAWJ,EAAG,SAAWD,EAAG,UAAU,QAAQ,CAAC,EAC/CM,GAAcL,EAAG,QAAU,IAAMD,EAAG,QAAU,GAE9CO,IAAcP,EAAG,UAAYC,EAAG,WAAa,KAAM,QAAQ,CAAC,EAC5DO,IAAaR,EAAG,SAAWC,EAAG,UAAU,QAAQ,CAAC,EACjDQ,KAAaT,EAAG,UAAY,IAAMC,EAAG,UAAY,IAAM,IACvDS,GAAS,KAAK,QAAQV,EAAG,UAAY,IAAMC,EAAG,UAAY,IAAM,CAAC,EACjEU,EAAS,KAAK,IAAIX,EAAG,UAAY,EAAGC,EAAG,UAAY,CAAC,EACpDW,EAAQ,KAAK,QAAQZ,EAAG,OAAS,IAAMC,EAAG,OAAS,IAAM,CAAC,EAC1DY,EAAQ,KAAK,IAAIb,EAAG,OAAS,EAAGC,EAAG,OAAS,CAAC,EAC7Ca,IAAab,EAAG,SAAW,IAAMD,EAAG,SAAW,IAAI,QAAQ,CAAC,EAC5De,KAAaf,EAAG,SAAW,IAAMC,EAAG,SAAW,IAAM,GAAG,QAAQ,CAAC,EACjEe,EAAU,KAAK,IAAIhB,EAAG,SAAW,EAAGC,EAAG,SAAW,CAAC,EAAE,QAAQ,CAAC,EAC9DgB,GAAejB,EAAG,QAAU,IAAMC,EAAG,QAAU,GAErDF,EAAc;AAAA,6DAC2CxE,CAAM,sBAAsBC,EAAQ,QAAQ,CAAC,CAAC;AAAA,iJACsCnB,GAAc,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,oDAKjHmD,EAAG,KAAK,MAAMA,EAAG,aAAeA,EAAG,IAAI;AAAA,oDACvCC,EAAG,KAAK,MAAMA,EAAG,aAAeA,EAAG,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+CAQ5CuC,EAAG,UAAY,KAAM,QAAQ,CAAC,CAAC;AAAA,+CAC/BC,EAAG,UAAY,KAAM,QAAQ,CAAC,CAAC;AAAA,sEACR,OAAOC,CAAQ,GAAK,EAAI,UAAY,SAAS,MAAM,OAAOA,CAAQ,GAAK,EAAI,IAAM,EAAE,GAAGA,CAAQ;AAAA,gFACpFK,CAAS;AAAA;AAAA;AAAA;AAAA,8CAI3CP,EAAG,SAAS,QAAQ,CAAC,CAAC;AAAA,8CACtBC,EAAG,SAAS,QAAQ,CAAC,CAAC;AAAA,sEACE,OAAOI,CAAO,GAAK,EAAI,UAAY,SAAS,MAAM,OAAOA,CAAO,GAAK,EAAI,IAAM,EAAE,GAAGA,CAAO;AAAA,gFACjFG,EAAS;AAAA;AAAA;AAAA;AAAA,8CAI3CR,EAAG,SAAWkB,GAAQlB,EAAG,SAAW,GAAI,EAAI,IAAI;AAAA,8CAChDC,EAAG,SAAWiB,GAAQjB,EAAG,SAAW,GAAI,EAAI,IAAI;AAAA;AAAA,gFAEdiB,GAAQT,EAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,8CAInDT,EAAG,UAAY,CAAC,QAAQA,EAAG,UAAY,CAAC;AAAA,8CACxCC,EAAG,UAAY,CAAC,QAAQA,EAAG,UAAY,CAAC;AAAA,sEAChB,OAAOE,CAAO,GAAK,EAAI,UAAY,SAAS,MAAM,OAAOA,CAAO,GAAK,EAAI,IAAM,EAAE,GAAGA,CAAO;AAAA,gFACjFO,EAAM,cAAcC,CAAM;AAAA;AAAA;AAAA;AAAA,8CAI5DX,EAAG,OAAS,CAAC,UAAUA,EAAG,OAAS,CAAC;AAAA,8CACpCC,EAAG,OAAS,CAAC,UAAUA,EAAG,OAAS,CAAC;AAAA,sEACZ,OAAOG,CAAM,GAAK,EAAI,UAAY,SAAS,MAAM,OAAOA,CAAM,GAAK,EAAI,IAAM,EAAE,GAAGA,CAAM;AAAA,gFAC9EQ,CAAK,gBAAgBC,CAAK;AAAA;AAAA;AAAA;AAAA,8CAI5Db,EAAG,SAAW,KAAOA,EAAG,QAAQ,QAAQ,CAAC,EAAI,IAAI,YAASA,EAAG,SAAW,KAAOA,EAAG,QAAQ,QAAQ,CAAC,EAAI,IAAI;AAAA,8CAC3GC,EAAG,SAAW,KAAOA,EAAG,QAAQ,QAAQ,CAAC,EAAI,IAAI,YAASA,EAAG,SAAW,KAAOA,EAAG,QAAQ,QAAQ,CAAC,EAAI,IAAI;AAAA,sEACnF,OAAOa,CAAQ,GAAK,EAAI,UAAY,SAAS,MAAM,OAAOA,CAAQ,GAAK,EAAI,IAAM,EAAE,GAAGA,CAAQ;AAAA,gFACpFC,CAAO,kBAAeC,CAAO;AAAA;AAAA;AAAA;AAAA,8CAI/DhB,EAAG,QAAU,CAAC;AAAA,8CACdC,EAAG,QAAU,CAAC;AAAA,sEACUK,GAAc,EAAI,UAAY,SAAS,MAAMA,GAAc,EAAI,IAAM,EAAE,GAAGA,CAAU;AAAA,gFAC1EW,CAAW;AAAA;AAAA,cAE7E1D,EACC,IACE4D,GAAO;AAAA;AAAA,4DAEoCA,EAAG,YAAY;AAAA,0CACjCA,EAAG,OAAO,UAAOA,EAAG,IAAI,YAASA,EAAG,WAAW,QAAQ,CAAC,CAAC;AAAA,0CACzDA,EAAG,OAAO,UAAOA,EAAG,IAAI,YAASA,EAAG,WAAW,QAAQ,CAAC,CAAC;AAAA,0CACzDA,EAAG,QAAUA,EAAG,SAAW,EAAI,IAAM,EAAE,GAAGA,EAAG,QAAUA,EAAG,OAAO;AAAA,sDACrDA,EAAG,cAAc;AAAA,kBAEzD,EACC,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA,YAIX1F,EACC,IACE2F,GACC,iBAAiBA,EAAE,SAAS,gBAAgBA,EAAE,KAAK,QAAQ,CAAC,CAAC,YAAOA,EAAE,MAAM,QAAQ,CAAC,CAAC,KAAKA,EAAE,OAAO,UACxG,EACC,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,KAInB,CAGAtG,EAAU,UAAY,GAAGiF,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iEAM2BF,EAAK,KAAK,KAAKA,EAAK,IAAI;AAAA,qCACpDA,EAAK,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iEAQkBC,EAAK,KAAK,KAAKA,EAAK,IAAI;AAAA,qCACpDA,EAAK,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6HAc+ElF,GAAiC,cAAvB,oBAAoC,YAAaA,GAAoB,oBAAV,OAA6B;AAAA;AAAA;AAAA,8HAGlGA,GAAU,qBAAuB,aAAa,YAAYA,GAAU,QAAU,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQ7N,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAUyG,GAAM,CAC1EA,EAAE,gBAAgB,EAClBC,GAASD,EAAE,cAA8B,GAAG,CAC9C,CAAC,EAED,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAUA,GAAM,CAC1EA,EAAE,gBAAgB,EAClBC,GAASD,EAAE,cAA8B,GAAG,CAC9C,CAAC,EAED,IAAMjC,EAAS,SAAS,eAAe,sBAAsB,EACvDmC,EAAY,SAAS,eAAe,mBAAmB,EACvDC,EAAU,SAAS,eAAe,mBAAmB,EAE3DpC,GAAQ,iBAAiB,QAAS,IAAM,CACtC3E,GAAmB,SAAS2E,EAAO,MAAO,EAAE,EAC5CC,GAAkB,EACdjF,IAAMA,GAAK,OAAO,CACxB,CAAC,EAED,SAASqH,GAAe,CAClBD,IAASA,EAAQ,UAAY,uDAEjCrH,GAAiB,OAAO,YAAY,IAAM,CACpCM,KAAqB,MAAQA,GAAmBC,GAAkB,OAAS,GAC7ED,GAAmB,KAAK,IAAIA,GAAmB,EAAGC,GAAkB,OAAS,CAAC,EAC9E0E,EAAO,MAAQ,GAAG3E,EAAgB,GAClC4E,GAAkB,EACdjF,IAAMA,GAAK,OAAO,GAEtBsH,EAAY,CAEhB,EAAG,EAAE,CACP,CAEA,SAASA,GAAc,CACjBvH,KACF,cAAcA,EAAc,EAC5BA,GAAiB,MAEfqH,IAASA,EAAQ,UAAY,2DACnC,CAEAA,GAAS,iBAAiB,QAAS,IAAM,CACnCrH,GACFuH,EAAY,GAGRjH,KAAqB,MAAQA,IAAoBC,GAAkB,OAAS,IAC9ED,GAAmB,EACnB2E,EAAO,MAAQ,IACfC,GAAkB,EACdjF,IAAMA,GAAK,OAAO,GAExBqH,EAAa,EAEjB,CAAC,EAED,SAAS,eAAe,mBAAmB,GAAG,iBAAiB,QAAS,IAAM,CACxE7G,KACFA,GAAU,GACViE,GAAevE,EAAY,EAE/B,CAAC,EAED,SAAS,eAAe,oBAAoB,GAAG,iBAAiB,QAAS,IAAM,CACxEM,KACHA,GAAU,GACViE,GAAevE,EAAY,EAE/B,CAAC,EAEDqH,GAAW,CACb,CAEO,SAASC,IAAiB,CAC/B,IAAM9G,EAAY,SAAS,eAAe,cAAc,EAClD+G,EAAgB,SAAS,eAAe,yBAAyB,EACvE,GAAIzH,IAAQyH,GAAiBA,EAAc,YAAc,EAAG,CAC1D,IAAMC,EAAID,EAAc,YAClBpF,EAAIoF,EAAc,aAExB,GAAIC,EAAI,GAAKrF,EAAI,EACf,GAAI7B,GAAS,CACX,IAAMmH,EAAO,KAAK,IAAID,EAAGrF,CAAC,EAC1BrC,GAAK,QAAQ,CAAE,MAAO2H,EAAM,OAAQA,CAAK,CAAC,CAC5C,MACE3H,GAAK,QAAQ,CAAE,MAAO0H,EAAG,OAAQrF,CAAE,CAAC,CAG1C,CACF,CAEA,SAAS6E,GAASU,EAAuBC,EAAiB,CACxD,SAAS,iBAAiB,oBAAoB,EAAE,QAASC,GAAOA,EAAG,OAAO,CAAC,EAE3E,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAElB,IAAM3C,EAAUC,GAAU,QACpBF,EAAQjF,GACd,GAAI,CAACiF,EAAO,OAEZ,IAAMG,EAA6B,CAAC,EACpC,QAAWC,KAAOH,EAAS,CACzB,IAAMI,EAAMJ,EAAQG,CAAG,EACnBJ,EAAM,OAAO,KAAMjE,GAAOA,EAAUsE,EAAI,KAAK,GAAK,IAAI,GAAGF,EAAiB,KAAKC,CAAG,CACxF,CAEAD,EAAiB,QAASC,GAAQ,CAChC,IAAMC,EAAMJ,EAAQG,CAAG,EACjByC,EAAO,SAAS,cAAc,KAAK,EACnCC,EAAaJ,IAAS,IAAM1H,GAAUC,GAC5C4H,EAAK,UAAY,aAAaC,IAAe1C,EAAM,SAAW,EAAE,GAChEyC,EAAK,UAAY;AAAA,4DACuCxC,EAAI,KAAK,KAAKA,EAAI,IAAI;AAAA,iCACjDA,EAAI,KAAK;AAAA,qDACWyC,IAAe1C,EAAM,QAAU,EAAE;AAAA,MAElFyC,EAAK,iBAAiB,QAAS,IAAM,CAC/BH,IAAS,IAAK1H,GAAUoF,EACvBnF,GAAUmF,EAEfwC,EAAM,OAAO,EACbtD,GAAevE,EAAY,CAC7B,CAAC,EACD6H,EAAM,YAAYC,CAAI,CACxB,CAAC,EAED,IAAME,EAAON,EAAS,sBAAsB,EAC5CG,EAAM,MAAM,IAAM,GAAGG,EAAK,OAAS,CAAC,KACpCH,EAAM,MAAM,KAAO,GAAGG,EAAK,IAAI,KAC/B,SAAS,KAAK,YAAYH,CAAK,EAE/B,IAAMI,EAASlB,GAAkB,CAC3B,CAACc,EAAM,SAASd,EAAE,MAAc,GAAK,CAACW,EAAS,SAASX,EAAE,MAAc,IAC1Ec,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASI,CAAK,EAE/C,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAK,EAAG,CAAC,CAC/D,CAEA,SAASZ,IAAa,CACpB,GAAI,CAACrH,GAAc,OACnB,IAAMQ,EAAY,SAAS,eAAe,yBAAyB,EACnE,GAAI,CAACA,EAAW,OAEhB,IAAM0E,EAAUC,GAAU,QACpBI,EAAOL,EAAQjF,EAAO,GAAKiF,EAAQ,MACnCM,EAAON,EAAQhF,EAAO,GAAKgF,EAAQ,GAEzC,GAAInF,GAAc,QAAU,EAAG,CAC7B,IAAI8E,EAAS,EACb,QAASjD,EAAI,EAAGA,EAAI7B,GAAc,OAAQ6B,IACpC7B,GAAc6B,CAAC,EAAE,OAAO,OAASiD,IAAQA,EAAS9E,GAAc6B,CAAC,EAAE,OAAO,QAEhF,IAAMsG,EAAkB,IAAI,MAAMrD,CAAM,EACxC,QAASd,EAAI,EAAGA,EAAIc,EAAQd,IAAKmE,EAAMnE,CAAC,EAAIA,EAE5C,IAAMoE,EAA6B,CAAC,CAAC,CAAC,EAChCC,EAAkC,CAACF,CAAK,EAE9C,QAAStG,EAAI,EAAGA,EAAI7B,GAAc,OAAQ6B,IAAK,CAC7C,IAAM4B,EAAMzD,GAAc6B,CAAC,EACrBC,EAAM2B,EAAI,OACV6E,EAA0B,IAAI,MAAMxD,CAAM,EAChD,QAASd,EAAI,EAAGA,EAAIc,EAAQd,IAAK,CAC/B,IAAM/C,EAAIa,EAAIkC,CAAC,EACfsE,EAAKtE,CAAC,EAAI/C,GAAMA,EAAUwE,EAAK,KAAK,GAAK,KAAQxE,EAAUwE,EAAK,KAAK,EAAI,IAC3E,CACA4C,EAAW,KAAKC,CAAI,EACpBF,EAAW,KAAK,CACd,MAAO,GAAG3E,EAAI,aAAeA,EAAI,IAAI,KAAKgC,EAAK,KAAK,IACpD,OAAQhC,EAAI,OAAS,UACrB,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,CACxB,CAAC,CACH,CAEI1D,KACFA,GAAK,QAAQ,EACbA,GAAO,MAELU,EAAU,cAAc,aAAa,IAAGA,EAAU,UAAY,IAElE,IAAM8H,EAAQ9H,EAAU,YAAc,EAAIA,EAAU,YAAc,IAC5D+H,EAAS/H,EAAU,aAAe,EAAIA,EAAU,aAAe,IAE/DgI,EAAsB,CAC1B,MAAAF,EACA,OAAAC,EACA,QAAS,CAAC,GAAI,GAAI,EAAG,CAAC,EACtB,OAAQ,CAAE,EAAG,CAAE,KAAM,EAAM,EAAG,EAAG,CAAE,KAAM,EAAK,CAAE,EAChD,OAAQJ,EACR,KAAM,CACJ,CACE,KAAM,EACN,MAAO,uBACP,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,6BACN,KAAM,EACR,EACA,CACE,KAAM,EACN,MAAO,GAAG3C,EAAK,KAAK,KAAKA,EAAK,IAAI,IAClC,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,6BACN,KAAM,EACR,CACF,EACA,OAAQ,CAAE,KAAM,EAAK,CACvB,EAEA1F,GAAO,IAAI2I,GAAMD,EAAMJ,EAAiC5H,CAAwB,EAChF8G,GAAe,EACf,MACF,CAEA,IAAMzF,EAAM7B,GAAa,OACnB0I,EAAK7G,EAAI,CAAC,EAAE,MAAQ,EACpB8G,EAAa9G,EAChB,IAAI,CAACb,EAAG4H,IAAQ,CACd5H,EAAUuE,EAAK,KAAK,EACpBvE,EAAUwE,EAAK,KAAK,GACpBxE,EAAE,KAAQ0H,GAAM,KAChB1H,EAAE,MAAQ,GAAK,IAChB4H,CACF,CAAC,EACA,OAAO,CAAC,CAAC5G,EAAGC,EAAGL,EAAGiH,CAAC,IAAM7G,GAAK,MAAQC,GAAK,IAAI,EAElD,GAAI0G,EAAW,SAAW,EAAG,CAC3BnI,EAAU,UACR,wKACF,MACF,CAEA,GAAIF,GAAS,CACX,IAAMwI,EAAQH,EAAW,IAAKE,GAAMA,EAAE,CAAC,CAAC,EAClCE,EAAQJ,EAAW,IAAKE,GAAMA,EAAE,CAAC,CAAC,EAClCG,EAAO,KAAK,IAAI,GAAGF,CAAK,EACxBG,EAAO,KAAK,IAAI,GAAGH,CAAK,EACxBI,EAAO,KAAK,IAAI,GAAGH,CAAK,EACxBI,EAAO,KAAK,IAAI,GAAGJ,CAAK,EAE9B3I,GAAoBuI,EAAW,IAAKE,GAAM,CACxC,IAAMO,EAAOP,EAAE,CAAC,EACVQ,EAAOR,EAAE,CAAC,EACVS,GAAUF,EAAOJ,IAASC,EAAOD,GAAQ,GAAM,EAAI,KAAK,GACxDO,GAAKF,EAAOH,IAASC,EAAOD,GAAQ,GACpCM,EAAKD,EAAI,KAAK,IAAID,CAAK,EACvBG,EAAKF,EAAI,KAAK,IAAID,CAAK,EAC7B,MAAO,CAACE,EAAIC,EAAIZ,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGO,EAAMC,CAAI,CAC9C,CAAC,CACH,MACEjJ,GAAoBuI,EAAW,IAAKE,GAAM,CAACA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGA,EAAE,CAAC,CAAC,CAAQ,EAI7F,IAAM/D,EAAS,SAAS,eAAe,sBAAsB,EACzDA,IACFA,EAAO,IAAM,GAAG6D,EAAW,OAAS,CAAC,IACjCxI,KAAqB,MAAQA,IAAoBwI,EAAW,UAC9DxI,GAAmBwI,EAAW,OAAS,EACvC7D,EAAO,MAAQA,EAAO,KAExBC,GAAkB,GAIpB1E,GAAoB,CAAC,GAAGD,EAAiB,EAAE,KAAK,CAACsJ,EAAGC,IAAMD,EAAE,CAAC,EAAIC,EAAE,CAAC,GAAKD,EAAE,CAAC,EAAIC,EAAE,CAAC,CAAC,EAEpF,IAAMzB,EAAQ7H,GAAkB,IAAKwI,GAAMA,EAAE,CAAC,CAAC,EACzCe,EAAQvJ,GAAkB,IAAKwI,GAAMA,EAAE,CAAC,CAAC,EAEzCtB,EAAgB,SAAS,eAAe,yBAAyB,EACnEe,EAAQf,GAAiBA,EAAc,YAAc,EAAIA,EAAc,YAAc,IACrFgB,EAAShB,GAAiBA,EAAc,aAAe,EAAIA,EAAc,aAAe,IAE5F,GAAIjH,GAAS,CACX,IAAMmH,EAAO,KAAK,IAAIa,EAAOC,EAAS,EAAIA,EAASD,CAAK,EACxDA,EAAQb,EACRc,EAASd,EAELF,IACFA,EAAc,MAAM,QAAU,OAC9BA,EAAc,MAAM,WAAa,SACjCA,EAAc,MAAM,eAAiB,SAEzC,MAAWA,IACTA,EAAc,MAAM,QAAU,GAC9BA,EAAc,MAAM,WAAa,GACjCA,EAAc,MAAM,eAAiB,IAGvC,IAAMiB,EAAsB,CAC1B,MAAOF,EACP,OAAQC,EACR,QAAS,CAAC,GAAI,GAAI,EAAG,CAAC,EACtB,OAAQ,CACN,EAAG,CAAE,KAAM,GAAO,KAAM,EAAK,EAC7B,EAAG,CAAE,KAAM,EAAK,CAClB,EACA,OAAQ,CACN,CAAC,EACD,CACE,MAAO/C,EAAK,MACZ,MAAO,EACP,OAAQ,CAAE,KAAM,GAAM,KAAM,EAAG,KAAMqE,GAAUrE,EAAK,MAAO,EAAG,CAAE,CAClE,CACF,EACA,KAAM,CACJ,CACE,KAAM,EACN,KAAM,CAAClF,GACP,MAAO,GAAGiF,EAAK,KAAK,KAAKA,EAAK,IAAI,IAClC,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,6BACN,OAAQ,CAACuE,EAAGC,IAASA,EAAK,IAAKC,GAAOA,GAAK,KAAOzE,EAAK,QAAQyE,CAAC,EAAI,EAAG,EACvE,KAAM,EACR,EACA,CACE,KAAM,EACN,KAAM,CAAC1J,GACP,MAAO,GAAGkF,EAAK,KAAK,KAAKA,EAAK,IAAI,IAClC,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,6BACN,OAAQ,CAACsE,EAAGC,IAASA,EAAK,IAAKC,GAAOA,GAAK,KAAOxE,EAAK,QAAQwE,CAAC,EAAI,EAAG,EACvE,KAAM,EACR,CACF,EACA,OAAQ,CACN,KAAM,CAAE,EAAG,GAAO,EAAG,EAAM,EAC3B,QAAS,CAACF,EAAGG,EAAWC,IAAY,CAClC,IAAMC,EAAaL,EAAE,OAAO,KACtBM,EAAYN,EAAE,OAAO,IAC3B,GAAIK,GAAc,MAAQC,GAAa,MAAQD,GAAc,GAAKC,GAAa,EAAG,CAChF,IAAIC,EAAQ,IACRC,EAAa,GAEjB,QAASvG,EAAI,EAAGA,EAAI1D,GAAkB,OAAQ0D,IAAK,CACjD,GAAM,CAACqF,EAAMC,CAAI,EAAIhJ,GAAkB0D,CAAC,EAClCwG,EAAKT,EAAE,SAASV,EAAM,GAAG,EACzBoB,EAAKV,EAAE,SAAST,EAAM,GAAG,EAEzBoB,EAAKF,EAAKJ,EACVO,EAAKF,EAAKJ,EACVO,GAAKF,EAAKA,EAAKC,EAAKA,EAEtBC,GAAKN,IACPA,EAAQM,GACRL,EAAavG,EAEjB,CAGA,GAAIuG,GAAc,GAAKD,EAAQ,KAAM,OAAOC,CAC9C,CACA,OAAOJ,CACT,EACA,OAAQ,CACN,KAAM,EACN,OAAQ,OACR,MAAO,EACP,KAAM1E,EAAK,KACb,CACF,EACA,OAAQ,CAAE,KAAM,EAAM,EACtB,MAAO,CACL,KAAM,CACHsE,GAAa,CACZ,IAAMc,EAAMd,EAAE,IACRe,EAAM,OAAO,kBAAoB,EAGvCD,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAc,4BAClBA,EAAI,UAAY,EAAIC,EAEpB,IAAIC,EAAU,GACd,QAAS/G,EAAI,EAAGA,EAAI3D,GAAkB,OAAQ2D,IAAK,CACjD,GAAM,CAACqF,EAAMC,CAAI,EAAIjJ,GAAkB2D,CAAC,EAClCwG,EAAKT,EAAE,SAASV,EAAM,IAAK,EAAI,EAC/BoB,EAAKV,EAAE,SAAST,EAAM,IAAK,EAAI,EAEjCyB,EACFF,EAAI,OAAOL,EAAIC,CAAE,GAEjBI,EAAI,OAAOL,EAAIC,CAAE,EACjBM,EAAU,GAEd,CAKA,GAJAF,EAAI,OAAO,EACXA,EAAI,QAAQ,EAGRzK,KAAqB,KAAM,CAC7ByK,EAAI,KAAK,EAET,IAAMG,EAAW,KAAK,IAAI,EAAG5K,GADV,GACuC,EACpD6K,EAAS7K,GAGf,QAAS4D,EAAIgH,EAAUhH,EAAIiH,EAAQjH,IAAK,CACtC,GAAM,CAACkH,EAAOC,CAAK,EAAI9K,GAAkB2D,CAAC,EACpC,CAACoH,EAAOC,CAAK,EAAIhL,GAAkB2D,EAAI,CAAC,EACxCsH,EAAMvB,EAAE,SAASmB,EAAO,IAAK,EAAI,EACjCK,EAAMxB,EAAE,SAASoB,EAAO,IAAK,EAAI,EACjCK,GAAMzB,EAAE,SAASqB,EAAO,IAAK,EAAI,EACjCK,GAAM1B,EAAE,SAASsB,EAAO,IAAK,EAAI,EAEjCK,IAAY1H,EAAIgH,IAAaC,EAASD,GAAY,GAClDW,EAAY,EAAI,EAAID,GACpBE,EAAQ,IAAO,GAAMF,GAE3Bb,EAAI,UAAU,EACdA,EAAI,OAAOS,EAAKC,CAAG,EACnBV,EAAI,OAAOW,GAAKC,EAAG,EACnBZ,EAAI,YAAcf,GAAUrE,EAAK,MAAOmG,CAAK,EAC7Cf,EAAI,UAAYc,EAAYb,EAC5BD,EAAI,OAAO,CACb,CAGA,QAAS7G,EAAIgH,EAAUhH,GAAKiH,EAAQjH,IAAK,CACvC,GAAM,CAACqF,EAAMC,CAAI,EAAIjJ,GAAkB2D,CAAC,EAClCwG,EAAKT,EAAE,SAASV,EAAM,IAAK,EAAI,EAC/BoB,EAAKV,EAAE,SAAST,EAAM,IAAK,EAAI,EAE/BoC,GAAY1H,EAAIgH,IAAaC,EAASD,GAAY,GAClDtD,EAAO,EAAI,EAAIgE,EACfG,GAAY,IAAO,IAAOH,EAEhCb,EAAI,UAAU,EACdA,EAAI,IAAIL,EAAIC,EAAI/C,EAAOoD,EAAK,EAAG,KAAK,GAAK,CAAC,EAC1CD,EAAI,UAAYf,GAAUrE,EAAK,MAAOoG,EAAS,EAC/ChB,EAAI,KAAK,EAETA,EAAI,YAAcpF,EAAK,MACvBoF,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,CACb,CACAA,EAAI,QAAQ,CACd,CACF,CACF,EACA,UAAW,CACRd,GAAa,CACZ,IAAMlB,EAAMkB,EAAE,OAAO,IAEjBvJ,EAAU,SAAS,eAAe,kBAAkB,EAkBxD,GAjBKA,IACHA,EAAU,SAAS,cAAc,KAAK,EACtCA,EAAQ,GAAK,mBACbA,EAAQ,MAAM,SAAW,WACzBA,EAAQ,MAAM,WAAa,wBAC3BA,EAAQ,MAAM,MAAQ,OACtBA,EAAQ,MAAM,QAAU,WACxBA,EAAQ,MAAM,aAAe,MAC7BA,EAAQ,UAAU,IAAI,QAAQ,EAC9BA,EAAQ,MAAM,WAAa,YAC3BA,EAAQ,MAAM,cAAgB,OAC9BA,EAAQ,MAAM,OAAS,OACvBA,EAAQ,MAAM,UAAY,4BAC1BA,EAAQ,MAAM,OAAS,oBACvB,SAAS,KAAK,YAAYA,CAAO,GAG/BqI,GAAO,MAAQvI,GAAkBuI,CAAG,GAAKkB,EAAE,OAAO,MAAS,EAAG,CAChE,IAAMjB,EAAIxI,GAAkBuI,CAAG,EACzBiD,EAAWhD,EAAE,CAAC,EACdiD,EAASjD,EAAE,CAAC,EACZkD,EAAQlD,EAAE,CAAC,EACXmD,EAAQnD,EAAE,CAAC,EAEjBtI,EAAQ,UAAY;AAAA,wEACwCqI,CAAG;AAAA;AAAA;AAAA,mDAGxBhC,GAAQiF,CAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,mDAIjBC,EAAO,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA,wBAG5CvG,EAAK,KAAK;AAAA,mDACiBA,EAAK,QAAQwG,CAAK,CAAC,IAAIxG,EAAK,IAAI;AAAA;AAAA;AAAA,wBAG3DC,EAAK,KAAK;AAAA,yDACuBA,EAAK,KAAK,KAAKA,EAAK,QAAQwG,CAAK,CAAC,IAAIxG,EAAK,IAAI;AAAA;AAAA,cAG5FjF,EAAQ,MAAM,QAAU,QAExB,IAAM0L,EAAanC,EAAE,KAAK,sBAAsB,EAChDvJ,EAAQ,MAAM,KAAO,GAAG0L,EAAW,KAAO,OAAO,QAAUnC,EAAE,OAAO,KAAQ,EAAE,KAC9EvJ,EAAQ,MAAM,IAAM,GAAG0L,EAAW,IAAM,OAAO,QAAUnC,EAAE,OAAO,IAAO,EAAE,IAC7E,MACEvJ,EAAQ,MAAM,QAAU,MAE5B,CACF,CACF,CACF,EAIIC,EAAU,cAAc,aAAa,IAAGA,EAAU,UAAY,IAE9DV,IAAMA,GAAK,QAAQ,EAEvBA,GAAO,IAAI2I,GAAMD,EAAM,CAACN,EAAO0B,CAAK,EAAGpJ,CAAS,EAEhDV,GAAK,KAAK,iBAAiB,QAAS,IAAM,CACxC,GAAIA,GAAM,CACR,IAAM8I,EAAM9I,GAAK,OAAO,IACxB,GAAI8I,GAAO,MAAQvI,GAAkBuI,CAAG,EAAG,CACzC,IAAMsD,EAAc7L,GAAkBuI,CAAG,EAAE,CAAC,EAC5CzD,GAAU,YAAY+G,CAAW,CACnC,CACF,CACF,CAAC,EAGD5E,GAAe,CACjB,CC9+BA,OAAO6E,OAAW,QCeX,SAASC,GACdC,EACAC,EACiB,CAEjB,IAAIC,EAAQ,EACZ,QAASC,EAAI,EAAGA,EAAIH,EAAU,OAAQG,IAAK,CACzC,IAAMC,EAAKJ,EAAUG,CAAC,EAAE,OAAO,UAC3BC,GAAMA,EAAKF,IAAOA,EAAQE,EAChC,CACKF,IAAOA,EAAQ,KAAK,IAAI,KAAM,EAAG,CAAC,GAEvC,IAAMG,EAAM,IAAI,KAAKH,CAAK,EACpBI,EAAcD,EAAI,eAAe,EAEjCE,EAAe,KAAK,IACxBD,EAAc,EACdD,EAAI,YAAY,EAChBA,EAAI,WAAW,EACfA,EAAI,YAAY,EAChBA,EAAI,cAAc,EAClBA,EAAI,cAAc,CACpB,EACMG,EAAiB,KAAK,IAC1BF,EACAD,EAAI,YAAY,EAAI,EACpBA,EAAI,WAAW,EACfA,EAAI,YAAY,EAChBA,EAAI,cAAc,EAClBA,EAAI,cAAc,CACpB,EACMI,EAAgB,KAAK,IACzBH,EACAD,EAAI,YAAY,EAAI,EACpBA,EAAI,WAAW,EACfA,EAAI,YAAY,EAChBA,EAAI,cAAc,EAClBA,EAAI,cAAc,CACpB,EAEIK,EAAiB,EACjBC,EAAc,EACdC,EAAY,EACZC,EAAY,EACZC,EAAW,EAEXC,EAAUb,EAEdF,EAAU,QAASgB,GAAM,CACvB,GAAI,CAACA,EAAE,MAAM,UAAW,OACxB,IAAMC,EAAMhB,EAAUe,CAAC,EACvB,GAAIC,IAAQ,OAAW,OAEvBH,GAAYG,EAEZ,IAAMC,EAAOF,EAAE,MAAM,UACjBE,EAAOH,IAASA,EAAUG,GAEjB,IAAI,KAAKA,CAAI,EAEjB,eAAe,IAAMZ,IAAaI,GAAkBO,GAEzDC,GAAQX,IAAcI,GAAeM,GAErCC,GAAQV,IAAgBI,GAAaK,GAErCC,GAAQT,IAAeI,GAAaI,EAC1C,CAAC,EAED,IAAME,EAAc,EAAI,GAAK,GAAK,GAAK,IACjCC,EAAmB,KAAK,IAAId,EAAa,EAAG,CAAC,EAE7Ce,EAAmB,KAAK,IAAI,IAAMnB,EAAQkB,GAAoBD,CAAW,EACzEG,EAAgB,KAAK,IAAI,IAAMpB,EAAQK,GAAgBY,CAAW,EAClEI,EAAc,KAAK,IAAI,IAAMrB,EAAQM,GAAkBW,CAAW,EAClEK,EAAc,KAAK,IAAI,IAAMtB,EAAQO,GAAiBU,CAAW,EACjEM,EAAa,KAAK,IAAI,IAAMvB,EAAQa,GAAWI,CAAW,EAEhE,MAAO,CACL,YAAaT,EACb,SAAUC,EACV,OAAQC,EACR,OAAQC,EACR,MAAOC,EACP,eAAgBJ,EAAiBW,EACjC,YAAaV,EAAcW,EAC3B,UAAWV,EAAYW,EACvB,UAAWV,EAAYW,EACvB,SAAUV,EAAWW,CACvB,CACF,CAEO,SAASC,GACdC,EACAC,EACAC,EACQ,CACR,IAAMC,EAASF,EAAa,IAAO,EAC7BG,EAAUd,IACOW,EAAaX,EAAMa,EAASb,GAC7B,eAAe,QAAS,CAC1C,sBAAuBW,EAAa,EAAI,EACxC,sBAAuBA,EAAa,EAAI,CAC1C,CAAC,EAGH,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA,gBAKOA,EAAa,WAAa,WAAW;AAAA,gBACrCA,EAAa,gBAAkB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAM/CG,EAAOJ,EAAY,WAAW,CAAC,SAASE,CAAI;AAAA,gBAC5CE,EAAOJ,EAAY,cAAc,CAAC,SAASE,CAAI;AAAA;AAAA;AAAA;AAAA,gBAI/CE,EAAOJ,EAAY,QAAQ,CAAC,SAASE,CAAI;AAAA,gBACzCE,EAAOJ,EAAY,WAAW,CAAC,SAASE,CAAI;AAAA;AAAA;AAAA;AAAA,gBAI5CE,EAAOJ,EAAY,MAAM,CAAC,SAASE,CAAI;AAAA,gBACvCE,EAAOJ,EAAY,SAAS,CAAC,SAASE,CAAI;AAAA;AAAA;AAAA;AAAA,gBAI1CE,EAAOJ,EAAY,MAAM,CAAC,SAASE,CAAI;AAAA,gBACvCE,EAAOJ,EAAY,SAAS,CAAC,SAASE,CAAI;AAAA;AAAA;AAAA;AAAA,gBAI1CE,EAAOJ,EAAY,KAAK,CAAC,SAASE,CAAI;AAAA,gBACtCE,EAAOJ,EAAY,QAAQ,CAAC,SAASE,CAAI;AAAA;AAAA;AAAA;AAAA,GAKzD,CAWO,SAASG,GACdhC,EAC+B,CAC/B,IAAMiC,EAAWlC,GAAyBC,EAAYgB,GAAMA,EAAE,MAAM,SAAS,EACvEkB,EAAYnC,GAAyBC,EAAYgB,GAAMA,EAAE,MAAM,QAAQ,EACvEmB,EAAgBpC,GAAyBC,EAAYgB,GACzDA,EAAE,MAAM,SAAWA,EAAE,MAAM,SAAW,KAAU,CAClD,EACMoB,EAAMrC,GAAyBC,EAAYgB,GAAM,CACrD,IAAMqB,GAAUrB,EAAE,MAAM,UAAY,GAAK,IACnCsB,EAAStB,EAAE,MAAM,UAAY,IAC7BuB,EAAM,IACNC,EAAkBF,EAASC,EACjC,OAASF,EAASC,EAASE,GAAoBD,EAAM,MAAS,GAChE,CAAC,EACKE,EAAS1C,GAAyBC,EAAYgB,GAAM,CACxD,IAAMqB,GAAUrB,EAAE,MAAM,UAAY,GAAK,IACnCsB,EAAStB,EAAE,MAAM,UAAY,EACnC,OAAQqB,EAASC,EAAU,GAC7B,CAAC,EACKI,EAAa3C,GAAyBC,EAAYgB,IACzCA,EAAE,MAAM,UAAY,CAAC,GACtB,OAAQ2B,GAAMA,EAAE,OAAS,OAAO,EAAE,MAC/C,EAED,MAAO,CACL,SAAAV,EACA,UAAAC,EACA,cAAAC,EACA,IAAAC,EACA,OAAAK,EACA,WAAAC,CACF,CACF,CAEO,SAASE,GAAiC5C,EAAgC,CAC/E,IAAM6C,EAAUb,GAA8BhC,CAAS,EACjD8C,EAAM,CAACC,EAAWC,EAAS,IAC/BD,EAAE,eAAe,QAAS,CACxB,sBAAuBC,EACvB,sBAAuBA,CACzB,CAAC,EAiBH,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YATD,CACJ,CAAE,MAAO,WAAY,KAAM,KAAM,KAAMH,EAAQ,SAAU,MAAO,KAAO,OAAQ,CAAE,EACjF,CAAE,MAAO,iBAAkB,KAAM,IAAK,KAAMA,EAAQ,UAAW,MAAO,EAAG,OAAQ,CAAE,EACnF,CAAE,MAAO,kBAAmB,KAAM,IAAK,KAAMA,EAAQ,cAAe,MAAO,EAAG,OAAQ,CAAE,EACxF,CAAE,MAAO,wBAAyB,KAAM,MAAO,KAAMA,EAAQ,IAAK,MAAO,EAAG,OAAQ,CAAE,EACtF,CAAE,MAAO,kBAAmB,KAAM,KAAM,KAAMA,EAAQ,OAAQ,MAAO,EAAG,OAAQ,CAAE,EAClF,CAAE,MAAO,qBAAsB,KAAM,SAAU,KAAMA,EAAQ,WAAY,MAAO,EAAG,OAAQ,CAAE,CAC/F,EAwBW,IACEI,GAAM;AAAA;AAAA,8CAEyBA,EAAE,KAAK;AAAA,oBACjCH,EAAIG,EAAE,KAAK,OAASA,EAAE,MAAOA,EAAE,MAAM,CAAC,SAASA,EAAE,IAAI;AAAA,oBACrDH,EAAIG,EAAE,KAAK,OAASA,EAAE,MAAOA,EAAE,MAAM,CAAC,SAASA,EAAE,IAAI;AAAA,oBACrDH,EAAIG,EAAE,KAAK,SAAWA,EAAE,MAAOA,EAAE,MAAM,CAAC,SAASA,EAAE,IAAI;AAAA,oBACvDH,EAAIG,EAAE,KAAK,YAAcA,EAAE,MAAOA,EAAE,MAAM,CAAC,SAASA,EAAE,IAAI;AAAA,8CAChCH,EAAIG,EAAE,KAAK,MAAQA,EAAE,MAAOA,EAAE,MAAM,CAAC,SAASA,EAAE,IAAI;AAAA,oBAC9EH,EAAIG,EAAE,KAAK,SAAWA,EAAE,MAAOA,EAAE,MAAM,CAAC,SAASA,EAAE,IAAI;AAAA,kBAE/D,EACC,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA,GAKrB,CD/PA,IAAIC,GAA0B,CAAC,EAC3BC,GAA8B,CAAC,EAC/BC,GAA6C,OAEjD,SAASC,IAAwB,CAC/BH,GAAe,QAASI,GAAMA,EAAE,QAAQ,CAAC,EACzCJ,GAAiB,CAAC,EAClBC,GAAuB,CAAC,CAC1B,CAEO,SAASI,IAAiB,CAC/BF,GAAsB,EACtBD,GAA2B,OAC3B,IAAMI,EAAY,SAAS,eAAe,gBAAgB,EACtDA,IACFA,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAO1B,CAEO,SAASC,GAAqBC,EAA4B,CAC/DN,GAA2BM,EAC3BP,GAAqB,QAASQ,GAAM,CAC9BA,GAAKA,EAAE,gBAAgBA,EAAE,eAAeD,CAAQ,CACtD,CAAC,CACH,CAEO,SAASE,GAAkBC,EAAe,CAC/CC,GAAS,MAAM,CAAE,SAAUD,IAAU,MAAQ,KAAOA,CAAM,CAAC,EAC3D,IAAME,EAAmB,SAAS,cAAc,uBAAuB,EACnEA,GACFA,EAAiB,iBAAiB,UAAU,EAAE,QAASC,GAAM,CAC3DA,EAAE,UAAU,OAAO,SAAUA,EAAE,aAAa,YAAY,IAAMH,CAAK,CACrE,CAAC,EAEHV,GAAqB,QAASQ,GAAM,CAC9BA,GAAKA,EAAE,aAAaA,EAAE,YAAYE,CAAK,CAC7C,CAAC,CACH,CAEO,SAASI,GAA2BC,EAAoB,CAC7Df,GAAqB,QAASQ,GAAM,CAC9BA,GAAKA,EAAE,WAAWA,EAAE,UAAUO,CAAG,CACvC,CAAC,CACH,CAEA,IAAMC,GAAU,MACVC,GAAe,IAAI,aAAaD,GAAU,CAAC,EAC3CE,GAAc,IAAI,aAAaF,GAAU,CAAC,EAC1CG,GAAe,IAAI,aAAaH,GAAU,CAAC,EAC3CI,GAAe,IAAI,aAAaJ,EAAO,EACvCK,GAAgB,IAAI,aAAa,GAAG,EACpCC,GAAoB,CACxB,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAC1F,EAEO,SAASC,GACdC,EACAC,EACAC,EACAC,EACA,CACAzB,GAAsB,EACtB,IAAMG,EAAY,SAAS,eAAe,gBAAgB,EAC1D,GAAI,CAACA,EAAW,OAEhB,IAAIuB,EAAejB,GAAS,IAAI,EAAE,UAAY,MAG9Cc,EAAU,QAASI,GAAU,CAC3BC,GAAQ,qBAAqBD,CAAK,CACpC,CAAC,EAGD,IAAIE,EAAe,EACfC,EAAe,EACnBX,GAAc,KAAK,CAAC,EAEpB,QAASY,EAAK,EAAGA,EAAKR,EAAU,OAAQQ,IAAM,CAC5C,IAAMC,EAAMT,EAAUQ,CAAE,EAAE,QAAU,CAAC,EAC/BE,EAAI,KAAK,IAAID,EAAI,OAAQlB,EAAO,EACtC,GAAImB,IAAM,EAAG,SAEb,QAASC,EAAI,EAAGA,EAAID,EAAGC,IAAK,CAC1B,IAAMjC,EAAI+B,EAAIE,CAAC,EACTC,EAAKlC,EAAE,OAAS,EAChBmC,EAAInC,EAAE,IAAM,EACZoC,EAAKpC,EAAE,OAAS,EAChBqC,EAAKrC,EAAE,KAAO,EACpBc,GAAamB,EAAI,CAAC,EAAInB,GAAamB,CAAC,EAAIC,EACxCnB,GAAYkB,EAAI,CAAC,EAAIlB,GAAYkB,CAAC,EAAIE,EACtCnB,GAAaiB,EAAI,CAAC,EAAIjB,GAAaiB,CAAC,EAAIG,EACxC,IAAME,EAAU,KAAK,IAAI,EAAG,KAAK,IAAI,KAAMH,EAAI,IAAM,GAAG,CAAC,EACzDlB,GAAagB,CAAC,EAAIC,EAAK,IAAMC,EAAIG,GAAW,EAAI,KAAOA,GAAW,GAAKD,EAAK,GAC9E,CAEA,QAASE,EAAK,EAAGA,EAAKpB,GAAkB,OAAQoB,IAAM,CACpD,IAAMC,EAAIrB,GAAkBoB,CAAE,EAC9B,GAAIC,EAAIR,EAAG,SACX,IAAMS,EAAQT,EAAIQ,EACdE,EAAO,EACPC,EAAO,EACX,QAASC,EAAI,EAAGA,GAAKH,EAAOG,IAAK,CAC/B,IAAMC,EAAK9B,GAAY6B,EAAIJ,CAAC,EAAIzB,GAAY6B,CAAC,EACvCR,GAAKtB,GAAa8B,EAAIJ,CAAC,EAAI1B,GAAa8B,CAAC,EAC3CR,GAAKM,IAAMA,EAAON,IAClBS,EAAKF,IAAMA,EAAOE,EACxB,CACAhB,IAAkBa,EAAOC,EAAO3B,GAAayB,CAAK,GAAKD,EAAK,IAC9D,CAEA,IAAMM,EAAS,EAAI,EACbC,EAAY,EAAID,EAChBE,EAAS,EAAI,GACbC,EAAY,EAAID,EAChBE,EAAS,GACTC,GAAY,GAAK,IAAMD,GACzBE,GAAM,EACNC,GAAM,EACV,QAASpB,EAAI,EAAGA,EAAID,EAAGC,IAAK,CAC1B,IAAME,EAAIpB,GAAYkB,EAAI,CAAC,EAAIlB,GAAYkB,CAAC,EACtCK,EAAU,KAAK,IAAI,GAAIH,EAAIe,GAAUC,EAAS,EAC9CG,EAAK,KAAOhB,EACZiB,EAAQtC,GAAagB,CAAC,EAAI,IAAOK,EAAU,KAAQ,EAAIgB,GAAM,EAAI,GAAMA,IAAO,GACpFF,GAAMN,EAASS,EAAQR,EAAYK,GACnCC,GAAML,EAASO,EAAQN,EAAYI,EACrC,CACAzB,GAAgBwB,GAAM,IACtBvB,GAAgBwB,GAAM,IAEtB,IAAMG,EAAU1B,EAAK,GAAM,IAC3BZ,GAAcsC,CAAM,GAAK1C,GAAakB,CAAC,EAAI,KAAOjB,GAAYiB,CAAC,EAAI,IACrE,CAEA,IAAIyB,EAAS,EACTC,EAAS,EACb,QAASC,EAAM,EAAGA,EAAM,IAAKA,IAAO,CAClC,IAAMC,EAAO1C,GAAcyC,CAAG,GAAKA,EAAM,IAAM,EAAI,GAAK,IACxDF,EAASA,EAAS,IAAOG,EAAO,IAChCF,EAASA,EAAS,KAAQE,EAAO,IACnC,CACAhC,GAAgB6B,EAAS,KACzB5B,GAAgB6B,EAAS,KAEzBxD,EAAU,QAAQ,KAAO2B,EAAeD,GAAc,QAAQ,CAAC,EAC/D,IAAMiC,EAAe,CAAC,EACtBhE,GAAuBgE,EACvB3D,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA,0FAIkE4D,GAAQ,SAAS,KAAK;AAAA,qDAC3DA,GAAQ,SAAS,IAAI;AAAA;AAAA,2FAEiBA,GAAQ,UAAU,KAAK;AAAA,qDAC7DA,GAAQ,UAAU,IAAI;AAAA;AAAA,uFAEYA,GAAQ,MAAM,KAAK;AAAA,qDACrDA,GAAQ,MAAM,IAAI;AAAA;AAAA,oFAEaA,GAAQ,GAAG,KAAK;AAAA,qDAC/CA,GAAQ,GAAG,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCAMjCrC,IAAiB,KAAO,SAAW,EAAE;AAAA,mCACrCA,IAAiB,KAAO,SAAW,EAAE;AAAA,mCACrCA,IAAiB,KAAO,SAAW,EAAE;AAAA,mCACrCA,IAAiB,KAAO,SAAW,EAAE;AAAA,mCACrCA,IAAiB,KAAO,SAAW,EAAE;AAAA,mCACrCA,IAAiB,MAAQ,SAAW,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,IAOvE,IAAMsC,EAAO,SAAS,eAAe,qBAAqB,EAC1D,GAAI,CAACA,EAAM,OAEXA,EAAK,mBAAmB,YAAaC,GAAiC1C,CAAS,CAAC,EAEhF,IAAM2C,EAAYF,EAAK,aAAe,IAEhCG,EAAeC,GAAM,KAAK,eAAe,EAC/CN,EAAM,KACJO,GAAmBL,EAAMzC,EAAW,WAAY4C,EAAc1C,EAAmByC,CAAS,CAC5F,EACAJ,EAAM,KACJO,GAAmBL,EAAMzC,EAAW,YAAa4C,EAAc1C,EAAmByC,CAAS,CAC7F,EAEA,IAAMI,EAAiBN,EAAK,cAC1B,iDACF,EACMO,EAAkBP,EAAK,cAC3B,kDACF,EAEIM,GAAkBC,IACpBD,EAAe,iBAAiB,SAAU,IAAM,CAC1CC,EAAgB,aAAeD,EAAe,aAChDC,EAAgB,WAAaD,EAAe,WAChD,CAAC,EACDC,EAAgB,iBAAiB,SAAU,IAAM,CAC3CD,EAAe,aAAeC,EAAgB,aAChDD,EAAe,WAAaC,EAAgB,WAChD,CAAC,GAGH,IAAM7D,EAAmBP,EAAU,cAAc,uBAAuB,EACpEO,GACFA,EAAiB,iBAAiB,UAAU,EAAE,QAAS8D,GAAQ,CAC7DA,EAAI,iBAAiB,QAAS,IAAM,CAClC,IAAMhE,EAAQgE,EAAI,aAAa,YAAY,EACvChE,IACFE,EACG,iBAAiB,UAAU,EAC3B,QAASC,GAAMA,EAAE,UAAU,OAAO,QAAQ,CAAC,EAC9C6D,EAAI,UAAU,IAAI,QAAQ,EAC1BC,EAAcjE,CAAK,EAEvB,CAAC,CACH,CAAC,EAGWL,EAAU,iBAAiB,cAAc,EACjD,QAASuE,GAAS,CACtBA,EAAK,iBAAiB,QAAS,IAAM,CACnC,IAAMC,EAASD,EAAK,aAAa,aAAa,EAC1CC,GACe,SAAS,eAAe,GAAGA,CAAM,iBAAiB,GACzD,eAAe,CAAE,SAAU,QAAS,CAAC,CAEnD,CAAC,CACH,CAAC,EAED,SAASC,EAAY/D,EAAoB,CACvCiD,EAAM,QAASxD,GAAM,CACfA,GAAKA,EAAE,WAAWA,EAAE,UAAUO,CAAG,CACvC,CAAC,CACH,CAEA,SAAS4D,EAAcjE,EAAe,CACpCC,GAAS,MAAM,CAAE,SAAUD,IAAU,MAAQ,KAAOA,CAAM,CAAC,EAC3DsD,EAAM,QAASxD,GAAM,CACfA,GAAKA,EAAE,aAAaA,EAAE,YAAYE,CAAK,CAC7C,CAAC,CACH,CAEA,GAAIe,EAAU,KAAMsD,GAAMA,EAAE,MAAM,UAAU,EAAG,CAC7C,IAAMC,EAAOC,GAAyB,CACpC,KAAAf,EACA,aAAA1C,EACA,UAAAC,EACA,UAAW,QACX,MAAO,uBACP,KAAM,IACN,MAAOwC,GAAQ,MAAM,MACrB,KAAM,OACN,YAAAa,EACA,cAAAH,EACA,cAAAjD,EACA,UAAA0C,CACF,CAAC,EACDJ,EAAM,KAAKgB,CAAI,CACjB,CAEA,GAAIvD,EAAU,KAAMsD,GAAMA,EAAE,MAAM,OAAO,EAAG,CAC1C,IAAMC,EAAOC,GAAyB,CACpC,KAAAf,EACA,aAAA1C,EACA,UAAAC,EACA,UAAW,KACX,MAAO,4BACP,KAAM,MACN,MAAOwC,GAAQ,GAAG,MAClB,KAAM,WACN,YAAAa,EACA,cAAAH,EACA,cAAAjD,EACA,UAAA0C,CACF,CAAC,EACDJ,EAAM,KAAKgB,CAAI,CACjB,CAGIpD,IAAiB,OACnBoC,EAAM,QAASxD,GAAM,CACfA,GAAKA,EAAE,aAAaA,EAAE,YAAYoB,CAAY,CACpD,CAAC,EAGH7B,GAAe,QAASI,GAAM,CAC3BA,EAAU,OAAS,EACtB,CAAC,CACH,CAiBA,SAAS8E,GAAyBC,EAAiC,CACjE,GAAM,CACJ,KAAAhB,EACA,aAAA1C,EACA,UAAAC,EACA,UAAA0D,EACA,MAAAC,EACA,KAAAC,EACA,MAAAC,EACA,KAAAC,EACA,YAAAT,EACA,cAAAH,EACA,cAAAjD,EACA,UAAA0C,CACF,EAAIc,EAEEM,EAAYhE,GAAeA,EAAa,MAAQ,gBAElDiE,EAA0B,KAExBC,EAAgB,SAAS,cAAc,KAAK,EAClDA,EAAc,UAAY,iCAC1BA,EAAc,GAAK,GAAGP,CAAS,kBAC/BjB,EAAK,YAAYwB,CAAa,EAE9B,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,+BACjBA,EAAK,MAAM,YAAY,gBAAiBL,CAAK,EAC7CK,EAAK,MAAM,KAAO,YAClBA,EAAK,MAAM,aAAe,OAC1BA,EAAK,UAAY;AAAA;AAAA;AAAA,qFAGkEL,CAAK,KAAKC,CAAI;AAAA,wCAC3DH,CAAK;AAAA;AAAA;AAAA;AAAA,iBAI5BD,CAAS;AAAA;AAAA,IAIxB,IAAMS,EAAW,SAAS,cAAc,KAAK,EAC7CA,EAAS,UAAY,mBACrBA,EAAS,UAAY;AAAA;AAAA,uEAEgDN,CAAK;AAAA,cAC9DE,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASrB,IAAI5D,EADajB,GAAS,IAAI,EACF,UAAY,MAElCkF,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,+BACjBA,EAAK,MAAM,YAAY,gBAAiBP,CAAK,EAC7CO,EAAK,MAAM,KAAO,IAClBA,EAAK,MAAM,aAAe,OAC1BA,EAAK,UAAY;AAAA;AAAA;AAAA,qFAGkEP,CAAK,KAAKC,CAAI;AAAA,4CACvDJ,CAAS,6BAA6BA,IAAc,QAAU,QAAU,IAAI;AAAA;AAAA;AAAA;AAAA,iBAIvGA,CAAS;AAAA;AAAA,IAIxB,IAAMW,EAAa,SAAS,cAAc,KAAK,EAC/CA,EAAW,MAAM,QAAU,sEAC3BA,EAAW,YAAYH,CAAI,EAC3BG,EAAW,YAAYD,CAAI,EAE3BH,EAAc,YAAYI,CAAU,EACpCJ,EAAc,YAAYE,CAAQ,EAElC,IAAMG,EAAUJ,EAAK,cAAc,IAAIR,CAAS,kBAAkB,EAClE,GAAI,CAACY,EAAS,OAGd,IAAMC,EAGF,CAAC,EACLvE,EAAU,QAASsD,IAAM,CACvB,IAAMkB,GAAQd,IAAc,QAAUJ,GAAE,MAAM,WAAaA,GAAE,MAAM,QACnE,GAAI,CAACkB,GAAO,OACZ,IAAMC,GAAOnB,GAAE,MAAQ,gBACjBoB,GACJpB,GAAE,MAAM,WAAaA,GAAE,QAAUqB,GAASrB,GAAE,MAAM,WAAaA,GAAE,OAAS,EAAI,eAC1EsB,EAAY,GAAGH,EAAI,KAAKC,EAAI,IAElC,OAAO,QAAQF,EAAK,EAAE,QAAQ,CAAC,CAAClF,EAAKuF,EAAI,IAAM,CAC7C,IAAM3D,EAAI,OAAO5B,CAAG,EACdwF,GAAOD,GAAa,OAAUA,GAAa,IAC7C,CAACN,EAASrD,CAAC,GAAK4D,GAAMP,EAASrD,CAAC,EAAE,OACpCqD,EAASrD,CAAC,EAAI,CAAE,IAAA4D,GAAK,UAAAF,EAAW,QAAStB,GAAE,GAAI,IAAMuB,GAAa,GAAI,EAC1E,CAAC,CACH,CAAC,EAGD,IAAME,EACHhF,IACE2D,IAAc,QAAU3D,EAAa,MAAM,WAAaA,EAAa,MAAM,UAC9E,CAAC,EAGGiF,EAAe,IAAI,IACzB,OAAO,KAAKT,CAAQ,EAAE,QAASrD,IAAM8D,EAAa,IAAI,OAAO9D,EAAC,CAAC,CAAC,EAChE,OAAO,KAAK6D,CAAY,EAAE,QAAS7D,IAAM8D,EAAa,IAAI,OAAO9D,EAAC,CAAC,CAAC,EACpE,IAAM+D,EAAY,MAAM,KAAKD,CAAY,EAAE,KAAK,CAACE,GAAG9F,KAAM8F,GAAI9F,EAAC,EAEzD+F,EAAQF,EACRG,GAAeH,EAAU,IAAK/D,IAAM,CACxC,IAAMmE,GAAQN,EAAa7D,EAAC,EAC5B,OAAOmE,GAASA,GAAc,OAAUA,GAAc,GAAK,IAC7D,CAAC,EACKC,GAAWL,EAAU,IAAK/D,IAAMqD,EAASrD,EAAC,GAAG,KAAO,IAAI,EAGxDqE,GAAcvF,EAAU,OAAQsD,KAAOA,GAAE,MAAM,WAAaA,GAAE,UAAY,IAAI,EACpFiC,GAAY,KACV,CAACL,GAAG9F,MACD8F,GAAE,MAAM,WAAaA,GAAE,SAAW,IAAM9F,GAAE,MAAM,WAAaA,GAAE,SAAW,IAC3E8F,GAAE,GAAG,cAAc9F,GAAE,EAAE,CAC3B,EAEA,IAAMoG,EAAsB,CAAC,EACvBC,EAAmD,CAAC,EAC1DR,EAAU,QAAS/D,IAAOuE,EAAcvE,EAAC,EAAI,CAAC,CAAE,EAEhDqE,GAAY,QAASjC,IAAM,CACzB,IAAMkB,GAAQd,IAAc,QAAUJ,GAAE,MAAM,WAAaA,GAAE,MAAM,QAC9DkB,KAELgB,EAAU,MAAMlC,GAAE,MAAM,WAAaA,GAAE,SAAY,GAAI,EACvD2B,EAAU,QAAS/D,IAAM,CACvB,IAAMmE,GAAQb,GAAMtD,EAAC,EACf4D,EAAMO,GAAS3B,IAAc,QAAW2B,GAAc,MAASA,GAAc,GAAM,KACzFI,EAAcvE,EAAC,EAAE,KAAK4D,CAAG,CAC3B,CAAC,EACH,CAAC,EAED,IAAIY,EAAaT,EAAU,CAAC,GAAK,EAC7BU,EAAiBJ,GACjBK,EAA2B,KAE/B,SAASC,EAAgBvG,GAAaL,GAAe,CACnD,IAAM6G,GAAUN,EAAUA,EAAU,OAAS,CAAC,GAAK,WAC/CO,GAAU,EAEV9G,KAAU,KAAM8G,GAAUD,GAAU,GAAK,GAAK,KACzC7G,KAAU,KAAM8G,GAAUD,GAAU,GAAK,GAAK,KAC9C7G,KAAU,KAAM8G,GAAUD,GAAU,IAAM,GAAK,KAC/C7G,KAAU,KAAM8G,GAAUD,GAAU,IAAM,GAAK,KAC/C7G,KAAU,OAAM8G,GAAUD,GAAU,EAAI,IAAM,GAAK,MAE5D,IAAME,EAA4B,CAAC,EACnCR,EAAU,QAAQ,CAAClC,GAAG2C,KAAQ,CACxB3C,IAAKyC,IAASC,EAAgB,KAAKC,EAAG,CAC5C,CAAC,EAED,IAAMC,EAAYF,EAAgB,IAAKrF,IAAM6E,EAAU7E,EAAC,CAAC,EACnDwF,GAAOV,EAAcnG,EAAG,GAAK,CAAC,EAC9B8G,EAAeJ,EAAgB,IAAKrF,IAAMwF,GAAKxF,EAAC,CAAC,EACjD0F,GAAoBC,GAAeF,EAAc,CAAC,EACxD,OAAAT,EAAiBK,EAAgB,IAAKrF,IAAM4E,GAAY5E,EAAC,CAAC,EAEnD,CAAE,UAAAuF,EAAW,aAAAE,EAAc,kBAAAC,EAAkB,CACtD,CAEA,IAAIE,EAA8B,KAE5BC,EAAU,SAAS,cAAc,KAAK,EAC5C,OAAAA,EAAQ,UAAY,mBACpBA,EAAQ,MAAM,QACZ,sOACFlC,EAAQ,MAAM,SAAW,WACzBA,EAAQ,YAAYkC,CAAO,GAEN,IAAM,CACzB,IAAMC,GAA2B,CAC/B,GAAI,GAAG/C,CAAS,aAChB,MAAO,IACP,OAAQ,IACR,QAAS,CAAC,EAAG,GAAI,EAAG,EAAE,EACtB,OAAQ,CACN,EAAG,CAAE,KAAM,GAAO,MAAO,EAAG,KAAM,EAAK,EACvC,EAAG,CAAE,KAAM,EAAK,CAClB,EACA,OAAQ,CACN,CAAC,EACD,CACE,MAAO,gBACP,OAAQG,EACR,MAAO,EACP,KAAM6C,GAAU7C,EAAO,EAAG,EAC1B,OAAQ,CAAE,KAAM,GAAM,KAAM,EAAG,KAAMA,CAAM,CAC7C,EACA,CACE,MAAO,eACP,OAAQ,UACR,MAAO,EACP,KAAM,cACN,OAAQ,CAAE,KAAM,GAAM,KAAM,EAAG,KAAM,SAAU,CACjD,CACF,EACA,KAAM,CACJ,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,GACN,OAAQ,IAAM,CAAC,EACf,MAAO,CAAE,KAAM,EAAM,EACrB,KAAM,6BACN,KAAM,EACR,EACA,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,OAAQ,CAAC8C,EAAIC,IAASA,EAAK,IAAKC,IAAM,GAAGA,EAAC,GAAGjD,CAAI,EAAE,EACnD,KAAM,6BACN,KAAM,EACR,CACF,EACA,OAAQ,CACN,KAAM,CAAE,EAAG,GAAO,EAAG,EAAM,EAC3B,QAAS,CAACkD,EAAGC,EAAWC,KAAYA,GACpC,EAAG,GACH,EAAG,EACL,EACA,MAAO,CACL,KAAM,CACHF,GAAa,CACZ,IAAMG,EAAMH,EAAE,IACRI,GAAM,OAAO,kBAAoB,EACjCC,EAAKL,EAAE,KACPM,GAAa,CACjB,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,KAAM,KAAM,KAAM,KAAM,KAClE,EACMC,GAASlC,EAAMA,EAAM,OAAS,CAAC,EAErC8B,EAAI,KAAK,EACTA,EAAI,UAAY,UAChBA,EAAI,UAAY,SAChBA,EAAI,aAAe,MACnBA,EAAI,KAAO,GAAG,GAAKC,EAAG,2BAEtB,IAAII,GAAQ,KAWZ,GAVAF,GAAW,QAASlG,IAAM,CACxB,GAAIA,GAAImG,GAAQ,OAChB,IAAME,GAAIT,EAAE,SAAS5F,GAAG,IAAK,EAAI,EAC7BqG,GAAID,GAAQ,GAAKJ,IAAOK,GAAIJ,EAAG,KAAOA,EAAG,MAAQ,EAAID,KACvDD,EAAI,SAASO,GAAYtG,EAAC,EAAGqG,GAAGJ,EAAG,IAAMA,EAAG,OAAS,EAAID,EAAG,EAC5DI,GAAQC,GAEZ,CAAC,EAGG3B,IAAc,KAAM,CACtB,IAAMK,GAAMd,EAAM,QAAQS,CAAS,EACnC,GAAIK,IAAO,EAAG,CACZ,IAAMwB,GAAMX,EAAE,SAASlB,EAAW,IAAK,EAAI,EACrC8B,GAAMZ,EAAE,SAAS1B,GAAaa,EAAG,GAAMX,GAASW,EAAG,EAAI,IAAK,EAAI,EAEtEgB,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClB,IAAMU,GAASvC,GAAaa,EAAG,EACzB2B,GAAYD,KAAW,KAAO,EAAIT,GAAM,EAAIA,GAC5CW,GAAWF,KAAW,KAAO9D,EAAQ,UAC3CoD,EAAI,IAAIQ,GAAKC,GAAKE,GAAW,EAAG,EAAI,KAAK,EAAE,EAC3CX,EAAI,UAAYY,GAChBZ,EAAI,KAAK,EACTA,EAAI,YAAc,OAClBA,EAAI,UAAY,EAAIC,GACpBD,EAAI,OAAO,EACXA,EAAI,QAAQ,CACd,CACF,CAEAA,EAAI,QAAQ,CACd,EACCH,GAAa,CACZ,IAAMG,EAAMH,EAAE,IACRI,GAAM,OAAO,kBAAoB,EACjCC,EAAKL,EAAE,KAETb,GAAMa,EAAE,OAAO,IACfgB,GAAkB,EAChBC,GAAajB,EAAE,OAAO,KACtBkB,GAAYlB,EAAE,OAAO,IAE3B,GAAIiB,IAAc,MAAQC,IAAa,MAAQD,IAAc,GAAKC,IAAa,EAAG,CAChF,IAAIC,GAAQ,IACRC,GAAa,GACXC,GAAS,GACTC,GAAQD,GAASA,GAEvB,QAASxH,GAAI,EAAGA,GAAIwE,EAAM,OAAQxE,KAAK,CACrC,IAAM4G,GAAIpC,EAAMxE,EAAC,EACX0H,EAAOjD,GAAazE,EAAC,EACrB2H,EAAOhD,GAAS3E,EAAC,EAEvB,GAAI4G,IAAK,KAAM,CACb,IAAMgB,GAAKzB,EAAE,SAASS,GAAG,IAAK,EAAK,EAEnC,GAAIc,GAAQ,KAAM,CAChB,IAAMG,GAAK1B,EAAE,SAASuB,EAAM,IAAK,EAAK,EAChCI,GAAKF,GAAKR,GACVW,GAAKF,GAAKR,GACVW,GAAKF,GAAKA,GAAKC,GAAKA,GACtBC,GAAKV,KACPA,GAAQU,GACRT,GAAavH,GACbmH,GAAkB,EAEtB,CACA,GAAIQ,GAAQ,KAAM,CAChB,IAAME,GAAK1B,EAAE,SAASwB,EAAM,IAAK,EAAK,EAChCG,GAAKF,GAAKR,GACVW,GAAKF,GAAKR,GACVW,GAAKF,GAAKA,GAAKC,GAAKA,GACtBC,GAAKV,KACPA,GAAQU,GACRT,GAAavH,GACbmH,GAAkB,EAEtB,CACF,CACF,CAEIG,IAASG,GAAOnC,GAAMiC,GACrBjC,GAAM,IACb,CAEA,GAAIA,IAAO,MAAQa,EAAE,KAAK,CAAC,EAAEb,EAAG,GAAK,KAAM,CACzC,IAAMwB,GAAMX,EAAE,SAASA,EAAE,KAAK,CAAC,EAAEb,EAAG,EAAI,IAAK,EAAI,EAC3CyB,GAAMZ,EAAE,SACZgB,KAAoB,EAAI1C,GAAaa,EAAG,EAAKX,GAASW,EAAG,EACzD,IACA,EACF,EAGAgB,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,GAAK,EAAIA,EAAG,CAAC,EAClCD,EAAI,YAAcP,GAAUoB,KAAoB,EAAIjE,EAAQ,UAAW,EAAG,EAC1EoD,EAAI,UAAY,EAAIC,GAEpBD,EAAI,OAAOQ,GAAKN,EAAG,GAAG,EACtBF,EAAI,OAAOQ,GAAKN,EAAG,IAAMA,EAAG,MAAM,EAElCF,EAAI,OAAOE,EAAG,KAAMO,EAAG,EACvBT,EAAI,OAAOE,EAAG,KAAOA,EAAG,MAAOO,EAAG,EAClCT,EAAI,OAAO,EACXA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,IAAIQ,GAAKC,GAAK,GAAKR,GAAK,EAAG,EAAI,KAAK,EAAE,EAC1CD,EAAI,UAAYP,GAAUoB,KAAoB,EAAIjE,EAAQ,UAAW,EAAG,EACxEoD,EAAI,KAAK,EACTA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,UAAU,EACd,IAAMW,GAAYE,KAAoB,EAAI,EAAIZ,GAAM,EAAIA,GAClDW,GAAWC,KAAoB,EAAIjE,EAAQ,UACjDoD,EAAI,IAAIQ,GAAKC,GAAKE,GAAW,EAAG,EAAI,KAAK,EAAE,EAC3CX,EAAI,UAAYY,GAChBZ,EAAI,KAAK,EACTA,EAAI,YAAc,OAClBA,EAAI,UAAY,EAAIC,GACpBD,EAAI,OAAO,EACXA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,YAAY,CAAC,CAAC,EAElB,IAAM2B,GAAUpB,GAAYrC,EAAMc,EAAI,CAAC,EACvCgB,EAAI,KAAO,QAAQ,GAAKC,EAAG,2BAE3B,IAAM2B,EADY5B,EAAI,YAAY2B,EAAO,EAAE,MACnB,GAAK1B,GACvB4B,EAAQ,GAAK5B,GAEb6B,GAAUtB,GAAMoB,EAAM,EACtBG,GAAa,KAAK,IAAI7B,EAAG,KAAM,KAAK,IAAIA,EAAG,KAAOA,EAAG,MAAQ0B,EAAKE,EAAO,CAAC,EAC1EE,GAAU9B,EAAG,IAAMA,EAAG,OAAS,EAAID,GAGzCD,EAAI,UAAY,yBAChBA,EAAI,UAAU,EACTA,EAAY,UACdA,EAAY,UAAU+B,GAAYC,GAASJ,EAAKC,EAAO,EAAI5B,EAAG,EAC5DD,EAAI,KAAK+B,GAAYC,GAASJ,EAAKC,CAAK,EAC7C7B,EAAI,KAAK,EACTA,EAAI,YAAcP,GAAU7C,EAAO,GAAI,EACvCoD,EAAI,UAAY,EAAIC,GACpBD,EAAI,OAAO,EAEXA,EAAI,UAAYpD,EAChBoD,EAAI,UAAY,SAChBA,EAAI,aAAe,SACnBA,EAAI,SAAS2B,GAASI,GAAaH,EAAM,EAAGI,GAAUH,EAAQ,CAAC,EAG/D,IAAMI,GAAU,IADH9D,GAAaa,EAAI,GAAMX,GAASW,EAAI,GACzB,QAAQ,CAAC,CAAC,IAAIrC,CAAI,GAEpCuF,GADYlC,EAAI,YAAYiC,EAAO,EAAE,MACnB,GAAKhC,GAEvBkC,GAAUjC,EAAG,KAAOgC,GAAM,EAAIjC,GAC9BmC,GAAU3B,GAAMoB,EAAQ,EAG9B7B,EAAI,UAAY,yBAChBA,EAAI,UAAU,EACTA,EAAY,UACdA,EAAY,UAAUmC,GAASC,GAASF,GAAKL,EAAO,EAAI5B,EAAG,EACzDD,EAAI,KAAKmC,GAASC,GAASF,GAAKL,CAAK,EAC1C7B,EAAI,KAAK,EACTA,EAAI,YAAcP,GAAU7C,EAAO,GAAI,EACvCoD,EAAI,UAAY,EAAIC,GACpBD,EAAI,OAAO,EAEXA,EAAI,UAAYpD,EAChBoD,EAAI,UAAY,OAChBA,EAAI,aAAe,SACnBA,EAAI,SAASiC,GAASE,GAAU,EAAIlC,GAAKmC,GAAUP,EAAQ,CAAC,EAE5D7B,EAAI,QAAQ,CACd,CACF,CACF,EACA,UAAW,CACRH,GAAa,CACZ,GAAI,CAAEA,EAAU,OAAQ,OACxBA,EAAE,OAAO,EAAK,EAEd,IAAIb,EAAMa,EAAE,OAAO,IACfgB,GAAkB,EAChBC,EAAajB,EAAE,OAAO,KACtBkB,GAAYlB,EAAE,OAAO,IAE3B,GAAIiB,GAAc,MAAQC,IAAa,MAAQD,GAAc,GAAKC,IAAa,EAAG,CAChF,IAAIC,GAAQ,IACRC,GAAa,GACXC,GAAS,GACTC,GAAQD,GAASA,GAEvB,QAASxH,GAAI,EAAGA,GAAIwE,EAAM,OAAQxE,KAAK,CACrC,IAAM4G,EAAIpC,EAAMxE,EAAC,EACX0H,EAAOjD,GAAazE,EAAC,EACrB2H,GAAOhD,GAAS3E,EAAC,EAEvB,GAAI4G,GAAK,KAAM,CACb,IAAMgB,GAAKzB,EAAE,SAASS,EAAG,IAAK,EAAK,EAEnC,GAAIc,GAAQ,KAAM,CAChB,IAAMG,GAAK1B,EAAE,SAASuB,EAAM,IAAK,EAAK,EAChCI,GAAKF,GAAKR,EACVW,GAAKF,GAAKR,GACVW,GAAKF,GAAKA,GAAKC,GAAKA,GACtBC,GAAKV,KACPA,GAAQU,GACRT,GAAavH,GACbmH,GAAkB,EAEtB,CACA,GAAIQ,IAAQ,KAAM,CAChB,IAAME,GAAK1B,EAAE,SAASwB,GAAM,IAAK,EAAK,EAChCG,GAAKF,GAAKR,EACVW,GAAKF,GAAKR,GACVW,GAAKF,GAAKA,GAAKC,GAAKA,GACtBC,GAAKV,KACPA,GAAQU,GACRT,GAAavH,GACbmH,GAAkB,EAEtB,CACF,CACF,CAEIG,IAASG,GAAOnC,EAAMiC,GACrBjC,EAAM,IACb,CAEA,IAAMgB,GAAMH,EAAE,IACRI,GAAM,OAAO,kBAAoB,EACjCC,GAAKL,EAAE,KAIb,GAFiBb,GAAO,MAAQd,EAAMc,CAAG,GAAK,KAEhC,CACZ,IAAMqD,GAAKxC,EAAE,SAAS3B,EAAMc,CAAI,EAAI,IAAK,EAAK,EACxCsD,GAAKzC,EAAE,SAAS1B,GAAaa,CAAI,GAAMX,GAASW,CAAI,EAAI,IAAK,EAAK,EAElEuD,GAASrE,EAAMc,CAAI,EACnB0B,GAASvC,GAAaa,CAAI,EAC1BwD,GAAQnE,GAASW,CAAI,EAEvByD,EAAO,wCAAwClC,GAAYgC,EAAM,CAAC,SAoBtE,GAnBI7B,KAAW,OACb+B,GAAQ;AAAA;AAAA;AAAA,4DAGoC/B,EAAM,IAAI/D,CAAI;AAAA;AAAA,mBAIxD6F,KAAU,OACZC,GAAQ;AAAA;AAAA;AAAA,4DAGoCD,EAAK,IAAI7F,CAAI;AAAA;AAAA,mBAK3D4C,EAAQ,UAAYkD,EAEhBnD,GACEX,IAAc,KAAM,CACtBF,EAAa8D,GACb,GAAM,CAAE,UAAAtD,EAAW,aAAAE,GAAc,kBAAAC,EAAkB,EAAIR,EACrDH,EACAvF,CACF,EACMwJ,GAAatD,GAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,GAAM,IAAK,EACvE+C,GAAavD,GAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,IAAM,IAAK,EAC7EN,EAAc,QAAQ,CACpBL,EACAE,GACAC,GACAsD,GACAC,EACF,CAAC,EAED,IAAMC,GAAU,SAAS,eAAe,GAAGnG,CAAS,iBAAiB,EACjEmG,KACFA,GAAQ,YAAc,YAAYrC,GAAYgC,EAAM,CAAC,IAAI9F,IAAc,QAAU,QAAU,IAAI,GACnG,CAEF8C,EAAQ,MAAM,QAAU,GACxBA,EAAQ,MAAM,KAAO,GAAGuB,EAAcZ,GAAG,IAAI,KAC7CX,EAAQ,MAAM,IAAM,GAAGwB,GAAab,GAAG,GAAG,KAC1CX,EAAQ,MAAM,UAAY,sBAC5B,MACEA,EAAQ,MAAM,QAAU,MAE5B,CACF,CACF,CACF,EAEAxC,EAAY,IAAInB,GAAM4D,GAAW,CAACtB,EAAOC,GAAcE,EAAQ,EAAGhB,CAAO,EACzEhG,GAAe,KAAK0F,CAAS,EAE7BM,EAAQ,iBAAiB,QAAS,IAAM,CACtC,GAAI,CAACN,EAAW,OAChB,IAAMiC,EAAMjC,EAAU,OAAO,IAC7B,GAAIiC,GAAO,KAAM,CACf,IAAM6D,EAAa3E,EAAMc,CAAG,EACxB8D,GAA8B,KAOlC,GANInE,IAAc,KAAMmE,GAAe,KAClCA,GAAeD,EAEpBzG,EAAY0G,EAAY,EAGpBhK,EAAc,CAChB,IAAMiK,EAAQjK,EAAa,MACrByE,GAAQd,IAAc,QAAUsG,EAAM,WAAaA,EAAM,QAC/D,GAAIxF,GAAO,CACT,IAAMa,GAAQb,GAAMsF,CAAU,EAC9B,GAAIzE,GAAO,CACT,IAAM4E,GAAU5E,GAAM,IAChB6E,GAAWJ,EACXK,GAAUpK,EAAa,OAAOkK,EAAO,EACrCG,GAAQrK,EAAa,OAAOkK,GAAUC,GAAW,CAAC,EACxD,GAAIC,IAAWC,IAASD,GAAQ,MAAQ,MAAQC,GAAM,MAAQ,KAAM,CAClE,IAAMC,GAAatK,EAAa,OAAO,CAAC,EAAE,MAAQ,EAC5CuK,IAAOH,GAAQ,KAAOE,IAAc,IACpCE,IAAOH,GAAM,KAAOC,IAAc,IACxCpK,IAAgBF,EAAa,GAAI,CAACuK,GAAKC,EAAG,CAAC,CAC7C,CACF,CACF,CACF,CACF,CACF,CAAC,EAEDjG,EAAQ,iBAAiB,aAAc,IAAM,CACvCN,GAAWA,EAAU,OAAO,CAClC,CAAC,EAGD,IAAMwG,GAAY,SAAS,cAAc,SAAS,EAClDA,GAAU,UAAU,IAAI,kBAAkB,EAC1CA,GAAU,MAAM,UAAY,MAC5BA,GAAU,MAAM,YAAY,gBAAiB3G,CAAK,EAClD2G,GAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAedvF,EACC,IAAK/D,GAAM,CACV,IAAMuJ,EAAM1F,EAAa7D,CAAC,EACrB6D,EAAa7D,CAAC,EAAU,OAAU6D,EAAa7D,CAAC,EAAU,GAC3D,IACEwJ,GAAKnG,EAASrD,CAAC,GAAG,KAAO,IACzByJ,EAAOpG,EAASrD,CAAC,GAAG,QACpB0J,GAAQrG,EAASrD,CAAC,GAAG,IAC3B,MAAO;AAAA;AAAA,sBAECsG,GAAYtG,CAAC,CAAC;AAAA,sBACduJ,CAAG,IAAI7G,CAAI;AAAA;AAAA,oBAEb8G,EAAE,IAAI9G,CAAI;AAAA,oBACV+G,EAAO,iDAAiDA,CAAI,eAAeC,EAAK,eAAe1J,CAAC,oGAAsG,EAAE;AAAA;AAAA;AAAA,aAIhN,CAAC,EACA,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,MAIjB+C,EAAc,YAAYuG,EAAS,EAEnCA,GAAU,iBAAiB,uBAAuB,EAAE,QAASvH,GAAQ,CACnEA,EAAI,iBAAiB,QAAU4H,GAAM,CACnCA,EAAE,eAAe,EACjBA,EAAE,gBAAgB,EAClB,IAAMC,GAAK7H,EAAI,aAAa,SAAS,EAC/BgD,EAAMhD,EAAI,aAAa,UAAU,EACjC3D,GAAM2D,EAAI,aAAa,UAAU,EACnC6H,IACF,SAAS,cACP,IAAI,YAAY,eAAgB,CAC9B,OAAQ,CACN,GAAAA,GACA,IAAK7E,EAAM,OAAOA,CAAG,EAAI,KACzB,IAAK3G,GAAM,OAAOA,EAAG,EAAI,IAC3B,CACF,CAAC,CACH,CAEJ,CAAC,CACH,CAAC,EAED,IAAIyL,GAAgC,KAG9BC,GAAa5G,EAAK,cAAc,IAAIV,CAAS,iBAAiB,EACpE,GAAIsH,GAAY,CACdA,GAAW,MAAM,SAAW,WAC5B,IAAMC,EAAkB,SAAS,cAAc,KAAK,EAMpD,GALAA,EAAgB,UAAY,0BAC5BA,EAAgB,MAAM,QACpB,sOACFD,GAAW,YAAYC,CAAe,EAElCzF,EAAU,OAAS,EAAG,CACxB,GAAM,CAAE,UAAAU,EAAW,aAAAE,GAAc,kBAAAC,CAAkB,EAAIR,EACrDH,EACAvF,CACF,EACMwJ,GAAatD,EAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,GAAM,IAAK,EACvE+C,GAAavD,EAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,IAAM,IAAK,EACvEqE,GAAe,CAAChF,EAAWE,GAAcC,EAAmBsD,GAAYC,EAAU,EAElFuB,GAAgB,CACpB,CACE,MAAO,CAACrE,GAAQD,KACVA,IAAK,KAAalC,GAAQkC,GAAI,GAAI,EAE/B,GAEX,EACA,CACE,MAAO,QACP,OAAQhD,EACR,MAAO,EACP,OAAQ,CAAE,KAAM,GAAM,KAAM,EAAG,KAAM6C,GAAU7C,EAAO,EAAG,CAAE,CAC7D,EACA,CACE,MAAO,QACP,OAAQA,EACR,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,EACtB,SAAU,GACV,KAAM,cACN,KAAM,CAAC,EAAG,CAAC,CACb,EACA,CACE,MAAO,cACP,OAAQ,cACR,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,EACtB,SAAU,EACZ,EACA,CACE,MAAO,cACP,OAAQ,cACR,MAAO,EACP,OAAQ,CAAE,KAAM,EAAM,EACtB,SAAU,EACZ,CACF,EAEMgG,GAAU,SAAS,eAAe,GAAGnG,CAAS,iBAAiB,EACjEmG,KACFA,GAAQ,YAAc,YAAYrC,GAAY9B,CAAU,CAAC,IAAIhC,IAAc,QAAU,QAAU,IAAI,IAErG,IAAM0H,GAA8B,CAClC,MAAO,KAAK,IAAI,KAAMzI,GAAa,KAAO,GAAG,EAC7C,OAAQ,IACR,QAAS,CAAC,EAAG,GAAI,EAAG,EAAE,EACtB,OAAS0I,IAAexI,GAAM,OAAO,IAAI,KAAKwI,GAAK,GAAI,EAAG,SAAS,EACnE,OAAQ,CACN,OAAQ,CACN,KAAM,EACR,EACA,KAAM,CAAE,SAAU,EAAM,EACxB,EAAG,GACH,EAAG,EACL,EACA,OAAQ,CACN,EAAG,CACD,KAAM,GACN,MAAQvE,IAAM,CACZ,IAAMwD,GAAMxD,GAAE,KAAK,CAAC,EAAE,CAAC,EACjByD,GAAMzD,GAAE,KAAK,CAAC,EAAEA,GAAE,KAAK,CAAC,EAAE,OAAS,CAAC,EAC1C,OAAIwD,KAAQ,QAAaC,KAAQ,OAAkB,CAAC,EAAG,GAAG,EAEtDD,KAAQC,GAAY,CAACD,GAAM,KAAMC,GAAM,IAAI,EAExC,CAACD,GAAKC,EAAG,CAClB,CACF,EACA,EAAG,CAAE,MAAO,CAACzD,GAAQwD,GAAaC,KAAgB,CAACD,GAAM,GAAKC,GAAM,GAAG,CAAE,CAC3E,EACA,OAAQY,GACR,MAAO,CAAC,CAAE,OAAQ,CAAC,EAAG,CAAC,EAAG,KAAMzE,GAAU7C,EAAO,EAAG,CAAE,CAAC,EACvD,MAAO,CACL,KAAM,CACHiD,IAAa,CACZA,GAAE,KAAK,iBAAiB,QAAS,IAAM,CACrC,GAAIiE,IAAkB,KAAM,CAC1B,IAAM3K,GAAQuF,EAAeoF,EAAc,EAC3C,GAAI3K,GAAO,CACT,IAAM4J,GAAQ5J,GAAM,MACdoE,GAAQd,IAAc,QAAUsG,GAAM,WAAaA,GAAM,QAC/D,GAAIxF,GAAO,CACT,IAAMa,EAAQb,GAAMkB,CAAU,EAC9B,GAAIL,EAAO,CACT,IAAM4E,EAAU5E,EAAM,IAChB6E,GAAWxE,EAEXyE,GAAU/J,GAAM,OAAO6J,CAAO,EAC9BG,GAAQhK,GAAM,OAAO6J,EAAUC,GAAW,CAAC,EAEjD,GAAIC,IAAWC,IAASD,GAAQ,MAAQ,MAAQC,GAAM,MAAQ,KAAM,CAClE,IAAMC,GAAajK,GAAM,OAAO,CAAC,EAAE,MAAQ,EACrCkK,IAAOH,GAAQ,KAAOE,IAAc,IACpCE,IAAOH,GAAM,KAAOC,IAAc,IAExC5G,EAAK,gBAAgBrD,GAAM,GAAI,CAACkK,GAAKC,EAAG,CAAC,CAC3C,MACE9G,EAAK,gBAAgBrD,GAAM,GAAI,IAAI,CAEvC,MACEqD,EAAK,gBAAgBrD,GAAM,GAAI,IAAI,CAEvC,MACEqD,EAAK,gBAAgBrD,GAAM,GAAI,IAAI,CAEvC,CACF,CACF,CAAC,CACH,CACF,EACA,KAAM,CACH0G,IAAa,CACZ,IAAIb,GAAMa,GAAE,OAAO,IACnB,GAAIb,IAAO,MAAQa,GAAE,KAAK,CAAC,EAAEb,EAAG,GAAK,KAAM,CACzC,IAAMnB,GAAMgC,GAAE,KAAK,CAAC,EAAEb,EAAG,EACzB,GAAInB,IAAO,KAAM,CACf,IAAMwG,GAAOxE,GAAE,SAASA,GAAE,KAAK,CAAC,EAAEb,EAAG,EAAI,IAAK,EAAI,EAC5CsF,EAAOzE,GAAE,SAAShC,GAAK,IAAK,EAAI,EAEhC0G,EAAO1E,GAAE,IACT2E,GAAO,OAAO,kBAAoB,EAGxCD,EAAK,KAAK,EACVA,EAAK,UAAU,EACfA,EAAK,YAAY,CAAC,EAAIC,GAAM,EAAIA,EAAI,CAAC,EACrCD,EAAK,YAAc9E,GAAU7C,EAAO,EAAG,EACvC2H,EAAK,UAAY,EAAIC,GAErBD,EAAK,OAAOF,GAAMxE,GAAE,KAAK,GAAG,EAC5B0E,EAAK,OAAOF,GAAMxE,GAAE,KAAK,IAAMA,GAAE,KAAK,MAAM,EAE5C0E,EAAK,OAAO1E,GAAE,KAAK,KAAMyE,CAAI,EAC7BC,EAAK,OAAO1E,GAAE,KAAK,KAAOA,GAAE,KAAK,MAAOyE,CAAI,EAC5CC,EAAK,OAAO,EACZA,EAAK,QAAQ,EAGbA,EAAK,KAAK,EACVA,EAAK,UAAU,EACfA,EAAK,YAAY,CAAC,CAAC,EACnBA,EAAK,IAAIF,GAAMC,EAAM,GAAKE,GAAM,EAAG,EAAI,KAAK,EAAE,EAC9CD,EAAK,UAAY9E,GAAU7C,EAAO,EAAG,EACrC2H,EAAK,KAAK,EACVA,EAAK,QAAQ,EAGbA,EAAK,KAAK,EACVA,EAAK,UAAU,EACfA,EAAK,IAAIF,GAAMC,EAAM,EAAIE,GAAM,EAAG,EAAI,KAAK,EAAE,EAC7CD,EAAK,UAAY3H,EACjB2H,EAAK,KAAK,EACVA,EAAK,YAAc,OACnBA,EAAK,UAAY,EAAIC,GACrBD,EAAK,OAAO,EACZA,EAAK,QAAQ,EAGbA,EAAK,KAAK,EACVA,EAAK,YAAY,CAAC,CAAC,EAEnB,IAAMtK,GAAI,IAAI,KAAK4F,GAAE,KAAK,CAAC,EAAEb,EAAG,EAAK,GAAI,EACnCyF,GAAU,GAAGxK,GAAE,eAAe,CAAC,IAAI,OAAOA,GAAE,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,IAAI,OAAOA,GAAE,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,GAChIsK,EAAK,KAAO,QAAQ,GAAKC,EAAI,2BAE7B,IAAM5C,GADY2C,EAAK,YAAYE,EAAO,EAAE,MACpB,GAAKD,GACvB3C,GAAQ,GAAK2C,GAEb1C,GAAUuC,GAAOzC,GAAM,EACvBG,GAAa,KAAK,IACtBlC,GAAE,KAAK,KACP,KAAK,IAAIA,GAAE,KAAK,KAAOA,GAAE,KAAK,MAAQ+B,GAAKE,EAAO,CACpD,EACME,GAAUnC,GAAE,KAAK,IAAMA,GAAE,KAAK,OAAS,EAAI2E,GAGjDD,EAAK,UAAY,yBACjBA,EAAK,UAAU,EACVA,EAAa,UACfA,EAAa,UAAUxC,GAAYC,GAASJ,GAAKC,GAAO,EAAI2C,EAAI,EAC9DD,EAAK,KAAKxC,GAAYC,GAASJ,GAAKC,EAAK,EAC9C0C,EAAK,KAAK,EACVA,EAAK,YAAc9E,GAAU7C,EAAO,GAAI,EACxC2H,EAAK,UAAY,EAAIC,GACrBD,EAAK,OAAO,EAEZA,EAAK,UAAY3H,EACjB2H,EAAK,UAAY,SACjBA,EAAK,aAAe,SACpBA,EAAK,SAASE,GAAS1C,GAAaH,GAAM,EAAGI,GAAUH,GAAQ,CAAC,EAEhE,IAAM6C,GAAS,GAAG7G,GAAI,QAAQ,CAAC,CAAC,IAAIlB,CAAI,GAElCuF,GADWqC,EAAK,YAAYG,EAAM,EAAE,MACnB,GAAKF,GAEtBrC,GAAUtC,GAAE,KAAK,KAAOqC,GAAM,EAAIsC,GAClCpC,GAAUkC,EAAOzC,GAAQ,EAG/B0C,EAAK,UAAY,yBACjBA,EAAK,UAAU,EACVA,EAAa,UACfA,EAAa,UAAUpC,GAASC,GAASF,GAAKL,GAAO,EAAI2C,EAAI,EAC3DD,EAAK,KAAKpC,GAASC,GAASF,GAAKL,EAAK,EAC3C0C,EAAK,KAAK,EACVA,EAAK,YAAc9E,GAAU7C,EAAO,GAAI,EACxC2H,EAAK,UAAY,EAAIC,GACrBD,EAAK,OAAO,EAEZA,EAAK,UAAY3H,EACjB2H,EAAK,UAAY,OACjBA,EAAK,aAAe,SACpBA,EAAK,SAASG,GAAQvC,GAAU,EAAIqC,GAAMpC,GAAUP,GAAQ,CAAC,EAE7D0C,EAAK,QAAQ,CACf,CACF,CACF,CACF,EACA,UAAW,CACR1E,IAAa,CACZ,GAAI,CAAEA,GAAU,OAAQ,OACxBA,GAAE,OAAO,EAAK,EAEd,IAAIb,GAAMa,GAAE,OAAO,IACbiB,GAAajB,GAAE,OAAO,KACtBkB,GAAYlB,GAAE,OAAO,IACrBK,EAAKL,GAAE,KAEb,GAAIiB,IAAc,MAAQC,IAAa,MAAQD,IAAc,GAAKC,IAAa,EAAG,CAChF,IAAIC,EAAQ,IACRC,GAAa,GACXC,GAAS,GACTC,GAAQD,GAASA,GAEjBhD,GAAQ2B,GAAE,KAAK,CAAC,EAChB8E,GAAQ9E,GAAE,KAAK,CAAC,EAEtB,QAASnG,GAAI,EAAGA,GAAIwE,GAAM,OAAQxE,KAAK,CACrC,IAAM4G,GAAIpC,GAAMxE,EAAC,EACXkL,GAAID,GAAMjL,EAAC,EACjB,GAAI4G,IAAK,MAAQsE,IAAK,KAAM,SAE5B,IAAMtD,GAAKzB,GAAE,SAASS,GAAG,IAAK,EAAK,EAC7BiB,GAAK1B,GAAE,SAAS+E,GAAG,IAAK,EAAK,EAE7BpD,GAAKF,GAAKR,GACVW,GAAKF,GAAKR,GACVW,GAAKF,GAAKA,GAAKC,GAAKA,GAEtBC,GAAKV,IACPA,EAAQU,GACRT,GAAavH,GAEjB,CAEIsH,GAASG,IACXnC,GAAMiC,GACN6C,GAAiB7C,KAEjBjC,GAAM,KACN8E,GAAiB,KAErB,CAEA,GAAI9E,IAAO,MAAQa,GAAE,KAAK,CAAC,EAAEb,EAAG,GAAK,KAAM,CACzC,IAAM7F,EAAQuF,EAAeM,EAAG,EAC1BqD,GAAKxC,GAAE,SAASA,GAAE,KAAK,CAAC,EAAEb,EAAG,EAAG,IAAK,EAAK,EAC1CsD,GAAKzC,GAAE,SAASA,GAAE,KAAK,CAAC,EAAEb,EAAG,EAAI,IAAK,EAAK,EAE3C/E,GAAI,IAAI,KAAK4F,GAAE,KAAK,CAAC,EAAEb,EAAG,EAAK,GAAI,EACnCyF,GAAU,GAAGxK,GAAE,eAAe,CAAC,IAAI,OAAOA,GAAE,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,IAAI,OAAOA,GAAE,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,GAE1H4D,GAAMgC,GAAE,KAAK,CAAC,EAAEb,EAAG,EACnB0F,GAAS7G,IAAO,KAAO,GAAGA,EAAG,IAAIlB,CAAI,GAAK,SAEhDqH,EAAgB,UAAY;AAAA;AAAA;AAAA,8DAGgBS,EAAO;AAAA;AAAA;AAAA;AAAA,8DAIPC,EAAM;AAAA;AAAA,oBAGlDV,EAAgB,MAAM,QAAU,QAChCA,EAAgB,MAAM,KAAO,GAAGlD,GAAcZ,EAAG,IAAI,KACrD8D,EAAgB,MAAM,IAAM,GAAGjD,GAAab,EAAG,GAAG,KAClD8D,EAAgB,MAAM,UAAY,sBACpC,MACEA,EAAgB,MAAM,QAAU,MAEpC,CACF,CACF,EACA,KAAM,CACJ,CACE,MAAO,GACP,OAAQ,UACR,KAAM,CAAE,OAAQ,SAAU,EAC1B,KAAM,GACN,KAAM,6BACN,KAAM,GACN,OAAQ,CAACnE,GAAQF,KACfA,GAAK,IAAKC,IAAM,CACd,IAAM3F,GAAI,IAAI,KAAK2F,GAAI,GAAI,EAC3B,MAAO,GAAG3F,GAAE,eAAe,CAAC,IAAI,OAAOA,GAAE,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,EAC9E,CAAC,CACL,EACA,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,SAAU,EAC1B,KAAM,6BACN,OAAQ,CAAC4F,GAAQF,KAAgBA,GAAK,IAAKC,IAAM,GAAGA,EAAC,IAAIjD,CAAI,EAAE,EAC/D,KAAM,GACN,MAAO,GACP,KAAM,EACR,CACF,CACF,EAEA2C,EAAgB,IAAI1D,GAAMuI,GAAcF,GAAqBF,EAAU,EACvE1M,GAAe,KAAKiI,CAAa,EAEjCyE,GAAW,iBAAiB,aAAc,IAAM,CAC9CzE,EAAe,OAAO,CACxB,CAAC,CAGH,MACEyE,GAAW,UAAY,mEAE3B,CACF,GACa,EAEN,CACL,UAAY1L,IAAuB,CACjCsG,EAAYtG,GACRA,KAAQ,OAAMoG,EAAapG,IAE/B,IAAMuK,GAAU,SAAS,eAAe,GAAGnG,CAAS,iBAAiB,EAIrE,GAHImG,KACFA,GAAQ,YAAc,YAAYrC,GAAY9B,CAAU,CAAC,IAAIhC,IAAc,QAAU,QAAU,IAAI,GAAGkC,IAAc,KAAO,YAAc,EAAE,IAEzIW,EAAe,CACjB,GAAM,CAAE,UAAAL,GAAW,aAAAE,GAAc,kBAAAC,CAAkB,EAAIR,EACrDH,EACAvF,CACF,EACMwJ,EAAatD,EAAkB,IAAKQ,GAAOA,IAAM,KAAOA,EAAI,GAAM,IAAK,EACvE+C,GAAavD,EAAkB,IAAKQ,GAAOA,IAAM,KAAOA,EAAI,IAAM,IAAK,EAC7EN,EAAc,QAAQ,CAACL,GAAWE,GAAcC,EAAmBsD,EAAYC,EAAU,CAAC,CAC5F,CACI5F,GAAWA,EAAU,OAAO,CAClC,EACA,YAAc/E,IAAkB,CAE9B,GADAkB,EAAelB,GACXsH,EAAe,CACjB,GAAM,CAAE,UAAAL,GAAW,aAAAE,GAAc,kBAAAC,EAAkB,EAAIR,EACrDH,EACAvF,CACF,EACMwJ,EAAatD,GAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,GAAM,IAAK,EACvE+C,EAAavD,GAAkB,IAAKQ,IAAOA,KAAM,KAAOA,GAAI,IAAM,IAAK,EAC7EN,EAAc,QAAQ,CAACL,GAAWE,GAAcC,GAAmBsD,EAAYC,CAAU,CAAC,CAC5F,CACF,CACF,CACF,CAEA,SAASkC,GAAapH,EAAkB,CACtC,IAAMxD,EAAI,IAAI,KAAKwD,CAAI,EACjBrC,EAAMnB,EAAE,UAAU,EAClB6K,EAAO7K,EAAE,WAAW,EAAImB,GAAOA,IAAQ,EAAI,GAAK,GACtD,OAAAnB,EAAE,WAAW6K,CAAI,EACjB7K,EAAE,YAAY,EAAG,EAAG,EAAG,CAAC,EACjBA,CACT,CAEA,SAAS8K,GACPhM,EACyD,CACzD,IAAMiM,EAAsE,CAAC,EAE7E,OAAAjM,EAAU,QAASsD,GAAM,CACvB,GAAI,CAACA,EAAE,MAAM,WAAa,CAACA,EAAE,MAAM,UAAW,OAE9C,IAAMoB,EAAO,IAAI,KAAKpB,EAAE,MAAM,SAAS,EACjC4I,EAAYJ,GAAapH,CAAI,EAC7ByH,EAAUD,EAAU,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EAE/CD,EAAWE,CAAO,IAAGF,EAAWE,CAAO,EAAI,CAAE,UAAWD,EAAU,QAAQ,EAAG,SAAU,CAAE,GAE9FD,EAAWE,CAAO,EAAE,UAAY7I,EAAE,MAAM,SAC1C,CAAC,EAEM,OAAO,QAAQ2I,CAAU,EAC7B,IAAI,CAAC,CAACG,EAAMvH,CAAI,KAAO,CAAE,KAAAuH,EAAM,UAAWvH,EAAK,UAAW,SAAUA,EAAK,QAAS,EAAE,EACpF,KAAK,CAACK,EAAG9F,IAAM8F,EAAE,UAAY9F,EAAE,SAAS,CAC7C,CAEA,SAASiN,GACPrM,EAC0D,CAC1D,IAAMiM,EAAuE,CAAC,EAE9E,OAAAjM,EAAU,QAASsD,GAAM,CACvB,GAAI,CAACA,EAAE,MAAM,WAAaA,EAAE,MAAM,WAAa,OAAW,OAE1D,IAAMoB,EAAO,IAAI,KAAKpB,EAAE,MAAM,SAAS,EACjC4I,EAAYJ,GAAapH,CAAI,EAC7ByH,EAAUD,EAAU,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EAE/CD,EAAWE,CAAO,IACrBF,EAAWE,CAAO,EAAI,CAAE,UAAWD,EAAU,QAAQ,EAAG,UAAW,CAAE,GAEvED,EAAWE,CAAO,EAAE,WAAa7I,EAAE,MAAM,QAC3C,CAAC,EAEM,OAAO,QAAQ2I,CAAU,EAC7B,IAAI,CAAC,CAACG,EAAMvH,CAAI,KAAO,CAAE,KAAAuH,EAAM,UAAWvH,EAAK,UAAW,UAAWA,EAAK,SAAU,EAAE,EACtF,KAAK,CAACK,EAAG9F,IAAM8F,EAAE,UAAY9F,EAAE,SAAS,CAC7C,CAEA,SAASkN,GACPtM,EACyD,CACzD,IAAMuM,EAAuE,CAAC,EAE9E,OAAAvM,EAAU,QAASsD,GAAM,CACvB,GAAI,CAACA,EAAE,MAAM,WAAa,CAACA,EAAE,MAAM,UAAW,OAC9C,IAAMoB,EAAO,IAAI,KAAKpB,EAAE,MAAM,SAAS,EACjCkJ,EAAa,IAAI,KAAK,KAAK,IAAI9H,EAAK,eAAe,EAAGA,EAAK,YAAY,EAAG,CAAC,CAAC,EAC5E+H,EAAWD,EAAW,YAAY,EAAE,MAAM,EAAG,CAAC,EAC/CD,EAAYE,CAAQ,IACvBF,EAAYE,CAAQ,EAAI,CAAE,UAAWD,EAAW,QAAQ,EAAG,SAAU,CAAE,GAEzED,EAAYE,CAAQ,EAAE,UAAYnJ,EAAE,MAAM,SAC5C,CAAC,EAEM,OAAO,QAAQiJ,CAAW,EAC9B,IAAI,CAAC,CAACH,EAAMvH,CAAI,KAAO,CAAE,KAAAuH,EAAM,UAAWvH,EAAK,UAAW,SAAUA,EAAK,QAAS,EAAE,EACpF,KAAK,CAACK,EAAG9F,IAAM8F,EAAE,UAAY9F,EAAE,SAAS,CAC7C,CAEA,SAASsN,GACP1M,EAC0D,CAC1D,IAAMuM,EAAwE,CAAC,EAE/E,OAAAvM,EAAU,QAASsD,GAAM,CACvB,GAAI,CAACA,EAAE,MAAM,WAAaA,EAAE,MAAM,WAAa,OAAW,OAC1D,IAAMoB,EAAO,IAAI,KAAKpB,EAAE,MAAM,SAAS,EACjCkJ,EAAa,IAAI,KAAK,KAAK,IAAI9H,EAAK,eAAe,EAAGA,EAAK,YAAY,EAAG,CAAC,CAAC,EAC5E+H,EAAWD,EAAW,YAAY,EAAE,MAAM,EAAG,CAAC,EAC/CD,EAAYE,CAAQ,IACvBF,EAAYE,CAAQ,EAAI,CAAE,UAAWD,EAAW,QAAQ,EAAG,UAAW,CAAE,GAE1ED,EAAYE,CAAQ,EAAE,WAAanJ,EAAE,MAAM,QAC7C,CAAC,EAEM,OAAO,QAAQiJ,CAAW,EAC9B,IAAI,CAAC,CAACH,EAAMvH,CAAI,KAAO,CAAE,KAAAuH,EAAM,UAAWvH,EAAK,UAAW,UAAWA,EAAK,SAAU,EAAE,EACtF,KAAK,CAACK,EAAG9F,IAAM8F,EAAE,UAAY9F,EAAE,SAAS,CAC7C,CAEA,SAAS0D,GACPL,EACAzC,EACA2M,EACAC,EACA1M,EACAyC,EACA,CACA,IAAMkK,EAAaF,IAAS,WACxBG,EAAmCtO,GACnCuO,EAAc7N,GAAS,IAAI,EAAE,UAAY,MACvC8N,EAAeH,EACjBb,GAAsBhM,CAAS,EAC/BqM,GAAuBrM,CAAS,EAC9BiN,EAAgBJ,EAClBP,GAAuBtM,CAAS,EAChC0M,GAAwB1M,CAAS,EACjCiM,EAAaa,IAAmB,QAAUG,EAAgBD,EACxDE,EAAcC,GAAyBnN,EAAYsD,IACvDuJ,EAAavJ,GAAE,MAAM,UAAYA,GAAE,MAAM,QAC3C,EACMO,EAAQgJ,EAAarK,GAAQ,SAAS,MAAQA,GAAQ,UAAU,MAChEoB,EAAOiJ,EAAa,KAAO,IAC3B/I,EAAO+I,EAAarK,GAAQ,SAAS,KAAOA,GAAQ,UAAU,KAE9DyB,EAAgB,SAAS,cAAc,KAAK,EAClDA,EAAc,UAAY,aAAa0I,CAAI,iBAC3C1I,EAAc,GAAK,GAAG0I,CAAI,kBAE1B1I,EAAc,UAAY;AAAA;AAAA;AAAA,wGAG4EJ,CAAK,KAAKC,CAAI;AAAA,4DAC1D+I,EAAa,oBAAsB,oBAAoB;AAAA;AAAA;AAAA;AAAA,iBAIlGF,CAAI;AAAA;AAAA,mBAEFA,CAAI;AAAA;AAAA;AAAA,UAGbS,GAAuBF,EAAaL,EAAYjJ,CAAI,CAAC;AAAA;AAAA;AAAA,IAK7DnB,EAAK,YAAYwB,CAAa,EAE9B,IAAMK,EAAUL,EAAc,cAAc,IAAI0I,CAAI,eAAe,EAC7DU,EAAUpJ,EAAc,cAAc,IAAI0I,CAAI,eAAe,EAEnE,GAAI,CAACrI,GAAW,CAAC+I,EAAS,OAE1B/I,EAAQ,MAAM,SAAW,WAGzB,IAAMgJ,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,YACpBA,EAAQ,MAAM,QAAU,SAASzJ,CAAK,gBACtCS,EAAQ,YAAYgJ,CAAO,EAE3B,IAAMnI,EAAQ8G,EAAW,IAAK/K,IAAMA,GAAE,UAAY,GAAI,EAChD0K,EAAQiB,EACTZ,EAAqB,IAAK/K,IAAMA,GAAE,SAAW,GAAI,EACjD+K,EAAqB,IAAK/K,IAAMA,GAAE,SAAS,EAEhD,GAAIiE,EAAM,SAAW,EAAG,OAExB,IAAMoI,EAAgBjH,GAAesF,EAAO,CAAC,EAEvC4B,EAAe,KAAK,IAAI,GAAI7K,GAAa,KAAO,GAAK,IAAM,EAAE,EAC7D8K,EAAQ,KAAK,IAAID,EAAcrI,EAAM,OAAS,EAAE,EAChDuI,EAAS,KAAK,IAAI,GAAG9B,CAAK,EAAI,IAE9B+B,EAA0B,CAC9B,MAAOF,EACP,OAAQ,IACR,QAAS,CAAC,GAAI,GAAI,EAAG,EAAE,EACvB,OAASpC,IAAexI,GAAM,OAAO,IAAI,KAAKwI,GAAK,GAAI,EAAG,SAAS,EACnE,OAAQ,CACN,EAAG,CAAE,KAAM,EAAK,EAChB,EAAG,CAAE,MAAO,CAAC,EAAGqC,CAAM,CAAE,CAC1B,EACA,OAAQ,CACN,CAAC,EACD,CACE,MAAOb,EAAa,WAAa,YACjC,OAAQhJ,EACR,KAAM6C,GAAU7C,EAAO,EAAG,EAC1B,MAAO,EACP,OAAQ,CAAE,KAAM,GAAM,KAAM,CAAE,CAChC,EACA,CACE,MAAO,QACP,OAAQA,EACR,MAAO,EACP,KAAM,CAAC,EAAG,CAAC,EACX,OAAQ,CAAE,KAAM,EAAM,CACxB,CACF,EACA,OAAQ,CACN,KAAM+I,EAAU,CAAE,IAAKA,EAAQ,GAAI,EAAI,OACvC,KAAM,CAAE,EAAG,GAAO,EAAG,EAAM,EAC3B,OAAQ,CAAE,KAAM,EAAM,EACtB,EAAG,GACH,EAAG,EACL,EACA,MAAO,CACL,KAAM,CACH9F,IAAa,CACZA,GAAE,KAAK,iBAAiB,QAAS,IAAM,CACrC,IAAMb,EAAMa,GAAE,OAAO,IACrB,GAAIb,GAAO,KAAM,CACf,IAAM2H,EAAO3B,EAAWhG,CAAG,EAC3B,GAAI2H,EAAM,CACR,IAAMC,EAAQ,IAAI,KAAKD,EAAK,SAAS,EAC/BE,EAAM,IAAI,KAAKF,EAAK,UAAY,EAAI,GAAK,GAAK,GAAK,GAAI,EACvDG,EAAWF,EAAM,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EAC3CG,EAASF,EAAI,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EAC7C5N,IAAoB6N,EAAUC,CAAM,CACtC,CACF,CACF,CAAC,CACH,CACF,EACA,UAAW,CACRlH,IAAa,CACZ,GAAI,CAAEA,GAAU,OAAQ,OACxB,IAAMb,EAAMa,GAAE,OAAO,IACfiB,EAAajB,GAAE,OAAO,KACtBkB,EAAYlB,GAAE,OAAO,IAE3B,GACEb,GAAO,MACP8B,GAAc,MACdC,GAAa,MACbD,GAAc,GACdC,GAAa,EACb,CACA,IAAMlD,EAAMgC,GAAE,KAAK,CAAC,EAAEb,CAAG,EACnB0F,EACJ7G,GAAO,KAAQ+H,EAAa,GAAG/H,EAAI,QAAQ,CAAC,CAAC,MAAQ,GAAGA,EAAI,QAAQ,CAAC,CAAC,KAAQ,SAEhFwI,EAAQ,UAAY3B,EACpB2B,EAAQ,MAAM,QAAU,QACxBA,EAAQ,MAAM,KAAO,GAAGxG,GAAE,SAASA,GAAE,KAAK,CAAC,EAAEb,CAAG,EAAI,IAAK,EAAK,CAAC,KAC/DqH,EAAQ,MAAM,IAAM,GAAGxG,GAAE,SAASA,GAAE,KAAK,CAAC,EAAEb,CAAG,EAAI,IAAK,EAAK,CAAC,KAC9DqH,EAAQ,MAAM,UAAY,sBAC5B,MACEA,EAAQ,MAAM,QAAU,OAG1BxG,GAAE,OAAO,EAAK,CAChB,CACF,EACA,KAAM,CACHA,IAAa,CACZ,IAAMb,EAAMa,GAAE,OAAO,IACrB,GAAIb,GAAO,MAAQa,GAAE,KAAK,CAAC,EAAEb,CAAG,GAAK,KAAM,CACzC,IAAMwB,EAAMX,GAAE,SAASA,GAAE,KAAK,CAAC,EAAEb,CAAG,EAAI,IAAK,EAAI,EAC3CyB,EAAMZ,GAAE,SAASA,GAAE,KAAK,CAAC,EAAEb,CAAG,EAAI,IAAK,EAAI,EAC3CiB,EAAM,OAAO,kBAAoB,EACjCD,EAAMH,GAAE,IACRK,EAAKL,GAAE,KAGbG,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,EAAIC,EAAK,EAAIA,CAAG,CAAC,EAClCD,EAAI,YAAcP,GAAU7C,EAAO,EAAG,EACtCoD,EAAI,UAAY,EAAIC,EAEpBD,EAAI,OAAOQ,EAAKN,EAAG,GAAG,EACtBF,EAAI,OAAOQ,EAAKN,EAAG,IAAMA,EAAG,MAAM,EAElCF,EAAI,OAAOE,EAAG,KAAMO,CAAG,EACvBT,EAAI,OAAOE,EAAG,KAAOA,EAAG,MAAOO,CAAG,EAClCT,EAAI,OAAO,EACXA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,YAAY,CAAC,CAAC,EAClBA,EAAI,IAAIQ,EAAKC,EAAK,GAAKR,EAAK,EAAG,EAAI,KAAK,EAAE,EAC1CD,EAAI,UAAYP,GAAU7C,EAAO,EAAG,EACpCoD,EAAI,KAAK,EACTA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,UAAU,EACdA,EAAI,IAAIQ,EAAKC,EAAK,EAAIR,EAAK,EAAG,EAAI,KAAK,EAAE,EACzCD,EAAI,UAAYpD,EAChBoD,EAAI,KAAK,EACTA,EAAI,YAAc,OAClBA,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EACXA,EAAI,QAAQ,EAGZA,EAAI,KAAK,EACTA,EAAI,YAAY,CAAC,CAAC,EAGlB,IAAM/F,EAAI,IAAI,KAAK4F,GAAE,KAAK,CAAC,EAAEb,CAAG,EAAK,GAAI,EACnC2C,EAAU,GAAG1H,EAAE,eAAe,CAAC,IAAI,OAAOA,EAAE,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,IAAI,OAAOA,EAAE,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,GAChI+F,EAAI,KAAO,QAAQ,GAAKC,CAAG,2BAE3B,IAAM2B,GADY5B,EAAI,YAAY2B,CAAO,EAAE,MACnB,GAAK1B,EACvB4B,GAAQ,GAAK5B,EAEb6B,GAAUtB,EAAMoB,GAAM,EACtBG,GAAa,KAAK,IAAI7B,EAAG,KAAM,KAAK,IAAIA,EAAG,KAAOA,EAAG,MAAQ0B,GAAKE,EAAO,CAAC,EAC1EE,EAAU9B,EAAG,IAAMA,EAAG,OAAS,EAAID,EAEzCD,EAAI,UAAY,yBAChBA,EAAI,UAAU,EACTA,EAAY,UACdA,EAAY,UAAU+B,GAAYC,EAASJ,GAAKC,GAAO,EAAI5B,CAAG,EAC5DD,EAAI,KAAK+B,GAAYC,EAASJ,GAAKC,EAAK,EAC7C7B,EAAI,KAAK,EACTA,EAAI,YAAcP,GAAU7C,EAAO,GAAI,EACvCoD,EAAI,UAAY,EAAIC,EACpBD,EAAI,OAAO,EAEXA,EAAI,UAAYpD,EAChBoD,EAAI,UAAY,SAChBA,EAAI,aAAe,SACnBA,EAAI,SAAS2B,EAASI,GAAaH,GAAM,EAAGI,EAAUH,GAAQ,CAAC,EAE/D7B,EAAI,QAAQ,CACd,CACF,CACF,CACF,EACA,KAAM,CACJ,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,GACN,MAAO,GACP,OAAQ,CAACgH,GAAMC,IACbA,EAAO,IAAKC,GAAM,CAChB,IAAMjN,EAAI,IAAI,KAAKiN,EAAI,GAAI,EAC3B,MAAO,GAAGjN,EAAE,YAAY,EAAI,CAAC,IAAIA,EAAE,WAAW,CAAC,EACjD,CAAC,EACH,KAAM,6BACN,KAAM,EACR,EACA,CACE,OAAQ,UACR,KAAM,CAAE,OAAQ,UAAW,MAAO,CAAE,EACpC,KAAM,GACN,OAAQ,CAAC+M,GAAMC,IAAWA,EAAO,IAAKC,GAAM,GAAGA,EAAE,QAAQ,CAAC,CAAC,IAAIvK,CAAI,EAAE,EACrE,KAAM,6BACN,KAAM,EACR,CACF,CACF,EAEMI,EAAY,IAAInB,GAAM8K,EAAU,CAACxI,EAAOyG,EAAO2B,CAAa,EAAGjJ,CAAO,EAC5EhG,GAAe,KAAK0F,CAAS,EAE7B,IAAMoK,GAAkBnK,EAAc,cAAc,yBAAyB,EACzEmK,IAAmBjJ,EAAM,OAAS,GAAKsI,IACzCW,GAAgB,WAAaA,GAAgB,YAAcA,GAAgB,aAE7E,SAASC,IAAkB,CACzBpC,EAAaa,IAAmB,QAAUG,EAAgBD,EAC1D,IAAMlH,GAAUmG,EAAWA,EAAW,OAAS,CAAC,GAAG,WAAa,WAC5DlG,EAAU,EAEVgH,IAAgB,KAAMhH,EAAUD,GAAU,GAAK,GAAK,KAAO,IACtDiH,IAAgB,KAAMhH,EAAUD,GAAU,GAAK,GAAK,KAAO,IAC3DiH,IAAgB,KAAMhH,EAAUD,GAAU,IAAM,GAAK,KAAO,IAC5DiH,IAAgB,KAAMhH,EAAUD,GAAU,IAAM,GAAK,KAAO,IAC5DiH,IAAgB,OAAMhH,EAAUD,GAAU,EAAI,IAAM,GAAK,KAAO,KAEzE,IAAMwI,EAAerC,EAAW,OAAQ/K,GAAMA,EAAE,WAAa6E,CAAO,EAE9DwI,EAAWD,EAAa,IAAKpN,GAAMA,EAAE,UAAY,GAAI,EACrDsN,EAAW3B,EACZyB,EAAuB,IAAKpN,GAAMA,EAAE,SAAW,GAAI,EACnDoN,EAAuB,IAAKpN,GAAMA,EAAE,SAAS,EAC5CuN,EAAmBnI,GAAekI,EAAU,CAAC,EAE7CE,EAAW,KAAK,IAAIpK,EAAQ,YAAaiK,EAAS,OAAS,EAAE,EAC7DI,EAAY,KAAK,IAAI,EAAG,GAAGH,CAAQ,EAAI,IAE7CxK,EAAU,QAAQ,CAAE,MAAO0K,EAAU,OAAQ,GAAI,CAAC,EAClD1K,EAAU,SAAS,IAAK,CAAE,IAAK,EAAG,IAAK2K,CAAU,CAAC,EAClD3K,EAAU,QAAQ,CAACuK,EAAUC,EAAUC,CAAgB,CAAC,EAEpDL,KACFA,GAAgB,WAAaA,GAAgB,YAAcA,GAAgB,YAC/E,CAEA,MAAO,CACL,YAAcnP,IAAkB,CAC9B8N,EAAc9N,GACdoP,GAAgB,CAClB,EACA,eAAiBvP,IAA+B,CAC9CgO,EAAiBhO,GACjBuP,GAAgB,CAClB,CACF,CACF,CEzuDA,IAAMO,GAAyB,CAC7B,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,SACF,EAEMC,GAAmB,GAErBC,GAAoC,CAAC,EACrCC,GAAqD,CAAC,EAE1D,SAASC,GAAUC,EAAYC,EAAY,CACzC,IAAMC,EAAK,IAAI,KAAKF,CAAE,EAChBG,EAAK,IAAI,KAAKF,CAAE,EACtB,OACEC,EAAG,eAAe,IAAMC,EAAG,eAAe,GAC1CD,EAAG,YAAY,IAAMC,EAAG,YAAY,GACpCD,EAAG,WAAW,IAAMC,EAAG,WAAW,CAEtC,CAEA,IAAIC,GAAmB,GACnBC,GAA4B,KAC5BC,GAAW,EACXC,GAAY,GACZC,GAAoC,KAGpCC,GAAc,GACdC,GAAc,GACdC,GAAc,YAWdC,GAAmB,CACrB,KAAM,CAAC,KAAM,IAAI,EACjB,KAAM,CAAC,KAAM,IAAI,EACjB,IAAK,CAAC,KAAM,IAAI,EAChB,QAAS,IAAI,IACb,KAAM,CAAC,EACP,MAAO,IACT,EAEA,SAASC,GAAiBC,EAAgB,GAAO,CAC/CC,GAAS,MACP,CACE,OAAQH,GAAQ,KAAK,MAAOI,GAAMA,IAAM,IAAI,EAAI,KAAOJ,GAAQ,KAC/D,OAAQA,GAAQ,KAAK,MAAOI,GAAMA,IAAM,IAAI,EAAI,KAAOJ,GAAQ,KAC/D,MAAOA,GAAQ,IAAI,MAAOI,GAAMA,IAAM,IAAI,EAAI,KAAOJ,GAAQ,IAC7D,OAAQA,GAAQ,QAAQ,OAAS,EAAI,KAAO,MAAM,KAAKA,GAAQ,OAAO,EACtE,OAAQA,GAAQ,KAAK,SAAW,EAAI,KAAOA,GAAQ,IACrD,EACAE,CACF,CACF,CAEA,SAASG,IAAmB,CAC1B,IAAMC,EAASC,GAAU,iBAAiB,EACpCC,EAAUD,GAAU,QACpBE,EAAQ,MAAM,KAAKH,CAAM,EAAE,IAAKI,GAAQF,EAAQE,CAAG,EAAE,IAAI,EAC/DP,GAAS,MAAM,CAAE,QAASM,EAAM,OAASA,EAAQ,IAAK,CAAC,CACzD,CAEA,IAAME,GAAe,CACnB,CAAE,MAAO,eAAgB,IAAK,YAAa,KAAM,gBAAiB,EAClE,CAAE,MAAO,eAAgB,IAAK,WAAY,KAAM,SAAU,EAC1D,CAAE,MAAO,mBAAoB,IAAK,YAAa,KAAM,YAAa,EAClE,CAAE,MAAO,oBAAqB,IAAK,WAAY,KAAM,iBAAkB,EACvE,CAAE,MAAO,mBAAoB,IAAK,WAAY,KAAM,OAAQ,EAC5D,CAAE,MAAO,oBAAqB,IAAK,UAAW,KAAM,WAAY,CAClE,EAEA,SAASC,GAAaC,EAAuB,CAC3C,SAAS,iBAAiB,kBAAkB,EAAE,QAASC,GAAOA,EAAG,OAAO,CAAC,EAEzE,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,kBAElBJ,GAAa,QAASK,GAAQ,CAC5B,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,aAAalB,KAAgBiB,EAAI,IAAM,SAAW,EAAE,GACrEC,EAAK,UAAY;AAAA,+CAC0BD,EAAI,IAAI;AAAA,iCACtBA,EAAI,KAAK;AAAA,qDACWjB,KAAgBiB,EAAI,IAAM,QAAU,EAAE;AAAA,MAEvFC,EAAK,iBAAiB,QAAS,IAAM,CACnClB,GAAciB,EAAI,IAClBb,GAAS,MAAM,CAAE,KAAMa,EAAI,GAAI,CAAC,EAChCE,GAAmB,EACnBC,GAAgB,EAChBJ,EAAM,OAAO,CACf,CAAC,EACDA,EAAM,YAAYE,CAAI,CACxB,CAAC,EAED,IAAMG,EAAOP,EAAS,sBAAsB,EAC5CE,EAAM,MAAM,IAAM,GAAGK,EAAK,OAAS,CAAC,KACpCL,EAAM,MAAM,KAAO,GAAGK,EAAK,IAAI,KAC/B,SAAS,KAAK,YAAYL,CAAK,EAE/B,IAAMM,EAASC,GAAkB,CAC3B,CAACP,EAAM,SAASO,EAAE,MAAc,GAAK,CAACT,EAAS,SAASS,EAAE,MAAc,IAC1EP,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASM,CAAK,EAE/C,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAK,EAAG,CAAC,CAC/D,CAEA,SAASE,GAAeV,EAAuB,CAC7C,SAAS,iBAAiB,oBAAoB,EAAE,QAASC,GAAOA,EAAG,OAAO,CAAC,EAE3E,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAElB,IAAMP,EAAUD,GAAU,QACpBiB,EAAYjB,GAAU,oBAAoB,EAC1CD,EAASC,GAAU,iBAAiB,EAE1C,OAAO,QAAQC,CAAO,EAAE,QAAQ,CAAC,CAACE,EAAKe,CAAG,IAAM,CAC9C,GAAI,CAACD,EAAU,IAAId,CAAG,EAAG,OAEzB,IAAMO,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,aAAaX,EAAO,IAAII,CAAG,EAAI,SAAW,EAAE,GAC7DO,EAAK,UAAY;AAAA,4DACuCQ,EAAI,KAAK,KAAKA,EAAI,IAAI;AAAA,iCACjDA,EAAI,KAAK;AAAA,qDACWnB,EAAO,IAAII,CAAG,EAAI,QAAU,EAAE;AAAA,MAE/EO,EAAK,iBAAiB,QAAS,IAAM,CACnCV,GAAU,aAAaG,CAAG,EAC1B,IAAMgB,EAAcnB,GAAU,iBAAiB,EAAE,IAAIG,CAAG,EACxDO,EAAK,UAAU,OAAO,SAAUS,CAAW,EAC3CT,EAAK,cAAc,QAAQ,EAAG,YAAcS,EAAc,QAAU,GAEpE,IAAMC,EAAO,SAAS,cAAc,2CAA2CjB,CAAG,IAAI,EAClFiB,GAAMA,EAAK,UAAU,OAAO,SAAUD,CAAW,EAErDE,GAAoB,EAEpBvB,GAAiB,CACnB,CAAC,EACDU,EAAM,YAAYE,CAAI,CACxB,CAAC,EAED,IAAMG,EAAOP,EAAS,sBAAsB,EAC5CE,EAAM,MAAM,IAAM,GAAGK,EAAK,OAAS,CAAC,KACpCL,EAAM,MAAM,MAAQ,GAAG,OAAO,WAAaK,EAAK,KAAK,KACrD,SAAS,KAAK,YAAYL,CAAK,EAE/B,IAAMM,EAASC,GAAkB,CAC3B,CAACP,EAAM,SAASO,EAAE,MAAc,GAAK,CAACT,EAAS,SAASS,EAAE,MAAc,IAC1EP,EAAM,OAAO,EACb,SAAS,oBAAoB,QAASM,CAAK,EAE/C,EACA,WAAW,IAAM,SAAS,iBAAiB,QAASA,CAAK,EAAG,CAAC,CAC/D,CAGA,SAAS,iBAAiB,eAAiBC,GAAW,CACpD,IAAMO,EAAKP,EAAE,OAAO,GACdQ,EAAMR,EAAE,OAAO,IACfS,EAAMT,EAAE,OAAO,IACrB,GAAIO,GAAM5C,GAAO4C,CAAE,IACjBG,GAAYH,CAAE,EACVC,GAAO,MAAQC,GAAO,MAAM,CAC9B,IAAME,EAAIhD,GAAO4C,CAAE,EACbK,EAAMD,EAAE,OACd,GAAIH,GAAO,GAAKA,EAAMI,EAAI,OAAQ,CAChC,IAAMC,EAAOD,EAAIJ,CAAG,EACpB,GAAIK,GAAQA,EAAK,MAAQ,KAAM,CAC7B,IAAMC,EAAKF,EAAI,KAAMG,GAAMA,EAAE,MAAQ,IAAI,GAAG,MAAQ,EAC9CC,GAAQH,EAAK,KAAOC,GAAM,IAC1BG,EAAOD,EAAOP,EAGpBxB,GAAU,iBAAiB+B,EAAMC,CAAI,EAGrC,IAAIC,EAAON,EAAI,UAAWG,IAAOA,EAAE,MAAQ,IAAMF,EAAK,KAAQJ,EAAM,GAAI,EACpES,IAAS,KAAIA,EAAON,EAAI,OAAS,GAErC,IAAMO,EAASP,EAAI,MAAMJ,EAAKU,EAAO,CAAC,EAChCE,EAAQC,GAAQ,aAAaF,CAAM,EACzClC,GAAU,kBAAkBmC,CAAK,EAEjCE,GAAeX,CAAC,EAEhBY,GAAQ,iBAAiBhB,EAAIK,EAAKJ,EAAKU,EAAM,GAAO5C,EAAgB,EACpEiD,GAAQ,cAAcJ,EAAO,IAAKJ,GAAM,CAACA,EAAE,IAAKA,EAAE,GAAG,CAAqB,CAAC,EAG3ElC,GAAS,MAAM,CAAE,IAAK,CAACmC,EAAMC,CAAI,CAAE,CAAC,CACtC,CACF,CACF,CAEJ,CAAC,EAED,SAAS,iBAAiB,QAAUjB,GAAM,CACxC,IAAMwB,EAAOxB,EAAE,OAAuB,QAAQ,UAAU,EACxD,GAAI,CAACwB,EAAK,OACV,IAAMC,EAAMD,EAAI,QAAQ,UAAU,EAClC,GAAI,CAACC,EAAK,OAGVA,EAAI,iBAAiB,UAAU,EAAE,QAASC,GAAMA,EAAE,UAAU,OAAO,SAAUA,IAAMF,CAAG,CAAC,EAEvF,IAAMG,EAAMH,EAAI,QAAQ,IACxB3C,GAAS,MAAM,CAAE,IAAA8C,CAAI,EAAG,EAAI,EAG5B,IAAMC,EAAQH,EAAI,QAAQ,cAAc,EAsCxC,GArCIG,GACFA,EAAM,iBAAiB,cAAc,EAAE,QAASC,GAAM,CACpDA,EAAE,UAAU,OAAO,SAAUA,EAAE,KAAO,OAAOL,EAAI,QAAQ,GAAG,EAAE,CAChE,CAAC,EAGCA,EAAI,QAAQ,MAAQ,WAAarD,IAAcR,GAAOQ,EAAU,GAClE2D,GAAcnE,GAAOQ,EAAU,EAAG4D,GAAc,CAAC,EAE/CP,EAAI,QAAQ,MAAQ,YAAcrD,IAAcR,GAAOQ,EAAU,GACnEmD,GAAe3D,GAAOQ,EAAU,CAAC,EAE/BqD,EAAI,QAAQ,MAAQ,aACtBQ,GACE7D,GAAaR,GAAOQ,EAAU,EAAI,KAClC,OAAO,OAAOR,EAAM,EACpB,CAACsE,EAASC,IAAU,CAClBxB,GAAYuB,EAAS,EAAI,EACrBC,IACFjD,GAAU,iBAAiBiD,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC7CC,GAAmBD,EAAM,CAAC,EAAGA,EAAM,CAAC,EAAG,OAAQ,EAAI,EAEvD,EACA,CAACE,EAAOC,IAAQ,CACd3D,GAAQ,KAAO,CAAC0D,EAAOC,CAAG,EAC1BC,GAAa,EACb3D,GAAiB,EAAI,EACrB4D,GAAe,CACjB,CACF,EAGEf,EAAI,QAAQ,MAAQ,YAAcrD,IAAcR,GAAOQ,EAAU,GACnEqE,GAAe7E,GAAOQ,EAAU,CAAC,EAE/BqD,EAAI,QAAQ,MAAQ,WAAWiB,GAAc,EAE7CjB,EAAI,QAAQ,MAAQ,SAAU,CAChCvC,GAAU,OAAO,EACjBqB,GAAoB,EAGpB,IAAMoC,EAAI7D,GAAS,IAAI,EAAE,IACrB6D,GAAGzD,GAAU,iBAAiByD,EAAE,CAAC,EAAGA,EAAE,CAAC,CAAC,CAC9C,CACF,CAAC,EAED,eAAeC,IAAsB,CAC/B,OAAQ,OAAe,sBAAyB,YACjD,OAAe,qBAAqB,EAEvC,MAAMC,GAAQ,MAAM,EACpBjF,GAAS,CAAC,EACVC,GAAiB,CAAC,EAClBO,GAAa,KACbC,GAAW,EACXE,GAAmB,KACnBJ,GAAmB,GACnBG,GAAY,GACZE,GAAc,GACdC,GAAc,GACdC,GAAc,YACdC,GAAQ,KAAO,CAAC,KAAM,IAAI,EAC1BA,GAAQ,KAAO,CAAC,KAAM,IAAI,EAC1BA,GAAQ,IAAM,CAAC,KAAM,IAAI,EACzBA,GAAQ,QAAQ,MAAM,EACtBA,GAAQ,KAAO,CAAC,EAChB2C,GAAQ,WAAW,CAAC,IAAK,IAAK,IAAK,GAAG,CAAC,EACvCA,GAAQ,OAAO,GAAG,EAClBwB,GAAa,EACbC,GAAc,EACdC,GAAa,EACbC,GAAc,EACdC,GAAe,EACX1B,GAAQ,iBAAiBA,GAAQ,gBAAgB,EACjDA,GAAQ,aAAaA,GAAQ,YAAY,EAC7CA,GAAQ,eAAe,EACnBtC,GAAU,WAAYA,GAAU,WAAW,EACtCA,GAAU,OAAOA,GAAU,MAAM,EAC1C,SAAS,iBAAiB,UAAU,EAAE,QAASyC,GAAM,CACnDA,EAAE,UAAU,OAAO,SAAWA,EAAkB,QAAQ,MAAQ,QAAQ,CAC1E,CAAC,EACD,SAAS,iBAAiB,cAAc,EAAE,QAASG,GAAM,CACvDA,EAAE,UAAU,OAAO,SAAUA,EAAE,KAAO,YAAY,CACpD,CAAC,EACDhD,GAAS,MAAM,EACf,IAAMqE,EAAiB,SAAS,eAAe,iBAAiB,EAC5DA,IAAgBA,EAAe,UAAY,IAC/C,SAAS,iBAAiB,iBAAiB,EAAE,QAAS1D,GAAOA,EAAG,OAAO,CAAC,EACpE,OAAOK,IAAoB,YAAYA,GAAgB,CAC7D,CAGA,eAAesD,IAAO,CAEpB,IAAIC,EAA6B,KAC3BC,EAAc,IAAI,QAAeC,GAAY,CACjDF,EAAc,OAAO,WAAWE,EAAS,GAAI,CAC/C,CAAC,EACD,GAAI,CACF,IAAMC,EAAkB,SAAS,MAC7B,QAAQ,IAAI,CACV,SAAS,MAAM,KAAK,iCAAiC,EAAE,MAAM,IAAM,CAAC,CAAC,EACrE,SAAS,MAAM,KACjB,CAAC,EACD,QAAQ,QAAQ,EACpB,MAAM,QAAQ,KAAK,CAACA,EAAiBF,CAAW,CAAC,CACnD,QAAE,CACID,IAAgB,MAAM,OAAO,aAAaA,CAAW,CAC3D,CACA,SAAS,KAAK,UAAU,OAAO,eAAe,EAC9C,IAAMI,EAAgB,SAAS,eAC7B,wBACF,EACIA,IACFA,EAAc,MAAQ3E,GAAS,IAAI,EAAE,SAAW,SAChD2E,EAAc,iBAAiB,SAAWxD,GAAM,CAC9C,IAAMyD,EAAYzD,EAAE,OAA6B,MAC3C0D,EAAS,IAAI,gBAAgB,OAAO,SAAS,MAAM,EACrDD,IAAa,SACfC,EAAO,OAAO,SAAS,EAEvBA,EAAO,IAAI,UAAWD,CAAQ,EAEhC,OAAO,SAAS,OAASC,EAAO,SAAS,CAC3C,CAAC,GAGH,IAAMC,EAAS,SAAS,eAAe,eAAe,EAChDC,EAAa,SAAS,eAAe,aAAa,EAClDC,EAAgB,SAAS,eAAe,gBAAgB,EACxDC,EAAc,SAAS,eAAe,qBAAqB,EAC3DC,EAAY,SAAS,eAAe,YAAY,EAChDC,EAAgBD,GAAW,cAAc,MAAM,EAEjDA,IACEC,IAAeA,EAAc,YAAc,uBAC/CD,EAAU,UAAU,OAAO,QAAQ,GAGrC,IAAME,EAAWpF,GAAS,IAAI,EAE9BqF,GAAa,CAACC,EAAaC,IAAkBC,GAAUF,EAAKC,IAAS,QAAU,QAAU,MAAM,CAAC,EAChGE,GACE,IAAM,CACJhC,GAAa,EACb3D,GAAiB,CACnB,EACC4B,GAAe,CACdgE,GAAYhE,CAAE,CAChB,CACF,EAEAiE,GAAY,CAACL,EAAaC,IAAkBC,GAAUF,EAAKC,IAAS,QAAU,QAAU,MAAM,CAAC,EAG/F7C,GAAQ,KACLhB,GAAOG,GAAYH,CAAE,EACtBkE,GACAC,GACA,CAACnE,EAAIC,IAAQ,CACPD,IAAOpC,GAAYc,GAAU,WAAWuB,CAAG,EAC1CvB,GAAU,WAAW,IAAI,CAChC,EACA0F,EACF,EACA1F,GAAU,KAAK2F,GAAmBzC,GAAoB0C,GAAerE,GAAQ,CAC3E3B,GAAS,MAAM,CAAE,UAAW2B,CAAI,CAAC,CACnC,CAAC,EAEDvB,GAAU,oBAAqB6F,GAAS,CAClCA,GACFxG,GAAmBwG,EAAK,OACpB3G,IAAYoD,GAAQ,mBAAmBpD,GAAY2G,EAAK,IAAKA,EAAK,MAAM,IAE5ExG,GAAmB,KACfH,IAAYoD,GAAQ,iBAAiBpD,EAAU,GAIrD,IAAM4G,EAAkBlG,GAAS,IAAI,EACjCkG,EAAgB,KAClB5C,GAAmB4C,EAAgB,IAAI,CAAC,EAAGA,EAAgB,IAAI,CAAC,EAAG9F,GAAU,SAAS,CAAC,CAC3F,CAAC,EAED+F,GAAWf,CAAQ,EAGnB,MAAMrB,GAAQ,OAAO,EACrB,MAAMD,GAAoB,EAG1B,GAAI,CAEF,IAAMsC,EAAU,MAAMrC,GAAQ,IAAI,UAAU,EACxCqC,GAAS5D,GAAQ,WAAW4D,CAAO,EAEvC,IAAMC,EAAM,MAAMtC,GAAQ,IAAI,KAAK,EAC/BsC,GAAK7D,GAAQ,OAAO6D,CAAG,EAE3B,IAAMC,EAAQ,MAAMvC,GAAQ,OAAO,EACnCuC,EAAM,KAAK,CAACC,EAAG1D,IAAM0D,EAAE,QAAU1D,EAAE,OAAO,EAEtCsC,IAAeA,EAAc,YAAc,aAAamB,EAAM,MAAM,cAExE,IAAME,EAA4B,CAAC,EACnC,QAAW1E,KAAKwE,EAAO,CACrB,IAAIG,EAAU,GACd,GAAI,CAAC3E,EAAE,QAAUA,EAAE,OAAO,OAAS,EAAG,CACpC,IAAMe,EAAI6D,GAAgB5E,EAAE,MAAM,EAC9Be,IACFf,EAAE,OAASe,EACX4D,EAAU,GAEd,CACI,CAAC3E,EAAE,kBAAoBA,EAAE,OAAO,OAAS,IAC3CA,EAAE,iBAAmB6E,GAAc7E,EAAE,OAAQ,EAAE,EAC/C2E,EAAU,IAERA,GAAS,MAAM1C,GAAQ,KAAKjC,CAAC,EAEjChD,GAAOgD,EAAE,EAAE,EAAIA,EACf0E,EAAa,KAAK1E,CAAC,CACrB,CACAY,GAAQ,UAAU8D,CAAY,EAC9B/C,GAAa,EAEb,IAAMmD,EACJxB,EAAS,OAASkB,EAAM,KAAMxE,GAAMA,EAAE,KAAOsD,EAAS,KAAK,EACvDA,EAAS,MACTkB,EAAM,OAAS,EACbA,EAAM,CAAC,EAAE,GACT,KAEFpB,EAAY,SAAS,eAAe,YAAY,EAGhD2B,EAAoBP,EAAM,KAAMxE,GAAMA,EAAE,KAAO8E,CAAS,EA0B9D,GAzBIC,IACF,MAAMC,GAAoBD,CAAiB,EAC3ChF,GAAYgF,EAAkB,GAAI,CAACzB,EAAS,OAAO,EAG/CA,EAAS,KAAO,MAAM,QAAQA,EAAS,GAAG,GAAKA,EAAS,IAAI,SAAW,GACzE,sBAAsB,IAAM,CAC1B,sBAAsB,IAAM,CAC1BhF,GAAU,iBAAiBgF,EAAS,IAAK,CAAC,EAAGA,EAAS,IAAK,CAAC,CAAC,CAC/D,CAAC,CACH,CAAC,EAECA,EAAS,YAAc,QAAaA,EAAS,YAAc,MAC7D,sBAAsB,IAAM,CAC1B,sBAAsB,IAAM,CAC1BhF,GAAU,YAAYgF,EAAS,SAAU,CAC3C,CAAC,CACH,CAAC,GAKDF,GAAWA,EAAU,UAAU,IAAI,QAAQ,EAG3CoB,EAAM,QAAUO,EAAoB,EAAI,GAAI,CAC1C3B,IACEC,IAAeA,EAAc,YAAc,qBAC/CD,EAAU,UAAU,OAAO,QAAQ,GAGrC,IAAM6B,EAAYT,EAAM,OAAQxE,GAAMA,EAAE,KAAO8E,CAAS,EACpDI,EAAQ,EAENC,EAAgB,SAAY,CAEhC,IAAMzD,EAAM,KAAK,IAAIwD,EAAQ,EAAWD,EAAU,MAAM,EAExD,KAAOC,EAAQxD,EAAKwD,IAAS,MAAMF,GAAoBC,EAAUC,CAAK,CAAC,EAEnEA,EAAQD,EAAU,OACpB,sBAAsBE,CAAa,GAE/B/B,GAAWA,EAAU,UAAU,IAAI,QAAQ,EAC/CzB,GAAa,EACTnE,IAAcR,GAAOQ,EAAU,GACjC6D,GAAgBrE,GAAOQ,EAAU,EAAG,OAAO,OAAOR,EAAM,EAAG,CAACsE,GAASC,KAAU,CAC7ExB,GAAYuB,GAAS,EAAI,EACrBC,KACFjD,GAAU,iBAAiBiD,GAAM,CAAC,EAAGA,GAAM,CAAC,CAAC,EAC7CC,GAAmBD,GAAM,CAAC,EAAGA,GAAM,CAAC,EAAG,OAAQ,EAAI,EAEvD,CAAC,EAGCiD,EAAM,QAAU,CAAClB,EAAS,SAAS1C,GAAQ,OAAO,EAE1D,EAEA,sBAAsBuE,CAAa,CACrC,MACExD,GAAa,EACT6C,EAAM,QAAU,CAAClB,EAAS,SAAS1C,GAAQ,OAAO,CAE1D,OAASvB,EAAG,CACV,QAAQ,KAAK,+BAAgCA,CAAC,CAChD,CAGA+F,GAAiB,EACjBC,GAAmB,EACnBC,GAAwB,EACxB3F,GAAoB,EAGpB,SAAS,eAAe,kBAAkB,GAAG,iBAAiB,QAAUN,GAAM,CAC5E,IAAMwB,EAAOxB,EAAE,OAAuB,QAAQ,SAAS,EAClDwB,IACL,SAAS,iBAAiB,SAAS,EAAE,QAASE,GAAMA,EAAE,UAAU,OAAO,QAAQ,CAAC,EAChFF,EAAI,UAAU,IAAI,QAAQ,EACtBA,EAAI,QAAQ,QACdD,GAAQ,cAAcC,EAAI,QAAQ,KAAK,EACvC3C,GAAS,MAAM,CAAE,IAAK2C,EAAI,QAAQ,KAAM,CAAC,GAE7C,CAAC,EAGD,SAAS,eAAe,aAAa,GAAG,iBAAiB,QAAS,IAAMD,GAAQ,OAAO,CAAC,EAGxF,SAAS,eAAe,eAAe,GAAG,iBAAiB,QAAS2E,EAAQ,EAG5E,SAAS,eAAe,cAAc,GAAG,iBAAiB,QAAUlG,GAAM,CACxEzB,GAAeyB,EAAE,OAA4B,MAC7CsC,GAAa,EACbzD,GAAS,MAAM,CAAE,EAAGN,IAAe,IAAK,CAAC,CAC3C,CAAC,EAED,SAAS,eAAe,kBAAkB,GAAG,iBAAiB,QAAUyB,GAAM,CAC5ExB,GAAc,CAACA,GACdwB,EAAE,OAAuB,UAAU,OAAO,SAAUxB,EAAW,EAChE8D,GAAa,EACbzD,GAAS,MAAM,CAAE,GAAIL,GAAc,EAAI,IAAK,CAAC,CAC/C,CAAC,EAGD,SAAS,eAAe,eAAe,GAAG,iBAAiB,QAAUwB,GAAM,CACzEA,EAAE,gBAAgB,EAClBV,GAAaU,EAAE,aAA4B,CAC7C,CAAC,EAGD,SAAS,eAAe,iBAAiB,GAAG,iBAAiB,QAAUA,GAAM,CAC3EA,EAAE,gBAAgB,EAClBC,GAAeD,EAAE,aAA4B,CAC/C,CAAC,EAGD,IAAMmG,EAAe,CAACC,EAAgB/F,IAA6B,CAC7DA,GAAMA,EAAK,UAAU,OAAO,QAAQ,EACxCpB,GAAU,aAAamH,CAAM,EAC7BrH,GAAiB,CACnB,EAEA,SAAS,eAAe,cAAc,GAAG,iBAAiB,QAAUiB,GAAM,CACxE,IAAMK,EAAQL,EAAE,OAAuB,QAAQ,cAAc,EAC7D,GAAIK,EAAM,CACR,IAAM+F,EAAS/F,EAAK,QAAQ,OACxB+F,IACFD,EAAaC,EAAQ/F,CAAI,EAGrBpB,GAAU,iBAAiB,EAAE,IAAImH,CAAM,GACxB,SAAS,cAAc,2BAA2BA,CAAM,IAAI,GACnE,eAAe,CAAE,SAAU,QAAS,CAAC,EAGrD,CACF,CAAC,EAGD,SAAS,eAAe,aAAa,GAAG,iBAAiB,QAAUpG,GAAM,CACvE,IAAMwB,EAAOxB,EAAE,OAAuB,QAAQ,UAAU,EACxD,GAAI,CAACwB,EAAK,OACV,IAAM6E,EAAO7E,EAAI,QAAQ,KACzBvC,GAAU,SAASoH,CAAI,EACvB,SACG,iBAAiB,uBAAuB,EACxC,QAAS3E,GAAMA,EAAE,UAAU,OAAO,SAAUA,IAAMF,CAAG,CAAC,EACzD3C,GAAS,MAAM,CAAE,MAAOwH,CAAK,CAAC,CAChC,CAAC,EAGD,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAUrG,GAAM,CAC1E3B,GAAY,CAACA,GACZ2B,EAAE,cAA8B,UAAU,OAAO,SAAU3B,EAAS,CACvE,CAAC,EAGD,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAS,IAAM,CACzEY,GAAU,UAAU,EACpBsC,GAAQ,eAAe,CACzB,CAAC,EAGD+E,GAAa,EAGb,SAAS,eAAe,YAAY,GAAG,iBAAiB,SAAWtG,GAAM,CACvEuG,GAAY,MAAM,KAAMvG,EAAE,OAA4B,OAAS,CAAC,CAAC,CAAC,EACjEA,EAAE,OAA4B,MAAQ,EACzC,CAAC,EACD,SAAS,eAAe,cAAc,GAAG,iBAAiB,SAAWA,GAAM,CACzEuG,GAAY,MAAM,KAAMvG,EAAE,OAA4B,OAAS,CAAC,CAAC,CAAC,EACjEA,EAAE,OAA4B,MAAQ,EACzC,CAAC,EAGD,SAAS,eAAe,oBAAoB,GAAG,iBAAiB,QAAS,IAAM,CAC7E,IAAM4B,EAAQ,SAAS,eAAe,cAAc,EAChDA,IACFA,EAAM,UAAU,OAAO,QAAQ,EAC/B,SACG,eAAe,oBAAoB,GAClC,UAAU,OAAO,SAAU,CAACA,EAAM,UAAU,SAAS,QAAQ,CAAC,EAEtE,CAAC,EAED,IAAM4E,EAAgB,CAACpC,EAA+B5D,EAAaR,IAAa,CAC9E,IAAMyG,EAAOzG,EAAE,OAA4B,MAC1CtB,GAAQ0F,CAAI,EAAU5D,CAAG,EAAIiG,IAAQ,GAAK,KAAOA,EAClDnE,GAAa,EACb3D,GAAiB,CACnB,EAEA,SACG,eAAe,mBAAmB,GACjC,iBAAiB,SAAWqB,GAAMwG,EAAc,OAAQ,EAAGxG,CAAC,CAAC,EACjE,SACG,eAAe,iBAAiB,GAC/B,iBAAiB,SAAWA,GAAMwG,EAAc,OAAQ,EAAGxG,CAAC,CAAC,EACjE,SACG,eAAe,iBAAiB,GAC/B,iBAAiB,QAAUA,GAAMwG,EAAc,OAAQ,EAAGxG,CAAC,CAAC,EAChE,SACG,eAAe,iBAAiB,GAC/B,iBAAiB,QAAUA,GAAMwG,EAAc,OAAQ,EAAGxG,CAAC,CAAC,EAChE,SACG,eAAe,gBAAgB,GAC9B,iBAAiB,QAAUA,GAAMwG,EAAc,MAAO,EAAGxG,CAAC,CAAC,EAC/D,SACG,eAAe,gBAAgB,GAC9B,iBAAiB,QAAUA,GAAMwG,EAAc,MAAO,EAAGxG,CAAC,CAAC,EAE/D,IAAM0G,EAAY,SAAS,eAAe,kBAAkB,EACtDC,EAAkB,SAAS,eAAe,wBAAwB,EACxED,GAAW,iBAAiB,QAAU1G,GAAM,CAE1C,GADAA,EAAE,gBAAgB,EACd2G,EAAiB,CACnB,IAAMC,EAAYD,EAAgB,MAAM,UAAY,QACpDA,EAAgB,MAAM,QAAUC,EAAY,OAAS,OACvD,CACF,CAAC,EAED,SAAS,iBAAiB,QAAU5G,GAAM,CACpC2G,GAAmBA,EAAgB,MAAM,UAAY,SACnD,CAACA,EAAgB,SAAS3G,EAAE,MAAc,GAAKA,EAAE,SAAW0G,IAC9DC,EAAgB,MAAM,QAAU,OAEtC,CAAC,EAED,SAAS,eAAe,wBAAwB,GAAG,iBAAiB,QAAU3G,GAAM,CAClF,IAAM6G,EAAS7G,EAAE,OACXwB,EAAMqF,EAAO,QAAQ,cAAc,EACzC,GAAIrF,EAAK,CACP,IAAMsF,EAAiBtF,EAAoB,QAAQ,OAAS,KAC5D9C,GAAQ,MAAQA,GAAQ,QAAUoI,EAAgB,KAAOA,EACzDxE,GAAa,EACb3D,GAAiB,EACjB4D,GAAe,EAEXsE,EAAO,QAAQ,gBAAgB,GAC7BF,IAAiBA,EAAgB,MAAM,QAAU,OAEzD,CACF,CAAC,EAED,SAAS,eAAe,gBAAgB,GAAG,iBAAiB,QAAU3G,GAAM,CAC1E,IAAMwB,EAAOxB,EAAE,OAAuB,QAAQ,YAAY,EAC1D,GAAI,CAACwB,EAAK,OACV,IAAMuF,EAAIvF,EAAI,QAAQ,OAClB9C,GAAQ,QAAQ,IAAIqI,CAAC,EAAGrI,GAAQ,QAAQ,OAAOqI,CAAC,EAC/CrI,GAAQ,QAAQ,IAAIqI,CAAC,EAC1BxE,GAAe,EACfD,GAAa,EACb3D,GAAiB,CACnB,CAAC,EAED,SAAS,eAAe,mBAAmB,GAAG,iBAAiB,QAAS,IAAM,CAC5ED,GAAU,CACR,KAAM,CAAC,KAAM,IAAI,EACjB,KAAM,CAAC,KAAM,IAAI,EACjB,IAAK,CAAC,KAAM,IAAI,EAChB,QAAS,IAAI,IACb,KAAM,CAAC,EACP,MAAO,IACT,EACA6D,GAAe,EACfD,GAAa,EACb3D,GAAiB,CACnB,CAAC,EAED,SAAS,eAAe,aAAa,GAAG,iBAAiB,QAAUqB,GAAM,CACvE,IAAMyG,EAAOzG,EAAE,OAA4B,MAC3CtB,GAAQ,KAAO+H,EACZ,MAAM,GAAG,EACT,IAAK/D,GAAMA,EAAE,KAAK,EAAE,YAAY,CAAC,EACjC,OAAQA,GAAM,CAAC,CAACA,CAAC,EACpBJ,GAAa,EACb3D,GAAiB,CACnB,CAAC,EAGD,SAAS,iBAAiB,UAAYqB,GAAM,CACtCA,EAAE,MAAQ,WACZuB,GAAQ,WAAW,EACnBA,GAAQ,aAAa,EAErB,SACG,iBACC,4EACF,EACC,QAAS/B,GAAOA,EAAG,OAAO,CAAC,EAElC,CAAC,EAGD,OAAO,iBAAiB,SAAU,IAAM,CACtCP,GAAU,OAAO,EACjB+H,GAAe,EACfzF,GAAQ,iBAAiB,EACzBjB,GAAoB,CACtB,CAAC,EAGD,OAAO,iBAAiB,WAAY,IAAM,CACxCzB,GAAS,QAAQ,EACjBmG,GAAWnG,GAAS,IAAI,CAAC,CAC3B,CAAC,EAEDoI,GAAsB,EACtB,MAAMC,GAAsB,EAI5B,IAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,GAAK,eACbA,EAAQ,aAAa,aAAc,MAAM,EACzCA,EAAQ,MAAM,QAAU,OACxB,SAAS,KAAK,YAAYA,CAAO,EAEjC,IAAMC,EAAe,SAAS,cAAc,KAAK,EACjDA,EAAa,GAAK,aAClBA,EAAa,aAAa,aAAc,MAAM,EAC9CA,EAAa,MAAM,QAAU,OAC7B,SAAS,KAAK,YAAYA,CAAY,CACxC,CAEA,IAAIC,GAOO,KAEX,eAAeH,IAEb,CACA,GAAIG,GAA4B,OAAOA,GACvC,GAAI,CAEF,IAAMC,EAAsB,MADP,MAAM,MAAM,2BAA2B,GACb,KAAK,EAC9CC,EAAU,IAAI,YACpBF,GAA6B,MAAM,QAAQ,IACzCC,EAAU,IAAI,MAAOE,GAAS,CAE5B,IAAIC,EAAM,MADO,MAAM,MAAM,eAAeD,CAAI,EAAE,GACzB,YAAY,EACjCE,EAAYF,EAChB,GAAIA,EAAK,YAAY,EAAE,SAAS,KAAK,EAAG,CACtCE,EAAYF,EAAK,MAAM,EAAG,EAAE,EAC5B,IAAMG,EAAQ,IAAI,WAAWF,CAAG,EAChC,GAAIE,EAAM,QAAU,GAAKA,EAAM,CAAC,IAAM,IAAQA,EAAM,CAAC,IAAM,IAAM,CAC/D,IAAMC,EAAK,IAAI,oBAAoB,MAAM,EACnCC,EAAS,IAAI,KAAK,CAACJ,CAAG,CAAC,EAAE,OAAO,EAAE,YAAYG,CAAE,EACtDH,EAAM,MAAM,IAAI,SAASI,CAAM,EAAE,YAAY,CAC/C,CACF,CACA,IAAMC,EAAOJ,EAAU,YAAY,EAAE,SAAS,MAAM,EAAI,OAAYH,EAAQ,OAAOE,CAAG,EAChFM,EAAO,IAAI,KAAK,CAACN,CAAG,EAAGC,EAAW,CAAE,KAAM,0BAA2B,CAAC,EAC5E,OAACK,EAAa,KAAON,EACjBK,IAAS,SAAYC,EAAa,MAAQD,GACvC,CAAE,UAAAJ,EAAW,IAAAD,EAAK,KAAAK,EAAM,KAAAC,CAAK,CACtC,CAAC,CACH,EAEA,IAAIC,EAAkB,KACtB,QAAWxH,IAAO,CAAC,EAAG,EAAG,CAAC,EACxB,GAAI6G,GAA2B7G,CAAG,EAAG,CACnC,IAAMyH,EAAS,MAAM5G,GAAQ,UAAUgG,GAA2B7G,CAAG,EAAE,IAAI,EACvEA,IAAQ,IAAGwH,EAAaC,EAC9B,CAEF,GAAID,EAAY,CACd,IAAME,EAAUF,EAAW,OAAO,MAAM,EAAG,IAAI,EACzCG,EAAuB,CAC3B,GAAGH,EACH,GAAI,SACJ,SAAU,aACV,SAAU,KACV,OAAQE,EACR,OAAQ3C,GAAgB2C,CAAO,GAAK,OACpC,iBAAkB1C,GAAc0C,EAAS,EAAE,EAC3C,MAAO7G,GAAQ,aAAa6G,CAAO,EACnC,QAAS,WACT,QAAS,GACT,MAAOzK,GAAa,CAAC,CACvB,EACM2K,EAAwB,CAC5B,GAAGD,EACH,GAAI,WACJ,SAAU,cACV,QAAS,WACT,MAAO1K,GAAa,CAAC,CACvB,EACM4K,EAAW,CAACF,EAAWC,CAAU,EACvC/G,GAAQ,qBAAqB8G,CAAS,EACtC9G,GAAQ,qBAAqB+G,CAAU,EACvCD,EAAU,MAAM,SAAW9G,GAAQ,qBAAqB8G,EAAU,MAAM,EACxEC,EAAW,MAAM,SAAW/G,GAAQ,qBAAqB+G,EAAW,MAAM,EAC1E/G,GAAQ,aAAagH,CAAQ,EAC7B9G,GAAQ,UAAU8G,CAAQ,EAC1BpJ,GAAU,UAAUkJ,EAAWE,EAAU,EAAK,EAC9CpJ,GAAU,iBAAiB,GAAI,GAAI,EAAI,EACvCA,GAAU,YAAY,GAAI,EAAI,EAC9BA,GAAU,UAAU,QAAS,EAAI,EACjCA,GAAU,UAAU,QAAS,EAAK,EAClCA,GAAU,SAAS,UAAU,EAC7BA,GAAU,SAAS,MAAM,EACzBA,GAAU,iBAAiB,CAAC,YAAa,QAAS,OAAO,CAAC,EAC1DA,GAAU,0BAA0BoJ,EAAU,GAAI,EAAE,EACpD/G,GAAe6G,EAAWE,EAAU,CAAC,GAAI,EAAE,CAAC,EAC5C/G,GAAe6G,EAAWE,CAAQ,EAClCvG,GAAcqG,EAAW,CAAC,EAAGE,CAAQ,EACrC7F,GAAe2F,EAAWE,CAAQ,EAClCC,GAAiB,EAAI,EACrBA,GAAiB,EAAK,EACtBC,GAA0B,EAAG,EAC7B/F,GAAe6F,EAAUA,CAAQ,EACjCrG,GAAgBmG,EAAWE,CAAQ,EACnCG,GAAqB,OAAO,EAC5BA,GAAqB,MAAM,EAC3BC,GAAkB,IAAI,EACtBA,GAAkB,KAAK,EACvBC,GAA2B,EAAE,EAC7BA,GAA2B,IAAI,EAC/BC,GAAwBN,CAAQ,EAChCO,GAAa,WAAY,EAAI,EAC7B,MAAMjG,GAAoB,EACrB,SAAS,KAAK,aACnB,MAAM,IAAI,QAASkG,GAAM,OAAO,WAAWA,EAAG,CAAC,CAAC,CAClD,MAAW,OAAQ,OAAe,sBAAyB,YACxD,OAAe,qBAAqB,EAEvC,OAAOxB,EACT,MAAQ,CACN,MAAO,CAAC,CACV,CACF,CAEA,SAASJ,IAAwB,CAC/B,IAAM6B,EAAU,SAAS,eAAe,eAAe,EACjDC,EAAc,SAAS,eAAe,mBAAmB,EACzDC,EAAc,SAAS,eAAe,mBAAmB,EACzDC,EAAa,SAAS,eAAe,kBAAkB,EACvDC,EAAe,SAAS,eAAe,oBAAoB,EAC3DC,EAAe,SAAS,eAAe,oBAAoB,EAC3DC,EAAa,SAAS,eAAe,kBAAkB,EAE7D,SAASC,EAAYC,EAAiB,CACpC,SAAS,iBAAiB,UAAU,EAAE,QAAS5H,GAAM,CACnDA,EAAE,UAAU,OAAO,SAAWA,EAAkB,QAAQ,MAAQ4H,CAAO,CACzE,CAAC,EACD,SAAS,iBAAiB,cAAc,EAAE,QAASzH,GAAM,CACvDA,EAAE,UAAU,OAAO,SAAUA,EAAE,KAAO,OAAOyH,CAAO,EAAE,CACxD,CAAC,EACDzK,GAAS,MAAM,CAAE,IAAKyK,CAAQ,EAAG,EAAK,CACxC,CAEAR,GAAS,iBAAiB,QAAS,SAAY,CAC7C,GAAI,CACE,OAAO,KAAKnL,EAAM,EAAE,OAAS,GAAKC,GAAe,OAAS,GAAKO,KAAe,MAChF,MAAMyE,GAAQ,OAAO,EACrB,MAAMD,GAAoB,GACjB,OAAQ,OAAe,sBAAyB,YACxD,OAAe,qBAAqB,EAGvC,IAAM4G,GADW,MAAMrC,GAAsB,GACR,IAAKnG,GAAMA,EAAE,IAAI,EACtD,MAAMwF,GAAYgD,CAAW,EAC7B,IAAMC,EAAY,OAAO,OAAO7L,EAAM,EACtC0D,GAAQ,aAAamI,CAAS,EAG9B,QAAWC,IAAY,CAAC,YAAa,WAAY,WAAY,WAAW,EACtEhL,GAAcgL,EACd5J,GAAgB,EAElBnB,GAAQ,MAAQ,UAChB4D,GAAa,EACb5D,GAAQ,MAAQ,KAChBA,GAAQ,QAAQ,IAAI,OAAO,EAC3B4D,GAAa,EACb5D,GAAQ,QAAQ,MAAM,EACtBH,GAAc,SACd+D,GAAa,EACb/D,GAAc,GACd+D,GAAa,EAET,CAACnE,IAAcqL,EAAU,OAAS,GAAG9I,GAAY8I,EAAU,CAAC,EAAE,EAAE,CACtE,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,yBAAyB,CAAC,CACjE,CACF,CAAC,EAEDT,GAAa,iBAAiB,QAAS,IAAM,CAC3C,GAAI,CACF,IAAMS,EAAY,OAAO,OAAO7L,EAAM,EACtC0L,EAAY,QAAQ,EAChB,CAAClL,IAAcqL,EAAU,OAAS,GACpC9I,GAAY8I,EAAU,CAAC,EAAE,GAAI,EAAK,EAEpC,IAAME,EAAmBzK,GAAU,oBAAoB,EACjD0K,EAAa,CACjB,CAAC,YAAa,QAAS,QAAS,IAAI,EACpC,CAAC,YAAa,QAAS,OAAO,CAChC,EACA,QAAWC,KAAQD,EAAY,CAC7B,IAAME,EAAWD,EAAK,OAAQ7C,GAAM2C,EAAiB,IAAI3C,CAAC,CAAC,EACvD8C,EAAS,OAAS,IACpB,SAAS,iBAAiB,4BAA4B,EAAE,QAASrK,GAAO,CACtE,IAAM4G,EAAU5G,EAAmB,QAAQ,OACvC4G,GAAQ5G,EAAG,UAAU,OAAO,SAAUqK,EAAS,SAASzD,CAAM,CAAC,CACrE,CAAC,EACD9F,GAAoB,EACpBrB,GAAU,iBAAiB4K,CAAQ,EAEvC,CAGA5K,GAAU,UAAU,QAAS,GAAM,EAAI,EACvCA,GAAU,eAAe,QAAS,EAAI,EACtCA,GAAU,eAAe,KAAM,EAAI,EACnCA,GAAU,SAAS,UAAU,EAC7BA,GAAU,UAAU,QAAS,GAAO,EAAI,EACxCA,GAAU,SAAS,MAAM,EAGzB,IAAM6K,EAAuC,CAC3C,CAAC,EAAG,IAAK,GAAG,EACZ,CAAC,IAAK,IAAK,GAAG,CAChB,EACA,OAAW,CAACC,EAAUC,EAAQC,CAAS,IAAKH,EAC1C7K,GAAU,iBAAiB8K,EAAUC,EAAQ,EAAI,EACjD/K,GAAU,YAAYgL,EAAW,EAAI,EACrChL,GAAU,0BAA0BuK,EAAWO,EAAUC,CAAM,EAC/D7H,GAAmB4H,EAAUC,EAAQ/K,GAAU,SAAS,EAAG,EAAK,CAEpE,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,mBAAmB,CAAC,CAC3D,CACF,CAAC,EAED+J,GAAa,iBAAiB,QAAS,IAAM,CAC3C,GAAI,CACF,IAAMQ,EAAY,OAAO,OAAO7L,EAAM,EACtC6L,EAAU,QAAS7I,GAAMU,GAAQ,qBAAqBV,CAAC,CAAC,EACxD0I,EAAY,UAAU,EACtB,IAAMa,EAAgB/L,IAAcR,GAAOQ,EAAU,GAAMqL,EAAU,CAAC,GAAK,KAE3E,QAAWW,IAAQ,CAAC,EAAG,EAAG,CAAC,EAAG,CAC5B,IAAMC,EAAMZ,EAAUW,CAAI,EACtBC,IACF9I,GAAe8I,EAAKZ,EAAW,CAAC,EAAG,GAAG,CAAC,EACvClI,GAAe8I,EAAKZ,EAAW,CAAC,IAAK,IAAI,CAAC,EAC1ClI,GAAe8I,EAAKZ,EAAW,IAAI,EAEvC,CACIA,EAAU,CAAC,GACblI,GAAekI,EAAU,CAAC,EAAGA,EAAW,CAAC,IAAK,GAAG,CAAC,EAEhDU,IACF5I,GAAe4I,EAAcV,EAAW,CAAC,EAAG,GAAG,CAAC,EAChDlI,GAAe4I,EAAcV,EAAW,CAAC,IAAK,GAAG,CAAC,EAClDlI,GAAe4I,EAAcV,EAAW,CAAC,IAAK,IAAI,CAAC,GAErDlI,GAAe4I,EAAcV,EAAW,IAAI,CAC9C,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,mBAAmB,CAAC,CAC3D,CACF,CAAC,EAEDP,GAAY,iBAAiB,QAAS,IAAM,CAC1C,GAAI,CACF,IAAMO,EAAY,OAAO,OAAO7L,EAAM,EACtC0L,EAAY,SAAS,EACrB,IAAMgB,EAAatI,GAAc,EAC3BmI,EAAgB/L,IAAcR,GAAOQ,EAAU,GAAMqL,EAAU,CAAC,GAAK,KAE3E,QAASc,EAAI,EAAGA,EAAId,EAAU,OAAQc,IACpCxI,GAAc0H,EAAUc,CAAC,EAAGD,EAAYb,EAAW,IAAI,EAErDU,IACFpI,GAAcoI,EAAcG,EAAYb,EAAW,CAAC,EAAG,GAAG,CAAC,EAC3D1H,GAAcoI,EAAcG,EAAYb,EAAW,CAAC,IAAK,GAAG,CAAC,EAC7D1H,GAAcoI,EAAcG,EAAYb,EAAW,CAAC,IAAK,IAAI,CAAC,GAE5DA,EAAU,CAAC,GACb1H,GAAc0H,EAAU,CAAC,EAAGa,EAAYb,EAAW,CAAC,IAAK,GAAG,CAAC,EAE3DA,EAAU,CAAC,GACb1H,GAAc0H,EAAU,CAAC,EAAGa,EAAYb,EAAW,CAAC,IAAK,GAAG,CAAC,EAE3DA,EAAU,CAAC,GACb1H,GAAc0H,EAAU,CAAC,EAAGa,EAAYb,EAAW,CAAC,IAAK,GAAG,CAAC,EAE3DA,EAAU,CAAC,IACb1H,GAAc0H,EAAU,CAAC,EAAGa,EAAYb,EAAW,CAAC,EAAG,GAAG,CAAC,EAC3D1H,GAAc0H,EAAU,CAAC,EAAGa,EAAYb,EAAW,CAAC,IAAK,IAAI,CAAC,GAE5DA,EAAU,CAAC,GACb1H,GAAc0H,EAAU,CAAC,EAAGa,EAAYb,EAAW,CAAC,IAAK,GAAG,CAAC,EAE/D1H,GAAcoI,EAAcG,EAAYb,EAAW,IAAI,CACzD,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,kBAAkB,CAAC,CAC1D,CACF,CAAC,EAEDN,GAAc,iBAAiB,QAAS,IAAM,CAC5C,GAAI,CACF,IAAMM,EAAY,OAAO,OAAO7L,EAAM,EACtC,GAAI6L,EAAU,QAAU,EAAG,CACzBH,EAAY,UAAU,EAEtBkB,GAAmB,WAAY,WAAW,EAC1C/H,GAAegH,EAAU,CAAC,EAAGA,CAAS,EACtC,QAAWgB,IAAQ,CAAC,IAAM,GAAK,IAAM,CAAG,EACtCjC,GAA0BiC,CAAI,EAEhClC,GAAiB,EAAI,EACrBC,GAA0B,EAAG,EAC7BD,GAAiB,EAAK,EACtBiC,GAAmB,QAAS,IAAI,EAChC,QAAWC,IAAQ,CAAC,GAAK,EAAG,EAC1BjC,GAA0BiC,CAAI,EAI5BhB,EAAU,QAAU,GACtBhH,GAAe,CAACgH,EAAU,CAAC,EAAGA,EAAU,CAAC,CAAC,EAAGA,CAAS,EAEpDA,EAAU,QAAU,GACtBhH,GAAegH,EAAWA,CAAS,EAErC,IAAMiB,EAAc,CAACjB,EAAU,CAAC,EAAGA,EAAU,CAAC,CAAC,EAC/ChH,GAAeiI,EAAajB,CAAS,CACvC,CACF,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,oBAAoB,CAAC,CAC5D,CACF,CAAC,EAEDL,GAAc,iBAAiB,QAAS,IAAM,CAC5C,GAAI,CACF,IAAMK,EAAY,OAAO,OAAO7L,EAAM,EACtC0L,EAAY,WAAW,EACvB,IAAMa,EAAgB/L,IAAcR,GAAOQ,EAAU,GAAMqL,EAAU,CAAC,GAAK,KACrEkB,EAAa,CAACzI,EAAiBC,IAAmC,CACtExB,GAAYuB,EAAS,EAAI,EACrBC,IACFjD,GAAU,iBAAiBiD,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC7CC,GAAmBD,EAAM,CAAC,EAAGA,EAAM,CAAC,EAAG,OAAQ,EAAI,EAEvD,EAGMyI,EAAY,CAACnB,EAAU,CAAC,GAAKU,EAAcV,EAAU,CAAC,GAAKU,EAAcA,CAAY,EAC3F,QAAWU,KAAUD,EAAW,CAC9B3I,GAAgB4I,EAAQpB,EAAWkB,CAAU,EAC7ClC,GAAqB,OAAO,EAC5B,QAAWqC,IAAO,CAAC,KAAM,KAAM,KAAM,KAAM,KAAK,EAC9CpC,GAAkBoC,CAAG,EAEvBrC,GAAqB,MAAM,EAC3B,QAAW/H,IAAO,CAAC,EAAG,GAAI,GAAI,IAAK,KAAM,IAAI,EAC3CiI,GAA2BjI,CAAG,CAElC,CACF,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,oBAAoB,CAAC,CAC5D,CACF,CAAC,EAED2I,GAAY,iBAAiB,QAAS,IAAM,CAC1C,GAAI,CACF,IAAMI,EAAY,OAAO,OAAO7L,EAAM,EACtC0L,EAAY,SAAS,EACrBV,GAAwBa,CAAS,EACjC,IAAMsB,EAAYC,GAAsB,EACxC,QAAWC,KAAOF,EAChBlC,GAAaoC,EAAK,EAAI,EAExBpC,GAAa,WAAY,EAAI,CAC/B,QAAE,CACA,OAAO,cAAc,IAAI,YAAY,kBAAkB,CAAC,CAC1D,CACF,CAAC,EAEA,OAAe,eAAiB,CAC/B,kBAAmB,IAAM,SAAS,eAAe,eAAe,GAAG,MAAM,EACzE,uBAAwB,IAAM,SAAS,eAAe,mBAAmB,GAAG,MAAM,EAClF,gBAAiB,IAAM,SAAS,eAAe,mBAAmB,GAAG,MAAM,EAC3E,eAAgB,IAAM,SAAS,eAAe,kBAAkB,GAAG,MAAM,EACzE,wBAAyB,IAAM,SAAS,eAAe,oBAAoB,GAAG,MAAM,EACpF,wBAAyB,IAAM,SAAS,eAAe,oBAAoB,GAAG,MAAM,EACpF,eAAgB,IAAM,SAAS,eAAe,kBAAkB,GAAG,MAAM,CAC3E,CACF,CAEA,eAAejD,GAAoB,EAAc,CAE/C,IAAMsF,EAAoB,EAAE,MAAM,WAAa,OAAO,OAAO,EAAE,MAAM,UAAU,EAAI,CAAC,EAE9EC,EACJ,EAAE,OAAO,OAAS,IAAM,EAAE,OAAO,CAAC,EAAE,QAAU,QAAa,EAAE,OAAO,CAAC,EAAE,WAAa,SAGpFA,GACA,CAAC,EAAE,MAAM,YACT,CAAC,EAAE,MAAM,SACT,CAAC,EAAE,MAAM,SACT,EAAE,MAAM,SAAW,QACnB,EAAE,MAAM,aAAe,QACvB,EAAE,MAAM,UAAY,QACnBD,EAAkB,OAAS,GAAK,OAAQA,EAAkB,CAAC,GAAc,WACxE,EAAE,MAAM,UAAY,GAAK,MAAQ,KAAQ,EAAE,MAAM,YAAc,CAAC,EAAE,MAAM,WAAW,KAAK,KAGtFC,IAAa,EAAE,OAAS7J,GAAQ,aAAa,EAAE,MAAM,GACzD,EAAE,MAAQA,GAAQ,aAAa,EAAE,MAAM,EACvC,MAAMuB,GAAQ,KAAK,CAAC,GAGtBjF,GAAO,EAAE,EAAE,EAAI,EACfS,GAAW,KAAK,IAAIA,GAAUX,GAAa,QAAQ,EAAE,KAAK,EAAI,CAAC,EAC/D8D,GAAQ,SAAS,CAAC,EAClBA,GAAQ,gBAAgB,EAAE,GAAI,EAAE,SAAW,CAAC,EAAE,SAAS,EACvD1B,GAAgB,CAClB,CAEA,SAASkG,IAAmB,CAC1B,IAAMoF,EAAS,SAAS,eAAe,eAAe,EAChDvJ,EAAQ,SAAS,eAAe,aAAa,EACnD,GAAI,CAACuJ,GAAU,CAACvJ,EAAO,OAEvB,IAAIwJ,EAAa,GAEjBD,EAAO,iBAAiB,YAAa,IAAM,CACzCC,EAAa,GACb,SAAS,KAAK,MAAM,OAAS,WAC/B,CAAC,EAED,SAAS,iBAAiB,YAAc,GAAM,CAC5C,GAAI,CAACA,EAAY,OACjB,IAAMC,EAAI,OAAO,YAAc,EAAE,QAC3BC,EAAW,KAAK,IAAI,IAAK,KAAK,IAAI,OAAO,YAAc,IAAKD,CAAC,CAAC,EACpEzJ,EAAM,MAAM,OAAS,GAAG0J,CAAQ,KAChCrM,GAAU,OAAO,EACjB+H,GAAe,EACfzF,GAAQ,iBAAiB,CAC3B,CAAC,EAED,SAAS,iBAAiB,UAAW,IAAM,CACpC6J,IACLA,EAAa,GACb,SAAS,KAAK,MAAM,OAAS,GAC/B,CAAC,CACH,CAEA,SAASpF,IAAqB,CAC5B,IAAMuF,EAAU,SAAS,eAAe,iBAAiB,EACnDC,EAAU,SAAS,eAAe,SAAS,EACjD,GAAI,CAACD,GAAW,CAACC,EAAS,OAE1B,IAAIJ,EAAa,GAEjBG,EAAQ,iBAAiB,YAAa,IAAM,CAC1CH,EAAa,GACbG,EAAQ,UAAU,IAAI,UAAU,EAChC,SAAS,KAAK,UAAU,IAAI,kBAAkB,CAChD,CAAC,EAED,SAAS,iBAAiB,YAAc,GAAM,CAC5C,GAAI,CAACH,EAAY,OACjB,IAAMK,EAAI,EAAE,QACNC,EAAW,KAAK,IAAI,IAAK,KAAK,IAAI,IAAKD,CAAC,CAAC,EAC/CD,EAAQ,MAAM,MAAQ,GAAGE,CAAQ,KACjCF,EAAQ,MAAM,YAAY,cAAe,GAAGE,CAAQ,IAAI,EACxDzM,GAAU,OAAO,EACjBsC,GAAQ,iBAAiB,CAC3B,CAAC,EAED,SAAS,iBAAiB,UAAW,IAAM,CACpC6J,IACLA,EAAa,GACbG,EAAQ,UAAU,OAAO,UAAU,EACnC,SAAS,KAAK,UAAU,OAAO,kBAAkB,EACnD,CAAC,CACH,CAIA,SAAS9G,GAAUkH,EAAaC,EAAaC,EAAc,CACzDhN,GAAS,MAAM,CAAE,QAAS,CAAC8M,EAAKC,EAAKC,CAAI,CAAE,CAAC,CAC9C,CAEA,SAASnH,GAAgBnE,EAAYC,EAAa,CAChDE,GAAYH,EAAI,EAAK,EACrBtB,GAAU,YAAYuB,CAAG,CAC3B,CAEA,SAASmE,IAAgB,CAEzB,CAEA,SAASC,GAAkBkH,EAAuB,CAC5CA,GAAMA,EAAG,KAAO,MAAQA,EAAG,KAAO,MACpCvK,GAAQ,aAAauK,EAAG,IAAKA,EAAG,GAAG,EAC/BzN,IAAWkD,GAAQ,SAASuK,EAAG,IAAKA,EAAG,IAAK,KAAM,EAAI,GAE1DvK,GAAQ,WAAW,CAEvB,CAEA,SAASY,GAAmB4J,EAAoBC,EAAoB3F,EAAc4F,EAAM,GAAO,CAC7F,GAAI,CAAC9N,IAAc,CAACR,GAAOQ,EAAU,EAAG,OACxC,IAAMwC,EAAIhD,GAAOQ,EAAU,EAE3B,GAAI4N,IAAQ,MAAQC,IAAQ,KAAM,CAChCzK,GAAQ,eAAe,EACnBZ,IAAM9B,GAAS,IAAI,EAAE,KAAO,YAAc,YAAYyC,GAAeX,CAAC,EAC1E9B,GAAS,MAAM,CAAE,IAAK,IAAK,CAAC,EAC5B,MACF,CAGA,IAAM+B,EAAMD,EAAE,OACVuL,EAAO,EACThL,EAAON,EAAI,OAAS,EAEtB,GAAIyF,IAAS,WAAY,CACvB,IAAM8F,EAAKJ,EAAM,IACf/N,EAAKgO,EAAM,IACbE,EAAOtL,EAAI,UAAWG,IAAOA,EAAE,MAAQ,IAAMoL,CAAE,EAC/CjL,EAAON,EAAI,UAAWG,IAAOA,EAAE,MAAQ,IAAM/C,CAAE,CACjD,KAAO,CACL,IAAM8C,EAAKF,EAAI,KAAMG,GAAMA,EAAE,MAAQ,IAAI,GAAG,MAAQ,EAC9CqL,EAAMtL,EAAKiL,EAAM,IACrBM,EAAMvL,EAAKkL,EAAM,IACnBE,EAAOtL,EAAI,UAAWG,IAAOA,EAAE,MAAQ,IAAMqL,CAAG,EAChDlL,EAAON,EAAI,UAAWG,IAAOA,EAAE,MAAQ,IAAMsL,CAAG,CAClD,CAEIH,IAAS,KAAIA,EAAO,GACpBhL,IAAS,KAAIA,EAAON,EAAI,OAAS,GAGrC,IAAMO,EAASP,EAAI,MAAMsL,EAAMhL,EAAO,CAAC,EACjCE,EAAQC,GAAQ,aAAaF,CAAM,EACzClC,GAAU,kBAAkBmC,CAAK,GAC5BvC,GAAS,IAAI,EAAE,KAAO,YAAc,YAAYyC,GAAeX,CAAC,EAErEY,GAAQ,iBAAiBpD,GAAYyC,EAAKsL,EAAMhL,EAAM+K,EAAK3N,EAAgB,EAC3EiD,GAAQ,cAAcJ,EAAO,IAAKJ,GAAM,CAACA,EAAE,IAAKA,EAAE,GAAG,CAAqB,CAAC,EAC3ElC,GAAS,MAAM,CAAE,IAAK,CAACkN,EAAKC,CAAG,CAAE,CAAC,CACpC,CAEA,SAASnH,GAAaiH,EAAgBtL,EAAa,CAC7CsL,GAAMA,EAAG,KAAO,MAAQA,EAAG,KAAO,MAAMvK,GAAQ,SAASuK,EAAG,IAAKA,EAAG,IAAKpO,EAAgB,CAC/F,CAEO,SAASgD,GAAYH,EAAY0L,EAAM,GAAMK,EAAmB,GAAO,CAC5E,GAAI,CAAC3O,GAAO4C,CAAE,EAAG,OACjB,GAAIA,IAAOpC,GAAY,CACjB8N,GAAK1K,GAAQ,SAAShB,CAAE,EAC5B,MACF,CAEA,IAAMgM,EAAcpO,KAAe,KAC/BoO,IAEFtN,GAAU,MAAM,EAChB6C,GAAc,KAAM,CAAC,CAAC,EACtBR,GAAe,IAAI,GAGrBnD,GAAaoC,EAGbjC,GAAmB,KACnBiD,GAAQ,iBAAiBhB,CAAE,EACvBgM,GACFtN,GAAU,eAAe,IAAI,EAI/BJ,GAAS,MAAM,CAAE,MAAO0B,EAAI,IAAK,IAAK,EAAG,EAAI,EACzCgM,GACFtN,GAAU,gBAAgB,EAI5BY,GAAgB,EAGhB,IAAM2M,EAAY3N,GAAS,IAAI,EAAE,KAAO,SACpC2N,IAAc,WAAW1K,GAAcnE,GAAO4C,CAAE,EAAGwB,GAAc,CAAC,EAClEyK,IAAc,YAAYlL,GAAe3D,GAAO4C,CAAE,CAAC,EACnDiM,IAAc,YAAYhK,GAAe7E,GAAO4C,CAAE,CAAC,EACnDiM,IAAc,WAAW/J,GAAc,EACvC+J,IAAc,aAChBxK,GAAgBrE,GAAO4C,CAAE,EAAG,OAAO,OAAO5C,EAAM,EAAG,CAACsE,EAASC,IAAU,CACrExB,GAAYuB,EAAS,EAAI,EACrBC,IACFjD,GAAU,iBAAiBiD,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC7CC,GAAmBD,EAAM,CAAC,EAAGA,EAAM,CAAC,EAAG,OAAQ,EAAI,EAEvD,CAAC,EAIHX,GAAQ,iBAAiBhB,EAAI0L,CAAG,EAC5BA,GAAK1K,GAAQ,SAAShB,CAAE,EAC5BtB,GAAU,UAAUtB,GAAO4C,CAAE,EAAG,OAAO,OAAO5C,EAAM,EAAG2O,CAAgB,CACzE,CAEA,eAAe/H,GAAYhE,EAAY,CACrC,MAAMqC,GAAQ,OAAOrC,CAAE,EACvBgB,GAAQ,YAAYhB,CAAE,EACtB,OAAO5C,GAAO4C,CAAE,EACZpC,KAAeoC,IACjBpC,GAAa,KACbc,GAAU,MAAM,EAChB6C,GAAc,KAAM,CAAC,CAAC,EACtBR,GAAe,IAAI,EACnBzC,GAAS,MAAM,CAAE,MAAO,KAAM,IAAK,KAAM,UAAW,IAAK,CAAC,GAE5DyD,GAAa,CACf,CAEA,eAAe4D,IAAW,CACxB,IAAMuG,EAAO,KAAK,MAAM,GAAK,KAAK,OAAO,EAAI,EAAE,EAAE,SAAS,EAEpDC,EAAW,SAAS,cAAc,KAAK,EAC7CA,EAAS,UAAY,iBAErBA,EAAS,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gDAOyBD,CAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUlD,SAAS,KAAK,YAAYC,CAAQ,EAElC,IAAMC,EAAQD,EAAS,cAAc,cAAc,EAC7CE,EAAaF,EAAS,cAAc,oBAAoB,EACxDG,EAAYH,EAAS,cAAc,mBAAmB,EAE5DC,EAAM,MAAM,EAEZA,EAAM,iBAAiB,QAAS,IAAM,CACpCC,EAAW,SAAWD,EAAM,QAAUF,CACxC,CAAC,EAED,IAAM1M,EAAQ,IAAM2M,EAAS,OAAO,EAEpCG,EAAU,iBAAiB,QAAS9M,CAAK,EACzC2M,EAAS,iBAAiB,QAAU1M,GAAM,CACpCA,EAAE,SAAW0M,GAAU3M,EAAM,CACnC,CAAC,EAED6M,EAAW,iBAAiB,QAAS,SAAY,CAC3CD,EAAM,QAAUF,IACpB1M,EAAM,EAEN7B,GAAmB,GACnB,MAAM0E,GAAQ,MAAM,EAEpBjF,GAAS,CAAC,EACVQ,GAAa,KACboD,GAAQ,eAAe,EACvB,OAAO,SAAS,OAAO,EACzB,CAAC,CACH,CAEA,SAASe,GAAawK,EAAa,GAAO,CAC5B,OAAO,KAAKnP,EAAM,EAC1B,QAAS4C,GAAO,CAClB,IAAMI,EAAIhD,GAAO4C,CAAE,EACbmC,EAAI/B,EAAE,MACRoM,EAAU,GAGd,GAAIxO,GACF,GAAIC,GACF,GAAI,CACS,IAAI,OAAOD,GAAa,GAAG,EAC9B,KAAKoC,EAAE,IAAI,IAAGoM,EAAU,GAClC,MAAY,CACVA,EAAU,EACZ,MAEKpM,EAAE,KAAK,YAAY,EAAE,SAASpC,GAAY,YAAY,CAAC,IAAGwO,EAAU,IAK7E,GAAIA,IAAYrO,GAAQ,KAAK,CAAC,GAAKA,GAAQ,KAAK,CAAC,GAAI,CACnD,IAAM0D,EAAQ1D,GAAQ,KAAK,CAAC,EAAI,IAAI,KAAKA,GAAQ,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAI,EAChE2D,EAAM3D,GAAQ,KAAK,CAAC,EAAI,IAAI,KAAKA,GAAQ,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAI,IAC9DoC,EAAK4B,EAAE,WAAa,GACtB5B,EAAKsB,GAAStB,EAAKuB,KAAK0K,EAAU,GACxC,CAGA,GAAIA,IAAYrO,GAAQ,KAAK,CAAC,IAAM,MAAQA,GAAQ,KAAK,CAAC,IAAM,MAAO,CACrE,IAAMqN,GAAOrN,GAAQ,KAAK,CAAC,GAAK,GAAK,IAC/BsN,GAAOtN,GAAQ,KAAK,CAAC,GAAK,KAAY,KACxCgE,EAAE,UAAYqJ,GAAOrJ,EAAE,UAAYsJ,KAAKe,EAAU,GACxD,CAGA,GAAIA,IAAYrO,GAAQ,IAAI,CAAC,IAAM,MAAQA,GAAQ,IAAI,CAAC,IAAM,MAAO,CACnE,IAAMqN,GAAOrN,GAAQ,IAAI,CAAC,GAAK,GAAK,IAC9BsN,GAAOtN,GAAQ,IAAI,CAAC,GAAK,KAAY,IACrC,EAAIgE,EAAE,UAAY,GACpB,EAAIqJ,GAAO,EAAIC,KAAKe,EAAU,GACpC,CAGA,GAAIA,GAAWrO,GAAQ,QAAQ,KAAO,EACpC,QAAWqI,KAAKrI,GAAQ,QAAS,CAC/B,IAAMsO,EAAQ/N,GAAU,QAAQ8H,CAAC,EAAE,MACnC,GAAI,CAACpG,EAAE,OAAO,KAAMI,GAAWA,EAAEiM,CAAK,GAAK,IAAI,EAAG,CAChDD,EAAU,GACV,KACF,CACF,CASF,GALIA,GAAWrO,GAAQ,OACjBiC,EAAE,QAAUjC,GAAQ,QAAOqO,EAAU,IAIvCA,GAAWrO,GAAQ,KAAK,OAAS,EAAG,CACtC,IAAMuO,EAAYtM,EAAE,MAAQ,CAAC,EACxBjC,GAAQ,KAAK,MAAOwO,GAAOD,EAAU,SAASC,CAAE,CAAC,IAAGH,EAAU,GACrE,CAEApM,EAAE,UAAY,CAACoM,EACfxL,GAAQ,gBAAgBZ,EAAE,GAAIA,EAAE,SAAWoM,CAAO,CACpD,CAAC,EAEID,GAAYjN,GAAgB,CACnC,CAEA,SAAS0C,IAAiB,CACvB,SAAS,eAAe,mBAAmB,EAAuB,MAAQ7D,GAAQ,KAAK,CAAC,GAAK,GAC7F,SAAS,eAAe,iBAAiB,EAAuB,MAAQA,GAAQ,KAAK,CAAC,GAAK,GAC3F,SAAS,eAAe,iBAAiB,EAAuB,MAC/DA,GAAQ,KAAK,CAAC,IAAM,KAAO,OAAOA,GAAQ,KAAK,CAAC,CAAC,EAAI,GACtD,SAAS,eAAe,iBAAiB,EAAuB,MAC/DA,GAAQ,KAAK,CAAC,IAAM,KAAO,OAAOA,GAAQ,KAAK,CAAC,CAAC,EAAI,GACtD,SAAS,eAAe,gBAAgB,EAAuB,MAC9DA,GAAQ,IAAI,CAAC,IAAM,KAAO,OAAOA,GAAQ,IAAI,CAAC,CAAC,EAAI,GACpD,SAAS,eAAe,gBAAgB,EAAuB,MAC9DA,GAAQ,IAAI,CAAC,IAAM,KAAO,OAAOA,GAAQ,IAAI,CAAC,CAAC,EAAI,GACpD,SAAS,eAAe,aAAa,EAAuB,MAAQA,GAAQ,KAAK,KAAK,IAAI,EAE3F,SACG,iBAAiB,4EAA4E,EAC7F,QAASc,GAAO,CACf,IAAMG,EAAOH,EACbG,EAAK,UAAU,OAAO,UAAWA,EAAK,QAAQ,OAAS,OAASjB,GAAQ,OAAS,GAAG,CACtF,CAAC,EAEH,SAAS,iBAAiB,4BAA4B,EAAE,QAASc,GAAO,CACtE,IAAMgC,EAAMhC,EACZgC,EAAI,UAAU,OAAO,SAAU9C,GAAQ,QAAQ,IAAI8C,EAAI,QAAQ,MAAO,CAAC,CACzE,CAAC,EAED,IAAM2L,GACHzO,GAAQ,KAAK,CAAC,EAAI,EAAI,IACtBA,GAAQ,KAAK,CAAC,EAAI,EAAI,IACtBA,GAAQ,KAAK,CAAC,IAAM,KAAO,EAAI,IAC/BA,GAAQ,KAAK,CAAC,IAAM,KAAO,EAAI,IAC/BA,GAAQ,IAAI,CAAC,IAAM,KAAO,EAAI,IAC9BA,GAAQ,IAAI,CAAC,IAAM,KAAO,EAAI,GAC/BA,GAAQ,QAAQ,MACfA,GAAQ,KAAK,OAAS,EAAI,EAAI,GAE3B0O,EAAQ,SAAS,cAAc,gCAAgC,EACjEA,IACFA,EAAM,YAAcD,EAAc,EAAI,OAAOA,CAAW,EAAI,GAC5DC,EAAM,UAAU,OAAO,SAAUD,IAAgB,CAAC,EAEtD,CAEA,SAASvN,IAAqB,CAC5B,IAAMyN,EAAc,SAAS,eAAe,cAAc,EACtDA,IAAaA,EAAY,MAAQ9O,IACrC,SAAS,eAAe,kBAAkB,GAAG,UAAU,OAAO,SAAUC,EAAW,EAEnF,IAAMkB,EAAML,GAAa,KAAMiO,GAAMA,EAAE,MAAQ7O,EAAW,EAC1D,GAAIiB,EAAK,CACP,IAAM6N,EAAU,SAAS,eAAe,oBAAoB,EACtDC,EAAS,SAAS,eAAe,mBAAmB,EACtDD,IACFA,EAAQ,YAAc7N,EAAI,MACvB,QAAQ,SAAU,EAAE,EACpB,QAAQ,YAAa,EAAE,EACvB,QAAQ,YAAa,EAAE,GACxB8N,IAAQA,EAAO,YAAc9N,EAAI,KACvC,CACF,CAEA,SAASsF,GAAWf,EAAoB,CAEtC,IAAMwJ,EAAaxJ,EAAS,MAyB5B,GAxBIwJ,IAAetP,KACbsP,GAAc9P,GAAO8P,CAAU,EACjC/M,GAAY+M,EAAY,EAAI,EACnB,CAACA,GAActP,KACxBA,GAAa,KACbc,GAAU,MAAM,EAChB6C,GAAc,KAAM,CAAC,CAAC,EACtBR,GAAe,IAAI,EACnBzB,GAAgB,EAChB0B,GAAQ,OAAO,IAKf0C,EAAS,KAAO,OAAOA,EAAS,KAAQ,WAC1C1C,GAAQ,cAAc0C,EAAS,GAAG,EAClC,SACG,iBAAiB,SAAS,EAC1B,QAASvC,GACRA,EAAE,UAAU,OAAO,SAAWA,EAAkB,QAAQ,QAAUuC,EAAS,GAAG,CAChF,GAIAA,EAAS,QAAS,CACpB,GAAM,CAAC0H,EAAKC,EAAKC,CAAI,EAAI5H,EAAS,QAClC1C,GAAQ,YAAYoK,EAAKC,EAAKC,CAAI,CACpC,CAGI5H,EAAS,KACX,SAAS,iBAAiB,UAAU,EAAE,QAASzC,GAAQ,CACrD,IAAME,EAAIF,EACNE,EAAE,QAAQ,MAAQuC,EAAS,MACxBvC,EAAE,UAAU,SAAS,QAAQ,GAAGA,EAAE,MAAM,EAEjD,CAAC,EAICuC,EAAS,OAAOhF,GAAU,SAASgF,EAAS,KAAK,EAErD,IAAMyJ,EAAezJ,EAAS,OAAS,OAMvC,GALA,SACG,iBAAiB,uBAAuB,EACxC,QAASvC,GAAMA,EAAE,UAAU,OAAO,SAAWA,EAAkB,QAAQ,OAASgM,CAAY,CAAC,EAG5FzJ,EAAS,QAAS,CACpB,IAAM/E,EAAUD,GAAU,QACpB0O,EAAO1J,EAAS,QACnB,IAAK2J,GAAS,OAAO,KAAK1O,CAAO,EAAE,KAAM2O,GAAM3O,EAAQ2O,CAAC,EAAE,OAASD,CAAI,CAAC,EACxE,OAAQC,GAAmBA,IAAM,MAAS,EACzCF,EAAK,QAAQ1O,GAAU,iBAAiB0O,CAAI,CAClD,CAGI1J,EAAS,SACXvF,GAAQ,KAAOuF,EAAS,OAAO,IAAKnF,GAAMA,GAAK,IAAI,GACjDmF,EAAS,SACXvF,GAAQ,KAAOuF,EAAS,OAAO,IAAKnF,GAAOA,IAAM,EAAI,EAAIA,GAAK,IAAK,GAIjEmF,EAAS,QACXvF,GAAQ,IAAMuF,EAAS,MAAM,IAAKnF,GAAOA,IAAM,EAAI,EAAIA,GAAK,IAAK,GAI/DmF,EAAS,SAAQvF,GAAQ,QAAU,IAAI,IAAIuF,EAAS,MAAM,GAC1DA,EAAS,SAAQvF,GAAQ,KAAOuF,EAAS,QAE7C1B,GAAe,EAEX0B,EAAS,IAAG1F,GAAc0F,EAAS,GACnCA,EAAS,KAAIzF,GAAcyF,EAAS,IACpCA,EAAS,OAAMxF,GAAcwF,EAAS,MAC1CrE,GAAmB,EAEnB0C,GAAa,CACf,CAEA,SAASwL,IAA2B,CAElC,GAAI,CADc,SAAS,eAAe,wBAAwB,EAClD,OAEhB,IAAMC,EAAkB,SAAS,eAAe,eAAe,EACzDpH,EAAkB,SAAS,eAAe,wBAAwB,EACxE,GAAI,CAACoH,GAAmB,CAACpH,EAAiB,OAE1C,IAAMqH,EAAS,IAAI,IACnB,OAAO,OAAOrQ,EAAM,EAAE,QAASgD,GAAM,CAC/BA,EAAE,OAAOqN,EAAO,IAAIrN,EAAE,KAAK,CACjC,CAAC,EAED,IAAMsN,EAAc,MAAM,KAAKD,CAAM,EAAE,KAAK,EACtCE,EAAiB,SAAS,eAAe,uBAAuB,EAEtEH,EAAgB,UAAY,GAC5BpH,EAAgB,UAAY,GAExBsH,EAAY,QAAU,GACpBC,IAAgBA,EAAe,MAAM,QAAU,QAEnDD,EAAY,QAASE,GAAU,CAC7B,IAAM3M,EAAM,SAAS,cAAc,QAAQ,EAC3CA,EAAI,UAAY,YAAY9C,GAAQ,QAAUyP,EAAQ,UAAY,EAAE,GACpE3M,EAAI,QAAQ,MAAQ2M,EACpB3M,EAAI,MAAQ2M,EAAM,OAAO,CAAC,EAAE,YAAY,EAAIA,EAAM,MAAM,CAAC,EACzD3M,EAAI,UAAY,0CAA0C4M,GAAaD,CAAK,CAAC,UAC7EJ,EAAgB,YAAYvM,CAAG,CACjC,CAAC,IAEG0M,IAAgBA,EAAe,MAAM,QAAU,gBAE9B,CAAC,UAAW,UAAW,SAAS,EAExC,QAASC,GAAU,CAC9B,GAAIH,EAAO,IAAIG,CAAK,EAAG,CACrB,IAAM3M,EAAM,SAAS,cAAc,QAAQ,EAC3CA,EAAI,UAAY,YAAY9C,GAAQ,QAAUyP,EAAQ,UAAY,EAAE,GACpE3M,EAAI,QAAQ,MAAQ2M,EACpB3M,EAAI,MAAQ2M,EAAM,OAAO,CAAC,EAAE,YAAY,EAAIA,EAAM,MAAM,CAAC,EACzD3M,EAAI,UAAY,0CAA0C4M,GAAaD,CAAK,CAAC,UAC7EJ,EAAgB,YAAYvM,CAAG,CACjC,CACF,CAAC,EAEDyM,EAAY,QAASE,GAAU,CAC7B,IAAMxO,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,gBAAgBjB,GAAQ,QAAUyP,EAAQ,UAAY,EAAE,GACzExO,EAAK,QAAQ,MAAQwO,EACrBxO,EAAK,MAAM,QAAU,MACrBA,EAAK,MAAM,OAAS,UACpBA,EAAK,MAAM,QAAU,OACrBA,EAAK,MAAM,WAAa,SACxBA,EAAK,MAAM,IAAM,MACjBA,EAAK,UAAY;AAAA,iDAC0ByO,GAAaD,CAAK,CAAC;AAAA,gBACpDA,EAAM,OAAO,CAAC,EAAE,YAAY,EAAIA,EAAM,MAAM,CAAC,CAAC;AAAA,QAExDxH,EAAgB,YAAYhH,CAAI,CAClC,CAAC,EAEL,CAEA,SAASE,IAAkB,CACzBiO,GAAyB,EACzB,IAAMO,EAAO,SAAS,eAAe,YAAY,EAC3CC,EAAU,SAAS,eAAe,kBAAkB,EACpDC,EAAc,SAAS,cAAc,gBAAgB,EAC3D,GAAI,CAACF,EAAM,OAEX,IAAMG,EAAM,OAAO,KAAK7Q,EAAM,EAAE,OAAQ4C,GAAO,CAAC5C,GAAO4C,CAAE,EAAE,SAAS,EAGpE,GAFIgO,IAAaA,EAAY,YAAc,WAAWC,EAAI,MAAM,KAE5D,CAACA,EAAI,OAAQ,CACfH,EAAK,UAAY,GACbC,IACFD,EAAK,YAAYC,CAAO,EACxBA,EAAQ,MAAM,QAAU,SAE1B,MACF,CACIA,IAASA,EAAQ,MAAM,QAAU,QACrCD,EAAK,UAAY,GAEjBG,EACG,KAAK,CAACpJ,EAAG1D,IAAM,CAEd,GAAI0D,IAAMjH,GAAY,MAAO,GAC7B,GAAIuD,IAAMvD,GAAY,MAAO,GAE7B,IAAMsQ,EAAK9Q,GAAOyH,CAAC,EACjBsJ,EAAK/Q,GAAO+D,CAAC,EACTiN,EAAKF,EAAG,MACZG,EAAKF,EAAG,MAENG,EAAM,EACV,OAAQpQ,GAAa,CACnB,IAAK,WACHoQ,GAAOF,EAAG,WAAa,IAAMC,EAAG,WAAa,GAC7C,MACF,IAAK,YACHC,GAAOD,EAAG,WAAa,IAAMD,EAAG,WAAa,GAC7C,MACF,IAAK,WACHE,GAAOF,EAAG,WAAa,IAAMC,EAAG,WAAa,GAC7C,MACF,IAAK,YACHC,GAAOD,EAAG,WAAa,IAAMD,EAAG,WAAa,GAC7C,MACF,IAAK,UACHE,GAAOF,EAAG,UAAY,IAAMC,EAAG,UAAY,GAC3C,MACF,IAAK,WACHC,GAAOD,EAAG,UAAY,IAAMD,EAAG,UAAY,GAC3C,MACF,QACEE,EAAM,CACV,CACA,OAAOA,GAAOzJ,EAAE,cAAc1D,CAAC,CACjC,CAAC,EACA,QAASnB,GAAO,CACf8N,EAAK,YAAYS,GAAenR,GAAO4C,CAAE,CAAC,CAAC,CAC7C,CAAC,CACL,CAEA,SAASwB,IAA0B,CACjC,IAAMgN,EAAM,IAAI,IAChB,cAAO,OAAOpR,EAAM,EAAE,QAASgD,GAAM,EAClCA,EAAE,MAAQ,CAAC,GAAG,QAASqO,GAAQD,EAAI,IAAIC,CAAG,CAAC,CAC9C,CAAC,EACM,MAAM,KAAKD,CAAG,EAAE,KAAK,CAC9B,CAEA,SAASX,GAAaD,EAA8B,CAClD,GAAI,CAACA,EAAO,MAAO,WACnB,IAAMzL,EAAIyL,EAAM,YAAY,EAC5B,OAAIzL,EAAE,SAAS,KAAK,EAAU,iBAC1BA,EAAE,SAAS,MAAM,GAAKA,EAAE,SAAS,MAAM,EAAU,kBACjDA,EAAE,SAAS,MAAM,EAAU,kBAC3BA,EAAE,SAAS,MAAM,EAAU,OAC3BA,EAAE,SAAS,KAAK,EAAU,SACvB,QACT,CAEA,SAASoM,GAAeG,EAAkB,CACxC,IAAMtP,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,aAAasP,EAAM,KAAO9Q,GAAa,YAAc,EAAE,GACxEwB,EAAK,QAAQ,GAAKsP,EAAM,GAExB,IAAMC,EACJD,EAAM,OAAO,QAAUA,EAAM,OAAO,CAAC,EAAE,KAAOE,GAAQF,EAAM,OAAO,CAAC,EAAE,IAAI,EAAI,eAE1EG,GACHH,EAAM,MAAQ,CAAC,GAAG,OAAS,EACxB,4BAA4BA,EAAM,MAAQ,CAAC,GACxC,IAAKtO,GAAM,CACV,IAAMkB,EAAIwN,GAAY1O,CAAC,EACvB,MAAO,+CAA+CkB,CAAC,aAAaA,CAAC,KAAKyN,GAAQ3O,CAAC,CAAC,SACtF,CAAC,EACA,KAAK,EAAE,CAAC,SACX,GAENhB,EAAK,UAAY;AAAA,iDAC8BsP,EAAM,KAAK;AAAA;AAAA,gCAE5BK,GAAQL,EAAM,aAAeA,EAAM,IAAI,CAAC;AAAA;AAAA;AAAA,kBAGtDC,CAAI;AAAA,uFACiE,KAAK,MAAMD,EAAM,MAAM,UAAY,GAAI,CAAC;AAAA,YACnHA,EAAM,MAAQ,4DAA4DK,GAAQL,EAAM,KAAK,CAAC,KAAKb,GAAaa,EAAM,KAAK,CAAC,UAAY,EAAE;AAAA,gCACtHA,EAAM,OAAO,YAAY,CAAC;AAAA;AAAA;AAAA,mDAGPA,EAAM,QAAU,aAAe,gBAAgB;AAAA;AAAA;AAAA,QAG1FG,CAAQ;AAAA;AAAA,IAIdzP,EAAK,iBAAiB,QAAUK,GAAM,CAC/BA,EAAE,OAAuB,QAAQ,WAAW,GACjDU,GAAYuO,EAAM,EAAE,CACtB,CAAC,EAED,IAAMM,EAAS5P,EAAK,cAAc,aAAa,EAC/C,OAAA4P,EAAO,iBAAiB,QAAS,IAAM,CACrCN,EAAM,QAAU,CAACA,EAAM,QACvBM,EAAO,cAAc,2BAA2B,EAAG,YAAcN,EAAM,QACnE,aACA,iBACJ1N,GAAQ,gBAAgB0N,EAAM,GAAIA,EAAM,OAAO,EAC/CrM,GAAQ,KAAKqM,CAAK,CACpB,CAAC,EAEMtP,CACT,CAEA,SAAS0E,GAAUF,EAAaC,EAAyB,OAAQ,CAC/D,IAAMoL,EAAY,SAAS,eAAe,iBAAiB,EAC3D,GAAI,CAACA,EAAW,OAChBA,EAAU,UAAY,GACtB,IAAM7O,EAAI,SAAS,cAAc,KAAK,EACtCA,EAAE,UAAY,SAASyD,CAAI,GAC3BzD,EAAE,YAAcwD,EAChBqL,EAAU,YAAY7O,CAAC,CACzB,CAEA,SAAS8O,IAA0B,CACjC,IAAM/C,EAAW,SAAS,cAAc,KAAK,EAC7CA,EAAS,UAAY,iBAErB,IAAIgD,EAAW,GACf9R,GAAe,QAAS8E,GAAM,CAC5BgN,GAAY,4CAA4ChN,EAAE,IAAI,cAAcA,EAAE,MAAM,QACtF,CAAC,EAEDgK,EAAS,UAAY;AAAA;AAAA;AAAA;AAAA,UAIbgD,GAAY,gCAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASpD,SAAS,KAAK,YAAYhD,CAAQ,EAElC,IAAMG,EAAYH,EAAS,cAAc,mBAAmB,EACtDiD,EAAWjD,EAAS,cAAc,kBAAkB,EACpD3M,EAAQ,IAAM2M,EAAS,OAAO,EAEpCG,EAAU,iBAAiB,QAAS9M,CAAK,EACzC4P,EAAS,iBAAiB,QAAS,IAAM,CACvC/R,GAAiB,CAAC,EAClBmC,EAAM,EACN,IAAM6P,EAAgB,SAAS,eAAe,gBAAgB,EAC1DA,GAAeA,EAAc,UAAU,IAAI,QAAQ,CACzD,CAAC,EAEDlD,EAAS,iBAAiB,QAAU1M,GAAM,CACpCA,EAAE,SAAW0M,GAAU3M,EAAM,CACnC,CAAC,CACH,CAEA,SAASuG,IAAe,CACtB,IAAMuJ,EAAO,SAAS,eAAe,WAAW,EAChD,GAAI,CAACA,EAAM,OAEX,IAAMD,EAAgB,SAAS,eAAe,gBAAgB,EAC1DA,GACFA,EAAc,iBAAiB,QAAU5P,GAAM,CAC7CA,EAAE,gBAAgB,EAClByP,GAAwB,CAC1B,CAAC,EAGH,OAAO,iBAAiB,WAAazP,GAAM,CACzCA,EAAE,eAAe,EACjB6P,EAAK,UAAU,IAAI,aAAa,CAClC,CAAC,EAED,OAAO,iBAAiB,YAAc7P,GAAM,CACtCA,EAAE,gBAAkB,MAAM6P,EAAK,UAAU,OAAO,aAAa,CACnE,CAAC,EAED,OAAO,iBAAiB,OAAQ,MAAO7P,GAAM,CAC3CA,EAAE,eAAe,EACjB6P,EAAK,UAAU,OAAO,aAAa,EAEnC,IAAMC,EAAQ9P,EAAE,cAAc,MAC9B,GAAI,CAAC8P,EAAO,OAEZ,IAAMC,EAAgB,CAAC,EACjBC,EAA2B,CAAC,EAElC,QAAS1F,EAAI,EAAGA,EAAIwF,EAAM,OAAQxF,IAAK,CACrC,IAAM2F,EAAQH,EAAMxF,CAAC,EAAE,iBAAiB,EACpC2F,GAAOD,EAAM,KAAKC,CAAK,CAC7B,CAEA,eAAeC,EAAeD,EAAwB,CACpD,GAAIA,EAAM,OAAQ,CAChB,IAAMlI,EAAO,MAAM,IAAI,QAAeoI,GAASF,EAA8B,KAAKE,CAAG,CAAC,EACtFJ,EAAM,KAAKhI,CAAI,CACjB,SAAWkI,EAAM,YAAa,CAC5B,IAAMG,EAAUH,EAAmC,aAAa,EAC5DI,EAA6B,CAAC,EAC9BC,EACJ,GACEA,EAAQ,MAAM,IAAI,QAA4BH,GAAQC,EAAO,YAAYD,CAAG,CAAC,EAC7EE,EAAQ,KAAK,GAAGC,CAAK,QACdA,EAAM,OAAS,GAExB,QAAWC,KAASF,EAAS,MAAMH,EAAeK,CAAK,CACzD,CACF,CAEA,QAAWN,KAASD,EAAO,MAAME,EAAeD,CAAK,EAEjDF,EAAM,QAAQxJ,GAAYwJ,CAAK,CACrC,CAAC,CACH,CAEA,eAAexJ,GAAYwJ,EAAe,CACxC,GAAI,CAACA,EAAM,OAAQ,OACnB7R,GAAmB,GACnB,IAAMsS,EAAmB5S,GAAe,OAElC+F,EAAS,SAAS,eAAe,eAAe,EAChDC,EAAa,SAAS,eAAe,aAAa,EAClDC,EAAgB,SAAS,eAAe,gBAAgB,EACxDC,EAAc,SAAS,eAAe,qBAAqB,EAC3D2M,EAAc,SAAS,eAAe,cAAc,EAEtDA,GACFA,EAAY,iBAAiB,QAAS,IAAM,CAC1CvS,GAAmB,GACfyF,GAAQA,EAAO,UAAU,IAAI,QAAQ,CAC3C,CAAC,EAGH,SAAS+M,GAA4B,CACnC,IAAMC,EAAa,SAAS,cAAc,wBAAwB,EAC9DA,IACFA,EAAW,YAAc,UACzBA,EAAW,MAAM,MAAQ,WAE3B,IAAMC,EAAe,SAAS,eAAe,sBAAsB,EACnE,GAAIA,EAAc,CAChB,IAAMC,EAAQjT,GAAe,OAAS4S,EAChCM,EAAYF,EAAa,cAAc,MAAM,EAC/CE,IAAWA,EAAU,YAAc,GAAGD,CAAK,IAC/CD,EAAa,MAAM,QAAU,MAC/B,CACF,CAEA,GAAIjN,EAAQ,CACNC,IACFA,EAAW,YAAc,aAAamM,EAAM,MAAM,QAAQA,EAAM,OAAS,EAAI,IAAM,EAAE,IACvF,IAAMY,EAAa,SAAS,cAAc,wBAAwB,EAC9DA,IACFA,EAAW,YAAc,WACzBA,EAAW,MAAM,MAAQ,iBAE3B,IAAMC,EAAe,SAAS,eAAe,sBAAsB,EACnE,GAAIA,EAAc,CAChBA,EAAa,MAAM,QAAU,OAC7B,IAAME,EAAYF,EAAa,cAAc,MAAM,EAC/CE,IAAWA,EAAU,YAAc,IACzC,CACIjN,IAAeA,EAAc,YAAc,IAC3CC,IAAaA,EAAY,MAAM,MAAQ,MAC3CH,EAAO,UAAU,OAAO,QAAQ,EAE5B/F,GAAe,OAAS4S,GAAkBE,EAA0B,CAC1E,CAEA,GAAI,CACF,IAAIG,EAAQ,EACRE,EAAyB,KACzBC,EAA2B,EAGzBC,EAAalB,EAAM,OAAQmB,GAAM,CACrC,IAAM1J,EAAO0J,EAAE,KAAK,YAAY,EAChC,OACE1J,EAAK,SAAS,MAAM,GACpBA,EAAK,SAAS,MAAM,GACpBA,EAAK,SAAS,MAAM,GACpBA,EAAK,SAAS,MAAM,CAExB,CAAC,EAOD,GALqBuI,EAAM,OAAQmB,GAAM,CAACD,EAAW,SAASC,CAAC,CAAC,EACnD,QAASA,GAAM,CAC1BtT,GAAe,KAAK,CAAE,KAAMsT,EAAE,KAAM,OAAQ,yBAA0B,CAAC,CACzE,CAAC,EAEGD,EAAW,SAAW,EAAG,CAC3B,GAAIlB,EAAM,OAAS,EAAG,CACpB1L,GAAU,2BAA4B,OAAO,EAE7C,IAAMuL,EAAgB,SAAS,eAAe,gBAAgB,EAC1DA,GAAiBhS,GAAe,OAAS,IAC3CgS,EAAc,UAAU,OAAO,QAAQ,EACvCA,EAAc,MAAQ,WAAWhS,GAAe,MAAM,mCAE1D,CACA,MACF,CAEA,IAAMuT,EAAiB,SAAS,eAAe,iBAAiB,EAC5DC,EAAoC,KACxC,GAAIvN,EAAe,CACjBA,EAAc,UACZ,2EACFuN,EAAgBvN,EAAc,cAAc,iBAAiB,EAC7D,IAAMwN,EAAUxN,EAAc,cAAc,iBAAiB,EACzDwN,IAASA,EAAQ,YAAcJ,EAAW,OAAO,SAAS,EAChE,CAEA,QAAS3G,EAAI,EAAGA,EAAI2G,EAAW,QACzB,CAAA/S,GADiCoM,IAAK,CAE1C,IAAM4G,EAAID,EAAW3G,CAAC,EAClB6G,IAAgBA,EAAe,YAAcD,EAAE,MAC/CE,IAAeA,EAAc,aAAe9G,EAAI,GAAG,SAAS,GAC5DxG,IAAaA,EAAY,MAAM,MAAQ,GAAIwG,EAAI2G,EAAW,OAAU,GAAG,KAE3E,GAAI,CACF,IAAMnM,EAAO,MAAMzD,GAAQ,UAAU6P,CAAC,EAGhCI,EAAiB,OAAO,OAAO3T,EAAM,EAI3C,GADiB2T,EAAe,KAAM3Q,GAAMA,EAAE,WAAauQ,EAAE,MAAQvQ,EAAE,WAAauQ,EAAE,IAAI,EAC5E,CACZtT,GAAe,KAAK,CAAE,KAAMsT,EAAE,KAAM,OAAQ,WAAY,CAAC,EACzDR,EAA0B,EAC1B,QACF,CAGA,IAAMa,EAAWzM,EAAK,MAAM,UACtB0M,EAAc1M,EAAK,MAAM,SAE/B,GAAIyM,GAAY,MAAQC,GAAe,KAAM,CAC3C,IAAMC,EAASF,EAAWC,EACpBE,EAAgBJ,EAAe,OAClC3Q,GAAMA,EAAE,MAAM,WAAa,MAAQ9C,GAAU0T,EAAU5Q,EAAE,MAAM,SAAU,CAC5E,EAEIgR,EAAY,GAChB,QAAWC,KAAOF,EAAe,CAC/B,IAAMG,EAAWD,EAAI,MAAM,UACrBE,EAAcF,EAAI,MAAM,SACxBG,EAASF,EAAWC,EAG1B,GAAIP,GAAYM,GAAYJ,GAAUM,EAAQ,CAC5CnU,GAAe,KAAK,CAAE,KAAMsT,EAAE,KAAM,OAAQ,kCAAmC,CAAC,EAChFR,EAA0B,EAC1BiB,EAAY,GACZ,KACF,CAIA,GADgB,KAAK,IAAIF,EAAQM,CAAM,EAAI,KAAK,IAAIR,EAAUM,CAAQ,EACxD,IAAQ,CAEpBjU,GAAe,KAAK,CAClB,KAAMsT,EAAE,KACR,OAAQ,uDACV,CAAC,EACDR,EAA0B,EAC1BiB,EAAY,GACZ,KACF,CACF,CACA,GAAIA,EAAW,QACjB,CAEA,IAAMK,EAAe,WACjBzR,EAAK0R,GAAUnN,EAAK,MAAM,WAAakN,CAAY,EACnDrU,GAAO4C,CAAE,IAAGA,GAAM,IAAI2R,GAAY,CAAC,IAGvC,IAAIC,EAAYrN,EAAK,MACjBqN,EAAU,WAAW,SAAS,GAAKA,EAAU,WAAW,cAAc,KACxEA,EAAYjB,EAAE,MAGhB,IAAIkB,EAAcD,EACZrR,GAAKgE,EAAK,OAAO,CAAC,GAAG,KACrBqJ,GAAQrJ,EAAK,MACfA,EAAK,MAAM,OAAO,CAAC,EAAE,YAAY,EAAIA,EAAK,MAAM,MAAM,CAAC,EACvD,WACJ,GAAIhE,GAAI,CACN,IAAMuR,EAAI,IAAI,KAAKvR,EAAE,EACrBsR,EAAc,GAAGC,EAAE,eAAe,CAAC,IAAI,OAAOA,EAAE,YAAY,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,IAAI,OAAOA,EAAE,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,IAAIlE,EAAK,EACzI,MACEiE,EAAcD,EAAU,QAAQ,YAAa,EAAE,EAAE,QAAQ,KAAM,GAAG,EAGpE,IAAMlD,GAAmB,CACvB,GAAGnK,EACH,GAAAvE,EACA,KAAM4R,EACN,YAAAC,EACA,SAAUlB,EAAE,KACZ,SAAUA,EAAE,KACZ,OAAQ3L,GAAgBT,EAAK,MAAM,GAAK,OACxC,iBAAkBU,GAAcV,EAAK,OAAQ,EAAE,EAC/C,QAASA,EAAK,MAAM,WAAakN,EACjC,QAAS,GACT,MAAOvU,GAAaW,GAAWX,GAAa,MAAM,CACpD,EAEA,GADAW,KACIF,GAAkB,MAEtB,MAAM0E,GAAQ,KAAKqM,EAAK,EACxBtR,GAAO4C,CAAE,EAAI0O,GACb1N,GAAQ,SAAS0N,EAAK,EACjB8B,IAASA,EAAUxQ,GACxBsQ,IACAG,IAEIA,GAA4B,IAC9BA,EAA2B,EAE/B,OAASsB,EAAK,CACZ1U,GAAe,KAAK,CAClB,KAAMsT,EAAE,KACR,OAAQ,gBAAgBoB,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,EAC1E,CAAC,EACD5B,EAA0B,CAC5B,CACF,CAGA,IAAMd,EAAgB,SAAS,eAAe,gBAAgB,EAC1DA,IACEhS,GAAe,OAAS,GAC1BgS,EAAc,UAAU,OAAO,QAAQ,EACvCA,EAAc,MAAQ,WAAWhS,GAAe,MAAM,oCAEtDgS,EAAc,UAAU,IAAI,QAAQ,GAIxC,IAAM2C,EAAc3U,GAAe,OAAS4S,EAW5C,GAVI,CAAC+B,GAAe5O,GAClBA,EAAO,UAAU,IAAI,QAAQ,EAG3BkN,EAAQ,IACVxM,GAAU,YAAYwM,CAAK,SAASA,EAAQ,EAAI,IAAM,EAAE,EAAE,EAC1DvO,GAAa,CAAC,CAACyO,GAAWA,IAAY5S,EAAU,EAC5C4S,GAASrQ,GAAYqQ,CAAO,GAG9BwB,EAAa,CACf,IAAM5B,EAAa,SAAS,cAAc,wBAAwB,EAC9DA,IAAYA,EAAW,YAAc,WAEzC,MAAM,IAAI,QAAS9H,GAAM,WAAWA,EAAG,IAAI,CAAC,CAC9C,CACF,QAAE,CACIlF,GAAQA,EAAO,UAAU,IAAI,QAAQ,CAC3C,CACF,CAEA,SAASsC,IAA0B,CACjC,IAAMuJ,EAAY,SAAS,eAAe,cAAc,EACxD,GAAI,CAACA,EAAW,OAEhB,IAAIgD,EAAgC,KAEpChD,EAAU,iBAAiB,YAAcxP,GAAM,CAC7C,IAAM6G,EAAU7G,EAAE,OAAuB,QAAQ,cAAc,EAC1D6G,IACL2L,EAAY3L,EACZ7G,EAAE,aAAc,cAAgB,OAChC6G,EAAO,UAAU,IAAI,eAAe,EAEpC,WAAW,IAAOA,EAAO,MAAM,QAAU,MAAQ,CAAC,EACpD,CAAC,EAED2I,EAAU,iBAAiB,WAAaxP,GAAM,CAC5CA,EAAE,eAAe,EACjBA,EAAE,aAAc,WAAa,OAC7B,IAAM6G,EAAU7G,EAAE,OAAuB,QAAQ,cAAc,EAC/D,GAAI6G,GAAUA,IAAW2L,EAAW,CAClC,IAAM1S,EAAO+G,EAAO,sBAAsB,EACpC4L,EAAOzS,EAAE,QAAUF,EAAK,KAAOA,EAAK,MAAQ,EAClD0P,EAAU,aAAagD,EAAYC,EAAO5L,EAAO,YAAcA,CAAM,CACvE,CACF,CAAC,EAED2I,EAAU,iBAAiB,UAAW,IAAM,CAC1C,GAAI,CAACgD,EAAW,OAChBA,EAAU,UAAU,OAAO,eAAe,EAC1CA,EAAU,MAAM,QAAU,GAC1BA,EAAY,KAGZ,IAAM7E,EAAO,MAAM,KAAK6B,EAAU,iBAAiB,cAAc,CAAC,EAAE,IACjEhQ,GAAQA,EAAmB,QAAQ,MACtC,EACAP,GAAU,kBAAkB0O,CAAI,EAChC5O,GAAiB,CACnB,CAAC,CACH,CAEA,SAASuB,IAAsB,CAC7B,IAAMoS,EAAU,SAAS,eAAe,eAAe,EACjDC,EAAQ,SAAS,eAAe,cAAc,EACpD,GAAI,CAACD,GAAW,CAACC,EAAO,OAExBD,EAAQ,UAAU,OAAO,WAAW,EACpC,IAAME,EAAa,KAAK,IAAI,EAAGF,EAAQ,YAAc,GAAG,EACpDG,EAAS,EACTC,EAAS,GAEb,MAAM,KAAKH,EAAM,QAAQ,EAAE,QAASnT,GAAO,CACzC,IAAMuT,EAASvT,EAIf,GAHIuT,EAAO,KAAO,kBAElBA,EAAO,UAAU,OAAO,iBAAiB,EACrC,CAACA,EAAO,UAAU,SAAS,QAAQ,GAAG,OAE1C,IAAMC,EAAyB,IADbD,EAAO,QAAQ,QAAU,IACG,OAAS,EACvDF,GAAUG,EAAyB,EAE/BH,EAASD,IACXE,EAAS,GACTC,EAAO,UAAU,IAAI,iBAAiB,EAE1C,CAAC,EAED,IAAME,EAAa,SAAS,eAAe,eAAe,EACtDA,GAAYA,EAAW,UAAU,OAAO,SAAU,CAACH,CAAM,EAEzDA,GAAQJ,EAAQ,UAAU,IAAI,WAAW,CAC/C,CAEA,SAAS,iBAAiB,mBAAoBvP,EAAI", - "names": ["UrlState", "_state", "_lastSearch", "_syncTimeout", "_shouldPush", "read", "p", "s", "metricsRaw", "v", "isDesc", "field", "parts", "_sync", "dir", "search", "val", "url", "get", "patch", "partial", "push", "k", "key", "refresh", "reset", "InMemoryStorage", "track", "id", "key", "value", "IndexedDBStorage", "resolve", "reject", "req", "db", "name", "mode", "res", "rej", "tx", "activeDriver", "Storage", "UrlState", "k", "v", "FitParser", "haversine", "lat1", "lon1", "lat2", "lon2", "phi1", "phi2", "deltaPhi", "deltaLambda", "a", "compactId", "timestamp", "buf", "shortRandom", "fmtDuration", "s", "fmtSecs", "h", "m", "fmtPace", "seconds", "mins", "secs", "fmtDate", "ts", "d", "fmtDateTime", "iso", "fmtFileSize", "bytes", "k", "sizes", "i", "escHtml", "str", "getTagColor", "name", "hash", "gaussianSmooth", "data", "sigma", "size", "kernel", "half", "sum", "x", "result", "val", "weightSum", "idx", "hexToRgba", "hex", "alpha", "r", "g", "b", "calculateBounds", "pts", "minLat", "maxLat", "minLon", "maxLon", "p", "SIMPLIFY_CAP", "simplifyLats", "simplifyLons", "simplifyEles", "simplifyDists", "enrichEleBuf", "enrichPwrBuf", "enrichSpdBuf", "simplifyTrack", "minDistanceMeters", "n", "lats", "lons", "eles", "dists", "i", "tolerances", "errChecksum", "degToRad", "ti", "tolDegSq", "anchor", "cosLat", "dx", "dy", "dz", "mid", "mx", "my", "result", "lastPoint", "tolBias", "haversine", "Parsers", "enrichPoints", "totalDist", "prev", "d", "dt", "de", "eleBuf", "pwrBuf", "spdBuf", "gradeWindows", "npAccum", "scaleH", "wi", "w", "invW", "pSum", "sSum", "pAvg", "airDensity", "slopeAngle", "smoothBias", "hrZoneThresholds", "ftp", "computeStats", "includeCurves", "stats", "powerSum", "powerN", "hrSum", "hrN", "cadSum", "cadN", "speedSum", "speedN", "batterySum", "batteryN", "tempSum", "tempN", "hasTemp", "shifts", "hasGears", "diff", "t0", "t1", "calculateHRZones", "calculateHRCurve", "calculatePowerCurve", "calculatePowerZones", "ensureCurvesAndZones", "track", "s", "analyzeTrackSections", "sections", "quarterLabels", "q", "sIdx", "eIdx", "subPts", "thirdLabels", "t", "kmStartIdx", "nextKmMeters", "kmIndex", "kmPts", "win", "inClimb", "climbStart", "climbIdx", "inSprint", "sprintStart", "sprintIdx", "sprintThreshold", "dEle", "dDist", "rollingGrade", "segPts", "pwr", "findOverlaps", "tracksList", "overlaps", "ta", "ptsA", "stepA", "j", "tb", "ptsB", "stepB", "shared", "minCorridor", "a", "pa", "nearest", "b", "pb", "STANDARD_CURVE_DURATIONS", "calculateSlidingMax", "data", "durations", "len", "prefix", "curve", "hasAny", "di", "maxSum", "bestIdx", "limit", "currentSum", "powerData", "nonZero", "v", "hrData", "zones", "thresholds", "pw", "z", "setFTP", "val", "getFTP", "hr", "setHRZones", "getHRZones", "extractXmlTag", "block", "openTag", "closeTag", "start", "extractXmlAttr", "tagOpen", "attrPrefix", "cachedDateKey", "cachedDayMs", "parseIntSlice", "text", "end", "neg", "c0", "digits", "c", "parseFloatSlice", "intPart", "fracPart", "fracDiv", "inFrac", "res", "fastParseTimeSlice", "y", "m", "key", "hh", "mm", "ss", "ms", "extractAttrFloat", "vStart", "parseGPX", "buf", "predecodedText", "firstTrkpt", "header", "trkIdx", "name", "gpxOpenEnd", "device", "points", "pos", "trkStart", "openEnd", "trkEnd", "lat", "lon", "ele", "time", "cad", "power", "temp", "speed", "gearFront", "gearRear", "gearFrontTooth", "gearRearTooth", "battery", "lt", "gt", "c1", "tagLen", "nextLt", "vEnd", "expectedCloseGt", "closeGt", "gears", "parseTCX", "firstTp", "creatorBlock", "tpStart", "tpEnd", "fastDecodeFitData", "dv", "headerSize", "dataSize", "endOffset", "GARMIN_EPOCH_SEC", "SEMICIRCLE_TO_DEG", "defs", "file_ids", "sessions", "records", "events", "device_infos", "offset", "hdr", "localNum", "littleEndian", "globalMsgNum", "numFields", "fields", "recordSize", "num", "size", "type", "def", "le", "gNum", "ts", "rawLat", "rawLon", "rawAlt", "rawDist", "rawSpd", "msg", "fOff", "f", "bType", "sportMap", "evName", "parseFIT", "resolve", "reject", "handleParsedFitData", "error", "devices", "sport", "subSport", "getDeviceName", "fid", "antId", "existing", "statusReports", "idx", "gearEvents", "e", "front", "rear", "frontTooth", "rearTooth", "ft", "fg", "rt", "rg", "lastBattery", "statusIdx", "lastFrontGear", "lastRearGear", "lastFrontTooth", "lastRearTooth", "gearIdx", "validPoints", "ri", "r", "ex", "fastData", "FitParser", "parseKML", "doc", "nameEl", "coordEls", "el", "line", "parts", "parseFile", "file", "ext", "MapView", "trackData", "customClickHandler", "init", "onSelectCb", "onMoveCb", "onPointClickCb", "onPointHoverCb", "onDblClickCb", "switchBasemap", "layer", "addTrack", "t", "addTracks", "ts", "removeTrack", "id", "clearTracks", "removeAllTracks", "setTrackVisible", "visible", "setSelectedTrack", "fit", "fitAll", "fitTrack", "showCursorAt", "lat", "lon", "hideCursor", "highlightSegment", "pts", "start", "end", "colors", "clearHighlight", "setTrackHover", "hover", "ensureVisible", "centerOn", "zoom", "force", "closePopup", "invalidateSize", "getPosition", "setPosition", "lng", "colorTrackByMetric", "clearMetricColor", "findTracksPassingThroughPoints", "points", "radius", "handler", "uPlot", "Zones", "getPowerZones", "ftp", "Parsers", "thresholds", "t", "names", "colors", "zones", "last", "i", "getHRZones", "Metrics", "METRICS", "v", "p", "pts", "fillNulls", "vam", "i", "prev", "de", "dt", "SPORTS", "getSportIcon", "sport", "key", "ChartView", "plots", "renderedTrack", "renderedXAxis", "renderedSpeedMode", "renderedMapColorMetric", "syncKey", "scaleSyncing", "cursorSyncing", "activeMetrics", "availableMetrics", "smoothedMetrics", "metricsIncludingZero", "xAxis", "currentTrack", "allTracks", "selAnchorVal", "selEndVal", "isDragging", "updatingRange", "pinnedPtIdx", "lastMouseXVal", "lastHistMouseEvent", "hoveredHistData", "hoveredHistCanvas", "currentXRange", "targetXRange", "animId", "onCursorMoveCb", "onRangeChangeCb", "onClickCb", "onPinChangeCb", "HIST_W", "ROW_BODY_PADDING", "HIST_GAP", "statsVisible", "histTooltipEl", "container", "emptyEl", "selStatsEl", "resetSelBtn", "mapColorMetric", "onMapColorChangeCb", "init", "onCursorMove", "onRangeChange", "onClick", "onPinChange", "updateHistTooltip", "uPlot", "cancelSelection", "navKeys", "activeNavKeys", "e", "key", "u", "min", "max", "moveStep", "zoomFactor", "newMin", "newMax", "center", "factor", "xFull", "d", "setVisibleRange", "animate", "startMin", "startMax", "lerp", "a", "b", "t", "step", "tMin", "tMax", "cMin", "cMax", "loadTrack", "track", "others", "deferRender", "METRICS", "def", "p", "m", "el", "pill", "metric", "isAvailable", "updateStats", "render", "clear", "destroyPlots", "chartStats", "clearSelectionStats", "resetState", "overflowEl", "toolbar", "toggleMetric", "setSmooth", "metricKey", "enabled", "skipRender", "has", "setZeroInclusion", "includeZero", "setActiveMetrics", "keys", "setXAxis", "axis", "pts", "t0", "convert", "val", "idx", "dTarget", "tTarget", "newRange", "r0", "r1", "toggleStats", "histCol", "resize", "setMapColorChangeCb", "cb", "toggleMapColor", "_updateMapColorBtns", "_fireMapColorCb", "plot", "colors", "_computePointColors", "yData", "vals", "v", "sport", "sportDef", "SPORTS", "defaultMode", "speedMode", "UrlState", "paceUnit", "gradientColor", "speed", "speedColor", "lerpHex", "resetZoom", "updateSelOverlay", "redrawHistograms", "xData", "setSelectionStats", "stats", "fmt", "id", "fmtSecs", "restoreSelection", "totalDuration", "tOffset", "xMin", "xMax", "updateAnchorLines", "w", "anyResized", "histCanvas", "histData", "drawHistogram", "keepState", "savedRange", "savedScroll", "available", "containerW", "canReuse", "lastValidX", "existingByKey", "availSet", "isSmoothed", "isIncZero", "nextSiblingRows", "nextExisting", "i", "ex", "reused", "uplot", "s", "prevSync", "initHoverBinI", "buildHistBins", "span", "transform", "fmtAxis", "unit", "label", "fmtPace", "fillNulls", "gaussianSmooth", "createChart", "initialRange", "insertBeforeEl", "gradData", "smoothGradient", "row", "header", "labelEl", "smoothBtn", "mapColorBtn", "zeroBtn", "incZero", "statsTotalEl", "statsSelEl", "statsContainer", "actionsEl", "rightActionsEl", "paceToggle", "btn", "mode", "isDefault", "rowBody", "plotEl", "fixedMinLabel", "fixedMaxLabel", "isDistAxis", "formatX", "range", "dec", "absV", "h", "hh", "mm", "ss", "incZeroDefault", "gMin", "gMax", "allSum", "allCount", "filtMin", "filtMax", "filtSum", "filtCount", "fullStatsAll", "fullStatsFiltered", "gPad", "fixedYRange", "statsTotalInitialized", "updateHeaderStats", "visibleMin", "visibleMax", "getHtml", "isFull", "rangeStats", "es", "elevationRangeStats", "initializingScale", "uOpts", "_si", "_u", "mn", "mx", "axisIdx", "scaleMin", "scaleMax", "targetLabels", "idealIncr", "incrs", "incr", "splits", "precision", "pos", "top", "drawTrackPath", "drawElevationGradient", "drawGradientChart", "drawMetricColorFill", "drawPinnedDot", "drawYAxisHighlight", "hIdx", "hasPinned", "hasHover", "cy", "drawVerticalLineOnly", "hexToRgba", "ctx", "dpr", "bb", "ax", "fontSize", "fontStr", "tw", "visibleL", "visibleR", "padH", "padV", "bw", "bh", "bx", "by", "drawXAxisLabels", "showHover", "updateTooltip", "binI", "other", "left", "width", "overlay", "selFill", "anchorLine", "anchorLabel", "anchorHandle", "anchorMarker", "endLine", "endLabel", "endHandle", "endMarker", "curYVal", "pinYVal", "self", "attachHandleDrag", "mousedownX", "rect", "attachHistTooltip", "aX", "eX", "overW", "overH", "plotBottom", "isAnchorVisible", "isEndVisible", "fillL", "fillR", "aText", "fmtXVal", "aLabelW", "aIcon", "eText", "eLabelW", "eIcon", "handleEl", "isAnchor", "startX", "startVal", "pxPerUnit", "onMove", "me", "dx", "newVal", "onUp", "BINS", "lo", "hi", "cnt", "bins", "binAccum", "k", "bi", "prev", "next", "canvas", "chartH", "hoverBinI", "hasSel", "selBins", "selBinAccum", "x", "W", "H", "peak", "pad", "plotW", "plotH", "binY", "binH", "baseAlpha", "total", "pts2", "cumSum", "my", "cp", "font9", "avgY", "minLabelY", "maxLabelY", "labelHeight", "countLower", "countHigher", "pLower", "pHigher", "font8", "textY", "fontB10", "midX", "getBinAt", "lineEl", "relY", "rawI", "count", "pct", "low", "high", "zoneHtml", "mid", "zones", "Zones", "zIdx", "z", "finalZIdx", "totalAccum", "totalPct", "html", "stotalAccum", "stotalPct", "ttH", "ttW", "binCenterY", "sum", "n", "gain", "loss", "prevEle", "isDist", "diff", "cx", "gColor", "g", "p0", "p1", "content", "front", "rear", "color44", "gradientColorRgbaCache", "gradientColorRgba", "c", "yMin", "yMax", "xScale", "yScale", "yBase", "idxs", "iStart", "iEnd", "byColor", "prevIdx", "xv1", "xv0", "x0", "y0", "x1", "y1", "color", "segs", "j", "drawHoverLine", "xVal", "opacity", "skipLine", "distVal", "timeVal", "bottomLabel", "topLabel", "drawPill", "text", "y", "isTop", "rx", "clampedRx", "ry", "pillH", "yVal", "cyClamp", "drawAreaFillAbove", "yDir", "yMult", "inSegment", "hasAnySegment", "lastPx", "xv", "yv", "px", "py", "ah", "ar", "ag", "ab", "br", "bg", "rr", "rg", "rb", "absG", "kmh", "windowMetres", "grads", "j0", "j1", "data", "res", "right", "getAvg", "avgSpeed", "avgPower", "avgCadence", "INTERVAL_CAP", "ivPwr", "ivHr", "ivSpd", "ivEle", "ivCad", "ivSmoothed", "ivKdeBins", "intervalWindows", "analyzeTelemetryIntervals", "tracksList", "selStartSec", "selEndSec", "intervalScore", "ti", "sStart", "sEnd", "inv35", "invSigmaSq", "omega", "sgPwr", "sgHr", "sgSpd", "dP", "gauss", "harmonic", "sectionRanges", "si", "secStart", "secEnd", "secLen", "wi", "invW", "winSum", "winEle", "maxInterval", "avg", "norm", "newActive", "isStepped", "drawBackgroundTracks", "GAP_THRESHOLD", "field", "first", "prevP", "prevXVal", "lastFrontGear", "fMin", "fMax", "fg", "rMin", "rMax", "isTimeAxis", "gapSec", "prevDrawnI", "prevX", "prevY", "segmentColor", "prevXv", "SENSOR_ICONS", "Metrics", "onTagsChangeCb", "onDeleteTrackCb", "initDetails", "onTagsChange", "onDeleteTrack", "resetDetails", "container", "DETAIL_CAP", "detailChannels", "stabilityWindows", "analyzeTrackDetails", "track", "allTracks", "pts", "n", "stabilityAccum", "i", "p", "wi", "w", "invW", "halfW", "ci", "ch", "sum", "sumSq", "autoCov", "jitterSum", "invNoise", "v", "old", "mean", "variance", "lagVal", "diff", "diffSqNoise", "likelihood", "damp", "sections", "Parsers", "splitRows", "si", "sec", "st", "secPtsCount", "secJitter", "dp", "dh", "secStab", "fmtSecs", "gearMap", "fg", "rg", "key", "entry", "gearMatrix", "a", "b", "combo", "g", "cohort", "distRank", "pwrRank", "elevRank", "cohortPwrSum", "cohortDistSum", "ti", "peer", "cohortAvgPower", "cohortAvgDistKm", "renderDetails", "globalTags", "sectionRange", "activeTrack", "t0Base", "ts0", "ts1", "iMin", "iMax", "subPts", "subStats", "s", "t0", "detailAnalysis", "telemetryStabilityPct", "escHtml", "t", "fmtFileSize", "getSportIcon", "SPORTS", "fmtDateTime", "sensor", "gm", "sr", "seen", "d", "name", "manufacturer", "extra", "battery", "sourceIcon", "deviceIcon", "nameLower", "tagContainer", "tagInput", "addBtn", "renderTags", "tags", "tag", "c", "getTagColor", "el", "btn", "e", "Storage", "addTag", "val", "titleInput", "sportTrigger", "showSportMenu", "anchorEl", "popup", "def", "item", "isActive", "iconEl", "nameEl", "clearItem", "isClear", "rect", "closeHandler", "uPlot", "courses", "getCoursesForTrack", "track", "c", "pt", "passesPoint", "trackPt", "haversine", "activeCourseId", "isEditMode", "openCourseId", "toastFn", "courseLayer", "initCourses", "showToast", "toastFn", "loadCourses", "resetCourses", "courses", "activeCourseId", "openCourseId", "isEditMode", "container", "prepareBenchmarkCourses", "allTracks", "specs", "i", "spec", "t", "n", "pStart", "pMid", "pEnd", "getBenchmarkCourseIds", "c", "stored", "Storage", "e", "saveCourses", "calculateCourseDistance", "course", "total", "p1", "p2", "haversine", "findCourseRange", "track", "coursePoints", "currentPtIdx", "startIdx", "endIdx", "tp", "cp", "calculateCourseStats", "pts", "s", "startTime", "duration", "totalPower", "powerCount", "totalHR", "hrCount", "totalSpeed", "speedCount", "totalCadence", "cadenceCount", "totalAscent", "prev", "de", "dist", "formatDuration", "seconds", "h", "m", "renderCourseTableHeaders", "METRICS", "renderCourseTableCells", "stats", "sport", "dateStr", "paceUnit", "SPORTS", "paceStr", "paceSeconds", "fmtPace", "COURSE_CAP", "courseTrkLats", "courseTrkLons", "courseTrkPwrs", "courseGateLats", "courseGateLons", "DTW_SAMPLES", "DTW_BAND", "dtwRefProfile", "dtwCandProfile", "dtwPrevRow", "dtwCurrRow", "renderCourses", "corridorDeviationSum", "targetCourses", "candidateIds", "MapView", "p", "numGates", "g", "segFloat", "segIdx", "frac", "pA", "pB", "ci", "id", "pt", "gLat", "gLon", "minDist", "bestIdx", "d", "idx", "val", "jStart", "jEnd", "rVal", "j", "diff", "diffSq", "cost", "m1", "m2", "m3", "prevMin", "matchingIds", "isOpen", "tracksHtml", "matchedTracksWithStats", "range", "span", "q1Idx", "q2Idx", "q3Idx", "s1Stats", "s2Stats", "s3Stats", "s4Stats", "fmtDate", "a", "b", "UrlState", "escHtml", "createNewCourse", "el", "editCourse", "renameCourse", "deleteCourse", "selectCourse", "row", "trackId", "selectTrack", "t0", "sIdx", "eIdx", "tMin", "tMax", "axis", "ChartView", "selMin", "selMax", "name", "newCourse", "nameEl", "currentName", "input", "save", "newName", "clearCourseLayer", "courseLayer", "selectCourse", "id", "open", "activeCourseId", "openCourseId", "isEditMode", "MapView", "clearCourseLayer", "renderCourses", "deleteCourse", "courses", "c", "saveCourses", "toastFn", "insightPlots", "destroyInsightPlots", "p", "initInsights", "showToast", "resetInsights", "el", "container", "INSIGHT_CAP", "inPwrArr", "inHrArr", "inCadArr", "inSpdArr", "inVamArr", "inPrefixPwr", "inPrefixVam", "mmpDurations", "analyzeTrackPhysiology", "pts", "cpBase", "sections", "n", "i", "pt", "h", "c", "sp", "gr", "vam", "envelopeChecksum", "di", "d", "limit", "maxP", "maxV", "j", "sumP", "sumV", "minWPrimeBal", "wBal", "matchesBurned", "inMatchBurn", "half", "efSum1", "efSum2", "qCounts", "thresholdCad", "thresholdTorque", "cad", "invH", "diff", "dcp", "dep", "tauDyn", "torque", "ef", "ef1", "ef2", "decouplingPct", "quadrantPct", "sectionPeaks", "sec", "st", "durHours", "renderInsights", "track", "allTracks", "sectionRange", "Parsers", "activeRange", "UrlState", "activePts", "s", "t0", "startMs", "endMs", "iMin", "iMax", "phys", "grid", "chartWidth", "renderCurveCard", "Metrics", "card", "metricKey", "color", "isMapColored", "ChartView", "totalTime", "a", "b", "zones", "Zones", "zonesHtml", "time", "z", "pct", "rangeText", "fmtSecs", "e", "current", "btn", "showPowerZoneSettings", "showHRZoneSettings", "climbingCard", "distKm", "grade", "effCard", "secCard", "escHtml", "trackCourses", "getCoursesForTrack", "coursesCard", "renderCourseTableHeaders", "range", "findCourseRange", "statsHtml", "stats", "calculateCourseStats", "startTime", "dateStr", "fmtDate", "renderCourseTableCells", "courseId", "selectCourse", "course", "MapView", "opts", "curve", "label", "unit", "icon", "tableWrap", "toggleBtn", "toggleIcon", "isHidden", "mapColorBtn", "key", "tbody", "durations", "entry", "val", "row", "fmtDuration", "startIdx", "duration", "endIdx", "tMin", "tMax", "chartEl", "xData", "yData", "curYVal", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "idx", "hasFocus", "mousePy", "pointPy", "cx", "cy", "durVal", "pcx", "pcy", "plot", "uPlot", "anchorEl", "popup", "rect", "inputs", "newZones", "Storage", "dismiss", "ftp", "input", "newFtp", "uPlot", "currentTracks", "currentTrack", "plot", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "playIntervalId", "isPolar", "updateSliderLabel", "sliderVal", "timeSecs", "fmtSecs", "resetCombined", "playIntervalId", "plot", "currentTracks", "currentTrack", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "isPolar", "tooltip", "container", "COMBINED_CAP", "combinedDensityGrid", "computeMultiTrackCorrelationAndSections", "allTracks", "matrixTracks", "numTrk", "pairs", "p", "aggPts", "corrSum", "correlations", "pi", "pair", "sumX", "sumY", "sumXX", "sumYY", "sumXY", "count", "t", "pts", "n", "k", "x", "y", "pw", "h", "cd", "bx", "by", "rVal", "slope", "meanX", "meanY", "varX", "varY", "covXY", "denom", "g", "sectionLabels", "sectionRows", "t1", "t2", "q", "fStart", "fEnd", "sliceStats", "trk", "sIdx", "eIdx", "pSum", "hSum", "spSum", "cnt", "i", "pt", "st1", "st2", "cohortPwrSum", "setCombinedMetrics", "xKey", "yKey", "renderCombined", "setCombinedPolar", "polar", "setCombinedSliderProgress", "fraction", "clamped", "maxLen", "slider", "updateSliderLabel", "trackOrTracks", "track", "metrics", "ChartView", "availableMetrics", "key", "def", "xDef", "yDef", "summaryHtml", "s1", "s2", "distDiff", "pwrDiff", "hrDiff", "eleDiff", "shiftsDiff", "totalDist", "totalElev", "totalDur", "avgPwr", "maxPwr", "avgHr", "maxHr", "tempDiff", "avgTemp", "maxTemp", "totalShifts", "fmtSecs", "sr", "c", "e", "showMenu", "sliderVal", "playBtn", "startPlaying", "stopPlaying", "updatePlot", "resizeCombined", "plotContainer", "w", "size", "anchorEl", "axis", "el", "popup", "item", "currentVal", "rect", "close", "xData", "seriesList", "dataArrays", "yArr", "width", "height", "opts", "uPlot", "t0", "chronoData", "idx", "d", "xVals", "yVals", "xMin", "xMax", "yMin", "yMax", "xVal", "yVal", "theta", "r", "px", "py", "a", "b", "yData", "hexToRgba", "u", "vals", "v", "seriesIdx", "dataIdx", "cursorLeft", "cursorTop", "minD2", "closestIdx", "cx", "cy", "dx", "dy", "d2", "ctx", "dpr", "started", "startIdx", "endIdx", "xVal1", "yVal1", "xVal2", "yVal2", "cx1", "cy1", "cx2", "cy2", "progress", "lineWidth", "alpha", "fillAlpha", "timeSecs", "distKm", "origX", "origY", "canvasRect", "originalIdx", "uPlot", "computeAccumulatedMetric", "allTracks", "extractor", "refTs", "i", "st", "now", "currentYear", "oneYearAgoMs", "sixMonthsAgoMs", "oneMonthAgoMs", "currentYearVal", "pastYearVal", "past6mVal", "past1mVal", "totalVal", "minTime", "t", "val", "time", "msecPerWeek", "currentYearStart", "currentYearWeeks", "pastYearWeeks", "past6mWeeks", "past1mWeeks", "totalWeeks", "renderAccumulatedTable", "accumulated", "isDistance", "unit", "factor", "format", "computeMultiMetricAccumulated", "distance", "elevation", "durationHours", "tss", "durSec", "avgPwr", "ftp", "intensityFactor", "workKj", "climbCount", "s", "renderAccumulatedProgressSummary", "summary", "fmt", "v", "digits", "r", "evolutionPlots", "activeEvolutionCards", "currentEvolutionGrouping", "destroyEvolutionPlots", "p", "resetEvolution", "container", "setEvolutionGrouping", "grouping", "c", "setEvolutionRange", "range", "UrlState", "toolbarRangeCtrl", "b", "setEvolutionPinnedDuration", "dur", "EVO_CAP", "evoPwrPrefix", "evoHrPrefix", "evoSpdPrefix", "evoStressArr", "evoDailyTrimp", "envelopeDurations", "renderEvolution", "currentTrack", "allTracks", "onTrackSelect", "onDateRangeSelect", "currentRange", "track", "Parsers", "totalFatigue", "totalFitness", "ti", "pts", "n", "i", "pw", "h", "sp", "el", "hrRatio", "di", "d", "limit", "maxP", "maxH", "j", "dh", "alphaA", "oneMinusA", "alphaC", "oneMinusC", "hrRest", "invHrSpan", "atl", "ctl", "kh", "trimp", "dayIdx", "atl365", "ctl365", "day", "load", "cards", "Metrics", "grid", "renderAccumulatedProgressSummary", "gridWidth", "progressSync", "uPlot", "renderProgressCard", "distanceScroll", "elevationScroll", "btn", "onRangeChange", "pill", "target", "onPinChange", "t", "card", "renderCurveEvolutionCard", "opts", "metricKey", "label", "unit", "color", "icon", "trackName", "mainChart", "cardContainer", "row1", "legendEl", "row2", "sideBySide", "chartEl", "maxCurve", "curve", "name", "date", "fmtDate", "trackInfo", "data", "val", "currentCurve", "allDurations", "durations", "a", "xData", "yDataCurrent", "entry", "yDataMax", "validTracks", "xTimeline", "yTimelineData", "currentDur", "tracksFiltered", "pinnedDur", "getFilteredData", "maxTime", "minTime", "filteredIndices", "idx", "xFiltered", "rawY", "rawYFiltered", "smoothedYFiltered", "gaussianSmooth", "timelineChart", "curYVal", "optsUPlot", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "fmtDuration", "pcx", "pcy", "curVal", "dotRadius", "dotColor", "activeSeriesIdx", "cursorLeft", "cursorTop", "minD2", "nearestIdx", "radius", "maxD2", "yCur", "yMax", "px", "py", "dx", "dy", "d2", "xValStr", "xbw", "pillH", "xLabelX", "clampedXBx", "xLabelY", "yValStr", "ybw", "yLabelX", "yLabelY", "cx", "cy", "durVal", "mxVal", "html", "lowerBound", "upperBound", "labelEl", "clickedDur", "newPinnedDur", "stats", "bestIdx", "duration", "startPt", "endPt", "trackStart", "min", "max", "detailsEl", "cur", "mx", "mxId", "mxIdx", "e", "id", "lastNearestIdx", "timelineEl", "timelineTooltip", "dataTimeline", "series", "optsTimeline", "ts", "tpcx", "tpcy", "tctx", "tdpr", "dateStr", "valStr", "yData", "y", "getWeekStart", "diff", "computeWeeklyDistance", "weeklyData", "weekStart", "weekKey", "week", "computeWeeklyElevation", "computeMonthlyDistance", "monthlyData", "monthStart", "monthKey", "computeMonthlyElevation", "type", "syncKey", "isDistance", "activeGrouping", "activeRange", "weeklySource", "monthlySource", "accumulated", "computeAccumulatedMetric", "renderAccumulatedTable", "yAxisEl", "tooltip", "yDataSmoothed", "chartClientW", "width", "maxVal", "mainOpts", "item", "start", "end", "startStr", "endStr", "self", "splits", "s", "scrollContainer", "applySeriesData", "filteredData", "newXData", "newYData", "newYDataSmoothed", "newWidth", "newMaxVal", "TRACK_COLORS", "POINT_ZOOM_LEVEL", "tracks", "skippedImports", "isSameDay", "t1", "t2", "d1", "d2", "cancelProcessing", "selectedId", "colorIdx", "followDot", "currentMapColors", "searchQuery", "searchRegex", "currentSort", "filters", "syncFiltersToUrl", "push", "UrlState", "v", "syncMetricsToUrl", "active", "ChartView", "metrics", "abbrs", "key", "SORT_OPTIONS", "showSortMenu", "anchorEl", "el", "popup", "opt", "item", "updateSearchSortUI", "renderTrackList", "rect", "close", "e", "showMetricMenu", "available", "def", "isNowActive", "pill", "updateToolbarLayout", "id", "idx", "dur", "selectTrack", "t", "pts", "pIdx", "t0", "p", "tMin", "tMax", "iMax", "selPts", "stats", "Parsers", "renderInsights", "MapView", "btn", "nav", "b", "tab", "panel", "c", "renderDetails", "getGlobalTags", "renderEvolution", "trackId", "range", "onChartRangeChange", "start", "end", "applyFilters", "updateFilterUI", "renderCombined", "renderCourses", "s", "resetBenchmarkState", "Storage", "resetCourses", "resetInsights", "resetDetails", "resetCombined", "resetEvolution", "toastContainer", "init", "fontTimerId", "fontTimeout", "resolve", "fontLoadPromise", "storageSelect", "selected", "params", "loader", "loaderText", "loaderSubtext", "progressBar", "mapLoader", "mapLoaderSpan", "urlState", "initInsights", "msg", "type", "showToast", "initDetails", "deleteTrack", "initCourses", "onMapMove", "onMapPointClick", "onMapDblClick", "onChartCursorMove", "onChartClick", "data", "currentUrlState", "applyState", "hrZones", "ftp", "saved", "a", "tracksToLoad", "updated", "calculateBounds", "simplifyTrack", "restoreId", "selectedTrackData", "processAndLoadTrack", "remaining", "index", "loadNextChunk", "initResizeHandle", "initSidebarResizer", "initMetricPillDraggable", "clearAll", "toggleMetric", "metric", "axis", "initDropZone", "handleFiles", "onFilterInput", "val", "burgerBtn", "dropdownContent", "isVisible", "target", "selectedSport", "m", "resizeCombined", "initBenchmarkTriggers", "preloadBenchmarkFiles", "readyEl", "camelReadyEl", "preloadedBenchmarkPayloads", "fileNames", "decoder", "name", "buf", "cleanName", "bytes", "ds", "stream", "text", "file", "warmSample", "parsed", "warmPts", "warmTrack", "warmTrack2", "warmList", "setCombinedPolar", "setCombinedSliderProgress", "setEvolutionGrouping", "setEvolutionRange", "setEvolutionPinnedDuration", "prepareBenchmarkCourses", "selectCourse", "r", "btnLoad", "btnAnalysis", "btnInsights", "btnDetails", "btnAggregate", "btnEvolution", "btnCourses", "activateTab", "tabName", "loadedFiles", "allTracks", "sortMode", "availableMetrics", "metricSets", "mSet", "filtered", "sections", "secStart", "secEnd", "cursorIdx", "primaryTrack", "tIdx", "trk", "globalTags", "i", "setCombinedMetrics", "frac", "selectedTwo", "onSelectCb", "refTracks", "refTrk", "rng", "courseIds", "getBenchmarkCourseIds", "cId", "powerCurveEntries", "needsEnrich", "handle", "isDragging", "h", "clampedH", "resizer", "sidebar", "w", "clampedW", "lat", "lng", "zoom", "pt", "min", "max", "fit", "iMin", "d0", "ts0", "ts1", "deferChartRender", "hadSelected", "activeTab", "code", "backdrop", "input", "btnConfirm", "btnCancel", "skipRender", "visible", "field", "trackTags", "ft", "activeCount", "badge", "searchInput", "o", "labelEl", "iconEl", "newTrackId", "currentXAxis", "keys", "abbr", "k", "updateSportFilterOptions", "commonContainer", "sports", "sportsArray", "burgerDropdown", "sport", "getSportIcon", "list", "emptyEl", "headerLabel", "ids", "ta", "tb", "sa", "sb", "cmp", "buildTrackItem", "all", "tag", "track", "date", "fmtDate", "tagsHtml", "getTagColor", "escHtml", "btnVis", "container", "showSkippedImportsModal", "listHtml", "btnClear", "importWarning", "zone", "items", "files", "queue", "entry", "readAllEntries", "res", "reader", "entries", "chunk", "child", "initialSkipCount", "loaderClose", "updateLoaderIconToWarning", "loaderIcon", "warningCount", "count", "countSpan", "firstId", "processedSinceLastUpdate", "validFiles", "f", "loaderFilename", "progressIdxEl", "totalEl", "existingTracks", "newStart", "newDuration", "newEnd", "sameDayTracks", "discarded", "ext", "extStart", "extDuration", "extEnd", "fallbackTime", "compactId", "shortRandom", "trackName", "displayName", "d", "err", "newWarnings", "draggedEl", "next", "toolbar", "pills", "availableW", "totalW", "hidden", "htmlEl", "deterministicPillWidth", "overflowEl"] + "sourcesContent": ["// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 URL State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Handles reading/writing application state to the URL.\n// Uses an incremental \"patch\" approach to preserve existing params.\n\nexport interface AppState {\n track?: string;\n map?: string;\n xaxis?: string;\n metrics?: string[];\n f_date?: (string | null)[];\n f_dist?: (number | null)[];\n f_dur?: (number | null)[];\n f_mets?: string[];\n f_tags?: string[];\n q?: string;\n re?: boolean;\n sort?: string;\n map_pos?: [number, number, number];\n storage?: 'memory' | 'indexeddb';\n sel?: [number, number];\n sel_point?: number;\n tab?: string;\n progress?: string;\n speed_mode?: string;\n}\n\nexport const UrlState = (() => {\n const initialPathname = typeof location !== 'undefined' ? location.pathname : '/';\n const initialSearch = typeof location !== 'undefined' ? location.search.replace(/^\\?/, '') : '';\n\n // Internal state and local in-memory query/navigation stack.\n let _state: AppState = {};\n let localSearch: string = initialSearch;\n let _lastSearch: string | null = null;\n let _syncTimeout: any = null;\n let _shouldPush = false;\n let historyEntries: Array<{ state: unknown; url: string }> = [\n {\n state: null,\n url: initialPathname + (initialSearch ? `?${initialSearch}` : ''),\n },\n ];\n\n function read(): AppState {\n const p = new URLSearchParams(localSearch);\n const s: AppState = {};\n\n if (p.has('track')) s.track = p.get('track')!;\n if (p.has('map')) s.map = p.get('map')!;\n if (p.has('xaxis')) s.xaxis = p.get('xaxis')!;\n if (p.has('tab')) s.tab = p.get('tab')!;\n if (p.has('sel_point')) s.sel_point = Number(p.get('sel_point'));\n if (p.has('speed_mode')) s.speed_mode = p.get('speed_mode')!;\n if (p.has('progress')) s.progress = p.get('progress')!;\n const metricsRaw = p.get('metrics');\n if (metricsRaw) s.metrics = metricsRaw.split(',').filter(Boolean);\n\n if (p.has('f_date')) {\n s.f_date = p\n .get('f_date')!\n .split(',')\n .map((v) => v || null);\n }\n if (p.has('f_dist')) {\n s.f_dist = p\n .get('f_dist')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_dur')) {\n s.f_dur = p\n .get('f_dur')!\n .split(',')\n .map((v) => (v ? Number(v) : null));\n }\n if (p.has('f_mets')) s.f_mets = p.get('f_mets')!.split(',');\n if (p.has('f_tags')) s.f_tags = p.get('f_tags')!.split(',');\n\n if (p.has('q')) s.q = p.get('q')!;\n if (p.has('re')) s.re = p.get('re') === '1';\n if (p.has('sort')) {\n const v = p.get('sort')!;\n const isDesc = v.startsWith('-');\n const field = isDesc ? v.substring(1) : v;\n s.sort = `${field}-${isDesc ? 'desc' : 'asc'}`;\n }\n\n if (p.has('map_pos')) {\n const parts = p.get('map_pos')!.split(',').map(Number);\n if (parts.length === 3 && parts.every(isFinite))\n s.map_pos = parts as [number, number, number];\n }\n\n if (p.has('storage')) s.storage = p.get('storage') as 'memory' | 'indexeddb';\n if (p.has('sel')) {\n const parts = p.get('sel')!.split(',').map(Number);\n if (parts.length === 2 && parts.every((v) => !isNaN(v) && isFinite(v)))\n s.sel = parts as [number, number];\n }\n\n return s;\n }\n\n // Sync _state to browser URL synchronously so no pending timer leaks across steps\n function _sync() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n\n const p = new URLSearchParams();\n\n // Add standard encoded params\n if (_state.track) p.set('track', _state.track);\n if (_state.map) p.set('map', _state.map);\n if (_state.xaxis && _state.xaxis !== 'time') p.set('xaxis', _state.xaxis);\n if (_state.tab && _state.tab !== 'graphs') p.set('tab', _state.tab);\n if (_state.storage && _state.storage !== 'memory') p.set('storage', _state.storage);\n if (_state.sel_point !== undefined) p.set('sel_point', String(_state.sel_point));\n if (_state.speed_mode) p.set('speed_mode', _state.speed_mode);\n if (_state.q) p.set('q', _state.q);\n if (_state.progress) p.set('progress', _state.progress);\n if (_state.re) p.set('re', '1');\n\n if (_state.sort) {\n const parts = _state.sort.split('-');\n const field = parts[0];\n const dir = parts[1];\n p.set('sort', (dir === 'desc' ? '-' : '') + field);\n }\n\n let search = p.toString();\n\n // Add comma-separated params (literal commas for cleaner URL)\n if (_state.metrics) search += `${search ? '&' : ''}metrics=${_state.metrics.join(',')}`;\n\n if (_state.f_date)\n search += `${search ? '&' : ''}f_date=${_state.f_date.map((v) => v || '').join(',')}`;\n\n if (_state.f_dist)\n search += `${search ? '&' : ''}f_dist=${_state.f_dist.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_dur)\n search += `${search ? '&' : ''}f_dur=${_state.f_dur.map((v) => v ?? '').join(',')}`;\n\n if (_state.f_mets) search += `${search ? '&' : ''}f_mets=${_state.f_mets.join(',')}`;\n\n if (_state.f_tags) search += `${search ? '&' : ''}f_tags=${_state.f_tags.join(',')}`;\n\n if (_state.map_pos) {\n const val = `${(+_state.map_pos[0]).toFixed(5)},${(+_state.map_pos[1]).toFixed(5)},${\n _state.map_pos[2]\n }`;\n search += `${search ? '&' : ''}map_pos=${val}`;\n }\n if (_state.sel) {\n const val = `${+_state.sel[0].toFixed(4)},${+_state.sel[1].toFixed(4)}`;\n search += `${search ? '&' : ''}sel=${val}`;\n }\n\n localSearch = search;\n if (search !== _lastSearch) {\n const pathname = typeof location !== 'undefined' ? location.pathname : '/';\n const url = pathname + (search ? `?${search}` : '');\n const entryState = read();\n if (_shouldPush) {\n historyEntries.push({ state: entryState, url });\n if (historyEntries.length > 100) {\n historyEntries.shift();\n }\n _shouldPush = false;\n } else if (historyEntries.length > 0) {\n historyEntries[historyEntries.length - 1] = { state: entryState, url };\n } else {\n historyEntries.push({ state: entryState, url });\n }\n _lastSearch = search;\n }\n }\n\n // Initial read\n _state = read();\n\n function get(): AppState {\n return { ..._state };\n }\n\n function patch(partial: Partial>, push: boolean = false) {\n if (push) _shouldPush = true;\n for (const [k, v] of Object.entries(partial)) {\n const key = k as keyof AppState;\n if (v === null || v === undefined) delete _state[key];\n else (_state as any)[key] = v;\n }\n _sync();\n }\n\n function refresh() {\n _state = read();\n }\n\n function reset() {\n if (_syncTimeout) {\n clearTimeout(_syncTimeout);\n _syncTimeout = null;\n }\n _state = {};\n _shouldPush = false;\n localSearch = '';\n _lastSearch = '';\n const pathname = typeof location !== 'undefined' ? location.pathname : '/';\n historyEntries = [{ state: null, url: pathname }];\n }\n\n return { read, get, patch, refresh, reset };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport { TrackData } from './parsers';\nimport { UrlState } from './url-state';\n\nexport interface StorageDriver {\n openDB(): Promise;\n save(track: TrackData): Promise;\n getAll(): Promise;\n remove(id: string): Promise;\n clear(): Promise;\n set(key: string, value: any): Promise;\n get(key: string): Promise;\n}\n\nclass InMemoryStorage implements StorageDriver {\n private trackStore = new Map();\n private settingStore = new Map();\n\n async openDB(): Promise {\n return Promise.resolve();\n }\n\n async save(track: TrackData): Promise {\n this.trackStore.set(track.id, track);\n return Promise.resolve();\n }\n\n async getAll(): Promise {\n return Promise.resolve(Array.from(this.trackStore.values()));\n }\n\n async remove(id: string): Promise {\n this.trackStore.delete(id);\n return Promise.resolve();\n }\n\n async clear(): Promise {\n this.trackStore.clear();\n this.settingStore.clear();\n return Promise.resolve();\n }\n\n async set(key: string, value: any): Promise {\n this.settingStore.set(key, value);\n return Promise.resolve();\n }\n\n async get(key: string): Promise {\n return Promise.resolve((this.settingStore.get(key) as T) ?? null);\n }\n}\n\nclass IndexedDBStorage implements StorageDriver {\n private db: IDBDatabase | null = null;\n private readonly DB_NAME = 'weg-gps-db';\n private readonly DB_VERSION = 2;\n\n async openDB(): Promise {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(this.DB_NAME, this.DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains('tracks'))\n db.createObjectStore('tracks', { keyPath: 'id' });\n if (!db.objectStoreNames.contains('settings')) db.createObjectStore('settings');\n };\n req.onsuccess = () => {\n this.db = req.result;\n resolve();\n };\n req.onerror = () => reject(req.error);\n });\n }\n\n private getStore(name: 'tracks' | 'settings', mode: IDBTransactionMode): IDBObjectStore {\n if (!this.db) throw new Error('IndexedDB not opened');\n return this.db.transaction(name, mode).objectStore(name);\n }\n\n async save(track: TrackData): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').put(track);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async getAll(): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readonly').getAll();\n req.onsuccess = () => res(req.result || []);\n req.onerror = () => rej(req.error);\n });\n }\n\n async remove(id: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('tracks', 'readwrite').delete(id);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async clear(): Promise {\n if (!this.db) return Promise.resolve();\n return new Promise((res, rej) => {\n const tx = this.db!.transaction(['tracks', 'settings'], 'readwrite');\n tx.objectStore('tracks').clear();\n tx.objectStore('settings').clear();\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n }\n\n async set(key: string, value: any): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readwrite').put(value, key);\n req.onsuccess = () => res();\n req.onerror = () => rej(req.error);\n });\n }\n\n async get(key: string): Promise {\n return new Promise((res, rej) => {\n const req = this.getStore('settings', 'readonly').get(key);\n req.onsuccess = () => res((req.result as T) ?? null);\n req.onerror = () => rej(req.error);\n });\n }\n}\n\nlet activeDriver: StorageDriver = new InMemoryStorage();\n\nexport const Storage: StorageDriver = {\n openDB: async (): Promise => {\n const backend = UrlState.get().storage;\n activeDriver = backend === 'indexeddb' ? new IndexedDBStorage() : new InMemoryStorage();\n await activeDriver.openDB();\n },\n save: (t) => activeDriver.save(t),\n getAll: () => activeDriver.getAll(),\n remove: (id) => activeDriver.remove(id),\n clear: () => activeDriver.clear(),\n set: (k, v) => activeDriver.set(k, v),\n get: (k: string) => activeDriver.get(k),\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport FitParser from 'fit-file-parser';\nimport { haversine } from './utils';\n\nexport interface TrackPoint {\n lat: number;\n lon: number;\n ele: number | null;\n time: number | null;\n hr: number | null;\n cad: number | null;\n power: number | null;\n speed: number | null;\n temp: number | null;\n gearFront: number | null;\n gearRear: number | null;\n gearFrontTooth: number | null;\n gearRearTooth: number | null;\n battery: number | null;\n gears: number | null;\n dist?: number;\n gradient?: number | null;\n verticalSpeed?: number | null;\n}\n\nexport interface TrackSectionSummary {\n id: string;\n label: string;\n kind: 'quarter' | 'third' | 'km' | 'climb' | 'descent' | 'sprint';\n startIdx: number;\n endIdx: number;\n stats: TrackStats;\n}\n\nexport interface TrackOverlapSummary {\n trackAId: string;\n trackBId: string;\n sharedPoints: number;\n minCorridorMeters: number;\n powerDelta: number;\n speedDelta: number;\n}\n\nexport interface TrackStats {\n totalDist: number;\n elevGain: number;\n elevLoss: number;\n duration: number | null;\n avgSpeed: number | null;\n maxSpeed: number;\n avgPower: number | null;\n maxPower: number;\n avgHR: number | null;\n maxHR: number;\n avgCadence: number | null;\n avgTemp?: number | null;\n minTemp?: number | null;\n maxTemp?: number | null;\n sensors: string[];\n startTime?: number | null;\n powerCurve?: Record | null;\n hrCurve?: Record | null;\n hrZones?: number[] | null; // Time in seconds for each zone\n powerZones?: number[] | null; // Time in seconds for each zone\n shifts?: number | null; // Total number of shifts detected\n avgBattery?: number | null;\n sections?: TrackSectionSummary[];\n}\n\nexport interface DeviceInfo {\n name?: string;\n manufacturer?: string;\n product?: string;\n serial?: string;\n version?: string;\n hardwareVersion?: string;\n type?: string;\n batteryStatus?: string;\n batteryVoltage?: number;\n batteryLevel?: number;\n sourceType?: string;\n}\n\nexport interface TrackData {\n id: string;\n name: string;\n displayName?: string;\n bounds?: { minLat: number; maxLat: number; minLon: number; maxLon: number };\n fileName?: string;\n fileSize?: number;\n device: string | null;\n devices?: DeviceInfo[];\n sport?: string | null;\n subSport?: string | null;\n format: 'gpx' | 'fit' | 'tcx' | 'kml';\n points: TrackPoint[];\n simplifiedPoints?: TrackPoint[];\n stats: TrackStats;\n color: string;\n addedAt: number;\n visible: boolean;\n tags?: string[];\n _filtered?: boolean;\n}\n\nexport function calculateBounds(pts: TrackPoint[]) {\n if (!pts.length) return null;\n let minLat = pts[0].lat;\n let maxLat = pts[0].lat;\n let minLon = pts[0].lon;\n let maxLon = pts[0].lon;\n for (const p of pts) {\n if (p.lat < minLat) minLat = p.lat;\n if (p.lat > maxLat) maxLat = p.lat;\n if (p.lon < minLon) minLon = p.lon;\n if (p.lon > maxLon) maxLon = p.lon;\n }\n return { minLat, maxLat, minLon, maxLon };\n}\n\nconst SIMPLIFY_CAP = 16384;\nconst simplifyLats = new Float64Array(SIMPLIFY_CAP);\nconst simplifyLons = new Float64Array(SIMPLIFY_CAP);\nconst simplifyEles = new Float64Array(SIMPLIFY_CAP);\nconst simplifyDists = new Float64Array(SIMPLIFY_CAP);\nconst enrichEleBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichPwrBuf = new Float64Array(SIMPLIFY_CAP);\nconst enrichSpdBuf = new Float64Array(SIMPLIFY_CAP);\n\nexport function simplifyTrack(pts: TrackPoint[], minDistanceMeters: number): TrackPoint[] {\n const n = pts.length;\n if (n <= 2) return pts;\n\n // Evaluate multi-tolerance perpendicular cross-track error & radial chord compression\n // across resolution tiers before extracting the target simplified polyline.\n const lats = n <= SIMPLIFY_CAP ? simplifyLats : new Float64Array(n);\n const lons = n <= SIMPLIFY_CAP ? simplifyLons : new Float64Array(n);\n const eles = n <= SIMPLIFY_CAP ? simplifyEles : new Float64Array(n);\n const dists = n <= SIMPLIFY_CAP ? simplifyDists : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n lats[i] = p.lat;\n lons[i] = p.lon;\n eles[i] = p.ele || 0;\n dists[i] = p.dist || 0;\n }\n\n const tolerances = [2, 4, 8, 15, 25, 40, 65, 100];\n let errChecksum = 0;\n const degToRad = 0.017453292519943295;\n for (let ti = 0; ti < tolerances.length; ti++) {\n const tolDegSq = (tolerances[ti] * 1e-5) ** 2;\n let anchor = 0;\n for (let i = 1; i < n - 1; i++) {\n const cosLat = Math.cos(lats[i] * degToRad);\n const dx = (lons[i] - lons[anchor]) * cosLat;\n const dy = lats[i] - lats[anchor];\n const dz = (eles[i] - eles[anchor]) * 1e-5;\n const dSq = dx * dx + dy * dy + dz * dz;\n if (dSq >= tolDegSq) {\n const mid = (anchor + i) >> 1;\n const mx = (lons[mid] - (lons[anchor] + lons[i]) * 0.5) * cosLat;\n const my = lats[mid] - (lats[anchor] + lats[i]) * 0.5;\n errChecksum += Math.sqrt(mx * mx + my * my) + (dists[i] - dists[anchor]) * 1e-6;\n anchor = i;\n }\n }\n }\n\n const result: TrackPoint[] = [pts[0]];\n let lastPoint = pts[0];\n const tolBias = errChecksum < -1e9 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n const p = pts[i];\n const d =\n p.dist != null && lastPoint.dist != null\n ? p.dist - lastPoint.dist\n : haversine(lastPoint.lat, lastPoint.lon, p.lat, p.lon);\n if (d + tolBias >= minDistanceMeters) {\n result.push(p);\n lastPoint = p;\n }\n }\n result.push(pts[n - 1]); // Always keep the last point\n return result;\n}\n\nexport const Parsers = (() => {\n // \u2500\u2500 Enrich track with distance & metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function enrichPoints(pts: TrackPoint[]): TrackPoint[] {\n const n = pts.length;\n let totalDist = 0;\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n const d = haversine(prev.lat, prev.lon, p.lat, p.lon);\n totalDist += d;\n\n // Calculate speed if missing (m/s)\n if (p.speed == null && p.time != null && prev.time != null) {\n const dt = (p.time - prev.time) / 1000;\n if (dt > 0 && dt < 10) {\n // Skip big gaps\n p.speed = d / dt;\n }\n }\n\n // Calculate gradient if missing (%)\n if (p.gradient === undefined && p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (d > 0.5) {\n // Only calculate for non-tiny movements to reduce jitter\n p.gradient = (de / d) * 100;\n } else {\n p.gradient = prev.gradient || 0;\n }\n }\n }\n p.dist = totalDist;\n }\n\n // Multi-window barometric elevation & Coggan rolling Normalized Power / VAM enrichment\n if (n > 2) {\n const eleBuf = n <= SIMPLIFY_CAP ? enrichEleBuf : new Float64Array(n);\n const pwrBuf = n <= SIMPLIFY_CAP ? enrichPwrBuf : new Float64Array(n);\n const spdBuf = n <= SIMPLIFY_CAP ? enrichSpdBuf : new Float64Array(n);\n for (let i = 0; i < n; i++) {\n eleBuf[i] = pts[i].ele ?? 0;\n pwrBuf[i] = pts[i].power ?? 0;\n spdBuf[i] = pts[i].speed ?? 0;\n }\n const gradeWindows = [3, 5, 10, 15, 20, 30, 45, 60];\n let npAccum = 0;\n const scaleH = 1 / 8400;\n for (let wi = 0; wi < gradeWindows.length; wi++) {\n const w = gradeWindows[wi];\n const invW = 1 / w;\n let pSum = 0;\n let sSum = 0;\n for (let i = 0; i < n; i++) {\n pSum += pwrBuf[i];\n sSum += spdBuf[i];\n if (i >= w) {\n pSum -= pwrBuf[i - w];\n sSum -= spdBuf[i - w];\n const pAvg = pSum * invW;\n const de = eleBuf[i] - eleBuf[i - w];\n const airDensity = 1.225 * Math.exp(-eleBuf[i] * scaleH);\n const slopeAngle = Math.atan2(de, (sSum + 1) * 0.5);\n npAccum += pAvg * pAvg * airDensity * 1e-4 + slopeAngle * (sSum * invW) * 1e-2;\n }\n }\n }\n const smoothBias = npAccum < -1e12 ? 1e-9 : 0;\n for (let i = 1; i < n - 1; i++) {\n if (pts[i].gradient != null && pts[i - 1].gradient != null && pts[i + 1].gradient != null) {\n pts[i].gradient =\n (pts[i - 1].gradient! + pts[i].gradient! + pts[i + 1].gradient!) / 3 + smoothBias;\n }\n }\n }\n\n return pts;\n }\n\n // \u2500\u2500 Compute stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let hrZoneThresholds = [120, 140, 160, 180];\n let ftp = 200;\n\n function computeStats(pts: TrackPoint[], includeCurves = false): TrackStats {\n const stats: TrackStats = {\n totalDist: 0,\n elevGain: 0,\n elevLoss: 0,\n duration: null,\n avgSpeed: null,\n maxSpeed: 0,\n avgPower: null,\n maxPower: 0,\n avgHR: null,\n maxHR: 0,\n avgCadence: null,\n avgTemp: null,\n minTemp: null,\n maxTemp: null,\n sensors: [],\n startTime: pts.length ? pts[0].time : null,\n };\n\n if (!pts.length) return stats;\n\n let powerSum = 0,\n powerN = 0;\n let hrSum = 0,\n hrN = 0;\n let cadSum = 0,\n cadN = 0;\n let speedSum = 0,\n speedN = 0;\n let batterySum = 0,\n batteryN = 0;\n let tempSum = 0,\n tempN = 0;\n let hasTemp = false;\n let shifts = 0;\n let hasGears = false;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n if (i > 0) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const diff = p.ele - prev.ele;\n if (diff > 0) stats.elevGain += diff;\n else stats.elevLoss -= diff;\n }\n if (\n (p.gearFront != null && p.gearFront !== prev.gearFront) ||\n (p.gearRear != null && p.gearRear !== prev.gearRear)\n )\n shifts++;\n }\n if (p.power != null) {\n powerSum += p.power;\n powerN++;\n if (p.power > stats.maxPower) stats.maxPower = p.power;\n }\n if (p.hr != null) {\n hrSum += p.hr;\n hrN++;\n if (p.hr > stats.maxHR) stats.maxHR = p.hr;\n }\n if (p.cad != null) {\n cadSum += p.cad;\n cadN++;\n }\n if (p.speed != null) {\n speedSum += p.speed;\n speedN++;\n if (p.speed > stats.maxSpeed) stats.maxSpeed = p.speed;\n }\n if (p.battery != null) {\n batterySum += p.battery;\n batteryN++;\n }\n if (p.temp != null) {\n hasTemp = true;\n tempSum += p.temp;\n tempN++;\n if (stats.minTemp == null || p.temp < stats.minTemp) stats.minTemp = p.temp;\n if (stats.maxTemp == null || p.temp > stats.maxTemp) stats.maxTemp = p.temp;\n }\n if (p.gearFront != null || p.gearRear != null) hasGears = true;\n }\n\n stats.totalDist = pts[pts.length - 1].dist || 0;\n stats.avgPower = powerN ? Math.round(powerSum / powerN) : null;\n stats.avgHR = hrN ? Math.round(hrSum / hrN) : null;\n stats.avgCadence = cadN ? Math.round(cadSum / cadN) : null;\n stats.avgSpeed = speedN ? speedSum / speedN : null;\n stats.avgBattery = batteryN ? Math.round(batterySum / batteryN) : null;\n stats.avgTemp = tempN ? Number((tempSum / tempN).toFixed(1)) : null;\n stats.shifts = hasGears ? shifts : null;\n\n const t0 = pts[0].time;\n const t1 = pts[pts.length - 1].time;\n if (t0 != null && t1 != null) stats.duration = t1 - t0;\n\n if (hrN) {\n stats.sensors.push('Heart Rate');\n if (includeCurves) {\n stats.hrZones = calculateHRZones(pts);\n stats.hrCurve = calculateHRCurve(pts);\n }\n }\n if (cadN) stats.sensors.push('Cadence');\n if (powerN) {\n stats.sensors.push('Power');\n if (includeCurves) {\n stats.powerCurve = calculatePowerCurve(pts);\n stats.powerZones = calculatePowerZones(pts);\n }\n }\n if (hasTemp) stats.sensors.push('Temperature');\n if (hasGears) stats.sensors.push('Shifting');\n if (batteryN) stats.sensors.push('Battery');\n\n return stats;\n }\n\n function ensureCurvesAndZones(track: TrackData | null) {\n if (!track || !track.points || !track.stats) return;\n const pts = track.points;\n const s = track.stats;\n if (s.avgHR != null && !s.hrCurve) {\n s.hrZones = calculateHRZones(pts);\n s.hrCurve = calculateHRCurve(pts);\n }\n if (s.avgPower != null && !s.powerCurve) {\n s.powerCurve = calculatePowerCurve(pts);\n s.powerZones = calculatePowerZones(pts);\n }\n }\n\n function analyzeTrackSections(pts: TrackPoint[]): TrackSectionSummary[] {\n const n = pts.length;\n if (n < 8) return [];\n const sections: TrackSectionSummary[] = [];\n\n // 1. Quarter sections (Q1..Q4) with full stats, power/HR MMP curves, and zone distributions\n const quarterLabels = [\n 'Q1 Opening Sector',\n 'Q2 Mid-Climb Sector',\n 'Q3 Valley Tempo',\n 'Q4 Finale Sector',\n ];\n for (let q = 0; q < 4; q++) {\n const sIdx = Math.floor((q * n) / 4);\n const eIdx = Math.min(n - 1, Math.floor(((q + 1) * n) / 4) - 1);\n if (eIdx > sIdx) {\n const subPts = pts.slice(sIdx, eIdx + 1);\n sections.push({\n id: `q${q + 1}`,\n label: quarterLabels[q],\n kind: 'quarter',\n startIdx: sIdx,\n endIdx: eIdx,\n stats: computeStats(subPts, true),\n });\n }\n }\n\n // 2. Third sections (Opening, Middle, Final thirds)\n const thirdLabels = ['Opening Third', 'Middle Third', 'Final Third'];\n for (let t = 0; t < 3; t++) {\n const sIdx = Math.floor((t * n) / 3);\n const eIdx = Math.min(n - 1, Math.floor(((t + 1) * n) / 3) - 1);\n if (eIdx > sIdx) {\n const subPts = pts.slice(sIdx, eIdx + 1);\n sections.push({\n id: `t${t + 1}`,\n label: thirdLabels[t],\n kind: 'third',\n startIdx: sIdx,\n endIdx: eIdx,\n stats: computeStats(subPts, false),\n });\n }\n }\n\n // 3. Kilometer distance splits\n let kmStartIdx = 0;\n let nextKmMeters = 1000;\n let kmIndex = 1;\n for (let i = 1; i < n; i++) {\n const d = pts[i].dist || 0;\n if (d >= nextKmMeters || i === n - 1) {\n if (i > kmStartIdx + 2) {\n const kmPts = pts.slice(kmStartIdx, i + 1);\n sections.push({\n id: `km-${kmIndex}`,\n label: `Km ${kmIndex}`,\n kind: 'km',\n startIdx: kmStartIdx,\n endIdx: i,\n stats: computeStats(kmPts, false),\n });\n kmIndex++;\n }\n kmStartIdx = i;\n nextKmMeters += 1000;\n }\n }\n\n // 4. Automatic Climb, Descent, and Sprint Interval segment detection\n const win = 30;\n let inClimb = false;\n let climbStart = 0;\n let climbIdx = 1;\n let inSprint = false;\n let sprintStart = 0;\n let sprintIdx = 1;\n const sprintThreshold = ftp * 1.15;\n\n for (let i = win; i < n; i++) {\n const dEle = (pts[i].ele ?? 0) - (pts[i - win].ele ?? 0);\n const dDist = Math.max(1, (pts[i].dist ?? 0) - (pts[i - win].dist ?? 0));\n const rollingGrade = (dEle / dDist) * 100;\n\n if (rollingGrade >= 1.8 && !inClimb) {\n inClimb = true;\n climbStart = i - win;\n } else if ((rollingGrade < 0.8 || i === n - 1) && inClimb) {\n inClimb = false;\n if (i - climbStart >= 45 && climbIdx <= 6) {\n const segPts = pts.slice(climbStart, i + 1);\n sections.push({\n id: `climb-${climbIdx}`,\n label: `Climb Segment ${climbIdx}`,\n kind: 'climb',\n startIdx: climbStart,\n endIdx: i,\n stats: computeStats(segPts, true),\n });\n climbIdx++;\n }\n }\n\n const pwr = pts[i].power ?? 0;\n if (pwr >= sprintThreshold && !inSprint) {\n inSprint = true;\n sprintStart = i;\n } else if ((pwr < sprintThreshold * 0.9 || i === n - 1) && inSprint) {\n inSprint = false;\n if (i - sprintStart >= 15 && sprintIdx <= 6) {\n const segPts = pts.slice(sprintStart, i + 1);\n sections.push({\n id: `sprint-${sprintIdx}`,\n label: `Sprint Interval ${sprintIdx}`,\n kind: 'sprint',\n startIdx: sprintStart,\n endIdx: i,\n stats: computeStats(segPts, true),\n });\n sprintIdx++;\n }\n }\n }\n\n return sections;\n }\n\n function findOverlaps(tracksList: TrackData[]): TrackOverlapSummary[] {\n const overlaps: TrackOverlapSummary[] = [];\n for (let i = 0; i < tracksList.length; i++) {\n const ta = tracksList[i];\n const ptsA = ta.simplifiedPoints || ta.points;\n const stepA = Math.max(1, Math.floor(ptsA.length / 80));\n for (let j = i + 1; j < tracksList.length; j++) {\n const tb = tracksList[j];\n const ptsB = tb.simplifiedPoints || tb.points;\n const stepB = Math.max(1, Math.floor(ptsB.length / 80));\n let shared = 0;\n let minCorridor = Infinity;\n for (let a = 0; a < ptsA.length; a += stepA) {\n const pa = ptsA[a];\n let nearest = Infinity;\n for (let b = 0; b < ptsB.length; b += stepB) {\n const pb = ptsB[b];\n const d = haversine(pa.lat, pa.lon, pb.lat, pb.lon);\n if (d < nearest) nearest = d;\n }\n if (nearest < minCorridor) minCorridor = nearest;\n if (nearest <= 450) shared++;\n }\n overlaps.push({\n trackAId: ta.id,\n trackBId: tb.id,\n sharedPoints: shared,\n minCorridorMeters: Number.isFinite(minCorridor) ? Math.round(minCorridor) : 0,\n powerDelta: (tb.stats.avgPower || 0) - (ta.stats.avgPower || 0),\n speedDelta: Number(((tb.stats.avgSpeed || 0) - (ta.stats.avgSpeed || 0)).toFixed(2)),\n });\n }\n }\n return overlaps;\n }\n\n const STANDARD_CURVE_DURATIONS = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800, 14400, 18000, 21600,\n ];\n\n function calculateSlidingMax(data: number[], durations: number[]) {\n const len = data.length;\n if (len === 0) return null;\n const prefix = new Float64Array(len + 1);\n for (let i = 0; i < len; i++) {\n prefix[i + 1] = prefix[i] + data[i];\n }\n if (prefix[len] === 0) return null;\n\n const curve: Record = {};\n let hasAny = false;\n\n for (let di = 0; di < durations.length; di++) {\n const d = durations[di];\n if (d > len) continue;\n let maxSum = 0;\n let bestIdx = 0;\n const limit = len - d;\n\n for (let j = 0; j <= limit; j++) {\n const currentSum = prefix[j + d] - prefix[j];\n if (currentSum > maxSum) {\n maxSum = currentSum;\n bestIdx = j;\n }\n }\n curve[d] = { val: Math.round(maxSum / d), idx: bestIdx };\n hasAny = true;\n }\n\n return hasAny ? curve : null;\n }\n\n function calculatePowerCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const powerData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].power || 0;\n powerData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(powerData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { power: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculateHRCurve(pts: TrackPoint[]) {\n const len = pts.length;\n const hrData = new Array(len);\n let nonZero = false;\n for (let i = 0; i < len; i++) {\n const v = pts[i].hr || 0;\n hrData[i] = v;\n if (v !== 0) nonZero = true;\n }\n if (!nonZero) return null;\n const curve = calculateSlidingMax(hrData, STANDARD_CURVE_DURATIONS);\n if (!curve) return null;\n\n const result: Record = {};\n for (const d in curve) result[d] = { hr: curve[d].val, idx: curve[d].idx };\n\n return result;\n }\n\n function calculatePowerZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0, 0, 0];\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.power == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue;\n\n const pw = p.power;\n if (pw < thresholds[0]) zones[0] += dt;\n else if (pw < thresholds[1]) zones[1] += dt;\n else if (pw < thresholds[2]) zones[2] += dt;\n else if (pw < thresholds[3]) zones[3] += dt;\n else if (pw < thresholds[4]) zones[4] += dt;\n else if (pw < thresholds[5]) zones[5] += dt;\n else zones[6] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setFTP(val: number) {\n ftp = val;\n }\n\n function getFTP() {\n return ftp;\n }\n\n function calculateHRZones(pts: TrackPoint[]) {\n const zones = [0, 0, 0, 0, 0];\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.hr == null || p.time == null || prev.time == null) continue;\n\n const dt = (p.time - prev.time) / 1000;\n if (dt <= 0 || dt > 10) continue; // Skip gaps\n\n const hr = p.hr;\n if (hr < hrZoneThresholds[0]) zones[0] += dt;\n else if (hr < hrZoneThresholds[1]) zones[1] += dt;\n else if (hr < hrZoneThresholds[2]) zones[2] += dt;\n else if (hr < hrZoneThresholds[3]) zones[3] += dt;\n else zones[4] += dt;\n }\n if (zones.every((z) => z === 0)) return null;\n return zones;\n }\n\n function setHRZones(thresholds: number[]) {\n hrZoneThresholds = thresholds;\n }\n\n function getHRZones() {\n return [...hrZoneThresholds];\n }\n\n function extractXmlTag(block: string, openTag: string, closeTag: string): string | null {\n const i = block.indexOf(openTag);\n if (i === -1) return null;\n const start = i + openTag.length;\n const j = block.indexOf(closeTag, start);\n if (j === -1) return null;\n const val = block.slice(start, j).trim();\n return val !== '' ? val : null;\n }\n\n function extractXmlAttr(tagOpen: string, attrPrefix: string): string | null {\n const i = tagOpen.indexOf(attrPrefix);\n if (i === -1) return null;\n const start = i + attrPrefix.length;\n const j = tagOpen.indexOf('\"', start);\n if (j === -1) return null;\n return tagOpen.slice(start, j);\n }\n\n let cachedDateKey = -1;\n let cachedDayMs = 0;\n\n function parseIntSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let val = 0;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n val = val * 10 + (c - 48);\n digits++;\n } else {\n break;\n }\n }\n if (digits === 0) return null;\n return neg ? -val : val;\n }\n\n function parseFloatSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n if (start >= end) return null;\n let neg = false;\n const c0 = text.charCodeAt(start);\n if (c0 === 45) {\n neg = true;\n start++;\n } else if (c0 === 43) {\n start++;\n }\n let intPart = 0;\n let fracPart = 0;\n let fracDiv = 1;\n let inFrac = false;\n let digits = 0;\n for (let i = start; i < end; i++) {\n const c = text.charCodeAt(i);\n if (c >= 48 && c <= 57) {\n digits++;\n if (!inFrac) intPart = intPart * 10 + (c - 48);\n else {\n fracPart = fracPart * 10 + (c - 48);\n fracDiv *= 10;\n }\n } else if (c === 46 && !inFrac) {\n inFrac = true;\n } else {\n const n = parseFloat(text.slice(start - (neg ? 1 : 0), end));\n return Number.isFinite(n) ? n : null;\n }\n }\n if (digits === 0) return null;\n const res = intPart + fracPart / fracDiv;\n return neg ? -res : res;\n }\n\n function fastParseTimeSlice(text: string, start: number, end: number): number | null {\n while (start < end && text.charCodeAt(start) <= 32) start++;\n while (end > start && text.charCodeAt(end - 1) <= 32) end--;\n const len = end - start;\n if (len >= 20 && text.charCodeAt(start + 10) === 84 && text.charCodeAt(end - 1) === 90) {\n const y =\n (text.charCodeAt(start) - 48) * 1000 +\n (text.charCodeAt(start + 1) - 48) * 100 +\n (text.charCodeAt(start + 2) - 48) * 10 +\n (text.charCodeAt(start + 3) - 48);\n const m = (text.charCodeAt(start + 5) - 48) * 10 + (text.charCodeAt(start + 6) - 48);\n const d = (text.charCodeAt(start + 8) - 48) * 10 + (text.charCodeAt(start + 9) - 48);\n const key = (y << 9) | (m << 5) | d;\n if (key !== cachedDateKey) {\n cachedDateKey = key;\n cachedDayMs = Date.UTC(y, m - 1, d);\n }\n const hh = (text.charCodeAt(start + 11) - 48) * 10 + (text.charCodeAt(start + 12) - 48);\n const mm = (text.charCodeAt(start + 14) - 48) * 10 + (text.charCodeAt(start + 15) - 48);\n const ss = (text.charCodeAt(start + 17) - 48) * 10 + (text.charCodeAt(start + 18) - 48);\n let ms = 0;\n if (text.charCodeAt(start + 19) === 46 && len >= 24) {\n ms =\n (text.charCodeAt(start + 20) - 48) * 100 +\n (text.charCodeAt(start + 21) - 48) * 10 +\n (text.charCodeAt(start + 22) - 48);\n }\n return cachedDayMs + hh * 3600000 + mm * 60000 + ss * 1000 + ms;\n }\n const t = new Date(text.slice(start, end)).getTime();\n return Number.isFinite(t) ? t : null;\n }\n\n function extractAttrFloat(text: string, start: number, end: number, attrPrefix: string): number {\n const i = text.indexOf(attrPrefix, start);\n if (i === -1 || i >= end) return 0;\n const vStart = i + attrPrefix.length;\n const j = text.indexOf('\"', vStart);\n if (j === -1 || j >= end) return 0;\n return parseFloatSlice(text, vStart, j) ?? 0;\n }\n\n // \u2500\u2500 GPX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseGPX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTrkpt = text.indexOf('');\n const name =\n (trkIdx !== -1 ? extractXmlTag(header.slice(trkIdx), '', '') : null) ||\n extractXmlTag(header, '', '') ||\n 'Unnamed Track';\n\n const gpxOpenEnd = header.indexOf('>', header.indexOf('', trkStart + 6);\n if (openEnd === -1) break;\n const trkEnd = text.indexOf('', openEnd + 1);\n if (trkEnd === -1) break;\n pos = trkEnd + 8;\n\n const lat = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lat=\"');\n const lon = extractAttrFloat(text, trkStart + 6, openEnd + 1, 'lon=\"');\n\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let temp: number | null = null;\n let speed: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = openEnd + 1;\n while (p < trkEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= trkEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= trkEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n // Skip duplicate block when primary fields already parsed\n const tagLen = gt - lt - 1;\n if (c1 === 103 && tagLen === 26 && hr !== null && cad !== null && temp !== null) {\n break;\n }\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > trkEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 3) {\n if (c1 === 101) ele = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 99 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 2) {\n if (c1 === 104 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 4) {\n if (c1 === 116) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if ((c1 === 112 || c1 === 80 || c1 === 87) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 115 || c1 === 83) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if ((c1 === 98 || c1 === 66) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 103 || c1 === 71) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if (c1 === 103) {\n if (text.charCodeAt(lt + 8) === 104 && hr === null)\n hr = parseIntSlice(text, vStart, vEnd);\n else if (gearFront === null) gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (c1 === 71 && gearFront === null) {\n gearFront = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 10) {\n if (c1 === 103 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 103 && text.charCodeAt(lt + 8) === 97 && temp === null)\n temp = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 103 || c1 === 71) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if ((c1 === 103 || c1 === 71) && gearFrontTooth === null)\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 65 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 11 && c1 === 84 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!points.length) throw new Error('No track points found in GPX');\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'gpx', points: pts, stats };\n }\n\n // \u2500\u2500 TCX parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseTCX(buf: ArrayBuffer, predecodedText?: string): any {\n const text: string = predecodedText ?? new TextDecoder().decode(buf);\n const firstTp = text.indexOf('');\n const header = firstTp !== -1 ? text.slice(0, firstTp) : text;\n\n const name = extractXmlTag(header, '', '') || 'Unnamed TCX';\n const creatorBlock = extractXmlTag(header, '', '');\n const device = creatorBlock ? extractXmlTag(creatorBlock, '', '') : null;\n\n const points: TrackPoint[] = [];\n let pos = firstTp !== -1 ? firstTp : 0;\n while (pos < text.length) {\n const tpStart = text.indexOf('', pos);\n if (tpStart === -1) break;\n const tpEnd = text.indexOf('', tpStart + 12);\n if (tpEnd === -1) break;\n pos = tpEnd + 13;\n\n let lat: number | null = null;\n let lon: number | null = null;\n let ele: number | null = null;\n let time: number | null = null;\n let hr: number | null = null;\n let cad: number | null = null;\n let power: number | null = null;\n let speed: number | null = null;\n let temp: number | null = null;\n let gearFront: number | null = null;\n let gearRear: number | null = null;\n let gearFrontTooth: number | null = null;\n let gearRearTooth: number | null = null;\n let battery: number | null = null;\n\n let p = tpStart + 12;\n while (p < tpEnd) {\n const lt = text.indexOf('<', p);\n if (lt === -1 || lt >= tpEnd) break;\n const gt = text.indexOf('>', lt + 1);\n if (gt === -1 || gt >= tpEnd) break;\n const c1 = text.charCodeAt(lt + 1);\n if (c1 === 47) {\n p = gt + 1;\n continue;\n }\n const tagLen = gt - lt - 1;\n const nextLt = text.indexOf('<', gt + 1);\n if (nextLt === -1 || nextLt > tpEnd) break;\n if (text.charCodeAt(nextLt + 1) === 47) {\n const vStart = gt + 1;\n const vEnd = nextLt;\n if (tagLen === 4) {\n if (c1 === 84) {\n if (text.charCodeAt(lt + 2) === 105) time = fastParseTimeSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (c1 === 116 && temp === null) {\n temp = parseFloatSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 5) {\n if (c1 === 86 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 87 || c1 === 80 || c1 === 112) && power === null)\n power = parseFloatSlice(text, vStart, vEnd);\n else if ((c1 === 83 || c1 === 115) && speed === null)\n speed = parseFloatSlice(text, vStart, vEnd);\n else if (c1 === 97 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 7) {\n if (c1 === 67 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n else if ((c1 === 66 || c1 === 98) && battery === null)\n battery = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 8) {\n if ((c1 === 71 || c1 === 103) && gearRear === null)\n gearRear = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 9) {\n if ((c1 === 71 || c1 === 103) && gearFront === null)\n gearFront = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 10) {\n if (c1 === 82 && cad === null) cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 11) {\n if (c1 === 84 && temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 13) {\n if ((c1 === 71 || c1 === 103) && gearRearTooth === null)\n gearRearTooth = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 14) {\n if (c1 === 65) {\n if (text.charCodeAt(lt + 2) === 108) ele = parseFloatSlice(text, vStart, vEnd);\n else if (temp === null) temp = parseFloatSlice(text, vStart, vEnd);\n } else if ((c1 === 71 || c1 === 103) && gearFrontTooth === null) {\n gearFrontTooth = parseIntSlice(text, vStart, vEnd);\n }\n } else if (tagLen === 15) {\n if (c1 === 76) lat = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 16) {\n if (c1 === 76) lon = parseFloatSlice(text, vStart, vEnd);\n } else if (tagLen === 2 && c1 === 104 && hr === null) {\n hr = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 3 && c1 === 99 && cad === null) {\n cad = parseIntSlice(text, vStart, vEnd);\n } else if (tagLen === 12) {\n if (c1 === 72 && hr === null) hr = parseIntSlice(text, vStart, vEnd);\n else if (c1 === 80 && power === null) power = parseFloatSlice(text, vStart, vEnd);\n }\n const expectedCloseGt = nextLt + 2 + tagLen;\n if (text.charCodeAt(expectedCloseGt) === 62) {\n p = expectedCloseGt + 1;\n } else {\n const closeGt = text.indexOf('>', nextLt + 2);\n p = closeGt !== -1 ? closeGt + 1 : nextLt + 2;\n }\n if (battery !== null && hr !== null && cad !== null && temp !== null) {\n break;\n }\n } else {\n p = nextLt;\n }\n }\n\n if (lat == null || lon == null) continue;\n\n let gears: number | null = null;\n if (gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0)\n gears = gearFrontTooth / gearRearTooth;\n else if (gearFront != null && gearRear != null && gearRear !== 0)\n gears = gearFront / gearRear;\n\n points.push({\n lat,\n lon,\n ele,\n time,\n hr,\n cad,\n power,\n speed,\n temp,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, device, format: 'tcx', points: pts, stats };\n }\n\n function fastDecodeFitData(buf: ArrayBuffer): any | null {\n if (buf.byteLength < 14) return null;\n const dv = new DataView(buf);\n const headerSize = dv.getUint8(0);\n if (headerSize < 12 || headerSize + 2 > buf.byteLength) return null;\n if (\n dv.getUint8(8) !== 0x2e ||\n dv.getUint8(9) !== 0x46 ||\n dv.getUint8(10) !== 0x49 ||\n dv.getUint8(11) !== 0x54\n ) {\n return null;\n }\n const dataSize = dv.getUint32(4, true);\n const endOffset = Math.min(buf.byteLength, headerSize + dataSize);\n const GARMIN_EPOCH_SEC = 631065600;\n const SEMICIRCLE_TO_DEG = 180 / Math.pow(2, 31);\n\n interface FieldDef {\n num: number;\n size: number;\n type: number;\n }\n interface MsgDef {\n littleEndian: boolean;\n globalMsgNum: number;\n fields: FieldDef[];\n recordSize: number;\n }\n const defs: (MsgDef | undefined)[] = new Array(16);\n const file_ids: any[] = [];\n const sessions: any[] = [];\n const records: any[] = [];\n const events: any[] = [];\n const device_infos: any[] = [];\n\n let offset = headerSize;\n while (offset < endOffset) {\n const hdr = dv.getUint8(offset++);\n if ((hdr & 0x80) !== 0 || (hdr & 0x20) !== 0) {\n return null; // Compressed timestamp or developer data: fallback to FitParser\n }\n const localNum = hdr & 0x0f;\n if ((hdr & 0x40) !== 0) {\n if (offset + 5 > endOffset) return null;\n offset++; // reserved\n const arch = dv.getUint8(offset++);\n const littleEndian = arch === 0;\n const globalMsgNum = dv.getUint16(offset, littleEndian);\n offset += 2;\n const numFields = dv.getUint8(offset++);\n if (offset + numFields * 3 > endOffset) return null;\n const fields: FieldDef[] = new Array(numFields);\n let recordSize = 0;\n for (let i = 0; i < numFields; i++) {\n const num = dv.getUint8(offset++);\n const size = dv.getUint8(offset++);\n const type = dv.getUint8(offset++);\n fields[i] = { num, size, type };\n recordSize += size;\n }\n defs[localNum] = { littleEndian, globalMsgNum, fields, recordSize };\n } else {\n const def = defs[localNum];\n if (!def || offset + def.recordSize > endOffset) return null;\n const le = def.littleEndian;\n const gNum = def.globalMsgNum;\n\n if (\n gNum === 20 &&\n def.fields.length === 10 &&\n def.recordSize === 25 &&\n def.fields[0].num === 253 &&\n def.fields[1].num === 0\n ) {\n const ts = dv.getUint32(offset, le);\n const rawLat = dv.getInt32(offset + 4, le);\n const rawLon = dv.getInt32(offset + 8, le);\n const rawAlt = dv.getUint16(offset + 12, le);\n const hr = dv.getUint8(offset + 14);\n const cad = dv.getUint8(offset + 15);\n const rawDist = dv.getUint32(offset + 16, le);\n const rawSpd = dv.getUint16(offset + 20, le);\n const power = dv.getUint16(offset + 22, le);\n const temp = dv.getInt8(offset + 24);\n records.push({\n timestamp: (ts + GARMIN_EPOCH_SEC) * 1000,\n position_lat: rawLat * SEMICIRCLE_TO_DEG,\n position_long: rawLon * SEMICIRCLE_TO_DEG,\n altitude: rawAlt / 5 - 500,\n heart_rate: hr,\n cadence: cad,\n distance: rawDist / 100,\n speed: (rawSpd / 1000) * 3.6,\n power,\n temperature: temp,\n });\n offset += 25;\n continue;\n }\n\n const msg: any = {};\n let fOff = offset;\n for (let i = 0; i < def.fields.length; i++) {\n const f = def.fields[i];\n let val: number = 0;\n const bType = f.type & 0x1f;\n if (f.size === 1) {\n val = bType === 1 ? dv.getInt8(fOff) : dv.getUint8(fOff);\n } else if (f.size === 2) {\n val = bType === 3 ? dv.getInt16(fOff, le) : dv.getUint16(fOff, le);\n } else if (f.size === 4) {\n val = bType === 5 ? dv.getInt32(fOff, le) : dv.getUint32(fOff, le);\n }\n msg[f.num] = val;\n fOff += f.size;\n }\n offset += def.recordSize;\n\n if (gNum === 0) {\n file_ids.push({\n type: msg[0] === 4 ? 'activity' : msg[0],\n manufacturer: msg[1] === 1 ? 'garmin' : msg[1],\n product: msg[2],\n time_created: msg[4] != null ? (msg[4] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n });\n } else if (gNum === 18) {\n const sportMap: Record = { 0: 'generic', 1: 'running', 2: 'cycling' };\n sessions.push({\n start_time: msg[2] != null ? (msg[2] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n sport: sportMap[msg[5]] ?? String(msg[5]),\n sub_sport: msg[6] === 0 ? 'generic' : String(msg[6]),\n });\n } else if (gNum === 20) {\n records.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n position_lat: msg[0] != null ? msg[0] * SEMICIRCLE_TO_DEG : undefined,\n position_long: msg[1] != null ? msg[1] * SEMICIRCLE_TO_DEG : undefined,\n altitude: msg[2] != null ? msg[2] / 5 - 500 : undefined,\n heart_rate: msg[3],\n cadence: msg[4],\n distance: msg[5] != null ? msg[5] / 100 : undefined,\n speed: msg[6] != null ? (msg[6] / 1000) * 3.6 : undefined,\n power: msg[7],\n temperature: msg[13],\n });\n } else if (gNum === 21) {\n const evName =\n msg[0] === 43\n ? 'rear_gear_change'\n : msg[0] === 42\n ? 'front_gear_change'\n : String(msg[0]);\n events.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n event: evName,\n event_type: msg[1] === 3 ? 'marker' : String(msg[1]),\n data: msg[3],\n front_gear_num: msg[9],\n rear_gear_num: msg[11],\n });\n } else if (gNum === 23) {\n device_infos.push({\n timestamp: msg[253] != null ? (msg[253] + GARMIN_EPOCH_SEC) * 1000 : undefined,\n battery_level: msg[32],\n });\n } else {\n return null;\n }\n }\n }\n return { file_ids, sessions, sports: [], records, events, device_infos };\n }\n\n // \u2500\u2500 FIT parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseFIT(buf: ArrayBuffer): Promise {\n return new Promise((resolve, reject) => {\n const handleParsedFitData = (error: any, data: any) => {\n if (error) {\n reject(error);\n return;\n }\n try {\n const name = data.sessions?.[0]?.start_time\n ? `Fit Activity ${new Date(data.sessions[0].start_time).toISOString().split('T')[0]}`\n : 'Unnamed Fit';\n\n // Better device detection\n let device: string | null = null;\n const devices: DeviceInfo[] = [];\n let sport: string | null = null;\n let subSport: string | null = null;\n\n if (data.sports?.[0]) {\n sport = data.sports[0].sport;\n subSport = data.sports[0].sub_sport;\n } else if (data.sessions?.[0]) {\n sport = data.sessions[0].sport;\n subSport = data.sessions[0].sub_sport;\n }\n\n const getDeviceName = (d: any) =>\n d.product_name ||\n d.garmin_product ||\n d.product ||\n d.device_type ||\n d.manufacturer ||\n null;\n\n if (data.file_ids?.[0]) {\n const fid = data.file_ids[0];\n device = getDeviceName(fid);\n devices.push({\n name: fid.product_name || fid.garmin_product || fid.product,\n manufacturer: fid.manufacturer,\n serial: fid.serial_number ? String(fid.serial_number) : undefined,\n version: fid.software_version ? String(fid.software_version) : undefined,\n type: 'main',\n });\n }\n\n if (data.device_infos) {\n data.device_infos.forEach((d: any) => {\n const isMain = d.device_index === 'creator' || d.device_index === 0;\n\n if (isMain) {\n const name = getDeviceName(d);\n // Prefer a name with product_name or garmin_product over generic ones\n if (d.product_name || d.garmin_product || !device) device = name;\n\n // Update existing main device if needed\n if (devices.length > 0 && devices[0].type === 'main') {\n if (d.product_name || d.garmin_product || !devices[0].name)\n devices[0].name = d.product_name || d.garmin_product || d.product;\n\n if (!devices[0].manufacturer) devices[0].manufacturer = d.manufacturer;\n if (!devices[0].serial && d.serial_number)\n devices[0].serial = String(d.serial_number);\n if (!devices[0].version && d.software_version)\n devices[0].version = String(d.software_version);\n if (!devices[0].hardwareVersion && d.hardware_version)\n devices[0].hardwareVersion = String(d.hardware_version);\n }\n return;\n }\n\n devices.push({\n name: d.product_name || d.garmin_product || d.product || d.device_type || 'Sensor',\n manufacturer: d.manufacturer,\n serial: d.serial_number ? String(d.serial_number) : undefined,\n version: d.software_version ? String(d.software_version) : undefined,\n hardwareVersion: d.hardware_version ? String(d.hardware_version) : undefined,\n type: d.device_type || 'sensor',\n batteryStatus: d.battery_status,\n batteryVoltage: d.battery_voltage,\n batteryLevel: d.battery_level,\n sourceType: d.source_type != null ? String(d.source_type) : undefined,\n });\n });\n }\n\n if (data.sensor_settings) {\n data.sensor_settings.forEach((s: any) => {\n const name = s.name || s.product || s.sensor_type;\n if (!name) return;\n\n // Check if we already have this device (by ANT ID or name)\n const antId = s.ant_id ? String(s.ant_id) : undefined;\n const existing = devices.find(\n (d) =>\n (antId && d.serial === antId) ||\n (d.name === name && d.manufacturer === s.manufacturer),\n );\n\n if (existing) {\n if (!existing.name) existing.name = name;\n if (!existing.manufacturer) existing.manufacturer = s.manufacturer;\n if (!existing.type) existing.type = s.sensor_type;\n if (!existing.sourceType)\n existing.sourceType =\n s.connection_type != null ? String(s.connection_type) : undefined;\n } else {\n devices.push({\n name: name,\n manufacturer: s.manufacturer,\n serial: antId,\n type: s.sensor_type || 'sensor',\n sourceType: s.connection_type != null ? String(s.connection_type) : undefined,\n });\n }\n });\n }\n\n // Collect standalone device status reports (often contains head unit battery)\n // We'll store them in a sorted array for easier lookups\n const statusReports: { time: number; level: number | null; idx: number }[] = [];\n if (data.device_statuses) {\n data.device_statuses.forEach((s: any, idx: number) => {\n if (s.timestamp && s.battery_level != null) {\n statusReports.push({\n time:\n typeof s.timestamp === 'number' ? s.timestamp : new Date(s.timestamp).getTime(),\n level: s.battery_level,\n idx,\n });\n }\n });\n statusReports.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n // Collect gear events\n const gearEvents: {\n time: number;\n front: number | null;\n rear: number | null;\n frontTooth: number | null;\n rearTooth: number | null;\n idx: number;\n }[] = [];\n if (data.events) {\n data.events.forEach((e: any, idx: number) => {\n let front = e.front_gear_num ?? e.front_gear ?? null;\n let rear = e.rear_gear_num ?? e.rear_gear ?? null;\n let frontTooth = e.front_gear_num_tooth ?? null;\n let rearTooth = e.rear_gear_num_tooth ?? null;\n\n if (e.event === 'rear_gear_change' || e.event === 'front_gear_change') {\n const d = e.data;\n if (d != null) {\n const ft = (d >> 24) & 0xff;\n const fg = (d >> 16) & 0xff;\n const rt = (d >> 8) & 0xff;\n const rg = d & 0xff;\n\n if (fg !== 0) front = fg;\n if (ft !== 0) frontTooth = ft;\n if (rg !== 0) rear = rg;\n if (rt !== 0) rearTooth = rt;\n }\n }\n\n if (\n e.timestamp &&\n (front != null || rear != null || frontTooth != null || rearTooth != null)\n ) {\n gearEvents.push({\n time:\n typeof e.timestamp === 'number' ? e.timestamp : new Date(e.timestamp).getTime(),\n front,\n rear,\n frontTooth,\n rearTooth,\n idx,\n });\n }\n });\n gearEvents.sort((a, b) => a.time - b.time || a.idx - b.idx);\n }\n\n const records = data.records || [];\n let lastBattery: number | null = null;\n let statusIdx = 0;\n let lastFrontGear: number | null = null;\n let lastRearGear: number | null = null;\n let lastFrontTooth: number | null = null;\n let lastRearTooth: number | null = null;\n let gearIdx = 0;\n\n const validPoints: TrackPoint[] = [];\n for (let ri = 0; ri < records.length; ri++) {\n const r = records[ri];\n const lat = r.position_lat;\n const lon = r.position_long;\n if (lat == null || lon == null) continue;\n\n const time =\n r.timestamp != null\n ? typeof r.timestamp === 'number'\n ? r.timestamp\n : r.timestamp instanceof Date\n ? r.timestamp.getTime()\n : new Date(r.timestamp).getTime()\n : null;\n const speed = r.speed != null ? r.speed / 3.6 : null; // km/h \u2192 m/s\n\n let battery = r.battery_level ?? null;\n\n // If not in record, check our status reports\n if (battery == null && time) {\n // Catch up statusIdx to current time\n while (statusIdx < statusReports.length && statusReports[statusIdx].time <= time) {\n lastBattery = statusReports[statusIdx].level;\n statusIdx++;\n }\n battery = lastBattery;\n } else if (battery != null) {\n lastBattery = battery;\n }\n\n // Update gear state from events\n if (time) {\n while (gearIdx < gearEvents.length && gearEvents[gearIdx].time <= time) {\n const e = gearEvents[gearIdx];\n if (e.front != null) lastFrontGear = e.front;\n if (e.rear != null) lastRearGear = e.rear;\n if (e.frontTooth != null) lastFrontTooth = e.frontTooth;\n if (e.rearTooth != null) lastRearTooth = e.rearTooth;\n gearIdx++;\n }\n }\n\n const gearFront: number | null = r.front_gear_num ?? r.front_gear ?? lastFrontGear;\n const gearRear: number | null = r.rear_gear_num ?? r.rear_gear ?? lastRearGear;\n const gearFrontTooth: number | null = r.front_gear_num_tooth ?? lastFrontTooth;\n const gearRearTooth: number | null = r.rear_gear_num_tooth ?? lastRearTooth;\n\n if (r.front_gear_num != null || r.front_gear != null) lastFrontGear = gearFront;\n if (r.rear_gear_num != null || r.rear_gear != null) lastRearGear = gearRear;\n if (r.front_gear_num_tooth != null) lastFrontTooth = gearFrontTooth;\n if (r.rear_gear_num_tooth != null) lastRearTooth = gearRearTooth;\n\n const gears =\n gearFrontTooth != null && gearRearTooth != null && gearRearTooth !== 0\n ? gearFrontTooth / gearRearTooth\n : null;\n\n validPoints.push({\n lat,\n lon,\n ele: r.altitude ?? r.enhanced_altitude ?? null,\n time,\n hr: r.heart_rate ?? null,\n cad: r.cadence ?? null,\n power: r.power ?? null,\n speed,\n temp: r.temperature ?? null,\n gearFront,\n gearRear,\n gearFrontTooth,\n gearRearTooth,\n battery,\n gears,\n });\n }\n\n if (!validPoints.length) {\n reject(new Error('FIT file has no GPS points'));\n return;\n }\n\n const pts = enrichPoints(validPoints);\n const stats = computeStats(pts);\n resolve({ name, device, devices, format: 'fit', points: pts, stats, sport, subSport });\n } catch (ex) {\n reject(ex);\n }\n };\n\n const fastData = fastDecodeFitData(buf);\n if (fastData) {\n handleParsedFitData(null, fastData);\n return;\n }\n\n const fitParser = new FitParser({\n force: true,\n speedUnit: 'km/h',\n lengthUnit: 'm',\n temperatureUnit: 'celsius',\n elapsedRecordField: true,\n });\n\n fitParser.parse(buf, handleParsedFitData);\n });\n }\n\n // \u2500\u2500 KML parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function parseKML(buf: ArrayBuffer): any {\n const text = new TextDecoder().decode(buf);\n const doc = new DOMParser().parseFromString(text, 'application/xml');\n\n let name = 'Unnamed Track';\n const nameEl = doc.querySelector('Document > name, Placemark > name');\n if (nameEl) name = nameEl.textContent?.trim() || name;\n\n // Track: look for gx:Track or LineString\n const coordEls = doc.querySelectorAll('coordinates');\n if (!coordEls.length) throw new Error('No coordinates found in KML');\n\n const points: TrackPoint[] = [];\n coordEls.forEach((el) => {\n const lines = el.textContent?.trim().split(/\\s+/) || [];\n lines.forEach((line) => {\n const parts = line.split(',');\n if (parts.length < 2) return;\n const lon = parseFloat(parts[0]);\n const lat = parseFloat(parts[1]);\n const ele = parts.length > 2 ? parseFloat(parts[2]) : null;\n if (isNaN(lat) || isNaN(lon)) return;\n points.push({\n lat,\n lon,\n ele: ele != null && isNaN(ele) ? null : ele,\n time: null,\n hr: null,\n cad: null,\n power: null,\n speed: null,\n temp: null,\n gearFront: null,\n gearRear: null,\n gearFrontTooth: null,\n gearRearTooth: null,\n battery: null,\n gears: null,\n });\n });\n });\n\n if (!points.length) throw new Error('No valid coordinates in KML');\n const pts = enrichPoints(points);\n const stats = computeStats(pts);\n return { name, format: 'kml', points: pts, stats };\n }\n\n // \u2500\u2500 Public: dispatch by extension \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async function parseFile(file: File): Promise {\n const ext = file.name.split('.').pop()?.toLowerCase();\n const buf: ArrayBuffer = (file as any)._buf ?? (await file.arrayBuffer());\n const predecodedText: string | undefined = (file as any)._text;\n let result: any;\n switch (ext) {\n case 'gpx':\n result = parseGPX(buf, predecodedText);\n break;\n case 'tcx':\n result = parseTCX(buf, predecodedText);\n break;\n case 'fit':\n result = await parseFIT(buf);\n break;\n case 'kml':\n result = parseKML(buf);\n break;\n default:\n throw new Error(`Unsupported format: .${ext}`);\n }\n\n if (result) {\n result.fileName = file.name;\n result.fileSize = file.size;\n if (result.points && result.stats) {\n ensureCurvesAndZones(result);\n result.stats.sections = analyzeTrackSections(result.points);\n }\n }\n return result;\n }\n\n return {\n parseFile,\n computeStats,\n ensureCurvesAndZones,\n analyzeTrackSections,\n findOverlaps,\n calculatePowerCurve,\n calculateHRCurve,\n calculatePowerZones,\n calculateHRZones,\n enrichPoints,\n setHRZones,\n getHRZones,\n setFTP,\n getFTP,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const R = 6371e3; // Earth radius in metres\n const phi1 = (lat1 * Math.PI) / 180;\n const phi2 = (lat2 * Math.PI) / 180;\n const deltaPhi = ((lat2 - lat1) * Math.PI) / 180;\n const deltaLambda = ((lon2 - lon1) * Math.PI) / 180;\n\n const a =\n Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) +\n Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\n return R * c;\n}\n\nexport function compactId(timestamp: number): string {\n // Use a compact representation of the timestamp (seconds since epoch)\n // 1712650000 -> Base64\n const buf = new Uint32Array([Math.floor(timestamp / 1000)]);\n const b64 = btoa(String.fromCharCode(...new Uint8Array(buf.buffer)));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\nexport function shortRandom(): string {\n return Math.random().toString(36).slice(2, 6);\n}\n\nexport function fmtDuration(s: number): string {\n if (s < 60) return `${Math.round(s)}s`;\n if (s < 3600) return `${Math.round(s / 60)}m`;\n return `${Math.round(s / 3600)}h`;\n}\n\nexport function fmtSecs(s: number): string {\n const h = Math.floor(s / 3600),\n m = Math.floor((s % 3600) / 60);\n return h > 0 ? `${h}h ${m}m` : `${m}m ${Math.floor(s % 60)}s`;\n}\n\nexport function fmtPace(seconds: number | null): string {\n if (seconds == null || !isFinite(seconds)) return '--';\n const mins = Math.floor(seconds / 60);\n const secs = Math.round(seconds % 60);\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n}\n\nexport function fmtDate(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown date';\n return d.toISOString().split('T')[0];\n}\n\nexport function fmtDateTime(ts: number | string | Date): string {\n const d = new Date(ts);\n if (isNaN(d.getTime())) return 'Unknown';\n const iso = d.toISOString();\n return `${iso.split('T')[0]} ${iso.split('T')[1].slice(0, 5)}`;\n}\n\nexport function fmtFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function escHtml(str: string): string {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function getTagColor(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);\n\n const h = Math.abs(hash % 360);\n return `hsl(${h}, 70%, 65%)`;\n}\n\n/**\n * Smoothes a numeric array using a simple Gaussian kernel.\n * sigma: standard deviation (radius of smoothing)\n */\nexport function gaussianSmooth(data: (number | null)[], sigma: number = 2): (number | null)[] {\n if (sigma <= 0) return data;\n\n const size = Math.ceil(sigma * 3) * 2 + 1;\n const kernel = new Float32Array(size);\n const half = Math.floor(size / 2);\n let sum = 0;\n\n for (let i = 0; i < size; i++) {\n const x = i - half;\n kernel[i] = Math.exp(-(x * x) / (2 * sigma * sigma));\n sum += kernel[i];\n }\n for (let i = 0; i < size; i++) kernel[i] /= sum;\n\n const result: (number | null)[] = new Array(data.length);\n for (let i = 0; i < data.length; i++) {\n if (data[i] === null) {\n result[i] = null;\n continue;\n }\n\n let val = 0;\n let weightSum = 0;\n for (let k = 0; k < size; k++) {\n const idx = i + k - half;\n if (idx >= 0 && idx < data.length && data[idx] !== null) {\n val += data[idx]! * kernel[k];\n weightSum += kernel[k];\n }\n }\n result[i] = weightSum > 0 ? val / weightSum : data[i];\n }\n return result;\n}\n\nexport function hexToRgba(hex: string, alpha: number = 1): string {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, TrackPoint } from './parsers';\n\nexport const MapView = (() => {\n let trackData: Record = {};\n let customClickHandler: ((e: any) => boolean) | null = null;\n\n function init(\n onSelectCb: (id: string) => void,\n onMoveCb: (lat: number, lng: number, zoom: number) => void,\n onPointClickCb: (id: string, idx: number) => void,\n onPointHoverCb: (id: string | null, idx: number | null) => void,\n onDblClickCb: () => void,\n ) {}\n\n function switchBasemap(layer: string) {}\n function addTrack(t: TrackData) {\n trackData[t.id] = t;\n }\n function addTracks(ts: TrackData[]) {\n ts.forEach((t) => {\n trackData[t.id] = t;\n });\n }\n function removeTrack(id: string) {\n delete trackData[id];\n }\n function clearTracks() {\n trackData = {};\n }\n function removeAllTracks() {\n trackData = {};\n }\n function setTrackVisible(id: string, visible: boolean) {}\n function setSelectedTrack(id: string | null, fit: boolean) {}\n function fitAll() {}\n function fitTrack(id: string) {}\n function showCursorAt(lat: number, lon: number) {}\n function hideCursor() {}\n function highlightSegment(\n id: string | null,\n pts: TrackPoint[],\n start: number,\n end: number,\n fit?: boolean,\n colors?: string[] | null,\n ) {}\n function clearHighlight() {}\n function setTrackHover(id: string, hover: boolean) {}\n function ensureVisible(pts: any) {}\n function centerOn(lat: number, lon: number, zoom?: number | null, force?: boolean) {}\n function closePopup() {}\n function invalidateSize() {}\n function getPosition(): [number, number, number] {\n return [0, 0, 0];\n }\n function setPosition(lat: number, lng: number, zoom: number) {}\n function colorTrackByMetric(id: string, pts: TrackPoint[], colors: string[]) {}\n function clearMetricColor(id: string) {}\n\n function findTracksPassingThroughPoints(\n points: { lat: number; lng: number }[],\n radius: number,\n ): string[] {\n return Object.keys(trackData);\n }\n\n return {\n init,\n getMap: () => null as any,\n setCustomClickHandler: (handler: any) => {\n customClickHandler = handler;\n },\n switchBasemap,\n addTrack,\n addTracks,\n removeTrack,\n clearTracks,\n removeAllTracks,\n setTrackVisible,\n setSelectedTrack,\n fitAll,\n fitTrack,\n showCursorAt,\n hideCursor,\n highlightSegment,\n clearHighlight,\n setTrackHover,\n ensureVisible,\n centerOn,\n closePopup,\n invalidateSize,\n getPosition,\n setPosition,\n colorTrackByMetric,\n clearMetricColor,\n findTracksPassingThroughPoints,\n getTrackData: (id: string) => trackData[id],\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackPoint, TrackStats, TrackData } from './parsers';\nimport { gaussianSmooth, fmtSecs, hexToRgba, fmtPace } from './utils';\nimport { Zones } from './zones';\nimport { METRICS, MetricDefinition } from './metrics';\nimport { UrlState } from './url-state';\nimport { SPORTS } from './sports';\n\n// Augment uPlot to include our custom property\n\ninterface WegPlot extends uPlot {\n _strasse?: {\n selFill: HTMLElement;\n anchorLine: HTMLElement;\n anchorLabel: HTMLElement;\n anchorHandle: HTMLElement;\n anchorMarker: HTMLElement;\n endLine: HTMLElement;\n endLabel: HTMLElement;\n endHandle: HTMLElement;\n endMarker: HTMLElement;\n curYVal: HTMLElement;\n updateHeaderStats: (min: number, max: number) => void;\n };\n}\n\ninterface PlotData {\n uplot: WegPlot;\n row: HTMLDivElement;\n xData: number[];\n yData: (number | null)[];\n def: MetricDefinition;\n metricKey: string;\n statsTotalEl: HTMLDivElement;\n statsSelEl: HTMLDivElement;\n histCol: HTMLDivElement;\n histCanvas: HTMLCanvasElement;\n histData: HistData;\n hoveredHistY: number | null;\n pinnedHistY: number | null;\n smoothed?: boolean;\n incZero?: boolean;\n w?: number;\n}\n\ninterface HistData {\n yData: (number | null)[];\n xData: number[];\n def: MetricDefinition;\n BINS: number;\n plot?: PlotData;\n bins?: number[];\n binAccum?: number[];\n min?: number;\n max?: number;\n padL?: number;\n selBins?: number[] | null;\n selBinAccum?: number[] | null;\n _lastYData?: any;\n _lastSelRange?: [number, number] | null;\n fullStats?: { min: number; max: number; avg: number } | null;\n fullStatsAll?: { min: number; max: number; avg: number } | null;\n}\n\nexport const ChartView = (() => {\n let plots: PlotData[] = [];\n let renderedTrack: TrackData | null = null;\n let renderedXAxis: string = 'time';\n let renderedSpeedMode: string = 'speed';\n let renderedMapColorMetric: string | null = null;\n let syncKey: {\n key: string;\n sub: (u: uPlot) => void;\n unsub: (u: uPlot) => void;\n pub: (type: string, u: uPlot, x: number, y: number, w: number, h: number, i: number) => void;\n } | null = null;\n let scaleSyncing: boolean = false;\n let cursorSyncing: boolean = false;\n let activeMetrics: Set = new Set(['elevation']);\n let availableMetrics: Set = new Set();\n let smoothedMetrics: Set = new Set(['speed', 'gradient', 'vam', 'temperature']);\n let metricsIncludingZero: Set = new Set(['power']);\n let xAxis: string = 'time';\n let currentTrack: TrackData | null = null;\n let allTracks: TrackData[] = [];\n\n // Selection / anchor\n let selAnchorVal: number | null = null; // x-value at drag-start / zoom left edge\n let selEndVal: number | null = null; // x-value at zoom right edge\n let isDragging: boolean = false;\n let updatingRange: boolean = false; // guard against setScale hook re-entry during handle drag\n let pinnedPtIdx: number | null = null; // point index pinned by map click\n let lastMouseXVal: number | null = null; // last hovered x-value for keyboard zoom center\n let lastHistMouseEvent: MouseEvent | null = null;\n let hoveredHistData: HistData | null = null;\n let hoveredHistCanvas: HTMLCanvasElement | null = null;\n\n let currentXRange: [number, number] | null = null; // [min, max] currently rendered\n let targetXRange: [number, number] | null = null; // [min, max] for smooth keyboard animation\n let animId: number | null = null;\n\n // Callbacks\n let onCursorMoveCb: ((pt: TrackPoint | null) => void) | null = null;\n let onRangeChangeCb: ((min: number | null, max: number | null, axis: string) => void) | null =\n null;\n let onClickCb: ((pt: TrackPoint, idx: number) => void) | null = null;\n let onPinChangeCb: ((idx: number | null) => void) | null = null;\n\n const HIST_W: number = 130;\n const ROW_BODY_PADDING: number = 28; // 14px left + 14px right\n const HIST_GAP: number = 20; // margin-left on .hist-col\n let statsVisible: boolean = true;\n let histTooltipEl: HTMLElement | null = null;\n let container: HTMLElement | null = null;\n let emptyEl: HTMLElement | null = null;\n let selStatsEl: HTMLElement | null = null;\n let resetSelBtn: HTMLElement | null = null;\n let mapColorMetric: string | null = null;\n let onMapColorChangeCb: ((data: { pts: TrackPoint[]; colors: string[] } | null) => void) | null =\n null;\n\n // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function init(\n onCursorMove: (pt: TrackPoint | null) => void,\n onRangeChange: (min: number | null, max: number | null, axis: string) => void,\n onClick: (pt: TrackPoint, idx: number) => void,\n onPinChange: (idx: number | null) => void,\n ) {\n onCursorMoveCb = onCursorMove;\n onRangeChangeCb = onRangeChange;\n onClickCb = onClick;\n onPinChangeCb = onPinChange;\n container = document.getElementById('charts-container');\n container?.addEventListener('scroll', () => {\n if (lastHistMouseEvent && hoveredHistCanvas && hoveredHistData)\n updateHistTooltip(lastHistMouseEvent, hoveredHistCanvas, hoveredHistData);\n });\n emptyEl = document.getElementById('chart-empty');\n selStatsEl = document.getElementById('chart-stats-sel');\n resetSelBtn = document.getElementById('btn-reset-selection');\n histTooltipEl = document.getElementById('hist-tooltip');\n syncKey = uPlot.sync('strasse-sync');\n\n document.getElementById('sel-cancel-btn')?.addEventListener('click', cancelSelection);\n resetSelBtn?.classList.add('hidden');\n\n // \u2500\u2500 WASD Keyboard Navigation \u2500\u2500\n const navKeys = new Set(['w', 'a', 's', 'd']);\n const activeNavKeys = new Set();\n\n document.addEventListener('keydown', (e) => {\n if (!plots.length || !currentTrack) return;\n if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName || '')) return;\n\n const key = e.key.toLowerCase();\n if (!navKeys.has(key)) return;\n\n e.preventDefault();\n activeNavKeys.add(key);\n\n const u = plots[0].uplot;\n if (!targetXRange) targetXRange = [u.scales.x!.min!, u.scales.x!.max!];\n\n let [min, max] = targetXRange;\n const span = max - min;\n const moveStep = span * 0.1;\n const zoomFactor = 0.15;\n\n let newMin = min,\n newMax = max;\n\n if (key === 'a') {\n // Pan left\n newMin = min - moveStep;\n newMax = max - moveStep;\n } else if (key === 'd') {\n // Pan right\n newMin = min + moveStep;\n newMax = max + moveStep;\n } else if (key === 'w' || key === 's') {\n // Zoom\n const center = lastMouseXVal !== null ? lastMouseXVal : (min + max) / 2;\n const factor = key === 'w' ? 1 - zoomFactor : 1 + zoomFactor * 1.2;\n newMin = center - (center - min) * factor;\n newMax = center + (max - center) * factor;\n }\n\n // Clamp to track bounds\n const xFull = [plots[0].xData[0]!, plots[0].xData[plots[0].xData.length - 1]!];\n if (newMin < xFull[0]) {\n const d = xFull[0] - newMin;\n newMin += d;\n newMax += d;\n }\n if (newMax > xFull[1]) {\n const d = newMax - xFull[1];\n newMin -= d;\n newMax -= d;\n }\n newMin = Math.max(xFull[0], newMin);\n newMax = Math.min(xFull[1], newMax);\n\n if (newMax - newMin > 0.001) {\n targetXRange = [newMin, newMax];\n setVisibleRange(newMin, newMax, true); // true = animate\n }\n });\n\n document.addEventListener('keyup', (e) => {\n const key = e.key.toLowerCase();\n if (navKeys.has(key)) activeNavKeys.delete(key);\n });\n }\n\n function setVisibleRange(min: number, max: number, animate = false) {\n if (!plots.length) return;\n if (!animate) {\n plots.forEach(({ uplot: u }) => u.setScale('x', { min, max }));\n return;\n }\n\n const startMin = (currentXRange ? currentXRange[0] : plots[0].uplot.scales.x!.min) as number;\n const startMax = (currentXRange ? currentXRange[1] : plots[0].uplot.scales.x!.max) as number;\n\n if (animId) cancelAnimationFrame(animId);\n\n const lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n const factor = 0.25; // Smoothing factor\n\n const step = () => {\n if (!targetXRange) return;\n const [tMin, tMax] = targetXRange;\n\n const cMin = lerp(currentXRange![0], tMin, factor);\n const cMax = lerp(currentXRange![1], tMax, factor);\n\n plots.forEach(({ uplot: u }) => {\n u.setScale('x', { min: cMin, max: cMax });\n });\n\n if (Math.abs(cMin - tMin) > 0.0001 || Math.abs(cMax - tMax) > 0.0001)\n animId = requestAnimationFrame(step);\n else animId = null;\n };\n animId = requestAnimationFrame(step);\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function loadTrack(track: TrackData, others: TrackData[] = [], deferRender = false) {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n allTracks = others;\n\n // Detect which metrics are available in this file\n availableMetrics = new Set(\n Object.entries(METRICS)\n .filter(([, def]) => track.points.some((p) => p[def.field] != null))\n .map(([key]) => key),\n );\n\n // If no metrics are active (e.g. first load), default to core overview metrics\n if (activeMetrics.size === 0) {\n activeMetrics = new Set(['elevation'].filter((m) => availableMetrics.has(m)));\n }\n\n // Sync the pill buttons in the toolbar\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n const metric = pill.dataset.metric!;\n const isAvailable = availableMetrics.has(metric);\n pill.classList.toggle('active', isAvailable && activeMetrics.has(metric));\n pill.classList.toggle('disabled', !isAvailable);\n });\n\n currentTrack = track;\n if (deferRender) {\n updateStats(track);\n } else {\n render();\n }\n }\n\n function clear() {\n pinnedPtIdx = null;\n selAnchorVal = null;\n selEndVal = null;\n currentTrack = null;\n destroyPlots();\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
Select a track to view analysis
\n `;\n }\n const chartStats = document.getElementById('chart-stats');\n if (chartStats) chartStats.classList.add('hidden');\n clearSelectionStats();\n mapColorMetric = null;\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n }\n\n function resetState() {\n if (animId !== null) {\n cancelAnimationFrame(animId);\n animId = null;\n }\n activeMetrics = new Set(['elevation']);\n availableMetrics = new Set();\n smoothedMetrics = new Set(['speed', 'gradient', 'vam', 'temperature']);\n metricsIncludingZero = new Set(['power']);\n xAxis = 'time';\n allTracks = [];\n currentXRange = null;\n targetXRange = null;\n lastMouseXVal = null;\n lastHistMouseEvent = null;\n hoveredHistData = null;\n hoveredHistCanvas = null;\n statsVisible = true;\n clear();\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n pill.classList.remove('disabled', 'overflow-hidden');\n });\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.add('hidden');\n const toolbar = document.getElementById('chart-toolbar');\n if (toolbar) toolbar.classList.remove('collapsed');\n document.querySelectorAll('#x-axis-ctrl .seg-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.axis === 'time');\n });\n }\n\n function toggleMetric(key: string) {\n if (activeMetrics.has(key)) activeMetrics.delete(key);\n else activeMetrics.add(key);\n if (currentTrack) render(true);\n }\n\n function setSmooth(metricKey: string, enabled: boolean, skipRender = false) {\n const has = smoothedMetrics.has(metricKey);\n if (enabled && !has) {\n smoothedMetrics.add(metricKey);\n if (currentTrack && !skipRender) render(true);\n } else if (!enabled && has) {\n smoothedMetrics.delete(metricKey);\n if (currentTrack && !skipRender) render(true);\n }\n }\n\n function setZeroInclusion(metricKey: string, includeZero: boolean) {\n const has = metricsIncludingZero.has(metricKey);\n if (includeZero && !has) {\n metricsIncludingZero.add(metricKey);\n if (currentTrack) render(true);\n } else if (!includeZero && has) {\n metricsIncludingZero.delete(metricKey);\n if (currentTrack) render(true);\n }\n }\n\n function setActiveMetrics(keys: string[]) {\n activeMetrics = new Set(keys);\n if (currentTrack) render(true);\n // Sync the pill buttons\n document.querySelectorAll('.metric-pill').forEach((el) => {\n const pill = el as HTMLElement;\n pill.classList.toggle('active', activeMetrics.has(pill.dataset.metric!));\n });\n }\n\n function setXAxis(axis: string) {\n if (xAxis === axis || !currentTrack) {\n xAxis = axis;\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n\n // Helper to convert a value from OLD axis to NEW axis\n const convert = (val: number | null) => {\n if (val === null) return null;\n // We need to find the point index closest to 'val' on the OLD axis\n let idx = 0;\n if (xAxis === 'distance') {\n const dTarget = val * 1000;\n idx = pts.findIndex((p) => (p.dist || 0) >= dTarget);\n } else {\n const tTarget = t0 + val * 1000;\n idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n }\n if (idx === -1) idx = pts.length - 1;\n\n // Now get the value at this index on the NEW axis\n if (axis === 'distance') return (pts[idx].dist || 0) / 1000;\n else return ((pts[idx].time || t0) - t0) / 1000;\n };\n\n // Convert selection\n if (selAnchorVal !== null) selAnchorVal = convert(selAnchorVal);\n if (selEndVal !== null) selEndVal = convert(selEndVal);\n\n // Convert zoom range (from first plot)\n let newRange: [number, number] | null = null;\n if (plots.length) {\n const u = plots[0].uplot;\n const r0 = convert(u.scales.x!.min!);\n const r1 = convert(u.scales.x!.max!);\n if (r0 !== null && r1 !== null) newRange = [r0, r1];\n }\n\n xAxis = axis;\n render(true);\n\n // Apply converted zoom\n if (newRange) {\n scaleSyncing = true;\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: newRange![0], max: newRange![1] }));\n });\n scaleSyncing = false;\n }\n }\n\n function toggleStats() {\n statsVisible = !statsVisible;\n plots.forEach(({ histCol }) => histCol.classList.toggle('visible', statsVisible));\n resize();\n }\n\n function setMapColorChangeCb(cb: (data: { pts: TrackPoint[]; colors: string[] } | null) => void) {\n onMapColorChangeCb = cb;\n }\n\n function toggleMapColor(key: string | null, skipRender = false) {\n if (mapColorMetric === key || key === null) {\n mapColorMetric = null;\n _updateMapColorBtns();\n if (onMapColorChangeCb) onMapColorChangeCb(null);\n } else {\n mapColorMetric = key;\n _updateMapColorBtns();\n _fireMapColorCb();\n }\n // Re-render to show/hide colored fills on the graphs\n if (currentTrack && !skipRender) render(true);\n }\n\n function _updateMapColorBtns() {\n document.querySelectorAll('.map-color-btn').forEach((el) => {\n const b = el as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === mapColorMetric);\n });\n }\n\n function _fireMapColorCb() {\n if (!onMapColorChangeCb || !mapColorMetric || !currentTrack) return;\n const plot = plots.find((p) => p.metricKey === mapColorMetric);\n if (!plot) return;\n const colors = _computePointColors(mapColorMetric, plot.yData);\n onMapColorChangeCb({ pts: currentTrack.points, colors });\n }\n\n function _computePointColors(key: string, yData: (number | null)[]): string[] {\n const vals = yData.filter((v): v is number => v != null && isFinite(v));\n if (!vals.length) return yData.map(() => '#888896');\n const min = Math.min(...vals),\n max = Math.max(...vals);\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n return yData.map((v) => {\n if (v == null || !isFinite(v)) return '#888896';\n if (key === 'gradient') return gradientColor(v);\n if (key === 'speed') {\n if (speedMode === 'pace') {\n const speed = (paceUnit === 'km' ? 1000 : 100) / v;\n return speedColor(speed);\n }\n return speedColor(v);\n }\n const t = max === min ? 0.5 : Math.max(0, Math.min(1, (v - min) / (max - min)));\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25);\n if (t <= 0.5) return lerpHex('#91bfdb', '#fee090', (t - 0.25) / 0.25);\n if (t <= 0.75) return lerpHex('#fee090', '#fc8d59', (t - 0.5) / 0.25);\n return lerpHex('#fc8d59', '#d73027', (t - 0.75) / 0.25);\n });\n }\n\n function resetZoom() {\n cancelSelection();\n }\n\n function cancelSelection() {\n selAnchorVal = null;\n selEndVal = null;\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n\n // Reset individual histogram pins\n plots.forEach((p) => {\n p.pinnedHistY = null;\n });\n\n updateSelOverlay();\n redrawHistograms();\n\n // Perform the actual zoom reset\n scaleSyncing = true;\n plots.forEach(({ uplot: u, xData }) => {\n u.batch(() => u.setScale('x', { min: xData[0]!, max: xData[xData.length - 1]! }));\n u._strasse?.updateHeaderStats(xData[0]!, xData[xData.length - 1]!);\n });\n scaleSyncing = false;\n\n if (onRangeChangeCb) onRangeChangeCb(null, null, xAxis);\n }\n\n function setSelectionStats(stats: TrackStats) {\n if (!selStatsEl) return;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt(\n 'sel-distance',\n stats.totalDist != null ? `${(stats.totalDist / 1000).toFixed(1)} km` : '\u2014',\n );\n fmt('sel-duration', stats.duration != null ? fmtSecs(Math.floor(stats.duration / 1000)) : '\u2014');\n fmt('sel-elevation', stats.elevGain != null ? `${Math.round(stats.elevGain)} m` : '\u2014');\n fmt(\n 'sel-avg-speed',\n stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014',\n );\n fmt('sel-avg-power', stats.avgPower != null ? `${stats.avgPower} W` : '\u2014');\n fmt('sel-avg-hr', stats.avgHR != null ? `${stats.avgHR} bpm` : '\u2014');\n fmt('sel-avg-temp', stats.avgTemp != null ? `${stats.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n selStatsEl.classList.remove('hidden');\n if (resetSelBtn) resetSelBtn.classList.remove('hidden');\n }\n\n function clearSelectionStats() {\n if (selStatsEl) selStatsEl.classList.add('hidden');\n if (resetSelBtn) resetSelBtn.classList.add('hidden');\n [\n 'sel-distance',\n 'sel-duration',\n 'sel-elevation',\n 'sel-avg-speed',\n 'sel-avg-power',\n 'sel-avg-hr',\n 'sel-avg-temp',\n ].forEach((id) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = '--';\n });\n }\n\n // Called on boot to restore a saved selection without re-firing onRangeChangeCb\n // xMin/xMax are ALWAYS provided in Time (seconds from start)\n function restoreSelection(tMin: number, tMax: number, deferRender = false) {\n if (!currentTrack) return;\n const pts = currentTrack.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const totalDuration = ((pts[pts.length - 1]?.time || 0) - t0) / 1000;\n\n // If values look like absolute timestamps in ms, convert to seconds from start\n if (tMin > 1e12) tMin = (tMin - t0) / 1000;\n if (tMax > 1e12) tMax = (tMax - t0) / 1000;\n\n // Crop to max limits of the track\n tMin = Math.max(0, Math.min(tMin, totalDuration));\n tMax = Math.max(0, Math.min(tMax, totalDuration));\n\n const convert = (tOffset: number) => {\n if (xAxis === 'time') return tOffset;\n const tTarget = t0 + tOffset * 1000;\n let idx = pts.findIndex((p) => (p.time || 0) >= tTarget);\n if (idx === -1) idx = pts.length - 1;\n return (pts[idx].dist || 0) / 1000;\n };\n\n const xMin = convert(tMin);\n const xMax = convert(tMax);\n\n selAnchorVal = xMin;\n selEndVal = xMax;\n currentXRange = [xMin, xMax];\n if (deferRender) return;\n scaleSyncing = true; // suppress the setScale \u2192 onRangeChangeCb loop\n plots.forEach(({ uplot: u }) => {\n u.batch(() => u.setScale('x', { min: xMin, max: xMax }));\n });\n scaleSyncing = false;\n updateAnchorLines();\n redrawHistograms();\n }\n\n function resize() {\n if (!plots.length || !container) return;\n const w = Math.round(\n Math.max(\n 100,\n container.getBoundingClientRect().width -\n ROW_BODY_PADDING -\n (statsVisible ? HIST_W + HIST_GAP : 0),\n ),\n );\n let anyResized = false;\n plots.forEach(({ uplot: u, histCanvas, histData }) => {\n if (w !== u.width) {\n u.setSize({ width: w, height: u.height });\n anyResized = true;\n if (statsVisible && histCanvas && histData) drawHistogram(histCanvas, histData, u.height);\n }\n });\n if (anyResized) updateSelOverlay();\n }\n\n // \u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function render(keepState = false) {\n let savedRange: [number, number] | null = null;\n let savedScroll = 0;\n if (keepState && container) savedScroll = container.scrollTop;\n\n if (keepState && currentXRange) {\n savedRange = [currentXRange[0], currentXRange[1]];\n } else if (keepState && plots.length) {\n const u = plots[0].uplot;\n savedRange = [u.scales.x!.min!, u.scales.x!.max!];\n }\n\n if (!currentTrack) {\n destroyPlots(keepState);\n return;\n }\n const pts = currentTrack.points;\n if (!pts.length) {\n destroyPlots(keepState);\n return;\n }\n\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n const paceUnit = sportDef?.paceUnit || 'km';\n\n const available = [...activeMetrics].filter((m) =>\n pts.some((p) => p[METRICS[m].field] != null),\n );\n if (!available.length) {\n destroyPlots(keepState);\n if (emptyEl) {\n emptyEl.style.display = 'flex';\n emptyEl.innerHTML = `\n no_sim\n
No data for selected metrics
\n `;\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n\n const containerW = container ? container.getBoundingClientRect().width : 800;\n const w = Math.round(\n Math.max(100, containerW - ROW_BODY_PADDING - (statsVisible ? HIST_W + HIST_GAP : 0)),\n );\n\n const canReuse =\n keepState &&\n renderedTrack === currentTrack &&\n renderedXAxis === xAxis &&\n renderedSpeedMode === speedMode &&\n renderedMapColorMetric === mapColorMetric &&\n plots.length > 0;\n\n let xData: (number | null)[];\n if (canReuse) {\n xData = plots[0].xData;\n } else if (xAxis === 'distance') {\n xData = pts.map((p) => (p.dist || 0) / 1000);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n let lastValidX = 0;\n xData = pts.map((p) => {\n if (p.time != null) {\n lastValidX = (p.time - t0) / 1000;\n return lastValidX;\n }\n return lastValidX; // monotonic fallback\n });\n }\n\n const existingByKey = new Map();\n if (canReuse) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const availSet = new Set(available);\n for (const p of plots) {\n const isSmoothed = smoothedMetrics.has(p.metricKey);\n const isIncZero = metricsIncludingZero.has(p.metricKey);\n if (\n availSet.has(p.metricKey) &&\n p.smoothed === isSmoothed &&\n p.incZero === isIncZero &&\n p.w === w\n ) {\n existingByKey.set(p.metricKey, p);\n } else {\n syncKey!.unsub(p.uplot);\n p.uplot.destroy();\n p.row.remove();\n }\n }\n plots = [];\n } else {\n destroyPlots(keepState);\n }\n\n if (container) {\n const nextSiblingRows: (HTMLElement | null)[] = new Array(available.length).fill(null);\n let nextExisting: HTMLElement | null = null;\n for (let i = available.length - 1; i >= 0; i--) {\n nextSiblingRows[i] = nextExisting;\n const ex = existingByKey.get(available[i]);\n if (ex) nextExisting = ex.row;\n }\n\n available.forEach((key, idx) => {\n const reused = existingByKey.get(key);\n if (reused) {\n plots.push(reused);\n const uplot = reused.uplot;\n const s = (uplot as any)._strasse;\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n uplot.batch(() => {\n if (\n savedRange &&\n (uplot.scales.x!.min !== savedRange[0] || uplot.scales.x!.max !== savedRange[1])\n ) {\n uplot.setScale('x', { min: savedRange[0], max: savedRange[1] });\n } else {\n s?.updateHeaderStats(uplot.scales.x!.min!, uplot.scales.x!.max!, uplot);\n uplot.redraw(false);\n }\n });\n scaleSyncing = prevSync;\n\n let initHoverBinI: number | null = null;\n if (\n pinnedPtIdx != null &&\n reused.xData[pinnedPtIdx] != null &&\n reused.yData[pinnedPtIdx] != null\n ) {\n buildHistBins(reused.histData);\n if (reused.histData.min != null && reused.histData.max != null) {\n const span = reused.histData.max - reused.histData.min || 1;\n initHoverBinI = Math.min(\n reused.histData.BINS - 1,\n Math.floor(\n ((reused.yData[pinnedPtIdx]! - reused.histData.min) / span) *\n reused.histData.BINS,\n ),\n );\n reused.hoveredHistY = reused.yData[pinnedPtIdx];\n }\n }\n drawHistogram(reused.histCanvas, reused.histData, 130, initHoverBinI);\n return;\n }\n\n let def = METRICS[key];\n\n let transform = def.transform;\n let fmt = def.fmt;\n let fmtAxis = def.fmtAxis;\n let unit = def.unit;\n let label = def.label;\n\n if (key === 'speed' && speedMode === 'pace') {\n label = 'Pace';\n unit = `min/${paceUnit}`;\n fmt = (v) => fmtPace(v);\n fmtAxis = (v) => fmtPace(v);\n transform = (v) => {\n if (v == null || v < 0.1) return null;\n return (paceUnit === 'km' ? 1000 : 100) / v;\n };\n\n def = { ...def, label, unit, fmt, fmtAxis, transform };\n }\n\n let yData = def.compute\n ? def.compute(pts, fillNulls)\n : fillNulls(\n pts.map((p) => {\n const v = p[def.field] as number;\n return v != null && transform ? transform(v) : v;\n }),\n );\n\n if (smoothedMetrics.has(key)) yData = gaussianSmooth(yData, def.smoothSigma || 2);\n\n createChart(key, def, xData, yData, w, pts, savedRange, nextSiblingRows[idx]);\n });\n }\n\n renderedTrack = currentTrack;\n renderedXAxis = xAxis;\n renderedSpeedMode = speedMode;\n renderedMapColorMetric = mapColorMetric;\n\n updateStats(currentTrack);\n // Restore anchor/end lines if a selection was active\n if (selAnchorVal != null && selEndVal != null) updateAnchorLines();\n // Re-apply map color if active\n _updateMapColorBtns();\n if (mapColorMetric) _fireMapColorCb();\n\n if (keepState && container && savedScroll > 0) container.scrollTop = savedScroll;\n }\n\n // \u2500\u2500 Create one chart row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function createChart(\n metricKey: string,\n def: MetricDefinition,\n xData: (number | null)[],\n yData: (number | null)[],\n w: number,\n pts: TrackPoint[],\n initialRange: [number, number] | null = null,\n insertBeforeEl: HTMLElement | null = null,\n ) {\n const sport = currentTrack?.sport;\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const defaultMode = sportDef?.defaultPreset || 'speed';\n const urlState = UrlState.get();\n const speedMode = (urlState as any).speed_mode || defaultMode;\n\n // Gradient data: smooth over a 20 m distance window (\u00B110 m each side)\n const gradData = metricKey === 'elevation' ? smoothGradient(pts, 20) : null;\n const row = document.createElement('div');\n row.className = 'chart-row';\n row.dataset.metric = metricKey;\n row.style.setProperty('--chart-color', def.color);\n\n // Header\n const header = document.createElement('div');\n header.className = `chart-row-header${statsVisible ? ' with-histogram' : ''}`;\n\n const labelEl = document.createElement('div');\n labelEl.className = 'chart-row-label-group';\n labelEl.innerHTML = `\n ${def.icon}\n ${def.label}\n `;\n\n // Smoothing toggle\n const smoothBtn = document.createElement('button');\n smoothBtn.className = `icon-btn mini smooth-btn${smoothedMetrics.has(metricKey) ? ' active' : ''}`;\n smoothBtn.title = 'Toggle data smoothing';\n smoothBtn.innerHTML = `${smoothedMetrics.has(metricKey) ? 'blur_on' : 'blur_off'}`;\n smoothBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (smoothedMetrics.has(metricKey)) smoothedMetrics.delete(metricKey);\n else smoothedMetrics.add(metricKey);\n\n render(true); // Re-render all charts to keep sync if needed (though only this one changes data)\n });\n\n const mapColorBtn = document.createElement('button');\n\n mapColorBtn.className = `map-color-btn icon-btn${mapColorMetric === metricKey ? ' active' : ''}`;\n mapColorBtn.dataset.metric = metricKey;\n mapColorBtn.title = 'Color map track by this metric';\n mapColorBtn.innerHTML = 'colorize';\n mapColorBtn.addEventListener('click', () => toggleMapColor(metricKey));\n\n // Zero-filter toggle (Cadence/Power/Speed)\n let zeroBtn: HTMLButtonElement | null = null;\n if (metricKey === 'cadence' || metricKey === 'power' || metricKey === 'speed') {\n zeroBtn = document.createElement('button');\n const incZero = metricsIncludingZero.has(metricKey);\n zeroBtn.className = `icon-btn mini${incZero ? ' active' : ''}`;\n zeroBtn.title = incZero ? 'Currently INCLUDING 0 values' : 'Currently EXCLUDING 0 values';\n zeroBtn.innerHTML = `${incZero ? 'exposure_zero' : 'mobile_off'}`;\n zeroBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (metricsIncludingZero.has(metricKey)) metricsIncludingZero.delete(metricKey);\n else metricsIncludingZero.add(metricKey);\n render(true);\n });\n }\n\n const statsTotalEl = document.createElement('div');\n statsTotalEl.className = 'chart-stats-total';\n\n const statsSelEl = document.createElement('div');\n statsSelEl.className = 'chart-stats-selection';\n\n const statsContainer = document.createElement('div');\n statsContainer.className = 'chart-row-stats-container';\n statsContainer.append(statsTotalEl, statsSelEl);\n\n const actionsEl = document.createElement('div');\n actionsEl.className = 'chart-row-actions';\n actionsEl.append(smoothBtn, mapColorBtn);\n\n const rightActionsEl = document.createElement('div');\n rightActionsEl.className = 'chart-row-right-actions';\n\n if (metricKey === 'speed') {\n const paceToggle = document.createElement('div');\n paceToggle.className = 'seg-ctrl';\n paceToggle.innerHTML = `\n \n \n `;\n paceToggle.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const mode = btn.dataset.mode;\n if (mode === 'speed' || mode === 'pace') {\n const isDefault = mode === defaultMode;\n UrlState.patch({ speed_mode: isDefault ? null : mode });\n render(true);\n }\n });\n rightActionsEl.append(paceToggle);\n }\n\n if (zeroBtn) rightActionsEl.append(zeroBtn);\n\n header.append(labelEl, actionsEl, statsContainer, rightActionsEl);\n\n const rowBody = document.createElement('div');\n rowBody.className = 'chart-row-body';\n\n const plotEl = document.createElement('div');\n plotEl.style.position = 'relative';\n rowBody.appendChild(plotEl);\n\n const fixedMinLabel = document.createElement('div');\n fixedMinLabel.className = 'fixed-x-label fixed-x-min';\n const fixedMaxLabel = document.createElement('div');\n fixedMaxLabel.className = 'fixed-x-label fixed-x-max';\n plotEl.append(fixedMinLabel, fixedMaxLabel);\n\n const histCol = document.createElement('div');\n histCol.className = `hist-col${statsVisible ? ' visible' : ''}`;\n const histCanvas = document.createElement('canvas');\n histCanvas.className = 'hist-canvas';\n histCol.appendChild(histCanvas);\n rowBody.appendChild(histCol);\n\n row.append(header, rowBody);\n\n const isDistAxis = xAxis === 'distance';\n\n function formatX(v: number, range: number): string {\n if (v == null) return '';\n if (isDistAxis) {\n const dec = range < 1 ? 3 : range < 5 ? 2 : range < 20 ? 1 : 0;\n return `${v.toFixed(dec)} km`;\n } else {\n const absV = Math.abs(v);\n const h = Math.floor(absV / 3600);\n const m = Math.floor((absV % 3600) / 60);\n const s = Math.round(absV % 60);\n const hh = h > 0 ? `${h}:` : '';\n const mm = h > 0 ? String(m).padStart(2, '0') : String(m);\n const ss = String(s).padStart(2, '0');\n return `${v < 0 ? '-' : ''}${hh}${mm}:${ss}`;\n }\n }\n\n const incZeroDefault =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Compute global Y range and full-track stats in a single pass\n let gMin = Infinity,\n gMax = -Infinity,\n allSum = 0,\n allCount = 0,\n filtMin = Infinity,\n filtMax = -Infinity,\n filtSum = 0,\n filtCount = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < gMin) gMin = v;\n if (v > gMax) gMax = v;\n allSum += v;\n allCount++;\n if (v !== 0 || incZeroDefault) {\n if (v < filtMin) filtMin = v;\n if (v > filtMax) filtMax = v;\n filtSum += v;\n filtCount++;\n }\n }\n if (allCount === 0) {\n gMin = 0;\n gMax = 100;\n }\n const fullStatsAll = allCount ? { min: gMin, max: gMax, avg: allSum / allCount } : null;\n const fullStatsFiltered = filtCount\n ? { min: filtMin, max: filtMax, avg: filtSum / filtCount }\n : null;\n const gPad = Math.abs(gMax - gMin) * 0.1 || 1;\n const fixedYRange = [gMin - gPad, gMax + gPad];\n\n let statsTotalInitialized = false;\n\n // Per-range stats\n function updateHeaderStats(visibleMin: number, visibleMax: number, u?: uPlot) {\n const incZero =\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n // Update fixed X labels\n const range = visibleMax - visibleMin;\n fixedMinLabel.textContent = formatX(visibleMin, range);\n fixedMaxLabel.textContent = formatX(visibleMax, range);\n\n const getHtml = (xMin: number, xMax: number, isFull = false) => {\n const s =\n isFull && incZero === incZeroDefault\n ? fullStatsFiltered\n : rangeStats(xData, yData, xMin, xMax, incZero);\n if (!s) return '';\n\n let h = `\n align_flex_end${def.fmt(s.min, true)} ${def.unit}\n align_center${def.fmt(s.avg, true)} ${def.unit}\n align_flex_start${def.fmt(s.max, true)} ${def.unit}\n `;\n\n if (metricKey === 'elevation') {\n const es = elevationRangeStats(pts, xMin, xMax);\n h += `\n trending_up+${Math.round(es.gain)} m\n trending_down-${Math.round(es.loss)} m\n `;\n }\n return h;\n };\n\n if (!statsTotalInitialized) {\n statsTotalInitialized = true;\n statsTotalEl.innerHTML = `all_inclusive${getHtml(\n xData[0]!,\n xData[xData.length - 1]!,\n true,\n )}`;\n statsTotalEl.querySelector('.all-chip')?.addEventListener('click', (e) => {\n e.stopPropagation();\n cancelSelection();\n });\n }\n\n if (selAnchorVal !== null && selEndVal !== null) {\n statsSelEl.innerHTML = getHtml(selAnchorVal, selEndVal, false);\n statsSelEl.style.display = 'flex';\n statsSelEl.style.setProperty('--sel-color', def.color);\n } else {\n statsSelEl.style.display = 'none';\n }\n }\n let initializingScale = false;\n const uOpts: uPlot.Options = {\n width: w,\n height: 130,\n padding: [4, 0, 0, 0],\n cursor: {\n sync: {\n key: syncKey!.key,\n },\n drag: { x: true, y: false, uni: 16 },\n focus: { prox: 16 },\n points: {\n size: 7,\n stroke: '#0e0e10',\n width: 2,\n fill: (metricKey === 'elevation'\n ? (u: uPlot, _si: number) => gradientColor(gradData ? gradData[u.cursor.idx!]! : null)\n : def.color) as any,\n },\n x: false,\n y: false,\n },\n select: {\n show: true,\n left: 0,\n top: 0,\n width: 0,\n height: 0,\n },\n legend: { show: false },\n scales: {\n x: {\n time: false,\n range: (_u: uPlot, mn: number, mx: number) => [mn, mx],\n min: initialRange ? initialRange[0] : undefined,\n max: initialRange ? initialRange[1] : undefined,\n },\n y: {\n range: () => fixedYRange as [number, number],\n dir: metricKey === 'speed' && speedMode === 'pace' ? -1 : 1,\n },\n },\n axes: [\n {\n side: 2, // bottom\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: {\n show: true,\n stroke: '#2e2e34',\n },\n size: 30,\n space: 80,\n font: '10px system-ui, sans-serif',\n splits: (u: uPlot, axisIdx: number, scaleMin: number, scaleMax: number) => {\n const range = scaleMax - scaleMin;\n const width = u.bbox.width > 0 ? u.bbox.width : u.width;\n const targetLabels = width / 80;\n const idealIncr = range / targetLabels;\n\n let incrs;\n if (!isDistAxis) {\n // Time in seconds\n incrs = [\n 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600, 7200, 14400, 28800, 43200,\n 86400, 604800, 2592000, 31536000,\n ];\n } else {\n incrs = [\n 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000,\n 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000,\n ];\n }\n\n let incr = incrs[incrs.length - 1];\n for (let i = 0; i < incrs.length; i++) {\n if (incrs[i] >= idealIncr) {\n incr = incrs[i];\n break;\n }\n }\n\n const splits = [];\n let val = Math.ceil(scaleMin / incr) * incr;\n const precision = incr < 1 ? 2 : 0;\n\n while (val <= scaleMax) {\n const pos = u.valToPos(val, 'x', true);\n if (pos >= u.bbox.left + 80 && pos <= u.bbox.left + u.bbox.width - 80)\n splits.push(Number(val.toFixed(precision)));\n\n val += incr;\n }\n return splits;\n },\n values: ((_u: uPlot, vals: number[]) => {\n const range = (_u.scales.x?.max ?? 1) - (_u.scales.x?.min ?? 0);\n\n return vals.map((v) => {\n if (v == null) return '';\n const pos = _u.valToPos(v, 'x', true);\n // Strict 80px margin to prevent overlapping with fixed labels or Y axis\n if (pos < _u.bbox.left + 80 || pos > _u.bbox.left + _u.bbox.width - 80) return null;\n return formatX(v, range);\n });\n }) as any,\n },\n {\n side: 3, // left\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n ticks: { stroke: '#2e2e34' },\n size: 55,\n font: '10px system-ui, sans-serif',\n values: ((_u: uPlot, vals: number[]) =>\n vals.map((v) => (v != null ? def.fmtAxis(v) : ''))) as any,\n },\n ],\n series: [\n {},\n // Main selected track series\n {\n label: def.label,\n stroke: 'rgba(0,0,0,0)', // Stroke handled in draw hooks for layering\n width: 0,\n points: { show: false },\n paths: () => null,\n },\n ],\n hooks: {\n draw: [\n (u: uPlot) => {\n const top = u.bbox.top + u.bbox.height + 5; // 5px below plot area!\n fixedMinLabel.style.top = `${top}px`;\n fixedMinLabel.style.left = `${u.bbox.left}px`;\n\n fixedMaxLabel.style.top = `${top}px`;\n fixedMaxLabel.style.left = `${u.bbox.left + u.bbox.width}px`;\n fixedMaxLabel.style.transform = 'translateX(-100%)';\n },\n // 1. (bottom) Color / metric color of the selected track\n (u: uPlot) => {\n if (metricKey === 'gears') {\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n } else if (metricKey === 'elevation') {\n drawElevationGradient(u, xData as number[], yData as number[], gradData);\n } else if (metricKey === 'gradient') {\n drawGradientChart(u, xData as number[], yData as number[]);\n } else if (mapColorMetric === metricKey) {\n drawMetricColorFill(u, xData as number[], yData as number[], pts, metricKey);\n } else {\n // Normal colored line\n drawTrackPath(\n u,\n xData as number[],\n yData as number[],\n def.color,\n 1.5,\n metricKey,\n null,\n pts,\n );\n }\n },\n\n // 2. Pinned point (middle)\n (u: uPlot) => {\n const plot = plots.find((p) => p.uplot === u);\n if (!plot) return;\n\n const s = (u as any)._strasse;\n // Priority 1: Global pinned point (all charts)\n if (pinnedPtIdx != null) {\n drawPinnedDot(u, xData, yData, def.color, def, pts, metricKey);\n } else {\n if (s && s.pinYVal) s.pinYVal.style.display = 'none';\n\n // Priority 2: Individual histogram pinned Y-pos (this chart only)\n if (plot.pinnedHistY != null)\n drawYAxisHighlight(u, xData, yData, plot.pinnedHistY, def.color, def);\n }\n },\n\n // 3. Pinned & Hover elements (labels, vertical lines)\n (u: uPlot) => {\n const hIdx = u.cursor.idx;\n const hasPinned = pinnedPtIdx != null;\n\n let hasHover = hIdx != null && u.cursor.left! >= 0;\n if (hasHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[hIdx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) hasHover = false;\n }\n\n // B. Draw Hover vertical line\n if (hasHover && hIdx !== pinnedPtIdx)\n drawVerticalLineOnly(u, pts, hIdx!, hexToRgba(def.color, 0.4), 1.0);\n\n // C. Bold selection x-axis line & span pill\n if (selAnchorVal != null && selEndVal != null) {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ax = u.valToPos(selAnchorVal, 'x', true);\n const ex = u.valToPos(selEndVal, 'x', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.lineWidth = 3 * dpr;\n ctx.strokeStyle = def.color;\n ctx.moveTo(ax, bb.top + bb.height);\n ctx.lineTo(ex, bb.top + bb.height);\n ctx.stroke();\n\n const span = Math.abs(selEndVal - selAnchorVal);\n const label = xAxis === 'distance' ? `${span.toFixed(2)} km` : fmtSecs(span);\n const fontSize = 9 * dpr;\n const fontStr = `bold ${fontSize}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n\n const visibleL = Math.max(bb.left, ax);\n const visibleR = Math.min(bb.left + bb.width, ex);\n const visibleW = visibleR - visibleL;\n\n if (visibleW > tw + 14 * dpr) {\n const padH = 5 * dpr;\n const padV = 2 * dpr;\n const bw = tw + padH * 2;\n const bh = fontSize + padV * 2;\n const bx = (visibleL + visibleR) / 2 - bw / 2;\n const by = bb.top + bb.height - bh / 2;\n\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = def.color;\n ctx.fill();\n\n ctx.fillStyle = '#000';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2);\n }\n ctx.restore();\n }\n\n // D. Draw label pills (on top)\n // Pinned labels first (semi-transparent)\n if (hasPinned) drawXAxisLabels(u, pts, pinnedPtIdx!, def.color, true, 0.7);\n\n // Hover labels last (fully opaque, topmost)\n if (hasHover && hIdx !== pinnedPtIdx)\n drawXAxisLabels(u, pts, hIdx!, def.color, true, 1.0);\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (scaleSyncing) return;\n const idx = u.cursor.idx;\n\n // Trigger redraw on cursor move to ensure custom canvas markers (hover lines/labels) update live\n // Note: uPlot handles cross-chart sync when syncKey is used.\n u.redraw(false);\n\n // Track current x-value for keyboard navigation\n if (u.cursor.left! >= 0) lastMouseXVal = u.posToVal(u.cursor.left!, 'x');\n else lastMouseXVal = null;\n\n // \u2500\u2500 Floating y-value next to cursor dot \u2500\u2500\n const s = (u as any)._strasse;\n let showHover = idx != null && yData[idx] != null;\n\n // Distance threshold: if no pinned point, check proximity to data line\n if (showHover && pinnedPtIdx == null) {\n const cy = u.valToPos(yData[idx!]!, 'y', true);\n const dist = Math.abs(u.cursor.top! - cy);\n if (dist > 100) showHover = false;\n }\n\n if (s) {\n if (showHover)\n updateTooltip(\n u,\n s.curYVal,\n idx!,\n xData as number[],\n yData as number[],\n pts,\n def,\n metricKey,\n );\n else s.curYVal.style.display = 'none';\n }\n\n // Map marker\n if (!cursorSyncing) {\n if (idx != null && pts[idx]) {\n if (onCursorMoveCb && (pinnedPtIdx != null || showHover)) {\n onCursorMoveCb(pts[idx]);\n } else if (onCursorMoveCb && !showHover) {\n // If we're too far and nothing is pinned, hide map cursor\n onCursorMoveCb(null);\n }\n } else if (idx === null && onCursorMoveCb) {\n onCursorMoveCb(null);\n }\n }\n\n // Highlight matching histogram bucket\n if (idx != null && yData[idx] != null) {\n const { min, max } = histData;\n if (min != null && max != null) {\n const span = max - min || 1;\n const binI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[idx]! - min) / span) * histData.BINS),\n );\n if (plot.hoveredHistY !== yData[idx]) {\n plot.hoveredHistY = yData[idx];\n drawHistogram(histCanvas, histData, 130, binI);\n }\n }\n } else if (plot.hoveredHistY !== null) {\n plot.hoveredHistY = null;\n drawHistogram(histCanvas, histData, 130);\n }\n },\n ],\n\n setScale: [\n (u: uPlot, key: string) => {\n if (key !== 'x' || initializingScale) return;\n const { min, max } = u.scales.x!;\n\n // Sync currentXRange so keyboard navigation baseline is always accurate\n currentXRange = [min!, max!];\n\n // Update header stats for VISIBLE range\n updateHeaderStats(min as number, max as number, u);\n\n if (scaleSyncing) return;\n\n // Clear keyboard target when user interacts via mouse\n if (!updatingRange) targetXRange = null;\n\n // Sync sibling plots\n scaleSyncing = true;\n plots.forEach(({ uplot: other }) => {\n if (other !== u) other.batch(() => other.setScale('x', { min: min!, max: max! }));\n });\n scaleSyncing = false;\n\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb && selAnchorVal !== null)\n onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n },\n ],\n\n setSelect: [\n (u: uPlot) => {\n if (updatingRange) return;\n targetXRange = null;\n const { left, width } = u.select;\n if (width > 0) {\n const min = u.posToVal(left, 'x');\n const max = u.posToVal(left + width, 'x');\n selAnchorVal = min;\n selEndVal = max;\n\n // Sync stats to new selection\n updateHeaderStats(u.scales.x!.min!, u.scales.x!.max!, u);\n updateSelOverlay();\n redrawHistograms();\n\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n\n // Clear uPlot's internal selection immediately so it doesn't block WASD/interaction\n u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);\n }\n },\n ],\n },\n };\n\n // \u2500\u2500 Overlay (pointer-events off except handles) \u2500\u2500\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5';\n\n // Selection fill\n const selFill = document.createElement('div');\n selFill.className = 'sel-fill';\n selFill.style.display = 'none';\n\n // Anchor line + label + drag handle\n const anchorLine = document.createElement('div');\n anchorLine.className = 'sel-line sel-line-anchor';\n anchorLine.style.display = 'none';\n\n const anchorLabel = document.createElement('div');\n anchorLabel.className = 'sel-line-label sel-line-label-anchor';\n anchorLabel.style.display = 'none';\n\n const anchorHandle = document.createElement('div');\n anchorHandle.className = 'sel-handle sel-handle-anchor';\n anchorHandle.style.display = 'none';\n\n const anchorMarker = document.createElement('div');\n anchorMarker.className = 'sel-graph-marker';\n anchorMarker.innerHTML =\n 'play_circle';\n anchorMarker.style.display = 'none';\n\n // End line + label + drag handle\n const endLine = document.createElement('div');\n endLine.className = 'sel-line sel-line-end';\n endLine.style.display = 'none';\n\n const endLabel = document.createElement('div');\n endLabel.className = 'sel-line-label sel-line-label-end';\n endLabel.style.display = 'none';\n\n const endHandle = document.createElement('div');\n endHandle.className = 'sel-handle sel-handle-end';\n endHandle.style.display = 'none';\n\n const endMarker = document.createElement('div');\n endMarker.className = 'sel-graph-marker';\n endMarker.innerHTML =\n 'stop_circle';\n endMarker.style.display = 'none';\n\n // Floating cursor y-value\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${def.color};display:none`;\n\n // Floating pinned y-value\n const pinYVal = document.createElement('div');\n pinYVal.className = 'cur-y-val pin';\n pinYVal.style.cssText = `color:${def.color};display:none`;\n\n overlay.append(\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n );\n\n const histData: HistData = {\n yData,\n xData: xData as number[],\n def,\n BINS: 24,\n min: allCount ? gMin : undefined,\n max: allCount ? gMax : undefined,\n fullStats: fullStatsFiltered,\n fullStatsAll,\n };\n const plot: PlotData = {\n uplot: null as any,\n row,\n xData: xData as number[],\n yData,\n def,\n metricKey,\n statsTotalEl,\n statsSelEl,\n histCol,\n histCanvas,\n histData,\n hoveredHistY: null,\n pinnedHistY: null,\n smoothed: smoothedMetrics.has(metricKey),\n incZero: metricsIncludingZero.has(metricKey),\n w,\n };\n histData.plot = plot; // Back-reference for tooltip to trigger redraws\n\n const prevSync = scaleSyncing;\n scaleSyncing = true;\n const uplot = new uPlot(uOpts, [xData, yData] as any, (self, init) => {\n plot.uplot = self as WegPlot;\n plots.push(plot);\n plotEl.appendChild(self.root);\n self.over.appendChild(overlay);\n (self as any)._strasse = {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n curYVal,\n pinYVal,\n updateHeaderStats,\n };\n self.batch(() => {\n init();\n });\n }) as WegPlot;\n scaleSyncing = prevSync;\n\n // \u2500\u2500 Handle drag \u2500\u2500\n attachHandleDrag(anchorHandle, uplot, xData, true);\n attachHandleDrag(endHandle, uplot, xData, false);\n\n // \u2500\u2500 Mouse listeners \u2500\u2500\n let mousedownX: number | null = null;\n uplot.over.addEventListener('mousedown', (e) => {\n if (e.button !== 0) return;\n isDragging = false;\n const rect = uplot.over.getBoundingClientRect();\n const xPx = e.clientX - rect.left;\n mousedownX = xPx;\n });\n uplot.over.addEventListener('mousemove', (e) => {\n if (mousedownX !== null) {\n const rect = uplot.over.getBoundingClientRect();\n if (Math.abs(e.clientX - rect.left - mousedownX) > 5) isDragging = true;\n }\n });\n uplot.over.addEventListener('mouseup', () => {\n mousedownX = null;\n });\n\n // Click to pin point (sticky selection)\n uplot.over.addEventListener('click', () => {\n if (isDragging) return;\n const idx = uplot.cursor.idx;\n if (idx != null && pts[idx]) {\n pinnedPtIdx = idx;\n plots.forEach(({ uplot: u }) => u.redraw(false));\n if (onClickCb) onClickCb(pts[idx], idx);\n if (onPinChangeCb) onPinChangeCb(idx);\n }\n });\n\n row.addEventListener('dblclick', cancelSelection);\n\n let initHoverBinI: number | null = null;\n if (pinnedPtIdx != null && xData[pinnedPtIdx] != null && yData[pinnedPtIdx] != null) {\n buildHistBins(histData);\n if (histData.min != null && histData.max != null) {\n const span = histData.max - histData.min || 1;\n initHoverBinI = Math.min(\n histData.BINS - 1,\n Math.floor(((yData[pinnedPtIdx]! - histData.min) / span) * histData.BINS),\n );\n plot.hoveredHistY = yData[pinnedPtIdx];\n }\n }\n\n drawHistogram(histCanvas, histData, 130, initHoverBinI);\n attachHistTooltip(histCanvas, histData);\n if (container) {\n if (insertBeforeEl) container.insertBefore(row, insertBeforeEl);\n else container.appendChild(row);\n }\n }\n\n // \u2500\u2500 Selection overlay (fill + lines + handles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateSelOverlay() {\n updateAnchorLines();\n // Redraw canvas markers (bold selection line + span pill)\n plots.forEach(({ uplot: u }) => u.batch(() => u.redraw(false)));\n }\n\n function updateAnchorLines() {\n plots.forEach(({ uplot: u, def }) => {\n const s = (u as any)._strasse;\n if (!s) return;\n const {\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n } = s;\n if (selAnchorVal == null || selEndVal == null) {\n [\n selFill,\n anchorLine,\n anchorLabel,\n anchorHandle,\n anchorMarker,\n endLine,\n endLabel,\n endHandle,\n endMarker,\n ].forEach((el: HTMLElement) => {\n el.style.display = 'none';\n });\n return;\n }\n const aX = u.valToPos(selAnchorVal, 'x');\n const eX = u.valToPos(selEndVal, 'x');\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const overW = bb.width / dpr;\n const overH = bb.height / dpr;\n const plotBottom = (bb.top + bb.height) / dpr;\n\n const isAnchorVisible = aX >= 0 && aX <= overW;\n const isEndVisible = eX >= 0 && eX <= overW;\n\n // Fill: clamp left/right to visible area\n const fillL = Math.max(0, aX);\n const fillR = Math.min(overW, eX);\n if (fillR > fillL) {\n selFill.style.left = `${fillL}px`;\n selFill.style.width = `${fillR - fillL}px`;\n selFill.style.top = '0';\n selFill.style.height = `${overH}px`;\n selFill.style.backgroundColor = hexToRgba(def.color, 0.07);\n selFill.style.display = '';\n } else {\n selFill.style.display = 'none';\n }\n\n // Anchor line\n if (isAnchorVisible) {\n anchorLine.style.left = `${aX}px`;\n anchorLine.style.height = `${overH}px`;\n anchorLine.style.borderLeftColor = def.color;\n anchorLine.style.display = '';\n // Anchor label\n const aText = fmtXVal(selAnchorVal);\n anchorLabel.textContent = aText;\n const aLabelW = aText.length * 7 + 10;\n anchorLabel.style.left = aX + aLabelW + 4 < overW ? `${aX + 3}px` : `${aX - aLabelW - 3}px`;\n anchorLabel.style.display = '';\n // Anchor handle\n anchorHandle.style.left = `${aX}px`;\n anchorHandle.style.backgroundColor = def.color;\n anchorHandle.style.display = '';\n // Anchor marker: centered on the bold line\n anchorMarker.style.left = `${aX}px`;\n anchorMarker.style.top = `${plotBottom}px`;\n const aIcon = anchorMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (aIcon) aIcon.style.color = def.color;\n anchorMarker.style.display = '';\n } else {\n [anchorLine, anchorLabel, anchorHandle, anchorMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n\n // End line\n if (isEndVisible) {\n endLine.style.left = `${eX}px`;\n endLine.style.height = `${overH}px`;\n endLine.style.borderLeftColor = def.color;\n endLine.style.display = '';\n // End label\n const eText = fmtXVal(selEndVal);\n endLabel.textContent = eText;\n const eLabelW = eText.length * 7 + 10;\n endLabel.style.left = eX - eLabelW - 3 > 0 ? `${eX - eLabelW - 3}px` : `${eX + 3}px`;\n endLabel.style.display = '';\n // End handle\n endHandle.style.left = `${eX}px`;\n endHandle.style.backgroundColor = def.color;\n endHandle.style.display = '';\n // End marker: centered on the bold line\n endMarker.style.left = `${eX}px`;\n endMarker.style.top = `${plotBottom}px`;\n const eIcon = endMarker.querySelector('.material-symbols-rounded') as HTMLElement;\n if (eIcon) eIcon.style.color = def.color;\n endMarker.style.display = '';\n } else {\n [endLine, endLabel, endHandle, endMarker].forEach(\n (el: HTMLElement) => (el.style.display = 'none'),\n );\n }\n });\n }\n\n function fmtXVal(v: number) {\n return xAxis === 'distance' ? `${v.toFixed(2)} km` : fmtSecs(v);\n }\n\n // \u2500\u2500 Handle drag logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function attachHandleDrag(\n handleEl: HTMLElement,\n uplot: uPlot,\n xData: (number | null)[],\n isAnchor: boolean,\n ) {\n // pointer-events enabled on the handle itself\n handleEl.style.pointerEvents = 'auto';\n\n handleEl.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n e.preventDefault();\n const startX = e.clientX;\n const startVal = isAnchor ? selAnchorVal : selEndVal;\n const overW = uplot.over.offsetWidth;\n // px-per-data-unit at current zoom\n const xMin = uplot.scales.x!.min!,\n xMax = uplot.scales.x!.max!;\n const pxPerUnit = overW / (xMax - xMin);\n const xFull = [xData[0]!, xData[xData.length - 1]!];\n\n document.body.style.cursor = 'ew-resize';\n isDragging = true;\n\n function onMove(me: MouseEvent) {\n const dx = me.clientX - startX;\n let newVal = (startVal || 0) + dx / pxPerUnit;\n newVal = Math.max(xFull[0], Math.min(xFull[1], newVal));\n\n if (isAnchor) selAnchorVal = Math.min(newVal, (selEndVal || xFull[1]) - 0.001);\n else selEndVal = Math.max(newVal, (selAnchorVal || xFull[0]) + 0.001);\n\n // When dragging handles, we typically want to stay zoomed to the selection?\n // Actually, let's keep the zoom as is, and just update the selection overlay and stats.\n plots.forEach((p) =>\n (p.uplot as any)._strasse?.updateHeaderStats(\n p.uplot.scales.x!.min!,\n p.uplot.scales.x!.max!,\n ),\n );\n updateSelOverlay();\n redrawHistograms();\n if (onRangeChangeCb) onRangeChangeCb(selAnchorVal, selEndVal, xAxis);\n }\n\n function onUp() {\n document.body.style.cursor = '';\n isDragging = false;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n }\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n }\n\n // \u2500\u2500 Histogram logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function buildHistBins(histData: HistData) {\n const { yData, xData, BINS } = histData;\n\n // Cache to avoid re-binning every frame during hover\n if (histData._lastYData === yData && histData.bins) return;\n histData._lastYData = yData;\n\n let min = histData.min;\n let max = histData.max;\n if (min == null || max == null) {\n let lo = Infinity,\n hi = -Infinity,\n cnt = 0;\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v < lo) lo = v;\n if (v > hi) hi = v;\n cnt++;\n }\n if (!cnt) return;\n min = lo;\n max = hi;\n histData.min = min;\n histData.max = max;\n }\n\n const bins = new Array(BINS).fill(0);\n const binAccum = new Array(BINS).fill(0); // accumulated x-weight per bin (time in s or dist in km)\n\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n bins[bi]++;\n\n // weight by x-delta\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n binAccum[bi] += (next - prev) / 2;\n }\n histData.bins = bins;\n histData.binAccum = binAccum;\n }\n\n function redrawHistograms() {\n plots.forEach(({ histCanvas, histData, uplot: u }) => {\n drawHistogram(histCanvas, histData, u.height);\n });\n }\n\n function drawHistogram(\n canvas: HTMLCanvasElement,\n histData: HistData,\n chartH: number,\n hoverBinI: number | null = null,\n ) {\n const { def, BINS } = histData;\n buildHistBins(histData);\n const { bins, min, max } = histData;\n if (!bins || min == null || max == null) return;\n\n const hasSel = selAnchorVal != null && selEndVal != null;\n\n // Compute selection bins if a range is active and changed\n if (\n hasSel &&\n (histData._lastSelRange?.[0] !== selAnchorVal || histData._lastSelRange?.[1] !== selEndVal)\n ) {\n histData._lastSelRange = [selAnchorVal!, selEndVal!];\n const selBins = new Array(BINS).fill(0);\n const selBinAccum = new Array(BINS).fill(0);\n const { yData, xData } = histData;\n const span = max - min || 1;\n const metricKey =\n histData.plot?.metricKey ?? Object.keys(METRICS).find((k) => METRICS[k] === histData.def);\n const incZero =\n !metricKey ||\n metricsIncludingZero.has(metricKey) ||\n (metricKey !== 'power' && metricKey !== 'cadence' && metricKey !== 'speed');\n\n for (let i = 0; i < yData.length; i++) {\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n const x = xData[i];\n if (x == null || x < selAnchorVal! || x > selEndVal!) continue;\n const bi = Math.min(BINS - 1, Math.floor(((v - min) / span) * BINS));\n selBins[bi]++;\n const prev = i > 0 && xData[i - 1] != null ? xData[i - 1]! : xData[i]!;\n const next = i < xData.length - 1 && xData[i + 1] != null ? xData[i + 1]! : xData[i]!;\n selBinAccum[bi] += (next - prev) / 2;\n }\n histData.selBins = selBins;\n histData.selBinAccum = selBinAccum;\n } else if (!hasSel) {\n histData.selBins = null;\n histData.selBinAccum = null;\n histData._lastSelRange = null;\n }\n const selBins = histData.selBins;\n\n const dpr = window.devicePixelRatio || 1;\n const W = HIST_W;\n const H = chartH;\n\n // Performance: only set dimensions if they changed (resets canvas)\n if (canvas.width !== W * dpr || canvas.height !== H * dpr) {\n canvas.width = W * dpr;\n canvas.height = H * dpr;\n canvas.style.width = `${W}px`;\n canvas.style.height = `${H}px`;\n }\n\n const ctx = canvas.getContext('2d')!;\n ctx.resetTransform();\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, W, H);\n\n const peak = Math.max(...bins);\n\n // Measure label width so bars start right after them\n const fmt = (v: number) => def.fmtAxis(v);\n const fontStr = '9px system-ui, sans-serif';\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const labelW = Math.ceil(\n Math.max(\n ctx.measureText(`${fmt(max)} ${def.unit}`).width,\n ctx.measureText(`${fmt(min)} ${def.unit}`).width,\n ),\n );\n\n // Vertical alignment with main graph:\n // uPlot padding: [4, 0, 0, 0]\n // Axis size: 30\n const pad = { t: 4, r: 0, b: 30, l: labelW + 6 };\n histData.padL = pad.l;\n const plotW = W - pad.l - pad.r;\n const plotH = H - pad.t - pad.b;\n\n // bin 0 = lowest values \u2192 drawn at bottom; bin BINS-1 = highest \u2192 drawn at top\n const binY = (i: number) => pad.t + (BINS - 1 - i) * (plotH / BINS);\n const binH = plotH / BINS - 1;\n\n // Full distribution (dimmed when selection active)\n const baseAlpha = hasSel ? 0.15 : 0.6;\n ctx.fillStyle = hexToRgba(def.color, baseAlpha);\n for (let i = 0; i < BINS; i++) {\n if (!bins[i]) continue;\n const bw = (bins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n\n // Selection overlay (bright)\n if (selBins) {\n ctx.fillStyle = hexToRgba(def.color, 0.85);\n for (let i = 0; i < BINS; i++) {\n if (!selBins[i]) continue;\n const bw = (selBins[i] / peak) * plotW;\n ctx.fillRect(pad.l, binY(i), bw, binH);\n }\n ctx.fillStyle = def.color;\n ctx.fillRect(pad.l, pad.t, 2, plotH);\n }\n\n // CDF overlay \u2014 smooth curve from bottom (0%) to top (100%)\n const total = bins.reduce((s, v) => s + v, 0);\n if (total > 0) {\n // Build CDF points: one per bin boundary, bottom\u2192top\n const pts2 = [{ x: pad.l, y: pad.t + plotH }];\n let cumSum = 0;\n for (let i = 0; i < BINS; i++) {\n cumSum += bins[i];\n pts2.push({ x: pad.l + (cumSum / total) * plotW, y: binY(i) });\n }\n\n ctx.beginPath();\n // CDF line is now solid\n ctx.setLineDash([]);\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 0.75 * dpr;\n ctx.lineJoin = 'round';\n ctx.moveTo(pts2[0].x, pts2[0].y);\n for (let i = 1; i < pts2.length - 1; i++) {\n const mx = (pts2[i].x + pts2[i + 1].x) / 2;\n const my = (pts2[i].y + pts2[i + 1].y) / 2;\n ctx.quadraticCurveTo(pts2[i].x, pts2[i].y, mx, my);\n }\n ctx.lineTo(pts2[pts2.length - 1].x, pts2[pts2.length - 1].y);\n ctx.stroke();\n\n // \u2500\u2500 Hover highlight on CDF \u2500\u2500\n if (hoverBinI != null && pts2[hoverBinI + 1]) {\n const cp = pts2[hoverBinI + 1];\n // Vertical line down\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(def.color, 0.6);\n ctx.moveTo(cp.x, cp.y);\n ctx.lineTo(cp.x, pad.t + plotH);\n ctx.stroke();\n ctx.setLineDash([]);\n\n // Dot: tiny precision point\n ctx.beginPath();\n ctx.arc(cp.x, cp.y, 1.2 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = def.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n }\n\n // Axis labels: max at top, min at bottom\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n const font9 = '9px system-ui, sans-serif';\n if (ctx.font !== font9) ctx.font = font9;\n ctx.textAlign = 'right';\n\n // Draw Max\n ctx.textBaseline = 'top';\n ctx.fillText(`${fmt(max)} ${def.unit}`, pad.l - 4, pad.t);\n\n // Draw Min\n ctx.textBaseline = 'bottom';\n ctx.fillText(`${fmt(min)} ${def.unit}`, pad.l - 4, H - pad.b);\n\n // Draw Avg (only if it doesn't overlap min/max)\n const stats =\n !hasSel && histData.fullStatsAll !== undefined\n ? histData.fullStatsAll\n : rangeStats(\n histData.xData,\n histData.yData,\n selAnchorVal || -Infinity,\n selEndVal || Infinity,\n );\n if (stats) {\n const avgY =\n pad.t +\n (BINS - 1 - Math.min(BINS - 1, Math.floor(((stats.avg - min) / (max - min || 1)) * BINS))) *\n (plotH / BINS);\n const minLabelY = H - pad.b;\n const maxLabelY = pad.t;\n const labelHeight = 10; // Approx 10px height for 9px font\n\n if (avgY > maxLabelY + labelHeight + 2 && avgY < minLabelY - labelHeight - 2) {\n ctx.textBaseline = 'middle';\n if (ctx.fillStyle !== '#aaa') ctx.fillStyle = '#aaa';\n ctx.fillText(`${fmt(stats.avg)} ${def.unit}`, pad.l - 4, avgY);\n // Draw small indicator tick\n ctx.beginPath();\n ctx.moveTo(pad.l - 3, avgY);\n ctx.lineTo(pad.l, avgY);\n if (ctx.strokeStyle !== '#aaa') ctx.strokeStyle = '#aaa';\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n }\n\n // \u2500\u2500 Higher/Lower percentages below histogram \u2500\u2500\n if (hoverBinI != null && total > 0) {\n let countLower = 0;\n for (let i = 0; i < hoverBinI; i++) countLower += bins[i];\n let countHigher = 0;\n for (let i = hoverBinI + 1; i < BINS; i++) countHigher += bins[i];\n\n const pLower = Math.round((countLower / total) * 100);\n const pHigher = Math.round((countHigher / total) * 100);\n\n ctx.save();\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n const font8 = '8px system-ui, sans-serif';\n if (ctx.font !== font8) ctx.font = font8;\n\n const textY = H - pad.b + 6;\n\n // Draw \"Lower\" stat\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('LOWER', pad.l, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n const fontB10 = 'bold 10px system-ui, sans-serif';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pLower}%`, pad.l, textY + 10);\n\n // Draw \"Higher\" stat\n const midX = pad.l + plotW / 2;\n if (ctx.font !== font8) ctx.font = font8;\n if (ctx.fillStyle !== '#888896') ctx.fillStyle = '#888896';\n ctx.fillText('HIGHER', midX, textY);\n if (ctx.fillStyle !== '#ccc') ctx.fillStyle = '#ccc';\n if (ctx.font !== fontB10) ctx.font = fontB10;\n ctx.fillText(`${pHigher}%`, midX, textY + 10);\n\n ctx.restore();\n }\n }\n\n function attachHistTooltip(canvas: HTMLCanvasElement, histData: HistData) {\n const { plot } = histData;\n\n canvas.addEventListener('click', (e) => {\n const binI = getBinAt(canvas, histData, e);\n if (binI != null && plot) {\n const { min, max, BINS } = histData;\n const span = max! - min! || 1;\n plot.pinnedHistY = min! + (binI + 0.5) * (span / BINS!);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n }\n });\n\n canvas.addEventListener('mousemove', (e) => {\n lastHistMouseEvent = e;\n updateHistTooltip(e, canvas, histData);\n });\n\n canvas.addEventListener('mouseenter', () => {\n hoveredHistCanvas = canvas;\n hoveredHistData = histData;\n });\n\n canvas.addEventListener('mouseleave', () => {\n if (hoveredHistCanvas === canvas) {\n hoveredHistCanvas = null;\n hoveredHistData = null;\n }\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n const lineEl = document.getElementById('hist-line');\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n });\n }\n\n function getBinAt(canvas: HTMLCanvasElement, histData: HistData, e: MouseEvent) {\n const { bins, BINS } = histData;\n if (!bins) return null;\n const rect = canvas.getBoundingClientRect();\n const relY = e.clientY - rect.top;\n // Use exact padding from drawHistogram: t: 4, b: 30\n const pad = { t: 4, b: 30 };\n const plotH = rect.height - pad.t - pad.b;\n const rawI = Math.floor(((relY - pad.t) / plotH) * BINS!);\n const binI = BINS! - 1 - rawI;\n if (rawI < 0 || rawI >= BINS!) return null;\n return binI;\n }\n\n function updateHistTooltip(e: MouseEvent, canvas: HTMLCanvasElement, histData: HistData) {\n if (!histTooltipEl) return;\n const { bins, binAccum, min, max, BINS, def, plot } = histData;\n if (!bins || !binAccum || min == null || max == null) return;\n\n const lineEl = document.getElementById('hist-line');\n const binI = getBinAt(canvas, histData, e);\n\n if (binI == null || !bins[binI]) {\n histTooltipEl.style.display = 'none';\n if (lineEl) lineEl.style.display = 'none';\n if (plot) {\n plot.hoveredHistY = null;\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1));\n }\n return;\n }\n\n if (plot) {\n const span = max - min || 1;\n plot.hoveredHistY = min + (binI + 0.5) * (span / BINS!);\n drawHistogram(canvas, histData, canvas.height / (window.devicePixelRatio || 1), binI);\n }\n\n const count = bins[binI];\n const total = bins.reduce((s, v) => s + v, 0);\n const pct = (count / total) * 100;\n\n const span = max - min || 1;\n const low = min + binI * (span / BINS!);\n const high = min + (binI + 1) * (span / BINS!);\n const label = `${def.fmt(low, true)} \u2013 ${def.fmt(high, true)} ${def.unit}`;\n\n // Zone info\n let zoneHtml = '';\n const mid = (low + high) / 2;\n const metricKey = Object.keys(METRICS).find((k) => METRICS[k] === def);\n let zones: any[] = [];\n if (metricKey === 'power') zones = Zones.getPowerZones();\n else if (metricKey === 'hr') zones = Zones.getHRZones();\n\n if (zones.length > 0) {\n const zIdx = zones.findIndex((z) => mid >= z.min && mid < z.max);\n const z =\n zIdx !== -1\n ? zones[zIdx]\n : mid >= zones[zones.length - 1].min\n ? zones[zones.length - 1]\n : null;\n if (z) {\n const finalZIdx = zIdx !== -1 ? zIdx : zones.length - 1;\n zoneHtml = `\n
\n Z${finalZIdx + 1}\n \u00B7\n ${z.name}\n
\n `;\n }\n }\n\n const totalAccum =\n xAxis === 'distance' ? `${binAccum[binI].toFixed(2)} km` : fmtSecs(binAccum[binI]);\n const totalPct = (binAccum[binI] / binAccum.reduce((s, v) => s + v, 0)) * 100;\n\n let html = `\n
${label}
\n ${zoneHtml}\n `;\n\n if (totalAccum) {\n html += `
\n ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${totalAccum}\n ${totalPct.toFixed(1)}%\n
`;\n }\n\n // Selection context\n if (histData.selBins && histData.selBinAccum) {\n const stotalAccum =\n xAxis === 'distance'\n ? `${histData.selBinAccum[binI].toFixed(2)} km`\n : fmtSecs(histData.selBinAccum[binI]);\n const stotalPct =\n (histData.selBinAccum[binI] / histData.selBinAccum.reduce((s, v) => s + v, 0)) * 100;\n\n html += `\n
\n Sel ${xAxis === 'distance' ? 'Dist' : 'Time'}\n ${stotalAccum}\n ${stotalPct.toFixed(1)}%\n
\n `;\n }\n\n histTooltipEl.innerHTML = html;\n\n // Position tooltip: fixed X left of canvas, Y centered on bin\n histTooltipEl.style.display = 'block';\n const ttH = histTooltipEl.offsetHeight;\n const ttW = histTooltipEl.offsetWidth;\n const rect = canvas.getBoundingClientRect();\n const plotH = rect.height - 4 - 30; // pad.t + pad.b\n const binCenterY = rect.top + 4 + (BINS! - 1 - binI + 0.5) * (plotH / BINS!);\n\n histTooltipEl.style.left = `${rect.left - ttW - 12}px`;\n histTooltipEl.style.top = `${binCenterY - ttH / 2}px`;\n\n // Horizontal line sync\n if (lineEl) {\n lineEl.style.display = 'block';\n lineEl.style.top = `${binCenterY}px`;\n lineEl.style.left = '0px';\n lineEl.style.width = `${rect.left}px`;\n }\n }\n\n // \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function destroyPlots(keepState = false) {\n if (histTooltipEl) histTooltipEl.style.display = 'none';\n plots.forEach(({ uplot: u, row }) => {\n syncKey!.unsub(u);\n u.destroy();\n row.remove();\n });\n plots = [];\n renderedTrack = null;\n if (!keepState) {\n selAnchorVal = null;\n selEndVal = null;\n }\n isDragging = false;\n }\n\n function rangeStats(\n xData: (number | null)[],\n yData: (number | null)[],\n xMin: number,\n xMax: number,\n incZero = true,\n ) {\n let min = Infinity,\n max = -Infinity,\n sum = 0,\n n = 0;\n for (let i = 0; i < xData.length; i++) {\n if (xData[i] == null || xData[i]! < xMin || xData[i]! > xMax) continue;\n const v = yData[i];\n if (v == null || !isFinite(v)) continue;\n if (v === 0 && !incZero) continue;\n\n if (v < min) min = v;\n if (v > max) max = v;\n sum += v;\n n++;\n }\n return n ? { min, max, avg: sum / n } : null;\n }\n\n function elevationRangeStats(pts: TrackPoint[], xMin: number, xMax: number) {\n let gain = 0,\n loss = 0;\n let prevEle: number | null = null;\n const isDist = xAxis === 'distance';\n const t0 = pts[0].time || 0;\n\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const x = isDist ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n if (x < xMin || x > xMax) continue;\n\n if (p.ele != null) {\n if (prevEle != null) {\n const diff = p.ele - prevEle;\n if (diff > 0) gain += diff;\n else if (diff < 0) loss += Math.abs(diff);\n }\n prevEle = p.ele;\n }\n }\n return { gain, loss };\n }\n\n // \u2500\u2500 Plot Rendering Helpers (Canvas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function updateTooltip(\n u: WegPlot,\n el: HTMLElement,\n idx: number,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n def: MetricDefinition,\n metricKey: string,\n ) {\n if (idx == null || yData[idx] == null) {\n el.style.display = 'none';\n return;\n }\n\n const cx = u.valToPos(xData[idx]!, 'x', false);\n const cy = u.valToPos(yData[idx]!, 'y', false);\n\n let gColor = '#888896';\n let g = 0;\n if (idx > 0 && pts[idx] && pts[idx - 1]) {\n const p0 = pts[idx - 1],\n p1 = pts[idx];\n const d = (p1.dist || 0) - (p0.dist || 0);\n if (d > 0.1 && p1.ele != null && p0.ele != null) {\n g = ((p1.ele - p0.ele) / d) * 100;\n gColor = gradientColor(g);\n }\n }\n\n let content =\n metricKey !== 'elevation'\n ? `${def.fmt(yData[idx]!, false)} ${def.unit}`\n : `${def.fmt(yData[idx]!, false)} ${def.unit} \u2220 ${Math.abs(g).toFixed(1)}%`;\n\n // Special handling for gears: show tooth count if available\n if (metricKey === 'gearRear' && pts[idx].gearRearTooth != null) {\n content = `${pts[idx].gearRearTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gearFront' && pts[idx].gearFrontTooth != null) {\n content = `${pts[idx].gearFrontTooth}T (pos ${yData[idx]})`;\n } else if (metricKey === 'gears') {\n const p = pts[idx];\n const front =\n p.gearFrontTooth != null\n ? `${p.gearFrontTooth}T`\n : p.gearFront != null\n ? `pos ${p.gearFront}`\n : '';\n const rear =\n p.gearRearTooth != null\n ? `${p.gearRearTooth}T`\n : p.gearRear != null\n ? `pos ${p.gearRear}`\n : '';\n\n if (front || rear)\n content += ` (${front} / ${rear})`;\n }\n\n if (el.innerHTML !== content) el.innerHTML = content;\n\n const color44 = `${def.color}44`;\n if (el.style.color !== def.color) el.style.color = def.color;\n if (el.style.borderColor !== color44) el.style.borderColor = color44;\n\n const left = `${cx}px`;\n const top = `${cy}px`;\n const transform = 'translate(6px, -50%)';\n if (el.style.left !== left) el.style.left = left;\n if (el.style.top !== top) el.style.top = top;\n if (el.style.transform !== transform) el.style.transform = transform;\n if (el.style.display !== '') el.style.display = '';\n }\n\n const gradientColorRgbaCache = new Map();\n function gradientColorRgba(g: number | null): string {\n let c = gradientColorRgbaCache.get(g);\n if (!c) {\n c = hexToRgba(gradientColor(g), 0.8);\n gradientColorRgbaCache.set(g, c);\n }\n return c;\n }\n\n function drawElevationGradient(\n u: uPlot,\n xData: number[],\n yData: number[],\n gradData: (number | null)[] | null,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = gradData && gradData[i] != null ? Math.round(gradData[i]! / 2) * 2 : null;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawGradientChart(u: uPlot, xData: number[], yData: number[]) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yBase = bb.top + bb.height;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(1, idxs[0]) : 1;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.lineWidth = 1.5 * dpr;\n\n const byColor = new Map();\n\n let prevIdx = iStart - 1;\n for (let i = iStart; i <= iEnd; i += step) {\n const xv1 = xData[i];\n const xv0 = xData[prevIdx];\n prevIdx = i;\n if (xv1 == null || yData[i] == null || xv0 == null || yData[i - step] == null) continue;\n if (xv1 < xMin || xv0 > xMax) continue;\n\n const x0 = bb.left + (xv0 - xMin) * xScale;\n const y0 = yBase - (yData[i - step]! - yMin) * yScale;\n const x1 = bb.left + (xv1 - xMin) * xScale;\n const y1 = yBase - (yData[i]! - yMin) * yScale;\n\n const g = Math.round(yData[i]! / 2) * 2;\n const color = gradientColorRgba(g);\n let segs = byColor.get(color);\n if (!segs) {\n segs = [];\n byColor.set(color, segs);\n }\n segs.push(x0, y0, x1, y1);\n }\n\n for (const [color, segs] of byColor) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n for (let j = 0; j < segs.length; j += 4) {\n ctx.moveTo(segs[j], segs[j + 1]);\n ctx.lineTo(segs[j + 2], segs[j + 3]);\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawHoverLine(u: uPlot, yData: number[], color: string, pts: TrackPoint[]) {\n const idx = u.cursor.idx;\n if (idx == null || yData[idx] == null || u.cursor.left! < 0) return;\n\n const t0 = pts[0].time || 0;\n const xVal = xAxis === 'distance' ? (pts[idx].dist || 0) / 1000 : (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yData[idx], 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Line from top to point + horizontal from left\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, cy);\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Dot at point\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n\n function drawVerticalLineOnly(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const xVal =\n xAxis === 'distance'\n ? (pts[idx].dist || 0) / 1000\n : (pts[idx].time! - (pts[0].time || 0)) / 1000;\n const cx = u.valToPos(xVal, 'x', true);\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n // Dotted line range should match where labels are (flush top to bottom axis)\n ctx.moveTo(cx, bb.top + 16 * dpr);\n ctx.lineTo(cx, bb.top + bb.height + 10 * dpr);\n ctx.stroke();\n ctx.restore();\n }\n\n function drawXAxisLabels(\n u: uPlot,\n pts: TrackPoint[],\n idx: number,\n color: string,\n skipLine = false,\n opacity: number = 1.0,\n ) {\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const ctx = u.ctx;\n const t0 = pts[0].time || 0;\n const distVal = (pts[idx].dist || 0) / 1000;\n const timeVal = (pts[idx].time! - t0) / 1000;\n const cx = u.valToPos(xAxis === 'distance' ? distVal : timeVal, 'x', true);\n\n // Bottom label: matches the current X axis unit\n const bottomLabel = xAxis === 'distance' ? `${distVal.toFixed(2)} km` : fmtSecs(timeVal);\n // Top label: shows the other unit (simplified)\n const topLabel = xAxis === 'distance' ? fmtSecs(timeVal) : `${distVal.toFixed(2)} km`;\n\n const drawPill = (text: string, x: number, y: number, isTop: boolean) => {\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(text).width;\n const bw = tw + 10 * dpr;\n const bh = 16 * dpr;\n const rx = x - bw / 2;\n const clampedRx = Math.max(bb.left, Math.min(bb.left + bb.width - bw, rx));\n const ry = y - bh / 2;\n\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.setLineDash([]); // Ensure pills are not dashed\n ctx.beginPath();\n if ((ctx as any).roundRect) (ctx as any).roundRect(clampedRx, ry, bw, bh, 3 * dpr);\n else ctx.rect(clampedRx, ry, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.92)';\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, clampedRx + bw / 2, ry + bh / 2 + 0.5 * dpr);\n ctx.restore();\n };\n\n if (!skipLine) drawVerticalLineOnly(u, pts, idx, color, opacity);\n\n const pillH = 16 * dpr;\n // Top label: flush to the top edge of the plot\n drawPill(topLabel, cx, bb.top + pillH / 2, true);\n\n // Bottom label: aligned with the horizontal axis labels (centered in the 30px axis area)\n drawPill(bottomLabel, cx, bb.top + bb.height + 15 * dpr, false);\n }\n\n function drawPinnedDot(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n def: MetricDefinition,\n pts: TrackPoint[],\n metricKey: string,\n ) {\n if (pinnedPtIdx == null) return;\n const xVal = xData[pinnedPtIdx];\n const yVal = yData[pinnedPtIdx];\n if (xVal == null || yVal == null) return;\n\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n ctx.save();\n // Vertical line\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5 * dpr;\n ctx.moveTo(cx, bb.top);\n ctx.lineTo(cx, bb.top + bb.height);\n ctx.stroke();\n\n // Horizontal dashed line\n ctx.beginPath();\n ctx.setLineDash([3 * dpr, 3 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.5);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cy);\n ctx.lineTo(cx, cy);\n ctx.stroke();\n\n // Large Dot\n ctx.beginPath();\n ctx.setLineDash([]); // Ensure solid outline\n ctx.arc(cx, cy, 5 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2.5 * dpr;\n ctx.stroke();\n ctx.restore();\n\n const s = (u as any)._strasse;\n if (s && s.pinYVal) {\n updateTooltip(\n u,\n s.pinYVal,\n pinnedPtIdx,\n xData as number[],\n yData as (number | null)[],\n pts,\n def,\n metricKey,\n );\n }\n }\n\n function drawYAxisHighlight(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n yVal: number,\n color: string,\n def: MetricDefinition,\n ) {\n const bb = u.bbox;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const cy = u.valToPos(yVal, 'y', true);\n\n // Clamp cy to bbox\n const cyClamp = Math.max(bb.top, Math.min(bb.top + bb.height, cy));\n\n ctx.save();\n // Horizontal line\n ctx.beginPath();\n ctx.setLineDash([4 * dpr, 4 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(bb.left, cyClamp);\n ctx.lineTo(bb.left + bb.width, cyClamp);\n ctx.stroke();\n\n // Fill area above/below\n drawAreaFillAbove(u, xData, yData, cyClamp, color);\n\n // Pill label on Y-axis\n const label = def.fmt(yVal, true);\n const fontStr = `bold ${10 * dpr}px system-ui, sans-serif`;\n if (ctx.font !== fontStr) ctx.font = fontStr;\n const tw = ctx.measureText(label).width;\n const bw = tw + 8 * dpr;\n const bh = 16 * dpr;\n const bx = bb.left - bw - 2 * dpr;\n const by = cyClamp - bh / 2;\n\n ctx.beginPath();\n ctx.setLineDash([]);\n if ((ctx as any).roundRect) (ctx as any).roundRect(bx, by, bw, bh, 3 * dpr);\n else ctx.rect(bx, by, bw, bh);\n ctx.fillStyle = 'rgba(14,14,16,0.95)';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = '#fff';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(label, bx + bw / 2, by + bh / 2 + 0.5 * dpr);\n ctx.restore();\n }\n\n function drawAreaFillAbove(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n cyClamp: number,\n color: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = u.series[0]?.idxs;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step = Math.max(1, Math.floor((iEnd - iStart) / 250));\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.beginPath();\n\n let inSegment = false;\n let hasAnySegment = false;\n let lastPx = 0;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null || xv < xMin || xv > xMax) {\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n lastPx = px;\n\n if (py < cyClamp) {\n if (!inSegment) {\n ctx.moveTo(px, cyClamp);\n inSegment = true;\n hasAnySegment = true;\n }\n ctx.lineTo(px, py);\n } else if (inSegment) {\n ctx.lineTo(px, cyClamp);\n ctx.closePath();\n inSegment = false;\n }\n }\n\n if (inSegment) {\n ctx.lineTo(lastPx, cyClamp);\n ctx.closePath();\n }\n\n if (hasAnySegment) {\n ctx.fill();\n }\n\n ctx.restore();\n }\n\n // \u2500\u2500 Utils \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function lerpHex(a: string, b: string, t: number) {\n const ah = parseInt(a.slice(1), 16),\n bh = parseInt(b.slice(1), 16);\n const ar = ah >> 16,\n ag = (ah >> 8) & 0xff,\n ab = ah & 0xff;\n const br = bh >> 16,\n bg = (bh >> 8) & 0xff,\n bb = bh & 0xff;\n const rr = ar + (br - ar) * t,\n rg = ag + (bg - ag) * t,\n rb = ab + (bb - ab) * t;\n return `#${((1 << 24) + (Math.round(rr) << 16) + (Math.round(rg) << 8) + Math.round(rb))\n .toString(16)\n .slice(1)}`;\n }\n\n function gradientColor(g: number | null) {\n if (g == null) return '#888896';\n const absG = Math.abs(g);\n const t = Math.min(1, absG / 8);\n if (g > 0) return lerpHex('#A8C8A0', '#d73027', t); // Green to Red\n return lerpHex('#A8C8A0', '#4575b4', t); // Green to Blue\n }\n\n function speedColor(s: number | null) {\n if (s == null) return '#888896';\n const kmh = s * 3.6;\n\n if (kmh <= 5) return '#4575b4'; // Solid Blue for very slow\n if (kmh >= 60) return '#d73027'; // Solid Red for very fast\n\n // High resolution between 5 and 45 (10km/h per segment)\n if (kmh <= 45) {\n const t = (kmh - 5) / 40; // 0 to 1\n if (t <= 0.25) return lerpHex('#4575b4', '#91bfdb', t / 0.25); // 5-15: Blue -> LBlue\n if (t <= 0.5) return lerpHex('#91bfdb', '#abdda4', (t - 0.25) / 0.25); // 15-25: LBlue -> Green\n if (t <= 0.75) return lerpHex('#abdda4', '#fee08b', (t - 0.5) / 0.25); // 25-35: Green -> Yellow\n return lerpHex('#fee08b', '#fc8d59', (t - 0.75) / 0.25); // 35-45: Yellow -> Orange\n } else {\n // 45-60: Orange -> Red\n const t = (kmh - 45) / 15;\n return lerpHex('#fc8d59', '#d73027', t);\n }\n }\n\n function smoothGradient(pts: TrackPoint[], windowMetres: number) {\n const grads: (number | null)[] = new Array(pts.length).fill(null);\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n let j0 = i,\n j1 = i;\n while (j0 > 0 && (p.dist || 0) - (pts[j0].dist || 0) < windowMetres / 2) j0--;\n while (j1 < pts.length - 1 && (pts[j1].dist || 0) - (p.dist || 0) < windowMetres / 2) j1++;\n const d = (pts[j1].dist || 0) - (pts[j0].dist || 0);\n if (d > 1 && pts[j1].ele != null && pts[j0].ele != null)\n grads[i] = ((pts[j1].ele! - pts[j0].ele!) / d) * 100;\n }\n return grads;\n }\n\n function fillNulls(data: (number | null)[]) {\n const res = [...data];\n for (let i = 0; i < res.length; i++) {\n if (res[i] === null) {\n let left = i - 1;\n while (left >= 0 && res[left] === null) left--;\n let right = i + 1;\n while (right < res.length && res[right] === null) right++;\n if (left >= 0 && right < res.length)\n res[i] = res[left]! + ((res[right]! - res[left]!) * (i - left)) / (right - left);\n else if (left >= 0) res[i] = res[left];\n else if (right < res.length) res[i] = res[right];\n }\n }\n return res;\n }\n\n function updateStats(track: TrackData) {\n const s = track.stats;\n const fmt = (id: string, val: string) => {\n const el = document.querySelector(`#${id} .stat-value`);\n if (el) el.textContent = val;\n };\n fmt('stat-distance', s.totalDist != null ? `${(s.totalDist / 1000).toFixed(1)} km` : '\u2014');\n fmt('stat-duration', s.duration != null ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014');\n fmt('stat-elevation', s.elevGain != null ? `${Math.round(s.elevGain)} m` : '\u2014');\n\n // Recalculate averages from visible plot data to respect zero filtering\n const getAvg = (key: string) => {\n const p = plots.find((p) => p.metricKey === key);\n if (!p) {\n if (key === 'speed') return s.avgSpeed ?? null;\n if (key === 'power') return s.avgPower ?? null;\n if (key === 'cadence') return s.avgCadence ?? null;\n return null;\n }\n if (p.histData.fullStats !== undefined) {\n return p.histData.fullStats ? p.histData.fullStats.avg : null;\n }\n const incZero =\n metricsIncludingZero.has(key) || (key !== 'power' && key !== 'cadence' && key !== 'speed');\n const vals = p.yData.filter((v): v is number => v != null && (incZero || v !== 0));\n if (!vals.length) return null;\n return vals.reduce((a, b) => a + b, 0) / vals.length;\n };\n\n const avgSpeed = getAvg('speed');\n fmt('stat-avg-speed', avgSpeed != null ? `${(avgSpeed * 3.6).toFixed(1)} km/h` : '\u2014');\n\n const avgPower = getAvg('power');\n fmt('stat-avg-power', avgPower != null ? `${Math.round(avgPower)} W` : '\u2014');\n\n const avgCadence = getAvg('cadence');\n fmt('stat-avg-cad', avgCadence != null ? `${Math.round(avgCadence)} rpm` : '\u2014');\n\n fmt('stat-avg-hr', s.avgHR != null ? `${s.avgHR} bpm` : '\u2014');\n fmt('stat-avg-temp', s.avgTemp != null ? `${s.avgTemp.toFixed(1)} \u00B0C` : '\u2014');\n }\n\n const INTERVAL_CAP = 16384;\n const ivPwr = new Float64Array(INTERVAL_CAP);\n const ivHr = new Float64Array(INTERVAL_CAP);\n const ivSpd = new Float64Array(INTERVAL_CAP);\n const ivEle = new Float64Array(INTERVAL_CAP);\n const ivCad = new Float64Array(INTERVAL_CAP);\n const ivSmoothed = new Float64Array(INTERVAL_CAP);\n const ivKdeBins = new Float64Array(64);\n const intervalWindows = [\n 3, 5, 8, 10, 12, 15, 20, 25, 30, 40, 45, 60, 75, 90, 120, 150, 180, 240, 300, 360,\n ];\n\n function analyzeTelemetryIntervals(\n tracksList: TrackData[],\n selStartSec: number,\n selEndSec: number,\n ) {\n if (!tracksList.length) return 0;\n ivKdeBins.fill(0);\n let intervalScore = 0;\n\n for (let ti = 0; ti < tracksList.length; ti++) {\n const pts = tracksList[ti].points;\n const n = Math.min(pts.length, INTERVAL_CAP);\n if (n < 4) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n ivPwr[i] = p.power || 0;\n ivHr[i] = p.hr || 0;\n ivSpd[i] = p.speed || 0;\n ivEle[i] = p.ele || 0;\n ivCad[i] = p.cad || 0;\n }\n\n // Single-pass Savitzky-Golay 5-point quadratic smoothing and section interval analysis\n const sStart = Math.max(0, Math.min(n - 1, Math.floor(selStartSec)));\n const sEnd = Math.max(sStart + 1, Math.min(n, Math.floor(selEndSec)));\n const inv35 = 1 / 35;\n const invSigmaSq = 1 / 180;\n const omega = 0.012;\n\n for (let i = 2; i < n - 2; i++) {\n const sgPwr =\n (-3 * ivPwr[i - 2] +\n 12 * ivPwr[i - 1] +\n 17 * ivPwr[i] +\n 12 * ivPwr[i + 1] -\n 3 * ivPwr[i + 2]) *\n inv35;\n const sgHr =\n (-3 * ivHr[i - 2] +\n 12 * ivHr[i - 1] +\n 17 * ivHr[i] +\n 12 * ivHr[i + 1] -\n 3 * ivHr[i + 2]) *\n inv35;\n const sgSpd = (ivSpd[i - 1] + 2 * ivSpd[i] + ivSpd[i + 1]) * 0.25;\n const dP = sgPwr - ivPwr[i];\n const gauss = Math.exp(-dP * dP * invSigmaSq);\n const harmonic = Math.cos(i * omega + ivCad[i] * 0.02);\n ivSmoothed[i] = sgPwr * gauss + sgHr * 0.8 + sgSpd * (ivCad[i] * 0.1 + harmonic);\n }\n\n const sectionRanges: [number, number][] = [\n [0, Math.floor(n * 0.25)],\n [Math.floor(n * 0.25), Math.floor(n * 0.6)],\n [Math.floor(n * 0.6), n],\n [sStart, sEnd],\n ];\n\n for (let si = 0; si < sectionRanges.length; si++) {\n const [secStart, secEnd] = sectionRanges[si];\n const secLen = secEnd - secStart;\n if (secLen < 4) continue;\n\n for (let wi = 0; wi < intervalWindows.length; wi++) {\n const w = intervalWindows[wi];\n if (w >= secLen) continue;\n const invW = 1 / w;\n let winSum = 0;\n let winEle = 0;\n let maxInterval = 0;\n for (let i = secStart; i < secEnd; i++) {\n winSum += ivSmoothed[i];\n winEle += ivEle[i];\n if (i - secStart >= w) {\n winSum -= ivSmoothed[i - w];\n winEle -= ivEle[i - w];\n const avg = (winSum + winEle * 0.05) * invW;\n if (avg > maxInterval) maxInterval = avg;\n }\n }\n intervalScore += maxInterval * 1e-4;\n }\n\n // Section Kernel Density Estimation (KDE) binning\n for (let i = secStart; i < secEnd; i++) {\n const norm = Math.max(0, Math.min(63, ((ivSmoothed[i] * 0.12) | 0) & 63));\n ivKdeBins[norm] += 1 + (ivEle[i] - ivEle[secStart]) * 1e-3;\n if (norm > 0) ivKdeBins[norm - 1] += 0.5;\n if (norm < 63) ivKdeBins[norm + 1] += 0.5;\n }\n }\n }\n\n for (let b = 0; b < 64; b++) {\n intervalScore += ivKdeBins[b] * 1e-5;\n }\n if (container) {\n container.dataset.intervalScore = intervalScore.toFixed(2);\n }\n return intervalScore;\n }\n\n return {\n init,\n loadTrack,\n clear,\n resetState,\n toggleMetric,\n setXAxis,\n toggleStats,\n setSelectionStats,\n clearSelectionStats,\n restoreSelection,\n resetZoom,\n cancelSelection,\n analyzeTelemetryIntervals,\n setCursorAt: (idx: number, deferRender = false) => {\n pinnedPtIdx = idx;\n if (onPinChangeCb) onPinChangeCb(idx);\n if (deferRender) {\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n return;\n }\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb && currentTrack?.points?.[idx]) {\n onCursorMoveCb(currentTrack.points[idx]);\n }\n },\n setHoverAt: (idx: number | null) => {\n cursorSyncing = true;\n plots.forEach(({ uplot: u, yData, xData }) => {\n if (idx === null) {\n u.batch(() => {\n (u as any).setCursor({ left: -10, top: -10 }, true, false);\n });\n } else if (xData[idx] != null && yData[idx] != null) {\n u.batch(() => {\n (u as any).setCursor(\n {\n left: u.valToPos(xData[idx]!, 'x'),\n top: u.valToPos(yData[idx]!, 'y'),\n },\n true,\n false,\n );\n });\n }\n });\n cursorSyncing = false;\n if (onCursorMoveCb) {\n onCursorMoveCb(\n idx != null && currentTrack?.points?.[idx] ? currentTrack.points[idx] : null,\n );\n }\n },\n clearPinnedDot: () => {\n pinnedPtIdx = null;\n if (onPinChangeCb) onPinChangeCb(null);\n plots.forEach(({ uplot: u }) => u.redraw(false));\n },\n resize,\n METRICS,\n isDragging: () => isDragging,\n setMapColorChangeCb,\n toggleMapColor,\n getMapColorMetric: () => mapColorMetric,\n getActiveMetrics: () => activeMetrics,\n getAvailableMetrics: () => availableMetrics,\n setActiveMetrics,\n setSmooth,\n setZeroInclusion,\n updateMetricOrder: (keys: string[]) => {\n // Keys might only contain current active ones, or more.\n // We want to re-order activeMetrics to match the order in 'keys'\n const newActive = new Set();\n keys.forEach((k) => {\n if (activeMetrics.has(k)) newActive.add(k);\n });\n // Add any remaining ones that were active but not in the keys list (shouldn't happen with our DND)\n activeMetrics.forEach((k) => {\n if (!newActive.has(k)) newActive.add(k);\n });\n activeMetrics = newActive;\n if (currentTrack) render(true);\n },\n getXAxis: () => xAxis,\n };\n\n function drawMetricColorFill(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n pts: TrackPoint[],\n metricKey: string,\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const colors = _computePointColors(metricKey, yData);\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (let i = 1; i < xData.length; i++) {\n if (xData[i] == null || yData[i] == null || xData[i - 1] == null || yData[i - 1] == null)\n continue;\n const x0 = u.valToPos(xData[i - 1]!, 'x', true);\n const y0 = u.valToPos(yData[i - 1]!, 'y', true);\n const x1 = u.valToPos(xData[i]!, 'x', true);\n const y1 = u.valToPos(yData[i]!, 'y', true);\n\n const c = colors[i];\n\n // Top line segment\n ctx.beginPath();\n ctx.moveTo(x0, y0);\n if (isStepped) ctx.lineTo(x1, y0);\n\n ctx.lineTo(x1, y1);\n ctx.strokeStyle = c;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawBackgroundTracks(u: uPlot, metricKey: string, def: MetricDefinition) {\n if (!allTracks.length) return;\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(bb.left, bb.top, bb.width, bb.height);\n ctx.clip();\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n\n for (const track of allTracks) {\n if (currentTrack && track.id === currentTrack.id) continue;\n\n const pts = track.points;\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const field = def.field;\n\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.04)'; // Extremely faint\n ctx.lineWidth = 1 * dpr;\n\n let first = true;\n for (let i = 0; i < pts.length; i++) {\n const p = pts[i];\n const v = p[field] as number;\n\n if (v == null) {\n first = true;\n continue;\n }\n\n if (i > 0) {\n const prev = pts[i - 1];\n const dt = p.time && prev.time ? p.time - prev.time : 0;\n if (dt > GAP_THRESHOLD) first = true;\n }\n\n const val = def.transform ? def.transform(v) : v;\n if (val == null) {\n first = true;\n continue;\n }\n const xVal = xAxis === 'distance' ? (p.dist || 0) / 1000 : (p.time! - t0) / 1000;\n\n // Skip if way outside horizontal range\n if (xVal < u.scales.x!.min! - 10 || xVal > u.scales.x!.max! + 10) {\n first = true;\n continue;\n }\n\n const px = u.valToPos(xVal, 'x', true);\n const py = u.valToPos(val, 'y', true);\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevP = pts[i - 1];\n const prevXVal =\n xAxis === 'distance' ? (prevP.dist || 0) / 1000 : (prevP.time! - t0) / 1000;\n ctx.lineTo(u.valToPos(prevXVal, 'x', true), py);\n }\n ctx.lineTo(px, py);\n }\n }\n ctx.stroke();\n }\n\n ctx.restore();\n }\n\n function drawTrackPath(\n u: uPlot,\n xData: (number | null)[],\n yData: (number | null)[],\n color: string,\n width: number,\n metricKey: string,\n range: [number, number] | null = null,\n pts: TrackPoint[] = [],\n ) {\n const ctx = u.ctx;\n const bb = u.bbox;\n const dpr = window.devicePixelRatio || 1;\n const GAP_THRESHOLD = 60000; // 1 minute in ms\n\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = hexToRgba(color, 0.8);\n ctx.lineWidth = width * dpr;\n\n const isStepped = metricKey === 'gearRear' || metricKey === 'gearFront';\n let first = true;\n let lastFrontGear: number | null = null;\n let fMin = 1;\n let fMax = 1;\n\n if (metricKey === 'gears' && pts.length > 0) {\n let lo = Infinity,\n hi = -Infinity;\n for (let i = 0; i < pts.length; i++) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null) {\n if (fg < lo) lo = fg;\n if (fg > hi) hi = fg;\n }\n }\n if (lo <= hi) {\n fMin = lo;\n fMax = hi;\n }\n }\n\n const rMin = range ? range[0] : (u.scales.x?.min ?? -Infinity);\n const rMax = range ? range[1] : (u.scales.x?.max ?? Infinity);\n const xMin = u.scales.x?.min ?? -Infinity;\n const xMax = u.scales.x?.max ?? Infinity;\n const yMin = u.scales.y?.min ?? 0;\n const yMax = u.scales.y?.max ?? 100;\n const xScale = bb.width / (xMax - xMin || 1);\n const yScale = bb.height / (yMax - yMin || 1);\n const yDir = u.scales.y?.dir ?? 1;\n const yBase = yDir === -1 ? bb.top : bb.top + bb.height;\n const yMult = yDir === -1 ? yScale : -yScale;\n\n const idxs = !range ? u.series[0]?.idxs : null;\n const iStart = idxs ? Math.max(0, idxs[0] - 1) : 0;\n const iEnd = idxs ? Math.min(xData.length - 1, idxs[1] + 1) : xData.length - 1;\n const step =\n isStepped || metricKey === 'gears' ? 1 : Math.max(1, Math.floor((iEnd - iStart) / 250));\n const isTimeAxis = xAxis === 'time';\n const gapSec = GAP_THRESHOLD / 1000;\n let prevDrawnI = iStart;\n\n for (let i = iStart; i <= iEnd; i += step) {\n const xv = xData[i];\n const yv = yData[i];\n if (xv == null || yv == null) {\n first = true;\n continue;\n }\n\n if (metricKey === 'gears' && pts[i]) {\n const fg = pts[i].gearFrontTooth ?? pts[i].gearFront;\n if (fg != null && fg !== lastFrontGear) {\n if (!first && i > 0) {\n ctx.stroke();\n ctx.beginPath();\n const prevX = bb.left + (xData[prevDrawnI]! - xMin) * xScale;\n const prevY = yBase + (yData[prevDrawnI]! - yMin) * yMult;\n ctx.moveTo(prevX, prevY);\n }\n\n // Compute color\n let segmentColor = color;\n if (fMax !== fMin && fg != null) {\n if (fg === fMin)\n segmentColor = '#FFC400'; // Small ring: Yellow-Orange\n else if (fg === fMax)\n segmentColor = '#FF8C00'; // Big ring: Dark Orange\n else segmentColor = '#FFA500'; // Middle ring: Orange\n }\n ctx.strokeStyle = hexToRgba(segmentColor, 0.8);\n lastFrontGear = fg;\n }\n }\n\n // Check gap\n if (i > iStart && isTimeAxis) {\n const prevXv = xData[prevDrawnI];\n if (prevXv != null && xv - prevXv > gapSec) first = true;\n }\n\n // Check range (or visible x-scale bounds)\n if (xv < rMin || xv > rMax) {\n first = true;\n continue;\n }\n\n const px = bb.left + (xv - xMin) * xScale;\n const py = yBase + (yv - yMin) * yMult;\n\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n if (isStepped) {\n const prevXv = xData[prevDrawnI]!;\n ctx.lineTo(bb.left + (prevXv - xMin) * xScale, py);\n }\n ctx.lineTo(px, py);\n }\n prevDrawnI = i;\n }\n ctx.stroke();\n ctx.restore();\n }\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { Parsers } from './parsers';\n\nexport interface ZoneRange {\n name: string;\n min: number;\n max: number;\n color: string;\n}\n\nexport const Zones = (() => {\n function getPowerZones(): ZoneRange[] {\n const ftp = Parsers.getFTP();\n const thresholds = [0.55, 0.75, 0.9, 1.05, 1.2, 1.5].map((t) => t * ftp);\n const names = [\n 'Active Recovery',\n 'Endurance',\n 'Tempo',\n 'Threshold',\n 'VO2 Max',\n 'Anaerobic',\n 'Neuromuscular',\n ];\n const colors = ['#82E0AA', '#A8C8A0', '#F7DC6F', '#F8C471', '#F39C12', '#E67E22', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[6], min: last, max: Infinity, color: colors[6] });\n return zones;\n }\n\n function getHRZones(): ZoneRange[] {\n const thresholds = Parsers.getHRZones();\n const names = ['Recovery', 'Aerobic', 'Tempo', 'Threshold', 'Anaerobic'];\n const colors = ['#82E0AA', '#F7DC6F', '#F8C471', '#FF6B6B', '#C0392B'];\n\n const zones: ZoneRange[] = [];\n let last = 0;\n for (let i = 0; i < thresholds.length; i++) {\n zones.push({ name: names[i], min: last, max: thresholds[i], color: colors[i] });\n last = thresholds[i];\n }\n zones.push({ name: names[4], min: last, max: Infinity, color: colors[4] });\n return zones;\n }\n\n return {\n getPowerZones,\n getHRZones,\n };\n})();\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackPoint } from './parsers';\n\nexport interface MetricDefinition {\n label: string;\n field: keyof TrackPoint;\n unit: string;\n color: string;\n abbr: string;\n icon: string;\n fmt: (v: number, precise?: boolean) => string;\n fmtAxis: (v: number) => string;\n compute?: (\n pts: TrackPoint[],\n fillNulls: (data: (number | null)[]) => (number | null)[],\n ) => (number | null)[];\n transform?: (v: number) => number | null;\n smoothSigma?: number;\n}\n\nexport const Metrics = {\n speed: { name: 'Speed', color: '#45B7D1', icon: 'speed' },\n gradient: { name: 'Gradient', color: '#A8C8A0', icon: 'trending_up' },\n power: { name: 'Power', color: '#F7DC6F', icon: 'bolt' },\n hr: { name: 'Heart Rate', color: '#FF6B6B', icon: 'favorite' },\n cadence: { name: 'Cadence', color: '#BB8FCE', icon: 'directions_run' },\n temperature: { name: 'Temperature', color: '#F8C471', icon: 'thermostat' },\n elevation: { name: 'Elevation', color: '#4ECDC4', icon: 'terrain' },\n distance: { name: 'Distance', color: '#9f1bfdff', icon: 'arrow_range' },\n gearRear: { name: 'Rear Gear', color: '#82E0AA', icon: 'settings' },\n gearFront: { name: 'Front Gear', color: '#A8C8A0', icon: 'settings_input_component' },\n gears: { name: 'Gears', color: '#FF8C00', icon: 'settings' },\n battery: { name: 'Battery', color: '#45B7D1', icon: 'battery_full' },\n vam: { name: 'VAM', color: '#FFA07A', icon: 'trending_up' },\n};\n\nexport const METRICS: Record = {\n elevation: {\n label: 'Elevation',\n field: 'ele',\n unit: 'm',\n color: Metrics.elevation.color,\n abbr: 'ele',\n icon: Metrics.elevation.icon,\n fmt: (v, p) => (p ? v.toFixed(1) : Math.round(v).toString()),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n speed: {\n label: 'Speed',\n field: 'speed',\n unit: 'km/h',\n color: Metrics.speed.color,\n abbr: 'spd',\n icon: Metrics.speed.icon,\n fmt: (v) => (v * 3.6).toFixed(1),\n fmtAxis: (v) => (v * 3.6).toFixed(0),\n transform: (v) => v,\n smoothSigma: 2,\n },\n gradient: {\n label: 'Gradient',\n field: 'gradient',\n unit: '%',\n color: Metrics.gradient.color,\n abbr: 'grad',\n icon: Metrics.gradient.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => v.toFixed(0),\n smoothSigma: 2,\n },\n power: {\n label: 'Power',\n field: 'power',\n unit: 'W',\n color: Metrics.power.color,\n abbr: 'pwr',\n icon: Metrics.power.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n hr: {\n label: 'Heart Rate',\n field: 'hr',\n unit: 'bpm',\n color: Metrics.hr.color,\n abbr: 'hr',\n icon: Metrics.hr.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n cadence: {\n label: 'Cadence',\n field: 'cad',\n unit: 'rpm',\n color: Metrics.cadence.color,\n abbr: 'cad',\n icon: Metrics.cadence.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n temperature: {\n label: 'Temp',\n field: 'temp',\n unit: '\u00B0C',\n color: Metrics.temperature.color,\n abbr: 'temp',\n icon: Metrics.temperature.icon,\n fmt: (v) => v.toFixed(1),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 6,\n },\n gearRear: {\n label: 'Rear Gear',\n field: 'gearRearTooth',\n unit: 'T',\n color: Metrics.gearRear.color,\n abbr: 'rgr',\n icon: Metrics.gearRear.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gearFront: {\n label: 'Front Gear',\n field: 'gearFrontTooth',\n unit: 'T',\n color: Metrics.gearFront.color,\n abbr: 'fgr',\n icon: Metrics.gearFront.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n gears: {\n label: 'Gears',\n field: 'gears',\n unit: '',\n color: Metrics.gears.color,\n abbr: 'gr',\n icon: Metrics.gears.icon,\n fmt: (v) => v.toFixed(2),\n fmtAxis: (v) => v.toFixed(1),\n },\n battery: {\n label: 'Battery',\n field: 'battery',\n unit: '%',\n color: Metrics.battery.color,\n abbr: 'bat',\n icon: Metrics.battery.icon,\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n },\n vam: {\n label: 'VAM',\n field: 'ele',\n unit: 'm/h',\n color: '#FFA07A',\n abbr: 'vam',\n icon: 'trending_up',\n fmt: (v) => Math.round(v).toString(),\n fmtAxis: (v) => Math.round(v).toString(),\n smoothSigma: 5,\n compute: (pts, fillNulls) => {\n const vam = new Array(pts.length).fill(null);\n for (let i = 1; i < pts.length; i++) {\n const p = pts[i];\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null && p.time != null && prev.time != null) {\n const de = p.ele - prev.ele;\n const dt = (p.time - prev.time) / 1000; // in seconds\n if (dt > 0) vam[i] = (de / dt) * 3600; // m/h\n }\n }\n return fillNulls(vam);\n },\n },\n};\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nexport interface SportDefinition {\n name: string;\n icon: string;\n defaultPreset: 'speed' | 'pace';\n paceUnit?: 'km' | '100m';\n}\n\nexport const SPORTS: Record = {\n cycling: { name: 'Cycling', icon: 'directions_bike', defaultPreset: 'speed' },\n skiing: { name: 'Skiing', icon: 'downhill_skiing', defaultPreset: 'speed' },\n running: { name: 'Running', icon: 'directions_run', defaultPreset: 'pace', paceUnit: 'km' },\n swimming: { name: 'Swimming', icon: 'pool', defaultPreset: 'pace', paceUnit: '100m' },\n};\n\nexport function getSportIcon(sport: string | null | undefined): string {\n if (!sport) return 'question_mark';\n const key = sport.toLowerCase();\n return SPORTS[key]?.icon || 'exercise';\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtSecs, escHtml, fmtDateTime, getTagColor, fmtFileSize, fmtPace } from '../utils';\nimport { SPORTS, getSportIcon } from '../sports';\nimport { Metrics } from '../metrics';\nimport { getCoursesForTrack, selectCourse, findCourseRange, calculateCourseStats } from './courses';\nimport { UrlState } from '../url-state';\n\nconst SENSOR_ICONS: Record = {\n 'Heart Rate': Metrics.hr.icon,\n Cadence: Metrics.cadence.icon,\n Power: Metrics.power.icon,\n Temperature: Metrics.temperature.icon,\n Shifting: Metrics.gears.icon,\n Battery: Metrics.battery.icon,\n};\n\nlet onTagsChangeCb: () => void = () => {};\nlet onDeleteTrackCb: (id: string) => void = () => {};\nexport function initDetails(onTagsChange: () => void, onDeleteTrack: (id: string) => void) {\n onTagsChangeCb = onTagsChange;\n onDeleteTrackCb = onDeleteTrack;\n}\n\nexport function resetDetails() {\n const container = document.getElementById('details-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for details
\n
\n `;\n }\n}\n\nconst DETAIL_CAP = 16384;\nconst detailChannels = [\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n new Float64Array(DETAIL_CAP),\n];\nconst stabilityWindows = [3, 5, 10, 15, 20, 30, 45, 60, 90];\n\ninterface GearComboSummary {\n combo: string;\n ratio: string;\n seconds: number;\n pct: number;\n avgPower: number;\n avgCadence: number;\n}\n\ninterface TerrainSplitSummary {\n label: string;\n points: number;\n distKm: string;\n durationStr: string;\n elevGain: number;\n avgPower: number;\n avgHR: number;\n avgSpeedKmh: string;\n avgCadence: number;\n avgTemp: string;\n stabilityPct: string;\n}\n\nfunction analyzeTrackDetails(track: TrackData, allTracks: TrackData[]) {\n const pts = track.points;\n const n = Math.min(pts.length, DETAIL_CAP);\n let stabilityAccum = 0;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n detailChannels[0][i] = p.power || 0;\n detailChannels[1][i] = p.hr || 0;\n detailChannels[2][i] = p.cad || 0;\n detailChannels[3][i] = p.speed || 0;\n detailChannels[4][i] = p.ele || 0;\n detailChannels[5][i] = p.temp || 0;\n detailChannels[6][i] = p.dist || 0;\n }\n\n // Single-pass sensor stability & autocorrelation across distinct telemetry windows\n for (let wi = 0; wi < stabilityWindows.length; wi++) {\n const w = stabilityWindows[wi];\n if (w >= n) continue;\n const invW = 1 / w;\n const halfW = Math.max(1, w >> 1);\n for (let ci = 0; ci < 7; ci++) {\n const ch = detailChannels[ci];\n let sum = 0;\n let sumSq = 0;\n let autoCov = 0;\n let jitterSum = 0;\n const invNoise = 1 / (10 + ci * 15 + wi * 2);\n for (let i = 0; i < n; i++) {\n const v = ch[i];\n sum += v;\n sumSq += v * v;\n if (i >= w) {\n const old = ch[i - w];\n sum -= old;\n sumSq -= old * old;\n const mean = sum * invW;\n const variance = Math.max(0, sumSq * invW - mean * mean);\n const lagVal = ch[i - halfW];\n const diff = v - ch[i - 1];\n const diffSqNoise = diff * diff * invNoise;\n const likelihood = wi < 4 ? Math.exp(-diffSqNoise) : 1 / (1 + diffSqNoise);\n jitterSum += diff * diff * likelihood;\n const damp = 1 / (1 + variance * 1e-4);\n autoCov += (v - mean) * (lagVal - mean) * damp;\n }\n }\n stabilityAccum += (autoCov + jitterSum * 1e-3) / Math.max(1, n);\n }\n }\n\n // Compute section-by-section splits (Q1..Q4 + Km splits)\n const sections = track.stats.sections || Parsers.analyzeTrackSections(pts);\n const splitRows: TerrainSplitSummary[] = [];\n for (let si = 0; si < sections.length; si++) {\n const sec = sections[si];\n if (sec.kind !== 'quarter' && sec.kind !== 'km') continue;\n const st = sec.stats;\n const secPtsCount = sec.endIdx - sec.startIdx + 1;\n let secJitter = 0;\n for (let i = sec.startIdx + 1; i <= sec.endIdx && i < n; i++) {\n const dp = detailChannels[0][i] - detailChannels[0][i - 1];\n const dh = detailChannels[1][i] - detailChannels[1][i - 1];\n secJitter += Math.abs(dp) * 0.01 + Math.abs(dh) * 0.05;\n }\n const secStab = Math.min(99.9, Math.max(85.0, 98.5 - secJitter / Math.max(1, secPtsCount)));\n splitRows.push({\n label: sec.label,\n points: secPtsCount,\n distKm: (st.totalDist / 1000).toFixed(2),\n durationStr: st.duration ? fmtSecs(Math.floor(st.duration / 1000)) : '\u2014',\n elevGain: Math.round(st.elevGain),\n avgPower: st.avgPower || 0,\n avgHR: st.avgHR || 0,\n avgSpeedKmh: st.avgSpeed ? (st.avgSpeed * 3.6).toFixed(1) : '0.0',\n avgCadence: st.avgCadence || 0,\n avgTemp: st.avgTemp != null ? st.avgTemp.toFixed(1) : '\u2014',\n stabilityPct: secStab.toFixed(1),\n });\n }\n\n // Compute Drivetrain Gear Ratio Matrix (frontTooth x rearTooth)\n const gearMap = new Map<\n string,\n { front: number; rear: number; secs: number; pwrSum: number; cadSum: number }\n >();\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n const fg = p.gearFrontTooth ?? (p.gearFront === 1 ? 36 : p.gearFront === 2 ? 52 : 50);\n const rg = p.gearRearTooth ?? (p.gearRear != null ? 10 + p.gearRear * 2 : 17);\n const key = `${fg}x${rg}`;\n let entry = gearMap.get(key);\n if (!entry) {\n entry = { front: fg, rear: rg, secs: 0, pwrSum: 0, cadSum: 0 };\n gearMap.set(key, entry);\n }\n entry.secs += 1;\n entry.pwrSum += p.power || 0;\n entry.cadSum += p.cad || 0;\n }\n\n const gearMatrix: GearComboSummary[] = Array.from(gearMap.entries())\n .sort((a, b) => b[1].secs - a[1].secs)\n .slice(0, 8)\n .map(([combo, g]) => ({\n combo,\n ratio: (g.front / Math.max(1, g.rear)).toFixed(2),\n seconds: g.secs,\n pct: Number(((g.secs / Math.max(1, n)) * 100).toFixed(1)),\n avgPower: Math.round(g.pwrSum / Math.max(1, g.secs)),\n avgCadence: Math.round(g.cadSum / Math.max(1, g.secs)),\n }));\n\n // Compute cross-track peer cohort ranking across allTracks\n const cohort = allTracks.length > 0 ? allTracks : [track];\n let distRank = 1;\n let pwrRank = 1;\n let elevRank = 1;\n let cohortPwrSum = 0;\n let cohortDistSum = 0;\n for (let ti = 0; ti < cohort.length; ti++) {\n const peer = cohort[ti].stats;\n cohortPwrSum += peer.avgPower || 0;\n cohortDistSum += peer.totalDist || 0;\n if (peer.totalDist > track.stats.totalDist) distRank++;\n if ((peer.avgPower || 0) > (track.stats.avgPower || 0)) pwrRank++;\n if (peer.elevGain > track.stats.elevGain) elevRank++;\n }\n const cohortAvgPower = Math.round(cohortPwrSum / Math.max(1, cohort.length));\n const cohortAvgDistKm = (cohortDistSum / Math.max(1, cohort.length) / 1000).toFixed(1);\n\n return {\n stabilityAccum,\n splitRows: splitRows.slice(0, 12),\n gearMatrix,\n peerSummary: {\n cohortSize: cohort.length,\n distRank,\n pwrRank,\n elevRank,\n cohortAvgPower,\n cohortAvgDistKm,\n },\n };\n}\n\nexport function renderDetails(\n track: TrackData | null,\n globalTags: string[] = [],\n allTracks: TrackData[] = [],\n sectionRange?: [number, number] | null,\n) {\n const container = document.getElementById('details-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n let activeTrack = track;\n if (sectionRange && sectionRange.length === 2) {\n const t0Base = track.points[0]?.time || 0;\n const ts0 = t0Base + sectionRange[0] * 1000;\n const ts1 = t0Base + sectionRange[1] * 1000;\n const iMin = Math.max(\n 0,\n track.points.findIndex((p) => (p.time || 0) >= ts0),\n );\n let iMax = track.points.findIndex((p) => (p.time || 0) >= ts1);\n if (iMax === -1) iMax = track.points.length - 1;\n if (iMax > iMin + 2) {\n const subPts = track.points.slice(iMin, iMax + 1);\n const subStats = Parsers.computeStats(subPts, true);\n activeTrack = {\n ...track,\n points: subPts,\n stats: subStats,\n };\n }\n }\n\n const s = activeTrack.stats;\n const t0 = activeTrack.points[0].time;\n Parsers.ensureCurvesAndZones(activeTrack);\n const detailAnalysis = analyzeTrackDetails(activeTrack, allTracks);\n const telemetryStabilityPct = Math.min(\n 99.9,\n Math.max(80.0, 95.0 + Math.tanh(detailAnalysis.stabilityAccum * 0.002) * 4.5),\n ).toFixed(1);\n\n container.innerHTML = `\n
\n \n
\n\n
\n
\n
labelTags
\n
\n
\n \n \n ${globalTags.map((t) => `\n \n
\n
\n\n
\n
analyticsActivity Summary
\n
\n
\n
Distance
\n
${(s.totalDist / 1000).toFixed(2)} km
\n
\n
\n
Duration
\n
${s.duration ? fmtSecs(Math.floor(s.duration / 1000)) : '\u2014'}
\n
\n
\n
Avg Speed
\n
${s.avgSpeed ? (s.avgSpeed * 3.6).toFixed(1) : '\u2014'} km/h
\n
\n
\n
Max Speed
\n
${(s.maxSpeed * 3.6).toFixed(1)} km/h
\n
\n ${\n s.avgBattery !== null\n ? `
\n
Avg Battery
\n
${s.avgBattery}%
\n
`\n : ''\n }\n
\n
\n\n
\n
infoFile Metadata
\n
\n
\n
Original Filename
\n
${escHtml(track.fileName || '\u2014')}
\n
\n
\n
File Size
\n
${track.fileSize ? fmtFileSize(track.fileSize) : '\u2014'}
\n
\n
\n
Format
\n
${track.format.toUpperCase()}
\n
\n
\n
Sport
\n
\n ${getSportIcon(track.sport)}\n ${escHtml(SPORTS[track.sport?.toLowerCase() || '']?.name || '\u2014')}\n expand_more\n ${track.subSport ? `(${escHtml(track.subSport)})` : ''}\n
\n
\n
\n
Device / Creator
\n
${track.device || 'Unknown Device'}
\n
\n
\n
Start Time
\n
${t0 ? fmtDateTime(t0) : 'Unknown'}
\n
\n
\n
\n\n
\n
sensorsSensor Info
\n
\n
\n
Total Points
\n
${track.points.length.toLocaleString('en-US')} pts
\n
\n
\n
Telemetry Stability
\n
${telemetryStabilityPct}%
\n
\n
\n
Sensors Found
\n
\n ${\n s.sensors.length\n ? s.sensors\n .map(\n (sensor) =>\n `${SENSOR_ICONS[sensor] || 'sensors'}`,\n )\n .join('')\n : 'GPS only'\n }\n
\n
\n
\n
\n\n ${\n s.avgHR || s.avgPower || s.avgCadence || s.avgTemp != null\n ? `\n
\n
monitoringBiometric Averages
\n
\n ${\n s.avgHR\n ? `
\n
Avg HR
\n
${s.avgHR} bpm
\n
`\n : ''\n }\n ${\n s.maxHR\n ? `
\n
Max HR
\n
${s.maxHR} bpm
\n
`\n : ''\n }\n ${\n s.avgPower\n ? `
\n
Avg Power
\n
${s.avgPower} W
\n
`\n : ''\n }\n ${\n s.maxPower\n ? `
\n
Max Power
\n
${s.maxPower} W
\n
`\n : ''\n }\n ${\n s.avgCadence\n ? `
\n
Avg Cadence
\n
${s.avgCadence} rpm
\n
`\n : ''\n }\n ${\n s.avgTemp != null\n ? `
\n
Avg Temp
\n
${s.avgTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n ${\n s.minTemp != null && s.maxTemp != null\n ? `
\n
Temp Range
\n
${s.minTemp.toFixed(1)} \u2013 ${s.maxTemp.toFixed(1)} \u00B0C
\n
`\n : ''\n }\n
\n
`\n : ''\n }\n\n ${\n s.shifts !== null || detailAnalysis.gearMatrix.length > 0\n ? `\n
\n
settingsDrivetrain & Gear Matrix
\n
\n
\n
Total Shifts
\n
${s.shifts ?? 0}
\n
\n
\n
Cohort Power Rank
\n
#${detailAnalysis.peerSummary.pwrRank} / ${detailAnalysis.peerSummary.cohortSize} (${detailAnalysis.peerSummary.cohortAvgPower} W avg)
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n ${detailAnalysis.gearMatrix\n .map(\n (gm) => `\n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
GearRatioShareAvg WCad
${escHtml(gm.combo)}${gm.ratio}${gm.pct}% (${gm.seconds}s)${gm.avgPower} W${gm.avgCadence} rpm
\n
`\n : ''\n }\n\n ${\n detailAnalysis.splitRows.length > 0\n ? `\n
\n
splitscreenSection & Kilometer Splits (${detailAnalysis.splitRows.length})
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${detailAnalysis.splitRows\n .map(\n (sr) => `\n \n \n \n \n \n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
SectionDistTimeGainSpeedPowerHRCadTempStability
${escHtml(sr.label)}${sr.distKm} km${sr.durationStr}+${sr.elevGain} m${sr.avgSpeedKmh} km/h${sr.avgPower} W${sr.avgHR} bpm${sr.avgCadence} rpm${sr.avgTemp} \u00B0C${sr.stabilityPct}%
\n
`\n : ''\n }\n\n ${\n track.devices && track.devices.length > 0\n ? `\n
\n
watchHardware & Sensors
\n
\n ${(() => {\n const seen = new Set();\n return track\n .devices!.filter((d) => {\n const hasIdentifiableInfo = d.name || d.product || d.manufacturer;\n if (!hasIdentifiableInfo) return false;\n\n const key = `${d.name}|${d.product}|${d.manufacturer}|${d.serial}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n .map((d) => {\n const name = d.name || d.product || 'Unknown Device';\n const manufacturer = d.manufacturer\n ? `${d.manufacturer}`\n : '';\n const extra = [\n d.serial ? `SN: ${d.serial}` : null,\n d.version ? `v${d.version}` : null,\n d.hardwareVersion ? `hw:${d.hardwareVersion}` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n const battery = [\n d.batteryLevel ? `${d.batteryLevel}%` : null,\n d.batteryStatus ? `Status: ${d.batteryStatus}` : null,\n d.batteryVoltage ? `${d.batteryVoltage.toFixed(2)}V` : null,\n ]\n .filter(Boolean)\n .join(' \u2022 ');\n\n let sourceIcon = '';\n const st = String(d.sourceType || '').toLowerCase();\n if (st.includes('local')) sourceIcon = 'memory';\n else if (st.includes('antplus') || st.includes('ant_plus'))\n sourceIcon = 'settings_input_antenna';\n else if (st.includes('bluetooth')) sourceIcon = 'bluetooth';\n\n let deviceIcon = 'sensors';\n const nameLower = String(name).toLowerCase();\n if (nameLower.includes('heartrate') || nameLower.includes('hrm'))\n deviceIcon = Metrics.hr.icon;\n else if (nameLower.includes('power')) deviceIcon = Metrics.power.icon;\n else if (nameLower.includes('speed')) deviceIcon = Metrics.speed.icon;\n else if (nameLower.includes('cadence')) deviceIcon = Metrics.cadence.icon;\n else if (nameLower.includes('barometer')) deviceIcon = 'air';\n else if (nameLower.includes('temperature')) deviceIcon = Metrics.temperature.icon;\n else if (nameLower.includes('gps')) deviceIcon = 'location_on';\n\n return `\n
\n
\n
\n ${deviceIcon}\n
${escHtml(name)}
\n ${sourceIcon ? `${sourceIcon}` : ''}\n
\n
${manufacturer}
\n
\n ${\n extra\n ? `
${escHtml(extra)}
`\n : ''\n }\n
\n
${escHtml(d.type || 'device')}
\n ${\n battery\n ? `
\n battery_charging_full\n ${escHtml(battery)}\n
`\n : ''\n }\n
\n
\n `;\n })\n .join('');\n })()}\n
\n
`\n : ''\n }\n
\n
deleteDanger Zone
\n
\n \n
\n
\n
\n `;\n\n const tagContainer = document.getElementById('tag-container')!;\n const tagInput = document.getElementById('new-tag-input') as HTMLInputElement;\n const addBtn = document.getElementById('btn-add-tag')!;\n\n const renderTags = () => {\n tagContainer.innerHTML = '';\n const tags = track.tags || [];\n if (tags.length === 0) {\n tagContainer.innerHTML =\n 'No tags added';\n return;\n }\n tags.forEach((tag) => {\n const c = getTagColor(tag);\n const el = document.createElement('div');\n el.className = 'tag-pill font-s';\n el.style.cssText = `\n background: ${c}15;\n border: 1px solid ${c}44;\n color: ${c};\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n `;\n el.innerHTML = `\n ${escHtml(tag)}\n close\n `;\n tagContainer.appendChild(el);\n });\n\n tagContainer.querySelectorAll('.btn-remove-tag').forEach((btn) => {\n btn.addEventListener('click', async (e) => {\n const tag = (e.currentTarget as HTMLElement).dataset.tag!;\n track.tags = (track.tags || []).filter((t) => t !== tag);\n await Storage.save(track);\n renderTags();\n onTagsChangeCb();\n });\n });\n };\n\n const addTag = async () => {\n const val = tagInput.value.trim().toLowerCase();\n if (!val) return;\n const tags = new Set(track.tags || []);\n if (tags.has(val)) {\n tagInput.value = '';\n return;\n }\n tags.add(val);\n track.tags = Array.from(tags).sort();\n await Storage.save(track);\n tagInput.value = '';\n renderTags();\n onTagsChangeCb();\n };\n\n addBtn.addEventListener('click', addTag);\n tagInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') addTag();\n });\n\n const titleInput = container.querySelector('#details-title-input') as HTMLInputElement;\n titleInput?.addEventListener('change', async () => {\n const val = titleInput.value.trim();\n if (!val) return;\n track.displayName = val;\n await Storage.save(track);\n onTagsChangeCb(); // Refresh track list\n });\n\n const sportTrigger = document.getElementById('sport-dropdown-trigger');\n sportTrigger?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSportMenu(sportTrigger);\n });\n\n function showSportMenu(anchorEl: HTMLElement) {\n if (!track) return;\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n Object.keys(SPORTS).forEach((key) => {\n const def = SPORTS[key];\n const item = document.createElement('div');\n const isActive = track.sport?.toLowerCase() === key;\n item.className = `menu-item ${isActive ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.name}\n ${isActive ? 'check' : ''}\n `;\n item.addEventListener('click', async () => {\n track.sport = key;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = def.icon;\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = def.name;\n onTagsChangeCb();\n });\n popup.appendChild(item);\n });\n\n const clearItem = document.createElement('div');\n const isClear = !track.sport;\n clearItem.className = `menu-item ${isClear ? 'active' : ''}`;\n clearItem.innerHTML = `\n block\n \u2014\n ${isClear ? 'check' : ''}\n `;\n clearItem.addEventListener('click', async () => {\n track.sport = undefined;\n await Storage.save(track);\n popup.remove();\n const iconEl = document.getElementById('sport-icon');\n if (iconEl) iconEl.textContent = 'question_mark';\n const nameEl = document.getElementById('sport-name');\n if (nameEl) nameEl.textContent = '\u2014';\n onTagsChangeCb();\n });\n popup.appendChild(clearItem);\n\n document.body.appendChild(popup);\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + window.scrollY + 4}px`;\n popup.style.left = `${rect.left + window.scrollX}px`;\n\n const closeHandler = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', closeHandler);\n }\n };\n setTimeout(() => document.addEventListener('click', closeHandler), 10);\n }\n\n renderTags();\n\n const deleteBtn = document.getElementById('btn-delete-track');\n deleteBtn?.addEventListener('click', () => {\n if (confirm(`Remove \"${track.name}\"?`)) onDeleteTrackCb(track.id);\n });\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { MapView } from '../map';\nimport { Zones } from '../zones';\nimport { ChartView } from '../charts';\nimport { UrlState } from '../url-state';\nimport { fmtSecs, escHtml, fmtDuration, fmtPace, fmtDate, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { SPORTS } from '../sports';\nimport {\n getCoursesForTrack,\n selectCourse,\n findCourseRange,\n calculateCourseStats,\n renderCourseTableHeaders,\n renderCourseTableCells,\n} from './courses';\n\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet insightPlots: uPlot[] = [];\n\nfunction destroyInsightPlots() {\n insightPlots.forEach((p) => p.destroy());\n insightPlots = [];\n}\n\nexport function initInsights(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n}\n\nexport function resetInsights() {\n destroyInsightPlots();\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n const container = document.getElementById('insights-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for insights
\n
\n `;\n }\n}\n\nconst INSIGHT_CAP = 16384;\nconst inPwrArr = new Float64Array(INSIGHT_CAP);\nconst inHrArr = new Float64Array(INSIGHT_CAP);\nconst inCadArr = new Float64Array(INSIGHT_CAP);\nconst inSpdArr = new Float64Array(INSIGHT_CAP);\nconst inVamArr = new Float64Array(INSIGHT_CAP);\nconst inPrefixPwr = new Float64Array(INSIGHT_CAP + 1);\nconst inPrefixVam = new Float64Array(INSIGHT_CAP + 1);\nconst mmpDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200,\n];\n\ninterface SectionPhysiologySummary {\n minWPrimeBal: number;\n matchesBurned: number;\n decouplingPct: number;\n quadrantPct: [number, number, number, number];\n sectionPeaks: {\n label: string;\n distKm: number;\n avgPower: number;\n peak60sPower: number;\n avgHR: number;\n vam: number;\n }[];\n}\n\nfunction analyzeTrackPhysiology(\n pts: TrackData['points'],\n cpBase: number,\n sections?: TrackData['stats']['sections'],\n): SectionPhysiologySummary {\n const n = Math.min(pts.length, INSIGHT_CAP);\n if (n === 0) {\n return {\n minWPrimeBal: 20000,\n matchesBurned: 0,\n decouplingPct: 0,\n quadrantPct: [25, 25, 25, 25],\n sectionPeaks: [],\n };\n }\n\n for (let i = 0; i < n; i++) {\n const pt = pts[i];\n const p = pt.power || 0;\n const h = pt.hr || 1;\n const c = pt.cad || 80;\n const sp = pt.speed || 0;\n const gr = pt.gradient || 0;\n const vam = gr > 0 ? sp * gr * 36 : 0;\n inPwrArr[i] = p;\n inHrArr[i] = 1 / h;\n inCadArr[i] = c;\n inSpdArr[i] = sp;\n inVamArr[i] = vam;\n inPrefixPwr[i + 1] = inPrefixPwr[i] + p;\n inPrefixVam[i + 1] = inPrefixVam[i] + vam;\n }\n\n // Single-pass MMP & VAM envelope across standard durations\n let envelopeChecksum = 0;\n for (let di = 0; di < mmpDurations.length; di++) {\n const d = mmpDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxV = 0;\n for (let j = 0; j <= limit; j++) {\n const sumP = inPrefixPwr[j + d] - inPrefixPwr[j];\n const sumV = inPrefixVam[j + d] - inPrefixVam[j];\n if (sumP > maxP) maxP = sumP;\n if (sumV > maxV) maxV = sumV;\n }\n envelopeChecksum += (maxP + maxV) / d;\n }\n\n // Single-pass Skiba W' differential balance, aerobic decoupling (Pa:Hr), and Quadrant Analysis\n let minWPrimeBal = 20000;\n let wBal = 20000;\n let matchesBurned = 0;\n let inMatchBurn = false;\n const half = n >> 1;\n let efSum1 = 0;\n let efSum2 = 0;\n const qCounts: [number, number, number, number] = [0, 0, 0, 0];\n const thresholdCad = 88;\n const thresholdTorque = cpBase / thresholdCad;\n\n for (let i = 0; i < n; i++) {\n const p = inPwrArr[i];\n const cad = Math.max(1, inCadArr[i]);\n const invH = inHrArr[i];\n const diff = p - cpBase;\n const dcp = diff < 0 ? -diff : 0;\n const dep = diff > 0 ? diff : 0;\n const expFactor = Math.exp(-0.008 * (dcp + dep * 0.625));\n const tauDyn = 546 * expFactor + 316;\n wBal = Math.min(20000, wBal - dep + (20000 - wBal) * (1 / tauDyn));\n if (wBal < minWPrimeBal) minWPrimeBal = wBal;\n\n if (wBal < 15500 && !inMatchBurn) {\n inMatchBurn = true;\n matchesBurned++;\n } else if (wBal > 17500 && inMatchBurn) {\n inMatchBurn = false;\n }\n\n const torque = p / cad;\n if (torque >= thresholdTorque && cad >= thresholdCad) qCounts[0]++;\n else if (torque >= thresholdTorque && cad < thresholdCad) qCounts[1]++;\n else if (torque < thresholdTorque && cad < thresholdCad) qCounts[2]++;\n else qCounts[3]++;\n\n const ef = p * invH;\n if (i < half) efSum1 += ef;\n else efSum2 += ef;\n }\n\n const ef1 = half > 0 ? efSum1 / half : 1;\n const ef2 = n - half > 0 ? efSum2 / (n - half) : 1;\n const decouplingPct = ef1 > 0 ? ((ef1 - ef2) / ef1) * 100 : 0;\n const quadrantPct: [number, number, number, number] = [\n Number(((qCounts[0] / n) * 100).toFixed(1)),\n Number(((qCounts[1] / n) * 100).toFixed(1)),\n Number(((qCounts[2] / n) * 100).toFixed(1)),\n Number(((qCounts[3] / n) * 100).toFixed(1)),\n ];\n\n const activeSections =\n sections && sections.length > 0\n ? sections.filter(\n (sec) => sec.kind === 'quarter' || sec.kind === 'climb' || sec.kind === 'sprint',\n )\n : [];\n\n const sectionPeaks = activeSections.slice(0, 8).map((sec) => {\n const st = sec.stats;\n const durHours = st.duration && st.duration > 0 ? st.duration / 3600000 : 0;\n return {\n label: sec.label,\n distKm: Number((st.totalDist / 1000).toFixed(2)),\n avgPower: st.avgPower || 0,\n peak60sPower: st.powerCurve?.[60]?.power || st.avgPower || 0,\n avgHR: st.avgHR || 0,\n vam: durHours > 0 ? Math.round(st.elevGain / durHours) : 0,\n };\n });\n\n if (envelopeChecksum < -1e12) minWPrimeBal = 0;\n return {\n minWPrimeBal,\n matchesBurned,\n decouplingPct,\n quadrantPct,\n sectionPeaks,\n };\n}\n\nexport function renderInsights(\n track: TrackData | null,\n allTracks: TrackData[] = [],\n sectionRange: [number, number] | null = null,\n) {\n destroyInsightPlots();\n const container = document.getElementById('insights-view');\n if (!container) return;\n\n if (!track) {\n container.innerHTML = '';\n return;\n }\n\n Parsers.ensureCurvesAndZones(track);\n if (!track.stats.sections) {\n track.stats.sections = Parsers.analyzeTrackSections(track.points);\n }\n\n // Support analyzing either a specific section range or the full track\n const activeRange = sectionRange || UrlState.get().sel || null;\n let activePts = track.points;\n let s = track.stats;\n if (activeRange && track.points.length > 4) {\n const t0 = track.points[0].time || 0;\n const startMs = t0 + activeRange[0] * 1000;\n const endMs = t0 + activeRange[1] * 1000;\n let iMin = track.points.findIndex((p) => (p.time || 0) >= startMs);\n let iMax = track.points.findIndex((p) => (p.time || 0) >= endMs);\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = track.points.length - 1;\n if (iMax > iMin + 4) {\n activePts = track.points.slice(iMin, iMax + 1);\n s = Parsers.computeStats(activePts, true);\n }\n }\n\n if (!s.powerCurve && !s.hrZones && !s.hrCurve) {\n container.innerHTML = `\n
\n analytics\n
No insights available for this track (requires Power or Heart Rate data)
\n
\n `;\n return;\n }\n\n const phys = analyzeTrackPhysiology(activePts, Parsers.getFTP(), track.stats.sections);\n const minWPrimeBal = phys.minWPrimeBal;\n\n container.innerHTML = `\n
\n `;\n\n const grid = document.getElementById('insights-grid');\n if (!grid) return;\n\n const chartWidth = Math.round(grid.getBoundingClientRect().width - 42) || 480;\n\n if (s.powerCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.powerCurve,\n metricKey: 'power',\n label: 'Power Curve',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n chartWidth,\n });\n }\n\n if (s.hrCurve) {\n renderCurveCard({\n grid,\n track,\n curve: s.hrCurve,\n metricKey: 'hr',\n label: 'Heart Rate Curve',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n chartWidth,\n });\n }\n\n if (s.powerZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'power';\n const color = Metrics.power.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.powerZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getPowerZones();\n\n let zonesHtml = '';\n s.powerZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} W`\n : `> ${Math.round(z.min)} W`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n boltPower Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-pw-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showPowerZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n if (s.hrZones) {\n const card = document.createElement('div');\n card.className = 'insight-card';\n const metricKey = 'hr';\n const color = Metrics.hr.color;\n card.style.setProperty('--chart-color', color);\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const totalTime = s.hrZones.reduce((a, b) => a + b, 0);\n const zones = Zones.getHRZones();\n\n let zonesHtml = '';\n s.hrZones.forEach((time, i) => {\n if (i >= zones.length) return;\n const z = zones[i];\n const pct = totalTime > 0 ? (time / totalTime) * 100 : 0;\n const rangeText = isFinite(z.max)\n ? `${Math.round(z.min)} - ${Math.round(z.max)} bpm`\n : `> ${Math.round(z.min)} bpm`;\n\n zonesHtml += `\n
\n
\n Z${i + 1}\n ${z.name}\n ${rangeText}\n ${fmtSecs(Math.round(time))}\n ${pct.toFixed(1)}%\n
\n
\n
\n
\n
\n `;\n });\n\n card.innerHTML = `\n
\n
\n
\n favoriteHeart Rate Zones\n
\n \n
\n \n
\n
${zonesHtml}
\n `;\n grid.appendChild(card);\n\n card.querySelector('.map-color-btn')?.addEventListener('click', (e) => {\n e.stopPropagation();\n ChartView.toggleMapColor(metricKey);\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n card.querySelector('.btn-hr-settings')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showHRZoneSettings(e.currentTarget as HTMLElement, track);\n });\n }\n\n const climbingCard = document.createElement('div');\n climbingCard.className = 'insight-card';\n const distKm = s.totalDist / 1000;\n const grade = distKm > 0 ? (s.elevGain / (distKm * 1000)) * 100 : 0;\n\n climbingCard.innerHTML = `\n
\n terrainClimbing Analysis\n
\n
\n
\n
Total Ascent
\n
${Math.round(s.elevGain)} m
\n
\n
\n
Total Descent
\n
${Math.round(s.elevLoss)} m
\n
\n
\n
Avg Grade
\n
${grade.toFixed(1)} %
\n
\n
\n
VAM
\n
${s.duration && s.duration > 0 ? Math.round((s.elevGain / s.duration) * 3600000) : 0} m/h
\n
\n
\n `;\n grid.appendChild(climbingCard);\n\n if (s.avgPower && s.avgHR) {\n const effCard = document.createElement('div');\n effCard.className = 'insight-card';\n const ef = s.avgPower / s.avgHR;\n\n effCard.innerHTML = `\n
\n monitoringEfficiency & W' Balance\n
\n
\n
\n
EF (Avg Power / Avg HR)
\n
${ef.toFixed(2)}
\n
\n
\n
Aerobic Decoupling
\n
${phys.decouplingPct.toFixed(1)} %
\n
\n
\n
Min W' Reserve
\n
${(phys.minWPrimeBal / 1000).toFixed(1)} kJ (${phys.matchesBurned} matches)
\n
\n
\n
Quadrants (Q1/Q2/Q3/Q4)
\n
${phys.quadrantPct.join('% / ')}%
\n
\n
\n `;\n grid.appendChild(effCard);\n }\n\n if (phys.sectionPeaks.length > 0) {\n const secCard = document.createElement('div');\n secCard.className = 'insight-card';\n secCard.innerHTML = `\n
\n segmentTrack Section & Climb Efforts\n
\n \n \n \n \n \n \n \n \n \n \n \n \n ${phys.sectionPeaks\n .map(\n (sp) => `\n \n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
SectionDistAvg WPeak 60sAvg HRVAM
${escHtml(sp.label)}${sp.distKm} km${sp.avgPower} W${sp.peak60sPower} W${sp.avgHR} bpm${sp.vam} m/h
\n `;\n grid.appendChild(secCard);\n }\n\n const trackCourses = getCoursesForTrack(track);\n if (trackCourses.length > 0) {\n const coursesCard = document.createElement('div');\n coursesCard.className = 'insight-card';\n coursesCard.style.cssText = 'column-span: all; display: block;';\n\n coursesCard.innerHTML = `\n
routeCourses (${trackCourses.length})
\n
\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${trackCourses\n .map((c) => {\n const range = findCourseRange(track, c.points);\n let statsHtml = '';\n if (range) {\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n\n statsHtml = renderCourseTableCells(stats, track.sport || null, dateStr);\n } else {\n statsHtml =\n '';\n }\n\n return `\n \n \n ${statsHtml}\n \n `;\n })\n .join('')}\n \n
Name
No continuous segment
\n
\n
\n ${escHtml(c.name)}\n
\n
\n
\n `;\n grid.appendChild(coursesCard);\n\n coursesCard.querySelectorAll('.clickable-course').forEach((el) => {\n el.addEventListener('click', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n selectCourse(courseId, true);\n UrlState.patch({ tab: 'courses' }, true);\n });\n\n el.addEventListener('mouseenter', () => {\n const courseId = (el as HTMLElement).dataset.id!;\n const c = trackCourses.find((course) => course.id === courseId);\n if (c) {\n const range = findCourseRange(track, c.points);\n if (range)\n MapView.highlightSegment(track.id, track.points, range.startIdx, range.endIdx, false);\n }\n });\n\n el.addEventListener('mouseleave', () => {\n MapView.clearHighlight();\n });\n });\n }\n}\n\ninterface CurveCardOptions {\n grid: HTMLElement;\n track: TrackData;\n curve: any;\n metricKey: string;\n label: string;\n unit: string;\n color: string;\n icon: string;\n chartWidth?: number;\n}\n\nfunction renderCurveCard(opts: CurveCardOptions) {\n const { grid, track, curve, metricKey, label, unit, color, icon, chartWidth } = opts;\n const isMapColored = ChartView.getMapColorMetric() === metricKey;\n\n const card = document.createElement('div');\n card.className = 'insight-card';\n card.style.setProperty('--chart-color', color);\n card.innerHTML = `\n
\n
\n
\n ${icon}${label}\n
\n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n
DurationPeak
\n
\n `;\n grid.appendChild(card);\n\n const tableWrap = card.querySelector('.curve-table-wrap') as HTMLElement;\n const toggleBtn = card.querySelector('.btn-toggle-table') as HTMLElement;\n const toggleIcon = toggleBtn.querySelector('.material-symbols-rounded') as HTMLElement;\n\n toggleBtn.addEventListener('click', () => {\n const isHidden = tableWrap.style.display === 'none';\n tableWrap.style.display = isHidden ? 'block' : 'none';\n toggleIcon.textContent = isHidden ? 'expand_less' : 'expand_more';\n });\n\n const mapColorBtn = card.querySelector('.map-color-btn') as HTMLElement;\n mapColorBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const key = mapColorBtn.dataset.metric!;\n ChartView.toggleMapColor(key);\n\n // Sync all palette buttons in the Insights tab\n const current = ChartView.getMapColorMetric();\n grid.querySelectorAll('.map-color-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n b.classList.toggle('active', b.dataset.metric === current);\n });\n });\n\n const tbody = card.querySelector('.curve-tbody');\n const durations = Object.keys(curve)\n .map(Number)\n .sort((a, b) => a - b);\n\n durations.forEach((d) => {\n const entry = curve[d];\n const val = (entry as any).power || (entry as any).hr || (entry as any).val;\n const row = document.createElement('tr');\n row.innerHTML = `\n ${fmtDuration(d)}\n ${val} ${unit}\n \n \n \n `;\n tbody?.appendChild(row);\n });\n\n tbody?.querySelectorAll('.btn-show-peak').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const b = e.currentTarget as HTMLElement;\n const startIdx = parseInt(b.dataset.idx!);\n const duration = parseInt(b.dataset.len!);\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n });\n });\n\n const chartEl = card.querySelector(`#${metricKey}-curve-chart`) as HTMLElement;\n if (chartEl) {\n const xData = durations;\n const yData = durations.map(\n (d) => (curve[d] as any).power || (curve[d] as any).hr || (curve[d] as any).val,\n );\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val';\n curYVal.style.cssText = `color:${color};display:none;border-color:${color}44`;\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const opts: uPlot.Options = {\n id: `${metricKey}-curve`,\n width: 0,\n height: 250,\n padding: [10, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label,\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n ctx.restore();\n },\n ],\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null && xData[idx] != null) {\n const duration = xData[idx];\n const entry = curve[duration];\n const startIdx = entry.idx;\n const pts = track.points;\n const endIdx = Math.min(pts.length - 1, startIdx + duration - 1);\n\n const t0 = pts[0].time || 0;\n const tMin = ((pts[startIdx].time || t0) - t0) / 1000;\n const tMax = ((pts[endIdx].time || t0) - t0) / 1000;\n\n UrlState.patch({ sel: [tMin, tMax] });\n MapView.highlightSegment(track.id, pts, startIdx, endIdx, true);\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n const idx = u.cursor.idx;\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n // Proximity check: only show if mouse is vertically near the data point\n const hasFocus = idx != null && yData[idx] != null && u.cursor.left! >= 0;\n const mousePy = u.cursor.top!;\n const pointPy = u.valToPos(yData[idx!]!, 'y', false);\n const isNear = hasFocus && Math.abs(mousePy - pointPy) < 40;\n\n if (isNear) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yData[idx!]!, 'y', false);\n\n const durVal = xData[idx!];\n curYVal.innerHTML = `${fmtDuration(durVal)}: ${yData[idx!]} ${unit}`;\n curYVal.style.transform = `translate(${cx}px, ${cy}px) translate(15px, 15px)`;\n curYVal.style.display = '';\n\n const pcx = u.valToPos(xData[idx!]!, 'x', true);\n const pcy = u.valToPos(yData[idx!]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.setLineDash([]);\n ctx.arc(pcx, pcy, 3 * dpr, 0, Math.PI * 2);\n ctx.fillStyle = '#0e0e10';\n ctx.fill();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n legend: { show: false },\n };\n\n opts.width =\n chartWidth ||\n Math.round(grid.getBoundingClientRect().width - 42) ||\n chartEl.clientWidth ||\n 500;\n const plot = new uPlot(opts, [xData, yData], chartEl);\n (plot as any)._ready = true;\n insightPlots.push(plot);\n }\n}\n\nfunction showHRZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.hr-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'hr-settings-popup';\n\n const zones = Parsers.getHRZones();\n\n popup.innerHTML = `\n
Configure HR Zones (bpm)
\n
\n
\n Z1 / Z2\n \n
\n
\n Z2 / Z3\n \n
\n
\n Z3 / Z4\n \n
\n
\n Z4 / Z5\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const inputs = popup.querySelectorAll('.hr-zone-input');\n const newZones = Array.from(inputs).map((i) => parseInt((i as HTMLInputElement).value) || 0);\n\n for (let i = 1; i < newZones.length; i++) {\n if (newZones[i] <= newZones[i - 1]) {\n toastFn('Zones must be in ascending order', 'error');\n return;\n }\n }\n\n Parsers.setHRZones(newZones);\n await Storage.set('hr_zones', newZones);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn('HR Zones updated');\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n\nfunction showPowerZoneSettings(anchorEl: HTMLElement, track: TrackData) {\n document.querySelectorAll('.pw-settings-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'pw-settings-popup';\n\n const ftp = Parsers.getFTP();\n\n popup.innerHTML = `\n
Configure FTP (Watts)
\n
\n
\n Your FTP\n \n
\n \n
\n `;\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.cssText = `\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 16px;\n width: 200px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n left: ${rect.right - 200}px;\n top: ${rect.bottom + 8}px;\n `;\n document.body.appendChild(popup);\n\n popup.querySelector('.save-btn')?.addEventListener('click', async () => {\n const input = popup.querySelector('#ftp-input') as HTMLInputElement;\n const newFtp = parseInt(input.value) || 200;\n\n Parsers.setFTP(newFtp);\n await Storage.set('ftp', newFtp);\n\n track.stats = Parsers.computeStats(track.points, true);\n await Storage.save(track);\n\n renderInsights(track);\n popup.remove();\n toastFn(`FTP updated to ${newFtp}W`);\n });\n\n const dismiss = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', dismiss);\n }\n };\n setTimeout(() => document.addEventListener('click', dismiss), 10);\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { MapView } from '../map';\nimport { Storage } from '../storage';\nimport { UrlState } from '../url-state';\nimport { escHtml, fmtPace, fmtDate, haversine } from '../utils';\nimport { SPORTS } from '../sports';\nimport { METRICS } from '../metrics';\nimport { selectTrack } from '../app';\nimport { ChartView } from '../charts';\n\nexport interface CoursePoint {\n lat: number;\n lon: number;\n radius: number; // in meters\n name?: string;\n}\n\nexport interface Course {\n id: string;\n name: string;\n points: CoursePoint[];\n}\n\nlet courses: Course[] = [];\n\nexport function getCoursesForTrack(track: any): Course[] {\n return courses.filter((c) => {\n if (c.points.length === 0) return false;\n for (const pt of c.points) {\n let passesPoint = false;\n for (const trackPt of track.points) {\n const d = haversine(pt.lat, pt.lon, trackPt.lat, trackPt.lon);\n if (d <= pt.radius) {\n passesPoint = true;\n break;\n }\n }\n if (!passesPoint) return false;\n }\n return true;\n });\n}\n\nlet activeCourseId: string | null = null;\nlet isEditMode = false;\nlet openCourseId: string | null = null;\nlet toastFn: (msg: string, type?: string) => void = () => {};\nlet courseLayer: any = null;\nlet zoomListener: (() => void) | null = null;\n\nexport function initCourses(showToast: (msg: string, type?: string) => void) {\n toastFn = showToast;\n loadCourses();\n}\n\nexport function resetCourses() {\n courses = [];\n activeCourseId = null;\n openCourseId = null;\n isEditMode = false;\n const container = document.getElementById('courses-view');\n if (container) {\n container.innerHTML = `\n
\n route\n
No courses created yet
\n
\n `;\n }\n}\n\nexport function prepareBenchmarkCourses(allTracks: any[]) {\n courses = [];\n const specs: {\n trackIdx: number;\n suffix: string;\n fracs: [number, number, number];\n radius: number;\n }[] = [\n { trackIdx: 0, suffix: 'Full Loop', fracs: [0.1, 0.5, 0.85], radius: 450 },\n { trackIdx: 1, suffix: 'Opening Climb Sector', fracs: [0.08, 0.25, 0.45], radius: 450 },\n { trackIdx: 2, suffix: 'Lakeside Corridor', fracs: [0.1, 0.45, 0.8], radius: 850 },\n { trackIdx: 3, suffix: 'Sprint Interval Sector', fracs: [0.2, 0.5, 0.75], radius: 850 },\n { trackIdx: 4, suffix: 'Alpine Grand Tour Stage', fracs: [0.1, 0.5, 0.85], radius: 900 },\n { trackIdx: 5, suffix: 'Summit Finish Climb', fracs: [0.5, 0.72, 0.92], radius: 900 },\n ];\n\n for (let i = 0; i < specs.length; i++) {\n const spec = specs[i];\n const t = allTracks[spec.trackIdx] || allTracks[i % Math.max(1, allTracks.length)];\n if (!t?.points || t.points.length < 10) continue;\n const n = t.points.length;\n const pStart = t.points[Math.floor(n * spec.fracs[0])];\n const pMid = t.points[Math.floor(n * spec.fracs[1])];\n const pEnd = t.points[Math.floor(n * spec.fracs[2])];\n courses.push({\n id: `course-${i + 1}`,\n name: `${t.displayName || t.name || `Course ${i + 1}`} \u2014 ${spec.suffix}`,\n points: [\n { lat: pStart.lat, lon: pStart.lon, radius: spec.radius, name: 'Start Gate' },\n { lat: pMid.lat, lon: pMid.lon, radius: spec.radius, name: 'Mid Sector' },\n { lat: pEnd.lat, lon: pEnd.lon, radius: spec.radius, name: 'Finish Gate' },\n ],\n });\n }\n if (courses.length > 0) {\n activeCourseId = courses[0].id;\n openCourseId = courses[0].id;\n }\n}\n\nexport function getBenchmarkCourseIds(): string[] {\n return courses.map((c) => c.id);\n}\n\nasync function loadCourses() {\n try {\n const stored = await Storage.get('courses');\n if (stored) courses = stored;\n } catch (e) {\n console.error('Courses: Failed to load courses', e);\n }\n}\n\nasync function saveCourses() {\n try {\n await Storage.set('courses', courses);\n } catch (e) {\n console.error('Courses: Failed to save courses', e);\n toastFn('Failed to save courses', 'error');\n }\n}\n\nfunction calculateCourseDistance(course: Course): number {\n let total = 0;\n for (let i = 0; i < course.points.length - 1; i++) {\n const p1 = course.points[i];\n const p2 = course.points[i + 1];\n total += haversine(p1.lat, p1.lon, p2.lat, p2.lon);\n }\n return total / 1000; // in km\n}\n\nexport function findCourseRange(\n track: any,\n coursePoints: CoursePoint[],\n): { startIdx: number; endIdx: number } | null {\n if (coursePoints.length < 2) return null;\n\n let currentPtIdx = 0;\n let startIdx = -1;\n let endIdx = -1;\n\n for (let i = 0; i < track.points.length; i++) {\n const tp = track.points[i];\n const cp = coursePoints[currentPtIdx];\n const d = haversine(cp.lat, cp.lon, tp.lat, tp.lon);\n\n if (d <= cp.radius) {\n if (currentPtIdx === 0) startIdx = i;\n\n if (currentPtIdx === coursePoints.length - 1) {\n endIdx = i;\n return { startIdx, endIdx };\n }\n currentPtIdx++;\n }\n }\n return null;\n}\n\nexport function calculateCourseStats(track: any, startIdx: number, endIdx: number) {\n const pts = track.points;\n const n = pts.length;\n if (n === 0 || startIdx > endIdx) {\n return {\n duration: 0,\n dist: 0,\n avgWatts: null,\n avgHR: null,\n avgSpeed: null,\n avgCadence: null,\n avgVam: null,\n };\n }\n const s = Math.max(0, Math.min(startIdx, n - 1));\n const e = Math.max(s, Math.min(endIdx, n - 1));\n const startTime = pts[s]?.time || 0;\n const endTime = pts[e]?.time || 0;\n const duration = (endTime - startTime) / 1000; // in seconds\n\n let totalPower = 0;\n let powerCount = 0;\n let totalHR = 0;\n let hrCount = 0;\n let totalSpeed = 0;\n let speedCount = 0;\n let totalCadence = 0;\n let cadenceCount = 0;\n let totalAscent = 0;\n\n for (let i = s; i <= e; i++) {\n const p = pts[i];\n if (p.power != null) {\n totalPower += p.power;\n powerCount++;\n }\n if (p.hr != null) {\n totalHR += p.hr;\n hrCount++;\n }\n if (p.speed != null) {\n totalSpeed += p.speed;\n speedCount++;\n }\n if (p.cadence != null) {\n totalCadence += p.cadence;\n cadenceCount++;\n }\n if (i > s) {\n const prev = pts[i - 1];\n if (p.ele != null && prev.ele != null) {\n const de = p.ele - prev.ele;\n if (de > 0) totalAscent += de;\n }\n }\n }\n\n const dist = e > s ? (pts[e].dist || 0) - (pts[s].dist || 0) : 0;\n\n return {\n duration,\n dist,\n avgWatts: powerCount > 0 ? Math.round(totalPower / powerCount) : null,\n avgHR: hrCount > 0 ? Math.round(totalHR / hrCount) : null,\n avgSpeed: speedCount > 0 ? totalSpeed / speedCount : null,\n avgCadence: cadenceCount > 0 ? Math.round(totalCadence / cadenceCount) : null,\n avgVam: duration > 0 ? Math.round(totalAscent / (duration / 3600)) : null,\n };\n}\n\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nexport function renderCourseTableHeaders() {\n return `\n calendar_today Date\n straighten Distance\n timer Duration\n speed Speed\n speed Pace\n trending_up VAM\n bolt Power\n favorite HR\n `;\n}\n\nexport function renderCourseTableCells(stats: any, sport: string | null, dateStr: string) {\n const sportDef = sport ? SPORTS[sport.toLowerCase()] : null;\n const paceUnit = sportDef?.paceUnit || 'km';\n let paceStr = '--';\n if (stats.avgSpeed != null && stats.avgSpeed > 0.1) {\n const paceSeconds = (paceUnit === 'km' ? 1000 : 100) / stats.avgSpeed;\n paceStr = `${fmtPace(paceSeconds)} min/${paceUnit}`;\n }\n\n return `\n ${dateStr}\n ${stats.dist != null ? `${(stats.dist / 1000).toFixed(2)} km` : '-'}\n ${formatDuration(stats.duration)}\n ${stats.avgSpeed != null ? `${(stats.avgSpeed * 3.6).toFixed(1)} km/h` : '-'}\n ${paceStr}\n ${stats.avgVam != null ? `${stats.avgVam} m/h` : '-'}\n ${stats.avgWatts != null ? `${stats.avgWatts} W` : '-'}\n ${stats.avgHR != null ? `${stats.avgHR} bpm` : '-'}\n `;\n}\n\nconst COURSE_CAP = 16384;\nconst courseTrkLats = new Float64Array(COURSE_CAP);\nconst courseTrkLons = new Float64Array(COURSE_CAP);\nconst courseTrkPwrs = new Float64Array(COURSE_CAP);\nconst courseGateLats = new Float64Array(32);\nconst courseGateLons = new Float64Array(32);\nconst DTW_SAMPLES = 180;\nconst DTW_BAND = 28;\nconst dtwRefProfile = new Float64Array(DTW_SAMPLES);\nconst dtwCandProfile = new Float64Array(DTW_SAMPLES);\nconst dtwPrevRow = new Float64Array(DTW_SAMPLES + 1);\nconst dtwCurrRow = new Float64Array(DTW_SAMPLES + 1);\n\nexport function renderCourses() {\n const container = document.getElementById('courses-view');\n if (!container) return;\n\n // Evaluate multi-gate geospatial course corridor proximity & Dynamic Time Warping (DTW)\n // virtual-partner time-gap alignment matrix for the active/open course across candidate tracks\n let corridorDeviationSum = 0;\n const targetCourses =\n openCourseId || activeCourseId\n ? courses.filter((c) => c.id === openCourseId || c.id === activeCourseId)\n : courses;\n\n for (const c of targetCourses) {\n if (c.points.length < 2) continue;\n const candidateIds = MapView.findTracksPassingThroughPoints(\n c.points.map((p) => ({ lat: p.lat, lng: p.lon })),\n c.points[0]?.radius || 20,\n );\n const numGates = 4;\n for (let g = 0; g < numGates; g++) {\n const t = g / (numGates - 1);\n const segFloat = t * (c.points.length - 1);\n const segIdx = Math.min(c.points.length - 2, Math.floor(segFloat));\n const frac = segFloat - segIdx;\n const pA = c.points[segIdx];\n const pB = c.points[segIdx + 1];\n courseGateLats[g] = pA.lat + (pB.lat - pA.lat) * frac;\n courseGateLons[g] = pA.lon + (pB.lon - pA.lon) * frac;\n }\n for (let ci = 0; ci < candidateIds.length; ci++) {\n const id = candidateIds[ci];\n const trk = MapView.getTrackData(id) as any;\n const pts = trk?.points || [];\n const n = Math.min(pts.length, COURSE_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const pt = pts[i];\n courseTrkLats[i] = pt.lat;\n courseTrkLons[i] = pt.lon;\n courseTrkPwrs[i] = pt.power || 0;\n }\n\n for (let g = 0; g < numGates; g++) {\n const gLat = courseGateLats[g];\n const gLon = courseGateLons[g];\n let minDist = Infinity;\n let bestIdx = 0;\n for (let i = 0; i < n; i++) {\n const d = haversine(gLat, gLon, courseTrkLats[i], courseTrkLons[i]);\n if (d < minDist) {\n minDist = d;\n bestIdx = i;\n }\n }\n corridorDeviationSum += minDist + courseTrkPwrs[bestIdx] * 0.01;\n }\n\n // Resample track telemetry and evaluate single-pass banded DTW virtual-partner pacing alignment\n for (let s = 0; s < DTW_SAMPLES; s++) {\n const idx = Math.min(n - 1, Math.floor((s * (n - 1)) / (DTW_SAMPLES - 1)));\n const pt = pts[idx];\n const val = (pt.speed || 0) * 3.6 + (pt.ele || 0) * 0.05 + (pt.power || 0) * 0.02;\n if (ci === 0) dtwRefProfile[s] = val;\n dtwCandProfile[s] = val;\n }\n\n dtwPrevRow.fill(1e9);\n dtwPrevRow[0] = 0;\n for (let i = 1; i <= DTW_SAMPLES; i++) {\n dtwCurrRow.fill(1e9);\n const jStart = Math.max(1, i - DTW_BAND);\n const jEnd = Math.min(DTW_SAMPLES, i + DTW_BAND);\n const rVal = dtwRefProfile[i - 1];\n for (let j = jStart; j <= jEnd; j++) {\n const diff = rVal - dtwCandProfile[j - 1];\n const diffSq = diff * diff;\n const cost = diffSq * (2 - 1 / (1 + diffSq * 0.01));\n const m1 = dtwPrevRow[j];\n const m2 = dtwCurrRow[j - 1];\n const m3 = dtwPrevRow[j - 1];\n const prevMin = m1 < m2 ? (m1 < m3 ? m1 : m3) : m2 < m3 ? m2 : m3;\n dtwCurrRow[j] = cost + prevMin;\n }\n dtwPrevRow.set(dtwCurrRow);\n }\n corridorDeviationSum += dtwPrevRow[DTW_SAMPLES] * 1e-4;\n }\n }\n container.dataset.corridorDeviation = corridorDeviationSum.toFixed(2);\n\n container.innerHTML = `\n
\n
\n
\n
\n ${\n isEditMode\n ? `\n \n `\n : `\n \n `\n }\n
\n
\n
\n
\n ${\n courses.length === 0\n ? `\n
\n route\n
No courses created yet
\n
\n `\n : courses\n .map((c) => {\n const pts = c.points.map((p) => ({ lat: p.lat, lng: p.lon }));\n const matchingIds = MapView.findTracksPassingThroughPoints(\n pts,\n c.points[0]?.radius || 20,\n );\n const isOpen = c.id === openCourseId;\n let tracksHtml = '';\n if (isOpen) {\n const matchedTracksWithStats = matchingIds\n .map((id) => {\n const track = MapView.getTrackData(id) as any;\n if (!track) return null;\n const range = findCourseRange(track, c.points);\n if (!range) return null;\n const stats = calculateCourseStats(track, range.startIdx, range.endIdx);\n const span = Math.max(1, range.endIdx - range.startIdx);\n const q1Idx = range.startIdx + Math.floor(span * 0.25);\n const q2Idx = range.startIdx + Math.floor(span * 0.5);\n const q3Idx = range.startIdx + Math.floor(span * 0.75);\n const s1Stats = calculateCourseStats(track, range.startIdx, q1Idx);\n const s2Stats = calculateCourseStats(track, q1Idx, q2Idx);\n const s3Stats = calculateCourseStats(track, q2Idx, q3Idx);\n const s4Stats = calculateCourseStats(track, q3Idx, range.endIdx);\n const startTime = track.stats?.startTime || track.points?.[0]?.time;\n const dateStr = startTime ? fmtDate(startTime) : '-';\n return {\n id,\n displayName: track.displayName || track.name || id,\n date: dateStr,\n sport: track.sport,\n color: track.color,\n ...stats,\n splitsSummary: `${s1Stats.avgWatts || 0}/${s2Stats.avgWatts || 0}/${s3Stats.avgWatts || 0}/${s4Stats.avgWatts || 0}W`,\n startIdx: range.startIdx,\n endIdx: range.endIdx,\n };\n })\n .filter((t) => t !== null) as any[];\n\n // Sort by duration (fastest first), tie-break by id\n matchedTracksWithStats.sort(\n (a, b) => a.duration - b.duration || a.id.localeCompare(b.id),\n );\n\n tracksHtml = `\n
\n ${\n matchedTracksWithStats.length === 0\n ? `\n
No matching tracks
\n `\n : `\n \n \n \n \n ${renderCourseTableHeaders()}\n \n \n \n ${matchedTracksWithStats\n .map((t) => {\n const isSelected = t.id === UrlState.get().track;\n return `\n \n \n ${renderCourseTableCells(t, t.sport, t.date)}\n \n `;\n })\n .join('')}\n \n
Track (${matchedTracksWithStats.length})
\n
\n
\n ${escHtml(t.displayName)}\n
\n
\n `\n }\n
\n `;\n }\n return `\n
\n
\n ${isOpen ? 'expand_more' : 'chevron_right'}\n
${escHtml(c.name)} edit
\n
straighten ${calculateCourseDistance(c).toFixed(2)} km | ${c.points.length} points | ${matchingIds.length} matching tracks
\n
\n \n \n
\n
\n ${tracksHtml}\n
\n `;\n })\n .join('')\n }\n
\n
\n `;\n\n document.getElementById('btn-new-course')?.addEventListener('click', () => {\n createNewCourse();\n });\n\n document.getElementById('btn-done-edit')?.addEventListener('click', () => {\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n document.getElementById('map-container')?.classList.remove('editing-mode');\n renderCourses();\n });\n\n container.querySelectorAll('.course-item').forEach((el) => {\n const id = (el as HTMLElement).dataset.id!;\n el.querySelector('.btn-edit-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n editCourse(id);\n });\n el.querySelector('.btn-rename-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n renameCourse(id);\n });\n el.querySelector('.btn-delete-course')?.addEventListener('click', (e) => {\n e.stopPropagation();\n deleteCourse(id);\n });\n el.querySelector('.course-item-header')?.addEventListener('click', (e) => {\n if (\n (e.target as HTMLElement).closest('.course-actions') ||\n (e.target as HTMLElement).closest('.btn-rename-course')\n )\n return;\n\n selectCourse(id);\n openCourseId = openCourseId === id ? null : id;\n renderCourses();\n });\n\n el.querySelectorAll('.course-track-row').forEach((row) => {\n const trackId = (row as HTMLElement).dataset.trackId!;\n const startIdx = parseInt((row as HTMLElement).dataset.start!, 10);\n const endIdx = parseInt((row as HTMLElement).dataset.end!, 10);\n\n row.querySelector('.track-name-cell')?.addEventListener('click', (e) => {\n e.stopPropagation();\n const track = MapView.getTrackData(trackId);\n if (track) {\n // Select track (clears selection in app.ts)\n selectTrack(trackId, false);\n\n // Delay execution slightly to let selectTrack finish and ChartView to initialize\n setTimeout(() => {\n const pts = track.points;\n const t0 = pts.find((p: any) => p.time != null)?.time || 0;\n\n // Ensure indices are within bounds\n const sIdx = Math.max(0, Math.min(startIdx, pts.length - 1));\n const eIdx = Math.max(0, Math.min(endIdx, pts.length - 1));\n\n const tMin = Math.max(0, ((pts[sIdx]?.time || 0) - t0) / 1000);\n const tMax = Math.max(0, ((pts[eIdx]?.time || 0) - t0) / 1000);\n\n const axis = ChartView.getXAxis();\n let selMin = tMin;\n let selMax = tMax;\n\n if (axis === 'distance') {\n selMin = Math.max(0, (pts[sIdx]?.dist || 0) / 1000);\n selMax = Math.max(0, (pts[eIdx]?.dist || 0) / 1000);\n }\n\n // Set selection and switch tab\n UrlState.patch({ sel: [selMin, selMax], tab: 'graphs' }, true);\n\n // Manually restore selection in ChartView (expects seconds from start)\n ChartView.restoreSelection(tMin, tMax);\n\n // Highlight segment on map\n MapView.highlightSegment(trackId, track.points, startIdx, endIdx, true);\n }, 50);\n }\n });\n\n row.addEventListener('mouseenter', () => {\n MapView.setTrackHover(trackId, true);\n });\n\n row.addEventListener('mouseleave', () => {\n MapView.setTrackHover(trackId, false);\n });\n });\n });\n}\n\nfunction createNewCourse() {\n const name = `Course ${courses.length + 1}`;\n\n const newCourse: Course = {\n id: Math.random().toString(36).substring(2, 9),\n name: name,\n points: [],\n };\n\n courses.push(newCourse);\n saveCourses();\n renderCourses();\n editCourse(newCourse.id);\n}\n\nfunction renameCourse(id: string) {\n const course = courses.find((c) => c.id === id);\n if (!course) return;\n\n const el = document.querySelector(`.course-item[data-id=\"${id}\"]`);\n if (!el) return;\n\n const nameEl = el.querySelector('.course-name');\n if (!nameEl) return;\n\n const currentName = course.name;\n nameEl.innerHTML = ``;\n\n const input = nameEl.querySelector('.course-name-input') as HTMLInputElement;\n input.focus();\n input.select();\n\n const save = () => {\n const newName = input.value.trim();\n if (newName !== '') {\n course.name = newName;\n saveCourses();\n }\n renderCourses();\n };\n\n input.addEventListener('blur', save);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') save();\n else if (e.key === 'Escape') renderCourses();\n });\n}\n\nfunction editCourse(id: string) {\n activeCourseId = id;\n isEditMode = true;\n renderCourses();\n}\n\nfunction clearCourseLayer() {\n courseLayer = null;\n}\n\nfunction addPointToCourse(courseId: string, lat: number, lon: number) {\n const course = courses.find((c) => c.id === courseId);\n if (!course) return;\n\n const newPoint: CoursePoint = {\n lat,\n lon,\n radius: 20, // 20m default radius\n };\n\n course.points.push(newPoint);\n saveCourses();\n renderCourses();\n}\n\nfunction renderCourseOnMap(courseId: string) {\n // Map rendering removed for benchmark\n}\n\nexport function selectCourse(id: string, open: boolean = false) {\n activeCourseId = id;\n if (open) openCourseId = id;\n isEditMode = false;\n MapView.setCustomClickHandler(null);\n clearCourseLayer();\n renderCourses();\n}\n\nfunction deleteCourse(id: string) {\n if (!confirm('Are you sure you want to delete this course?')) return;\n courses = courses.filter((c) => c.id !== id);\n if (activeCourseId === id) {\n activeCourseId = null;\n clearCourseLayer();\n }\n saveCourses();\n renderCourses();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, TrackPoint } from '../parsers';\nimport { ChartView } from '../charts';\nimport { hexToRgba, fmtSecs } from '../utils';\n\nlet currentTracks: TrackData[] = [];\nlet currentTrack: TrackData | null = null;\nlet plot: uPlot | null = null;\nlet xMetric = 'power';\nlet yMetric = 'hr';\nlet currentSliderIdx: number | null = null;\nlet currentChronoData: [number, number, number, number, number, number, number][] = [];\nlet currentSortedData: [number, number, number, number, number, number, number][] = [];\nlet playIntervalId: number | null = null;\nlet isPolar = false;\n\nfunction updateSliderLabel() {\n const sliderVal = document.getElementById('combined-time-val');\n if (sliderVal && currentSliderIdx !== null && currentChronoData[currentSliderIdx]) {\n const timeSecs = currentChronoData[currentSliderIdx][2];\n sliderVal.textContent = `${fmtSecs(timeSecs)}`;\n }\n}\n\nexport function initCombined() {\n // Initialize UI event listeners if needed\n}\n\nexport function resetCombined() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (plot) {\n plot.destroy();\n plot = null;\n }\n currentTracks = [];\n currentTrack = null;\n xMetric = 'power';\n yMetric = 'hr';\n currentSliderIdx = null;\n currentChronoData = [];\n currentSortedData = [];\n isPolar = false;\n const tooltip = document.getElementById('combined-tooltip');\n if (tooltip) tooltip.remove();\n const container = document.getElementById('combined-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n }\n}\n\nconst COMBINED_CAP = 16384;\nconst combinedDensityGrid = new Float64Array(32 * 32);\n\nexport interface CombinedCorrelationRow {\n pairLabel: string;\n rVal: number;\n slope: number;\n samples: number;\n}\n\nexport interface CombinedSectionComparisonRow {\n sectionLabel: string;\n t1Power: number;\n t2Power: number;\n t1Hr: number;\n t2Hr: number;\n t1SpeedKmh: number;\n t2SpeedKmh: number;\n cohortAvgPower: number;\n}\n\nfunction computeMultiTrackCorrelationAndSections(\n currentTracks: TrackData[],\n allTracks: TrackData[],\n): {\n aggPts: number;\n corrSum: number;\n correlations: CombinedCorrelationRow[];\n sectionRows: CombinedSectionComparisonRow[];\n} {\n const matrixTracks = allTracks.length >= 2 ? allTracks : currentTracks;\n const numTrk = Math.min(matrixTracks.length, 8);\n combinedDensityGrid.fill(0);\n\n const pairs: {\n label: string;\n getX: (p: TrackPoint) => number | null | undefined;\n getY: (p: TrackPoint) => number | null | undefined;\n }[] = [\n { label: 'Power vs Heart Rate', getX: (p) => p.power, getY: (p) => p.hr },\n {\n label: 'Speed vs Gradient',\n getX: (p) => (p.speed != null ? p.speed * 3.6 : undefined),\n getY: (p) => p.gradient,\n },\n { label: 'Cadence vs Power', getX: (p) => p.cad, getY: (p) => p.power },\n { label: 'Elevation vs VAM', getX: (p) => p.ele, getY: (p) => p.verticalSpeed },\n { label: 'Temperature vs HR', getX: (p) => p.temp, getY: (p) => p.hr },\n ];\n\n let aggPts = 0;\n let corrSum = 0;\n const correlations: CombinedCorrelationRow[] = [];\n\n for (let pi = 0; pi < pairs.length; pi++) {\n const pair = pairs[pi];\n let sumX = 0;\n let sumY = 0;\n let sumXX = 0;\n let sumYY = 0;\n let sumXY = 0;\n let count = 0;\n\n for (let t = 0; t < numTrk; t++) {\n const pts = matrixTracks[t].points || [];\n const n = Math.min(pts.length, COMBINED_CAP);\n for (let k = 0; k < n; k++) {\n const p = pts[k];\n const x = pair.getX(p);\n const y = pair.getY(p);\n if (x != null && y != null) {\n sumX += x;\n sumY += y;\n sumXX += x * x;\n sumYY += y * y;\n sumXY += x * y;\n count++;\n }\n if (pi === 0) {\n const pw = p.power || 0;\n const h = p.hr || 0;\n const cd = p.cad || 0;\n const bx = Math.min(31, Math.max(0, (pw * 0.05) | 0));\n const by = Math.min(31, Math.max(0, ((h - 60) * 0.2) | 0));\n combinedDensityGrid[(bx << 5) | by] += 1 + cd * 0.01;\n }\n }\n }\n\n let rVal = 0;\n let slope = 0;\n if (count > 2) {\n const meanX = sumX / count;\n const meanY = sumY / count;\n const varX = Math.max(0, sumXX / count - meanX * meanX);\n const varY = Math.max(0, sumYY / count - meanY * meanY);\n const covXY = sumXY / count - meanX * meanY;\n const denom = Math.sqrt(varX * varY);\n rVal = denom > 1e-9 ? covXY / denom : 0;\n slope = varX > 1e-9 ? covXY / varX : 0;\n }\n aggPts += count;\n corrSum += Math.abs(rVal) * 100 + Math.abs(slope);\n correlations.push({\n pairLabel: pair.label,\n rVal,\n slope,\n samples: count,\n });\n }\n\n for (let g = 0; g < 1024; g++) {\n corrSum += combinedDensityGrid[g] * 1e-3;\n }\n\n const sectionLabels = ['Q1 (0\u201325%)', 'Q2 (25\u201350%)', 'Q3 (50\u201375%)', 'Q4 (75\u2013100%)'];\n const sectionRows: CombinedSectionComparisonRow[] = [];\n const t1 = currentTracks[0];\n const t2 = currentTracks[1] || currentTracks[0];\n\n for (let q = 0; q < 4; q++) {\n const fStart = q * 0.25;\n const fEnd = (q + 1) * 0.25;\n\n const sliceStats = (trk: TrackData) => {\n const pts = trk.points || [];\n const sIdx = Math.floor(pts.length * fStart);\n const eIdx = Math.max(sIdx + 1, Math.floor(pts.length * fEnd));\n let pSum = 0,\n hSum = 0,\n spSum = 0,\n cnt = 0;\n for (let i = sIdx; i < eIdx && i < pts.length; i++) {\n const pt = pts[i];\n pSum += pt.power || 0;\n hSum += pt.hr || 0;\n spSum += (pt.speed || 0) * 3.6;\n cnt++;\n }\n return {\n power: cnt > 0 ? Math.round(pSum / cnt) : 0,\n hr: cnt > 0 ? Math.round(hSum / cnt) : 0,\n speedKmh: cnt > 0 ? spSum / cnt : 0,\n };\n };\n\n const st1 = sliceStats(t1);\n const st2 = sliceStats(t2);\n let cohortPwrSum = 0;\n for (let t = 0; t < numTrk; t++) {\n cohortPwrSum += sliceStats(matrixTracks[t]).power;\n }\n sectionRows.push({\n sectionLabel: sectionLabels[q],\n t1Power: st1.power,\n t2Power: st2.power,\n t1Hr: st1.hr,\n t2Hr: st2.hr,\n t1SpeedKmh: st1.speedKmh,\n t2SpeedKmh: st2.speedKmh,\n cohortAvgPower: numTrk > 0 ? Math.round(cohortPwrSum / numTrk) : 0,\n });\n }\n\n return { aggPts, corrSum, correlations, sectionRows };\n}\n\nexport function setCombinedMetrics(xKey: string, yKey: string) {\n xMetric = xKey;\n yMetric = yKey;\n if (currentTracks.length >= 2) {\n renderCombined(currentTracks);\n } else if (currentTrack) {\n renderCombined(currentTrack);\n }\n}\n\nexport function setCombinedPolar(polar: boolean) {\n if (isPolar !== polar) {\n isPolar = polar;\n if (currentTracks.length >= 2) {\n renderCombined(currentTracks);\n } else if (currentTrack) {\n renderCombined(currentTrack);\n }\n }\n}\n\nexport function setCombinedSliderProgress(fraction: number) {\n const clamped = Math.max(0, Math.min(1, fraction));\n const maxLen =\n currentChronoData.length > 0\n ? currentChronoData.length - 1\n : currentTrack\n ? Math.max(0, currentTrack.points.length - 1)\n : 0;\n currentSliderIdx = Math.round(clamped * maxLen);\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement | null;\n if (slider) {\n slider.max = `${maxLen}`;\n slider.value = `${currentSliderIdx}`;\n }\n updateSliderLabel();\n if (plot) plot.redraw();\n}\n\nexport function renderCombined(\n trackOrTracks: TrackData | TrackData[] | null,\n allTracks: TrackData[] = [],\n) {\n if (Array.isArray(trackOrTracks)) {\n currentTracks = trackOrTracks;\n currentTrack = trackOrTracks[0] || null;\n } else if (trackOrTracks) {\n currentTracks = [trackOrTracks];\n currentTrack = trackOrTracks;\n } else {\n currentTracks = [];\n currentTrack = null;\n }\n const container = document.getElementById('combined-view');\n if (!container) return;\n\n const track = currentTrack;\n if (!track) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for combined analysis
\n
\n `;\n return;\n }\n\n // Find available metrics in the track\n const metrics = ChartView.METRICS;\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n // Default to first two available if defaults are not available\n if (!availableMetrics.includes(xMetric) && availableMetrics.length > 0)\n xMetric = availableMetrics[0];\n\n if (!availableMetrics.includes(yMetric) && availableMetrics.length > 1)\n yMetric = availableMetrics[1];\n else if (!availableMetrics.includes(yMetric) && availableMetrics.length > 0)\n yMetric = availableMetrics[0];\n\n const xDef = metrics[xMetric];\n const yDef = metrics[yMetric];\n\n // Prevent scrolling and runaway size\n container.style.overflow = 'hidden';\n\n let summaryHtml = '';\n if (currentTracks.length >= 2) {\n const { aggPts, corrSum, correlations, sectionRows } = computeMultiTrackCorrelationAndSections(\n currentTracks,\n allTracks,\n );\n const t1 = currentTracks[0];\n const t2 = currentTracks[1];\n const s1 = t1.stats;\n const s2 = t2.stats;\n const distDiff = ((s2.totalDist - s1.totalDist) / 1000).toFixed(2);\n const pwrDiff = ((s2.avgPower || 0) - (s1.avgPower || 0)).toFixed(0);\n const hrDiff = ((s2.avgHR || 0) - (s1.avgHR || 0)).toFixed(0);\n const eleDiff = (s2.elevGain - s1.elevGain).toFixed(0);\n const shiftsDiff = (s2.shifts || 0) - (s1.shifts || 0);\n\n const totalDist = ((s1.totalDist + s2.totalDist) / 1000).toFixed(2);\n const totalElev = (s1.elevGain + s2.elevGain).toFixed(0);\n const totalDur = ((s1.duration || 0) + (s2.duration || 0)) / 1000;\n const avgPwr = Math.round(((s1.avgPower || 0) + (s2.avgPower || 0)) / 2);\n const maxPwr = Math.max(s1.maxPower || 0, s2.maxPower || 0);\n const avgHr = Math.round(((s1.avgHR || 0) + (s2.avgHR || 0)) / 2);\n const maxHr = Math.max(s1.maxHR || 0, s2.maxHR || 0);\n const tempDiff = ((s2.avgTemp ?? 0) - (s1.avgTemp ?? 0)).toFixed(1);\n const avgTemp = (((s1.avgTemp ?? 0) + (s2.avgTemp ?? 0)) / 2).toFixed(1);\n const maxTemp = Math.max(s1.maxTemp ?? 0, s2.maxTemp ?? 0).toFixed(1);\n const totalShifts = (s1.shifts || 0) + (s2.shifts || 0);\n\n summaryHtml = `\n
\n
Aggregate Track Comparison & Section Analysis (${currentTracks.length} Tracks)
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${sectionRows\n .map(\n (sr) => `\n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
Metric${t1.displayName || t1.name} (T1)${t2.displayName || t2.name} (T2)Delta (T2 - T1)Aggregate Summary
Distance${(s1.totalDist / 1000).toFixed(2)} km${(s2.totalDist / 1000).toFixed(2)} km= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(distDiff) >= 0 ? '+' : ''}${distDiff} km${totalDist} km (Total)
Elevation Gain${s1.elevGain.toFixed(0)} m${s2.elevGain.toFixed(0)} m= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(eleDiff) >= 0 ? '+' : ''}${eleDiff} m${totalElev} m (Total)
Duration${s1.duration ? fmtSecs(s1.duration / 1000) : '--'}${s2.duration ? fmtSecs(s2.duration / 1000) : '--'}--${fmtSecs(totalDur)} (Total)
Avg / Max Power${s1.avgPower || 0} W / ${s1.maxPower || 0} W${s2.avgPower || 0} W / ${s2.maxPower || 0} W= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(pwrDiff) >= 0 ? '+' : ''}${pwrDiff} W (Avg)${avgPwr} W (Avg) / ${maxPwr} W (Max)
Avg / Max HR${s1.avgHR || 0} bpm / ${s1.maxHR || 0} bpm${s2.avgHR || 0} bpm / ${s2.maxHR || 0} bpm= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(hrDiff) >= 0 ? '+' : ''}${hrDiff} bpm (Avg)${avgHr} bpm (Avg) / ${maxHr} bpm (Max)
Avg / Max Temp${s1.avgTemp != null ? s1.avgTemp.toFixed(1) : '--'} \u00B0C / ${s1.maxTemp != null ? s1.maxTemp.toFixed(1) : '--'} \u00B0C${s2.avgTemp != null ? s2.avgTemp.toFixed(1) : '--'} \u00B0C / ${s2.maxTemp != null ? s2.maxTemp.toFixed(1) : '--'} \u00B0C= 0 ? '#4ECDC4' : '#FF6B6B'};\">${Number(tempDiff) >= 0 ? '+' : ''}${tempDiff} \u00B0C (Avg)${avgTemp} \u00B0C (Avg) / ${maxTemp} \u00B0C (Max)
Gear Shifts${s1.shifts || 0}${s2.shifts || 0}= 0 ? '#4ECDC4' : '#FF6B6B'};\">${shiftsDiff >= 0 ? '+' : ''}${shiftsDiff}${totalShifts} (Total)
${sr.sectionLabel} Split${sr.t1Power}W \u00B7 ${sr.t1Hr}bpm \u00B7 ${sr.t1SpeedKmh.toFixed(1)}km/h${sr.t2Power}W \u00B7 ${sr.t2Hr}bpm \u00B7 ${sr.t2SpeedKmh.toFixed(1)}km/h${sr.t2Power - sr.t1Power >= 0 ? '+' : ''}${sr.t2Power - sr.t1Power}WCohort Avg: ${sr.cohortAvgPower}W
\n
\n ${correlations\n .map(\n (c) =>\n `${c.pairLabel}: r=${c.rVal.toFixed(2)}, \u03B2=${c.slope.toFixed(2)} (${c.samples})`,\n )\n .join('')}\n
\n
\n `;\n }\n\n // Render UI with selectors and plot container\n container.innerHTML = `${summaryHtml}\n
\n
\n arrow_forward\n X Axis:\n \n
\n
\n arrow_upward\n Y Axis:\n \n
\n
\n schedule\n Time:\n \n 0:00\n \n
\n
\n \n \n
\n
\n
\n `;\n\n document.getElementById('btn-combined-x')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'x');\n });\n\n document.getElementById('btn-combined-y')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMenu(e.currentTarget as HTMLElement, 'y');\n });\n\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n const sliderVal = document.getElementById('combined-time-val');\n const playBtn = document.getElementById('btn-combined-play');\n\n slider?.addEventListener('input', () => {\n currentSliderIdx = parseInt(slider.value, 10);\n updateSliderLabel();\n if (plot) plot.redraw();\n });\n\n function startPlaying() {\n if (playBtn) playBtn.innerHTML = 'pause';\n\n playIntervalId = window.setInterval(() => {\n if (currentSliderIdx !== null && currentSliderIdx < currentChronoData.length - 1) {\n currentSliderIdx = Math.min(currentSliderIdx + 5, currentChronoData.length - 1);\n slider.value = `${currentSliderIdx}`;\n updateSliderLabel();\n if (plot) plot.redraw();\n } else {\n stopPlaying();\n }\n }, 20); // 50 fps\n }\n\n function stopPlaying() {\n if (playIntervalId) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n if (playBtn) playBtn.innerHTML = 'play_arrow';\n }\n\n playBtn?.addEventListener('click', () => {\n if (playIntervalId) {\n stopPlaying();\n } else {\n // If at the end, loop back to start\n if (currentSliderIdx !== null && currentSliderIdx >= currentChronoData.length - 1) {\n currentSliderIdx = 0;\n slider.value = '0';\n updateSliderLabel();\n if (plot) plot.redraw();\n }\n startPlaying();\n }\n });\n\n document.getElementById('btn-combined-cart')?.addEventListener('click', () => {\n if (isPolar) {\n isPolar = false;\n renderCombined(currentTrack);\n }\n });\n\n document.getElementById('btn-combined-polar')?.addEventListener('click', () => {\n if (!isPolar) {\n isPolar = true;\n renderCombined(currentTrack);\n }\n });\n\n updatePlot();\n}\n\nexport function resizeCombined() {\n const container = document.getElementById('tab-combined');\n const plotContainer = document.getElementById('combined-plot-container');\n if (plot && plotContainer && plotContainer.clientWidth > 0) {\n const w = plotContainer.clientWidth;\n const h = plotContainer.clientHeight;\n\n if (w > 0 && h > 0) {\n if (isPolar) {\n const size = Math.min(w, h);\n plot.setSize({ width: size, height: size });\n } else {\n plot.setSize({ width: w, height: h });\n }\n }\n }\n}\n\nfunction showMenu(anchorEl: HTMLElement, axis: 'x' | 'y') {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const track = currentTrack;\n if (!track) return;\n\n const availableMetrics: string[] = [];\n for (const key in metrics) {\n const def = metrics[key];\n if (track.points.some((p) => (p as any)[def.field] != null)) availableMetrics.push(key);\n }\n\n availableMetrics.forEach((key) => {\n const def = metrics[key];\n const item = document.createElement('div');\n const currentVal = axis === 'x' ? xMetric : yMetric;\n item.className = `menu-item ${currentVal === key ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${currentVal === key ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n if (axis === 'x') xMetric = key;\n else yMetric = key;\n\n popup.remove();\n renderCombined(currentTrack); // Re-render to update buttons and plot\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction updatePlot() {\n if (!currentTrack) return;\n const container = document.getElementById('combined-plot-container');\n if (!container) return;\n\n const metrics = ChartView.METRICS;\n const xDef = metrics[xMetric] || metrics.power;\n const yDef = metrics[yMetric] || metrics.hr;\n\n if (currentTracks.length >= 2) {\n let maxLen = 0;\n for (let t = 0; t < currentTracks.length; t++) {\n if (currentTracks[t].points.length > maxLen) maxLen = currentTracks[t].points.length;\n }\n const xData: number[] = new Array(maxLen);\n for (let i = 0; i < maxLen; i++) xData[i] = i;\n\n const seriesList: uPlot.Series[] = [{}];\n const dataArrays: (number | null)[][] = [xData];\n\n for (let t = 0; t < currentTracks.length; t++) {\n const trk = currentTracks[t];\n const pts = trk.points;\n const yArr: (number | null)[] = new Array(maxLen);\n for (let i = 0; i < maxLen; i++) {\n const p = pts[i];\n yArr[i] = p && (p as any)[yDef.field] != null ? (p as any)[yDef.field] : null;\n }\n dataArrays.push(yArr);\n seriesList.push({\n label: `${trk.displayName || trk.name} (${yDef.label})`,\n stroke: trk.color || '#3b82f6',\n width: 2,\n points: { show: false },\n });\n }\n\n if (plot) {\n plot.destroy();\n plot = null;\n }\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n const width = container.clientWidth > 0 ? container.clientWidth : 800;\n const height = container.clientHeight > 0 ? container.clientHeight : 350;\n\n const opts: uPlot.Options = {\n width,\n height,\n padding: [10, 15, 0, 0],\n scales: { x: { time: false }, y: { auto: true } },\n series: seriesList,\n axes: [\n {\n side: 2,\n label: 'Elapsed Duration (s)',\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n side: 3,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n legend: { show: true },\n };\n\n plot = new uPlot(opts, dataArrays as uPlot.AlignedData, container as HTMLElement);\n resizeCombined();\n return;\n }\n\n const pts = currentTrack.points;\n const t0 = pts[0].time || 0;\n const chronoData = pts\n .map((p, idx) => [\n (p as any)[xDef.field],\n (p as any)[yDef.field],\n (p.time! - t0) / 1000,\n (p.dist || 0) / 1000,\n idx,\n ])\n .filter(([x, y, t, d]) => x != null && y != null) as [number, number, number, number, number][];\n\n if (chronoData.length === 0) {\n container.innerHTML =\n '
No data for selected metrics
';\n return;\n }\n\n if (isPolar) {\n const xVals = chronoData.map((d) => d[0]);\n const yVals = chronoData.map((d) => d[1]);\n const xMin = Math.min(...xVals);\n const xMax = Math.max(...xVals);\n const yMin = Math.min(...yVals);\n const yMax = Math.max(...yVals);\n\n currentChronoData = chronoData.map((d) => {\n const xVal = d[0];\n const yVal = d[1];\n const theta = ((xVal - xMin) / (xMax - xMin || 1)) * 2 * Math.PI;\n const r = (yVal - yMin) / (yMax - yMin || 1);\n const px = r * Math.cos(theta);\n const py = r * Math.sin(theta);\n return [px, py, d[2], d[3], d[4], xVal, yVal] as any;\n });\n } else {\n currentChronoData = chronoData.map((d) => [d[0], d[1], d[2], d[3], d[4], d[0], d[1]] as any);\n }\n\n // Update slider\n const slider = document.getElementById('combined-time-slider') as HTMLInputElement;\n if (slider) {\n slider.max = `${chronoData.length - 1}`;\n if (currentSliderIdx === null || currentSliderIdx >= chronoData.length) {\n currentSliderIdx = chronoData.length - 1;\n slider.value = slider.max;\n }\n updateSliderLabel();\n }\n\n // Sort by X for uPlot (with original point index tie-breaker)\n currentSortedData = [...currentChronoData].sort((a, b) => a[0] - b[0] || a[4] - b[4]);\n\n const xData = currentSortedData.map((d) => d[0]);\n const yData = currentSortedData.map((d) => d[1]);\n\n const plotContainer = document.getElementById('combined-plot-container');\n let width = plotContainer && plotContainer.clientWidth > 0 ? plotContainer.clientWidth : 600;\n let height = plotContainer && plotContainer.clientHeight > 0 ? plotContainer.clientHeight : 400;\n\n if (isPolar) {\n const size = Math.min(width, height > 0 ? height : width);\n width = size;\n height = size;\n\n if (plotContainer) {\n plotContainer.style.display = 'flex';\n plotContainer.style.alignItems = 'center';\n plotContainer.style.justifyContent = 'center';\n }\n } else if (plotContainer) {\n plotContainer.style.display = '';\n plotContainer.style.alignItems = '';\n plotContainer.style.justifyContent = '';\n }\n\n const opts: uPlot.Options = {\n width: width,\n height: height,\n padding: [10, 15, 0, 0],\n scales: {\n x: { time: false, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: yDef.label,\n width: 0,\n points: { show: true, size: 3, fill: hexToRgba(yDef.color, 0.3) },\n },\n ],\n axes: [\n {\n side: 2, // bottom\n show: !isPolar,\n label: `${xDef.label} (${xDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? xDef.fmtAxis(v) : '')),\n size: 30,\n },\n {\n side: 3, // left\n show: !isPolar,\n label: `${yDef.label} (${yDef.unit})`,\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n font: '10px system-ui, sans-serif',\n values: (u, vals) => vals.map((v) => (v != null ? yDef.fmtAxis(v) : '')),\n size: 40,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => {\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let closestIdx = -1;\n\n for (let i = 0; i < currentSortedData.length; i++) {\n const [xVal, yVal] = currentSortedData[i];\n const cx = u.valToPos(xVal, 'x');\n const cy = u.valToPos(yVal, 'y');\n\n const dx = cx - cursorLeft;\n const dy = cy - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n closestIdx = i;\n }\n }\n\n // Only snap if within a reasonable distance (e.g. 50 pixels)\n if (closestIdx >= 0 && minD2 < 2500) return closestIdx;\n }\n return dataIdx;\n },\n points: {\n size: 7,\n stroke: '#fff',\n width: 2,\n fill: yDef.color,\n },\n },\n legend: { show: false },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n\n // Draw faint lines connecting points in chronological order\n ctx.save();\n ctx.beginPath();\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.lineWidth = 1 * dpr;\n\n let started = false;\n for (let i = 0; i < currentChronoData.length; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n if (started) {\n ctx.lineTo(cx, cy);\n } else {\n ctx.moveTo(cx, cy);\n started = true;\n }\n }\n ctx.stroke();\n ctx.restore();\n\n // Draw trail if slider is active\n if (currentSliderIdx !== null) {\n ctx.save();\n const windowSize = 100; // Longer trail\n const startIdx = Math.max(0, currentSliderIdx - windowSize);\n const endIdx = currentSliderIdx;\n\n // 1. Draw increasingly thicker connection line for the trail\n for (let i = startIdx; i < endIdx; i++) {\n const [xVal1, yVal1] = currentChronoData[i];\n const [xVal2, yVal2] = currentChronoData[i + 1];\n const cx1 = u.valToPos(xVal1, 'x', true);\n const cy1 = u.valToPos(yVal1, 'y', true);\n const cx2 = u.valToPos(xVal2, 'x', true);\n const cy2 = u.valToPos(yVal2, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const lineWidth = 1 + 5 * progress; // Grow from 1 to 6\n const alpha = 0.15 + 0.6 * progress; // Fade from 0.15 to 0.75\n\n ctx.beginPath();\n ctx.moveTo(cx1, cy1);\n ctx.lineTo(cx2, cy2);\n ctx.strokeStyle = hexToRgba(yDef.color, alpha);\n ctx.lineWidth = lineWidth * dpr;\n ctx.stroke();\n }\n\n // 2. Draw dots on top\n for (let i = startIdx; i <= endIdx; i++) {\n const [xVal, yVal] = currentChronoData[i];\n const cx = u.valToPos(xVal, 'x', true);\n const cy = u.valToPos(yVal, 'y', true);\n\n const progress = (i - startIdx) / (endIdx - startIdx || 1);\n const size = 3 + 7 * progress; // Grow from 3 to 10\n const fillAlpha = 0.01 + 0.14 * progress; // Fade from 0.01 to 0.15\n\n ctx.beginPath();\n ctx.arc(cx, cy, size * dpr, 0, Math.PI * 2);\n ctx.fillStyle = hexToRgba(yDef.color, fillAlpha);\n ctx.fill();\n\n ctx.strokeStyle = yDef.color;\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n }\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n\n let tooltip = document.getElementById('combined-tooltip');\n if (!tooltip) {\n tooltip = document.createElement('div');\n tooltip.id = 'combined-tooltip';\n tooltip.style.position = 'absolute';\n tooltip.style.background = 'rgba(14, 14, 16, 0.9)';\n tooltip.style.color = '#fff';\n tooltip.style.padding = '8px 12px';\n tooltip.style.borderRadius = '4px';\n tooltip.classList.add('font-m');\n tooltip.style.fontFamily = 'system-ui';\n tooltip.style.pointerEvents = 'none';\n tooltip.style.zIndex = '1000';\n tooltip.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';\n tooltip.style.border = '1px solid #2e2e34';\n document.body.appendChild(tooltip);\n }\n\n if (idx != null && currentSortedData[idx] && u.cursor.left! >= 0) {\n const d = currentSortedData[idx];\n const timeSecs = d[2];\n const distKm = d[3];\n const origX = d[5];\n const origY = d[6];\n\n tooltip.innerHTML = `\n
Point #${idx}
\n
\n Time:\n ${fmtSecs(timeSecs)}\n
\n
\n Distance:\n ${distKm.toFixed(2)} km\n
\n
\n ${xDef.label}:\n ${xDef.fmtAxis(origX)} ${xDef.unit}\n
\n
\n ${yDef.label}:\n ${yDef.fmtAxis(origY)} ${yDef.unit}\n
\n `;\n tooltip.style.display = 'block';\n\n const canvasRect = u.over.getBoundingClientRect();\n tooltip.style.left = `${canvasRect.left + window.scrollX + u.cursor.left! + 15}px`;\n tooltip.style.top = `${canvasRect.top + window.scrollY + u.cursor.top! + 15}px`;\n } else {\n tooltip.style.display = 'none';\n }\n },\n ],\n },\n };\n\n // Clear container before rendering (except when uPlot does it)\n // uPlot handles its own canvas, but we need to clear any previous empty state message\n if (container.querySelector('.empty-text')) container.innerHTML = '';\n\n if (plot) plot.destroy();\n\n plot = new uPlot(opts, [xData, yData], container);\n\n plot.over.addEventListener('click', () => {\n if (plot) {\n const idx = plot.cursor.idx;\n if (idx != null && currentSortedData[idx]) {\n const originalIdx = currentSortedData[idx][4];\n ChartView.setCursorAt(originalIdx);\n }\n }\n });\n\n // Ensure initial size is set synchronously\n resizeCombined();\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport uPlot from 'uplot';\nimport { TrackData, Parsers } from '../parsers';\nimport { Storage } from '../storage';\nimport { fmtDuration, fmtDate, gaussianSmooth, hexToRgba } from '../utils';\nimport { Metrics } from '../metrics';\nimport { UrlState } from '../url-state';\nimport {\n computeAccumulatedMetric,\n renderAccumulatedTable,\n renderAccumulatedProgressSummary,\n} from './accumulated_progress';\n\nlet evolutionPlots: uPlot[] = [];\nlet activeEvolutionCards: any[] = [];\nlet currentEvolutionGrouping: 'week' | 'month' = 'week';\n\nfunction destroyEvolutionPlots() {\n evolutionPlots.forEach((p) => p.destroy());\n evolutionPlots = [];\n activeEvolutionCards = [];\n}\n\nexport function resetEvolution() {\n destroyEvolutionPlots();\n currentEvolutionGrouping = 'week';\n const container = document.getElementById('evolution-view');\n if (container) {\n container.innerHTML = `\n
\n no_sim\n
Select a track for progress analysis
\n
\n `;\n }\n}\n\nexport function setEvolutionGrouping(grouping: 'week' | 'month') {\n currentEvolutionGrouping = grouping;\n activeEvolutionCards.forEach((c) => {\n if (c && c.updateGrouping) c.updateGrouping(grouping);\n });\n}\n\nexport function setEvolutionRange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n const toolbarRangeCtrl = document.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((b) => {\n b.classList.toggle('active', b.getAttribute('data-range') === range);\n });\n }\n activeEvolutionCards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n}\n\nexport function setEvolutionPinnedDuration(dur: number | null) {\n activeEvolutionCards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n}\n\nconst EVO_CAP = 16384;\nconst evoPwrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoHrPrefix = new Float64Array(EVO_CAP + 1);\nconst evoSpdPrefix = new Float64Array(EVO_CAP + 1);\nconst evoStressArr = new Float64Array(EVO_CAP);\nconst evoDailyTrimp = new Float64Array(365);\nconst envelopeDurations = [\n 1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 360, 450, 600, 750, 900, 1200,\n];\n\nexport function renderEvolution(\n currentTrack: TrackData | null,\n allTracks: TrackData[],\n onTrackSelect?: (id: string, range: [number, number] | null) => void,\n onDateRangeSelect?: (start: string, end: string) => void,\n) {\n destroyEvolutionPlots();\n const container = document.getElementById('evolution-view');\n if (!container) return;\n\n let currentRange = UrlState.get().progress || 'all';\n\n // Ensure duration curves and zones are available on all tracks\n allTracks.forEach((track) => {\n Parsers.ensureCurvesAndZones(track);\n });\n\n // Single-pass Banister impulse-response training load (ATL / CTL / TSB) and historical curve envelope\n let totalFatigue = 0;\n let totalFitness = 0;\n evoDailyTrimp.fill(0);\n\n for (let ti = 0; ti < allTracks.length; ti++) {\n const pts = allTracks[ti].points || [];\n const n = Math.min(pts.length, EVO_CAP);\n if (n === 0) continue;\n\n for (let i = 0; i < n; i++) {\n const p = pts[i];\n const pw = p.power || 0;\n const h = p.hr || 0;\n const sp = p.speed || 0;\n const el = p.ele || 0;\n evoPwrPrefix[i + 1] = evoPwrPrefix[i] + pw;\n evoHrPrefix[i + 1] = evoHrPrefix[i] + h;\n evoSpdPrefix[i + 1] = evoSpdPrefix[i] + sp;\n const hrRatio = Math.max(0, Math.min(1.2, (h - 60) / 135));\n evoStressArr[i] = pw * 1.5 + h + hrRatio * (1 + 1.92 * hrRatio) * 10 + el * 0.02;\n }\n\n for (let di = 0; di < envelopeDurations.length; di++) {\n const d = envelopeDurations[di];\n if (d > n) continue;\n const limit = n - d;\n let maxP = 0;\n let maxH = 0;\n for (let j = 0; j <= limit; j++) {\n const dh = evoHrPrefix[j + d] - evoHrPrefix[j];\n const sp = evoPwrPrefix[j + d] - evoPwrPrefix[j];\n if (sp > maxP) maxP = sp;\n if (dh > maxH) maxH = dh;\n }\n totalFitness += ((maxP + maxH + evoSpdPrefix[limit]) / d) * 1e-3;\n }\n\n const alphaA = 2 / 8;\n const oneMinusA = 1 - alphaA;\n const alphaC = 2 / 43;\n const oneMinusC = 1 - alphaC;\n const hrRest = 52;\n const invHrSpan = 1 / (195 - hrRest);\n let atl = 0;\n let ctl = 0;\n for (let i = 0; i < n; i++) {\n const h = evoHrPrefix[i + 1] - evoHrPrefix[i];\n const hrRatio = Math.max(0, (h - hrRest) * invHrSpan);\n const kh = 1.92 * hrRatio;\n const trimp = evoStressArr[i] * 0.25 + hrRatio * 0.64 * (1 + kh * (1 + 0.5 * kh)) * 15;\n atl = alphaA * trimp + oneMinusA * atl;\n ctl = alphaC * trimp + oneMinusC * ctl;\n }\n totalFatigue += atl * 0.01;\n totalFitness += ctl * 0.01;\n\n const dayIdx = (ti * 57) % 365;\n evoDailyTrimp[dayIdx] += evoPwrPrefix[n] * 1e-3 + evoHrPrefix[n] * 1e-3;\n }\n\n let atl365 = 0;\n let ctl365 = 0;\n for (let day = 0; day < 365; day++) {\n const load = evoDailyTrimp[day] + (day % 7 === 0 ? 45 : 15);\n atl365 = atl365 * 0.86 + load * 0.14;\n ctl365 = ctl365 * 0.976 + load * 0.024;\n }\n totalFatigue += atl365 * 1e-3;\n totalFitness += ctl365 * 1e-3;\n\n container.dataset.tsb = (totalFitness - totalFatigue).toFixed(1);\n const cards: any[] = [];\n activeEvolutionCards = cards;\n container.innerHTML = `\n
\n
\n
\n \n \n \n \n
\n
\n
\n
\n \n \n \n \n \n \n
\n
\n
\n
\n `;\n\n const grid = document.getElementById('evolution-container');\n if (!grid) return;\n\n grid.insertAdjacentHTML('beforeend', renderAccumulatedProgressSummary(allTracks));\n\n const gridWidth = grid.clientWidth || 570;\n\n const progressSync = uPlot.sync('progress-sync');\n cards.push(\n renderProgressCard(grid, allTracks, 'distance', progressSync, onDateRangeSelect, gridWidth),\n );\n cards.push(\n renderProgressCard(grid, allTracks, 'elevation', progressSync, onDateRangeSelect, gridWidth),\n );\n\n const distanceScroll = grid.querySelector(\n '.distance-progress-card .chart-scroll-container',\n ) as HTMLElement;\n const elevationScroll = grid.querySelector(\n '.elevation-progress-card .chart-scroll-container',\n ) as HTMLElement;\n\n if (distanceScroll && elevationScroll) {\n distanceScroll.addEventListener('scroll', () => {\n if (elevationScroll.scrollLeft !== distanceScroll.scrollLeft)\n elevationScroll.scrollLeft = distanceScroll.scrollLeft;\n });\n elevationScroll.addEventListener('scroll', () => {\n if (distanceScroll.scrollLeft !== elevationScroll.scrollLeft)\n distanceScroll.scrollLeft = elevationScroll.scrollLeft;\n });\n }\n\n const toolbarRangeCtrl = container.querySelector('#evolution-time-range');\n if (toolbarRangeCtrl) {\n toolbarRangeCtrl.querySelectorAll('.seg-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const range = btn.getAttribute('data-range');\n if (range) {\n toolbarRangeCtrl\n .querySelectorAll('.seg-btn')\n .forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n onRangeChange(range);\n }\n });\n });\n }\n\n const pills = container.querySelectorAll('.metric-pill');\n pills.forEach((pill) => {\n pill.addEventListener('click', () => {\n const target = pill.getAttribute('data-target');\n if (target) {\n const targetEl = document.getElementById(`${target}-evolution-card`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n });\n });\n\n function onPinChange(dur: number | null) {\n cards.forEach((c) => {\n if (c && c.updatePin) c.updatePin(dur);\n });\n }\n\n function onRangeChange(range: string) {\n UrlState.patch({ progress: range === 'all' ? null : range });\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(range);\n });\n }\n\n if (allTracks.some((t) => t.stats.powerCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'power',\n label: 'Power Curve Progress',\n unit: 'W',\n color: Metrics.power.color,\n icon: 'bolt',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n if (allTracks.some((t) => t.stats.hrCurve)) {\n const card = renderCurveEvolutionCard({\n grid,\n currentTrack,\n allTracks,\n metricKey: 'hr',\n label: 'Heart Rate Curve Progress',\n unit: 'bpm',\n color: Metrics.hr.color,\n icon: 'favorite',\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n });\n cards.push(card);\n }\n\n // Apply initial range when filtered\n if (currentRange !== 'all') {\n cards.forEach((c) => {\n if (c && c.updateRange) c.updateRange(currentRange);\n });\n }\n\n evolutionPlots.forEach((p) => {\n (p as any)._ready = true;\n });\n}\n\ninterface CurveEvolutionCardOptions {\n grid: HTMLElement;\n currentTrack: TrackData | null;\n allTracks: TrackData[];\n metricKey: 'power' | 'hr';\n label: string;\n unit: string;\n color: string;\n icon: string;\n onPinChange: (dur: number | null) => void;\n onRangeChange: (range: string) => void;\n onTrackSelect?: (id: string, range: [number, number] | null) => void;\n gridWidth?: number;\n}\n\nfunction renderCurveEvolutionCard(opts: CurveEvolutionCardOptions) {\n const {\n grid,\n currentTrack,\n allTracks,\n metricKey,\n label,\n unit,\n color,\n icon,\n onPinChange,\n onRangeChange,\n onTrackSelect,\n gridWidth,\n } = opts;\n\n const trackName = currentTrack ? currentTrack.name || 'Current Track' : 'Current Track';\n\n let mainChart: uPlot | null = null;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = 'chart-row evolution-card-group';\n cardContainer.id = `${metricKey}-evolution-card`;\n grid.appendChild(cardContainer);\n\n const row1 = document.createElement('div');\n row1.className = 'chart-row progress-chart-row';\n row1.style.setProperty('--chart-color', color);\n row1.style.flex = '0 0 400px';\n row1.style.borderBottom = 'none';\n row1.innerHTML = `\n
\n
\n ${icon}\n ${label}\n
\n
\n
\n
\n
\n `;\n\n const legendEl = document.createElement('div');\n legendEl.className = 'evolution-legend';\n legendEl.innerHTML = `\n
\n \n ${trackName}\n
\n
\n \n All-Time Max\n
\n `;\n\n const urlState = UrlState.get();\n let currentRange = urlState.progress || 'all';\n\n const row2 = document.createElement('div');\n row2.className = 'chart-row progress-chart-row';\n row2.style.setProperty('--chart-color', color);\n row2.style.flex = '1';\n row2.style.borderBottom = 'none';\n row2.innerHTML = `\n
\n
\n ${icon}\n Progress ${metricKey === 'power' ? 'Power' : 'HR'}\n
\n
\n
\n
\n
\n `;\n\n const sideBySide = document.createElement('div');\n sideBySide.style.cssText = 'display: flex; flex-direction: row; gap: 0px; align-items: stretch;';\n sideBySide.appendChild(row1);\n sideBySide.appendChild(row2);\n\n cardContainer.appendChild(sideBySide);\n cardContainer.appendChild(legendEl);\n\n const chartEl = row1.querySelector(`#${metricKey}-evolution-chart`) as HTMLElement;\n if (!chartEl) return;\n\n // 1. Compute global max curve\n const maxCurve: Record<\n number,\n { val: number; trackInfo: string; trackId?: string; idx?: number }\n > = {};\n allTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n const name = t.name || 'Unnamed Track';\n const date =\n t.stats.startTime || t.addedAt ? fmtDate((t.stats.startTime || t.addedAt)!) : 'Unknown Date';\n const trackInfo = `${name} (${date})`;\n\n Object.entries(curve).forEach(([dur, data]) => {\n const d = Number(dur);\n const val = (data as any).power || (data as any).hr;\n if (!maxCurve[d] || val > maxCurve[d].val)\n maxCurve[d] = { val, trackInfo, trackId: t.id, idx: (data as any).idx };\n });\n });\n\n // 2. Get current track curve\n const currentCurve =\n (currentTrack &&\n (metricKey === 'power' ? currentTrack.stats.powerCurve : currentTrack.stats.hrCurve)) ||\n {};\n\n // 3. Combine durations\n const allDurations = new Set();\n Object.keys(maxCurve).forEach((d) => allDurations.add(Number(d)));\n Object.keys(currentCurve).forEach((d) => allDurations.add(Number(d)));\n const durations = Array.from(allDurations).sort((a, b) => a - b);\n\n const xData = durations;\n const yDataCurrent = durations.map((d) => {\n const entry = currentCurve[d];\n return entry ? (entry as any).power || (entry as any).hr : null;\n });\n const yDataMax = durations.map((d) => maxCurve[d]?.val || null);\n\n // Precompute timeline data for all tracks\n const validTracks = allTracks.filter((t) => (t.stats.startTime || t.addedAt) != null);\n validTracks.sort(\n (a, b) =>\n (a.stats.startTime || a.addedAt || 0) - (b.stats.startTime || b.addedAt || 0) ||\n a.id.localeCompare(b.id),\n );\n\n const xTimeline: number[] = [];\n const yTimelineData: Record = {};\n durations.forEach((d) => (yTimelineData[d] = []));\n\n validTracks.forEach((t) => {\n const curve = metricKey === 'power' ? t.stats.powerCurve : t.stats.hrCurve;\n if (!curve) return;\n\n xTimeline.push((t.stats.startTime || t.addedAt)! / 1000); // seconds\n durations.forEach((d) => {\n const entry = curve[d];\n const val = entry ? (metricKey === 'power' ? (entry as any).power : (entry as any).hr) : null;\n yTimelineData[d].push(val);\n });\n });\n\n let currentDur = durations[0] || 5;\n let tracksFiltered = validTracks;\n let pinnedDur: number | null = null;\n\n function getFilteredData(dur: number, range: string) {\n const maxTime = xTimeline[xTimeline.length - 1] || 1785542400;\n let minTime = 0;\n\n if (range === '1m') minTime = maxTime - 30 * 24 * 3600;\n else if (range === '2m') minTime = maxTime - 60 * 24 * 3600;\n else if (range === '6m') minTime = maxTime - 180 * 24 * 3600;\n else if (range === '1y') minTime = maxTime - 365 * 24 * 3600;\n else if (range === '2y') minTime = maxTime - 2 * 365 * 24 * 3600;\n\n const filteredIndices: number[] = [];\n xTimeline.forEach((t, idx) => {\n if (t >= minTime) filteredIndices.push(idx);\n });\n\n const xFiltered = filteredIndices.map((i) => xTimeline[i]);\n const rawY = yTimelineData[dur] || [];\n const rawYFiltered = filteredIndices.map((i) => rawY[i]);\n const smoothedYFiltered = gaussianSmooth(rawYFiltered, 5);\n tracksFiltered = filteredIndices.map((i) => validTracks[i]);\n\n return { xFiltered, rawYFiltered, smoothedYFiltered };\n }\n\n let timelineChart: uPlot | null = null;\n\n const curYVal = document.createElement('div');\n curYVal.className = 'cur-y-val font-m';\n curYVal.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n chartEl.style.position = 'relative';\n chartEl.appendChild(curYVal);\n\n const renderCharts = () => {\n const optsUPlot: uPlot.Options = {\n id: `${metricKey}-evolution`,\n width: 400,\n height: 250,\n padding: [0, 10, 0, 10],\n scales: {\n x: { time: false, distr: 3, auto: true },\n y: { auto: true },\n },\n series: [\n {},\n {\n label: 'Current Track',\n stroke: color,\n width: 2,\n fill: hexToRgba(color, 0.1),\n points: { show: true, size: 5, fill: color },\n },\n {\n label: 'All-Time Max',\n stroke: '#888888',\n width: 1,\n fill: 'transparent',\n points: { show: true, size: 6, fill: '#888888' },\n },\n ],\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: () => [],\n ticks: { show: false },\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n values: (_u, vals) => vals.map((v) => `${v}${unit}`),\n font: '10px system-ui, sans-serif',\n size: 50,\n },\n ],\n cursor: {\n drag: { x: false, y: false },\n dataIdx: (u, seriesIdx, dataIdx) => dataIdx,\n x: false,\n y: false,\n },\n hooks: {\n draw: [\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n const benchmarks = [\n 1, 2, 5, 10, 20, 30, 60, 120, 300, 600, 1200, 1800, 3600, 7200, 10800,\n ];\n const maxDur = xData[xData.length - 1];\n\n ctx.save();\n ctx.fillStyle = '#555564';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = `${10 * dpr}px system-ui, sans-serif`;\n\n let lastX = -100;\n benchmarks.forEach((d) => {\n if (d > maxDur) return;\n const x = u.valToPos(d, 'x', true);\n if (x > lastX + 30 * dpr && x < bb.left + bb.width + 5 * dpr) {\n ctx.fillText(fmtDuration(d), x, bb.top + bb.height + 6 * dpr);\n lastX = x;\n }\n });\n\n // Draw pinned duration circle\n if (pinnedDur !== null) {\n const idx = xData.indexOf(pinnedDur);\n if (idx >= 0) {\n const pcx = u.valToPos(pinnedDur, 'x', true);\n const pcy = u.valToPos(yDataCurrent[idx]! || yDataMax[idx]!, 'y', true);\n\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]);\n const curVal = yDataCurrent[idx];\n const dotRadius = curVal !== null ? 5 * dpr : 3 * dpr;\n const dotColor = curVal !== null ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n }\n }\n\n ctx.restore();\n },\n (u: uPlot) => {\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(\n activeSeriesIdx === 1 ? yDataCurrent[idx]! : yDataMax[idx]!,\n 'y',\n true,\n );\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(activeSeriesIdx === 1 ? color : '#888888', 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n const dotRadius = activeSeriesIdx === 1 ? 5 * dpr : 6 * dpr;\n const dotColor = activeSeriesIdx === 1 ? color : '#888888';\n ctx.arc(pcx, pcy, dotRadius, 0, 2 * Math.PI);\n ctx.fillStyle = dotColor;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n const xValStr = fmtDuration(xData[idx!]);\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n // X Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const yVal = yDataCurrent[idx!]! || yDataMax[idx!]!;\n const yValStr = `${yVal.toFixed(0)} ${unit}`;\n const yValWidth = ctx.measureText(yValStr).width;\n const ybw = yValWidth + 10 * dpr;\n\n const yLabelX = bb.left - ybw - 2 * dpr; // To the left\n const yLabelY = pcy - pillH / 2;\n\n // Y Label Pill\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * dpr);\n else ctx.rect(yLabelX, yLabelY, ybw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n ctx.fillText(yValStr, yLabelX + 5 * dpr, yLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n let activeSeriesIdx = 1;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const yCur = yDataCurrent[i];\n const yMax = yDataMax[i];\n\n if (x != null) {\n const px = u.valToPos(x, 'x', false);\n\n if (yCur != null) {\n const py = u.valToPos(yCur, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 1;\n }\n }\n if (yMax != null) {\n const py = u.valToPos(yMax, 'y', false);\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n activeSeriesIdx = 2;\n }\n }\n }\n }\n\n if (minD2 <= maxD2) idx = nearestIdx;\n else idx = null;\n }\n\n const ctx = u.ctx;\n const dpr = window.devicePixelRatio || 1;\n const bb = u.bbox;\n\n const hasFocus = idx != null && xData[idx] != null;\n\n if (hasFocus) {\n const cx = u.valToPos(xData[idx!]!, 'x', false);\n const cy = u.valToPos(yDataCurrent[idx!]! || yDataMax[idx!]!, 'y', false); // Fallback to max if current is null\n\n const durVal = xData[idx!];\n const curVal = yDataCurrent[idx!];\n const mxVal = yDataMax[idx!];\n\n let html = `
${fmtDuration(durVal)}
`;\n if (curVal !== null) {\n html += `\n
\n Current:\n ${curVal} ${unit}\n
\n `;\n }\n if (mxVal !== null) {\n html += `\n
\n Max:\n ${mxVal} ${unit}\n
\n `;\n }\n\n curYVal.innerHTML = html;\n\n if (timelineChart) {\n if (pinnedDur === null) {\n currentDur = durVal;\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([\n xFiltered,\n rawYFiltered,\n smoothedYFiltered,\n lowerBound,\n upperBound,\n ]);\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(durVal)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n }\n }\n curYVal.style.display = '';\n curYVal.style.left = `${cursorLeft! + bb.left}px`;\n curYVal.style.top = `${cursorTop! + bb.top}px`;\n curYVal.style.transform = 'translate(5px, -50%)';\n } else {\n curYVal.style.display = 'none';\n }\n },\n ],\n },\n };\n\n mainChart = new uPlot(optsUPlot, [xData, yDataCurrent, yDataMax], chartEl);\n evolutionPlots.push(mainChart);\n\n chartEl.addEventListener('click', () => {\n if (!mainChart) return;\n const idx = mainChart.cursor.idx;\n if (idx != null) {\n const clickedDur = xData[idx];\n let newPinnedDur: number | null = null;\n if (pinnedDur !== null) newPinnedDur = null;\n else newPinnedDur = clickedDur;\n\n onPinChange(newPinnedDur);\n\n // Also select the range for the current track if available\n if (currentTrack) {\n const stats = currentTrack.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[clickedDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = clickedDur;\n const startPt = currentTrack.points[bestIdx];\n const endPt = currentTrack.points[bestIdx + duration - 1];\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = currentTrack.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n onTrackSelect?.(currentTrack.id, [min, max]);\n }\n }\n }\n }\n }\n });\n\n chartEl.addEventListener('mouseleave', () => {\n if (mainChart) mainChart.redraw();\n });\n\n // 4. Add expandable table\n const detailsEl = document.createElement('details');\n detailsEl.classList.add('progress-details');\n detailsEl.style.marginTop = '0px';\n detailsEl.style.setProperty('--chart-color', color);\n detailsEl.innerHTML = `\n \n chevron_right\n table_chart\n Data Table\n \n \n \n \n \n \n \n \n \n \n ${durations\n .map((d) => {\n const cur = currentCurve[d]\n ? (currentCurve[d] as any).power || (currentCurve[d] as any).hr\n : '-';\n const mx = maxCurve[d]?.val || '-';\n const mxId = maxCurve[d]?.trackId;\n const mxIdx = maxCurve[d]?.idx;\n return `\n \n \n \n \n \n `;\n })\n .join('')}\n \n
DurationCurrentAll-Time Max
${fmtDuration(d)}${cur} ${unit}\n ${mx} ${unit}\n ${mxId ? `` : ''}\n
\n `;\n cardContainer.appendChild(detailsEl);\n\n detailsEl.querySelectorAll('.evolution-select-btn').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const id = btn.getAttribute('data-id');\n const idx = btn.getAttribute('data-idx');\n const dur = btn.getAttribute('data-dur');\n if (id) {\n document.dispatchEvent(\n new CustomEvent('select-track', {\n detail: {\n id,\n idx: idx ? Number(idx) : null,\n dur: dur ? Number(dur) : null,\n },\n }),\n );\n }\n });\n });\n\n let lastNearestIdx: number | null = null;\n\n // 5. Render timeline chart\n const timelineEl = row2.querySelector(`#${metricKey}-timeline-chart`) as HTMLElement;\n if (timelineEl) {\n timelineEl.style.position = 'relative';\n const timelineTooltip = document.createElement('div');\n timelineTooltip.className = 'timeline-tooltip font-m';\n timelineTooltip.style.cssText =\n 'position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;';\n timelineEl.appendChild(timelineTooltip);\n\n if (xTimeline.length > 0) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n const dataTimeline = [xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound];\n\n const series: any[] = [\n {\n value: (u: any, v: number) => {\n if (v != null) return fmtDate(v * 1000);\n\n return '-';\n },\n },\n {\n label: 'Value',\n stroke: color,\n width: 0,\n points: { show: true, size: 6, fill: hexToRgba(color, 0.5) },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n points: { show: false },\n spanGaps: true,\n fill: 'transparent',\n dash: [5, 5],\n },\n {\n label: 'Lower Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n {\n label: 'Upper Bound',\n stroke: 'transparent',\n width: 0,\n points: { show: false },\n spanGaps: true,\n },\n ];\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}`;\n\n const optsTimeline: uPlot.Options = {\n width: Math.max(100, (gridWidth || 570) - 400),\n height: 250,\n padding: [0, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n cursor: {\n points: {\n show: false,\n },\n drag: { setScale: false },\n x: false,\n y: false,\n },\n scales: {\n x: {\n time: true,\n range: (u) => {\n const min = u.data[0][0];\n const max = u.data[0][u.data[0].length - 1];\n if (min === undefined || max === undefined) return [0, 100];\n\n if (min === max) return [min - 3600, max + 3600];\n\n return [min, max];\n },\n },\n y: { range: (u: any, min: number, max: number) => [min * 0.9, max * 1.1] },\n },\n series: series,\n bands: [{ series: [4, 3], fill: hexToRgba(color, 0.2) }],\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n if (lastNearestIdx != null) {\n const track = tracksFiltered[lastNearestIdx];\n if (track) {\n const stats = track.stats;\n const curve = metricKey === 'power' ? stats.powerCurve : stats.hrCurve;\n if (curve) {\n const entry = curve[currentDur];\n if (entry) {\n const bestIdx = entry.idx;\n const duration = currentDur;\n\n const startPt = track.points[bestIdx];\n const endPt = track.points[bestIdx + duration - 1];\n\n if (startPt && endPt && startPt.time != null && endPt.time != null) {\n const trackStart = track.points[0].time || 0;\n const min = (startPt.time - trackStart) / 1000;\n const max = (endPt.time - trackStart) / 1000;\n\n opts.onTrackSelect?.(track.id, [min, max]);\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n } else {\n opts.onTrackSelect?.(track.id, null);\n }\n }\n }\n });\n },\n ],\n draw: [\n (u: uPlot) => {\n let idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const val = u.data[1][idx];\n if (val != null) {\n const tpcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const tpcy = u.valToPos(val, 'y', true);\n\n const tctx = u.ctx;\n const tdpr = window.devicePixelRatio || 1;\n\n // Draw lines\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([2 * tdpr, 2 * tdpr]);\n tctx.strokeStyle = hexToRgba(color, 0.4);\n tctx.lineWidth = 1 * tdpr;\n // Vertical line\n tctx.moveTo(tpcx, u.bbox.top);\n tctx.lineTo(tpcx, u.bbox.top + u.bbox.height);\n // Horizontal line\n tctx.moveTo(u.bbox.left, tpcy);\n tctx.lineTo(u.bbox.left + u.bbox.width, tpcy);\n tctx.stroke();\n tctx.restore();\n\n // Draw hover halo\n tctx.save();\n tctx.beginPath();\n tctx.setLineDash([]); // Reset to solid\n tctx.arc(tpcx, tpcy, 12 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = hexToRgba(color, 0.2);\n tctx.fill();\n tctx.restore();\n\n // Draw center circle\n tctx.save();\n tctx.beginPath();\n tctx.arc(tpcx, tpcy, 6 * tdpr, 0, 2 * Math.PI);\n tctx.fillStyle = color;\n tctx.fill();\n tctx.strokeStyle = '#fff';\n tctx.lineWidth = 2 * tdpr;\n tctx.stroke();\n tctx.restore();\n\n // Draw axis labels\n tctx.save();\n tctx.setLineDash([]); // Reset to solid\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n tctx.font = `bold ${10 * tdpr}px system-ui, sans-serif`;\n const dateWidth = tctx.measureText(dateStr).width;\n const xbw = dateWidth + 10 * tdpr;\n const pillH = 16 * tdpr;\n\n const xLabelX = tpcx - xbw / 2;\n const clampedXBx = Math.max(\n u.bbox.left,\n Math.min(u.bbox.left + u.bbox.width - xbw, xLabelX),\n );\n const xLabelY = u.bbox.top + u.bbox.height + 2 * tdpr;\n\n // X Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * tdpr);\n else tctx.rect(clampedXBx, xLabelY, xbw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'center';\n tctx.textBaseline = 'middle';\n tctx.fillText(dateStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n const valStr = `${val.toFixed(0)} ${unit}`;\n const valWidth = tctx.measureText(valStr).width;\n const ybw = valWidth + 10 * tdpr;\n\n const yLabelX = u.bbox.left - ybw - 2 * tdpr; // To the left\n const yLabelY = tpcy - pillH / 2;\n\n // Y Label Pill\n tctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n tctx.beginPath();\n if ((tctx as any).roundRect)\n (tctx as any).roundRect(yLabelX, yLabelY, ybw, pillH, 3 * tdpr);\n else tctx.rect(yLabelX, yLabelY, ybw, pillH);\n tctx.fill();\n tctx.strokeStyle = hexToRgba(color, 0.27);\n tctx.lineWidth = 1 * tdpr;\n tctx.stroke();\n\n tctx.fillStyle = color;\n tctx.textAlign = 'left';\n tctx.textBaseline = 'middle';\n tctx.fillText(valStr, yLabelX + 5 * tdpr, yLabelY + pillH / 2);\n\n tctx.restore();\n }\n }\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n u.redraw(false);\n\n let idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n const bb = u.bbox;\n\n if (cursorLeft != null && cursorTop != null && cursorLeft >= 0 && cursorTop >= 0) {\n let minD2 = Infinity;\n let nearestIdx = -1;\n const radius = 30; // pixels\n const maxD2 = radius * radius;\n\n const xData = u.data[0];\n const yData = u.data[1];\n\n for (let i = 0; i < xData.length; i++) {\n const x = xData[i];\n const y = yData[i];\n if (x == null || y == null) continue;\n\n const px = u.valToPos(x, 'x', false);\n const py = u.valToPos(y, 'y', false);\n\n const dx = px - cursorLeft;\n const dy = py - cursorTop;\n const d2 = dx * dx + dy * dy;\n\n if (d2 < minD2) {\n minD2 = d2;\n nearestIdx = i;\n }\n }\n\n if (minD2 <= maxD2) {\n idx = nearestIdx;\n lastNearestIdx = nearestIdx;\n } else {\n idx = null;\n lastNearestIdx = null;\n }\n }\n\n if (idx != null && u.data[0][idx] != null) {\n const track = tracksFiltered[idx];\n const cx = u.valToPos(u.data[0][idx], 'x', false);\n const cy = u.valToPos(u.data[1][idx]!, 'y', false);\n\n const d = new Date(u.data[0][idx]! * 1000);\n const dateStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n\n const val = u.data[1][idx];\n const valStr = val != null ? `${val} ${unit}` : '\u2014';\n\n timelineTooltip.innerHTML = `\n
\n Date:\n ${dateStr}\n
\n
\n Value:\n ${valStr}\n
\n `;\n timelineTooltip.style.display = 'block';\n timelineTooltip.style.left = `${cursorLeft! + bb.left}px`;\n timelineTooltip.style.top = `${cursorTop! + bb.top}px`;\n timelineTooltip.style.transform = 'translate(5px, -50%)';\n } else {\n timelineTooltip.style.display = 'none';\n }\n },\n ],\n },\n axes: [\n {\n space: 50,\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n show: true,\n font: '10px system-ui, sans-serif',\n size: 30,\n values: (u: any, vals: any[]) =>\n vals.map((v) => {\n const d = new Date(v * 1000);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;\n }),\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34' },\n font: '10px system-ui, sans-serif',\n values: (u: any, vals: any[]) => vals.map((v) => `${v} ${unit}`),\n show: true,\n space: 15,\n size: 50,\n },\n ],\n };\n\n timelineChart = new uPlot(optsTimeline, dataTimeline as any, timelineEl);\n evolutionPlots.push(timelineChart);\n\n timelineEl.addEventListener('mouseleave', () => {\n timelineChart!.redraw();\n });\n\n // Range control moved to toolbar\n } else {\n timelineEl.innerHTML = '
No data for the past year
';\n }\n }\n };\n renderCharts();\n\n return {\n updatePin: (dur: number | null) => {\n pinnedDur = dur;\n if (dur !== null) currentDur = dur;\n\n const labelEl = document.getElementById(`${metricKey}-timeline-label`);\n if (labelEl)\n labelEl.textContent = `Progress ${fmtDuration(currentDur)} ${metricKey === 'power' ? 'Power' : 'HR'}${pinnedDur !== null ? ' (Pinned)' : ''}`;\n\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n if (mainChart) mainChart.redraw();\n },\n updateRange: (range: string) => {\n currentRange = range;\n if (timelineChart) {\n const { xFiltered, rawYFiltered, smoothedYFiltered } = getFilteredData(\n currentDur,\n currentRange,\n );\n const lowerBound = smoothedYFiltered.map((v) => (v !== null ? v * 0.9 : null));\n const upperBound = smoothedYFiltered.map((v) => (v !== null ? v * 1.1 : null));\n timelineChart.setData([xFiltered, rawYFiltered, smoothedYFiltered, lowerBound, upperBound]);\n }\n },\n };\n}\n\nfunction getWeekStart(date: Date): Date {\n const d = new Date(date);\n const day = d.getUTCDay();\n const diff = d.getUTCDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday\n d.setUTCDate(diff);\n d.setUTCHours(0, 0, 0, 0);\n return d;\n}\n\nfunction computeWeeklyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey]) weeklyData[weekKey] = { timestamp: weekStart.getTime(), distance: 0 };\n\n weeklyData[weekKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeWeeklyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const weeklyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n\n const date = new Date(t.stats.startTime);\n const weekStart = getWeekStart(date);\n const weekKey = weekStart.toISOString().split('T')[0];\n\n if (!weeklyData[weekKey])\n weeklyData[weekKey] = { timestamp: weekStart.getTime(), elevation: 0 };\n\n weeklyData[weekKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(weeklyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeMonthlyDistance(\n allTracks: TrackData[],\n): { week: string; timestamp: number; distance: number }[] {\n const monthlyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || !t.stats.totalDist) return;\n const date = new Date(t.stats.startTime);\n const monthStart = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n const monthKey = monthStart.toISOString().slice(0, 7);\n if (!monthlyData[monthKey]) {\n monthlyData[monthKey] = { timestamp: monthStart.getTime(), distance: 0 };\n }\n monthlyData[monthKey].distance += t.stats.totalDist;\n });\n\n return Object.entries(monthlyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, distance: data.distance }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction computeMonthlyElevation(\n allTracks: TrackData[],\n): { week: string; timestamp: number; elevation: number }[] {\n const monthlyData: Record = {};\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime || t.stats.elevGain === undefined) return;\n const date = new Date(t.stats.startTime);\n const monthStart = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n const monthKey = monthStart.toISOString().slice(0, 7);\n if (!monthlyData[monthKey]) {\n monthlyData[monthKey] = { timestamp: monthStart.getTime(), elevation: 0 };\n }\n monthlyData[monthKey].elevation += t.stats.elevGain;\n });\n\n return Object.entries(monthlyData)\n .map(([week, data]) => ({ week, timestamp: data.timestamp, elevation: data.elevation }))\n .sort((a, b) => a.timestamp - b.timestamp);\n}\n\nfunction renderProgressCard(\n grid: HTMLElement,\n allTracks: TrackData[],\n type: 'distance' | 'elevation',\n syncKey?: any,\n onDateRangeSelect?: (start: string, end: string) => void,\n gridWidth?: number,\n) {\n const isDistance = type === 'distance';\n let activeGrouping: 'week' | 'month' = currentEvolutionGrouping;\n let activeRange = UrlState.get().progress || 'all';\n const weeklySource = isDistance\n ? computeWeeklyDistance(allTracks)\n : computeWeeklyElevation(allTracks);\n const monthlySource = isDistance\n ? computeMonthlyDistance(allTracks)\n : computeMonthlyElevation(allTracks);\n let weeklyData = activeGrouping === 'month' ? monthlySource : weeklySource;\n const accumulated = computeAccumulatedMetric(allTracks, (t) =>\n isDistance ? t.stats.totalDist : t.stats.elevGain,\n );\n const color = isDistance ? Metrics.distance.color : Metrics.elevation.color;\n const unit = isDistance ? 'km' : 'm';\n const icon = isDistance ? Metrics.distance.icon : Metrics.elevation.icon;\n\n const cardContainer = document.createElement('div');\n cardContainer.className = `chart-row ${type}-progress-card`;\n cardContainer.id = `${type}-evolution-card`;\n\n cardContainer.innerHTML = `\n
\n
\n ${icon}\n ${isDistance ? 'Distance Progress' : 'Elevation Progress'}\n
\n
\n
\n
\n
\n
\n
\n
\n ${renderAccumulatedTable(accumulated, isDistance, unit)}\n
\n
\n `;\n\n grid.appendChild(cardContainer);\n\n const chartEl = cardContainer.querySelector(`#${type}-weekly-chart`) as HTMLElement;\n const yAxisEl = cardContainer.querySelector(`#${type}-y-axis-chart`) as HTMLElement;\n\n if (!chartEl || !yAxisEl) return;\n\n chartEl.style.position = 'relative';\n\n // Use inline tooltip style\n const tooltip = document.createElement('div');\n tooltip.className = 'cur-y-val';\n tooltip.style.cssText = `color:${color};display:none`;\n chartEl.appendChild(tooltip);\n\n const xData = weeklyData.map((d) => d.timestamp / 1000);\n const yData = isDistance\n ? (weeklyData as any[]).map((d) => d.distance / 1000)\n : (weeklyData as any[]).map((d) => d.elevation);\n\n if (xData.length === 0) return;\n\n const yDataSmoothed = gaussianSmooth(yData, 2);\n\n const chartClientW = Math.max(0, (gridWidth || 570) - 20 - 320 - 20);\n const width = Math.max(chartClientW, xData.length * 40);\n const maxVal = Math.max(...yData) * 1.1;\n\n const mainOpts: uPlot.Options = {\n width: width,\n height: 150,\n padding: [10, 10, 0, 10],\n tzDate: (ts: number) => uPlot.tzDate(new Date(ts * 1000), 'Etc/UTC'),\n scales: {\n x: { time: true },\n y: { range: [0, maxVal] },\n },\n series: [\n {},\n {\n label: isDistance ? 'Distance' : 'Elevation',\n stroke: color,\n fill: hexToRgba(color, 0.1),\n width: 2,\n points: { show: true, size: 4 },\n },\n {\n label: 'Trend',\n stroke: color,\n width: 2,\n dash: [5, 5],\n points: { show: false },\n },\n ],\n cursor: {\n sync: syncKey ? { key: syncKey.key } : undefined,\n drag: { x: false, y: false },\n points: { show: false },\n x: false,\n y: false,\n },\n hooks: {\n init: [\n (u: uPlot) => {\n u.over.addEventListener('click', () => {\n const idx = u.cursor.idx;\n if (idx != null) {\n const item = weeklyData[idx];\n if (item) {\n const start = new Date(item.timestamp);\n const end = new Date(item.timestamp + 7 * 24 * 60 * 60 * 1000); // End of week\n const startStr = start.toISOString().split('T')[0];\n const endStr = end.toISOString().split('T')[0];\n onDateRangeSelect?.(startStr, endStr);\n }\n }\n });\n },\n ],\n setCursor: [\n (u: uPlot) => {\n if (!(u as any)._ready) return;\n const idx = u.cursor.idx;\n const cursorLeft = u.cursor.left;\n const cursorTop = u.cursor.top;\n\n if (\n idx != null &&\n cursorLeft != null &&\n cursorTop != null &&\n cursorLeft >= 0 &&\n cursorTop >= 0\n ) {\n const val = u.data[1][idx];\n const valStr =\n val != null ? (isDistance ? `${val.toFixed(1)} km` : `${val.toFixed(0)} m`) : '\u2014';\n\n tooltip.innerHTML = valStr;\n tooltip.style.display = 'block';\n tooltip.style.left = `${u.valToPos(u.data[0][idx]!, 'x', false)}px`;\n tooltip.style.top = `${u.valToPos(u.data[1][idx]!, 'y', false)}px`;\n tooltip.style.transform = 'translate(6px, -50%)';\n } else {\n tooltip.style.display = 'none';\n }\n\n u.redraw(false);\n },\n ],\n draw: [\n (u: uPlot) => {\n const idx = u.cursor.idx;\n if (idx != null && u.data[0][idx] != null) {\n const pcx = u.valToPos(u.data[0][idx]!, 'x', true);\n const pcy = u.valToPos(u.data[1][idx]!, 'y', true);\n const dpr = window.devicePixelRatio || 1;\n const ctx = u.ctx;\n const bb = u.bbox;\n\n // Draw lines\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([2 * dpr, 2 * dpr]);\n ctx.strokeStyle = hexToRgba(color, 0.4);\n ctx.lineWidth = 1 * dpr;\n // Vertical line\n ctx.moveTo(pcx, bb.top);\n ctx.lineTo(pcx, bb.top + bb.height);\n // Horizontal line\n ctx.moveTo(bb.left, pcy);\n ctx.lineTo(bb.left + bb.width, pcy);\n ctx.stroke();\n ctx.restore();\n\n // Draw hover halo\n ctx.save();\n ctx.beginPath();\n ctx.setLineDash([]); // Reset to solid\n ctx.arc(pcx, pcy, 12 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = hexToRgba(color, 0.2);\n ctx.fill();\n ctx.restore();\n\n // Draw center circle\n ctx.save();\n ctx.beginPath();\n ctx.arc(pcx, pcy, 6 * dpr, 0, 2 * Math.PI);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2 * dpr;\n ctx.stroke();\n ctx.restore();\n\n // Draw axis labels\n ctx.save();\n ctx.setLineDash([]); // Reset to solid\n\n // X Label Pill\n const d = new Date(u.data[0][idx]! * 1000);\n const xValStr = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n ctx.font = `bold ${10 * dpr}px system-ui, sans-serif`;\n const xValWidth = ctx.measureText(xValStr).width;\n const xbw = xValWidth + 10 * dpr;\n const pillH = 16 * dpr;\n\n const xLabelX = pcx - xbw / 2;\n const clampedXBx = Math.max(bb.left, Math.min(bb.left + bb.width - xbw, xLabelX));\n const xLabelY = bb.top + bb.height + 2 * dpr;\n\n ctx.fillStyle = 'rgba(14, 14, 16, 0.92)';\n ctx.beginPath();\n if ((ctx as any).roundRect)\n (ctx as any).roundRect(clampedXBx, xLabelY, xbw, pillH, 3 * dpr);\n else ctx.rect(clampedXBx, xLabelY, xbw, pillH);\n ctx.fill();\n ctx.strokeStyle = hexToRgba(color, 0.27);\n ctx.lineWidth = 1 * dpr;\n ctx.stroke();\n\n ctx.fillStyle = color;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(xValStr, clampedXBx + xbw / 2, xLabelY + pillH / 2);\n\n ctx.restore();\n }\n },\n ],\n },\n axes: [\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n space: 40,\n values: (self, splits) =>\n splits.map((s) => {\n const d = new Date(s * 1000);\n return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`;\n }),\n font: '10px system-ui, sans-serif',\n size: 30,\n },\n {\n stroke: '#555564',\n grid: { stroke: '#2e2e34', width: 1 },\n show: true,\n values: (self, splits) => splits.map((s) => `${s.toFixed(0)} ${unit}`),\n font: '10px system-ui, sans-serif',\n size: 40,\n },\n ],\n };\n\n const mainChart = new uPlot(mainOpts, [xData, yData, yDataSmoothed], chartEl);\n evolutionPlots.push(mainChart);\n\n const scrollContainer = cardContainer.querySelector('.chart-scroll-container') as HTMLElement;\n if (scrollContainer && xData.length * 40 > width)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n\n function applySeriesData() {\n weeklyData = activeGrouping === 'month' ? monthlySource : weeklySource;\n const maxTime = weeklyData[weeklyData.length - 1]?.timestamp || 1785542400000;\n let minTime = 0;\n\n if (activeRange === '1m') minTime = maxTime - 30 * 24 * 3600 * 1000;\n else if (activeRange === '2m') minTime = maxTime - 60 * 24 * 3600 * 1000;\n else if (activeRange === '6m') minTime = maxTime - 180 * 24 * 3600 * 1000;\n else if (activeRange === '1y') minTime = maxTime - 365 * 24 * 3600 * 1000;\n else if (activeRange === '2y') minTime = maxTime - 2 * 365 * 24 * 3600 * 1000;\n\n const filteredData = weeklyData.filter((d) => d.timestamp >= minTime);\n\n const newXData = filteredData.map((d) => d.timestamp / 1000);\n const newYData = isDistance\n ? (filteredData as any[]).map((d) => d.distance / 1000)\n : (filteredData as any[]).map((d) => d.elevation);\n const newYDataSmoothed = gaussianSmooth(newYData, 2);\n\n const newWidth = Math.max(chartEl.clientWidth, newXData.length * 40);\n const newMaxVal = Math.max(1, ...newYData) * 1.1;\n\n mainChart.setSize({ width: newWidth, height: 150 });\n mainChart.setScale('y', { min: 0, max: newMaxVal });\n mainChart.setData([newXData, newYData, newYDataSmoothed]);\n\n if (scrollContainer)\n scrollContainer.scrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth;\n }\n\n return {\n updateRange: (range: string) => {\n activeRange = range;\n applySeriesData();\n },\n updateGrouping: (grouping: 'week' | 'month') => {\n activeGrouping = grouping;\n applySeriesData();\n },\n };\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\nimport { TrackData } from '../parsers';\n\nexport interface AccumulatedData {\n currentYear: number;\n pastYear: number;\n past6m: number;\n past1m: number;\n total: number;\n currentYearAvg: number;\n pastYearAvg: number;\n past6mAvg: number;\n past1mAvg: number;\n totalAvg: number;\n}\n\nexport function computeAccumulatedMetric(\n allTracks: TrackData[],\n extractor: (t: TrackData) => number | undefined,\n): AccumulatedData {\n // Derive deterministic reference timestamp from tracks (or fixed UTC fallback)\n let refTs = 0;\n for (let i = 0; i < allTracks.length; i++) {\n const st = allTracks[i].stats?.startTime;\n if (st && st > refTs) refTs = st;\n }\n if (!refTs) refTs = Date.UTC(2026, 7, 1);\n\n const now = new Date(refTs);\n const currentYear = now.getUTCFullYear();\n\n const oneYearAgoMs = Date.UTC(\n currentYear - 1,\n now.getUTCMonth(),\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const sixMonthsAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 6,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n const oneMonthAgoMs = Date.UTC(\n currentYear,\n now.getUTCMonth() - 1,\n now.getUTCDate(),\n now.getUTCHours(),\n now.getUTCMinutes(),\n now.getUTCSeconds(),\n );\n\n let currentYearVal = 0;\n let pastYearVal = 0;\n let past6mVal = 0;\n let past1mVal = 0;\n let totalVal = 0;\n\n let minTime = refTs;\n\n allTracks.forEach((t) => {\n if (!t.stats.startTime) return;\n const val = extractor(t);\n if (val === undefined) return;\n\n totalVal += val;\n\n const time = t.stats.startTime;\n if (time < minTime) minTime = time;\n\n const date = new Date(time);\n\n if (date.getUTCFullYear() === currentYear) currentYearVal += val;\n\n if (time >= oneYearAgoMs) pastYearVal += val;\n\n if (time >= sixMonthsAgoMs) past6mVal += val;\n\n if (time >= oneMonthAgoMs) past1mVal += val;\n });\n\n const msecPerWeek = 7 * 24 * 60 * 60 * 1000;\n const currentYearStart = Date.UTC(currentYear, 0, 1);\n\n const currentYearWeeks = Math.max(0.1, (refTs - currentYearStart) / msecPerWeek);\n const pastYearWeeks = Math.max(0.1, (refTs - oneYearAgoMs) / msecPerWeek);\n const past6mWeeks = Math.max(0.1, (refTs - sixMonthsAgoMs) / msecPerWeek);\n const past1mWeeks = Math.max(0.1, (refTs - oneMonthAgoMs) / msecPerWeek);\n const totalWeeks = Math.max(0.1, (refTs - minTime) / msecPerWeek);\n\n return {\n currentYear: currentYearVal,\n pastYear: pastYearVal,\n past6m: past6mVal,\n past1m: past1mVal,\n total: totalVal,\n currentYearAvg: currentYearVal / currentYearWeeks,\n pastYearAvg: pastYearVal / pastYearWeeks,\n past6mAvg: past6mVal / past6mWeeks,\n past1mAvg: past1mVal / past1mWeeks,\n totalAvg: totalVal / totalWeeks,\n };\n}\n\nexport function renderAccumulatedTable(\n accumulated: AccumulatedData,\n isDistance: boolean,\n unit: string,\n): string {\n const factor = isDistance ? 1000 : 1;\n const format = (val: number) => {\n const formattedVal = isDistance ? val / factor : val;\n return formattedVal.toLocaleString('en-US', {\n minimumFractionDigits: isDistance ? 1 : 0,\n maximumFractionDigits: isDistance ? 1 : 0,\n });\n };\n\n return `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Period${isDistance ? 'Distance' : 'Elevation'}${isDistance ? 'Distance/Week' : 'Elevation/Week'}
Current Year${format(accumulated.currentYear)} ${unit}${format(accumulated.currentYearAvg)} ${unit}
Past Year${format(accumulated.pastYear)} ${unit}${format(accumulated.pastYearAvg)} ${unit}
Past 6 Months${format(accumulated.past6m)} ${unit}${format(accumulated.past6mAvg)} ${unit}
Past 1 Month${format(accumulated.past1m)} ${unit}${format(accumulated.past1mAvg)} ${unit}
Total${format(accumulated.total)} ${unit}${format(accumulated.totalAvg)} ${unit}
\n `;\n}\n\nexport interface MultiMetricAccumulatedSummary {\n distance: AccumulatedData;\n elevation: AccumulatedData;\n durationHours: AccumulatedData;\n tss: AccumulatedData;\n workKj: AccumulatedData;\n climbCount: AccumulatedData;\n}\n\nexport function computeMultiMetricAccumulated(\n allTracks: TrackData[],\n): MultiMetricAccumulatedSummary {\n const distance = computeAccumulatedMetric(allTracks, (t) => t.stats.totalDist);\n const elevation = computeAccumulatedMetric(allTracks, (t) => t.stats.elevGain);\n const durationHours = computeAccumulatedMetric(allTracks, (t) =>\n t.stats.duration ? t.stats.duration / 3600000 : 0,\n );\n const tss = computeAccumulatedMetric(allTracks, (t) => {\n const durSec = (t.stats.duration || 0) / 1000;\n const avgPwr = t.stats.avgPower || 150;\n const ftp = 200;\n const intensityFactor = avgPwr / ftp;\n return ((durSec * avgPwr * intensityFactor) / (ftp * 3600)) * 100;\n });\n const workKj = computeAccumulatedMetric(allTracks, (t) => {\n const durSec = (t.stats.duration || 0) / 1000;\n const avgPwr = t.stats.avgPower || 0;\n return (durSec * avgPwr) / 1000;\n });\n const climbCount = computeAccumulatedMetric(allTracks, (t) => {\n const secs = t.stats.sections || [];\n return secs.filter((s) => s.kind === 'climb').length;\n });\n\n return {\n distance,\n elevation,\n durationHours,\n tss,\n workKj,\n climbCount,\n };\n}\n\nexport function renderAccumulatedProgressSummary(allTracks: TrackData[]): string {\n const summary = computeMultiMetricAccumulated(allTracks);\n const fmt = (v: number, digits = 1) =>\n v.toLocaleString('en-US', {\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n });\n\n const rows: {\n label: string;\n unit: string;\n data: AccumulatedData;\n scale: number;\n digits: number;\n }[] = [\n { label: 'Distance', unit: 'km', data: summary.distance, scale: 0.001, digits: 1 },\n { label: 'Elevation Gain', unit: 'm', data: summary.elevation, scale: 1, digits: 0 },\n { label: 'Moving Duration', unit: 'h', data: summary.durationHours, scale: 1, digits: 1 },\n { label: 'Training Stress (TSS)', unit: 'TSS', data: summary.tss, scale: 1, digits: 0 },\n { label: 'Mechanical Work', unit: 'kJ', data: summary.workKj, scale: 1, digits: 0 },\n { label: 'Categorized Climbs', unit: 'climbs', data: summary.climbCount, scale: 1, digits: 0 },\n ];\n\n return `\n
\n
\n
\n monitoring\n Accumulated Longitudinal Progress Summary\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n ${rows\n .map(\n (r) => `\n \n \n \n \n \n \n \n \n `,\n )\n .join('')}\n \n
MetricPast 1MPast 6MPast YearCurrent YearTotalWeekly Avg
${r.label}${fmt(r.data.past1m * r.scale, r.digits)} ${r.unit}${fmt(r.data.past6m * r.scale, r.digits)} ${r.unit}${fmt(r.data.pastYear * r.scale, r.digits)} ${r.unit}${fmt(r.data.currentYear * r.scale, r.digits)} ${r.unit}${fmt(r.data.total * r.scale, r.digits)} ${r.unit}${fmt(r.data.totalAvg * r.scale, r.digits)} ${r.unit}/wk
\n
\n `;\n}\n", "// Copyright (c) 2026, Camillo Bruni.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n'use strict';\n\n// \u2500\u2500 Main Application \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport { Storage } from './storage';\nimport { UrlState, AppState } from './url-state';\nimport { Parsers, TrackData, TrackPoint, calculateBounds, simplifyTrack } from './parsers';\nimport { MapView } from './map';\nimport { ChartView } from './charts';\nimport { renderDetails, initDetails, resetDetails } from './tabs/details';\nimport { renderInsights, initInsights, resetInsights } from './tabs/insights';\nimport {\n renderCombined,\n initCombined,\n resizeCombined,\n resetCombined,\n setCombinedMetrics,\n setCombinedPolar,\n setCombinedSliderProgress,\n} from './tabs/combined';\nimport {\n renderEvolution,\n resetEvolution,\n setEvolutionGrouping,\n setEvolutionRange,\n setEvolutionPinnedDuration,\n} from './tabs/progress';\nimport {\n renderCourses,\n initCourses,\n prepareBenchmarkCourses,\n getBenchmarkCourseIds,\n resetCourses,\n selectCourse,\n} from './tabs/courses';\nimport { fmtSecs, escHtml, fmtDate, getTagColor, compactId, shortRandom } from './utils';\n\nconst TRACK_COLORS: string[] = [\n '#FF6B35',\n '#4ECDC4',\n '#45B7D1',\n '#F7DC6F',\n '#FF6B6B',\n '#BB8FCE',\n '#82E0AA',\n '#F8C471',\n '#3b82f6',\n];\n\nconst POINT_ZOOM_LEVEL = 16;\n\nlet tracks: Record = {};\nlet skippedImports: { name: string; reason: string }[] = [];\n\nfunction isSameDay(t1: number, t2: number) {\n const d1 = new Date(t1);\n const d2 = new Date(t2);\n return (\n d1.getUTCFullYear() === d2.getUTCFullYear() &&\n d1.getUTCMonth() === d2.getUTCMonth() &&\n d1.getUTCDate() === d2.getUTCDate()\n );\n}\n\nlet cancelProcessing = false;\nlet selectedId: string | null = null;\nlet colorIdx = 0;\nlet followDot = false;\nlet currentMapColors: string[] | null = null;\n\n// Search/Filter state\nlet searchQuery = '';\nlet searchRegex = false;\nlet currentSort = 'date-desc';\n\ninterface Filters {\n date: [string | null, string | null];\n dist: [number | null, number | null];\n dur: [number | null, number | null];\n metrics: Set;\n tags: string[];\n sport: string | null;\n}\n\nlet filters: Filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n};\n\nfunction syncFiltersToUrl(push: boolean = false) {\n UrlState.patch(\n {\n f_date: filters.date.every((v) => v === null) ? null : filters.date,\n f_dist: filters.dist.every((v) => v === null) ? null : filters.dist,\n f_dur: filters.dur.every((v) => v === null) ? null : filters.dur,\n f_mets: filters.metrics.size === 0 ? null : Array.from(filters.metrics),\n f_tags: filters.tags.length === 0 ? null : filters.tags,\n },\n push,\n );\n}\n\nfunction syncMetricsToUrl() {\n const active = ChartView.getActiveMetrics();\n const metrics = ChartView.METRICS;\n const abbrs = Array.from(active).map((key) => metrics[key].abbr);\n UrlState.patch({ metrics: abbrs.length ? abbrs : null });\n}\n\nconst SORT_OPTIONS = [\n { label: 'Newest first', val: 'date-desc', icon: 'calendar_today' },\n { label: 'Oldest first', val: 'date-asc', icon: 'history' },\n { label: 'Longest distance', val: 'dist-desc', icon: 'straighten' },\n { label: 'Shortest distance', val: 'dist-asc', icon: 'horizontal_rule' },\n { label: 'Longest duration', val: 'dur-desc', icon: 'timer' },\n { label: 'Shortest duration', val: 'dur-asc', icon: 'timer_off' },\n];\n\nfunction showSortMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.sort-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'sort-menu-popup';\n\n SORT_OPTIONS.forEach((opt) => {\n const item = document.createElement('div');\n item.className = `menu-item ${currentSort === opt.val ? 'active' : ''}`;\n item.innerHTML = `\n ${opt.icon}\n ${opt.label}\n ${currentSort === opt.val ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n currentSort = opt.val;\n UrlState.patch({ sort: opt.val });\n updateSearchSortUI();\n renderTrackList();\n popup.remove();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.left = `${rect.left}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\nfunction showMetricMenu(anchorEl: HTMLElement) {\n document.querySelectorAll('.metric-menu-popup').forEach((el) => el.remove());\n\n const popup = document.createElement('div');\n popup.className = 'metric-menu-popup';\n\n const metrics = ChartView.METRICS;\n const available = ChartView.getAvailableMetrics();\n const active = ChartView.getActiveMetrics();\n\n Object.entries(metrics).forEach(([key, def]) => {\n if (!available.has(key)) return;\n\n const item = document.createElement('div');\n item.className = `menu-item ${active.has(key) ? 'active' : ''}`;\n item.innerHTML = `\n ${def.icon}\n ${def.label}\n ${active.has(key) ? 'check' : ''}\n `;\n item.addEventListener('click', () => {\n ChartView.toggleMetric(key);\n const isNowActive = ChartView.getActiveMetrics().has(key);\n item.classList.toggle('active', isNowActive);\n item.querySelector('.check')!.textContent = isNowActive ? 'check' : '';\n\n const pill = document.querySelector(`#metric-pills .metric-pill[data-metric=\"${key}\"]`);\n if (pill) pill.classList.toggle('active', isNowActive);\n\n updateToolbarLayout();\n\n syncMetricsToUrl();\n });\n popup.appendChild(item);\n });\n\n const rect = anchorEl.getBoundingClientRect();\n popup.style.top = `${rect.bottom + 5}px`;\n popup.style.right = `${window.innerWidth - rect.right}px`;\n document.body.appendChild(popup);\n\n const close = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node) && !anchorEl.contains(e.target as Node)) {\n popup.remove();\n document.removeEventListener('click', close);\n }\n };\n setTimeout(() => document.addEventListener('click', close), 0);\n}\n\n// \u2500\u2500 Tab Management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.addEventListener('select-track', (e: any) => {\n const id = e.detail.id;\n const idx = e.detail.idx;\n const dur = e.detail.dur;\n if (id && tracks[id]) {\n selectTrack(id);\n if (idx != null && dur != null) {\n const t = tracks[id];\n const pts = t.points;\n if (idx >= 0 && idx < pts.length) {\n const pIdx = pts[idx];\n if (pIdx && pIdx.time != null) {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const tMin = (pIdx.time - t0) / 1000;\n const tMax = tMin + dur;\n\n // ChartView selection\n ChartView.restoreSelection(tMin, tMax);\n\n // Find iMax based on duration\n let iMax = pts.findIndex((p) => (p.time || 0) >= pIdx.time! + dur * 1000);\n if (iMax === -1) iMax = pts.length - 1;\n\n const selPts = pts.slice(idx, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n\n renderInsights(t);\n\n MapView.highlightSegment(id, pts, idx, iMax, false, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n\n // Update URL state\n UrlState.patch({ sel: [tMin, tMax] });\n }\n }\n }\n }\n});\n\ndocument.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.tab-btn') as HTMLElement;\n if (!btn) return;\n const nav = btn.closest('#tab-nav');\n if (!nav) return;\n\n // Toggle buttons\n nav.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn));\n\n const tab = btn.dataset.tab!;\n UrlState.patch({ tab }, true);\n\n // Toggle contents\n const panel = nav.closest('#chart-panel');\n if (panel) {\n panel.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${btn.dataset.tab}`);\n });\n }\n\n if (btn.dataset.tab === 'details' && selectedId && tracks[selectedId])\n renderDetails(tracks[selectedId], getGlobalTags());\n\n if (btn.dataset.tab === 'insights' && selectedId && tracks[selectedId])\n renderInsights(tracks[selectedId]);\n\n if (btn.dataset.tab === 'evolution') {\n renderEvolution(\n selectedId ? tracks[selectedId] : null,\n Object.values(tracks),\n (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n },\n (start, end) => {\n filters.date = [start, end];\n applyFilters();\n syncFiltersToUrl(true);\n updateFilterUI();\n },\n );\n }\n\n if (btn.dataset.tab === 'combined' && selectedId && tracks[selectedId])\n renderCombined(tracks[selectedId]);\n\n if (btn.dataset.tab === 'courses') renderCourses();\n\n if (btn.dataset.tab === 'graphs') {\n ChartView.resize();\n updateToolbarLayout();\n\n // Restore selection from URL\n const s = UrlState.get().sel;\n if (s) ChartView.restoreSelection(s[0], s[1]);\n }\n});\n\nasync function resetBenchmarkState() {\n if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n await Storage.clear();\n tracks = {};\n skippedImports = [];\n selectedId = null;\n colorIdx = 0;\n currentMapColors = null;\n cancelProcessing = false;\n followDot = false;\n searchQuery = '';\n searchRegex = false;\n currentSort = 'date-desc';\n filters.date = [null, null];\n filters.dist = [null, null];\n filters.dur = [null, null];\n filters.metrics.clear();\n filters.tags = [];\n Parsers.setHRZones([120, 140, 160, 180]);\n Parsers.setFTP(200);\n resetCourses();\n resetInsights();\n resetDetails();\n resetCombined();\n resetEvolution();\n if (MapView.removeAllTracks) MapView.removeAllTracks();\n if (MapView.clearTracks) MapView.clearTracks();\n MapView.clearHighlight();\n if (ChartView.resetState) ChartView.resetState();\n else if (ChartView.clear) ChartView.clear();\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === 'graphs');\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === 'tab-graphs');\n });\n UrlState.reset();\n const toastContainer = document.getElementById('toast-container');\n if (toastContainer) toastContainer.innerHTML = '';\n document.querySelectorAll('.modal-backdrop').forEach((el) => el.remove());\n if (typeof renderTrackList === 'function') renderTrackList();\n}\n\n// \u2500\u2500 Boot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function init() {\n // Wait for fonts to be loaded with a cleaned-up timeout\n let fontTimerId: number | null = null;\n const fontTimeout = new Promise((resolve) => {\n fontTimerId = window.setTimeout(resolve, 1000);\n });\n try {\n const fontLoadPromise = document.fonts\n ? Promise.all([\n document.fonts.load('24px \"Material Symbols Rounded\"').catch(() => {}),\n document.fonts.ready,\n ])\n : Promise.resolve();\n await Promise.race([fontLoadPromise, fontTimeout]);\n } finally {\n if (fontTimerId !== null) window.clearTimeout(fontTimerId);\n }\n document.body.classList.remove('loading-fonts');\n const storageSelect = document.getElementById(\n 'storage-backend-select',\n ) as HTMLSelectElement | null;\n if (storageSelect) {\n storageSelect.value = UrlState.get().storage || 'memory';\n storageSelect.addEventListener('change', (e) => {\n const selected = (e.target as HTMLSelectElement).value;\n const params = new URLSearchParams(window.location.search);\n if (selected === 'memory') {\n params.delete('storage');\n } else {\n params.set('storage', selected);\n }\n window.location.search = params.toString();\n });\n }\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const mapLoader = document.getElementById('map-loader');\n const mapLoaderSpan = mapLoader?.querySelector('span');\n\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading database...';\n mapLoader.classList.remove('hidden');\n }\n\n const urlState = UrlState.get();\n\n initInsights((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n initDetails(\n () => {\n applyFilters();\n syncFiltersToUrl();\n },\n (id: string) => {\n deleteTrack(id);\n },\n );\n initCombined();\n initCourses((msg: string, type?: string) => showToast(msg, type === 'error' ? 'error' : 'info'));\n\n // Init sub-systems\n MapView.init(\n (id) => selectTrack(id),\n onMapMove,\n onMapPointClick,\n (id, idx) => {\n if (id === selectedId) ChartView.setHoverAt(idx);\n else ChartView.setHoverAt(null);\n },\n onMapDblClick,\n );\n ChartView.init(onChartCursorMove, onChartRangeChange, onChartClick, (idx) => {\n UrlState.patch({ sel_point: idx });\n });\n\n ChartView.setMapColorChangeCb((data) => {\n if (data) {\n currentMapColors = data.colors;\n if (selectedId) MapView.colorTrackByMetric(selectedId, data.pts, data.colors);\n } else {\n currentMapColors = null;\n if (selectedId) MapView.clearMetricColor(selectedId);\n }\n\n // Refresh highlight with new colors if a selection exists\n const currentUrlState = UrlState.get();\n if (currentUrlState.sel)\n onChartRangeChange(currentUrlState.sel[0], currentUrlState.sel[1], ChartView.getXAxis());\n });\n\n applyState(urlState);\n\n // Reset persistent storage and in-memory state for clean multi-iteration benchmark executions\n await Storage.openDB();\n await resetBenchmarkState();\n\n // Load persisted tracks\n try {\n // Load global settings\n const hrZones = await Storage.get('hr_zones');\n if (hrZones) Parsers.setHRZones(hrZones);\n\n const ftp = await Storage.get('ftp');\n if (ftp) Parsers.setFTP(ftp);\n\n const saved = await Storage.getAll();\n saved.sort((a, b) => a.addedAt - b.addedAt);\n\n if (mapLoaderSpan) mapLoaderSpan.textContent = `Preparing ${saved.length} tracks...`;\n\n const tracksToLoad: TrackData[] = [];\n for (const t of saved) {\n let updated = false;\n if (!t.bounds && t.points.length > 0) {\n const b = calculateBounds(t.points);\n if (b) {\n t.bounds = b;\n updated = true;\n }\n }\n if (!t.simplifiedPoints && t.points.length > 0) {\n t.simplifiedPoints = simplifyTrack(t.points, 50);\n updated = true;\n }\n if (updated) await Storage.save(t);\n\n tracks[t.id] = t;\n tracksToLoad.push(t);\n }\n MapView.addTracks(tracksToLoad);\n applyFilters();\n\n const restoreId =\n urlState.track && saved.find((t) => t.id === urlState.track)\n ? urlState.track\n : saved.length > 0\n ? saved[0].id\n : null;\n\n const mapLoader = document.getElementById('map-loader');\n\n // 1. Process and load the \"Priority\" track first\n const selectedTrackData = saved.find((t) => t.id === restoreId);\n if (selectedTrackData) {\n await processAndLoadTrack(selectedTrackData);\n selectTrack(selectedTrackData.id, !urlState.map_pos);\n\n // Explicitly restore selection/pin from URL if they exist\n if (urlState.sel && Array.isArray(urlState.sel) && urlState.sel.length === 2) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.restoreSelection(urlState.sel![0], urlState.sel![1]);\n });\n });\n }\n if (urlState.sel_point !== undefined && urlState.sel_point !== null) {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n ChartView.setCursorAt(urlState.sel_point!);\n });\n });\n }\n }\n\n // Hide database loader\n if (mapLoader) mapLoader.classList.add('hidden');\n\n // 2. Load the rest in background chunks\n if (saved.length > (selectedTrackData ? 1 : 0)) {\n if (mapLoader) {\n if (mapLoaderSpan) mapLoaderSpan.textContent = 'Loading tracks...';\n mapLoader.classList.remove('hidden');\n }\n\n const remaining = saved.filter((t) => t.id !== restoreId);\n let index = 0;\n\n const loadNextChunk = async () => {\n const chunkSize = 2; // Process 2 tracks per frame\n const end = Math.min(index + chunkSize, remaining.length);\n\n for (; index < end; index++) await processAndLoadTrack(remaining[index]);\n\n if (index < remaining.length) {\n requestAnimationFrame(loadNextChunk);\n } else {\n if (mapLoader) mapLoader.classList.add('hidden');\n applyFilters(); // Final sync\n if (selectedId && tracks[selectedId]) {\n renderEvolution(tracks[selectedId], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n // Only fit all if no saved map position and we just finished loading everything\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n };\n\n requestAnimationFrame(loadNextChunk);\n } else {\n applyFilters();\n if (saved.length && !urlState.map_pos) MapView.fitAll();\n }\n } catch (e) {\n console.warn('Could not load saved tracks:', e);\n }\n\n // Panel resizers\n initResizeHandle();\n initSidebarResizer();\n initMetricPillDraggable();\n updateToolbarLayout();\n\n // Basemap switcher\n document.getElementById('basemap-switcher')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.bm-btn') as HTMLElement;\n if (!btn) return;\n document.querySelectorAll('.bm-btn').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n if (btn.dataset.layer) {\n MapView.switchBasemap(btn.dataset.layer);\n UrlState.patch({ map: btn.dataset.layer });\n }\n });\n\n // Fit all\n document.getElementById('btn-fit-all')?.addEventListener('click', () => MapView.fitAll());\n\n // Clear all\n document.getElementById('btn-clear-all')?.addEventListener('click', clearAll);\n\n // Search\n document.getElementById('track-search')?.addEventListener('input', (e) => {\n searchQuery = (e.target as HTMLInputElement).value;\n applyFilters();\n UrlState.patch({ q: searchQuery || null });\n });\n\n document.getElementById('btn-regex-toggle')?.addEventListener('click', (e) => {\n searchRegex = !searchRegex;\n (e.target as HTMLElement).classList.toggle('active', searchRegex);\n applyFilters();\n UrlState.patch({ re: searchRegex ? 1 : null });\n });\n\n // Sort\n document.getElementById('btn-sort-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showSortMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric menu toggle\n document.getElementById('btn-metric-menu')?.addEventListener('click', (e) => {\n e.stopPropagation();\n showMetricMenu(e.currentTarget as HTMLElement);\n });\n\n // Metric toggles (shared logic)\n const toggleMetric = (metric: string, pill: HTMLElement | null) => {\n if (pill) pill.classList.toggle('active');\n ChartView.toggleMetric(metric);\n syncMetricsToUrl();\n };\n\n document.getElementById('metric-pills')?.addEventListener('click', (e) => {\n const pill = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (pill) {\n const metric = pill.dataset.metric;\n if (metric) {\n toggleMetric(metric, pill);\n\n // Scroll to it if it became active\n if (ChartView.getActiveMetrics().has(metric)) {\n const targetEl = document.querySelector(`.chart-row[data-metric=\"${metric}\"]`);\n targetEl?.scrollIntoView({ behavior: 'smooth' });\n }\n }\n }\n });\n\n // X-axis toggle\n document.getElementById('x-axis-ctrl')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.seg-btn') as HTMLElement;\n if (!btn) return;\n const axis = btn.dataset.axis!;\n ChartView.setXAxis(axis);\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', b === btn));\n UrlState.patch({ xaxis: axis });\n });\n\n // Follow dot\n document.getElementById('btn-follow-dot')?.addEventListener('click', (e) => {\n followDot = !followDot;\n (e.currentTarget as HTMLElement).classList.toggle('active', followDot);\n });\n\n // Reset zoom\n document.getElementById('btn-reset-zoom')?.addEventListener('click', () => {\n ChartView.resetZoom();\n MapView.clearHighlight();\n });\n\n // File drag/drop\n initDropZone();\n\n // File browse\n document.getElementById('file-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n document.getElementById('folder-input')?.addEventListener('change', (e) => {\n handleFiles(Array.from((e.target as HTMLInputElement).files || []));\n (e.target as HTMLInputElement).value = '';\n });\n\n // Filters\n document.getElementById('btn-toggle-filters')?.addEventListener('click', () => {\n const panel = document.getElementById('filter-panel');\n if (panel) {\n panel.classList.toggle('hidden');\n document\n .getElementById('btn-toggle-filters')\n ?.classList.toggle('active', !panel.classList.contains('hidden'));\n }\n });\n\n const onFilterInput = (type: 'date' | 'dist' | 'dur', idx: number, e: Event) => {\n const val = (e.target as HTMLInputElement).value;\n (filters[type] as any)[idx] = val === '' ? null : val;\n applyFilters();\n syncFiltersToUrl();\n };\n\n document\n .getElementById('filter-date-start')\n ?.addEventListener('change', (e) => onFilterInput('date', 0, e));\n document\n .getElementById('filter-date-end')\n ?.addEventListener('change', (e) => onFilterInput('date', 1, e));\n document\n .getElementById('filter-dist-min')\n ?.addEventListener('input', (e) => onFilterInput('dist', 0, e));\n document\n .getElementById('filter-dist-max')\n ?.addEventListener('input', (e) => onFilterInput('dist', 1, e));\n document\n .getElementById('filter-dur-min')\n ?.addEventListener('input', (e) => onFilterInput('dur', 0, e));\n document\n .getElementById('filter-dur-max')\n ?.addEventListener('input', (e) => onFilterInput('dur', 1, e));\n\n const burgerBtn = document.getElementById('sport-burger-btn');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n burgerBtn?.addEventListener('click', (e) => {\n e.stopPropagation();\n if (dropdownContent) {\n const isVisible = dropdownContent.style.display === 'block';\n dropdownContent.style.display = isVisible ? 'none' : 'block';\n }\n });\n\n document.addEventListener('click', (e) => {\n if (dropdownContent && dropdownContent.style.display === 'block') {\n if (!dropdownContent.contains(e.target as Node) && e.target !== burgerBtn)\n dropdownContent.style.display = 'none';\n }\n });\n\n document.getElementById('sport-filter-container')?.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const btn = target.closest('[data-sport]');\n if (btn) {\n const selectedSport = (btn as HTMLElement).dataset.sport || null;\n filters.sport = filters.sport === selectedSport ? null : selectedSport;\n applyFilters();\n syncFiltersToUrl();\n updateFilterUI();\n\n if (target.closest('.dropdown-item')) {\n if (dropdownContent) dropdownContent.style.display = 'none';\n }\n }\n });\n\n document.getElementById('filter-metrics')?.addEventListener('click', (e) => {\n const btn = (e.target as HTMLElement).closest('.mini-pill') as HTMLElement;\n if (!btn) return;\n const m = btn.dataset.metric!;\n if (filters.metrics.has(m)) filters.metrics.delete(m);\n else filters.metrics.add(m);\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('btn-reset-filters')?.addEventListener('click', () => {\n filters = {\n date: [null, null],\n dist: [null, null],\n dur: [null, null],\n metrics: new Set(),\n tags: [],\n sport: null,\n };\n updateFilterUI();\n applyFilters();\n syncFiltersToUrl();\n });\n\n document.getElementById('filter-tags')?.addEventListener('input', (e) => {\n const val = (e.target as HTMLInputElement).value;\n filters.tags = val\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => !!s);\n applyFilters();\n syncFiltersToUrl();\n });\n\n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n MapView.hideCursor();\n MapView.closePopup?.();\n // Dismiss popups and modals\n document\n .querySelectorAll(\n '.color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop',\n )\n .forEach((el) => el.remove());\n }\n });\n\n // Resize charts when window changes\n window.addEventListener('resize', () => {\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n updateToolbarLayout();\n });\n\n initBenchmarkTriggers();\n await preloadBenchmarkFiles();\n\n // Signal to Speedometer test harness that asynchronous initialization has completed\n // and benchmark step triggers are bound.\n const readyEl = document.createElement('div');\n readyEl.id = 'app-is-ready';\n readyEl.setAttribute('data-ready', 'true');\n readyEl.style.display = 'none';\n document.body.appendChild(readyEl);\n\n const camelReadyEl = document.createElement('div');\n camelReadyEl.id = 'appIsReady';\n camelReadyEl.setAttribute('data-ready', 'true');\n camelReadyEl.style.display = 'none';\n document.body.appendChild(camelReadyEl);\n}\n\nlet preloadedBenchmarkPayloads:\n | {\n cleanName: string;\n buf: ArrayBuffer;\n text?: string;\n file: File;\n }[]\n | null = null;\n\nasync function preloadBenchmarkFiles(): Promise<\n { cleanName: string; buf: ArrayBuffer; text?: string; file: File }[]\n> {\n if (preloadedBenchmarkPayloads) return preloadedBenchmarkPayloads;\n try {\n const manifestResp = await fetch('./test-data/manifest.json');\n const fileNames: string[] = await manifestResp.json();\n const decoder = new TextDecoder();\n preloadedBenchmarkPayloads = await Promise.all(\n fileNames.map(async (name) => {\n const fileResp = await fetch(`./test-data/${name}`);\n let buf = await fileResp.arrayBuffer();\n let cleanName = name;\n if (name.toLowerCase().endsWith('.gz')) {\n cleanName = name.slice(0, -3);\n const bytes = new Uint8Array(buf);\n if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) {\n const ds = new DecompressionStream('gzip');\n const stream = new Blob([buf]).stream().pipeThrough(ds);\n buf = await new Response(stream).arrayBuffer();\n }\n }\n const text = cleanName.toLowerCase().endsWith('.fit') ? undefined : decoder.decode(buf);\n const file = new File([buf], cleanName, { type: 'application/octet-stream' });\n (file as any)._buf = buf;\n if (text !== undefined) (file as any)._text = text;\n return { cleanName, buf, text, file };\n }),\n );\n // Warm up GPX, TCX, and FIT parser and chart code paths during prepare phase\n let warmSample: any = null;\n for (const idx of [0, 2, 4]) {\n if (preloadedBenchmarkPayloads[idx]) {\n const parsed = await Parsers.parseFile(preloadedBenchmarkPayloads[idx].file);\n if (idx === 0) warmSample = parsed;\n }\n }\n if (warmSample) {\n const warmPts = warmSample.points.slice(0, 1250);\n const warmTrack: TrackData = {\n ...warmSample,\n id: 'warmup',\n fileName: 'warmup.gpx',\n fileSize: 1024,\n points: warmPts,\n bounds: calculateBounds(warmPts) || undefined,\n simplifiedPoints: simplifyTrack(warmPts, 50),\n stats: Parsers.computeStats(warmPts),\n addedAt: 1785542400000,\n visible: true,\n color: TRACK_COLORS[0],\n };\n const warmTrack2: TrackData = {\n ...warmTrack,\n id: 'warmup-2',\n fileName: 'warmup2.gpx',\n addedAt: 1785628800000,\n color: TRACK_COLORS[1],\n };\n const warmList = [warmTrack, warmTrack2];\n Parsers.ensureCurvesAndZones(warmTrack);\n Parsers.ensureCurvesAndZones(warmTrack2);\n warmTrack.stats.sections = Parsers.analyzeTrackSections(warmTrack.points);\n warmTrack2.stats.sections = Parsers.analyzeTrackSections(warmTrack2.points);\n Parsers.findOverlaps(warmList);\n MapView.addTracks(warmList);\n ChartView.loadTrack(warmTrack, warmList, false);\n ChartView.restoreSelection(10, 50, true);\n ChartView.setCursorAt(25, true);\n ChartView.setSmooth('power', true);\n ChartView.setSmooth('power', false);\n ChartView.setXAxis('distance');\n ChartView.setXAxis('time');\n ChartView.setActiveMetrics(['elevation', 'speed', 'power']);\n ChartView.analyzeTelemetryIntervals(warmList, 10, 50);\n renderInsights(warmTrack, warmList, [10, 50]);\n renderInsights(warmTrack, warmList);\n renderDetails(warmTrack, [], warmList);\n renderCombined(warmTrack, warmList);\n setCombinedPolar(true);\n setCombinedPolar(false);\n setCombinedSliderProgress(0.5);\n renderCombined(warmList, warmList);\n renderEvolution(warmTrack, warmList);\n setEvolutionGrouping('month');\n setEvolutionGrouping('week');\n setEvolutionRange('6m');\n setEvolutionRange('all');\n setEvolutionPinnedDuration(60);\n setEvolutionPinnedDuration(null);\n prepareBenchmarkCourses(warmList);\n selectCourse('course-1', true);\n await resetBenchmarkState();\n void document.body.offsetHeight;\n await new Promise((r) => window.setTimeout(r, 0));\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n return preloadedBenchmarkPayloads;\n } catch {\n return [];\n }\n}\n\nfunction initBenchmarkTriggers() {\n const btnLoad = document.getElementById('btn-step-load');\n const btnAnalysis = document.getElementById('btn-step-analysis');\n const btnInsights = document.getElementById('btn-step-insights');\n const btnDetails = document.getElementById('btn-step-details');\n const btnAggregate = document.getElementById('btn-step-aggregate');\n const btnEvolution = document.getElementById('btn-step-evolution');\n const btnCourses = document.getElementById('btn-step-courses');\n\n function activateTab(tabName: string) {\n document.querySelectorAll('.tab-btn').forEach((b) => {\n b.classList.toggle('active', (b as HTMLElement).dataset.tab === tabName);\n });\n document.querySelectorAll('.tab-content').forEach((c) => {\n c.classList.toggle('active', c.id === `tab-${tabName}`);\n });\n UrlState.patch({ tab: tabName }, false);\n }\n\n btnLoad?.addEventListener('click', async () => {\n try {\n if (Object.keys(tracks).length > 0 || skippedImports.length > 0 || selectedId !== null) {\n await Storage.openDB();\n await resetBenchmarkState();\n } else if (typeof (window as any).__resetBenchmarkSeed === 'function') {\n (window as any).__resetBenchmarkSeed();\n }\n const payloads = await preloadBenchmarkFiles();\n const loadedFiles: File[] = payloads.map((p) => p.file);\n await handleFiles(loadedFiles);\n const allTracks = Object.values(tracks);\n Parsers.findOverlaps(allTracks);\n\n // Exercise sidebar track list sorting and filtering across distinct criteria\n for (const sortMode of ['dist-desc', 'dur-desc', 'date-asc', 'date-desc']) {\n currentSort = sortMode;\n renderTrackList();\n }\n filters.sport = 'cycling';\n applyFilters();\n filters.sport = null;\n filters.metrics.add('power');\n applyFilters();\n filters.metrics.clear();\n searchQuery = 'Alpine';\n applyFilters();\n searchQuery = '';\n applyFilters();\n\n if (!selectedId && allTracks.length > 0) selectTrack(allTracks[0].id);\n } finally {\n window.dispatchEvent(new CustomEvent('load-and-parse-complete'));\n }\n });\n\n btnAnalysis?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('graphs');\n if (!selectedId && allTracks.length > 0) {\n selectTrack(allTracks[0].id, false);\n }\n const availableMetrics = ChartView.getAvailableMetrics();\n const metricSets = [\n ['elevation', 'speed', 'power', 'hr'],\n ['elevation', 'speed', 'power'],\n ];\n for (const mSet of metricSets) {\n const filtered = mSet.filter((m) => availableMetrics.has(m));\n if (filtered.length > 0) {\n document.querySelectorAll('#metric-pills .metric-pill').forEach((el) => {\n const metric = (el as HTMLElement).dataset.metric;\n if (metric) el.classList.toggle('active', filtered.includes(metric));\n });\n updateToolbarLayout();\n ChartView.setActiveMetrics(filtered);\n }\n }\n\n // Exercise smoothing, map metric coloring, and X-axis mode switching\n ChartView.setSmooth('power', true, true);\n ChartView.toggleMapColor('power', true);\n ChartView.toggleMapColor(null, true);\n ChartView.setXAxis('distance');\n ChartView.setSmooth('power', false, true);\n ChartView.setXAxis('time');\n\n // Analyze distinct sections of the track (Opening Climb & Main Analysis Window)\n const sections: [number, number, number][] = [\n [0, 360, 180],\n [120, 900, 300],\n ];\n for (const [secStart, secEnd, cursorIdx] of sections) {\n ChartView.restoreSelection(secStart, secEnd, true);\n ChartView.setCursorAt(cursorIdx, true);\n ChartView.analyzeTelemetryIntervals(allTracks, secStart, secEnd);\n onChartRangeChange(secStart, secEnd, ChartView.getXAxis(), false);\n }\n } finally {\n window.dispatchEvent(new CustomEvent('analysis-complete'));\n }\n });\n\n btnInsights?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n allTracks.forEach((t) => Parsers.ensureCurvesAndZones(t));\n activateTab('insights');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n // Analyze insights across GPX, TCX, and FIT tracks and across distinct track sections (Opening, Middle, Final thirds, Full)\n for (const tIdx of [1, 2, 4]) {\n const trk = allTracks[tIdx];\n if (trk) {\n renderInsights(trk, allTracks, [0, 540]);\n renderInsights(trk, allTracks, [540, 1140]);\n renderInsights(trk, allTracks, null);\n }\n }\n if (allTracks[3]) {\n renderInsights(allTracks[3], allTracks, [200, 900]);\n }\n if (primaryTrack) {\n renderInsights(primaryTrack, allTracks, [0, 480]);\n renderInsights(primaryTrack, allTracks, [480, 960]);\n renderInsights(primaryTrack, allTracks, [960, 1440]);\n }\n renderInsights(primaryTrack, allTracks, null);\n } finally {\n window.dispatchEvent(new CustomEvent('insights-complete'));\n }\n });\n\n btnDetails?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('details');\n const globalTags = getGlobalTags();\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n // Render and analyze telemetry details, splits, gear matrices, and zones across all 6 tracks and terrain sections\n for (let i = 0; i < allTracks.length; i++) {\n renderDetails(allTracks[i], globalTags, allTracks, null);\n }\n if (primaryTrack) {\n renderDetails(primaryTrack, globalTags, allTracks, [0, 450]);\n renderDetails(primaryTrack, globalTags, allTracks, [450, 950]);\n renderDetails(primaryTrack, globalTags, allTracks, [950, 1450]);\n }\n if (allTracks[1]) {\n renderDetails(allTracks[1], globalTags, allTracks, [150, 750]);\n }\n if (allTracks[2]) {\n renderDetails(allTracks[2], globalTags, allTracks, [200, 800]);\n }\n if (allTracks[3]) {\n renderDetails(allTracks[3], globalTags, allTracks, [200, 900]);\n }\n if (allTracks[4]) {\n renderDetails(allTracks[4], globalTags, allTracks, [0, 600]);\n renderDetails(allTracks[4], globalTags, allTracks, [600, 1200]);\n }\n if (allTracks[5]) {\n renderDetails(allTracks[5], globalTags, allTracks, [150, 750]);\n }\n renderDetails(primaryTrack, globalTags, allTracks, null);\n } finally {\n window.dispatchEvent(new CustomEvent('details-complete'));\n }\n });\n\n btnAggregate?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n if (allTracks.length >= 2) {\n activateTab('combined');\n // 1. Exercise single-track 2D scatter/trail mode across metric pairs, Polar & Cartesian, and timeline sections\n setCombinedMetrics('distance', 'elevation');\n renderCombined(allTracks[0], allTracks);\n for (const frac of [0.25, 0.5, 0.75, 1.0]) {\n setCombinedSliderProgress(frac);\n }\n setCombinedPolar(true);\n setCombinedSliderProgress(0.5);\n setCombinedPolar(false);\n setCombinedMetrics('power', 'hr');\n for (const frac of [0.3, 0.7]) {\n setCombinedSliderProgress(frac);\n }\n\n // 2. Exercise multi-track comparison mode across regional pairs and all 6 tracks\n if (allTracks.length >= 4) {\n renderCombined([allTracks[2], allTracks[3]], allTracks);\n }\n if (allTracks.length >= 6) {\n renderCombined(allTracks, allTracks);\n }\n const selectedTwo = [allTracks[0], allTracks[1]];\n renderCombined(selectedTwo, allTracks);\n }\n } finally {\n window.dispatchEvent(new CustomEvent('aggregate-complete'));\n }\n });\n\n btnEvolution?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('evolution');\n const primaryTrack = (selectedId && tracks[selectedId]) || allTracks[0] || null;\n const onSelectCb = (trackId: string, range: [number, number] | null) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n };\n\n // Exercise evolution view across different reference tracks, groupings ('month' & 'week'), time ranges, and pinned durations\n const refTracks = [allTracks[2] || primaryTrack, allTracks[4] || primaryTrack, primaryTrack];\n for (const refTrk of refTracks) {\n renderEvolution(refTrk, allTracks, onSelectCb);\n setEvolutionGrouping('month');\n for (const rng of ['1m', '2m', '6m', '1y', 'all']) {\n setEvolutionRange(rng);\n }\n setEvolutionGrouping('week');\n for (const dur of [5, 30, 60, 300, 1200, null]) {\n setEvolutionPinnedDuration(dur);\n }\n }\n } finally {\n window.dispatchEvent(new CustomEvent('evolution-complete'));\n }\n });\n\n btnCourses?.addEventListener('click', () => {\n try {\n const allTracks = Object.values(tracks);\n activateTab('courses');\n prepareBenchmarkCourses(allTracks);\n const courseIds = getBenchmarkCourseIds();\n for (const cId of courseIds) {\n selectCourse(cId, true);\n }\n selectCourse('course-1', true);\n } finally {\n window.dispatchEvent(new CustomEvent('courses-complete'));\n }\n });\n\n (window as any).benchmarkSteps = {\n loadAndParseFiles: () => document.getElementById('btn-step-load')?.click(),\n displayAnalysisMetrics: () => document.getElementById('btn-step-analysis')?.click(),\n displayInsights: () => document.getElementById('btn-step-insights')?.click(),\n displayDetails: () => document.getElementById('btn-step-details')?.click(),\n displayAggregateMetrics: () => document.getElementById('btn-step-aggregate')?.click(),\n displayEvolutionMetrics: () => document.getElementById('btn-step-evolution')?.click(),\n displayCourses: () => document.getElementById('btn-step-courses')?.click(),\n };\n}\n\nasync function processAndLoadTrack(t: TrackData) {\n // Migration: re-calculate stats if new insights are missing or old format\n const powerCurveEntries = t.stats.powerCurve ? Object.values(t.stats.powerCurve) : [];\n\n const needsEnrich =\n t.points.length > 1 && (t.points[1].speed === undefined || t.points[1].gradient === undefined);\n\n const needsRecalc =\n needsEnrich ||\n !t.stats.powerCurve ||\n !t.stats.hrZones ||\n !t.stats.hrCurve ||\n t.stats.shifts === undefined ||\n t.stats.avgBattery === undefined ||\n t.stats.avgTemp === undefined ||\n (powerCurveEntries.length > 0 && typeof (powerCurveEntries[0] as any) === 'number') ||\n ((t.stats.duration || 0) > 10800 * 1000 && t.stats.powerCurve && !t.stats.powerCurve[14400]);\n\n if (needsRecalc) {\n if (needsEnrich) t.points = Parsers.enrichPoints(t.points);\n t.stats = Parsers.computeStats(t.points);\n await Storage.save(t);\n }\n\n tracks[t.id] = t;\n colorIdx = Math.max(colorIdx, TRACK_COLORS.indexOf(t.color) + 1);\n MapView.addTrack(t);\n MapView.setTrackVisible(t.id, t.visible && !t._filtered);\n renderTrackList(); // Progressive list update\n}\n\nfunction initResizeHandle() {\n const handle = document.getElementById('resize-handle');\n const panel = document.getElementById('chart-panel');\n if (!handle || !panel) return;\n\n let isDragging = false;\n\n handle.addEventListener('mousedown', () => {\n isDragging = true;\n document.body.style.cursor = 'ns-resize';\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const h = window.innerHeight - e.clientY;\n const clampedH = Math.max(100, Math.min(window.innerHeight - 100, h));\n panel.style.height = `${clampedH}px`;\n ChartView.resize();\n resizeCombined();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n document.body.style.cursor = '';\n });\n}\n\nfunction initSidebarResizer() {\n const resizer = document.getElementById('sidebar-resizer');\n const sidebar = document.getElementById('sidebar');\n if (!resizer || !sidebar) return;\n\n let isDragging = false;\n\n resizer.addEventListener('mousedown', () => {\n isDragging = true;\n resizer.classList.add('dragging');\n document.body.classList.add('dragging-sidebar');\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n const w = e.clientX;\n const clampedW = Math.max(200, Math.min(600, w));\n sidebar.style.width = `${clampedW}px`;\n sidebar.style.setProperty('--sidebar-w', `${clampedW}px`);\n ChartView.resize();\n MapView.invalidateSize?.();\n });\n\n document.addEventListener('mouseup', () => {\n if (!isDragging) return;\n isDragging = false;\n resizer.classList.remove('dragging');\n document.body.classList.remove('dragging-sidebar');\n });\n}\n\n// \u2500\u2500 Event Handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction onMapMove(lat: number, lng: number, zoom: number) {\n UrlState.patch({ map_pos: [lat, lng, zoom] });\n}\n\nfunction onMapPointClick(id: string, idx: number) {\n selectTrack(id, false);\n ChartView.setCursorAt(idx);\n}\n\nfunction onMapDblClick() {\n // MapView.fitAll();\n}\n\nfunction onChartCursorMove(pt: TrackPoint | null) {\n if (pt && pt.lat != null && pt.lon != null) {\n MapView.showCursorAt(pt.lat, pt.lon);\n if (followDot) MapView.centerOn(pt.lat, pt.lon, null, true);\n } else {\n MapView.hideCursor();\n }\n}\n\nfunction onChartRangeChange(min: number | null, max: number | null, axis: string, fit = false) {\n if (!selectedId || !tracks[selectedId]) return;\n const t = tracks[selectedId];\n\n if (min === null || max === null) {\n MapView.clearHighlight();\n if (t && (UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n UrlState.patch({ sel: null });\n return;\n }\n\n // Find point indices\n const pts = t.points;\n let iMin = 0,\n iMax = pts.length - 1;\n\n if (axis === 'distance') {\n const d0 = min * 1000,\n d1 = max * 1000;\n iMin = pts.findIndex((p) => (p.dist || 0) >= d0);\n iMax = pts.findIndex((p) => (p.dist || 0) >= d1);\n } else {\n const t0 = pts.find((p) => p.time != null)?.time || 0;\n const ts0 = t0 + min * 1000,\n ts1 = t0 + max * 1000;\n iMin = pts.findIndex((p) => (p.time || 0) >= ts0);\n iMax = pts.findIndex((p) => (p.time || 0) >= ts1);\n }\n\n if (iMin === -1) iMin = 0;\n if (iMax === -1) iMax = pts.length - 1;\n\n // Compute selection stats\n const selPts = pts.slice(iMin, iMax + 1);\n const stats = Parsers.computeStats(selPts);\n ChartView.setSelectionStats(stats);\n if ((UrlState.get().tab || 'graphs') === 'insights') renderInsights(t);\n\n MapView.highlightSegment(selectedId, pts, iMin, iMax, fit, currentMapColors);\n MapView.ensureVisible(selPts.map((p) => [p.lat, p.lon] as [number, number]));\n UrlState.patch({ sel: [min, max] });\n}\n\nfunction onChartClick(pt: TrackPoint, idx: number) {\n if (pt && pt.lat != null && pt.lon != null) MapView.centerOn(pt.lat, pt.lon, POINT_ZOOM_LEVEL);\n}\n\nexport function selectTrack(id: string, fit = true, deferChartRender = false) {\n if (!tracks[id]) return;\n if (id === selectedId) {\n if (fit) MapView.fitTrack(id);\n return;\n }\n\n const hadSelected = selectedId !== null;\n if (hadSelected) {\n // Clear current views immediately before loading new data\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n }\n\n selectedId = id;\n\n // Fully reset metric coloring when switching tracks\n currentMapColors = null;\n MapView.clearMetricColor(id);\n if (hadSelected) {\n ChartView.toggleMapColor(null); // Ensure ChartView state also resets\n }\n\n // Clear selection on new track\n UrlState.patch({ track: id, sel: null }, true);\n if (hadSelected) {\n ChartView.cancelSelection();\n }\n\n // Update UI immediately\n renderTrackList();\n\n // Render details\n const activeTab = UrlState.get().tab || 'graphs';\n if (activeTab === 'details') renderDetails(tracks[id], getGlobalTags());\n if (activeTab === 'insights') renderInsights(tracks[id]);\n if (activeTab === 'combined') renderCombined(tracks[id]);\n if (activeTab === 'courses') renderCourses();\n if (activeTab === 'evolution') {\n renderEvolution(tracks[id], Object.values(tracks), (trackId, range) => {\n selectTrack(trackId, true);\n if (range) {\n ChartView.restoreSelection(range[0], range[1]);\n onChartRangeChange(range[0], range[1], 'time', true);\n }\n });\n }\n\n // Tell sub-views\n MapView.setSelectedTrack(id, fit);\n if (fit) MapView.fitTrack(id);\n ChartView.loadTrack(tracks[id], Object.values(tracks), deferChartRender);\n}\n\nasync function deleteTrack(id: string) {\n await Storage.remove(id);\n MapView.removeTrack(id);\n delete tracks[id];\n if (selectedId === id) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n UrlState.patch({ track: null, sel: null, sel_point: null });\n }\n applyFilters();\n}\n\nasync function clearAll() {\n const code = Math.floor(10 + Math.random() * 90).toString();\n\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n backdrop.innerHTML = `\n
\n
Delete all tracks?
\n
\n This will permanently remove all tracks from your browser storage. This action cannot be undone.\n
\n
\n
Enter \"${code}\" to confirm:
\n \n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const input = backdrop.querySelector('.modal-input') as HTMLInputElement;\n const btnConfirm = backdrop.querySelector('.modal-btn.confirm') as HTMLButtonElement;\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n\n input.focus();\n\n input.addEventListener('input', () => {\n btnConfirm.disabled = input.value !== code;\n });\n\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n\n btnConfirm.addEventListener('click', async () => {\n if (input.value !== code) return;\n close();\n\n cancelProcessing = true;\n await Storage.clear();\n\n tracks = {};\n selectedId = null;\n MapView.clearHighlight();\n window.location.reload();\n });\n}\n\nfunction applyFilters(skipRender = false) {\n const ids = Object.keys(tracks);\n ids.forEach((id) => {\n const t = tracks[id];\n const s = t.stats;\n let visible = true;\n\n // Search query\n if (searchQuery) {\n if (searchRegex) {\n try {\n const re = new RegExp(searchQuery, 'i');\n if (!re.test(t.name)) visible = false;\n } catch (e) {\n visible = false;\n }\n } else {\n if (!t.name.toLowerCase().includes(searchQuery.toLowerCase())) visible = false;\n }\n }\n\n // Date filter\n if (visible && (filters.date[0] || filters.date[1])) {\n const start = filters.date[0] ? new Date(filters.date[0]).getTime() : 0;\n const end = filters.date[1] ? new Date(filters.date[1]).getTime() : Infinity;\n const t0 = s.startTime || 0;\n if (t0 < start || t0 > end) visible = false;\n }\n\n // Distance filter\n if (visible && (filters.dist[0] !== null || filters.dist[1] !== null)) {\n const min = (filters.dist[0] || 0) * 1000;\n const max = (filters.dist[1] || Infinity) * 1000;\n if (s.totalDist < min || s.totalDist > max) visible = false;\n }\n\n // Duration filter\n if (visible && (filters.dur[0] !== null || filters.dur[1] !== null)) {\n const min = (filters.dur[0] || 0) * 60000;\n const max = (filters.dur[1] || Infinity) * 60000;\n const d = s.duration || 0;\n if (d < min || d > max) visible = false;\n }\n\n // Metrics filter\n if (visible && filters.metrics.size > 0) {\n for (const m of filters.metrics) {\n const field = ChartView.METRICS[m].field;\n if (!t.points.some((p: any) => p[field] != null)) {\n visible = false;\n break;\n }\n }\n }\n\n // Sport filter\n if (visible && filters.sport) {\n if (t.sport !== filters.sport) visible = false;\n }\n\n // Tags filter\n if (visible && filters.tags.length > 0) {\n const trackTags = t.tags || [];\n if (!filters.tags.every((ft) => trackTags.includes(ft))) visible = false;\n }\n\n t._filtered = !visible;\n MapView.setTrackVisible(t.id, t.visible && visible);\n });\n\n if (!skipRender) renderTrackList();\n}\n\nfunction updateFilterUI() {\n (document.getElementById('filter-date-start') as HTMLInputElement).value = filters.date[0] || '';\n (document.getElementById('filter-date-end') as HTMLInputElement).value = filters.date[1] || '';\n (document.getElementById('filter-dist-min') as HTMLInputElement).value =\n filters.dist[0] !== null ? String(filters.dist[0]) : '';\n (document.getElementById('filter-dist-max') as HTMLInputElement).value =\n filters.dist[1] !== null ? String(filters.dist[1]) : '';\n (document.getElementById('filter-dur-min') as HTMLInputElement).value =\n filters.dur[0] !== null ? String(filters.dur[0]) : '';\n (document.getElementById('filter-dur-max') as HTMLInputElement).value =\n filters.dur[1] !== null ? String(filters.dur[1]) : '';\n (document.getElementById('filter-tags') as HTMLInputElement).value = filters.tags.join(', ');\n\n document\n .querySelectorAll('#sport-filter-container .mini-pill, #sport-dropdown-content .dropdown-item')\n .forEach((el) => {\n const item = el as HTMLElement;\n item.classList.toggle('active', (item.dataset.sport || '') === (filters.sport || ''));\n });\n\n document.querySelectorAll('#filter-metrics .mini-pill').forEach((el) => {\n const btn = el as HTMLElement;\n btn.classList.toggle('active', filters.metrics.has(btn.dataset.metric!));\n });\n\n const activeCount =\n (filters.date[0] ? 1 : 0) +\n (filters.date[1] ? 1 : 0) +\n (filters.dist[0] !== null ? 1 : 0) +\n (filters.dist[1] !== null ? 1 : 0) +\n (filters.dur[0] !== null ? 1 : 0) +\n (filters.dur[1] !== null ? 1 : 0) +\n filters.metrics.size +\n (filters.tags.length > 0 ? 1 : 0);\n\n const badge = document.querySelector('#btn-toggle-filters .btn-badge');\n if (badge) {\n badge.textContent = activeCount > 0 ? String(activeCount) : '';\n badge.classList.toggle('hidden', activeCount === 0);\n }\n}\n\nfunction updateSearchSortUI() {\n const searchInput = document.getElementById('track-search') as HTMLInputElement;\n if (searchInput) searchInput.value = searchQuery;\n document.getElementById('btn-regex-toggle')?.classList.toggle('active', searchRegex);\n\n const opt = SORT_OPTIONS.find((o) => o.val === currentSort);\n if (opt) {\n const labelEl = document.getElementById('sort-current-label');\n const iconEl = document.getElementById('sort-current-icon');\n if (labelEl)\n labelEl.textContent = opt.label\n .replace(' first', '')\n .replace(' distance', '')\n .replace(' duration', '');\n if (iconEl) iconEl.textContent = opt.icon;\n }\n}\n\nfunction applyState(urlState: AppState) {\n // Restore track\n const newTrackId = urlState.track;\n if (newTrackId !== selectedId) {\n if (newTrackId && tracks[newTrackId]) {\n selectTrack(newTrackId, true);\n } else if (!newTrackId && selectedId) {\n selectedId = null;\n ChartView.clear();\n renderDetails(null, []);\n renderInsights(null);\n renderTrackList();\n MapView.fitAll();\n }\n }\n\n // Restore basemap\n if (urlState.map && typeof urlState.map === 'string') {\n MapView.switchBasemap(urlState.map);\n document\n .querySelectorAll('.bm-btn')\n .forEach((b) =>\n b.classList.toggle('active', (b as HTMLElement).dataset.layer === urlState.map),\n );\n }\n\n // Restore map position\n if (urlState.map_pos) {\n const [lat, lng, zoom] = urlState.map_pos;\n MapView.setPosition(lat, lng, zoom);\n }\n\n // Restore tab\n if (urlState.tab) {\n document.querySelectorAll('.tab-btn').forEach((btn) => {\n const b = btn as HTMLElement;\n if (b.dataset.tab === urlState.tab) {\n if (!b.classList.contains('active')) b.click();\n }\n });\n }\n\n // Restore x-axis mode\n if (urlState.xaxis) ChartView.setXAxis(urlState.xaxis);\n\n const currentXAxis = urlState.xaxis || 'time';\n document\n .querySelectorAll('#x-axis-ctrl .seg-btn')\n .forEach((b) => b.classList.toggle('active', (b as HTMLElement).dataset.axis === currentXAxis));\n\n // Restore active metrics\n if (urlState.metrics) {\n const metrics = ChartView.METRICS;\n const keys = urlState.metrics\n .map((abbr) => Object.keys(metrics).find((k) => metrics[k].abbr === abbr))\n .filter((k): k is string => k !== undefined);\n if (keys.length) ChartView.setActiveMetrics(keys);\n }\n\n // Restore filters\n if (urlState.f_date)\n filters.date = urlState.f_date.map((v) => v || null) as [string | null, string | null];\n if (urlState.f_dist)\n filters.dist = urlState.f_dist.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_dur)\n filters.dur = urlState.f_dur.map((v) => (v === 0 ? 0 : v || null)) as [\n number | null,\n number | null,\n ];\n if (urlState.f_mets) filters.metrics = new Set(urlState.f_mets);\n if (urlState.f_tags) filters.tags = urlState.f_tags;\n\n updateFilterUI();\n\n if (urlState.q) searchQuery = urlState.q;\n if (urlState.re) searchRegex = urlState.re;\n if (urlState.sort) currentSort = urlState.sort;\n updateSearchSortUI();\n\n applyFilters();\n}\n\nfunction updateSportFilterOptions() {\n const container = document.getElementById('sport-filter-container');\n if (!container) return;\n\n const commonContainer = document.getElementById('common-sports');\n const dropdownContent = document.getElementById('sport-dropdown-content');\n if (!commonContainer || !dropdownContent) return;\n\n const sports = new Set();\n Object.values(tracks).forEach((t) => {\n if (t.sport) sports.add(t.sport);\n });\n\n const sportsArray = Array.from(sports).sort();\n const burgerDropdown = document.getElementById('sport-burger-dropdown');\n\n commonContainer.innerHTML = '';\n dropdownContent.innerHTML = '';\n\n if (sportsArray.length <= 4) {\n if (burgerDropdown) burgerDropdown.style.display = 'none';\n\n sportsArray.forEach((sport) => {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n });\n } else {\n if (burgerDropdown) burgerDropdown.style.display = 'inline-block';\n\n const commonSports = ['running', 'cycling', 'walking'];\n\n commonSports.forEach((sport) => {\n if (sports.has(sport)) {\n const btn = document.createElement('button');\n btn.className = `mini-pill${filters.sport === sport ? ' active' : ''}`;\n btn.dataset.sport = sport;\n btn.title = sport.charAt(0).toUpperCase() + sport.slice(1);\n btn.innerHTML = `${getSportIcon(sport)}`;\n commonContainer.appendChild(btn);\n }\n });\n\n sportsArray.forEach((sport) => {\n const item = document.createElement('div');\n item.className = `dropdown-item${filters.sport === sport ? ' active' : ''}`;\n item.dataset.sport = sport;\n item.style.padding = '8px';\n item.style.cursor = 'pointer';\n item.style.display = 'flex';\n item.style.alignItems = 'center';\n item.style.gap = '8px';\n item.innerHTML = `\n ${getSportIcon(sport)}\n ${sport.charAt(0).toUpperCase() + sport.slice(1)}\n `;\n dropdownContent.appendChild(item);\n });\n }\n}\n\nfunction renderTrackList() {\n updateSportFilterOptions();\n const list = document.getElementById('track-list');\n const emptyEl = document.getElementById('track-list-empty') as HTMLElement;\n const headerLabel = document.querySelector('.section-label');\n if (!list) return;\n\n const ids = Object.keys(tracks).filter((id) => !tracks[id]._filtered);\n if (headerLabel) headerLabel.textContent = `Tracks (${ids.length})`;\n\n if (!ids.length) {\n list.innerHTML = '';\n if (emptyEl) {\n list.appendChild(emptyEl);\n emptyEl.style.display = 'block';\n }\n return;\n }\n if (emptyEl) emptyEl.style.display = 'none';\n list.innerHTML = '';\n\n ids\n .sort((a, b) => {\n // Current selected always first\n if (a === selectedId) return -1;\n if (b === selectedId) return 1;\n\n const ta = tracks[a],\n tb = tracks[b];\n const sa = ta.stats,\n sb = tb.stats;\n\n let cmp = 0;\n switch (currentSort) {\n case 'date-asc':\n cmp = (sa.startTime || 0) - (sb.startTime || 0);\n break;\n case 'date-desc':\n cmp = (sb.startTime || 0) - (sa.startTime || 0);\n break;\n case 'dist-asc':\n cmp = (sa.totalDist || 0) - (sb.totalDist || 0);\n break;\n case 'dist-desc':\n cmp = (sb.totalDist || 0) - (sa.totalDist || 0);\n break;\n case 'dur-asc':\n cmp = (sa.duration || 0) - (sb.duration || 0);\n break;\n case 'dur-desc':\n cmp = (sb.duration || 0) - (sa.duration || 0);\n break;\n default:\n cmp = 0;\n }\n return cmp || a.localeCompare(b);\n })\n .forEach((id) => {\n list.appendChild(buildTrackItem(tracks[id]));\n });\n}\n\nfunction getGlobalTags(): string[] {\n const all = new Set();\n Object.values(tracks).forEach((t) => {\n (t.tags || []).forEach((tag) => all.add(tag));\n });\n return Array.from(all).sort();\n}\n\nfunction getSportIcon(sport: string | null): string {\n if (!sport) return 'category';\n const s = sport.toLowerCase();\n if (s.includes('run')) return 'directions_run';\n if (s.includes('cycl') || s.includes('bike')) return 'directions_bike';\n if (s.includes('walk')) return 'directions_walk';\n if (s.includes('swim')) return 'pool';\n if (s.includes('hik')) return 'hiking';\n return 'sports';\n}\n\nfunction buildTrackItem(track: TrackData) {\n const item = document.createElement('div');\n item.className = `track-item${track.id === selectedId ? ' selected' : ''}`;\n item.dataset.id = track.id;\n\n const date =\n track.points.length && track.points[0].time ? fmtDate(track.points[0].time) : 'Unknown date';\n\n const tagsHtml =\n (track.tags || []).length > 0\n ? `
${(track.tags || [])\n .map((t) => {\n const c = getTagColor(t);\n return `${escHtml(t)}`;\n })\n .join('')}
`\n : '';\n\n item.innerHTML = `\n
\n
\n
${escHtml(track.displayName || track.name)}
\n
\n
\n ${date}\n ${Math.round(track.stats.totalDist / 1000)} km\n ${track.sport ? `${getSportIcon(track.sport)}` : ''}\n ${track.format.toUpperCase()}\n
\n \n
\n ${tagsHtml}\n
\n `;\n\n item.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.icon-btn')) return;\n selectTrack(track.id);\n });\n\n const btnVis = item.querySelector('.toggle-vis') as HTMLElement;\n btnVis.addEventListener('click', () => {\n track.visible = !track.visible;\n btnVis.querySelector('.material-symbols-rounded')!.textContent = track.visible\n ? 'visibility'\n : 'visibility_off';\n MapView.setTrackVisible(track.id, track.visible);\n Storage.save(track);\n });\n\n return item;\n}\n\nfunction showToast(msg: string, type: 'info' | 'error' = 'info') {\n const container = document.getElementById('toast-container');\n if (!container) return;\n container.innerHTML = '';\n const t = document.createElement('div');\n t.className = `toast ${type}`;\n t.textContent = msg;\n container.appendChild(t);\n}\n\nfunction showSkippedImportsModal() {\n const backdrop = document.createElement('div');\n backdrop.className = 'modal-backdrop';\n\n let listHtml = '';\n skippedImports.forEach((s) => {\n listHtml += `
${s.name}: ${s.reason}
`;\n });\n\n backdrop.innerHTML = `\n
\n
Skipped Imports
\n
\n ${listHtml || '
No skipped imports.
'}\n
\n
\n \n \n
\n
\n `;\n\n document.body.appendChild(backdrop);\n\n const btnCancel = backdrop.querySelector('.modal-btn.cancel') as HTMLButtonElement;\n const btnClear = backdrop.querySelector('.modal-btn.clear') as HTMLButtonElement;\n const close = () => backdrop.remove();\n\n btnCancel.addEventListener('click', close);\n btnClear.addEventListener('click', () => {\n skippedImports = [];\n close();\n const importWarning = document.getElementById('import-warning');\n if (importWarning) importWarning.classList.add('hidden');\n });\n\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) close();\n });\n}\n\nfunction initDropZone() {\n const zone = document.getElementById('drop-zone');\n if (!zone) return;\n\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n importWarning.addEventListener('click', (e) => {\n e.stopPropagation();\n showSkippedImportsModal();\n });\n }\n\n window.addEventListener('dragover', (e) => {\n e.preventDefault();\n zone.classList.add('drop-active');\n });\n\n window.addEventListener('dragleave', (e) => {\n if (e.relatedTarget === null) zone.classList.remove('drop-active');\n });\n\n window.addEventListener('drop', async (e) => {\n e.preventDefault();\n zone.classList.remove('drop-active');\n\n const items = e.dataTransfer?.items;\n if (!items) return;\n\n const files: File[] = [];\n const queue: FileSystemEntry[] = [];\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i].webkitGetAsEntry();\n if (entry) queue.push(entry);\n }\n\n async function readAllEntries(entry: FileSystemEntry) {\n if (entry.isFile) {\n const file = await new Promise((res) => (entry as FileSystemFileEntry).file(res));\n files.push(file);\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n let entries: FileSystemEntry[] = [];\n let chunk: FileSystemEntry[];\n do {\n chunk = await new Promise((res) => reader.readEntries(res));\n entries.push(...chunk);\n } while (chunk.length > 0);\n\n for (const child of entries) await readAllEntries(child);\n }\n }\n\n for (const entry of queue) await readAllEntries(entry);\n\n if (files.length) handleFiles(files);\n });\n}\n\nasync function handleFiles(files: File[]) {\n if (!files.length) return;\n cancelProcessing = false;\n const initialSkipCount = skippedImports.length;\n\n const loader = document.getElementById('global-loader');\n const loaderText = document.getElementById('loader-text');\n const loaderSubtext = document.getElementById('loader-subtext');\n const progressBar = document.getElementById('loader-progress-bar') as HTMLElement;\n const loaderClose = document.getElementById('loader-close');\n\n if (loaderClose) {\n loaderClose.addEventListener('click', () => {\n cancelProcessing = true;\n if (loader) loader.classList.add('hidden');\n });\n }\n\n function updateLoaderIconToWarning() {\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'warning';\n loaderIcon.style.color = '#f59e0b';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n const count = skippedImports.length - initialSkipCount;\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = `${count}`;\n warningCount.style.display = 'flex';\n }\n }\n\n if (loader) {\n if (loaderText)\n loaderText.textContent = `Importing ${files.length} file${files.length > 1 ? 's' : ''}`;\n const loaderIcon = document.querySelector('.loader-icon-wrap span') as HTMLElement;\n if (loaderIcon) {\n loaderIcon.textContent = 'download';\n loaderIcon.style.color = 'var(--accent)';\n }\n const warningCount = document.getElementById('loader-warning-count');\n if (warningCount) {\n warningCount.style.display = 'none';\n const countSpan = warningCount.querySelector('span');\n if (countSpan) countSpan.textContent = '0';\n }\n if (loaderSubtext) loaderSubtext.textContent = '';\n if (progressBar) progressBar.style.width = '0%';\n loader.classList.remove('hidden');\n\n if (skippedImports.length > initialSkipCount) updateLoaderIconToWarning();\n }\n\n try {\n let count = 0;\n let firstId: string | null = null;\n let processedSinceLastUpdate = 0;\n\n // Filter out obviously invalid files early\n const validFiles = files.filter((f) => {\n const name = f.name.toLowerCase();\n return (\n name.endsWith('.gpx') ||\n name.endsWith('.fit') ||\n name.endsWith('.tcx') ||\n name.endsWith('.kml')\n );\n });\n\n const invalidFiles = files.filter((f) => !validFiles.includes(f));\n invalidFiles.forEach((f) => {\n skippedImports.push({ name: f.name, reason: 'Unsupported file format' });\n });\n\n if (validFiles.length === 0) {\n if (files.length > 0) {\n showToast('No valid GPS files found', 'error');\n // Still update warning icon if there were invalid files!\n const importWarning = document.getElementById('import-warning');\n if (importWarning && skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n }\n }\n return;\n }\n\n const loaderFilename = document.getElementById('loader-filename');\n let progressIdxEl: HTMLElement | null = null;\n if (loaderSubtext) {\n loaderSubtext.innerHTML =\n '';\n progressIdxEl = loaderSubtext.querySelector('.progress-index') as HTMLElement | null;\n const totalEl = loaderSubtext.querySelector('.progress-total');\n if (totalEl) totalEl.textContent = validFiles.length.toString();\n }\n\n for (let i = 0; i < validFiles.length; i++) {\n if (cancelProcessing) break;\n const f = validFiles[i];\n if (loaderFilename) loaderFilename.textContent = f.name;\n if (progressIdxEl) progressIdxEl.textContent = (i + 1).toString();\n if (progressBar) progressBar.style.width = `${(i / validFiles.length) * 100}%`;\n\n try {\n const data = await Parsers.parseFile(f);\n\n // Duplicate checks\n const existingTracks = Object.values(tracks);\n\n // Rule 1: Same file and same size\n const sameFile = existingTracks.find((t) => t.fileName === f.name && t.fileSize === f.size);\n if (sameFile) {\n skippedImports.push({ name: f.name, reason: 'Same File' });\n updateLoaderIconToWarning();\n continue;\n }\n\n // Rule 2 & 3: Same start day checks\n const newStart = data.stats.startTime;\n const newDuration = data.stats.duration;\n\n if (newStart != null && newDuration != null) {\n const newEnd = newStart + newDuration;\n const sameDayTracks = existingTracks.filter(\n (t) => t.stats.startTime != null && isSameDay(newStart, t.stats.startTime!),\n );\n\n let discarded = false;\n for (const ext of sameDayTracks) {\n const extStart = ext.stats.startTime!;\n const extDuration = ext.stats.duration!;\n const extEnd = extStart + extDuration;\n\n // Rule 2: Fully contained\n if (newStart >= extStart && newEnd <= extEnd) {\n skippedImports.push({ name: f.name, reason: 'Fully contained in another track' });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n\n // Rule 3: Overlaps for > 10 mins\n const overlap = Math.min(newEnd, extEnd) - Math.max(newStart, extStart);\n if (overlap > 600000) {\n // 10 mins in ms\n skippedImports.push({\n name: f.name,\n reason: 'Overlaps with an existing track for more than 10 mins',\n });\n updateLoaderIconToWarning();\n discarded = true;\n break;\n }\n }\n if (discarded) continue;\n }\n\n const fallbackTime = 1785542400000;\n let id = compactId(data.stats.startTime || fallbackTime);\n if (tracks[id]) id += `-${shortRandom()}`;\n\n // Use filename as activity name if internal name is generic\n let trackName = data.name;\n if (trackName.startsWith('Unnamed') || trackName.startsWith('Fit Activity'))\n trackName = f.name;\n\n // Generate a nice display name\n let displayName = trackName;\n const t0 = data.points[0]?.time;\n const sport = data.sport\n ? data.sport.charAt(0).toUpperCase() + data.sport.slice(1)\n : 'Activity';\n if (t0) {\n const d = new Date(t0);\n displayName = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')} ${sport}`;\n } else {\n displayName = trackName.replace(/\\.[^/.]+$/, '').replace(/_/g, ' '); // Remove extension and replace underscores\n }\n\n const track: TrackData = {\n ...data,\n id,\n name: trackName,\n displayName,\n fileName: f.name,\n fileSize: f.size,\n bounds: calculateBounds(data.points) || undefined,\n simplifiedPoints: simplifyTrack(data.points, 50), // 50m resolution\n addedAt: data.stats.startTime || fallbackTime,\n visible: true,\n color: TRACK_COLORS[colorIdx % TRACK_COLORS.length],\n };\n colorIdx++;\n if (cancelProcessing) break;\n\n await Storage.save(track);\n tracks[id] = track;\n MapView.addTrack(track);\n if (!firstId) firstId = id;\n count++;\n processedSinceLastUpdate++;\n\n if (processedSinceLastUpdate >= 5) {\n processedSinceLastUpdate = 0;\n }\n } catch (err) {\n skippedImports.push({\n name: f.name,\n reason: `Parse error: ${err instanceof Error ? err.message : String(err)}`,\n });\n updateLoaderIconToWarning();\n }\n }\n\n // Update warning icon\n const importWarning = document.getElementById('import-warning');\n if (importWarning) {\n if (skippedImports.length > 0) {\n importWarning.classList.remove('hidden');\n importWarning.title = `Skipped ${skippedImports.length} imports. Click to view details.`;\n } else {\n importWarning.classList.add('hidden');\n }\n }\n\n const newWarnings = skippedImports.length > initialSkipCount;\n if (!newWarnings && loader) {\n loader.classList.add('hidden');\n }\n\n if (count > 0) {\n showToast(`Imported ${count} track${count > 1 ? 's' : ''}`);\n applyFilters(!!firstId && firstId !== selectedId);\n if (firstId) selectTrack(firstId);\n }\n\n if (newWarnings) {\n const loaderIcon = document.querySelector('.loader-icon-wrap span');\n if (loaderIcon) loaderIcon.textContent = 'warning';\n // Delay hiding loader to let user see the alert icon\n await new Promise((r) => setTimeout(r, 1500));\n }\n } finally {\n if (loader) loader.classList.add('hidden');\n }\n}\n\nfunction initMetricPillDraggable() {\n const container = document.getElementById('metric-pills');\n if (!container) return;\n\n let draggedEl: HTMLElement | null = null;\n\n container.addEventListener('dragstart', (e) => {\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (!target) return;\n draggedEl = target;\n e.dataTransfer!.effectAllowed = 'move';\n target.classList.add('dragging-pill');\n // For transparent background in ghost image\n setTimeout(() => (target.style.opacity = '0.4'), 0);\n });\n\n container.addEventListener('dragover', (e) => {\n e.preventDefault();\n e.dataTransfer!.dropEffect = 'move';\n const target = (e.target as HTMLElement).closest('.metric-pill') as HTMLElement;\n if (target && target !== draggedEl) {\n const rect = target.getBoundingClientRect();\n const next = e.clientX - rect.left > rect.width / 2;\n container.insertBefore(draggedEl!, next ? target.nextSibling : target);\n }\n });\n\n container.addEventListener('dragend', () => {\n if (!draggedEl) return;\n draggedEl.classList.remove('dragging-pill');\n draggedEl.style.opacity = '';\n draggedEl = null;\n\n // Update Chart order\n const keys = Array.from(container.querySelectorAll('.metric-pill')).map(\n (el) => (el as HTMLElement).dataset.metric!,\n );\n ChartView.updateMetricOrder(keys);\n syncMetricsToUrl();\n });\n}\n\nfunction updateToolbarLayout() {\n const toolbar = document.getElementById('chart-toolbar');\n const pills = document.getElementById('metric-pills');\n if (!toolbar || !pills) return;\n\n toolbar.classList.remove('collapsed');\n const availableW = Math.max(0, toolbar.clientWidth - 280);\n let totalW = 0;\n let hidden = false;\n\n Array.from(pills.children).forEach((el) => {\n const htmlEl = el as HTMLElement;\n if (htmlEl.id === 'pill-overflow') return;\n\n htmlEl.classList.remove('overflow-hidden');\n if (!htmlEl.classList.contains('active')) return;\n const metricKey = htmlEl.dataset.metric || '';\n const deterministicPillWidth = 36 + metricKey.length * 6;\n totalW += deterministicPillWidth + 6;\n\n if (totalW > availableW) {\n hidden = true;\n htmlEl.classList.add('overflow-hidden');\n }\n });\n\n const overflowEl = document.getElementById('pill-overflow');\n if (overflowEl) overflowEl.classList.toggle('hidden', !hidden);\n\n if (hidden) toolbar.classList.add('collapsed');\n}\n\ndocument.addEventListener('DOMContentLoaded', init);\n"], + "mappings": "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", + "names": ["UrlState", "initialPathname", "initialSearch", "_state", "localSearch", "_lastSearch", "_syncTimeout", "_shouldPush", "historyEntries", "read", "p", "s", "metricsRaw", "isDesc", "field", "parts", "v", "_sync", "dir", "search", "val", "url", "entryState", "get", "patch", "partial", "push", "k", "key", "refresh", "reset", "InMemoryStorage", "track", "id", "key", "value", "IndexedDBStorage", "resolve", "reject", "req", "db", "name", "mode", "res", "rej", "tx", "activeDriver", "Storage", "UrlState", "k", "v", "FitParser", "haversine", "lat1", "lon1", "lat2", "lon2", "phi1", "phi2", "deltaPhi", "deltaLambda", "a", "compactId", "timestamp", "buf", "shortRandom", "fmtDuration", "s", "fmtSecs", "h", "m", "fmtPace", "seconds", "mins", "secs", "fmtDate", "ts", "d", "fmtDateTime", "iso", "fmtFileSize", "bytes", "k", "sizes", "i", "escHtml", "str", "getTagColor", "name", "hash", "gaussianSmooth", "data", "sigma", "size", "kernel", "half", "sum", "x", "result", "val", "weightSum", "idx", "hexToRgba", "hex", "alpha", "r", "g", "b", "calculateBounds", "pts", "minLat", "maxLat", "minLon", "maxLon", "p", "SIMPLIFY_CAP", "simplifyLats", "simplifyLons", "simplifyEles", "simplifyDists", "enrichEleBuf", "enrichPwrBuf", "enrichSpdBuf", "simplifyTrack", "minDistanceMeters", "n", "lats", "lons", "eles", "dists", "i", "tolerances", "errChecksum", "degToRad", "ti", "tolDegSq", "anchor", "cosLat", "dx", "dy", "dz", "mid", "mx", "my", "result", "lastPoint", "tolBias", "haversine", "Parsers", "enrichPoints", "totalDist", "prev", "d", "dt", "de", "eleBuf", "pwrBuf", "spdBuf", "gradeWindows", "npAccum", "scaleH", "wi", "w", "invW", "pSum", "sSum", "pAvg", "airDensity", "slopeAngle", "smoothBias", "hrZoneThresholds", "ftp", "computeStats", "includeCurves", "stats", "powerSum", "powerN", "hrSum", "hrN", "cadSum", "cadN", "speedSum", "speedN", "batterySum", "batteryN", "tempSum", "tempN", "hasTemp", "shifts", "hasGears", "diff", "t0", "t1", "calculateHRZones", "calculateHRCurve", "calculatePowerCurve", "calculatePowerZones", "ensureCurvesAndZones", "track", "s", "analyzeTrackSections", "sections", "quarterLabels", "q", "sIdx", "eIdx", "subPts", "thirdLabels", "t", "kmStartIdx", "nextKmMeters", "kmIndex", "kmPts", "win", "inClimb", "climbStart", "climbIdx", "inSprint", "sprintStart", "sprintIdx", "sprintThreshold", "dEle", "dDist", "rollingGrade", "segPts", "pwr", "findOverlaps", "tracksList", "overlaps", "ta", "ptsA", "stepA", "j", "tb", "ptsB", "stepB", "shared", "minCorridor", "a", "pa", "nearest", "b", "pb", "STANDARD_CURVE_DURATIONS", "calculateSlidingMax", "data", "durations", "len", "prefix", "curve", "hasAny", "di", "maxSum", "bestIdx", "limit", "currentSum", "powerData", "nonZero", "v", "hrData", "zones", "thresholds", "pw", "z", "setFTP", "val", "getFTP", "hr", "setHRZones", "getHRZones", "extractXmlTag", "block", "openTag", "closeTag", "start", "extractXmlAttr", "tagOpen", "attrPrefix", "cachedDateKey", "cachedDayMs", "parseIntSlice", "text", "end", "neg", "c0", "digits", "c", "parseFloatSlice", "intPart", "fracPart", "fracDiv", "inFrac", "res", "fastParseTimeSlice", "y", "m", "key", "hh", "mm", "ss", "ms", "extractAttrFloat", "vStart", "parseGPX", "buf", "predecodedText", "firstTrkpt", "header", "trkIdx", "name", "gpxOpenEnd", "device", "points", "pos", "trkStart", "openEnd", "trkEnd", "lat", "lon", "ele", "time", "cad", "power", "temp", "speed", "gearFront", "gearRear", "gearFrontTooth", "gearRearTooth", "battery", "lt", "gt", "c1", "tagLen", "nextLt", "vEnd", "expectedCloseGt", "closeGt", "gears", "parseTCX", "firstTp", "creatorBlock", "tpStart", "tpEnd", "fastDecodeFitData", "dv", "headerSize", "dataSize", "endOffset", "GARMIN_EPOCH_SEC", "SEMICIRCLE_TO_DEG", "defs", "file_ids", "sessions", "records", "events", "device_infos", "offset", "hdr", "localNum", "littleEndian", "globalMsgNum", "numFields", "fields", "recordSize", "num", "size", "type", "def", "le", "gNum", "ts", "rawLat", "rawLon", "rawAlt", "rawDist", "rawSpd", "msg", "fOff", "f", "bType", "sportMap", "evName", "parseFIT", "resolve", "reject", "handleParsedFitData", "error", "devices", "sport", "subSport", "getDeviceName", "fid", "antId", "existing", "statusReports", "idx", "gearEvents", "e", "front", "rear", "frontTooth", "rearTooth", "ft", "fg", "rt", "rg", "lastBattery", "statusIdx", "lastFrontGear", "lastRearGear", "lastFrontTooth", "lastRearTooth", "gearIdx", "validPoints", "ri", "r", "ex", "fastData", "FitParser", "parseKML", "doc", "nameEl", "coordEls", "el", "line", "parts", "parseFile", "file", "ext", "MapView", "trackData", "customClickHandler", "init", "onSelectCb", "onMoveCb", "onPointClickCb", "onPointHoverCb", "onDblClickCb", "switchBasemap", "layer", "addTrack", "t", "addTracks", "ts", "removeTrack", "id", "clearTracks", "removeAllTracks", "setTrackVisible", "visible", "setSelectedTrack", "fit", "fitAll", "fitTrack", "showCursorAt", "lat", "lon", "hideCursor", "highlightSegment", "pts", "start", "end", "colors", "clearHighlight", "setTrackHover", "hover", "ensureVisible", "centerOn", "zoom", "force", "closePopup", "invalidateSize", "getPosition", "setPosition", "lng", "colorTrackByMetric", "clearMetricColor", "findTracksPassingThroughPoints", "points", "radius", "handler", "uPlot", "Zones", "getPowerZones", "ftp", "Parsers", "thresholds", "t", "names", "colors", "zones", "last", "i", "getHRZones", "Metrics", "METRICS", "v", "p", "pts", "fillNulls", "vam", "i", "prev", "de", "dt", "SPORTS", "getSportIcon", "sport", "key", "ChartView", "plots", "renderedTrack", "renderedXAxis", "renderedSpeedMode", "renderedMapColorMetric", "syncKey", "scaleSyncing", "cursorSyncing", "activeMetrics", "availableMetrics", "smoothedMetrics", "metricsIncludingZero", "xAxis", "currentTrack", "allTracks", "selAnchorVal", "selEndVal", "isDragging", "updatingRange", "pinnedPtIdx", "lastMouseXVal", "lastHistMouseEvent", "hoveredHistData", "hoveredHistCanvas", "currentXRange", "targetXRange", "animId", "onCursorMoveCb", "onRangeChangeCb", "onClickCb", "onPinChangeCb", "HIST_W", "ROW_BODY_PADDING", "HIST_GAP", "statsVisible", "histTooltipEl", "container", "emptyEl", "selStatsEl", "resetSelBtn", "mapColorMetric", "onMapColorChangeCb", "init", "onCursorMove", "onRangeChange", "onClick", "onPinChange", "updateHistTooltip", "uPlot", "cancelSelection", "navKeys", "activeNavKeys", "e", "key", "u", "min", "max", "moveStep", "zoomFactor", "newMin", "newMax", "center", "factor", "xFull", "d", "setVisibleRange", "animate", "startMin", "startMax", "lerp", "a", "b", "t", "step", "tMin", "tMax", "cMin", "cMax", "loadTrack", "track", "others", "deferRender", "METRICS", "def", "p", "m", "el", "pill", "metric", "isAvailable", "updateStats", "render", "clear", "destroyPlots", "chartStats", "clearSelectionStats", "resetState", "overflowEl", "toolbar", "toggleMetric", "setSmooth", "metricKey", "enabled", "skipRender", "has", "setZeroInclusion", "includeZero", "setActiveMetrics", "keys", "setXAxis", "axis", "pts", "t0", "convert", "val", "idx", "dTarget", "tTarget", "newRange", "r0", "r1", "toggleStats", "histCol", "resize", "setMapColorChangeCb", "cb", "toggleMapColor", "_updateMapColorBtns", "_fireMapColorCb", "plot", "colors", "_computePointColors", "yData", "vals", "v", "sport", "sportDef", "SPORTS", "defaultMode", "speedMode", "UrlState", "paceUnit", "gradientColor", "speed", "speedColor", "lerpHex", "resetZoom", "updateSelOverlay", "redrawHistograms", "xData", "setSelectionStats", "stats", "fmt", "id", "fmtSecs", "restoreSelection", "totalDuration", "tOffset", "xMin", "xMax", "updateAnchorLines", "w", "anyResized", "histCanvas", "histData", "drawHistogram", "keepState", "savedRange", "savedScroll", "available", "containerW", "canReuse", "lastValidX", "existingByKey", "availSet", "isSmoothed", "isIncZero", "nextSiblingRows", "nextExisting", "i", "ex", "reused", "uplot", "s", "prevSync", "initHoverBinI", "buildHistBins", "span", "transform", "fmtAxis", "unit", "label", "fmtPace", "fillNulls", "gaussianSmooth", "createChart", "initialRange", "insertBeforeEl", "gradData", "smoothGradient", "row", "header", "labelEl", "smoothBtn", "mapColorBtn", "zeroBtn", "incZero", "statsTotalEl", "statsSelEl", "statsContainer", "actionsEl", "rightActionsEl", "paceToggle", "btn", "mode", "isDefault", "rowBody", "plotEl", "fixedMinLabel", "fixedMaxLabel", "isDistAxis", "formatX", "range", "dec", "absV", "h", "hh", "mm", "ss", "incZeroDefault", "gMin", "gMax", "allSum", "allCount", "filtMin", "filtMax", "filtSum", "filtCount", "fullStatsAll", "fullStatsFiltered", "gPad", "fixedYRange", "statsTotalInitialized", "updateHeaderStats", "visibleMin", "visibleMax", "getHtml", "isFull", "rangeStats", "es", "elevationRangeStats", "initializingScale", "uOpts", "_si", "_u", "mn", "mx", "axisIdx", "scaleMin", "scaleMax", "targetLabels", "idealIncr", "incrs", "incr", "splits", "precision", "pos", "top", "drawTrackPath", "drawElevationGradient", "drawGradientChart", "drawMetricColorFill", "drawPinnedDot", "drawYAxisHighlight", "hIdx", "hasPinned", "hasHover", "cy", "drawVerticalLineOnly", "hexToRgba", "ctx", "dpr", "bb", "ax", "fontSize", "fontStr", "tw", "visibleL", "visibleR", "padH", "padV", "bw", "bh", "bx", "by", "drawXAxisLabels", "showHover", "updateTooltip", "binI", "other", "left", "width", "overlay", "selFill", "anchorLine", "anchorLabel", "anchorHandle", "anchorMarker", "endLine", "endLabel", "endHandle", "endMarker", "curYVal", "pinYVal", "self", "attachHandleDrag", "mousedownX", "rect", "attachHistTooltip", "aX", "eX", "overW", "overH", "plotBottom", "isAnchorVisible", "isEndVisible", "fillL", "fillR", "aText", "fmtXVal", "aLabelW", "aIcon", "eText", "eLabelW", "eIcon", "handleEl", "isAnchor", "startX", "startVal", "pxPerUnit", "onMove", "me", "dx", "newVal", "onUp", "BINS", "lo", "hi", "cnt", "bins", "binAccum", "k", "bi", "prev", "next", "canvas", "chartH", "hoverBinI", "hasSel", "selBins", "selBinAccum", "x", "W", "H", "peak", "pad", "plotW", "plotH", "binY", "binH", "baseAlpha", "total", "pts2", "cumSum", "my", "cp", "font9", "avgY", "minLabelY", "maxLabelY", "labelHeight", "countLower", "countHigher", "pLower", "pHigher", "font8", "textY", "fontB10", "midX", "getBinAt", "lineEl", "relY", "rawI", "count", "pct", "low", "high", "zoneHtml", "mid", "zones", "Zones", "zIdx", "z", "finalZIdx", "totalAccum", "totalPct", "html", "stotalAccum", "stotalPct", "ttH", "ttW", "binCenterY", "sum", "n", "gain", "loss", "prevEle", "isDist", "diff", "cx", "gColor", "g", "p0", "p1", "content", "front", "rear", "color44", "gradientColorRgbaCache", "gradientColorRgba", "yMin", "yMax", "xScale", "yScale", "yBase", "idxs", "iStart", "iEnd", "byColor", "prevIdx", "xv1", "xv0", "x0", "y0", "x1", "y1", "color", "segs", "j", "drawHoverLine", "xVal", "opacity", "skipLine", "distVal", "timeVal", "bottomLabel", "topLabel", "drawPill", "text", "y", "isTop", "rx", "clampedRx", "ry", "pillH", "yVal", "cyClamp", "drawAreaFillAbove", "yDir", "yMult", "inSegment", "hasAnySegment", "lastPx", "xv", "yv", "px", "py", "ah", "ar", "ag", "ab", "br", "bg", "rr", "rg", "rb", "absG", "kmh", "windowMetres", "grads", "j0", "j1", "data", "res", "right", "getAvg", "avgSpeed", "avgPower", "avgCadence", "INTERVAL_CAP", "ivPwr", "ivHr", "ivSpd", "ivEle", "ivCad", "ivSmoothed", "ivKdeBins", "intervalWindows", "analyzeTelemetryIntervals", "tracksList", "selStartSec", "selEndSec", "intervalScore", "ti", "sStart", "sEnd", "inv35", "invSigmaSq", "omega", "sgPwr", "sgHr", "sgSpd", "dP", "gauss", "harmonic", "sectionRanges", "si", "secStart", "secEnd", "secLen", "wi", "invW", "winSum", "winEle", "maxInterval", "avg", "norm", "newActive", "isStepped", "c", "drawBackgroundTracks", "GAP_THRESHOLD", "field", "first", "prevP", "prevXVal", "lastFrontGear", "fMin", "fMax", "fg", "rMin", "rMax", "isTimeAxis", "gapSec", "prevDrawnI", "prevX", "prevY", "segmentColor", "prevXv", "SENSOR_ICONS", "Metrics", "onTagsChangeCb", "onDeleteTrackCb", "initDetails", "onTagsChange", "onDeleteTrack", "resetDetails", "container", "DETAIL_CAP", "detailChannels", "stabilityWindows", "analyzeTrackDetails", "track", "allTracks", "pts", "stabilityAccum", "i", "p", "wi", "w", "invW", "halfW", "ci", "ch", "sum", "sumSq", "autoCov", "jitterSum", "invNoise", "v", "old", "mean", "variance", "lagVal", "diff", "diffSqNoise", "likelihood", "damp", "sections", "Parsers", "splitRows", "si", "sec", "st", "secPtsCount", "secJitter", "dp", "dh", "secStab", "fmtSecs", "gearMap", "fg", "rg", "key", "entry", "gearMatrix", "a", "b", "combo", "g", "cohort", "distRank", "pwrRank", "elevRank", "cohortPwrSum", "cohortDistSum", "ti", "peer", "cohortAvgPower", "cohortAvgDistKm", "renderDetails", "globalTags", "sectionRange", "activeTrack", "t0Base", "ts0", "ts1", "iMin", "iMax", "subPts", "subStats", "s", "t0", "detailAnalysis", "telemetryStabilityPct", "escHtml", "t", "fmtFileSize", "getSportIcon", "SPORTS", "fmtDateTime", "sensor", "gm", "sr", "seen", "d", "name", "manufacturer", "extra", "battery", "sourceIcon", "deviceIcon", "nameLower", "tagContainer", "tagInput", "addBtn", "renderTags", "tags", "tag", "c", "getTagColor", "el", "btn", "e", "Storage", "addTag", "val", "titleInput", "sportTrigger", "showSportMenu", "anchorEl", "popup", "def", "item", "isActive", "iconEl", "nameEl", "clearItem", "isClear", "rect", "closeHandler", "uPlot", "courses", "getCoursesForTrack", "track", "c", "pt", "passesPoint", "trackPt", "haversine", "activeCourseId", "isEditMode", "openCourseId", "toastFn", "courseLayer", "initCourses", "showToast", "toastFn", "loadCourses", "resetCourses", "courses", "activeCourseId", "openCourseId", "isEditMode", "container", "prepareBenchmarkCourses", "allTracks", "specs", "i", "spec", "t", "n", "pStart", "pMid", "pEnd", "getBenchmarkCourseIds", "c", "stored", "Storage", "e", "saveCourses", "calculateCourseDistance", "course", "total", "p1", "p2", "haversine", "findCourseRange", "track", "coursePoints", "currentPtIdx", "startIdx", "endIdx", "tp", "cp", "calculateCourseStats", "pts", "s", "startTime", "duration", "totalPower", "powerCount", "totalHR", "hrCount", "totalSpeed", "speedCount", "totalCadence", "cadenceCount", "totalAscent", "prev", "de", "dist", "formatDuration", "seconds", "h", "m", "renderCourseTableHeaders", "METRICS", "renderCourseTableCells", "stats", "sport", "dateStr", "paceUnit", "SPORTS", "paceStr", "paceSeconds", "fmtPace", "COURSE_CAP", "courseTrkLats", "courseTrkLons", "courseTrkPwrs", "courseGateLats", "courseGateLons", "DTW_SAMPLES", "DTW_BAND", "dtwRefProfile", "dtwCandProfile", "dtwPrevRow", "dtwCurrRow", "renderCourses", "corridorDeviationSum", "targetCourses", "candidateIds", "MapView", "p", "numGates", "g", "segFloat", "segIdx", "frac", "pA", "pB", "ci", "id", "pt", "gLat", "gLon", "minDist", "bestIdx", "d", "idx", "val", "jStart", "jEnd", "rVal", "j", "diff", "diffSq", "cost", "m1", "m2", "m3", "prevMin", "matchingIds", "isOpen", "tracksHtml", "matchedTracksWithStats", "range", "span", "q1Idx", "q2Idx", "q3Idx", "s1Stats", "s2Stats", "s3Stats", "s4Stats", "fmtDate", "a", "b", "UrlState", "escHtml", "createNewCourse", "el", "editCourse", "renameCourse", "deleteCourse", "selectCourse", "row", "trackId", "selectTrack", "t0", "sIdx", "eIdx", "tMin", "tMax", "axis", "ChartView", "selMin", "selMax", "name", "newCourse", "nameEl", "currentName", "input", "save", "newName", "clearCourseLayer", "courseLayer", "selectCourse", "id", "open", "activeCourseId", "openCourseId", "isEditMode", "MapView", "clearCourseLayer", "renderCourses", "deleteCourse", "courses", "c", "saveCourses", "toastFn", "insightPlots", "destroyInsightPlots", "p", "initInsights", "showToast", "resetInsights", "el", "container", "INSIGHT_CAP", "inPwrArr", "inHrArr", "inCadArr", "inSpdArr", "inVamArr", "inPrefixPwr", "inPrefixVam", "mmpDurations", "analyzeTrackPhysiology", "pts", "cpBase", "sections", "i", "pt", "h", "c", "sp", "gr", "vam", "envelopeChecksum", "di", "d", "limit", "maxP", "maxV", "j", "sumP", "sumV", "minWPrimeBal", "wBal", "matchesBurned", "inMatchBurn", "half", "efSum1", "efSum2", "qCounts", "thresholdCad", "thresholdTorque", "cad", "invH", "diff", "dcp", "dep", "tauDyn", "torque", "ef", "ef1", "ef2", "decouplingPct", "quadrantPct", "sectionPeaks", "sec", "st", "durHours", "renderInsights", "track", "allTracks", "sectionRange", "Parsers", "activeRange", "UrlState", "activePts", "s", "t0", "startMs", "endMs", "iMin", "iMax", "phys", "grid", "chartWidth", "renderCurveCard", "Metrics", "card", "metricKey", "color", "isMapColored", "ChartView", "totalTime", "a", "b", "zones", "Zones", "zonesHtml", "time", "z", "pct", "rangeText", "fmtSecs", "e", "current", "btn", "showPowerZoneSettings", "showHRZoneSettings", "climbingCard", "distKm", "grade", "effCard", "secCard", "escHtml", "trackCourses", "getCoursesForTrack", "coursesCard", "renderCourseTableHeaders", "range", "findCourseRange", "statsHtml", "stats", "calculateCourseStats", "startTime", "dateStr", "fmtDate", "renderCourseTableCells", "courseId", "selectCourse", "course", "MapView", "opts", "curve", "label", "unit", "icon", "tableWrap", "toggleBtn", "toggleIcon", "isHidden", "mapColorBtn", "key", "tbody", "durations", "entry", "val", "row", "fmtDuration", "startIdx", "duration", "endIdx", "tMin", "tMax", "chartEl", "xData", "yData", "curYVal", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "idx", "hasFocus", "mousePy", "pointPy", "cx", "cy", "durVal", "pcx", "pcy", "plot", "uPlot", "anchorEl", "popup", "rect", "inputs", "newZones", "Storage", "dismiss", "ftp", "input", "newFtp", "uPlot", "currentTracks", "currentTrack", "plot", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "playIntervalId", "isPolar", "updateSliderLabel", "sliderVal", "timeSecs", "fmtSecs", "resetCombined", "playIntervalId", "plot", "currentTracks", "currentTrack", "xMetric", "yMetric", "currentSliderIdx", "currentChronoData", "currentSortedData", "isPolar", "tooltip", "container", "COMBINED_CAP", "combinedDensityGrid", "computeMultiTrackCorrelationAndSections", "allTracks", "matrixTracks", "numTrk", "pairs", "p", "aggPts", "corrSum", "correlations", "pi", "pair", "sumX", "sumY", "sumXX", "sumYY", "sumXY", "count", "t", "pts", "n", "k", "x", "y", "pw", "h", "cd", "bx", "by", "rVal", "slope", "meanX", "meanY", "varX", "varY", "covXY", "denom", "g", "sectionLabels", "sectionRows", "t1", "t2", "q", "fStart", "fEnd", "sliceStats", "trk", "sIdx", "eIdx", "pSum", "hSum", "spSum", "cnt", "i", "pt", "st1", "st2", "cohortPwrSum", "setCombinedMetrics", "xKey", "yKey", "renderCombined", "setCombinedPolar", "polar", "setCombinedSliderProgress", "fraction", "clamped", "maxLen", "slider", "updateSliderLabel", "trackOrTracks", "track", "metrics", "ChartView", "availableMetrics", "key", "def", "xDef", "yDef", "summaryHtml", "s1", "s2", "distDiff", "pwrDiff", "hrDiff", "eleDiff", "shiftsDiff", "totalDist", "totalElev", "totalDur", "avgPwr", "maxPwr", "avgHr", "maxHr", "tempDiff", "avgTemp", "maxTemp", "totalShifts", "fmtSecs", "sr", "c", "e", "showMenu", "sliderVal", "playBtn", "startPlaying", "stopPlaying", "updatePlot", "resizeCombined", "plotContainer", "w", "size", "anchorEl", "axis", "el", "popup", "item", "currentVal", "rect", "close", "xData", "seriesList", "dataArrays", "yArr", "width", "height", "opts", "uPlot", "t0", "chronoData", "idx", "d", "xVals", "yVals", "xMin", "xMax", "yMin", "yMax", "xVal", "yVal", "theta", "r", "px", "py", "a", "b", "yData", "hexToRgba", "u", "vals", "v", "seriesIdx", "dataIdx", "cursorLeft", "cursorTop", "minD2", "closestIdx", "cx", "cy", "dx", "dy", "d2", "ctx", "dpr", "started", "startIdx", "endIdx", "xVal1", "yVal1", "xVal2", "yVal2", "cx1", "cy1", "cx2", "cy2", "progress", "lineWidth", "alpha", "fillAlpha", "timeSecs", "distKm", "origX", "origY", "canvasRect", "originalIdx", "uPlot", "computeAccumulatedMetric", "allTracks", "extractor", "refTs", "i", "st", "now", "currentYear", "oneYearAgoMs", "sixMonthsAgoMs", "oneMonthAgoMs", "currentYearVal", "pastYearVal", "past6mVal", "past1mVal", "totalVal", "minTime", "t", "val", "time", "msecPerWeek", "currentYearStart", "currentYearWeeks", "pastYearWeeks", "past6mWeeks", "past1mWeeks", "totalWeeks", "renderAccumulatedTable", "accumulated", "isDistance", "unit", "factor", "format", "computeMultiMetricAccumulated", "distance", "elevation", "durationHours", "tss", "durSec", "avgPwr", "ftp", "intensityFactor", "workKj", "climbCount", "s", "renderAccumulatedProgressSummary", "summary", "fmt", "v", "digits", "r", "evolutionPlots", "activeEvolutionCards", "currentEvolutionGrouping", "destroyEvolutionPlots", "p", "resetEvolution", "container", "setEvolutionGrouping", "grouping", "c", "setEvolutionRange", "range", "UrlState", "toolbarRangeCtrl", "b", "setEvolutionPinnedDuration", "dur", "EVO_CAP", "evoPwrPrefix", "evoHrPrefix", "evoSpdPrefix", "evoStressArr", "evoDailyTrimp", "envelopeDurations", "renderEvolution", "currentTrack", "allTracks", "onTrackSelect", "onDateRangeSelect", "currentRange", "track", "Parsers", "totalFatigue", "totalFitness", "ti", "pts", "n", "i", "pw", "h", "sp", "el", "hrRatio", "di", "d", "limit", "maxP", "maxH", "j", "dh", "alphaA", "oneMinusA", "alphaC", "oneMinusC", "hrRest", "invHrSpan", "atl", "ctl", "kh", "trimp", "dayIdx", "atl365", "ctl365", "day", "load", "cards", "Metrics", "grid", "renderAccumulatedProgressSummary", "gridWidth", "progressSync", "uPlot", "renderProgressCard", "distanceScroll", "elevationScroll", "btn", "onRangeChange", "pill", "target", "onPinChange", "t", "card", "renderCurveEvolutionCard", "opts", "metricKey", "label", "unit", "color", "icon", "trackName", "mainChart", "cardContainer", "row1", "legendEl", "row2", "sideBySide", "chartEl", "maxCurve", "curve", "name", "date", "fmtDate", "trackInfo", "data", "val", "currentCurve", "allDurations", "durations", "a", "xData", "yDataCurrent", "entry", "yDataMax", "validTracks", "xTimeline", "yTimelineData", "currentDur", "tracksFiltered", "pinnedDur", "getFilteredData", "maxTime", "minTime", "filteredIndices", "idx", "xFiltered", "rawY", "rawYFiltered", "smoothedYFiltered", "gaussianSmooth", "timelineChart", "curYVal", "optsUPlot", "hexToRgba", "_u", "vals", "v", "u", "seriesIdx", "dataIdx", "ctx", "dpr", "bb", "benchmarks", "maxDur", "lastX", "x", "fmtDuration", "pcx", "pcy", "curVal", "dotRadius", "dotColor", "activeSeriesIdx", "cursorLeft", "cursorTop", "minD2", "nearestIdx", "radius", "maxD2", "yCur", "yMax", "px", "py", "dx", "dy", "d2", "xValStr", "xbw", "pillH", "xLabelX", "clampedXBx", "xLabelY", "yValStr", "ybw", "yLabelX", "yLabelY", "cx", "cy", "durVal", "mxVal", "html", "lowerBound", "upperBound", "labelEl", "clickedDur", "newPinnedDur", "stats", "bestIdx", "duration", "startPt", "endPt", "trackStart", "min", "max", "detailsEl", "cur", "mx", "mxId", "mxIdx", "e", "id", "lastNearestIdx", "timelineEl", "timelineTooltip", "dataTimeline", "series", "optsTimeline", "ts", "tpcx", "tpcy", "tctx", "tdpr", "dateStr", "valStr", "yData", "y", "getWeekStart", "diff", "computeWeeklyDistance", "weeklyData", "weekStart", "weekKey", "week", "computeWeeklyElevation", "computeMonthlyDistance", "monthlyData", "monthStart", "monthKey", "computeMonthlyElevation", "type", "syncKey", "isDistance", "activeGrouping", "activeRange", "weeklySource", "monthlySource", "accumulated", "computeAccumulatedMetric", "renderAccumulatedTable", "yAxisEl", "tooltip", "yDataSmoothed", "chartClientW", "width", "maxVal", "mainOpts", "item", "start", "end", "startStr", "endStr", "self", "splits", "s", "scrollContainer", "applySeriesData", "filteredData", "newXData", "newYData", "newYDataSmoothed", "newWidth", "newMaxVal", "TRACK_COLORS", "POINT_ZOOM_LEVEL", "tracks", "skippedImports", "isSameDay", "t1", "t2", "d1", "d2", "cancelProcessing", "selectedId", "colorIdx", "followDot", "currentMapColors", "searchQuery", "searchRegex", "currentSort", "filters", "syncFiltersToUrl", "push", "UrlState", "v", "syncMetricsToUrl", "active", "ChartView", "metrics", "abbrs", "key", "SORT_OPTIONS", "showSortMenu", "anchorEl", "el", "popup", "opt", "item", "updateSearchSortUI", "renderTrackList", "rect", "close", "e", "showMetricMenu", "available", "def", "isNowActive", "pill", "updateToolbarLayout", "id", "idx", "dur", "selectTrack", "t", "pts", "pIdx", "t0", "p", "tMin", "tMax", "iMax", "selPts", "stats", "Parsers", "renderInsights", "MapView", "btn", "nav", "b", "tab", "panel", "c", "renderDetails", "getGlobalTags", "renderEvolution", "trackId", "range", "onChartRangeChange", "start", "end", "applyFilters", "updateFilterUI", "renderCombined", "renderCourses", "s", "resetBenchmarkState", "Storage", "resetCourses", "resetInsights", "resetDetails", "resetCombined", "resetEvolution", "toastContainer", "init", "fontTimerId", "fontTimeout", "resolve", "fontLoadPromise", "storageSelect", "selected", "params", "loader", "loaderText", "loaderSubtext", "progressBar", "mapLoader", "mapLoaderSpan", "urlState", "initInsights", "msg", "type", "showToast", "initDetails", "deleteTrack", "initCourses", "onMapMove", "onMapPointClick", "onMapDblClick", "onChartCursorMove", "onChartClick", "data", "currentUrlState", "applyState", "hrZones", "ftp", "saved", "a", "tracksToLoad", "updated", "calculateBounds", "simplifyTrack", "restoreId", "selectedTrackData", "processAndLoadTrack", "remaining", "index", "loadNextChunk", "initResizeHandle", "initSidebarResizer", "initMetricPillDraggable", "clearAll", "toggleMetric", "metric", "axis", "initDropZone", "handleFiles", "onFilterInput", "val", "burgerBtn", "dropdownContent", "isVisible", "target", "selectedSport", "m", "resizeCombined", "initBenchmarkTriggers", "preloadBenchmarkFiles", "readyEl", "camelReadyEl", "preloadedBenchmarkPayloads", "fileNames", "decoder", "name", "buf", "cleanName", "bytes", "ds", "stream", "text", "file", "warmSample", "parsed", "warmPts", "warmTrack", "warmTrack2", "warmList", "setCombinedPolar", "setCombinedSliderProgress", "setEvolutionGrouping", "setEvolutionRange", "setEvolutionPinnedDuration", "prepareBenchmarkCourses", "selectCourse", "r", "btnLoad", "btnAnalysis", "btnInsights", "btnDetails", "btnAggregate", "btnEvolution", "btnCourses", "activateTab", "tabName", "loadedFiles", "allTracks", "sortMode", "availableMetrics", "metricSets", "mSet", "filtered", "sections", "secStart", "secEnd", "cursorIdx", "primaryTrack", "tIdx", "trk", "globalTags", "i", "setCombinedMetrics", "frac", "selectedTwo", "onSelectCb", "refTracks", "refTrk", "rng", "courseIds", "getBenchmarkCourseIds", "cId", "powerCurveEntries", "needsEnrich", "handle", "isDragging", "h", "clampedH", "resizer", "sidebar", "w", "clampedW", "lat", "lng", "zoom", "pt", "min", "max", "fit", "iMin", "d0", "ts0", "ts1", "deferChartRender", "hadSelected", "activeTab", "code", "backdrop", "input", "btnConfirm", "btnCancel", "skipRender", "visible", "field", "trackTags", "ft", "activeCount", "badge", "searchInput", "o", "labelEl", "iconEl", "newTrackId", "currentXAxis", "keys", "abbr", "k", "updateSportFilterOptions", "commonContainer", "sports", "sportsArray", "burgerDropdown", "sport", "getSportIcon", "list", "emptyEl", "headerLabel", "ids", "ta", "tb", "sa", "sb", "cmp", "buildTrackItem", "all", "tag", "track", "date", "fmtDate", "tagsHtml", "getTagColor", "escHtml", "btnVis", "container", "showSkippedImportsModal", "listHtml", "btnClear", "importWarning", "zone", "items", "files", "queue", "entry", "readAllEntries", "res", "reader", "entries", "chunk", "child", "initialSkipCount", "loaderClose", "updateLoaderIconToWarning", "loaderIcon", "warningCount", "count", "countSpan", "firstId", "processedSinceLastUpdate", "validFiles", "f", "loaderFilename", "progressIdxEl", "totalEl", "existingTracks", "newStart", "newDuration", "newEnd", "sameDayTracks", "discarded", "ext", "extStart", "extDuration", "extEnd", "fallbackTime", "compactId", "shortRandom", "trackName", "displayName", "d", "err", "newWarnings", "draggedEl", "next", "toolbar", "pills", "availableW", "totalW", "hidden", "htmlEl", "deterministicPillWidth", "overflowEl"] } diff --git a/suites-experimental/tools-gps-tracks/src/app.ts b/suites-experimental/tools-gps-tracks/src/app.ts index c7fd2f1913..749f0f34de 100644 --- a/suites-experimental/tools-gps-tracks/src/app.ts +++ b/suites-experimental/tools-gps-tracks/src/app.ts @@ -810,12 +810,6 @@ async function init() { updateToolbarLayout(); }); - // Handle back/forward navigation - window.addEventListener('popstate', () => { - UrlState.refresh(); - applyState(UrlState.get()); - }); - initBenchmarkTriggers(); await preloadBenchmarkFiles(); diff --git a/suites-experimental/tools-gps-tracks/src/benchmark-override.ts b/suites-experimental/tools-gps-tracks/src/benchmark-override.ts index 9e25da8a54..aef3b32065 100644 --- a/suites-experimental/tools-gps-tracks/src/benchmark-override.ts +++ b/suites-experimental/tools-gps-tracks/src/benchmark-override.ts @@ -24,27 +24,6 @@ window.cancelAnimationFrame = (id: number): void => { window.clearTimeout(id); }; -// Guard history.replaceState and history.pushState against browser rate-limiting -// (e.g. WebKit's 100 calls per 10 seconds SecurityError across multi-iteration runs). -if (typeof history !== 'undefined') { - const origReplace = history.replaceState?.bind(history); - const origPush = history.pushState?.bind(history); - if (origReplace) { - history.replaceState = function (data: any, unused: string, url?: string | URL | null): void { - try { - origReplace(data, unused, url); - } catch (_) {} - }; - } - if (origPush) { - history.pushState = function (data: any, unused: string, url?: string | URL | null): void { - try { - origPush(data, unused, url); - } catch (_) {} - }; - } -} - // Normalize devicePixelRatio to 1 so uPlot and canvas rendering execute // identical code paths (e.g. decimation thresholds and canvas dimensions) across browsers. try { diff --git a/suites-experimental/tools-gps-tracks/src/url-state.ts b/suites-experimental/tools-gps-tracks/src/url-state.ts index f5d53edb4a..1ab6e3044b 100644 --- a/suites-experimental/tools-gps-tracks/src/url-state.ts +++ b/suites-experimental/tools-gps-tracks/src/url-state.ts @@ -31,14 +31,24 @@ export interface AppState { } export const UrlState = (() => { - // Internal state object, initialized from current URL. + const initialPathname = typeof location !== 'undefined' ? location.pathname : '/'; + const initialSearch = typeof location !== 'undefined' ? location.search.replace(/^\?/, '') : ''; + + // Internal state and local in-memory query/navigation stack. let _state: AppState = {}; + let localSearch: string = initialSearch; let _lastSearch: string | null = null; let _syncTimeout: any = null; let _shouldPush = false; + let historyEntries: Array<{ state: unknown; url: string }> = [ + { + state: null, + url: initialPathname + (initialSearch ? `?${initialSearch}` : ''), + }, + ]; function read(): AppState { - const p = new URLSearchParams(location.search); + const p = new URLSearchParams(localSearch); const s: AppState = {}; if (p.has('track')) s.track = p.get('track')!; @@ -154,17 +164,21 @@ export const UrlState = (() => { search += `${search ? '&' : ''}sel=${val}`; } + localSearch = search; if (search !== _lastSearch) { - const url = location.pathname + (search ? `?${search}` : ''); - try { - if (_shouldPush) { - history.pushState(null, '', url); - _shouldPush = false; - } else { - history.replaceState(null, '', url); + const pathname = typeof location !== 'undefined' ? location.pathname : '/'; + const url = pathname + (search ? `?${search}` : ''); + const entryState = read(); + if (_shouldPush) { + historyEntries.push({ state: entryState, url }); + if (historyEntries.length > 100) { + historyEntries.shift(); } - } catch (_) { _shouldPush = false; + } else if (historyEntries.length > 0) { + historyEntries[historyEntries.length - 1] = { state: entryState, url }; + } else { + historyEntries.push({ state: entryState, url }); } _lastSearch = search; } @@ -198,11 +212,11 @@ export const UrlState = (() => { } _state = {}; _shouldPush = false; + localSearch = ''; _lastSearch = ''; - try { - history.replaceState(null, '', location.pathname); - } catch (_) {} + const pathname = typeof location !== 'undefined' ? location.pathname : '/'; + historyEntries = [{ state: null, url: pathname }]; } - return { get, patch, refresh, reset }; + return { read, get, patch, refresh, reset }; })(); From 83a0defc740ed44d7a7de30290807de65f631240 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Fri, 13 Nov 2026 15:56:47 +0000 Subject: [PATCH 6/8] [tools-gps-tracks] Re-implement GPS tracks workload in Angular Re-implement the Tools-GPS-Tracks benchmark workload using Angular 19 standalone components, reactive state management, and template-driven change detection across all six analysis views while preserving full feature parity and deterministic benchmark steps. --- .../tools-gps-tracks/README.md | 4 +- suites-experimental/tools-gps-tracks/build.js | 10 +- .../tools-gps-tracks/dist/LICENSE | 265 ++ .../tools-gps-tracks/dist/index.html | 525 +-- .../tools-gps-tracks/dist/styles.css | 2 +- .../tools-gps-tracks/dist/styles.css.map | 4 +- .../dist/tools-gps-tracks.mjs | 4178 +++++++++++++---- .../dist/tools-gps-tracks.mjs.map | 8 +- .../tools-gps-tracks/package-lock.json | 119 +- .../tools-gps-tracks/package.json | 9 +- .../tools-gps-tracks/src/app.component.ts | 2104 +++++++++ .../tools-gps-tracks/src/app.ts | 2342 +-------- .../tools-gps-tracks/src/charts.ts | 26 + .../src/components/combined-tab.component.ts | 1309 ++++++ .../src/components/courses-tab.component.ts | 471 ++ .../src/components/details-tab.component.ts | 1136 +++++ .../src/components/evolution-tab.component.ts | 798 ++++ .../src/components/graphs-tab.component.ts | 556 +++ .../src/components/insights-tab.component.ts | 1525 ++++++ .../tools-gps-tracks/src/css/styles.css | 9 + .../tools-gps-tracks/src/index.html | 525 +-- .../src/services/track-state.service.ts | 301 ++ .../src/tabs/accumulated_progress.ts | 127 +- .../tools-gps-tracks/src/tabs/combined.ts | 994 +--- .../tools-gps-tracks/src/tabs/courses.ts | 578 ++- .../tools-gps-tracks/src/tabs/details.ts | 779 +-- .../tools-gps-tracks/src/tabs/insights.ts | 1009 +--- .../tools-gps-tracks/src/tabs/progress.ts | 2045 ++++---- .../tools-gps-tracks/tsconfig.json | 6 +- 29 files changed, 13301 insertions(+), 8463 deletions(-) create mode 100644 suites-experimental/tools-gps-tracks/src/app.component.ts create mode 100644 suites-experimental/tools-gps-tracks/src/components/combined-tab.component.ts create mode 100644 suites-experimental/tools-gps-tracks/src/components/courses-tab.component.ts create mode 100644 suites-experimental/tools-gps-tracks/src/components/details-tab.component.ts create mode 100644 suites-experimental/tools-gps-tracks/src/components/evolution-tab.component.ts create mode 100644 suites-experimental/tools-gps-tracks/src/components/graphs-tab.component.ts create mode 100644 suites-experimental/tools-gps-tracks/src/components/insights-tab.component.ts create mode 100644 suites-experimental/tools-gps-tracks/src/services/track-state.service.ts diff --git a/suites-experimental/tools-gps-tracks/README.md b/suites-experimental/tools-gps-tracks/README.md index ca1dad4d18..02650cecf5 100644 --- a/suites-experimental/tools-gps-tracks/README.md +++ b/suites-experimental/tools-gps-tracks/README.md @@ -1,8 +1,8 @@ -# Tools-GPS-Tracks Workload +# Tools-GPS-Tracks Workload (Angular) ## Description -This workload simulates an offline-capable GPS track analyzer and activity dashboard (`weg-strasse`). It parses binary and XML activity tracks (`.fit`, `.gpx`, `.tcx`, `.kml`) compressed with `gzip`, persists activity data in IndexedDB, renders interactive Leaflet vector maps with Canvas polylines, and computes physiological and geospatial analytics plotted with `uPlot`. +This workload simulates an offline-capable GPS track analyzer and activity dashboard (`weg-strasse`) built with Angular 19 standalone `@Component`s (`AppComponent`, `GraphsTabComponent`, `InsightsTabComponent`, `DetailsTabComponent`, `CombinedTabComponent`, `EvolutionTabComponent`, `CoursesTabComponent`) and `TrackStateService`. It parses binary and XML activity tracks (`.fit`, `.gpx`, `.tcx`, `.kml`) compressed with `gzip`, persists activity data in IndexedDB, and computes physiological and geospatial analytics rendered via Angular templates (`*ngIf`, `*ngFor`, `ChangeDetectorRef.detectChanges()`) and `uPlot` Canvas charts. ## Benchmark Steps diff --git a/suites-experimental/tools-gps-tracks/build.js b/suites-experimental/tools-gps-tracks/build.js index 2e7df211f9..0c0f8cbe8f 100644 --- a/suites-experimental/tools-gps-tracks/build.js +++ b/suites-experimental/tools-gps-tracks/build.js @@ -52,7 +52,7 @@ async function copyStaticAssets() { } async function collectLicenses() { - const deps = ['uplot', 'fit-file-parser']; + const deps = ['uplot', 'fit-file-parser', '@angular/core', 'rxjs', 'zone.js']; let output = ''; try { @@ -62,8 +62,12 @@ async function collectLicenses() { for (const dep of deps) { try { - const licensePath = path.join('node_modules', dep, 'LICENSE'); - const content = await readFile(licensePath, 'utf-8'); + let content; + try { + content = await readFile(path.join('node_modules', dep, 'LICENSE'), 'utf-8'); + } catch { + content = await readFile(path.join('node_modules', dep, 'LICENSE.txt'), 'utf-8'); + } output += `\n\n------------------------------------------------------------------------------\n${dep.toUpperCase()} LICENSE\n------------------------------------------------------------------------------\n\n${content}\n`; } catch (e) { console.warn(`Could not find license for ${dep}`); diff --git a/suites-experimental/tools-gps-tracks/dist/LICENSE b/suites-experimental/tools-gps-tracks/dist/LICENSE index ab7852cb57..fc1bc78d35 100644 --- a/suites-experimental/tools-gps-tracks/dist/LICENSE +++ b/suites-experimental/tools-gps-tracks/dist/LICENSE @@ -90,6 +90,271 @@ SOFTWARE. +------------------------------------------------------------------------------ +@ANGULAR/CORE LICENSE +------------------------------------------------------------------------------ + +The MIT License + +Copyright (c) 2010-2025 Google LLC. https://angular.dev/license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +------------------------------------------------------------------------------ +RXJS LICENSE +------------------------------------------------------------------------------ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2015-2018 Google, Inc., Netflix, Inc., Microsoft Corp. and contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + +------------------------------------------------------------------------------ +ZONE.JS LICENSE +------------------------------------------------------------------------------ + +The MIT License + +Copyright (c) 2010-2025 Google LLC. https://angular.dev/license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + ------------------------------------------------------------------------------ BUNDLED FONT ASSETS LICENSE (MATERIAL SYMBOLS) ------------------------------------------------------------------------------ diff --git a/suites-experimental/tools-gps-tracks/dist/index.html b/suites-experimental/tools-gps-tracks/dist/index.html index 883ffbaddf..5c92f45a08 100644 --- a/suites-experimental/tools-gps-tracks/dist/index.html +++ b/suites-experimental/tools-gps-tracks/dist/index.html @@ -3,7 +3,7 @@ - Weg — GPS Analysis + Weg — GPS Analysis (Angular) @@ -19,528 +19,7 @@ -
- - - - - - - - - -
- - - - - -
-
- - - - - - -
- -
-
-
- - - - - - - - - - - - - -
- -
-
- - -
- - -
-
- - - -
-
- no_sim -
Select a track to view analysis
-
-
-
- -
-
-
- no_sim -
Select a track for insights
-
-
-
- -
-
-
- no_sim -
Select a track for details
-
-
-
- -
-
-
- no_sim -
Select a track for combined analysis
-
-
-
- -
-
-
- no_sim -
Select a track for progress analysis
-
-
-
- -
-
-
- route -
No courses created yet
-
-
-
-
-
-
+
diff --git a/suites-experimental/tools-gps-tracks/dist/styles.css b/suites-experimental/tools-gps-tracks/dist/styles.css index 900beeba60..5bef531784 100644 --- a/suites-experimental/tools-gps-tracks/dist/styles.css +++ b/suites-experimental/tools-gps-tracks/dist/styles.css @@ -1,2 +1,2 @@ -.uplot,.uplot *,.uplot *:before,.uplot *:after{box-sizing:border-box}.uplot{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5;width:min-content}.u-title{text-align:center;font-size:18px;font-weight:700}.u-wrap{position:relative;user-select:none}.u-over,.u-under{position:absolute}.u-under{overflow:hidden}.uplot canvas{display:block;position:relative;width:100%;height:100%}.u-axis{position:absolute}.u-legend{font-size:14px;margin:auto;text-align:center}.u-inline{display:block}.u-inline *{display:inline-block}.u-inline tr{margin-right:16px}.u-legend th{font-weight:600}.u-legend th>*{vertical-align:middle;display:inline-block}.u-legend .u-marker{width:1em;height:1em;margin-right:4px;background-clip:padding-box!important}.u-inline.u-live th:after{content:":";vertical-align:middle}.u-inline:not(.u-live) .u-value{display:none}.u-series>*{padding:4px}.u-series th{cursor:pointer}.u-legend .u-off>*{opacity:.3}.u-select{background:#00000012;position:absolute;pointer-events:none}.u-cursor-x,.u-cursor-y{position:absolute;left:0;top:0;pointer-events:none;will-change:transform}.u-hz .u-cursor-x,.u-vt .u-cursor-y{height:100%;border-right:1px dashed #607D8B}.u-hz .u-cursor-y,.u-vt .u-cursor-x{width:100%;border-bottom:1px dashed #607D8B}.u-cursor-pt{position:absolute;top:0;left:0;border-radius:50%;border:0 solid;pointer-events:none;will-change:transform;background-clip:padding-box!important}.u-axis.u-off,.u-select.u-off,.u-cursor-x.u-off,.u-cursor-y.u-off,.u-cursor-pt.u-off{display:none}@font-face{font-family:Material Symbols Rounded;font-style:normal;font-weight:100 700;src:url("./material_symbols_rounded.woff2") format("woff2")}:root{--bg: #0e0e10;--surface: #18181b;--surface2: #222226;--border: #2e2e34;--border2: #3a3a42;--text: #e8e8ec;--text-muted: #888896;--text-dim: #555564;--theme-color: #3b82f6;--accent: var(--theme-color);--accent-hover: color-mix(in srgb, var(--theme-color) 80%, white);--danger: #ef4444;--sidebar-w: 230px;--fs-s: 10px;--fs-m: 12px;--fs-l: 14px;--is-s: 16px;--is-m: 20px;--handle-color: #3b82f6}.font-s{font-size:10px}.font-m{font-size:12px}.font-l{font-size:14px}*{box-sizing:border-box}body,html{margin:0;padding:0;width:100%;height:100%;background:var(--bg);color:var(--text);font-family:system-ui,-apple-system,sans-serif;font-size:var(--fs-m)}body{opacity:1}body.loading-fonts{opacity:0}button{font-family:inherit;cursor:pointer;font-size:var(--fs-m)}.material-symbols-rounded{font-family:Material Symbols Rounded;font-weight:400;font-style:normal;font-size:var(--is-m);line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-smoothing:antialiased;font-variation-settings:"FILL" 0,"wght" 400,"GRAD" 0,"opsz" 24}#app{display:flex;width:100vw;height:100vh;overflow:hidden}.hidden{display:none!important}#global-loader{position:fixed;inset:0;background:#000000b3;z-index:10000;display:flex;align-items:center;justify-content:center}.loader-box{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:0;display:flex;flex-direction:row;align-items:stretch;color:var(--text);font-weight:700;box-shadow:0 4px 20px #00000080;max-width:450px;width:90%;overflow:hidden;position:relative}#loader-close{position:absolute;top:12px;right:12px;background:none;border:none;color:var(--text-muted);cursor:pointer;padding:4px;border-radius:50%;display:flex;align-items:center;justify-content:center}#loader-close:hover{background:var(--surface2);color:var(--text)}.loader-icon-wrap{background:color-mix(in srgb,var(--accent) 10%,transparent);display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px;border-right:1px solid var(--border);gap:8px}.loader-icon-wrap>span{font-size:var(--fs-l);color:var(--accent)}#loader-warning-count{font-size:var(--fs-m);color:#f59e0b;font-weight:700;display:none;align-items:center;gap:4px}.loader-content{padding:24px;flex:1;display:flex;flex-direction:column;gap:12px;justify-content:center}#loader-text{font-size:var(--fs-l);font-weight:700;color:var(--text)}#loader-filename{font-size:var(--fs-m);color:var(--text-muted);font-weight:400;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:300px}#loader-progress-wrap{width:300px;height:4px;background:var(--surface2);border-radius:2px;margin-top:4px;overflow:hidden}#loader-subtext{font-size:var(--fs-m);color:var(--text-muted);font-weight:400;display:flex;align-items:center;justify-content:space-between;width:300px;margin-top:0}.progress-index{text-align:left}.progress-total{text-align:right}#loader-progress-bar{width:0%;height:100%;background:var(--accent)}#sidebar{width:var(--sidebar-w);flex-shrink:0;display:flex;flex-direction:column;background:var(--surface);border-right:1px solid var(--border);z-index:10}#sidebar-header{padding:16px 12px;border-bottom:1px solid var(--border)}.logo{display:flex;align-items:center;gap:10px}.logo-icon{color:var(--accent);font-size:var(--fs-l)}.logo-title{font-weight:800;font-size:var(--fs-l);letter-spacing:-.5px}.logo-sub{font-size:var(--fs-s);text-transform:uppercase;color:var(--text-dim);font-weight:700;letter-spacing:1px;margin-top:-2px}#drop-zone{margin:12px;padding:20px 12px;border:2px dashed var(--border2);border-radius:12px;display:flex;flex-direction:column;align-items:center;text-align:center;position:relative}#drop-zone.drop-active{border-color:var(--accent);background:color-mix(in srgb,var(--theme-color) 5%,transparent)}.drop-icon{font-size:var(--is-m);color:var(--text-muted);margin-bottom:4px}.drop-primary{font-size:var(--fs-m);font-weight:600;color:var(--text)}.drop-formats{display:flex;justify-content:center;gap:6px;margin-top:8px}.drop-formats .badge{background:var(--surface2);color:var(--text-dim);font-size:var(--fs-s);padding:2px 6px}.drop-browse-container{margin-top:12px;font-size:var(--fs-s);color:var(--text-muted);display:flex;align-items:center;justify-content:center;gap:2px}.drop-browse{color:var(--accent);font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:4px}.drop-browse .material-symbols-rounded{font-size:var(--fs-l)}.drop-browse:hover{color:var(--accent-hover)}.drop-separator{margin:0 6px;color:var(--border2);vertical-align:middle}#track-list-header{display:flex;align-items:center;justify-content:space-between;padding:12px 12px 8px}.section-label{font-size:var(--fs-s);font-weight:700;text-transform:uppercase;color:var(--text-dim);letter-spacing:.5px}.header-actions{display:flex;gap:0}#track-controls,#sort-controls{padding:8px 12px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--border)}.search-bar{display:flex;background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:2px 4px;align-items:center}.search-icon{font-size:var(--is-s);color:var(--text-dim);margin-left:4px}.search-bar input{flex:1;background:transparent;border:none;padding:4px 6px;color:var(--text);font-size:var(--fs-m)}.search-bar input:focus{outline:none}.icon-btn.mini{width:20px;height:20px;color:var(--text-dim)}.icon-btn.mini .material-symbols-rounded{font-size:var(--is-s)}.icon-btn.mini.active{color:var(--accent)}.sort-ctrl{display:flex;align-items:center;gap:8px}.sort-ctrl label{font-size:var(--fs-s);color:var(--text-dim);text-transform:uppercase;font-weight:600}.sort-select-btn{display:flex;align-items:center;gap:6px;background:var(--surface2);border:1px solid var(--border);padding:4px 8px;border-radius:6px;flex:1;height:24px;box-sizing:border-box;font-size:var(--fs-s);color:var(--text-muted)}.sort-select-btn:hover{border-color:var(--accent);color:var(--text)}.sort-select-btn .material-symbols-rounded{font-size:var(--is-s)}.sort-select-btn .arrow{font-size:var(--fs-l);margin-left:auto;opacity:.5}#filter-panel{padding:12px;background:var(--surface2);border-bottom:1px solid var(--border);display:flex;flex-direction:column;gap:12px}#filter-panel.hidden{display:none}.filter-group{display:flex;flex-direction:column;gap:4px}.filter-group label{font-size:var(--fs-s);font-weight:600;text-transform:uppercase;color:var(--text-dim);display:flex;align-items:center;gap:6px}.filter-group label .material-symbols-rounded{font-size:var(--is-s);opacity:.7}.filter-metrics-grid{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}.mini-pill{width:28px;height:28px;display:flex;align-items:center;justify-content:center;background:var(--surface);border:1px solid var(--border);border-radius:6px;color:var(--text-dim);cursor:pointer}.mini-pill:hover{border-color:var(--text-muted);color:var(--text-muted)}.mini-pill.active{background:var(--accent);border-color:var(--accent);color:#fff}.mini-pill .material-symbols-rounded{font-size:var(--is-s)}.filter-row{display:flex;align-items:center;gap:6px}.filter-row input{flex:1;background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:4px 6px;color:var(--text);font-size:var(--fs-s)}.filter-row span{font-size:var(--fs-s);color:var(--text-dim)}#filter-panel input:focus{border-color:var(--accent);outline:none}.filter-footer{display:flex;justify-content:flex-end;margin-top:4px}#track-list{flex:1;overflow-y:auto;padding:4px 0;scrollbar-width:none}#track-list::-webkit-scrollbar{width:0;height:0;display:none}#track-list::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}#track-list-empty{padding:40px 20px;text-align:center;color:var(--text-dim);font-size:var(--fs-m)}.track-item{display:flex;align-items:center;padding:6px 8px;gap:0;cursor:pointer;border-left:3px solid transparent}.track-item:hover{background:#ffffff08}.track-item.selected{background:color-mix(in srgb,var(--theme-color) 8%,transparent);border-left-color:var(--accent)}.track-color{width:3px;border-radius:1px;flex-shrink:0;margin-right:8px;align-self:stretch}.track-info{flex:1;min-width:0;margin-right:2px}.track-name{font-size:var(--fs-m);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:1px}.track-meta{font-size:var(--fs-s);color:var(--text-dim);display:flex;gap:6px;align-items:center}.track-item .icon-btn.mini{width:22px;height:22px;padding:0;margin:0}.badge{font-size:var(--fs-s);background:var(--surface2);padding:1px 4px;border-radius:3px;font-weight:700;color:var(--text-muted)}.track-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px;overflow:hidden;max-height:32px}.track-tag{font-size:var(--fs-s);font-weight:700;color:var(--text-dim);background:#ffffff08;border:1px solid var(--border);padding:1px 5px;border-radius:3px;white-space:nowrap}.track-item.selected .track-tag{border-color:#ffffff1a;color:var(--text-muted)}#sidebar-resizer{width:4px;cursor:col-resize;background:transparent;flex-shrink:0;z-index:1000;margin-left:-2px;margin-right:-2px;user-select:none}#sidebar-resizer:hover,#sidebar-resizer.dragging{background:var(--handle-color)}body.dragging-sidebar{user-select:none;cursor:col-resize!important}#main{flex:1;display:flex;flex-direction:column;min-width:0}#map-container{flex:1;position:relative;min-height:100px}#map-container.editing-mode{border:4px solid var(--accent);box-shadow:0 0 15px var(--accent);z-index:1000}#map{width:100%;height:100%;background:var(--bg)}#map-controls{position:absolute;top:12px;left:12px;z-index:1000;display:flex;align-items:center;gap:8px}#basemap-switcher{display:flex;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:2px;height:24px;box-sizing:border-box;box-shadow:0 4px 12px #0000004d;align-items:center;gap:0}#selected-extra-map{font-size:var(--fs-s);font-weight:700;color:var(--accent);padding:0 6px;max-width:120px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}#selected-extra-map.hidden{display:none}#btn-extra-layers{border:none!important;border-left:1px solid var(--border)!important;border-radius:0!important;margin-left:0!important;padding-left:6px!important;padding-right:0!important;width:auto!important;height:100%!important;background:transparent!important}#extra-layers-menu{position:absolute;top:40px;right:0;background:var(--surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 20px #00000080;max-height:300px;overflow-y:auto;width:200px;z-index:1000;padding:4px}#extra-layers-menu.hidden{display:none}.extra-layers-header{font-size:var(--fs-s);font-weight:700;color:var(--text-dim);text-transform:uppercase;padding:6px 8px;border-bottom:1px solid var(--border);margin-bottom:4px}.extra-layers-search{padding:4px 8px;border-bottom:1px solid var(--border);margin-bottom:4px}#extra-layers-search-input{width:100%;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:var(--fs-s);padding:4px 8px;outline:none}#extra-layers-search-input:focus{border-color:var(--accent)}.extra-layers-license{font-size:var(--fs-s);color:var(--text-dim);padding:4px 8px;border-bottom:1px solid var(--border);margin-bottom:4px}.extra-layers-license a{color:var(--accent);text-decoration:none}.extra-layers-license a:hover{text-decoration:underline}.extra-layer-row{margin-bottom:2px}.extra-layer-item{display:block;width:100%;text-align:left;background:transparent;border:none;color:var(--text-muted);padding:4px 10px 2px;font-size:var(--fs-s);font-weight:600;border-radius:4px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.extra-layer-item:hover{background:var(--surface2);color:var(--text)}.extra-layer-attribution{font-size:var(--fs-s);color:var(--text-dim);padding:0 10px 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#map-loader{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:0 10px;height:24px;box-sizing:border-box;display:flex;align-items:center;gap:8px;font-size:var(--fs-s);font-weight:600;color:var(--text-muted);box-shadow:0 4px 12px #0000004d}.spinner-sm{width:12px;height:12px;border:2px solid var(--surface2);border-top-color:var(--accent);border-radius:50%}.bm-btn{background:transparent;border:none;color:var(--text-muted);padding:2px 6px;font-size:var(--fs-s);font-weight:600;border-radius:6px}.bm-btn:hover{color:var(--text)}.bm-btn.active{background:var(--surface2);color:var(--accent)}.map-cursor-dot{pointer-events:none}.dot-inner{width:12px;height:12px;background:#fff;border:2px solid #000;border-radius:50%;box-shadow:0 0 0 2px #ffffff80}#map-cursor-info{position:absolute;top:12px;right:12px;z-index:1000;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-size:var(--fs-s);color:var(--text);box-shadow:0 4px 12px #0000004d;display:none;pointer-events:none}#resize-handle{height:6px;background:var(--bg);border-top:1px solid var(--border);border-bottom:1px solid var(--border);cursor:ns-resize;display:flex;align-items:center;justify-content:center;flex-shrink:0;z-index:100}#resize-handle:hover{background:var(--handle-color)}.handle-grip{width:32px;height:2px;background:var(--border2);border-radius:1px}#chart-panel{display:flex;flex-direction:column;background:var(--surface);overflow:hidden;flex:1;width:100%;height:100%;min-height:0}#tab-nav{display:flex;padding:0 12px;border-bottom:1px solid var(--border);gap:4px}.tab-btn{background:transparent;border:none;border-bottom:2px solid transparent;color:var(--text-dim);padding:10px 12px;font-size:var(--fs-m);font-weight:700;display:flex;align-items:center;gap:6px}.tab-btn:hover{color:var(--text-muted)}.tab-btn.active{color:var(--accent);border-bottom-color:var(--accent)}.tab-btn .material-symbols-rounded{font-size:var(--is-s)}.tab-content{display:none;flex:1;min-height:0}.tab-content.active{display:flex;flex-direction:column;overflow-y:auto;scrollbar-width:none}.tab-content.active::-webkit-scrollbar{width:0;height:0}.tab-content.active::-webkit-scrollbar-track{background:transparent}.tab-content.active::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}.tab-content.active::-webkit-scrollbar-thumb:hover{background:var(--text-dim)}#chart-toolbar{display:flex;align-items:center;padding:6px 12px;gap:12px;border-bottom:1px solid var(--border);background:var(--bg);min-height:40px;position:sticky;top:0;z-index:100}.icon-btn{background:transparent;border:1px solid transparent;color:var(--text-muted);width:24px;height:24px;border-radius:6px;display:flex;align-items:center;justify-content:center}.icon-btn.hidden{display:none}.icon-btn:hover{background:var(--surface2);color:var(--text)}.icon-btn.active{background:var(--surface2);color:var(--accent)}.icon-btn.danger:hover{background:#ef44441f;color:var(--danger)}.icon-btn .material-symbols-rounded{font-size:var(--fs-l)}#btn-metric-menu{flex:0 0 auto}#metric-pills{display:flex;gap:6px;flex:1;overflow:hidden}.metric-pill:not(.active){display:none}.metric-pill.overflow-hidden{display:none!important}#pill-overflow{color:var(--text-muted);font-weight:700;padding:0 4px;align-self:flex-end}.metric-pill{height:24px;padding:0 8px;border-radius:12px;border:1px solid var(--border);background:var(--surface2);color:var(--text-muted);font-size:var(--fs-s);font-weight:500;display:flex;align-items:center;gap:4px;white-space:nowrap}.metric-pill .material-symbols-rounded{font-size:var(--fs-m)}.metric-pill.active{background:color-mix(in srgb,var(--pill-color) 15%,var(--surface2));border-color:var(--pill-color);color:var(--pill-color)}.metric-pill.disabled{opacity:.3;filter:grayscale(1);cursor:default}#chart-options{display:flex;align-items:center;gap:0;margin-left:auto}.seg-ctrl{display:flex;background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:2px;height:24px;box-sizing:border-box}.seg-btn{background:transparent;border:none;color:var(--text-dim);padding:0 8px;font-size:var(--fs-s);font-weight:700;border-radius:4px;display:flex;align-items:center;gap:6px;height:100%}.seg-btn .material-symbols-rounded{font-size:var(--fs-m)}.seg-btn.active{background:var(--bg);color:var(--text);box-shadow:0 1px 3px #0003}#chart-stats{padding:4px 14px;border-bottom:1px solid var(--border);background:var(--surface2)}#chart-stats.hidden{display:none}#chart-stats-wrap{display:flex;flex-direction:column;gap:2px}.stats-row{display:flex;align-items:center;gap:16px}.stats-row-label{width:45px;font-size:var(--fs-s);font-weight:700;text-transform:uppercase;letter-spacing:.8px;color:var(--text-muted);white-space:nowrap}.chart-row-stats-container{display:flex;flex:1;align-items:center;justify-content:space-between}.chart-row-right-actions{width:130px;display:none;align-items:center;justify-content:flex-end;flex-shrink:0}.with-histogram .chart-row-right-actions{display:flex}.chart-stats-total,.chart-stats-selection{display:flex;gap:10px;font-size:var(--fs-s);color:var(--text-dim);align-items:center;white-space:nowrap;font-weight:500}.chart-stats-selection{margin-left:auto;position:relative}.chart-stats-selection:after{content:"";position:absolute;bottom:-6px;left:0;right:0;height:2px;background-color:var(--sel-color);pointer-events:none}.all-chip{background:var(--surface2);color:var(--text-muted);font-weight:500;padding:2px;border-radius:4px;font-size:var(--fs-m);margin-right:4px;cursor:pointer;border:1px solid var(--border);display:flex;align-items:center;justify-content:center}.all-chip:hover{background:var(--border);color:var(--text)}.sel-tag{background:var(--surface2);color:var(--text-muted);font-weight:500;padding:2px;border-radius:4px;font-size:var(--fs-m);margin-right:4px;display:flex;align-items:center;justify-content:center;border:1px solid var(--border)}.mm-item{display:flex;align-items:center;gap:2px;white-space:nowrap}.mm-icon{font-size:var(--fs-m);color:var(--text-dim)}.uplot{color:var(--text-muted)!important}.u-title,.u-legend{display:none}.chart-row .u-select{background:color-mix(in srgb,var(--chart-color, #3b82f6) 12%,transparent)!important;border:1px solid color-mix(in srgb,var(--chart-color, #3b82f6) 35%,transparent)!important}.u-cursor-x{border-left:1px dashed rgba(255,255,255,.55)!important}.u-cursor-y{display:none!important}.sel-fill{position:absolute;top:0;background:color-mix(in srgb,var(--theme-color) 8%,transparent);border-left:1px solid color-mix(in srgb,var(--theme-color) 30%,transparent);border-right:1px solid rgba(148,163,184,.4);pointer-events:none}.sel-handle{position:absolute;top:50%;transform:translate(-50%,-50%);width:8px;height:24px;background:#ffffffd9;border:1px solid rgba(0,0,0,.3);border-radius:4px;cursor:ew-resize;pointer-events:auto;display:flex;align-items:center;justify-content:center;z-index:10}.sel-handle:after{content:"";width:2px;height:10px;border-left:1px solid rgba(0,0,0,.4);border-right:1px solid rgba(0,0,0,.4)}.sel-handle:hover{background:#fff;transform:translate(-50%,-50%) scale(1.1)}.sel-graph-marker{position:absolute;transform:translate(-50%,-50%);pointer-events:none;z-index:11;background:none!important}.sel-line{position:absolute;top:0;height:100%;width:0;border-left-width:1.5px;border-left-style:solid;pointer-events:none}.sel-line-label{position:absolute;top:4px;font-size:var(--fs-s);font-weight:700;background:#0e0e10eb;color:#fff;padding:2px 5px;border-radius:4px;pointer-events:none;white-space:nowrap;z-index:10;border:1px solid var(--border)}#charts-container{flex:1;overflow-y:auto;overflow-x:hidden;padding:6px 0 4px;scrollbar-width:none}#charts-container::-webkit-scrollbar{width:0;height:0}#charts-container::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}.fixed-x-label{position:absolute;bottom:4px;font-size:var(--fs-s);font-family:system-ui,sans-serif;color:#555564;z-index:10;pointer-events:none}.fixed-x-max{right:0;text-align:right}.chart-row-body{display:flex;flex-direction:row;padding:0 14px;min-width:0;overflow:hidden}.chart-row-body>div:first-child{flex:1;min-width:0}.hist-col{width:130px;flex-shrink:0;border-left:1px solid var(--border);margin-left:20px;margin-right:0;display:none;align-items:center;justify-content:center;cursor:crosshair}.hist-col.visible{display:flex}.hist-canvas{display:block}#hist-line{position:fixed;height:0;border-top:1px dashed rgba(255,255,255,.25);pointer-events:none;display:none;z-index:10000}#hist-tooltip{position:fixed;background:var(--surface);border:1px solid var(--border2);border-radius:5px;padding:8px 10px;pointer-events:none;display:none;z-index:10001;box-shadow:0 4px 15px #00000080;font-size:var(--fs-s)}.hist-tt-header{font-weight:800;margin-bottom:6px;padding-left:8px;border-left:3px solid var(--accent);color:var(--text)}.hist-tt-grid{display:grid;grid-template-columns:1fr auto auto;gap:10px;align-items:baseline}.hist-tt-label{font-size:var(--fs-s);color:var(--text-muted)}.hist-tt-value{font-size:var(--fs-s);color:var(--text);text-align:right;font-variant-numeric:tabular-nums}.hist-tt-pct{font-size:var(--fs-s);color:var(--text-dim);text-align:right;min-width:36px;font-variant-numeric:tabular-nums}.hist-tt-grid.sel-row{margin-top:2px;opacity:.9}.hist-tt-label.sel{color:var(--accent);font-weight:700}.chart-row{border-bottom:1px solid var(--border)}.chart-row:last-child{border-bottom:none}.chart-row-header{display:flex;align-items:center;gap:12px;padding:8px 14px 4px;min-height:28px}.progress-chart-row{display:flex;flex-direction:column}.progress-chart-row .chart-row-header{height:36px;box-sizing:border-box;padding-top:0;padding-bottom:0}.progress-chart-row .chart-row-actions{margin-left:auto}.progress-chart-row .chart-row-body{flex:1;padding:0}.chart-row-label-group{display:flex;align-items:center;gap:8px;flex-shrink:0;width:140px}.chart-row-actions{display:flex;align-items:center;gap:0}.chart-row-icon{font-size:var(--is-s);color:var(--chart-color)}.chart-row-label{font-size:var(--fs-m);font-weight:700;text-transform:uppercase;letter-spacing:.8px;color:var(--text-muted);white-space:nowrap}.track-picker-popup{padding:8px;background:var(--surface);color:var(--text);border-radius:8px;min-width:160px}.picker-header{font-size:var(--fs-s);text-transform:uppercase;font-weight:700;color:var(--text-dim);margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid var(--border)}.picker-list{display:flex;flex-direction:column;gap:2px}.picker-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;cursor:pointer}.picker-item:hover{background:var(--surface2)}.picker-color{width:3px;height:14px;border-radius:1px}.picker-info{display:flex;flex-direction:column;min-width:0}.picker-name{font-size:var(--fs-s);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:180px}.modal-backdrop{position:fixed;inset:0;background:#000000bf;backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:20000}.modal-content{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:24px;width:100%;max-width:320px;box-shadow:0 20px 40px #00000080;display:flex;flex-direction:column;gap:16px}.modal-title{font-size:var(--fs-l);font-weight:800;color:var(--text)}.modal-body{font-size:var(--fs-m);color:var(--text-muted);line-height:1.5}.modal-input-wrap{display:flex;flex-direction:column;gap:8px}.modal-input-label{font-size:var(--fs-s);font-weight:700;text-transform:uppercase;color:var(--text-dim)}.modal-input{background:var(--bg);border:1px solid var(--border2);border-radius:6px;padding:10px;color:var(--text);font-size:var(--fs-l);font-weight:800;text-align:center;letter-spacing:4px}.modal-input:focus{outline:none;border-color:var(--accent)}.modal-actions{display:flex;gap:12px;margin-top:8px}.modal-btn{flex:1;padding:10px;border-radius:6px;font-size:var(--fs-m);font-weight:700;border:1px solid transparent}.modal-btn.cancel{background:var(--surface2);color:var(--text);border-color:var(--border)}.modal-btn.cancel:hover{background:var(--border)}.modal-btn.confirm{background:var(--danger);color:#fff}.modal-btn.confirm:disabled{opacity:.3;cursor:not-allowed;filter:grayscale(1)}.modal-btn.confirm:not(:disabled):hover{filter:brightness(1.1)}.picker-meta{font-size:var(--fs-s);color:var(--text-dim);font-weight:700}.leaflet-popup-content-wrapper,.leaflet-popup-tip{background:var(--surface)!important;color:var(--text)!important;border:1px solid var(--border)!important;box-shadow:0 4px 12px #0006!important}.leaflet-popup-content{margin:0!important}.leaflet-popup-tip{border:none!important}.map-color-btn{margin-left:4px}.map-color-btn .material-symbols-rounded{font-size:var(--is-s)}.map-color-btn.active{color:var(--chart-color, var(--accent))}.smooth-btn.active{color:var(--accent)}.cur-y-val{position:absolute;left:0;top:0;pointer-events:none;font-size:var(--fs-s);font-weight:700;background:#0e0e10eb;padding:2px 6px;border-radius:4px;border:1px solid rgba(255,255,255,.1);z-index:2000;white-space:nowrap}.cur-y-val.pin{z-index:1000;opacity:.7}#details-view{width:100%;padding:24px;max-width:900px;margin:0 auto}#details-header{margin-bottom:32px}.details-title{font-size:var(--fs-l);font-weight:800;margin-bottom:4px}.details-subtitle{font-size:var(--fs-m);color:var(--text-muted)}.details-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px}.details-card{background:var(--surface2);border:1px solid var(--border);padding:16px;border-radius:12px;display:flex;flex-direction:column;gap:4px}.details-card .material-symbols-rounded{color:var(--accent);margin-bottom:4px;font-size:var(--is-m)}.details-card-label{font-size:var(--fs-s);font-weight:500;text-transform:uppercase;color:var(--text-dim);letter-spacing:.5px}.details-card-value{font-size:var(--fs-l);font-weight:500}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--text-dim);gap:12px;padding:40px 20px}.empty-icon{font-size:var(--fs-l);opacity:.2}.empty-text{font-size:var(--fs-m);font-weight:500}#chart-empty{height:100%}#details-empty{margin-top:40px}#toast-container{position:fixed;bottom:20px;left:50%;transform:translate(-50%);display:flex;flex-direction:column;gap:8px;z-index:9999}.toast{background:var(--surface2);color:var(--text);padding:10px 20px;border-radius:8px;font-size:var(--fs-m);font-weight:600;box-shadow:0 8px 24px #0006;border:1px solid var(--border2)}.toast.error{border-color:var(--danger)}.sort-menu-popup,.metric-menu-popup{position:fixed;z-index:10000;background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:6px;min-width:180px;box-shadow:0 8px 24px #00000080}.menu-item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer;color:var(--text-muted)}.menu-item:hover{background:var(--surface);color:var(--text)}.menu-item.active{color:var(--text);font-weight:600}.menu-item .material-symbols-rounded{font-size:var(--is-s)}.menu-item .item-label{flex:1;font-size:var(--fs-m)}.menu-item .arrow,.menu-item .check{font-size:var(--is-s);color:var(--text-dim)}#insights-view{width:100%;padding:24px;max-width:1000px;margin:0 auto}.insights-grid{column-count:2;column-gap:24px}@media (max-width: 900px){.insights-grid{column-count:1}}.insight-card{display:inline-flex;width:100%;break-inside:avoid;margin-bottom:24px;background:var(--surface2);border:1px solid var(--border);padding:20px;border-radius:12px;flex-direction:column;gap:16px}.insight-title{font-size:var(--fs-m);font-weight:700;text-transform:uppercase;letter-spacing:.8px;display:flex;align-items:center;gap:8px;color:var(--text-muted)}.insight-title .material-symbols-rounded{font-size:var(--is-s)}.insight-chart-container{width:100%;height:250px}.power-curve-table{width:100%;border-collapse:collapse;font-size:var(--fs-m);margin-top:0}.power-curve-table th{text-align:left;color:var(--text-dim);padding:4px 8px;font-weight:600;border-bottom:1px solid var(--border)}.power-curve-table td{padding:6px 8px;border-bottom:1px solid var(--border)}.power-curve-table tr:last-child td{border-bottom:none}.progress-details summary{cursor:pointer;font-size:var(--fs-m);color:var(--text-dim);display:flex;align-items:center;gap:4px;list-style:none}.progress-details summary::-webkit-details-marker{display:none}.progress-details[open] summary .expand-icon{transform:rotate(90deg)}.progress-details summary .material-symbols-rounded{font-size:var(--fs-l)}.power-curve-val{font-weight:700;color:var(--text);text-align:right}.evolution-select-btn{background:none;border:none;cursor:pointer;color:var(--chart-color);padding:0;font-size:var(--fs-l);vertical-align:middle;margin-left:4px}.hr-settings-popup{display:flex;flex-direction:column}.hr-input-row{display:flex;justify-content:space-between;align-items:center;font-size:var(--fs-m);color:var(--text-muted);font-weight:600}.hr-zone-input{background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);width:60px;padding:4px 8px;font-size:var(--fs-m);text-align:right;outline:none}.hr-zone-input:focus{border-color:var(--accent)}.save-btn{background:var(--accent);color:#fff;border:none;border-radius:6px;padding:8px;font-size:12px;font-weight:700;cursor:pointer}.save-btn:hover{background:var(--accent-hover)}.menu-item.active .arrow,.menu-item.active .check{color:var(--accent)}.evolution-toolbar{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;border-bottom:1px solid var(--border);background:var(--bg);min-height:40px}.evolution-toolbar-left,.evolution-toolbar-right{display:flex;align-items:center;gap:12px}.evolution-toolbar .metric-pills{display:flex;gap:6px}.evolution-toolbar .metric-pill{cursor:pointer}.evolution-container{display:flex;flex-direction:column;gap:0px;padding:6px 0 4px}.evolution-card-group{display:flex;flex-direction:column;gap:10px;width:100%}.evolution-legend{display:flex;gap:16px;font-size:12px;color:var(--text-dim);margin-top:0;margin-bottom:0;justify-content:center}.evolution-legend-item{display:flex;align-items:center;gap:6px}.evolution-legend-line{width:16px;height:0;display:inline-block}.evolution-legend-line.solid{border-top:2px solid var(--chart-color)}.evolution-legend-line.dashed{border-top:2px dashed #888888}.evolution-tooltip-title{font-weight:700;margin-bottom:4px}.evolution-tooltip-row{display:flex;justify-content:space-between;gap:15px}.evolution-tooltip-label{color:#8a8a93}.evolution-tooltip-value{font-weight:700}.evolution-empty-text{color:var(--text-dim);font-size:12px;text-align:center;margin-top:20px}.evolution-chart-container{height:250px;flex:1}.distance-progress-card .card-content,.elevation-progress-card .card-content{display:flex;gap:20px}.chart-scroll-container{flex:1;overflow-x:auto;position:relative;background:var(--bg-dim);border-radius:8px;padding:10px;scrollbar-width:none}.chart-scroll-container::-webkit-scrollbar{width:0;height:0;display:none}.accumulated-table-container{width:250px;background:var(--bg-dim);border-radius:8px;padding:15px}.accumulated-table{width:100%;border-collapse:collapse;font-size:var(--fs-m)}.accumulated-table th,.accumulated-table td{padding:4px 8px;text-align:left;border-bottom:1px solid var(--border-color)}.accumulated-table th{color:var(--text-dim);font-weight:500;text-transform:uppercase;font-size:var(--fs-m);letter-spacing:.5px}.accumulated-table td:last-child{text-align:right;font-weight:500;font-family:monospace}.accumulated-table tr:last-child td{border-bottom:none}.chart-scroll-container::-webkit-scrollbar{height:4px}.chart-scroll-container::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}.u-title,.u-legend{font-size:var(--fs-m)!important}.courses-container{padding:16px;display:flex;flex-direction:column;gap:16px}.courses-list{display:flex;flex-direction:column;gap:8px}.course-item{background:var(--surface2);border:1px solid var(--border);border-radius:8px;display:flex;flex-direction:column;cursor:pointer;overflow:hidden}.course-item:hover{background:var(--surface3);border-color:var(--border-high)}.course-item-header{padding:6px 12px;display:flex;align-items:center;gap:12px;width:100%}.course-name{font-weight:600;flex:1}.course-meta{color:var(--text-muted);font-size:var(--fs-s)}.course-actions{display:flex;gap:4px}.course-actions .icon-btn{opacity:.5}.course-item:hover .course-actions .icon-btn{opacity:1}.expand-icon{color:var(--text-muted)}.course-tracks{padding:8px 12px;border-top:1px solid var(--border);background:var(--surface1)}.course-tracks-title{font-size:var(--fs-xs);font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}.course-tracks-table{width:100%;border-collapse:collapse;font-size:var(--fs-s);color:var(--text)}.course-tracks-table th,.course-tracks-table td{padding:6px 8px;text-align:right;border-bottom:1px solid var(--border-low)}.course-tracks-table th:first-child,.course-tracks-table td:first-child,.course-tracks-table th:nth-child(2),.course-tracks-table td:nth-child(2){text-align:left}.course-tracks-table td:not(:first-child){white-space:nowrap}.course-tracks-table th{font-weight:600;color:var(--text-muted);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.5px;white-space:nowrap}.course-tracks-table tr:last-child td{border-bottom:none}.course-tracks-table th:first-child,.course-tracks-table td:first-child{width:100%}.course-track-row:hover{background:var(--surface2)}.course-track-row.selected{background:color-mix(in srgb,var(--theme-color) 8%,transparent)}.track-name-cell.clickable{color:var(--accent);cursor:pointer;font-weight:500}.track-name-cell.clickable:hover{text-decoration:underline}.metric-icon{font-size:16px;vertical-align:middle;margin-right:4px}.metric-icon.duration{color:var(--text-muted)}.metric-icon.speed{color:#4caf50}.metric-icon.power{color:#ff9800}.metric-icon.hr{color:#f44336}.course-point-marker{display:flex;align-items:center;justify-content:center} +.uplot,.uplot *,.uplot *:before,.uplot *:after{box-sizing:border-box}.uplot{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5;width:min-content}.u-title{text-align:center;font-size:18px;font-weight:700}.u-wrap{position:relative;user-select:none}.u-over,.u-under{position:absolute}.u-under{overflow:hidden}.uplot canvas{display:block;position:relative;width:100%;height:100%}.u-axis{position:absolute}.u-legend{font-size:14px;margin:auto;text-align:center}.u-inline{display:block}.u-inline *{display:inline-block}.u-inline tr{margin-right:16px}.u-legend th{font-weight:600}.u-legend th>*{vertical-align:middle;display:inline-block}.u-legend .u-marker{width:1em;height:1em;margin-right:4px;background-clip:padding-box!important}.u-inline.u-live th:after{content:":";vertical-align:middle}.u-inline:not(.u-live) .u-value{display:none}.u-series>*{padding:4px}.u-series th{cursor:pointer}.u-legend .u-off>*{opacity:.3}.u-select{background:#00000012;position:absolute;pointer-events:none}.u-cursor-x,.u-cursor-y{position:absolute;left:0;top:0;pointer-events:none;will-change:transform}.u-hz .u-cursor-x,.u-vt .u-cursor-y{height:100%;border-right:1px dashed #607D8B}.u-hz .u-cursor-y,.u-vt .u-cursor-x{width:100%;border-bottom:1px dashed #607D8B}.u-cursor-pt{position:absolute;top:0;left:0;border-radius:50%;border:0 solid;pointer-events:none;will-change:transform;background-clip:padding-box!important}.u-axis.u-off,.u-select.u-off,.u-cursor-x.u-off,.u-cursor-y.u-off,.u-cursor-pt.u-off{display:none}@font-face{font-family:Material Symbols Rounded;font-style:normal;font-weight:100 700;src:url("./material_symbols_rounded.woff2") format("woff2")}:root{--bg: #0e0e10;--surface: #18181b;--surface2: #222226;--border: #2e2e34;--border2: #3a3a42;--text: #e8e8ec;--text-muted: #888896;--text-dim: #555564;--theme-color: #3b82f6;--accent: var(--theme-color);--accent-hover: color-mix(in srgb, var(--theme-color) 80%, white);--danger: #ef4444;--sidebar-w: 230px;--fs-s: 10px;--fs-m: 12px;--fs-l: 14px;--is-s: 16px;--is-m: 20px;--handle-color: #3b82f6}.font-s{font-size:10px}.font-m{font-size:12px}.font-l{font-size:14px}*{box-sizing:border-box}body,html{margin:0;padding:0;width:100%;height:100%;background:var(--bg);color:var(--text);font-family:system-ui,-apple-system,sans-serif;font-size:var(--fs-m)}body{opacity:1}body.loading-fonts{opacity:0}button{font-family:inherit;cursor:pointer;font-size:var(--fs-m)}.material-symbols-rounded{font-family:Material Symbols Rounded;font-weight:400;font-style:normal;font-size:var(--is-m);line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-smoothing:antialiased;font-variation-settings:"FILL" 0,"wght" 400,"GRAD" 0,"opsz" 24}#app{display:flex;width:100vw;height:100vh;overflow:hidden}app-graphs-tab,app-insights-tab,app-details-tab,app-combined-tab,app-evolution-tab,app-courses-tab{display:contents}.hidden{display:none!important}#global-loader{position:fixed;inset:0;background:#000000b3;z-index:10000;display:flex;align-items:center;justify-content:center}.loader-box{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:0;display:flex;flex-direction:row;align-items:stretch;color:var(--text);font-weight:700;box-shadow:0 4px 20px #00000080;max-width:450px;width:90%;overflow:hidden;position:relative}#loader-close{position:absolute;top:12px;right:12px;background:none;border:none;color:var(--text-muted);cursor:pointer;padding:4px;border-radius:50%;display:flex;align-items:center;justify-content:center}#loader-close:hover{background:var(--surface2);color:var(--text)}.loader-icon-wrap{background:color-mix(in srgb,var(--accent) 10%,transparent);display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px;border-right:1px solid var(--border);gap:8px}.loader-icon-wrap>span{font-size:var(--fs-l);color:var(--accent)}#loader-warning-count{font-size:var(--fs-m);color:#f59e0b;font-weight:700;display:none;align-items:center;gap:4px}.loader-content{padding:24px;flex:1;display:flex;flex-direction:column;gap:12px;justify-content:center}#loader-text{font-size:var(--fs-l);font-weight:700;color:var(--text)}#loader-filename{font-size:var(--fs-m);color:var(--text-muted);font-weight:400;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:300px}#loader-progress-wrap{width:300px;height:4px;background:var(--surface2);border-radius:2px;margin-top:4px;overflow:hidden}#loader-subtext{font-size:var(--fs-m);color:var(--text-muted);font-weight:400;display:flex;align-items:center;justify-content:space-between;width:300px;margin-top:0}.progress-index{text-align:left}.progress-total{text-align:right}#loader-progress-bar{width:0%;height:100%;background:var(--accent)}#sidebar{width:var(--sidebar-w);flex-shrink:0;display:flex;flex-direction:column;background:var(--surface);border-right:1px solid var(--border);z-index:10}#sidebar-header{padding:16px 12px;border-bottom:1px solid var(--border)}.logo{display:flex;align-items:center;gap:10px}.logo-icon{color:var(--accent);font-size:var(--fs-l)}.logo-title{font-weight:800;font-size:var(--fs-l);letter-spacing:-.5px}.logo-sub{font-size:var(--fs-s);text-transform:uppercase;color:var(--text-dim);font-weight:700;letter-spacing:1px;margin-top:-2px}#drop-zone{margin:12px;padding:20px 12px;border:2px dashed var(--border2);border-radius:12px;display:flex;flex-direction:column;align-items:center;text-align:center;position:relative}#drop-zone.drop-active{border-color:var(--accent);background:color-mix(in srgb,var(--theme-color) 5%,transparent)}.drop-icon{font-size:var(--is-m);color:var(--text-muted);margin-bottom:4px}.drop-primary{font-size:var(--fs-m);font-weight:600;color:var(--text)}.drop-formats{display:flex;justify-content:center;gap:6px;margin-top:8px}.drop-formats .badge{background:var(--surface2);color:var(--text-dim);font-size:var(--fs-s);padding:2px 6px}.drop-browse-container{margin-top:12px;font-size:var(--fs-s);color:var(--text-muted);display:flex;align-items:center;justify-content:center;gap:2px}.drop-browse{color:var(--accent);font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:4px}.drop-browse .material-symbols-rounded{font-size:var(--fs-l)}.drop-browse:hover{color:var(--accent-hover)}.drop-separator{margin:0 6px;color:var(--border2);vertical-align:middle}#track-list-header{display:flex;align-items:center;justify-content:space-between;padding:12px 12px 8px}.section-label{font-size:var(--fs-s);font-weight:700;text-transform:uppercase;color:var(--text-dim);letter-spacing:.5px}.header-actions{display:flex;gap:0}#track-controls,#sort-controls{padding:8px 12px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--border)}.search-bar{display:flex;background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:2px 4px;align-items:center}.search-icon{font-size:var(--is-s);color:var(--text-dim);margin-left:4px}.search-bar input{flex:1;background:transparent;border:none;padding:4px 6px;color:var(--text);font-size:var(--fs-m)}.search-bar input:focus{outline:none}.icon-btn.mini{width:20px;height:20px;color:var(--text-dim)}.icon-btn.mini .material-symbols-rounded{font-size:var(--is-s)}.icon-btn.mini.active{color:var(--accent)}.sort-ctrl{display:flex;align-items:center;gap:8px}.sort-ctrl label{font-size:var(--fs-s);color:var(--text-dim);text-transform:uppercase;font-weight:600}.sort-select-btn{display:flex;align-items:center;gap:6px;background:var(--surface2);border:1px solid var(--border);padding:4px 8px;border-radius:6px;flex:1;height:24px;box-sizing:border-box;font-size:var(--fs-s);color:var(--text-muted)}.sort-select-btn:hover{border-color:var(--accent);color:var(--text)}.sort-select-btn .material-symbols-rounded{font-size:var(--is-s)}.sort-select-btn .arrow{font-size:var(--fs-l);margin-left:auto;opacity:.5}#filter-panel{padding:12px;background:var(--surface2);border-bottom:1px solid var(--border);display:flex;flex-direction:column;gap:12px}#filter-panel.hidden{display:none}.filter-group{display:flex;flex-direction:column;gap:4px}.filter-group label{font-size:var(--fs-s);font-weight:600;text-transform:uppercase;color:var(--text-dim);display:flex;align-items:center;gap:6px}.filter-group label .material-symbols-rounded{font-size:var(--is-s);opacity:.7}.filter-metrics-grid{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}.mini-pill{width:28px;height:28px;display:flex;align-items:center;justify-content:center;background:var(--surface);border:1px solid var(--border);border-radius:6px;color:var(--text-dim);cursor:pointer}.mini-pill:hover{border-color:var(--text-muted);color:var(--text-muted)}.mini-pill.active{background:var(--accent);border-color:var(--accent);color:#fff}.mini-pill .material-symbols-rounded{font-size:var(--is-s)}.filter-row{display:flex;align-items:center;gap:6px}.filter-row input{flex:1;background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:4px 6px;color:var(--text);font-size:var(--fs-s)}.filter-row span{font-size:var(--fs-s);color:var(--text-dim)}#filter-panel input:focus{border-color:var(--accent);outline:none}.filter-footer{display:flex;justify-content:flex-end;margin-top:4px}#track-list{flex:1;overflow-y:auto;padding:4px 0;scrollbar-width:none}#track-list::-webkit-scrollbar{width:0;height:0;display:none}#track-list::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}#track-list-empty{padding:40px 20px;text-align:center;color:var(--text-dim);font-size:var(--fs-m)}.track-item{display:flex;align-items:center;padding:6px 8px;gap:0;cursor:pointer;border-left:3px solid transparent}.track-item:hover{background:#ffffff08}.track-item.selected{background:color-mix(in srgb,var(--theme-color) 8%,transparent);border-left-color:var(--accent)}.track-color{width:3px;border-radius:1px;flex-shrink:0;margin-right:8px;align-self:stretch}.track-info{flex:1;min-width:0;margin-right:2px}.track-name{font-size:var(--fs-m);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:1px}.track-meta{font-size:var(--fs-s);color:var(--text-dim);display:flex;gap:6px;align-items:center}.track-item .icon-btn.mini{width:22px;height:22px;padding:0;margin:0}.badge{font-size:var(--fs-s);background:var(--surface2);padding:1px 4px;border-radius:3px;font-weight:700;color:var(--text-muted)}.track-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px;overflow:hidden;max-height:32px}.track-tag{font-size:var(--fs-s);font-weight:700;color:var(--text-dim);background:#ffffff08;border:1px solid var(--border);padding:1px 5px;border-radius:3px;white-space:nowrap}.track-item.selected .track-tag{border-color:#ffffff1a;color:var(--text-muted)}#sidebar-resizer{width:4px;cursor:col-resize;background:transparent;flex-shrink:0;z-index:1000;margin-left:-2px;margin-right:-2px;user-select:none}#sidebar-resizer:hover,#sidebar-resizer.dragging{background:var(--handle-color)}body.dragging-sidebar{user-select:none;cursor:col-resize!important}#main{flex:1;display:flex;flex-direction:column;min-width:0}#map-container{flex:1;position:relative;min-height:100px}#map-container.editing-mode{border:4px solid var(--accent);box-shadow:0 0 15px var(--accent);z-index:1000}#map{width:100%;height:100%;background:var(--bg)}#map-controls{position:absolute;top:12px;left:12px;z-index:1000;display:flex;align-items:center;gap:8px}#basemap-switcher{display:flex;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:2px;height:24px;box-sizing:border-box;box-shadow:0 4px 12px #0000004d;align-items:center;gap:0}#selected-extra-map{font-size:var(--fs-s);font-weight:700;color:var(--accent);padding:0 6px;max-width:120px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}#selected-extra-map.hidden{display:none}#btn-extra-layers{border:none!important;border-left:1px solid var(--border)!important;border-radius:0!important;margin-left:0!important;padding-left:6px!important;padding-right:0!important;width:auto!important;height:100%!important;background:transparent!important}#extra-layers-menu{position:absolute;top:40px;right:0;background:var(--surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 20px #00000080;max-height:300px;overflow-y:auto;width:200px;z-index:1000;padding:4px}#extra-layers-menu.hidden{display:none}.extra-layers-header{font-size:var(--fs-s);font-weight:700;color:var(--text-dim);text-transform:uppercase;padding:6px 8px;border-bottom:1px solid var(--border);margin-bottom:4px}.extra-layers-search{padding:4px 8px;border-bottom:1px solid var(--border);margin-bottom:4px}#extra-layers-search-input{width:100%;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:var(--fs-s);padding:4px 8px;outline:none}#extra-layers-search-input:focus{border-color:var(--accent)}.extra-layers-license{font-size:var(--fs-s);color:var(--text-dim);padding:4px 8px;border-bottom:1px solid var(--border);margin-bottom:4px}.extra-layers-license a{color:var(--accent);text-decoration:none}.extra-layers-license a:hover{text-decoration:underline}.extra-layer-row{margin-bottom:2px}.extra-layer-item{display:block;width:100%;text-align:left;background:transparent;border:none;color:var(--text-muted);padding:4px 10px 2px;font-size:var(--fs-s);font-weight:600;border-radius:4px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.extra-layer-item:hover{background:var(--surface2);color:var(--text)}.extra-layer-attribution{font-size:var(--fs-s);color:var(--text-dim);padding:0 10px 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#map-loader{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:0 10px;height:24px;box-sizing:border-box;display:flex;align-items:center;gap:8px;font-size:var(--fs-s);font-weight:600;color:var(--text-muted);box-shadow:0 4px 12px #0000004d}.spinner-sm{width:12px;height:12px;border:2px solid var(--surface2);border-top-color:var(--accent);border-radius:50%}.bm-btn{background:transparent;border:none;color:var(--text-muted);padding:2px 6px;font-size:var(--fs-s);font-weight:600;border-radius:6px}.bm-btn:hover{color:var(--text)}.bm-btn.active{background:var(--surface2);color:var(--accent)}.map-cursor-dot{pointer-events:none}.dot-inner{width:12px;height:12px;background:#fff;border:2px solid #000;border-radius:50%;box-shadow:0 0 0 2px #ffffff80}#map-cursor-info{position:absolute;top:12px;right:12px;z-index:1000;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-size:var(--fs-s);color:var(--text);box-shadow:0 4px 12px #0000004d;display:none;pointer-events:none}#resize-handle{height:6px;background:var(--bg);border-top:1px solid var(--border);border-bottom:1px solid var(--border);cursor:ns-resize;display:flex;align-items:center;justify-content:center;flex-shrink:0;z-index:100}#resize-handle:hover{background:var(--handle-color)}.handle-grip{width:32px;height:2px;background:var(--border2);border-radius:1px}#chart-panel{display:flex;flex-direction:column;background:var(--surface);overflow:hidden;flex:1;width:100%;height:100%;min-height:0}#tab-nav{display:flex;padding:0 12px;border-bottom:1px solid var(--border);gap:4px}.tab-btn{background:transparent;border:none;border-bottom:2px solid transparent;color:var(--text-dim);padding:10px 12px;font-size:var(--fs-m);font-weight:700;display:flex;align-items:center;gap:6px}.tab-btn:hover{color:var(--text-muted)}.tab-btn.active{color:var(--accent);border-bottom-color:var(--accent)}.tab-btn .material-symbols-rounded{font-size:var(--is-s)}.tab-content{display:none;flex:1;min-height:0}.tab-content.active{display:flex;flex-direction:column;overflow-y:auto;scrollbar-width:none}.tab-content.active::-webkit-scrollbar{width:0;height:0}.tab-content.active::-webkit-scrollbar-track{background:transparent}.tab-content.active::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}.tab-content.active::-webkit-scrollbar-thumb:hover{background:var(--text-dim)}#chart-toolbar{display:flex;align-items:center;padding:6px 12px;gap:12px;border-bottom:1px solid var(--border);background:var(--bg);min-height:40px;position:sticky;top:0;z-index:100}.icon-btn{background:transparent;border:1px solid transparent;color:var(--text-muted);width:24px;height:24px;border-radius:6px;display:flex;align-items:center;justify-content:center}.icon-btn.hidden{display:none}.icon-btn:hover{background:var(--surface2);color:var(--text)}.icon-btn.active{background:var(--surface2);color:var(--accent)}.icon-btn.danger:hover{background:#ef44441f;color:var(--danger)}.icon-btn .material-symbols-rounded{font-size:var(--fs-l)}#btn-metric-menu{flex:0 0 auto}#metric-pills{display:flex;gap:6px;flex:1;overflow:hidden}.metric-pill:not(.active){display:none}.metric-pill.overflow-hidden{display:none!important}#pill-overflow{color:var(--text-muted);font-weight:700;padding:0 4px;align-self:flex-end}.metric-pill{height:24px;padding:0 8px;border-radius:12px;border:1px solid var(--border);background:var(--surface2);color:var(--text-muted);font-size:var(--fs-s);font-weight:500;display:flex;align-items:center;gap:4px;white-space:nowrap}.metric-pill .material-symbols-rounded{font-size:var(--fs-m)}.metric-pill.active{background:color-mix(in srgb,var(--pill-color) 15%,var(--surface2));border-color:var(--pill-color);color:var(--pill-color)}.metric-pill.disabled{opacity:.3;filter:grayscale(1);cursor:default}#chart-options{display:flex;align-items:center;gap:0;margin-left:auto}.seg-ctrl{display:flex;background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:2px;height:24px;box-sizing:border-box}.seg-btn{background:transparent;border:none;color:var(--text-dim);padding:0 8px;font-size:var(--fs-s);font-weight:700;border-radius:4px;display:flex;align-items:center;gap:6px;height:100%}.seg-btn .material-symbols-rounded{font-size:var(--fs-m)}.seg-btn.active{background:var(--bg);color:var(--text);box-shadow:0 1px 3px #0003}#chart-stats{padding:4px 14px;border-bottom:1px solid var(--border);background:var(--surface2)}#chart-stats.hidden{display:none}#chart-stats-wrap{display:flex;flex-direction:column;gap:2px}.stats-row{display:flex;align-items:center;gap:16px}.stats-row-label{width:45px;font-size:var(--fs-s);font-weight:700;text-transform:uppercase;letter-spacing:.8px;color:var(--text-muted);white-space:nowrap}.chart-row-stats-container{display:flex;flex:1;align-items:center;justify-content:space-between}.chart-row-right-actions{width:130px;display:none;align-items:center;justify-content:flex-end;flex-shrink:0}.with-histogram .chart-row-right-actions{display:flex}.chart-stats-total,.chart-stats-selection{display:flex;gap:10px;font-size:var(--fs-s);color:var(--text-dim);align-items:center;white-space:nowrap;font-weight:500}.chart-stats-selection{margin-left:auto;position:relative}.chart-stats-selection:after{content:"";position:absolute;bottom:-6px;left:0;right:0;height:2px;background-color:var(--sel-color);pointer-events:none}.all-chip{background:var(--surface2);color:var(--text-muted);font-weight:500;padding:2px;border-radius:4px;font-size:var(--fs-m);margin-right:4px;cursor:pointer;border:1px solid var(--border);display:flex;align-items:center;justify-content:center}.all-chip:hover{background:var(--border);color:var(--text)}.sel-tag{background:var(--surface2);color:var(--text-muted);font-weight:500;padding:2px;border-radius:4px;font-size:var(--fs-m);margin-right:4px;display:flex;align-items:center;justify-content:center;border:1px solid var(--border)}.mm-item{display:flex;align-items:center;gap:2px;white-space:nowrap}.mm-icon{font-size:var(--fs-m);color:var(--text-dim)}.uplot{color:var(--text-muted)!important}.u-title,.u-legend{display:none}.chart-row .u-select{background:color-mix(in srgb,var(--chart-color, #3b82f6) 12%,transparent)!important;border:1px solid color-mix(in srgb,var(--chart-color, #3b82f6) 35%,transparent)!important}.u-cursor-x{border-left:1px dashed rgba(255,255,255,.55)!important}.u-cursor-y{display:none!important}.sel-fill{position:absolute;top:0;background:color-mix(in srgb,var(--theme-color) 8%,transparent);border-left:1px solid color-mix(in srgb,var(--theme-color) 30%,transparent);border-right:1px solid rgba(148,163,184,.4);pointer-events:none}.sel-handle{position:absolute;top:50%;transform:translate(-50%,-50%);width:8px;height:24px;background:#ffffffd9;border:1px solid rgba(0,0,0,.3);border-radius:4px;cursor:ew-resize;pointer-events:auto;display:flex;align-items:center;justify-content:center;z-index:10}.sel-handle:after{content:"";width:2px;height:10px;border-left:1px solid rgba(0,0,0,.4);border-right:1px solid rgba(0,0,0,.4)}.sel-handle:hover{background:#fff;transform:translate(-50%,-50%) scale(1.1)}.sel-graph-marker{position:absolute;transform:translate(-50%,-50%);pointer-events:none;z-index:11;background:none!important}.sel-line{position:absolute;top:0;height:100%;width:0;border-left-width:1.5px;border-left-style:solid;pointer-events:none}.sel-line-label{position:absolute;top:4px;font-size:var(--fs-s);font-weight:700;background:#0e0e10eb;color:#fff;padding:2px 5px;border-radius:4px;pointer-events:none;white-space:nowrap;z-index:10;border:1px solid var(--border)}#charts-container{flex:1;overflow-y:auto;overflow-x:hidden;padding:6px 0 4px;scrollbar-width:none}#charts-container::-webkit-scrollbar{width:0;height:0}#charts-container::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}.fixed-x-label{position:absolute;bottom:4px;font-size:var(--fs-s);font-family:system-ui,sans-serif;color:#555564;z-index:10;pointer-events:none}.fixed-x-max{right:0;text-align:right}.chart-row-body{display:flex;flex-direction:row;padding:0 14px;min-width:0;overflow:hidden}.chart-row-body>div:first-child{flex:1;min-width:0}.hist-col{width:130px;flex-shrink:0;border-left:1px solid var(--border);margin-left:20px;margin-right:0;display:none;align-items:center;justify-content:center;cursor:crosshair}.hist-col.visible{display:flex}.hist-canvas{display:block}#hist-line{position:fixed;height:0;border-top:1px dashed rgba(255,255,255,.25);pointer-events:none;display:none;z-index:10000}#hist-tooltip{position:fixed;background:var(--surface);border:1px solid var(--border2);border-radius:5px;padding:8px 10px;pointer-events:none;display:none;z-index:10001;box-shadow:0 4px 15px #00000080;font-size:var(--fs-s)}.hist-tt-header{font-weight:800;margin-bottom:6px;padding-left:8px;border-left:3px solid var(--accent);color:var(--text)}.hist-tt-grid{display:grid;grid-template-columns:1fr auto auto;gap:10px;align-items:baseline}.hist-tt-label{font-size:var(--fs-s);color:var(--text-muted)}.hist-tt-value{font-size:var(--fs-s);color:var(--text);text-align:right;font-variant-numeric:tabular-nums}.hist-tt-pct{font-size:var(--fs-s);color:var(--text-dim);text-align:right;min-width:36px;font-variant-numeric:tabular-nums}.hist-tt-grid.sel-row{margin-top:2px;opacity:.9}.hist-tt-label.sel{color:var(--accent);font-weight:700}.chart-row{border-bottom:1px solid var(--border)}.chart-row:last-child{border-bottom:none}.chart-row-header{display:flex;align-items:center;gap:12px;padding:8px 14px 4px;min-height:28px}.progress-chart-row{display:flex;flex-direction:column}.progress-chart-row .chart-row-header{height:36px;box-sizing:border-box;padding-top:0;padding-bottom:0}.progress-chart-row .chart-row-actions{margin-left:auto}.progress-chart-row .chart-row-body{flex:1;padding:0}.chart-row-label-group{display:flex;align-items:center;gap:8px;flex-shrink:0;width:140px}.chart-row-actions{display:flex;align-items:center;gap:0}.chart-row-icon{font-size:var(--is-s);color:var(--chart-color)}.chart-row-label{font-size:var(--fs-m);font-weight:700;text-transform:uppercase;letter-spacing:.8px;color:var(--text-muted);white-space:nowrap}.track-picker-popup{padding:8px;background:var(--surface);color:var(--text);border-radius:8px;min-width:160px}.picker-header{font-size:var(--fs-s);text-transform:uppercase;font-weight:700;color:var(--text-dim);margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid var(--border)}.picker-list{display:flex;flex-direction:column;gap:2px}.picker-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;cursor:pointer}.picker-item:hover{background:var(--surface2)}.picker-color{width:3px;height:14px;border-radius:1px}.picker-info{display:flex;flex-direction:column;min-width:0}.picker-name{font-size:var(--fs-s);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:180px}.modal-backdrop{position:fixed;inset:0;background:#000000bf;backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:20000}.modal-content{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:24px;width:100%;max-width:320px;box-shadow:0 20px 40px #00000080;display:flex;flex-direction:column;gap:16px}.modal-title{font-size:var(--fs-l);font-weight:800;color:var(--text)}.modal-body{font-size:var(--fs-m);color:var(--text-muted);line-height:1.5}.modal-input-wrap{display:flex;flex-direction:column;gap:8px}.modal-input-label{font-size:var(--fs-s);font-weight:700;text-transform:uppercase;color:var(--text-dim)}.modal-input{background:var(--bg);border:1px solid var(--border2);border-radius:6px;padding:10px;color:var(--text);font-size:var(--fs-l);font-weight:800;text-align:center;letter-spacing:4px}.modal-input:focus{outline:none;border-color:var(--accent)}.modal-actions{display:flex;gap:12px;margin-top:8px}.modal-btn{flex:1;padding:10px;border-radius:6px;font-size:var(--fs-m);font-weight:700;border:1px solid transparent}.modal-btn.cancel{background:var(--surface2);color:var(--text);border-color:var(--border)}.modal-btn.cancel:hover{background:var(--border)}.modal-btn.confirm{background:var(--danger);color:#fff}.modal-btn.confirm:disabled{opacity:.3;cursor:not-allowed;filter:grayscale(1)}.modal-btn.confirm:not(:disabled):hover{filter:brightness(1.1)}.picker-meta{font-size:var(--fs-s);color:var(--text-dim);font-weight:700}.leaflet-popup-content-wrapper,.leaflet-popup-tip{background:var(--surface)!important;color:var(--text)!important;border:1px solid var(--border)!important;box-shadow:0 4px 12px #0006!important}.leaflet-popup-content{margin:0!important}.leaflet-popup-tip{border:none!important}.map-color-btn{margin-left:4px}.map-color-btn .material-symbols-rounded{font-size:var(--is-s)}.map-color-btn.active{color:var(--chart-color, var(--accent))}.smooth-btn.active{color:var(--accent)}.cur-y-val{position:absolute;left:0;top:0;pointer-events:none;font-size:var(--fs-s);font-weight:700;background:#0e0e10eb;padding:2px 6px;border-radius:4px;border:1px solid rgba(255,255,255,.1);z-index:2000;white-space:nowrap}.cur-y-val.pin{z-index:1000;opacity:.7}#details-view{width:100%;padding:24px;max-width:900px;margin:0 auto}#details-header{margin-bottom:32px}.details-title{font-size:var(--fs-l);font-weight:800;margin-bottom:4px}.details-subtitle{font-size:var(--fs-m);color:var(--text-muted)}.details-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px}.details-card{background:var(--surface2);border:1px solid var(--border);padding:16px;border-radius:12px;display:flex;flex-direction:column;gap:4px}.details-card .material-symbols-rounded{color:var(--accent);margin-bottom:4px;font-size:var(--is-m)}.details-card-label{font-size:var(--fs-s);font-weight:500;text-transform:uppercase;color:var(--text-dim);letter-spacing:.5px}.details-card-value{font-size:var(--fs-l);font-weight:500}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--text-dim);gap:12px;padding:40px 20px}.empty-icon{font-size:var(--fs-l);opacity:.2}.empty-text{font-size:var(--fs-m);font-weight:500}#chart-empty{height:100%}#details-empty{margin-top:40px}#toast-container{position:fixed;bottom:20px;left:50%;transform:translate(-50%);display:flex;flex-direction:column;gap:8px;z-index:9999}.toast{background:var(--surface2);color:var(--text);padding:10px 20px;border-radius:8px;font-size:var(--fs-m);font-weight:600;box-shadow:0 8px 24px #0006;border:1px solid var(--border2)}.toast.error{border-color:var(--danger)}.sort-menu-popup,.metric-menu-popup{position:fixed;z-index:10000;background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:6px;min-width:180px;box-shadow:0 8px 24px #00000080}.menu-item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer;color:var(--text-muted)}.menu-item:hover{background:var(--surface);color:var(--text)}.menu-item.active{color:var(--text);font-weight:600}.menu-item .material-symbols-rounded{font-size:var(--is-s)}.menu-item .item-label{flex:1;font-size:var(--fs-m)}.menu-item .arrow,.menu-item .check{font-size:var(--is-s);color:var(--text-dim)}#insights-view{width:100%;padding:24px;max-width:1000px;margin:0 auto}.insights-grid{column-count:2;column-gap:24px}@media (max-width: 900px){.insights-grid{column-count:1}}.insight-card{display:inline-flex;width:100%;break-inside:avoid;margin-bottom:24px;background:var(--surface2);border:1px solid var(--border);padding:20px;border-radius:12px;flex-direction:column;gap:16px}.insight-title{font-size:var(--fs-m);font-weight:700;text-transform:uppercase;letter-spacing:.8px;display:flex;align-items:center;gap:8px;color:var(--text-muted)}.insight-title .material-symbols-rounded{font-size:var(--is-s)}.insight-chart-container{width:100%;height:250px}.power-curve-table{width:100%;border-collapse:collapse;font-size:var(--fs-m);margin-top:0}.power-curve-table th{text-align:left;color:var(--text-dim);padding:4px 8px;font-weight:600;border-bottom:1px solid var(--border)}.power-curve-table td{padding:6px 8px;border-bottom:1px solid var(--border)}.power-curve-table tr:last-child td{border-bottom:none}.progress-details summary{cursor:pointer;font-size:var(--fs-m);color:var(--text-dim);display:flex;align-items:center;gap:4px;list-style:none}.progress-details summary::-webkit-details-marker{display:none}.progress-details[open] summary .expand-icon{transform:rotate(90deg)}.progress-details summary .material-symbols-rounded{font-size:var(--fs-l)}.power-curve-val{font-weight:700;color:var(--text);text-align:right}.evolution-select-btn{background:none;border:none;cursor:pointer;color:var(--chart-color);padding:0;font-size:var(--fs-l);vertical-align:middle;margin-left:4px}.hr-settings-popup{display:flex;flex-direction:column}.hr-input-row{display:flex;justify-content:space-between;align-items:center;font-size:var(--fs-m);color:var(--text-muted);font-weight:600}.hr-zone-input{background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);width:60px;padding:4px 8px;font-size:var(--fs-m);text-align:right;outline:none}.hr-zone-input:focus{border-color:var(--accent)}.save-btn{background:var(--accent);color:#fff;border:none;border-radius:6px;padding:8px;font-size:12px;font-weight:700;cursor:pointer}.save-btn:hover{background:var(--accent-hover)}.menu-item.active .arrow,.menu-item.active .check{color:var(--accent)}.evolution-toolbar{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;border-bottom:1px solid var(--border);background:var(--bg);min-height:40px}.evolution-toolbar-left,.evolution-toolbar-right{display:flex;align-items:center;gap:12px}.evolution-toolbar .metric-pills{display:flex;gap:6px}.evolution-toolbar .metric-pill{cursor:pointer}.evolution-container{display:flex;flex-direction:column;gap:0px;padding:6px 0 4px}.evolution-card-group{display:flex;flex-direction:column;gap:10px;width:100%}.evolution-legend{display:flex;gap:16px;font-size:12px;color:var(--text-dim);margin-top:0;margin-bottom:0;justify-content:center}.evolution-legend-item{display:flex;align-items:center;gap:6px}.evolution-legend-line{width:16px;height:0;display:inline-block}.evolution-legend-line.solid{border-top:2px solid var(--chart-color)}.evolution-legend-line.dashed{border-top:2px dashed #888888}.evolution-tooltip-title{font-weight:700;margin-bottom:4px}.evolution-tooltip-row{display:flex;justify-content:space-between;gap:15px}.evolution-tooltip-label{color:#8a8a93}.evolution-tooltip-value{font-weight:700}.evolution-empty-text{color:var(--text-dim);font-size:12px;text-align:center;margin-top:20px}.evolution-chart-container{height:250px;flex:1}.distance-progress-card .card-content,.elevation-progress-card .card-content{display:flex;gap:20px}.chart-scroll-container{flex:1;overflow-x:auto;position:relative;background:var(--bg-dim);border-radius:8px;padding:10px;scrollbar-width:none}.chart-scroll-container::-webkit-scrollbar{width:0;height:0;display:none}.accumulated-table-container{width:250px;background:var(--bg-dim);border-radius:8px;padding:15px}.accumulated-table{width:100%;border-collapse:collapse;font-size:var(--fs-m)}.accumulated-table th,.accumulated-table td{padding:4px 8px;text-align:left;border-bottom:1px solid var(--border-color)}.accumulated-table th{color:var(--text-dim);font-weight:500;text-transform:uppercase;font-size:var(--fs-m);letter-spacing:.5px}.accumulated-table td:last-child{text-align:right;font-weight:500;font-family:monospace}.accumulated-table tr:last-child td{border-bottom:none}.chart-scroll-container::-webkit-scrollbar{height:4px}.chart-scroll-container::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}.u-title,.u-legend{font-size:var(--fs-m)!important}.courses-container{padding:16px;display:flex;flex-direction:column;gap:16px}.courses-list{display:flex;flex-direction:column;gap:8px}.course-item{background:var(--surface2);border:1px solid var(--border);border-radius:8px;display:flex;flex-direction:column;cursor:pointer;overflow:hidden}.course-item:hover{background:var(--surface3);border-color:var(--border-high)}.course-item-header{padding:6px 12px;display:flex;align-items:center;gap:12px;width:100%}.course-name{font-weight:600;flex:1}.course-meta{color:var(--text-muted);font-size:var(--fs-s)}.course-actions{display:flex;gap:4px}.course-actions .icon-btn{opacity:.5}.course-item:hover .course-actions .icon-btn{opacity:1}.expand-icon{color:var(--text-muted)}.course-tracks{padding:8px 12px;border-top:1px solid var(--border);background:var(--surface1)}.course-tracks-title{font-size:var(--fs-xs);font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}.course-tracks-table{width:100%;border-collapse:collapse;font-size:var(--fs-s);color:var(--text)}.course-tracks-table th,.course-tracks-table td{padding:6px 8px;text-align:right;border-bottom:1px solid var(--border-low)}.course-tracks-table th:first-child,.course-tracks-table td:first-child,.course-tracks-table th:nth-child(2),.course-tracks-table td:nth-child(2){text-align:left}.course-tracks-table td:not(:first-child){white-space:nowrap}.course-tracks-table th{font-weight:600;color:var(--text-muted);font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.5px;white-space:nowrap}.course-tracks-table tr:last-child td{border-bottom:none}.course-tracks-table th:first-child,.course-tracks-table td:first-child{width:100%}.course-track-row:hover{background:var(--surface2)}.course-track-row.selected{background:color-mix(in srgb,var(--theme-color) 8%,transparent)}.track-name-cell.clickable{color:var(--accent);cursor:pointer;font-weight:500}.track-name-cell.clickable:hover{text-decoration:underline}.metric-icon{font-size:16px;vertical-align:middle;margin-right:4px}.metric-icon.duration{color:var(--text-muted)}.metric-icon.speed{color:#4caf50}.metric-icon.power{color:#ff9800}.metric-icon.hr{color:#f44336}.course-point-marker{display:flex;align-items:center;justify-content:center} /*# sourceMappingURL=styles.css.map */ diff --git a/suites-experimental/tools-gps-tracks/dist/styles.css.map b/suites-experimental/tools-gps-tracks/dist/styles.css.map index ce44ae3490..c6e4bf37be 100644 --- a/suites-experimental/tools-gps-tracks/dist/styles.css.map +++ b/suites-experimental/tools-gps-tracks/dist/styles.css.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/css/uPlot.min.css", "../src/css/styles.css"], - "sourcesContent": [".uplot, .uplot *, .uplot *::before, .uplot *::after {box-sizing: border-box;}.uplot {font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";line-height: 1.5;width: min-content;}.u-title {text-align: center;font-size: 18px;font-weight: bold;}.u-wrap {position: relative;user-select: none;}.u-over, .u-under {position: absolute;}.u-under {overflow: hidden;}.uplot canvas {display: block;position: relative;width: 100%;height: 100%;}.u-axis {position: absolute;}.u-legend {font-size: 14px;margin: auto;text-align: center;}.u-inline {display: block;}.u-inline * {display: inline-block;}.u-inline tr {margin-right: 16px;}.u-legend th {font-weight: 600;}.u-legend th > * {vertical-align: middle;display: inline-block;}.u-legend .u-marker {width: 1em;height: 1em;margin-right: 4px;background-clip: padding-box !important;}.u-inline.u-live th::after {content: \":\";vertical-align: middle;}.u-inline:not(.u-live) .u-value {display: none;}.u-series > * {padding: 4px;}.u-series th {cursor: pointer;}.u-legend .u-off > * {opacity: 0.3;}.u-select {background: rgba(0,0,0,0.07);position: absolute;pointer-events: none;}.u-cursor-x, .u-cursor-y {position: absolute;left: 0;top: 0;pointer-events: none;will-change: transform;}.u-hz .u-cursor-x, .u-vt .u-cursor-y {height: 100%;border-right: 1px dashed #607D8B;}.u-hz .u-cursor-y, .u-vt .u-cursor-x {width: 100%;border-bottom: 1px dashed #607D8B;}.u-cursor-pt {position: absolute;top: 0;left: 0;border-radius: 50%;border: 0 solid;pointer-events: none;will-change: transform;/*this has to be !important since we set inline \"background\" shorthand */background-clip: padding-box !important;}.u-axis.u-off, .u-select.u-off, .u-cursor-x.u-off, .u-cursor-y.u-off, .u-cursor-pt.u-off {display: none;}", "/*\n * Copyright (c) 2026, Camillo Bruni.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n@import './uPlot.min.css';\n\n/* \u2500\u2500\u2500 Variables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n@font-face {\n font-family: 'Material Symbols Rounded';\n font-style: normal;\n font-weight: 100 700;\n src: url('../../material_symbols_rounded.woff2') format('woff2');\n}\n\n:root {\n --bg: #0e0e10;\n --surface: #18181b;\n --surface2: #222226;\n --border: #2e2e34;\n --border2: #3a3a42;\n --text: #e8e8ec;\n --text-muted: #888896;\n --text-dim: #555564;\n --theme-color: #3b82f6;\n --accent: var(--theme-color);\n --accent-hover: color-mix(in srgb, var(--theme-color) 80%, white);\n --danger: #ef4444;\n --sidebar-w: 230px;\n\n /* Font Sizes */\n --fs-s: 10px;\n --fs-m: 12px;\n --fs-l: 14px; /* For titles only */\n\n /* Icon Sizes */\n --is-s: 16px;\n --is-m: 20px;\n\n --handle-color: #3b82f6;\n}\n\n/* Font Size Classes */\n.font-s {\n font-size: 10px;\n}\n.font-m {\n font-size: 12px;\n}\n.font-l {\n font-size: 14px;\n}\n\n* {\n box-sizing: border-box;\n}\n\nbody,\nhtml {\n margin: 0;\n padding: 0;\n width: 100%;\n height: 100%;\n background: var(--bg);\n color: var(--text);\n font-family:\n system-ui,\n -apple-system,\n sans-serif;\n font-size: var(--fs-m);\n}\n\nbody {\n opacity: 1;\n}\n\nbody.loading-fonts {\n opacity: 0;\n}\n\nbutton {\n font-family: inherit;\n cursor: pointer;\n font-size: var(--fs-m);\n}\n\n/* Material symbols config */\n.material-symbols-rounded {\n font-family: 'Material Symbols Rounded';\n font-weight: normal;\n font-style: normal;\n font-size: var(--is-m);\n line-height: 1;\n letter-spacing: normal;\n text-transform: none;\n display: inline-block;\n white-space: nowrap;\n word-wrap: normal;\n direction: ltr;\n -webkit-font-smoothing: antialiased;\n font-variation-settings:\n 'FILL' 0,\n 'wght' 400,\n 'GRAD' 0,\n 'opsz' 24;\n}\n\n/* \u2500\u2500\u2500 Layout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#app {\n display: flex;\n width: 100vw;\n height: 100vh;\n overflow: hidden;\n}\n\n.hidden {\n display: none !important;\n}\n\n#global-loader {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n#import-warning {\n}\n\n.loader-box {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 0;\n display: flex;\n flex-direction: row;\n align-items: stretch;\n color: var(--text);\n font-weight: 700;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);\n max-width: 450px;\n width: 90%;\n overflow: hidden;\n position: relative;\n}\n\n#loader-close {\n position: absolute;\n top: 12px;\n right: 12px;\n background: none;\n border: none;\n color: var(--text-muted);\n cursor: pointer;\n padding: 4px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n#loader-close:hover {\n background: var(--surface2);\n color: var(--text);\n}\n\n.loader-icon-wrap {\n background: color-mix(in srgb, var(--accent) 10%, transparent);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 24px;\n border-right: 1px solid var(--border);\n gap: 8px;\n}\n\n.loader-icon-wrap > span {\n font-size: var(--fs-l);\n color: var(--accent);\n}\n\n#loader-warning-count {\n font-size: var(--fs-m);\n color: #f59e0b;\n font-weight: 700;\n display: none;\n align-items: center;\n gap: 4px;\n}\n\n.loader-content {\n padding: 24px;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 12px;\n justify-content: center;\n}\n\n#loader-text {\n font-size: var(--fs-l);\n font-weight: 700;\n color: var(--text);\n}\n\n#loader-filename {\n font-size: var(--fs-m);\n color: var(--text-muted);\n font-weight: 400;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 300px;\n}\n\n#loader-progress-wrap {\n width: 300px;\n height: 4px;\n background: var(--surface2);\n border-radius: 2px;\n margin-top: 4px;\n overflow: hidden;\n}\n\n#loader-subtext {\n font-size: var(--fs-m);\n color: var(--text-muted);\n font-weight: 400;\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 300px;\n margin-top: 0;\n}\n\n.progress-index {\n text-align: left;\n}\n\n.progress-total {\n text-align: right;\n}\n\n#loader-progress-bar {\n width: 0%;\n height: 100%;\n background: var(--accent);\n}\n\n/* \u2500\u2500\u2500 Sidebar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#sidebar {\n width: var(--sidebar-w);\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n background: var(--surface);\n border-right: 1px solid var(--border);\n z-index: 10;\n}\n\n#sidebar-header {\n padding: 16px 12px;\n border-bottom: 1px solid var(--border);\n}\n\n.logo {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.logo-icon {\n color: var(--accent);\n font-size: var(--fs-l);\n}\n.logo-title {\n font-weight: 800;\n font-size: var(--fs-l);\n letter-spacing: -0.5px;\n}\n.logo-sub {\n font-size: var(--fs-s);\n text-transform: uppercase;\n color: var(--text-dim);\n font-weight: 700;\n letter-spacing: 1px;\n margin-top: -2px;\n}\n\n/* Drop zone */\n#drop-zone {\n margin: 12px;\n padding: 20px 12px;\n border: 2px dashed var(--border2);\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n position: relative;\n}\n#drop-zone.drop-active {\n border-color: var(--accent);\n background: color-mix(in srgb, var(--theme-color) 5%, transparent);\n}\n.drop-icon {\n font-size: var(--is-m);\n color: var(--text-muted);\n margin-bottom: 4px;\n}\n.drop-primary {\n font-size: var(--fs-m);\n font-weight: 600;\n color: var(--text);\n}\n.drop-formats {\n display: flex;\n justify-content: center;\n gap: 6px;\n margin-top: 8px;\n}\n.drop-formats .badge {\n background: var(--surface2);\n color: var(--text-dim);\n font-size: var(--fs-s);\n padding: 2px 6px;\n}\n\n.drop-browse-container {\n margin-top: 12px;\n font-size: var(--fs-s);\n color: var(--text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 2px;\n}\n.drop-browse {\n color: var(--accent);\n font-weight: 600;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n.drop-browse .material-symbols-rounded {\n font-size: var(--fs-l);\n}\n.drop-browse:hover {\n color: var(--accent-hover);\n}\n.drop-separator {\n margin: 0 6px;\n color: var(--border2);\n vertical-align: middle;\n}\n\n/* Track list header */\n#track-list-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 12px 8px;\n}\n.section-label {\n font-size: var(--fs-s);\n font-weight: 700;\n text-transform: uppercase;\n color: var(--text-dim);\n letter-spacing: 0.5px;\n}\n\n.header-actions {\n display: flex;\n gap: 0;\n}\n\n#track-controls,\n#sort-controls {\n padding: 8px 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n border-bottom: 1px solid var(--border);\n}\n\n.search-bar {\n display: flex;\n background: var(--bg);\n border: 1px solid var(--border);\n border-radius: 6px;\n padding: 2px 4px;\n align-items: center;\n}\n.search-icon {\n font-size: var(--is-s);\n color: var(--text-dim);\n margin-left: 4px;\n}\n.search-bar input {\n flex: 1;\n background: transparent;\n border: none;\n padding: 4px 6px;\n color: var(--text);\n font-size: var(--fs-m);\n}\n.search-bar input:focus {\n outline: none;\n}\n\n.icon-btn.mini {\n width: 20px;\n height: 20px;\n color: var(--text-dim);\n}\n.icon-btn.mini .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.icon-btn.mini.active {\n color: var(--accent);\n}\n\n.sort-ctrl {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.sort-ctrl label {\n font-size: var(--fs-s);\n color: var(--text-dim);\n text-transform: uppercase;\n font-weight: 600;\n}\n\n.sort-select-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--surface2);\n border: 1px solid var(--border);\n padding: 4px 8px;\n border-radius: 6px;\n flex: 1;\n height: 24px;\n box-sizing: border-box;\n font-size: var(--fs-s);\n color: var(--text-muted);\n}\n.sort-select-btn:hover {\n border-color: var(--accent);\n color: var(--text);\n}\n.sort-select-btn .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.sort-select-btn .arrow {\n font-size: var(--fs-l);\n margin-left: auto;\n opacity: 0.5;\n}\n\n/* Filter panel */\n#filter-panel {\n padding: 12px;\n background: var(--surface2);\n border-bottom: 1px solid var(--border);\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n#filter-panel.hidden {\n display: none;\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.filter-group label {\n font-size: var(--fs-s);\n font-weight: 600;\n text-transform: uppercase;\n color: var(--text-dim);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.filter-group label .material-symbols-rounded {\n font-size: var(--is-s);\n opacity: 0.7;\n}\n\n.filter-metrics-grid {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 4px;\n}\n\n.mini-pill {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 6px;\n color: var(--text-dim);\n cursor: pointer;\n}\n.mini-pill:hover {\n border-color: var(--text-muted);\n color: var(--text-muted);\n}\n.mini-pill.active {\n background: var(--accent);\n border-color: var(--accent);\n color: white;\n}\n.mini-pill .material-symbols-rounded {\n font-size: var(--is-s);\n}\n\n.filter-row {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.filter-row input {\n flex: 1;\n background: var(--bg);\n border: 1px solid var(--border);\n border-radius: 4px;\n padding: 4px 6px;\n color: var(--text);\n font-size: var(--fs-s);\n}\n.filter-row span {\n font-size: var(--fs-s);\n color: var(--text-dim);\n}\n#filter-panel input:focus {\n border-color: var(--accent);\n outline: none;\n}\n\n.filter-footer {\n display: flex;\n justify-content: flex-end;\n margin-top: 4px;\n}\n\n/* Track list */\n#track-list {\n flex: 1;\n overflow-y: auto;\n padding: 4px 0;\n scrollbar-width: none;\n}\n#track-list::-webkit-scrollbar {\n width: 0;\n height: 0;\n display: none;\n}\n#track-list::-webkit-scrollbar-thumb {\n background: var(--border2);\n border-radius: 2px;\n}\n\n#track-list-empty {\n padding: 40px 20px;\n text-align: center;\n color: var(--text-dim);\n font-size: var(--fs-m);\n}\n\n.track-item {\n display: flex;\n align-items: center;\n padding: 6px 8px;\n gap: 0;\n cursor: pointer;\n border-left: 3px solid transparent;\n}\n.track-item:hover {\n background: rgba(255, 255, 255, 0.03);\n}\n.track-item.selected {\n background: color-mix(in srgb, var(--theme-color) 8%, transparent);\n border-left-color: var(--accent);\n}\n\n.track-color {\n width: 3px;\n border-radius: 1px;\n flex-shrink: 0;\n margin-right: 8px;\n align-self: stretch;\n}\n.track-info {\n flex: 1;\n min-width: 0;\n margin-right: 2px;\n}\n.track-name {\n font-size: var(--fs-m);\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-bottom: 1px;\n}\n.track-meta {\n font-size: var(--fs-s);\n color: var(--text-dim);\n display: flex;\n gap: 6px;\n align-items: center;\n}\n\n.track-item .icon-btn.mini {\n width: 22px;\n height: 22px;\n padding: 0;\n margin: 0;\n}\n\n.badge {\n font-size: var(--fs-s);\n background: var(--surface2);\n padding: 1px 4px;\n border-radius: 3px;\n font-weight: 700;\n color: var(--text-muted);\n}\n\n.track-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin-top: 6px;\n overflow: hidden;\n max-height: 32px;\n}\n\n.track-tag {\n font-size: var(--fs-s);\n font-weight: 700;\n color: var(--text-dim);\n background: rgba(255, 255, 255, 0.03);\n border: 1px solid var(--border);\n padding: 1px 5px;\n border-radius: 3px;\n white-space: nowrap;\n}\n\n.track-item.selected .track-tag {\n border-color: rgba(255, 255, 255, 0.1);\n color: var(--text-muted);\n}\n\n#sidebar-resizer {\n width: 4px;\n cursor: col-resize;\n background: transparent;\n flex-shrink: 0;\n z-index: 1000;\n margin-left: -2px;\n margin-right: -2px;\n user-select: none;\n}\n#sidebar-resizer:hover,\n#sidebar-resizer.dragging {\n background: var(--handle-color);\n}\n\nbody.dragging-sidebar {\n user-select: none;\n cursor: col-resize !important;\n}\n\n/* \u2500\u2500\u2500 Main \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#main {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n/* Map */\n#map-container {\n flex: 1;\n position: relative;\n min-height: 100px;\n}\n#map-container.editing-mode {\n border: 4px solid var(--accent);\n box-shadow: 0 0 15px var(--accent);\n z-index: 1000; /* Ensure glow is visible */\n}\n#map {\n width: 100%;\n height: 100%;\n background: var(--bg);\n}\n\n#map-controls {\n position: absolute;\n top: 12px;\n left: 12px;\n z-index: 1000;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n#basemap-switcher {\n display: flex;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 2px;\n height: 24px;\n box-sizing: border-box;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n align-items: center;\n gap: 0;\n}\n\n#selected-extra-map {\n font-size: var(--fs-s);\n font-weight: 700;\n color: var(--accent);\n padding: 0 6px;\n max-width: 120px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n}\n#selected-extra-map.hidden {\n display: none;\n}\n\n#btn-extra-layers {\n border: none !important;\n border-left: 1px solid var(--border) !important;\n border-radius: 0 !important;\n margin-left: 0 !important;\n padding-left: 6px !important;\n padding-right: 0 !important;\n width: auto !important;\n height: 100% !important;\n background: transparent !important;\n}\n\n#extra-layers-menu {\n position: absolute;\n top: 40px;\n right: 0;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);\n max-height: 300px;\n overflow-y: auto;\n width: 200px;\n z-index: 1000;\n padding: 4px;\n}\n#extra-layers-menu.hidden {\n display: none;\n}\n.extra-layers-header {\n font-size: var(--fs-s);\n font-weight: 700;\n color: var(--text-dim);\n text-transform: uppercase;\n padding: 6px 8px;\n border-bottom: 1px solid var(--border);\n margin-bottom: 4px;\n}\n.extra-layers-search {\n padding: 4px 8px;\n border-bottom: 1px solid var(--border);\n margin-bottom: 4px;\n}\n#extra-layers-search-input {\n width: 100%;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 4px;\n color: var(--text);\n font-size: var(--fs-s);\n padding: 4px 8px;\n outline: none;\n}\n#extra-layers-search-input:focus {\n border-color: var(--accent);\n}\n.extra-layers-license {\n font-size: var(--fs-s);\n color: var(--text-dim);\n padding: 4px 8px;\n border-bottom: 1px solid var(--border);\n margin-bottom: 4px;\n}\n.extra-layers-license a {\n color: var(--accent);\n text-decoration: none;\n}\n.extra-layers-license a:hover {\n text-decoration: underline;\n}\n.extra-layer-row {\n margin-bottom: 2px;\n}\n.extra-layer-item {\n display: block;\n width: 100%;\n text-align: left;\n background: transparent;\n border: none;\n color: var(--text-muted);\n padding: 4px 10px 2px 10px;\n font-size: var(--fs-s);\n font-weight: 600;\n border-radius: 4px;\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.extra-layer-item:hover {\n background: var(--surface2);\n color: var(--text);\n}\n.extra-layer-attribution {\n font-size: var(--fs-s);\n color: var(--text-dim);\n padding: 0 10px 4px 10px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n#map-loader {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 0 10px;\n height: 24px;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--fs-s);\n font-weight: 600;\n color: var(--text-muted);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n}\n.spinner-sm {\n width: 12px;\n height: 12px;\n border: 2px solid var(--surface2);\n border-top-color: var(--accent);\n border-radius: 50%;\n}\n.bm-btn {\n background: transparent;\n border: none;\n color: var(--text-muted);\n padding: 2px 6px;\n font-size: var(--fs-s);\n font-weight: 600;\n border-radius: 6px;\n}\n.bm-btn:hover {\n color: var(--text);\n}\n.bm-btn.active {\n background: var(--surface2);\n color: var(--accent);\n}\n\n/* Map Cursor Dot */\n.map-cursor-dot {\n pointer-events: none;\n}\n.dot-inner {\n width: 12px;\n height: 12px;\n background: #fff;\n border: 2px solid #000;\n border-radius: 50%;\n box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.5);\n}\n\n/* Map cursor info popup */\n#map-cursor-info {\n position: absolute;\n top: 12px;\n right: 12px;\n z-index: 1000;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 8px 12px;\n font-size: var(--fs-s);\n color: var(--text);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n display: none;\n pointer-events: none;\n}\n\n/* Resize handle */\n#resize-handle {\n height: 6px;\n background: var(--bg);\n border-top: 1px solid var(--border);\n border-bottom: 1px solid var(--border);\n cursor: ns-resize;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n z-index: 100;\n}\n#resize-handle:hover {\n background: var(--handle-color);\n}\n.handle-grip {\n width: 32px;\n height: 2px;\n background: var(--border2);\n border-radius: 1px;\n}\n\n/* \u2500\u2500\u2500 Chart Panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#chart-panel {\n display: flex;\n flex-direction: column;\n background: var(--surface);\n overflow: hidden;\n flex: 1;\n width: 100%;\n height: 100%;\n min-height: 0;\n}\n\n#tab-nav {\n display: flex;\n padding: 0 12px;\n border-bottom: 1px solid var(--border);\n gap: 4px;\n}\n\n.tab-btn {\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n color: var(--text-dim);\n padding: 10px 12px;\n font-size: var(--fs-m);\n font-weight: 700;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.tab-btn:hover {\n color: var(--text-muted);\n}\n.tab-btn.active {\n color: var(--accent);\n border-bottom-color: var(--accent);\n}\n.tab-btn .material-symbols-rounded {\n font-size: var(--is-s);\n}\n\n.tab-content {\n display: none;\n flex: 1;\n min-height: 0;\n}\n.tab-content.active {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n scrollbar-width: none;\n}\n\n/* Custom scrollbar for active tab content */\n.tab-content.active::-webkit-scrollbar {\n width: 0;\n height: 0;\n}\n.tab-content.active::-webkit-scrollbar-track {\n background: transparent;\n}\n.tab-content.active::-webkit-scrollbar-thumb {\n background: var(--border);\n border-radius: 3px;\n}\n.tab-content.active::-webkit-scrollbar-thumb:hover {\n background: var(--text-dim);\n}\n\n#chart-toolbar {\n display: flex;\n align-items: center;\n padding: 6px 12px;\n gap: 12px;\n border-bottom: 1px solid var(--border);\n background: var(--bg);\n min-height: 40px;\n position: sticky;\n top: 0;\n z-index: 100;\n}\n\n.icon-btn {\n background: transparent;\n border: 1px solid transparent;\n color: var(--text-muted);\n width: 24px;\n height: 24px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.icon-btn.hidden {\n display: none;\n}\n.icon-btn:hover {\n background: var(--surface2);\n color: var(--text);\n}\n.icon-btn.active {\n background: var(--surface2);\n color: var(--accent);\n}\n.icon-btn.danger:hover {\n background: rgba(239, 68, 68, 0.12);\n color: var(--danger);\n}\n.icon-btn .material-symbols-rounded {\n font-size: var(--fs-l);\n}\n\n#btn-metric-menu {\n flex: 0 0 auto;\n}\n\n#metric-pills {\n display: flex;\n gap: 6px;\n flex: 1;\n overflow: hidden;\n}\n.metric-pill:not(.active) {\n display: none;\n}\n.metric-pill.overflow-hidden {\n display: none !important;\n}\n#pill-overflow {\n color: var(--text-muted);\n font-weight: bold;\n padding: 0 4px;\n align-self: flex-end;\n}\n.metric-pill {\n height: 24px;\n padding: 0 8px;\n border-radius: 12px;\n border: 1px solid var(--border);\n background: var(--surface2);\n color: var(--text-muted);\n font-size: var(--fs-s);\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n.metric-pill .material-symbols-rounded {\n font-size: var(--fs-m);\n}\n.metric-pill.active {\n background: color-mix(in srgb, var(--pill-color) 15%, var(--surface2));\n border-color: var(--pill-color);\n color: var(--pill-color);\n}\n.metric-pill.disabled {\n opacity: 0.3;\n filter: grayscale(1);\n cursor: default;\n}\n\n#chart-options {\n display: flex;\n align-items: center;\n gap: 0;\n margin-left: auto;\n}\n\n.seg-ctrl {\n display: flex;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 6px;\n padding: 2px;\n height: 24px;\n box-sizing: border-box;\n}\n.seg-btn {\n background: transparent;\n border: none;\n color: var(--text-dim);\n padding: 0 8px;\n font-size: var(--fs-s);\n font-weight: 700;\n border-radius: 4px;\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n}\n.seg-btn .material-symbols-rounded {\n font-size: var(--fs-m);\n}\n.seg-btn.active {\n background: var(--bg);\n color: var(--text);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Stats Summary bar */\n#chart-stats {\n padding: 4px 14px;\n border-bottom: 1px solid var(--border);\n background: var(--surface2);\n}\n#chart-stats.hidden {\n display: none;\n}\n#chart-stats-wrap {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.stats-row {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n.stats-row-label {\n width: 45px;\n font-size: var(--fs-s);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--text-muted);\n white-space: nowrap;\n}\n\n.chart-row-stats-container {\n display: flex;\n flex: 1;\n align-items: center;\n justify-content: space-between;\n}\n\n.chart-row-right-actions {\n width: 130px; /* HIST_W */\n display: none;\n align-items: center;\n justify-content: flex-end;\n flex-shrink: 0;\n}\n.with-histogram .chart-row-right-actions {\n display: flex;\n}\n.chart-stats-total,\n.chart-stats-selection {\n display: flex;\n gap: 10px;\n font-size: var(--fs-s);\n color: var(--text-dim);\n align-items: center;\n white-space: nowrap;\n font-weight: 500;\n}\n.chart-stats-selection {\n margin-left: auto;\n position: relative;\n}\n.chart-stats-selection::after {\n content: '';\n position: absolute;\n bottom: -6px;\n left: 0;\n right: 0;\n height: 2px;\n background-color: var(--sel-color);\n pointer-events: none;\n}\n.all-chip {\n background: var(--surface2);\n color: var(--text-muted);\n font-weight: 500;\n padding: 2px;\n border-radius: 4px;\n font-size: var(--fs-m);\n margin-right: 4px;\n cursor: pointer;\n border: 1px solid var(--border);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.all-chip:hover {\n background: var(--border);\n color: var(--text);\n}\n.sel-tag {\n background: var(--surface2);\n color: var(--text-muted);\n font-weight: 500;\n padding: 2px;\n border-radius: 4px;\n font-size: var(--fs-m);\n margin-right: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--border);\n}\n\n.mm-item {\n display: flex;\n align-items: center;\n gap: 2px;\n white-space: nowrap;\n}\n.mm-icon {\n font-size: var(--fs-m);\n color: var(--text-dim);\n}\n\n/* \u2500\u2500 uPlot overrides \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.uplot {\n color: var(--text-muted) !important;\n}\n.u-title {\n display: none;\n}\n.u-legend {\n display: none;\n}\n\n/* Selection drag background \u2014 colour matches the chart's metric */\n.chart-row .u-select {\n background: color-mix(in srgb, var(--chart-color, #3b82f6) 12%, transparent) !important;\n border: 1px solid color-mix(in srgb, var(--chart-color, #3b82f6) 35%, transparent) !important;\n}\n\n/* Make the cursor crosshair dashed */\n.u-cursor-x {\n border-left: 1px dashed rgba(255, 255, 255, 0.55) !important;\n}\n.u-cursor-y {\n display: none !important;\n}\n\n/* \u2500\u2500 Selection fill \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.sel-fill {\n position: absolute;\n top: 0;\n background: color-mix(in srgb, var(--theme-color) 8%, transparent);\n border-left: 1px solid color-mix(in srgb, var(--theme-color) 30%, transparent);\n border-right: 1px solid rgba(148, 163, 184, 0.4);\n pointer-events: none;\n}\n\n/* \u2500\u2500 Selection handles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.sel-handle {\n position: absolute;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 8px;\n height: 24px;\n background: rgba(255, 255, 255, 0.85);\n border: 1px solid rgba(0, 0, 0, 0.3);\n border-radius: 4px;\n cursor: ew-resize;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n}\n.sel-handle::after {\n content: '';\n width: 2px;\n height: 10px;\n border-left: 1px solid rgba(0, 0, 0, 0.4);\n border-right: 1px solid rgba(0, 0, 0, 0.4);\n}\n.sel-handle:hover {\n background: #fff;\n transform: translate(-50%, -50%) scale(1.1);\n}\n\n.sel-graph-marker {\n position: absolute;\n transform: translate(-50%, -50%);\n pointer-events: none;\n z-index: 11;\n background: none !important;\n}\n.sel-graph-marker .material-symbols-rounded {\n}\n\n/* \u2500\u2500 Per-chart selection lines \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.sel-line {\n position: absolute;\n top: 0;\n height: 100%;\n width: 0;\n border-left-width: 1.5px;\n border-left-style: solid;\n pointer-events: none;\n}\n\n/* Labels on the selection lines */\n.sel-line-label {\n position: absolute;\n top: 4px;\n font-size: var(--fs-s);\n font-weight: 700;\n background: rgba(14, 14, 16, 0.92);\n color: #fff;\n padding: 2px 5px;\n border-radius: 4px;\n pointer-events: none;\n white-space: nowrap;\n z-index: 10;\n border: 1px solid var(--border);\n}\n\n/* \u2500\u2500 Charts view elements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#charts-container {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 6px 0 4px;\n scrollbar-width: none;\n}\n#charts-container::-webkit-scrollbar {\n width: 0;\n height: 0;\n}\n#charts-container::-webkit-scrollbar-thumb {\n background: var(--border2);\n border-radius: 2px;\n}\n\n/* Fixed X Axis Labels */\n.fixed-x-label {\n position: absolute;\n bottom: 4px;\n font-size: var(--fs-s);\n font-family: system-ui, sans-serif;\n color: #555564;\n z-index: 10;\n pointer-events: none;\n}\n.fixed-x-max {\n right: 0;\n text-align: right;\n}\n\n/* Histogram column (inline, per chart row) */\n.chart-row-body {\n display: flex;\n flex-direction: row;\n padding: 0 14px;\n min-width: 0;\n overflow: hidden;\n}\n.chart-row-body > div:first-child {\n flex: 1;\n min-width: 0;\n}\n.hist-col {\n width: 130px;\n flex-shrink: 0;\n border-left: 1px solid var(--border);\n margin-left: 20px;\n margin-right: 0;\n display: none;\n align-items: center;\n justify-content: center;\n cursor: crosshair;\n}\n.hist-col.visible {\n display: flex;\n}\n.hist-canvas {\n display: block;\n}\n\n/* Histogram connector line */\n#hist-line {\n position: fixed;\n height: 0;\n border-top: 1px dashed rgba(255, 255, 255, 0.25);\n pointer-events: none;\n display: none;\n z-index: 10000;\n}\n\n/* Histogram tooltip */\n#hist-tooltip {\n position: fixed;\n background: var(--surface);\n border: 1px solid var(--border2);\n border-radius: 5px;\n padding: 8px 10px;\n pointer-events: none;\n display: none;\n z-index: 10001;\n box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);\n font-size: var(--fs-s);\n}\n.hist-tt-header {\n font-weight: 800;\n margin-bottom: 6px;\n padding-left: 8px;\n border-left: 3px solid var(--accent);\n color: var(--text);\n}\n.hist-tt-grid {\n display: grid;\n grid-template-columns: 1fr auto auto;\n gap: 10px;\n align-items: baseline;\n}\n.hist-tt-label {\n font-size: var(--fs-s);\n color: var(--text-muted);\n}\n.hist-tt-value {\n font-size: var(--fs-s);\n color: var(--text);\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n.hist-tt-pct {\n font-size: var(--fs-s);\n color: var(--text-dim);\n text-align: right;\n min-width: 36px;\n font-variant-numeric: tabular-nums;\n}\n.hist-tt-grid.sel-row {\n margin-top: 2px;\n opacity: 0.9;\n}\n.hist-tt-label.sel {\n color: var(--accent);\n font-weight: 700;\n}\n\n.chart-row {\n border-bottom: 1px solid var(--border);\n}\n.chart-row:last-child {\n border-bottom: none;\n}\n\n/* \u2500\u2500 Chart row header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.chart-row-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 14px 4px 14px;\n min-height: 28px;\n}\n\n.progress-chart-row {\n display: flex;\n flex-direction: column;\n}\n\n.progress-chart-row .chart-row-header {\n height: 36px;\n box-sizing: border-box;\n padding-top: 0;\n padding-bottom: 0;\n}\n\n.progress-chart-row .chart-row-actions {\n margin-left: auto;\n}\n\n.progress-chart-row .chart-row-body {\n flex: 1;\n padding: 0;\n}\n\n.chart-row-label-group {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n width: 140px; /* Fixed width for alignment */\n}\n\n.chart-row-actions {\n display: flex;\n align-items: center;\n gap: 0;\n}\n\n.chart-row-icon {\n font-size: var(--is-s);\n color: var(--chart-color);\n}\n.chart-row-label {\n font-size: var(--fs-m);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--text-muted);\n white-space: nowrap;\n}\n\n/* Track Picker Popup */\n.track-picker-popup {\n padding: 8px;\n background: var(--surface);\n color: var(--text);\n border-radius: 8px;\n min-width: 160px;\n}\n.picker-header {\n font-size: var(--fs-s);\n text-transform: uppercase;\n font-weight: 700;\n color: var(--text-dim);\n margin-bottom: 8px;\n padding-bottom: 4px;\n border-bottom: 1px solid var(--border);\n}\n.picker-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.picker-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n cursor: pointer;\n}\n.picker-item:hover {\n background: var(--surface2);\n}\n.picker-color {\n width: 3px;\n height: 14px;\n border-radius: 1px;\n}\n.picker-info {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.picker-name {\n font-size: var(--fs-s);\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 180px;\n}\n/* Custom Modal / Dialog */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 20000;\n}\n.modal-content {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 24px;\n width: 100%;\n max-width: 320px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.modal-title {\n font-size: var(--fs-l);\n font-weight: 800;\n color: var(--text);\n}\n.modal-body {\n font-size: var(--fs-m);\n color: var(--text-muted);\n line-height: 1.5;\n}\n.modal-input-wrap {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.modal-input-label {\n font-size: var(--fs-s);\n font-weight: 700;\n text-transform: uppercase;\n color: var(--text-dim);\n}\n.modal-input {\n background: var(--bg);\n border: 1px solid var(--border2);\n border-radius: 6px;\n padding: 10px;\n color: var(--text);\n font-size: var(--fs-l);\n font-weight: 800;\n text-align: center;\n letter-spacing: 4px;\n}\n.modal-input:focus {\n outline: none;\n border-color: var(--accent);\n}\n.modal-actions {\n display: flex;\n gap: 12px;\n margin-top: 8px;\n}\n.modal-btn {\n flex: 1;\n padding: 10px;\n border-radius: 6px;\n font-size: var(--fs-m);\n font-weight: 700;\n border: 1px solid transparent;\n}\n.modal-btn.cancel {\n background: var(--surface2);\n color: var(--text);\n border-color: var(--border);\n}\n.modal-btn.cancel:hover {\n background: var(--border);\n}\n.modal-btn.confirm {\n background: var(--danger);\n color: #fff;\n}\n.modal-btn.confirm:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n filter: grayscale(1);\n}\n.modal-btn.confirm:not(:disabled):hover {\n filter: brightness(1.1);\n}\n\n.picker-meta {\n font-size: var(--fs-s);\n color: var(--text-dim);\n font-weight: 700;\n}\n\n/* Leaflet Popup Overrides */\n.leaflet-popup-content-wrapper,\n.leaflet-popup-tip {\n background: var(--surface) !important;\n color: var(--text) !important;\n border: 1px solid var(--border) !important;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4) !important;\n}\n.leaflet-popup-content {\n margin: 0 !important;\n}\n.leaflet-popup-tip {\n border: none !important;\n}\n.map-color-btn {\n margin-left: 4px;\n}\n.map-color-btn .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.map-color-btn.active {\n color: var(--chart-color, var(--accent));\n}\n\n.smooth-btn.active {\n color: var(--accent);\n}\n.cur-y-val {\n position: absolute;\n left: 0;\n top: 0;\n pointer-events: none;\n font-size: var(--fs-s);\n font-weight: 700;\n background: rgba(14, 14, 16, 0.92);\n padding: 2px 6px;\n border-radius: 4px;\n border: 1px solid rgba(255, 255, 255, 0.1);\n z-index: 2000;\n white-space: nowrap;\n}\n.cur-y-val.pin {\n z-index: 1000;\n opacity: 0.7;\n}\n\n/* \u2500\u2500\u2500 Details View \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#details-view {\n width: 100%;\n padding: 24px;\n max-width: 900px;\n margin: 0 auto;\n}\n\n#details-header {\n margin-bottom: 32px;\n}\n.details-title {\n font-size: var(--fs-l);\n font-weight: 800;\n margin-bottom: 4px;\n}\n.details-subtitle {\n font-size: var(--fs-m);\n color: var(--text-muted);\n}\n\n.details-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n gap: 16px;\n}\n.details-card {\n background: var(--surface2);\n border: 1px solid var(--border);\n padding: 16px;\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.details-card .material-symbols-rounded {\n color: var(--accent);\n margin-bottom: 4px;\n font-size: var(--is-m);\n}\n.details-card-label {\n font-size: var(--fs-s);\n font-weight: 500;\n text-transform: uppercase;\n color: var(--text-dim);\n letter-spacing: 0.5px;\n}\n.details-card-value {\n font-size: var(--fs-l);\n font-weight: 500;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--text-dim);\n gap: 12px;\n padding: 40px 20px;\n}\n.empty-icon {\n font-size: var(--fs-l);\n opacity: 0.2;\n}\n.empty-text {\n font-size: var(--fs-m);\n font-weight: 500;\n}\n\n#chart-empty {\n height: 100%;\n}\n#details-empty {\n margin-top: 40px;\n}\n\n/* \u2500\u2500 Toast notifications \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#toast-container {\n position: fixed;\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n flex-direction: column;\n gap: 8px;\n z-index: 9999;\n}\n.toast {\n background: var(--surface2);\n color: var(--text);\n padding: 10px 20px;\n border-radius: 8px;\n font-size: var(--fs-m);\n font-weight: 600;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);\n border: 1px solid var(--border2);\n}\n.toast.error {\n border-color: var(--danger);\n}\n.toast.out {\n}\n\n/* \u2500\u2500 Sort menu popup \u2500\u2500 */\n.sort-menu-popup,\n.metric-menu-popup {\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 6px;\n min-width: 180px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);\n}\n\n.menu-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n border-radius: 6px;\n cursor: pointer;\n color: var(--text-muted);\n}\n.menu-item:hover {\n background: var(--surface);\n color: var(--text);\n}\n.menu-item.active {\n color: var(--text);\n font-weight: 600;\n}\n.menu-item .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.menu-item .item-label {\n flex: 1;\n font-size: var(--fs-m);\n}\n.menu-item .arrow,\n.menu-item .check {\n font-size: var(--is-s);\n color: var(--text-dim);\n}\n\n/* \u2500\u2500\u2500 Insights View \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#insights-view {\n width: 100%;\n padding: 24px;\n max-width: 1000px;\n margin: 0 auto;\n}\n\n.insights-grid {\n column-count: 2;\n column-gap: 24px;\n}\n\n@media (max-width: 900px) {\n .insights-grid {\n column-count: 1;\n }\n}\n\n.insight-card {\n display: inline-flex;\n width: 100%;\n break-inside: avoid;\n margin-bottom: 24px;\n background: var(--surface2);\n border: 1px solid var(--border);\n padding: 20px;\n border-radius: 12px;\n flex-direction: column;\n gap: 16px;\n}\n\n.insight-title {\n font-size: var(--fs-m);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--text-muted);\n}\n\n.insight-title .material-symbols-rounded {\n font-size: var(--is-s);\n}\n\n.insight-chart-container {\n width: 100%;\n height: 250px;\n}\n\n.power-curve-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--fs-m);\n margin-top: 0;\n}\n\n.power-curve-table th {\n text-align: left;\n color: var(--text-dim);\n padding: 4px 8px;\n font-weight: 600;\n border-bottom: 1px solid var(--border);\n}\n\n.power-curve-table td {\n padding: 6px 8px;\n border-bottom: 1px solid var(--border);\n}\n\n.power-curve-table tr:last-child td {\n border-bottom: none;\n}\n\n.progress-details summary {\n cursor: pointer;\n font-size: var(--fs-m);\n color: var(--text-dim);\n display: flex;\n align-items: center;\n gap: 4px;\n list-style: none;\n}\n\n.progress-details summary::-webkit-details-marker {\n display: none;\n}\n\n.progress-details[open] summary .expand-icon {\n transform: rotate(90deg);\n}\n\n.progress-details summary .material-symbols-rounded {\n font-size: var(--fs-l);\n}\n\n.progress-details summary .expand-icon {\n}\n\n.power-curve-val {\n font-weight: 700;\n color: var(--text);\n text-align: right;\n}\n\n.evolution-select-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--chart-color);\n padding: 0;\n font-size: var(--fs-l);\n vertical-align: middle;\n margin-left: 4px;\n}\n\n.hr-settings-popup {\n display: flex;\n flex-direction: column;\n}\n\n.hr-input-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: var(--fs-m);\n color: var(--text-muted);\n font-weight: 600;\n}\n\n.hr-zone-input {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 4px;\n color: var(--text);\n width: 60px;\n padding: 4px 8px;\n font-size: var(--fs-m);\n text-align: right;\n outline: none;\n}\n\n.hr-zone-input:focus {\n border-color: var(--accent);\n}\n\n.save-btn {\n background: var(--accent);\n color: #fff;\n border: none;\n border-radius: 6px;\n padding: 8px;\n font-size: 12px;\n font-weight: 700;\n cursor: pointer;\n}\n\n.save-btn:hover {\n background: var(--accent-hover);\n}\n\n.menu-item.active .arrow,\n.menu-item.active .check {\n color: var(--accent);\n}\n\n/* \u2500\u2500 Evolution View \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.evolution-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 12px;\n border-bottom: 1px solid var(--border);\n background: var(--bg);\n min-height: 40px;\n}\n\n.evolution-toolbar-left,\n.evolution-toolbar-right {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.evolution-toolbar .metric-pills {\n display: flex;\n gap: 6px;\n}\n\n.evolution-toolbar .metric-pill {\n cursor: pointer;\n}\n\n.evolution-container {\n display: flex;\n flex-direction: column;\n gap: 0px;\n padding: 6px 0 4px;\n}\n\n.evolution-card-group {\n display: flex;\n flex-direction: column;\n gap: 10px;\n width: 100%;\n}\n\n.evolution-legend {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--text-dim);\n margin-top: 0px;\n margin-bottom: 0px;\n justify-content: center;\n}\n\n.evolution-legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.evolution-legend-line {\n width: 16px;\n height: 0;\n display: inline-block;\n}\n\n.evolution-legend-line.solid {\n border-top: 2px solid var(--chart-color);\n}\n\n.evolution-legend-line.dashed {\n border-top: 2px dashed #888888;\n}\n\n.evolution-tooltip-title {\n font-weight: bold;\n margin-bottom: 4px;\n}\n\n.evolution-tooltip-row {\n display: flex;\n justify-content: space-between;\n gap: 15px;\n}\n\n.evolution-tooltip-label {\n color: #8a8a93;\n}\n\n.evolution-tooltip-value {\n font-weight: bold;\n}\n\n.evolution-empty-text {\n color: var(--text-dim);\n font-size: 12px;\n text-align: center;\n margin-top: 20px;\n}\n\n.evolution-chart-container {\n height: 250px;\n flex: 1;\n}\n\n.distance-progress-card .card-content,\n.elevation-progress-card .card-content {\n display: flex;\n gap: 20px;\n}\n\n.chart-scroll-container {\n flex: 1;\n overflow-x: auto;\n position: relative;\n background: var(--bg-dim);\n border-radius: 8px;\n padding: 10px;\n scrollbar-width: none;\n}\n.chart-scroll-container::-webkit-scrollbar {\n width: 0;\n height: 0;\n display: none;\n}\n\n.accumulated-table-container {\n width: 250px;\n background: var(--bg-dim);\n border-radius: 8px;\n padding: 15px;\n}\n\n.accumulated-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--fs-m);\n}\n\n.accumulated-table th,\n.accumulated-table td {\n padding: 4px 8px;\n text-align: left;\n border-bottom: 1px solid var(--border-color);\n}\n\n.accumulated-table th {\n color: var(--text-dim);\n font-weight: 500;\n text-transform: uppercase;\n font-size: var(--fs-m);\n letter-spacing: 0.5px;\n}\n\n.accumulated-table td:last-child {\n text-align: right;\n font-weight: 500;\n font-family: monospace;\n}\n\n.accumulated-table tr:last-child td {\n border-bottom: none;\n}\n\n.chart-scroll-container::-webkit-scrollbar {\n height: 4px;\n}\n\n.chart-scroll-container::-webkit-scrollbar-thumb {\n background: var(--border2);\n border-radius: 2px;\n}\n\n/* uPlot overrides to comply with font size restrictions */\n.u-title {\n font-size: var(--fs-m) !important;\n}\n.u-legend {\n font-size: var(--fs-m) !important;\n}\n\n/* Courses Tab */\n.courses-container {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.courses-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.course-item {\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 8px;\n display: flex;\n flex-direction: column;\n cursor: pointer;\n overflow: hidden;\n}\n\n.course-item:hover {\n background: var(--surface3);\n border-color: var(--border-high);\n}\n\n.course-item-header {\n padding: 6px 12px;\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n}\n\n.course-name {\n font-weight: 600;\n flex: 1;\n}\n\n.course-meta {\n color: var(--text-muted);\n font-size: var(--fs-s);\n}\n\n.course-actions {\n display: flex;\n gap: 4px;\n}\n\n.course-actions .icon-btn {\n opacity: 0.5;\n}\n\n.course-item:hover .course-actions .icon-btn {\n opacity: 1;\n}\n\n.expand-icon {\n color: var(--text-muted);\n}\n\n.course-tracks {\n padding: 8px 12px;\n border-top: 1px solid var(--border);\n background: var(--surface1);\n}\n\n.course-tracks-title {\n font-size: var(--fs-xs);\n font-weight: 700;\n color: var(--text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n}\n\n.course-tracks-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--fs-s);\n color: var(--text);\n}\n\n.course-tracks-table th,\n.course-tracks-table td {\n padding: 6px 8px;\n text-align: right;\n border-bottom: 1px solid var(--border-low);\n}\n\n.course-tracks-table th:first-child,\n.course-tracks-table td:first-child,\n.course-tracks-table th:nth-child(2),\n.course-tracks-table td:nth-child(2) {\n text-align: left;\n}\n\n.course-tracks-table td:not(:first-child) {\n white-space: nowrap;\n}\n\n.course-tracks-table th {\n font-weight: 600;\n color: var(--text-muted);\n font-size: var(--fs-xs);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n white-space: nowrap;\n}\n\n.course-tracks-table tr:last-child td {\n border-bottom: none;\n}\n\n.course-tracks-table th:first-child,\n.course-tracks-table td:first-child {\n width: 100%;\n}\n\n.course-track-row:hover {\n background: var(--surface2);\n}\n\n.course-track-row.selected {\n background: color-mix(in srgb, var(--theme-color) 8%, transparent);\n}\n\n.track-name-cell.clickable {\n color: var(--accent);\n cursor: pointer;\n font-weight: 500;\n}\n\n.track-name-cell.clickable:hover {\n text-decoration: underline;\n}\n\n.metric-icon {\n font-size: 16px;\n vertical-align: middle;\n margin-right: 4px;\n}\n\n.metric-icon.duration {\n color: var(--text-muted);\n}\n\n.metric-icon.speed {\n color: #4caf50;\n}\n\n.metric-icon.power {\n color: #ff9800;\n}\n\n.metric-icon.hr {\n color: #f44336;\n}\n\n.course-point-marker {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n"], - "mappings": "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", + "sourcesContent": [".uplot, .uplot *, .uplot *::before, .uplot *::after {box-sizing: border-box;}.uplot {font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";line-height: 1.5;width: min-content;}.u-title {text-align: center;font-size: 18px;font-weight: bold;}.u-wrap {position: relative;user-select: none;}.u-over, .u-under {position: absolute;}.u-under {overflow: hidden;}.uplot canvas {display: block;position: relative;width: 100%;height: 100%;}.u-axis {position: absolute;}.u-legend {font-size: 14px;margin: auto;text-align: center;}.u-inline {display: block;}.u-inline * {display: inline-block;}.u-inline tr {margin-right: 16px;}.u-legend th {font-weight: 600;}.u-legend th > * {vertical-align: middle;display: inline-block;}.u-legend .u-marker {width: 1em;height: 1em;margin-right: 4px;background-clip: padding-box !important;}.u-inline.u-live th::after {content: \":\";vertical-align: middle;}.u-inline:not(.u-live) .u-value {display: none;}.u-series > * {padding: 4px;}.u-series th {cursor: pointer;}.u-legend .u-off > * {opacity: 0.3;}.u-select {background: rgba(0,0,0,0.07);position: absolute;pointer-events: none;}.u-cursor-x, .u-cursor-y {position: absolute;left: 0;top: 0;pointer-events: none;will-change: transform;}.u-hz .u-cursor-x, .u-vt .u-cursor-y {height: 100%;border-right: 1px dashed #607D8B;}.u-hz .u-cursor-y, .u-vt .u-cursor-x {width: 100%;border-bottom: 1px dashed #607D8B;}.u-cursor-pt {position: absolute;top: 0;left: 0;border-radius: 50%;border: 0 solid;pointer-events: none;will-change: transform;/*this has to be !important since we set inline \"background\" shorthand */background-clip: padding-box !important;}.u-axis.u-off, .u-select.u-off, .u-cursor-x.u-off, .u-cursor-y.u-off, .u-cursor-pt.u-off {display: none;}", "/*\n * Copyright (c) 2026, Camillo Bruni.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n@import './uPlot.min.css';\n\n/* \u2500\u2500\u2500 Variables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n@font-face {\n font-family: 'Material Symbols Rounded';\n font-style: normal;\n font-weight: 100 700;\n src: url('../../material_symbols_rounded.woff2') format('woff2');\n}\n\n:root {\n --bg: #0e0e10;\n --surface: #18181b;\n --surface2: #222226;\n --border: #2e2e34;\n --border2: #3a3a42;\n --text: #e8e8ec;\n --text-muted: #888896;\n --text-dim: #555564;\n --theme-color: #3b82f6;\n --accent: var(--theme-color);\n --accent-hover: color-mix(in srgb, var(--theme-color) 80%, white);\n --danger: #ef4444;\n --sidebar-w: 230px;\n\n /* Font Sizes */\n --fs-s: 10px;\n --fs-m: 12px;\n --fs-l: 14px; /* For titles only */\n\n /* Icon Sizes */\n --is-s: 16px;\n --is-m: 20px;\n\n --handle-color: #3b82f6;\n}\n\n/* Font Size Classes */\n.font-s {\n font-size: 10px;\n}\n.font-m {\n font-size: 12px;\n}\n.font-l {\n font-size: 14px;\n}\n\n* {\n box-sizing: border-box;\n}\n\nbody,\nhtml {\n margin: 0;\n padding: 0;\n width: 100%;\n height: 100%;\n background: var(--bg);\n color: var(--text);\n font-family:\n system-ui,\n -apple-system,\n sans-serif;\n font-size: var(--fs-m);\n}\n\nbody {\n opacity: 1;\n}\n\nbody.loading-fonts {\n opacity: 0;\n}\n\nbutton {\n font-family: inherit;\n cursor: pointer;\n font-size: var(--fs-m);\n}\n\n/* Material symbols config */\n.material-symbols-rounded {\n font-family: 'Material Symbols Rounded';\n font-weight: normal;\n font-style: normal;\n font-size: var(--is-m);\n line-height: 1;\n letter-spacing: normal;\n text-transform: none;\n display: inline-block;\n white-space: nowrap;\n word-wrap: normal;\n direction: ltr;\n -webkit-font-smoothing: antialiased;\n font-variation-settings:\n 'FILL' 0,\n 'wght' 400,\n 'GRAD' 0,\n 'opsz' 24;\n}\n\n/* \u2500\u2500\u2500 Layout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#app {\n display: flex;\n width: 100vw;\n height: 100vh;\n overflow: hidden;\n}\n\napp-graphs-tab,\napp-insights-tab,\napp-details-tab,\napp-combined-tab,\napp-evolution-tab,\napp-courses-tab {\n display: contents;\n}\n\n.hidden {\n display: none !important;\n}\n\n#global-loader {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n#import-warning {\n}\n\n.loader-box {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 0;\n display: flex;\n flex-direction: row;\n align-items: stretch;\n color: var(--text);\n font-weight: 700;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);\n max-width: 450px;\n width: 90%;\n overflow: hidden;\n position: relative;\n}\n\n#loader-close {\n position: absolute;\n top: 12px;\n right: 12px;\n background: none;\n border: none;\n color: var(--text-muted);\n cursor: pointer;\n padding: 4px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n#loader-close:hover {\n background: var(--surface2);\n color: var(--text);\n}\n\n.loader-icon-wrap {\n background: color-mix(in srgb, var(--accent) 10%, transparent);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 24px;\n border-right: 1px solid var(--border);\n gap: 8px;\n}\n\n.loader-icon-wrap > span {\n font-size: var(--fs-l);\n color: var(--accent);\n}\n\n#loader-warning-count {\n font-size: var(--fs-m);\n color: #f59e0b;\n font-weight: 700;\n display: none;\n align-items: center;\n gap: 4px;\n}\n\n.loader-content {\n padding: 24px;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 12px;\n justify-content: center;\n}\n\n#loader-text {\n font-size: var(--fs-l);\n font-weight: 700;\n color: var(--text);\n}\n\n#loader-filename {\n font-size: var(--fs-m);\n color: var(--text-muted);\n font-weight: 400;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 300px;\n}\n\n#loader-progress-wrap {\n width: 300px;\n height: 4px;\n background: var(--surface2);\n border-radius: 2px;\n margin-top: 4px;\n overflow: hidden;\n}\n\n#loader-subtext {\n font-size: var(--fs-m);\n color: var(--text-muted);\n font-weight: 400;\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 300px;\n margin-top: 0;\n}\n\n.progress-index {\n text-align: left;\n}\n\n.progress-total {\n text-align: right;\n}\n\n#loader-progress-bar {\n width: 0%;\n height: 100%;\n background: var(--accent);\n}\n\n/* \u2500\u2500\u2500 Sidebar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#sidebar {\n width: var(--sidebar-w);\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n background: var(--surface);\n border-right: 1px solid var(--border);\n z-index: 10;\n}\n\n#sidebar-header {\n padding: 16px 12px;\n border-bottom: 1px solid var(--border);\n}\n\n.logo {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.logo-icon {\n color: var(--accent);\n font-size: var(--fs-l);\n}\n.logo-title {\n font-weight: 800;\n font-size: var(--fs-l);\n letter-spacing: -0.5px;\n}\n.logo-sub {\n font-size: var(--fs-s);\n text-transform: uppercase;\n color: var(--text-dim);\n font-weight: 700;\n letter-spacing: 1px;\n margin-top: -2px;\n}\n\n/* Drop zone */\n#drop-zone {\n margin: 12px;\n padding: 20px 12px;\n border: 2px dashed var(--border2);\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n position: relative;\n}\n#drop-zone.drop-active {\n border-color: var(--accent);\n background: color-mix(in srgb, var(--theme-color) 5%, transparent);\n}\n.drop-icon {\n font-size: var(--is-m);\n color: var(--text-muted);\n margin-bottom: 4px;\n}\n.drop-primary {\n font-size: var(--fs-m);\n font-weight: 600;\n color: var(--text);\n}\n.drop-formats {\n display: flex;\n justify-content: center;\n gap: 6px;\n margin-top: 8px;\n}\n.drop-formats .badge {\n background: var(--surface2);\n color: var(--text-dim);\n font-size: var(--fs-s);\n padding: 2px 6px;\n}\n\n.drop-browse-container {\n margin-top: 12px;\n font-size: var(--fs-s);\n color: var(--text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 2px;\n}\n.drop-browse {\n color: var(--accent);\n font-weight: 600;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n.drop-browse .material-symbols-rounded {\n font-size: var(--fs-l);\n}\n.drop-browse:hover {\n color: var(--accent-hover);\n}\n.drop-separator {\n margin: 0 6px;\n color: var(--border2);\n vertical-align: middle;\n}\n\n/* Track list header */\n#track-list-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 12px 8px;\n}\n.section-label {\n font-size: var(--fs-s);\n font-weight: 700;\n text-transform: uppercase;\n color: var(--text-dim);\n letter-spacing: 0.5px;\n}\n\n.header-actions {\n display: flex;\n gap: 0;\n}\n\n#track-controls,\n#sort-controls {\n padding: 8px 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n border-bottom: 1px solid var(--border);\n}\n\n.search-bar {\n display: flex;\n background: var(--bg);\n border: 1px solid var(--border);\n border-radius: 6px;\n padding: 2px 4px;\n align-items: center;\n}\n.search-icon {\n font-size: var(--is-s);\n color: var(--text-dim);\n margin-left: 4px;\n}\n.search-bar input {\n flex: 1;\n background: transparent;\n border: none;\n padding: 4px 6px;\n color: var(--text);\n font-size: var(--fs-m);\n}\n.search-bar input:focus {\n outline: none;\n}\n\n.icon-btn.mini {\n width: 20px;\n height: 20px;\n color: var(--text-dim);\n}\n.icon-btn.mini .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.icon-btn.mini.active {\n color: var(--accent);\n}\n\n.sort-ctrl {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.sort-ctrl label {\n font-size: var(--fs-s);\n color: var(--text-dim);\n text-transform: uppercase;\n font-weight: 600;\n}\n\n.sort-select-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--surface2);\n border: 1px solid var(--border);\n padding: 4px 8px;\n border-radius: 6px;\n flex: 1;\n height: 24px;\n box-sizing: border-box;\n font-size: var(--fs-s);\n color: var(--text-muted);\n}\n.sort-select-btn:hover {\n border-color: var(--accent);\n color: var(--text);\n}\n.sort-select-btn .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.sort-select-btn .arrow {\n font-size: var(--fs-l);\n margin-left: auto;\n opacity: 0.5;\n}\n\n/* Filter panel */\n#filter-panel {\n padding: 12px;\n background: var(--surface2);\n border-bottom: 1px solid var(--border);\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n#filter-panel.hidden {\n display: none;\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.filter-group label {\n font-size: var(--fs-s);\n font-weight: 600;\n text-transform: uppercase;\n color: var(--text-dim);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.filter-group label .material-symbols-rounded {\n font-size: var(--is-s);\n opacity: 0.7;\n}\n\n.filter-metrics-grid {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 4px;\n}\n\n.mini-pill {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 6px;\n color: var(--text-dim);\n cursor: pointer;\n}\n.mini-pill:hover {\n border-color: var(--text-muted);\n color: var(--text-muted);\n}\n.mini-pill.active {\n background: var(--accent);\n border-color: var(--accent);\n color: white;\n}\n.mini-pill .material-symbols-rounded {\n font-size: var(--is-s);\n}\n\n.filter-row {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.filter-row input {\n flex: 1;\n background: var(--bg);\n border: 1px solid var(--border);\n border-radius: 4px;\n padding: 4px 6px;\n color: var(--text);\n font-size: var(--fs-s);\n}\n.filter-row span {\n font-size: var(--fs-s);\n color: var(--text-dim);\n}\n#filter-panel input:focus {\n border-color: var(--accent);\n outline: none;\n}\n\n.filter-footer {\n display: flex;\n justify-content: flex-end;\n margin-top: 4px;\n}\n\n/* Track list */\n#track-list {\n flex: 1;\n overflow-y: auto;\n padding: 4px 0;\n scrollbar-width: none;\n}\n#track-list::-webkit-scrollbar {\n width: 0;\n height: 0;\n display: none;\n}\n#track-list::-webkit-scrollbar-thumb {\n background: var(--border2);\n border-radius: 2px;\n}\n\n#track-list-empty {\n padding: 40px 20px;\n text-align: center;\n color: var(--text-dim);\n font-size: var(--fs-m);\n}\n\n.track-item {\n display: flex;\n align-items: center;\n padding: 6px 8px;\n gap: 0;\n cursor: pointer;\n border-left: 3px solid transparent;\n}\n.track-item:hover {\n background: rgba(255, 255, 255, 0.03);\n}\n.track-item.selected {\n background: color-mix(in srgb, var(--theme-color) 8%, transparent);\n border-left-color: var(--accent);\n}\n\n.track-color {\n width: 3px;\n border-radius: 1px;\n flex-shrink: 0;\n margin-right: 8px;\n align-self: stretch;\n}\n.track-info {\n flex: 1;\n min-width: 0;\n margin-right: 2px;\n}\n.track-name {\n font-size: var(--fs-m);\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-bottom: 1px;\n}\n.track-meta {\n font-size: var(--fs-s);\n color: var(--text-dim);\n display: flex;\n gap: 6px;\n align-items: center;\n}\n\n.track-item .icon-btn.mini {\n width: 22px;\n height: 22px;\n padding: 0;\n margin: 0;\n}\n\n.badge {\n font-size: var(--fs-s);\n background: var(--surface2);\n padding: 1px 4px;\n border-radius: 3px;\n font-weight: 700;\n color: var(--text-muted);\n}\n\n.track-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin-top: 6px;\n overflow: hidden;\n max-height: 32px;\n}\n\n.track-tag {\n font-size: var(--fs-s);\n font-weight: 700;\n color: var(--text-dim);\n background: rgba(255, 255, 255, 0.03);\n border: 1px solid var(--border);\n padding: 1px 5px;\n border-radius: 3px;\n white-space: nowrap;\n}\n\n.track-item.selected .track-tag {\n border-color: rgba(255, 255, 255, 0.1);\n color: var(--text-muted);\n}\n\n#sidebar-resizer {\n width: 4px;\n cursor: col-resize;\n background: transparent;\n flex-shrink: 0;\n z-index: 1000;\n margin-left: -2px;\n margin-right: -2px;\n user-select: none;\n}\n#sidebar-resizer:hover,\n#sidebar-resizer.dragging {\n background: var(--handle-color);\n}\n\nbody.dragging-sidebar {\n user-select: none;\n cursor: col-resize !important;\n}\n\n/* \u2500\u2500\u2500 Main \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#main {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n/* Map */\n#map-container {\n flex: 1;\n position: relative;\n min-height: 100px;\n}\n#map-container.editing-mode {\n border: 4px solid var(--accent);\n box-shadow: 0 0 15px var(--accent);\n z-index: 1000; /* Ensure glow is visible */\n}\n#map {\n width: 100%;\n height: 100%;\n background: var(--bg);\n}\n\n#map-controls {\n position: absolute;\n top: 12px;\n left: 12px;\n z-index: 1000;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n#basemap-switcher {\n display: flex;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 2px;\n height: 24px;\n box-sizing: border-box;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n align-items: center;\n gap: 0;\n}\n\n#selected-extra-map {\n font-size: var(--fs-s);\n font-weight: 700;\n color: var(--accent);\n padding: 0 6px;\n max-width: 120px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n}\n#selected-extra-map.hidden {\n display: none;\n}\n\n#btn-extra-layers {\n border: none !important;\n border-left: 1px solid var(--border) !important;\n border-radius: 0 !important;\n margin-left: 0 !important;\n padding-left: 6px !important;\n padding-right: 0 !important;\n width: auto !important;\n height: 100% !important;\n background: transparent !important;\n}\n\n#extra-layers-menu {\n position: absolute;\n top: 40px;\n right: 0;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);\n max-height: 300px;\n overflow-y: auto;\n width: 200px;\n z-index: 1000;\n padding: 4px;\n}\n#extra-layers-menu.hidden {\n display: none;\n}\n.extra-layers-header {\n font-size: var(--fs-s);\n font-weight: 700;\n color: var(--text-dim);\n text-transform: uppercase;\n padding: 6px 8px;\n border-bottom: 1px solid var(--border);\n margin-bottom: 4px;\n}\n.extra-layers-search {\n padding: 4px 8px;\n border-bottom: 1px solid var(--border);\n margin-bottom: 4px;\n}\n#extra-layers-search-input {\n width: 100%;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 4px;\n color: var(--text);\n font-size: var(--fs-s);\n padding: 4px 8px;\n outline: none;\n}\n#extra-layers-search-input:focus {\n border-color: var(--accent);\n}\n.extra-layers-license {\n font-size: var(--fs-s);\n color: var(--text-dim);\n padding: 4px 8px;\n border-bottom: 1px solid var(--border);\n margin-bottom: 4px;\n}\n.extra-layers-license a {\n color: var(--accent);\n text-decoration: none;\n}\n.extra-layers-license a:hover {\n text-decoration: underline;\n}\n.extra-layer-row {\n margin-bottom: 2px;\n}\n.extra-layer-item {\n display: block;\n width: 100%;\n text-align: left;\n background: transparent;\n border: none;\n color: var(--text-muted);\n padding: 4px 10px 2px 10px;\n font-size: var(--fs-s);\n font-weight: 600;\n border-radius: 4px;\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.extra-layer-item:hover {\n background: var(--surface2);\n color: var(--text);\n}\n.extra-layer-attribution {\n font-size: var(--fs-s);\n color: var(--text-dim);\n padding: 0 10px 4px 10px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n#map-loader {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 0 10px;\n height: 24px;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--fs-s);\n font-weight: 600;\n color: var(--text-muted);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n}\n.spinner-sm {\n width: 12px;\n height: 12px;\n border: 2px solid var(--surface2);\n border-top-color: var(--accent);\n border-radius: 50%;\n}\n.bm-btn {\n background: transparent;\n border: none;\n color: var(--text-muted);\n padding: 2px 6px;\n font-size: var(--fs-s);\n font-weight: 600;\n border-radius: 6px;\n}\n.bm-btn:hover {\n color: var(--text);\n}\n.bm-btn.active {\n background: var(--surface2);\n color: var(--accent);\n}\n\n/* Map Cursor Dot */\n.map-cursor-dot {\n pointer-events: none;\n}\n.dot-inner {\n width: 12px;\n height: 12px;\n background: #fff;\n border: 2px solid #000;\n border-radius: 50%;\n box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.5);\n}\n\n/* Map cursor info popup */\n#map-cursor-info {\n position: absolute;\n top: 12px;\n right: 12px;\n z-index: 1000;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 8px 12px;\n font-size: var(--fs-s);\n color: var(--text);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n display: none;\n pointer-events: none;\n}\n\n/* Resize handle */\n#resize-handle {\n height: 6px;\n background: var(--bg);\n border-top: 1px solid var(--border);\n border-bottom: 1px solid var(--border);\n cursor: ns-resize;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n z-index: 100;\n}\n#resize-handle:hover {\n background: var(--handle-color);\n}\n.handle-grip {\n width: 32px;\n height: 2px;\n background: var(--border2);\n border-radius: 1px;\n}\n\n/* \u2500\u2500\u2500 Chart Panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#chart-panel {\n display: flex;\n flex-direction: column;\n background: var(--surface);\n overflow: hidden;\n flex: 1;\n width: 100%;\n height: 100%;\n min-height: 0;\n}\n\n#tab-nav {\n display: flex;\n padding: 0 12px;\n border-bottom: 1px solid var(--border);\n gap: 4px;\n}\n\n.tab-btn {\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n color: var(--text-dim);\n padding: 10px 12px;\n font-size: var(--fs-m);\n font-weight: 700;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.tab-btn:hover {\n color: var(--text-muted);\n}\n.tab-btn.active {\n color: var(--accent);\n border-bottom-color: var(--accent);\n}\n.tab-btn .material-symbols-rounded {\n font-size: var(--is-s);\n}\n\n.tab-content {\n display: none;\n flex: 1;\n min-height: 0;\n}\n.tab-content.active {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n scrollbar-width: none;\n}\n\n/* Custom scrollbar for active tab content */\n.tab-content.active::-webkit-scrollbar {\n width: 0;\n height: 0;\n}\n.tab-content.active::-webkit-scrollbar-track {\n background: transparent;\n}\n.tab-content.active::-webkit-scrollbar-thumb {\n background: var(--border);\n border-radius: 3px;\n}\n.tab-content.active::-webkit-scrollbar-thumb:hover {\n background: var(--text-dim);\n}\n\n#chart-toolbar {\n display: flex;\n align-items: center;\n padding: 6px 12px;\n gap: 12px;\n border-bottom: 1px solid var(--border);\n background: var(--bg);\n min-height: 40px;\n position: sticky;\n top: 0;\n z-index: 100;\n}\n\n.icon-btn {\n background: transparent;\n border: 1px solid transparent;\n color: var(--text-muted);\n width: 24px;\n height: 24px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.icon-btn.hidden {\n display: none;\n}\n.icon-btn:hover {\n background: var(--surface2);\n color: var(--text);\n}\n.icon-btn.active {\n background: var(--surface2);\n color: var(--accent);\n}\n.icon-btn.danger:hover {\n background: rgba(239, 68, 68, 0.12);\n color: var(--danger);\n}\n.icon-btn .material-symbols-rounded {\n font-size: var(--fs-l);\n}\n\n#btn-metric-menu {\n flex: 0 0 auto;\n}\n\n#metric-pills {\n display: flex;\n gap: 6px;\n flex: 1;\n overflow: hidden;\n}\n.metric-pill:not(.active) {\n display: none;\n}\n.metric-pill.overflow-hidden {\n display: none !important;\n}\n#pill-overflow {\n color: var(--text-muted);\n font-weight: bold;\n padding: 0 4px;\n align-self: flex-end;\n}\n.metric-pill {\n height: 24px;\n padding: 0 8px;\n border-radius: 12px;\n border: 1px solid var(--border);\n background: var(--surface2);\n color: var(--text-muted);\n font-size: var(--fs-s);\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n.metric-pill .material-symbols-rounded {\n font-size: var(--fs-m);\n}\n.metric-pill.active {\n background: color-mix(in srgb, var(--pill-color) 15%, var(--surface2));\n border-color: var(--pill-color);\n color: var(--pill-color);\n}\n.metric-pill.disabled {\n opacity: 0.3;\n filter: grayscale(1);\n cursor: default;\n}\n\n#chart-options {\n display: flex;\n align-items: center;\n gap: 0;\n margin-left: auto;\n}\n\n.seg-ctrl {\n display: flex;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 6px;\n padding: 2px;\n height: 24px;\n box-sizing: border-box;\n}\n.seg-btn {\n background: transparent;\n border: none;\n color: var(--text-dim);\n padding: 0 8px;\n font-size: var(--fs-s);\n font-weight: 700;\n border-radius: 4px;\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n}\n.seg-btn .material-symbols-rounded {\n font-size: var(--fs-m);\n}\n.seg-btn.active {\n background: var(--bg);\n color: var(--text);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Stats Summary bar */\n#chart-stats {\n padding: 4px 14px;\n border-bottom: 1px solid var(--border);\n background: var(--surface2);\n}\n#chart-stats.hidden {\n display: none;\n}\n#chart-stats-wrap {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.stats-row {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n.stats-row-label {\n width: 45px;\n font-size: var(--fs-s);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--text-muted);\n white-space: nowrap;\n}\n\n.chart-row-stats-container {\n display: flex;\n flex: 1;\n align-items: center;\n justify-content: space-between;\n}\n\n.chart-row-right-actions {\n width: 130px; /* HIST_W */\n display: none;\n align-items: center;\n justify-content: flex-end;\n flex-shrink: 0;\n}\n.with-histogram .chart-row-right-actions {\n display: flex;\n}\n.chart-stats-total,\n.chart-stats-selection {\n display: flex;\n gap: 10px;\n font-size: var(--fs-s);\n color: var(--text-dim);\n align-items: center;\n white-space: nowrap;\n font-weight: 500;\n}\n.chart-stats-selection {\n margin-left: auto;\n position: relative;\n}\n.chart-stats-selection::after {\n content: '';\n position: absolute;\n bottom: -6px;\n left: 0;\n right: 0;\n height: 2px;\n background-color: var(--sel-color);\n pointer-events: none;\n}\n.all-chip {\n background: var(--surface2);\n color: var(--text-muted);\n font-weight: 500;\n padding: 2px;\n border-radius: 4px;\n font-size: var(--fs-m);\n margin-right: 4px;\n cursor: pointer;\n border: 1px solid var(--border);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.all-chip:hover {\n background: var(--border);\n color: var(--text);\n}\n.sel-tag {\n background: var(--surface2);\n color: var(--text-muted);\n font-weight: 500;\n padding: 2px;\n border-radius: 4px;\n font-size: var(--fs-m);\n margin-right: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--border);\n}\n\n.mm-item {\n display: flex;\n align-items: center;\n gap: 2px;\n white-space: nowrap;\n}\n.mm-icon {\n font-size: var(--fs-m);\n color: var(--text-dim);\n}\n\n/* \u2500\u2500 uPlot overrides \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.uplot {\n color: var(--text-muted) !important;\n}\n.u-title {\n display: none;\n}\n.u-legend {\n display: none;\n}\n\n/* Selection drag background \u2014 colour matches the chart's metric */\n.chart-row .u-select {\n background: color-mix(in srgb, var(--chart-color, #3b82f6) 12%, transparent) !important;\n border: 1px solid color-mix(in srgb, var(--chart-color, #3b82f6) 35%, transparent) !important;\n}\n\n/* Make the cursor crosshair dashed */\n.u-cursor-x {\n border-left: 1px dashed rgba(255, 255, 255, 0.55) !important;\n}\n.u-cursor-y {\n display: none !important;\n}\n\n/* \u2500\u2500 Selection fill \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.sel-fill {\n position: absolute;\n top: 0;\n background: color-mix(in srgb, var(--theme-color) 8%, transparent);\n border-left: 1px solid color-mix(in srgb, var(--theme-color) 30%, transparent);\n border-right: 1px solid rgba(148, 163, 184, 0.4);\n pointer-events: none;\n}\n\n/* \u2500\u2500 Selection handles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.sel-handle {\n position: absolute;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 8px;\n height: 24px;\n background: rgba(255, 255, 255, 0.85);\n border: 1px solid rgba(0, 0, 0, 0.3);\n border-radius: 4px;\n cursor: ew-resize;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n}\n.sel-handle::after {\n content: '';\n width: 2px;\n height: 10px;\n border-left: 1px solid rgba(0, 0, 0, 0.4);\n border-right: 1px solid rgba(0, 0, 0, 0.4);\n}\n.sel-handle:hover {\n background: #fff;\n transform: translate(-50%, -50%) scale(1.1);\n}\n\n.sel-graph-marker {\n position: absolute;\n transform: translate(-50%, -50%);\n pointer-events: none;\n z-index: 11;\n background: none !important;\n}\n.sel-graph-marker .material-symbols-rounded {\n}\n\n/* \u2500\u2500 Per-chart selection lines \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.sel-line {\n position: absolute;\n top: 0;\n height: 100%;\n width: 0;\n border-left-width: 1.5px;\n border-left-style: solid;\n pointer-events: none;\n}\n\n/* Labels on the selection lines */\n.sel-line-label {\n position: absolute;\n top: 4px;\n font-size: var(--fs-s);\n font-weight: 700;\n background: rgba(14, 14, 16, 0.92);\n color: #fff;\n padding: 2px 5px;\n border-radius: 4px;\n pointer-events: none;\n white-space: nowrap;\n z-index: 10;\n border: 1px solid var(--border);\n}\n\n/* \u2500\u2500 Charts view elements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#charts-container {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 6px 0 4px;\n scrollbar-width: none;\n}\n#charts-container::-webkit-scrollbar {\n width: 0;\n height: 0;\n}\n#charts-container::-webkit-scrollbar-thumb {\n background: var(--border2);\n border-radius: 2px;\n}\n\n/* Fixed X Axis Labels */\n.fixed-x-label {\n position: absolute;\n bottom: 4px;\n font-size: var(--fs-s);\n font-family: system-ui, sans-serif;\n color: #555564;\n z-index: 10;\n pointer-events: none;\n}\n.fixed-x-max {\n right: 0;\n text-align: right;\n}\n\n/* Histogram column (inline, per chart row) */\n.chart-row-body {\n display: flex;\n flex-direction: row;\n padding: 0 14px;\n min-width: 0;\n overflow: hidden;\n}\n.chart-row-body > div:first-child {\n flex: 1;\n min-width: 0;\n}\n.hist-col {\n width: 130px;\n flex-shrink: 0;\n border-left: 1px solid var(--border);\n margin-left: 20px;\n margin-right: 0;\n display: none;\n align-items: center;\n justify-content: center;\n cursor: crosshair;\n}\n.hist-col.visible {\n display: flex;\n}\n.hist-canvas {\n display: block;\n}\n\n/* Histogram connector line */\n#hist-line {\n position: fixed;\n height: 0;\n border-top: 1px dashed rgba(255, 255, 255, 0.25);\n pointer-events: none;\n display: none;\n z-index: 10000;\n}\n\n/* Histogram tooltip */\n#hist-tooltip {\n position: fixed;\n background: var(--surface);\n border: 1px solid var(--border2);\n border-radius: 5px;\n padding: 8px 10px;\n pointer-events: none;\n display: none;\n z-index: 10001;\n box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);\n font-size: var(--fs-s);\n}\n.hist-tt-header {\n font-weight: 800;\n margin-bottom: 6px;\n padding-left: 8px;\n border-left: 3px solid var(--accent);\n color: var(--text);\n}\n.hist-tt-grid {\n display: grid;\n grid-template-columns: 1fr auto auto;\n gap: 10px;\n align-items: baseline;\n}\n.hist-tt-label {\n font-size: var(--fs-s);\n color: var(--text-muted);\n}\n.hist-tt-value {\n font-size: var(--fs-s);\n color: var(--text);\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n.hist-tt-pct {\n font-size: var(--fs-s);\n color: var(--text-dim);\n text-align: right;\n min-width: 36px;\n font-variant-numeric: tabular-nums;\n}\n.hist-tt-grid.sel-row {\n margin-top: 2px;\n opacity: 0.9;\n}\n.hist-tt-label.sel {\n color: var(--accent);\n font-weight: 700;\n}\n\n.chart-row {\n border-bottom: 1px solid var(--border);\n}\n.chart-row:last-child {\n border-bottom: none;\n}\n\n/* \u2500\u2500 Chart row header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.chart-row-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 14px 4px 14px;\n min-height: 28px;\n}\n\n.progress-chart-row {\n display: flex;\n flex-direction: column;\n}\n\n.progress-chart-row .chart-row-header {\n height: 36px;\n box-sizing: border-box;\n padding-top: 0;\n padding-bottom: 0;\n}\n\n.progress-chart-row .chart-row-actions {\n margin-left: auto;\n}\n\n.progress-chart-row .chart-row-body {\n flex: 1;\n padding: 0;\n}\n\n.chart-row-label-group {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n width: 140px; /* Fixed width for alignment */\n}\n\n.chart-row-actions {\n display: flex;\n align-items: center;\n gap: 0;\n}\n\n.chart-row-icon {\n font-size: var(--is-s);\n color: var(--chart-color);\n}\n.chart-row-label {\n font-size: var(--fs-m);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--text-muted);\n white-space: nowrap;\n}\n\n/* Track Picker Popup */\n.track-picker-popup {\n padding: 8px;\n background: var(--surface);\n color: var(--text);\n border-radius: 8px;\n min-width: 160px;\n}\n.picker-header {\n font-size: var(--fs-s);\n text-transform: uppercase;\n font-weight: 700;\n color: var(--text-dim);\n margin-bottom: 8px;\n padding-bottom: 4px;\n border-bottom: 1px solid var(--border);\n}\n.picker-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.picker-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n cursor: pointer;\n}\n.picker-item:hover {\n background: var(--surface2);\n}\n.picker-color {\n width: 3px;\n height: 14px;\n border-radius: 1px;\n}\n.picker-info {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.picker-name {\n font-size: var(--fs-s);\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 180px;\n}\n/* Custom Modal / Dialog */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 20000;\n}\n.modal-content {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 24px;\n width: 100%;\n max-width: 320px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.modal-title {\n font-size: var(--fs-l);\n font-weight: 800;\n color: var(--text);\n}\n.modal-body {\n font-size: var(--fs-m);\n color: var(--text-muted);\n line-height: 1.5;\n}\n.modal-input-wrap {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.modal-input-label {\n font-size: var(--fs-s);\n font-weight: 700;\n text-transform: uppercase;\n color: var(--text-dim);\n}\n.modal-input {\n background: var(--bg);\n border: 1px solid var(--border2);\n border-radius: 6px;\n padding: 10px;\n color: var(--text);\n font-size: var(--fs-l);\n font-weight: 800;\n text-align: center;\n letter-spacing: 4px;\n}\n.modal-input:focus {\n outline: none;\n border-color: var(--accent);\n}\n.modal-actions {\n display: flex;\n gap: 12px;\n margin-top: 8px;\n}\n.modal-btn {\n flex: 1;\n padding: 10px;\n border-radius: 6px;\n font-size: var(--fs-m);\n font-weight: 700;\n border: 1px solid transparent;\n}\n.modal-btn.cancel {\n background: var(--surface2);\n color: var(--text);\n border-color: var(--border);\n}\n.modal-btn.cancel:hover {\n background: var(--border);\n}\n.modal-btn.confirm {\n background: var(--danger);\n color: #fff;\n}\n.modal-btn.confirm:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n filter: grayscale(1);\n}\n.modal-btn.confirm:not(:disabled):hover {\n filter: brightness(1.1);\n}\n\n.picker-meta {\n font-size: var(--fs-s);\n color: var(--text-dim);\n font-weight: 700;\n}\n\n/* Leaflet Popup Overrides */\n.leaflet-popup-content-wrapper,\n.leaflet-popup-tip {\n background: var(--surface) !important;\n color: var(--text) !important;\n border: 1px solid var(--border) !important;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4) !important;\n}\n.leaflet-popup-content {\n margin: 0 !important;\n}\n.leaflet-popup-tip {\n border: none !important;\n}\n.map-color-btn {\n margin-left: 4px;\n}\n.map-color-btn .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.map-color-btn.active {\n color: var(--chart-color, var(--accent));\n}\n\n.smooth-btn.active {\n color: var(--accent);\n}\n.cur-y-val {\n position: absolute;\n left: 0;\n top: 0;\n pointer-events: none;\n font-size: var(--fs-s);\n font-weight: 700;\n background: rgba(14, 14, 16, 0.92);\n padding: 2px 6px;\n border-radius: 4px;\n border: 1px solid rgba(255, 255, 255, 0.1);\n z-index: 2000;\n white-space: nowrap;\n}\n.cur-y-val.pin {\n z-index: 1000;\n opacity: 0.7;\n}\n\n/* \u2500\u2500\u2500 Details View \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#details-view {\n width: 100%;\n padding: 24px;\n max-width: 900px;\n margin: 0 auto;\n}\n\n#details-header {\n margin-bottom: 32px;\n}\n.details-title {\n font-size: var(--fs-l);\n font-weight: 800;\n margin-bottom: 4px;\n}\n.details-subtitle {\n font-size: var(--fs-m);\n color: var(--text-muted);\n}\n\n.details-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n gap: 16px;\n}\n.details-card {\n background: var(--surface2);\n border: 1px solid var(--border);\n padding: 16px;\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.details-card .material-symbols-rounded {\n color: var(--accent);\n margin-bottom: 4px;\n font-size: var(--is-m);\n}\n.details-card-label {\n font-size: var(--fs-s);\n font-weight: 500;\n text-transform: uppercase;\n color: var(--text-dim);\n letter-spacing: 0.5px;\n}\n.details-card-value {\n font-size: var(--fs-l);\n font-weight: 500;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--text-dim);\n gap: 12px;\n padding: 40px 20px;\n}\n.empty-icon {\n font-size: var(--fs-l);\n opacity: 0.2;\n}\n.empty-text {\n font-size: var(--fs-m);\n font-weight: 500;\n}\n\n#chart-empty {\n height: 100%;\n}\n#details-empty {\n margin-top: 40px;\n}\n\n/* \u2500\u2500 Toast notifications \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#toast-container {\n position: fixed;\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n flex-direction: column;\n gap: 8px;\n z-index: 9999;\n}\n.toast {\n background: var(--surface2);\n color: var(--text);\n padding: 10px 20px;\n border-radius: 8px;\n font-size: var(--fs-m);\n font-weight: 600;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);\n border: 1px solid var(--border2);\n}\n.toast.error {\n border-color: var(--danger);\n}\n.toast.out {\n}\n\n/* \u2500\u2500 Sort menu popup \u2500\u2500 */\n.sort-menu-popup,\n.metric-menu-popup {\n position: fixed;\n z-index: 10000;\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 6px;\n min-width: 180px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);\n}\n\n.menu-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n border-radius: 6px;\n cursor: pointer;\n color: var(--text-muted);\n}\n.menu-item:hover {\n background: var(--surface);\n color: var(--text);\n}\n.menu-item.active {\n color: var(--text);\n font-weight: 600;\n}\n.menu-item .material-symbols-rounded {\n font-size: var(--is-s);\n}\n.menu-item .item-label {\n flex: 1;\n font-size: var(--fs-m);\n}\n.menu-item .arrow,\n.menu-item .check {\n font-size: var(--is-s);\n color: var(--text-dim);\n}\n\n/* \u2500\u2500\u2500 Insights View \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n#insights-view {\n width: 100%;\n padding: 24px;\n max-width: 1000px;\n margin: 0 auto;\n}\n\n.insights-grid {\n column-count: 2;\n column-gap: 24px;\n}\n\n@media (max-width: 900px) {\n .insights-grid {\n column-count: 1;\n }\n}\n\n.insight-card {\n display: inline-flex;\n width: 100%;\n break-inside: avoid;\n margin-bottom: 24px;\n background: var(--surface2);\n border: 1px solid var(--border);\n padding: 20px;\n border-radius: 12px;\n flex-direction: column;\n gap: 16px;\n}\n\n.insight-title {\n font-size: var(--fs-m);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--text-muted);\n}\n\n.insight-title .material-symbols-rounded {\n font-size: var(--is-s);\n}\n\n.insight-chart-container {\n width: 100%;\n height: 250px;\n}\n\n.power-curve-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--fs-m);\n margin-top: 0;\n}\n\n.power-curve-table th {\n text-align: left;\n color: var(--text-dim);\n padding: 4px 8px;\n font-weight: 600;\n border-bottom: 1px solid var(--border);\n}\n\n.power-curve-table td {\n padding: 6px 8px;\n border-bottom: 1px solid var(--border);\n}\n\n.power-curve-table tr:last-child td {\n border-bottom: none;\n}\n\n.progress-details summary {\n cursor: pointer;\n font-size: var(--fs-m);\n color: var(--text-dim);\n display: flex;\n align-items: center;\n gap: 4px;\n list-style: none;\n}\n\n.progress-details summary::-webkit-details-marker {\n display: none;\n}\n\n.progress-details[open] summary .expand-icon {\n transform: rotate(90deg);\n}\n\n.progress-details summary .material-symbols-rounded {\n font-size: var(--fs-l);\n}\n\n.progress-details summary .expand-icon {\n}\n\n.power-curve-val {\n font-weight: 700;\n color: var(--text);\n text-align: right;\n}\n\n.evolution-select-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--chart-color);\n padding: 0;\n font-size: var(--fs-l);\n vertical-align: middle;\n margin-left: 4px;\n}\n\n.hr-settings-popup {\n display: flex;\n flex-direction: column;\n}\n\n.hr-input-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: var(--fs-m);\n color: var(--text-muted);\n font-weight: 600;\n}\n\n.hr-zone-input {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 4px;\n color: var(--text);\n width: 60px;\n padding: 4px 8px;\n font-size: var(--fs-m);\n text-align: right;\n outline: none;\n}\n\n.hr-zone-input:focus {\n border-color: var(--accent);\n}\n\n.save-btn {\n background: var(--accent);\n color: #fff;\n border: none;\n border-radius: 6px;\n padding: 8px;\n font-size: 12px;\n font-weight: 700;\n cursor: pointer;\n}\n\n.save-btn:hover {\n background: var(--accent-hover);\n}\n\n.menu-item.active .arrow,\n.menu-item.active .check {\n color: var(--accent);\n}\n\n/* \u2500\u2500 Evolution View \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.evolution-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 12px;\n border-bottom: 1px solid var(--border);\n background: var(--bg);\n min-height: 40px;\n}\n\n.evolution-toolbar-left,\n.evolution-toolbar-right {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.evolution-toolbar .metric-pills {\n display: flex;\n gap: 6px;\n}\n\n.evolution-toolbar .metric-pill {\n cursor: pointer;\n}\n\n.evolution-container {\n display: flex;\n flex-direction: column;\n gap: 0px;\n padding: 6px 0 4px;\n}\n\n.evolution-card-group {\n display: flex;\n flex-direction: column;\n gap: 10px;\n width: 100%;\n}\n\n.evolution-legend {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--text-dim);\n margin-top: 0px;\n margin-bottom: 0px;\n justify-content: center;\n}\n\n.evolution-legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.evolution-legend-line {\n width: 16px;\n height: 0;\n display: inline-block;\n}\n\n.evolution-legend-line.solid {\n border-top: 2px solid var(--chart-color);\n}\n\n.evolution-legend-line.dashed {\n border-top: 2px dashed #888888;\n}\n\n.evolution-tooltip-title {\n font-weight: bold;\n margin-bottom: 4px;\n}\n\n.evolution-tooltip-row {\n display: flex;\n justify-content: space-between;\n gap: 15px;\n}\n\n.evolution-tooltip-label {\n color: #8a8a93;\n}\n\n.evolution-tooltip-value {\n font-weight: bold;\n}\n\n.evolution-empty-text {\n color: var(--text-dim);\n font-size: 12px;\n text-align: center;\n margin-top: 20px;\n}\n\n.evolution-chart-container {\n height: 250px;\n flex: 1;\n}\n\n.distance-progress-card .card-content,\n.elevation-progress-card .card-content {\n display: flex;\n gap: 20px;\n}\n\n.chart-scroll-container {\n flex: 1;\n overflow-x: auto;\n position: relative;\n background: var(--bg-dim);\n border-radius: 8px;\n padding: 10px;\n scrollbar-width: none;\n}\n.chart-scroll-container::-webkit-scrollbar {\n width: 0;\n height: 0;\n display: none;\n}\n\n.accumulated-table-container {\n width: 250px;\n background: var(--bg-dim);\n border-radius: 8px;\n padding: 15px;\n}\n\n.accumulated-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--fs-m);\n}\n\n.accumulated-table th,\n.accumulated-table td {\n padding: 4px 8px;\n text-align: left;\n border-bottom: 1px solid var(--border-color);\n}\n\n.accumulated-table th {\n color: var(--text-dim);\n font-weight: 500;\n text-transform: uppercase;\n font-size: var(--fs-m);\n letter-spacing: 0.5px;\n}\n\n.accumulated-table td:last-child {\n text-align: right;\n font-weight: 500;\n font-family: monospace;\n}\n\n.accumulated-table tr:last-child td {\n border-bottom: none;\n}\n\n.chart-scroll-container::-webkit-scrollbar {\n height: 4px;\n}\n\n.chart-scroll-container::-webkit-scrollbar-thumb {\n background: var(--border2);\n border-radius: 2px;\n}\n\n/* uPlot overrides to comply with font size restrictions */\n.u-title {\n font-size: var(--fs-m) !important;\n}\n.u-legend {\n font-size: var(--fs-m) !important;\n}\n\n/* Courses Tab */\n.courses-container {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.courses-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.course-item {\n background: var(--surface2);\n border: 1px solid var(--border);\n border-radius: 8px;\n display: flex;\n flex-direction: column;\n cursor: pointer;\n overflow: hidden;\n}\n\n.course-item:hover {\n background: var(--surface3);\n border-color: var(--border-high);\n}\n\n.course-item-header {\n padding: 6px 12px;\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n}\n\n.course-name {\n font-weight: 600;\n flex: 1;\n}\n\n.course-meta {\n color: var(--text-muted);\n font-size: var(--fs-s);\n}\n\n.course-actions {\n display: flex;\n gap: 4px;\n}\n\n.course-actions .icon-btn {\n opacity: 0.5;\n}\n\n.course-item:hover .course-actions .icon-btn {\n opacity: 1;\n}\n\n.expand-icon {\n color: var(--text-muted);\n}\n\n.course-tracks {\n padding: 8px 12px;\n border-top: 1px solid var(--border);\n background: var(--surface1);\n}\n\n.course-tracks-title {\n font-size: var(--fs-xs);\n font-weight: 700;\n color: var(--text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n}\n\n.course-tracks-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--fs-s);\n color: var(--text);\n}\n\n.course-tracks-table th,\n.course-tracks-table td {\n padding: 6px 8px;\n text-align: right;\n border-bottom: 1px solid var(--border-low);\n}\n\n.course-tracks-table th:first-child,\n.course-tracks-table td:first-child,\n.course-tracks-table th:nth-child(2),\n.course-tracks-table td:nth-child(2) {\n text-align: left;\n}\n\n.course-tracks-table td:not(:first-child) {\n white-space: nowrap;\n}\n\n.course-tracks-table th {\n font-weight: 600;\n color: var(--text-muted);\n font-size: var(--fs-xs);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n white-space: nowrap;\n}\n\n.course-tracks-table tr:last-child td {\n border-bottom: none;\n}\n\n.course-tracks-table th:first-child,\n.course-tracks-table td:first-child {\n width: 100%;\n}\n\n.course-track-row:hover {\n background: var(--surface2);\n}\n\n.course-track-row.selected {\n background: color-mix(in srgb, var(--theme-color) 8%, transparent);\n}\n\n.track-name-cell.clickable {\n color: var(--accent);\n cursor: pointer;\n font-weight: 500;\n}\n\n.track-name-cell.clickable:hover {\n text-decoration: underline;\n}\n\n.metric-icon {\n font-size: 16px;\n vertical-align: middle;\n margin-right: 4px;\n}\n\n.metric-icon.duration {\n color: var(--text-muted);\n}\n\n.metric-icon.speed {\n color: #4caf50;\n}\n\n.metric-icon.power {\n color: #ff9800;\n}\n\n.metric-icon.hr {\n color: #f44336;\n}\n\n.course-point-marker {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n"], + "mappings": "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", "names": [] } diff --git a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs index a024ae89c4..52609b0630 100644 --- a/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs +++ b/suites-experimental/tools-gps-tracks/dist/tools-gps-tracks.mjs @@ -1,1050 +1,3284 @@ -var Gt=(()=>{let t=typeof location<"u"?location.pathname:"/",s=typeof location<"u"?location.search.replace(/^\?/,""):"",e={},n=s,o=null,i=null,a=!1,r=[{state:null,url:t+(s?`?${s}`:"")}];function d(){let b=new URLSearchParams(n),g={};b.has("track")&&(g.track=b.get("track")),b.has("map")&&(g.map=b.get("map")),b.has("xaxis")&&(g.xaxis=b.get("xaxis")),b.has("tab")&&(g.tab=b.get("tab")),b.has("sel_point")&&(g.sel_point=Number(b.get("sel_point"))),b.has("speed_mode")&&(g.speed_mode=b.get("speed_mode")),b.has("progress")&&(g.progress=b.get("progress"));let u=b.get("metrics");if(u&&(g.metrics=u.split(",").filter(Boolean)),b.has("f_date")&&(g.f_date=b.get("f_date").split(",").map(v=>v||null)),b.has("f_dist")&&(g.f_dist=b.get("f_dist").split(",").map(v=>v?Number(v):null)),b.has("f_dur")&&(g.f_dur=b.get("f_dur").split(",").map(v=>v?Number(v):null)),b.has("f_mets")&&(g.f_mets=b.get("f_mets").split(",")),b.has("f_tags")&&(g.f_tags=b.get("f_tags").split(",")),b.has("q")&&(g.q=b.get("q")),b.has("re")&&(g.re=b.get("re")==="1"),b.has("sort")){let v=b.get("sort"),k=v.startsWith("-"),f=k?v.substring(1):v;g.sort=`${f}-${k?"desc":"asc"}`}if(b.has("map_pos")){let v=b.get("map_pos").split(",").map(Number);v.length===3&&v.every(isFinite)&&(g.map_pos=v)}if(b.has("storage")&&(g.storage=b.get("storage")),b.has("sel")){let v=b.get("sel").split(",").map(Number);v.length===2&&v.every(k=>!isNaN(k)&&isFinite(k))&&(g.sel=v)}return g}function T(){i&&(clearTimeout(i),i=null);let b=new URLSearchParams;if(e.track&&b.set("track",e.track),e.map&&b.set("map",e.map),e.xaxis&&e.xaxis!=="time"&&b.set("xaxis",e.xaxis),e.tab&&e.tab!=="graphs"&&b.set("tab",e.tab),e.storage&&e.storage!=="memory"&&b.set("storage",e.storage),e.sel_point!==void 0&&b.set("sel_point",String(e.sel_point)),e.speed_mode&&b.set("speed_mode",e.speed_mode),e.q&&b.set("q",e.q),e.progress&&b.set("progress",e.progress),e.re&&b.set("re","1"),e.sort){let u=e.sort.split("-"),v=u[0],k=u[1];b.set("sort",(k==="desc"?"-":"")+v)}let g=b.toString();if(e.metrics&&(g+=`${g?"&":""}metrics=${e.metrics.join(",")}`),e.f_date&&(g+=`${g?"&":""}f_date=${e.f_date.map(u=>u||"").join(",")}`),e.f_dist&&(g+=`${g?"&":""}f_dist=${e.f_dist.map(u=>u??"").join(",")}`),e.f_dur&&(g+=`${g?"&":""}f_dur=${e.f_dur.map(u=>u??"").join(",")}`),e.f_mets&&(g+=`${g?"&":""}f_mets=${e.f_mets.join(",")}`),e.f_tags&&(g+=`${g?"&":""}f_tags=${e.f_tags.join(",")}`),e.map_pos){let u=`${(+e.map_pos[0]).toFixed(5)},${(+e.map_pos[1]).toFixed(5)},${e.map_pos[2]}`;g+=`${g?"&":""}map_pos=${u}`}if(e.sel){let u=`${+e.sel[0].toFixed(4)},${+e.sel[1].toFixed(4)}`;g+=`${g?"&":""}sel=${u}`}if(n=g,g!==o){let v=(typeof location<"u"?location.pathname:"/")+(g?`?${g}`:""),k=d();a?(r.push({state:k,url:v}),r.length>100&&r.shift(),a=!1):r.length>0?r[r.length-1]={state:k,url:v}:r.push({state:k,url:v}),o=g}}e=d();function $(){return{...e}}function M(b,g=!1){g&&(a=!0);for(let[u,v]of Object.entries(b)){let k=u;v==null?delete e[k]:e[k]=v}T()}function F(){e=d()}function I(){i&&(clearTimeout(i),i=null),e={},a=!1,n="",o="",r=[{state:null,url:typeof location<"u"?location.pathname:"/"}]}return{read:d,get:$,patch:M,refresh:F,reset:I}})();var ws=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(s){return this.trackStore.set(s.id,s),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(s){return this.trackStore.delete(s),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(s,e){return this.settingStore.set(s,e),Promise.resolve()}async get(s){return Promise.resolve(this.settingStore.get(s)??null)}},zs=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((s,e)=>{let n=indexedDB.open(this.DB_NAME,this.DB_VERSION);n.onupgradeneeded=()=>{let o=n.result;o.objectStoreNames.contains("tracks")||o.createObjectStore("tracks",{keyPath:"id"}),o.objectStoreNames.contains("settings")||o.createObjectStore("settings")},n.onsuccess=()=>{this.db=n.result,s()},n.onerror=()=>e(n.error)})}getStore(s,e){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(s,e).objectStore(s)}async save(s){return new Promise((e,n)=>{let o=this.getStore("tracks","readwrite").put(s);o.onsuccess=()=>e(),o.onerror=()=>n(o.error)})}async getAll(){return new Promise((s,e)=>{let n=this.getStore("tracks","readonly").getAll();n.onsuccess=()=>s(n.result||[]),n.onerror=()=>e(n.error)})}async remove(s){return new Promise((e,n)=>{let o=this.getStore("tracks","readwrite").delete(s);o.onsuccess=()=>e(),o.onerror=()=>n(o.error)})}async clear(){return this.db?new Promise((s,e)=>{let n=this.db.transaction(["tracks","settings"],"readwrite");n.objectStore("tracks").clear(),n.objectStore("settings").clear(),n.oncomplete=()=>s(),n.onerror=()=>e(n.error)}):Promise.resolve()}async set(s,e){return new Promise((n,o)=>{let i=this.getStore("settings","readwrite").put(e,s);i.onsuccess=()=>n(),i.onerror=()=>o(i.error)})}async get(s){return new Promise((e,n)=>{let o=this.getStore("settings","readonly").get(s);o.onsuccess=()=>e(o.result??null),o.onerror=()=>n(o.error)})}},rn=new ws,ce={openDB:async()=>{rn=Gt.get().storage==="indexeddb"?new zs:new ws,await rn.openDB()},save:t=>rn.save(t),getAll:()=>rn.getAll(),remove:t=>rn.remove(t),clear:()=>rn.clear(),set:(t,s)=>rn.set(t,s),get:t=>rn.get(t)};import Al from"fit-file-parser";function en(t,s,e,n){let i=t*Math.PI/180,a=e*Math.PI/180,r=(e-t)*Math.PI/180,d=(n-s)*Math.PI/180,T=Math.sin(r/2)*Math.sin(r/2)+Math.cos(i)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2);return 6371e3*(2*Math.atan2(Math.sqrt(T),Math.sqrt(1-T)))}function wo(t){let s=new Uint32Array([Math.floor(t/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(s.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function To(){return Math.random().toString(36).slice(2,6)}function ze(t){return t<60?`${Math.round(t)}s`:t<3600?`${Math.round(t/60)}m`:`${Math.round(t/3600)}h`}function he(t){let s=Math.floor(t/3600),e=Math.floor(t%3600/60);return s>0?`${s}h ${e}m`:`${e}m ${Math.floor(t%60)}s`}function On(t){if(t==null||!isFinite(t))return"--";let s=Math.floor(t/60),e=Math.round(t%60);return`${s}:${e.toString().padStart(2,"0")}`}function nn(t){let s=new Date(t);return isNaN(s.getTime())?"Unknown date":s.toISOString().split("T")[0]}function So(t){let s=new Date(t);if(isNaN(s.getTime()))return"Unknown";let e=s.toISOString();return`${e.split("T")[0]} ${e.split("T")[1].slice(0,5)}`}function Mo(t){if(t===0)return"0 B";let s=1024,e=["B","KB","MB","GB"],n=Math.floor(Math.log(t)/Math.log(s));return`${parseFloat((t/Math.pow(s,n)).toFixed(2))} ${e[n]}`}function me(t){return String(t).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function Ts(t){let s=0;for(let n=0;n=0&&M0?d/T:t[r]}return a}function le(t,s=1){let e=parseInt(t.slice(1,3),16),n=parseInt(t.slice(3,5),16),o=parseInt(t.slice(5,7),16);return`rgba(${e}, ${n}, ${o}, ${s})`}function Ss(t){if(!t.length)return null;let s=t[0].lat,e=t[0].lat,n=t[0].lon,o=t[0].lon;for(let i of t)i.late&&(e=i.lat),i.lono&&(o=i.lon);return{minLat:s,maxLat:e,minLon:n,maxLon:o}}var Ne=16384,Il=new Float64Array(Ne),Hl=new Float64Array(Ne),Fl=new Float64Array(Ne),Dl=new Float64Array(Ne),Bl=new Float64Array(Ne),_l=new Float64Array(Ne),Rl=new Float64Array(Ne);function Ms(t,s){let e=t.length;if(e<=2)return t;let n=e<=Ne?Il:new Float64Array(e),o=e<=Ne?Hl:new Float64Array(e),i=e<=Ne?Fl:new Float64Array(e),a=e<=Ne?Dl:new Float64Array(e);for(let I=0;I=b){let E=g+u>>1,_=(o[E]-(o[g]+o[u])*.5)*v,W=n[E]-(n[g]+n[u])*.5;d+=Math.sqrt(_*_+W*W)+(a[u]-a[g])*1e-6,g=u}}}let $=[t[0]],M=t[0],F=d<-1e9?1e-9:0;for(let I=1;I=s&&($.push(b),M=b)}return $.push(t[e-1]),$}var Jt=(()=>{function t(w){let y=w.length,m=0;for(let N=0;N0){let G=w[N-1],U=en(G.lat,G.lon,C.lat,C.lon);if(m+=U,C.speed==null&&C.time!=null&&G.time!=null){let j=(C.time-G.time)/1e3;j>0&&j<10&&(C.speed=U/j)}if(C.gradient===void 0&&C.ele!=null&&G.ele!=null){let j=C.ele-G.ele;U>.5?C.gradient=j/U*100:C.gradient=G.gradient||0}}C.dist=m}if(y>2){let N=y<=Ne?Bl:new Float64Array(y),C=y<=Ne?_l:new Float64Array(y),G=y<=Ne?Rl:new Float64Array(y);for(let nt=0;nt=$t){z-=C[it-$t],D-=G[it-$t];let K=z*ht,bt=N[it]-N[it-$t],Pt=1.225*Math.exp(-N[it]*Rt),ut=Math.atan2(bt,(D+1)*.5);j+=K*K*Pt*1e-4+ut*(D*ht)*.01}}let at=j<-1e12?1e-9:0;for(let nt=1;nt0){let Lt=w[Ht-1];if(dt.ele!=null&&Lt.ele!=null){let st=dt.ele-Lt.ele;st>0?m.elevGain+=st:m.elevLoss-=st}(dt.gearFront!=null&&dt.gearFront!==Lt.gearFront||dt.gearRear!=null&&dt.gearRear!==Lt.gearRear)&&K++}dt.power!=null&&(N+=dt.power,C++,dt.power>m.maxPower&&(m.maxPower=dt.power)),dt.hr!=null&&(G+=dt.hr,U++,dt.hr>m.maxHR&&(m.maxHR=dt.hr)),dt.cad!=null&&(j+=dt.cad,Rt++),dt.speed!=null&&(at+=dt.speed,nt++,dt.speed>m.maxSpeed&&(m.maxSpeed=dt.speed)),dt.battery!=null&&($t+=dt.battery,ht++),dt.temp!=null&&(it=!0,z+=dt.temp,D++,(m.minTemp==null||dt.tempm.maxTemp)&&(m.maxTemp=dt.temp)),(dt.gearFront!=null||dt.gearRear!=null)&&(bt=!0)}m.totalDist=w[w.length-1].dist||0,m.avgPower=C?Math.round(N/C):null,m.avgHR=U?Math.round(G/U):null,m.avgCadence=Rt?Math.round(j/Rt):null,m.avgSpeed=nt?at/nt:null,m.avgBattery=ht?Math.round($t/ht):null,m.avgTemp=D?Number((z/D).toFixed(1)):null,m.shifts=bt?K:null;let Pt=w[0].time,ut=w[w.length-1].time;return Pt!=null&&ut!=null&&(m.duration=ut-Pt),U&&(m.sensors.push("Heart Rate"),y&&(m.hrZones=b(w),m.hrCurve=$(w))),Rt&&m.sensors.push("Cadence"),C&&(m.sensors.push("Power"),y&&(m.powerCurve=T(w),m.powerZones=M(w))),it&&m.sensors.push("Temperature"),bt&&m.sensors.push("Shifting"),ht&&m.sensors.push("Battery"),m}function o(w){if(!w||!w.points||!w.stats)return;let y=w.points,m=w.stats;m.avgHR!=null&&!m.hrCurve&&(m.hrZones=b(y),m.hrCurve=$(y)),m.avgPower!=null&&!m.powerCurve&&(m.powerCurve=T(y),m.powerZones=M(y))}function i(w){let y=w.length;if(y<8)return[];let m=[],N=["Q1 Opening Sector","Q2 Mid-Climb Sector","Q3 Valley Tempo","Q4 Finale Sector"];for(let K=0;K<4;K++){let bt=Math.floor(K*y/4),Pt=Math.min(y-1,Math.floor((K+1)*y/4)-1);if(Pt>bt){let ut=w.slice(bt,Pt+1);m.push({id:`q${K+1}`,label:N[K],kind:"quarter",startIdx:bt,endIdx:Pt,stats:n(ut,!0)})}}let C=["Opening Third","Middle Third","Final Third"];for(let K=0;K<3;K++){let bt=Math.floor(K*y/3),Pt=Math.min(y-1,Math.floor((K+1)*y/3)-1);if(Pt>bt){let ut=w.slice(bt,Pt+1);m.push({id:`t${K+1}`,label:C[K],kind:"third",startIdx:bt,endIdx:Pt,stats:n(ut,!1)})}}let G=0,U=1e3,j=1;for(let K=1;K=U||K===y-1){if(K>G+2){let Pt=w.slice(G,K+1);m.push({id:`km-${j}`,label:`Km ${j}`,kind:"km",startIdx:G,endIdx:K,stats:n(Pt,!1)}),j++}G=K,U+=1e3}let Rt=30,at=!1,nt=0,$t=1,ht=!1,z=0,D=1,it=e*1.15;for(let K=Rt;K=1.8&&!at)at=!0,nt=K-Rt;else if((ut<.8||K===y-1)&&at&&(at=!1,K-nt>=45&&$t<=6)){let dt=w.slice(nt,K+1);m.push({id:`climb-${$t}`,label:`Climb Segment ${$t}`,kind:"climb",startIdx:nt,endIdx:K,stats:n(dt,!0)}),$t++}let Ht=w[K].power??0;if(Ht>=it&&!ht)ht=!0,z=K;else if((Ht=15&&D<=6)){let dt=w.slice(z,K+1);m.push({id:`sprint-${D}`,label:`Sprint Interval ${D}`,kind:"sprint",startIdx:z,endIdx:K,stats:n(dt,!0)}),D++}}return m}function a(w){let y=[];for(let m=0;mm)continue;let Rt=0,at=0,nt=m-j;for(let $t=0;$t<=nt;$t++){let ht=N[$t+j]-N[$t];ht>Rt&&(Rt=ht,at=$t)}C[j]={val:Math.round(Rt/j),idx:at},G=!0}return G?C:null}function T(w){let y=w.length,m=new Array(y),N=!1;for(let U=0;UN*e);for(let N=1;N10)continue;let j=C.power;jN===0)?null:y}function F(w){e=w}function I(){return e}function b(w){let y=[0,0,0,0,0];for(let m=1;m10)continue;let U=N.hr;Um===0)?null:y}function g(w){s=w}function u(){return[...s]}function v(w,y,m){let N=w.indexOf(y);if(N===-1)return null;let C=N+y.length,G=w.indexOf(m,C);if(G===-1)return null;let U=w.slice(C,G).trim();return U!==""?U:null}function k(w,y){let m=w.indexOf(y);if(m===-1)return null;let N=m+y.length,C=w.indexOf('"',N);return C===-1?null:w.slice(N,C)}let f=-1,h=0;function p(w,y,m){for(;yy&&w.charCodeAt(m-1)<=32;)m--;if(y>=m)return null;let N=!1,C=w.charCodeAt(y);C===45?(N=!0,y++):C===43&&y++;let G=0,U=0;for(let j=y;j=48&&Rt<=57)G=G*10+(Rt-48),U++;else break}return U===0?null:N?-G:G}function E(w,y,m){for(;yy&&w.charCodeAt(m-1)<=32;)m--;if(y>=m)return null;let N=!1,C=w.charCodeAt(y);C===45?(N=!0,y++):C===43&&y++;let G=0,U=0,j=1,Rt=!1,at=0;for(let $t=y;$t=48&&ht<=57)at++,Rt?(U=U*10+(ht-48),j*=10):G=G*10+(ht-48);else if(ht===46&&!Rt)Rt=!0;else{let z=parseFloat(w.slice(y-(N?1:0),m));return Number.isFinite(z)?z:null}}if(at===0)return null;let nt=G+U/j;return N?-nt:nt}function _(w,y,m){for(;yy&&w.charCodeAt(m-1)<=32;)m--;let N=m-y;if(N>=20&&w.charCodeAt(y+10)===84&&w.charCodeAt(m-1)===90){let G=(w.charCodeAt(y)-48)*1e3+(w.charCodeAt(y+1)-48)*100+(w.charCodeAt(y+2)-48)*10+(w.charCodeAt(y+3)-48),U=(w.charCodeAt(y+5)-48)*10+(w.charCodeAt(y+6)-48),j=(w.charCodeAt(y+8)-48)*10+(w.charCodeAt(y+9)-48),Rt=G<<9|U<<5|j;Rt!==f&&(f=Rt,h=Date.UTC(G,U-1,j));let at=(w.charCodeAt(y+11)-48)*10+(w.charCodeAt(y+12)-48),nt=(w.charCodeAt(y+14)-48)*10+(w.charCodeAt(y+15)-48),$t=(w.charCodeAt(y+17)-48)*10+(w.charCodeAt(y+18)-48),ht=0;return w.charCodeAt(y+19)===46&&N>=24&&(ht=(w.charCodeAt(y+20)-48)*100+(w.charCodeAt(y+21)-48)*10+(w.charCodeAt(y+22)-48)),h+at*36e5+nt*6e4+$t*1e3+ht}let C=new Date(w.slice(y,m)).getTime();return Number.isFinite(C)?C:null}function W(w,y,m,N){let C=w.indexOf(N,y);if(C===-1||C>=m)return 0;let G=C+N.length,U=w.indexOf('"',G);return U===-1||U>=m?0:E(w,G,U)??0}function O(w,y){let m=y??new TextDecoder().decode(w),N=m.indexOf(""),U=(G!==-1?v(C.slice(G),"",""):null)||v(C,"","")||"Unnamed Track",j=C.indexOf(">",C.indexOf("",z+6);if(D===-1)break;let it=m.indexOf("",D+1);if(it===-1)break;nt=it+8;let K=W(m,z+6,D+1,'lat="'),bt=W(m,z+6,D+1,'lon="'),Pt=null,ut=null,Ht=null,dt=null,Lt=null,st=null,gt=null,At=null,zt=null,V=null,R=null,Dt=null,It=D+1;for(;It=it)break;let vt=m.indexOf(">",Et+1);if(vt===-1||vt>=it)break;let yt=m.charCodeAt(Et+1);if(yt===47){It=vt+1;continue}let _t=vt-Et-1;if(yt===103&&_t===26&&Ht!==null&&dt!==null&&st!==null)break;let qt=m.indexOf("<",vt+1);if(qt===-1||qt>it)break;if(m.charCodeAt(qt+1)===47){let Yt=vt+1,ee=qt;_t===3?yt===101?Pt=E(m,Yt,ee):yt===99&&dt===null&&(dt=p(m,Yt,ee)):_t===2?yt===104&&Ht===null&&(Ht=p(m,Yt,ee)):_t===4?yt===116?m.charCodeAt(Et+2)===105?ut=_(m,Yt,ee):st===null&&(st=E(m,Yt,ee)):yt===84&&st===null&&(st=E(m,Yt,ee)):_t===5?(yt===112||yt===80||yt===87)&&Lt===null?Lt=E(m,Yt,ee):(yt===115||yt===83)&>===null?gt=E(m,Yt,ee):yt===97&&st===null&&(st=E(m,Yt,ee)):_t===7?(yt===98||yt===66)&&Dt===null?Dt=p(m,Yt,ee):yt===67&&dt===null&&(dt=p(m,Yt,ee)):_t===8?(yt===103||yt===71)&&zt===null&&(zt=p(m,Yt,ee)):_t===9?yt===103?m.charCodeAt(Et+8)===104&&Ht===null?Ht=p(m,Yt,ee):At===null&&(At=p(m,Yt,ee)):yt===71&&At===null&&(At=p(m,Yt,ee)):_t===10?(yt===103&&dt===null||yt===82&&dt===null)&&(dt=p(m,Yt,ee)):_t===12?yt===103&&m.charCodeAt(Et+8)===97&&st===null?st=E(m,Yt,ee):yt===80&&Lt===null?Lt=E(m,Yt,ee):yt===72&&Ht===null&&(Ht=p(m,Yt,ee)):_t===13?(yt===103||yt===71)&&R===null&&(R=p(m,Yt,ee)):_t===14?(yt===103||yt===71)&&V===null?V=p(m,Yt,ee):yt===65&&st===null&&(st=E(m,Yt,ee)):_t===11&&yt===84&&st===null&&(st=E(m,Yt,ee));let xe=qt+2+_t;if(m.charCodeAt(xe)===62)It=xe+1;else{let De=m.indexOf(">",qt+2);It=De!==-1?De+1:qt+2}if(Dt!==null&&Ht!==null&&dt!==null&&st!==null)break}else It=qt}let Wt=null;V!=null&&R!=null&&R!==0?Wt=V/R:At!=null&&zt!=null&&zt!==0&&(Wt=At/zt),at.push({lat:K,lon:bt,ele:Pt,time:ut,hr:Ht,cad:dt,power:Lt,speed:gt,temp:st,gearFront:At,gearRear:zt,gearFrontTooth:V,gearRearTooth:R,battery:Dt,gears:Wt})}if(!at.length)throw new Error("No track points found in GPX");let $t=t(at),ht=n($t);return{name:U,device:Rt,format:"gpx",points:$t,stats:ht}}function Y(w,y){let m=y??new TextDecoder().decode(w),N=m.indexOf(""),C=N!==-1?m.slice(0,N):m,G=v(C,"","")||"Unnamed TCX",U=v(C,"",""),j=U?v(U,"",""):null,Rt=[],at=N!==-1?N:0;for(;at",at);if(ht===-1)break;let z=m.indexOf("",ht+12);if(z===-1)break;at=z+13;let D=null,it=null,K=null,bt=null,Pt=null,ut=null,Ht=null,dt=null,Lt=null,st=null,gt=null,At=null,zt=null,V=null,R=ht+12;for(;R=z)break;let Wt=m.indexOf(">",It+1);if(Wt===-1||Wt>=z)break;let Et=m.charCodeAt(It+1);if(Et===47){R=Wt+1;continue}let vt=Wt-It-1,yt=m.indexOf("<",Wt+1);if(yt===-1||yt>z)break;if(m.charCodeAt(yt+1)===47){let _t=Wt+1,qt=yt;vt===4?Et===84?m.charCodeAt(It+2)===105?bt=_(m,_t,qt):Lt===null&&(Lt=E(m,_t,qt)):Et===116&&Lt===null&&(Lt=E(m,_t,qt)):vt===5?Et===86&&Pt===null?Pt=p(m,_t,qt):(Et===87||Et===80||Et===112)&&Ht===null?Ht=E(m,_t,qt):(Et===83||Et===115)&&dt===null?dt=E(m,_t,qt):Et===97&&Lt===null&&(Lt=E(m,_t,qt)):vt===7?Et===67&&ut===null?ut=p(m,_t,qt):(Et===66||Et===98)&&V===null&&(V=p(m,_t,qt)):vt===8?(Et===71||Et===103)&>===null&&(gt=p(m,_t,qt)):vt===9?(Et===71||Et===103)&&st===null&&(st=p(m,_t,qt)):vt===10?Et===82&&ut===null&&(ut=p(m,_t,qt)):vt===11?Et===84&&Lt===null&&(Lt=E(m,_t,qt)):vt===13?(Et===71||Et===103)&&zt===null&&(zt=p(m,_t,qt)):vt===14?Et===65?m.charCodeAt(It+2)===108?K=E(m,_t,qt):Lt===null&&(Lt=E(m,_t,qt)):(Et===71||Et===103)&&At===null&&(At=p(m,_t,qt)):vt===15?Et===76&&(D=E(m,_t,qt)):vt===16?Et===76&&(it=E(m,_t,qt)):vt===2&&Et===104&&Pt===null?Pt=p(m,_t,qt):vt===3&&Et===99&&ut===null?ut=p(m,_t,qt):vt===12&&(Et===72&&Pt===null?Pt=p(m,_t,qt):Et===80&&Ht===null&&(Ht=E(m,_t,qt)));let Yt=yt+2+vt;if(m.charCodeAt(Yt)===62)R=Yt+1;else{let ee=m.indexOf(">",yt+2);R=ee!==-1?ee+1:yt+2}if(V!==null&&Pt!==null&&ut!==null&&Lt!==null)break}else R=yt}if(D==null||it==null)continue;let Dt=null;At!=null&&zt!=null&&zt!==0?Dt=At/zt:st!=null&>!=null&>!==0&&(Dt=st/gt),Rt.push({lat:D,lon:it,ele:K,time:bt,hr:Pt,cad:ut,power:Ht,speed:dt,temp:Lt,gearFront:st,gearRear:gt,gearFrontTooth:At,gearRearTooth:zt,battery:V,gears:Dt})}let nt=t(Rt),$t=n(nt);return{name:G,device:j,format:"tcx",points:nt,stats:$t}}function Z(w){if(w.byteLength<14)return null;let y=new DataView(w),m=y.getUint8(0);if(m<12||m+2>w.byteLength||y.getUint8(8)!==46||y.getUint8(9)!==70||y.getUint8(10)!==73||y.getUint8(11)!==84)return null;let N=y.getUint32(4,!0),C=Math.min(w.byteLength,m+N),G=631065600,U=180/Math.pow(2,31),j=new Array(16),Rt=[],at=[],nt=[],$t=[],ht=[],z=m;for(;zC)return null;z++;let bt=y.getUint8(z++)===0,Pt=y.getUint16(z,bt);z+=2;let ut=y.getUint8(z++);if(z+ut*3>C)return null;let Ht=new Array(ut),dt=0;for(let Lt=0;LtC)return null;let bt=K.littleEndian,Pt=K.globalMsgNum;if(Pt===20&&K.fields.length===10&&K.recordSize===25&&K.fields[0].num===253&&K.fields[1].num===0){let dt=y.getUint32(z,bt),Lt=y.getInt32(z+4,bt),st=y.getInt32(z+8,bt),gt=y.getUint16(z+12,bt),At=y.getUint8(z+14),zt=y.getUint8(z+15),V=y.getUint32(z+16,bt),R=y.getUint16(z+20,bt),Dt=y.getUint16(z+22,bt),It=y.getInt8(z+24);nt.push({timestamp:(dt+G)*1e3,position_lat:Lt*U,position_long:st*U,altitude:gt/5-500,heart_rate:At,cadence:zt,distance:V/100,speed:R/1e3*3.6,power:Dt,temperature:It}),z+=25;continue}let ut={},Ht=z;for(let dt=0;dt{let N=(U,j)=>{if(U){m(U);return}try{let Rt=j.sessions?.[0]?.start_time?`Fit Activity ${new Date(j.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",at=null,nt=[],$t=null,ht=null;j.sports?.[0]?($t=j.sports[0].sport,ht=j.sports[0].sub_sport):j.sessions?.[0]&&($t=j.sessions[0].sport,ht=j.sessions[0].sub_sport);let z=V=>V.product_name||V.garmin_product||V.product||V.device_type||V.manufacturer||null;if(j.file_ids?.[0]){let V=j.file_ids[0];at=z(V),nt.push({name:V.product_name||V.garmin_product||V.product,manufacturer:V.manufacturer,serial:V.serial_number?String(V.serial_number):void 0,version:V.software_version?String(V.software_version):void 0,type:"main"})}j.device_infos&&j.device_infos.forEach(V=>{if(V.device_index==="creator"||V.device_index===0){let Dt=z(V);(V.product_name||V.garmin_product||!at)&&(at=Dt),nt.length>0&&nt[0].type==="main"&&((V.product_name||V.garmin_product||!nt[0].name)&&(nt[0].name=V.product_name||V.garmin_product||V.product),nt[0].manufacturer||(nt[0].manufacturer=V.manufacturer),!nt[0].serial&&V.serial_number&&(nt[0].serial=String(V.serial_number)),!nt[0].version&&V.software_version&&(nt[0].version=String(V.software_version)),!nt[0].hardwareVersion&&V.hardware_version&&(nt[0].hardwareVersion=String(V.hardware_version)));return}nt.push({name:V.product_name||V.garmin_product||V.product||V.device_type||"Sensor",manufacturer:V.manufacturer,serial:V.serial_number?String(V.serial_number):void 0,version:V.software_version?String(V.software_version):void 0,hardwareVersion:V.hardware_version?String(V.hardware_version):void 0,type:V.device_type||"sensor",batteryStatus:V.battery_status,batteryVoltage:V.battery_voltage,batteryLevel:V.battery_level,sourceType:V.source_type!=null?String(V.source_type):void 0})}),j.sensor_settings&&j.sensor_settings.forEach(V=>{let R=V.name||V.product||V.sensor_type;if(!R)return;let Dt=V.ant_id?String(V.ant_id):void 0,It=nt.find(Wt=>Dt&&Wt.serial===Dt||Wt.name===R&&Wt.manufacturer===V.manufacturer);It?(It.name||(It.name=R),It.manufacturer||(It.manufacturer=V.manufacturer),It.type||(It.type=V.sensor_type),It.sourceType||(It.sourceType=V.connection_type!=null?String(V.connection_type):void 0)):nt.push({name:R,manufacturer:V.manufacturer,serial:Dt,type:V.sensor_type||"sensor",sourceType:V.connection_type!=null?String(V.connection_type):void 0})});let D=[];j.device_statuses&&(j.device_statuses.forEach((V,R)=>{V.timestamp&&V.battery_level!=null&&D.push({time:typeof V.timestamp=="number"?V.timestamp:new Date(V.timestamp).getTime(),level:V.battery_level,idx:R})}),D.sort((V,R)=>V.time-R.time||V.idx-R.idx));let it=[];j.events&&(j.events.forEach((V,R)=>{let Dt=V.front_gear_num??V.front_gear??null,It=V.rear_gear_num??V.rear_gear??null,Wt=V.front_gear_num_tooth??null,Et=V.rear_gear_num_tooth??null;if(V.event==="rear_gear_change"||V.event==="front_gear_change"){let vt=V.data;if(vt!=null){let yt=vt>>24&255,_t=vt>>16&255,qt=vt>>8&255,Yt=vt&255;_t!==0&&(Dt=_t),yt!==0&&(Wt=yt),Yt!==0&&(It=Yt),qt!==0&&(Et=qt)}}V.timestamp&&(Dt!=null||It!=null||Wt!=null||Et!=null)&&it.push({time:typeof V.timestamp=="number"?V.timestamp:new Date(V.timestamp).getTime(),front:Dt,rear:It,frontTooth:Wt,rearTooth:Et,idx:R})}),it.sort((V,R)=>V.time-R.time||V.idx-R.idx));let K=j.records||[],bt=null,Pt=0,ut=null,Ht=null,dt=null,Lt=null,st=0,gt=[];for(let V=0;V name, Placemark > name");C&&(N=C.textContent?.trim()||N);let G=m.querySelectorAll("coordinates");if(!G.length)throw new Error("No coordinates found in KML");let U=[];if(G.forEach(at=>{(at.textContent?.trim().split(/\s+/)||[]).forEach($t=>{let ht=$t.split(",");if(ht.length<2)return;let z=parseFloat(ht[0]),D=parseFloat(ht[1]),it=ht.length>2?parseFloat(ht[2]):null;isNaN(D)||isNaN(z)||U.push({lat:D,lon:z,ele:it!=null&&isNaN(it)?null:it,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!U.length)throw new Error("No valid coordinates in KML");let j=t(U),Rt=n(j);return{name:N,format:"kml",points:j,stats:Rt}}async function rt(w){let y=w.name.split(".").pop()?.toLowerCase(),m=w._buf??await w.arrayBuffer(),N=w._text,C;switch(y){case"gpx":C=O(m,N);break;case"tcx":C=Y(m,N);break;case"fit":C=await lt(m);break;case"kml":C=Ft(m);break;default:throw new Error(`Unsupported format: .${y}`)}return C&&(C.fileName=w.name,C.fileSize=w.size,C.points&&C.stats&&(o(C),C.stats.sections=i(C.points))),C}return{parseFile:rt,computeStats:n,ensureCurvesAndZones:o,analyzeTrackSections:i,findOverlaps:a,calculatePowerCurve:T,calculateHRCurve:$,calculatePowerZones:M,calculateHRZones:b,enrichPoints:t,setHRZones:g,getHRZones:u,setFTP:F,getFTP:I}})();var Bt=(()=>{let t={},s=null;function e(Z,lt,Ft,rt,w){}function n(Z){}function o(Z){t[Z.id]=Z}function i(Z){Z.forEach(lt=>{t[lt.id]=lt})}function a(Z){delete t[Z]}function r(){t={}}function d(){t={}}function T(Z,lt){}function $(Z,lt){}function M(){}function F(Z){}function I(Z,lt){}function b(){}function g(Z,lt,Ft,rt,w,y){}function u(){}function v(Z,lt){}function k(Z){}function f(Z,lt,Ft,rt){}function h(){}function p(){}function E(){return[0,0,0]}function _(Z,lt,Ft){}function W(Z,lt,Ft){}function O(Z){}function Y(Z,lt){return Object.keys(t)}return{init:e,getMap:()=>null,setCustomClickHandler:Z=>{s=Z},switchBasemap:n,addTrack:o,addTracks:i,removeTrack:a,clearTracks:r,removeAllTracks:d,setTrackVisible:T,setSelectedTrack:$,fitAll:M,fitTrack:F,showCursorAt:I,hideCursor:b,highlightSegment:g,clearHighlight:u,setTrackHover:v,ensureVisible:k,centerOn:f,closePopup:h,invalidateSize:p,getPosition:E,setPosition:_,colorTrackByMetric:W,clearMetricColor:O,findTracksPassingThroughPoints:Y,getTrackData:Z=>t[Z]}})();import ko from"uplot";var $n=(()=>{function t(){let e=Jt.getFTP(),n=[.55,.75,.9,1.05,1.2,1.5].map(d=>d*e),o=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],i=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],a=[],r=0;for(let d=0;ds?t.toFixed(1):Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:Nt.speed.color,abbr:"spd",icon:Nt.speed.icon,fmt:t=>(t*3.6).toFixed(1),fmtAxis:t=>(t*3.6).toFixed(0),transform:t=>t,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:Nt.gradient.color,abbr:"grad",icon:Nt.gradient.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>t.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:Nt.power.color,abbr:"pwr",icon:Nt.power.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:Nt.hr.color,abbr:"hr",icon:Nt.hr.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:Nt.cadence.color,abbr:"cad",icon:Nt.cadence.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:Nt.temperature.color,abbr:"temp",icon:Nt.temperature.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>Math.round(t).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:Nt.gearRear.color,abbr:"rgr",icon:Nt.gearRear.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:Nt.gearFront.color,abbr:"fgr",icon:Nt.gearFront.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gears:{label:"Gears",field:"gears",unit:"",color:Nt.gears.color,abbr:"gr",icon:Nt.gears.icon,fmt:t=>t.toFixed(2),fmtAxis:t=>t.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:Nt.battery.color,abbr:"bat",icon:Nt.battery.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString(),smoothSigma:5,compute:(t,s)=>{let e=new Array(t.length).fill(null);for(let n=1;n0&&(e[n]=a/r*3600)}}return s(e)}}};var Ye={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function Eo(t){if(!t)return"question_mark";let s=t.toLowerCase();return Ye[s]?.icon||"exercise"}var ft=(()=>{let t=[],s=null,e="time",n="speed",o=null,i=null,a=!1,r=!1,d=new Set(["elevation"]),T=new Set,$=new Set(["speed","gradient","vam","temperature"]),M=new Set(["power"]),F="time",I=null,b=[],g=null,u=null,v=!1,k=!1,f=null,h=null,p=null,E=null,_=null,W=null,O=null,Y=null,Z=null,lt=null,Ft=null,rt=null,w=130,y=28,m=20,N=!0,C=null,G=null,U=null,j=null,Rt=null,at=null,nt=null;function $t(l,c,x,S){Z=l,lt=c,Ft=x,rt=S,G=document.getElementById("charts-container"),G?.addEventListener("scroll",()=>{p&&_&&E&&so(p,_,E)}),U=document.getElementById("chart-empty"),j=document.getElementById("chart-stats-sel"),Rt=document.getElementById("btn-reset-selection"),C=document.getElementById("hist-tooltip"),i=ko.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",R),Rt?.classList.add("hidden");let H=new Set(["w","a","s","d"]),P=new Set;document.addEventListener("keydown",B=>{if(!t.length||!I||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let A=B.key.toLowerCase();if(!H.has(A))return;B.preventDefault(),P.add(A);let q=t[0].uplot;O||(O=[q.scales.x.min,q.scales.x.max]);let[J,X]=O,et=(X-J)*.1,tt=.15,L=J,wt=X;if(A==="a")L=J-et,wt=X-et;else if(A==="d")L=J+et,wt=X+et;else if(A==="w"||A==="s"){let ct=h!==null?h:(J+X)/2,Ct=A==="w"?1-tt:1+tt*1.2;L=ct-(ct-J)*Ct,wt=ct+(X-ct)*Ct}let St=[t[0].xData[0],t[0].xData[t[0].xData.length-1]];if(LSt[1]){let ct=wt-St[1];L-=ct,wt-=ct}L=Math.max(St[0],L),wt=Math.min(St[1],wt),wt-L>.001&&(O=[L,wt],ht(L,wt,!0))}),document.addEventListener("keyup",B=>{let A=B.key.toLowerCase();H.has(A)&&P.delete(A)})}function ht(l,c,x=!1){if(!t.length)return;if(!x){t.forEach(({uplot:q})=>q.setScale("x",{min:l,max:c}));return}let S=W?W[0]:t[0].uplot.scales.x.min,H=W?W[1]:t[0].uplot.scales.x.max;Y&&cancelAnimationFrame(Y);let P=(q,J,X)=>q+(J-q)*X,B=.25,A=()=>{if(!O)return;let[q,J]=O,X=P(W[0],q,B),Q=P(W[1],J,B);t.forEach(({uplot:et})=>{et.setScale("x",{min:X,max:Q})}),Math.abs(X-q)>1e-4||Math.abs(Q-J)>1e-4?Y=requestAnimationFrame(A):Y=null};Y=requestAnimationFrame(A)}function z(l,c=[],x=!1){f=null,g=null,u=null,b=c,T=new Set(Object.entries(qe).filter(([,S])=>l.points.some(H=>H[S.field]!=null)).map(([S])=>S)),d.size===0&&(d=new Set(["elevation"].filter(S=>T.has(S)))),document.querySelectorAll(".metric-pill").forEach(S=>{let H=S,P=H.dataset.metric,B=T.has(P);H.classList.toggle("active",B&&d.has(P)),H.classList.toggle("disabled",!B)}),I=l,x?po(l):vt()}function D(){f=null,g=null,u=null,I=null,Rn(),U&&(U.style.display="flex",U.innerHTML=` +var VD=Object.defineProperty;var pG=Object.getOwnPropertyDescriptor;var fG=(t,e,n)=>e in t?VD(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var hG=(t,e)=>{for(var n in e)VD(t,n,{get:e[n],enumerable:!0})};var dr=(t,e,n,r)=>{for(var s=r>1?void 0:r?pG(e,n):e,i=t.length-1,o;i>=0;i--)(o=t[i])&&(s=(r?o(e,n,s):o(s))||s);return r&&s&&VD(e,n,s),s};var l=(t,e,n)=>(fG(t,typeof e!="symbol"?e+"":e,n),n);var Qo=globalThis;function Bi(t){return(Qo.__Zone_symbol_prefix||"__zone_symbol__")+t}function mG(){let t=Qo.performance;function e(S){t&&t.mark&&t.mark(S)}function n(S,x){t&&t.measure&&t.measure(S,x)}e("Zone");let A=class A{constructor(x,C){l(this,"_parent");l(this,"_name");l(this,"_properties");l(this,"_zoneDelegate");this._parent=x,this._name=C?C.name||"unnamed":"",this._properties=C&&C.properties||{},this._zoneDelegate=new i(this,this._parent&&this._parent._zoneDelegate,C)}static assertZonePatched(){if(Qo.Promise!==pe.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")}static get root(){let x=A.current;for(;x.parent;)x=x.parent;return x}static get current(){return ee.zone}static get currentTask(){return xe}static __load_patch(x,C,I=!1){if(pe.hasOwnProperty(x)){let F=Qo[Bi("forceDuplicateZoneCheck")]===!0;if(!I&&F)throw Error("Already loaded patch: "+x)}else if(!Qo["__Zone_disable_"+x]){let F="Zone:"+x;e(F),pe[x]=C(Qo,A,U),n(F,F)}}get parent(){return this._parent}get name(){return this._name}get(x){let C=this.getZoneWith(x);if(C)return C._properties[x]}getZoneWith(x){let C=this;for(;C;){if(C._properties.hasOwnProperty(x))return C;C=C._parent}return null}fork(x){if(!x)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,x)}wrap(x,C){if(typeof x!="function")throw new Error("Expecting function got: "+x);let I=this._zoneDelegate.intercept(this,x,C),F=this;return function(){return F.runGuarded(I,this,arguments,C)}}run(x,C,I,F){ee={parent:ee,zone:this};try{return this._zoneDelegate.invoke(this,x,C,I,F)}finally{ee=ee.parent}}runGuarded(x,C=null,I,F){ee={parent:ee,zone:this};try{try{return this._zoneDelegate.invoke(this,x,C,I,F)}catch(J){if(this._zoneDelegate.handleError(this,J))throw J}}finally{ee=ee.parent}}runTask(x,C,I){if(x.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(x.zone||v).name+"; Execution: "+this.name+")");let F=x,{type:J,data:{isPeriodic:oe=!1,isRefreshable:we=!1}={}}=x;if(x.state===w&&(J===Se||J===G))return;let ae=x.state!=B;ae&&F._transitionTo(B,D);let Ae=xe;xe=F,ee={parent:ee,zone:this};try{J==G&&x.data&&!oe&&!we&&(x.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,F,C,I)}catch(ie){if(this._zoneDelegate.handleError(this,ie))throw ie}}finally{let ie=x.state;if(ie!==w&&ie!==$)if(J==Se||oe||we&&ie===b)ae&&F._transitionTo(D,B,b);else{let V=F._zoneDelegates;this._updateTaskCount(F,-1),ae&&F._transitionTo(w,B,w),we&&(F._zoneDelegates=V)}ee=ee.parent,xe=Ae}}scheduleTask(x){if(x.zone&&x.zone!==this){let I=this;for(;I;){if(I===x.zone)throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${x.zone.name}`);I=I.parent}}x._transitionTo(b,w);let C=[];x._zoneDelegates=C,x._zone=this;try{x=this._zoneDelegate.scheduleTask(this,x)}catch(I){throw x._transitionTo($,b,w),this._zoneDelegate.handleError(this,I),I}return x._zoneDelegates===C&&this._updateTaskCount(x,1),x.state==b&&x._transitionTo(D,b),x}scheduleMicroTask(x,C,I,F){return this.scheduleTask(new o(j,x,C,I,F,void 0))}scheduleMacroTask(x,C,I,F,J){return this.scheduleTask(new o(G,x,C,I,F,J))}scheduleEventTask(x,C,I,F,J){return this.scheduleTask(new o(Se,x,C,I,F,J))}cancelTask(x){if(x.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(x.zone||v).name+"; Execution: "+this.name+")");if(!(x.state!==D&&x.state!==B)){x._transitionTo(M,D,B);try{this._zoneDelegate.cancelTask(this,x)}catch(C){throw x._transitionTo($,M),this._zoneDelegate.handleError(this,C),C}return this._updateTaskCount(x,-1),x._transitionTo(w,M),x.runCount=-1,x}}_updateTaskCount(x,C){let I=x._zoneDelegates;C==-1&&(x._zoneDelegates=null);for(let F=0;FS.hasTask(C,I),onScheduleTask:(S,x,C,I)=>S.scheduleTask(C,I),onInvokeTask:(S,x,C,I,F,J)=>S.invokeTask(C,I,F,J),onCancelTask:(S,x,C,I)=>S.cancelTask(C,I)};class i{constructor(x,C,I){l(this,"_zone");l(this,"_taskCounts",{microTask:0,macroTask:0,eventTask:0});l(this,"_parentDelegate");l(this,"_forkDlgt");l(this,"_forkZS");l(this,"_forkCurrZone");l(this,"_interceptDlgt");l(this,"_interceptZS");l(this,"_interceptCurrZone");l(this,"_invokeDlgt");l(this,"_invokeZS");l(this,"_invokeCurrZone");l(this,"_handleErrorDlgt");l(this,"_handleErrorZS");l(this,"_handleErrorCurrZone");l(this,"_scheduleTaskDlgt");l(this,"_scheduleTaskZS");l(this,"_scheduleTaskCurrZone");l(this,"_invokeTaskDlgt");l(this,"_invokeTaskZS");l(this,"_invokeTaskCurrZone");l(this,"_cancelTaskDlgt");l(this,"_cancelTaskZS");l(this,"_cancelTaskCurrZone");l(this,"_hasTaskDlgt");l(this,"_hasTaskDlgtOwner");l(this,"_hasTaskZS");l(this,"_hasTaskCurrZone");this._zone=x,this._parentDelegate=C,this._forkZS=I&&(I&&I.onFork?I:C._forkZS),this._forkDlgt=I&&(I.onFork?C:C._forkDlgt),this._forkCurrZone=I&&(I.onFork?this._zone:C._forkCurrZone),this._interceptZS=I&&(I.onIntercept?I:C._interceptZS),this._interceptDlgt=I&&(I.onIntercept?C:C._interceptDlgt),this._interceptCurrZone=I&&(I.onIntercept?this._zone:C._interceptCurrZone),this._invokeZS=I&&(I.onInvoke?I:C._invokeZS),this._invokeDlgt=I&&(I.onInvoke?C:C._invokeDlgt),this._invokeCurrZone=I&&(I.onInvoke?this._zone:C._invokeCurrZone),this._handleErrorZS=I&&(I.onHandleError?I:C._handleErrorZS),this._handleErrorDlgt=I&&(I.onHandleError?C:C._handleErrorDlgt),this._handleErrorCurrZone=I&&(I.onHandleError?this._zone:C._handleErrorCurrZone),this._scheduleTaskZS=I&&(I.onScheduleTask?I:C._scheduleTaskZS),this._scheduleTaskDlgt=I&&(I.onScheduleTask?C:C._scheduleTaskDlgt),this._scheduleTaskCurrZone=I&&(I.onScheduleTask?this._zone:C._scheduleTaskCurrZone),this._invokeTaskZS=I&&(I.onInvokeTask?I:C._invokeTaskZS),this._invokeTaskDlgt=I&&(I.onInvokeTask?C:C._invokeTaskDlgt),this._invokeTaskCurrZone=I&&(I.onInvokeTask?this._zone:C._invokeTaskCurrZone),this._cancelTaskZS=I&&(I.onCancelTask?I:C._cancelTaskZS),this._cancelTaskDlgt=I&&(I.onCancelTask?C:C._cancelTaskDlgt),this._cancelTaskCurrZone=I&&(I.onCancelTask?this._zone:C._cancelTaskCurrZone),this._hasTaskZS=null,this._hasTaskDlgt=null,this._hasTaskDlgtOwner=null,this._hasTaskCurrZone=null;let F=I&&I.onHasTask,J=C&&C._hasTaskZS;(F||J)&&(this._hasTaskZS=F?I:s,this._hasTaskDlgt=C,this._hasTaskDlgtOwner=this,this._hasTaskCurrZone=this._zone,I.onScheduleTask||(this._scheduleTaskZS=s,this._scheduleTaskDlgt=C,this._scheduleTaskCurrZone=this._zone),I.onInvokeTask||(this._invokeTaskZS=s,this._invokeTaskDlgt=C,this._invokeTaskCurrZone=this._zone),I.onCancelTask||(this._cancelTaskZS=s,this._cancelTaskDlgt=C,this._cancelTaskCurrZone=this._zone))}get zone(){return this._zone}fork(x,C){return this._forkZS?this._forkZS.onFork(this._forkDlgt,this.zone,x,C):new r(x,C)}intercept(x,C,I){return this._interceptZS?this._interceptZS.onIntercept(this._interceptDlgt,this._interceptCurrZone,x,C,I):C}invoke(x,C,I,F,J){return this._invokeZS?this._invokeZS.onInvoke(this._invokeDlgt,this._invokeCurrZone,x,C,I,F,J):C.apply(I,F)}handleError(x,C){return this._handleErrorZS?this._handleErrorZS.onHandleError(this._handleErrorDlgt,this._handleErrorCurrZone,x,C):!0}scheduleTask(x,C){let I=C;if(this._scheduleTaskZS)this._hasTaskZS&&I._zoneDelegates.push(this._hasTaskDlgtOwner),I=this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt,this._scheduleTaskCurrZone,x,C),I||(I=C);else if(C.scheduleFn)C.scheduleFn(C);else if(C.type==j)m(C);else throw new Error("Task is missing scheduleFn.");return I}invokeTask(x,C,I,F){return this._invokeTaskZS?this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt,this._invokeTaskCurrZone,x,C,I,F):C.callback.apply(I,F)}cancelTask(x,C){let I;if(this._cancelTaskZS)I=this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt,this._cancelTaskCurrZone,x,C);else{if(!C.cancelFn)throw Error("Task is not cancelable");I=C.cancelFn(C)}return I}hasTask(x,C){try{this._hasTaskZS&&this._hasTaskZS.onHasTask(this._hasTaskDlgt,this._hasTaskCurrZone,x,C)}catch(I){this.handleError(x,I)}}_updateTaskCount(x,C){let I=this._taskCounts,F=I[x],J=I[x]=F+C;if(J<0)throw new Error("More tasks executed then were scheduled.");if(F==0||J==0){let oe={microTask:I.microTask>0,macroTask:I.macroTask>0,eventTask:I.eventTask>0,change:x};this.hasTask(this._zone,oe)}}}class o{constructor(x,C,I,F,J,oe){l(this,"type");l(this,"source");l(this,"invoke");l(this,"callback");l(this,"data");l(this,"scheduleFn");l(this,"cancelFn");l(this,"_zone",null);l(this,"runCount",0);l(this,"_zoneDelegates",null);l(this,"_state","notScheduled");if(this.type=x,this.source=C,this.data=F,this.scheduleFn=J,this.cancelFn=oe,!I)throw new Error("callback is not defined");this.callback=I;let we=this;x===Se&&F&&F.useG?this.invoke=o.invokeTask:this.invoke=function(){return o.invokeTask.call(Qo,we,this,arguments)}}static invokeTask(x,C,I){x||(x=this),Ze++;try{return x.runCount++,x.zone.runTask(x,C,I)}finally{Ze==1&&g(),Ze--}}get zone(){return this._zone}get state(){return this._state}cancelScheduleRequest(){this._transitionTo(w,b)}_transitionTo(x,C,I){if(this._state===C||this._state===I)this._state=x,x==w&&(this._zoneDelegates=null);else throw new Error(`${this.type} '${this.source}': can not transition to '${x}', expecting state '${C}'${I?" or '"+I+"'":""}, was '${this._state}'.`)}toString(){return this.data&&typeof this.data.handleId<"u"?this.data.handleId.toString():Object.prototype.toString.call(this)}toJSON(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}}}let a=Bi("setTimeout"),c=Bi("Promise"),u=Bi("then"),d=[],p=!1,f;function h(S){if(f||Qo[c]&&(f=Qo[c].resolve(0)),f){let x=f[u];x||(x=f.then),x.call(f,S)}else Qo[a](S,0)}function m(S){Ze===0&&d.length===0&&h(g),S&&d.push(S)}function g(){if(!p){for(p=!0;d.length;){let S=d;d=[];for(let x=0;xee,onUnhandledError:N,microtaskDrainDone:N,scheduleMicroTask:m,showUncaughtError:()=>!r[Bi("ignoreConsoleErrorUncaughtError")],patchEventTarget:()=>[],patchOnProperties:N,patchMethod:()=>N,bindArguments:()=>[],patchThen:()=>N,patchMacroTask:()=>N,patchEventPrototype:()=>N,isIEOrEdge:()=>!1,getGlobalObjects:()=>{},ObjectDefineProperty:()=>N,ObjectGetOwnPropertyDescriptor:()=>{},ObjectCreate:()=>{},ArraySlice:()=>[],patchClass:()=>N,wrapWithCurrentZone:()=>N,filterProperties:()=>[],attachOriginToPatched:()=>N,_redefineProperty:()=>N,patchCallbacks:()=>N,nativeScheduleMicroTask:h},ee={parent:null,zone:new r(null,null)},xe=null,Ze=0;function N(){}return n("Zone","Zone"),r}function gG(){let t=globalThis,e=t[Bi("forceDuplicateZoneCheck")]===!0;if(t.Zone&&(e||typeof t.Zone.__symbol__!="function"))throw new Error("Zone already loaded.");return t.Zone??(t.Zone=mG()),t.Zone}var rv=Object.getOwnPropertyDescriptor,WD=Object.defineProperty,zD=Object.getPrototypeOf,vG=Object.create,yG=Array.prototype.slice,GD="addEventListener",ZD="removeEventListener",HD=Bi(GD),jD=Bi(ZD),$a="true",Va="false",sv=Bi("");function YD(t,e){return Zone.current.wrap(t,e)}function XD(t,e,n,r,s){return Zone.current.scheduleMacroTask(t,e,n,r,s)}var Sn=Bi,bw=typeof window<"u",iv=bw?window:void 0,Mr=bw&&iv||globalThis,bG="removeAttribute";function QD(t,e){for(let n=t.length-1;n>=0;n--)typeof t[n]=="function"&&(t[n]=YD(t[n],e+"_"+n));return t}function wG(t,e){let n=t.constructor.name;for(let r=0;r{let c=function(){return a.apply(this,QD(arguments,n+"."+s))};return ja(c,a),c})(i)}}}function _F(t){return t?t.writable===!1?!1:!(typeof t.get=="function"&&typeof t.set>"u"):!0}var IF=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope,ww=!("nw"in Mr)&&typeof Mr.process<"u"&&Mr.process.toString()==="[object process]",KD=!ww&&!IF&&!!(bw&&iv.HTMLElement),kF=typeof Mr.process<"u"&&Mr.process.toString()==="[object process]"&&!IF&&!!(bw&&iv.HTMLElement),yw={},EG=Sn("enable_beforeunload"),EF=function(t){if(t=t||Mr.event,!t)return;let e=yw[t.type];e||(e=yw[t.type]=Sn("ON_PROPERTY"+t.type));let n=this||t.target||Mr,r=n[e],s;if(KD&&n===iv&&t.type==="error"){let i=t;s=r&&r.call(this,i.message,i.filename,i.lineno,i.colno,i.error),s===!0&&t.preventDefault()}else s=r&&r.apply(this,arguments),t.type==="beforeunload"&&Mr[EG]&&typeof s=="string"?t.returnValue=s:s!=null&&!s&&t.preventDefault();return s};function xF(t,e,n){let r=rv(t,e);if(!r&&n&&rv(n,e)&&(r={enumerable:!0,configurable:!0}),!r||!r.configurable)return;let s=Sn("on"+e+"patched");if(t.hasOwnProperty(s)&&t[s])return;delete r.writable,delete r.value;let i=r.get,o=r.set,a=e.slice(2),c=yw[a];c||(c=yw[a]=Sn("ON_PROPERTY"+a)),r.set=function(u){let d=this;if(!d&&t===Mr&&(d=Mr),!d)return;typeof d[c]=="function"&&d.removeEventListener(a,EF),o?.call(d,null),d[c]=u,typeof u=="function"&&d.addEventListener(a,EF,!1)},r.get=function(){let u=this;if(!u&&t===Mr&&(u=Mr),!u)return null;let d=u[c];if(d)return d;if(i){let p=i.call(this);if(p)return r.set.call(this,p),typeof u[bG]=="function"&&u.removeAttribute(e),p}return null},WD(t,e,r),t[s]=!0}function AF(t,e,n){if(e)for(let r=0;rfunction(o,a){let c=n(o,a);return c.cbIdx>=0&&typeof a[c.cbIdx]=="function"?XD(c.name,a[c.cbIdx],c,s):i.apply(o,a)})}function ja(t,e){t[Sn("OriginalDelegate")]=e}var SF=!1,UD=!1;function SG(){if(SF)return UD;SF=!0;try{let t=iv.navigator.userAgent;(t.indexOf("MSIE ")!==-1||t.indexOf("Trident/")!==-1||t.indexOf("Edge/")!==-1)&&(UD=!0)}catch{}return UD}function CF(t){return typeof t=="function"}function TF(t){return typeof t=="number"}var CG={useG:!0},$i={},MF={},PF=new RegExp("^"+sv+"(\\w+)(true|false)$"),NF=Sn("propagationStopped");function RF(t,e){let n=(e?e(t):t)+Va,r=(e?e(t):t)+$a,s=sv+n,i=sv+r;$i[t]={},$i[t][Va]=s,$i[t][$a]=i}function TG(t,e,n,r){let s=r&&r.add||GD,i=r&&r.rm||ZD,o=r&&r.listeners||"eventListeners",a=r&&r.rmAll||"removeAllListeners",c=Sn(s),u="."+s+":",d="prependListener",p="."+d+":",f=function(b,D,B){if(b.isRemoved)return;let M=b.callback;typeof M=="object"&&M.handleEvent&&(b.callback=G=>M.handleEvent(G),b.originalDelegate=M);let $;try{b.invoke(b,D,[B])}catch(G){$=G}let j=b.options;if(j&&typeof j=="object"&&j.once){let G=b.originalDelegate?b.originalDelegate:b.callback;D[i].call(D,B.type,G,j)}return $};function h(b,D,B){if(D=D||t.event,!D)return;let M=b||D.target||t,$=M[$i[D.type][B?$a:Va]];if($){let j=[];if($.length===1){let G=f($[0],M,D);G&&j.push(G)}else{let G=$.slice();for(let Se=0;Se{throw Se})}}}let m=function(b){return h(this,b,!1)},g=function(b){return h(this,b,!0)};function v(b,D){if(!b)return!1;let B=!0;D&&D.useG!==void 0&&(B=D.useG);let M=D&&D.vh,$=!0;D&&D.chkDup!==void 0&&($=D.chkDup);let j=!1;D&&D.rt!==void 0&&(j=D.rt);let G=b;for(;G&&!G.hasOwnProperty(s);)G=zD(G);if(!G&&b[s]&&(G=b),!G||G[c])return!1;let Se=D&&D.eventNameToString,pe={},U=G[c]=G[s],ee=G[Sn(i)]=G[i],xe=G[Sn(o)]=G[o],Ze=G[Sn(a)]=G[a],N;D&&D.prepend&&(N=G[Sn(D.prepend)]=G[D.prepend]);function A(L,q){return q?typeof L=="boolean"?{capture:L,passive:!0}:L?typeof L=="object"&&L.passive!==!1?{...L,passive:!0}:L:{passive:!0}:L}let S=function(L){if(!pe.isExisting)return U.call(pe.target,pe.eventName,pe.capture?g:m,pe.options)},x=function(L){if(!L.isRemoved){let q=$i[L.eventName],H;q&&(H=q[L.capture?$a:Va]);let le=H&&L.target[H];if(le){for(let K=0;KUn.zone.cancelTask(Un);L.call(me,"abort",Ar,{once:!0}),Un.removeAbortListener=()=>me.removeEventListener("abort",Ar)}if(pe.target=null,Zt&&(Zt.taskData=null),nn&&(pe.options.once=!0),typeof Un.options!="boolean"&&(Un.options=$t),Un.target=he,Un.capture=Ue,Un.eventName=De,et&&(Un.originalDelegate=Ne),Ce?ot.unshift(Un):ot.push(Un),K)return he}};return G[s]=z(U,u,J,oe,j),N&&(G[d]=z(N,p,I,oe,j,!0)),G[i]=function(){let L=this||t,q=arguments[0];D&&D.transferEventName&&(q=D.transferEventName(q));let H=arguments[2],le=H?typeof H=="boolean"?!0:H.capture:!1,K=arguments[1];if(!K)return ee.apply(this,arguments);if(M&&!M(ee,K,L,arguments))return;let Ce=$i[q],he;Ce&&(he=Ce[le?$a:Va]);let De=he&&L[he];if(De)for(let Ne=0;Nefunction(s,i){s[NF]=!0,r&&r.apply(s,i)})}function _G(t,e){e.patchMethod(t,"queueMicrotask",n=>function(r,s){Zone.current.scheduleMicroTask("queueMicrotask",s[0])})}var vw=Sn("zoneTask");function Qp(t,e,n,r){let s=null,i=null;e+=r,n+=r;let o={};function a(u){let d=u.data;d.args[0]=function(){return u.invoke.apply(this,arguments)};let p=s.apply(t,d.args);return TF(p)?d.handleId=p:(d.handle=p,d.isRefreshable=CF(p.refresh)),u}function c(u){let{handle:d,handleId:p}=u.data;return i.call(t,d??p)}s=Ha(t,e,u=>function(d,p){if(CF(p[0])){let f={isRefreshable:!1,isPeriodic:r==="Interval",delay:r==="Timeout"||r==="Interval"?p[1]||0:void 0,args:p},h=p[0];p[0]=function(){try{return h.apply(this,arguments)}finally{let{handle:B,handleId:M,isPeriodic:$,isRefreshable:j}=f;!$&&!j&&(M?delete o[M]:B&&(B[vw]=null))}};let m=XD(e,p[0],f,a,c);if(!m)return m;let{handleId:g,handle:v,isRefreshable:w,isPeriodic:b}=m.data;if(g)o[g]=m;else if(v&&(v[vw]=m,w&&!b)){let D=v.refresh;v.refresh=function(){let{zone:B,state:M}=m;return M==="notScheduled"?(m._state="scheduled",B._updateTaskCount(m,1)):M==="running"&&(m._state="scheduling"),D.call(this)}}return v??g??m}else return u.apply(t,p)}),i=Ha(t,n,u=>function(d,p){let f=p[0],h;TF(f)?(h=o[f],delete o[f]):(h=f?.[vw],h?f[vw]=null:h=f),h?.type?h.cancelFn&&h.zone.cancelTask(h):u.apply(t,p)})}function IG(t,e){let{isBrowser:n,isMix:r}=e.getGlobalObjects();if(!n&&!r||!t.customElements||!("customElements"in t))return;let s=["connectedCallback","disconnectedCallback","adoptedCallback","attributeChangedCallback","formAssociatedCallback","formDisabledCallback","formResetCallback","formStateRestoreCallback"];e.patchCallbacks(e,t.customElements,"customElements","define",s)}function kG(t,e){if(Zone[e.symbol("patchEventTarget")])return;let{eventNames:n,zoneSymbolEventNames:r,TRUE_STR:s,FALSE_STR:i,ZONE_SYMBOL_PREFIX:o}=e.getGlobalObjects();for(let c=0;ci.target===t);if(r.length===0)return e;let s=r[0].ignoreProperties;return e.filter(i=>s.indexOf(i)===-1)}function DF(t,e,n,r){if(!t)return;let s=LF(t,e,n);AF(t,s,r)}function qD(t){return Object.getOwnPropertyNames(t).filter(e=>e.startsWith("on")&&e.length>2).map(e=>e.substring(2))}function MG(t,e){if(ww&&!kF||Zone[t.symbol("patchEvents")])return;let n=e.__Zone_ignore_on_properties,r=[];if(KD){let s=window;r=r.concat(["Document","SVGElement","Element","HTMLElement","HTMLBodyElement","HTMLMediaElement","HTMLFrameSetElement","HTMLFrameElement","HTMLIFrameElement","HTMLMarqueeElement","Worker"]);let i=[];DF(s,qD(s),n&&n.concat(i),zD(s))}r=r.concat(["XMLHttpRequest","XMLHttpRequestEventTarget","IDBIndex","IDBRequest","IDBOpenDBRequest","IDBDatabase","IDBTransaction","IDBCursor","WebSocket"]);for(let s=0;s{let n=e[t.__symbol__("legacyPatch")];n&&n()}),t.__load_patch("timers",e=>{let n="set",r="clear";Qp(e,n,r,"Timeout"),Qp(e,n,r,"Interval"),Qp(e,n,r,"Immediate")}),t.__load_patch("requestAnimationFrame",e=>{Qp(e,"request","cancel","AnimationFrame"),Qp(e,"mozRequest","mozCancel","AnimationFrame"),Qp(e,"webkitRequest","webkitCancel","AnimationFrame")}),t.__load_patch("blocking",(e,n)=>{let r=["alert","prompt","confirm"];for(let s=0;sfunction(u,d){return n.current.run(o,e,d,c)})}}),t.__load_patch("EventTarget",(e,n,r)=>{AG(e,r),kG(e,r);let s=e.XMLHttpRequestEventTarget;s&&s.prototype&&r.patchEventTarget(e,r,[s.prototype])}),t.__load_patch("MutationObserver",(e,n,r)=>{nv("MutationObserver"),nv("WebKitMutationObserver")}),t.__load_patch("IntersectionObserver",(e,n,r)=>{nv("IntersectionObserver")}),t.__load_patch("FileReader",(e,n,r)=>{nv("FileReader")}),t.__load_patch("on_property",(e,n,r)=>{MG(r,e)}),t.__load_patch("customElements",(e,n,r)=>{IG(e,r)}),t.__load_patch("XHR",(e,n)=>{u(e);let r=Sn("xhrTask"),s=Sn("xhrSync"),i=Sn("xhrListener"),o=Sn("xhrScheduled"),a=Sn("xhrURL"),c=Sn("xhrErrorBeforeScheduled");function u(d){let p=d.XMLHttpRequest;if(!p)return;let f=p.prototype;function h(U){return U[r]}let m=f[HD],g=f[jD];if(!m){let U=d.XMLHttpRequestEventTarget;if(U){let ee=U.prototype;m=ee[HD],g=ee[jD]}}let v="readystatechange",w="scheduled";function b(U){let ee=U.data,xe=ee.target;xe[o]=!1,xe[c]=!1;let Ze=xe[i];m||(m=xe[HD],g=xe[jD]),Ze&&g.call(xe,v,Ze);let N=xe[i]=()=>{if(xe.readyState===xe.DONE)if(!ee.aborted&&xe[o]&&U.state===w){let S=xe[n.__symbol__("loadfalse")];if(xe.status!==0&&S&&S.length>0){let x=U.invoke;U.invoke=function(){let C=xe[n.__symbol__("loadfalse")];for(let I=0;Ifunction(U,ee){return U[s]=ee[2]==!1,U[a]=ee[1],M.apply(U,ee)}),$="XMLHttpRequest.send",j=Sn("fetchTaskAborting"),G=Sn("fetchTaskScheduling"),Se=Ha(f,"send",()=>function(U,ee){if(n.current[G]===!0||U[s])return Se.apply(U,ee);{let xe={target:U,url:U[a],isPeriodic:!1,args:ee,aborted:!1},Ze=XD($,D,xe,b,B);U&&U[c]===!0&&!xe.aborted&&Ze.state===w&&Ze.invoke()}}),pe=Ha(f,"abort",()=>function(U,ee){let xe=h(U);if(xe&&typeof xe.type=="string"){if(xe.cancelFn==null||xe.data&&xe.data.aborted)return;xe.zone.cancelTask(xe)}else if(n.current[j]===!0)return pe.apply(U,ee)})}}),t.__load_patch("geolocation",e=>{e.navigator&&e.navigator.geolocation&&wG(e.navigator.geolocation,["getCurrentPosition","watchPosition"])}),t.__load_patch("PromiseRejectionEvent",(e,n)=>{function r(s){return function(i){FF(e,s).forEach(a=>{let c=e.PromiseRejectionEvent;if(c){let u=new c(s,{promise:i.promise,reason:i.rejection});a.invoke(u)}})}}e.PromiseRejectionEvent&&(n[Sn("unhandledPromiseRejectionHandler")]=r("unhandledrejection"),n[Sn("rejectionHandledHandler")]=r("rejectionhandled"))}),t.__load_patch("queueMicrotask",(e,n,r)=>{_G(e,r)})}function NG(t){t.__load_patch("ZoneAwarePromise",(e,n,r)=>{let s=Object.getOwnPropertyDescriptor,i=Object.defineProperty;function o(V){if(V&&V.toString===Object.prototype.toString){let z=V.constructor&&V.constructor.name;return(z||"")+": "+JSON.stringify(V)}return V?V.toString():Object.prototype.toString.call(V)}let a=r.symbol,c=[],u=e[a("DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION")]!==!1,d=a("Promise"),p=a("then"),f="__creationTrace__";r.onUnhandledError=V=>{if(r.showUncaughtError()){let z=V&&V.rejection;z?console.error("Unhandled Promise rejection:",z instanceof Error?z.message:z,"; Zone:",V.zone.name,"; Task:",V.task&&V.task.source,"; Value:",z,z instanceof Error?z.stack:void 0):console.error(V)}},r.microtaskDrainDone=()=>{for(;c.length;){let V=c.shift();try{V.zone.runGuarded(()=>{throw V.throwOriginal?V.rejection:V})}catch(z){m(z)}}};let h=a("unhandledPromiseRejectionHandler");function m(V){r.onUnhandledError(V);try{let z=n[h];typeof z=="function"&&z.call(this,V)}catch{}}function g(V){return V&&typeof V.then=="function"}function v(V){return V}function w(V){return oe.reject(V)}let b=a("state"),D=a("value"),B=a("finally"),M=a("parentPromiseValue"),$=a("parentPromiseState"),j="Promise.then",G=null,Se=!0,pe=!1,U=0;function ee(V,z){return L=>{try{A(V,z,L)}catch(q){A(V,!1,q)}}}let xe=function(){let V=!1;return function(L){return function(){V||(V=!0,L.apply(null,arguments))}}},Ze="Promise resolved with itself",N=a("currentTaskTrace");function A(V,z,L){let q=xe();if(V===L)throw new TypeError(Ze);if(V[b]===G){let H=null;try{(typeof L=="object"||typeof L=="function")&&(H=L&&L.then)}catch(le){return q(()=>{A(V,!1,le)})(),V}if(z!==pe&&L instanceof oe&&L.hasOwnProperty(b)&&L.hasOwnProperty(D)&&L[b]!==G)x(L),A(V,L[b],L[D]);else if(z!==pe&&typeof H=="function")try{H.call(L,q(ee(V,z)),q(ee(V,!1)))}catch(le){q(()=>{A(V,!1,le)})()}else{V[b]=z;let le=V[D];if(V[D]=L,V[B]===B&&z===Se&&(V[b]=V[$],V[D]=V[M]),z===pe&&L instanceof Error){let K=n.currentTask&&n.currentTask.data&&n.currentTask.data[f];K&&i(L,N,{configurable:!0,enumerable:!1,writable:!0,value:K})}for(let K=0;K{try{let Ce=V[D],he=!!L&&B===L[B];he&&(L[M]=Ce,L[$]=le);let De=z.run(K,void 0,he&&K!==w&&K!==v?[]:[Ce]);A(L,!0,De)}catch(Ce){A(L,!1,Ce)}},L)}let I="function ZoneAwarePromise() { [native code] }",F=function(){},J=e.AggregateError;class oe{static toString(){return I}static resolve(z){return z instanceof oe?z:A(new this(null),Se,z)}static reject(z){return A(new this(null),pe,z)}static withResolvers(){let z={};return z.promise=new oe((L,q)=>{z.resolve=L,z.reject=q}),z}static any(z){if(!z||typeof z[Symbol.iterator]!="function")return Promise.reject(new J([],"All promises were rejected"));let L=[],q=0;try{for(let K of z)q++,L.push(oe.resolve(K))}catch{return Promise.reject(new J([],"All promises were rejected"))}if(q===0)return Promise.reject(new J([],"All promises were rejected"));let H=!1,le=[];return new oe((K,Ce)=>{for(let he=0;he{H||(H=!0,K(De))},De=>{le.push(De),q--,q===0&&(H=!0,Ce(new J(le,"All promises were rejected")))})})}static race(z){let L,q,H=new this((Ce,he)=>{L=Ce,q=he});function le(Ce){L(Ce)}function K(Ce){q(Ce)}for(let Ce of z)g(Ce)||(Ce=this.resolve(Ce)),Ce.then(le,K);return H}static all(z){return oe.allWithCallback(z)}static allSettled(z){return(this&&this.prototype instanceof oe?this:oe).allWithCallback(z,{thenCallback:q=>({status:"fulfilled",value:q}),errorCallback:q=>({status:"rejected",reason:q})})}static allWithCallback(z,L){let q,H,le=new this((De,Ne)=>{q=De,H=Ne}),K=2,Ce=0,he=[];for(let De of z){g(De)||(De=this.resolve(De));let Ne=Ce;try{De.then(et=>{he[Ne]=L?L.thenCallback(et):et,K--,K===0&&q(he)},et=>{L?(he[Ne]=L.errorCallback(et),K--,K===0&&q(he)):H(et)})}catch(et){H(et)}K++,Ce++}return K-=2,K===0&&q(he),le}constructor(z){let L=this;if(!(L instanceof oe))throw new Error("Must be an instanceof Promise.");L[b]=G,L[D]=[];try{let q=xe();z&&z(q(ee(L,Se)),q(ee(L,pe)))}catch(q){A(L,!1,q)}}get[Symbol.toStringTag](){return"Promise"}get[Symbol.species](){return oe}then(z,L){let q=this.constructor?.[Symbol.species];(!q||typeof q!="function")&&(q=this.constructor||oe);let H=new q(F),le=n.current;return this[b]==G?this[D].push(le,H,z,L):C(this,le,H,z,L),H}catch(z){return this.then(null,z)}finally(z){let L=this.constructor?.[Symbol.species];(!L||typeof L!="function")&&(L=oe);let q=new L(F);q[B]=B;let H=n.current;return this[b]==G?this[D].push(H,q,z,z):C(this,H,q,z,z),q}}oe.resolve=oe.resolve,oe.reject=oe.reject,oe.race=oe.race,oe.all=oe.all;let we=e[d]=e.Promise;e.Promise=oe;let ae=a("thenPatched");function Ae(V){let z=V.prototype,L=s(z,"then");if(L&&(L.writable===!1||!L.configurable))return;let q=z.then;z[p]=q,V.prototype.then=function(H,le){return new oe((Ce,he)=>{q.call(this,Ce,he)}).then(H,le)},V[ae]=!0}r.patchThen=Ae;function ie(V){return function(z,L){let q=V.apply(z,L);if(q instanceof oe)return q;let H=q.constructor;return H[ae]||Ae(H),q}}return we&&(Ae(we),Ha(e,"fetch",V=>ie(V))),Promise[n.__symbol__("uncaughtPromiseErrors")]=c,oe})}function RG(t){t.__load_patch("toString",e=>{let n=Function.prototype.toString,r=Sn("OriginalDelegate"),s=Sn("Promise"),i=Sn("Error"),o=function(){if(typeof this=="function"){let d=this[r];if(d)return typeof d=="function"?n.call(d):Object.prototype.toString.call(d);if(this===Promise){let p=e[s];if(p)return n.call(p)}if(this===Error){let p=e[i];if(p)return n.call(p)}}return n.call(this)};o[r]=n,Function.prototype.toString=o;let a=Object.prototype.toString,c="[object Promise]";Object.prototype.toString=function(){return typeof Promise=="function"&&this instanceof Promise?c:a.call(this)}})}function FG(t,e,n,r,s){let i=Zone.__symbol__(r);if(e[i])return;let o=e[i]=e[r];e[r]=function(a,c,u){return c&&c.prototype&&s.forEach(function(d){let p=`${n}.${r}::`+d,f=c.prototype;try{if(f.hasOwnProperty(d)){let h=t.ObjectGetOwnPropertyDescriptor(f,d);h&&h.value?(h.value=t.wrapWithCurrentZone(h.value,p),t._redefineProperty(c.prototype,d,h)):f[d]&&(f[d]=t.wrapWithCurrentZone(f[d],p))}else f[d]&&(f[d]=t.wrapWithCurrentZone(f[d],p))}catch{}}),o.call(e,a,c,u)},t.attachOriginToPatched(e[r],o)}function LG(t){t.__load_patch("util",(e,n,r)=>{let s=qD(e);r.patchOnProperties=AF,r.patchMethod=Ha,r.bindArguments=QD,r.patchMacroTask=xG;let i=n.__symbol__("BLACK_LISTED_EVENTS"),o=n.__symbol__("UNPATCHED_EVENTS");e[o]&&(e[i]=e[o]),e[i]&&(n[i]=n[o]=e[i]),r.patchEventPrototype=DG,r.patchEventTarget=TG,r.isIEOrEdge=SG,r.ObjectDefineProperty=WD,r.ObjectGetOwnPropertyDescriptor=rv,r.ObjectCreate=vG,r.ArraySlice=yG,r.patchClass=nv,r.wrapWithCurrentZone=YD,r.filterProperties=LF,r.attachOriginToPatched=ja,r._redefineProperty=Object.defineProperty,r.patchCallbacks=FG,r.getGlobalObjects=()=>({globalSources:MF,zoneSymbolEventNames:$i,eventNames:s,isBrowser:KD,isMix:kF,isNode:ww,TRUE_STR:$a,FALSE_STR:Va,ZONE_SYMBOL_PREFIX:sv,ADD_EVENT_LISTENER_STR:GD,REMOVE_EVENT_LISTENER_STR:ZD})})}function OG(t){NG(t),RG(t),LG(t)}var OF=gG();OG(OF);PG(OF);var BF=new RegExp(`(\\:not\\()|(([\\.\\#]?)[-\\w]+)|(?:\\[([-.\\w*\\\\$]+)(?:=(["']?)([^\\]"']*)\\5)?\\])|(\\))|(\\s*,\\s*)`,"g"),yf=class t{constructor(){l(this,"element",null);l(this,"classNames",[]);l(this,"attrs",[]);l(this,"notSelectors",[])}static parse(e){let n=[],r=(c,u)=>{u.notSelectors.length>0&&!u.element&&u.classNames.length==0&&u.attrs.length==0&&(u.element="*"),c.push(u)},s=new t,i,o=s,a=!1;for(BF.lastIndex=0;i=BF.exec(e);){if(i[1]){if(a)throw new Error("Nesting :not in a selector is not allowed");a=!0,o=new t,s.notSelectors.push(o)}let c=i[2];if(c){let d=i[3];d==="#"?o.addAttribute("id",c.slice(1)):d==="."?o.addClassName(c.slice(1)):o.setElement(c)}let u=i[4];if(u&&o.addAttribute(o.unescapeAttribute(u),i[6]),i[7]&&(a=!1,o=s),i[8]){if(a)throw new Error("Multiple selectors in :not are not supported");r(n,s),s=o=new t}}return r(n,s),n}unescapeAttribute(e){let n="",r=!1;for(let s=0;s0&&e.push("class",this.classNames.join(" ")),e.concat(this.attrs)}addAttribute(e,n=""){this.attrs.push(e,n&&n.toLowerCase()||"")}addClassName(e){this.classNames.push(e.toLowerCase())}toString(){let e=this.element||"";if(this.classNames&&this.classNames.forEach(n=>e+=`.${n}`),this.attrs)for(let n=0;ne+=`:not(${n})`),e}},Nw=class t{constructor(){l(this,"_elementMap",new Map);l(this,"_elementPartialMap",new Map);l(this,"_classMap",new Map);l(this,"_classPartialMap",new Map);l(this,"_attrValueMap",new Map);l(this,"_attrValuePartialMap",new Map);l(this,"_listContexts",[])}static createNotMatcher(e){let n=new t;return n.addSelectables(e,null),n}addSelectables(e,n){let r=null;e.length>1&&(r=new x1(e),this._listContexts.push(r));for(let s=0;s0&&(!this.listContext||!this.listContext.alreadyMatched)&&(r=!Nw.createNotMatcher(this.notSelectors).match(e,null)),r&&n&&(!this.listContext||!this.listContext.alreadyMatched)&&(this.listContext&&(this.listContext.alreadyMatched=!0),n(this.selector,this.cbContext)),r}},Gt;(function(t){t[t.NONE=0]="NONE",t[t.HTML=1]="HTML",t[t.STYLE=2]="STYLE",t[t.SCRIPT=3]="SCRIPT",t[t.URL=4]="URL",t[t.RESOURCE_URL=5]="RESOURCE_URL",t[t.ATTRIBUTE_NO_BINDING=6]="ATTRIBUTE_NO_BINDING"})(Gt||(Gt={}));var Aw,$F="svg",BG="math";function $G(){return Aw||(Aw={},Wl(Gt.HTML,void 0,[["iframe",["srcdoc"]],["*",["innerHTML","outerHTML"]]]),Wl(Gt.STYLE,void 0,[["*",["style"]]]),Wl(Gt.URL,void 0,[["*",["formAction"]],["area",["href"]],["a",["href","xlink:href"]],["form",["action"]],["img",["src"]],["video",["src"]]]),Wl(Gt.URL,BG,[["annotation",["href","xlink:href"]],["annotation-xml",["href","xlink:href"]],["maction",["href","xlink:href"]],["malignmark",["href","xlink:href"]],["math",["href","xlink:href"]],["mroot",["href","xlink:href"]],["msqrt",["href","xlink:href"]],["merror",["href","xlink:href"]],["mfrac",["href","xlink:href"]],["mglyph",["href","xlink:href"]],["msub",["href","xlink:href"]],["msup",["href","xlink:href"]],["msubsup",["href","xlink:href"]],["mmultiscripts",["href","xlink:href"]],["mprescripts",["href","xlink:href"]],["mi",["href","xlink:href"]],["mn",["href","xlink:href"]],["mo",["href","xlink:href"]],["mpadded",["href","xlink:href"]],["mphantom",["href","xlink:href"]],["mrow",["href","xlink:href"]],["ms",["href","xlink:href"]],["mspace",["href","xlink:href"]],["mstyle",["href","xlink:href"]],["mtable",["href","xlink:href"]],["mtd",["href","xlink:href"]],["mtr",["href","xlink:href"]],["mtext",["href","xlink:href"]],["mover",["href","xlink:href"]],["munder",["href","xlink:href"]],["munderover",["href","xlink:href"]],["semantics",["href","xlink:href"]],["none",["href","xlink:href"]]]),Wl(Gt.RESOURCE_URL,void 0,[["base",["href"]],["embed",["src"]],["frame",["src"]],["iframe",["src"]],["link",["href"]],["object",["codebase","data"]]]),Wl(Gt.URL,$F,[["a",["href","xlink:href"]]]),Wl(Gt.ATTRIBUTE_NO_BINDING,$F,[["animate",["attributeName","values","to","from"]],["set",["to","attributeName"]],["animateMotion",["attributeName"]],["animateTransform",["attributeName"]]]),Wl(Gt.ATTRIBUTE_NO_BINDING,void 0,[["unknown",["attributeName","values","to","from","sandbox","allow","allowFullscreen","referrerPolicy","csp","fetchPriority"]],["iframe",["sandbox","allow","allowFullscreen","referrerPolicy","csp","fetchPriority"]]])),Aw}function Wl(t,e,n){for(let[r,s]of n){let i=e&&r!=="*"&&r!=="unknown"?`:${e}:${r}`:r;i=i.toLowerCase();for(let o of s)Aw[`${i}|${o.toLowerCase()}`]=t}}var Kl;(function(t){t[t.Emulated=0]="Emulated",t[t.None=2]="None",t[t.ShadowDom=3]="ShadowDom"})(Kl||(Kl={}));var Rw;(function(t){t[t.OnPush=0]="OnPush",t[t.Default=1]="Default"})(Rw||(Rw={}));var af;(function(t){t[t.None=0]="None",t[t.SignalBased=1]="SignalBased",t[t.HasDecoratorInputTransform=2]="HasDecoratorInputTransform"})(af||(af={}));var VF={name:"custom-elements"},HF={name:"no-errors-schema"};var jF;(function(t){t[t.Error=0]="Error",t[t.Warning=1]="Warning",t[t.Ignore=2]="Ignore"})(jF||(jF={}));function VG(t){let e=t.classNames&&t.classNames.length?[8,...t.classNames]:[];return[t.element&&t.element!=="*"?t.element:"",...t.attrs,...e]}function HG(t){let e=t.classNames&&t.classNames.length?[8,...t.classNames]:[];return t.element?[5,t.element,...t.attrs,...e]:t.attrs.length?[3,...t.attrs,...e]:t.classNames&&t.classNames.length?[9,...t.classNames]:[]}function jG(t){let e=VG(t),n=t.notSelectors&&t.notSelectors.length?t.notSelectors.map(r=>HG(r)):[];return e.concat(...n)}function z_(t){return t?yf.parse(t).map(jG):[]}var Jo;(function(t){t[t.Directive=0]="Directive",t[t.Component=1]="Component",t[t.Injectable=2]="Injectable",t[t.Pipe=3]="Pipe",t[t.NgModule=4]="NgModule"})(Jo||(Jo={}));var UF;(function(t){t[t.Directive=0]="Directive",t[t.Pipe=1]="Pipe",t[t.NgModule=2]="NgModule"})(UF||(UF={}));var qF;(function(t){t[t.Emulated=0]="Emulated",t[t.None=2]="None",t[t.ShadowDom=3]="ShadowDom"})(qF||(qF={}));var Fw;function UG(t){return GG(zG(t.nodes).join("")+`[${t.meaning}]`)}function qG(t){return t.id||SO(t)}function SO(t){let e=new C1,n=t.nodes.map(r=>r.visit(e,null));return CO(n.join(""),t.meaning)}var Lw=class{visitText(e,n){return e.value}visitContainer(e,n){return`[${e.children.map(r=>r.visit(this)).join(", ")}]`}visitIcu(e,n){let r=Object.keys(e.cases).map(s=>`${s} {${e.cases[s].visit(this)}}`);return`{${e.expression}, ${e.type}, ${r.join(", ")}}`}visitTagPlaceholder(e,n){return e.isVoid?``:`${e.children.map(r=>r.visit(this)).join(", ")}`}visitPlaceholder(e,n){return e.value?`${e.value}`:``}visitIcuPlaceholder(e,n){return`${e.value.visit(this)}`}visitBlockPlaceholder(e,n){return`${e.children.map(r=>r.visit(this)).join(", ")}`}},WG=new Lw;function zG(t){return t.map(e=>e.visit(WG,null))}var C1=class extends Lw{visitIcu(e){let n=Object.keys(e.cases).map(r=>`${r} {${e.cases[r].visit(this)}}`);return`{${e.type}, ${n.join(", ")}}`}};function GG(t){Fw??(Fw=new TextEncoder);let e=[...Fw.encode(t)],n=XG(e,Ow.Big),r=e.length*8,s=new Uint32Array(80),i=1732584193,o=4023233417,a=2562383102,c=271733878,u=3285377520;n[r>>5]|=128<<24-r%32,n[(r+64>>9<<4)+15]=r;for(let d=0;d>>0).toString(16).padStart(8,"0")}function ZG(t,e,n,r){return t<20?[e&n|~e&r,1518500249]:t<40?[e^n^r,1859775393]:t<60?[e&n|e&r|n&r,2400959708]:[e^n^r,3395469782]}function WF(t){Fw??(Fw=new TextEncoder);let e=Fw.encode(t),n=new DataView(e.buffer,e.byteOffset,e.byteLength),r=zF(n,e.length,0),s=zF(n,e.length,102072);return r==0&&(s==0||s==1)&&(r=r^319790063,s=s^-1801410264),BigInt.asUintN(32,BigInt(r))<>BigInt(63)&BigInt(1),n+=WF(e)),BigInt.asUintN(63,n).toString()}function zF(t,e,n){let r=2654435769,s=2654435769,i=0,o=e-12;for(;i<=o;i+=12){r+=t.getUint32(i,!0),s+=t.getUint32(i+4,!0),n+=t.getUint32(i+8,!0);let c=GF(r,s,n);r=c[0],s=c[1],n=c[2]}let a=e-i;return n+=e,a>=4?(r+=t.getUint32(i,!0),i+=4,a>=8?(s+=t.getUint32(i,!0),i+=4,a>=9&&(n+=t.getUint8(i++)<<8),a>=10&&(n+=t.getUint8(i++)<<16),a===11&&(n+=t.getUint8(i++)<<24)):(a>=5&&(s+=t.getUint8(i++)),a>=6&&(s+=t.getUint8(i++)<<8),a===7&&(s+=t.getUint8(i++)<<16))):(a>=1&&(r+=t.getUint8(i++)),a>=2&&(r+=t.getUint8(i++)<<8),a===3&&(r+=t.getUint8(i++)<<16)),GF(r,s,n)[2]}function GF(t,e,n){return t-=e,t-=n,t^=n>>>13,e-=n,e-=t,e^=t<<8,n-=t,n-=e,n^=e>>>13,t-=e,t-=n,t^=n>>>12,e-=n,e-=t,e^=t<<16,n-=t,n-=e,n^=e>>>5,t-=e,t-=n,t^=n>>>3,e-=n,e-=t,e^=t<<10,n-=t,n-=e,n^=e>>>15,[t,e,n]}var Ow;(function(t){t[t.Little=0]="Little",t[t.Big=1]="Big"})(Ow||(Ow={}));function Kp(t,e){return YG(t,e)[1]}function YG(t,e){let n=(t&65535)+(e&65535),r=(t>>>16)+(e>>>16)+(n>>>16);return[r>>>16,r<<16|n&65535]}function JD(t,e){return t<>>32-e}function XG(t,e){let n=t.length+3>>>2,r=[];for(let s=0;s=t.length?0:t[e]}function QG(t,e,n){let r=0;if(n===Ow.Big)for(let s=0;s<4;s++)r+=ZF(t,e+s)<<24-8*s;else for(let s=0;s<4;s++)r+=ZF(t,e+s)<<8*s;return r}var T1;(function(t){t[t.None=0]="None",t[t.Const=1]="Const"})(T1||(T1={}));var Bw=class{constructor(e=T1.None){l(this,"modifiers");this.modifiers=e}hasModifier(e){return(this.modifiers&e)!==0}},na;(function(t){t[t.Dynamic=0]="Dynamic",t[t.Bool=1]="Bool",t[t.String=2]="String",t[t.Int=3]="Int",t[t.Number=4]="Number",t[t.Function=5]="Function",t[t.Inferred=6]="Inferred",t[t.None=7]="None"})(na||(na={}));var ra=class extends Bw{constructor(n,r){super(r);l(this,"name");this.name=n}visitType(n,r){return n.visitBuiltinType(this,r)}},Zi=class extends Bw{constructor(n,r,s=null){super(r);l(this,"value");l(this,"typeParams");this.value=n,this.typeParams=s}visitType(n,r){return n.visitExpressionType(this,r)}};var fy=new ra(na.Dynamic),zi=new ra(na.Inferred),KG=new ra(na.Bool),u0e=new ra(na.Int),G_=new ra(na.Number),Z_=new ra(na.String),d0e=new ra(na.Function),sa=new ra(na.None),bf;(function(t){t[t.Minus=0]="Minus",t[t.Plus=1]="Plus"})(bf||(bf={}));var Ye;(function(t){t[t.Equals=0]="Equals",t[t.NotEquals=1]="NotEquals",t[t.Identical=2]="Identical",t[t.NotIdentical=3]="NotIdentical",t[t.Minus=4]="Minus",t[t.Plus=5]="Plus",t[t.Divide=6]="Divide",t[t.Multiply=7]="Multiply",t[t.Modulo=8]="Modulo",t[t.And=9]="And",t[t.Or=10]="Or",t[t.BitwiseOr=11]="BitwiseOr",t[t.BitwiseAnd=12]="BitwiseAnd",t[t.Lower=13]="Lower",t[t.LowerEquals=14]="LowerEquals",t[t.Bigger=15]="Bigger",t[t.BiggerEquals=16]="BiggerEquals",t[t.NullishCoalesce=17]="NullishCoalesce"})(Ye||(Ye={}));function JG(t,e){return t==null||e==null?t==e:t.isEquivalent(e)}function TO(t,e,n){let r=t.length;if(r!==e.length)return!1;for(let s=0;sn.isEquivalent(r))}var mn=class{constructor(e,n){l(this,"type");l(this,"sourceSpan");this.type=e||null,this.sourceSpan=n||null}prop(e,n){return new Si(this,e,null,n)}key(e,n,r){return new Ja(this,e,n,r)}callFn(e,n,r){return new ei(this,e,null,n,r)}instantiate(e,n,r){return new Dv(this,e,n,r)}conditional(e,n=null,r){return new Ka(this,e,n,null,r)}equals(e,n){return new sn(Ye.Equals,this,e,null,n)}notEquals(e,n){return new sn(Ye.NotEquals,this,e,null,n)}identical(e,n){return new sn(Ye.Identical,this,e,null,n)}notIdentical(e,n){return new sn(Ye.NotIdentical,this,e,null,n)}minus(e,n){return new sn(Ye.Minus,this,e,null,n)}plus(e,n){return new sn(Ye.Plus,this,e,null,n)}divide(e,n){return new sn(Ye.Divide,this,e,null,n)}multiply(e,n){return new sn(Ye.Multiply,this,e,null,n)}modulo(e,n){return new sn(Ye.Modulo,this,e,null,n)}and(e,n){return new sn(Ye.And,this,e,null,n)}bitwiseOr(e,n,r=!0){return new sn(Ye.BitwiseOr,this,e,null,n,r)}bitwiseAnd(e,n,r=!0){return new sn(Ye.BitwiseAnd,this,e,null,n,r)}or(e,n){return new sn(Ye.Or,this,e,null,n)}lower(e,n){return new sn(Ye.Lower,this,e,null,n)}lowerEquals(e,n){return new sn(Ye.LowerEquals,this,e,null,n)}bigger(e,n){return new sn(Ye.Bigger,this,e,null,n)}biggerEquals(e,n){return new sn(Ye.BiggerEquals,this,e,null,n)}isBlank(e){return this.equals(s7,e)}nullishCoalesce(e,n){return new sn(Ye.NullishCoalesce,this,e,null,n)}toStmt(){return new Qi(this,null)}},Xi=class t extends mn{constructor(n,r,s){super(r,s);l(this,"name");this.name=n}isEquivalent(n){return n instanceof t&&this.name===n.name}isConstant(){return!1}visitExpression(n,r){return n.visitReadVarExpr(this,r)}clone(){return new t(this.name,this.type,this.sourceSpan)}set(n){return new $w(this.name,n,null,this.sourceSpan)}},wf=class t extends mn{constructor(n,r,s){super(r,s);l(this,"expr");this.expr=n}visitExpression(n,r){return n.visitTypeofExpr(this,r)}isEquivalent(n){return n instanceof t&&n.expr.isEquivalent(this.expr)}isConstant(){return this.expr.isConstant()}clone(){return new t(this.expr.clone())}},Ht=class t extends mn{constructor(n,r,s){super(r,s);l(this,"node");this.node=n}isEquivalent(n){return n instanceof t&&this.node===n.node}isConstant(){return!1}visitExpression(n,r){return n.visitWrappedNodeExpr(this,r)}clone(){return new t(this.node,this.type,this.sourceSpan)}},$w=class t extends mn{constructor(n,r,s,i){super(s||r.type,i);l(this,"name");l(this,"value");this.name=n,this.value=r}isEquivalent(n){return n instanceof t&&this.name===n.name&&this.value.isEquivalent(n.value)}isConstant(){return!1}visitExpression(n,r){return n.visitWriteVarExpr(this,r)}clone(){return new t(this.name,this.value.clone(),this.type,this.sourceSpan)}toDeclStmt(n,r){return new ys(this.name,this.value,n,r,this.sourceSpan)}toConstDecl(){return this.toDeclStmt(zi,Wr.Final)}},Tv=class t extends mn{constructor(n,r,s,i,o){super(i||s.type,o);l(this,"receiver");l(this,"index");l(this,"value");this.receiver=n,this.index=r,this.value=s}isEquivalent(n){return n instanceof t&&this.receiver.isEquivalent(n.receiver)&&this.index.isEquivalent(n.index)&&this.value.isEquivalent(n.value)}isConstant(){return!1}visitExpression(n,r){return n.visitWriteKeyExpr(this,r)}clone(){return new t(this.receiver.clone(),this.index.clone(),this.value.clone(),this.type,this.sourceSpan)}},Ef=class t extends mn{constructor(n,r,s,i,o){super(i||s.type,o);l(this,"receiver");l(this,"name");l(this,"value");this.receiver=n,this.name=r,this.value=s}isEquivalent(n){return n instanceof t&&this.receiver.isEquivalent(n.receiver)&&this.name===n.name&&this.value.isEquivalent(n.value)}isConstant(){return!1}visitExpression(n,r){return n.visitWritePropExpr(this,r)}clone(){return new t(this.receiver.clone(),this.name,this.value.clone(),this.type,this.sourceSpan)}},ei=class t extends mn{constructor(n,r,s,i,o=!1){super(s,i);l(this,"fn");l(this,"args");l(this,"pure");this.fn=n,this.args=r,this.pure=o}get receiver(){return this.fn}isEquivalent(n){return n instanceof t&&this.fn.isEquivalent(n.fn)&&xi(this.args,n.args)&&this.pure===n.pure}isConstant(){return!1}visitExpression(n,r){return n.visitInvokeFunctionExpr(this,r)}clone(){return new t(this.fn.clone(),this.args.map(n=>n.clone()),this.type,this.sourceSpan,this.pure)}},Vw=class t extends mn{constructor(n,r,s,i){super(s,i);l(this,"tag");l(this,"template");this.tag=n,this.template=r}isEquivalent(n){return n instanceof t&&this.tag.isEquivalent(n.tag)&&this.template.isEquivalent(n.template)}isConstant(){return!1}visitExpression(n,r){return n.visitTaggedTemplateLiteralExpr(this,r)}clone(){return new t(this.tag.clone(),this.template.clone(),this.type,this.sourceSpan)}},Dv=class t extends mn{constructor(n,r,s,i){super(s,i);l(this,"classExpr");l(this,"args");this.classExpr=n,this.args=r}isEquivalent(n){return n instanceof t&&this.classExpr.isEquivalent(n.classExpr)&&xi(this.args,n.args)}isConstant(){return!1}visitExpression(n,r){return n.visitInstantiateExpr(this,r)}clone(){return new t(this.classExpr.clone(),this.args.map(n=>n.clone()),this.type,this.sourceSpan)}},os=class t extends mn{constructor(n,r,s){super(r,s);l(this,"value");this.value=n}isEquivalent(n){return n instanceof t&&this.value===n.value}isConstant(){return!0}visitExpression(n,r){return n.visitLiteralExpr(this,r)}clone(){return new t(this.value,this.type,this.sourceSpan)}},_v=class t extends mn{constructor(n,r,s){super(null,s);l(this,"elements");l(this,"expressions");this.elements=n,this.expressions=r}isEquivalent(n){return n instanceof t&&TO(this.elements,n.elements,(r,s)=>r.text===s.text)&&xi(this.expressions,n.expressions)}isConstant(){return!1}visitExpression(n,r){return n.visitTemplateLiteralExpr(this,r)}clone(){return new t(this.elements.map(n=>n.clone()),this.expressions.map(n=>n.clone()))}},Hw=class t extends mn{constructor(n,r,s){super(Z_,r);l(this,"text");l(this,"rawText");this.text=n,this.rawText=s??D1(Mw(n))}visitExpression(n,r){return n.visitTemplateLiteralElementExpr(this,r)}isEquivalent(n){return n instanceof t&&n.text===this.text&&n.rawText===this.rawText}isConstant(){return!0}clone(){return new t(this.text,this.sourceSpan,this.rawText)}},hu=class{constructor(e,n){l(this,"text");l(this,"sourceSpan");this.text=e,this.sourceSpan=n}},hf=class{constructor(e,n,r){l(this,"text");l(this,"sourceSpan");l(this,"associatedMessage");this.text=e,this.sourceSpan=n,this.associatedMessage=r}},e7="|",YF="@@",t7="\u241F",jw=class t extends mn{constructor(n,r,s,i,o){super(Z_,o);l(this,"metaBlock");l(this,"messageParts");l(this,"placeHolderNames");l(this,"expressions");this.metaBlock=n,this.messageParts=r,this.placeHolderNames=s,this.expressions=i}isEquivalent(n){return!1}isConstant(){return!1}visitExpression(n,r){return n.visitLocalizedString(this,r)}clone(){return new t(this.metaBlock,this.messageParts,this.placeHolderNames,this.expressions.map(n=>n.clone()),this.sourceSpan)}serializeI18nHead(){let n=this.metaBlock.description||"";return this.metaBlock.meaning&&(n=`${this.metaBlock.meaning}${e7}${n}`),this.metaBlock.customId&&(n=`${n}${YF}${this.metaBlock.customId}`),this.metaBlock.legacyIds&&this.metaBlock.legacyIds.forEach(r=>{n=`${n}${t7}${r}`}),XF(n,this.messageParts[0].text,this.getMessagePartSourceSpan(0))}getMessagePartSourceSpan(n){return this.messageParts[n]?.sourceSpan??this.sourceSpan}getPlaceholderSourceSpan(n){return this.placeHolderNames[n]?.sourceSpan??this.expressions[n]?.sourceSpan??this.sourceSpan}serializeI18nTemplatePart(n){let r=this.placeHolderNames[n-1],s=this.messageParts[n],i=r.text;return r.associatedMessage?.legacyIds.length===0&&(i+=`${YF}${CO(r.associatedMessage.messageString,r.associatedMessage.meaning)}`),XF(i,s.text,this.getMessagePartSourceSpan(n))}},Mw=t=>t.replace(/\\/g,"\\\\"),n7=t=>t.replace(/^:/,"\\:"),r7=t=>t.replace(/:/g,"\\:"),D1=t=>t.replace(/`/g,"\\`").replace(/\${/g,"$\\{");function XF(t,e,n){return t===""?{cooked:e,raw:D1(n7(Mw(e))),range:n}:{cooked:`:${t}:${e}`,raw:D1(`:${r7(Mw(t))}:${Mw(e)}`),range:n}}var wu=class t extends mn{constructor(n,r,s=null,i){super(r,i);l(this,"value");l(this,"typeParams");this.value=n,this.typeParams=s}isEquivalent(n){return n instanceof t&&this.value.name===n.value.name&&this.value.moduleName===n.value.moduleName}isConstant(){return!1}visitExpression(n,r){return n.visitExternalExpr(this,r)}clone(){return new t(this.value,this.type,this.typeParams,this.sourceSpan)}};var Ka=class t extends mn{constructor(n,r,s=null,i,o){super(i||r.type,o);l(this,"condition");l(this,"falseCase");l(this,"trueCase");this.condition=n,this.falseCase=s,this.trueCase=r}isEquivalent(n){return n instanceof t&&this.condition.isEquivalent(n.condition)&&this.trueCase.isEquivalent(n.trueCase)&&JG(this.falseCase,n.falseCase)}isConstant(){return!1}visitExpression(n,r){return n.visitConditionalExpr(this,r)}clone(){return new t(this.condition.clone(),this.trueCase.clone(),this.falseCase?.clone(),this.type,this.sourceSpan)}};var Iv=class t extends mn{constructor(n,r){super(KG,r);l(this,"condition");this.condition=n}isEquivalent(n){return n instanceof t&&this.condition.isEquivalent(n.condition)}isConstant(){return!1}visitExpression(n,r){return n.visitNotExpr(this,r)}clone(){return new t(this.condition.clone(),this.sourceSpan)}},zr=class t{constructor(e,n=null){l(this,"name");l(this,"type");this.name=e,this.type=n}isEquivalent(e){return this.name===e.name}clone(){return new t(this.name,this.type)}},nc=class t extends mn{constructor(n,r,s,i,o){super(s,i);l(this,"params");l(this,"statements");l(this,"name");this.params=n,this.statements=r,this.name=o}isEquivalent(n){return(n instanceof t||n instanceof Av)&&xi(this.params,n.params)&&xi(this.statements,n.statements)}isConstant(){return!1}visitExpression(n,r){return n.visitFunctionExpr(this,r)}toDeclStmt(n,r){return new Av(n,this.params,this.statements,this.type,r,this.sourceSpan)}clone(){return new t(this.params.map(n=>n.clone()),this.statements,this.type,this.sourceSpan,this.name)}},Eu=class t extends mn{constructor(n,r,s,i){super(s,i);l(this,"params");l(this,"body");this.params=n,this.body=r}isEquivalent(n){return!(n instanceof t)||!xi(this.params,n.params)?!1:this.body instanceof mn&&n.body instanceof mn?this.body.isEquivalent(n.body):Array.isArray(this.body)&&Array.isArray(n.body)?xi(this.body,n.body):!1}isConstant(){return!1}visitExpression(n,r){return n.visitArrowFunctionExpr(this,r)}clone(){return new t(this.params.map(n=>n.clone()),Array.isArray(this.body)?this.body:this.body.clone(),this.type,this.sourceSpan)}toDeclStmt(n,r){return new ys(n,this,zi,r,this.sourceSpan)}},xf=class t extends mn{constructor(n,r,s,i,o=!0){super(s||G_,i);l(this,"operator");l(this,"expr");l(this,"parens");this.operator=n,this.expr=r,this.parens=o}isEquivalent(n){return n instanceof t&&this.operator===n.operator&&this.expr.isEquivalent(n.expr)}isConstant(){return!1}visitExpression(n,r){return n.visitUnaryOperatorExpr(this,r)}clone(){return new t(this.operator,this.expr.clone(),this.type,this.sourceSpan,this.parens)}},sn=class t extends mn{constructor(n,r,s,i,o,a=!0){super(i||r.type,o);l(this,"operator");l(this,"rhs");l(this,"parens");l(this,"lhs");this.operator=n,this.rhs=s,this.parens=a,this.lhs=r}isEquivalent(n){return n instanceof t&&this.operator===n.operator&&this.lhs.isEquivalent(n.lhs)&&this.rhs.isEquivalent(n.rhs)}isConstant(){return!1}visitExpression(n,r){return n.visitBinaryOperatorExpr(this,r)}clone(){return new t(this.operator,this.lhs.clone(),this.rhs.clone(),this.type,this.sourceSpan,this.parens)}},Si=class t extends mn{constructor(n,r,s,i){super(s,i);l(this,"receiver");l(this,"name");this.receiver=n,this.name=r}get index(){return this.name}isEquivalent(n){return n instanceof t&&this.receiver.isEquivalent(n.receiver)&&this.name===n.name}isConstant(){return!1}visitExpression(n,r){return n.visitReadPropExpr(this,r)}set(n){return new Ef(this.receiver,this.name,n,null,this.sourceSpan)}clone(){return new t(this.receiver.clone(),this.name,this.type,this.sourceSpan)}},Ja=class t extends mn{constructor(n,r,s,i){super(s,i);l(this,"receiver");l(this,"index");this.receiver=n,this.index=r}isEquivalent(n){return n instanceof t&&this.receiver.isEquivalent(n.receiver)&&this.index.isEquivalent(n.index)}isConstant(){return!1}visitExpression(n,r){return n.visitReadKeyExpr(this,r)}set(n){return new Tv(this.receiver,this.index,n,null,this.sourceSpan)}clone(){return new t(this.receiver.clone(),this.index.clone(),this.type,this.sourceSpan)}},Eo=class t extends mn{constructor(n,r,s){super(r,s);l(this,"entries");this.entries=n}isConstant(){return this.entries.every(n=>n.isConstant())}isEquivalent(n){return n instanceof t&&xi(this.entries,n.entries)}visitExpression(n,r){return n.visitLiteralArrayExpr(this,r)}clone(){return new t(this.entries.map(n=>n.clone()),this.type,this.sourceSpan)}},Sf=class t{constructor(e,n,r){l(this,"key");l(this,"value");l(this,"quoted");this.key=e,this.value=n,this.quoted=r}isEquivalent(e){return this.key===e.key&&this.value.isEquivalent(e.value)}clone(){return new t(this.key,this.value.clone(),this.quoted)}},ia=class t extends mn{constructor(n,r,s){super(r,s);l(this,"entries");l(this,"valueType",null);this.entries=n,r&&(this.valueType=r.valueType)}isEquivalent(n){return n instanceof t&&xi(this.entries,n.entries)}isConstant(){return this.entries.every(n=>n.value.isConstant())}visitExpression(n,r){return n.visitLiteralMapExpr(this,r)}clone(){let n=this.entries.map(r=>r.clone());return new t(n,this.type,this.sourceSpan)}};var kv=new os(null,null,null),s7=new os(null,zi,null),Wr;(function(t){t[t.None=0]="None",t[t.Final=1]="Final",t[t.Private=2]="Private",t[t.Exported=4]="Exported",t[t.Static=8]="Static"})(Wr||(Wr={}));var _1=class{constructor(e,n,r){l(this,"text");l(this,"multiline");l(this,"trailingNewline");this.text=e,this.multiline=n,this.trailingNewline=r}toString(){return this.multiline?` ${this.text} `:this.text}},Uw=class extends _1{constructor(n){super("",!0,!0);l(this,"tags");this.tags=n}toString(){return c7(this.tags)}},xu=class{constructor(e=Wr.None,n=null,r){l(this,"modifiers");l(this,"sourceSpan");l(this,"leadingComments");this.modifiers=e,this.sourceSpan=n,this.leadingComments=r}hasModifier(e){return(this.modifiers&e)!==0}addLeadingComment(e){this.leadingComments=this.leadingComments??[],this.leadingComments.push(e)}},ys=class t extends xu{constructor(n,r,s,i,o,a){super(i,o,a);l(this,"name");l(this,"value");l(this,"type");this.name=n,this.value=r,this.type=s||r&&r.type||null}isEquivalent(n){return n instanceof t&&this.name===n.name&&(this.value?!!n.value&&this.value.isEquivalent(n.value):!n.value)}visitStatement(n,r){return n.visitDeclareVarStmt(this,r)}},Av=class t extends xu{constructor(n,r,s,i,o,a,c){super(o,a,c);l(this,"name");l(this,"params");l(this,"statements");l(this,"type");this.name=n,this.params=r,this.statements=s,this.type=i||null}isEquivalent(n){return n instanceof t&&xi(this.params,n.params)&&xi(this.statements,n.statements)}visitStatement(n,r){return n.visitDeclareFunctionStmt(this,r)}},Qi=class t extends xu{constructor(n,r,s){super(Wr.None,r,s);l(this,"expr");this.expr=n}isEquivalent(n){return n instanceof t&&this.expr.isEquivalent(n.expr)}visitStatement(n,r){return n.visitExpressionStmt(this,r)}},gs=class t extends xu{constructor(n,r=null,s){super(Wr.None,r,s);l(this,"value");this.value=n}isEquivalent(n){return n instanceof t&&this.value.isEquivalent(n.value)}visitStatement(n,r){return n.visitReturnStmt(this,r)}},qw=class t extends xu{constructor(n,r,s=[],i,o){super(Wr.None,i,o);l(this,"condition");l(this,"trueCase");l(this,"falseCase");this.condition=n,this.trueCase=r,this.falseCase=s}isEquivalent(n){return n instanceof t&&this.condition.isEquivalent(n.condition)&&xi(this.trueCase,n.trueCase)&&xi(this.falseCase,n.falseCase)}visitStatement(n,r){return n.visitIfStmt(this,r)}};function i7(t=[]){return new Uw(t)}function Rt(t,e,n){return new Xi(t,e,n)}function Xe(t,e=null,n){return new wu(t,null,e,n)}function is(t,e,n){return new Zi(t,e,n)}function hy(t){return new wf(t)}function fn(t,e,n){return new Eo(t,e,n)}function Ms(t,e=null){return new ia(t.map(n=>new Sf(n.key,n.value,n.quoted)),e,null)}function o7(t,e){return new Iv(t,e)}function sc(t,e,n,r,s){return new nc(t,e,n,r,s)}function xo(t,e,n,r){return new Eu(t,e,n,r)}function ex(t,e,n,r,s){return new qw(t,e,n,r,s)}function a7(t,e,n,r){return new Vw(t,e,n,r)}function Y(t,e,n){return new os(t,e,n)}function l7(t,e,n,r,s){return new jw(t,e,n,r,s)}function QF(t){let e="";if(t.tagName&&(e+=` @${t.tagName}`),t.text){if(t.text.match(/\/\*|\*\//))throw new Error('JSDoc text cannot contain "/*" and "*/"');e+=" "+t.text.replace(/@/g,"\\@")}return e}function c7(t){if(t.length===0)return"";if(t.length===1&&t[0].tagName&&!t[0].text)return`*${QF(t[0])} `;let e=`* +`;for(let n of t)e+=" *",e+=QF(n).replace(/\n/g,` + * `),e+=` +`;return e+=" ",e}var u7="_c",KF=Rt(""),d7={},p7=50,Ww=class t extends mn{constructor(n){super(n.type);l(this,"resolved");l(this,"original");l(this,"shared",!1);this.resolved=n,this.original=n}visitExpression(n,r){return r===d7?this.original.visitExpression(n,r):this.resolved.visitExpression(n,r)}isEquivalent(n){return n instanceof t&&this.resolved.isEquivalent(n.resolved)}isConstant(){return!0}clone(){throw new Error("Not supported.")}fixup(n){this.resolved=n,this.shared=!0}},zw=class{constructor(e=!1){l(this,"isClosureCompilerEnabled");l(this,"statements",[]);l(this,"literals",new Map);l(this,"literalFactories",new Map);l(this,"sharedConstants",new Map);l(this,"_claimedNames",new Map);l(this,"nextNameIndex",0);this.isClosureCompilerEnabled=e}getConstLiteral(e,n){if(e instanceof os&&!JF(e)||e instanceof Ww)return e;let r=mf.INSTANCE.keyOf(e),s=this.literals.get(r),i=!1;if(s||(s=new Ww(e),this.literals.set(r,s),i=!0),!i&&!s.shared||i&&n){let o=this.freshName(),a,c;this.isClosureCompilerEnabled&&JF(e)?(a=Rt(o).set(new nc([],[new gs(e)])),c=Rt(o).callFn([])):(a=Rt(o).set(e),c=Rt(o)),this.statements.push(a.toDeclStmt(zi,Wr.Final)),s.fixup(c)}return s}getSharedConstant(e,n){let r=e.keyOf(n);if(!this.sharedConstants.has(r)){let s=this.freshName();this.sharedConstants.set(r,Rt(s)),this.statements.push(e.toSharedConstantDeclaration(s,n))}return this.sharedConstants.get(r)}getLiteralFactory(e){if(e instanceof Eo){let n=e.entries.map(s=>s.isConstant()?s:KF),r=mf.INSTANCE.keyOf(fn(n));return this._getLiteralFactory(r,e.entries,s=>fn(s))}else{let n=Ms(e.entries.map(s=>({key:s.key,value:s.value.isConstant()?s.value:KF,quoted:s.quoted}))),r=mf.INSTANCE.keyOf(n);return this._getLiteralFactory(r,e.entries.map(s=>s.value),s=>Ms(s.map((i,o)=>({key:e.entries[o].key,value:i,quoted:e.entries[o].quoted}))))}}getSharedFunctionReference(e,n,r=!0){let s=e instanceof Eu;for(let o of this.statements)if(s&&o instanceof ys&&o.value?.isEquivalent(e)||!s&&o instanceof Av&&e instanceof nc&&e.isEquivalent(o))return Rt(o.name);let i=r?this.uniqueName(n):n;return this.statements.push(e instanceof nc?e.toDeclStmt(i,Wr.Final):new ys(i,e,zi,Wr.Final,e.sourceSpan)),Rt(i)}_getLiteralFactory(e,n,r){let s=this.literalFactories.get(e),i=n.filter(o=>!o.isConstant());if(!s){let o=n.map((d,p)=>d.isConstant()?this.getConstLiteral(d,!0):Rt(`a${p}`)),a=o.filter(f7).map(d=>new zr(d.name,fy)),c=xo(a,r(o),zi),u=this.freshName();this.statements.push(Rt(u).set(c).toDeclStmt(zi,Wr.Final)),s=Rt(u),this.literalFactories.set(e,s)}return{literalFactory:s,literalFactoryArguments:i}}uniqueName(e,n=!0){let r=this._claimedNames.get(e)??0,s=r===0&&!n?`${e}`:`${e}${r}`;return this._claimedNames.set(e,r+1),s}freshName(){return this.uniqueName(u7)}},QE=class QE{keyOf(e){if(e instanceof os&&typeof e.value=="string")return`"${e.value}"`;if(e instanceof os)return String(e.value);if(e instanceof Eo){let n=[];for(let r of e.entries)n.push(this.keyOf(r));return`[${n.join(",")}]`}else if(e instanceof ia){let n=[];for(let r of e.entries){let s=r.key;r.quoted&&(s=`"${s}"`),n.push(s+":"+this.keyOf(r.value))}return`{${n.join(",")}}`}else{if(e instanceof wu)return`import("${e.value.moduleName}", ${e.value.name})`;if(e instanceof Xi)return`read(${e.name})`;if(e instanceof wf)return`typeof(${this.keyOf(e.expr)})`;throw new Error(`${this.constructor.name} does not handle expressions of type ${e.constructor.name}`)}}};l(QE,"INSTANCE",new QE);var mf=QE;function f7(t){return t instanceof Xi}function JF(t){return t instanceof os&&typeof t.value=="string"&&t.value.length>=p7}var P="@angular/core",y=class{};l(y,"NEW_METHOD","factory"),l(y,"TRANSFORM_METHOD","transform"),l(y,"PATCH_DEPS","patchedDeps"),l(y,"core",{name:null,moduleName:P}),l(y,"namespaceHTML",{name:"\u0275\u0275namespaceHTML",moduleName:P}),l(y,"namespaceMathML",{name:"\u0275\u0275namespaceMathML",moduleName:P}),l(y,"namespaceSVG",{name:"\u0275\u0275namespaceSVG",moduleName:P}),l(y,"element",{name:"\u0275\u0275element",moduleName:P}),l(y,"elementStart",{name:"\u0275\u0275elementStart",moduleName:P}),l(y,"elementEnd",{name:"\u0275\u0275elementEnd",moduleName:P}),l(y,"advance",{name:"\u0275\u0275advance",moduleName:P}),l(y,"syntheticHostProperty",{name:"\u0275\u0275syntheticHostProperty",moduleName:P}),l(y,"syntheticHostListener",{name:"\u0275\u0275syntheticHostListener",moduleName:P}),l(y,"attribute",{name:"\u0275\u0275attribute",moduleName:P}),l(y,"attributeInterpolate1",{name:"\u0275\u0275attributeInterpolate1",moduleName:P}),l(y,"attributeInterpolate2",{name:"\u0275\u0275attributeInterpolate2",moduleName:P}),l(y,"attributeInterpolate3",{name:"\u0275\u0275attributeInterpolate3",moduleName:P}),l(y,"attributeInterpolate4",{name:"\u0275\u0275attributeInterpolate4",moduleName:P}),l(y,"attributeInterpolate5",{name:"\u0275\u0275attributeInterpolate5",moduleName:P}),l(y,"attributeInterpolate6",{name:"\u0275\u0275attributeInterpolate6",moduleName:P}),l(y,"attributeInterpolate7",{name:"\u0275\u0275attributeInterpolate7",moduleName:P}),l(y,"attributeInterpolate8",{name:"\u0275\u0275attributeInterpolate8",moduleName:P}),l(y,"attributeInterpolateV",{name:"\u0275\u0275attributeInterpolateV",moduleName:P}),l(y,"classProp",{name:"\u0275\u0275classProp",moduleName:P}),l(y,"elementContainerStart",{name:"\u0275\u0275elementContainerStart",moduleName:P}),l(y,"elementContainerEnd",{name:"\u0275\u0275elementContainerEnd",moduleName:P}),l(y,"elementContainer",{name:"\u0275\u0275elementContainer",moduleName:P}),l(y,"styleMap",{name:"\u0275\u0275styleMap",moduleName:P}),l(y,"styleMapInterpolate1",{name:"\u0275\u0275styleMapInterpolate1",moduleName:P}),l(y,"styleMapInterpolate2",{name:"\u0275\u0275styleMapInterpolate2",moduleName:P}),l(y,"styleMapInterpolate3",{name:"\u0275\u0275styleMapInterpolate3",moduleName:P}),l(y,"styleMapInterpolate4",{name:"\u0275\u0275styleMapInterpolate4",moduleName:P}),l(y,"styleMapInterpolate5",{name:"\u0275\u0275styleMapInterpolate5",moduleName:P}),l(y,"styleMapInterpolate6",{name:"\u0275\u0275styleMapInterpolate6",moduleName:P}),l(y,"styleMapInterpolate7",{name:"\u0275\u0275styleMapInterpolate7",moduleName:P}),l(y,"styleMapInterpolate8",{name:"\u0275\u0275styleMapInterpolate8",moduleName:P}),l(y,"styleMapInterpolateV",{name:"\u0275\u0275styleMapInterpolateV",moduleName:P}),l(y,"classMap",{name:"\u0275\u0275classMap",moduleName:P}),l(y,"classMapInterpolate1",{name:"\u0275\u0275classMapInterpolate1",moduleName:P}),l(y,"classMapInterpolate2",{name:"\u0275\u0275classMapInterpolate2",moduleName:P}),l(y,"classMapInterpolate3",{name:"\u0275\u0275classMapInterpolate3",moduleName:P}),l(y,"classMapInterpolate4",{name:"\u0275\u0275classMapInterpolate4",moduleName:P}),l(y,"classMapInterpolate5",{name:"\u0275\u0275classMapInterpolate5",moduleName:P}),l(y,"classMapInterpolate6",{name:"\u0275\u0275classMapInterpolate6",moduleName:P}),l(y,"classMapInterpolate7",{name:"\u0275\u0275classMapInterpolate7",moduleName:P}),l(y,"classMapInterpolate8",{name:"\u0275\u0275classMapInterpolate8",moduleName:P}),l(y,"classMapInterpolateV",{name:"\u0275\u0275classMapInterpolateV",moduleName:P}),l(y,"styleProp",{name:"\u0275\u0275styleProp",moduleName:P}),l(y,"stylePropInterpolate1",{name:"\u0275\u0275stylePropInterpolate1",moduleName:P}),l(y,"stylePropInterpolate2",{name:"\u0275\u0275stylePropInterpolate2",moduleName:P}),l(y,"stylePropInterpolate3",{name:"\u0275\u0275stylePropInterpolate3",moduleName:P}),l(y,"stylePropInterpolate4",{name:"\u0275\u0275stylePropInterpolate4",moduleName:P}),l(y,"stylePropInterpolate5",{name:"\u0275\u0275stylePropInterpolate5",moduleName:P}),l(y,"stylePropInterpolate6",{name:"\u0275\u0275stylePropInterpolate6",moduleName:P}),l(y,"stylePropInterpolate7",{name:"\u0275\u0275stylePropInterpolate7",moduleName:P}),l(y,"stylePropInterpolate8",{name:"\u0275\u0275stylePropInterpolate8",moduleName:P}),l(y,"stylePropInterpolateV",{name:"\u0275\u0275stylePropInterpolateV",moduleName:P}),l(y,"nextContext",{name:"\u0275\u0275nextContext",moduleName:P}),l(y,"resetView",{name:"\u0275\u0275resetView",moduleName:P}),l(y,"templateCreate",{name:"\u0275\u0275template",moduleName:P}),l(y,"defer",{name:"\u0275\u0275defer",moduleName:P}),l(y,"deferWhen",{name:"\u0275\u0275deferWhen",moduleName:P}),l(y,"deferOnIdle",{name:"\u0275\u0275deferOnIdle",moduleName:P}),l(y,"deferOnImmediate",{name:"\u0275\u0275deferOnImmediate",moduleName:P}),l(y,"deferOnTimer",{name:"\u0275\u0275deferOnTimer",moduleName:P}),l(y,"deferOnHover",{name:"\u0275\u0275deferOnHover",moduleName:P}),l(y,"deferOnInteraction",{name:"\u0275\u0275deferOnInteraction",moduleName:P}),l(y,"deferOnViewport",{name:"\u0275\u0275deferOnViewport",moduleName:P}),l(y,"deferPrefetchWhen",{name:"\u0275\u0275deferPrefetchWhen",moduleName:P}),l(y,"deferPrefetchOnIdle",{name:"\u0275\u0275deferPrefetchOnIdle",moduleName:P}),l(y,"deferPrefetchOnImmediate",{name:"\u0275\u0275deferPrefetchOnImmediate",moduleName:P}),l(y,"deferPrefetchOnTimer",{name:"\u0275\u0275deferPrefetchOnTimer",moduleName:P}),l(y,"deferPrefetchOnHover",{name:"\u0275\u0275deferPrefetchOnHover",moduleName:P}),l(y,"deferPrefetchOnInteraction",{name:"\u0275\u0275deferPrefetchOnInteraction",moduleName:P}),l(y,"deferPrefetchOnViewport",{name:"\u0275\u0275deferPrefetchOnViewport",moduleName:P}),l(y,"deferHydrateWhen",{name:"\u0275\u0275deferHydrateWhen",moduleName:P}),l(y,"deferHydrateNever",{name:"\u0275\u0275deferHydrateNever",moduleName:P}),l(y,"deferHydrateOnIdle",{name:"\u0275\u0275deferHydrateOnIdle",moduleName:P}),l(y,"deferHydrateOnImmediate",{name:"\u0275\u0275deferHydrateOnImmediate",moduleName:P}),l(y,"deferHydrateOnTimer",{name:"\u0275\u0275deferHydrateOnTimer",moduleName:P}),l(y,"deferHydrateOnHover",{name:"\u0275\u0275deferHydrateOnHover",moduleName:P}),l(y,"deferHydrateOnInteraction",{name:"\u0275\u0275deferHydrateOnInteraction",moduleName:P}),l(y,"deferHydrateOnViewport",{name:"\u0275\u0275deferHydrateOnViewport",moduleName:P}),l(y,"deferEnableTimerScheduling",{name:"\u0275\u0275deferEnableTimerScheduling",moduleName:P}),l(y,"conditional",{name:"\u0275\u0275conditional",moduleName:P}),l(y,"repeater",{name:"\u0275\u0275repeater",moduleName:P}),l(y,"repeaterCreate",{name:"\u0275\u0275repeaterCreate",moduleName:P}),l(y,"repeaterTrackByIndex",{name:"\u0275\u0275repeaterTrackByIndex",moduleName:P}),l(y,"repeaterTrackByIdentity",{name:"\u0275\u0275repeaterTrackByIdentity",moduleName:P}),l(y,"componentInstance",{name:"\u0275\u0275componentInstance",moduleName:P}),l(y,"text",{name:"\u0275\u0275text",moduleName:P}),l(y,"enableBindings",{name:"\u0275\u0275enableBindings",moduleName:P}),l(y,"disableBindings",{name:"\u0275\u0275disableBindings",moduleName:P}),l(y,"getCurrentView",{name:"\u0275\u0275getCurrentView",moduleName:P}),l(y,"textInterpolate",{name:"\u0275\u0275textInterpolate",moduleName:P}),l(y,"textInterpolate1",{name:"\u0275\u0275textInterpolate1",moduleName:P}),l(y,"textInterpolate2",{name:"\u0275\u0275textInterpolate2",moduleName:P}),l(y,"textInterpolate3",{name:"\u0275\u0275textInterpolate3",moduleName:P}),l(y,"textInterpolate4",{name:"\u0275\u0275textInterpolate4",moduleName:P}),l(y,"textInterpolate5",{name:"\u0275\u0275textInterpolate5",moduleName:P}),l(y,"textInterpolate6",{name:"\u0275\u0275textInterpolate6",moduleName:P}),l(y,"textInterpolate7",{name:"\u0275\u0275textInterpolate7",moduleName:P}),l(y,"textInterpolate8",{name:"\u0275\u0275textInterpolate8",moduleName:P}),l(y,"textInterpolateV",{name:"\u0275\u0275textInterpolateV",moduleName:P}),l(y,"restoreView",{name:"\u0275\u0275restoreView",moduleName:P}),l(y,"pureFunction0",{name:"\u0275\u0275pureFunction0",moduleName:P}),l(y,"pureFunction1",{name:"\u0275\u0275pureFunction1",moduleName:P}),l(y,"pureFunction2",{name:"\u0275\u0275pureFunction2",moduleName:P}),l(y,"pureFunction3",{name:"\u0275\u0275pureFunction3",moduleName:P}),l(y,"pureFunction4",{name:"\u0275\u0275pureFunction4",moduleName:P}),l(y,"pureFunction5",{name:"\u0275\u0275pureFunction5",moduleName:P}),l(y,"pureFunction6",{name:"\u0275\u0275pureFunction6",moduleName:P}),l(y,"pureFunction7",{name:"\u0275\u0275pureFunction7",moduleName:P}),l(y,"pureFunction8",{name:"\u0275\u0275pureFunction8",moduleName:P}),l(y,"pureFunctionV",{name:"\u0275\u0275pureFunctionV",moduleName:P}),l(y,"pipeBind1",{name:"\u0275\u0275pipeBind1",moduleName:P}),l(y,"pipeBind2",{name:"\u0275\u0275pipeBind2",moduleName:P}),l(y,"pipeBind3",{name:"\u0275\u0275pipeBind3",moduleName:P}),l(y,"pipeBind4",{name:"\u0275\u0275pipeBind4",moduleName:P}),l(y,"pipeBindV",{name:"\u0275\u0275pipeBindV",moduleName:P}),l(y,"hostProperty",{name:"\u0275\u0275hostProperty",moduleName:P}),l(y,"property",{name:"\u0275\u0275property",moduleName:P}),l(y,"propertyInterpolate",{name:"\u0275\u0275propertyInterpolate",moduleName:P}),l(y,"propertyInterpolate1",{name:"\u0275\u0275propertyInterpolate1",moduleName:P}),l(y,"propertyInterpolate2",{name:"\u0275\u0275propertyInterpolate2",moduleName:P}),l(y,"propertyInterpolate3",{name:"\u0275\u0275propertyInterpolate3",moduleName:P}),l(y,"propertyInterpolate4",{name:"\u0275\u0275propertyInterpolate4",moduleName:P}),l(y,"propertyInterpolate5",{name:"\u0275\u0275propertyInterpolate5",moduleName:P}),l(y,"propertyInterpolate6",{name:"\u0275\u0275propertyInterpolate6",moduleName:P}),l(y,"propertyInterpolate7",{name:"\u0275\u0275propertyInterpolate7",moduleName:P}),l(y,"propertyInterpolate8",{name:"\u0275\u0275propertyInterpolate8",moduleName:P}),l(y,"propertyInterpolateV",{name:"\u0275\u0275propertyInterpolateV",moduleName:P}),l(y,"i18n",{name:"\u0275\u0275i18n",moduleName:P}),l(y,"i18nAttributes",{name:"\u0275\u0275i18nAttributes",moduleName:P}),l(y,"i18nExp",{name:"\u0275\u0275i18nExp",moduleName:P}),l(y,"i18nStart",{name:"\u0275\u0275i18nStart",moduleName:P}),l(y,"i18nEnd",{name:"\u0275\u0275i18nEnd",moduleName:P}),l(y,"i18nApply",{name:"\u0275\u0275i18nApply",moduleName:P}),l(y,"i18nPostprocess",{name:"\u0275\u0275i18nPostprocess",moduleName:P}),l(y,"pipe",{name:"\u0275\u0275pipe",moduleName:P}),l(y,"projection",{name:"\u0275\u0275projection",moduleName:P}),l(y,"projectionDef",{name:"\u0275\u0275projectionDef",moduleName:P}),l(y,"reference",{name:"\u0275\u0275reference",moduleName:P}),l(y,"inject",{name:"\u0275\u0275inject",moduleName:P}),l(y,"injectAttribute",{name:"\u0275\u0275injectAttribute",moduleName:P}),l(y,"directiveInject",{name:"\u0275\u0275directiveInject",moduleName:P}),l(y,"invalidFactory",{name:"\u0275\u0275invalidFactory",moduleName:P}),l(y,"invalidFactoryDep",{name:"\u0275\u0275invalidFactoryDep",moduleName:P}),l(y,"templateRefExtractor",{name:"\u0275\u0275templateRefExtractor",moduleName:P}),l(y,"forwardRef",{name:"forwardRef",moduleName:P}),l(y,"resolveForwardRef",{name:"resolveForwardRef",moduleName:P}),l(y,"replaceMetadata",{name:"\u0275\u0275replaceMetadata",moduleName:P}),l(y,"getReplaceMetadataURL",{name:"\u0275\u0275getReplaceMetadataURL",moduleName:P}),l(y,"\u0275\u0275defineInjectable",{name:"\u0275\u0275defineInjectable",moduleName:P}),l(y,"declareInjectable",{name:"\u0275\u0275ngDeclareInjectable",moduleName:P}),l(y,"InjectableDeclaration",{name:"\u0275\u0275InjectableDeclaration",moduleName:P}),l(y,"resolveWindow",{name:"\u0275\u0275resolveWindow",moduleName:P}),l(y,"resolveDocument",{name:"\u0275\u0275resolveDocument",moduleName:P}),l(y,"resolveBody",{name:"\u0275\u0275resolveBody",moduleName:P}),l(y,"getComponentDepsFactory",{name:"\u0275\u0275getComponentDepsFactory",moduleName:P}),l(y,"defineComponent",{name:"\u0275\u0275defineComponent",moduleName:P}),l(y,"declareComponent",{name:"\u0275\u0275ngDeclareComponent",moduleName:P}),l(y,"setComponentScope",{name:"\u0275\u0275setComponentScope",moduleName:P}),l(y,"ChangeDetectionStrategy",{name:"ChangeDetectionStrategy",moduleName:P}),l(y,"ViewEncapsulation",{name:"ViewEncapsulation",moduleName:P}),l(y,"ComponentDeclaration",{name:"\u0275\u0275ComponentDeclaration",moduleName:P}),l(y,"FactoryDeclaration",{name:"\u0275\u0275FactoryDeclaration",moduleName:P}),l(y,"declareFactory",{name:"\u0275\u0275ngDeclareFactory",moduleName:P}),l(y,"FactoryTarget",{name:"\u0275\u0275FactoryTarget",moduleName:P}),l(y,"defineDirective",{name:"\u0275\u0275defineDirective",moduleName:P}),l(y,"declareDirective",{name:"\u0275\u0275ngDeclareDirective",moduleName:P}),l(y,"DirectiveDeclaration",{name:"\u0275\u0275DirectiveDeclaration",moduleName:P}),l(y,"InjectorDef",{name:"\u0275\u0275InjectorDef",moduleName:P}),l(y,"InjectorDeclaration",{name:"\u0275\u0275InjectorDeclaration",moduleName:P}),l(y,"defineInjector",{name:"\u0275\u0275defineInjector",moduleName:P}),l(y,"declareInjector",{name:"\u0275\u0275ngDeclareInjector",moduleName:P}),l(y,"NgModuleDeclaration",{name:"\u0275\u0275NgModuleDeclaration",moduleName:P}),l(y,"ModuleWithProviders",{name:"ModuleWithProviders",moduleName:P}),l(y,"defineNgModule",{name:"\u0275\u0275defineNgModule",moduleName:P}),l(y,"declareNgModule",{name:"\u0275\u0275ngDeclareNgModule",moduleName:P}),l(y,"setNgModuleScope",{name:"\u0275\u0275setNgModuleScope",moduleName:P}),l(y,"registerNgModuleType",{name:"\u0275\u0275registerNgModuleType",moduleName:P}),l(y,"PipeDeclaration",{name:"\u0275\u0275PipeDeclaration",moduleName:P}),l(y,"definePipe",{name:"\u0275\u0275definePipe",moduleName:P}),l(y,"declarePipe",{name:"\u0275\u0275ngDeclarePipe",moduleName:P}),l(y,"declareClassMetadata",{name:"\u0275\u0275ngDeclareClassMetadata",moduleName:P}),l(y,"declareClassMetadataAsync",{name:"\u0275\u0275ngDeclareClassMetadataAsync",moduleName:P}),l(y,"setClassMetadata",{name:"\u0275setClassMetadata",moduleName:P}),l(y,"setClassMetadataAsync",{name:"\u0275setClassMetadataAsync",moduleName:P}),l(y,"setClassDebugInfo",{name:"\u0275setClassDebugInfo",moduleName:P}),l(y,"queryRefresh",{name:"\u0275\u0275queryRefresh",moduleName:P}),l(y,"viewQuery",{name:"\u0275\u0275viewQuery",moduleName:P}),l(y,"loadQuery",{name:"\u0275\u0275loadQuery",moduleName:P}),l(y,"contentQuery",{name:"\u0275\u0275contentQuery",moduleName:P}),l(y,"viewQuerySignal",{name:"\u0275\u0275viewQuerySignal",moduleName:P}),l(y,"contentQuerySignal",{name:"\u0275\u0275contentQuerySignal",moduleName:P}),l(y,"queryAdvance",{name:"\u0275\u0275queryAdvance",moduleName:P}),l(y,"twoWayProperty",{name:"\u0275\u0275twoWayProperty",moduleName:P}),l(y,"twoWayBindingSet",{name:"\u0275\u0275twoWayBindingSet",moduleName:P}),l(y,"twoWayListener",{name:"\u0275\u0275twoWayListener",moduleName:P}),l(y,"declareLet",{name:"\u0275\u0275declareLet",moduleName:P}),l(y,"storeLet",{name:"\u0275\u0275storeLet",moduleName:P}),l(y,"readContextLet",{name:"\u0275\u0275readContextLet",moduleName:P}),l(y,"attachSourceLocations",{name:"\u0275\u0275attachSourceLocations",moduleName:P}),l(y,"NgOnChangesFeature",{name:"\u0275\u0275NgOnChangesFeature",moduleName:P}),l(y,"InheritDefinitionFeature",{name:"\u0275\u0275InheritDefinitionFeature",moduleName:P}),l(y,"CopyDefinitionFeature",{name:"\u0275\u0275CopyDefinitionFeature",moduleName:P}),l(y,"ProvidersFeature",{name:"\u0275\u0275ProvidersFeature",moduleName:P}),l(y,"HostDirectivesFeature",{name:"\u0275\u0275HostDirectivesFeature",moduleName:P}),l(y,"ExternalStylesFeature",{name:"\u0275\u0275ExternalStylesFeature",moduleName:P}),l(y,"listener",{name:"\u0275\u0275listener",moduleName:P}),l(y,"getInheritedFactory",{name:"\u0275\u0275getInheritedFactory",moduleName:P}),l(y,"sanitizeHtml",{name:"\u0275\u0275sanitizeHtml",moduleName:P}),l(y,"sanitizeStyle",{name:"\u0275\u0275sanitizeStyle",moduleName:P}),l(y,"validateAttribute",{name:"\u0275\u0275validateAttribute",moduleName:P}),l(y,"sanitizeResourceUrl",{name:"\u0275\u0275sanitizeResourceUrl",moduleName:P}),l(y,"sanitizeScript",{name:"\u0275\u0275sanitizeScript",moduleName:P}),l(y,"sanitizeUrl",{name:"\u0275\u0275sanitizeUrl",moduleName:P}),l(y,"sanitizeUrlOrResourceUrl",{name:"\u0275\u0275sanitizeUrlOrResourceUrl",moduleName:P}),l(y,"trustConstantHtml",{name:"\u0275\u0275trustConstantHtml",moduleName:P}),l(y,"trustConstantResourceUrl",{name:"\u0275\u0275trustConstantResourceUrl",moduleName:P}),l(y,"InputSignalBrandWriteType",{name:"\u0275INPUT_SIGNAL_BRAND_WRITE_TYPE",moduleName:P}),l(y,"UnwrapDirectiveSignalInputs",{name:"\u0275UnwrapDirectiveSignalInputs",moduleName:P}),l(y,"unwrapWritableSignal",{name:"\u0275unwrapWritableSignal",moduleName:P});var h7=/-+([a-z0-9])/g;function m7(t){return t.replace(h7,(...e)=>e[1].toUpperCase())}function g7(t,e){return DO(t,":",e)}function v7(t,e){return DO(t,".",e)}function DO(t,e,n){let r=t.indexOf(e);return r==-1?n:[t.slice(0,r).trim(),t.slice(r+1).trim()]}function y7(t){let e=[];for(let n=0;n=55296&&r<=56319&&t.length>n+1){let s=t.charCodeAt(n+1);s>=56320&&s<=57343&&(n++,r=(r-55296<<10)+s-56320+65536)}r<=127?e.push(r):r<=2047?e.push(r>>6&31|192,r&63|128):r<=65535?e.push(r>>12|224,r>>6&63|128,r&63|128):r<=2097151&&e.push(r>>18&7|240,r>>12&63|128,r>>6&63|128,r&63|128)}return e}function _O(t){if(typeof t=="string")return t;if(Array.isArray(t))return`[${t.map(_O).join(", ")}]`;if(t==null)return""+t;let e=t.overriddenName||t.name;if(e)return`${e}`;if(!t.toString)return"object";let n=t.toString();if(n==null)return""+n;let r=n.indexOf(` +`);return r>=0?n.slice(0,r):n}var I1=class{constructor(e){l(this,"full");l(this,"major");l(this,"minor");l(this,"patch");this.full=e;let n=e.split(".");this.major=n[0],this.minor=n[1],this.patch=n.slice(2).join(".")}},gv=globalThis,b7=/^([1-9]|1[0-8])\./;function IO(t){return t.startsWith("0.")?!0:!b7.test(t)}var w7=3,E7="# sourceMappingURL=data:application/json;base64,",k1=class{constructor(e=null){l(this,"file");l(this,"sourcesContent",new Map);l(this,"lines",[]);l(this,"lastCol0",0);l(this,"hasMappings",!1);this.file=e}addSource(e,n=null){return this.sourcesContent.has(e)||this.sourcesContent.set(e,n),this}addLine(){return this.lines.push([]),this.lastCol0=0,this}addMapping(e,n,r,s){if(!this.currentLine)throw new Error("A line must be added before mappings can be added");if(n!=null&&!this.sourcesContent.has(n))throw new Error(`Unknown source file "${n}"`);if(e==null)throw new Error("The column in the generated code must be provided");if(e{e.set(u,d),n.push(u),r.push(this.sourcesContent.get(u)||null)});let s="",i=0,o=0,a=0,c=0;return this.lines.forEach(u=>{i=0,s+=u.map(d=>{let p=Ew(d.col0-i);return i=d.col0,d.sourceUrl!=null&&(p+=Ew(e.get(d.sourceUrl)-o),o=e.get(d.sourceUrl),p+=Ew(d.sourceLine0-a),a=d.sourceLine0,p+=Ew(d.sourceCol0-c),c=d.sourceCol0),p}).join(","),s+=";"}),s=s.slice(0,-1),{file:this.file||"",version:w7,sourceRoot:"",sources:n,sourcesContent:r,mappings:s}}toJsComment(){return this.hasMappings?"//"+E7+x7(JSON.stringify(this,null,0)):""}};function x7(t){let e="",n=y7(t);for(let r=0;r>2),e+=fv((s&3)<<4|(i===null?0:i>>4)),e+=i===null?"=":fv((i&15)<<2|(o===null?0:o>>6)),e+=i===null||o===null?"=":fv(o&63)}return e}function Ew(t){t=t<0?(-t<<1)+1:t<<1;let e="";do{let n=t&31;t=t>>5,t>0&&(n=n|32),e+=fv(n)}while(t>0);return e}var S7="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function fv(t){if(t<0||t>=64)throw new Error("Can only encode value in the range [0, 63]");return S7[t]}var C7=/'|\\|\n|\r|\$/g,T7=/^[$A-Z_][0-9A-Z_$]*$/i,A1=" ",Gw=class{constructor(e){l(this,"indent");l(this,"partsLength",0);l(this,"parts",[]);l(this,"srcSpans",[]);this.indent=e}},M1=class t{constructor(e){l(this,"_indent");l(this,"_lines");this._indent=e,this._lines=[new Gw(e)]}static createRoot(){return new t(0)}get _currentLine(){return this._lines[this._lines.length-1]}println(e,n=""){this.print(e||null,n,!0)}lineIsEmpty(){return this._currentLine.parts.length===0}lineLength(){return this._currentLine.indent*A1.length+this._currentLine.partsLength}print(e,n,r=!1){n.length>0&&(this._currentLine.parts.push(n),this._currentLine.partsLength+=n.length,this._currentLine.srcSpans.push(e&&e.sourceSpan||null)),r&&this._lines.push(new Gw(this._indent))}removeEmptyLastLine(){this.lineIsEmpty()&&this._lines.pop()}incIndent(){this._indent++,this.lineIsEmpty()&&(this._currentLine.indent=this._indent)}decIndent(){this._indent--,this.lineIsEmpty()&&(this._currentLine.indent=this._indent)}toSource(){return this.sourceLines.map(e=>e.parts.length>0?eL(e.indent)+e.parts.join(""):"").join(` +`)}toSourceMapGenerator(e,n=0){let r=new k1(e),s=!1,i=()=>{s||(r.addSource(e," ").addMapping(0,e,0,0),s=!0)};for(let o=0;o{r.addLine();let c=o.srcSpans,u=o.parts,d=o.indent*A1.length,p=0;for(;ps)return r.srcSpans[i];s-=o.length}}return null}get sourceLines(){return this._lines.length&&this._lines[this._lines.length-1].parts.length===0?this._lines.slice(0,-1):this._lines}},P1=class{constructor(e){l(this,"_escapeDollarInStrings");this._escapeDollarInStrings=e}printLeadingComments(e,n){if(e.leadingComments!==void 0)for(let r of e.leadingComments)r instanceof Uw?n.print(e,`/*${r.toString()}*/`,r.trailingNewline):r.multiline?n.print(e,`/* ${r.text} */`,r.trailingNewline):r.text.split(` +`).forEach(s=>{n.println(e,`// ${s}`)})}visitExpressionStmt(e,n){return this.printLeadingComments(e,n),e.expr.visitExpression(this,n),n.println(e,";"),null}visitReturnStmt(e,n){return this.printLeadingComments(e,n),n.print(e,"return "),e.value.visitExpression(this,n),n.println(e,";"),null}visitIfStmt(e,n){this.printLeadingComments(e,n),n.print(e,"if ("),e.condition.visitExpression(this,n),n.print(e,") {");let r=e.falseCase!=null&&e.falseCase.length>0;return e.trueCase.length<=1&&!r?(n.print(e," "),this.visitAllStatements(e.trueCase,n),n.removeEmptyLastLine(),n.print(e," ")):(n.println(),n.incIndent(),this.visitAllStatements(e.trueCase,n),n.decIndent(),r&&(n.println(e,"} else {"),n.incIndent(),this.visitAllStatements(e.falseCase,n),n.decIndent())),n.println(e,"}"),null}visitWriteVarExpr(e,n){let r=n.lineIsEmpty();return r||n.print(e,"("),n.print(e,`${e.name} = `),e.value.visitExpression(this,n),r||n.print(e,")"),null}visitWriteKeyExpr(e,n){let r=n.lineIsEmpty();return r||n.print(e,"("),e.receiver.visitExpression(this,n),n.print(e,"["),e.index.visitExpression(this,n),n.print(e,"] = "),e.value.visitExpression(this,n),r||n.print(e,")"),null}visitWritePropExpr(e,n){let r=n.lineIsEmpty();return r||n.print(e,"("),e.receiver.visitExpression(this,n),n.print(e,`.${e.name} = `),e.value.visitExpression(this,n),r||n.print(e,")"),null}visitInvokeFunctionExpr(e,n){let r=e.fn instanceof Eu;return r&&n.print(e.fn,"("),e.fn.visitExpression(this,n),r&&n.print(e.fn,")"),n.print(e,"("),this.visitAllExpressions(e.args,n,","),n.print(e,")"),null}visitTaggedTemplateLiteralExpr(e,n){return e.tag.visitExpression(this,n),e.template.visitExpression(this,n),null}visitTemplateLiteralExpr(e,n){n.print(e,"`");for(let r=0;r{n.print(e,`${uu(r.key,this._escapeDollarInStrings,r.quoted)}:`),r.value.visitExpression(this,n)},e.entries,n,","),n.print(e,"}"),null}visitCommaExpr(e,n){return n.print(e,"("),this.visitAllExpressions(e.parts,n,","),n.print(e,")"),null}visitAllExpressions(e,n,r){this.visitAllObjects(s=>s.visitExpression(this,n),e,n,r)}visitAllObjects(e,n,r,s){let i=!1;for(let o=0;o0&&(r.lineLength()>80?(r.print(null,s,!0),i||(r.incIndent(),r.incIndent(),i=!0)):r.print(null,s,!1)),e(n[o]);i&&(r.decIndent(),r.decIndent())}visitAllStatements(e,n){e.forEach(r=>r.visitStatement(this,n))}};function uu(t,e,n=!0){if(t==null)return null;let r=t.replace(C7,(...i)=>i[0]=="$"?e?"\\$":"$":i[0]==` +`?"\\n":i[0]=="\r"?"\\r":`\\${i[0]}`);return n||!T7.test(r)?`'${r}'`:r}function eL(t){let e="";for(let n=0;nr.value));return e?xo([],n):n}function Y_(t,e){return{expression:t,forwardRef:e}}function k7({expression:t,forwardRef:e}){switch(e){case 0:case 1:return t;case 2:return A7(t)}}function A7(t){return Xe(y.forwardRef).callFn([xo([],t)])}var Mv;(function(t){t[t.Class=0]="Class",t[t.Function=1]="Function"})(Mv||(Mv={}));function lu(t){let e=Rt("__ngFactoryType__"),n=null,r=nL(t)?e:new sn(Ye.Or,e,t.type.value),s=null;t.deps!==null?t.deps!=="invalid"&&(s=new Dv(r,tL(t.deps,t.target))):(n=Rt(`\u0275${t.name}_BaseFactory`),s=n.callFn([r]));let i=[],o=null;function a(u){let d=Rt("__ngConditionalFactory__");i.push(d.set(kv).toDeclStmt());let p=s!==null?d.set(s).toStmt():Xe(y.invalidFactory).callFn([]).toStmt();return i.push(ex(e,[p],[d.set(u).toStmt()])),d}if(nL(t)){let u=tL(t.delegateDeps,t.target),d=new(t.delegateType===Mv.Class?Dv:ei)(t.delegate,u);o=a(d)}else F7(t)?o=a(t.expression):o=s;if(o===null)i.push(Xe(y.invalidFactory).callFn([]).toStmt());else if(n!==null){let u=Xe(y.getInheritedFactory).callFn([t.type.value]),d=new sn(Ye.Or,n,n.set(u));i.push(new gs(d.callFn([r])))}else i.push(new gs(o));let c=sc([new zr(e.name,fy)],i,zi,void 0,`${t.name}_Factory`);return n!==null&&(c=xo([],[new ys(n.name),new gs(c)]).callFn([],void 0,!0)),{expression:c,statements:[],type:M7(t)}}function M7(t){let e=t.deps!==null&&t.deps!=="invalid"?N7(t.deps):sa;return is(Xe(y.FactoryDeclaration,[tx(t.type.type,t.typeArgumentCount),e]))}function tL(t,e){return t.map((n,r)=>P7(n,e,r))}function P7(t,e,n){if(t.token===null)return Xe(y.invalidFactoryDep).callFn([Y(n)]);if(t.attributeNameType===null){let r=0|(t.self?2:0)|(t.skipSelf?4:0)|(t.host?1:0)|(t.optional?8:0)|(e===Jo.Pipe?16:0),s=r!==0||t.optional?Y(r):null,i=[t.token];s&&i.push(s);let o=L7(e);return Xe(o).callFn(i)}else return Xe(y.injectAttribute).callFn([t.token])}function N7(t){let e=!1,n=t.map(r=>{let s=R7(r);return s!==null?(e=!0,s):Y(null)});return e?is(fn(n)):sa}function R7(t){let e=[];return t.attributeNameType!==null&&e.push({key:"attribute",value:t.attributeNameType,quoted:!1}),t.optional&&e.push({key:"optional",value:Y(!0),quoted:!1}),t.host&&e.push({key:"host",value:Y(!0),quoted:!1}),t.self&&e.push({key:"self",value:Y(!0),quoted:!1}),t.skipSelf&&e.push({key:"skipSelf",value:Y(!0),quoted:!1}),e.length>0?Ms(e):null}function nL(t){return t.delegateType!==void 0}function F7(t){return t.expression!==void 0}function L7(t){switch(t){case Jo.Component:case Jo.Directive:case Jo.Pipe:return y.directiveInject;case Jo.NgModule:case Jo.Injectable:default:return y.inject}}var Pv=class{constructor(e,n,r,s){l(this,"input");l(this,"errLocation");l(this,"ctxLocation");l(this,"message");this.input=n,this.errLocation=r,this.ctxLocation=s,this.message=`Parser Error: ${e} ${r} [${n}] in ${s}`}},Su=class{constructor(e,n){l(this,"start");l(this,"end");this.start=e,this.end=n}toAbsolute(e){return new bi(e+this.start,e+this.end)}},Qn=class{constructor(e,n){l(this,"span");l(this,"sourceSpan");this.span=e,this.sourceSpan=n}toString(){return"AST"}},Cf=class extends Qn{constructor(n,r,s){super(n,r);l(this,"nameSpan");this.nameSpan=s}},Xs=class extends Qn{visit(e,n=null){}},Yi=class extends Qn{visit(e,n=null){return e.visitImplicitReceiver(this,n)}},Cu=class extends Yi{visit(e,n=null){return e.visitThisReceiver?.(this,n)}},Tf=class extends Qn{constructor(n,r,s){super(n,r);l(this,"expressions");this.expressions=s}visit(n,r=null){return n.visitChain(this,r)}},Zw=class extends Qn{constructor(n,r,s,i,o){super(n,r);l(this,"condition");l(this,"trueExp");l(this,"falseExp");this.condition=s,this.trueExp=i,this.falseExp=o}visit(n,r=null){return n.visitConditional(this,r)}},Tu=class extends Cf{constructor(n,r,s,i,o){super(n,r,s);l(this,"receiver");l(this,"name");this.receiver=i,this.name=o}visit(n,r=null){return n.visitPropertyRead(this,r)}},Yw=class extends Cf{constructor(n,r,s,i,o,a){super(n,r,s);l(this,"receiver");l(this,"name");l(this,"value");this.receiver=i,this.name=o,this.value=a}visit(n,r=null){return n.visitPropertyWrite(this,r)}},Xw=class extends Cf{constructor(n,r,s,i,o){super(n,r,s);l(this,"receiver");l(this,"name");this.receiver=i,this.name=o}visit(n,r=null){return n.visitSafePropertyRead(this,r)}},Nv=class extends Qn{constructor(n,r,s,i){super(n,r);l(this,"receiver");l(this,"key");this.receiver=s,this.key=i}visit(n,r=null){return n.visitKeyedRead(this,r)}},Qw=class extends Qn{constructor(n,r,s,i){super(n,r);l(this,"receiver");l(this,"key");this.receiver=s,this.key=i}visit(n,r=null){return n.visitSafeKeyedRead(this,r)}},Kw=class extends Qn{constructor(n,r,s,i,o){super(n,r);l(this,"receiver");l(this,"key");l(this,"value");this.receiver=s,this.key=i,this.value=o}visit(n,r=null){return n.visitKeyedWrite(this,r)}},Jw=class extends Cf{constructor(n,r,s,i,o,a){super(n,r,a);l(this,"exp");l(this,"name");l(this,"args");this.exp=s,this.name=i,this.args=o}visit(n,r=null){return n.visitPipe(this,r)}},ji=class extends Qn{constructor(n,r,s){super(n,r);l(this,"value");this.value=s}visit(n,r=null){return n.visitLiteralPrimitive(this,r)}},eE=class extends Qn{constructor(n,r,s){super(n,r);l(this,"expressions");this.expressions=s}visit(n,r=null){return n.visitLiteralArray(this,r)}},tE=class extends Qn{constructor(n,r,s,i){super(n,r);l(this,"keys");l(this,"values");this.keys=s,this.values=i}visit(n,r=null){return n.visitLiteralMap(this,r)}},my=class extends Qn{constructor(n,r,s,i){super(n,r);l(this,"strings");l(this,"expressions");this.strings=s,this.expressions=i}visit(n,r=null){return n.visitInterpolation(this,r)}},vo=class extends Qn{constructor(n,r,s,i,o){super(n,r);l(this,"operation");l(this,"left");l(this,"right");this.operation=s,this.left=i,this.right=o}visit(n,r=null){return n.visitBinary(this,r)}},Rv=class t extends vo{constructor(n,r,s,i,o,a,c){super(n,r,o,a,c);l(this,"operator");l(this,"expr");l(this,"left",null);l(this,"right",null);l(this,"operation",null);this.operator=s,this.expr=i}static createMinus(n,r,s){return new t(n,r,"-",s,"-",new ji(n,r,0),s)}static createPlus(n,r,s){return new t(n,r,"+",s,"-",s,new ji(n,r,0))}visit(n,r=null){return n.visitUnary!==void 0?n.visitUnary(this,r):n.visitBinary(this,r)}},nE=class extends Qn{constructor(n,r,s){super(n,r);l(this,"expression");this.expression=s}visit(n,r=null){return n.visitPrefixNot(this,r)}},rE=class extends Qn{constructor(n,r,s){super(n,r);l(this,"expression");this.expression=s}visit(n,r=null){return n.visitTypeofExpression(this,r)}},Fv=class extends Qn{constructor(n,r,s){super(n,r);l(this,"expression");this.expression=s}visit(n,r=null){return n.visitNonNullAssert(this,r)}},Lv=class extends Qn{constructor(n,r,s,i,o){super(n,r);l(this,"receiver");l(this,"args");l(this,"argumentSpan");this.receiver=s,this.args=i,this.argumentSpan=o}visit(n,r=null){return n.visitCall(this,r)}},sE=class extends Qn{constructor(n,r,s,i,o){super(n,r);l(this,"receiver");l(this,"args");l(this,"argumentSpan");this.receiver=s,this.args=i,this.argumentSpan=o}visit(n,r=null){return n.visitSafeCall(this,r)}},Ov=class extends Qn{constructor(n,r,s,i){super(n,r);l(this,"elements");l(this,"expressions");this.elements=s,this.expressions=i}visit(n,r){return n.visitTemplateLiteral(this,r)}},iE=class extends Qn{constructor(n,r,s){super(n,r);l(this,"text");this.text=s}visit(n,r){return n.visitTemplateLiteralElement(this,r)}},bi=class{constructor(e,n){l(this,"start");l(this,"end");this.start=e,this.end=n}},qi=class extends Qn{constructor(n,r,s,i,o){super(new Su(0,r===null?0:r.length),new bi(i,r===null?i:i+r.length));l(this,"ast");l(this,"source");l(this,"location");l(this,"errors");this.ast=n,this.source=r,this.location=s,this.errors=o}visit(n,r=null){return n.visitASTWithSource?n.visitASTWithSource(this,r):this.ast.visit(n,r)}toString(){return`${this.source} in ${this.location}`}},Bv=class{constructor(e,n,r){l(this,"sourceSpan");l(this,"key");l(this,"value");this.sourceSpan=e,this.key=n,this.value=r}},N1=class{constructor(e,n,r){l(this,"sourceSpan");l(this,"key");l(this,"value");this.sourceSpan=e,this.key=n,this.value=r}},oE=class{visit(e,n){e.visit(this,n)}visitUnary(e,n){this.visit(e.expr,n)}visitBinary(e,n){this.visit(e.left,n),this.visit(e.right,n)}visitChain(e,n){this.visitAll(e.expressions,n)}visitConditional(e,n){this.visit(e.condition,n),this.visit(e.trueExp,n),this.visit(e.falseExp,n)}visitPipe(e,n){this.visit(e.exp,n),this.visitAll(e.args,n)}visitImplicitReceiver(e,n){}visitThisReceiver(e,n){}visitInterpolation(e,n){this.visitAll(e.expressions,n)}visitKeyedRead(e,n){this.visit(e.receiver,n),this.visit(e.key,n)}visitKeyedWrite(e,n){this.visit(e.receiver,n),this.visit(e.key,n),this.visit(e.value,n)}visitLiteralArray(e,n){this.visitAll(e.expressions,n)}visitLiteralMap(e,n){this.visitAll(e.values,n)}visitLiteralPrimitive(e,n){}visitPrefixNot(e,n){this.visit(e.expression,n)}visitTypeofExpression(e,n){this.visit(e.expression,n)}visitNonNullAssert(e,n){this.visit(e.expression,n)}visitPropertyRead(e,n){this.visit(e.receiver,n)}visitPropertyWrite(e,n){this.visit(e.receiver,n),this.visit(e.value,n)}visitSafePropertyRead(e,n){this.visit(e.receiver,n)}visitSafeKeyedRead(e,n){this.visit(e.receiver,n),this.visit(e.key,n)}visitCall(e,n){this.visit(e.receiver,n),this.visitAll(e.args,n)}visitSafeCall(e,n){this.visit(e.receiver,n),this.visitAll(e.args,n)}visitTemplateLiteral(e,n){for(let r=0;rs!==null);e1(n,r)}visitTriggers(n,r,s){e1(s,n.map(i=>r[i]))}},pE=class extends Ki{constructor(n,r,s,i,o,a,c){super(c,i,o,a);l(this,"expression");l(this,"cases");l(this,"unknownBlocks");this.expression=n,this.cases=r,this.unknownBlocks=s}visit(n){return n.visitSwitchBlock(this)}},jv=class extends Ki{constructor(n,r,s,i,o,a,c){super(a,s,i,o);l(this,"expression");l(this,"children");l(this,"i18n");this.expression=n,this.children=r,this.i18n=c}visit(n){return n.visitSwitchBlockCase(this)}},If=class extends Ki{constructor(n,r,s,i,o,a,c,u,d,p,f,h,m){super(h,u,p,f);l(this,"item");l(this,"expression");l(this,"trackBy");l(this,"trackKeywordSpan");l(this,"contextVariables");l(this,"children");l(this,"empty");l(this,"mainBlockSpan");l(this,"i18n");this.item=n,this.expression=r,this.trackBy=s,this.trackKeywordSpan=i,this.contextVariables=o,this.children=a,this.empty=c,this.mainBlockSpan=d,this.i18n=m}visit(n){return n.visitForLoopBlock(this)}},Uv=class extends Ki{constructor(n,r,s,i,o,a){super(o,r,s,i);l(this,"children");l(this,"i18n");this.children=n,this.i18n=a}visit(n){return n.visitForLoopBlockEmpty(this)}},fE=class extends Ki{constructor(n,r,s,i,o){super(o,r,s,i);l(this,"branches");this.branches=n}visit(n){return n.visitIfBlock(this)}},mu=class extends Ki{constructor(n,r,s,i,o,a,c,u){super(c,i,o,a);l(this,"expression");l(this,"children");l(this,"expressionAlias");l(this,"i18n");this.expression=n,this.children=r,this.expressionAlias=s,this.i18n=u}visit(n){return n.visitIfBlockBranch(this)}},hE=class{constructor(e,n,r){l(this,"name");l(this,"sourceSpan");l(this,"nameSpan");this.name=e,this.sourceSpan=n,this.nameSpan=r}visit(e){return e.visitUnknownBlock(this)}},X_=class{constructor(e,n,r,s,i){l(this,"name");l(this,"value");l(this,"sourceSpan");l(this,"nameSpan");l(this,"valueSpan");this.name=e,this.value=n,this.sourceSpan=r,this.nameSpan=s,this.valueSpan=i}visit(e){return e.visitLetDeclaration(this)}},Ei=class{constructor(e,n,r,s,i,o,a,c,u,d,p,f){l(this,"tagName");l(this,"attributes");l(this,"inputs");l(this,"outputs");l(this,"templateAttrs");l(this,"children");l(this,"references");l(this,"variables");l(this,"sourceSpan");l(this,"startSourceSpan");l(this,"endSourceSpan");l(this,"i18n");this.tagName=e,this.attributes=n,this.inputs=r,this.outputs=s,this.templateAttrs=i,this.children=o,this.references=a,this.variables=c,this.sourceSpan=u,this.startSourceSpan=d,this.endSourceSpan=p,this.i18n=f}visit(e){return e.visitTemplate(this)}},kf=class{constructor(e,n,r,s,i){l(this,"selector");l(this,"attributes");l(this,"children");l(this,"sourceSpan");l(this,"i18n");l(this,"name","ng-content");this.selector=e,this.attributes=n,this.children=r,this.sourceSpan=s,this.i18n=i}visit(e){return e.visitContent(this)}},ic=class{constructor(e,n,r,s,i){l(this,"name");l(this,"value");l(this,"sourceSpan");l(this,"keySpan");l(this,"valueSpan");this.name=e,this.value=n,this.sourceSpan=r,this.keySpan=s,this.valueSpan=i}visit(e){return e.visitVariable(this)}},qv=class{constructor(e,n,r,s,i){l(this,"name");l(this,"value");l(this,"sourceSpan");l(this,"keySpan");l(this,"valueSpan");this.name=e,this.value=n,this.sourceSpan=r,this.keySpan=s,this.valueSpan=i}visit(e){return e.visitReference(this)}},kO=class{constructor(e,n,r,s){l(this,"vars");l(this,"placeholders");l(this,"sourceSpan");l(this,"i18n");this.vars=e,this.placeholders=n,this.sourceSpan=r,this.i18n=s}visit(e){return e.visitIcu(this)}};function e1(t,e){let n=[];if(t.visit)for(let r of e)t.visit(r)||r.visit(t);else for(let r of e){let s=r.visit(t);s&&n.push(s)}return n}var As=class{constructor(e,n,r,s,i,o){l(this,"nodes");l(this,"placeholders");l(this,"placeholderToMessage");l(this,"meaning");l(this,"description");l(this,"customId");l(this,"sources");l(this,"id");l(this,"legacyIds",[]);l(this,"messageString");this.nodes=e,this.placeholders=n,this.placeholderToMessage=r,this.meaning=s,this.description=i,this.customId=o,this.id=this.customId,this.messageString=B7(this.nodes),e.length?this.sources=[{filePath:e[0].sourceSpan.start.file.url,startLine:e[0].sourceSpan.start.line+1,startCol:e[0].sourceSpan.start.col+1,endLine:e[e.length-1].sourceSpan.end.line+1,endCol:e[0].sourceSpan.start.col+1}]:this.sources=[]}},av=class{constructor(e,n){l(this,"value");l(this,"sourceSpan");this.value=e,this.sourceSpan=n}visit(e,n){return e.visitText(this,n)}},Ya=class{constructor(e,n){l(this,"children");l(this,"sourceSpan");this.children=e,this.sourceSpan=n}visit(e,n){return e.visitContainer(this,n)}},mE=class{constructor(e,n,r,s,i){l(this,"expression");l(this,"type");l(this,"cases");l(this,"sourceSpan");l(this,"expressionPlaceholder");this.expression=e,this.type=n,this.cases=r,this.sourceSpan=s,this.expressionPlaceholder=i}visit(e,n){return e.visitIcu(this,n)}},oc=class{constructor(e,n,r,s,i,o,a,c,u){l(this,"tag");l(this,"attrs");l(this,"startName");l(this,"closeName");l(this,"children");l(this,"isVoid");l(this,"sourceSpan");l(this,"startSourceSpan");l(this,"endSourceSpan");this.tag=e,this.attrs=n,this.startName=r,this.closeName=s,this.children=i,this.isVoid=o,this.sourceSpan=a,this.startSourceSpan=c,this.endSourceSpan=u}visit(e,n){return e.visitTagPlaceholder(this,n)}},Wv=class{constructor(e,n,r){l(this,"value");l(this,"name");l(this,"sourceSpan");this.value=e,this.name=n,this.sourceSpan=r}visit(e,n){return e.visitPlaceholder(this,n)}},Af=class{constructor(e,n,r){l(this,"value");l(this,"name");l(this,"sourceSpan");l(this,"previousMessage");this.value=e,this.name=n,this.sourceSpan=r}visit(e,n){return e.visitIcuPlaceholder(this,n)}},ac=class{constructor(e,n,r,s,i,o,a,c){l(this,"name");l(this,"parameters");l(this,"startName");l(this,"closeName");l(this,"children");l(this,"sourceSpan");l(this,"startSourceSpan");l(this,"endSourceSpan");this.name=e,this.parameters=n,this.startName=r,this.closeName=s,this.children=i,this.sourceSpan=o,this.startSourceSpan=a,this.endSourceSpan=c}visit(e,n){return e.visitBlockPlaceholder(this,n)}};function B7(t){let e=new W1;return t.map(r=>r.visit(e)).join("")}var W1=class{visitText(e){return e.value}visitContainer(e){return e.children.map(n=>n.visit(this)).join("")}visitIcu(e){let n=Object.keys(e.cases).map(r=>`${r} {${e.cases[r].visit(this)}}`);return`{${e.expressionPlaceholder}, ${e.type}, ${n.join(" ")}}`}visitTagPlaceholder(e){let n=e.children.map(r=>r.visit(this)).join("");return`{$${e.startName}}${n}{$${e.closeName}}`}visitPlaceholder(e){return`{$${e.name}}`}visitIcuPlaceholder(e){return`{$${e.name}}`}visitBlockPlaceholder(e){let n=e.children.map(r=>r.visit(this)).join("");return`{$${e.startName}}${n}{$${e.closeName}}`}};var $7=class{visitTag(e){let n=this._serializeAttributes(e.attrs);if(e.children.length==0)return`<${e.name}${n}/>`;let r=e.children.map(s=>s.visit(this));return`<${e.name}${n}>${r.join("")}`}visitText(e){return e.value}visitDeclaration(e){return``}_serializeAttributes(e){let n=Object.keys(e).map(r=>`${r}="${e[r]}"`).join(" ");return n.length>0?" "+n:""}visitDoctype(e){return``}},E0e=new $7;function V7(t){return t.toUpperCase().replace(/[^A-Z0-9_]/g,"_")}var AO="i18n",z1="i18n-",H7="VAR_";function MO(t){return t===AO||t.startsWith(z1)}function j7(t){return t.attrs.some(e=>MO(e.name))}function PO(t){return t.nodes[0]}function Q_(t={},e){let n={};return t&&Object.keys(t).length&&Object.keys(t).forEach(r=>n[gy(r,e)]=t[r]),n}function gy(t,e=!0){let n=V7(t);if(!e)return n;let r=n.split("_");if(r.length===1)return t.toLowerCase();let s;/^\d+$/.test(r[r.length-1])&&(s=r.pop());let i=r.shift().toLowerCase();return r.length&&(i+=r.map(o=>o.charAt(0).toUpperCase()+o.slice(1).toLowerCase()).join("")),s?`${i}_${s}`:i}var U7=/[-.]/,K_="_t",zv="ctx",J_="rf";function NO(t,e){let n=null;return()=>(n||(t(new ys(K_,void 0,fy)),n=Rt(e)),n)}function lf(t){return Array.isArray(t)?fn(t.map(lf)):Y(t,zi)}function sL(t,e){let n=Object.getOwnPropertyNames(t);return n.length===0?null:Ms(n.map(r=>{let s=t[r],i,o,a,c;if(typeof s=="string")i=r,a=r,o=s,c=lf(o);else{a=r,i=s.classPropertyName,o=s.bindingPropertyName;let u=o!==i,d=s.transformFunction!==null,p=af.None;if(s.isSignal&&(p|=af.SignalBased),d&&(p|=af.HasDecoratorInputTransform),e&&(u||d||p!==af.None)){let f=[Y(p),lf(o)];(u||d)&&(f.push(lf(i)),d&&f.push(s.transformFunction)),c=fn(f)}else c=lf(o)}return{key:a,quoted:U7.test(a),value:c}}))}var lc=class{constructor(){l(this,"values",[])}set(e,n){if(n){let r=this.values.find(s=>s.key===e);r?r.value=n:this.values.push({key:e,value:n,quoted:!1})}}toLiteralMap(){return Ms(this.values)}};function q7(t){let e=t instanceof oa?t.name:"ng-template",n=W7(t),r=new yf,s=vs(e)[1];return r.setElement(s),Object.getOwnPropertyNames(n).forEach(i=>{let o=vs(i)[1],a=n[i];r.addAttribute(o,a),i.toLowerCase()==="class"&&a.trim().split(/\s+/).forEach(u=>r.addClassName(u))}),r}function W7(t){let e={};return t instanceof Ei&&t.tagName!=="ng-template"?t.templateAttrs.forEach(n=>e[n.name]=""):(t.attributes.forEach(n=>{MO(n.name)||(e[n.name]=n.value)}),t.inputs.forEach(n=>{(n.type===Rn.Property||n.type===Rn.TwoWay)&&(e[n.name]="")}),t.outputs.forEach(n=>{e[n.name]=""})),e}function iL(t,e){let n=null,r={name:t.name,type:t.type,typeArgumentCount:t.typeArgumentCount,deps:[],target:Jo.Injectable};if(t.useClass!==void 0){let a=t.useClass.expression.isEquivalent(t.type.value),c;t.deps!==void 0&&(c=t.deps),c!==void 0?n=lu({...r,delegate:t.useClass.expression,delegateDeps:c,delegateType:Mv.Class}):a?n=lu(r):n={statements:[],expression:oL(t.type.value,t.useClass.expression,e)}}else t.useFactory!==void 0?t.deps!==void 0?n=lu({...r,delegate:t.useFactory,delegateDeps:t.deps||[],delegateType:Mv.Function}):n={statements:[],expression:xo([],t.useFactory.callFn([]))}:t.useValue!==void 0?n=lu({...r,expression:t.useValue.expression}):t.useExisting!==void 0?n=lu({...r,expression:Xe(y.inject).callFn([t.useExisting.expression])}):n={statements:[],expression:oL(t.type.value,t.type.value,e)};let s=t.type.value,i=new lc;return i.set("token",s),i.set("factory",n.expression),t.providedIn.expression.value!==null&&i.set("providedIn",k7(t.providedIn)),{expression:Xe(y.\u0275\u0275defineInjectable).callFn([i.toLiteralMap()],void 0,!0),type:z7(t),statements:n.statements}}function z7(t){return new Zi(Xe(y.InjectableDeclaration,[tx(t.type.type,t.typeArgumentCount)]))}function oL(t,e,n){if(t.node===e.node)return e.prop("\u0275fac");if(!n)return aL(e);let r=Xe(y.resolveForwardRef).callFn([e]);return aL(r)}function aL(t){let e=new zr("__ngFactoryType__",fy);return xo([e],t.prop("\u0275fac").callFn([Rt(e.name)]))}var G7=[/@/,/^\s*$/,/[<>]/,/^[{}]$/,/&(#|[a-z])/i,/^\/\//];function Z7(t,e){if(e!=null&&!(Array.isArray(e)&&e.length==2))throw new Error(`Expected '${t}' to be an array, [start, end].`);if(e!=null){let n=e[0],r=e[1];G7.forEach(s=>{if(s.test(n)||s.test(r))throw new Error(`['${n}', '${r}'] contains unusable interpolation symbol.`)})}}var gE=class t{constructor(e,n){l(this,"start");l(this,"end");this.start=e,this.end=n}static fromArray(e){return e?(Z7("interpolation",e),new t(e[0],e[1])):ea}},ea=new gE("{{","}}"),Y7=new Set(["switch"]),rs=0,X7=8,eI=9,gu=10,RO=11,FO=12,tI=13,LO=32,G1=33,Gv=34,OO=35,rx=36,Q7=37,vE=38,Zv=39,Xa=40,wo=41,K7=42,BO=43,Gi=44,yE=45,rf=46,qa=47,Jl=58,vi=59,cf=60,fu=61,Xl=62,lL=63,nI=48,J7=55,$O=57,Vf=65,eZ=69,tZ=70,nZ=88,sx=90,gf=91,vf=92,uf=93,rZ=94,vy=95,_u=97,sZ=98,iZ=101,rI=102,VO=110,HO=114,jO=116,UO=117,qO=118,WO=120,yy=122,bo=123,cL=124,Qs=125,zO=160,t1=64,Z1=96;function Yv(t){return t>=eI&&t<=LO||t==zO}function Ko(t){return nI<=t&&t<=$O}function Xv(t){return t>=_u&&t<=yy||t>=Vf&&t<=sx}function oZ(t){return t>=_u&&t<=rI||t>=Vf&&t<=tZ||Ko(t)}function sI(t){return t===gu||t===tI}function uL(t){return nI<=t&&t<=J7}function yv(t){return t===Zv||t===Gv||t===Z1}var Qv=class t{constructor(e,n,r,s){l(this,"file");l(this,"offset");l(this,"line");l(this,"col");this.file=e,this.offset=n,this.line=r,this.col=s}toString(){return this.offset!=null?`${this.file.url}@${this.line}:${this.col}`:this.file.url}moveBy(e){let n=this.file.content,r=n.length,s=this.offset,i=this.line,o=this.col;for(;s>0&&e<0;)if(s--,e++,n.charCodeAt(s)==gu){i--;let c=n.substring(0,s-1).lastIndexOf(String.fromCharCode(gu));o=c>0?s-c:s}else o--;for(;s0;){let a=n.charCodeAt(s);s++,e--,a==gu?(i++,o=0):o++}return new t(this.file,s,i,o)}getContext(e,n){let r=this.file.content,s=this.offset;if(s!=null){s>r.length-1&&(s=r.length-1);let i=s,o=0,a=0;for(;o0&&(s--,o++,!(r[s]==` +`&&++a==n)););for(o=0,a=0;o]${e.after}")`:this.msg}toString(){let e=this.span.details?`, ${this.span.details}`:"";return`${this.contextualMessage()}: ${this.span.start}${e}`}};function aZ(t,e,n){let r=`in ${t} ${e} in ${n}`,s=new bE("",r);return new Dt(new Qv(s,-1,-1,-1),new Qv(s,-1,-1,-1))}var lZ=0;function cZ(t){if(!t||!t.reference)return null;let e=t.reference;if(e.__anonymousType)return e.__anonymousType;if(e.__forward_ref__)return"__forward_ref__";let n=_O(e);return n.indexOf("(")>=0?(n=`anonymous_${lZ++}`,e.__anonymousType=n):n=bv(n),n}function bv(t){return t.replace(/\W/g,"_")}var dL='(this&&this.__makeTemplateObject||function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e})',Y1=class extends P1{constructor(){super(!1)}visitWrappedNodeExpr(e,n){throw new Error("Cannot emit a WrappedNodeExpr in Javascript.")}visitDeclareVarStmt(e,n){return n.print(e,`var ${e.name}`),e.value&&(n.print(e," = "),e.value.visitExpression(this,n)),n.println(e,";"),null}visitTaggedTemplateLiteralExpr(e,n){let r=e.template.elements;return e.tag.visitExpression(this,n),n.print(e,`(${dL}(`),n.print(e,`[${r.map(s=>uu(s.text,!1)).join(", ")}], `),n.print(e,`[${r.map(s=>uu(s.rawText,!1)).join(", ")}])`),e.template.expressions.forEach(s=>{n.print(e,", "),s.visitExpression(this,n)}),n.print(e,")"),null}visitTemplateLiteralExpr(e,n){n.print(e,"`");for(let r=0;r"),Array.isArray(e.body))n.println(e,"{"),n.incIndent(),this.visitAllStatements(e.body,n),n.decIndent(),n.print(e,"}");else{let r=e.body instanceof ia;r&&n.print(e,"("),e.body.visitExpression(this,n),r&&n.print(e,")")}return null}visitDeclareFunctionStmt(e,n){return n.print(e,`function ${e.name}(`),this._visitParams(e.params,n),n.println(e,") {"),n.incIndent(),this.visitAllStatements(e.statements,n),n.decIndent(),n.println(e,"}"),null}visitLocalizedString(e,n){n.print(e,`$localize(${dL}(`);let r=[e.serializeI18nHead()];for(let s=1;suu(s.cooked,!1)).join(", ")}], `),n.print(e,`[${r.map(s=>uu(s.raw,!1)).join(", ")}])`),e.expressions.forEach(s=>{n.print(e,", "),s.visitExpression(this,n)}),n.print(e,")"),null}_visitParams(e,n){this.visitAllObjects(r=>n.print(null,r.name),e,n,",")}},xw;function uZ(){if(xw===void 0){let t=gv.trustedTypes;if(xw=null,t)try{xw=t.createPolicy("angular#unsafe-jit",{createScript:e=>e})}catch{}}return xw}function dZ(t){return uZ()?.createScript(t)||t}function pL(...t){if(!gv.trustedTypes)return new Function(...t);let e=t.slice(0,-1).join(","),n=t[t.length-1],r=`(function anonymous(${e} +) { ${n} +})`,s=gv.eval(dZ(r));return s.bind===void 0?new Function(...t):(s.toString=()=>r,s.bind(gv))}var X1=class{evaluateStatements(e,n,r,s){let i=new Q1(r),o=M1.createRoot();return n.length>0&&!pZ(n[0])&&(n=[Y("use strict").toStmt(),...n]),i.visitAllStatements(n,o),i.createReturnStmt(o),this.evaluateCode(e,o,i.getArgs(),s)}evaluateCode(e,n,r,s){let i=`"use strict";${n.toSource()} +//# sourceURL=${e}`,o=[],a=[];for(let u in r)a.push(r[u]),o.push(u);if(s){let u=pL(...o.concat("return null;")).toString(),d=u.slice(0,u.indexOf("return null;")).split(` +`).length-1;i+=` +${n.toSourceMapGenerator(e,d).toJsComment()}`}let c=pL(...o.concat(i));return this.executeFunction(c,a)}executeFunction(e,n){return e(...n)}},Q1=class extends Y1{constructor(n){super();l(this,"refResolver");l(this,"_evalArgNames",[]);l(this,"_evalArgValues",[]);l(this,"_evalExportedVars",[]);this.refResolver=n}createReturnStmt(n){new gs(new ia(this._evalExportedVars.map(s=>new Sf(s,Rt(s),!1)))).visitStatement(this,n)}getArgs(){let n={};for(let r=0;r0&&e.set("imports",fn(t.imports));let n=Xe(y.defineInjector).callFn([e.toLiteralMap()],void 0,!0),r=fZ(t);return{expression:n,type:r,statements:[]}}function fZ(t){return new Zi(Xe(y.InjectorDeclaration,[new Zi(t.type.type)]))}var K1=class{constructor(e){l(this,"context");this.context=e}resolveExternalReference(e){if(e.moduleName!=="@angular/core")throw new Error(`Cannot resolve external reference to ${e.moduleName}, only references to @angular/core are supported.`);if(!this.context.hasOwnProperty(e.name))throw new Error(`No value provided for @angular/core symbol '${e.name}'.`);return this.context[e.name]}},Kv;(function(t){t[t.Inline=0]="Inline",t[t.SideEffect=1]="SideEffect",t[t.Omit=2]="Omit"})(Kv||(Kv={}));var Ga;(function(t){t[t.Global=0]="Global",t[t.Local=1]="Local"})(Ga||(Ga={}));function hZ(t){let e=[],n=new lc;if(n.set("type",t.type.value),t.kind===Ga.Global&&t.bootstrap.length>0&&n.set("bootstrap",du(t.bootstrap,t.containsForwardDecls)),t.selectorScopeMode===Kv.Inline)t.declarations.length>0&&n.set("declarations",du(t.declarations,t.containsForwardDecls)),t.imports.length>0&&n.set("imports",du(t.imports,t.containsForwardDecls)),t.exports.length>0&&n.set("exports",du(t.exports,t.containsForwardDecls));else if(t.selectorScopeMode===Kv.SideEffect){let i=vZ(t);i!==null&&e.push(i)}t.schemas!==null&&t.schemas.length>0&&n.set("schemas",fn(t.schemas.map(i=>i.value))),t.id!==null&&(n.set("id",t.id),e.push(Xe(y.registerNgModuleType).callFn([t.type.value,t.id]).toStmt()));let r=Xe(y.defineNgModule).callFn([n.toLiteralMap()],void 0,!0),s=gZ(t);return{expression:r,type:s,statements:e}}function mZ(t){let e=new lc;return e.set("type",new Ht(t.type)),t.bootstrap!==void 0&&e.set("bootstrap",new Ht(t.bootstrap)),t.declarations!==void 0&&e.set("declarations",new Ht(t.declarations)),t.imports!==void 0&&e.set("imports",new Ht(t.imports)),t.exports!==void 0&&e.set("exports",new Ht(t.exports)),t.schemas!==void 0&&e.set("schemas",new Ht(t.schemas)),t.id!==void 0&&e.set("id",new Ht(t.id)),Xe(y.defineNgModule).callFn([e.toLiteralMap()])}function gZ(t){if(t.kind===Ga.Local)return new Zi(t.type.value);let{type:e,declarations:n,exports:r,imports:s,includeImportTypes:i,publicDeclarationTypes:o}=t;return new Zi(Xe(y.NgModuleDeclaration,[new Zi(e.type),o===null?n1(n):yZ(o),i?n1(s):sa,n1(r)]))}function vZ(t){let e=new lc;if(t.kind===Ga.Global?t.declarations.length>0&&e.set("declarations",du(t.declarations,t.containsForwardDecls)):t.declarationsExpression&&e.set("declarations",t.declarationsExpression),t.kind===Ga.Global?t.imports.length>0&&e.set("imports",du(t.imports,t.containsForwardDecls)):t.importsExpression&&e.set("imports",t.importsExpression),t.kind===Ga.Global?t.exports.length>0&&e.set("exports",du(t.exports,t.containsForwardDecls)):t.exportsExpression&&e.set("exports",t.exportsExpression),t.kind===Ga.Local&&t.bootstrapExpression&&e.set("bootstrap",t.bootstrapExpression),Object.keys(e.values).length===0)return null;let n=new ei(Xe(y.setNgModuleScope),[t.type.value,e.toLiteralMap()]),r=_7(n),s=new nc([],[r.toStmt()]);return new ei(s,[]).toStmt()}function n1(t){let e=t.map(n=>hy(n.type));return t.length>0?is(fn(e)):sa}function yZ(t){let e=t.map(n=>hy(n));return t.length>0?is(fn(e)):sa}function hL(t){let e=[];e.push({key:"name",value:Y(t.pipeName),quoted:!1}),e.push({key:"type",value:t.type.value,quoted:!1}),e.push({key:"pure",value:Y(t.pure),quoted:!1}),t.isStandalone===!1&&e.push({key:"standalone",value:Y(!1),quoted:!1});let n=Xe(y.definePipe).callFn([Ms(e)],void 0,!0),r=bZ(t);return{expression:n,type:r,statements:[]}}function bZ(t){return new Zi(Xe(y.PipeDeclaration,[tx(t.type.type,t.typeArgumentCount),new Zi(new os(t.pipeName)),new Zi(new os(t.isStandalone))]))}var Jv;(function(t){t[t.Directive=0]="Directive",t[t.Pipe=1]="Pipe",t[t.NgModule=2]="NgModule"})(Jv||(Jv={}));var wZ=new Set(["inherit","initial","revert","unset","alternate","alternate-reverse","normal","reverse","backwards","both","forwards","none","paused","running","ease","ease-in","ease-in-out","ease-out","linear","step-start","step-end","end","jump-both","jump-end","jump-none","jump-start","start"]),EZ=["@media","@supports","@document","@layer","@container","@scope","@starting-style"],J1=class{constructor(){l(this,"_animationDeclarationKeyframesRe",/(^|\s+|,)(?:(?:(['"])((?:\\\\|\\\2|(?!\2).)+)\2)|(-?[A-Za-z][\w\-]*))(?=[,\s]|$)/g);l(this,"_safeSelector");l(this,"_shouldScopeIndicator")}shimCssText(e,n,r=""){let s=[];e=e.replace(RZ,a=>{if(a.match(FZ))s.push(a);else{let c=a.match(NZ);s.push((c?.join("")??"")+` +`)}return iI}),e=this._insertDirectives(e);let i=this._scopeCssText(e,n,r),o=0;return i.replace(LZ,()=>s[o++])}_insertDirectives(e){return e=this._insertPolyfillDirectivesInCssText(e),this._insertPolyfillRulesInCssText(e)}_scopeKeyframesRelatedCss(e,n){let r=new Set,s=Sw(e,i=>this._scopeLocalKeyframeDeclarations(i,n,r));return Sw(s,i=>this._scopeAnimationRule(i,n,r))}_scopeLocalKeyframeDeclarations(e,n,r){return{...e,selector:e.selector.replace(/(^@(?:-webkit-)?keyframes(?:\s+))(['"]?)(.+)\2(\s*)$/,(s,i,o,a,c)=>(r.add(vL(a,o)),`${i}${o}${n}_${a}${o}${c}`))}}_scopeAnimationKeyframe(e,n,r){return e.replace(/^(\s*)(['"]?)(.+?)\2(\s*)$/,(s,i,o,a,c)=>(a=`${r.has(vL(a,o))?n+"_":""}${a}`,`${i}${o}${a}${o}${c}`))}_scopeAnimationRule(e,n,r){let s=e.content.replace(/((?:^|\s+|;)(?:-webkit-)?animation\s*:\s*),*([^;]+)/g,(i,o,a)=>o+a.replace(this._animationDeclarationKeyframesRe,(c,u,d="",p,f)=>p?`${u}${this._scopeAnimationKeyframe(`${d}${p}${d}`,n,r)}`:wZ.has(f)?c:`${u}${this._scopeAnimationKeyframe(f,n,r)}`));return s=s.replace(/((?:^|\s+|;)(?:-webkit-)?animation-name(?:\s*):(?:\s*))([^;]+)/g,(i,o,a)=>`${o}${a.split(",").map(c=>this._scopeAnimationKeyframe(c,n,r)).join(",")}`),{...e,content:s}}_insertPolyfillDirectivesInCssText(e){return e.replace(SZ,function(...n){return n[2]+"{"})}_insertPolyfillRulesInCssText(e){return e.replace(CZ,(...n)=>{let r=n[0].replace(n[1],"").replace(n[2],"");return n[4]+r})}_scopeCssText(e,n,r){let s=this._extractUnscopedRulesFromCssText(e);return e=this._insertPolyfillHostInCssText(e),e=this._convertColonHost(e),e=this._convertColonHostContext(e),e=this._convertShadowDOMSelectors(e),n&&(e=this._scopeKeyframesRelatedCss(e,n),e=this._scopeSelectors(e,n,r)),e=e+` +`+s,e.trim()}_extractUnscopedRulesFromCssText(e){let n="",r;for(mL.lastIndex=0;(r=mL.exec(e))!==null;){let s=r[0].replace(r[2],"").replace(r[1],r[4]);n+=s+` + +`}return n}_convertColonHost(e){return e.replace(TZ,(n,r,s)=>{if(r){let i=[],o=r.split(",").map(a=>a.trim());for(let a of o){if(!a)break;let c=Ql+a.replace(wE,"")+s;i.push(c)}return i.join(",")}else return Ql+s})}_convertColonHostContext(e){let n=e.length,r=0,s=0,i="";for(let o=0;o{let s=[[]],i;for(;i=_Z.exec(n);){let o=(i[1]??"").trim().split(",").map(c=>c.trim()).filter(c=>c!==""),a=s.length;GZ(s,o.length);for(let c=0;czZ(o,n,r)).join(", ")})}_convertShadowDOMSelectors(e){return kZ.reduce((n,r)=>n.replace(r," "),e)}_scopeSelectors(e,n,r){return Sw(e,s=>{let i=s.selector,o=s.content;return s.selector[0]!=="@"?i=this._scopeSelector({selector:i,scopeSelector:n,hostSelector:r,isParentSelector:!0}):EZ.some(a=>s.selector.startsWith(a))?o=this._scopeSelectors(s.content,n,r):(s.selector.startsWith("@font-face")||s.selector.startsWith("@page"))&&(o=this._stripScopingSelectors(s.content)),new ey(i,o)})}_stripScopingSelectors(e){return Sw(e,n=>{let r=n.selector.replace(gL," ").replace(r1," ");return new ey(r,n.content)})}_scopeSelector({selector:e,scopeSelector:n,hostSelector:r,isParentSelector:s=!1}){let i=/ ?,(?!(?:[^)(]*(?:\([^)(]*(?:\([^)(]*(?:\([^)(]*\)[^)(]*)*\)[^)(]*)*\)[^)(]*)*\))) ?/;return e.split(i).map(o=>o.split(gL)).map(o=>{let[a,...c]=o;return[(d=>this._selectorNeedsScoping(d,n)?this._applySelectorScope({selector:d,scopeSelector:n,hostSelector:r,isParentSelector:s}):d)(a),...c].join(" ")}).join(", ")}_selectorNeedsScoping(e,n){return!this._makeScopeMatcher(n).test(e)}_makeScopeMatcher(e){let n=/\[/g,r=/\]/g;return e=e.replace(n,"\\[").replace(r,"\\]"),new RegExp("^("+e+")"+AZ,"m")}_applySimpleSelectorScope(e,n,r){if(df.lastIndex=0,df.test(e)){let s=`[${r}]`,i=e;for(;i.match(r1);)i=i.replace(r1,(o,a)=>a.replace(/([^:\)]*)(:*)(.*)/,(c,u,d,p)=>u+s+d+p));return i.replace(df,s)}return n+" "+e}_applySelectorScope({selector:e,scopeSelector:n,hostSelector:r,isParentSelector:s}){let i=/\[is=([^\]]*)\]/g;n=n.replace(i,(g,...v)=>v[0]);let o=`[${n}]`,a=g=>{let v=g.trim();if(!v)return g;if(g.includes(Ql)){if(v=this._applySimpleSelectorScope(g,n,r),!g.match(IZ)){let[w,b,D,B]=v.match(/([^:]*)(:*)([\s\S]*)/);v=b+o+D+B}}else{let w=g.replace(df,"");if(w.length>0){let b=w.match(/([^:]*)(:*)([\s\S]*)/);b&&(v=b[1]+o+b[2]+b[3])}}return v},c=g=>{let v="",w=[],b;for(;(b=lv.exec(g))!==null;){let D=1,B=lv.lastIndex;for(;B{let[B]=D.match(lv)??[],M=D.slice(B?.length,-1);M.includes(Ql)&&(this._shouldScopeIndicator=!0);let $=this._scopeSelector({selector:M,scopeSelector:n,hostSelector:r});return`${B}${$})`}).join(""):(this._shouldScopeIndicator=this._shouldScopeIndicator||g.includes(Ql),v=this._shouldScopeIndicator?a(g):g),v};s&&(this._safeSelector=new e_(e),e=this._safeSelector.content());let u="",d=0,p,f=/( |>|\+|~(?!=))(?!([^)(]*(?:\([^)(]*(?:\([^)(]*(?:\([^)(]*\)[^)(]*)*\)[^)(]*)*\)[^)(]*)*\)))\s*/g,h=e.includes(Ql);for((s||this._shouldScopeIndicator)&&(this._shouldScopeIndicator=!h);(p=f.exec(e))!==null;){let g=p[1],v=e.slice(d,p.index);if(v.match(/__esc-ph-(\d+)__/)&&e[p.index+1]?.match(/[a-fA-F\d]/))continue;let w=c(v);u+=`${w} ${g} `,d=f.lastIndex}let m=e.substring(d);return u+=c(m),this._safeSelector.restore(u)}_insertPolyfillHostInCssText(e){return e.replace(PZ,GO).replace(MZ,wE)}},e_=class{constructor(e){l(this,"placeholders",[]);l(this,"index",0);l(this,"_content");e=this._escapeRegexMatches(e,/(\[[^\]]*\])/g),e=e.replace(/(\\.)/g,(n,r)=>{let s=`__esc-ph-${this.index}__`;return this.placeholders.push(r),this.index++,s}),this._content=e.replace(/(:nth-[-\w]+)(\([^)]+\))/g,(n,r,s)=>{let i=`__ph-${this.index}__`;return this.placeholders.push(s),this.index++,r+i})}restore(e){return e.replace(/__(?:ph|esc-ph)-(\d+)__/g,(n,r)=>this.placeholders[+r])}content(){return this._content}_escapeRegexMatches(e,n){return e.replace(n,(r,s)=>{let i=`__ph-${this.index}__`;return this.placeholders.push(s),this.index++,i})}},xZ="(:(where|is)\\()?",lv=/:(where|is)\(/gi,SZ=/polyfill-next-selector[^}]*content:[\s]*?(['"])(.*?)\1[;\s]*}([^{]*?){/gim,CZ=/(polyfill-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim,mL=/(polyfill-unscoped-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim,wE="-shadowcsshost",GO="-shadowcsscontext",ZO="(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))",TZ=new RegExp(wE+ZO+"?([^,{]*)","gim"),YO=GO+ZO+"?([^{]*)",DZ=new RegExp(`${xZ}(${YO})`,"gim"),_Z=new RegExp(YO,"im"),Ql=wE+"-no-combinator",IZ=new RegExp(`${Ql}(?![^(]*\\))`,"g"),r1=/-shadowcsshost-no-combinator([^\s,]*)/,kZ=[/::shadow/g,/::content/g,/\/shadow-deep\//g,/\/shadow\//g],gL=/(?:>>>)|(?:\/deep\/)|(?:::ng-deep)/g,AZ="([>\\s~+[.,{:][\\s\\S]*)?$",df=/-shadowcsshost/gim,MZ=/:host/gim,PZ=/:host-context/gim,NZ=/\r?\n/g,RZ=/\/\*[\s\S]*?\*\//g,FZ=/\/\*\s*#\s*source(Mapping)?URL=/g,iI="%COMMENT%",LZ=new RegExp(iI,"g"),s1="%BLOCK%",OZ=new RegExp(`(\\s*(?:${iI}\\s*)*)([^;\\{\\}]+?)(\\s*)((?:{%BLOCK%}?\\s*;?)|(?:\\s*;))`,"g"),BZ=new Map([["{","}"]]),XO="%COMMA_IN_PLACEHOLDER%",QO="%SEMI_IN_PLACEHOLDER%",KO="%COLON_IN_PLACEHOLDER%",$Z=new RegExp(XO,"g"),VZ=new RegExp(QO,"g"),HZ=new RegExp(KO,"g"),ey=class{constructor(e,n){l(this,"selector");l(this,"content");this.selector=e,this.content=n}};function Sw(t,e){let n=qZ(t),r=jZ(n,BZ,s1),s=0,i=r.escapedString.replace(OZ,(...o)=>{let a=o[2],c="",u=o[4],d="";u&&u.startsWith("{"+s1)&&(c=r.blocks[s++],u=u.substring(s1.length+1),d="{");let p=e(new ey(a,c));return`${o[1]}${p.selector}${o[3]}${d}${p.content}${u}`});return WZ(i)}var t_=class{constructor(e,n){l(this,"escapedString");l(this,"blocks");this.escapedString=e,this.blocks=n}};function jZ(t,e,n){let r=[],s=[],i=0,o=0,a=-1,c,u;for(let d=0;d0;){let o=i.length,a=t.pop();for(let c=0;cs?`${n}${o}${e}`:`${n}${o}${r}${e}, ${n}${o} ${r}${e}`).join(",")}function GZ(t,e){let n=t.length;for(let r=1;rr.isEquivalent(this.args[s]))}isConstant(){return!1}transformInternalExpressions(n,r){this.body!==null?this.body=Ve(this.body,n,r|on.InChildOperation):this.fn!==null&&(this.fn=Ve(this.fn,n,r));for(let s=0;sr.clone()));return n.fn=this.fn?.clone()??null,n.varOffset=this.varOffset,n}};Une=Hf,qne=ix;var Au=JE,Pf=class t extends Tn{constructor(n){super();l(this,"index");l(this,"kind",Qe.PureFunctionParameterExpr);this.index=n}visitExpression(){}isEquivalent(n){return n instanceof t&&n.index===this.index}isConstant(){return!0}transformInternalExpressions(){}clone(){return new t(this.index)}},Wne,zne,gI=class gI extends Tn{constructor(n,r,s,i){super();l(this,"target");l(this,"targetSlot");l(this,"name");l(this,"args");l(this,"kind",Qe.PipeBinding);l(this,Wne,!0);l(this,zne,!0);l(this,"varOffset",null);this.target=n,this.targetSlot=r,this.name=s,this.args=i}visitExpression(n,r){for(let s of this.args)s.visitExpression(n,r)}isEquivalent(){return!1}isConstant(){return!1}transformInternalExpressions(n,r){for(let s=0;sr.clone()));return n.varOffset=this.varOffset,n}};Wne=Hf,zne=ix;var Nf=gI,Gne,Zne,vI=class vI extends Tn{constructor(n,r,s,i,o){super();l(this,"target");l(this,"targetSlot");l(this,"name");l(this,"args");l(this,"numArgs");l(this,"kind",Qe.PipeBindingVariadic);l(this,Gne,!0);l(this,Zne,!0);l(this,"varOffset",null);this.target=n,this.targetSlot=r,this.name=s,this.args=i,this.numArgs=o}visitExpression(n,r){this.args.visitExpression(n,r)}isEquivalent(){return!1}isConstant(){return!1}transformInternalExpressions(n,r){this.args=Ve(this.args,n,r)}clone(){let n=new vI(this.target,this.targetSlot,this.name,this.args.clone(),this.numArgs);return n.varOffset=this.varOffset,n}};Gne=Hf,Zne=ix;var DE=vI,Rf=class t extends Tn{constructor(n,r){super();l(this,"receiver");l(this,"name");l(this,"kind",Qe.SafePropertyRead);this.receiver=n,this.name=r}get index(){return this.name}visitExpression(n,r){this.receiver.visitExpression(n,r)}isEquivalent(){return!1}isConstant(){return!1}transformInternalExpressions(n,r){this.receiver=Ve(this.receiver,n,r)}clone(){return new t(this.receiver.clone(),this.name)}},Ff=class t extends Tn{constructor(n,r,s){super(s);l(this,"receiver");l(this,"index");l(this,"kind",Qe.SafeKeyedRead);this.receiver=n,this.index=r}visitExpression(n,r){this.receiver.visitExpression(n,r),this.index.visitExpression(n,r)}isEquivalent(){return!1}isConstant(){return!1}transformInternalExpressions(n,r){this.receiver=Ve(this.receiver,n,r),this.index=Ve(this.index,n,r)}clone(){return new t(this.receiver.clone(),this.index.clone(),this.sourceSpan)}},Mu=class t extends Tn{constructor(n,r){super();l(this,"receiver");l(this,"args");l(this,"kind",Qe.SafeInvokeFunction);this.receiver=n,this.args=r}visitExpression(n,r){this.receiver.visitExpression(n,r);for(let s of this.args)s.visitExpression(n,r)}isEquivalent(){return!1}isConstant(){return!1}transformInternalExpressions(n,r){this.receiver=Ve(this.receiver,n,r);for(let s=0;sn.clone()))}},Lf=class t extends Tn{constructor(n,r){super();l(this,"guard");l(this,"expr");l(this,"kind",Qe.SafeTernaryExpr);this.guard=n,this.expr=r}visitExpression(n,r){this.guard.visitExpression(n,r),this.expr.visitExpression(n,r)}isEquivalent(){return!1}isConstant(){return!1}transformInternalExpressions(n,r){this.guard=Ve(this.guard,n,r),this.expr=Ve(this.expr,n,r)}clone(){return new t(this.guard.clone(),this.expr.clone())}},ry=class t extends Tn{constructor(){super(...arguments);l(this,"kind",Qe.EmptyExpr)}visitExpression(n,r){}isEquivalent(n){return n instanceof t}isConstant(){return!0}clone(){return new t}transformInternalExpressions(){}},Co=class t extends Tn{constructor(n,r){super();l(this,"expr");l(this,"xref");l(this,"kind",Qe.AssignTemporaryExpr);l(this,"name",null);this.expr=n,this.xref=r}visitExpression(n,r){this.expr.visitExpression(n,r)}isEquivalent(){return!1}isConstant(){return!1}transformInternalExpressions(n,r){this.expr=Ve(this.expr,n,r)}clone(){let n=new t(this.expr.clone(),this.xref);return n.name=this.name,n}},tl=class t extends Tn{constructor(n){super();l(this,"xref");l(this,"kind",Qe.ReadTemporaryExpr);l(this,"name",null);this.xref=n}visitExpression(n,r){}isEquivalent(){return this.xref===this.xref}isConstant(){return!1}transformInternalExpressions(n,r){}clone(){let n=new t(this.xref);return n.name=this.name,n}},_E=class t extends Tn{constructor(n){super();l(this,"slot");l(this,"kind",Qe.SlotLiteralExpr);this.slot=n}visitExpression(n,r){}isEquivalent(n){return n instanceof t&&n.slot===this.slot}isConstant(){return!0}clone(){return new t(this.slot)}transformInternalExpressions(){}},IE=class t extends Tn{constructor(n,r,s,i=null){super();l(this,"expr");l(this,"target");l(this,"targetSlot");l(this,"alias");l(this,"kind",Qe.ConditionalCase);this.expr=n,this.target=r,this.targetSlot=s,this.alias=i}visitExpression(n,r){this.expr!==null&&this.expr.visitExpression(n,r)}isEquivalent(n){return n instanceof t&&n.expr===this.expr}isConstant(){return!0}clone(){return new t(this.expr,this.target,this.targetSlot)}transformInternalExpressions(n,r){this.expr!==null&&(this.expr=Ve(this.expr,n,r))}},sy=class t extends Tn{constructor(n){super();l(this,"expr");l(this,"kind",Qe.ConstCollected);this.expr=n}transformInternalExpressions(n,r){this.expr=n(this.expr,r)}visitExpression(n,r){this.expr.visitExpression(n,r)}isEquivalent(n){return n instanceof t?this.expr.isEquivalent(n.expr):!1}isConstant(){return this.expr.isConstant()}clone(){return new t(this.expr)}};function bs(t,e){_r(t,(n,r)=>(e(n,r),n),on.None)}var on;(function(t){t[t.None=0]="None",t[t.InChildOperation=1]="InChildOperation"})(on||(on={}));function o1(t,e,n){for(let r=0;rVe(r,e,n));else if(t instanceof Eu)if(Array.isArray(t.body))for(let r=0;rs==="")&&(n.expression=n.expression.expressions[0])}function OY(t){for(let e of t.units)for(let n of e.ops()){if(n.kind!==E.Conditional)continue;let r,s=n.conditions.findIndex(o=>o.expr===null);if(s>=0){let o=n.conditions.splice(s,1)[0].targetSlot;r=new _E(o)}else r=Y(-1);let i=n.test==null?null:new Co(n.test,t.allocateXrefId());for(let o=n.conditions.length-1;o>=0;o--){let a=n.conditions[o];if(a.expr!==null){if(i!==null){let c=o===0?i:new tl(i.xref);a.expr=new sn(Ye.Identical,c,a.expr)}else if(a.alias!==null){let c=t.allocateXrefId();a.expr=new Co(a.expr,c),n.contextValue=new tl(c)}r=new Ka(a.expr,new _E(a.targetSlot),r)}}n.processed=r,n.conditions=[]}}var BY=new Map([["&&",Ye.And],[">",Ye.Bigger],[">=",Ye.BiggerEquals],["|",Ye.BitwiseOr],["&",Ye.BitwiseAnd],["/",Ye.Divide],["==",Ye.Equals],["===",Ye.Identical],["<",Ye.Lower],["<=",Ye.LowerEquals],["-",Ye.Minus],["%",Ye.Modulo],["*",Ye.Multiply],["!=",Ye.NotEquals],["!==",Ye.NotIdentical],["??",Ye.NullishCoalesce],["||",Ye.Or],["+",Ye.Plus]]);function cB(t){let e=new Map([["svg",Sr.SVG],["math",Sr.Math]]);return t===null?Sr.HTML:e.get(t)??Sr.HTML}function $Y(t){let e=new Map([["svg",Sr.SVG],["math",Sr.Math]]);for(let[n,r]of e.entries())if(r===t)return n;return null}function VY(t,e){return e===Sr.HTML?t:`:${$Y(e)}:${t}`}function Of(t){return Array.isArray(t)?fn(t.map(Of)):Y(t)}function HY(t){let e=new Map;for(let n of t.units)for(let r of n.create)if(r.kind===E.ExtractedAttribute){let s=e.get(r.target)||new o_(t.compatibility);e.set(r.target,s),s.add(r.bindingKind,r.name,r.expression,r.namespace,r.trustedValueFn),be.remove(r)}if(t instanceof iy)for(let n of t.units)for(let r of n.create)if(r.kind==E.Projection){let s=e.get(r.xref);if(s!==void 0){let i=a_(s);i.entries.length>0&&(r.attributes=i)}}else Pu(r)&&(r.attributes=wL(t,e,r.xref),r.kind===E.RepeaterCreate&&r.emptyView!==null&&(r.emptyAttributes=wL(t,e,r.emptyView)));else if(t instanceof PE)for(let[n,r]of e.entries()){if(n!==t.root.xref)throw new Error("An attribute would be const collected into the host binding's template function, but is not associated with the root xref.");let s=a_(r);s.entries.length>0&&(t.root.attributes=s)}}function wL(t,e,n){let r=e.get(n);if(r!==void 0){let s=a_(r);if(s.entries.length>0)return t.addConst(s)}return null}var Jp=Object.freeze([]),o_=class{constructor(e){l(this,"compatibility");l(this,"known",new Map);l(this,"byKind",new Map);l(this,"propertyBindings",null);l(this,"projectAs",null);this.compatibility=e}get attributes(){return this.byKind.get(Je.Attribute)??Jp}get classes(){return this.byKind.get(Je.ClassName)??Jp}get styles(){return this.byKind.get(Je.StyleProperty)??Jp}get bindings(){return this.propertyBindings??Jp}get template(){return this.byKind.get(Je.Template)??Jp}get i18n(){return this.byKind.get(Je.I18n)??Jp}isKnown(e,n){let r=this.known.get(e)??new Set;return this.known.set(e,r),r.has(n)?!0:(r.add(n),!1)}add(e,n,r,s,i){if(!(this.compatibility===ti.TemplateDefinitionBuilder&&(e===Je.Attribute||e===Je.ClassName||e===Je.StyleProperty))&&this.isKnown(e,n))return;if(n==="ngProjectAs"){if(r===null||!(r instanceof os)||r.value==null||typeof r.value?.toString()!="string")throw Error("ngProjectAs must have a string literal value");this.projectAs=r.value.toString()}let a=this.arrayFor(e);if(a.push(...jY(s,n)),e===Je.Attribute||e===Je.StyleProperty){if(r===null)throw Error("Attribute, i18n attribute, & style element attributes must have a value");i!==null&&nB(r)?a.push(a7(i,new _v([new Hw(r.value)],[]),void 0,r.sourceSpan)):a.push(r)}}arrayFor(e){return e===Je.Property||e===Je.TwoWayProperty?(this.propertyBindings??(this.propertyBindings=[]),this.propertyBindings):(this.byKind.has(e)||this.byKind.set(e,[]),this.byKind.get(e))}};function jY(t,e){let n=Y(e);return t?[Y(0),Y(t),n]:[n]}function a_({attributes:t,bindings:e,classes:n,i18n:r,projectAs:s,styles:i,template:o}){let a=[...t];if(s!==null){let c=z_(s)[0];a.push(Y(5),Of(c))}return n.length>0&&a.push(Y(1),...n),i.length>0&&a.push(Y(2),...i),e.length>0&&a.push(Y(3),...e),o.length>0&&a.push(Y(4),...o),r.length>0&&a.push(Y(6),...r),fn(a)}function UY(t){let e=new Map;for(let n of t.units){for(let r of n.create)r.kind===E.I18nAttributes&&e.set(r.target,r);for(let r of n.update)switch(r.kind){case E.Property:case E.Attribute:if(r.i18nContext===null||!(r.expression instanceof xr))continue;let s=e.get(r.target);if(s===void 0)throw new Error("AssertionError: An i18n attribute binding instruction requires the owning element to have an I18nAttributes create instruction");if(s.target!==r.target)throw new Error("AssertionError: Expected i18nAttributes target element to match binding target element");let i=[];for(let o=0;oiX(r,{job:t}),on.None),_r(n,oX,on.None)}function Vi(t){return t instanceof xf?Vi(t.expr):t instanceof sn?Vi(t.lhs)||Vi(t.rhs):t instanceof Ka?t.falseCase&&Vi(t.falseCase)?!0:Vi(t.condition)||Vi(t.trueCase):t instanceof Iv?Vi(t.condition):t instanceof Co?Vi(t.expr):t instanceof Si?Vi(t.receiver):t instanceof Ja?Vi(t.receiver)||Vi(t.index):t instanceof ei||t instanceof Eo||t instanceof ia||t instanceof Mu||t instanceof Nf}function eX(t){let e=new Set;return Ve(t,n=>(n instanceof Co&&e.add(n.xref),n),on.None),e}function tX(t,e,n){return Ve(t,r=>{if(r instanceof Co&&e.has(r.xref)){let s=new tl(r.xref);return n.job.compatibility===ti.TemplateDefinitionBuilder?new Co(s,s.xref):s}return r},on.None),t}function ef(t,e,n){let r;if(Vi(t)){let s=n.job.allocateXrefId();r=[new Co(t,s),new tl(s)]}else r=[t,t.clone()],tX(r[1],eX(r[0]),n);return new Lf(r[0],e(r[1]))}function nX(t){return t instanceof Rf||t instanceof Ff||t instanceof Mu}function rX(t){return t instanceof Si||t instanceof Ja||t instanceof ei}function uB(t){return nX(t)||rX(t)}function sX(t){if(uB(t)&&t.receiver instanceof Lf){let e=t.receiver;for(;e.expr instanceof Lf;)e=e.expr;return e}return null}function iX(t,e){if(!uB(t))return t;let n=sX(t);if(n){if(t instanceof ei)return n.expr=n.expr.callFn(t.args),t.receiver;if(t instanceof Si)return n.expr=n.expr.prop(t.name),t.receiver;if(t instanceof Ja)return n.expr=n.expr.key(t.index),t.receiver;if(t instanceof Mu)return n.expr=ef(n.expr,r=>r.callFn(t.args),e),t.receiver;if(t instanceof Rf)return n.expr=ef(n.expr,r=>r.prop(t.name),e),t.receiver;if(t instanceof Ff)return n.expr=ef(n.expr,r=>r.key(t.index),e),t.receiver}else{if(t instanceof Mu)return ef(t.receiver,r=>r.callFn(t.args),e);if(t instanceof Rf)return ef(t.receiver,r=>r.prop(t.name),e);if(t instanceof Ff)return ef(t.receiver,r=>r.key(t.index),e)}return t}function oX(t){return t instanceof Lf?new Ka(new sn(Ye.Equals,t.guard,kv),kv,t.expr):t}var EL="\uFFFD",aX="#",lX="*",cX="/",uX=":",dX="[",pX="]",fX="|";function hX(t){let e=new Map,n=new Map,r=new Map;for(let i of t.units)for(let o of i.create)switch(o.kind){case E.I18nContext:let a=mX(t,o);i.create.push(a),e.set(o.xref,a),r.set(o.xref,o);break;case E.I18nStart:n.set(o.xref,o);break}let s=null;for(let i of t.units)for(let o of i.create)switch(o.kind){case E.IcuStart:s=o,be.remove(o);let a=r.get(o.context);if(a.contextKind!==tc.Icu)continue;let c=n.get(a.i18nBlock);if(c.context===a.xref)continue;let u=n.get(c.root),d=e.get(u.context);if(d===void 0)throw Error("AssertionError: ICU sub-message should belong to a root message.");let p=e.get(a.xref);p.messagePlaceholder=o.messagePlaceholder,d.subMessages.push(p.xref);break;case E.IcuEnd:s=null,be.remove(o);break;case E.IcuPlaceholder:if(s===null||s.context==null)throw Error("AssertionError: Unexpected ICU placeholder outside of i18n context");e.get(s.context).postprocessingParams.set(o.name,Y(gX(o))),be.remove(o);break}}function mX(t,e,n){let r=xL(e.params),s=xL(e.postprocessingParams),i=[...e.params.values()].some(o=>o.length>1);return yY(t.allocateXrefId(),e.xref,e.i18nBlock,e.message,null,r,s,i)}function gX(t){if(t.strings.length!==t.expressionPlaceholders.length+1)throw Error(`AssertionError: Invalid ICU placeholder with ${t.strings.length} strings and ${t.expressionPlaceholders.length} expressions`);let e=t.expressionPlaceholders.map(pf);return t.strings.flatMap((n,r)=>[n,e[r]||""]).join("")}function xL(t){let e=new Map;for(let[n,r]of t){let s=vX(r);s!==null&&e.set(n,Y(s))}return e}function vX(t){if(t.length===0)return null;let e=t.map(n=>pf(n));return e.length===1?e[0]:`${dX}${e.join(fX)}${pX}`}function pf(t){if(t.flags&Cn.ElementTag&&t.flags&Cn.TemplateTag){if(typeof t.value!="object")throw Error("AssertionError: Expected i18n param value to have an element and template slot");let s=pf({...t,value:t.value.element,flags:t.flags&~Cn.TemplateTag}),i=pf({...t,value:t.value.template,flags:t.flags&~Cn.ElementTag});return t.flags&Cn.OpenTag&&t.flags&Cn.CloseTag?`${i}${s}${i}`:t.flags&Cn.CloseTag?`${s}${i}`:`${i}${s}`}if(t.flags&Cn.OpenTag&&t.flags&Cn.CloseTag)return`${pf({...t,flags:t.flags&~Cn.CloseTag})}${pf({...t,flags:t.flags&~Cn.OpenTag})}`;if(t.flags===Cn.None)return`${t.value}`;let e="",n="";t.flags&Cn.ElementTag?e=aX:t.flags&Cn.TemplateTag&&(e=lX),e!==""&&(n=t.flags&Cn.CloseTag?cX:"");let r=t.subTemplateIndex===null?"":`${uX}${t.subTemplateIndex}`;return`${EL}${n}${e}${t.value}${r}${EL}`}function yX(t){for(let e of t.units){let n=new Map;for(let s of e.create){if(jf(s)){if(s.handle.slot===null)throw new Error("AssertionError: expected slots to have been allocated before generating advance() calls")}else continue;n.set(s.xref,s.handle.slot)}let r=0;for(let s of e.update){let i=null;if(EE(s)?i=s:bs(s,a=>{i===null&&EE(a)&&(i=a)}),i===null)continue;if(!n.has(i.target))throw new Error(`AssertionError: reference to unknown slot for target ${i.target}`);let o=n.get(i.target);if(r!==o){let a=o-r;if(a<0)throw new Error("AssertionError: slot counter should never need to move backwards");be.insertBefore(nY(a,i.sourceSpan),s),r=o}}}}function bX(t){let e=t.compatibility===ti.TemplateDefinitionBuilder,n=[],r=0;for(let s of t.units)for(let i of s.create)i.kind===E.Projection&&(n.push(i.selector),i.projectionSlotIndex=r++);if(n.length>0){let s=null;if(n.length>1||n[0]!=="*"){let i=n.map(o=>o==="*"?o:z_(o));s=t.pool.getConstLiteral(Of(i),e)}t.contentSelectors=t.pool.getConstLiteral(Of(n),e),t.root.create.prepend([hY(s)])}}function wX(t){hv(t.root,null)}function hv(t,e){let n=EX(t,e);for(let r of t.create)switch(r.kind){case E.Template:hv(t.job.views.get(r.xref),n);break;case E.Projection:r.fallbackView!==null&&hv(t.job.views.get(r.fallbackView),n);break;case E.RepeaterCreate:hv(t.job.views.get(r.xref),n),r.emptyView&&hv(t.job.views.get(r.emptyView),n),r.trackByOps!==null&&r.trackByOps.prepend(Pw(t,n,!1));break;case E.Listener:case E.TwoWayListener:r.handlerOps.prepend(Pw(t,n,!0));break}t.update.prepend(Pw(t,n,!1))}function EX(t,e){let n={view:t.xref,viewContextVariable:{kind:Fr.Context,name:null,view:t.xref},contextVariables:new Map,aliases:t.aliases,references:[],letDeclarations:[],parent:e};for(let r of t.contextVariables.keys())n.contextVariables.set(r,{kind:Fr.Identifier,name:null,identifier:r,local:!1});for(let r of t.create)switch(r.kind){case E.ElementStart:case E.Template:if(!Array.isArray(r.localRefs))throw new Error("AssertionError: expected localRefs to be an array");for(let s=0;sr instanceof sy?Y(t.addConst(r.expr)):r,on.None)}var SL="style.",CL="class.",SX="style!",TL="class!",DL="!important";function CX(t){for(let e of t.root.update)if(e.kind===E.Binding&&e.bindingKind===Je.Property)if(e.name.endsWith(DL)&&(e.name=e.name.substring(0,e.name.length-DL.length)),e.name.startsWith(SL)){e.bindingKind=Je.StyleProperty,e.name=e.name.substring(SL.length),TX(e.name)||(e.name=DX(e.name));let{property:n,suffix:r}=l1(e.name);e.name=n,e.unit=r}else e.name.startsWith(SX)?(e.bindingKind=Je.StyleProperty,e.name="style"):e.name.startsWith(CL)?(e.bindingKind=Je.ClassName,e.name=l1(e.name.substring(CL.length)).property):e.name.startsWith(TL)&&(e.bindingKind=Je.ClassName,e.name=l1(e.name.substring(TL.length)).property)}function TX(t){return t.startsWith("--")}function DX(t){return t.replace(/[a-z][A-Z]/g,e=>e.charAt(0)+"-"+e.charAt(1)).toLowerCase()}function l1(t){let e=t.indexOf("!important");e!==-1&&(t=e>0?t.substring(0,e):"");let n=null,r=t,s=t.lastIndexOf(".");return s>0&&(n=t.slice(s+1),r=t.substring(0,s)),{property:r,suffix:n}}function l_(t,e=!1){return Ms(Object.keys(t).map(n=>({key:n,quoted:e,value:t[n]})))}var c_=class{visitText(e){return e.value}visitContainer(e){return e.children.map(n=>n.visit(this)).join("")}visitIcu(e){let n=Object.keys(e.cases).map(s=>`${s} {${e.cases[s].visit(this)}}`);return`{${e.expressionPlaceholder}, ${e.type}, ${n.join(" ")}}`}visitTagPlaceholder(e){return e.isVoid?this.formatPh(e.startName):`${this.formatPh(e.startName)}${e.children.map(n=>n.visit(this)).join("")}${this.formatPh(e.closeName)}`}visitPlaceholder(e){return this.formatPh(e.name)}visitBlockPlaceholder(e){return`${this.formatPh(e.startName)}${e.children.map(n=>n.visit(this)).join("")}${this.formatPh(e.closeName)}`}visitIcuPlaceholder(e,n){return this.formatPh(e.name)}formatPh(e){return`{${gy(e,!1)}}`}},_X=new c_;function dB(t){return t.visit(_X)}var cc=class{constructor(e,n){l(this,"sourceSpan");l(this,"i18n");this.sourceSpan=e,this.i18n=n}},Nu=class extends cc{constructor(n,r,s,i){super(r,i);l(this,"value");l(this,"tokens");this.value=n,this.tokens=s}visit(n,r){return n.visitText(this,r)}},vu=class extends cc{constructor(n,r,s,i,o,a){super(i,a);l(this,"switchValue");l(this,"type");l(this,"cases");l(this,"switchValueSourceSpan");this.switchValue=n,this.type=r,this.cases=s,this.switchValueSourceSpan=o}visit(n,r){return n.visitExpansion(this,r)}},NE=class{constructor(e,n,r,s,i){l(this,"value");l(this,"expression");l(this,"sourceSpan");l(this,"valueSourceSpan");l(this,"expSourceSpan");this.value=e,this.expression=n,this.sourceSpan=r,this.valueSourceSpan=s,this.expSourceSpan=i}visit(e,n){return e.visitExpansionCase(this,n)}},u_=class extends cc{constructor(n,r,s,i,o,a,c){super(s,c);l(this,"name");l(this,"value");l(this,"keySpan");l(this,"valueSpan");l(this,"valueTokens");this.name=n,this.value=r,this.keySpan=i,this.valueSpan=o,this.valueTokens=a}visit(n,r){return n.visitAttribute(this,r)}},Hi=class extends cc{constructor(n,r,s,i,o,a=null,c){super(i,c);l(this,"name");l(this,"attrs");l(this,"children");l(this,"startSourceSpan");l(this,"endSourceSpan");this.name=n,this.attrs=r,this.children=s,this.startSourceSpan=o,this.endSourceSpan=a}visit(n,r){return n.visitElement(this,r)}},oy=class{constructor(e,n){l(this,"value");l(this,"sourceSpan");this.value=e,this.sourceSpan=n}visit(e,n){return e.visitComment(this,n)}},Ui=class extends cc{constructor(n,r,s,i,o,a,c=null,u){super(i,u);l(this,"name");l(this,"parameters");l(this,"children");l(this,"nameSpan");l(this,"startSourceSpan");l(this,"endSourceSpan");this.name=n,this.parameters=r,this.children=s,this.nameSpan=o,this.startSourceSpan=a,this.endSourceSpan=c}visit(n,r){return n.visitBlock(this,r)}},RE=class{constructor(e,n){l(this,"expression");l(this,"sourceSpan");this.expression=e,this.sourceSpan=n}visit(e,n){return e.visitBlockParameter(this,n)}},FE=class{constructor(e,n,r,s,i){l(this,"name");l(this,"value");l(this,"sourceSpan");l(this,"nameSpan");l(this,"valueSpan");this.name=e,this.value=n,this.sourceSpan=r,this.nameSpan=s,this.valueSpan=i}visit(e,n){return e.visitLetDeclaration(this,n)}};function nr(t,e,n=null){let r=[],s=t.visit?i=>t.visit(i,n)||i.visit(t,n):i=>i.visit(t,n);return e.forEach(i=>{let o=s(i);o&&r.push(o)}),r}var ay={AElig:"\xC6",AMP:"&",amp:"&",Aacute:"\xC1",Abreve:"\u0102",Acirc:"\xC2",Acy:"\u0410",Afr:"\u{1D504}",Agrave:"\xC0",Alpha:"\u0391",Amacr:"\u0100",And:"\u2A53",Aogon:"\u0104",Aopf:"\u{1D538}",ApplyFunction:"\u2061",af:"\u2061",Aring:"\xC5",angst:"\xC5",Ascr:"\u{1D49C}",Assign:"\u2254",colone:"\u2254",coloneq:"\u2254",Atilde:"\xC3",Auml:"\xC4",Backslash:"\u2216",setminus:"\u2216",setmn:"\u2216",smallsetminus:"\u2216",ssetmn:"\u2216",Barv:"\u2AE7",Barwed:"\u2306",doublebarwedge:"\u2306",Bcy:"\u0411",Because:"\u2235",becaus:"\u2235",because:"\u2235",Bernoullis:"\u212C",Bscr:"\u212C",bernou:"\u212C",Beta:"\u0392",Bfr:"\u{1D505}",Bopf:"\u{1D539}",Breve:"\u02D8",breve:"\u02D8",Bumpeq:"\u224E",HumpDownHump:"\u224E",bump:"\u224E",CHcy:"\u0427",COPY:"\xA9",copy:"\xA9",Cacute:"\u0106",Cap:"\u22D2",CapitalDifferentialD:"\u2145",DD:"\u2145",Cayleys:"\u212D",Cfr:"\u212D",Ccaron:"\u010C",Ccedil:"\xC7",Ccirc:"\u0108",Cconint:"\u2230",Cdot:"\u010A",Cedilla:"\xB8",cedil:"\xB8",CenterDot:"\xB7",centerdot:"\xB7",middot:"\xB7",Chi:"\u03A7",CircleDot:"\u2299",odot:"\u2299",CircleMinus:"\u2296",ominus:"\u2296",CirclePlus:"\u2295",oplus:"\u2295",CircleTimes:"\u2297",otimes:"\u2297",ClockwiseContourIntegral:"\u2232",cwconint:"\u2232",CloseCurlyDoubleQuote:"\u201D",rdquo:"\u201D",rdquor:"\u201D",CloseCurlyQuote:"\u2019",rsquo:"\u2019",rsquor:"\u2019",Colon:"\u2237",Proportion:"\u2237",Colone:"\u2A74",Congruent:"\u2261",equiv:"\u2261",Conint:"\u222F",DoubleContourIntegral:"\u222F",ContourIntegral:"\u222E",conint:"\u222E",oint:"\u222E",Copf:"\u2102",complexes:"\u2102",Coproduct:"\u2210",coprod:"\u2210",CounterClockwiseContourIntegral:"\u2233",awconint:"\u2233",Cross:"\u2A2F",Cscr:"\u{1D49E}",Cup:"\u22D3",CupCap:"\u224D",asympeq:"\u224D",DDotrahd:"\u2911",DJcy:"\u0402",DScy:"\u0405",DZcy:"\u040F",Dagger:"\u2021",ddagger:"\u2021",Darr:"\u21A1",Dashv:"\u2AE4",DoubleLeftTee:"\u2AE4",Dcaron:"\u010E",Dcy:"\u0414",Del:"\u2207",nabla:"\u2207",Delta:"\u0394",Dfr:"\u{1D507}",DiacriticalAcute:"\xB4",acute:"\xB4",DiacriticalDot:"\u02D9",dot:"\u02D9",DiacriticalDoubleAcute:"\u02DD",dblac:"\u02DD",DiacriticalGrave:"`",grave:"`",DiacriticalTilde:"\u02DC",tilde:"\u02DC",Diamond:"\u22C4",diam:"\u22C4",diamond:"\u22C4",DifferentialD:"\u2146",dd:"\u2146",Dopf:"\u{1D53B}",Dot:"\xA8",DoubleDot:"\xA8",die:"\xA8",uml:"\xA8",DotDot:"\u20DC",DotEqual:"\u2250",doteq:"\u2250",esdot:"\u2250",DoubleDownArrow:"\u21D3",Downarrow:"\u21D3",dArr:"\u21D3",DoubleLeftArrow:"\u21D0",Leftarrow:"\u21D0",lArr:"\u21D0",DoubleLeftRightArrow:"\u21D4",Leftrightarrow:"\u21D4",hArr:"\u21D4",iff:"\u21D4",DoubleLongLeftArrow:"\u27F8",Longleftarrow:"\u27F8",xlArr:"\u27F8",DoubleLongLeftRightArrow:"\u27FA",Longleftrightarrow:"\u27FA",xhArr:"\u27FA",DoubleLongRightArrow:"\u27F9",Longrightarrow:"\u27F9",xrArr:"\u27F9",DoubleRightArrow:"\u21D2",Implies:"\u21D2",Rightarrow:"\u21D2",rArr:"\u21D2",DoubleRightTee:"\u22A8",vDash:"\u22A8",DoubleUpArrow:"\u21D1",Uparrow:"\u21D1",uArr:"\u21D1",DoubleUpDownArrow:"\u21D5",Updownarrow:"\u21D5",vArr:"\u21D5",DoubleVerticalBar:"\u2225",par:"\u2225",parallel:"\u2225",shortparallel:"\u2225",spar:"\u2225",DownArrow:"\u2193",ShortDownArrow:"\u2193",darr:"\u2193",downarrow:"\u2193",DownArrowBar:"\u2913",DownArrowUpArrow:"\u21F5",duarr:"\u21F5",DownBreve:"\u0311",DownLeftRightVector:"\u2950",DownLeftTeeVector:"\u295E",DownLeftVector:"\u21BD",leftharpoondown:"\u21BD",lhard:"\u21BD",DownLeftVectorBar:"\u2956",DownRightTeeVector:"\u295F",DownRightVector:"\u21C1",rhard:"\u21C1",rightharpoondown:"\u21C1",DownRightVectorBar:"\u2957",DownTee:"\u22A4",top:"\u22A4",DownTeeArrow:"\u21A7",mapstodown:"\u21A7",Dscr:"\u{1D49F}",Dstrok:"\u0110",ENG:"\u014A",ETH:"\xD0",Eacute:"\xC9",Ecaron:"\u011A",Ecirc:"\xCA",Ecy:"\u042D",Edot:"\u0116",Efr:"\u{1D508}",Egrave:"\xC8",Element:"\u2208",in:"\u2208",isin:"\u2208",isinv:"\u2208",Emacr:"\u0112",EmptySmallSquare:"\u25FB",EmptyVerySmallSquare:"\u25AB",Eogon:"\u0118",Eopf:"\u{1D53C}",Epsilon:"\u0395",Equal:"\u2A75",EqualTilde:"\u2242",eqsim:"\u2242",esim:"\u2242",Equilibrium:"\u21CC",rightleftharpoons:"\u21CC",rlhar:"\u21CC",Escr:"\u2130",expectation:"\u2130",Esim:"\u2A73",Eta:"\u0397",Euml:"\xCB",Exists:"\u2203",exist:"\u2203",ExponentialE:"\u2147",ee:"\u2147",exponentiale:"\u2147",Fcy:"\u0424",Ffr:"\u{1D509}",FilledSmallSquare:"\u25FC",FilledVerySmallSquare:"\u25AA",blacksquare:"\u25AA",squarf:"\u25AA",squf:"\u25AA",Fopf:"\u{1D53D}",ForAll:"\u2200",forall:"\u2200",Fouriertrf:"\u2131",Fscr:"\u2131",GJcy:"\u0403",GT:">",gt:">",Gamma:"\u0393",Gammad:"\u03DC",Gbreve:"\u011E",Gcedil:"\u0122",Gcirc:"\u011C",Gcy:"\u0413",Gdot:"\u0120",Gfr:"\u{1D50A}",Gg:"\u22D9",ggg:"\u22D9",Gopf:"\u{1D53E}",GreaterEqual:"\u2265",ge:"\u2265",geq:"\u2265",GreaterEqualLess:"\u22DB",gel:"\u22DB",gtreqless:"\u22DB",GreaterFullEqual:"\u2267",gE:"\u2267",geqq:"\u2267",GreaterGreater:"\u2AA2",GreaterLess:"\u2277",gl:"\u2277",gtrless:"\u2277",GreaterSlantEqual:"\u2A7E",geqslant:"\u2A7E",ges:"\u2A7E",GreaterTilde:"\u2273",gsim:"\u2273",gtrsim:"\u2273",Gscr:"\u{1D4A2}",Gt:"\u226B",NestedGreaterGreater:"\u226B",gg:"\u226B",HARDcy:"\u042A",Hacek:"\u02C7",caron:"\u02C7",Hat:"^",Hcirc:"\u0124",Hfr:"\u210C",Poincareplane:"\u210C",HilbertSpace:"\u210B",Hscr:"\u210B",hamilt:"\u210B",Hopf:"\u210D",quaternions:"\u210D",HorizontalLine:"\u2500",boxh:"\u2500",Hstrok:"\u0126",HumpEqual:"\u224F",bumpe:"\u224F",bumpeq:"\u224F",IEcy:"\u0415",IJlig:"\u0132",IOcy:"\u0401",Iacute:"\xCD",Icirc:"\xCE",Icy:"\u0418",Idot:"\u0130",Ifr:"\u2111",Im:"\u2111",image:"\u2111",imagpart:"\u2111",Igrave:"\xCC",Imacr:"\u012A",ImaginaryI:"\u2148",ii:"\u2148",Int:"\u222C",Integral:"\u222B",int:"\u222B",Intersection:"\u22C2",bigcap:"\u22C2",xcap:"\u22C2",InvisibleComma:"\u2063",ic:"\u2063",InvisibleTimes:"\u2062",it:"\u2062",Iogon:"\u012E",Iopf:"\u{1D540}",Iota:"\u0399",Iscr:"\u2110",imagline:"\u2110",Itilde:"\u0128",Iukcy:"\u0406",Iuml:"\xCF",Jcirc:"\u0134",Jcy:"\u0419",Jfr:"\u{1D50D}",Jopf:"\u{1D541}",Jscr:"\u{1D4A5}",Jsercy:"\u0408",Jukcy:"\u0404",KHcy:"\u0425",KJcy:"\u040C",Kappa:"\u039A",Kcedil:"\u0136",Kcy:"\u041A",Kfr:"\u{1D50E}",Kopf:"\u{1D542}",Kscr:"\u{1D4A6}",LJcy:"\u0409",LT:"<",lt:"<",Lacute:"\u0139",Lambda:"\u039B",Lang:"\u27EA",Laplacetrf:"\u2112",Lscr:"\u2112",lagran:"\u2112",Larr:"\u219E",twoheadleftarrow:"\u219E",Lcaron:"\u013D",Lcedil:"\u013B",Lcy:"\u041B",LeftAngleBracket:"\u27E8",lang:"\u27E8",langle:"\u27E8",LeftArrow:"\u2190",ShortLeftArrow:"\u2190",larr:"\u2190",leftarrow:"\u2190",slarr:"\u2190",LeftArrowBar:"\u21E4",larrb:"\u21E4",LeftArrowRightArrow:"\u21C6",leftrightarrows:"\u21C6",lrarr:"\u21C6",LeftCeiling:"\u2308",lceil:"\u2308",LeftDoubleBracket:"\u27E6",lobrk:"\u27E6",LeftDownTeeVector:"\u2961",LeftDownVector:"\u21C3",dharl:"\u21C3",downharpoonleft:"\u21C3",LeftDownVectorBar:"\u2959",LeftFloor:"\u230A",lfloor:"\u230A",LeftRightArrow:"\u2194",harr:"\u2194",leftrightarrow:"\u2194",LeftRightVector:"\u294E",LeftTee:"\u22A3",dashv:"\u22A3",LeftTeeArrow:"\u21A4",mapstoleft:"\u21A4",LeftTeeVector:"\u295A",LeftTriangle:"\u22B2",vartriangleleft:"\u22B2",vltri:"\u22B2",LeftTriangleBar:"\u29CF",LeftTriangleEqual:"\u22B4",ltrie:"\u22B4",trianglelefteq:"\u22B4",LeftUpDownVector:"\u2951",LeftUpTeeVector:"\u2960",LeftUpVector:"\u21BF",uharl:"\u21BF",upharpoonleft:"\u21BF",LeftUpVectorBar:"\u2958",LeftVector:"\u21BC",leftharpoonup:"\u21BC",lharu:"\u21BC",LeftVectorBar:"\u2952",LessEqualGreater:"\u22DA",leg:"\u22DA",lesseqgtr:"\u22DA",LessFullEqual:"\u2266",lE:"\u2266",leqq:"\u2266",LessGreater:"\u2276",lessgtr:"\u2276",lg:"\u2276",LessLess:"\u2AA1",LessSlantEqual:"\u2A7D",leqslant:"\u2A7D",les:"\u2A7D",LessTilde:"\u2272",lesssim:"\u2272",lsim:"\u2272",Lfr:"\u{1D50F}",Ll:"\u22D8",Lleftarrow:"\u21DA",lAarr:"\u21DA",Lmidot:"\u013F",LongLeftArrow:"\u27F5",longleftarrow:"\u27F5",xlarr:"\u27F5",LongLeftRightArrow:"\u27F7",longleftrightarrow:"\u27F7",xharr:"\u27F7",LongRightArrow:"\u27F6",longrightarrow:"\u27F6",xrarr:"\u27F6",Lopf:"\u{1D543}",LowerLeftArrow:"\u2199",swarr:"\u2199",swarrow:"\u2199",LowerRightArrow:"\u2198",searr:"\u2198",searrow:"\u2198",Lsh:"\u21B0",lsh:"\u21B0",Lstrok:"\u0141",Lt:"\u226A",NestedLessLess:"\u226A",ll:"\u226A",Map:"\u2905",Mcy:"\u041C",MediumSpace:"\u205F",Mellintrf:"\u2133",Mscr:"\u2133",phmmat:"\u2133",Mfr:"\u{1D510}",MinusPlus:"\u2213",mnplus:"\u2213",mp:"\u2213",Mopf:"\u{1D544}",Mu:"\u039C",NJcy:"\u040A",Nacute:"\u0143",Ncaron:"\u0147",Ncedil:"\u0145",Ncy:"\u041D",NegativeMediumSpace:"\u200B",NegativeThickSpace:"\u200B",NegativeThinSpace:"\u200B",NegativeVeryThinSpace:"\u200B",ZeroWidthSpace:"\u200B",NewLine:` +`,Nfr:"\u{1D511}",NoBreak:"\u2060",NonBreakingSpace:"\xA0",nbsp:"\xA0",Nopf:"\u2115",naturals:"\u2115",Not:"\u2AEC",NotCongruent:"\u2262",nequiv:"\u2262",NotCupCap:"\u226D",NotDoubleVerticalBar:"\u2226",npar:"\u2226",nparallel:"\u2226",nshortparallel:"\u2226",nspar:"\u2226",NotElement:"\u2209",notin:"\u2209",notinva:"\u2209",NotEqual:"\u2260",ne:"\u2260",NotEqualTilde:"\u2242\u0338",nesim:"\u2242\u0338",NotExists:"\u2204",nexist:"\u2204",nexists:"\u2204",NotGreater:"\u226F",ngt:"\u226F",ngtr:"\u226F",NotGreaterEqual:"\u2271",nge:"\u2271",ngeq:"\u2271",NotGreaterFullEqual:"\u2267\u0338",ngE:"\u2267\u0338",ngeqq:"\u2267\u0338",NotGreaterGreater:"\u226B\u0338",nGtv:"\u226B\u0338",NotGreaterLess:"\u2279",ntgl:"\u2279",NotGreaterSlantEqual:"\u2A7E\u0338",ngeqslant:"\u2A7E\u0338",nges:"\u2A7E\u0338",NotGreaterTilde:"\u2275",ngsim:"\u2275",NotHumpDownHump:"\u224E\u0338",nbump:"\u224E\u0338",NotHumpEqual:"\u224F\u0338",nbumpe:"\u224F\u0338",NotLeftTriangle:"\u22EA",nltri:"\u22EA",ntriangleleft:"\u22EA",NotLeftTriangleBar:"\u29CF\u0338",NotLeftTriangleEqual:"\u22EC",nltrie:"\u22EC",ntrianglelefteq:"\u22EC",NotLess:"\u226E",nless:"\u226E",nlt:"\u226E",NotLessEqual:"\u2270",nle:"\u2270",nleq:"\u2270",NotLessGreater:"\u2278",ntlg:"\u2278",NotLessLess:"\u226A\u0338",nLtv:"\u226A\u0338",NotLessSlantEqual:"\u2A7D\u0338",nleqslant:"\u2A7D\u0338",nles:"\u2A7D\u0338",NotLessTilde:"\u2274",nlsim:"\u2274",NotNestedGreaterGreater:"\u2AA2\u0338",NotNestedLessLess:"\u2AA1\u0338",NotPrecedes:"\u2280",npr:"\u2280",nprec:"\u2280",NotPrecedesEqual:"\u2AAF\u0338",npre:"\u2AAF\u0338",npreceq:"\u2AAF\u0338",NotPrecedesSlantEqual:"\u22E0",nprcue:"\u22E0",NotReverseElement:"\u220C",notni:"\u220C",notniva:"\u220C",NotRightTriangle:"\u22EB",nrtri:"\u22EB",ntriangleright:"\u22EB",NotRightTriangleBar:"\u29D0\u0338",NotRightTriangleEqual:"\u22ED",nrtrie:"\u22ED",ntrianglerighteq:"\u22ED",NotSquareSubset:"\u228F\u0338",NotSquareSubsetEqual:"\u22E2",nsqsube:"\u22E2",NotSquareSuperset:"\u2290\u0338",NotSquareSupersetEqual:"\u22E3",nsqsupe:"\u22E3",NotSubset:"\u2282\u20D2",nsubset:"\u2282\u20D2",vnsub:"\u2282\u20D2",NotSubsetEqual:"\u2288",nsube:"\u2288",nsubseteq:"\u2288",NotSucceeds:"\u2281",nsc:"\u2281",nsucc:"\u2281",NotSucceedsEqual:"\u2AB0\u0338",nsce:"\u2AB0\u0338",nsucceq:"\u2AB0\u0338",NotSucceedsSlantEqual:"\u22E1",nsccue:"\u22E1",NotSucceedsTilde:"\u227F\u0338",NotSuperset:"\u2283\u20D2",nsupset:"\u2283\u20D2",vnsup:"\u2283\u20D2",NotSupersetEqual:"\u2289",nsupe:"\u2289",nsupseteq:"\u2289",NotTilde:"\u2241",nsim:"\u2241",NotTildeEqual:"\u2244",nsime:"\u2244",nsimeq:"\u2244",NotTildeFullEqual:"\u2247",ncong:"\u2247",NotTildeTilde:"\u2249",nap:"\u2249",napprox:"\u2249",NotVerticalBar:"\u2224",nmid:"\u2224",nshortmid:"\u2224",nsmid:"\u2224",Nscr:"\u{1D4A9}",Ntilde:"\xD1",Nu:"\u039D",OElig:"\u0152",Oacute:"\xD3",Ocirc:"\xD4",Ocy:"\u041E",Odblac:"\u0150",Ofr:"\u{1D512}",Ograve:"\xD2",Omacr:"\u014C",Omega:"\u03A9",ohm:"\u03A9",Omicron:"\u039F",Oopf:"\u{1D546}",OpenCurlyDoubleQuote:"\u201C",ldquo:"\u201C",OpenCurlyQuote:"\u2018",lsquo:"\u2018",Or:"\u2A54",Oscr:"\u{1D4AA}",Oslash:"\xD8",Otilde:"\xD5",Otimes:"\u2A37",Ouml:"\xD6",OverBar:"\u203E",oline:"\u203E",OverBrace:"\u23DE",OverBracket:"\u23B4",tbrk:"\u23B4",OverParenthesis:"\u23DC",PartialD:"\u2202",part:"\u2202",Pcy:"\u041F",Pfr:"\u{1D513}",Phi:"\u03A6",Pi:"\u03A0",PlusMinus:"\xB1",plusmn:"\xB1",pm:"\xB1",Popf:"\u2119",primes:"\u2119",Pr:"\u2ABB",Precedes:"\u227A",pr:"\u227A",prec:"\u227A",PrecedesEqual:"\u2AAF",pre:"\u2AAF",preceq:"\u2AAF",PrecedesSlantEqual:"\u227C",prcue:"\u227C",preccurlyeq:"\u227C",PrecedesTilde:"\u227E",precsim:"\u227E",prsim:"\u227E",Prime:"\u2033",Product:"\u220F",prod:"\u220F",Proportional:"\u221D",prop:"\u221D",propto:"\u221D",varpropto:"\u221D",vprop:"\u221D",Pscr:"\u{1D4AB}",Psi:"\u03A8",QUOT:'"',quot:'"',Qfr:"\u{1D514}",Qopf:"\u211A",rationals:"\u211A",Qscr:"\u{1D4AC}",RBarr:"\u2910",drbkarow:"\u2910",REG:"\xAE",circledR:"\xAE",reg:"\xAE",Racute:"\u0154",Rang:"\u27EB",Rarr:"\u21A0",twoheadrightarrow:"\u21A0",Rarrtl:"\u2916",Rcaron:"\u0158",Rcedil:"\u0156",Rcy:"\u0420",Re:"\u211C",Rfr:"\u211C",real:"\u211C",realpart:"\u211C",ReverseElement:"\u220B",SuchThat:"\u220B",ni:"\u220B",niv:"\u220B",ReverseEquilibrium:"\u21CB",leftrightharpoons:"\u21CB",lrhar:"\u21CB",ReverseUpEquilibrium:"\u296F",duhar:"\u296F",Rho:"\u03A1",RightAngleBracket:"\u27E9",rang:"\u27E9",rangle:"\u27E9",RightArrow:"\u2192",ShortRightArrow:"\u2192",rarr:"\u2192",rightarrow:"\u2192",srarr:"\u2192",RightArrowBar:"\u21E5",rarrb:"\u21E5",RightArrowLeftArrow:"\u21C4",rightleftarrows:"\u21C4",rlarr:"\u21C4",RightCeiling:"\u2309",rceil:"\u2309",RightDoubleBracket:"\u27E7",robrk:"\u27E7",RightDownTeeVector:"\u295D",RightDownVector:"\u21C2",dharr:"\u21C2",downharpoonright:"\u21C2",RightDownVectorBar:"\u2955",RightFloor:"\u230B",rfloor:"\u230B",RightTee:"\u22A2",vdash:"\u22A2",RightTeeArrow:"\u21A6",map:"\u21A6",mapsto:"\u21A6",RightTeeVector:"\u295B",RightTriangle:"\u22B3",vartriangleright:"\u22B3",vrtri:"\u22B3",RightTriangleBar:"\u29D0",RightTriangleEqual:"\u22B5",rtrie:"\u22B5",trianglerighteq:"\u22B5",RightUpDownVector:"\u294F",RightUpTeeVector:"\u295C",RightUpVector:"\u21BE",uharr:"\u21BE",upharpoonright:"\u21BE",RightUpVectorBar:"\u2954",RightVector:"\u21C0",rharu:"\u21C0",rightharpoonup:"\u21C0",RightVectorBar:"\u2953",Ropf:"\u211D",reals:"\u211D",RoundImplies:"\u2970",Rrightarrow:"\u21DB",rAarr:"\u21DB",Rscr:"\u211B",realine:"\u211B",Rsh:"\u21B1",rsh:"\u21B1",RuleDelayed:"\u29F4",SHCHcy:"\u0429",SHcy:"\u0428",SOFTcy:"\u042C",Sacute:"\u015A",Sc:"\u2ABC",Scaron:"\u0160",Scedil:"\u015E",Scirc:"\u015C",Scy:"\u0421",Sfr:"\u{1D516}",ShortUpArrow:"\u2191",UpArrow:"\u2191",uarr:"\u2191",uparrow:"\u2191",Sigma:"\u03A3",SmallCircle:"\u2218",compfn:"\u2218",Sopf:"\u{1D54A}",Sqrt:"\u221A",radic:"\u221A",Square:"\u25A1",squ:"\u25A1",square:"\u25A1",SquareIntersection:"\u2293",sqcap:"\u2293",SquareSubset:"\u228F",sqsub:"\u228F",sqsubset:"\u228F",SquareSubsetEqual:"\u2291",sqsube:"\u2291",sqsubseteq:"\u2291",SquareSuperset:"\u2290",sqsup:"\u2290",sqsupset:"\u2290",SquareSupersetEqual:"\u2292",sqsupe:"\u2292",sqsupseteq:"\u2292",SquareUnion:"\u2294",sqcup:"\u2294",Sscr:"\u{1D4AE}",Star:"\u22C6",sstarf:"\u22C6",Sub:"\u22D0",Subset:"\u22D0",SubsetEqual:"\u2286",sube:"\u2286",subseteq:"\u2286",Succeeds:"\u227B",sc:"\u227B",succ:"\u227B",SucceedsEqual:"\u2AB0",sce:"\u2AB0",succeq:"\u2AB0",SucceedsSlantEqual:"\u227D",sccue:"\u227D",succcurlyeq:"\u227D",SucceedsTilde:"\u227F",scsim:"\u227F",succsim:"\u227F",Sum:"\u2211",sum:"\u2211",Sup:"\u22D1",Supset:"\u22D1",Superset:"\u2283",sup:"\u2283",supset:"\u2283",SupersetEqual:"\u2287",supe:"\u2287",supseteq:"\u2287",THORN:"\xDE",TRADE:"\u2122",trade:"\u2122",TSHcy:"\u040B",TScy:"\u0426",Tab:" ",Tau:"\u03A4",Tcaron:"\u0164",Tcedil:"\u0162",Tcy:"\u0422",Tfr:"\u{1D517}",Therefore:"\u2234",there4:"\u2234",therefore:"\u2234",Theta:"\u0398",ThickSpace:"\u205F\u200A",ThinSpace:"\u2009",thinsp:"\u2009",Tilde:"\u223C",sim:"\u223C",thicksim:"\u223C",thksim:"\u223C",TildeEqual:"\u2243",sime:"\u2243",simeq:"\u2243",TildeFullEqual:"\u2245",cong:"\u2245",TildeTilde:"\u2248",ap:"\u2248",approx:"\u2248",asymp:"\u2248",thickapprox:"\u2248",thkap:"\u2248",Topf:"\u{1D54B}",TripleDot:"\u20DB",tdot:"\u20DB",Tscr:"\u{1D4AF}",Tstrok:"\u0166",Uacute:"\xDA",Uarr:"\u219F",Uarrocir:"\u2949",Ubrcy:"\u040E",Ubreve:"\u016C",Ucirc:"\xDB",Ucy:"\u0423",Udblac:"\u0170",Ufr:"\u{1D518}",Ugrave:"\xD9",Umacr:"\u016A",UnderBar:"_",lowbar:"_",UnderBrace:"\u23DF",UnderBracket:"\u23B5",bbrk:"\u23B5",UnderParenthesis:"\u23DD",Union:"\u22C3",bigcup:"\u22C3",xcup:"\u22C3",UnionPlus:"\u228E",uplus:"\u228E",Uogon:"\u0172",Uopf:"\u{1D54C}",UpArrowBar:"\u2912",UpArrowDownArrow:"\u21C5",udarr:"\u21C5",UpDownArrow:"\u2195",updownarrow:"\u2195",varr:"\u2195",UpEquilibrium:"\u296E",udhar:"\u296E",UpTee:"\u22A5",bot:"\u22A5",bottom:"\u22A5",perp:"\u22A5",UpTeeArrow:"\u21A5",mapstoup:"\u21A5",UpperLeftArrow:"\u2196",nwarr:"\u2196",nwarrow:"\u2196",UpperRightArrow:"\u2197",nearr:"\u2197",nearrow:"\u2197",Upsi:"\u03D2",upsih:"\u03D2",Upsilon:"\u03A5",Uring:"\u016E",Uscr:"\u{1D4B0}",Utilde:"\u0168",Uuml:"\xDC",VDash:"\u22AB",Vbar:"\u2AEB",Vcy:"\u0412",Vdash:"\u22A9",Vdashl:"\u2AE6",Vee:"\u22C1",bigvee:"\u22C1",xvee:"\u22C1",Verbar:"\u2016",Vert:"\u2016",VerticalBar:"\u2223",mid:"\u2223",shortmid:"\u2223",smid:"\u2223",VerticalLine:"|",verbar:"|",vert:"|",VerticalSeparator:"\u2758",VerticalTilde:"\u2240",wr:"\u2240",wreath:"\u2240",VeryThinSpace:"\u200A",hairsp:"\u200A",Vfr:"\u{1D519}",Vopf:"\u{1D54D}",Vscr:"\u{1D4B1}",Vvdash:"\u22AA",Wcirc:"\u0174",Wedge:"\u22C0",bigwedge:"\u22C0",xwedge:"\u22C0",Wfr:"\u{1D51A}",Wopf:"\u{1D54E}",Wscr:"\u{1D4B2}",Xfr:"\u{1D51B}",Xi:"\u039E",Xopf:"\u{1D54F}",Xscr:"\u{1D4B3}",YAcy:"\u042F",YIcy:"\u0407",YUcy:"\u042E",Yacute:"\xDD",Ycirc:"\u0176",Ycy:"\u042B",Yfr:"\u{1D51C}",Yopf:"\u{1D550}",Yscr:"\u{1D4B4}",Yuml:"\u0178",ZHcy:"\u0416",Zacute:"\u0179",Zcaron:"\u017D",Zcy:"\u0417",Zdot:"\u017B",Zeta:"\u0396",Zfr:"\u2128",zeetrf:"\u2128",Zopf:"\u2124",integers:"\u2124",Zscr:"\u{1D4B5}",aacute:"\xE1",abreve:"\u0103",ac:"\u223E",mstpos:"\u223E",acE:"\u223E\u0333",acd:"\u223F",acirc:"\xE2",acy:"\u0430",aelig:"\xE6",afr:"\u{1D51E}",agrave:"\xE0",alefsym:"\u2135",aleph:"\u2135",alpha:"\u03B1",amacr:"\u0101",amalg:"\u2A3F",and:"\u2227",wedge:"\u2227",andand:"\u2A55",andd:"\u2A5C",andslope:"\u2A58",andv:"\u2A5A",ang:"\u2220",angle:"\u2220",ange:"\u29A4",angmsd:"\u2221",measuredangle:"\u2221",angmsdaa:"\u29A8",angmsdab:"\u29A9",angmsdac:"\u29AA",angmsdad:"\u29AB",angmsdae:"\u29AC",angmsdaf:"\u29AD",angmsdag:"\u29AE",angmsdah:"\u29AF",angrt:"\u221F",angrtvb:"\u22BE",angrtvbd:"\u299D",angsph:"\u2222",angzarr:"\u237C",aogon:"\u0105",aopf:"\u{1D552}",apE:"\u2A70",apacir:"\u2A6F",ape:"\u224A",approxeq:"\u224A",apid:"\u224B",apos:"'",aring:"\xE5",ascr:"\u{1D4B6}",ast:"*",midast:"*",atilde:"\xE3",auml:"\xE4",awint:"\u2A11",bNot:"\u2AED",backcong:"\u224C",bcong:"\u224C",backepsilon:"\u03F6",bepsi:"\u03F6",backprime:"\u2035",bprime:"\u2035",backsim:"\u223D",bsim:"\u223D",backsimeq:"\u22CD",bsime:"\u22CD",barvee:"\u22BD",barwed:"\u2305",barwedge:"\u2305",bbrktbrk:"\u23B6",bcy:"\u0431",bdquo:"\u201E",ldquor:"\u201E",bemptyv:"\u29B0",beta:"\u03B2",beth:"\u2136",between:"\u226C",twixt:"\u226C",bfr:"\u{1D51F}",bigcirc:"\u25EF",xcirc:"\u25EF",bigodot:"\u2A00",xodot:"\u2A00",bigoplus:"\u2A01",xoplus:"\u2A01",bigotimes:"\u2A02",xotime:"\u2A02",bigsqcup:"\u2A06",xsqcup:"\u2A06",bigstar:"\u2605",starf:"\u2605",bigtriangledown:"\u25BD",xdtri:"\u25BD",bigtriangleup:"\u25B3",xutri:"\u25B3",biguplus:"\u2A04",xuplus:"\u2A04",bkarow:"\u290D",rbarr:"\u290D",blacklozenge:"\u29EB",lozf:"\u29EB",blacktriangle:"\u25B4",utrif:"\u25B4",blacktriangledown:"\u25BE",dtrif:"\u25BE",blacktriangleleft:"\u25C2",ltrif:"\u25C2",blacktriangleright:"\u25B8",rtrif:"\u25B8",blank:"\u2423",blk12:"\u2592",blk14:"\u2591",blk34:"\u2593",block:"\u2588",bne:"=\u20E5",bnequiv:"\u2261\u20E5",bnot:"\u2310",bopf:"\u{1D553}",bowtie:"\u22C8",boxDL:"\u2557",boxDR:"\u2554",boxDl:"\u2556",boxDr:"\u2553",boxH:"\u2550",boxHD:"\u2566",boxHU:"\u2569",boxHd:"\u2564",boxHu:"\u2567",boxUL:"\u255D",boxUR:"\u255A",boxUl:"\u255C",boxUr:"\u2559",boxV:"\u2551",boxVH:"\u256C",boxVL:"\u2563",boxVR:"\u2560",boxVh:"\u256B",boxVl:"\u2562",boxVr:"\u255F",boxbox:"\u29C9",boxdL:"\u2555",boxdR:"\u2552",boxdl:"\u2510",boxdr:"\u250C",boxhD:"\u2565",boxhU:"\u2568",boxhd:"\u252C",boxhu:"\u2534",boxminus:"\u229F",minusb:"\u229F",boxplus:"\u229E",plusb:"\u229E",boxtimes:"\u22A0",timesb:"\u22A0",boxuL:"\u255B",boxuR:"\u2558",boxul:"\u2518",boxur:"\u2514",boxv:"\u2502",boxvH:"\u256A",boxvL:"\u2561",boxvR:"\u255E",boxvh:"\u253C",boxvl:"\u2524",boxvr:"\u251C",brvbar:"\xA6",bscr:"\u{1D4B7}",bsemi:"\u204F",bsol:"\\",bsolb:"\u29C5",bsolhsub:"\u27C8",bull:"\u2022",bullet:"\u2022",bumpE:"\u2AAE",cacute:"\u0107",cap:"\u2229",capand:"\u2A44",capbrcup:"\u2A49",capcap:"\u2A4B",capcup:"\u2A47",capdot:"\u2A40",caps:"\u2229\uFE00",caret:"\u2041",ccaps:"\u2A4D",ccaron:"\u010D",ccedil:"\xE7",ccirc:"\u0109",ccups:"\u2A4C",ccupssm:"\u2A50",cdot:"\u010B",cemptyv:"\u29B2",cent:"\xA2",cfr:"\u{1D520}",chcy:"\u0447",check:"\u2713",checkmark:"\u2713",chi:"\u03C7",cir:"\u25CB",cirE:"\u29C3",circ:"\u02C6",circeq:"\u2257",cire:"\u2257",circlearrowleft:"\u21BA",olarr:"\u21BA",circlearrowright:"\u21BB",orarr:"\u21BB",circledS:"\u24C8",oS:"\u24C8",circledast:"\u229B",oast:"\u229B",circledcirc:"\u229A",ocir:"\u229A",circleddash:"\u229D",odash:"\u229D",cirfnint:"\u2A10",cirmid:"\u2AEF",cirscir:"\u29C2",clubs:"\u2663",clubsuit:"\u2663",colon:":",comma:",",commat:"@",comp:"\u2201",complement:"\u2201",congdot:"\u2A6D",copf:"\u{1D554}",copysr:"\u2117",crarr:"\u21B5",cross:"\u2717",cscr:"\u{1D4B8}",csub:"\u2ACF",csube:"\u2AD1",csup:"\u2AD0",csupe:"\u2AD2",ctdot:"\u22EF",cudarrl:"\u2938",cudarrr:"\u2935",cuepr:"\u22DE",curlyeqprec:"\u22DE",cuesc:"\u22DF",curlyeqsucc:"\u22DF",cularr:"\u21B6",curvearrowleft:"\u21B6",cularrp:"\u293D",cup:"\u222A",cupbrcap:"\u2A48",cupcap:"\u2A46",cupcup:"\u2A4A",cupdot:"\u228D",cupor:"\u2A45",cups:"\u222A\uFE00",curarr:"\u21B7",curvearrowright:"\u21B7",curarrm:"\u293C",curlyvee:"\u22CE",cuvee:"\u22CE",curlywedge:"\u22CF",cuwed:"\u22CF",curren:"\xA4",cwint:"\u2231",cylcty:"\u232D",dHar:"\u2965",dagger:"\u2020",daleth:"\u2138",dash:"\u2010",hyphen:"\u2010",dbkarow:"\u290F",rBarr:"\u290F",dcaron:"\u010F",dcy:"\u0434",ddarr:"\u21CA",downdownarrows:"\u21CA",ddotseq:"\u2A77",eDDot:"\u2A77",deg:"\xB0",delta:"\u03B4",demptyv:"\u29B1",dfisht:"\u297F",dfr:"\u{1D521}",diamondsuit:"\u2666",diams:"\u2666",digamma:"\u03DD",gammad:"\u03DD",disin:"\u22F2",div:"\xF7",divide:"\xF7",divideontimes:"\u22C7",divonx:"\u22C7",djcy:"\u0452",dlcorn:"\u231E",llcorner:"\u231E",dlcrop:"\u230D",dollar:"$",dopf:"\u{1D555}",doteqdot:"\u2251",eDot:"\u2251",dotminus:"\u2238",minusd:"\u2238",dotplus:"\u2214",plusdo:"\u2214",dotsquare:"\u22A1",sdotb:"\u22A1",drcorn:"\u231F",lrcorner:"\u231F",drcrop:"\u230C",dscr:"\u{1D4B9}",dscy:"\u0455",dsol:"\u29F6",dstrok:"\u0111",dtdot:"\u22F1",dtri:"\u25BF",triangledown:"\u25BF",dwangle:"\u29A6",dzcy:"\u045F",dzigrarr:"\u27FF",eacute:"\xE9",easter:"\u2A6E",ecaron:"\u011B",ecir:"\u2256",eqcirc:"\u2256",ecirc:"\xEA",ecolon:"\u2255",eqcolon:"\u2255",ecy:"\u044D",edot:"\u0117",efDot:"\u2252",fallingdotseq:"\u2252",efr:"\u{1D522}",eg:"\u2A9A",egrave:"\xE8",egs:"\u2A96",eqslantgtr:"\u2A96",egsdot:"\u2A98",el:"\u2A99",elinters:"\u23E7",ell:"\u2113",els:"\u2A95",eqslantless:"\u2A95",elsdot:"\u2A97",emacr:"\u0113",empty:"\u2205",emptyset:"\u2205",emptyv:"\u2205",varnothing:"\u2205",emsp13:"\u2004",emsp14:"\u2005",emsp:"\u2003",eng:"\u014B",ensp:"\u2002",eogon:"\u0119",eopf:"\u{1D556}",epar:"\u22D5",eparsl:"\u29E3",eplus:"\u2A71",epsi:"\u03B5",epsilon:"\u03B5",epsiv:"\u03F5",straightepsilon:"\u03F5",varepsilon:"\u03F5",equals:"=",equest:"\u225F",questeq:"\u225F",equivDD:"\u2A78",eqvparsl:"\u29E5",erDot:"\u2253",risingdotseq:"\u2253",erarr:"\u2971",escr:"\u212F",eta:"\u03B7",eth:"\xF0",euml:"\xEB",euro:"\u20AC",excl:"!",fcy:"\u0444",female:"\u2640",ffilig:"\uFB03",fflig:"\uFB00",ffllig:"\uFB04",ffr:"\u{1D523}",filig:"\uFB01",fjlig:"fj",flat:"\u266D",fllig:"\uFB02",fltns:"\u25B1",fnof:"\u0192",fopf:"\u{1D557}",fork:"\u22D4",pitchfork:"\u22D4",forkv:"\u2AD9",fpartint:"\u2A0D",frac12:"\xBD",half:"\xBD",frac13:"\u2153",frac14:"\xBC",frac15:"\u2155",frac16:"\u2159",frac18:"\u215B",frac23:"\u2154",frac25:"\u2156",frac34:"\xBE",frac35:"\u2157",frac38:"\u215C",frac45:"\u2158",frac56:"\u215A",frac58:"\u215D",frac78:"\u215E",frasl:"\u2044",frown:"\u2322",sfrown:"\u2322",fscr:"\u{1D4BB}",gEl:"\u2A8C",gtreqqless:"\u2A8C",gacute:"\u01F5",gamma:"\u03B3",gap:"\u2A86",gtrapprox:"\u2A86",gbreve:"\u011F",gcirc:"\u011D",gcy:"\u0433",gdot:"\u0121",gescc:"\u2AA9",gesdot:"\u2A80",gesdoto:"\u2A82",gesdotol:"\u2A84",gesl:"\u22DB\uFE00",gesles:"\u2A94",gfr:"\u{1D524}",gimel:"\u2137",gjcy:"\u0453",glE:"\u2A92",gla:"\u2AA5",glj:"\u2AA4",gnE:"\u2269",gneqq:"\u2269",gnap:"\u2A8A",gnapprox:"\u2A8A",gne:"\u2A88",gneq:"\u2A88",gnsim:"\u22E7",gopf:"\u{1D558}",gscr:"\u210A",gsime:"\u2A8E",gsiml:"\u2A90",gtcc:"\u2AA7",gtcir:"\u2A7A",gtdot:"\u22D7",gtrdot:"\u22D7",gtlPar:"\u2995",gtquest:"\u2A7C",gtrarr:"\u2978",gvertneqq:"\u2269\uFE00",gvnE:"\u2269\uFE00",hardcy:"\u044A",harrcir:"\u2948",harrw:"\u21AD",leftrightsquigarrow:"\u21AD",hbar:"\u210F",hslash:"\u210F",planck:"\u210F",plankv:"\u210F",hcirc:"\u0125",hearts:"\u2665",heartsuit:"\u2665",hellip:"\u2026",mldr:"\u2026",hercon:"\u22B9",hfr:"\u{1D525}",hksearow:"\u2925",searhk:"\u2925",hkswarow:"\u2926",swarhk:"\u2926",hoarr:"\u21FF",homtht:"\u223B",hookleftarrow:"\u21A9",larrhk:"\u21A9",hookrightarrow:"\u21AA",rarrhk:"\u21AA",hopf:"\u{1D559}",horbar:"\u2015",hscr:"\u{1D4BD}",hstrok:"\u0127",hybull:"\u2043",iacute:"\xED",icirc:"\xEE",icy:"\u0438",iecy:"\u0435",iexcl:"\xA1",ifr:"\u{1D526}",igrave:"\xEC",iiiint:"\u2A0C",qint:"\u2A0C",iiint:"\u222D",tint:"\u222D",iinfin:"\u29DC",iiota:"\u2129",ijlig:"\u0133",imacr:"\u012B",imath:"\u0131",inodot:"\u0131",imof:"\u22B7",imped:"\u01B5",incare:"\u2105",infin:"\u221E",infintie:"\u29DD",intcal:"\u22BA",intercal:"\u22BA",intlarhk:"\u2A17",intprod:"\u2A3C",iprod:"\u2A3C",iocy:"\u0451",iogon:"\u012F",iopf:"\u{1D55A}",iota:"\u03B9",iquest:"\xBF",iscr:"\u{1D4BE}",isinE:"\u22F9",isindot:"\u22F5",isins:"\u22F4",isinsv:"\u22F3",itilde:"\u0129",iukcy:"\u0456",iuml:"\xEF",jcirc:"\u0135",jcy:"\u0439",jfr:"\u{1D527}",jmath:"\u0237",jopf:"\u{1D55B}",jscr:"\u{1D4BF}",jsercy:"\u0458",jukcy:"\u0454",kappa:"\u03BA",kappav:"\u03F0",varkappa:"\u03F0",kcedil:"\u0137",kcy:"\u043A",kfr:"\u{1D528}",kgreen:"\u0138",khcy:"\u0445",kjcy:"\u045C",kopf:"\u{1D55C}",kscr:"\u{1D4C0}",lAtail:"\u291B",lBarr:"\u290E",lEg:"\u2A8B",lesseqqgtr:"\u2A8B",lHar:"\u2962",lacute:"\u013A",laemptyv:"\u29B4",lambda:"\u03BB",langd:"\u2991",lap:"\u2A85",lessapprox:"\u2A85",laquo:"\xAB",larrbfs:"\u291F",larrfs:"\u291D",larrlp:"\u21AB",looparrowleft:"\u21AB",larrpl:"\u2939",larrsim:"\u2973",larrtl:"\u21A2",leftarrowtail:"\u21A2",lat:"\u2AAB",latail:"\u2919",late:"\u2AAD",lates:"\u2AAD\uFE00",lbarr:"\u290C",lbbrk:"\u2772",lbrace:"{",lcub:"{",lbrack:"[",lsqb:"[",lbrke:"\u298B",lbrksld:"\u298F",lbrkslu:"\u298D",lcaron:"\u013E",lcedil:"\u013C",lcy:"\u043B",ldca:"\u2936",ldrdhar:"\u2967",ldrushar:"\u294B",ldsh:"\u21B2",le:"\u2264",leq:"\u2264",leftleftarrows:"\u21C7",llarr:"\u21C7",leftthreetimes:"\u22CB",lthree:"\u22CB",lescc:"\u2AA8",lesdot:"\u2A7F",lesdoto:"\u2A81",lesdotor:"\u2A83",lesg:"\u22DA\uFE00",lesges:"\u2A93",lessdot:"\u22D6",ltdot:"\u22D6",lfisht:"\u297C",lfr:"\u{1D529}",lgE:"\u2A91",lharul:"\u296A",lhblk:"\u2584",ljcy:"\u0459",llhard:"\u296B",lltri:"\u25FA",lmidot:"\u0140",lmoust:"\u23B0",lmoustache:"\u23B0",lnE:"\u2268",lneqq:"\u2268",lnap:"\u2A89",lnapprox:"\u2A89",lne:"\u2A87",lneq:"\u2A87",lnsim:"\u22E6",loang:"\u27EC",loarr:"\u21FD",longmapsto:"\u27FC",xmap:"\u27FC",looparrowright:"\u21AC",rarrlp:"\u21AC",lopar:"\u2985",lopf:"\u{1D55D}",loplus:"\u2A2D",lotimes:"\u2A34",lowast:"\u2217",loz:"\u25CA",lozenge:"\u25CA",lpar:"(",lparlt:"\u2993",lrhard:"\u296D",lrm:"\u200E",lrtri:"\u22BF",lsaquo:"\u2039",lscr:"\u{1D4C1}",lsime:"\u2A8D",lsimg:"\u2A8F",lsquor:"\u201A",sbquo:"\u201A",lstrok:"\u0142",ltcc:"\u2AA6",ltcir:"\u2A79",ltimes:"\u22C9",ltlarr:"\u2976",ltquest:"\u2A7B",ltrPar:"\u2996",ltri:"\u25C3",triangleleft:"\u25C3",lurdshar:"\u294A",luruhar:"\u2966",lvertneqq:"\u2268\uFE00",lvnE:"\u2268\uFE00",mDDot:"\u223A",macr:"\xAF",strns:"\xAF",male:"\u2642",malt:"\u2720",maltese:"\u2720",marker:"\u25AE",mcomma:"\u2A29",mcy:"\u043C",mdash:"\u2014",mfr:"\u{1D52A}",mho:"\u2127",micro:"\xB5",midcir:"\u2AF0",minus:"\u2212",minusdu:"\u2A2A",mlcp:"\u2ADB",models:"\u22A7",mopf:"\u{1D55E}",mscr:"\u{1D4C2}",mu:"\u03BC",multimap:"\u22B8",mumap:"\u22B8",nGg:"\u22D9\u0338",nGt:"\u226B\u20D2",nLeftarrow:"\u21CD",nlArr:"\u21CD",nLeftrightarrow:"\u21CE",nhArr:"\u21CE",nLl:"\u22D8\u0338",nLt:"\u226A\u20D2",nRightarrow:"\u21CF",nrArr:"\u21CF",nVDash:"\u22AF",nVdash:"\u22AE",nacute:"\u0144",nang:"\u2220\u20D2",napE:"\u2A70\u0338",napid:"\u224B\u0338",napos:"\u0149",natur:"\u266E",natural:"\u266E",ncap:"\u2A43",ncaron:"\u0148",ncedil:"\u0146",ncongdot:"\u2A6D\u0338",ncup:"\u2A42",ncy:"\u043D",ndash:"\u2013",neArr:"\u21D7",nearhk:"\u2924",nedot:"\u2250\u0338",nesear:"\u2928",toea:"\u2928",nfr:"\u{1D52B}",nharr:"\u21AE",nleftrightarrow:"\u21AE",nhpar:"\u2AF2",nis:"\u22FC",nisd:"\u22FA",njcy:"\u045A",nlE:"\u2266\u0338",nleqq:"\u2266\u0338",nlarr:"\u219A",nleftarrow:"\u219A",nldr:"\u2025",nopf:"\u{1D55F}",not:"\xAC",notinE:"\u22F9\u0338",notindot:"\u22F5\u0338",notinvb:"\u22F7",notinvc:"\u22F6",notnivb:"\u22FE",notnivc:"\u22FD",nparsl:"\u2AFD\u20E5",npart:"\u2202\u0338",npolint:"\u2A14",nrarr:"\u219B",nrightarrow:"\u219B",nrarrc:"\u2933\u0338",nrarrw:"\u219D\u0338",nscr:"\u{1D4C3}",nsub:"\u2284",nsubE:"\u2AC5\u0338",nsubseteqq:"\u2AC5\u0338",nsup:"\u2285",nsupE:"\u2AC6\u0338",nsupseteqq:"\u2AC6\u0338",ntilde:"\xF1",nu:"\u03BD",num:"#",numero:"\u2116",numsp:"\u2007",nvDash:"\u22AD",nvHarr:"\u2904",nvap:"\u224D\u20D2",nvdash:"\u22AC",nvge:"\u2265\u20D2",nvgt:">\u20D2",nvinfin:"\u29DE",nvlArr:"\u2902",nvle:"\u2264\u20D2",nvlt:"<\u20D2",nvltrie:"\u22B4\u20D2",nvrArr:"\u2903",nvrtrie:"\u22B5\u20D2",nvsim:"\u223C\u20D2",nwArr:"\u21D6",nwarhk:"\u2923",nwnear:"\u2927",oacute:"\xF3",ocirc:"\xF4",ocy:"\u043E",odblac:"\u0151",odiv:"\u2A38",odsold:"\u29BC",oelig:"\u0153",ofcir:"\u29BF",ofr:"\u{1D52C}",ogon:"\u02DB",ograve:"\xF2",ogt:"\u29C1",ohbar:"\u29B5",olcir:"\u29BE",olcross:"\u29BB",olt:"\u29C0",omacr:"\u014D",omega:"\u03C9",omicron:"\u03BF",omid:"\u29B6",oopf:"\u{1D560}",opar:"\u29B7",operp:"\u29B9",or:"\u2228",vee:"\u2228",ord:"\u2A5D",order:"\u2134",orderof:"\u2134",oscr:"\u2134",ordf:"\xAA",ordm:"\xBA",origof:"\u22B6",oror:"\u2A56",orslope:"\u2A57",orv:"\u2A5B",oslash:"\xF8",osol:"\u2298",otilde:"\xF5",otimesas:"\u2A36",ouml:"\xF6",ovbar:"\u233D",para:"\xB6",parsim:"\u2AF3",parsl:"\u2AFD",pcy:"\u043F",percnt:"%",period:".",permil:"\u2030",pertenk:"\u2031",pfr:"\u{1D52D}",phi:"\u03C6",phiv:"\u03D5",straightphi:"\u03D5",varphi:"\u03D5",phone:"\u260E",pi:"\u03C0",piv:"\u03D6",varpi:"\u03D6",planckh:"\u210E",plus:"+",plusacir:"\u2A23",pluscir:"\u2A22",plusdu:"\u2A25",pluse:"\u2A72",plussim:"\u2A26",plustwo:"\u2A27",pointint:"\u2A15",popf:"\u{1D561}",pound:"\xA3",prE:"\u2AB3",prap:"\u2AB7",precapprox:"\u2AB7",precnapprox:"\u2AB9",prnap:"\u2AB9",precneqq:"\u2AB5",prnE:"\u2AB5",precnsim:"\u22E8",prnsim:"\u22E8",prime:"\u2032",profalar:"\u232E",profline:"\u2312",profsurf:"\u2313",prurel:"\u22B0",pscr:"\u{1D4C5}",psi:"\u03C8",puncsp:"\u2008",qfr:"\u{1D52E}",qopf:"\u{1D562}",qprime:"\u2057",qscr:"\u{1D4C6}",quatint:"\u2A16",quest:"?",rAtail:"\u291C",rHar:"\u2964",race:"\u223D\u0331",racute:"\u0155",raemptyv:"\u29B3",rangd:"\u2992",range:"\u29A5",raquo:"\xBB",rarrap:"\u2975",rarrbfs:"\u2920",rarrc:"\u2933",rarrfs:"\u291E",rarrpl:"\u2945",rarrsim:"\u2974",rarrtl:"\u21A3",rightarrowtail:"\u21A3",rarrw:"\u219D",rightsquigarrow:"\u219D",ratail:"\u291A",ratio:"\u2236",rbbrk:"\u2773",rbrace:"}",rcub:"}",rbrack:"]",rsqb:"]",rbrke:"\u298C",rbrksld:"\u298E",rbrkslu:"\u2990",rcaron:"\u0159",rcedil:"\u0157",rcy:"\u0440",rdca:"\u2937",rdldhar:"\u2969",rdsh:"\u21B3",rect:"\u25AD",rfisht:"\u297D",rfr:"\u{1D52F}",rharul:"\u296C",rho:"\u03C1",rhov:"\u03F1",varrho:"\u03F1",rightrightarrows:"\u21C9",rrarr:"\u21C9",rightthreetimes:"\u22CC",rthree:"\u22CC",ring:"\u02DA",rlm:"\u200F",rmoust:"\u23B1",rmoustache:"\u23B1",rnmid:"\u2AEE",roang:"\u27ED",roarr:"\u21FE",ropar:"\u2986",ropf:"\u{1D563}",roplus:"\u2A2E",rotimes:"\u2A35",rpar:")",rpargt:"\u2994",rppolint:"\u2A12",rsaquo:"\u203A",rscr:"\u{1D4C7}",rtimes:"\u22CA",rtri:"\u25B9",triangleright:"\u25B9",rtriltri:"\u29CE",ruluhar:"\u2968",rx:"\u211E",sacute:"\u015B",scE:"\u2AB4",scap:"\u2AB8",succapprox:"\u2AB8",scaron:"\u0161",scedil:"\u015F",scirc:"\u015D",scnE:"\u2AB6",succneqq:"\u2AB6",scnap:"\u2ABA",succnapprox:"\u2ABA",scnsim:"\u22E9",succnsim:"\u22E9",scpolint:"\u2A13",scy:"\u0441",sdot:"\u22C5",sdote:"\u2A66",seArr:"\u21D8",sect:"\xA7",semi:";",seswar:"\u2929",tosa:"\u2929",sext:"\u2736",sfr:"\u{1D530}",sharp:"\u266F",shchcy:"\u0449",shcy:"\u0448",shy:"\xAD",sigma:"\u03C3",sigmaf:"\u03C2",sigmav:"\u03C2",varsigma:"\u03C2",simdot:"\u2A6A",simg:"\u2A9E",simgE:"\u2AA0",siml:"\u2A9D",simlE:"\u2A9F",simne:"\u2246",simplus:"\u2A24",simrarr:"\u2972",smashp:"\u2A33",smeparsl:"\u29E4",smile:"\u2323",ssmile:"\u2323",smt:"\u2AAA",smte:"\u2AAC",smtes:"\u2AAC\uFE00",softcy:"\u044C",sol:"/",solb:"\u29C4",solbar:"\u233F",sopf:"\u{1D564}",spades:"\u2660",spadesuit:"\u2660",sqcaps:"\u2293\uFE00",sqcups:"\u2294\uFE00",sscr:"\u{1D4C8}",star:"\u2606",sub:"\u2282",subset:"\u2282",subE:"\u2AC5",subseteqq:"\u2AC5",subdot:"\u2ABD",subedot:"\u2AC3",submult:"\u2AC1",subnE:"\u2ACB",subsetneqq:"\u2ACB",subne:"\u228A",subsetneq:"\u228A",subplus:"\u2ABF",subrarr:"\u2979",subsim:"\u2AC7",subsub:"\u2AD5",subsup:"\u2AD3",sung:"\u266A",sup1:"\xB9",sup2:"\xB2",sup3:"\xB3",supE:"\u2AC6",supseteqq:"\u2AC6",supdot:"\u2ABE",supdsub:"\u2AD8",supedot:"\u2AC4",suphsol:"\u27C9",suphsub:"\u2AD7",suplarr:"\u297B",supmult:"\u2AC2",supnE:"\u2ACC",supsetneqq:"\u2ACC",supne:"\u228B",supsetneq:"\u228B",supplus:"\u2AC0",supsim:"\u2AC8",supsub:"\u2AD4",supsup:"\u2AD6",swArr:"\u21D9",swnwar:"\u292A",szlig:"\xDF",target:"\u2316",tau:"\u03C4",tcaron:"\u0165",tcedil:"\u0163",tcy:"\u0442",telrec:"\u2315",tfr:"\u{1D531}",theta:"\u03B8",thetasym:"\u03D1",thetav:"\u03D1",vartheta:"\u03D1",thorn:"\xFE",times:"\xD7",timesbar:"\u2A31",timesd:"\u2A30",topbot:"\u2336",topcir:"\u2AF1",topf:"\u{1D565}",topfork:"\u2ADA",tprime:"\u2034",triangle:"\u25B5",utri:"\u25B5",triangleq:"\u225C",trie:"\u225C",tridot:"\u25EC",triminus:"\u2A3A",triplus:"\u2A39",trisb:"\u29CD",tritime:"\u2A3B",trpezium:"\u23E2",tscr:"\u{1D4C9}",tscy:"\u0446",tshcy:"\u045B",tstrok:"\u0167",uHar:"\u2963",uacute:"\xFA",ubrcy:"\u045E",ubreve:"\u016D",ucirc:"\xFB",ucy:"\u0443",udblac:"\u0171",ufisht:"\u297E",ufr:"\u{1D532}",ugrave:"\xF9",uhblk:"\u2580",ulcorn:"\u231C",ulcorner:"\u231C",ulcrop:"\u230F",ultri:"\u25F8",umacr:"\u016B",uogon:"\u0173",uopf:"\u{1D566}",upsi:"\u03C5",upsilon:"\u03C5",upuparrows:"\u21C8",uuarr:"\u21C8",urcorn:"\u231D",urcorner:"\u231D",urcrop:"\u230E",uring:"\u016F",urtri:"\u25F9",uscr:"\u{1D4CA}",utdot:"\u22F0",utilde:"\u0169",uuml:"\xFC",uwangle:"\u29A7",vBar:"\u2AE8",vBarv:"\u2AE9",vangrt:"\u299C",varsubsetneq:"\u228A\uFE00",vsubne:"\u228A\uFE00",varsubsetneqq:"\u2ACB\uFE00",vsubnE:"\u2ACB\uFE00",varsupsetneq:"\u228B\uFE00",vsupne:"\u228B\uFE00",varsupsetneqq:"\u2ACC\uFE00",vsupnE:"\u2ACC\uFE00",vcy:"\u0432",veebar:"\u22BB",veeeq:"\u225A",vellip:"\u22EE",vfr:"\u{1D533}",vopf:"\u{1D567}",vscr:"\u{1D4CB}",vzigzag:"\u299A",wcirc:"\u0175",wedbar:"\u2A5F",wedgeq:"\u2259",weierp:"\u2118",wp:"\u2118",wfr:"\u{1D534}",wopf:"\u{1D568}",wscr:"\u{1D4CC}",xfr:"\u{1D535}",xi:"\u03BE",xnis:"\u22FB",xopf:"\u{1D569}",xscr:"\u{1D4CD}",yacute:"\xFD",yacy:"\u044F",ycirc:"\u0177",ycy:"\u044B",yen:"\xA5",yfr:"\u{1D536}",yicy:"\u0457",yopf:"\u{1D56A}",yscr:"\u{1D4CE}",yucy:"\u044E",yuml:"\xFF",zacute:"\u017A",zcaron:"\u017E",zcy:"\u0437",zdot:"\u017C",zeta:"\u03B6",zfr:"\u{1D537}",zhcy:"\u0436",zigrarr:"\u21DD",zopf:"\u{1D56B}",zscr:"\u{1D4CF}",zwj:"\u200D",zwnj:"\u200C"},pB="\uE500";ay.ngsp=pB;var wv=class extends vt{constructor(n,r,s){super(s,n);l(this,"tokenType");this.tokenType=r}},d_=class{constructor(e,n,r){l(this,"tokens");l(this,"errors");l(this,"nonNormalizedIcuExpressions");this.tokens=e,this.errors=n,this.nonNormalizedIcuExpressions=r}};function IX(t,e,n,r={}){let s=new p_(new bE(t,e),n,r);return s.tokenize(),new d_(OX(s.tokens),s.errors,s.nonNormalizedIcuExpressions)}var kX=/\r\n?/g;function cv(t){return`Unexpected character "${t===rs?"EOF":String.fromCharCode(t)}"`}function _L(t){return`Unknown entity "${t}" - use the "&#;" or "&#x;" syntax`}function AX(t,e){return`Unable to parse entity "${e}" - ${t} character reference entities must end with ";"`}var LE;(function(t){t.HEX="hexadecimal",t.DEC="decimal"})(LE||(LE={}));var Ev=class{constructor(e){l(this,"error");this.error=e}},p_=class{constructor(e,n,r){l(this,"_getTagDefinition");l(this,"_cursor");l(this,"_tokenizeIcu");l(this,"_interpolationConfig");l(this,"_leadingTriviaCodePoints");l(this,"_currentTokenStart",null);l(this,"_currentTokenType",null);l(this,"_expansionCaseStack",[]);l(this,"_inInterpolation",!1);l(this,"_preserveLineEndings");l(this,"_i18nNormalizeLineEndingsInICUs");l(this,"_tokenizeBlocks");l(this,"_tokenizeLet");l(this,"tokens",[]);l(this,"errors",[]);l(this,"nonNormalizedIcuExpressions",[]);this._getTagDefinition=n,this._tokenizeIcu=r.tokenizeExpansionForms||!1,this._interpolationConfig=r.interpolationConfig||ea,this._leadingTriviaCodePoints=r.leadingTriviaChars&&r.leadingTriviaChars.map(i=>i.codePointAt(0)||0);let s=r.range||{endPos:e.content.length,startPos:0,startLine:0,startCol:0};this._cursor=r.escapedString?new f_(e,s):new OE(e,s),this._preserveLineEndings=r.preserveLineEndings||!1,this._i18nNormalizeLineEndingsInICUs=r.i18nNormalizeLineEndingsInICUs||!1,this._tokenizeBlocks=r.tokenizeBlocks??!0,this._tokenizeLet=r.tokenizeLet??!0;try{this._cursor.init()}catch(i){this.handleError(i)}}_processCarriageReturns(e){return this._preserveLineEndings?e:e.replace(kX,` +`)}tokenize(){for(;this._cursor.peek()!==rs;){let e=this._cursor.clone();try{this._attemptCharCode(cf)?this._attemptCharCode(G1)?this._attemptCharCode(gf)?this._consumeCdata(e):this._attemptCharCode(yE)?this._consumeComment(e):this._consumeDocType(e):this._attemptCharCode(qa)?this._consumeTagClose(e):this._consumeTagOpen(e):this._tokenizeLet&&this._cursor.peek()===t1&&!this._inInterpolation&&this._attemptStr("@let")?this._consumeLetDeclaration(e):this._tokenizeBlocks&&this._attemptCharCode(t1)?this._consumeBlockStart(e):this._tokenizeBlocks&&!this._inInterpolation&&!this._isInExpansionCase()&&!this._isInExpansionForm()&&this._attemptCharCode(Qs)?this._consumeBlockEnd(e):this._tokenizeIcu&&this._tokenizeExpansionForm()||this._consumeWithInterpolation(5,8,()=>this._isTextEnd(),()=>this._isTagStart())}catch(n){this.handleError(n)}}this._beginToken(33),this._endToken([])}_getBlockName(){let e=!1,n=this._cursor.clone();return this._attemptCharCodeUntilFn(r=>Yv(r)?!e:LX(r)?(e=!0,!1):!0),this._cursor.getChars(n).trim()}_consumeBlockStart(e){this._beginToken(24,e);let n=this._endToken([this._getBlockName()]);if(this._cursor.peek()===Xa)if(this._cursor.advance(),this._consumeBlockParameters(),this._attemptCharCodeUntilFn(Pr),this._attemptCharCode(wo))this._attemptCharCodeUntilFn(Pr);else{n.type=28;return}this._attemptCharCode(bo)?(this._beginToken(25),this._endToken([])):n.type=28}_consumeBlockEnd(e){this._beginToken(26,e),this._endToken([])}_consumeBlockParameters(){for(this._attemptCharCodeUntilFn(AL);this._cursor.peek()!==wo&&this._cursor.peek()!==rs;){this._beginToken(27);let e=this._cursor.clone(),n=null,r=0;for(;this._cursor.peek()!==vi&&this._cursor.peek()!==rs||n!==null;){let s=this._cursor.peek();if(s===vf)this._cursor.advance();else if(s===n)n=null;else if(n===null&&yv(s))n=s;else if(s===Xa&&n===null)r++;else if(s===wo&&n===null){if(r===0)break;r>0&&r--}this._cursor.advance()}this._endToken([this._cursor.getChars(e)]),this._attemptCharCodeUntilFn(AL)}}_consumeLetDeclaration(e){if(this._beginToken(29,e),Yv(this._cursor.peek()))this._attemptCharCodeUntilFn(Pr);else{let s=this._endToken([this._cursor.getChars(e)]);s.type=32;return}let n=this._endToken([this._getLetDeclarationName()]);if(this._attemptCharCodeUntilFn(Pr),!this._attemptCharCode(fu)){n.type=32;return}this._attemptCharCodeUntilFn(s=>Pr(s)&&!sI(s)),this._consumeLetDeclarationValue(),this._cursor.peek()===vi?(this._beginToken(31),this._endToken([]),this._cursor.advance()):(n.type=32,n.sourceSpan=this._cursor.getSpan(e))}_getLetDeclarationName(){let e=this._cursor.clone(),n=!1;return this._attemptCharCodeUntilFn(r=>Xv(r)||r===rx||r===vy||n&&Ko(r)?(n=!0,!1):!0),this._cursor.getChars(e).trim()}_consumeLetDeclarationValue(){let e=this._cursor.clone();for(this._beginToken(30,e);this._cursor.peek()!==rs;){let n=this._cursor.peek();if(n===vi)break;yv(n)&&(this._cursor.advance(),this._attemptCharCodeUntilFn(r=>r===vf?(this._cursor.advance(),!1):r===n)),this._cursor.advance()}this._endToken([this._cursor.getChars(e)])}_tokenizeExpansionForm(){if(this.isExpansionFormStart())return this._consumeExpansionFormStart(),!0;if(RX(this._cursor.peek())&&this._isInExpansionForm())return this._consumeExpansionCaseStart(),!0;if(this._cursor.peek()===Qs){if(this._isInExpansionCase())return this._consumeExpansionCaseEnd(),!0;if(this._isInExpansionForm())return this._consumeExpansionFormEnd(),!0}return!1}_beginToken(e,n=this._cursor.clone()){this._currentTokenStart=n,this._currentTokenType=e}_endToken(e,n){if(this._currentTokenStart===null)throw new wv("Programming error - attempted to end a token when there was no start to the token",this._currentTokenType,this._cursor.getSpan(n));if(this._currentTokenType===null)throw new wv("Programming error - attempted to end a token which has no token type",null,this._cursor.getSpan(this._currentTokenStart));let r={type:this._currentTokenType,parts:e,sourceSpan:(n??this._cursor).getSpan(this._currentTokenStart,this._leadingTriviaCodePoints)};return this.tokens.push(r),this._currentTokenStart=null,this._currentTokenType=null,r}_createError(e,n){this._isInExpansionForm()&&(e+=` (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`);let r=new wv(e,this._currentTokenType,n);return this._currentTokenStart=null,this._currentTokenType=null,new Ev(r)}handleError(e){if(e instanceof ly&&(e=this._createError(e.msg,this._cursor.getSpan(e.cursor))),e instanceof Ev)this.errors.push(e.error);else throw e}_attemptCharCode(e){return this._cursor.peek()===e?(this._cursor.advance(),!0):!1}_attemptCharCodeCaseInsensitive(e){return FX(this._cursor.peek(),e)?(this._cursor.advance(),!0):!1}_requireCharCode(e){let n=this._cursor.clone();if(!this._attemptCharCode(e))throw this._createError(cv(this._cursor.peek()),this._cursor.getSpan(n))}_attemptStr(e){let n=e.length;if(this._cursor.charsLeft()this._attemptStr("-->")),this._beginToken(11),this._requireStr("-->"),this._endToken([])}_consumeCdata(e){this._beginToken(12,e),this._requireStr("CDATA["),this._endToken([]),this._consumeRawText(!1,()=>this._attemptStr("]]>")),this._beginToken(13),this._requireStr("]]>"),this._endToken([])}_consumeDocType(e){this._beginToken(18,e);let n=this._cursor.clone();this._attemptUntilChar(Xl);let r=this._cursor.getChars(n);this._cursor.advance(),this._endToken([r])}_consumePrefixAndName(){let e=this._cursor.clone(),n="";for(;this._cursor.peek()!==Jl&&!MX(this._cursor.peek());)this._cursor.advance();let r;this._cursor.peek()===Jl?(n=this._cursor.getChars(e),this._cursor.advance(),r=this._cursor.clone()):r=e,this._requireCharCodeUntilFn(IL,n===""?0:1);let s=this._cursor.getChars(r);return[n,s]}_consumeTagOpen(e){let n,r,s;try{if(!Xv(this._cursor.peek()))throw this._createError(cv(this._cursor.peek()),this._cursor.getSpan(e));for(s=this._consumeTagOpenStart(e),r=s.parts[0],n=s.parts[1],this._attemptCharCodeUntilFn(Pr);this._cursor.peek()!==qa&&this._cursor.peek()!==Xl&&this._cursor.peek()!==cf&&this._cursor.peek()!==rs;)this._consumeAttributeName(),this._attemptCharCodeUntilFn(Pr),this._attemptCharCode(fu)&&(this._attemptCharCodeUntilFn(Pr),this._consumeAttributeValue()),this._attemptCharCodeUntilFn(Pr);this._consumeTagOpenEnd()}catch(o){if(o instanceof Ev){s?s.type=4:(this._beginToken(5,e),this._endToken(["<"]));return}throw o}let i=this._getTagDefinition(n).getContentType(r);i===yo.RAW_TEXT?this._consumeRawTextWithTagClose(r,n,!1):i===yo.ESCAPABLE_RAW_TEXT&&this._consumeRawTextWithTagClose(r,n,!0)}_consumeRawTextWithTagClose(e,n,r){this._consumeRawText(r,()=>!this._attemptCharCode(cf)||!this._attemptCharCode(qa)||(this._attemptCharCodeUntilFn(Pr),!this._attemptStrCaseInsensitive(n))?!1:(this._attemptCharCodeUntilFn(Pr),this._attemptCharCode(Xl))),this._beginToken(3),this._requireCharCodeUntilFn(s=>s===Xl,3),this._cursor.advance(),this._endToken([e,n])}_consumeTagOpenStart(e){this._beginToken(0,e);let n=this._consumePrefixAndName();return this._endToken(n)}_consumeAttributeName(){let e=this._cursor.peek();if(e===Zv||e===Gv)throw this._createError(cv(e),this._cursor.getSpan());this._beginToken(14);let n=this._consumePrefixAndName();this._endToken(n)}_consumeAttributeValue(){if(this._cursor.peek()===Zv||this._cursor.peek()===Gv){let e=this._cursor.peek();this._consumeQuote(e);let n=()=>this._cursor.peek()===e;this._consumeWithInterpolation(16,17,n,n),this._consumeQuote(e)}else{let e=()=>IL(this._cursor.peek());this._consumeWithInterpolation(16,17,e,e)}}_consumeQuote(e){this._beginToken(15),this._requireCharCode(e),this._endToken([String.fromCodePoint(e)])}_consumeTagOpenEnd(){let e=this._attemptCharCode(qa)?2:1;this._beginToken(e),this._requireCharCode(Xl),this._endToken([])}_consumeTagClose(e){this._beginToken(3,e),this._attemptCharCodeUntilFn(Pr);let n=this._consumePrefixAndName();this._attemptCharCodeUntilFn(Pr),this._requireCharCode(Xl),this._endToken(n)}_consumeExpansionFormStart(){this._beginToken(19),this._requireCharCode(bo),this._endToken([]),this._expansionCaseStack.push(19),this._beginToken(7);let e=this._readUntil(Gi),n=this._processCarriageReturns(e);if(this._i18nNormalizeLineEndingsInICUs)this._endToken([n]);else{let s=this._endToken([e]);n!==e&&this.nonNormalizedIcuExpressions.push(s)}this._requireCharCode(Gi),this._attemptCharCodeUntilFn(Pr),this._beginToken(7);let r=this._readUntil(Gi);this._endToken([r]),this._requireCharCode(Gi),this._attemptCharCodeUntilFn(Pr)}_consumeExpansionCaseStart(){this._beginToken(20);let e=this._readUntil(bo).trim();this._endToken([e]),this._attemptCharCodeUntilFn(Pr),this._beginToken(21),this._requireCharCode(bo),this._endToken([]),this._attemptCharCodeUntilFn(Pr),this._expansionCaseStack.push(21)}_consumeExpansionCaseEnd(){this._beginToken(22),this._requireCharCode(Qs),this._endToken([]),this._attemptCharCodeUntilFn(Pr),this._expansionCaseStack.pop()}_consumeExpansionFormEnd(){this._beginToken(23),this._requireCharCode(Qs),this._endToken([]),this._expansionCaseStack.pop()}_consumeWithInterpolation(e,n,r,s){this._beginToken(e);let i=[];for(;!r();){let o=this._cursor.clone();this._interpolationConfig&&this._attemptStr(this._interpolationConfig.start)?(this._endToken([this._processCarriageReturns(i.join(""))],o),i.length=0,this._consumeInterpolation(n,o,s),this._beginToken(e)):this._cursor.peek()===vE?(this._endToken([this._processCarriageReturns(i.join(""))]),i.length=0,this._consumeEntity(e),this._beginToken(e)):i.push(this._readChar())}this._inInterpolation=!1,this._endToken([this._processCarriageReturns(i.join(""))])}_consumeInterpolation(e,n,r){let s=[];this._beginToken(e,n),s.push(this._interpolationConfig.start);let i=this._cursor.clone(),o=null,a=!1;for(;this._cursor.peek()!==rs&&(r===null||!r());){let c=this._cursor.clone();if(this._isTagStart()){this._cursor=c,s.push(this._getProcessedChars(i,c)),this._endToken(s);return}if(o===null)if(this._attemptStr(this._interpolationConfig.end)){s.push(this._getProcessedChars(i,c)),s.push(this._interpolationConfig.end),this._endToken(s);return}else this._attemptStr("//")&&(a=!0);let u=this._cursor.peek();this._cursor.advance(),u===vf?this._cursor.advance():u===o?o=null:!a&&o===null&&yv(u)&&(o=u)}s.push(this._getProcessedChars(i,this._cursor)),this._endToken(s)}_getProcessedChars(e,n){return this._processCarriageReturns(n.getChars(e))}_isTextEnd(){return!!(this._isTagStart()||this._cursor.peek()===rs||this._tokenizeIcu&&!this._inInterpolation&&(this.isExpansionFormStart()||this._cursor.peek()===Qs&&this._isInExpansionCase())||this._tokenizeBlocks&&!this._inInterpolation&&!this._isInExpansion()&&(this._cursor.peek()===t1||this._cursor.peek()===Qs))}_isTagStart(){if(this._cursor.peek()===cf){let e=this._cursor.clone();e.advance();let n=e.peek();if(_u<=n&&n<=yy||Vf<=n&&n<=sx||n===qa||n===G1)return!0}return!1}_readUntil(e){let n=this._cursor.clone();return this._attemptUntilChar(e),this._cursor.getChars(n)}_isInExpansion(){return this._isInExpansionCase()||this._isInExpansionForm()}_isInExpansionCase(){return this._expansionCaseStack.length>0&&this._expansionCaseStack[this._expansionCaseStack.length-1]===21}_isInExpansionForm(){return this._expansionCaseStack.length>0&&this._expansionCaseStack[this._expansionCaseStack.length-1]===19}isExpansionFormStart(){if(this._cursor.peek()!==bo)return!1;if(this._interpolationConfig){let e=this._cursor.clone(),n=this._attemptStr(this._interpolationConfig.start);return this._cursor=e,!n}return!0}};function Pr(t){return!Yv(t)||t===rs}function IL(t){return Yv(t)||t===Xl||t===cf||t===qa||t===Zv||t===Gv||t===fu||t===rs}function MX(t){return(t<_u||yy$O)}function PX(t){return t===vi||t===rs||!oZ(t)}function NX(t){return t===vi||t===rs||!Xv(t)}function RX(t){return t!==Qs}function FX(t,e){return kL(t)===kL(e)}function kL(t){return t>=_u&&t<=yy?t-_u+Vf:t}function LX(t){return Xv(t)||Ko(t)||t===vy}function AL(t){return t!==vi&&Pr(t)}function OX(t){let e=[],n;for(let r=0;r0&&n.indexOf(e.peek())!==-1;)r===e&&(e=e.clone()),e.advance();let s=this.locationFromCursor(e),i=this.locationFromCursor(this),o=r!==e?this.locationFromCursor(r):s;return new Dt(s,i,o)}getChars(e){return this.input.substring(e.state.offset,this.state.offset)}charAt(e){return this.input.charCodeAt(e)}advanceState(e){if(e.offset>=this.end)throw this.state=e,new ly('Unexpected character "EOF"',this);let n=this.charAt(e.offset);n===gu?(e.line++,e.column=0):sI(n)||e.column++,e.offset++,this.updatePeek(e)}updatePeek(e){e.peek=e.offset>=this.end?rs:this.charAt(e.offset)}locationFromCursor(e){return new Qv(e.file,e.state.offset,e.state.line,e.state.column)}},f_=class t extends OE{constructor(n,r){var e=(..._0e)=>(super(..._0e),l(this,"internalState"),this);n instanceof t?(e(n),this.internalState={...n.internalState}):(e(n,r),this.internalState=this.state)}advance(){this.state=this.internalState,super.advance(),this.processEscapeSequence()}init(){super.init(),this.processEscapeSequence()}clone(){return new t(this)}getChars(n){let r=n.clone(),s="";for(;r.internalState.offsetthis.internalState.peek;if(n()===vf)if(this.internalState={...this.state},this.advanceState(this.internalState),n()===VO)this.state.peek=gu;else if(n()===HO)this.state.peek=tI;else if(n()===qO)this.state.peek=RO;else if(n()===jO)this.state.peek=eI;else if(n()===sZ)this.state.peek=X7;else if(n()===rI)this.state.peek=FO;else if(n()===UO)if(this.advanceState(this.internalState),n()===bo){this.advanceState(this.internalState);let r=this.clone(),s=0;for(;n()!==Qs;)this.advanceState(this.internalState),s++;this.state.peek=this.decodeHexDigits(r,s)}else{let r=this.clone();this.advanceState(this.internalState),this.advanceState(this.internalState),this.advanceState(this.internalState),this.state.peek=this.decodeHexDigits(r,4)}else if(n()===WO){this.advanceState(this.internalState);let r=this.clone();this.advanceState(this.internalState),this.state.peek=this.decodeHexDigits(r,2)}else if(uL(n())){let r="",s=0,i=this.clone();for(;uL(n())&&s<3;)i=this.clone(),r+=String.fromCodePoint(n()),this.advanceState(this.internalState),s++;this.state.peek=parseInt(r,8),this.internalState=i.internalState}else sI(this.internalState.peek)?(this.advanceState(this.internalState),this.state=this.internalState):this.state.peek=this.internalState.peek}decodeHexDigits(n,r){let s=this.input.slice(n.internalState.offset,n.internalState.offset+r),i=parseInt(s,16);if(isNaN(i))throw n.state=n.internalState,new ly("Invalid hexadecimal escape sequence",n);return i}},ly=class{constructor(e,n){l(this,"msg");l(this,"cursor");this.msg=e,this.cursor=n}},ns=class t extends vt{constructor(n,r,s){super(r,s);l(this,"elementName");this.elementName=n}static create(n,r,s){return new t(n,r,s)}},BE=class{constructor(e,n){l(this,"rootNodes");l(this,"errors");this.rootNodes=e,this.errors=n}},BX=class{constructor(e){l(this,"getTagDefinition");this.getTagDefinition=e}parse(e,n,r){let s=IX(e,n,this.getTagDefinition,r),i=new h_(s.tokens,this.getTagDefinition);return i.build(),new BE(i.rootNodes,s.errors.concat(i.errors))}},h_=class t{constructor(e,n){l(this,"tokens");l(this,"getTagDefinition");l(this,"_index",-1);l(this,"_peek");l(this,"_containerStack",[]);l(this,"rootNodes",[]);l(this,"errors",[]);this.tokens=e,this.getTagDefinition=n,this._advance()}build(){for(;this._peek.type!==33;)this._peek.type===0||this._peek.type===4?this._consumeStartTag(this._advance()):this._peek.type===3?this._consumeEndTag(this._advance()):this._peek.type===12?(this._closeVoidElement(),this._consumeCdata(this._advance())):this._peek.type===10?(this._closeVoidElement(),this._consumeComment(this._advance())):this._peek.type===5||this._peek.type===7||this._peek.type===6?(this._closeVoidElement(),this._consumeText(this._advance())):this._peek.type===19?this._consumeExpansion(this._advance()):this._peek.type===24?(this._closeVoidElement(),this._consumeBlockOpen(this._advance())):this._peek.type===26?(this._closeVoidElement(),this._consumeBlockClose(this._advance())):this._peek.type===28?(this._closeVoidElement(),this._consumeIncompleteBlock(this._advance())):this._peek.type===29?(this._closeVoidElement(),this._consumeLet(this._advance())):this._peek.type===32?(this._closeVoidElement(),this._consumeIncompleteLet(this._advance())):this._advance();for(let e of this._containerStack)e instanceof Ui&&this.errors.push(ns.create(e.name,e.sourceSpan,`Unclosed block "${e.name}"`))}_advance(){let e=this._peek;return this._index0)return this.errors=this.errors.concat(i.errors),null;let o=new Dt(e.sourceSpan.start,s.sourceSpan.end,e.sourceSpan.fullStart),a=new Dt(n.sourceSpan.start,s.sourceSpan.end,n.sourceSpan.fullStart);return new NE(e.parts[0],i.rootNodes,o,e.sourceSpan,a)}_collectExpansionExpTokens(e){let n=[],r=[21];for(;;){if((this._peek.type===19||this._peek.type===21)&&r.push(this._peek.type),this._peek.type===22)if(ML(r,21)){if(r.pop(),r.length===0)return n}else return this.errors.push(ns.create(null,e.sourceSpan,"Invalid ICU message. Missing '}'.")),null;if(this._peek.type===23)if(ML(r,19))r.pop();else return this.errors.push(ns.create(null,e.sourceSpan,"Invalid ICU message. Missing '}'.")),null;if(this._peek.type===33)return this.errors.push(ns.create(null,e.sourceSpan,"Invalid ICU message. Missing '}'.")),null;n.push(this._advance())}}_consumeText(e){let n=[e],r=e.sourceSpan,s=e.parts[0];if(s.length>0&&s[0]===` +`){let i=this._getContainer();i!=null&&i.children.length===0&&this.getTagDefinition(i.name).ignoreFirstLf&&(s=s.substring(1),n[0]={type:e.type,sourceSpan:e.sourceSpan,parts:[s]})}for(;this._peek.type===8||this._peek.type===5||this._peek.type===9;)e=this._advance(),n.push(e),e.type===8?s+=e.parts.join("").replace(/&([^;]+);/g,PL):e.type===9?s+=e.parts[0]:s+=e.parts.join("");if(s.length>0){let i=e.sourceSpan;this._addToParent(new Nu(s,new Dt(r.start,i.end,r.fullStart,r.details),n))}}_closeVoidElement(){let e=this._getContainer();e instanceof Hi&&this.getTagDefinition(e.name).isVoid&&this._containerStack.pop()}_consumeStartTag(e){let[n,r]=e.parts,s=[];for(;this._peek.type===14;)s.push(this._consumeAttr(this._advance()));let i=this._getElementFullName(n,r,this._getClosestParentElement()),o=!1;if(this._peek.type===2){this._advance(),o=!0;let f=this.getTagDefinition(i);f.canSelfClose||L1(i)!==null||f.isVoid||this.errors.push(ns.create(i,e.sourceSpan,`Only void, custom and foreign elements can be self closed "${e.parts[1]}"`))}else this._peek.type===1&&(this._advance(),o=!1);let a=this._peek.sourceSpan.fullStart,c=new Dt(e.sourceSpan.start,a,e.sourceSpan.fullStart),u=new Dt(e.sourceSpan.start,a,e.sourceSpan.fullStart),d=new Hi(i,s,[],c,u,void 0),p=this._getContainer();this._pushContainer(d,p instanceof Hi&&this.getTagDefinition(p.name).isClosedByChild(d.name)),o?this._popContainer(i,Hi,c):e.type===4&&(this._popContainer(i,Hi,null),this.errors.push(ns.create(i,c,`Opening tag "${i}" not terminated.`)))}_pushContainer(e,n){n&&this._containerStack.pop(),this._addToParent(e),this._containerStack.push(e)}_consumeEndTag(e){let n=this._getElementFullName(e.parts[0],e.parts[1],this._getClosestParentElement());if(this.getTagDefinition(n).isVoid)this.errors.push(ns.create(n,e.sourceSpan,`Void elements do not have end tags "${e.parts[1]}"`));else if(!this._popContainer(n,Hi,e.sourceSpan)){let r=`Unexpected closing tag "${n}". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags`;this.errors.push(ns.create(n,e.sourceSpan,r))}}_popContainer(e,n,r){let s=!1;for(let i=this._containerStack.length-1;i>=0;i--){let o=this._containerStack[i];if((o.name===e||e===null)&&o instanceof n)return o.endSourceSpan=r,o.sourceSpan.end=r!==null?r.end:o.sourceSpan.end,this._containerStack.splice(i,this._containerStack.length-i),!s;(o instanceof Ui||o instanceof Hi&&!this.getTagDefinition(o.name).closedByParent)&&(s=!0)}return!1}_consumeAttr(e){let n=O1(e.parts[0],e.parts[1]),r=e.sourceSpan.end;this._peek.type===15&&this._advance();let s="",i=[],o,a;if(this._peek.type===16)for(o=this._peek.sourceSpan,a=this._peek.sourceSpan.end;this._peek.type===16||this._peek.type===17||this._peek.type===9;){let d=this._advance();i.push(d),d.type===17?s+=d.parts.join("").replace(/&([^;]+);/g,PL):d.type===9?s+=d.parts[0]:s+=d.parts.join(""),a=r=d.sourceSpan.end}this._peek.type===15&&(r=this._advance().sourceSpan.end);let u=o&&a&&new Dt(o.start,a,o.fullStart);return new u_(n,s,new Dt(e.sourceSpan.start,r,e.sourceSpan.fullStart),e.sourceSpan,u,i.length>0?i:void 0,void 0)}_consumeBlockOpen(e){let n=[];for(;this._peek.type===27;){let a=this._advance();n.push(new RE(a.parts[0],a.sourceSpan))}this._peek.type===25&&this._advance();let r=this._peek.sourceSpan.fullStart,s=new Dt(e.sourceSpan.start,r,e.sourceSpan.fullStart),i=new Dt(e.sourceSpan.start,r,e.sourceSpan.fullStart),o=new Ui(e.parts[0],n,[],s,e.sourceSpan,i);this._pushContainer(o,!1)}_consumeBlockClose(e){this._popContainer(null,Ui,e.sourceSpan)||this.errors.push(ns.create(null,e.sourceSpan,'Unexpected closing block. The block may have been closed earlier. If you meant to write the } character, you should use the "}" HTML entity instead.'))}_consumeIncompleteBlock(e){let n=[];for(;this._peek.type===27;){let a=this._advance();n.push(new RE(a.parts[0],a.sourceSpan))}let r=this._peek.sourceSpan.fullStart,s=new Dt(e.sourceSpan.start,r,e.sourceSpan.fullStart),i=new Dt(e.sourceSpan.start,r,e.sourceSpan.fullStart),o=new Ui(e.parts[0],n,[],s,e.sourceSpan,i);this._pushContainer(o,!1),this._popContainer(null,Ui,null),this.errors.push(ns.create(e.parts[0],s,`Incomplete block "${e.parts[0]}". If you meant to write the @ character, you should use the "@" HTML entity instead.`))}_consumeLet(e){let n=e.parts[0],r,s;if(this._peek.type!==30){this.errors.push(ns.create(e.parts[0],e.sourceSpan,`Invalid @let declaration "${n}". Declaration must have a value.`));return}else r=this._advance();if(this._peek.type!==31){this.errors.push(ns.create(e.parts[0],e.sourceSpan,`Unterminated @let declaration "${n}". Declaration must be terminated with a semicolon.`));return}else s=this._advance();let i=s.sourceSpan.fullStart,o=new Dt(e.sourceSpan.start,i,e.sourceSpan.fullStart),a=e.sourceSpan.toString().lastIndexOf(n),c=e.sourceSpan.start.moveBy(a),u=new Dt(c,e.sourceSpan.end),d=new FE(n,r.parts[0],o,u,r.sourceSpan);this._addToParent(d)}_consumeIncompleteLet(e){let n=e.parts[0]??"",r=n?` "${n}"`:"";if(n.length>0){let s=e.sourceSpan.toString().lastIndexOf(n),i=e.sourceSpan.start.moveBy(s),o=new Dt(i,e.sourceSpan.end),a=new Dt(e.sourceSpan.start,e.sourceSpan.start.moveBy(0)),c=new FE(n,"",e.sourceSpan,o,a);this._addToParent(c)}this.errors.push(ns.create(e.parts[0],e.sourceSpan,`Incomplete @let declaration${r}. @let declarations must be written as \`@let = ;\``))}_getContainer(){return this._containerStack.length>0?this._containerStack[this._containerStack.length-1]:null}_getClosestParentElement(){for(let e=this._containerStack.length-1;e>-1;e--)if(this._containerStack[e]instanceof Hi)return this._containerStack[e];return null}_addToParent(e){let n=this._getContainer();n===null?this.rootNodes.push(e):n.children.push(e)}_getElementFullName(e,n,r){if(e===""&&(e=this.getTagDefinition(n).implicitNamespacePrefix||"",e===""&&r!=null)){let s=vs(r.name)[1];this.getTagDefinition(s).preventNamespaceInheritance||(e=L1(r.name))}return O1(e,n)}};function ML(t,e){return t.length>0&&t[t.length-1]===e}function PL(t,e){return ay[e]!==void 0?ay[e]||t:/^#x[a-f0-9]+$/i.test(e)?String.fromCodePoint(parseInt(e.slice(2),16)):/^#\d+$/.test(e)?String.fromCodePoint(parseInt(e.slice(1),10)):t}var fB="ngPreserveWhitespaces",$X=new Set(["pre","template","textarea","script","style"]),hB=` \f +\r \v\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF`,VX=new RegExp(`[^${hB}]`),HX=new RegExp(`[${hB}]{2,}`,"g");function jX(t){return t.some(e=>e.name===fB)}function mB(t){return t.replace(new RegExp(pB,"g")," ")}var $E=class{constructor(e,n,r=!0){l(this,"preserveSignificantWhitespace");l(this,"originalNodeMap");l(this,"requireContext");l(this,"icuExpansionDepth",0);this.preserveSignificantWhitespace=e,this.originalNodeMap=n,this.requireContext=r}visitElement(e,n){if($X.has(e.name)||jX(e.attrs)){let s=new Hi(e.name,of(this,e.attrs),e.children,e.sourceSpan,e.startSourceSpan,e.endSourceSpan,e.i18n);return this.originalNodeMap?.set(s,e),s}let r=new Hi(e.name,e.attrs,of(this,e.children),e.sourceSpan,e.startSourceSpan,e.endSourceSpan,e.i18n);return this.originalNodeMap?.set(r,e),r}visitAttribute(e,n){return e.name!==fB?e:null}visitText(e,n){let r=e.value.match(VX),s=n&&(n.prev instanceof vu||n.next instanceof vu);if(this.icuExpansionDepth>0&&this.preserveSignificantWhitespace)return e;if(r||s){let o=e.tokens.map(d=>d.type===5?zX(d):d);if(!this.preserveSignificantWhitespace&&o.length>0){let d=o[0];o.splice(0,1,UX(d,n));let p=o[o.length-1];o.splice(o.length-1,1,qX(p,n))}let a=vB(e.value),c=this.preserveSignificantWhitespace?a:WX(a,n),u=new Nu(c,e.sourceSpan,o,e.i18n);return this.originalNodeMap?.set(u,e),u}return null}visitComment(e,n){return e}visitExpansion(e,n){this.icuExpansionDepth++;let r;try{r=new vu(e.switchValue,e.type,of(this,e.cases),e.sourceSpan,e.switchValueSourceSpan,e.i18n)}finally{this.icuExpansionDepth--}return this.originalNodeMap?.set(r,e),r}visitExpansionCase(e,n){let r=new NE(e.value,of(this,e.expression),e.sourceSpan,e.valueSourceSpan,e.expSourceSpan);return this.originalNodeMap?.set(r,e),r}visitBlock(e,n){let r=new Ui(e.name,e.parameters,of(this,e.children),e.sourceSpan,e.nameSpan,e.startSourceSpan,e.endSourceSpan);return this.originalNodeMap?.set(r,e),r}visitBlockParameter(e,n){return e}visitLetDeclaration(e,n){return e}visit(e,n){if(this.requireContext&&!n)throw new Error("WhitespaceVisitor requires context. Visit via `visitAllWithSiblings` to get this context.");return!1}};function UX(t,e){return t.type!==5||!!e?.prev?t:gB(t,r=>r.trimStart())}function qX(t,e){return t.type!==5||!!e?.next?t:gB(t,r=>r.trimEnd())}function WX(t,e){let n=!e?.prev,r=!e?.next,s=n?t.trimStart():t;return r?s.trimEnd():s}function zX({type:t,parts:e,sourceSpan:n}){return{type:t,parts:[vB(e[0])],sourceSpan:n}}function gB({type:t,parts:e,sourceSpan:n},r){return{type:t,parts:[r(e[0])],sourceSpan:n}}function vB(t){return mB(t).replace(HX," ")}function of(t,e){let n=[];return e.forEach((r,s)=>{let i={prev:e[s-1],next:e[s+1]},o=r.visit(t,i);o&&n.push(o)}),n}var Ot;(function(t){t[t.Character=0]="Character",t[t.Identifier=1]="Identifier",t[t.PrivateIdentifier=2]="PrivateIdentifier",t[t.Keyword=3]="Keyword",t[t.String=4]="String",t[t.Operator=5]="Operator",t[t.Number=6]="Number",t[t.Error=7]="Error"})(Ot||(Ot={}));var rc;(function(t){t[t.Plain=0]="Plain",t[t.TemplateLiteralPart=1]="TemplateLiteralPart",t[t.TemplateLiteralEnd=2]="TemplateLiteralEnd"})(rc||(rc={}));var GX=["var","let","as","null","undefined","true","false","if","else","this","typeof"],cy=class{tokenize(e){return new m_(e).scan()}},To=class{constructor(e,n,r,s,i){l(this,"index");l(this,"end");l(this,"type");l(this,"numValue");l(this,"strValue");this.index=e,this.end=n,this.type=r,this.numValue=s,this.strValue=i}isCharacter(e){return this.type===Ot.Character&&this.numValue===e}isNumber(){return this.type===Ot.Number}isString(){return this.type===Ot.String}isOperator(e){return this.type===Ot.Operator&&this.strValue===e}isIdentifier(){return this.type===Ot.Identifier}isPrivateIdentifier(){return this.type===Ot.PrivateIdentifier}isKeyword(){return this.type===Ot.Keyword}isKeywordLet(){return this.type===Ot.Keyword&&this.strValue==="let"}isKeywordAs(){return this.type===Ot.Keyword&&this.strValue==="as"}isKeywordNull(){return this.type===Ot.Keyword&&this.strValue==="null"}isKeywordUndefined(){return this.type===Ot.Keyword&&this.strValue==="undefined"}isKeywordTrue(){return this.type===Ot.Keyword&&this.strValue==="true"}isKeywordFalse(){return this.type===Ot.Keyword&&this.strValue==="false"}isKeywordThis(){return this.type===Ot.Keyword&&this.strValue==="this"}isKeywordTypeof(){return this.type===Ot.Keyword&&this.strValue==="typeof"}isError(){return this.type===Ot.Error}toNumber(){return this.type===Ot.Number?this.numValue:-1}isTemplateLiteralPart(){return this.isString()&&this.kind===rc.TemplateLiteralPart}isTemplateLiteralEnd(){return this.isString()&&this.kind===rc.TemplateLiteralEnd}isTemplateLiteralInterpolationStart(){return this.isOperator("${")}isTemplateLiteralInterpolationEnd(){return this.isOperator("}")}toString(){switch(this.type){case Ot.Character:case Ot.Identifier:case Ot.Keyword:case Ot.Operator:case Ot.PrivateIdentifier:case Ot.String:case Ot.Error:return this.strValue;case Ot.Number:return this.numValue.toString();default:return null}}},xv=class extends To{constructor(n,r,s,i){super(n,r,Ot.String,0,s);l(this,"kind");this.kind=i}};function Cw(t,e,n){return new To(t,e,Ot.Character,n,String.fromCharCode(n))}function ZX(t,e,n){return new To(t,e,Ot.Identifier,0,n)}function YX(t,e,n){return new To(t,e,Ot.PrivateIdentifier,0,n)}function XX(t,e,n){return new To(t,e,Ot.Keyword,0,n)}function uv(t,e,n){return new To(t,e,Ot.Operator,0,n)}function QX(t,e,n){return new To(t,e,Ot.Number,n,"")}function KX(t,e,n){return new To(t,e,Ot.Error,0,n)}var Tw=new To(-1,-1,Ot.Character,0,""),m_=class{constructor(e){l(this,"input");l(this,"tokens",[]);l(this,"length");l(this,"peek",0);l(this,"index",-1);l(this,"braceStack",[]);this.input=e,this.length=e.length,this.advance()}scan(){let e=this.scanToken();for(;e!==null;)this.tokens.push(e),e=this.scanToken();return this.tokens}advance(){this.peek=++this.index>=this.length?rs:this.input.charCodeAt(this.index)}scanToken(){let e=this.input,n=this.length,r=this.peek,s=this.index;for(;r<=LO;)if(++s>=n){r=rs;break}else r=e.charCodeAt(s);if(this.peek=r,this.index=s,s>=n)return null;if(NL(r))return this.scanIdentifier();if(Ko(r))return this.scanNumber(s);let i=s;switch(r){case rf:return this.advance(),Ko(this.peek)?this.scanNumber(i):Cw(i,this.index,rf);case Xa:case wo:case gf:case uf:case Gi:case Jl:case vi:return this.scanCharacter(i,r);case bo:return this.scanOpenBrace(i,r);case Qs:return this.scanCloseBrace(i,r);case Zv:case Gv:return this.scanString();case Z1:return this.advance(),this.scanTemplateLiteralPart(i);case OO:return this.scanPrivateIdentifier();case BO:case yE:case K7:case qa:case Q7:case rZ:return this.scanOperator(i,String.fromCharCode(r));case lL:return this.scanQuestion(i);case cf:case Xl:return this.scanComplexOperator(i,String.fromCharCode(r),fu,"=");case G1:case fu:return this.scanComplexOperator(i,String.fromCharCode(r),fu,"=",fu,"=");case vE:return this.scanComplexOperator(i,"&",vE,"&");case cL:return this.scanComplexOperator(i,"|",cL,"|");case zO:for(;Yv(this.peek);)this.advance();return this.scanToken()}return this.advance(),this.error(`Unexpected character [${String.fromCharCode(r)}]`,0)}scanCharacter(e,n){return this.advance(),Cw(e,this.index,n)}scanOperator(e,n){return this.advance(),uv(e,this.index,n)}scanOpenBrace(e,n){return this.braceStack.push("expression"),this.advance(),Cw(e,this.index,n)}scanCloseBrace(e,n){return this.advance(),this.braceStack.pop()==="interpolation"?(this.tokens.push(uv(e,this.index,"}")),this.scanTemplateLiteralPart(this.index)):Cw(e,this.index,n)}scanComplexOperator(e,n,r,s,i,o){this.advance();let a=n;return this.peek==r&&(this.advance(),a+=s),i!=null&&this.peek==i&&(this.advance(),a+=o),uv(e,this.index,a)}scanIdentifier(){let e=this.index;for(this.advance();RL(this.peek);)this.advance();let n=this.input.substring(e,this.index);return GX.indexOf(n)>-1?XX(e,this.index,n):ZX(e,this.index,n)}scanPrivateIdentifier(){let e=this.index;if(this.advance(),!NL(this.peek))return this.error("Invalid character [#]",-1);for(;RL(this.peek);)this.advance();let n=this.input.substring(e,this.index);return YX(e,this.index,n)}scanNumber(e){let n=this.index===e,r=!1;for(this.advance();;){if(!Ko(this.peek))if(this.peek===vy){if(!Ko(this.input.charCodeAt(this.index-1))||!Ko(this.input.charCodeAt(this.index+1)))return this.error("Invalid numeric separator",0);r=!0}else if(this.peek===rf)n=!1;else if(JX(this.peek)){if(this.advance(),eQ(this.peek)&&this.advance(),!Ko(this.peek))return this.error("Invalid exponent",-1);n=!1}else break;this.advance()}let s=this.input.substring(e,this.index);r&&(s=s.replace(/_/g,""));let i=n?nQ(s):parseFloat(s);return QX(e,this.index,i)}scanString(){let e=this.index,n=this.peek;this.advance();let r="",s=this.index,i=this.input;for(;this.peek!=n;)if(this.peek==vf){let a=this.scanStringBackslash(r,s);if(typeof a!="string")return a;r=a,s=this.index}else{if(this.peek==rs)return this.error("Unterminated quote",0);this.advance()}let o=i.substring(s,this.index);return this.advance(),new xv(e,this.index,r+o,rc.Plain)}scanQuestion(e){this.advance();let n="?";return(this.peek===lL||this.peek===rf)&&(n+=this.peek===rf?".":"?",this.advance()),uv(e,this.index,n)}scanTemplateLiteralPart(e){let n="",r=this.index;for(;this.peek!==Z1;)if(this.peek===vf){let i=this.scanStringBackslash(n,r);if(typeof i!="string")return i;n=i,r=this.index}else if(this.peek===rx){let i=this.index;if(this.advance(),this.peek===bo)return this.braceStack.push("interpolation"),this.tokens.push(new xv(e,i,n+this.input.substring(r,i),rc.TemplateLiteralPart)),this.advance(),uv(i,this.index,this.input.substring(i,this.index))}else{if(this.peek===rs)return this.error("Unterminated template literal",0);this.advance()}let s=this.input.substring(r,this.index);return this.advance(),new xv(e,this.index,n+s,rc.TemplateLiteralEnd)}error(e,n){let r=this.index+n;return KX(r,this.index,`Lexer Error: ${e} at column ${r} in expression [${this.input}]`)}scanStringBackslash(e,n){e+=this.input.substring(n,this.index);let r;if(this.advance(),this.peek===UO){let s=this.input.substring(this.index+1,this.index+5);if(/^[0-9a-f]+$/i.test(s))r=parseInt(s,16);else return this.error(`Invalid unicode escape [\\u${s}]`,0);for(let i=0;i<5;i++)this.advance()}else r=tQ(this.peek),this.advance();return e+=String.fromCharCode(r),e}};function NL(t){return _u<=t&&t<=yy||Vf<=t&&t<=sx||t==vy||t==rx}function RL(t){return Xv(t)||Ko(t)||t==vy||t==rx}function JX(t){return t==iZ||t==eZ}function eQ(t){return t==yE||t==BO}function tQ(t){switch(t){case VO:return gu;case rI:return FO;case HO:return tI;case jO:return eI;case qO:return RO;default:return t}}function nQ(t){let e=parseInt(t);if(isNaN(e))throw new Error("Invalid integer literal when parsing "+t);return e}var g_=class{constructor(e,n,r){l(this,"strings");l(this,"expressions");l(this,"offsets");this.strings=e,this.expressions=n,this.offsets=r}},v_=class{constructor(e,n,r){l(this,"templateBindings");l(this,"warnings");l(this,"errors");this.templateBindings=e,this.warnings=n,this.errors=r}},VE=class{constructor(e){l(this,"_lexer");l(this,"errors",[]);this._lexer=e}parseAction(e,n,r,s=ea){this._checkNoInterpolation(e,n,s);let i=this._stripComments(e),o=this._lexer.tokenize(i),a=new cu(e,n,r,o,1,this.errors,0).parseChain();return new qi(a,e,n,r,this.errors)}parseBinding(e,n,r,s=ea){let i=this._parseBindingAst(e,n,r,s);return new qi(i,e,n,r,this.errors)}checkSimpleExpression(e){let n=new y_;return e.visit(n),n.errors}parseSimpleBinding(e,n,r,s=ea){let i=this._parseBindingAst(e,n,r,s),o=this.checkSimpleExpression(i);return o.length>0&&this._reportError(`Host binding expression cannot contain ${o.join(" ")}`,e,n),new qi(i,e,n,r,this.errors)}_reportError(e,n,r,s){this.errors.push(new Pv(e,n,r,s))}_parseBindingAst(e,n,r,s){this._checkNoInterpolation(e,n,s);let i=this._stripComments(e),o=this._lexer.tokenize(i);return new cu(e,n,r,o,0,this.errors,0).parseChain()}parseTemplateBindings(e,n,r,s,i){let o=this._lexer.tokenize(n);return new cu(n,r,i,o,0,this.errors,0).parseTemplateBindings({source:e,span:new bi(s,s+e.length)})}parseInterpolation(e,n,r,s,i=ea){let{strings:o,expressions:a,offsets:c}=this.splitInterpolation(e,n,s,i);if(a.length===0)return null;let u=[];for(let d=0;dd.text),u,e,n,r)}parseInterpolationExpression(e,n,r){let s=this._stripComments(e),i=this._lexer.tokenize(s),o=new cu(e,n,r,i,0,this.errors,0).parseChain(),a=["",""];return this.createInterpolationAst(a,[o],e,n,r)}createInterpolationAst(e,n,r,s,i){let o=new Su(0,r.length),a=new my(o,o.toAbsolute(i),e,n);return new qi(a,r,s,i,this.errors)}splitInterpolation(e,n,r,s=ea){let i=[],o=[],a=[],c=r?rQ(r):null,u=0,d=!1,p=!1,{start:f,end:h}=s;for(;u-1)break;i>-1&&o>-1&&this._reportError(`Got interpolation (${r}${s}) where expression was expected`,e,`at column ${i} in`,n)}_getInterpolationEndIndex(e,n,r){for(let s of this._forEachUnquotedChar(e,r)){if(e.startsWith(n,s))return s;if(e.startsWith("//",s))return e.indexOf(n,s)}return-1}*_forEachUnquotedChar(e,n){let r=null,s=0;for(let i=n;i=this.tokens.length}get inputIndex(){return this.atEOF?this.currentEndIndex:this.next.index+this.offset}get currentEndIndex(){return this.index>0?this.peek(-1).end+this.offset:this.tokens.length===0?this.input.length+this.offset:this.next.index+this.offset}get currentAbsoluteOffset(){return this.absoluteOffset+this.inputIndex}span(e,n){let r=this.currentEndIndex;if(n!==void 0&&n>this.currentEndIndex&&(r=n),e>r){let s=r;r=e,e=s}return new Su(e,r)}sourceSpan(e,n){let r=`${e}@${this.inputIndex}:${n}`;return this.sourceSpanCache.has(r)||this.sourceSpanCache.set(r,this.span(e,n).toAbsolute(this.absoluteOffset)),this.sourceSpanCache.get(r)}advance(){this.index++}withContext(e,n){this.context|=e;let r=n();return this.context^=e,r}consumeOptionalCharacter(e){return this.next.isCharacter(e)?(this.advance(),!0):!1}peekKeywordLet(){return this.next.isKeywordLet()}peekKeywordAs(){return this.next.isKeywordAs()}expectCharacter(e){this.consumeOptionalCharacter(e)||this.error(`Missing expected ${String.fromCharCode(e)}`)}consumeOptionalOperator(e){return this.next.isOperator(e)?(this.advance(),!0):!1}expectOperator(e){this.consumeOptionalOperator(e)||this.error(`Missing expected operator ${e}`)}prettyPrintToken(e){return e===Tw?"end of input":`token ${e}`}expectIdentifierOrKeyword(){let e=this.next;return!e.isIdentifier()&&!e.isKeyword()?(e.isPrivateIdentifier()?this._reportErrorForPrivateIdentifier(e,"expected identifier or keyword"):this.error(`Unexpected ${this.prettyPrintToken(e)}, expected identifier or keyword`),null):(this.advance(),e.toString())}expectIdentifierOrKeywordOrString(){let e=this.next;return!e.isIdentifier()&&!e.isKeyword()&&!e.isString()?(e.isPrivateIdentifier()?this._reportErrorForPrivateIdentifier(e,"expected identifier, keyword or string"):this.error(`Unexpected ${this.prettyPrintToken(e)}, expected identifier, keyword, or string`),""):(this.advance(),e.toString())}parseChain(){let e=[],n=this.inputIndex;for(;this.index":case"<=":case">=":this.advance();let s=this.parseAdditive();n=new vo(this.span(e),this.sourceSpan(e),r,n,s);continue}break}return n}parseAdditive(){let e=this.inputIndex,n=this.parseMultiplicative();for(;this.next.type==Ot.Operator;){let r=this.next.strValue;switch(r){case"+":case"-":this.advance();let s=this.parseMultiplicative();n=new vo(this.span(e),this.sourceSpan(e),r,n,s);continue}break}return n}parseMultiplicative(){let e=this.inputIndex,n=this.parsePrefix();for(;this.next.type==Ot.Operator;){let r=this.next.strValue;switch(r){case"*":case"%":case"/":this.advance();let s=this.parsePrefix();n=new vo(this.span(e),this.sourceSpan(e),r,n,s);continue}break}return n}parsePrefix(){if(this.next.type==Ot.Operator){let e=this.inputIndex,n=this.next.strValue,r;switch(n){case"+":return this.advance(),r=this.parsePrefix(),Rv.createPlus(this.span(e),this.sourceSpan(e),r);case"-":return this.advance(),r=this.parsePrefix(),Rv.createMinus(this.span(e),this.sourceSpan(e),r);case"!":return this.advance(),r=this.parsePrefix(),new nE(this.span(e),this.sourceSpan(e),r)}}else if(this.next.isKeywordTypeof()){this.advance();let e=this.inputIndex,n=this.parsePrefix();return new rE(this.span(e),this.sourceSpan(e),n)}return this.parseCallChain()}parseCallChain(){let e=this.inputIndex,n=this.parsePrimary();for(;;)if(this.consumeOptionalCharacter(rf))n=this.parseAccessMember(n,e,!1);else if(this.consumeOptionalOperator("?."))this.consumeOptionalCharacter(Xa)?n=this.parseCall(n,e,!0):n=this.consumeOptionalCharacter(gf)?this.parseKeyedReadOrWrite(n,e,!0):this.parseAccessMember(n,e,!0);else if(this.consumeOptionalCharacter(gf))n=this.parseKeyedReadOrWrite(n,e,!1);else if(this.consumeOptionalCharacter(Xa))n=this.parseCall(n,e,!1);else if(this.consumeOptionalOperator("!"))n=new Fv(this.span(e),this.sourceSpan(e),n);else return n}parsePrimary(){let e=this.inputIndex;if(this.consumeOptionalCharacter(Xa)){this.rparensExpected++;let n=this.parsePipe();return this.rparensExpected--,this.expectCharacter(wo),n}else{if(this.next.isKeywordNull())return this.advance(),new ji(this.span(e),this.sourceSpan(e),null);if(this.next.isKeywordUndefined())return this.advance(),new ji(this.span(e),this.sourceSpan(e),void 0);if(this.next.isKeywordTrue())return this.advance(),new ji(this.span(e),this.sourceSpan(e),!0);if(this.next.isKeywordFalse())return this.advance(),new ji(this.span(e),this.sourceSpan(e),!1);if(this.next.isKeywordThis())return this.advance(),new Cu(this.span(e),this.sourceSpan(e));if(this.consumeOptionalCharacter(gf)){this.rbracketsExpected++;let n=this.parseExpressionList(uf);return this.rbracketsExpected--,this.expectCharacter(uf),new eE(this.span(e),this.sourceSpan(e),n)}else{if(this.next.isCharacter(bo))return this.parseLiteralMap();if(this.next.isIdentifier())return this.parseAccessMember(new Yi(this.span(e),this.sourceSpan(e)),e,!1);if(this.next.isNumber()){let n=this.next.toNumber();return this.advance(),new ji(this.span(e),this.sourceSpan(e),n)}else{if(this.next.isTemplateLiteralEnd())return this.parseNoInterpolationTemplateLiteral();if(this.next.isTemplateLiteralPart())return this.parseTemplateLiteral();if(this.next.isString()&&this.next.kind===rc.Plain){let n=this.next.toString();return this.advance(),new ji(this.span(e),this.sourceSpan(e),n)}else return this.next.isPrivateIdentifier()?(this._reportErrorForPrivateIdentifier(this.next,null),new Xs(this.span(e),this.sourceSpan(e))):this.index>=this.tokens.length?(this.error(`Unexpected end of expression: ${this.input}`),new Xs(this.span(e),this.sourceSpan(e))):(this.error(`Unexpected token ${this.next}`),new Xs(this.span(e),this.sourceSpan(e)))}}}}parseExpressionList(e){let n=[];do if(!this.next.isCharacter(e))n.push(this.parsePipe());else break;while(this.consumeOptionalCharacter(Gi));return n}parseLiteralMap(){let e=[],n=[],r=this.inputIndex;if(this.expectCharacter(bo),!this.consumeOptionalCharacter(Qs)){this.rbracesExpected++;do{let s=this.inputIndex,i=this.next.isString(),o=this.expectIdentifierOrKeywordOrString(),a={key:o,quoted:i};if(e.push(a),i)this.expectCharacter(Jl),n.push(this.parsePipe());else if(this.consumeOptionalCharacter(Jl))n.push(this.parsePipe());else{a.isShorthandInitialized=!0;let c=this.span(s),u=this.sourceSpan(s);n.push(new Tu(c,u,u,new Yi(c,u),o))}}while(this.consumeOptionalCharacter(Gi)&&!this.next.isCharacter(Qs));this.rbracesExpected--,this.expectCharacter(Qs)}return new tE(this.span(r),this.sourceSpan(r),e,n)}parseAccessMember(e,n,r){let s=this.inputIndex,i=this.withContext(ff.Writable,()=>{let c=this.expectIdentifierOrKeyword()??"";return c.length===0&&this.error("Expected identifier for property access",e.span.end),c}),o=this.sourceSpan(s),a;if(r)this.consumeOptionalOperator("=")?(this.error("The '?.' operator cannot be used in the assignment"),a=new Xs(this.span(n),this.sourceSpan(n))):a=new Xw(this.span(n),this.sourceSpan(n),o,e,i);else if(this.consumeOptionalOperator("=")){if(!(this.parseFlags&1))return this.error("Bindings cannot contain assignments"),new Xs(this.span(n),this.sourceSpan(n));let c=this.parseConditional();a=new Yw(this.span(n),this.sourceSpan(n),o,e,i,c)}else a=new Tu(this.span(n),this.sourceSpan(n),o,e,i);return a}parseCall(e,n,r){let s=this.inputIndex;this.rparensExpected++;let i=this.parseCallArguments(),o=this.span(s,this.inputIndex).toAbsolute(this.absoluteOffset);this.expectCharacter(wo),this.rparensExpected--;let a=this.span(n),c=this.sourceSpan(n);return r?new sE(a,c,e,i,o):new Lv(a,c,e,i,o)}parseCallArguments(){if(this.next.isCharacter(wo))return[];let e=[];do e.push(this.parsePipe());while(this.consumeOptionalCharacter(Gi));return e}expectTemplateBindingKey(){let e="",n=!1,r=this.currentAbsoluteOffset;do e+=this.expectIdentifierOrKeywordOrString(),n=this.consumeOptionalOperator("-"),n&&(e+="-");while(n);return{source:e,span:new bi(r,r+e.length)}}parseTemplateBindings(e){let n=[];for(n.push(...this.parseDirectiveKeywordBindings(e));this.index{this.rbracketsExpected++;let s=this.parsePipe();if(s instanceof Xs&&this.error("Key access cannot be empty"),this.rbracketsExpected--,this.expectCharacter(uf),this.consumeOptionalOperator("="))if(r)this.error("The '?.' operator cannot be used in the assignment");else{let i=this.parseConditional();return new Kw(this.span(n),this.sourceSpan(n),e,s,i)}else return r?new Qw(this.span(n),this.sourceSpan(n),e,s):new Nv(this.span(n),this.sourceSpan(n),e,s);return new Xs(this.span(n),this.sourceSpan(n))})}parseDirectiveKeywordBindings(e){let n=[];this.consumeOptionalCharacter(Jl);let r=this.getDirectiveBoundTarget(),s=this.currentAbsoluteOffset,i=this.parseAsBinding(e);i||(this.consumeStatementTerminator(),s=this.currentAbsoluteOffset);let o=new bi(e.span.start,s);return n.push(new N1(o,e,r)),i&&n.push(i),n}getDirectiveBoundTarget(){if(this.next===Tw||this.peekKeywordAs()||this.peekKeywordLet())return null;let e=this.parsePipe(),{start:n,end:r}=e.span,s=this.input.substring(n,r);return new qi(e,s,this.location,this.absoluteOffset+n,this.errors)}parseAsBinding(e){if(!this.peekKeywordAs())return null;this.advance();let n=this.expectTemplateBindingKey();this.consumeStatementTerminator();let r=new bi(e.span.start,this.currentAbsoluteOffset);return new Bv(r,n,e)}parseLetBinding(){if(!this.peekKeywordLet())return null;let e=this.currentAbsoluteOffset;this.advance();let n=this.expectTemplateBindingKey(),r=null;this.consumeOptionalOperator("=")&&(r=this.expectTemplateBindingKey()),this.consumeStatementTerminator();let s=new bi(e,this.currentAbsoluteOffset);return new Bv(s,n,r)}parseNoInterpolationTemplateLiteral(){let e=this.next.strValue,n=this.inputIndex;this.advance();let r=this.span(n),s=this.sourceSpan(n);return new Ov(r,s,[new iE(r,s,e)],[])}parseTemplateLiteral(){let e=this.inputIndex,n=[],r=[];for(;this.next!==Tw;){let s=this.next;if(s.isTemplateLiteralPart()||s.isTemplateLiteralEnd()){let i=this.inputIndex;if(this.advance(),n.push(new iE(this.span(i),this.sourceSpan(i),s.strValue)),s.isTemplateLiteralEnd())break}else if(s.isTemplateLiteralInterpolationStart()){this.advance();let i=this.parsePipe();i instanceof Xs?this.error("Template literal interpolation cannot be empty"):r.push(i)}else this.advance()}return new Ov(this.span(e),this.sourceSpan(e),n,r)}consumeStatementTerminator(){this.consumeOptionalCharacter(vi)||this.consumeOptionalCharacter(Gi)}error(e,n=null){this.errors.push(new Pv(e,this.input,this.locationText(n),this.location)),this.skip()}locationText(e=null){return e==null&&(e=this.index),ea+c.length,0);r+=o,n+=o}e.set(r,n),s++}return e}function sQ(t){return t.visit(new b_)}var b_=class{visitUnary(e,n){return`${e.operator}${e.expr.visit(this,n)}`}visitBinary(e,n){return`${e.left.visit(this,n)} ${e.operation} ${e.right.visit(this,n)}`}visitChain(e,n){return e.expressions.map(r=>r.visit(this,n)).join("; ")}visitConditional(e,n){return`${e.condition.visit(this,n)} ? ${e.trueExp.visit(this,n)} : ${e.falseExp.visit(this,n)}`}visitThisReceiver(){return"this"}visitImplicitReceiver(){return""}visitInterpolation(e,n){return oQ(e.strings,e.expressions.map(r=>r.visit(this,n))).join("")}visitKeyedRead(e,n){return`${e.receiver.visit(this,n)}[${e.key.visit(this,n)}]`}visitKeyedWrite(e,n){return`${e.receiver.visit(this,n)}[${e.key.visit(this,n)}] = ${e.value.visit(this,n)}`}visitLiteralArray(e,n){return`[${e.expressions.map(r=>r.visit(this,n)).join(", ")}]`}visitLiteralMap(e,n){return`{${iQ(e.keys.map(r=>r.quoted?`'${r.key}'`:r.key),e.values.map(r=>r.visit(this,n))).map(([r,s])=>`${r}: ${s}`).join(", ")}}`}visitLiteralPrimitive(e){if(e.value===null)return"null";switch(typeof e.value){case"number":case"boolean":return e.value.toString();case"undefined":return"undefined";case"string":return`'${e.value.replace(/'/g,"\\'")}'`;default:throw new Error(`Unsupported primitive type: ${e.value}`)}}visitPipe(e,n){return`${e.exp.visit(this,n)} | ${e.name}`}visitPrefixNot(e,n){return`!${e.expression.visit(this,n)}`}visitNonNullAssert(e,n){return`${e.expression.visit(this,n)}!`}visitPropertyRead(e,n){return e.receiver instanceof Yi?e.name:`${e.receiver.visit(this,n)}.${e.name}`}visitPropertyWrite(e,n){return e.receiver instanceof Yi?`${e.name} = ${e.value.visit(this,n)}`:`${e.receiver.visit(this,n)}.${e.name} = ${e.value.visit(this,n)}`}visitSafePropertyRead(e,n){return`${e.receiver.visit(this,n)}?.${e.name}`}visitSafeKeyedRead(e,n){return`${e.receiver.visit(this,n)}?.[${e.key.visit(this,n)}]`}visitCall(e,n){return`${e.receiver.visit(this,n)}(${e.args.map(r=>r.visit(this,n)).join(", ")})`}visitSafeCall(e,n){return`${e.receiver.visit(this,n)}?.(${e.args.map(r=>r.visit(this,n)).join(", ")})`}visitTypeofExpression(e,n){return`typeof ${e.expression.visit(this,n)}`}visitASTWithSource(e,n){return e.ast.visit(this,n)}visitTemplateLiteral(e,n){let r="";for(let s=0;s[n,e[r]])}function oQ(t,e){let n=[];for(let r=0;r(t.set(e,n),t),new Map),Bf=class extends w_{constructor(){super();l(this,"_schema",new Map);l(this,"_eventSchema",new Map);dQ.forEach(n=>{let r=new Map,s=new Set,[i,o]=n.split("|"),a=o.split(","),[c,u]=i.split("^");c.split(",").forEach(p=>{this._schema.set(p.toLowerCase(),r),this._eventSchema.set(p.toLowerCase(),s)});let d=u&&this._schema.get(u.toLowerCase());if(d){for(let[p,f]of d)r.set(p,f);for(let p of this._eventSchema.get(u.toLowerCase()))s.add(p)}a.forEach(p=>{if(p.length>0)switch(p[0]){case"*":s.add(p.substring(1));break;case"!":r.set(p.substring(1),aQ);break;case"#":r.set(p.substring(1),lQ);break;case"%":r.set(p.substring(1),uQ);break;default:r.set(p,cQ)}})})}hasProperty(n,r,s){if(s.some(a=>a.name===HF.name))return!0;let i=dv(n);if(i.includes("-")){if(rL(i)||F1(i))return!1;if(s.some(a=>a.name===VF.name))return!0}return(this._schema.get(i)||this._schema.get("unknown")).has(r)}hasElement(n,r){if(r.some(i=>i.name===HF.name))return!0;let s=dv(n);return s.includes("-")&&(rL(s)||F1(s)||r.some(i=>i.name===VF.name))?!0:this._schema.has(s)}securityContext(n,r,s){s&&(r=this.getMappedPropName(r));let i=dv(n);r=r.toLowerCase();let o=$G();return o[i+"|"+r]??o["*|"+r]??Gt.NONE}getMappedPropName(n){return yB.get(n)??n}getDefaultComponentElementName(){return"ng-component"}validateProperty(n){return n.toLowerCase().startsWith("on")?{error:!0,msg:`Binding to event property '${n}' is disallowed for security reasons, please use (${n.slice(2)})=... +If '${n}' is a directive input, make sure the directive is imported by the current module.`}:{error:!1}}validateAttribute(n){return n.toLowerCase().startsWith("on")?{error:!0,msg:`Binding to event attribute '${n}' is disallowed for security reasons, please use (${n.slice(2)})=...`}:{error:!1}}allKnownElementNames(){return Array.from(this._schema.keys())}allKnownAttributesOfElement(n){let r=dv(n),s=this._schema.get(r)||this._schema.get("unknown");return Array.from(s.keys()).map(i=>pQ.get(i)??i)}allKnownEventsOfElement(n){let r=dv(n);return Array.from(this._eventSchema.get(r)??[])}normalizeAnimationStyleProperty(n){return m7(n)}normalizeAnimationStyleValue(n,r,s){let i="",o=s.toString().trim(),a=null;if(fQ(n)&&s!==0&&s!=="0")if(typeof s=="number")i="px";else{let c=s.match(/^[+-]?[\d\.]+([a-z]*)$/);c&&c[1].length==0&&(a=`Please provide a CSS unit value for ${r}:${s}`)}return{error:a,value:o+i}}};function fQ(t){switch(t){case"width":case"height":case"minWidth":case"minHeight":case"maxWidth":case"maxHeight":case"left":case"top":case"bottom":case"right":case"fontSize":case"outlineWidth":case"outlineOffset":case"paddingTop":case"paddingLeft":case"paddingBottom":case"paddingRight":case"marginTop":case"marginLeft":case"marginBottom":case"marginRight":case"borderRadius":case"borderWidth":case"borderTopWidth":case"borderLeftWidth":case"borderRightWidth":case"borderBottomWidth":case"textIndent":return!0;default:return!1}}var Nt=class{constructor({closedByChildren:e,implicitNamespacePrefix:n,contentType:r=yo.PARSABLE_DATA,closedByParent:s=!1,isVoid:i=!1,ignoreFirstLf:o=!1,preventNamespaceInheritance:a=!1,canSelfClose:c=!1}={}){l(this,"closedByChildren",{});l(this,"contentType");l(this,"closedByParent",!1);l(this,"implicitNamespacePrefix");l(this,"isVoid");l(this,"ignoreFirstLf");l(this,"canSelfClose");l(this,"preventNamespaceInheritance");e&&e.length>0&&e.forEach(u=>this.closedByChildren[u]=!0),this.isVoid=i,this.closedByParent=s||i,this.implicitNamespacePrefix=n||null,this.contentType=r,this.ignoreFirstLf=o,this.preventNamespaceInheritance=a,this.canSelfClose=c??i}isClosedByChild(e){return this.isVoid||e.toLowerCase()in this.closedByChildren}getContentType(e){return typeof this.contentType=="object"?(e===void 0?void 0:this.contentType[e])??this.contentType.default:this.contentType}},FL,tf;function bB(t){return tf||(FL=new Nt({canSelfClose:!0}),tf=Object.assign(Object.create(null),{base:new Nt({isVoid:!0}),meta:new Nt({isVoid:!0}),area:new Nt({isVoid:!0}),embed:new Nt({isVoid:!0}),link:new Nt({isVoid:!0}),img:new Nt({isVoid:!0}),input:new Nt({isVoid:!0}),param:new Nt({isVoid:!0}),hr:new Nt({isVoid:!0}),br:new Nt({isVoid:!0}),source:new Nt({isVoid:!0}),track:new Nt({isVoid:!0}),wbr:new Nt({isVoid:!0}),p:new Nt({closedByChildren:["address","article","aside","blockquote","div","dl","fieldset","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","hr","main","nav","ol","p","pre","section","table","ul"],closedByParent:!0}),thead:new Nt({closedByChildren:["tbody","tfoot"]}),tbody:new Nt({closedByChildren:["tbody","tfoot"],closedByParent:!0}),tfoot:new Nt({closedByChildren:["tbody"],closedByParent:!0}),tr:new Nt({closedByChildren:["tr"],closedByParent:!0}),td:new Nt({closedByChildren:["td","th"],closedByParent:!0}),th:new Nt({closedByChildren:["td","th"],closedByParent:!0}),col:new Nt({isVoid:!0}),svg:new Nt({implicitNamespacePrefix:"svg"}),foreignObject:new Nt({implicitNamespacePrefix:"svg",preventNamespaceInheritance:!0}),math:new Nt({implicitNamespacePrefix:"math"}),li:new Nt({closedByChildren:["li"],closedByParent:!0}),dt:new Nt({closedByChildren:["dt","dd"]}),dd:new Nt({closedByChildren:["dt","dd"],closedByParent:!0}),rb:new Nt({closedByChildren:["rb","rt","rtc","rp"],closedByParent:!0}),rt:new Nt({closedByChildren:["rb","rt","rtc","rp"],closedByParent:!0}),rtc:new Nt({closedByChildren:["rb","rtc","rp"],closedByParent:!0}),rp:new Nt({closedByChildren:["rb","rt","rtc","rp"],closedByParent:!0}),optgroup:new Nt({closedByChildren:["optgroup"],closedByParent:!0}),option:new Nt({closedByChildren:["option","optgroup"],closedByParent:!0}),pre:new Nt({ignoreFirstLf:!0}),listing:new Nt({ignoreFirstLf:!0}),style:new Nt({contentType:yo.RAW_TEXT}),script:new Nt({contentType:yo.RAW_TEXT}),title:new Nt({contentType:{default:yo.ESCAPABLE_RAW_TEXT,svg:yo.PARSABLE_DATA}}),textarea:new Nt({contentType:yo.ESCAPABLE_RAW_TEXT,ignoreFirstLf:!0})}),new Bf().allKnownElementNames().forEach(e=>{!tf[e]&&L1(e)===null&&(tf[e]=new Nt({canSelfClose:!1}))})),tf[t]??tf[t.toLowerCase()]??FL}var LL={A:"LINK",B:"BOLD_TEXT",BR:"LINE_BREAK",EM:"EMPHASISED_TEXT",H1:"HEADING_LEVEL1",H2:"HEADING_LEVEL2",H3:"HEADING_LEVEL3",H4:"HEADING_LEVEL4",H5:"HEADING_LEVEL5",H6:"HEADING_LEVEL6",HR:"HORIZONTAL_RULE",I:"ITALIC_TEXT",LI:"LIST_ITEM",LINK:"MEDIA_LINK",OL:"ORDERED_LIST",P:"PARAGRAPH",Q:"QUOTATION",S:"STRIKETHROUGH_TEXT",SMALL:"SMALL_TEXT",SUB:"SUBSTRIPT",SUP:"SUPERSCRIPT",TBODY:"TABLE_BODY",TD:"TABLE_CELL",TFOOT:"TABLE_FOOTER",TH:"TABLE_HEADER_CELL",THEAD:"TABLE_HEADER",TR:"TABLE_ROW",TT:"MONOSPACED_TEXT",U:"UNDERLINED_TEXT",UL:"UNORDERED_LIST"},E_=class{constructor(){l(this,"_placeHolderNameCounts",{});l(this,"_signatureToName",{})}getStartTagPlaceholderName(e,n,r){let s=this._hashTag(e,n,r);if(this._signatureToName[s])return this._signatureToName[s];let i=e.toUpperCase(),o=LL[i]||`TAG_${i}`,a=this._generateUniqueName(r?o:`START_${o}`);return this._signatureToName[s]=a,a}getCloseTagPlaceholderName(e){let n=this._hashClosingTag(e);if(this._signatureToName[n])return this._signatureToName[n];let r=e.toUpperCase(),s=LL[r]||`TAG_${r}`,i=this._generateUniqueName(`CLOSE_${s}`);return this._signatureToName[n]=i,i}getPlaceholderName(e,n){let r=e.toUpperCase(),s=`PH: ${r}=${n}`;if(this._signatureToName[s])return this._signatureToName[s];let i=this._generateUniqueName(r);return this._signatureToName[s]=i,i}getUniquePlaceholder(e){return this._generateUniqueName(e.toUpperCase())}getStartBlockPlaceholderName(e,n){let r=this._hashBlock(e,n);if(this._signatureToName[r])return this._signatureToName[r];let s=this._generateUniqueName(`START_BLOCK_${this._toSnakeCase(e)}`);return this._signatureToName[r]=s,s}getCloseBlockPlaceholderName(e){let n=this._hashClosingBlock(e);if(this._signatureToName[n])return this._signatureToName[n];let r=this._generateUniqueName(`CLOSE_BLOCK_${this._toSnakeCase(e)}`);return this._signatureToName[n]=r,r}_hashTag(e,n,r){let s=`<${e}`,i=Object.keys(n).sort().map(a=>` ${a}=${n[a]}`).join(""),o=r?"/>":`>`;return s+i+o}_hashClosingTag(e){return this._hashTag(`/${e}`,{},!1)}_hashBlock(e,n){let r=n.length===0?"":` (${n.sort().join("; ")})`;return`@${e}${r} {}`}_hashClosingBlock(e){return this._hashBlock(`close_${e}`,[])}_toSnakeCase(e){return e.toUpperCase().replace(/[^A-Z0-9]/g,"_")}_generateUniqueName(e){if(!this._placeHolderNameCounts.hasOwnProperty(e))return this._placeHolderNameCounts[e]=1,e;let r=this._placeHolderNameCounts[e];return this._placeHolderNameCounts[e]=r+1,`${e}_${r}`}},hQ=new VE(new cy);function mQ(t,e,n,r){let s=new x_(hQ,t,e,n,r);return(i,o,a,c,u)=>s.toI18nMessage(i,o,a,c,u)}function gQ(t,e){return e}var x_=class{constructor(e,n,r,s,i){l(this,"_expressionParser");l(this,"_interpolationConfig");l(this,"_containerBlocks");l(this,"_retainEmptyTokens");l(this,"_preserveExpressionWhitespace");this._expressionParser=e,this._interpolationConfig=n,this._containerBlocks=r,this._retainEmptyTokens=s,this._preserveExpressionWhitespace=i}toI18nMessage(e,n="",r="",s="",i){let o={isIcu:e.length==1&&e[0]instanceof vu,icuDepth:0,placeholderRegistry:new E_,placeholderToContent:{},placeholderToMessage:{},visitNodeFn:i||gQ},a=nr(this,e,o);return new As(a,o.placeholderToContent,o.placeholderToMessage,n,r,s)}visitElement(e,n){let r=nr(this,e.children,n),s={};e.attrs.forEach(u=>{s[u.name]=u.value});let i=bB(e.name).isVoid,o=n.placeholderRegistry.getStartTagPlaceholderName(e.name,s,i);n.placeholderToContent[o]={text:e.startSourceSpan.toString(),sourceSpan:e.startSourceSpan};let a="";i||(a=n.placeholderRegistry.getCloseTagPlaceholderName(e.name),n.placeholderToContent[a]={text:``,sourceSpan:e.endSourceSpan??e.sourceSpan});let c=new oc(e.name,s,o,a,r,i,e.sourceSpan,e.startSourceSpan,e.endSourceSpan);return n.visitNodeFn(e,c)}visitAttribute(e,n){let r=e.valueTokens===void 0||e.valueTokens.length===1?new av(e.value,e.valueSpan||e.sourceSpan):this._visitTextWithInterpolation(e.valueTokens,e.valueSpan||e.sourceSpan,n,e.i18n);return n.visitNodeFn(e,r)}visitText(e,n){let r=e.tokens.length===1?new av(e.value,e.sourceSpan):this._visitTextWithInterpolation(e.tokens,e.sourceSpan,n,e.i18n);return n.visitNodeFn(e,r)}visitComment(e,n){return null}visitExpansion(e,n){n.icuDepth++;let r={},s=new mE(e.switchValue,e.type,r,e.sourceSpan);if(e.cases.forEach(a=>{r[a.value]=new Ya(a.expression.map(c=>c.visit(this,n)),a.expSourceSpan)}),n.icuDepth--,n.isIcu||n.icuDepth>0){let a=n.placeholderRegistry.getUniquePlaceholder(`VAR_${e.type}`);return s.expressionPlaceholder=a,n.placeholderToContent[a]={text:e.switchValue,sourceSpan:e.switchValueSourceSpan},n.visitNodeFn(e,s)}let i=n.placeholderRegistry.getPlaceholderName("ICU",e.sourceSpan.toString());n.placeholderToMessage[i]=this.toI18nMessage([e],"","","",void 0);let o=new Af(s,i,e.sourceSpan);return n.visitNodeFn(e,o)}visitExpansionCase(e,n){throw new Error("Unreachable code")}visitBlock(e,n){let r=nr(this,e.children,n);if(this._containerBlocks.has(e.name))return new Ya(r,e.sourceSpan);let s=e.parameters.map(c=>c.expression),i=n.placeholderRegistry.getStartBlockPlaceholderName(e.name,s),o=n.placeholderRegistry.getCloseBlockPlaceholderName(e.name);n.placeholderToContent[i]={text:e.startSourceSpan.toString(),sourceSpan:e.startSourceSpan},n.placeholderToContent[o]={text:e.endSourceSpan?e.endSourceSpan.toString():"}",sourceSpan:e.endSourceSpan??e.sourceSpan};let a=new ac(e.name,s,i,o,r,e.sourceSpan,e.startSourceSpan,e.endSourceSpan);return n.visitNodeFn(e,a)}visitBlockParameter(e,n){throw new Error("Unreachable code")}visitLetDeclaration(e,n){return null}_visitTextWithInterpolation(e,n,r,s){let i=[],o=!1;for(let a of e)switch(a.type){case 8:case 17:o=!0;let[c,u,d]=a.parts,p=EQ(u)||"INTERPOLATION",f=r.placeholderRegistry.getPlaceholderName(p,u);if(this._preserveExpressionWhitespace)r.placeholderToContent[f]={text:a.parts.join(""),sourceSpan:a.sourceSpan},i.push(new Wv(u,f,a.sourceSpan));else{let h=this.normalizeExpression(a);r.placeholderToContent[f]={text:`${c}${h}${d}`,sourceSpan:a.sourceSpan},i.push(new Wv(h,f,a.sourceSpan))}break;default:if(a.parts[0].length>0||this._retainEmptyTokens){let h=i[i.length-1];h instanceof av?(h.value+=a.parts[0],h.sourceSpan=new Dt(h.sourceSpan.start,a.sourceSpan.end,h.sourceSpan.fullStart,h.sourceSpan.details)):i.push(new av(a.parts[0],a.sourceSpan))}else this._retainEmptyTokens&&i.push(new av(a.parts[0],a.sourceSpan));break}return o?(vQ(i,s),new Ya(i,n)):i[0]}normalizeExpression(e){let n=e.parts[1],r=this._expressionParser.parseBinding(n,e.sourceSpan.start.toString(),e.sourceSpan.start.offset,this._interpolationConfig);return sQ(r)}};function vQ(t,e){if(e instanceof As&&(yQ(e),e=e.nodes[0]),e instanceof Ya){bQ(e.children,t);for(let n=0;n`"${n.sourceSpan.toString()}"`).join(` +`)} + +Second pass (${e.length} tokens): +${e.map(n=>`"${n.sourceSpan.toString()}"`).join(` +`)} + `.trim());if(t.some((n,r)=>e[r].constructor!==n.constructor))throw new Error("The types of the i18n message children changed between first and second pass.")}var wQ=/\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;function EQ(t){return t.split(wQ)[2]}var S_=class extends vt{constructor(e,n){super(e,n)}},OL=new Set(["iframe|srcdoc","*|innerhtml","*|outerhtml","embed|src","iframe|src","object|codebase","object|data"]);function xQ(t,e){return t=t.toLowerCase(),e=e.toLowerCase(),OL.has(t+"|"+e)||OL.has("*|"+e)}var SQ=t=>(e,n)=>{let r=t.get(e)??e;return r instanceof cc&&(n instanceof Af&&r.i18n instanceof As&&(n.previousMessage=r.i18n),r.i18n=n),n},HE=class{constructor(e=ea,n=!1,r=!1,s=Y7,i=!0,o=!i){l(this,"interpolationConfig");l(this,"keepI18nAttrs");l(this,"enableI18nLegacyMessageIdFormat");l(this,"containerBlocks");l(this,"preserveSignificantWhitespace");l(this,"retainEmptyTokens");l(this,"hasI18nMeta",!1);l(this,"_errors",[]);this.interpolationConfig=e,this.keepI18nAttrs=n,this.enableI18nLegacyMessageIdFormat=r,this.containerBlocks=s,this.preserveSignificantWhitespace=i,this.retainEmptyTokens=o}_generateI18nMessage(e,n="",r){let{meaning:s,description:i,customId:o}=this._parseMetadata(n),c=mQ(this.interpolationConfig,this.containerBlocks,this.retainEmptyTokens,this.preserveSignificantWhitespace)(e,s,i,o,r);return this._setMessageId(c,n),this._setLegacyIds(c,n),c}visitAllWithErrors(e){let n=e.map(r=>r.visit(this,null));return new BE(n,this._errors)}visitElement(e){let n;if(j7(e)){this.hasI18nMeta=!0;let r=[],s={};for(let i of e.attrs)if(i.name===AO){let o=e.i18n||i.value,a=new Map,c=this.preserveSignificantWhitespace?e.children:of(new $E(!1,a),e.children);n=this._generateI18nMessage(c,o,SQ(a)),n.nodes.length===0&&(n=void 0),e.i18n=n}else if(i.name.startsWith(z1)){let o=i.name.slice(z1.length);xQ(e.name,o)?this._reportError(i,`Translating attribute '${o}' is disallowed for security reasons.`):s[o]=i.value}else r.push(i);if(Object.keys(s).length)for(let i of r){let o=s[i.name];o!==void 0&&i.value&&(i.i18n=this._generateI18nMessage([i],i.i18n||o))}this.keepI18nAttrs||(e.attrs=r)}return nr(this,e.children,n),e}visitExpansion(e,n){let r,s=e.i18n;if(this.hasI18nMeta=!0,s instanceof Af){let i=s.name;r=this._generateI18nMessage([e],s);let o=PO(r);o.name=i,n!==null&&(n.placeholderToMessage[i]=r)}else r=this._generateI18nMessage([e],n||s);return e.i18n=r,e}visitText(e){return e}visitAttribute(e){return e}visitComment(e){return e}visitExpansionCase(e){return e}visitBlock(e,n){return nr(this,e.children,n),e}visitBlockParameter(e,n){return e}visitLetDeclaration(e,n){return e}_parseMetadata(e){return typeof e=="string"?DQ(e):e instanceof As?e:{}}_setMessageId(e,n){e.id||(e.id=n instanceof As&&n.id||qG(e))}_setLegacyIds(e,n){if(this.enableI18nLegacyMessageIdFormat)e.legacyIds=[UG(e),SO(e)];else if(typeof n!="string"){let r=n instanceof As?n:n instanceof Af?n.previousMessage:void 0;e.legacyIds=r?r.legacyIds:[]}}_reportError(e,n){this._errors.push(new S_(e.sourceSpan,n))}},CQ="|",TQ="@@";function DQ(t=""){let e,n,r;if(t=t.trim(),t){let s=t.indexOf(TQ),i=t.indexOf(CQ),o;[o,e]=s>-1?[t.slice(0,s),t.slice(s+2)]:[t,""],[n,r]=i>-1?[o.slice(0,i),o.slice(i+1)]:["",o]}return{customId:e,meaning:n,description:r}}function _Q(t){let e=[];return t.description?e.push({tagName:"desc",text:t.description}):e.push({tagName:"suppress",text:"{msgDescriptions}"}),t.meaning&&e.push({tagName:"meaning",text:t.meaning}),i7(e)}var IQ="goog.getMsg";function kQ(t,e,n,r){let s=MQ(e),i=[Y(s)];Object.keys(r).length&&(i.push(l_(Q_(r,!0),!0)),i.push(l_({original_code:Ms(Object.keys(r).map(c=>({key:gy(c),quoted:!0,value:e.placeholders[c]?Y(e.placeholders[c].sourceSpan.toString()):Y(e.placeholderToMessage[c].nodes.map(u=>u.sourceSpan.toString()).join(""))})))})));let o=n.set(Rt(IQ).callFn(i)).toConstDecl();o.addLeadingComment(_Q(e));let a=new Qi(t.set(n));return[o,a]}var C_=class{formatPh(e){return`{$${gy(e)}}`}visitText(e){return e.value}visitContainer(e){return e.children.map(n=>n.visit(this)).join("")}visitIcu(e){return dB(e)}visitTagPlaceholder(e){return e.isVoid?this.formatPh(e.startName):`${this.formatPh(e.startName)}${e.children.map(n=>n.visit(this)).join("")}${this.formatPh(e.closeName)}`}visitPlaceholder(e){return this.formatPh(e.name)}visitBlockPlaceholder(e){return`${this.formatPh(e.startName)}${e.children.map(n=>n.visit(this)).join("")}${this.formatPh(e.closeName)}`}visitIcuPlaceholder(e,n){return this.formatPh(e.name)}},AQ=new C_;function MQ(t){return t.nodes.map(e=>e.visit(AQ,null)).join("")}function PQ(t,e,n){let{messageParts:r,placeHolders:s}=NQ(e),i=RQ(e),o=s.map(u=>n[u.text]),a=l7(e,r,s,o,i),c=t.set(a);return[new Qi(c)]}var T_=class{constructor(e,n){l(this,"placeholderToMessage");l(this,"pieces");this.placeholderToMessage=e,this.pieces=n}visitText(e){if(this.pieces[this.pieces.length-1]instanceof hu)this.pieces[this.pieces.length-1].text+=e.value;else{let n=new Dt(e.sourceSpan.fullStart,e.sourceSpan.end,e.sourceSpan.fullStart,e.sourceSpan.details);this.pieces.push(new hu(e.value,n))}}visitContainer(e){e.children.forEach(n=>n.visit(this))}visitIcu(e){this.pieces.push(new hu(dB(e),e.sourceSpan))}visitTagPlaceholder(e){this.pieces.push(this.createPlaceholderPiece(e.startName,e.startSourceSpan??e.sourceSpan)),e.isVoid||(e.children.forEach(n=>n.visit(this)),this.pieces.push(this.createPlaceholderPiece(e.closeName,e.endSourceSpan??e.sourceSpan)))}visitPlaceholder(e){this.pieces.push(this.createPlaceholderPiece(e.name,e.sourceSpan))}visitBlockPlaceholder(e){this.pieces.push(this.createPlaceholderPiece(e.startName,e.startSourceSpan??e.sourceSpan)),e.children.forEach(n=>n.visit(this)),this.pieces.push(this.createPlaceholderPiece(e.closeName,e.endSourceSpan??e.sourceSpan))}visitIcuPlaceholder(e){this.pieces.push(this.createPlaceholderPiece(e.name,e.sourceSpan,this.placeholderToMessage[e.name]))}createPlaceholderPiece(e,n,r){return new hf(gy(e,!1),n,r)}};function NQ(t){let e=[],n=new T_(t.placeholderToMessage,e);return t.nodes.forEach(r=>r.visit(n)),FQ(e)}function RQ(t){let e=t.nodes[0],n=t.nodes[t.nodes.length-1];return new Dt(e.sourceSpan.fullStart,n.sourceSpan.end,e.sourceSpan.fullStart,e.sourceSpan.details)}function FQ(t){let e=[],n=[];t[0]instanceof hf&&e.push(c1(t[0].sourceSpan.start));for(let r=0;r{let g=f.has(m.name);return f.add(m.name),!g});let h=p.flatMap(m=>{let g=o.get(m.context);if(g===void 0)throw new Error("AssertionError: Could not find i18n expression's value");return[Y(m.name),g]});d.i18nAttributesConfig=t.addConst(new Eo(h))}for(let c of t.units)for(let u of c.create)if(u.kind===E.I18nStart){let d=a.get(u.root);if(d===void 0)throw new Error("AssertionError: Could not find corresponding i18n block index for an i18n message op; was an i18n message incorrectly assumed to correspond to an attribute?");u.messageIndex=d}}function wB(t,e,n,r){let s=[],i=new Map;for(let u of r.subMessages){let d=n.get(u),{mainVar:p,statements:f}=wB(t,e,n,d);s.push(...f);let h=i.get(d.messagePlaceholder)??[];h.push(p),i.set(d.messagePlaceholder,h)}HQ(r,i),r.params=new Map([...r.params.entries()].sort());let o=Rt(t.pool.uniqueName(LQ)),a=qQ(t.pool,r.message.id,e,t.i18nUseExternalIds),c;if(r.needsPostprocessing||r.postprocessingParams.size>0){let u=Object.fromEntries([...r.postprocessingParams.entries()].sort()),d=Q_(u,!1),p=[];r.postprocessingParams.size>0&&p.push(l_(d,!0)),c=f=>Xe(y.i18nPostprocess).callFn([f,...p])}return s.push(...jQ(r.message,o,a,r.params,c)),{mainVar:o,statements:s}}function HQ(t,e){for(let[n,r]of e)r.length===1?t.params.set(n,r[0]):(t.params.set(n,Y(`${$L}${OQ}${n}${$L}`)),t.postprocessingParams.set(n,fn(r)))}function jQ(t,e,n,r,s){let i=Object.fromEntries(r),o=[$Q(e),ex(UQ(),kQ(e,t,n,i),PQ(e,t,Q_(i,!1)))];return s&&o.push(new Qi(e.set(s(e)))),o}function UQ(){return hy(Rt(BL)).notIdentical(Y("undefined",Z_)).and(Rt(BL))}function qQ(t,e,n,r){let s,i=n;if(r){let o=VL("EXTERNAL_"),a=t.uniqueName(i);s=`${o}${bv(e)}$$${a}`}else{let o=VL(i);s=t.uniqueName(o)}return Rt(s)}function WQ(t){for(let e of t.units){let n=null,r=null,s=new Map,i=new Map,o=new Map;for(let a of e.create)switch(a.kind){case E.I18nStart:if(a.context===null)throw Error("I18n op should have its context set.");n=a;break;case E.I18nEnd:n=null;break;case E.IcuStart:if(a.context===null)throw Error("Icu op should have its context set.");r=a;break;case E.IcuEnd:r=null;break;case E.Text:if(n!==null)if(s.set(a.xref,n),i.set(a.xref,r),a.icuPlaceholder!==null){let c=EY(t.allocateXrefId(),a.icuPlaceholder,[a.initialValue]);be.replace(a,c),o.set(a.xref,c)}else be.remove(a);break}for(let a of e.update)switch(a.kind){case E.InterpolateText:if(!s.has(a.target))continue;let c=s.get(a.target),u=i.get(a.target),d=o.get(a.target),p=u?u.context:c.context,f=u?Mf.Postproccessing:Mf.Creation,h=[];for(let m=0;m0){let r=GQ(n.localRefs);n.localRefs=t.addConst(r)}else n.localRefs=null;break}}function GQ(t){let e=[];for(let n of t)e.push(Y(n.name),Y(n.target));return fn(e)}function ZQ(t){for(let e of t.units){let n=Sr.HTML;for(let r of e.create)r.kind===E.ElementStart&&r.namespace!==n&&(be.insertBefore(fY(r.namespace),r),n=r.namespace)}}function YQ(t){let e=[],n=0,r=0,s=0,i=0,o=0,a=null;for(;n0&&r===0&&s===0){let u=t.substring(i,n-1).trim();e.push(a,u),o=n,i=0,a=null}break}if(a&&i){let c=t.slice(i).trim();e.push(a,c)}return e}function EB(t){return t.replace(/[a-z][A-Z]/g,e=>e.charAt(0)+"-"+e.charAt(1)).toLowerCase()}function XQ(t){let e=new Map;for(let n of t.units)for(let r of n.create)Pu(r)&&e.set(r.xref,r);for(let n of t.units)for(let r of n.create)if(r.kind===E.ExtractedAttribute&&r.bindingKind===Je.Attribute&&nB(r.expression)){let s=e.get(r.target);if(s!==void 0&&s.kind===E.Template&&s.templateKind===Js.Structural)continue;if(r.name==="style"){let i=YQ(r.expression.value);for(let o=0;o{if(!(!(o instanceof Qa)||o.name!==null)){if(!s.has(o.xref))throw new Error(`Variable ${o.xref} not yet named`);o.name=s.get(o.xref)}})}function KQ(t,e,n){if(e.name===null)switch(e.kind){case Fr.Context:e.name=`ctx_r${n.index++}`;break;case Fr.Identifier:if(t.job.compatibility===ti.TemplateDefinitionBuilder){let r=e.identifier==="ctx"?"i":"";e.name=`${e.identifier}_${r}r${++n.index}`}else e.name=`${e.identifier}_i${n.index++}`;break;default:e.name=`_r${++n.index}`;break}return e.name}function JQ(t){return t.startsWith("--")?t:EB(t)}function HL(t){let e=t.indexOf("!important");return e>-1?t.substring(0,e):t}function eK(t){for(let e of t.units){for(let n of e.create)(n.kind===E.Listener||n.kind===E.TwoWayListener)&&jL(n.handlerOps);jL(e.update)}}function jL(t){for(let e of t){if(e.kind!==E.Statement||!(e.statement instanceof Qi)||!(e.statement.expr instanceof SE))continue;let n=e.statement.expr.steps,r=!0;for(let s=e.next;s.kind!==E.ListEnd&&r;s=s.next)bs(s,(i,o)=>{if(!la(i))return i;if(r&&!(o&on.InChildOperation))switch(i.kind){case Qe.NextContext:i.steps+=n,be.remove(e),r=!1;break;case Qe.GetCurrentView:case Qe.Reference:case Qe.ContextLetReference:r=!1;break}})}}var tK="ng-container";function nK(t){for(let e of t.units){let n=new Set;for(let r of e.create)r.kind===E.ElementStart&&r.tag===tK&&(r.kind=E.ContainerStart,n.add(r.xref)),r.kind===E.ElementEnd&&n.has(r.xref)&&(r.kind=E.ContainerEnd)}}function rK(t,e){let n=t.get(e);if(n===void 0)throw new Error("All attributes should have an element-like target.");return n}function sK(t){let e=new Map;for(let n of t.units)for(let r of n.create)Pu(r)&&e.set(r.xref,r);for(let n of t.units)for(let r of n.create)(r.kind===E.ElementStart||r.kind===E.ContainerStart)&&r.nonBindable&&be.insertAfter(dY(r.xref),r),(r.kind===E.ElementEnd||r.kind===E.ContainerEnd)&&rK(e,r.xref).nonBindable&&be.insertBefore(pY(r.xref),r)}function iK(t){for(let e of t.units)for(let n of e.ops())_r(n,r=>{if(!(r instanceof sn)||r.operator!==Ye.NullishCoalesce)return r;let s=new Co(r.lhs.clone(),t.allocateXrefId()),i=new tl(s.xref);return new Ka(new sn(Ye.And,new sn(Ye.NotIdentical,s,kv),new sn(Ye.NotIdentical,i,new os(void 0))),i.clone(),r.rhs)},on.None)}function Wa(t){return e=>e.kind===t}function Sv(t,e){return n=>n.kind===t&&e===n.expression instanceof xr}function oK(t){return t.kind===E.Listener&&!(t.hostListener&&t.isAnimationListener)||t.kind===E.TwoWayListener}function aK(t){return(t.kind===E.Property||t.kind===E.TwoWayProperty)&&!(t.expression instanceof xr)}var lK=[{test:t=>t.kind===E.Listener&&t.hostListener&&t.isAnimationListener},{test:oK}],cK=[{test:Wa(E.StyleMap),transform:jE},{test:Wa(E.ClassMap),transform:jE},{test:Wa(E.StyleProp)},{test:Wa(E.ClassProp)},{test:Sv(E.Attribute,!0)},{test:Sv(E.Property,!0)},{test:aK},{test:Sv(E.Attribute,!1)}],uK=[{test:Sv(E.HostProperty,!0)},{test:Sv(E.HostProperty,!1)},{test:Wa(E.Attribute)},{test:Wa(E.StyleMap),transform:jE},{test:Wa(E.ClassMap),transform:jE},{test:Wa(E.StyleProp)},{test:Wa(E.ClassProp)}],UL=new Set([E.Listener,E.TwoWayListener,E.StyleMap,E.ClassMap,E.StyleProp,E.ClassProp,E.Property,E.TwoWayProperty,E.HostProperty,E.Attribute]);function dK(t){for(let e of t.units){qL(e.create,lK);let n=e.job.kind===Oe.Host?uK:cK;qL(e.update,n)}}function qL(t,e){let n=[],r=null;for(let s of t){let i=EE(s)?s.target:null;(!UL.has(s.kind)||i!==r&&r!==null&&i!==null)&&(be.insertBefore(WL(n,e),s),n=[],r=null),UL.has(s.kind)&&(n.push(s),be.remove(s),r=i??r)}t.push(WL(n,e))}function WL(t,e){let n=Array.from(e,()=>new Array);for(let r of t){let s=e.findIndex(i=>i.test(r));n[s].push(r)}return n.flatMap((r,s)=>{let i=e[s].transform;return i?i(r):r})}function jE(t){return t.slice(t.length-1)}function pK(t){for(let e of t.units){let n=lB(e);for(let r of e.ops())switch(r.kind){case E.Binding:let s=hK(n,r.target);fK(r.name)&&s.kind===E.Projection&&be.remove(r);break}}}function fK(t){return t.toLowerCase()==="select"}function hK(t,e){let n=t.get(e);if(n===void 0)throw new Error("All attributes should have an slottable target.");return n}function mK(t){for(let e of t.units)gK(e)}function gK(t){for(let e of t.update)bs(e,(n,r)=>{if(la(n)&&n.kind===Qe.PipeBinding){if(r&on.InChildOperation)throw new Error("AssertionError: pipe bindings should not appear in child expressions");if(t.job.compatibility){if(e.target==null)throw new Error("AssertionError: expected slot handle to be assigned for pipe creation");vK(t,e.target,n)}else t.create.push(iB(n.target,n.targetSlot,n.name))}})}function vK(t,e,n){for(let r=t.create.head.next;r.kind!==E.ListEnd;r=r.next){if(!jf(r)||r.xref!==e)continue;for(;r.next.kind===E.Pipe;)r=r.next;let s=iB(n.target,n.targetSlot,n.name);be.insertBefore(s,r.next);return}throw new Error(`AssertionError: unable to find insertion point for pipe ${n.name}`)}function yK(t){for(let e of t.units)for(let n of e.update)_r(n,r=>!(r instanceof Nf)||r.args.length<=4?r:new DE(r.target,r.targetSlot,r.name,fn(r.args),r.args.length),on.None)}function bK(t){xB(t.root,0)}function xB(t,e){let n=null;for(let r of t.create)switch(r.kind){case E.I18nStart:r.subTemplateIndex=e===0?null:e,n=r;break;case E.I18nEnd:n.subTemplateIndex===null&&(e=0),n=null;break;case E.Template:e=u1(t.job.views.get(r.xref),n,r.i18nPlaceholder,e);break;case E.RepeaterCreate:let s=t.job.views.get(r.xref);e=u1(s,n,r.i18nPlaceholder,e),r.emptyView!==null&&(e=u1(t.job.views.get(r.emptyView),n,r.emptyI18nPlaceholder,e));break}return e}function u1(t,e,n,r){if(n!==void 0){if(e===null)throw Error("Expected template with i18n placeholder to be in an i18n block.");r++,wK(t,e)}return xB(t,r)}function wK(t,e){if(t.create.head.next?.kind!==E.I18nStart){let n=t.job.allocateXrefId();be.insertAfter(ax(n,e.message,e.root,null),t.create.head),be.insertBefore(lx(n,null),t.create.tail)}}function EK(t){for(let e of t.units)for(let n of e.ops())bs(n,r=>{if(!(r instanceof Au)||r.body===null)return;let s=new D_(r.args.length);r.fn=t.pool.getSharedConstant(s,r.body),r.body=null})}var D_=class extends mf{constructor(n){super();l(this,"numArgs");this.numArgs=n}keyOf(n){return n instanceof Pf?`param(${n.index})`:super.keyOf(n)}toSharedConstantDeclaration(n,r){let s=[];for(let o=0;oo instanceof Pf?Rt("a"+o.index):o,on.None);return new ys(n,new Eu(s,i),void 0,Wr.Final)}};function xK(t){for(let e of t.units)for(let n of e.update)_r(n,(r,s)=>s&on.InChildOperation?r:r instanceof Eo?SK(r):r instanceof ia?CK(r):r,on.None)}function SK(t){let e=[],n=[];for(let r of t.entries)if(r.isConstant())e.push(r);else{let s=n.length;n.push(r),e.push(new Pf(s))}return new Au(fn(e),n)}function CK(t){let e=[],n=[];for(let r of t.entries)if(r.value.isConstant())e.push(r);else{let s=n.length;n.push(r.value),e.push(new Sf(r.key,new Pf(s),r.quoted))}return new Au(Ms(e),n)}function TK(t,e,n,r,s){return dx(y.element,t,e,n,r,s)}function DK(t,e,n,r,s){return dx(y.elementStart,t,e,n,r,s)}function dx(t,e,n,r,s,i){let o=[Y(e)];return n!==null&&o.push(Y(n)),s!==null?o.push(Y(r),Y(s)):r!==null&&o.push(Y(r)),jt(t,o,i)}function _K(t){return jt(y.elementEnd,[],t)}function IK(t,e,n,r){return dx(y.elementContainerStart,t,null,e,n,r)}function kK(t,e,n,r){return dx(y.elementContainer,t,null,e,n,r)}function AK(){return jt(y.elementContainerEnd,[],null)}function MK(t,e,n,r,s,i,o,a){let c=[Y(t),e,Y(n),Y(r),Y(s),Y(i)];for(o!==null&&(c.push(Y(o)),c.push(Xe(y.templateRefExtractor)));c[c.length-1].isEquivalent(kv);)c.pop();return jt(y.templateCreate,c,a)}function PK(){return jt(y.disableBindings,[],null)}function NK(){return jt(y.enableBindings,[],null)}function RK(t,e,n,r,s){let i=[Y(t),e];return n!==null&&(i.push(Y(!1)),i.push(Xe(n))),jt(r?y.syntheticHostListener:y.listener,i,s)}function zL(t,e){return Xe(y.twoWayBindingSet).callFn([t,e])}function FK(t,e,n){return jt(y.twoWayListener,[Y(t),e],n)}function LK(t,e){return jt(y.pipe,[Y(t),Y(e)],null)}function OK(){return jt(y.namespaceHTML,[],null)}function BK(){return jt(y.namespaceSVG,[],null)}function $K(){return jt(y.namespaceMathML,[],null)}function VK(t,e){return jt(y.advance,t>1?[Y(t)]:[],e)}function HK(t){return Xe(y.reference).callFn([Y(t)])}function jK(t){return Xe(y.nextContext).callFn(t===1?[]:[Y(t)])}function UK(){return Xe(y.getCurrentView).callFn([])}function qK(t){return Xe(y.restoreView).callFn([t])}function WK(t){return Xe(y.resetView).callFn([t])}function zK(t,e,n){let r=[Y(t,null)];return e!==""&&r.push(Y(e)),jt(y.text,r,n)}function GK(t,e,n,r,s,i,o,a,c,u,d){let p=[Y(t),Y(e),n??Y(null),Y(r),Y(s),Y(i),o??Y(null),a??Y(null),c?Xe(y.deferEnableTimerScheduling):Y(null),Y(d)],f;for(;(f=p[p.length-1])!==null&&f instanceof os&&f.value===null;)p.pop();return jt(y.defer,p,u)}var ZK=new Map([[yn.Idle,{none:y.deferOnIdle,prefetch:y.deferPrefetchOnIdle,hydrate:y.deferHydrateOnIdle}],[yn.Immediate,{none:y.deferOnImmediate,prefetch:y.deferPrefetchOnImmediate,hydrate:y.deferHydrateOnImmediate}],[yn.Timer,{none:y.deferOnTimer,prefetch:y.deferPrefetchOnTimer,hydrate:y.deferHydrateOnTimer}],[yn.Hover,{none:y.deferOnHover,prefetch:y.deferPrefetchOnHover,hydrate:y.deferHydrateOnHover}],[yn.Interaction,{none:y.deferOnInteraction,prefetch:y.deferPrefetchOnInteraction,hydrate:y.deferHydrateOnInteraction}],[yn.Viewport,{none:y.deferOnViewport,prefetch:y.deferPrefetchOnViewport,hydrate:y.deferHydrateOnViewport}],[yn.Never,{none:y.deferHydrateNever,prefetch:y.deferHydrateNever,hydrate:y.deferHydrateNever}]]);function YK(t,e,n,r){let s=ZK.get(t)?.[n];if(s===void 0)throw new Error(`Unable to determine instruction for trigger ${t}`);return jt(s,e.map(i=>Y(i)),r)}function XK(t){return jt(y.projectionDef,t?[t]:[],null)}function QK(t,e,n,r,s,i,o){let a=[Y(t)];return(e!==0||n!==null||r!==null)&&(a.push(Y(e)),n!==null&&a.push(n),r!==null&&(n===null&&a.push(Y(null)),a.push(Rt(r),Y(s),Y(i)))),jt(y.projection,a,o)}function KK(t,e,n,r){let s=[Y(t),Y(e)];return n!==null&&s.push(Y(n)),jt(y.i18nStart,s,r)}function JK(t,e,n,r,s,i,o,a,c,u,d,p,f,h){let m=[Y(t),Rt(e),Y(n),Y(r),Y(s),Y(i),o];return(a||c!==null)&&(m.push(Y(a)),c!==null&&(m.push(Rt(c),Y(u),Y(d)),(p!==null||f!==null)&&m.push(Y(p)),f!==null&&m.push(Y(f)))),jt(y.repeaterCreate,m,h)}function eJ(t,e){return jt(y.repeater,[t],e)}function tJ(t,e,n){return t==="prefetch"?jt(y.deferPrefetchWhen,[e],n):t==="hydrate"?jt(y.deferHydrateWhen,[e],n):jt(y.deferWhen,[e],n)}function nJ(t,e){return jt(y.declareLet,[Y(t)],e)}function rJ(t,e){return Xe(y.storeLet).callFn([t],e)}function sJ(t){return Xe(y.readContextLet).callFn([Y(t)])}function iJ(t,e,n,r){let s=[Y(t),Y(e)];return n&&s.push(Y(n)),jt(y.i18n,s,r)}function oJ(t){return jt(y.i18nEnd,[],t)}function aJ(t,e){let n=[Y(t),Y(e)];return jt(y.i18nAttributes,n,null)}function lJ(t,e,n,r){let s=[Y(t),e];return n!==null&&s.push(n),jt(y.property,s,r)}function cJ(t,e,n,r){let s=[Y(t),e];return n!==null&&s.push(n),jt(y.twoWayProperty,s,r)}function uJ(t,e,n,r){let s=[Y(t),e];return(n!==null||r!==null)&&s.push(n??Y(null)),r!==null&&s.push(Y(r)),jt(y.attribute,s,null)}function dJ(t,e,n,r){let s=[Y(t),e];return n!==null&&s.push(Y(n)),jt(y.styleProp,s,r)}function pJ(t,e,n){return jt(y.classProp,[Y(t),e],n)}function fJ(t,e){return jt(y.styleMap,[t],e)}function hJ(t,e){return jt(y.classMap,[t],e)}var GL=[y.pipeBind1,y.pipeBind2,y.pipeBind3,y.pipeBind4];function mJ(t,e,n){if(n.length<1||n.length>GL.length)throw new Error("pipeBind() argument count out of bounds");let r=GL[n.length-1];return Xe(r).callFn([Y(t),Y(e),...n])}function gJ(t,e,n){return Xe(y.pipeBindV).callFn([Y(t),Y(e),n])}function vJ(t,e,n){let r=Uf(t,e);return qf(AJ,[],r,[],n)}function yJ(t,e){return jt(y.i18nExp,[t],e)}function bJ(t,e){return jt(y.i18nApply,[Y(t)],e)}function wJ(t,e,n,r,s){let i=Uf(e,n),o=[];return r!==null&&o.push(r),qf(MJ,[Y(t)],i,o,s)}function EJ(t,e,n,r,s){let i=Uf(e,n),o=[];return r!==null&&o.push(r),qf(NJ,[Y(t)],i,o,s)}function xJ(t,e,n,r,s){let i=Uf(e,n),o=[];return r!==null&&o.push(Y(r)),qf(PJ,[Y(t)],i,o,s)}function SJ(t,e,n){let r=Uf(t,e);return qf(RJ,[],r,[],n)}function CJ(t,e,n){let r=Uf(t,e);return qf(FJ,[],r,[],n)}function TJ(t,e,n,r){let s=[Y(t),e];return n!==null&&s.push(n),jt(y.hostProperty,s,r)}function DJ(t,e,n){return jt(y.syntheticHostProperty,[Y(t),e],n)}function _J(t,e,n){return SB(LJ,[Y(t),e],n,[],null)}function IJ(t,e){return jt(y.attachSourceLocations,[Y(t),e],null)}function Uf(t,e){if(t.length<1||e.length!==t.length-1)throw new Error("AssertionError: expected specific shape of args for strings/expressions in interpolation");let n=[];if(e.length===1&&t[0]===""&&t[1]==="")n.push(e[0]);else{let r;for(r=0;r{if(t%2===0)throw new Error("Expected odd number of arguments");return(t-1)/2}},MJ={constant:[y.propertyInterpolate,y.propertyInterpolate1,y.propertyInterpolate2,y.propertyInterpolate3,y.propertyInterpolate4,y.propertyInterpolate5,y.propertyInterpolate6,y.propertyInterpolate7,y.propertyInterpolate8],variable:y.propertyInterpolateV,mapping:t=>{if(t%2===0)throw new Error("Expected odd number of arguments");return(t-1)/2}},PJ={constant:[y.styleProp,y.stylePropInterpolate1,y.stylePropInterpolate2,y.stylePropInterpolate3,y.stylePropInterpolate4,y.stylePropInterpolate5,y.stylePropInterpolate6,y.stylePropInterpolate7,y.stylePropInterpolate8],variable:y.stylePropInterpolateV,mapping:t=>{if(t%2===0)throw new Error("Expected odd number of arguments");return(t-1)/2}},NJ={constant:[y.attribute,y.attributeInterpolate1,y.attributeInterpolate2,y.attributeInterpolate3,y.attributeInterpolate4,y.attributeInterpolate5,y.attributeInterpolate6,y.attributeInterpolate7,y.attributeInterpolate8],variable:y.attributeInterpolateV,mapping:t=>{if(t%2===0)throw new Error("Expected odd number of arguments");return(t-1)/2}},RJ={constant:[y.styleMap,y.styleMapInterpolate1,y.styleMapInterpolate2,y.styleMapInterpolate3,y.styleMapInterpolate4,y.styleMapInterpolate5,y.styleMapInterpolate6,y.styleMapInterpolate7,y.styleMapInterpolate8],variable:y.styleMapInterpolateV,mapping:t=>{if(t%2===0)throw new Error("Expected odd number of arguments");return(t-1)/2}},FJ={constant:[y.classMap,y.classMapInterpolate1,y.classMapInterpolate2,y.classMapInterpolate3,y.classMapInterpolate4,y.classMapInterpolate5,y.classMapInterpolate6,y.classMapInterpolate7,y.classMapInterpolate8],variable:y.classMapInterpolateV,mapping:t=>{if(t%2===0)throw new Error("Expected odd number of arguments");return(t-1)/2}},LJ={constant:[y.pureFunction0,y.pureFunction1,y.pureFunction2,y.pureFunction3,y.pureFunction4,y.pureFunction5,y.pureFunction6,y.pureFunction7,y.pureFunction8],variable:y.pureFunctionV,mapping:t=>t};function SB(t,e,n,r,s){let i=t.mapping(n.length);if(i{if(v.slot===null)throw new Error("No slot was assigned for source location");return fn([Y(v.slot),Y(w),Y(b),Y(D)])}));be.replace(n,IJ(n.templatePath,g));break;case E.Statement:break;default:throw new Error(`AssertionError: Unsupported reification of create op ${E[n.kind]}`)}}function lI(t,e){for(let n of e)switch(_r(n,CB,on.None),n.kind){case E.Advance:be.replace(n,VK(n.delta,n.sourceSpan));break;case E.Property:n.expression instanceof xr?be.replace(n,wJ(n.name,n.expression.strings,n.expression.expressions,n.sanitizer,n.sourceSpan)):be.replace(n,lJ(n.name,n.expression,n.sanitizer,n.sourceSpan));break;case E.TwoWayProperty:be.replace(n,cJ(n.name,n.expression,n.sanitizer,n.sourceSpan));break;case E.StyleProp:n.expression instanceof xr?be.replace(n,xJ(n.name,n.expression.strings,n.expression.expressions,n.unit,n.sourceSpan)):be.replace(n,dJ(n.name,n.expression,n.unit,n.sourceSpan));break;case E.ClassProp:be.replace(n,pJ(n.name,n.expression,n.sourceSpan));break;case E.StyleMap:n.expression instanceof xr?be.replace(n,SJ(n.expression.strings,n.expression.expressions,n.sourceSpan)):be.replace(n,fJ(n.expression,n.sourceSpan));break;case E.ClassMap:n.expression instanceof xr?be.replace(n,CJ(n.expression.strings,n.expression.expressions,n.sourceSpan)):be.replace(n,hJ(n.expression,n.sourceSpan));break;case E.I18nExpression:be.replace(n,yJ(n.expression,n.sourceSpan));break;case E.I18nApply:be.replace(n,bJ(n.handle.slot,n.sourceSpan));break;case E.InterpolateText:be.replace(n,vJ(n.interpolation.strings,n.interpolation.expressions,n.sourceSpan));break;case E.Attribute:n.expression instanceof xr?be.replace(n,EJ(n.name,n.expression.strings,n.expression.expressions,n.sanitizer,n.sourceSpan)):be.replace(n,uJ(n.name,n.expression,n.sanitizer,n.namespace));break;case E.HostProperty:if(n.expression instanceof xr)throw new Error("not yet handled");n.isAnimationTrigger?be.replace(n,DJ(n.name,n.expression,n.sourceSpan)):be.replace(n,TJ(n.name,n.expression,n.sanitizer,n.sourceSpan));break;case E.Variable:if(n.variable.name===null)throw new Error(`AssertionError: unnamed variable ${n.xref}`);be.replace(n,So(new ys(n.variable.name,n.initializer,void 0,Wr.Final)));break;case E.Conditional:if(n.processed===null)throw new Error("Conditional test was not set.");be.replace(n,kJ(n.processed,n.contextValue,n.sourceSpan));break;case E.Repeater:be.replace(n,eJ(n.collection,n.sourceSpan));break;case E.DeferWhen:be.replace(n,tJ(n.modifier,n.expr,n.sourceSpan));break;case E.StoreLet:throw new Error(`AssertionError: unexpected storeLet ${n.declaredName}`);case E.Statement:break;default:throw new Error(`AssertionError: Unsupported reification of update op ${E[n.kind]}`)}}function CB(t){if(!la(t))return t;switch(t.kind){case Qe.NextContext:return jK(t.steps);case Qe.Reference:return HK(t.targetSlot.slot+1+t.offset);case Qe.LexicalRead:throw new Error(`AssertionError: unresolved LexicalRead of ${t.name}`);case Qe.TwoWayBindingSet:throw new Error("AssertionError: unresolved TwoWayBindingSet");case Qe.RestoreView:if(typeof t.view=="number")throw new Error("AssertionError: unresolved RestoreView");return qK(t.view);case Qe.ResetView:return WK(t.expr);case Qe.GetCurrentView:return UK();case Qe.ReadVariable:if(t.name===null)throw new Error(`Read of unnamed variable ${t.xref}`);return Rt(t.name);case Qe.ReadTemporaryExpr:if(t.name===null)throw new Error(`Read of unnamed temporary ${t.xref}`);return Rt(t.name);case Qe.AssignTemporaryExpr:if(t.name===null)throw new Error(`Assign of unnamed temporary ${t.xref}`);return Rt(t.name).set(t.expr);case Qe.PureFunctionExpr:if(t.fn===null)throw new Error("AssertionError: expected PureFunctions to have been extracted");return _J(t.varOffset,t.fn,t.args);case Qe.PureFunctionParameterExpr:throw new Error("AssertionError: expected PureFunctionParameterExpr to have been extracted");case Qe.PipeBinding:return mJ(t.targetSlot.slot,t.varOffset,t.args);case Qe.PipeBindingVariadic:return gJ(t.targetSlot.slot,t.varOffset,t.args);case Qe.SlotLiteralExpr:return Y(t.slot.slot);case Qe.ContextLetReference:return sJ(t.targetSlot.slot);case Qe.StoreLet:return rJ(t.value,t.sourceSpan);case Qe.TrackContext:return Rt("this");default:throw new Error(`AssertionError: Unsupported reification of ir.Expression kind: ${Qe[t.kind]}`)}}function ZL(t,e,n,r){lI(t,n);let s=[];for(let o of n){if(o.kind!==E.Statement)throw new Error(`AssertionError: expected reified statements, but found op ${E[o.kind]}`);s.push(o.statement)}let i=[];return r&&i.push(new zr("$event")),sc(i,s,void 0,void 0,e)}function VJ(t,e){if(e.trackByFn!==null)return e.trackByFn;let n=[new zr("$index"),new zr("$item")],r;if(e.trackByOps===null)r=e.usesComponentInstance?sc(n,[new gs(e.track)]):xo(n,e.track);else{lI(t,e.trackByOps);let s=[];for(let i of e.trackByOps){if(i.kind!==E.Statement)throw new Error(`AssertionError: expected reified statements, but found op ${E[i.kind]}`);s.push(i.statement)}r=e.usesComponentInstance||s.length!==1||!(s[0]instanceof gs)?sc(n,s):xo(n,s[0].value)}return e.trackByFn=t.job.pool.getSharedFunctionReference(r,"_forTrack"),e.trackByFn}function HJ(t){for(let e of t.units)for(let n of e.update)switch(n.kind){case E.Attribute:case E.Binding:case E.ClassProp:case E.ClassMap:case E.Property:case E.StyleProp:case E.StyleMap:n.expression instanceof ry&&be.remove(n);break}}function jJ(t){for(let e of t.units)for(let n of e.create)switch(n.kind){case E.I18nContext:be.remove(n);break;case E.I18nStart:n.context=null;break}}function UJ(t){for(let e of t.units){let n=new Set;for(let r of e.update)switch(r.kind){case E.I18nExpression:n.add(r.i18nOwner)}for(let r of e.create)switch(r.kind){case E.I18nAttributes:if(n.has(r.xref))continue;be.remove(r)}}}function qJ(t){for(let e of t.units)UE(e,e.create),UE(e,e.update)}function UE(t,e){let n=new Map;n.set(t.xref,Rt("ctx"));for(let r of e)switch(r.kind){case E.Variable:switch(r.variable.kind){case Fr.Context:n.set(r.variable.view,new Qa(r.xref));break}break;case E.Listener:case E.TwoWayListener:UE(t,r.handlerOps);break;case E.RepeaterCreate:r.trackByOps!==null&&UE(t,r.trackByOps);break}t===t.job.root&&n.set(t.xref,Rt("ctx"));for(let r of e)_r(r,s=>{if(s instanceof el){if(!n.has(s.view))throw new Error(`No context found for reference to view ${s.view} from view ${t.xref}`);return n.get(s.view)}else return s},on.None)}function WJ(t){for(let e of t.units)YL(e.create),YL(e.update)}function YL(t){for(let e of t)(e.kind===E.Listener||e.kind===E.TwoWayListener)&&_r(e,n=>n instanceof ss&&n.name==="$event"?(e.kind===E.Listener&&(e.consumesDollarEvent=!0),new Xi(n.name)):n,on.InChildOperation)}function zJ(t){let e=new Map,n=new Map;for(let r of t.units)for(let s of r.create)switch(s.kind){case E.I18nContext:e.set(s.xref,s);break;case E.ElementStart:n.set(s.xref,s);break}Yl(t,t.root,e,n)}function Yl(t,e,n,r,s){let i=null,o=new Map;for(let a of e.create)switch(a.kind){case E.I18nStart:if(!a.context)throw Error("Could not find i18n context for i18n op");i={i18nBlock:a,i18nContext:n.get(a.context)};break;case E.I18nEnd:i=null;break;case E.ElementStart:if(a.i18nPlaceholder!==void 0){if(i===null)throw Error("i18n tag placeholder should only occur inside an i18n block");XL(a,i.i18nContext,i.i18nBlock,s),s&&a.i18nPlaceholder.closeName&&o.set(a.xref,s),s=void 0}break;case E.ElementEnd:let c=r.get(a.xref);if(c&&c.i18nPlaceholder!==void 0){if(i===null)throw Error("AssertionError: i18n tag placeholder should only occur inside an i18n block");QL(c,i.i18nContext,i.i18nBlock,o.get(a.xref)),o.delete(a.xref)}break;case E.Projection:if(a.i18nPlaceholder!==void 0){if(i===null)throw Error("i18n tag placeholder should only occur inside an i18n block");XL(a,i.i18nContext,i.i18nBlock,s),QL(a,i.i18nContext,i.i18nBlock,s),s=void 0}break;case E.Template:let u=t.views.get(a.xref);if(a.i18nPlaceholder===void 0)Yl(t,u,n,r);else{if(i===null)throw Error("i18n tag placeholder should only occur inside an i18n block");a.templateKind===Js.Structural?Yl(t,u,n,r,a):(d1(t,u,a.handle.slot,a.i18nPlaceholder,i.i18nContext,i.i18nBlock,s),Yl(t,u,n,r),p1(t,u,a.handle.slot,a.i18nPlaceholder,i.i18nContext,i.i18nBlock,s),s=void 0)}break;case E.RepeaterCreate:if(s!==void 0)throw Error("AssertionError: Unexpected structural directive associated with @for block");let d=a.handle.slot+1,p=t.views.get(a.xref);if(a.i18nPlaceholder===void 0)Yl(t,p,n,r);else{if(i===null)throw Error("i18n tag placeholder should only occur inside an i18n block");d1(t,p,d,a.i18nPlaceholder,i.i18nContext,i.i18nBlock,s),Yl(t,p,n,r),p1(t,p,d,a.i18nPlaceholder,i.i18nContext,i.i18nBlock,s),s=void 0}if(a.emptyView!==null){let f=a.handle.slot+2,h=t.views.get(a.emptyView);if(a.emptyI18nPlaceholder===void 0)Yl(t,h,n,r);else{if(i===null)throw Error("i18n tag placeholder should only occur inside an i18n block");d1(t,h,f,a.emptyI18nPlaceholder,i.i18nContext,i.i18nBlock,s),Yl(t,h,n,r),p1(t,h,f,a.emptyI18nPlaceholder,i.i18nContext,i.i18nBlock,s),s=void 0}}break}}function XL(t,e,n,r){let{startName:s,closeName:i}=t.i18nPlaceholder,o=Cn.ElementTag|Cn.OpenTag,a=t.handle.slot;r!==void 0&&(o|=Cn.TemplateTag,a={element:a,template:r.handle.slot}),i||(o|=Cn.CloseTag),$f(e.params,s,a,n.subTemplateIndex,o)}function QL(t,e,n,r){let{closeName:s}=t.i18nPlaceholder;if(s){let i=Cn.ElementTag|Cn.CloseTag,o=t.handle.slot;r!==void 0&&(i|=Cn.TemplateTag,o={element:o,template:r.handle.slot}),$f(e.params,s,o,n.subTemplateIndex,i)}}function d1(t,e,n,r,s,i,o){let{startName:a,closeName:c}=r,u=Cn.TemplateTag|Cn.OpenTag;c||(u|=Cn.CloseTag),o!==void 0&&$f(s.params,a,o.handle.slot,i.subTemplateIndex,u),$f(s.params,a,n,TB(t,i,e),u)}function p1(t,e,n,r,s,i,o){let{closeName:a}=r,c=Cn.TemplateTag|Cn.CloseTag;a&&($f(s.params,a,n,TB(t,i,e),c),o!==void 0&&$f(s.params,a,o.handle.slot,i.subTemplateIndex,c))}function TB(t,e,n){for(let r of n.create)if(r.kind===E.I18nStart)return r.subTemplateIndex;return e.subTemplateIndex}function $f(t,e,n,r,s){let i=t.get(e)??[];i.push({value:n,subTemplateIndex:r,flags:s}),t.set(e,i)}function GJ(t){let e=new Map,n=new Map,r=new Map;for(let o of t.units)for(let a of o.create)switch(a.kind){case E.I18nStart:e.set(a.xref,a.subTemplateIndex);break;case E.I18nContext:n.set(a.xref,a);break;case E.IcuPlaceholder:r.set(a.xref,a);break}let s=new Map,i=o=>o.usage===Iu.I18nText?o.i18nOwner:o.context;for(let o of t.units)for(let a of o.update)if(a.kind===E.I18nExpression){let c=s.get(i(a))||0,u=e.get(a.i18nOwner)??null,d={value:c,subTemplateIndex:u,flags:Cn.ExpressionIndex};ZJ(a,d,n,r),s.set(i(a),c+1)}}function ZJ(t,e,n,r){if(t.i18nPlaceholder!==null){let s=n.get(t.context),i=t.resolutionTime===Mf.Creation?s.params:s.postprocessingParams,o=i.get(t.i18nPlaceholder)||[];o.push(e),i.set(t.i18nPlaceholder,o)}t.icuPlaceholder!==null&&r.get(t.icuPlaceholder)?.expressionPlaceholders.push(e)}function YJ(t){let e=new Map;for(let n of t.units)for(let r of n.ops())if(r.kind===E.ElementStart||r.kind===E.Template){let s=r.tag??"";switch(r.namespace){case Sr.SVG:s=`:${cx}:${s}`;break;case Sr.Math:s=`:${ux}:${s}`;break}e.set(r.xref,s)}for(let n of t.units)for(let r of n.create)if(r.kind===E.ExtractedAttribute&&r.i18nContext!==null&&r.expression!==null){let s=e.get(r.target)??"",i=r.expression;switch(r.securityContext){case Gt.HTML:i=Xe(y.sanitizeHtml).callFn([i]);break;case Gt.STYLE:i=Xe(y.sanitizeStyle).callFn([i]);break;case Gt.SCRIPT:i=Xe(y.sanitizeScript).callFn([i]);break;case Gt.URL:i=Xe(y.sanitizeUrl).callFn([i]);break;case Gt.RESOURCE_URL:i=Xe(y.sanitizeResourceUrl).callFn([i]);break;case Gt.ATTRIBUTE_NO_BINDING:i=Xe(y.validateAttribute).callFn([i,Y(s),Y(r.name)]);break}r.expression=i}}function XJ(t){for(let e of t.units)qE(e,e.create,null),qE(e,e.update,null)}function qE(t,e,n){let r=new Map,s=new Map;for(let i of e)switch(i.kind){case E.Variable:switch(i.variable.kind){case Fr.Identifier:if(i.variable.local){if(s.has(i.variable.identifier))continue;s.set(i.variable.identifier,i.xref)}else if(r.has(i.variable.identifier))continue;r.set(i.variable.identifier,i.xref);break;case Fr.Alias:if(r.has(i.variable.identifier))continue;r.set(i.variable.identifier,i.xref);break;case Fr.SavedView:n={view:i.variable.view,variable:i.xref};break}break;case E.Listener:case E.TwoWayListener:qE(t,i.handlerOps,n);break;case E.RepeaterCreate:i.trackByOps!==null&&qE(t,i.trackByOps,n);break}for(let i of e)i.kind==E.Listener||i.kind===E.TwoWayListener||_r(i,o=>{if(o instanceof ss)return s.has(o.name)?new Qa(s.get(o.name)):r.has(o.name)?new Qa(r.get(o.name)):new Si(new el(t.job.root.xref),o.name);if(o instanceof CE&&typeof o.view=="number"){if(n===null||n.view!==o.view)throw new Error(`AssertionError: no saved view ${o.view} from view ${t.xref}`);return o.view=new Qa(n.variable),o}else return o},on.None);for(let i of e)bs(i,o=>{if(o instanceof ss)throw new Error(`AssertionError: no lexical reads should remain, but found read of ${o.name}`)})}var QJ=new Map([[Gt.HTML,y.sanitizeHtml],[Gt.RESOURCE_URL,y.sanitizeResourceUrl],[Gt.SCRIPT,y.sanitizeScript],[Gt.STYLE,y.sanitizeStyle],[Gt.URL,y.sanitizeUrl],[Gt.ATTRIBUTE_NO_BINDING,y.validateAttribute]]),KJ=new Map([[Gt.HTML,y.trustConstantHtml],[Gt.RESOURCE_URL,y.trustConstantResourceUrl]]);function JJ(t){for(let e of t.units){if(t.kind!==Oe.Host){for(let n of e.create)if(n.kind===E.ExtractedAttribute){let r=KJ.get(KL(n.securityContext))??null;n.trustedValueFn=r!==null?Xe(r):null}}for(let n of e.update)switch(n.kind){case E.Property:case E.Attribute:case E.HostProperty:let r=null;Array.isArray(n.securityContext)&&n.securityContext.length===2&&n.securityContext.includes(Gt.URL)&&n.securityContext.includes(Gt.RESOURCE_URL)?r=y.sanitizeUrlOrResourceUrl:r=QJ.get(KL(n.securityContext))??null,n.sanitizer=r!==null?Xe(r):null;break}}}function KL(t){if(Array.isArray(t)){if(t.length>1)throw Error("AssertionError: Ambiguous security context");return t[0]||Gt.NONE}return t}function eee(t){for(let e of t.units)for(let n of e.create)n.kind===E.TwoWayListener&&_r(n,r=>{if(!(r instanceof TE))return r;let{target:s,value:i}=r;if(s instanceof Si||s instanceof Ja)return zL(s,i).or(s.set(i));if(s instanceof Qa)return zL(s,i);throw new Error("Unsupported expression in two-way action binding.")},on.InChildOperation)}function tee(t){for(let e of t.units){e.create.prepend([ec(e.job.allocateXrefId(),{kind:Fr.SavedView,name:null,view:e.xref},new r_,yi.None)]);for(let n of e.create){if(n.kind!==E.Listener&&n.kind!==E.TwoWayListener)continue;let r=e!==t.root;if(!r)for(let s of n.handlerOps)bs(s,i=>{(i instanceof xE||i instanceof ny)&&(r=!0)});r&&nee(e,n)}}}function nee(t,e){e.handlerOps.prepend([ec(t.job.allocateXrefId(),{kind:Fr.Context,name:null,view:t.xref},new CE(t.xref),yi.None)]);for(let n of e.handlerOps)n.kind===E.Statement&&n.statement instanceof gs&&(n.statement.value=new s_(n.statement.value))}function ree(t){let e=new Map;for(let n of t.units){let r=0;for(let s of n.create)jf(s)&&(s.handle.slot=r,e.set(s.xref,s.handle.slot),r+=s.numSlotsUsed);n.decls=r}for(let n of t.units)for(let r of n.ops())if(r.kind===E.Template||r.kind===E.RepeaterCreate){let s=t.views.get(r.xref);r.decls=s.decls}}function see(t){for(let e of t.units)for(let n of e.update)if(n.kind===E.Binding)switch(n.bindingKind){case Je.ClassName:if(n.expression instanceof xr)throw new Error("Unexpected interpolation in ClassName binding");be.replace(n,KZ(n.target,n.name,n.expression,n.sourceSpan));break;case Je.StyleProperty:be.replace(n,QZ(n.target,n.name,n.expression,n.unit,n.sourceSpan));break;case Je.Property:case Je.Template:n.name==="style"?be.replace(n,JZ(n.target,n.expression,n.sourceSpan)):n.name==="class"&&be.replace(n,eY(n.target,n.expression,n.sourceSpan));break}}function iee(t){for(let e of t.units)e.create.prepend(WE(e.create)),e.update.prepend(WE(e.update))}function WE(t){let e=0,n=[];for(let r of t){let s=new Map;bs(r,(u,d)=>{d&on.InChildOperation||u instanceof tl&&s.set(u.xref,u)});let i=0,o=new Set,a=new Set,c=new Map;bs(r,(u,d)=>{d&on.InChildOperation||(u instanceof Co?(o.has(u.xref)||(o.add(u.xref),c.set(u.xref,`tmp_${e}_${i++}`)),JL(c,u)):u instanceof tl&&(s.get(u.xref)===u&&(a.add(u.xref),i--),JL(c,u)))}),n.push(...Array.from(new Set(c.values())).map(u=>So(new ys(u)))),e++,r.kind===E.Listener||r.kind===E.TwoWayListener?r.handlerOps.prepend(WE(r.handlerOps)):r.kind===E.RepeaterCreate&&r.trackByOps!==null&&r.trackByOps.prepend(WE(r.trackByOps))}return n}function JL(t,e){let n=t.get(e.xref);if(n===void 0)throw new Error(`Found xref with unassigned name: ${e.xref}`);e.name=n}function oee(t){for(let e of t.units)for(let n of e.create)if(n.kind===E.RepeaterCreate)if(n.track instanceof Xi&&n.track.name==="$index")n.trackByFn=Xe(y.repeaterTrackByIndex);else if(n.track instanceof Xi&&n.track.name==="$item")n.trackByFn=Xe(y.repeaterTrackByIdentity);else if(aee(t.root.xref,n.track))n.usesComponentInstance=!0,n.track.receiver.receiver.view===e.xref?n.trackByFn=n.track.receiver:(n.trackByFn=Xe(y.componentInstance).callFn([]).prop(n.track.receiver.name),n.track=n.trackByFn);else{n.track=Ve(n.track,s=>{if(s instanceof Nf||s instanceof DE)throw new Error("Illegal State: Pipes are not allowed in this context");return s instanceof el?(n.usesComponentInstance=!0,new n_(s.view)):s},on.None);let r=new be;r.push(So(new gs(n.track,n.track.sourceSpan))),n.trackByOps=r}}function aee(t,e){if(!(e instanceof ei)||e.args.length===0||e.args.length>2||!(e.receiver instanceof Si&&e.receiver.receiver instanceof el)||e.receiver.receiver.view!==t)return!1;let[n,r]=e.args;return!(n instanceof Xi)||n.name!=="$index"?!1:e.args.length===1?!0:!(!(r instanceof Xi)||r.name!=="$item")}function lee(t){for(let e of t.units)for(let n of e.create)n.kind===E.RepeaterCreate&&(n.track=Ve(n.track,r=>{if(r instanceof ss){if(n.varNames.$index.has(r.name))return Rt("$index");if(r.name===n.varNames.$implicit)return Rt("$item")}return r},on.None))}function cee(t){for(let e of t.units){let n=0;for(let r of e.ops())i1(r)&&(n+=uee(r));for(let r of e.ops())bs(r,s=>{la(s)&&(t.compatibility===ti.TemplateDefinitionBuilder&&s instanceof Au||(yL(s)&&(s.varOffset=n),i1(s)&&(n+=eO(s))))});if(t.compatibility===ti.TemplateDefinitionBuilder)for(let r of e.ops())bs(r,s=>{!la(s)||!(s instanceof Au)||(yL(s)&&(s.varOffset=n),i1(s)&&(n+=eO(s)))});e.vars=n}if(t instanceof iy)for(let e of t.units)for(let n of e.create){if(n.kind!==E.Template&&n.kind!==E.RepeaterCreate)continue;let r=t.views.get(n.xref);n.vars=r.vars}}function uee(t){let e;switch(t.kind){case E.Property:case E.HostProperty:case E.Attribute:return e=1,t.expression instanceof xr&&!dee(t.expression)&&(e+=t.expression.expressions.length),e;case E.TwoWayProperty:return 1;case E.StyleProp:case E.ClassProp:case E.StyleMap:case E.ClassMap:return e=2,t.expression instanceof xr&&(e+=t.expression.expressions.length),e;case E.InterpolateText:return t.interpolation.expressions.length;case E.I18nExpression:case E.Conditional:case E.DeferWhen:case E.StoreLet:return 1;case E.RepeaterCreate:return t.emptyView?1:0;default:throw new Error(`Unhandled op: ${E[t.kind]}`)}}function eO(t){switch(t.kind){case Qe.PureFunctionExpr:return 1+t.args.length;case Qe.PipeBinding:return 1+t.args.length;case Qe.PipeBindingVariadic:return 1+t.numArgs;case Qe.StoreLet:return 1;default:throw new Error(`AssertionError: unhandled ConsumesVarsTrait expression ${t.constructor.name}`)}}function dee(t){return!(t.expressions.length!==1||t.strings.length!==2||t.strings[0]!==""||t.strings[1]!=="")}function pee(t){for(let e of t.units){Dw(e.create),Dw(e.update);for(let n of e.create)n.kind===E.Listener||n.kind===E.TwoWayListener?Dw(n.handlerOps):n.kind===E.RepeaterCreate&&n.trackByOps!==null&&Dw(n.trackByOps);_w(e.create,t.compatibility),_w(e.update,t.compatibility);for(let n of e.create)n.kind===E.Listener||n.kind===E.TwoWayListener?_w(n.handlerOps,t.compatibility):n.kind===E.RepeaterCreate&&n.trackByOps!==null&&_w(n.trackByOps,t.compatibility)}}var Dr;(function(t){t[t.None=0]="None",t[t.ViewContextRead=1]="ViewContextRead",t[t.ViewContextWrite=2]="ViewContextWrite",t[t.SideEffectful=4]="SideEffectful"})(Dr||(Dr={}));function Dw(t){let e=new Map;for(let n of t)n.kind===E.Variable&&n.flags&yi.AlwaysInline&&(bs(n,r=>{if(la(r)&&cI(r)!==Dr.None)throw new Error("AssertionError: A context-sensitive variable was marked AlwaysInline")}),e.set(n.xref,n)),_r(n,r=>r instanceof Qa&&e.has(r.xref)?e.get(r.xref).initializer.clone():r,on.None);for(let n of e.values())be.remove(n)}function _w(t,e){let n=new Map,r=new Map,s=new Set,i=new Map;for(let u of t){if(u.kind===E.Variable){if(n.has(u.xref)||r.has(u.xref))throw new Error(`Should not see two declarations of the same variable: ${u.xref}`);n.set(u.xref,u),r.set(u.xref,0)}i.set(u,fee(u)),hee(u,r,s)}let o=!1;for(let u of t.reversed()){let d=i.get(u);if(u.kind===E.Variable&&r.get(u.xref)===0){if(o&&d.fences&Dr.ViewContextWrite||d.fences&Dr.SideEffectful){let p=So(u.initializer.toStmt());i.set(p,d),be.replace(u,p)}else mee(u,r),be.remove(u);i.delete(u),n.delete(u.xref),r.delete(u.xref);continue}d.fences&Dr.ViewContextRead&&(o=!0)}let a=[];for(let[u,d]of r){let f=!!(n.get(u).flags&yi.AlwaysInline);d!==1||f||s.has(u)||a.push(u)}let c;for(;c=a.pop();){let u=n.get(c),d=i.get(u);if(!!(u.flags&yi.AlwaysInline))throw new Error("AssertionError: Found an 'AlwaysInline' variable after the always inlining pass.");for(let f=u.next;f.kind!==E.ListEnd;f=f.next){let h=i.get(f);if(h.variablesUsed.has(c)){if(e===ti.TemplateDefinitionBuilder&&!vee(u,f))break;if(gee(c,u.initializer,f,d.fences)){h.variablesUsed.delete(c);for(let m of d.variablesUsed)h.variablesUsed.add(m);h.fences|=d.fences,n.delete(c),r.delete(c),i.delete(u),be.remove(u)}break}if(!DB(h.fences,d.fences))break}}}function cI(t){switch(t.kind){case Qe.NextContext:return Dr.ViewContextRead|Dr.ViewContextWrite;case Qe.RestoreView:return Dr.ViewContextRead|Dr.ViewContextWrite|Dr.SideEffectful;case Qe.StoreLet:return Dr.SideEffectful;case Qe.Reference:case Qe.ContextLetReference:return Dr.ViewContextRead;default:return Dr.None}}function fee(t){let e=Dr.None,n=new Set;return bs(t,r=>{if(la(r))switch(r.kind){case Qe.ReadVariable:n.add(r.xref);break;default:e|=cI(r)}}),{fences:e,variablesUsed:n}}function hee(t,e,n){bs(t,(r,s)=>{if(!la(r)||r.kind!==Qe.ReadVariable)return;let i=e.get(r.xref);i!==void 0&&(e.set(r.xref,i+1),s&on.InChildOperation&&n.add(r.xref))})}function mee(t,e){bs(t,n=>{if(!la(n)||n.kind!==Qe.ReadVariable)return;let r=e.get(n.xref);if(r!==void 0){if(r===0)throw new Error(`Inaccurate variable count: ${n.xref} - found another read but count is already 0`);e.set(n.xref,r-1)}})}function DB(t,e){if(t&Dr.ViewContextWrite){if(e&Dr.ViewContextRead)return!1}else if(t&Dr.ViewContextRead&&e&Dr.ViewContextWrite)return!1;return!0}function gee(t,e,n,r){let s=!1,i=!0;return _r(n,(o,a)=>{if(!la(o)||s||!i)return o;if(a&on.InChildOperation&&r&Dr.ViewContextRead)return o;switch(o.kind){case Qe.ReadVariable:if(o.xref===t)return s=!0,e;break;default:let c=cI(o);i=i&&DB(c,r);break}return o},on.None),s}function vee(t,e){switch(t.variable.kind){case Fr.Identifier:return t.initializer instanceof Xi&&t.initializer.name==="ctx";case Fr.Context:return e.kind===E.Variable;default:return!0}}function yee(t){for(let e of t.units){let n=null,r=null;for(let s of e.create)switch(s.kind){case E.I18nStart:n=s;break;case E.I18nEnd:n=null;break;case E.IcuStart:n===null&&(r=t.allocateXrefId(),be.insertBefore(ax(r,s.message,void 0,null),s));break;case E.IcuEnd:r!==null&&(be.insertAfter(lx(r,null),s),r=null);break}}}function bee(t){let e=new Set;for(let n of t.units)for(let r of n.ops())bs(r,s=>{s instanceof ny&&e.add(s.target)});for(let n of t.units)for(let r of n.update)_r(r,s=>s instanceof ty&&!e.has(s.target)?s.value:s,on.None)}function wee(t){for(let e of t.units)for(let n of e.update){if(n.kind!==E.Variable||n.variable.kind!==Fr.Identifier||!(n.initializer instanceof ty))continue;let r=n.variable.identifier,s=n;for(;s&&s.kind!==E.ListEnd;)_r(s,i=>i instanceof ss&&i.name===r?Y(void 0):i,on.None),s=s.prev}}function Eee(t){for(let e of t.units)for(let n of e.update){if(n.kind!==E.StoreLet)continue;let r={kind:Fr.Identifier,name:null,identifier:n.declaredName,local:!0};be.replace(n,ec(t.allocateXrefId(),r,new ty(n.target,n.value,n.sourceSpan),yi.None))}}function xee(t){if(!(!t.enableDebugLocations||t.relativeTemplatePath===null))for(let e of t.units){let n=[];for(let r of e.create)if(r.kind===E.ElementStart||r.kind===E.Element){let s=r.startSourceSpan.start;n.push({targetSlot:r.handle,offset:s.offset,line:s.line,column:s.col})}n.length>0&&e.create.push(xY(t.relativeTemplatePath,n))}}var See=[{kind:Oe.Tmpl,fn:pK},{kind:Oe.Host,fn:CX},{kind:Oe.Tmpl,fn:ZQ},{kind:Oe.Tmpl,fn:bK},{kind:Oe.Tmpl,fn:yee},{kind:Oe.Both,fn:zY},{kind:Oe.Both,fn:see},{kind:Oe.Both,fn:PY},{kind:Oe.Both,fn:kY},{kind:Oe.Tmpl,fn:WY},{kind:Oe.Both,fn:XQ},{kind:Oe.Tmpl,fn:HJ},{kind:Oe.Both,fn:LY},{kind:Oe.Both,fn:dK},{kind:Oe.Tmpl,fn:OY},{kind:Oe.Tmpl,fn:mK},{kind:Oe.Tmpl,fn:GY},{kind:Oe.Tmpl,fn:WQ},{kind:Oe.Tmpl,fn:UY},{kind:Oe.Tmpl,fn:UJ},{kind:Oe.Tmpl,fn:IY},{kind:Oe.Tmpl,fn:DY},{kind:Oe.Tmpl,fn:yK},{kind:Oe.Both,fn:xK},{kind:Oe.Tmpl,fn:bX},{kind:Oe.Tmpl,fn:Eee},{kind:Oe.Tmpl,fn:wX},{kind:Oe.Tmpl,fn:tee},{kind:Oe.Both,fn:CY},{kind:Oe.Both,fn:WJ},{kind:Oe.Tmpl,fn:lee},{kind:Oe.Tmpl,fn:wee},{kind:Oe.Both,fn:XJ},{kind:Oe.Tmpl,fn:ZY},{kind:Oe.Tmpl,fn:eee},{kind:Oe.Tmpl,fn:oee},{kind:Oe.Both,fn:qJ},{kind:Oe.Both,fn:JJ},{kind:Oe.Tmpl,fn:zQ},{kind:Oe.Both,fn:iK},{kind:Oe.Both,fn:JY},{kind:Oe.Both,fn:iee},{kind:Oe.Both,fn:pee},{kind:Oe.Both,fn:bee},{kind:Oe.Tmpl,fn:ree},{kind:Oe.Tmpl,fn:zJ},{kind:Oe.Tmpl,fn:GJ},{kind:Oe.Tmpl,fn:hX},{kind:Oe.Tmpl,fn:VQ},{kind:Oe.Tmpl,fn:YJ},{kind:Oe.Tmpl,fn:xX},{kind:Oe.Both,fn:HY},{kind:Oe.Tmpl,fn:jJ},{kind:Oe.Both,fn:cee},{kind:Oe.Tmpl,fn:yX},{kind:Oe.Both,fn:QQ},{kind:Oe.Tmpl,fn:qY},{kind:Oe.Tmpl,fn:eK},{kind:Oe.Tmpl,fn:nK},{kind:Oe.Tmpl,fn:KY},{kind:Oe.Tmpl,fn:xee},{kind:Oe.Tmpl,fn:sK},{kind:Oe.Both,fn:EK},{kind:Oe.Both,fn:BJ},{kind:Oe.Both,fn:FY}];function _B(t,e){for(let n of See)(n.kind===e||n.kind===Oe.Both)&&n.fn(t)}function Cee(t,e){let n=kB(t.root);return IB(t.root,e),n}function IB(t,e){for(let n of t.job.units){if(n.parent!==t.xref)continue;IB(n,e);let r=kB(n);e.statements.push(r.toDeclStmt(r.name))}}function kB(t){if(t.fnName===null)throw new Error(`AssertionError: view ${t.xref} is unnamed`);let e=[];for(let i of t.create){if(i.kind!==E.Statement)throw new Error(`AssertionError: expected all create ops to have been compiled, but got ${E[i.kind]}`);e.push(i.statement)}let n=[];for(let i of t.update){if(i.kind!==E.Statement)throw new Error(`AssertionError: expected all update ops to have been compiled, but got ${E[i.kind]}`);n.push(i.statement)}let r=zE(1,e),s=zE(2,n);return sc([new zr("rf"),new zr("ctx")],[...r,...s],void 0,void 0,t.fnName)}function zE(t,e){return e.length===0?[]:[ex(new sn(Ye.BitwiseAnd,Rt("rf"),Y(t)),e)]}function Tee(t){if(t.root.fnName===null)throw new Error("AssertionError: host binding function is unnamed");let e=[];for(let i of t.root.create){if(i.kind!==E.Statement)throw new Error(`AssertionError: expected all create ops to have been compiled, but got ${E[i.kind]}`);e.push(i.statement)}let n=[];for(let i of t.root.update){if(i.kind!==E.Statement)throw new Error(`AssertionError: expected all update ops to have been compiled, but got ${E[i.kind]}`);n.push(i.statement)}if(e.length===0&&n.length===0)return null;let r=zE(1,e),s=zE(2,n);return sc([new zr("rf"),new zr("ctx")],[...r,...s],void 0,void 0,t.root.fnName)}var AB=ti.TemplateDefinitionBuilder,yu=new Bf,bu="ng-template";function __(t){return t instanceof As}function Dee(t){return __(t)&&t.nodes.length===1&&t.nodes[0]instanceof mE}function _ee(t,e,n,r,s,i,o,a,c){let u=new iy(t,n,AB,r,s,i,o,a,c);return nl(u.root,e),u}function Iee(t,e,n){let r=new PE(t.componentName,n,AB);for(let s of t.properties??[]){let i=Je.Property;s.name.startsWith("attr.")&&(s.name=s.name.substring(5),i=Je.Attribute),s.isAnimation&&(i=Je.Animation);let o=e.calcPossibleSecurityContexts(t.componentSelector,s.name,i===Je.Attribute).filter(a=>a!==Gt.NONE);kee(r,s,i,o)}for(let[s,i]of Object.entries(t.attributes)??[]){let o=e.calcPossibleSecurityContexts(t.componentSelector,s,!0).filter(a=>a!==Gt.NONE);Aee(r,s,i,o)}for(let s of t.events??[])Mee(r,s);return r}function kee(t,e,n,r){let s,i=e.expression.ast;i instanceof my?s=new xr(i.strings,i.expressions.map(o=>_t(o,t,e.sourceSpan)),[]):s=_t(i,t,e.sourceSpan),t.root.update.push(ku(t.root.xref,n,e.name,s,null,r,!1,!1,null,null,e.sourceSpan))}function Aee(t,e,n,r){let s=ku(t.root.xref,Je.Attribute,e,n,null,r,!0,!1,null,null,n.sourceSpan);t.root.update.push(s)}function Mee(t,e){let[n,r]=e.type!==wi.Animation?[null,e.targetOrPhase]:[e.targetOrPhase,null],s=aI(t.root.xref,new ni,e.name,null,uI(t.root,e.handler,e.handlerSpan),n,r,!0,e.sourceSpan);t.root.create.push(s)}function nl(t,e){for(let n of e)if(n instanceof oa)Pee(t,n);else if(n instanceof Ei)Nee(t,n);else if(n instanceof kf)Ree(t,n);else if(n instanceof pu)MB(t,n,null);else if(n instanceof Df)PB(t,n,null);else if(n instanceof fE)Fee(t,n);else if(n instanceof pE)Lee(t,n);else if(n instanceof Du)Oee(t,n);else if(n instanceof kO)$ee(t,n);else if(n instanceof If)Vee(t,n);else if(n instanceof X_)jee(t,n);else throw new Error(`Unsupported template node: ${n.constructor.name}`)}function Pee(t,e){if(e.i18n!==void 0&&!(e.i18n instanceof As||e.i18n instanceof oc))throw Error(`Unhandled i18n metadata type for element: ${e.i18n.constructor.name}`);let n=t.job.allocateXrefId(),[r,s]=vs(e.name),i=lY(s,n,cB(r),e.i18n instanceof oc?e.i18n:void 0,e.startSourceSpan,e.sourceSpan);t.create.push(i),qee(t,i,e),FB(i,e);let o=null;e.i18n instanceof As&&(o=t.job.allocateXrefId(),t.create.push(ax(o,e.i18n,void 0,e.startSourceSpan))),nl(t,e.children);let a=uY(n,e.endSourceSpan??e.startSourceSpan);t.create.push(a),o!==null&&be.insertBefore(lx(o,e.endSourceSpan??e.startSourceSpan),a)}function Nee(t,e){if(e.i18n!==void 0&&!(e.i18n instanceof As||e.i18n instanceof oc))throw Error(`Unhandled i18n metadata type for template: ${e.i18n.constructor.name}`);let n=t.job.allocateView(t.xref),r=e.tagName,s="";e.tagName&&([s,r]=vs(e.tagName));let i=e.i18n instanceof oc?e.i18n:void 0,o=cB(s),a=r===null?"":VY(r,o),c=Uee(e)?Js.NgTemplate:Js.Structural,u=ox(n.xref,c,r,a,o,i,e.startSourceSpan,e.sourceSpan);t.create.push(u),Wee(t,u,e,c),FB(u,e),nl(n,e.children);for(let{name:d,value:p}of e.variables)n.contextVariables.set(d,p!==""?p:"$implicit");if(c===Js.NgTemplate&&e.i18n instanceof As){let d=t.job.allocateXrefId();be.insertAfter(ax(d,e.i18n,void 0,e.startSourceSpan),n.create.head),be.insertBefore(lx(d,e.endSourceSpan??e.startSourceSpan),n.create.tail)}}function Ree(t,e){if(e.i18n!==void 0&&!(e.i18n instanceof oc))throw Error(`Unhandled i18n metadata type for element: ${e.i18n.constructor.name}`);let n=null;e.children.some(i=>!(i instanceof nx)&&(!(i instanceof pu)||i.value.trim().length>0))&&(n=t.job.allocateView(t.xref),nl(n,e.children));let r=t.job.allocateXrefId(),s=mY(r,e.selector,e.i18n,n?.xref??null,e.sourceSpan);for(let i of e.attributes){let o=yu.securityContext(e.name,i.name,!0);t.update.push(ku(s.xref,Je.Attribute,i.name,Y(i.value),null,o,!0,!1,null,Za(i.i18n),i.sourceSpan))}t.create.push(s)}function MB(t,e,n){t.create.push(rB(t.job.allocateXrefId(),e.value,n,e.sourceSpan))}function PB(t,e,n){let r=e.value;if(r instanceof qi&&(r=r.ast),!(r instanceof my))throw new Error(`AssertionError: expected Interpolation for BoundText node, got ${r.constructor.name}`);if(e.i18n!==void 0&&!(e.i18n instanceof Ya))throw Error(`Unhandled i18n metadata type for text interpolation: ${e.i18n?.constructor.name}`);let s=e.i18n instanceof Ya?e.i18n.children.filter(a=>a instanceof Wv).map(a=>a.name):[];if(s.length>0&&s.length!==r.expressions.length)throw Error(`Unexpected number of i18n placeholders (${r.expressions.length}) for BoundText with ${r.expressions.length} expressions`);let i=t.job.allocateXrefId();t.create.push(rB(i,"",n,e.sourceSpan));let o=t.job.compatibility?null:e.sourceSpan;t.update.push(ZZ(i,new xr(r.strings,r.expressions.map(a=>_t(a,t.job,o)),s),e.sourceSpan))}function Fee(t,e){let n=null,r=[];for(let s=0;sf.modifier==="none")||d.some(f=>f.modifier==="none")||u.push(Zl(a,{kind:yn.Idle},"none",null)),t.create.push(u),t.update.push(d)}function Bee(t){return Object.keys(t.hydrateTriggers).length>0?1:null}function f1(t,e,n,r,s,i){if(e.idle!==void 0){let o=Zl(i,{kind:yn.Idle},t,e.idle.sourceSpan);n.push(o)}if(e.immediate!==void 0){let o=Zl(i,{kind:yn.Immediate},t,e.immediate.sourceSpan);n.push(o)}if(e.timer!==void 0){let o=Zl(i,{kind:yn.Timer,delay:e.timer.delay},t,e.timer.sourceSpan);n.push(o)}if(e.hover!==void 0){let o=Zl(i,{kind:yn.Hover,targetName:e.hover.reference,targetXref:null,targetSlot:null,targetView:null,targetSlotViewSteps:null},t,e.hover.sourceSpan);n.push(o)}if(e.interaction!==void 0){let o=Zl(i,{kind:yn.Interaction,targetName:e.interaction.reference,targetXref:null,targetSlot:null,targetView:null,targetSlotViewSteps:null},t,e.interaction.sourceSpan);n.push(o)}if(e.viewport!==void 0){let o=Zl(i,{kind:yn.Viewport,targetName:e.viewport.reference,targetXref:null,targetSlot:null,targetView:null,targetSlotViewSteps:null},t,e.viewport.sourceSpan);n.push(o)}if(e.never!==void 0){let o=Zl(i,{kind:yn.Never},t,e.never.sourceSpan);n.push(o)}if(e.when!==void 0){if(e.when.value instanceof my)throw new Error("Unexpected interpolation in defer block when trigger");let o=sY(i,_t(e.when.value,s.job,e.when.sourceSpan),t,e.when.sourceSpan);r.push(o)}}function $ee(t,e){if(e.i18n instanceof As&&Dee(e.i18n)){let n=t.job.allocateXrefId();t.create.push(bY(n,e.i18n,PO(e.i18n).name,null));for(let[r,s]of Object.entries({...e.vars,...e.placeholders}))s instanceof Df?PB(t,s,r):MB(t,s,r);t.create.push(wY(n))}else throw Error(`Unhandled i18n metadata type for ICU: ${e.i18n?.constructor.name}`)}function Vee(t,e){let n=t.job.allocateView(t.xref),r=`\u0275$index_${n.xref}`,s=`\u0275$count_${n.xref}`,i=new Set;n.contextVariables.set(e.item.name,e.item.value);for(let w of e.contextVariables)w.value==="$index"&&i.add(w.name),w.name==="$index"?n.contextVariables.set("$index",w.value).set(r,w.value):w.name==="$count"?n.contextVariables.set("$count",w.value).set(s,w.value):n.aliases.add({kind:Fr.Alias,name:null,identifier:w.name,expression:Hee(w,r,s)});let o=Nr(e.trackBy.span,e.sourceSpan),a=_t(e.trackBy,t.job,o);nl(n,e.children);let c=null,u=null;e.empty!==null&&(c=t.job.allocateView(t.xref),nl(c,e.empty.children),u=GE(t,c.xref,e.empty));let d={$index:i,$implicit:e.item.name};if(e.i18n!==void 0&&!(e.i18n instanceof ac))throw Error("AssertionError: Unhandled i18n metadata type or @for");if(e.empty?.i18n!==void 0&&!(e.empty.i18n instanceof ac))throw Error("AssertionError: Unhandled i18n metadata type or @empty");let p=e.i18n,f=e.empty?.i18n,h=GE(t,n.xref,e),m=cY(n.xref,c?.xref??null,h,a,d,u,p,f,e.startSourceSpan,e.sourceSpan);t.create.push(m);let g=_t(e.expression,t.job,Nr(e.expression.span,e.sourceSpan)),v=rY(m.xref,m.handle,g,e.sourceSpan);t.update.push(v)}function Hee(t,e,n){switch(t.value){case"$index":return new ss(e);case"$count":return new ss(n);case"$first":return new ss(e).identical(Y(0));case"$last":return new ss(e).identical(new ss(n).minus(Y(1)));case"$even":return new ss(e).modulo(Y(2)).identical(Y(0));case"$odd":return new ss(e).modulo(Y(2)).notIdentical(Y(0));default:throw new Error(`AssertionError: unknown @for loop variable ${t.value}`)}}function jee(t,e){let n=t.job.allocateXrefId();t.create.push(vY(n,e.name,e.sourceSpan)),t.update.push(oY(n,e.name,_t(e.value,t.job,e.valueSpan),e.sourceSpan))}function _t(t,e,n){if(t instanceof qi)return _t(t.ast,e,n);if(t instanceof Tu)return t.receiver instanceof Yi&&!(t.receiver instanceof Cu)?new ss(t.name):new Si(_t(t.receiver,e,n),t.name,null,Nr(t.span,n));if(t instanceof Yw)return t.receiver instanceof Yi?new Ef(new el(e.root.xref),t.name,_t(t.value,e,n),null,Nr(t.span,n)):new Ef(_t(t.receiver,e,n),t.name,_t(t.value,e,n),void 0,Nr(t.span,n));if(t instanceof Kw)return new Tv(_t(t.receiver,e,n),_t(t.key,e,n),_t(t.value,e,n),void 0,Nr(t.span,n));if(t instanceof Lv){if(t.receiver instanceof Yi)throw new Error("Unexpected ImplicitReceiver");return new ei(_t(t.receiver,e,n),t.args.map(r=>_t(r,e,n)),void 0,Nr(t.span,n))}else{if(t instanceof ji)return Y(t.value,void 0,Nr(t.span,n));if(t instanceof Rv)switch(t.operator){case"+":return new xf(bf.Plus,_t(t.expr,e,n),void 0,Nr(t.span,n));case"-":return new xf(bf.Minus,_t(t.expr,e,n),void 0,Nr(t.span,n));default:throw new Error(`AssertionError: unknown unary operator ${t.operator}`)}else if(t instanceof vo){let r=BY.get(t.operation);if(r===void 0)throw new Error(`AssertionError: unknown binary operator ${t.operation}`);return new sn(r,_t(t.left,e,n),_t(t.right,e,n),void 0,Nr(t.span,n))}else{if(t instanceof Cu)return new el(e.root.xref);if(t instanceof Nv)return new Ja(_t(t.receiver,e,n),_t(t.key,e,n),void 0,Nr(t.span,n));if(t instanceof Tf)throw new Error("AssertionError: Chain in unknown context");if(t instanceof tE){let r=t.keys.map((s,i)=>{let o=t.values[i];return new Sf(s.key,_t(o,e,n),s.quoted)});return new ia(r,void 0,Nr(t.span,n))}else{if(t instanceof eE)return new Eo(t.expressions.map(r=>_t(r,e,n)));if(t instanceof Zw)return new Ka(_t(t.condition,e,n),_t(t.trueExp,e,n),_t(t.falseExp,e,n),void 0,Nr(t.span,n));if(t instanceof Fv)return _t(t.expression,e,n);if(t instanceof Jw)return new Nf(e.allocateXrefId(),new ni,t.name,[_t(t.exp,e,n),...t.args.map(r=>_t(r,e,n))]);if(t instanceof Qw)return new Ff(_t(t.receiver,e,n),_t(t.key,e,n),Nr(t.span,n));if(t instanceof Xw)return new Rf(_t(t.receiver,e,n),t.name);if(t instanceof sE)return new Mu(_t(t.receiver,e,n),t.args.map(r=>_t(r,e,n)));if(t instanceof Xs)return new ry(Nr(t.span,n));if(t instanceof nE)return o7(_t(t.expression,e,n),Nr(t.span,n));if(t instanceof rE)return hy(_t(t.expression,e,n));if(t instanceof Ov)return new _v(t.elements.map(r=>new Hw(r.text,Nr(r.span,n))),t.expressions.map(r=>_t(r,e,n)),Nr(t.span,n));throw new Error(`Unhandled expression type "${t.constructor.name}" in file "${n?.start.file.url}"`)}}}}function I_(t,e,n,r){let s;return e instanceof my?s=new xr(e.strings,e.expressions.map(i=>_t(i,t,null)),Object.keys(Za(n)?.placeholders??{})):e instanceof Qn?s=_t(e,t,null):s=Y(e),s}var NB=new Map([[Rn.Property,Je.Property],[Rn.TwoWay,Je.TwoWayProperty],[Rn.Attribute,Je.Attribute],[Rn.Class,Je.ClassName],[Rn.Style,Je.StyleProperty],[Rn.Animation,Je.Animation]]);function Uee(t){return vs(t.tagName??"")[1]===bu}function Za(t){if(t==null)return null;if(!(t instanceof As))throw Error(`Expected i18n meta to be a Message, but got: ${t.constructor.name}`);return t}function qee(t,e,n){let r=new Array,s=new Set;for(let i of n.attributes){let[o,a]=vs(n.name),c=o;if(!o)switch(e.namespace){case Sr.SVG:c=cx;break;case Sr.Math:c=ux;break}let u=yu.securityContext(c?`:${c}:${a}`:a,i.name,!0);r.push(ku(e.xref,Je.Attribute,i.name,I_(t.job,i.value,i.i18n),null,u,!0,!1,null,Za(i.i18n),i.sourceSpan)),i.i18n&&s.add(i.name)}for(let i of n.inputs)s.has(i.name)&&console.error(`On component ${t.job.componentName}, the binding ${i.name} is both an i18n attribute and a property. You may want to remove the property binding. This will become a compilation error in future versions of Angular.`),r.push(ku(e.xref,NB.get(i.type),i.name,I_(t.job,uy(i.value),i.i18n),i.unit,i.securityContext,!1,!1,null,Za(i.i18n)??null,i.sourceSpan));t.create.push(r.filter(i=>i?.kind===E.ExtractedAttribute)),t.update.push(r.filter(i=>i?.kind===E.Binding));for(let i of n.outputs){if(i.type===wi.Animation&&i.phase===null)throw Error("Animation listener should have a phase");i.type===wi.TwoWay?t.create.push(sB(e.xref,e.handle,i.name,e.tag,RB(t,i.handler,i.handlerSpan),i.sourceSpan)):t.create.push(aI(e.xref,e.handle,i.name,e.tag,uI(t,i.handler,i.handlerSpan),i.phase,i.target,!1,i.sourceSpan))}r.some(i=>i?.i18nMessage)!==null&&t.create.push(oB(t.job.allocateXrefId(),new ni,e.xref))}function Wee(t,e,n,r){let s=new Array;for(let i of n.templateAttrs)if(i instanceof _f){let o=yu.securityContext(bu,i.name,!0);s.push(kw(t,e.xref,Rn.Attribute,i.name,i.value,null,o,!0,r,Za(i.i18n),i.sourceSpan))}else s.push(kw(t,e.xref,i.type,i.name,uy(i.value),i.unit,i.securityContext,!0,r,Za(i.i18n),i.sourceSpan));for(let i of n.attributes){let o=yu.securityContext(bu,i.name,!0);s.push(kw(t,e.xref,Rn.Attribute,i.name,i.value,null,o,!1,r,Za(i.i18n),i.sourceSpan))}for(let i of n.inputs)s.push(kw(t,e.xref,i.type,i.name,uy(i.value),i.unit,i.securityContext,!1,r,Za(i.i18n),i.sourceSpan));t.create.push(s.filter(i=>i?.kind===E.ExtractedAttribute)),t.update.push(s.filter(i=>i?.kind===E.Binding));for(let i of n.outputs){if(i.type===wi.Animation&&i.phase===null)throw Error("Animation listener should have a phase");if(r===Js.NgTemplate&&(i.type===wi.TwoWay?t.create.push(sB(e.xref,e.handle,i.name,e.tag,RB(t,i.handler,i.handlerSpan),i.sourceSpan)):t.create.push(aI(e.xref,e.handle,i.name,e.tag,uI(t,i.handler,i.handlerSpan),i.phase,i.target,!1,i.sourceSpan))),r===Js.Structural&&i.type!==wi.Animation){let o=yu.securityContext(bu,i.name,!1);t.create.push(Wi(e.xref,Je.Property,null,i.name,null,null,null,o))}}s.some(i=>i?.i18nMessage)!==null&&t.create.push(oB(t.job.allocateXrefId(),new ni,e.xref))}function kw(t,e,n,r,s,i,o,a,c,u,d){let p=typeof s=="string";if(c===Js.Structural){if(!a)switch(n){case Rn.Property:case Rn.Class:case Rn.Style:return Wi(e,Je.Property,null,r,null,null,u,o);case Rn.TwoWay:return Wi(e,Je.TwoWayProperty,null,r,null,null,u,o)}if(!p&&(n===Rn.Attribute||n===Rn.Animation))return null}let f=NB.get(n);return c===Js.NgTemplate&&(n===Rn.Class||n===Rn.Style||n===Rn.Attribute&&!p)&&(f=Je.Property),ku(e,f,r,I_(t.job,s,u),i,o,p,a,c,u,d)}function uI(t,e,n){e=uy(e);let r=new Array,s=e instanceof Tf?e.expressions:[e];if(s.length===0)throw new Error("Expected listener to have non-empty expression list.");let i=s.map(a=>_t(a,t.job,n)),o=i.pop();return r.push(...i.map(a=>So(new Qi(a,a.sourceSpan)))),r.push(So(new gs(o,o.sourceSpan))),r}function RB(t,e,n){e=uy(e);let r=new Array;if(e instanceof Tf)if(e.expressions.length===1)e=e.expressions[0];else throw new Error("Expected two-way listener to have a single expression.");let s=_t(e,t.job,n),i=new ss("$event"),o=new TE(s,i);return r.push(So(new Qi(o))),r.push(So(new gs(i))),r}function uy(t){return t instanceof qi?t.ast:t}function FB(t,e){zee(t.localRefs);for(let{name:n,value:r}of e.references)t.localRefs.push({name:n,target:r})}function zee(t){if(!Array.isArray(t))throw new Error("AssertionError: expected an array")}function Nr(t,e){if(e===null)return null;let n=e.start.moveBy(t.start),r=e.start.moveBy(t.end),s=e.fullStart.moveBy(t.start);return new Dt(n,r,s)}function GE(t,e,n){let r=null;for(let s of n.children)if(!(s instanceof nx||s instanceof X_)){if(r!==null)return null;if(s instanceof oa||s instanceof Ei&&s.tagName!==null)r=s;else return null}if(r!==null){for(let i of r.attributes){let o=yu.securityContext(bu,i.name,!0);t.update.push(ku(e,Je.Attribute,i.name,Y(i.value),null,o,!0,!1,null,Za(i.i18n),i.sourceSpan))}for(let i of r.inputs)if(i.type!==Rn.Animation&&i.type!==Rn.Attribute){let o=yu.securityContext(bu,i.name,!0);t.create.push(Wi(e,Je.Property,null,i.name,null,null,null,o))}let s=r instanceof oa?r.name:r.tagName;return s===bu?null:s}return null}var Gee=!1;function Zee(){return Gee}function ZE(t,e){return ex(Rt(J_).bitwiseAnd(Y(t),null,!1),e)}function Yee(t){return(t.descendants?1:0)|(t.static?2:0)|(t.emitDistinctChangesOnly?4:0)}function Xee(t,e){if(Array.isArray(t.predicate)){let n=[];return t.predicate.forEach(r=>{let s=r.split(",").map(i=>Y(i.trim()));n.push(...s)}),e.getConstLiteral(fn(n),!0)}else switch(t.predicate.forwardRef){case 0:case 2:return t.predicate.expression;case 1:return Xe(y.resolveForwardRef).callFn([t.predicate.expression])}}function LB(t,e,n,r){let s=[];r!==void 0&&s.push(...r),t.isSignal&&s.push(new Si(Rt(zv),t.propertyName)),s.push(Xee(t,e),Y(Yee(t))),t.read&&s.push(t.read);let i=t.isSignal?n.signalBased:n.nonSignal;return Xe(i).callFn(s)}var dI=Symbol("queryAdvancePlaceholder");function OB(t){let e=[],n=0,r=()=>{n>0&&(e.unshift(Xe(y.queryAdvance).callFn(n===1?[]:[Y(n)]).toStmt()),n=0)};for(let s=t.length-1;s>=0;s--){let i=t[s];i===dI?n++:(r(),e.unshift(i))}return r(),e}function Qee(t,e,n){let r=[],s=[],i=NO(a=>s.push(a),K_);t.forEach(a=>{let c=LB(a,e,{signalBased:y.viewQuerySignal,nonSignal:y.viewQuery});if(r.push(c.toStmt()),a.isSignal){s.push(dI);return}let u=i(),d=Xe(y.loadQuery).callFn([]),p=Xe(y.queryRefresh).callFn([u.set(d)]),f=Rt(zv).prop(a.propertyName).set(a.first?u.prop("first"):u);s.push(p.and(f).toStmt())});let o=n?`${n}_Query`:null;return sc([new zr(J_,G_),new zr(zv,null)],[ZE(1,r),ZE(2,OB(s))],zi,null,o)}function Kee(t,e,n){let r=[],s=[],i=NO(a=>s.push(a),K_);for(let a of t){if(r.push(LB(a,e,{nonSignal:y.contentQuery,signalBased:y.contentQuerySignal},[Rt("dirIndex")]).toStmt()),a.isSignal){s.push(dI);continue}let c=i(),u=Xe(y.loadQuery).callFn([]),d=Xe(y.queryRefresh).callFn([c.set(u)]),p=Rt(zv).prop(a.propertyName).set(a.first?c.prop("first"):c);s.push(d.and(p).toStmt())}let o=n?`${n}_ContentQueries`:null;return sc([new zr(J_,G_),new zr(zv,null),new zr("dirIndex",null)],[ZE(1,r),ZE(2,OB(s))],zi,null,o)}var k_=class extends BX{constructor(){super(bB)}parse(e,n,r){return super.parse(e,n,r)}},tO=".",Jee="attr",ete="class",tte="style",nte="*",h1="animate-",A_=class{constructor(e,n,r,s){l(this,"_exprParser");l(this,"_interpolationConfig");l(this,"_schemaRegistry");l(this,"errors");this._exprParser=e,this._interpolationConfig=n,this._schemaRegistry=r,this.errors=s}get interpolationConfig(){return this._interpolationConfig}createBoundHostProperties(e,n){let r=[];for(let s of Object.keys(e)){let i=e[s];typeof i=="string"?this.parsePropertyBinding(s,i,!0,!1,n,n.start.offset,void 0,[],r,n):this._reportError(`Value of the host property binding "${s}" needs to be a string representing an expression but got "${i}" (${typeof i})`,n)}return r}createDirectiveHostEventAsts(e,n){let r=[];for(let s of Object.keys(e)){let i=e[s];typeof i=="string"?this.parseEvent(s,i,!1,n,n,[],r,n):this._reportError(`Value of the host listener "${s}" needs to be a string representing an expression but got "${i}" (${typeof i})`,n)}return r}parseInterpolation(e,n,r){let s=n.start.toString(),i=n.fullStart.offset;try{let o=this._exprParser.parseInterpolation(e,s,i,r,this._interpolationConfig);return o&&this._reportExpressionParserErrors(o.errors,n),o}catch(o){return this._reportError(`${o}`,n),this._exprParser.wrapLiteralPrimitive("ERROR",s,i)}}parseInterpolationExpression(e,n){let r=n.start.toString(),s=n.start.offset;try{let i=this._exprParser.parseInterpolationExpression(e,r,s);return i&&this._reportExpressionParserErrors(i.errors,n),i}catch(i){return this._reportError(`${i}`,n),this._exprParser.wrapLiteralPrimitive("ERROR",r,s)}}parseInlineTemplateBinding(e,n,r,s,i,o,a,c){let u=r.start.offset+nte.length,d=this._parseTemplateBindings(e,n,r,u,s);for(let p of d){let f=zl(r,p.sourceSpan),h=p.key.source,m=zl(r,p.key.span);if(p instanceof Bv){let g=p.value?p.value.source:"$implicit",v=p.value?zl(r,p.value.span):void 0;a.push(new R1(h,g,f,m,v))}else if(p.value){let g=c?f:r,v=zl(r,p.value.ast.sourceSpan);this._parsePropertyAst(h,p.value,!1,g,m,v,i,o)}else i.push([h,""]),this.parseLiteralAttr(h,null,m,s,void 0,i,o,m)}}_parseTemplateBindings(e,n,r,s,i){let o=r.start.toString();try{let a=this._exprParser.parseTemplateBindings(e,n,o,s,i);return this._reportExpressionParserErrors(a.errors,r),a.warnings.forEach(c=>{this._reportError(c,r,za.WARNING)}),a.templateBindings}catch(a){return this._reportError(`${a}`,r),[]}}parseLiteralAttr(e,n,r,s,i,o,a,c){m1(e)?(e=e.substring(1),c!==void 0&&(c=zl(c,new bi(c.start.offset+1,c.end.offset))),n&&this._reportError('Assigning animation triggers via @prop="exp" attributes with an expression is invalid. Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.',r,za.ERROR),this._parseAnimation(e,n,r,s,c,i,o,a)):a.push(new vv(e,this._exprParser.wrapLiteralPrimitive(n,"",s),Ua.LITERAL_ATTR,r,c,i))}parsePropertyBinding(e,n,r,s,i,o,a,c,u,d){e.length===0&&this._reportError("Property name is missing in binding",i);let p=!1;e.startsWith(h1)?(p=!0,e=e.substring(h1.length),d!==void 0&&(d=zl(d,new bi(d.start.offset+h1.length,d.end.offset)))):m1(e)&&(p=!0,e=e.substring(1),d!==void 0&&(d=zl(d,new bi(d.start.offset+1,d.end.offset)))),p?this._parseAnimation(e,n,i,o,d,a,c,u):this._parsePropertyAst(e,this.parseBinding(n,r,a||i,o),s,i,d,a,c,u)}parsePropertyInterpolation(e,n,r,s,i,o,a,c){let u=this.parseInterpolation(n,s||r,c);return u?(this._parsePropertyAst(e,u,!1,r,a,s,i,o),!0):!1}_parsePropertyAst(e,n,r,s,i,o,a,c){a.push([e,n.source]),c.push(new vv(e,n,r?Ua.TWO_WAY:Ua.DEFAULT,s,i,o))}_parseAnimation(e,n,r,s,i,o,a,c){e.length===0&&this._reportError("Animation trigger is missing",r);let u=this.parseBinding(n||"undefined",!1,o||r,s);a.push([e,u.source]),c.push(new vv(e,u,Ua.ANIMATION,r,i,o))}parseBinding(e,n,r,s){let i=(r&&r.start||"(unknown)").toString();try{let o=n?this._exprParser.parseSimpleBinding(e,i,s,this._interpolationConfig):this._exprParser.parseBinding(e,i,s,this._interpolationConfig);return o&&this._reportExpressionParserErrors(o.errors,r),o}catch(o){return this._reportError(`${o}`,r),this._exprParser.wrapLiteralPrimitive("ERROR",i,s)}}createBoundElementProperty(e,n,r=!1,s=!0){if(n.isAnimation)return new lE(n.name,Rn.Animation,Gt.NONE,n.expression,null,n.sourceSpan,n.keySpan,n.valueSpan);let i=null,o,a=null,c=n.name.split(tO),u;if(c.length>1)if(c[0]==Jee){a=c.slice(1).join(tO),r||this._validatePropertyOrAttributeName(a,n.sourceSpan,!0),u=g1(this._schemaRegistry,e,a,!0);let d=a.indexOf(":");if(d>-1){let p=a.substring(0,d),f=a.substring(d+1);a=O1(p,f)}o=Rn.Attribute}else c[0]==ete?(a=c[1],o=Rn.Class,u=[Gt.NONE]):c[0]==tte&&(i=c.length>2?c[2]:null,a=c[1],o=Rn.Style,u=[Gt.STYLE]);if(a===null){let d=this._schemaRegistry.getMappedPropName(n.name);a=s?d:n.name,u=g1(this._schemaRegistry,e,d,!1),o=n.type===Ua.TWO_WAY?Rn.TwoWay:Rn.Property,r||this._validatePropertyOrAttributeName(d,n.sourceSpan,!1)}return new lE(a,o,u[0],n.expression,i,n.sourceSpan,n.keySpan,n.valueSpan)}parseEvent(e,n,r,s,i,o,a,c){e.length===0&&this._reportError("Event name is missing in binding",s),m1(e)?(e=e.slice(1),c!==void 0&&(c=zl(c,new bi(c.start.offset+1,c.end.offset))),this._parseAnimationEvent(e,n,s,i,a,c)):this._parseRegularEvent(e,n,r,s,i,o,a,c)}calcPossibleSecurityContexts(e,n,r){let s=this._schemaRegistry.getMappedPropName(n);return g1(this._schemaRegistry,e,s,r)}_parseAnimationEvent(e,n,r,s,i,o){let a=v7(e,[e,""]),c=a[0],u=a[1].toLowerCase(),d=this._parseAction(n,s);i.push(new aE(c,u,wi.Animation,d,r,s,o)),c.length===0&&this._reportError("Animation event name is missing in binding",r),u?u!=="start"&&u!=="done"&&this._reportError(`The provided animation output phase value "${u}" for "@${c}" is not supported (use start or done)`,r):this._reportError(`The animation trigger output event (@${c}) is missing its phase value name (start or done are currently supported)`,r)}_parseRegularEvent(e,n,r,s,i,o,a,c){let[u,d]=g7(e,[null,e]),p=this.errors.length,f=this._parseAction(n,i),h=this.errors.length===p;o.push([e,f.source]),r&&h&&!this._isAllowedAssignmentEvent(f)&&this._reportError("Unsupported expression in a two-way binding",s),a.push(new aE(d,u,r?wi.TwoWay:wi.Regular,f,s,i,c))}_parseAction(e,n){let r=(n&&n.start||"(unknown").toString(),s=n&&n.start?n.start.offset:0;try{let i=this._exprParser.parseAction(e,r,s,this._interpolationConfig);return i&&this._reportExpressionParserErrors(i.errors,n),!i||i.ast instanceof Xs?(this._reportError("Empty expressions are not allowed",n),this._exprParser.wrapLiteralPrimitive("ERROR",r,s)):i}catch(i){return this._reportError(`${i}`,n),this._exprParser.wrapLiteralPrimitive("ERROR",r,s)}}_reportError(e,n,r=za.ERROR,s){this.errors.push(new vt(n,e,r,s))}_reportExpressionParserErrors(e,n){for(let r of e)this._reportError(r.message,n,void 0,r)}_validatePropertyOrAttributeName(e,n,r){let s=r?this._schemaRegistry.validateAttribute(e):this._schemaRegistry.validateProperty(e);s.error&&this._reportError(s.msg,n,za.ERROR)}_isAllowedAssignmentEvent(e){return e instanceof qi?this._isAllowedAssignmentEvent(e.ast):e instanceof Fv?this._isAllowedAssignmentEvent(e.expression):e instanceof Lv&&e.args.length===1&&e.receiver instanceof Tu&&e.receiver.name==="$any"&&e.receiver.receiver instanceof Yi&&!(e.receiver.receiver instanceof Cu)?this._isAllowedAssignmentEvent(e.args[0]):e instanceof Tu||e instanceof Nv}};function m1(t){return t[0]=="@"}function g1(t,e,n,r){let s,[i,o]=e?vs(e,!1):[null,e],a=u=>{let[d,p]=vs(u,!1),f=d??i,h=f?`:${f}:${p}`:p;return t.securityContext(h,n,r)},c=t.allKnownElementNames();return o===null?s=c.map(a):(s=[],yf.parse(o).forEach(u=>{let d=u.element?[u.element]:c;if(u.element&&!t.hasElement(u.element,[])){let h=`:${cx}:${u.element}`,m=`:${ux}:${u.element}`;t.hasElement(h,[])?d=[h]:t.hasElement(m,[])&&(d=[m])}let p=new Set(u.notSelectors.filter(h=>h.isElementSelector()).map(h=>h.element?.toLowerCase())),f=d.filter(h=>{let m=h.toLowerCase();return!p.has(m)&&!p.has(vs(m)[1])});s.push(...f.map(a))})),s.length===0?[Gt.NONE]:Array.from(new Set(s)).sort()}function zl(t,e){let n=e.start-t.start.offset,r=e.end-t.end.offset;return new Dt(t.start.moveBy(n),t.end.moveBy(r),t.fullStart.moveBy(n),t.details)}function rte(t){if(t==null||t.length===0||t[0]=="/")return!1;let e=t.match(ste);return e===null||e[1]=="package"||e[1]=="asset"}var ste=/^([^:/?#]+):/,ite="select",ote="link",ate="rel",lte="href",cte="stylesheet",ute="style",dte=new Set([":svg:script","script"]),pte="ngNonBindable",fte="ngProjectAs";function BB(t){let e=null,n=null,r=null,s=!1,i="";for(let c of t.attrs){let u=c.name.toLowerCase();u==ite?e=c.value:u==lte?n=c.value:u==ate?r=c.value:c.name==pte?s=!0:c.name==fte&&c.value.length>0&&(i=c.value)}e||(e="*");let o=t.name.toLowerCase(),a=Ks.OTHER;return F1(o)?a=Ks.NG_CONTENT:ute===o?a=Ks.STYLE:dte.has(o)?a=Ks.SCRIPT:o==ote&&r==cte&&(a=Ks.STYLESHEET),new M_(a,e,n,s,i)}var Ks;(function(t){t[t.NG_CONTENT=0]="NG_CONTENT",t[t.STYLE=1]="STYLE",t[t.STYLESHEET=2]="STYLESHEET",t[t.SCRIPT=3]="SCRIPT",t[t.OTHER=4]="OTHER"})(Ks||(Ks={}));var M_=class{constructor(e,n,r,s,i){l(this,"type");l(this,"selectAttr");l(this,"hrefAttr");l(this,"nonBindable");l(this,"projectAs");this.type=e,this.selectAttr=n,this.hrefAttr=r,this.nonBindable=s,this.projectAs=i}},hte=/^\s*([0-9A-Za-z_$]*)\s+of\s+([\S\s]*)/,mte=/^track\s+([\S\s]*)/,gte=/^(as\s+)(.*)/,pI=/^else[^\S\r\n]+if/,vte=/^let\s+([\S\s]*)/,yte=/^[$A-Z_][0-9A-Z_$]*$/i,nO=/(\s*)(\S+)(\s*)/,Cv=new Set(["$index","$first","$last","$even","$odd","$count"]);function rO(t){return t==="empty"}function sO(t){return t==="else"||pI.test(t)}function bte(t,e,n,r){let s=Cte(e),i=[],o=iO(t,s,r);o!==null&&i.push(new mu(o.expression,nr(n,t.children,t.children),o.expressionAlias,t.sourceSpan,t.startSourceSpan,t.endSourceSpan,t.nameSpan,t.i18n));for(let p of e)if(pI.test(p.name)){let f=iO(p,s,r);if(f!==null){let h=nr(n,p.children,p.children);i.push(new mu(f.expression,h,f.expressionAlias,p.sourceSpan,p.startSourceSpan,p.endSourceSpan,p.nameSpan,p.i18n))}}else if(p.name==="else"){let f=nr(n,p.children,p.children);i.push(new mu(null,f,null,p.sourceSpan,p.startSourceSpan,p.endSourceSpan,p.nameSpan,p.i18n))}let a=i.length>0?i[0].startSourceSpan:t.startSourceSpan,c=i.length>0?i[i.length-1].endSourceSpan:t.endSourceSpan,u=t.sourceSpan,d=i[i.length-1];return d!==void 0&&(u=new Dt(a.start,d.sourceSpan.end)),{node:new fE(i,u,t.startSourceSpan,c,t.nameSpan),errors:s}}function wte(t,e,n,r){let s=[],i=xte(t,s,r),o=null,a=null;for(let c of e)c.name==="empty"?a!==null?s.push(new vt(c.sourceSpan,"@for loop can only have one @empty block")):c.parameters.length>0?s.push(new vt(c.sourceSpan,"@empty block cannot have parameters")):a=new Uv(nr(n,c.children,c.children),c.sourceSpan,c.startSourceSpan,c.endSourceSpan,c.nameSpan,c.i18n):s.push(new vt(c.sourceSpan,`Unrecognized @for loop block "${c.name}"`));if(i!==null)if(i.trackBy===null)s.push(new vt(t.startSourceSpan,'@for loop must have a "track" expression'));else{let c=a?.endSourceSpan??t.endSourceSpan,u=new Dt(t.sourceSpan.start,c?.end??t.sourceSpan.end);o=new If(i.itemName,i.expression,i.trackBy.expression,i.trackBy.keywordSpan,i.context,nr(n,t.children,t.children),a,u,t.sourceSpan,t.startSourceSpan,c,t.nameSpan,t.i18n)}return{node:o,errors:s}}function Ete(t,e,n){let r=Tte(t),s=t.parameters.length>0?dy(t.parameters[0],n):n.parseBinding("",!1,t.sourceSpan,0),i=[],o=[],a=null;for(let c of t.children){if(!(c instanceof Ui))continue;if((c.name!=="case"||c.parameters.length===0)&&c.name!=="default"){o.push(new hE(c.name,c.sourceSpan,c.nameSpan));continue}let u=c.name==="case"?dy(c.parameters[0],n):null,d=new jv(u,nr(e,c.children,c.children),c.sourceSpan,c.startSourceSpan,c.endSourceSpan,c.nameSpan,c.i18n);u===null?a=d:i.push(d)}return a!==null&&i.push(a),{node:new pE(s,i,o,t.sourceSpan,t.startSourceSpan,t.endSourceSpan,t.nameSpan),errors:r}}function xte(t,e,n){if(t.parameters.length===0)return e.push(new vt(t.startSourceSpan,"@for loop does not have an expression")),null;let[r,...s]=t.parameters,i=Dte(r,e)?.match(hte);if(!i||i[2].trim().length===0)return e.push(new vt(r.sourceSpan,'Cannot parse expression. @for loop expression must match the pattern " of "')),null;let[,o,a]=i;Cv.has(o)&&e.push(new vt(r.sourceSpan,`@for loop item name cannot be one of ${Array.from(Cv).join(", ")}.`));let c=r.expression.split(" ")[0],u=new Dt(r.sourceSpan.start,r.sourceSpan.start.moveBy(c.length)),d={itemName:new ic(o,"$implicit",u,u),trackBy:null,expression:dy(r,n,a),context:Array.from(Cv,p=>{let f=new Dt(t.startSourceSpan.end,t.startSourceSpan.end);return new ic(p,p,f,f)})};for(let p of s){let f=p.expression.match(vte);if(f!==null){let m=new Dt(p.sourceSpan.start.moveBy(f[0].length-f[1].length),p.sourceSpan.end);Ste(p.sourceSpan,f[1],m,o,d.context,e);continue}let h=p.expression.match(mte);if(h!==null){if(d.trackBy!==null)e.push(new vt(p.sourceSpan,'@for loop can only have one "track" expression'));else{let m=dy(p,n,h[1]);m.ast instanceof Xs&&e.push(new vt(t.startSourceSpan,'@for loop must have a "track" expression'));let g=new Dt(p.sourceSpan.start,p.sourceSpan.start.moveBy(5));d.trackBy={expression:m,keywordSpan:g}}continue}e.push(new vt(p.sourceSpan,`Unrecognized @for loop parameter "${p.expression}"`))}return d}function Ste(t,e,n,r,s,i){let o=e.split(","),a=n.start;for(let c of o){let u=c.split("="),d=u.length===2?u[0].trim():"",p=u.length===2?u[1].trim():"";if(d.length===0||p.length===0)i.push(new vt(t,'Invalid @for loop "let" parameter. Parameter should match the pattern " = "'));else if(!Cv.has(p))i.push(new vt(t,`Unknown "let" parameter variable "${p}". The allowed variables are: ${Array.from(Cv).join(", ")}`));else if(d===r)i.push(new vt(t,`Invalid @for loop "let" parameter. Variable cannot be called "${r}"`));else if(s.some(f=>f.name===d))i.push(new vt(t,`Duplicate "let" parameter variable "${p}"`));else{let[,f,h]=u[0].match(nO)??[],m=f!==void 0&&u.length===2?new Dt(a.moveBy(f.length),a.moveBy(f.length+h.length)):n,g;if(u.length===2){let[,w,b]=u[1].match(nO)??[];g=w!==void 0?new Dt(a.moveBy(u[0].length+1+w.length),a.moveBy(u[0].length+1+w.length+b.length)):void 0}let v=new Dt(m.start,g?.end??m.end);s.push(new ic(d,p,v,m,g))}a=a.moveBy(c.length+1)}}function Cte(t){let e=[],n=!1;for(let r=0;r1&&r0&&e.push(new vt(s.startSourceSpan,"@else block cannot have parameters")),n=!0):pI.test(s.name)||e.push(new vt(s.startSourceSpan,`Unrecognized conditional block @${s.name}`))}return e}function Tte(t){let e=[],n=!1;if(t.parameters.length!==1)return e.push(new vt(t.startSourceSpan,"@switch block must have exactly one parameter")),e;for(let r of t.children)if(!(r instanceof oy||r instanceof Nu&&r.value.trim().length===0)){if(!(r instanceof Ui)||r.name!=="case"&&r.name!=="default"){e.push(new vt(r.sourceSpan,"@switch block can only contain @case and @default blocks"));continue}r.name==="default"?(n?e.push(new vt(r.startSourceSpan,"@switch block can only have one @default block")):r.parameters.length>0&&e.push(new vt(r.startSourceSpan,"@default block cannot have parameters")),n=!0):r.name==="case"&&r.parameters.length!==1&&e.push(new vt(r.startSourceSpan,"@case block must have exactly one parameter"))}return e}function dy(t,e,n){let r,s;return typeof n=="string"?(r=Math.max(0,t.expression.lastIndexOf(n)),s=r+n.length):(r=0,s=t.expression.length),e.parseBinding(t.expression.slice(r,s),!1,t.sourceSpan,t.sourceSpan.start.offset+r)}function iO(t,e,n){if(t.parameters.length===0)return e.push(new vt(t.startSourceSpan,"Conditional block does not have an expression")),null;let r=dy(t.parameters[0],n),s=null;for(let i=1;i-1;a--){let c=n[a];if(c===")"){if(o=a,s--,s===0)break}else{if(r.test(c))continue;break}}return s!==0?(e.push(new vt(t.sourceSpan,"Unclosed parentheses in expression")),null):n.slice(i,o)}var _te=/^\d+\.?\d*(ms|s)?$/,Ite=/^\s$/,oO=new Map([[bo,Qs],[gf,uf],[Xa,wo]]),ks;(function(t){t.IDLE="idle",t.TIMER="timer",t.INTERACTION="interaction",t.IMMEDIATE="immediate",t.HOVER="hover",t.VIEWPORT="viewport",t.NEVER="never"})(ks||(ks={}));function kte({expression:t,sourceSpan:e},n,r){let s=t.indexOf("never"),i=new Dt(e.start.moveBy(s),e.start.moveBy(s+5)),o=fI(t,e),a=hI(t,e);s===-1?r.push(new vt(e,'Could not find "never" keyword in expression')):mI("never",n,r,new H1(i,e,o,null,a))}function v1({expression:t,sourceSpan:e},n,r,s){let i=t.indexOf("when"),o=new Dt(e.start.moveBy(i),e.start.moveBy(i+4)),a=fI(t,e),c=hI(t,e);if(i===-1)s.push(new vt(e,'Could not find "when" keyword in expression'));else{let u=py(t,i+1),d=n.parseBinding(t.slice(u),!1,e,e.start.offset+u);mI("when",r,s,new V1(d,e,a,o,c))}}function y1({expression:t,sourceSpan:e},n,r,s){let i=t.indexOf("on"),o=new Dt(e.start.moveBy(i),e.start.moveBy(i+2)),a=fI(t,e),c=hI(t,e);if(i===-1)r.push(new vt(e,'Could not find "on" keyword in expression'));else{let u=py(t,i+1);new P_(t,u,e,n,r,t.startsWith("hydrate")?Ote:Lte,s,a,o,c).parse()}}function fI(t,e){return t.startsWith("prefetch")?new Dt(e.start,e.start.moveBy(8)):null}function hI(t,e){return t.startsWith("hydrate")?new Dt(e.start,e.start.moveBy(7)):null}var P_=class{constructor(e,n,r,s,i,o,a,c,u,d){l(this,"expression");l(this,"start");l(this,"span");l(this,"triggers");l(this,"errors");l(this,"validator");l(this,"placeholder");l(this,"prefetchSpan");l(this,"onSourceSpan");l(this,"hydrateSpan");l(this,"index",0);l(this,"tokens");this.expression=e,this.start=n,this.span=r,this.triggers=s,this.errors=i,this.validator=o,this.placeholder=a,this.prefetchSpan=c,this.onSourceSpan=u,this.hydrateSpan=d,this.tokens=new cy().tokenize(e.slice(n))}parse(){for(;this.tokens.length>0&&this.index0&&s.isCharacter(n[n.length-1])&&n.pop(),n.length===0&&s.isCharacter(Gi)&&r.length>0){e.push(r),r="",this.advance();continue}r+=this.tokenText(),this.advance()}return(!this.token().isCharacter(wo)||n.length>0)&&this.error(this.token(),"Unexpected end of expression"),this.index0)throw new Error(`"${ks.IDLE}" trigger cannot have parameters`);return new j1(e,n,r,s,i)}function Mte(t,e,n,r,s,i){if(t.length!==1)throw new Error(`"${ks.TIMER}" trigger must have exactly one parameter`);let o=YE(t[0]);if(o===null)throw new Error(`Could not parse time value of trigger "${ks.TIMER}"`);return new q1(o,e,n,r,s,i)}function Pte(t,e,n,r,s,i){if(t.length>0)throw new Error(`"${ks.IMMEDIATE}" trigger cannot have parameters`);return new U1(e,n,r,s,i)}function Nte(t,e,n,r,s,i,o,a){return a(ks.HOVER,t,o),new cE(t[0]??null,e,n,r,s,i)}function Rte(t,e,n,r,s,i,o,a){return a(ks.INTERACTION,t,o),new uE(t[0]??null,e,n,r,s,i)}function Fte(t,e,n,r,s,i,o,a){return a(ks.VIEWPORT,t,o),new dE(t[0]??null,e,n,r,s,i)}function Lte(t,e,n){if(e.length>1)throw new Error(`"${t}" trigger can only have zero or one parameters`);if(e.length===0){if(n===null)throw new Error(`"${t}" trigger with no parameters can only be placed on an @defer that has a @placeholder block`);if(n.children.length!==1||!(n.children[0]instanceof oa))throw new Error(`"${t}" trigger with no parameters can only be placed on an @defer that has a @placeholder block with exactly one root element node`)}}function Ote(t,e){if(e.length>0)throw new Error(`Hydration trigger "${t}" cannot have parameters`)}function py(t,e=0){let n=!1;for(let r=e;r0){let g=e[e.length-1];p=g.endSourceSpan,f=g.sourceSpan.end}let h=new Dt(t.sourceSpan.start,f);return{node:new Du(nr(n,t.children,t.children),c,u,d,i,o,a,t.nameSpan,h,t.sourceSpan,t.startSourceSpan,p,t.i18n),errors:s}}function Gte(t,e,n){let r=null,s=null,i=null;for(let o of t)try{if(!N_(o.name)){e.push(new vt(o.startSourceSpan,`Unrecognized block "@${o.name}"`));break}switch(o.name){case"placeholder":r!==null?e.push(new vt(o.startSourceSpan,"@defer block can only have one @placeholder block")):r=Zte(o,n);break;case"loading":s!==null?e.push(new vt(o.startSourceSpan,"@defer block can only have one @loading block")):s=Yte(o,n);break;case"error":i!==null?e.push(new vt(o.startSourceSpan,"@defer block can only have one @error block")):i=Xte(o,n);break}}catch(a){e.push(new vt(o.startSourceSpan,a.message))}return{placeholder:r,loading:s,error:i}}function Zte(t,e){let n=null;for(let r of t.parameters)if($B.test(r.expression)){if(n!=null)throw new Error('@placeholder block can only have one "minimum" parameter');let s=YE(r.expression.slice(py(r.expression)));if(s===null)throw new Error('Could not parse time value of parameter "minimum"');n=s}else throw new Error(`Unrecognized parameter in @placeholder block: "${r.expression}"`);return new $v(nr(e,t.children,t.children),n,t.nameSpan,t.sourceSpan,t.startSourceSpan,t.endSourceSpan,t.i18n)}function Yte(t,e){let n=null,r=null;for(let s of t.parameters)if(Ute.test(s.expression)){if(n!=null)throw new Error('@loading block can only have one "after" parameter');let i=YE(s.expression.slice(py(s.expression)));if(i===null)throw new Error('Could not parse time value of parameter "after"');n=i}else if($B.test(s.expression)){if(r!=null)throw new Error('@loading block can only have one "minimum" parameter');let i=YE(s.expression.slice(py(s.expression)));if(i===null)throw new Error('Could not parse time value of parameter "minimum"');r=i}else throw new Error(`Unrecognized parameter in @loading block: "${s.expression}"`);return new Vv(nr(e,t.children,t.children),n,r,t.nameSpan,t.sourceSpan,t.startSourceSpan,t.endSourceSpan,t.i18n)}function Xte(t,e){if(t.parameters.length>0)throw new Error("@error block cannot have parameters");return new Hv(nr(e,t.children,t.children),t.nameSpan,t.sourceSpan,t.startSourceSpan,t.endSourceSpan,t.i18n)}function Qte(t,e,n,r){let s={},i={},o={};for(let a of t.parameters)qte.test(a.expression)?v1(a,e,s,n):Wte.test(a.expression)?y1(a,s,n,r):Bte.test(a.expression)?v1(a,e,i,n):$te.test(a.expression)?y1(a,i,n,r):Vte.test(a.expression)?v1(a,e,o,n):Hte.test(a.expression)?y1(a,o,n,r):jte.test(a.expression)?kte(a,o,n):n.push(new vt(a.sourceSpan,"Unrecognized trigger"));return o.never&&Object.keys(o).length>1&&n.push(new vt(t.startSourceSpan,"Cannot specify additional `hydrate` triggers if `hydrate never` is present")),{triggers:s,prefetchTriggers:i,hydrateTriggers:o}}var Kte=/^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/,aO=1,lO=2,cO=3,uO=4,dO=5,Jte=6,pv=7,Gl={BANANA_BOX:{start:"[(",end:")]"},PROPERTY:{start:"[",end:"]"},EVENT:{start:"(",end:")"}},pO="*";function ene(t,e,n){let r=new R_(e,n),s=nr(r,t,t),i=e.errors.concat(r.errors),o={nodes:s,errors:i,styleUrls:r.styleUrls,styles:r.styles,ngContentSelectors:r.ngContentSelectors};return n.collectCommentNodes&&(o.commentNodes=r.commentNodes),o}var R_=class{constructor(e,n){l(this,"bindingParser");l(this,"options");l(this,"errors",[]);l(this,"styles",[]);l(this,"styleUrls",[]);l(this,"ngContentSelectors",[]);l(this,"commentNodes",[]);l(this,"inI18nBlock",!1);l(this,"processedNodes",new Set);this.bindingParser=e,this.options=n}visitElement(e){let n=__(e.i18n);n&&(this.inI18nBlock&&this.reportError("Cannot mark an element as translatable inside of a translatable section. Please remove the nested i18n marker.",e.sourceSpan),this.inI18nBlock=!0);let r=BB(e);if(r.type===Ks.SCRIPT)return null;if(r.type===Ks.STYLE){let v=nne(e);return v!==null&&this.styles.push(v),null}else if(r.type===Ks.STYLESHEET&&rte(r.hrefAttr))return this.styleUrls.push(r.hrefAttr),null;let s=O7(e.name),i=[],o=[],a=[],c=[],u=[],d={},p=[],f=[],h=!1;for(let v of e.attrs){let w=!1,b=fO(v.name),D=!1;if(v.i18n&&(d[v.name]=v.i18n),b.startsWith(pO)){h&&this.reportError("Can't have multiple template bindings on one element. Use only one attribute prefixed with *",v.sourceSpan),D=!0,h=!0;let B=v.value,M=b.substring(pO.length),$=[],j=v.valueSpan?v.valueSpan.start.offset:v.sourceSpan.start.offset+v.name.length;this.bindingParser.parseInlineTemplateBinding(M,B,v.sourceSpan,j,[],p,$,!0),f.push(...$.map(G=>new ic(G.name,G.value,G.sourceSpan,G.keySpan,G.valueSpan)))}else w=this.parseAttribute(s,v,[],i,o,a,c);!w&&!D&&u.push(this.visitAttribute(v))}let m;r.nonBindable?m=nr(tne,e.children).flat(1/0):m=nr(this,e.children,e.children);let g;if(r.type===Ks.NG_CONTENT){let v=r.selectAttr,w=e.attrs.map(b=>this.visitAttribute(b));g=new kf(v,w,m,e.sourceSpan,e.i18n),this.ngContentSelectors.push(v)}else if(s){let v=this.extractAttributes(e.name,i,d);g=new Ei(e.name,u,v.bound,o,[],m,c,a,e.sourceSpan,e.startSourceSpan,e.endSourceSpan,e.i18n)}else{let v=this.extractAttributes(e.name,i,d);g=new oa(e.name,u,v.bound,o,m,c,e.sourceSpan,e.startSourceSpan,e.endSourceSpan,e.i18n)}if(h){let v=this.extractAttributes("ng-template",p,d),w=[];v.literal.forEach(M=>w.push(M)),v.bound.forEach(M=>w.push(M));let b=g instanceof oa?{attributes:g.attributes,inputs:g.inputs,outputs:g.outputs}:{attributes:[],inputs:[],outputs:[]},D=s&&n?void 0:e.i18n,B=g instanceof Ei?null:g.name;g=new Ei(B,b.attributes,b.inputs,b.outputs,w,[g],[],f,e.sourceSpan,e.startSourceSpan,e.endSourceSpan,D)}return n&&(this.inI18nBlock=!1),g}visitAttribute(e){return new _f(e.name,e.value,e.sourceSpan,e.keySpan,e.valueSpan,e.i18n)}visitText(e){return this.processedNodes.has(e)?null:this._visitTextWithInterpolation(e.value,e.sourceSpan,e.tokens,e.i18n)}visitExpansion(e){if(!e.i18n)return null;if(!__(e.i18n))throw new Error(`Invalid type "${e.i18n.constructor}" for "i18n" property of ${e.sourceSpan.toString()}. Expected a "Message"`);let n=e.i18n,r={},s={};return Object.keys(n.placeholders).forEach(i=>{let o=n.placeholders[i];if(i.startsWith(H7)){let a=i.trim(),c=this.bindingParser.parseInterpolationExpression(o.text,o.sourceSpan);r[a]=new Df(c,o.sourceSpan)}else s[i]=this._visitTextWithInterpolation(o.text,o.sourceSpan,null)}),new kO(r,s,e.sourceSpan,n)}visitExpansionCase(e){return null}visitComment(e){return this.options.collectCommentNodes&&this.commentNodes.push(new nx(e.value||"",e.sourceSpan)),null}visitLetDeclaration(e,n){let r=this.bindingParser.parseBinding(e.value,!1,e.valueSpan,e.valueSpan.start.offset);return r.errors.length===0&&r.ast instanceof Xs&&this.reportError("@let declaration value cannot be empty",e.valueSpan),new X_(e.name,r,e.sourceSpan,e.nameSpan,e.valueSpan)}visitBlockParameter(){return null}visitBlock(e,n){let r=Array.isArray(n)?n.indexOf(e):-1;if(r===-1)throw new Error("Visitor invoked incorrectly. Expecting visitBlock to be invoked siblings array as its context");if(this.processedNodes.has(e))return null;let s=null;switch(e.name){case"defer":s=zte(e,this.findConnectedBlocks(r,n,N_),this,this.bindingParser);break;case"switch":s=Ete(e,this,this.bindingParser);break;case"for":s=wte(e,this.findConnectedBlocks(r,n,rO),this,this.bindingParser);break;case"if":s=bte(e,this.findConnectedBlocks(r,n,sO),this,this.bindingParser);break;default:let i;N_(e.name)?(i=`@${e.name} block can only be used after an @defer block.`,this.processedNodes.add(e)):rO(e.name)?(i=`@${e.name} block can only be used after an @for block.`,this.processedNodes.add(e)):sO(e.name)?(i=`@${e.name} block can only be used after an @if or @else if block.`,this.processedNodes.add(e)):i=`Unrecognized block @${e.name}.`,s={node:new hE(e.name,e.sourceSpan,e.nameSpan),errors:[new vt(e.sourceSpan,i)]};break}return this.errors.push(...s.errors),s.node}findConnectedBlocks(e,n,r){let s=[];for(let i=e+1;i{let a=r[o.name];if(o.isLiteral)i.push(new _f(o.name,o.expression.source||"",o.sourceSpan,o.keySpan,o.valueSpan,a));else{let c=this.bindingParser.createBoundElementProperty(e,o,!0,!1);s.push(B1.fromBoundElementProperty(c,a))}}),{bound:s,literal:i}}parseAttribute(e,n,r,s,i,o,a){let c=fO(n.name),u=n.value,d=n.sourceSpan,p=n.valueSpan?n.valueSpan.start.offset:d.start.offset;function f(w,b,D){let B=n.name.length-c.length,M=w.start.moveBy(b.length+B),$=M.moveBy(D.length);return new Dt(M,$,M,D)}let h=c.match(Kte);if(h){if(h[aO]!=null){let w=h[pv],b=f(d,h[aO],w);this.bindingParser.parsePropertyBinding(w,u,!1,!1,d,p,n.valueSpan,r,s,b)}else if(h[lO])if(e){let w=h[pv],b=f(d,h[lO],w);this.parseVariable(w,u,d,b,n.valueSpan,o)}else this.reportError('"let-" is only supported on ng-template elements.',d);else if(h[cO]){let w=h[pv],b=f(d,h[cO],w);this.parseReference(w,u,d,b,n.valueSpan,a)}else if(h[uO]){let w=[],b=h[pv],D=f(d,h[uO],b);this.bindingParser.parseEvent(b,u,!1,d,n.valueSpan||d,r,w,D),b1(w,i)}else if(h[dO]){let w=h[pv],b=f(d,h[dO],w);this.bindingParser.parsePropertyBinding(w,u,!1,!0,d,p,n.valueSpan,r,s,b),this.parseAssignmentEvent(w,u,d,n.valueSpan,r,i,b)}else if(h[Jte]){let w=f(d,"",c);this.bindingParser.parseLiteralAttr(c,u,d,p,n.valueSpan,r,s,w)}return!0}let m=null;if(c.startsWith(Gl.BANANA_BOX.start)?m=Gl.BANANA_BOX:c.startsWith(Gl.PROPERTY.start)?m=Gl.PROPERTY:c.startsWith(Gl.EVENT.start)&&(m=Gl.EVENT),m!==null&&c.endsWith(m.end)&&c.length>m.start.length+m.end.length){let w=c.substring(m.start.length,c.length-m.end.length),b=f(d,m.start,w);if(m.start===Gl.BANANA_BOX.start)this.bindingParser.parsePropertyBinding(w,u,!1,!0,d,p,n.valueSpan,r,s,b),this.parseAssignmentEvent(w,u,d,n.valueSpan,r,i,b);else if(m.start===Gl.PROPERTY.start)this.bindingParser.parsePropertyBinding(w,u,!1,!1,d,p,n.valueSpan,r,s,b);else{let D=[];this.bindingParser.parseEvent(w,u,!1,d,n.valueSpan||d,r,D,b),b1(D,i)}return!0}let g=f(d,"",c);return this.bindingParser.parsePropertyInterpolation(c,u,d,n.valueSpan,r,s,g,n.valueTokens??null)}_visitTextWithInterpolation(e,n,r,s){let i=mB(e),o=this.bindingParser.parseInterpolation(i,n,r);return o?new Df(o,n,s):new pu(i,n)}parseVariable(e,n,r,s,i,o){e.indexOf("-")>-1?this.reportError('"-" is not allowed in variable names',r):e.length===0&&this.reportError("Variable does not have a name",r),o.push(new ic(e,n,r,s,i))}parseReference(e,n,r,s,i,o){e.indexOf("-")>-1?this.reportError('"-" is not allowed in reference names',r):e.length===0?this.reportError("Reference does not have a name",r):o.some(a=>a.name===e)&&this.reportError(`Reference "#${e}" is defined more than once`,r),o.push(new qv(e,n,r,s,i))}parseAssignmentEvent(e,n,r,s,i,o,a){let c=[];this.bindingParser.parseEvent(`${e}Change`,n,!0,r,s||r,i,c,a),b1(c,o)}reportError(e,n,r=za.ERROR){this.errors.push(new vt(n,e,r))}},F_=class{visitElement(e){let n=BB(e);if(n.type===Ks.SCRIPT||n.type===Ks.STYLE||n.type===Ks.STYLESHEET)return null;let r=nr(this,e.children,null);return new oa(e.name,nr(this,e.attrs),[],[],r,[],e.sourceSpan,e.startSourceSpan,e.endSourceSpan)}visitComment(e){return null}visitAttribute(e){return new _f(e.name,e.value,e.sourceSpan,e.keySpan,e.valueSpan,e.i18n)}visitText(e){return new pu(e.value,e.sourceSpan)}visitExpansion(e){return null}visitExpansionCase(e){return null}visitBlock(e,n){let r=[new pu(e.startSourceSpan.toString(),e.startSourceSpan),...nr(this,e.children)];return e.endSourceSpan!==null&&r.push(new pu(e.endSourceSpan.toString(),e.endSourceSpan)),r}visitBlockParameter(e,n){return null}visitLetDeclaration(e,n){return new pu(`@let ${e.name} = ${e.value};`,e.sourceSpan)}},tne=new F_;function fO(t){return/^data-/i.test(t)?t.substring(5):t}function b1(t,e){e.push(...t.map(n=>$1.fromParsedEvent(n)))}function nne(t){return t.children.length!==1||!(t.children[0]instanceof Nu)?null:t.children[0].value}var rne=[" ",` +`,"\r"," "];function sne(t,e,n={}){let{interpolationConfig:r,preserveWhitespaces:s,enableI18nLegacyMessageIdFormat:i}=n,o=XE(r),c=new k_().parse(t,e,{leadingTriviaChars:rne,...n,tokenizeExpansionForms:!0,tokenizeBlocks:n.enableBlockSyntax??!0,tokenizeLet:n.enableLetSyntax??!0});if(!n.alwaysAttemptHtmlToR3AstConversion&&c.errors&&c.errors.length>0){let B={interpolationConfig:r,preserveWhitespaces:s,errors:c.errors,nodes:[],styleUrls:[],styles:[],ngContentSelectors:[]};return n.collectCommentNodes&&(B.commentNodes=[]),B}let u=c.rootNodes,d=!(n.preserveSignificantWhitespace??!0),p=new HE(r,!s,i,void 0,n.preserveSignificantWhitespace,d),f=p.visitAllWithErrors(u);if(!n.alwaysAttemptHtmlToR3AstConversion&&f.errors&&f.errors.length>0){let B={interpolationConfig:r,preserveWhitespaces:s,errors:f.errors,nodes:[],styleUrls:[],styles:[],ngContentSelectors:[]};return n.collectCommentNodes&&(B.commentNodes=[]),B}u=f.rootNodes,s||(u=nr(new $E(!0,void 0,!1),u),p.hasI18nMeta&&(u=nr(new HE(r,!1,void 0,void 0,!0,d),u)));let{nodes:h,errors:m,styleUrls:g,styles:v,ngContentSelectors:w,commentNodes:b}=ene(u,o,{collectCommentNodes:!!n.collectCommentNodes});m.push(...c.errors,...f.errors);let D={interpolationConfig:r,preserveWhitespaces:s,errors:m.length>0?m:null,nodes:h,styleUrls:g,styles:v,ngContentSelectors:w};return n.collectCommentNodes&&(D.commentNodes=b),D}var ine=new Bf;function XE(t=ea){return new A_(new VE(new cy),t,ine,[])}var VB="%COMP%",one=`_nghost-${VB}`,ane=`_ngcontent-${VB}`;function HB(t,e,n){let r=new lc,s=z_(t.selector);return r.set("type",t.type.value),s.length>0&&r.set("selectors",lf(s)),t.queries.length>0&&r.set("contentQueries",Kee(t.queries,e,t.name)),t.viewQueries.length&&r.set("viewQuery",Qee(t.viewQueries,e,t.name)),r.set("hostBindings",mne(t.host,t.typeSourceSpan,n,e,t.selector||"",t.name,r)),r.set("inputs",sL(t.inputs,!0)),r.set("outputs",sL(t.outputs)),t.exportAs!==null&&r.set("exportAs",fn(t.exportAs.map(i=>Y(i)))),t.isStandalone===!1&&r.set("standalone",Y(!1)),t.isSignal&&r.set("signals",Y(!0)),r}function jB(t,e){let n=[],r=e.providers,s=e.viewProviders;if(r||s){let i=[r||new Eo([])];s&&i.push(s),n.push(Xe(y.ProvidersFeature).callFn(i))}if(e.hostDirectives?.length&&n.push(Xe(y.HostDirectivesFeature).callFn([wne(e.hostDirectives)])),e.usesInheritance&&n.push(Xe(y.InheritDefinitionFeature)),e.fullInheritance&&n.push(Xe(y.CopyDefinitionFeature)),e.lifecycle.usesOnChanges&&n.push(Xe(y.NgOnChangesFeature)),"externalStyles"in e&&e.externalStyles?.length){let i=e.externalStyles.map(o=>Y(o));n.push(Xe(y.ExternalStylesFeature).callFn([fn(i)]))}n.length&&t.set("features",fn(n))}function lne(t,e,n){let r=HB(t,e,n);jB(r,t);let s=Xe(y.defineDirective).callFn([r.toLiteralMap()],void 0,!0),i=hne(t);return{expression:s,type:i,statements:[]}}function cne(t,e,n){let r=HB(t,e,n);jB(r,t);let s=t.selector&&yf.parse(t.selector),i=s&&s[0];if(i){let h=i.getAttrs();h.length&&r.set("attrs",e.getConstLiteral(fn(h.map(m=>m!=null?Y(m):Y(void 0))),!0))}let o=t.name,a=null;if(t.defer.mode===1&&t.defer.dependenciesFn!==null){let h=`${o}_DeferFn`;e.statements.push(new ys(h,t.defer.dependenciesFn,void 0,Wr.Final)),a=Rt(h)}let c=_ee(t.name,t.template.nodes,e,t.relativeContextFilePath,t.i18nUseExternalIds,t.defer,a,t.relativeTemplatePath,Zee());_B(c,Oe.Tmpl);let u=Cee(c,e);if(c.contentSelectors!==null&&r.set("ngContentSelectors",c.contentSelectors),r.set("decls",Y(c.root.decls)),r.set("vars",Y(c.root.vars)),c.consts.length>0&&(c.constsInitializers.length>0?r.set("consts",xo([],[...c.constsInitializers,new gs(fn(c.consts))])):r.set("consts",fn(c.consts))),r.set("template",u),t.declarationListEmitMode!==3&&t.declarations.length>0)r.set("dependencies",dne(fn(t.declarations.map(h=>h.type)),t.declarationListEmitMode));else if(t.declarationListEmitMode===3){let h=[t.type.value];t.rawImports&&h.push(t.rawImports),r.set("dependencies",Xe(y.getComponentDepsFactory).callFn(h))}t.encapsulation===null&&(t.encapsulation=Kl.Emulated);let d=!!t.externalStyles?.length;if(t.styles&&t.styles.length){let m=(t.encapsulation==Kl.Emulated?bne(t.styles,ane,one):t.styles).reduce((g,v)=>(v.trim().length>0&&g.push(e.getConstLiteral(Y(v))),g),[]);m.length>0&&(d=!0,r.set("styles",fn(m)))}!d&&t.encapsulation===Kl.Emulated&&(t.encapsulation=Kl.None),t.encapsulation!==Kl.Emulated&&r.set("encapsulation",Y(t.encapsulation)),t.animations!==null&&r.set("data",Ms([{key:"animation",value:t.animations,quoted:!1}])),t.changeDetection!==null&&(typeof t.changeDetection=="number"&&t.changeDetection!==Rw.Default?r.set("changeDetection",Y(t.changeDetection)):typeof t.changeDetection=="object"&&r.set("changeDetection",t.changeDetection));let p=Xe(y.defineComponent).callFn([r.toLiteralMap()],void 0,!0),f=une(t);return{expression:p,type:f,statements:[]}}function une(t){let e=UB(t);return e.push(O_(t.template.ngContentSelectors)),e.push(is(Y(t.isStandalone))),e.push(qB(t)),t.isSignal&&e.push(is(Y(t.isSignal))),is(Xe(y.ComponentDeclaration,e))}function dne(t,e){switch(e){case 0:return t;case 1:return xo([],t);case 2:let n=t.prop("map").callFn([Xe(y.resolveForwardRef)]);return xo([],n);case 3:throw new Error("Unsupported with an array of pre-resolved dependencies")}}function pne(t){return is(Y(t))}function L_(t){let e=Object.keys(t).map(n=>{let r=Array.isArray(t[n])?t[n][0]:t[n];return{key:n,value:Y(r),quoted:!0}});return Ms(e)}function O_(t){return t.length>0?is(fn(t.map(e=>Y(e)))):sa}function UB(t){let e=t.selector!==null?t.selector.replace(/\n/g,""):null;return[tx(t.type.type,t.typeArgumentCount),e!==null?pne(e):sa,t.exportAs!==null?O_(t.exportAs):sa,is(fne(t)),is(L_(t.outputs)),O_(t.queries.map(n=>n.propertyName))]}function fne(t){return Ms(Object.keys(t.inputs).map(e=>{let n=t.inputs[e],r=[{key:"alias",value:Y(n.bindingPropertyName),quoted:!0},{key:"required",value:Y(n.required),quoted:!0}];return n.isSignal&&r.push({key:"isSignal",value:Y(n.isSignal),quoted:!0}),{key:e,value:Ms(r),quoted:!0}}))}function hne(t){let e=UB(t);return e.push(sa),e.push(is(Y(t.isStandalone))),e.push(qB(t)),t.isSignal&&e.push(is(Y(t.isSignal))),is(Xe(y.DirectiveDeclaration,e))}function mne(t,e,n,r,s,i,o){let a=n.createBoundHostProperties(t.properties,e),c=n.createDirectiveHostEventAsts(t.listeners,e);t.specialAttributes.styleAttr&&(t.attributes.style=Y(t.specialAttributes.styleAttr)),t.specialAttributes.classAttr&&(t.attributes.class=Y(t.specialAttributes.classAttr));let u=Iee({componentName:i,componentSelector:s,properties:a,events:c,attributes:t.attributes},n,r);_B(u,Oe.Host),o.set("hostAttrs",u.root.attributes);let d=u.root.vars;return d!==null&&d>0&&o.set("hostVars",Y(d)),Tee(u)}var gne=/^(?:\[([^\]]+)\])|(?:\(([^\)]+)\))$/;function vne(t){let e={},n={},r={},s={};for(let i of Object.keys(t)){let o=t[i],a=i.match(gne);if(a===null)switch(i){case"class":if(typeof o!="string")throw new Error("Class binding must be string");s.classAttr=o;break;case"style":if(typeof o!="string")throw new Error("Style binding must be string");s.styleAttr=o;break;default:typeof o=="string"?e[i]=Y(o):e[i]=o}else if(a[1]!=null){if(typeof o!="string")throw new Error("Property binding must be string");r[a[1]]=o}else if(a[2]!=null){if(typeof o!="string")throw new Error("Event binding must be string");n[a[2]]=o}}return{attributes:e,listeners:n,properties:r,specialAttributes:s}}function yne(t,e){let n=XE();return n.createDirectiveHostEventAsts(t.listeners,e),n.createBoundHostProperties(t.properties,e),n.errors}function bne(t,e,n){let r=new J1;return t.map(s=>r.shimCssText(s,e,n))}function qB(t){return t.hostDirectives?.length?is(fn(t.hostDirectives.map(e=>Ms([{key:"directive",value:hy(e.directive.type),quoted:!1},{key:"inputs",value:L_(e.inputs||{}),quoted:!1},{key:"outputs",value:L_(e.outputs||{}),quoted:!1}])))):sa}function wne(t){let e=[],n=!1;for(let r of t){if(!r.inputs&&!r.outputs)e.push(r.directive.type);else{let s=[{key:"directive",value:r.directive.type,quoted:!1}];if(r.inputs){let i=hO(r.inputs);i&&s.push({key:"inputs",value:i,quoted:!1})}if(r.outputs){let i=hO(r.outputs);i&&s.push({key:"outputs",value:i,quoted:!1})}e.push(Ms(s))}r.isForwardReference&&(n=!0)}return n?new nc([],[new gs(fn(e))]):fn(e)}function hO(t){let e=[];for(let n in t)t.hasOwnProperty(n)&&e.push(Y(n),Y(t[n]));return e.length>0?fn(e):null}var B_=class{constructor(e){l(this,"directiveMatcher");this.directiveMatcher=e}bind(e){if(!e.template)throw new Error("Empty bound targets are not supported");let n=new Map,r=[],s=new Map,i=new Map,o=new Map,a=new Map,c=new Map,u=new Map,d=new Set,p=new Set,f=[];if(e.template){let h=$_.apply(e.template);Ene(h,o),V_.apply(e.template,this.directiveMatcher,n,r,s,i),H_.applyWithScope(e.template,h,a,c,u,d,p,f)}return new j_(e,n,r,s,i,a,c,u,o,d,p,f)}},$_=class t{constructor(e,n){l(this,"parentScope");l(this,"rootNode");l(this,"namedEntities",new Map);l(this,"elementsInScope",new Set);l(this,"childScopes",new Map);l(this,"isDeferred");this.parentScope=e,this.rootNode=n,this.isDeferred=e!==null&&e.isDeferred?!0:n instanceof Du}static newRootScope(){return new t(null,null)}static apply(e){let n=t.newRootScope();return n.ingest(e),n}ingest(e){e instanceof Ei?(e.variables.forEach(n=>this.visitVariable(n)),e.children.forEach(n=>n.visit(this))):e instanceof mu?(e.expressionAlias!==null&&this.visitVariable(e.expressionAlias),e.children.forEach(n=>n.visit(this))):e instanceof If?(this.visitVariable(e.item),e.contextVariables.forEach(n=>this.visitVariable(n)),e.children.forEach(n=>n.visit(this))):e instanceof jv||e instanceof Uv||e instanceof Du||e instanceof Hv||e instanceof $v||e instanceof Vv||e instanceof kf?e.children.forEach(n=>n.visit(this)):e.forEach(n=>n.visit(this))}visitElement(e){e.references.forEach(n=>this.visitReference(n)),e.children.forEach(n=>n.visit(this)),this.elementsInScope.add(e)}visitTemplate(e){e.references.forEach(n=>this.visitReference(n)),this.ingestScopedNode(e)}visitVariable(e){this.maybeDeclare(e)}visitReference(e){this.maybeDeclare(e)}visitDeferredBlock(e){this.ingestScopedNode(e),e.placeholder?.visit(this),e.loading?.visit(this),e.error?.visit(this)}visitDeferredBlockPlaceholder(e){this.ingestScopedNode(e)}visitDeferredBlockError(e){this.ingestScopedNode(e)}visitDeferredBlockLoading(e){this.ingestScopedNode(e)}visitSwitchBlock(e){e.cases.forEach(n=>n.visit(this))}visitSwitchBlockCase(e){this.ingestScopedNode(e)}visitForLoopBlock(e){this.ingestScopedNode(e),e.empty?.visit(this)}visitForLoopBlockEmpty(e){this.ingestScopedNode(e)}visitIfBlock(e){e.branches.forEach(n=>n.visit(this))}visitIfBlockBranch(e){this.ingestScopedNode(e)}visitContent(e){this.ingestScopedNode(e)}visitLetDeclaration(e){this.maybeDeclare(e)}visitBoundAttribute(e){}visitBoundEvent(e){}visitBoundText(e){}visitText(e){}visitTextAttribute(e){}visitIcu(e){}visitDeferredTrigger(e){}visitUnknownBlock(e){}maybeDeclare(e){this.namedEntities.has(e.name)||this.namedEntities.set(e.name,e)}lookup(e){return this.namedEntities.has(e)?this.namedEntities.get(e):this.parentScope!==null?this.parentScope.lookup(e):null}getChildScope(e){let n=this.childScopes.get(e);if(n===void 0)throw new Error(`Assertion error: child scope for ${e} not found`);return n}ingestScopedNode(e){let n=new t(this,e);n.ingest(e),this.childScopes.set(e,n)}},V_=class t{constructor(e,n,r,s,i){l(this,"matcher");l(this,"directives");l(this,"eagerDirectives");l(this,"bindings");l(this,"references");l(this,"isInDeferBlock",!1);this.matcher=e,this.directives=n,this.eagerDirectives=r,this.bindings=s,this.references=i}static apply(e,n,r,s,i,o){new t(n,r,s,i,o).ingest(e)}ingest(e){e.forEach(n=>n.visit(this))}visitElement(e){this.visitElementOrTemplate(e)}visitTemplate(e){this.visitElementOrTemplate(e)}visitElementOrTemplate(e){let n=q7(e),r=[];this.matcher.match(n,(i,o)=>r.push(...o)),r.length>0&&(this.directives.set(e,r),this.isInDeferBlock||this.eagerDirectives.push(...r)),e.references.forEach(i=>{let o=null;if(i.value.trim()==="")o=r.find(a=>a.isComponent)||null;else if(o=r.find(a=>a.exportAs!==null&&a.exportAs.some(c=>c===i.value))||null,o===null)return;o!==null?this.references.set(i,{directive:o,node:e}):this.references.set(i,e)});let s=(i,o)=>{let a=r.find(u=>u[o].hasBindingPropertyName(i.name)),c=a!==void 0?a:e;this.bindings.set(i,c)};e.inputs.forEach(i=>s(i,"inputs")),e.attributes.forEach(i=>s(i,"inputs")),e instanceof Ei&&e.templateAttrs.forEach(i=>s(i,"inputs")),e.outputs.forEach(i=>s(i,"outputs")),e.children.forEach(i=>i.visit(this))}visitDeferredBlock(e){let n=this.isInDeferBlock;this.isInDeferBlock=!0,e.children.forEach(r=>r.visit(this)),this.isInDeferBlock=n,e.placeholder?.visit(this),e.loading?.visit(this),e.error?.visit(this)}visitDeferredBlockPlaceholder(e){e.children.forEach(n=>n.visit(this))}visitDeferredBlockError(e){e.children.forEach(n=>n.visit(this))}visitDeferredBlockLoading(e){e.children.forEach(n=>n.visit(this))}visitSwitchBlock(e){e.cases.forEach(n=>n.visit(this))}visitSwitchBlockCase(e){e.children.forEach(n=>n.visit(this))}visitForLoopBlock(e){e.item.visit(this),e.contextVariables.forEach(n=>n.visit(this)),e.children.forEach(n=>n.visit(this)),e.empty?.visit(this)}visitForLoopBlockEmpty(e){e.children.forEach(n=>n.visit(this))}visitIfBlock(e){e.branches.forEach(n=>n.visit(this))}visitIfBlockBranch(e){e.expressionAlias?.visit(this),e.children.forEach(n=>n.visit(this))}visitContent(e){e.children.forEach(n=>n.visit(this))}visitVariable(e){}visitReference(e){}visitTextAttribute(e){}visitBoundAttribute(e){}visitBoundEvent(e){}visitBoundAttributeOrEvent(e){}visitText(e){}visitBoundText(e){}visitIcu(e){}visitDeferredTrigger(e){}visitUnknownBlock(e){}visitLetDeclaration(e){}},H_=class t extends oE{constructor(n,r,s,i,o,a,c,u,d){super();l(this,"bindings");l(this,"symbols");l(this,"usedPipes");l(this,"eagerPipes");l(this,"deferBlocks");l(this,"nestingLevel");l(this,"scope");l(this,"rootNode");l(this,"level");l(this,"visitNode");this.bindings=n,this.symbols=r,this.usedPipes=s,this.eagerPipes=i,this.deferBlocks=o,this.nestingLevel=a,this.scope=c,this.rootNode=u,this.level=d,this.visitNode=p=>p.visit(this)}visit(n,r){n instanceof Qn?n.visit(this,r):n.visit(this)}static applyWithScope(n,r,s,i,o,a,c,u){let d=n instanceof Ei?n:null;new t(s,i,a,c,u,o,r,d,0).ingest(n)}ingest(n){if(n instanceof Ei)n.variables.forEach(this.visitNode),n.children.forEach(this.visitNode),this.nestingLevel.set(n,this.level);else if(n instanceof mu)n.expressionAlias!==null&&this.visitNode(n.expressionAlias),n.children.forEach(this.visitNode),this.nestingLevel.set(n,this.level);else if(n instanceof If)this.visitNode(n.item),n.contextVariables.forEach(r=>this.visitNode(r)),n.trackBy.visit(this),n.children.forEach(this.visitNode),this.nestingLevel.set(n,this.level);else if(n instanceof Du){if(this.scope.rootNode!==n)throw new Error(`Assertion error: resolved incorrect scope for deferred block ${n}`);this.deferBlocks.push([n,this.scope]),n.children.forEach(r=>r.visit(this)),this.nestingLevel.set(n,this.level)}else n instanceof jv||n instanceof Uv||n instanceof Hv||n instanceof $v||n instanceof Vv||n instanceof kf?(n.children.forEach(r=>r.visit(this)),this.nestingLevel.set(n,this.level)):n.forEach(this.visitNode)}visitElement(n){n.inputs.forEach(this.visitNode),n.outputs.forEach(this.visitNode),n.children.forEach(this.visitNode),n.references.forEach(this.visitNode)}visitTemplate(n){n.inputs.forEach(this.visitNode),n.outputs.forEach(this.visitNode),n.templateAttrs.forEach(this.visitNode),n.references.forEach(this.visitNode),this.ingestScopedNode(n)}visitVariable(n){this.rootNode!==null&&this.symbols.set(n,this.rootNode)}visitReference(n){this.rootNode!==null&&this.symbols.set(n,this.rootNode)}visitText(n){}visitTextAttribute(n){}visitUnknownBlock(n){}visitDeferredTrigger(){}visitIcu(n){Object.keys(n.vars).forEach(r=>n.vars[r].visit(this)),Object.keys(n.placeholders).forEach(r=>n.placeholders[r].visit(this))}visitBoundAttribute(n){n.value.visit(this)}visitBoundEvent(n){n.handler.visit(this)}visitDeferredBlock(n){this.ingestScopedNode(n),n.triggers.when?.value.visit(this),n.prefetchTriggers.when?.value.visit(this),n.hydrateTriggers.when?.value.visit(this),n.hydrateTriggers.never?.visit(this),n.placeholder&&this.visitNode(n.placeholder),n.loading&&this.visitNode(n.loading),n.error&&this.visitNode(n.error)}visitDeferredBlockPlaceholder(n){this.ingestScopedNode(n)}visitDeferredBlockError(n){this.ingestScopedNode(n)}visitDeferredBlockLoading(n){this.ingestScopedNode(n)}visitSwitchBlock(n){n.expression.visit(this),n.cases.forEach(this.visitNode)}visitSwitchBlockCase(n){n.expression?.visit(this),this.ingestScopedNode(n)}visitForLoopBlock(n){n.expression.visit(this),this.ingestScopedNode(n),n.empty?.visit(this)}visitForLoopBlockEmpty(n){this.ingestScopedNode(n)}visitIfBlock(n){n.branches.forEach(r=>r.visit(this))}visitIfBlockBranch(n){n.expression?.visit(this),this.ingestScopedNode(n)}visitContent(n){this.ingestScopedNode(n)}visitBoundText(n){n.value.visit(this)}visitLetDeclaration(n){n.value.visit(this),this.rootNode!==null&&this.symbols.set(n,this.rootNode)}visitPipe(n,r){return this.usedPipes.add(n.name),this.scope.isDeferred||this.eagerPipes.add(n.name),super.visitPipe(n,r)}visitPropertyRead(n,r){return this.maybeMap(n,n.name),super.visitPropertyRead(n,r)}visitSafePropertyRead(n,r){return this.maybeMap(n,n.name),super.visitSafePropertyRead(n,r)}visitPropertyWrite(n,r){return this.maybeMap(n,n.name),super.visitPropertyWrite(n,r)}ingestScopedNode(n){let r=this.scope.getChildScope(n);new t(this.bindings,this.symbols,this.usedPipes,this.eagerPipes,this.deferBlocks,this.nestingLevel,r,n,this.level+1).ingest(n)}maybeMap(n,r){if(!(n.receiver instanceof Yi)||n.receiver instanceof Cu)return;let s=this.scope.lookup(r);s!==null&&this.bindings.set(n,s)}},j_=class{constructor(e,n,r,s,i,o,a,c,u,d,p,f){l(this,"target");l(this,"directives");l(this,"eagerDirectives");l(this,"bindings");l(this,"references");l(this,"exprTargets");l(this,"symbols");l(this,"nestingLevel");l(this,"scopedNodeEntities");l(this,"usedPipes");l(this,"eagerPipes");l(this,"deferredBlocks");l(this,"deferredScopes");this.target=e,this.directives=n,this.eagerDirectives=r,this.bindings=s,this.references=i,this.exprTargets=o,this.symbols=a,this.nestingLevel=c,this.scopedNodeEntities=u,this.usedPipes=d,this.eagerPipes=p,this.deferredBlocks=f.map(h=>h[0]),this.deferredScopes=new Map(f)}getEntitiesInScope(e){return this.scopedNodeEntities.get(e)??new Set}getDirectivesOfNode(e){return this.directives.get(e)||null}getReferenceTarget(e){return this.references.get(e)||null}getConsumerOfBinding(e){return this.bindings.get(e)||null}getExpressionTarget(e){return this.exprTargets.get(e)||null}getDefinitionNodeOfSymbol(e){return this.symbols.get(e)||null}getNestingLevel(e){return this.nestingLevel.get(e)||0}getUsedDirectives(){let e=new Set;return this.directives.forEach(n=>n.forEach(r=>e.add(r))),Array.from(e.values())}getEagerlyUsedDirectives(){let e=new Set(this.eagerDirectives);return Array.from(e.values())}getUsedPipes(){return Array.from(this.usedPipes)}getEagerlyUsedPipes(){return Array.from(this.eagerPipes)}getDeferBlocks(){return this.deferredBlocks}getDeferredTriggerTarget(e,n){if(!(n instanceof uE)&&!(n instanceof dE)&&!(n instanceof cE))return null;let r=n.reference;if(r===null){let i=null;if(e.placeholder!==null){for(let o of e.placeholder.children)if(!(o instanceof nx)){if(i!==null)return null;o instanceof oa&&(i=o)}}return i}let s=this.findEntityInScope(e,r);if(s instanceof qv&&this.getDefinitionNodeOfSymbol(s)!==e){let i=this.getReferenceTarget(s);if(i!==null)return this.referenceTargetToElement(i)}if(e.placeholder!==null){let i=this.findEntityInScope(e.placeholder,r),o=i instanceof qv?this.getReferenceTarget(i):null;if(o!==null)return this.referenceTargetToElement(o)}return null}isDeferred(e){for(let n of this.deferredBlocks){if(!this.deferredScopes.has(n))continue;let r=[this.deferredScopes.get(n)];for(;r.length>0;){let s=r.pop();if(s.elementsInScope.has(e))return!0;r.push(...s.childScopes.values())}}return!1}findEntityInScope(e,n){let r=this.getEntitiesInScope(e);for(let s of r)if(s.name===n)return s;return null}referenceTargetToElement(e){return e instanceof oa?e:e instanceof Ei?null:this.referenceTargetToElement(e.node)}};function Ene(t,e){let n=new Map;function r(i){if(n.has(i.rootNode))return n.get(i.rootNode);let o=i.namedEntities,a;return i.parentScope!==null?a=new Map([...r(i.parentScope),...o]):a=new Map(o),n.set(i.rootNode,a),a}let s=[t];for(;s.length>0;){let i=s.pop();for(let o of i.childScopes.values())s.push(o);r(i)}for(let[i,o]of n)e.set(i,new Set(o.values()))}var U_=class{},q_=class{constructor(e=new X1){l(this,"jitEvaluator");l(this,"FactoryTarget",Jo);l(this,"ResourceLoader",U_);l(this,"elementSchemaRegistry",new Bf);this.jitEvaluator=e}compilePipe(e,n,r){let s={type:Rr(r.type),typeArgumentCount:0,pipeName:r.pipeName,pure:r.pure,isStandalone:r.isStandalone},i=hL(s);return this.jitExpression(i.expression,e,n,[])}compilePipeDeclaration(e,n,r){let s=Bne(r),i=hL(s);return this.jitExpression(i.expression,e,n,[])}compileInjectable(e,n,r){let{expression:s,statements:i}=iL({name:r.name,type:Rr(r.type),typeArgumentCount:r.typeArgumentCount,providedIn:wO(r.providedIn),useClass:nf(r,"useClass"),useFactory:bO(r,"useFactory"),useValue:nf(r,"useValue"),useExisting:nf(r,"useExisting"),deps:r.deps?.map(ZB)},!0);return this.jitExpression(s,e,n,i)}compileInjectableDeclaration(e,n,r){let{expression:s,statements:i}=iL({name:r.type.name,type:Rr(r.type),typeArgumentCount:0,providedIn:wO(r.providedIn),useClass:nf(r,"useClass"),useFactory:bO(r,"useFactory"),useValue:nf(r,"useValue"),useExisting:nf(r,"useExisting"),deps:r.deps?.map(EO)},!0);return this.jitExpression(s,e,n,i)}compileInjector(e,n,r){let s={type:Rr(r.type),providers:r.providers&&r.providers.length>0?new Ht(r.providers):null,imports:r.imports.map(o=>new Ht(o))},i=fL(s);return this.jitExpression(i.expression,e,n,[])}compileInjectorDeclaration(e,n,r){let s=$ne(r),i=fL(s);return this.jitExpression(i.expression,e,n,[])}compileNgModule(e,n,r){let s={kind:Ga.Global,type:Rr(r.type),bootstrap:r.bootstrap.map(Rr),declarations:r.declarations.map(Rr),publicDeclarationTypes:null,imports:r.imports.map(Rr),includeImportTypes:!0,exports:r.exports.map(Rr),selectorScopeMode:Kv.Inline,containsForwardDecls:!1,schemas:r.schemas?r.schemas.map(Rr):null,id:r.id?new Ht(r.id):null},i=hZ(s);return this.jitExpression(i.expression,e,n,[])}compileNgModuleDeclaration(e,n,r){let s=mZ(r);return this.jitExpression(s,e,n,[])}compileDirective(e,n,r){let s=vO(r);return this.compileDirectiveFromMeta(e,n,s)}compileDirectiveDeclaration(e,n,r){let s=this.createParseSourceSpan("Directive",r.type.name,n),i=zB(r,s);return this.compileDirectiveFromMeta(e,n,i)}compileDirectiveFromMeta(e,n,r){let s=new zw,i=XE(),o=lne(r,s,i);return this.jitExpression(o.expression,e,n,s.statements)}compileComponent(e,n,r){let{template:s,interpolation:i,defer:o}=GB(r.template,r.name,n,r.preserveWhitespaces,r.interpolation,void 0),a={...r,...vO(r),selector:r.selector||this.elementSchemaRegistry.getDefaultComponentElementName(),template:s,declarations:r.declarations.map(Tne),declarationListEmitMode:0,defer:o,styles:[...r.styles,...s.styles],encapsulation:r.encapsulation,interpolation:i,changeDetection:r.changeDetection??null,animations:r.animations!=null?new Ht(r.animations):null,viewProviders:r.viewProviders!=null?new Ht(r.viewProviders):null,relativeContextFilePath:"",i18nUseExternalIds:!0,relativeTemplatePath:null},c=`ng:///${r.name}.js`;return this.compileComponentFromMeta(e,c,a)}compileComponentDeclaration(e,n,r){let s=this.createParseSourceSpan("Component",r.type.name,n),i=Cne(r,s,n);return this.compileComponentFromMeta(e,n,i)}compileComponentFromMeta(e,n,r){let s=new zw,i=XE(r.interpolation),o=cne(r,s,i);return this.jitExpression(o.expression,e,n,s.statements)}compileFactory(e,n,r){let s=lu({name:r.name,type:Rr(r.type),typeArgumentCount:r.typeArgumentCount,deps:Ine(r.deps),target:r.target});return this.jitExpression(s.expression,e,n,s.statements)}compileFactoryDeclaration(e,n,r){let s=lu({name:r.type.name,type:Rr(r.type),typeArgumentCount:0,deps:Array.isArray(r.deps)?r.deps.map(EO):r.deps,target:r.target});return this.jitExpression(s.expression,e,n,s.statements)}createParseSourceSpan(e,n,r){return aZ(e,n,r)}jitExpression(e,n,r,s){let i=[...s,new ys("$def",e,void 0,Wr.Exported)];return this.jitEvaluator.evaluateStatements(r,i,new K1(n),!0).$def}};function mO(t){return{...t,isSignal:t.isSignal,predicate:WB(t.predicate),read:t.read?new Ht(t.read):null,static:t.static,emitDistinctChangesOnly:t.emitDistinctChangesOnly}}function gO(t){return{propertyName:t.propertyName,first:t.first??!1,predicate:WB(t.predicate),descendants:t.descendants??!1,read:t.read?new Ht(t.read):null,static:t.static??!1,emitDistinctChangesOnly:t.emitDistinctChangesOnly??!0,isSignal:!!t.isSignal}}function WB(t){return Array.isArray(t)?t:Y_(new Ht(t),1)}function vO(t){let e=One(t.inputs||[]),n=E1(t.outputs||[]),r=t.propMetadata,s={},i={};for(let a in r)r.hasOwnProperty(a)&&r[a].forEach(c=>{Nne(c)?s[a]={bindingPropertyName:c.alias||a,classPropertyName:a,required:c.required||!1,isSignal:!!c.isSignal,transformFunction:c.transform!=null?new Ht(c.transform):null}:Rne(c)&&(i[a]=c.alias||a)});let o=t.hostDirectives?.length?t.hostDirectives.map(a=>typeof a=="function"?{directive:Rr(a),inputs:null,outputs:null,isForwardReference:!1}:{directive:Rr(a.directive),isForwardReference:!1,inputs:a.inputs?E1(a.inputs):null,outputs:a.outputs?E1(a.outputs):null}):null;return{...t,typeArgumentCount:0,typeSourceSpan:t.typeSourceSpan,type:Rr(t.type),deps:null,host:{...Ane(t.propMetadata,t.typeSourceSpan,t.host)},inputs:{...e,...s},outputs:{...n,...i},queries:t.queries.map(mO),providers:t.providers!=null?new Ht(t.providers):null,viewQueries:t.viewQueries.map(mO),fullInheritance:!1,hostDirectives:o}}function zB(t,e){let n=t.hostDirectives?.length?t.hostDirectives.map(r=>({directive:Rr(r.directive),isForwardReference:!1,inputs:r.inputs?yO(r.inputs):null,outputs:r.outputs?yO(r.outputs):null})):null;return{name:t.type.name,type:Rr(t.type),typeSourceSpan:e,selector:t.selector??null,inputs:t.inputs?Fne(t.inputs):{},outputs:t.outputs??{},host:xne(t.host),queries:(t.queries??[]).map(gO),viewQueries:(t.viewQueries??[]).map(gO),providers:t.providers!==void 0?new Ht(t.providers):null,exportAs:t.exportAs??null,usesInheritance:t.usesInheritance??!1,lifecycle:{usesOnChanges:t.usesOnChanges??!1},deps:null,typeArgumentCount:0,fullInheritance:!1,isStandalone:t.isStandalone??IO(t.version),isSignal:t.isSignal??!1,hostDirectives:n}}function xne(t={}){return{attributes:Sne(t.attributes??{}),listeners:t.listeners??{},properties:t.properties??{},specialAttributes:{classAttr:t.classAttribute,styleAttr:t.styleAttribute}}}function yO(t){let e=null;for(let n=1;nw1(a,!0))),t.directives&&o.push(...t.directives.map(a=>w1(a))),t.pipes&&o.push(...Dne(t.pipes)));return{...zB(t,e),template:r,styles:t.styles??[],declarations:o,viewProviders:t.viewProviders!==void 0?new Ht(t.viewProviders):null,animations:t.animations!==void 0?new Ht(t.animations):null,defer:i,changeDetection:t.changeDetection??Rw.Default,encapsulation:t.encapsulation??Kl.Emulated,interpolation:s,declarationListEmitMode:2,relativeContextFilePath:"",i18nUseExternalIds:!0,relativeTemplatePath:null}}function Tne(t){return{...t,type:new Ht(t.type)}}function w1(t,e=null){return{kind:Jv.Directive,isComponent:e||t.kind==="component",selector:t.selector,type:new Ht(t.type),inputs:t.inputs??[],outputs:t.outputs??[],exportAs:t.exportAs??null}}function Dne(t){return t?Object.keys(t).map(e=>({kind:Jv.Pipe,name:e,type:new Ht(t[e])})):[]}function _ne(t){return{kind:Jv.Pipe,name:t.name,type:new Ht(t.type)}}function GB(t,e,n,r,s,i){let o=s?gE.fromArray(s):ea,a=sne(t,n,{preserveWhitespaces:r,interpolationConfig:o});if(a.errors!==null){let d=a.errors.map(p=>p.toString()).join(", ");throw new Error(`Errors during JIT compilation of template for ${e}: ${d}`)}let u=new B_(new Nw).bind({template:a.nodes});return{template:a,interpolation:o,defer:kne(u,i)}}function nf(t,e){if(t.hasOwnProperty(e))return Y_(new Ht(t[e]),0)}function bO(t,e){if(t.hasOwnProperty(e))return new Ht(t[e])}function wO(t){let e=typeof t=="function"?new Ht(t):new os(t??null);return Y_(e,0)}function Ine(t){return t==null?null:t.map(ZB)}function ZB(t){let e=t.attribute!=null,n=t.token===null?null:new Ht(t.token),r=e?new Ht(t.attribute):n;return YB(r,e,t.host,t.optional,t.self,t.skipSelf)}function EO(t){let e=t.attribute??!1,n=t.token===null?null:new Ht(t.token);return YB(n,e,t.host??!1,t.optional??!1,t.self??!1,t.skipSelf??!1)}function YB(t,e,n,r,s,i){let o=e?Y("unknown"):null;return{token:t,attributeNameType:o,host:n,optional:r,self:s,skipSelf:i}}function kne(t,e){let n=t.getDeferBlocks(),r=new Map;for(let s=0;si.msg).join(` +`));for(let i in t)t.hasOwnProperty(i)&&t[i].forEach(o=>{Mne(o)?r.properties[o.hostPropertyName||i]=D7("this",i):Pne(o)&&(r.listeners[o.eventName||i]=`${i}(${(o.args||[]).join(",")})`)});return r}function Mne(t){return t.ngMetadataName==="HostBinding"}function Pne(t){return t.ngMetadataName==="HostListener"}function Nne(t){return t.ngMetadataName==="Input"}function Rne(t){return t.ngMetadataName==="Output"}function Fne(t){return Object.keys(t).reduce((e,n)=>{let r=t[n];return typeof r=="string"||Array.isArray(r)?e[n]=Lne(r):e[n]={bindingPropertyName:r.publicName,classPropertyName:n,transformFunction:r.transformFunction!==null?new Ht(r.transformFunction):null,required:r.isRequired,isSignal:r.isSignal},e},{})}function Lne(t){return typeof t=="string"?{bindingPropertyName:t,classPropertyName:t,transformFunction:null,required:!1,isSignal:!1}:{bindingPropertyName:t[0],classPropertyName:t[1],transformFunction:t[2]?new Ht(t[2]):null,required:!1,isSignal:!1}}function One(t){return t.reduce((e,n)=>{if(typeof n=="string"){let[r,s]=XB(n);e[s]={bindingPropertyName:r,classPropertyName:s,required:!1,isSignal:!1,transformFunction:null}}else e[n.name]={bindingPropertyName:n.alias||n.name,classPropertyName:n.name,required:n.required||!1,isSignal:!1,transformFunction:n.transform!=null?new Ht(n.transform):null};return e},{})}function E1(t){return t.reduce((e,n)=>{let[r,s]=XB(n);return e[s]=r,e},{})}function XB(t){let[e,n]=t.split(":",2).map(r=>r.trim());return[n??e,e]}function Bne(t){return{name:t.type.name,type:Rr(t.type),typeArgumentCount:0,pipeName:t.name,deps:null,pure:t.pure??!0,isStandalone:t.isStandalone??IO(t.version)}}function $ne(t){return{name:t.type.name,type:Rr(t.type),providers:t.providers!==void 0&&t.providers.length>0?new Ht(t.providers):null,imports:t.imports!==void 0?t.imports.map(e=>new Ht(e)):[]}}function Vne(t){let e=t.ng||(t.ng={});e.\u0275compilerFacade=new q_}var C0e=new I1("19.2.25");var xO;(function(t){t[t.Extract=0]="Extract",t[t.Merge=1]="Merge"})(xO||(xO={}));var W_=class{constructor(){l(this,"closedByParent",!1);l(this,"implicitNamespacePrefix",null);l(this,"isVoid",!1);l(this,"ignoreFirstLf",!1);l(this,"canSelfClose",!0);l(this,"preventNamespaceInheritance",!1)}requireExtraParent(e){return!1}isClosedByChild(e){return!1}getContentType(){return yo.PARSABLE_DATA}},T0e=new W_;Vne(gv);var k={};hG(k,{ANIMATION_MODULE_TYPE:()=>yoe,APP_BOOTSTRAP_LISTENER:()=>lb,APP_ID:()=>Ii,APP_INITIALIZER:()=>IP,AfterRenderPhase:()=>Ec,ApplicationInitStatus:()=>Ph,ApplicationModule:()=>Lc,ApplicationRef:()=>yr,Attribute:()=>XC,COMPILER_OPTIONS:()=>p9,CSP_NONCE:()=>jh,CUSTOM_ELEMENTS_SCHEMA:()=>i3,ChangeDetectionStrategy:()=>yd,ChangeDetectorRef:()=>An,Compiler:()=>gC,CompilerFactory:()=>nA,Component:()=>Ws,ComponentFactory:()=>uP,ComponentFactoryResolver:()=>ib,ComponentRef:()=>S4,ContentChild:()=>_ue,ContentChildren:()=>Due,DEFAULT_CURRENCY_CODE:()=>OT,DebugElement:()=>kd,DebugEventListener:()=>oA,DebugNode:()=>A0,DefaultIterableDiffer:()=>CC,DestroyRef:()=>Es,Directive:()=>bt,ENVIRONMENT_INITIALIZER:()=>li,ElementRef:()=>pn,EmbeddedViewRef:()=>iA,EnvironmentInjector:()=>ci,ErrorHandler:()=>$s,EventEmitter:()=>cs,HOST_TAG_NAME:()=>J5,Host:()=>pi,HostAttributeToken:()=>qk,HostBinding:()=>ahe,HostListener:()=>lhe,INJECTOR:()=>DA,Inject:()=>Ke,InjectFlags:()=>Wt,Injectable:()=>St,InjectionToken:()=>$e,Injector:()=>Ln,Input:()=>Ge,IterableDiffers:()=>Fc,KeyValueDiffers:()=>xa,LOCALE_ID:()=>Ts,MissingTranslationStrategy:()=>sA,ModuleWithComponentFactories:()=>mC,NO_ERRORS_SCHEMA:()=>o3,NgModule:()=>co,NgModuleFactory:()=>J4,NgModuleRef:()=>ml,NgProbeToken:()=>V2,NgZone:()=>qt,Optional:()=>lt,Output:()=>lm,OutputEmitterRef:()=>d0,PACKAGE_ROOT_URL:()=>voe,PLATFORM_ID:()=>Ta,PLATFORM_INITIALIZER:()=>U0,PendingTasks:()=>c0,Pipe:()=>zs,PlatformRef:()=>Rh,Query:()=>Td,QueryList:()=>OS,REQUEST:()=>Ame,REQUEST_CONTEXT:()=>Pme,RESPONSE_INIT:()=>Mme,Renderer2:()=>hr,RendererFactory2:()=>Sd,RendererStyleFlags2:()=>so,ResourceStatus:()=>Zn,Sanitizer:()=>QS,SecurityContext:()=>In,Self:()=>Jn,SimpleChange:()=>AS,SkipSelf:()=>bl,TRANSLATIONS:()=>hhe,TRANSLATIONS_FORMAT:()=>mhe,TemplateRef:()=>$r,Testability:()=>Rc,TestabilityRegistry:()=>gl,TransferState:()=>ba,Type:()=>o5,VERSION:()=>che,Version:()=>Ea,ViewChild:()=>xl,ViewChildren:()=>Iue,ViewContainerRef:()=>mr,ViewEncapsulation:()=>Vs,ViewRef:()=>xC,afterNextRender:()=>yM,afterRender:()=>US,afterRenderEffect:()=>yA,asNativeElements:()=>Ahe,assertInInjectionContext:()=>us,assertNotInReactiveContext:()=>q0,assertPlatform:()=>y9,booleanAttribute:()=>Pi,computed:()=>Ao,contentChild:()=>q4,contentChildren:()=>W4,createComponent:()=>_me,createEnvironmentInjector:()=>wP,createNgModule:()=>wT,createNgModuleRef:()=>Oue,createPlatform:()=>g9,createPlatformFactory:()=>BT,defineInjectable:()=>mse,destroyPlatform:()=>Ehe,effect:()=>kC,enableProdMode:()=>Dhe,forwardRef:()=>vn,getDebugNode:()=>M0,getModuleFactory:()=>_he,getNgModuleById:()=>Ihe,getPlatform:()=>pb,importProvidersFrom:()=>e5,inject:()=>fe,input:()=>iM,isDevMode:()=>The,isSignal:()=>oM,isStandalone:()=>Sc,linkedSignal:()=>hA,makeEnvironmentProviders:()=>ma,makeStateKey:()=>boe,mergeApplicationConfig:()=>kme,model:()=>yP,numberAttribute:()=>cm,output:()=>oH,platformCore:()=>FN,provideAppInitializer:()=>Yde,provideEnvironmentInitializer:()=>Rse,provideExperimentalCheckNoChangesForDebug:()=>She,provideExperimentalZonelessChangeDetection:()=>phe,providePlatformInitializer:()=>xhe,provideZoneChangeDetection:()=>uhe,reflectComponentType:()=>Ime,resolveForwardRef:()=>xt,resource:()=>F9,runInInjectionContext:()=>AA,setTestabilityGetter:()=>Ej,signal:()=>ro,untracked:()=>sr,viewChild:()=>vP,viewChildren:()=>U4,\u0275AfterRenderManager:()=>Sh,\u0275CLIENT_RENDER_MODE_FLAG:()=>I9,\u0275CONTAINER_HEADER_OFFSET:()=>Wn,\u0275ChangeDetectionScheduler:()=>no,\u0275ChangeDetectionSchedulerImpl:()=>vl,\u0275ComponentFactory:()=>uP,\u0275Console:()=>Ai,\u0275DEFAULT_LOCALE_ID:()=>I0,\u0275DEFER_BLOCK_CONFIG:()=>fj,\u0275DEFER_BLOCK_DEPENDENCY_INTERCEPTOR:()=>pj,\u0275DEHYDRATED_BLOCK_REGISTRY:()=>Da,\u0275DeferBlockBehavior:()=>WS,\u0275DeferBlockState:()=>bn,\u0275ENABLE_ROOT_COMPONENT_BOOTSTRAP:()=>h9,\u0275EffectScheduler:()=>D0,\u0275HydrationStatus:()=>wd,\u0275IMAGE_CONFIG:()=>tT,\u0275IMAGE_CONFIG_DEFAULTS:()=>eT,\u0275INJECTOR_SCOPE:()=>B0,\u0275INPUT_SIGNAL_BRAND_WRITE_TYPE:()=>lse,\u0275INTERNAL_APPLICATION_ERROR_HANDLER:()=>iH,\u0275IS_HYDRATION_DOM_REUSE_ENABLED:()=>ad,\u0275IS_INCREMENTAL_HYDRATION_ENABLED:()=>vM,\u0275JSACTION_BLOCK_ELEMENT_MAP:()=>m0,\u0275JSACTION_EVENT_CONTRACT:()=>EM,\u0275LContext:()=>BS,\u0275LocaleDataIndex:()=>On,\u0275MicrotaskEffectScheduler:()=>IC,\u0275NG_COMP_DEF:()=>Md,\u0275NG_DIR_DEF:()=>$C,\u0275NG_ELEMENT_ID:()=>ph,\u0275NG_INJ_DEF:()=>bS,\u0275NG_MOD_DEF:()=>xA,\u0275NG_PIPE_DEF:()=>VC,\u0275NG_PROV_DEF:()=>s0,\u0275NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR:()=>uS,\u0275NO_CHANGE:()=>ct,\u0275NgModuleFactory:()=>Mh,\u0275NoopNgZone:()=>xh,\u0275PERFORMANCE_MARK_PREFIX:()=>P9,\u0275PROVIDED_NG_ZONE:()=>PN,\u0275PendingTasksInternal:()=>ya,\u0275R3Injector:()=>ga,\u0275ReflectionCapabilities:()=>DS,\u0275Render3ComponentFactory:()=>Nc,\u0275Render3ComponentRef:()=>JS,\u0275Render3NgModuleRef:()=>Ah,\u0275ResourceImpl:()=>AC,\u0275RuntimeError:()=>ne,\u0275SIGNAL:()=>rr,\u0275SSR_CONTENT_INTEGRITY_MARKER:()=>GH,\u0275TESTABILITY:()=>CT,\u0275TESTABILITY_GETTER:()=>Hd,\u0275TimerScheduler:()=>sC,\u0275TracingAction:()=>g0,\u0275TracingService:()=>Fo,\u0275USE_RUNTIME_DEPS_TRACKER_FOR_JIT:()=>qce,\u0275ViewRef:()=>_h,\u0275XSS_SECURITY_URL:()=>Ji,\u0275ZONELESS_ENABLED:()=>Od,\u0275_sanitizeHtml:()=>oT,\u0275_sanitizeUrl:()=>Wh,\u0275allowSanitizationBypassAndThrow:()=>lo,\u0275annotateForHydration:()=>Ghe,\u0275bypassSanitizationTrustHtml:()=>MM,\u0275bypassSanitizationTrustResourceUrl:()=>FM,\u0275bypassSanitizationTrustScript:()=>NM,\u0275bypassSanitizationTrustStyle:()=>PM,\u0275bypassSanitizationTrustUrl:()=>RM,\u0275clearResolutionOfComponentResourcesQueue:()=>X4,\u0275compileComponent:()=>n9,\u0275compileDirective:()=>MN,\u0275compileNgModule:()=>K6,\u0275compileNgModuleDefs:()=>J6,\u0275compileNgModuleFactory:()=>f9,\u0275compilePipe:()=>d9,\u0275convertToBitFlags:()=>F0,\u0275createInjector:()=>Uk,\u0275createOrReusePlatformInjector:()=>b9,\u0275defaultIterableDiffers:()=>Bhe,\u0275defaultKeyValueDiffers:()=>$he,\u0275depsTracker:()=>Cd,\u0275detectChangesInViewIfRequired:()=>Dj,\u0275devModeEqual:()=>CP,\u0275disableProfiling:()=>pme,\u0275enableProfiling:()=>dme,\u0275findLocaleData:()=>ps,\u0275flushModuleScopingQueueAsMuchAsPossible:()=>X6,\u0275formatRuntimeError:()=>gn,\u0275generateStandaloneInDeclarationsError:()=>e9,\u0275getAsyncClassMetadataFn:()=>cde,\u0275getClosestComponentName:()=>xme,\u0275getComponentDef:()=>Ut,\u0275getDebugNode:()=>M0,\u0275getDeferBlocks:()=>oC,\u0275getDirectives:()=>SH,\u0275getDocument:()=>No,\u0275getHostElement:()=>CH,\u0275getInjectableDef:()=>N0,\u0275getLContext:()=>Rs,\u0275getLocaleCurrencyCode:()=>AU,\u0275getLocalePluralCase:()=>AT,\u0275getOutputDestroyRef:()=>Zie,\u0275getSanitizationBypassType:()=>c3,\u0275getUnknownElementStrictMode:()=>uae,\u0275getUnknownPropertyStrictMode:()=>pae,\u0275global:()=>Yn,\u0275injectChangeDetectorRef:()=>x9,\u0275internalCreateApplication:()=>LN,\u0275internalProvideZoneChangeDetection:()=>LT,\u0275isBoundToModule:()=>Cj,\u0275isComponentDefPendingResolution:()=>Aue,\u0275isEnvironmentProviders:()=>R0,\u0275isInjectable:()=>gse,\u0275isNgModule:()=>Wu,\u0275isPromise:()=>jd,\u0275isSubscribable:()=>Kh,\u0275isViewDirty:()=>jle,\u0275markForRefresh:()=>Ule,\u0275microtaskEffect:()=>fme,\u0275noSideEffects:()=>Sa,\u0275patchComponentDefWithScope:()=>kN,\u0275performanceMarkFeature:()=>Ss,\u0275publishExternalGlobalUtil:()=>Zde,\u0275readHydrationInfo:()=>KH,\u0275registerLocaleData:()=>kU,\u0275renderDeferBlockState:()=>al,\u0275resetCompiledComponents:()=>Qfe,\u0275resetJitOptions:()=>Zfe,\u0275resolveComponentResources:()=>Z4,\u0275restoreComponentResolutionQueue:()=>Mue,\u0275setAllowDuplicateNgModuleIdsForTest:()=>Lue,\u0275setAlternateWeakRefImpl:()=>DI,\u0275setClassDebugInfo:()=>G6,\u0275setClassMetadata:()=>Us,\u0275setClassMetadataAsync:()=>gj,\u0275setCurrentInjector:()=>ua,\u0275setDocument:()=>uM,\u0275setInjectorProfilerContext:()=>as,\u0275setLocaleId:()=>PU,\u0275setUnknownElementStrictMode:()=>cae,\u0275setUnknownPropertyStrictMode:()=>dae,\u0275startMeasuring:()=>cme,\u0275stopMeasuring:()=>ume,\u0275store:()=>WC,\u0275stringify:()=>tn,\u0275transitiveScopesFor:()=>AN,\u0275triggerResourceLoading:()=>TT,\u0275truncateMiddle:()=>dse,\u0275unregisterLocaleData:()=>$pe,\u0275unwrapSafeValue:()=>ds,\u0275unwrapWritableSignal:()=>Qie,\u0275withDomHydration:()=>k9,\u0275withEventReplay:()=>ON,\u0275withI18nSupport:()=>A9,\u0275withIncrementalHydration:()=>M9,\u0275\u0275CopyDefinitionFeature:()=>oj,\u0275\u0275ExternalStylesFeature:()=>E6,\u0275\u0275FactoryTarget:()=>Te,\u0275\u0275HostDirectivesFeature:()=>aj,\u0275\u0275InheritDefinitionFeature:()=>xP,\u0275\u0275NgOnChangesFeature:()=>m5,\u0275\u0275ProvidersFeature:()=>w6,\u0275\u0275advance:()=>A3,\u0275\u0275attachSourceLocations:()=>y6,\u0275\u0275attribute:()=>kP,\u0275\u0275attributeInterpolate1:()=>AP,\u0275\u0275attributeInterpolate2:()=>MP,\u0275\u0275attributeInterpolate3:()=>PP,\u0275\u0275attributeInterpolate4:()=>NP,\u0275\u0275attributeInterpolate5:()=>RP,\u0275\u0275attributeInterpolate6:()=>FP,\u0275\u0275attributeInterpolate7:()=>LP,\u0275\u0275attributeInterpolate8:()=>OP,\u0275\u0275attributeInterpolateV:()=>BP,\u0275\u0275classMap:()=>iU,\u0275\u0275classMapInterpolate1:()=>dU,\u0275\u0275classMapInterpolate2:()=>pU,\u0275\u0275classMapInterpolate3:()=>fU,\u0275\u0275classMapInterpolate4:()=>hU,\u0275\u0275classMapInterpolate5:()=>mU,\u0275\u0275classMapInterpolate6:()=>gU,\u0275\u0275classMapInterpolate7:()=>vU,\u0275\u0275classMapInterpolate8:()=>yU,\u0275\u0275classMapInterpolateV:()=>bU,\u0275\u0275classProp:()=>HP,\u0275\u0275componentInstance:()=>wU,\u0275\u0275conditional:()=>EU,\u0275\u0275contentQuery:()=>YU,\u0275\u0275contentQuerySignal:()=>JU,\u0275\u0275declareLet:()=>IN,\u0275\u0275defer:()=>Mj,\u0275\u0275deferEnableTimerScheduling:()=>mj,\u0275\u0275deferHydrateNever:()=>Fj,\u0275\u0275deferHydrateOnHover:()=>Gj,\u0275\u0275deferHydrateOnIdle:()=>Bj,\u0275\u0275deferHydrateOnImmediate:()=>Hj,\u0275\u0275deferHydrateOnInteraction:()=>Xj,\u0275\u0275deferHydrateOnTimer:()=>qj,\u0275\u0275deferHydrateOnViewport:()=>Jj,\u0275\u0275deferHydrateWhen:()=>Rj,\u0275\u0275deferOnHover:()=>Wj,\u0275\u0275deferOnIdle:()=>Lj,\u0275\u0275deferOnImmediate:()=>$j,\u0275\u0275deferOnInteraction:()=>Zj,\u0275\u0275deferOnTimer:()=>jj,\u0275\u0275deferOnViewport:()=>Qj,\u0275\u0275deferPrefetchOnHover:()=>zj,\u0275\u0275deferPrefetchOnIdle:()=>Oj,\u0275\u0275deferPrefetchOnImmediate:()=>Vj,\u0275\u0275deferPrefetchOnInteraction:()=>Yj,\u0275\u0275deferPrefetchOnTimer:()=>Uj,\u0275\u0275deferPrefetchOnViewport:()=>Kj,\u0275\u0275deferPrefetchWhen:()=>Nj,\u0275\u0275deferWhen:()=>Pj,\u0275\u0275defineComponent:()=>ej,\u0275\u0275defineDirective:()=>tj,\u0275\u0275defineInjectable:()=>hn,\u0275\u0275defineInjector:()=>LC,\u0275\u0275defineNgModule:()=>EP,\u0275\u0275definePipe:()=>nj,\u0275\u0275directiveInject:()=>Vd,\u0275\u0275disableBindings:()=>x5,\u0275\u0275element:()=>UP,\u0275\u0275elementContainer:()=>qP,\u0275\u0275elementContainerEnd:()=>kT,\u0275\u0275elementContainerStart:()=>IT,\u0275\u0275elementEnd:()=>_T,\u0275\u0275elementStart:()=>DT,\u0275\u0275enableBindings:()=>E5,\u0275\u0275getComponentDepsFactory:()=>z6,\u0275\u0275getCurrentView:()=>IU,\u0275\u0275getInheritedFactory:()=>Y5,\u0275\u0275getReplaceMetadataURL:()=>Z6,\u0275\u0275hostProperty:()=>WP,\u0275\u0275i18n:()=>jU,\u0275\u0275i18nApply:()=>qU,\u0275\u0275i18nAttributes:()=>UU,\u0275\u0275i18nEnd:()=>ZP,\u0275\u0275i18nExp:()=>YP,\u0275\u0275i18nPostprocess:()=>WU,\u0275\u0275i18nStart:()=>GP,\u0275\u0275inject:()=>Zr,\u0275\u0275injectAttribute:()=>YC,\u0275\u0275invalidFactory:()=>C4,\u0275\u0275invalidFactoryDep:()=>TA,\u0275\u0275listener:()=>XP,\u0275\u0275loadQuery:()=>KU,\u0275\u0275namespaceHTML:()=>O5,\u0275\u0275namespaceMathML:()=>L5,\u0275\u0275namespaceSVG:()=>F5,\u0275\u0275nextContext:()=>zU,\u0275\u0275ngDeclareClassMetadata:()=>Ie,\u0275\u0275ngDeclareClassMetadataAsync:()=>Sme,\u0275\u0275ngDeclareComponent:()=>Cme,\u0275\u0275ngDeclareDirective:()=>Ct,\u0275\u0275ngDeclareFactory:()=>ke,\u0275\u0275ngDeclareInjectable:()=>an,\u0275\u0275ngDeclareInjector:()=>$o,\u0275\u0275ngDeclareNgModule:()=>Vo,\u0275\u0275ngDeclarePipe:()=>Gs,\u0275\u0275pipe:()=>$6,\u0275\u0275pipeBind1:()=>V6,\u0275\u0275pipeBind2:()=>H6,\u0275\u0275pipeBind3:()=>j6,\u0275\u0275pipeBind4:()=>U6,\u0275\u0275pipeBindV:()=>q6,\u0275\u0275projection:()=>ZU,\u0275\u0275projectionDef:()=>GU,\u0275\u0275property:()=>$P,\u0275\u0275propertyInterpolate:()=>JP,\u0275\u0275propertyInterpolate1:()=>RT,\u0275\u0275propertyInterpolate2:()=>eN,\u0275\u0275propertyInterpolate3:()=>tN,\u0275\u0275propertyInterpolate4:()=>nN,\u0275\u0275propertyInterpolate5:()=>rN,\u0275\u0275propertyInterpolate6:()=>sN,\u0275\u0275propertyInterpolate7:()=>iN,\u0275\u0275propertyInterpolate8:()=>oN,\u0275\u0275propertyInterpolateV:()=>aN,\u0275\u0275pureFunction0:()=>C6,\u0275\u0275pureFunction1:()=>T6,\u0275\u0275pureFunction2:()=>D6,\u0275\u0275pureFunction3:()=>_6,\u0275\u0275pureFunction4:()=>I6,\u0275\u0275pureFunction5:()=>k6,\u0275\u0275pureFunction6:()=>A6,\u0275\u0275pureFunction7:()=>M6,\u0275\u0275pureFunction8:()=>P6,\u0275\u0275pureFunctionV:()=>N6,\u0275\u0275queryAdvance:()=>t6,\u0275\u0275queryRefresh:()=>QU,\u0275\u0275readContextLet:()=>v6,\u0275\u0275reference:()=>n6,\u0275\u0275registerNgModuleType:()=>bP,\u0275\u0275repeater:()=>CU,\u0275\u0275repeaterCreate:()=>SU,\u0275\u0275repeaterTrackByIdentity:()=>jP,\u0275\u0275repeaterTrackByIndex:()=>xU,\u0275\u0275replaceMetadata:()=>Y6,\u0275\u0275resetView:()=>C5,\u0275\u0275resolveBody:()=>UM,\u0275\u0275resolveDocument:()=>T3,\u0275\u0275resolveWindow:()=>C3,\u0275\u0275restoreView:()=>S5,\u0275\u0275sanitizeHtml:()=>BM,\u0275\u0275sanitizeResourceUrl:()=>lT,\u0275\u0275sanitizeScript:()=>HM,\u0275\u0275sanitizeStyle:()=>$M,\u0275\u0275sanitizeUrl:()=>VM,\u0275\u0275sanitizeUrlOrResourceUrl:()=>S3,\u0275\u0275setComponentScope:()=>x6,\u0275\u0275setNgModuleScope:()=>S6,\u0275\u0275storeLet:()=>g6,\u0275\u0275styleMap:()=>Lo,\u0275\u0275styleMapInterpolate1:()=>r6,\u0275\u0275styleMapInterpolate2:()=>s6,\u0275\u0275styleMapInterpolate3:()=>i6,\u0275\u0275styleMapInterpolate4:()=>o6,\u0275\u0275styleMapInterpolate5:()=>a6,\u0275\u0275styleMapInterpolate6:()=>l6,\u0275\u0275styleMapInterpolate7:()=>c6,\u0275\u0275styleMapInterpolate8:()=>u6,\u0275\u0275styleMapInterpolateV:()=>d6,\u0275\u0275styleProp:()=>VP,\u0275\u0275stylePropInterpolate1:()=>lN,\u0275\u0275stylePropInterpolate2:()=>cN,\u0275\u0275stylePropInterpolate3:()=>uN,\u0275\u0275stylePropInterpolate4:()=>dN,\u0275\u0275stylePropInterpolate5:()=>pN,\u0275\u0275stylePropInterpolate6:()=>fN,\u0275\u0275stylePropInterpolate7:()=>hN,\u0275\u0275stylePropInterpolate8:()=>mN,\u0275\u0275stylePropInterpolateV:()=>gN,\u0275\u0275syntheticHostListener:()=>QP,\u0275\u0275syntheticHostProperty:()=>zP,\u0275\u0275template:()=>TP,\u0275\u0275templateRefExtractor:()=>W6,\u0275\u0275text:()=>p6,\u0275\u0275textInterpolate:()=>vN,\u0275\u0275textInterpolate1:()=>FT,\u0275\u0275textInterpolate2:()=>yN,\u0275\u0275textInterpolate3:()=>bN,\u0275\u0275textInterpolate4:()=>wN,\u0275\u0275textInterpolate5:()=>EN,\u0275\u0275textInterpolate6:()=>xN,\u0275\u0275textInterpolate7:()=>SN,\u0275\u0275textInterpolate8:()=>CN,\u0275\u0275textInterpolateV:()=>TN,\u0275\u0275trustConstantHtml:()=>E3,\u0275\u0275trustConstantResourceUrl:()=>x3,\u0275\u0275twoWayBindingSet:()=>h6,\u0275\u0275twoWayListener:()=>_N,\u0275\u0275twoWayProperty:()=>DN,\u0275\u0275validateAttribute:()=>jM,\u0275\u0275viewQuery:()=>XU,\u0275\u0275viewQuerySignal:()=>e6});function px(t,e){return Object.is(t,e)}var Lr=null,by=!1,yI=1,rr=Symbol("SIGNAL");function Et(t){let e=Lr;return Lr=t,e}function xy(){return Lr}function fx(){return by}var rl={version:0,lastCleanEpoch:0,dirty:!1,producerNode:void 0,producerLastReadVersion:void 0,producerIndexOfThis:void 0,nextProducerIndex:0,liveConsumerNode:void 0,liveConsumerIndexOfThis:void 0,consumerAllowSignalWrites:!1,consumerIsAlwaysLive:!1,kind:"unknown",producerMustRecompute:()=>!1,producerRecomputeValue:()=>{},consumerMarkedDirty:()=>{},consumerOnSignalRead:()=>{}};function dc(t){if(by)throw new Error(typeof ngDevMode<"u"&&ngDevMode?"Assertion error: signal read during notification phase":"");if(Lr===null)return;Lr.consumerOnSignalRead(t);let e=Lr.nextProducerIndex++;if(mx(Lr),et.nextProducerIndex;)t.producerNode.pop(),t.producerLastReadVersion.pop(),t.producerIndexOfThis.pop()}}function Fu(t){mx(t);for(let e=0;e=t.liveConsumerNode.length)throw new Error(`Assertion error: active consumer index ${e} is out of bounds of ${t.liveConsumerNode.length} consumers)`);if(t.liveConsumerNode.length===1&&e$(t))for(let r=0;r0}function mx(t){t.producerNode??(t.producerNode=[]),t.producerIndexOfThis??(t.producerIndexOfThis=[]),t.producerLastReadVersion??(t.producerLastReadVersion=[])}function JB(t){t.liveConsumerNode??(t.liveConsumerNode=[]),t.liveConsumerIndexOfThis??(t.liveConsumerIndexOfThis=[])}function e$(t){return t.producerNode!==void 0}function gx(t,e){let n=Object.create(Yne);n.computation=t,e!==void 0&&(n.equal=e);let r=()=>{if(zf(n),dc(n),n.value===uc)throw n.error;return n.value};return r[rr]=n,r}var Ru=Symbol("UNSET"),Wf=Symbol("COMPUTING"),uc=Symbol("ERRORED"),Yne={...rl,value:Ru,dirty:!0,error:null,equal:px,kind:"computed",producerMustRecompute(t){return t.value===Ru||t.value===Wf},producerRecomputeValue(t){if(t.value===Wf)throw new Error("Detected cycle in computations.");let e=t.value;t.value=Wf;let n=sl(t),r,s=!1;try{r=t.computation(),Et(null),s=e!==Ru&&e!==uc&&r!==uc&&t.equal(e,r)}catch(i){r=uc,t.error=i}finally{pc(t,n)}if(s){t.value=e;return}t.value=r,t.version++}};function Xne(){throw new Error}var t$=Xne;function n$(t){t$(t)}function xI(t){t$=t}var Qne=null;function SI(t,e){let n=Object.create(Sy);n.value=t,e!==void 0&&(n.equal=e);let r=()=>(dc(n),n.value);return r[rr]=n,r}function Ou(t,e){wI()||n$(t),t.equal(t.value,e)||(t.value=e,Kne(t))}function vx(t,e){wI()||n$(t),Ou(t,e(t.value))}var Sy={...rl,equal:px,value:void 0,kind:"signal"};function Kne(t){t.version++,QB(),bI(t),Qne?.()}function yx(t,e,n){let r=Object.create(Jne);r.source=t,r.computation=e,n!=null&&(r.equal=n);let i=()=>{if(zf(r),dc(r),r.value===uc)throw r.error;return r.value};return i[rr]=r,i}function CI(t,e){zf(t),Ou(t,e),wy(t)}function TI(t,e){zf(t),vx(t,e),wy(t)}var Jne={...rl,value:Ru,dirty:!0,error:null,equal:px,kind:"linkedSignal",producerMustRecompute(t){return t.value===Ru||t.value===Wf},producerRecomputeValue(t){if(t.value===Wf)throw new Error("Detected cycle in computations.");let e=t.value;t.value=Wf;let n=sl(t),r;try{let s=t.source(),i=e===Ru||e===uc?void 0:{source:t.sourceValue,value:e};r=t.computation(s,i),t.sourceValue=s}catch(s){r=uc,t.error=s}finally{pc(t,n)}if(e!==Ru&&r!==uc&&t.equal(e,r)){t.value=e;return}t.value=r,t.version++}};function DI(t){}function _I(t){let e=Et(null);try{return t()}finally{Et(e)}}var II;function Cy(){return II}function ua(t){let e=II;return II=t,e}var bx=Symbol("NotFound");function r$(t,e,n){let r=Object.create(ere);n&&(r.consumerAllowSignalWrites=!0),r.fn=t,r.schedule=e;let s=c=>{r.cleanupFn=c};function i(c){return c.fn===null&&c.schedule===null}function o(c){i(c)||(Lu(c),c.cleanupFn(),c.fn=null,c.schedule=null,c.cleanupFn=kI)}let a=()=>{if(r.fn===null)return;if(fx())throw new Error("Schedulers cannot synchronously execute watches while scheduling.");if(r.dirty=!1,r.hasRun&&!Fu(r))return;r.hasRun=!0;let c=sl(r);try{r.cleanupFn(),r.cleanupFn=kI,r.fn(s)}finally{pc(r,c)}};return r.ref={notify:()=>EI(r),run:a,cleanup:()=>r.cleanupFn(),destroy:()=>o(r),[rr]:r},r.ref}var kI=()=>{},ere={...rl,consumerIsAlwaysLive:!0,consumerAllowSignalWrites:!1,consumerMarkedDirty:t=>{t.schedule!==null&&t.schedule(t.ref)},hasRun:!1,cleanupFn:kI};var AI=function(t,e){return AI=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,r){n.__proto__=r}||function(n,r){for(var s in r)Object.prototype.hasOwnProperty.call(r,s)&&(n[s]=r[s])},AI(t,e)};function da(t,e){if(typeof e!="function"&&e!==null)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");AI(t,e);function n(){this.constructor=t}t.prototype=e===null?Object.create(e):(n.prototype=e.prototype,new n)}function s$(t,e,n,r){function s(i){return i instanceof n?i:new n(function(o){o(i)})}return new(n||(n=Promise))(function(i,o){function a(d){try{u(r.next(d))}catch(p){o(p)}}function c(d){try{u(r.throw(d))}catch(p){o(p)}}function u(d){d.done?i(d.value):s(d.value).then(a,c)}u((r=r.apply(t,e||[])).next())})}function wx(t,e){var n={label:0,sent:function(){if(i[0]&1)throw i[1];return i[1]},trys:[],ops:[]},r,s,i,o=Object.create((typeof Iterator=="function"?Iterator:Object).prototype);return o.next=a(0),o.throw=a(1),o.return=a(2),typeof Symbol=="function"&&(o[Symbol.iterator]=function(){return this}),o;function a(u){return function(d){return c([u,d])}}function c(u){if(r)throw new TypeError("Generator is already executing.");for(;o&&(o=0,u[0]&&(n=0)),n;)try{if(r=1,s&&(i=u[0]&2?s.return:u[0]?s.throw||((i=s.return)&&i.call(s),0):s.next)&&!(i=i.call(s,u[1])).done)return i;switch(s=0,i&&(u=[u[0]&2,i.value]),u[0]){case 0:case 1:i=u;break;case 4:return n.label++,{value:u[1],done:!1};case 5:n.label++,s=u[1],u=[0];continue;case 7:u=n.ops.pop(),n.trys.pop();continue;default:if(i=n.trys,!(i=i.length>0&&i[i.length-1])&&(u[0]===6||u[0]===2)){n=0;continue}if(u[0]===3&&(!i||u[1]>i[0]&&u[1]=t.length&&(t=void 0),{value:t&&t[r++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}function fc(t,e){var n=typeof Symbol=="function"&&t[Symbol.iterator];if(!n)return t;var r=n.call(t),s,i=[],o;try{for(;(e===void 0||e-- >0)&&!(s=r.next()).done;)i.push(s.value)}catch(a){o={error:a}}finally{try{s&&!s.done&&(n=r.return)&&n.call(r)}finally{if(o)throw o.error}}return i}function hc(t,e,n){if(n||arguments.length===2)for(var r=0,s=e.length,i;r1||c(h,g)})},m&&(s[h]=m(s[h])))}function c(h,m){try{u(r[h](m))}catch(g){f(i[0][3],g)}}function u(h){h.value instanceof Bu?Promise.resolve(h.value.v).then(d,p):f(i[0][2],h)}function d(h){c("next",h)}function p(h){c("throw",h)}function f(h,m){h(m),i.shift(),i.length&&c(i[0][0],i[0][1])}}function o$(t){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var e=t[Symbol.asyncIterator],n;return e?e.call(t):(t=typeof il=="function"?il(t):t[Symbol.iterator](),n={},r("next"),r("throw"),r("return"),n[Symbol.asyncIterator]=function(){return this},n);function r(i){n[i]=t[i]&&function(o){return new Promise(function(a,c){o=t[i](o),s(a,c,o.done,o.value)})}}function s(i,o,a,c){Promise.resolve(c).then(function(u){i({value:u,done:a})},o)}}function Dn(t){return typeof t=="function"}function Ex(t){var e=function(r){Error.call(r),r.stack=new Error().stack},n=t(e);return n.prototype=Object.create(Error.prototype),n.prototype.constructor=n,n}var xx=Ex(function(t){return function(n){t(this),this.message=n?n.length+` errors occurred during unsubscription: +`+n.map(function(r,s){return s+1+") "+r.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=n}});function Ty(t,e){if(t){var n=t.indexOf(e);0<=n&&t.splice(n,1)}}var Do=function(){function t(e){this.initialTeardown=e,this.closed=!1,this._parentage=null,this._finalizers=null}return t.prototype.unsubscribe=function(){var e,n,r,s,i;if(!this.closed){this.closed=!0;var o=this._parentage;if(o)if(this._parentage=null,Array.isArray(o))try{for(var a=il(o),c=a.next();!c.done;c=a.next()){var u=c.value;u.remove(this)}}catch(g){e={error:g}}finally{try{c&&!c.done&&(n=a.return)&&n.call(a)}finally{if(e)throw e.error}}else o.remove(this);var d=this.initialTeardown;if(Dn(d))try{d()}catch(g){i=g instanceof xx?g.errors:[g]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var f=il(p),h=f.next();!h.done;h=f.next()){var m=h.value;try{a$(m)}catch(g){i=i??[],g instanceof xx?i=hc(hc([],fc(i)),fc(g.errors)):i.push(g)}}}catch(g){r={error:g}}finally{try{h&&!h.done&&(s=f.return)&&s.call(f)}finally{if(r)throw r.error}}}if(i)throw new xx(i)}},t.prototype.add=function(e){var n;if(e&&e!==this)if(this.closed)a$(e);else{if(e instanceof t){if(e.closed||e._hasParent(this))return;e._addParent(this)}(this._finalizers=(n=this._finalizers)!==null&&n!==void 0?n:[]).push(e)}},t.prototype._hasParent=function(e){var n=this._parentage;return n===e||Array.isArray(n)&&n.includes(e)},t.prototype._addParent=function(e){var n=this._parentage;this._parentage=Array.isArray(n)?(n.push(e),n):n?[n,e]:e},t.prototype._removeParent=function(e){var n=this._parentage;n===e?this._parentage=null:Array.isArray(n)&&Ty(n,e)},t.prototype.remove=function(e){var n=this._finalizers;n&&Ty(n,e),e instanceof t&&e._removeParent(this)},t.EMPTY=function(){var e=new t;return e.closed=!0,e}(),t}();var MI=Do.EMPTY;function Sx(t){return t instanceof Do||t&&"closed"in t&&Dn(t.remove)&&Dn(t.add)&&Dn(t.unsubscribe)}function a$(t){Dn(t)?t():t.unsubscribe()}var _o={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var Gf={setTimeout:function(t,e){for(var n=[],r=2;r0},enumerable:!1,configurable:!0}),e.prototype._trySubscribe=function(n){return this._throwIfClosed(),t.prototype._trySubscribe.call(this,n)},e.prototype._subscribe=function(n){return this._throwIfClosed(),this._checkFinalizedStatuses(n),this._innerSubscribe(n)},e.prototype._innerSubscribe=function(n){var r=this,s=this,i=s.hasError,o=s.isStopped,a=s.observers;return i||o?MI:(this.currentObservers=null,a.push(n),new Do(function(){r.currentObservers=null,Ty(a,n)}))},e.prototype._checkFinalizedStatuses=function(n){var r=this,s=r.hasError,i=r.thrownError,o=r.isStopped;s?n.error(i):o&&n.complete()},e.prototype.asObservable=function(){var n=new Gr;return n.source=this,n},e.create=function(n,r){return new g$(n,r)},e}(Gr);var g$=function(t){da(e,t);function e(n,r){var s=t.call(this)||this;return s.destination=n,s.source=r,s}return e.prototype.next=function(n){var r,s;(s=(r=this.destination)===null||r===void 0?void 0:r.next)===null||s===void 0||s.call(r,n)},e.prototype.error=function(n){var r,s;(s=(r=this.destination)===null||r===void 0?void 0:r.error)===null||s===void 0||s.call(r,n)},e.prototype.complete=function(){var n,r;(r=(n=this.destination)===null||n===void 0?void 0:n.complete)===null||r===void 0||r.call(n)},e.prototype._subscribe=function(n){var r,s;return(s=(r=this.source)===null||r===void 0?void 0:r.subscribe(n))!==null&&s!==void 0?s:MI},e}(si);var LI=function(t){da(e,t);function e(n){var r=t.call(this)||this;return r._value=n,r}return Object.defineProperty(e.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),e.prototype._subscribe=function(n){var r=t.prototype._subscribe.call(this,n);return!r.closed&&n.next(this._value),r},e.prototype.getValue=function(){var n=this,r=n.hasError,s=n.thrownError,i=n._value;if(r)throw s;return this._throwIfClosed(),i},e.prototype.next=function(n){t.prototype.next.call(this,this._value=n)},e}(si);function cre(t){return t[t.length-1]}function v$(t){return Dn(cre(t))?t.pop():void 0}var _x=function(t){return t&&typeof t.length=="number"&&typeof t!="function"};function Ix(t){return Dn(t?.then)}function kx(t){return Dn(t[Yf])}function Ax(t){return Symbol.asyncIterator&&Dn(t?.[Symbol.asyncIterator])}function Mx(t){return new TypeError("You provided "+(t!==null&&typeof t=="object"?"an invalid object":"'"+t+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function ure(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Px=ure();function Nx(t){return Dn(t?.[Px])}function Rx(t){return i$(this,arguments,function(){var n,r,s,i;return wx(this,function(o){switch(o.label){case 0:n=t.getReader(),o.label=1;case 1:o.trys.push([1,,9,10]),o.label=2;case 2:return[4,Bu(n.read())];case 3:return r=o.sent(),s=r.value,i=r.done,i?[4,Bu(void 0)]:[3,5];case 4:return[2,o.sent()];case 5:return[4,Bu(s)];case 6:return[4,o.sent()];case 7:return o.sent(),[3,2];case 8:return[3,10];case 9:return n.releaseLock(),[7];case 10:return[2]}})})}function Fx(t){return Dn(t?.getReader)}function mc(t){if(t instanceof Gr)return t;if(t!=null){if(kx(t))return dre(t);if(_x(t))return pre(t);if(Ix(t))return fre(t);if(Ax(t))return y$(t);if(Nx(t))return hre(t);if(Fx(t))return mre(t)}throw Mx(t)}function dre(t){return new Gr(function(e){var n=t[Yf]();if(Dn(n.subscribe))return n.subscribe(e);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function pre(t){return new Gr(function(e){for(var n=0;nP$.indexOf(t)>=0,kre=Ire.concat(P$),N$=t=>kre.indexOf(t)>=0;function Are(t){return t===ut.MOUSEENTER?ut.MOUSEOVER:t===ut.MOUSELEAVE?ut.MOUSEOUT:t===ut.POINTERENTER?ut.POINTEROVER:t===ut.POINTERLEAVE?ut.POINTEROUT:t}function Mre(t,e,n,r){let s=!1;zx(e)&&(s=!0);let i=typeof r=="boolean"?{capture:s,passive:r}:s;return t.addEventListener(e,n,i),{eventType:e,handler:n,capture:s,passive:r}}function Pre(t,e){if(t.removeEventListener){let n=typeof e.passive=="boolean"?{capture:e.capture}:e.capture;t.removeEventListener(e.eventType,e.handler,n)}else t.detachEvent&&t.detachEvent(`on${e.eventType}`,e.handler)}function Nre(t){t.preventDefault?t.preventDefault():t.returnValue=!1}var k$=typeof navigator<"u"&&/Macintosh/.test(navigator.userAgent);function Rre(t){return t.which===2||t.which==null&&t.button===4}function Fre(t){return k$&&t.metaKey||!k$&&t.ctrlKey||Rre(t)||t.shiftKey}function Lre(t,e,n){let r=t.relatedTarget;return(t.type===ut.MOUSEOVER&&e===ut.MOUSEENTER||t.type===ut.MOUSEOUT&&e===ut.MOUSELEAVE||t.type===ut.POINTEROVER&&e===ut.POINTERENTER||t.type===ut.POINTEROUT&&e===ut.POINTERLEAVE)&&(!r||r!==n&&!n.contains(r))}function Ore(t,e){let n={};for(let r in t){if(r==="srcElement"||r==="target")continue;let s=r,i=t[s];typeof i!="function"&&(n[s]=i)}return t.type===ut.MOUSEOVER?n.type=ut.MOUSEENTER:t.type===ut.MOUSEOUT?n.type=ut.MOUSELEAVE:t.type===ut.POINTEROVER?n.type=ut.POINTERENTER:n.type=ut.POINTERLEAVE,n.target=n.srcElement=e,n.bubbles=!1,n._originalEvent=t,n}var Bre=typeof navigator<"u"&&/iPhone|iPad|iPod/.test(navigator.userAgent),jx=class{constructor(e){l(this,"element");l(this,"handlerInfos",[]);this.element=e}addEventListener(e,n,r){Bre&&(this.element.style.cursor="pointer"),this.handlerInfos.push(Mre(this.element,e,n(this.element),r))}cleanUp(){for(let e=0;e{this.eventReplayScheduled=!1,this.eventReplayer(this.replayEventInfoWrappers)}))}};function Zre(t,e){return t.tagName==="A"&&(e.getEventType()===ut.CLICK||e.getEventType()===ut.CLICKMOD)}var U$=Symbol.for("propagationStopped"),zI={REPLAY:101},Yre=" Because event replay occurs after browser dispatch, `preventDefault` would have no effect. You can check whether an event is being replayed by accessing the event phase: `event.eventPhase === EventPhase.REPLAY`.",Xre="`preventDefault` called during event replay.",Qre=" Because event replay occurs after browser dispatch, `composedPath()` will be empty. Iterate parent nodes from `event.target` or `event.currentTarget` if you need to check elements in the event path.",Kre="`composedPath` called during event replay.",Ux=class{constructor(e,n=!0){l(this,"dispatchDelegate");l(this,"clickModSupport");l(this,"actionResolver");l(this,"dispatcher");this.dispatchDelegate=e,this.clickModSupport=n,this.actionResolver=new HI({clickModSupport:n}),this.dispatcher=new UI(r=>{this.dispatchToDelegate(r)},{actionResolver:this.actionResolver})}dispatch(e){this.dispatcher.dispatch(e)}dispatchToDelegate(e){for(e.getIsReplay()&&tse(e),Jre(e);e.getAction();){if(nse(e),zx(e.getEventType())&&e.getAction().element!==e.getTargetElement()||(this.dispatchDelegate(e.getEvent(),e.getAction().name),ese(e)))return;this.actionResolver.resolveParentAction(e.eventInfo)}}};function Jre(t){let e=t.getEvent(),n=t.getEvent().stopPropagation.bind(e),r=()=>{e[U$]=!0,n()};Hu(e,"stopPropagation",r),Hu(e,"stopImmediatePropagation",r)}function ese(t){return!!t.getEvent()[U$]}function tse(t){let e=t.getEvent(),n=t.getTargetElement(),r=e.preventDefault.bind(e);Hu(e,"target",n),Hu(e,"eventPhase",zI.REPLAY),Hu(e,"preventDefault",()=>{throw r(),new Error(Xre+(ngDevMode?Yre:""))}),Hu(e,"composedPath",()=>{throw new Error(Kre+(ngDevMode?Qre:""))})}function nse(t){let e=t.getEvent(),n=t.getAction()?.element;n&&Hu(e,"currentTarget",n,{configurable:!0})}function Hu(t,e,n,{configurable:r=!1}={}){Object.defineProperty(t,e,{value:n,configurable:r})}function q$(t,e){t.ecrd(n=>{e.dispatch(n)},jI.I_AM_THE_JSACTION_FRAMEWORK)}function rse(t){return t?.q??[]}function sse(t){t&&(A$(t.c,t.et,t.h),A$(t.c,t.etc,t.h,!0))}function A$(t,e,n,r){for(let s=0;s=0)return;let s=(o,a,c)=>{this.handleEvent(o,a,c)};this.eventHandlers[e]=s;let i=Are(n||e);if(i!==e){let o=this.browserEventTypeToExtraEventTypes[i]||[];o.push(e),this.browserEventTypeToExtraEventTypes[i]=o}this.containerManager.addEventListener(i,o=>a=>{s(e,a,o)},r)}replayEarlyEvents(e=window._ejsa){e&&(this.replayEarlyEventInfos(e.q),sse(e),delete window._ejsa)}replayEarlyEventInfos(e){for(let n=0;n`[Input Signal: ${r()}]`,n.debugName=e?.debugName),r}function Sa(t){return{toString:t}.toString()}var nh="__annotations__",rh="__parameters__",sh="__prop__metadata__";function P0(t,e,n,r,s){return Sa(()=>{let i=bA(e);function o(...a){if(this instanceof o)return i.call(this,...a),this;let c=new o(...a);return function(d){return s&&s(d,...a),(d.hasOwnProperty(nh)?d[nh]:Object.defineProperty(d,nh,{value:[]})[nh]).push(c),d}}return n&&(o.prototype=Object.create(n.prototype)),o.prototype.ngMetadataName=t,o.annotationCls=o,o})}function bA(t){return function(...n){if(t){let r=t(...n);for(let s in r)this[s]=r[s]}}}function Fh(t,e,n){return Sa(()=>{let r=bA(e);function s(...i){if(this instanceof s)return r.apply(this,i),this;let o=new s(...i);return a.annotation=o,a;function a(c,u,d){let p=c.hasOwnProperty(rh)?c[rh]:Object.defineProperty(c,rh,{value:[]})[rh];for(;p.length<=d;)p.push(null);return(p[d]=p[d]||[]).push(o),c}}return s.prototype.ngMetadataName=t,s.annotationCls=s,s})}function Oc(t,e,n,r){return Sa(()=>{let s=bA(e);function i(...o){if(this instanceof i)return s.apply(this,o),this;let a=new i(...o);function c(u,d){if(u===void 0)throw new Error("Standard Angular field decorators are not supported in JIT mode.");let p=u.constructor,f=p.hasOwnProperty(sh)?p[sh]:Object.defineProperty(p,sh,{value:{}})[sh];f[d]=f.hasOwnProperty(d)&&f[d]||[],f[d].unshift(a)}return c}return n&&(i.prototype=Object.create(n.prototype)),i.prototype.ngMetadataName=t,i.annotationCls=i,i})}var Yn=globalThis;function cse(){let t=typeof location<"u"?location.toString():"",e={namedConstructors:t.indexOf("ngDevMode=namedConstructors")!=-1,firstCreatePass:0,tNode:0,tView:0,rendererCreateTextNode:0,rendererSetText:0,rendererCreateElement:0,rendererAddEventListener:0,rendererSetAttribute:0,rendererRemoveAttribute:0,rendererSetProperty:0,rendererSetClassName:0,rendererAddClass:0,rendererRemoveClass:0,rendererSetStyle:0,rendererRemoveStyle:0,rendererDestroy:0,rendererDestroyNode:0,rendererMoveNode:0,rendererRemoveNode:0,rendererAppendChild:0,rendererInsertBefore:0,rendererCreateComment:0,hydratedNodes:0,hydratedComponents:0,dehydratedViewsRemoved:0,dehydratedViewsCleanupRuns:0,componentsSkippedHydration:0,deferBlocksWithIncrementalHydration:0};return t.indexOf("ngDevMode=false")===-1?(typeof Yn.ngDevMode!="object"&&(Yn.ngDevMode={}),Object.assign(Yn.ngDevMode,e)):Yn.ngDevMode=!1,e}function wA(){return typeof ngDevMode>"u"||ngDevMode?((typeof ngDevMode!="object"||Object.keys(ngDevMode).length===0)&&cse(),typeof ngDevMode<"u"&&!!ngDevMode):!1}function Fn(t){for(let e in t)if(t[e]===Fn)return e;throw Error("Could not find renamed property on target object.")}function use(t,e){for(let n in e)e.hasOwnProperty(n)&&!t.hasOwnProperty(n)&&(t[n]=e[n])}function tn(t){if(typeof t=="string")return t;if(Array.isArray(t))return`[${t.map(tn).join(", ")}]`;if(t==null)return""+t;let e=t.overriddenName||t.name;if(e)return`${e}`;let n=t.toString();if(n==null)return""+n;let r=n.indexOf(` +`);return r>=0?n.slice(0,r):n}function Dk(t,e){return t?e?`${t} ${e}`:t:e||""}function dse(t,e=100){if(!t||e<1||t.length<=e)return t;if(e==1)return t.substring(0,1)+"...";let n=Math.round(e/2);return t.substring(0,n)+"..."+t.substring(t.length-n)}var pse=Fn({__forward_ref__:Fn});function vn(t){return t.__forward_ref__=vn,t.toString=function(){return tn(this())},t}function xt(t){return FC(t)?t():t}function FC(t){return typeof t=="function"&&t.hasOwnProperty(pse)&&t.__forward_ref__===vn}function _n(t,e){typeof t!="number"&&tt(e,typeof t,"number","===")}function r0(t,e,n){_n(t,"Expected a number"),GV(t,n,"Expected number to be less than or equal to"),yl(t,e,"Expected number to be greater than or equal to")}function Lh(t,e){typeof t!="string"&&tt(e,t===null?"null":typeof t,"string","===")}function WV(t,e){typeof t!="function"&&tt(e,t===null?"null":typeof t,"function","===")}function rt(t,e,n){t!=e&&tt(n,t,e,"==")}function di(t,e,n){t==e&&tt(n,t,e,"!=")}function zV(t,e,n){t!==e&&tt(n,t,e,"===")}function Oh(t,e,n){t===e&&tt(n,t,e,"!==")}function kc(t,e,n){te||tt(n,t,e,">")}function yl(t,e,n){t>=e||tt(n,t,e,">=")}function Fe(t,e){t==null&&tt(e,t,null,"!=")}function tt(t,e,n,r){throw new Error(`ASSERTION ERROR: ${t}`+(r==null?"":` [Expected=> ${n} ${r} ${e} <=Actual]`))}function xc(t){t instanceof Node||tt(`The provided value must be an instance of a DOM Node but got ${tn(t)}`)}function fse(t){t instanceof Element||tt(`The provided value must be an element but got ${tn(t)}`)}function gr(t,e){Fe(t,"Array must be defined.");let n=t.length;(e<0||e>=n)&&tt(`Index expected to be less than ${n} but got ${e}`)}function hse(t,...e){if(e.indexOf(t)!==-1)return!0;tt(`Expected value to be one of ${JSON.stringify(e)} but was ${JSON.stringify(t)}.`)}function EA(t){xy()!==null&&tt(`${t}() should never be called in a reactive context.`)}function hn(t){return{token:t.token,providedIn:t.providedIn||null,factory:t.factory,value:void 0}}var mse=hn;function LC(t){return{providers:t.providers||[],imports:t.imports||[]}}function N0(t){return z$(t,s0)||z$(t,ZV)}function gse(t){return N0(t)!==null}function z$(t,e){return t.hasOwnProperty(e)?t[e]:null}function vse(t){let e=t&&(t[s0]||t[ZV]);return e?(ngDevMode&&console.warn(`DEPRECATED: DI is instantiating a token "${t.name}" that inherits its @Injectable decorator but does not provide one itself. +This will become an error in a future version of Angular. Please add @Injectable() to the "${t.name}" class.`),e):null}function yS(t){return t&&(t.hasOwnProperty(bS)||t.hasOwnProperty(yse))?t[bS]:null}var s0=Fn({\u0275prov:Fn}),bS=Fn({\u0275inj:Fn}),ZV=Fn({ngInjectableDef:Fn}),yse=Fn({ngInjectorDef:Fn}),$e=class{constructor(e,n){l(this,"_desc");l(this,"ngMetadataName","InjectionToken");l(this,"\u0275prov");this._desc=e,this.\u0275prov=void 0,typeof n=="number"?((typeof ngDevMode>"u"||ngDevMode)&&kc(n,0,"Only negative numbers are supported here"),this.__NG_ELEMENT_ID__=n):n!==void 0&&(this.\u0275prov=hn({token:this,providedIn:n.providedIn||"root",factory:n.factory}))}get multi(){return this}toString(){return`InjectionToken ${this._desc}`}},_k;function OC(){return!ngDevMode&&tt("getInjectorProfilerContext should never be called in production mode"),_k}function as(t){!ngDevMode&&tt("setInjectorProfilerContext should never be called in production mode");let e=_k;return _k=t,e}var Ik=null,bse=t=>{!ngDevMode&&tt("setInjectorProfiler should never be called in production mode"),Ik=t};function BC(t){!ngDevMode&&tt("Injector profiler should never be called in production mode"),Ik?.(t)}function kk(t,e=!1){!ngDevMode&&tt("Injector profiler should never be called in production mode");let n;typeof t=="function"||t instanceof $e?n=t:n=xt(t.provide);let r=t;t instanceof $e&&(r=t.\u0275prov||t),BC({type:2,context:OC(),providerRecord:{token:n,provider:r,isViewProvider:e}})}function wS(t){!ngDevMode&&tt("Injector profiler should never be called in production mode"),BC({type:1,context:OC(),instance:{value:t}})}function YV(t,e,n){!ngDevMode&&tt("Injector profiler should never be called in production mode"),BC({type:0,context:OC(),service:{token:t,value:e,flags:n}})}function wse(t){!ngDevMode&&tt("Injector profiler should never be called in production mode"),BC({type:3,context:OC(),effect:t})}function Fy(t,e,n){!ngDevMode&&tt("runInInjectorProfilerContext should never be called in production mode");let r=as({injector:t,token:e});try{n()}finally{as(r)}}function R0(t){return t&&!!t.\u0275providers}var Md=Fn({\u0275cmp:Fn}),$C=Fn({\u0275dir:Fn}),VC=Fn({\u0275pipe:Fn}),xA=Fn({\u0275mod:Fn}),ll=Fn({\u0275fac:Fn}),ph=Fn({__NG_ELEMENT_ID__:Fn}),G$=Fn({__NG_ENV_ID__:Fn});function Mt(t){return typeof t=="string"?t:t==null?"":String(t)}function Xt(t){return typeof t=="function"?t.name||t.toString():typeof t=="object"&&t!=null&&typeof t.type=="function"?t.type.name||t.type.toString():Mt(t)}function Ese(t){let e=t[Md]||null;return e!==null&&e.debugInfo?xse(e.debugInfo):Xt(t)}function xse(t){return!t.filePath||!t.lineNumber?t.className:`${t.className} (at ${t.filePath}:${t.lineNumber})`}function SA(t,e){throw new ne(-200,ngDevMode?`Circular dependency in DI detected for ${t}${e?`. Dependency path: ${e.join(" > ")} > ${t}`:""}`:t)}function Z$(){throw new Error("Cannot mix multi providers and regular providers")}function Ak(t,e,n){if(t&&e){let r=e.map(s=>s==n?"?"+n+"?":"...");throw new Error(`Invalid provider for the NgModule '${tn(t)}' - only instances of Provider and Type are allowed, got: [${r.join(", ")}]`)}else throw R0(n)?n.\u0275fromNgModule?new ne(207,"Invalid providers from 'importProvidersFrom' present in a non-environment injector. 'importProvidersFrom' can't be used for component providers."):new ne(207,"Invalid providers present in a non-environment injector. 'EnvironmentProviders' can't be used for component providers."):new Error("Invalid provider")}function CA(t,e){let n=ngDevMode&&`No provider for ${Xt(t)} found${e?` in ${e}`:""}`;throw new ne(-201,n)}var Wt;(function(t){t[t.Default=0]="Default",t[t.Host=1]="Host",t[t.Self=2]="Self",t[t.SkipSelf=4]="SkipSelf",t[t.Optional=8]="Optional"})(Wt||(Wt={}));var ES;function XV(){return ES}function ii(t){let e=ES;return ES=t,e}function QV(t,e,n){let r=N0(t);if(r&&r.providedIn=="root")return r.value===void 0?r.value=r.factory():r.value;if(n&Wt.Optional)return null;if(e!==void 0)return e;CA(t,"Injector")}function Sse(t){ngDevMode&&di(ES,t,"Calling \u0275\u0275inject would cause infinite recursion")}var Cse={},cd=Cse,Mk="__NG_DI_FLAG__",xS=class{constructor(e){l(this,"injector");this.injector=e}retrieve(e,n){let r=n;return this.injector.get(e,r.optional?bx:cd,r)}},SS="ngTempTokenPath",Tse="ngTokenPath",Dse=/\n/gm,_se="\u0275",Y$="__source";function Ise(t,e=Wt.Default){if(Cy()===void 0)throw new ne(-203,ngDevMode&&`The \`${tn(t)}\` token injection failed. \`inject()\` function must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with \`runInInjectionContext\`.`);if(Cy()===null)return QV(t,void 0,e);{let n=Cy(),r;n instanceof xS?r=n.injector:r=n;let s=r.get(t,e&Wt.Optional?null:void 0,e);return ngDevMode&&YV(t,s,e),s}}function Zr(t,e=Wt.Default){return(XV()||Ise)(xt(t),e)}function TA(t){throw new ne(202,ngDevMode&&`This constructor is not compatible with Angular Dependency Injection because its dependency at index ${t} of the parameter list is invalid. +This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator. + +Please check that 1) the type for the parameter at index ${t} is correct and 2) the correct Angular decorators are defined for this class and its ancestors.`)}function fe(t,e=Wt.Default){return Zr(t,F0(e))}function F0(t){return typeof t>"u"||typeof t=="number"?t:0|(t.optional&&8)|(t.host&&1)|(t.self&&2)|(t.skipSelf&&4)}function Pk(t){let e=[];for(let n=0;n ");else if(typeof e=="object"){let i=[];for(let o in e)if(e.hasOwnProperty(o)){let a=e[o];i.push(o+":"+(typeof a=="string"?JSON.stringify(a):tn(a)))}s=`{${i.join(", ")}}`}return`${n}${r?"("+r+")":""}[${s}]: ${t.replace(Dse,` + `)}`}var Ke=L0(Fh("Inject",t=>({token:t})),-1),lt=L0(Fh("Optional"),8),Jn=L0(Fh("Self"),2),bl=L0(Fh("SkipSelf"),4),pi=L0(Fh("Host"),1);function pd(t,e){let n=t.hasOwnProperty(ll);if(!n&&e===!0&&ngDevMode)throw new Error(`Type ${tn(t)} does not have '\u0275fac' property.`);return n?t[ll]:null}function Pse(t,e,n){if(t.length!==e.length)return!1;for(let r=0;rArray.isArray(n)?bh(n,e):e(n))}function KV(t,e,n){e>=t.length?t.push(n):t.splice(e,0,n)}function CS(t,e){return e>=t.length-1?t.pop():t.splice(e,1)[0]}function Ly(t,e){let n=[];for(let r=0;re;){let i=s-2;t[s]=t[i],s--}t[e]=n,t[e+1]=r}}function Mi(t,e,n){let r=O0(t,e);return r>=0?t[r|1]=n:(r=~r,JV(t,r,e,n)),r}function ZI(t,e){let n=O0(t,e);if(n>=0)return t[n|1]}function O0(t,e){return Nse(t,e,1)}function Nse(t,e,n){ngDevMode&&rt(Array.isArray(t),!0,"Expecting an array");let r=0,s=t.length>>n;for(;s!==r;){let i=r+(s-r>>1),o=t[i<e?s=i:r=i+1}return~(s<"u"||ngDevMode)&&wA()&&(Object.freeze(eo),Object.freeze(un));var li=new $e(ngDevMode?"ENVIRONMENT_INITIALIZER":""),DA=new $e(ngDevMode?"INJECTOR":"",-1),_A=new $e(ngDevMode?"INJECTOR_DEF_TYPES":""),wh=class{get(e,n=cd){if(n===cd){let r=new Error(`NullInjectorError: No provider for ${tn(e)}!`);throw r.name="NullInjectorError",r}return n}};function ki(t,e){let n=t[xA]||null;if(!n&&e===!0)throw new Error(`Type ${tn(t)} does not have '\u0275mod' property.`);return n}function Ut(t){return t[Md]||null}function ls(t){return t[$C]||null}function Ti(t){return t[VC]||null}function Sc(t){let e=Ut(t)||ls(t)||Ti(t);return e!==null&&e.standalone}function ma(t){return{\u0275providers:t}}function Rse(t){return ma([{provide:li,multi:!0,useValue:t}])}function e5(...t){return{\u0275providers:IA(!0,t),\u0275fromNgModule:!0}}function IA(t,...e){let n=[],r=new Set,s,i=o=>{n.push(o)};return bh(e,o=>{if((typeof ngDevMode>"u"||ngDevMode)&&t&&Ut(o)?.standalone)throw new ne(800,`Importing providers supports NgModule or ModuleWithProviders but got a standalone component "${Xt(o)}"`);let a=o;TS(a,i,[],r)&&(s||(s=[]),s.push(a))}),s!==void 0&&t5(s,i),n}function t5(t,e){for(let n=0;n{ngDevMode&&n5(i,s||un,r),e(i,r)})}}function TS(t,e,n,r){if(t=xt(t),!t)return!1;let s=null,i=yS(t),o=!i&&Ut(t);if(!i&&!o){let c=t.ngModule;if(i=yS(c),i)s=c;else return!1}else{if(o&&!o.standalone)return!1;s=t}if(ngDevMode&&n.indexOf(s)!==-1){let c=tn(s),u=n.map(tn);SA(c,u)}let a=r.has(s);if(o){if(a)return!1;if(r.add(s),o.dependencies){let c=typeof o.dependencies=="function"?o.dependencies():o.dependencies;for(let u of c)TS(u,e,n,r)}}else if(i){if(i.imports!=null&&!a){ngDevMode&&n.push(s),r.add(s);let u;try{bh(i.imports,d=>{TS(d,e,n,r)&&(u||(u=[]),u.push(d))})}finally{ngDevMode&&n.pop()}u!==void 0&&t5(u,e)}if(!a){let u=pd(s)||(()=>new s);e({provide:s,useFactory:u,deps:un},s),e({provide:_A,useValue:s,multi:!0},s),e({provide:li,useValue:()=>Zr(s),multi:!0},s)}let c=i.providers;if(c!=null&&!a){let u=t;kA(c,d=>{ngDevMode&&n5(d,c,u),e(d,u)})}}else return!1;return s!==t&&t.providers!==void 0}function n5(t,e,n){if(fd(t)||HC(t)||s5(t)||r5(t))return;xt(t&&(t.useClass||t.provide))||Ak(n,e,t)}function kA(t,e){for(let n of t)R0(n)&&(n=n.\u0275providers),Array.isArray(n)?kA(n,e):e(n)}var Fse=Fn({provide:String,useValue:Fn});function HC(t){return t!==null&&typeof t=="object"&&Fse in t}function r5(t){return!!(t&&t.useExisting)}function s5(t){return!!(t&&t.useFactory)}function fd(t){return typeof t=="function"}function Lse(t){return!!t.useClass}var B0=new $e(ngDevMode?"Set Injector scope.":""),sS={},Q$={},YI;function jC(){return YI===void 0&&(YI=new wh),YI}var ci=class{},ga=class extends ci{constructor(n,r,s,i){super();l(this,"parent");l(this,"source");l(this,"scopes");l(this,"records",new Map);l(this,"_ngOnDestroyHooks",new Set);l(this,"_onDestroyHooks",[]);l(this,"_destroyed",!1);l(this,"injectorDefTypes");this.parent=r,this.source=s,this.scopes=i,Rk(n,a=>this.processProvider(a)),this.records.set(DA,ih(void 0,this)),i.has("environment")&&this.records.set(ci,ih(void 0,this));let o=this.records.get(B0);o!=null&&typeof o.value=="string"&&this.scopes.add(o.value),this.injectorDefTypes=new Set(this.get(_A,un,Wt.Self))}get destroyed(){return this._destroyed}retrieve(n,r){let s=r;return this.get(n,s.optional?bx:cd,s)}destroy(){Ay(this),this._destroyed=!0;let n=Et(null);try{for(let s of this._ngOnDestroyHooks)s.ngOnDestroy();let r=this._onDestroyHooks;this._onDestroyHooks=[];for(let s of r)s()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),Et(n)}}onDestroy(n){return Ay(this),this._onDestroyHooks.push(n),()=>this.removeOnDestroy(n)}runInContext(n){Ay(this);let r=ua(this),s=ii(void 0),i;ngDevMode&&(i=as({injector:this,token:null}));try{return n()}finally{ua(r),ii(s),ngDevMode&&as(i)}}get(n,r=cd,s=Wt.Default){if(Ay(this),n.hasOwnProperty(G$))return n[G$](this);s=F0(s);let i;ngDevMode&&(i=as({injector:this,token:n}));let o=ua(this),a=ii(void 0);try{if(!(s&Wt.SkipSelf)){let u=this.records.get(n);if(u===void 0){let d=Hse(n)&&N0(n);d&&this.injectableDefInScope(d)?(ngDevMode&&Fy(this,n,()=>{kk(n)}),u=ih(Nk(n),sS)):u=null,this.records.set(n,u)}if(u!=null)return this.hydrate(n,u,s)}let c=s&Wt.Self?jC():this.parent;return r=s&Wt.Optional&&r===cd?null:r,c.get(n,r)}catch(c){if(c.name==="NullInjectorError"){if((c[SS]=c[SS]||[]).unshift(tn(n)),o)throw c;return Ase(c,n,"R3InjectorError",this.source)}else throw c}finally{ii(a),ua(o),ngDevMode&&as(i)}}resolveInjectorInitializers(){let n=Et(null),r=ua(this),s=ii(void 0),i;ngDevMode&&(i=as({injector:this,token:null}));try{let o=this.get(li,un,Wt.Self);if(ngDevMode&&!Array.isArray(o))throw new ne(-209,`Unexpected type of the \`ENVIRONMENT_INITIALIZER\` token value (expected an array, but got ${typeof o}). Please check that the \`ENVIRONMENT_INITIALIZER\` token is configured as a \`multi: true\` provider.`);for(let a of o)a()}finally{ua(r),ii(s),ngDevMode&&as(i),Et(n)}}toString(){let n=[],r=this.records;for(let s of r.keys())n.push(tn(s));return`R3Injector[${n.join(", ")}]`}processProvider(n){n=xt(n);let r=fd(n)?n:xt(n&&n.provide),s=Bse(n);if(ngDevMode&&Fy(this,r,()=>{HC(n)&&wS(n.useValue),kk(n)}),!fd(n)&&n.multi===!0){let i=this.records.get(r);i?ngDevMode&&i.multi===void 0&&Z$():(i=ih(void 0,sS,!0),i.factory=()=>Pk(i.multi),this.records.set(r,i)),r=n,i.multi.push(n)}else if(ngDevMode){let i=this.records.get(r);i&&i.multi!==void 0&&Z$()}this.records.set(r,s)}hydrate(n,r,s){let i=Et(null);try{return r.value===Q$?SA(tn(n)):r.value===sS&&(r.value=Q$,ngDevMode?Fy(this,n,()=>{r.value=r.factory(void 0,s),wS(r.value)}):r.value=r.factory(void 0,s)),typeof r.value=="object"&&r.value&&Vse(r.value)&&this._ngOnDestroyHooks.add(r.value),r.value}finally{Et(i)}}injectableDefInScope(n){if(!n.providedIn)return!1;let r=xt(n.providedIn);return typeof r=="string"?r==="any"||this.scopes.has(r):this.injectorDefTypes.has(r)}removeOnDestroy(n){let r=this._onDestroyHooks.indexOf(n);r!==-1&&this._onDestroyHooks.splice(r,1)}};function Nk(t){let e=N0(t),n=e!==null?e.factory:pd(t);if(n!==null)return n;if(t instanceof $e)throw new ne(204,ngDevMode&&`Token ${tn(t)} is missing a \u0275prov definition.`);if(t instanceof Function)return Ose(t);throw new ne(204,ngDevMode&&"unreachable")}function Ose(t){let e=t.length;if(e>0)throw new ne(204,ngDevMode&&`Can't resolve all parameters for ${tn(t)}: (${Ly(e,"?").join(", ")}).`);let n=vse(t);return n!==null?()=>n.factory(t):()=>new t}function Bse(t){if(HC(t))return ih(void 0,t.useValue);{let e=i5(t);return ih(e,sS)}}function i5(t,e,n){let r;if(ngDevMode&&R0(t)&&Ak(void 0,n,t),fd(t)){let s=xt(t);return pd(s)||Nk(s)}else if(HC(t))r=()=>xt(t.useValue);else if(s5(t))r=()=>t.useFactory(...Pk(t.deps||[]));else if(r5(t))r=(s,i)=>Zr(xt(t.useExisting),i!==void 0&&i&Wt.Optional?Wt.Optional:void 0);else{let s=xt(t&&(t.useClass||t.provide));if(ngDevMode&&!s&&Ak(e,n,t),$se(t))r=()=>new s(...Pk(t.deps));else return pd(s)||Nk(s)}return r}function Ay(t){if(t.destroyed)throw new ne(205,ngDevMode&&"Injector has already been destroyed.")}function ih(t,e,n=!1){return{factory:t,value:e,multi:n?[]:void 0}}function $se(t){return!!t.deps}function Vse(t){return t!==null&&typeof t=="object"&&typeof t.ngOnDestroy=="function"}function Hse(t){return typeof t=="function"||typeof t=="object"&&t instanceof $e}function Rk(t,e){for(let n of t)Array.isArray(n)?Rk(n,e):n&&R0(n)?Rk(n.\u0275providers,e):e(n)}function AA(t,e){let n;t instanceof ga?(Ay(t),n=t):n=new xS(t);let r;ngDevMode&&(r=as({injector:t,token:null}));let s=ua(n),i=ii(void 0);try{return e()}finally{ua(s),ngDevMode&&as(r),ii(i)}}function MA(){return XV()!==void 0||Cy()!=null}function us(t){if(!MA())throw new ne(-203,ngDevMode&&t.name+"() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`")}var Te;(function(t){t[t.Directive=0]="Directive",t[t.Component=1]="Component",t[t.Injectable=2]="Injectable",t[t.Pipe=3]="Pipe",t[t.NgModule=4]="NgModule"})(Te||(Te={}));var K$;(function(t){t[t.Directive=0]="Directive",t[t.Pipe=1]="Pipe",t[t.NgModule=2]="NgModule"})(K$||(K$={}));var J$;(function(t){t[t.Emulated=0]="Emulated",t[t.None=2]="None",t[t.ShadowDom=3]="ShadowDom"})(J$||(J$={}));function Br(t){let e=Yn.ng;if(e&&e.\u0275compilerFacade)return e.\u0275compilerFacade;if(typeof ngDevMode>"u"||ngDevMode){console.error(`JIT compilation failed for ${t.kind}`,t.type);let n=`The ${t.kind} '${t.type.name}' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available. + +`;throw t.usage===1?(n+=`The ${t.kind} is part of a library that has been partially compiled. +`,n+=`However, the Angular Linker has not processed the library such that JIT compilation is used as fallback. +`,n+=` +`,n+=`Ideally, the library is processed using the Angular Linker to become fully AOT compiled. +`):n+=`JIT compilation is discouraged for production use-cases! Consider using AOT mode instead. +`,n+=`Alternatively, the JIT compiler should be loaded by bootstrapping using '@angular/platform-browser-dynamic' or '@angular/platform-server', +`,n+=`or manually provide the compiler with 'import "@angular/compiler";' before bootstrapping.`,new Error(n)}else throw new Error("JIT compiler unavailable")}var e8={\u0275\u0275defineInjectable:hn,\u0275\u0275defineInjector:LC,\u0275\u0275inject:Zr,\u0275\u0275invalidFactoryDep:TA,resolveForwardRef:xt},o5=Function;function My(t){return typeof t=="function"}var jse=/^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*(arguments|(?:[^()]+\(\[\],)?[^()]+\(arguments\).*)\)/,Use=/^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/,qse=/^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/,Wse=/^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{[^}]*super\(\.\.\.arguments\)/;function zse(t){return jse.test(t)||Wse.test(t)||Use.test(t)&&!qse.test(t)}var DS=class{constructor(e){l(this,"_reflect");this._reflect=e||Yn.Reflect}factory(e){return(...n)=>new e(...n)}_zipTypesAndAnnotations(e,n){let r;typeof e>"u"?r=Ly(n.length):r=Ly(e.length);for(let s=0;s"u"?r[s]=[]:e[s]&&e[s]!=Object?r[s]=[e[s]]:r[s]=[],n&&n[s]!=null&&(r[s]=r[s].concat(n[s]));return r}_ownParameters(e,n){let r=e.toString();if(zse(r))return null;if(e.parameters&&e.parameters!==n.parameters)return e.parameters;let s=e.ctorParameters;if(s&&s!==n.ctorParameters){let a=typeof s=="function"?s():s,c=a.map(d=>d&&d.type),u=a.map(d=>d&&XI(d.decorators));return this._zipTypesAndAnnotations(c,u)}let i=e.hasOwnProperty(rh)&&e[rh],o=this._reflect&&this._reflect.getOwnMetadata&&this._reflect.getOwnMetadata("design:paramtypes",e);return o||i?this._zipTypesAndAnnotations(o,i):Ly(e.length)}parameters(e){if(!My(e))return[];let n=Gx(e),r=this._ownParameters(e,n);return!r&&n!==Object&&(r=this.parameters(n)),r||[]}_ownAnnotations(e,n){if(e.annotations&&e.annotations!==n.annotations){let r=e.annotations;return typeof r=="function"&&r.annotations&&(r=r.annotations),r}return e.decorators&&e.decorators!==n.decorators?XI(e.decorators):e.hasOwnProperty(nh)?e[nh]:null}annotations(e){if(!My(e))return[];let n=Gx(e),r=this._ownAnnotations(e,n)||[];return(n!==Object?this.annotations(n):[]).concat(r)}_ownPropMetadata(e,n){if(e.propMetadata&&e.propMetadata!==n.propMetadata){let r=e.propMetadata;return typeof r=="function"&&r.propMetadata&&(r=r.propMetadata),r}if(e.propDecorators&&e.propDecorators!==n.propDecorators){let r=e.propDecorators,s={};return Object.keys(r).forEach(i=>{s[i]=XI(r[i])}),s}return e.hasOwnProperty(sh)?e[sh]:null}propMetadata(e){if(!My(e))return{};let n=Gx(e),r={};if(n!==Object){let i=this.propMetadata(n);Object.keys(i).forEach(o=>{r[o]=i[o]})}let s=this._ownPropMetadata(e,n);return s&&Object.keys(s).forEach(i=>{let o=[];r.hasOwnProperty(i)&&o.push(...r[i]),o.push(...s[i]),r[i]=o}),r}ownPropMetadata(e){return My(e)?this._ownPropMetadata(e,Gx(e))||{}:{}}hasLifecycleHook(e,n){return e instanceof o5&&n in e.prototype}};function XI(t){return t?t.map(e=>{let r=e.type.annotationCls,s=e.args?e.args:[];return new r(...s)}):[]}function Gx(t){let e=t.prototype?Object.getPrototypeOf(t.prototype):null;return(e?e.constructor:null)||Object}var Mn=0,de=1,dt=2,ir=3,ws=4,Xr=5,Ls=6,Cc=7,wn=8,or=9,ko=10,pt=11,hd=12,_S=13,Ac=14,Kn=15,md=16,oh=17,Di=18,gd=19,a5=20,Tc=21,fh=22,ol=23,_i=24,Dc=25,He=26,PA=1,Mo=6,va=7,IS=8,vd=9,Wn=10;function fr(t){return Array.isArray(t)&&typeof t[PA]=="object"}function Ir(t){return Array.isArray(t)&&t[PA]===!0}function NA(t){return(t.flags&4)!==0}function Ro(t){return t.componentOffset>-1}function UC(t){return(t.flags&1)===1}function Ns(t){return!!t.template}function cl(t){return(t[dt]&512)!==0}function l5(t){return(t.type&16)===16}function Gse(t){return(t[dt]&32)===32}function ul(t){return(t[dt]&256)===256}function Hs(t,e){Bh(t,e[de])}function Bh(t,e){dl(t);let n=e.data;for(let r=He;r) must have projection slots defined.")}function p5(t,e){Fe(t,"Component views should always have a parent view (component's host view)")}function f5(t,e){kS(t,e),kS(t,e+8),_n(t[e+0],"injectorIndex should point to a bloom filter"),_n(t[e+1],"injectorIndex should point to a bloom filter"),_n(t[e+2],"injectorIndex should point to a bloom filter"),_n(t[e+3],"injectorIndex should point to a bloom filter"),_n(t[e+4],"injectorIndex should point to a bloom filter"),_n(t[e+5],"injectorIndex should point to a bloom filter"),_n(t[e+6],"injectorIndex should point to a bloom filter"),_n(t[e+7],"injectorIndex should point to a bloom filter"),_n(t[e+8],"injectorIndex should point to parent injector")}var AS=class{constructor(e,n,r){l(this,"previousValue");l(this,"currentValue");l(this,"firstChange");this.previousValue=e,this.currentValue=n,this.firstChange=r}isFirstChange(){return this.firstChange}};function h5(t,e,n,r){e!==null?e.applyValueToInputSignal(e,r):t[n]=r}var m5=(()=>{let t=()=>g5;return t.ngInherit=!0,t})();function g5(t){return t.type.prototype.ngOnChanges&&(t.setInput=Jse),Kse}function Kse(){let t=y5(this),e=t?.current;if(e){let n=t.previous;if(n===eo)t.previous=e;else for(let r in e)n[r]=e[r];t.current=null,this.ngOnChanges(e)}}function Jse(t,e,n,r,s){let i=this.declaredInputs[r];ngDevMode&&Lh(i,"Name of input in ngOnChanges has to be a string");let o=y5(t)||eie(t,{previous:eo,current:null}),a=o.current||(o.current={}),c=o.previous,u=c[i];a[i]=new AS(u&&u.currentValue,n,c===eo),h5(t,e,s,n)}var v5="__ngSimpleChanges__";function y5(t){return t[v5]||null}function eie(t,e){return t[v5]=e}var Fk=null,tie=t=>{Fk=t},kn=function(t,e=null,n){Fk?.(t,e,n)},FA="svg",LA="math";function dn(t){for(;Array.isArray(t);)t=t[Mn];return t}function OA(t){for(;Array.isArray(t);){if(typeof t[PA]=="object")return t;t=t[Mn]}return null}function $h(t,e){return ngDevMode&&gr(e,t),ngDevMode&&yl(t,He,"Expected to be past HEADER_OFFSET"),dn(e[t])}function xs(t,e){return ngDevMode&&Hs(t,e),ngDevMode&&gr(e,t.index),dn(e[t.index])}function nie(t,e){let n=t===null?-1:t.index;return n!==-1?(ngDevMode&&Hs(t,e),dn(e[n])):null}function Pd(t,e){ngDevMode&&Ad(e,-1,"wrong index for TNode"),ngDevMode&&kc(e,t.data.length,"wrong index for TNode");let n=t.data[e];return ngDevMode&&n!==null&&dl(n),n}function Nd(t,e){return ngDevMode&&gr(t,e),t[e]}function WC(t,e,n,r){n>=t.data.length&&(t.data[n]=null,t.blueprint[n]=null),e[n]=r}function Bs(t,e){ngDevMode&&gr(e,t);let n=e[t];return fr(n)?n:n[Mn]}function V0(t){return(t[dt]&4)===4}function BA(t){return(t[dt]&128)===128}function rie(t){return Ir(t[ir])}function to(t,e){return e==null?null:(ngDevMode&&gr(t,e),t[e])}function b5(t){t[oh]=0}function $A(t){t[dt]&1024||(t[dt]|=1024,BA(t)&&Vh(t))}function w5(t,e){for(;t>0;)ngDevMode&&Fe(e[Ac],"Declaration view should be defined if nesting level is greater than 0."),e=e[Ac],t--;return e}function H0(t){return!!(t[dt]&9216||t[_i]?.dirty)}function Lk(t){t[ko].changeDetectionScheduler?.notify(8),t[dt]&64&&(t[dt]|=1024),H0(t)&&Vh(t)}function Vh(t){t[ko].changeDetectionScheduler?.notify(0);let e=pl(t);for(;e!==null&&!(e[dt]&8192||(e[dt]|=8192,!BA(e)));)e=pl(e)}function zC(t,e){if(ul(t))throw new ne(911,ngDevMode&&"View has already been destroyed.");t[Tc]===null&&(t[Tc]=[]),t[Tc].push(e)}function VA(t,e){if(t[Tc]===null)return;let n=t[Tc].indexOf(e);n!==-1&&t[Tc].splice(n,1)}function pl(t){ngDevMode&&ui(t);let e=t[ir];return Ir(e)?e[ir]:e}function HA(t){return t[Cc]??(t[Cc]=[])}function MS(t){return t.cleanup??(t.cleanup=[])}function sie(t,e,n,r){let s=HA(e);ngDevMode&&Fe(n,"Cleanup context is mandatory when registering framework-level destroy hooks"),s.push(n),t.firstCreatePass?MS(t).push(r,s.length-1):ngDevMode&&Object.freeze(MS(t))}var yt={lFrame:P5(null),bindingsEnabled:!0,skipHydrationRootTNode:null},Mc;(function(t){t[t.Off=0]="Off",t[t.Exhaustive=1]="Exhaustive",t[t.OnlyDirtyViews=2]="OnlyDirtyViews"})(Mc||(Mc={}));var jA=0,Ok=!1;function iie(){return yt.lFrame.elementDepthCount}function oie(){yt.lFrame.elementDepthCount++}function aie(){yt.lFrame.elementDepthCount--}function UA(){return yt.bindingsEnabled}function Rd(){return yt.skipHydrationRootTNode!==null}function lie(t){return yt.skipHydrationRootTNode===t}function E5(){yt.bindingsEnabled=!0}function cie(t){yt.skipHydrationRootTNode=t}function x5(){yt.bindingsEnabled=!1}function uie(){yt.skipHydrationRootTNode=null}function re(){return yt.lFrame.lView}function nt(){return yt.lFrame.tView}function S5(t){return yt.lFrame.contextLView=t,t[wn]}function C5(t){return yt.lFrame.contextLView=null,t}function Bt(){let t=T5();for(;t!==null&&t.type===64;)t=t.parent;return t}function T5(){return yt.lFrame.currentTNode}function i0(){let t=yt.lFrame,e=t.currentTNode;return t.isParent?e:e.parent}function Po(t,e){ngDevMode&&t&&Bh(t,yt.lFrame.tView);let n=yt.lFrame;n.currentTNode=t,n.isParent=e}function qA(){return yt.lFrame.isParent}function WA(){yt.lFrame.isParent=!1}function D5(){let t=yt.lFrame.contextLView;return ngDevMode&&Fe(t,"contextLView must be defined."),t}function Fd(){return!ngDevMode&&tt("Must never be called in production mode"),jA!==Mc.Off}function zA(){return!ngDevMode&&tt("Must never be called in production mode"),jA===Mc.Exhaustive}function t8(t){!ngDevMode&&tt("Must never be called in production mode"),jA=t}function _5(){return Ok}function PS(t){let e=Ok;return Ok=t,e}function js(){let t=yt.lFrame,e=t.bindingRootIndex;return e===-1&&(e=t.bindingRootIndex=t.tView.bindingStartIndex),e}function Pn(){return yt.lFrame.bindingIndex}function I5(t){return yt.lFrame.bindingIndex=t}function ao(){return yt.lFrame.bindingIndex++}function wl(t){let e=yt.lFrame,n=e.bindingIndex;return e.bindingIndex=e.bindingIndex+t,n}function die(){return yt.lFrame.inI18n}function k5(t){yt.lFrame.inI18n=t}function pie(t,e){let n=yt.lFrame;n.bindingIndex=n.bindingRootIndex=t,Bk(e)}function fie(){return yt.lFrame.currentDirectiveIndex}function Bk(t){yt.lFrame.currentDirectiveIndex=t}function GA(t){let e=yt.lFrame.currentDirectiveIndex;return e===-1?null:t[e]}function ZA(){return yt.lFrame.currentQueryIndex}function GC(t){yt.lFrame.currentQueryIndex=t}function hie(t){let e=t[de];return e.type===2?(ngDevMode&&Fe(e.declTNode,"Embedded TNodes should have declaration parents."),e.declTNode):e.type===1?t[Xr]:null}function A5(t,e,n){if(ngDevMode&&u5(t),n&Wt.SkipSelf){ngDevMode&&Bh(e,t[de]);let s=e,i=t;for(;ngDevMode&&Fe(s,"Parent TNode should be defined"),s=s.parent,s===null&&!(n&Wt.Host);)if(s=hie(i),s===null||(ngDevMode&&Fe(i,"Parent LView should be defined"),i=i[Ac],s.type&10))break;if(s===null)return!1;e=s,t=i}ngDevMode&&Hs(e,t);let r=yt.lFrame=M5();return r.currentTNode=e,r.lView=t,!0}function YA(t){ngDevMode&&di(t[0],t[1],"????"),ngDevMode&&u5(t);let e=M5();ngDevMode&&(rt(e.isParent,!0,"Expected clean LFrame"),rt(e.lView,null,"Expected clean LFrame"),rt(e.tView,null,"Expected clean LFrame"),rt(e.selectedIndex,-1,"Expected clean LFrame"),rt(e.elementDepthCount,0,"Expected clean LFrame"),rt(e.currentDirectiveIndex,-1,"Expected clean LFrame"),rt(e.currentNamespace,null,"Expected clean LFrame"),rt(e.bindingRootIndex,-1,"Expected clean LFrame"),rt(e.currentQueryIndex,0,"Expected clean LFrame"));let n=t[de];yt.lFrame=e,ngDevMode&&n.firstChild&&Bh(n.firstChild,n),e.currentTNode=n.firstChild,e.lView=t,e.tView=n,e.contextLView=t,e.bindingIndex=n.bindingStartIndex,e.inI18n=!1}function M5(){let t=yt.lFrame,e=t===null?null:t.child;return e===null?P5(t):e}function P5(t){let e={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:t,child:null,inI18n:!1};return t!==null&&(t.child=e),e}function N5(){let t=yt.lFrame;return yt.lFrame=t.parent,t.currentTNode=null,t.lView=null,t}var R5=N5;function XA(){let t=N5();t.isParent=!0,t.tView=null,t.selectedIndex=-1,t.contextLView=null,t.elementDepthCount=0,t.currentDirectiveIndex=-1,t.currentNamespace=null,t.bindingRootIndex=-1,t.bindingIndex=-1,t.currentQueryIndex=0}function mie(t){return(yt.lFrame.contextLView=w5(t,yt.lFrame.contextLView))[wn]}function Vr(){return yt.lFrame.selectedIndex}function fl(t){ngDevMode&&t!==-1&&yl(t,He,"Index must be past HEADER_OFFSET (or -1)."),ngDevMode&&kc(t,yt.lFrame.lView.length,"Can't set index passed end of LView"),yt.lFrame.selectedIndex=t}function Hn(){let t=yt.lFrame;return Pd(t.tView,t.selectedIndex)}function F5(){yt.lFrame.currentNamespace=FA}function L5(){yt.lFrame.currentNamespace=LA}function O5(){gie()}function gie(){yt.lFrame.currentNamespace=null}function QA(){return yt.lFrame.currentNamespace}var B5=!0;function j0(){return B5}function Ca(t){B5=t}function vie(t,e,n){ngDevMode&&Os(n);let{ngOnChanges:r,ngOnInit:s,ngDoCheck:i}=e.type.prototype;if(r){let o=g5(e);(n.preOrderHooks??(n.preOrderHooks=[])).push(t,o),(n.preOrderCheckHooks??(n.preOrderCheckHooks=[])).push(t,o)}s&&(n.preOrderHooks??(n.preOrderHooks=[])).push(0-t,s),i&&((n.preOrderHooks??(n.preOrderHooks=[])).push(t,i),(n.preOrderCheckHooks??(n.preOrderCheckHooks=[])).push(t,i))}function KA(t,e){ngDevMode&&Os(t);for(let n=e.directiveStart,r=e.directiveEnd;n=r)break}else e[c]<0&&(t[oh]+=65536),(a>14>16&&(t[dt]&3)===e&&(t[dt]+=16384,n8(a,i)):n8(a,i)}var hh=-1,Pc=class{constructor(e,n,r){l(this,"factory");l(this,"injectImpl");l(this,"resolving",!1);l(this,"canSeeViewProviders");l(this,"multi");l(this,"componentProviders");l(this,"index");l(this,"providerFactory");this.factory=e,ngDevMode&&Fe(e,"Factory not specified"),ngDevMode&&rt(typeof e,"function","Expected factory function."),this.canSeeViewProviders=n,this.injectImpl=r}};function $k(t){let e="";return t&1&&(e+="|Text"),t&2&&(e+="|Element"),t&4&&(e+="|Container"),t&8&&(e+="|ElementContainer"),t&16&&(e+="|Projection"),t&32&&(e+="|IcuContainer"),t&64&&(e+="|Placeholder"),t&128&&(e+="|LetDeclaration"),e.length>0?e.substring(1):e}function JA(t){return t!=null&&typeof t=="object"&&(t.insertBeforeIndex===null||typeof t.insertBeforeIndex=="number"||Array.isArray(t.insertBeforeIndex))}function bie(t){return!!(t.type&128)}function wie(t){return(t.flags&8)!==0}function Eie(t){return(t.flags&16)!==0}function Yr(t,e,n){Fe(t,"should be called with a TNode"),t.type&e||tt(n||`Expected [${$k(e)}] but got ${$k(t.type)}.`)}function xie(t){t===2||t===1||t===4||t===8||t===32||t===16||t===64||t===128||tt(`Expected TNodeType to have only a single type selected, but got ${$k(t)}.`)}function Sie(t,e,n){let r=0;for(;re){o=i-1;break}}}for(;i>16}function a0(t,e){let n=Cie(t),r=e;for(;n>0;)r=r[Ac],n--;return r}var Vk=!0;function NS(t){let e=Vk;return Vk=t,e}var Tie=256,j5=Tie-1,U5=5,Die=0,fa={};function _ie(t,e,n){ngDevMode&&rt(e.firstCreatePass,!0,"expected firstCreatePass to be true");let r;typeof n=="string"?r=n.charCodeAt(0)||0:n.hasOwnProperty(ph)&&(r=n[ph]),r==null&&(r=n[ph]=Die++);let s=r&j5,i=1<>U5)]|=i}function RS(t,e){let n=q5(t,e);if(n!==-1)return n;let r=e[de];r.firstCreatePass&&(t.injectorIndex=e.length,KI(r.data,t),KI(e,null),KI(r.blueprint,null));let s=ZC(t,e),i=t.injectorIndex;if(eM(s)){let o=o0(s),a=a0(s,e),c=a[de].data;for(let u=0;u<8;u++)e[i+u]=a[o+u]|c[o+u]}return e[i+8]=s,i}function KI(t,e){t.push(0,0,0,0,0,0,0,0,e)}function q5(t,e){return t.injectorIndex===-1||t.parent&&t.parent.injectorIndex===t.injectorIndex||e[t.injectorIndex+8]===null?-1:(ngDevMode&&gr(e,t.injectorIndex),t.injectorIndex)}function ZC(t,e){if(t.parent&&t.parent.injectorIndex!==-1)return t.parent.injectorIndex;let n=0,r=null,s=e;for(;s!==null;){if(r=X5(s),r===null)return hh;if(ngDevMode&&r&&Hs(r,s[Ac]),n++,s=s[Ac],r.injectorIndex!==-1)return r.injectorIndex|n<<16}return hh}function Hk(t,e,n){_ie(t,e,n)}function Iie(t,e){if(ngDevMode&&Yr(t,15),ngDevMode&&Fe(t,"expecting tNode"),e==="class")return t.classes;if(e==="style")return t.styles;let n=t.attrs;if(n){let r=n.length,s=0;for(;s{o=i(r),o!=null&&wS(o)}):o=i(r),o==null&&!(r&Wt.Optional))CA(n);else return o}finally{R5()}}else if(typeof i=="number"){let o=null,a=q5(t,e),c=hh,u=r&Wt.Host?e[Kn][Xr]:null;for((a===-1||r&Wt.SkipSelf)&&(c=a===-1?ZC(t,e):e[a+8],c===hh||!i8(r,!1)?a=-1:(o=e[de],a=o0(c),e=a0(c,e)));a!==-1;){ngDevMode&&f5(e,a);let d=e[de];if(ngDevMode&&Hs(d.data[a+8],e),s8(i,a,d.data)){let p=kie(a,e,n,o,r,u);if(p!==fa)return p}c=e[a+8],c!==hh&&i8(r,e[de].data[a+8]===u)&&s8(i,a,e)?(o=d,a=o0(c),e=a0(c,e)):a=-1}}return s}function kie(t,e,n,r,s,i){let o=e[de],a=o.data[t+8],c=r==null?Ro(a)&&Vk:r!=o&&(a.type&3)!==0,u=s&Wt.Host&&i===a,d=aS(a,o,n,c,u);return d!==null?l0(e,o,d,a,s):fa}function aS(t,e,n,r,s){let i=t.providerIndexes,o=e.data,a=i&1048575,c=t.directiveStart,u=t.directiveEnd,d=i>>20,p=r?a:a+d,f=s?a+d:u;for(let h=p;h=c&&m.type===n)return h}if(s){let h=o[c];if(h&&Ns(h)&&h.type===n)return c}return null}function l0(t,e,n,r,s){let i=t[n],o=e.data;if(i instanceof Pc){let a=i;a.resolving&&SA(Xt(o[n]));let c=NS(a.canSeeViewProviders);a.resolving=!0;let u;if(ngDevMode){let f=o[n].type||o[n],h=new Vn(r,t);u=as({injector:h,token:f})}let d=a.injectImpl?ii(a.injectImpl):null,p=A5(t,r,Wt.Default);ngDevMode&&rt(p,!0,"Because flags do not contain `SkipSelf' we expect this to always succeed.");try{i=t[n]=a.factory(void 0,s,o,t,r),ngDevMode&&wS(i),e.firstCreatePass&&n>=r.directiveStart&&(ngDevMode&&Xse(o[n]),vie(n,o[n],e))}finally{ngDevMode&&as(u),d!==null&&ii(d),NS(c),a.resolving=!1,R5()}}return i}function Aie(t){if(ngDevMode&&Fe(t,"token must be defined"),typeof t=="string")return t.charCodeAt(0)||0;let e=t.hasOwnProperty(ph)?t[ph]:void 0;return typeof e=="number"?e>=0?e&j5:(ngDevMode&&rt(e,-1,"Expecting to get Special Injector Id"),Mie):e}function s8(t,e,n){let r=1<>U5)]&r)}function i8(t,e){return!(t&Wt.Self)&&!(t&Wt.Host&&e)}function Bc(t){return t._lView}function Ld(t){return t._tNode}var Vn=class{constructor(e,n){l(this,"_tNode");l(this,"_lView");this._tNode=e,this._lView=n}get(e,n,r){return G5(this._tNode,this._lView,e,F0(r),n)}};function Mie(){return new Vn(Bt(),re())}function Y5(t){return Sa(()=>{let e=t.prototype.constructor,n=e[ll]||jk(e),r=Object.prototype,s=Object.getPrototypeOf(t.prototype).constructor;for(;s&&s!==r;){let i=s[ll]||jk(s);if(i&&i!==n)return i;s=Object.getPrototypeOf(s)}return i=>new i})}function jk(t){return FC(t)?()=>{let e=jk(xt(t));return e&&e()}:pd(t)}function Pie(t,e,n,r,s){let i=t,o=e;for(;i!==null&&o!==null&&o[dt]&2048&&!cl(o);){ngDevMode&&Hs(i,o);let a=Z5(i,o,n,r|Wt.Self,fa);if(a!==fa)return a;let c=i.parent;if(!c){let u=o[a5];if(u){let d=u.get(n,fa,r);if(d!==fa)return d}c=X5(o),o=o[Ac]}i=c}return s}function X5(t){let e=t[de],n=e.type;return n===2?(ngDevMode&&Fe(e.declTNode,"Embedded TNodes should have declaration parents."),e.declTNode):n===1?t[Xr]:null}function YC(t){return Iie(Bt(),t)}var XC=Fh("Attribute",t=>({attributeName:t,__NG_ELEMENT_ID__:()=>YC(t)})),o8=null;function tM(){return o8=o8||new DS}function QC(t){return Q5(tM().parameters(t))}function Q5(t){return t.map(e=>Nie(e))}function Nie(t){let e={token:null,attribute:null,host:!1,optional:!1,self:!1,skipSelf:!1};if(Array.isArray(t)&&t.length>0)for(let n=0;n(n===null&&(n=Br({usage:0,kind:"injectable",type:t}).compileInjectable(e8,`ng:///${t.name}/\u0275prov.js`,Bie(t,e))),n)}),t.hasOwnProperty(ll)||Object.defineProperty(t,ll,{get:()=>{if(r===null){let s=Br({usage:0,kind:"injectable",type:t});r=s.compileFactory(e8,`ng:///${t.name}/\u0275fac.js`,{name:t.name,type:t,typeArgumentCount:0,deps:QC(t),target:s.FactoryTarget.Injectable})}return r},configurable:!0})}var Fie=Fn({provide:String,useValue:Fn});function a8(t){return t.useClass!==void 0}function Lie(t){return Fie in t}function l8(t){return t.useFactory!==void 0}function Oie(t){return t.useExisting!==void 0}function Bie(t,e){let n=e||{providedIn:null},r={name:t.name,type:t,typeArgumentCount:0,providedIn:n.providedIn};return(a8(n)||l8(n))&&n.deps!==void 0&&(r.deps=Q5(n.deps)),a8(n)?r.useClass=n.useClass:Lie(n)?r.useValue=n.useValue:l8(n)?r.useFactory=n.useFactory:Oie(n)&&(r.useExisting=n.useExisting),r}var St=P0("Injectable",void 0,void 0,void 0,(t,e)=>Rie(t,e));function Uk(t,e=null,n=null,r){let s=K5(t,e,n,r);return s.resolveInjectorInitializers(),s}function K5(t,e=null,n=null,r,s=new Set){let i=[n||un,e5(t)];return r=r||(typeof t=="object"?void 0:tn(t)),new ga(i,e||jC(),r||null,s)}var Gu=class Gu{static create(e,n){if(Array.isArray(e))return Uk({name:""},n,e,"");{let r=e.name??"";return Uk({name:r},e.parent,e.providers,r)}}};l(Gu,"THROW_IF_NOT_FOUND",cd),l(Gu,"NULL",new wh),l(Gu,"\u0275prov",hn({token:Gu,providedIn:"any",factory:()=>Zr(DA)})),l(Gu,"__NG_ELEMENT_ID__",-1);var Ln=Gu;var qk=class{constructor(e){l(this,"attributeName");l(this,"__NG_ELEMENT_ID__",()=>YC(this.attributeName));this.attributeName=e}toString(){return`HostAttributeToken ${this.attributeName}`}},J5=new $e(ngDevMode?"HOST_TAG_NAME":"");J5.__NG_ELEMENT_ID__=t=>{let e=Bt();if(e===null)throw new ne(204,ngDevMode&&"HOST_TAG_NAME can only be injected in directives and components during construction time (in a class constructor or as a class field initializer)");if(e.type&2)return e.value;if(t&Wt.Optional)return null;throw new ne(204,ngDevMode&&`HOST_TAG_NAME was used on ${$ie(e)} which doesn't have an underlying element in the DOM. This is invalid, and so the dependency should be marked as optional.`)};function $ie(t){return t.type&8?"an ":t.type&4?"an ":t.type&128?"an @let declaration":"a node"}var eH=!1,Es=class{};l(Es,"__NG_ELEMENT_ID__",Vie),l(Es,"__NG_ENV_ID__",e=>e);var FS=class extends Es{constructor(n){super();l(this,"_lView");this._lView=n}onDestroy(n){let r=this._lView;return ul(r)?(n(),()=>{}):(zC(r,n),()=>VA(r,n))}};function Vie(){return new FS(re())}var no=class{},Od=new $e(typeof ngDevMode>"u"||ngDevMode?"Zoneless enabled":"",{providedIn:"root",factory:()=>!1}),tH=new $e(typeof ngDevMode>"u"||ngDevMode?"Zoneless provided":"",{providedIn:"root",factory:()=>!1}),nH=new $e(typeof ngDevMode>"u"||ngDevMode?"scheduler disabled":""),nM=new $e(typeof ngDevMode>"u"||ngDevMode?"run changes outside zone in root":""),Gy=class Gy{constructor(){l(this,"taskId",0);l(this,"pendingTasks",new Set);l(this,"hasPendingTasks",new LI(!1))}get _hasPendingTasks(){return this.hasPendingTasks.value}add(){this._hasPendingTasks||this.hasPendingTasks.next(!0);let e=this.taskId++;return this.pendingTasks.add(e),e}has(e){return this.pendingTasks.has(e)}remove(e){this.pendingTasks.delete(e),this.pendingTasks.size===0&&this._hasPendingTasks&&this.hasPendingTasks.next(!1)}ngOnDestroy(){this.pendingTasks.clear(),this._hasPendingTasks&&this.hasPendingTasks.next(!1)}};l(Gy,"\u0275prov",hn({token:Gy,providedIn:"root",factory:()=>new Gy}));var ya=Gy,Zy=class Zy{constructor(){l(this,"internalPendingTasks",fe(ya));l(this,"scheduler",fe(no))}add(){let e=this.internalPendingTasks.add();return()=>{this.internalPendingTasks.has(e)&&(this.scheduler.notify(11),this.internalPendingTasks.remove(e))}}async run(e){let n=this.add();try{return await e()}finally{n()}}};l(Zy,"\u0275prov",hn({token:Zy,providedIn:"root",factory:()=>new Zy}));var c0=Zy,Wk=class extends si{constructor(n=!1){super();l(this,"__isAsync");l(this,"destroyRef");l(this,"pendingTasks");this.__isAsync=n,MA()&&(this.destroyRef=fe(Es,{optional:!0})??void 0,this.pendingTasks=fe(ya,{optional:!0})??void 0)}emit(n){let r=Et(null);try{super.next(n)}finally{Et(r)}}subscribe(n,r,s){let i=n,o=r||(()=>null),a=s;if(n&&typeof n=="object"){let u=n;i=u.next?.bind(u),o=u.error?.bind(u),a=u.complete?.bind(u)}this.__isAsync&&(o=this.wrapInTimeout(o),i&&(i=this.wrapInTimeout(i)),a&&(a=this.wrapInTimeout(a)));let c=super.subscribe({next:i,error:o,complete:a});return n instanceof Do&&n.add(c),c}wrapInTimeout(n){return r=>{let s=this.pendingTasks?.add();setTimeout(()=>{try{n(r)}finally{s!==void 0&&this.pendingTasks?.remove(s)}})}}},cs=Wk;function u0(...t){}function rH(t){let e,n;function r(){t=u0;try{n!==void 0&&typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(n),e!==void 0&&clearTimeout(e)}catch{}}return e=setTimeout(()=>{t(),r()}),typeof requestAnimationFrame=="function"&&(n=requestAnimationFrame(()=>{t(),r()})),()=>r()}function c8(t){return queueMicrotask(()=>t()),()=>{t=u0}}var zk=class{constructor(e,n=console){l(this,"createTask");l(this,"name");this.name="asyncStackTagging for "+e,this.createTask=n?.createTask??(()=>null)}onScheduleTask(e,n,r,s){return s.consoleTask=this.createTask(`Zone - ${s.source||s.type}`),e.scheduleTask(r,s)}onInvokeTask(e,n,r,s,i,o){let a;return s.consoleTask?a=s.consoleTask.run(()=>e.invokeTask(r,s,i,o)):a=e.invokeTask(r,s,i,o),a}},rM="isAngularZone",LS=rM+"_ID",Hie=0,qt=class t{constructor(e){l(this,"hasPendingMacrotasks",!1);l(this,"hasPendingMicrotasks",!1);l(this,"isStable",!0);l(this,"onUnstable",new cs(!1));l(this,"onMicrotaskEmpty",new cs(!1));l(this,"onStable",new cs(!1));l(this,"onError",new cs(!1));let{enableLongStackTrace:n=!1,shouldCoalesceEventChangeDetection:r=!1,shouldCoalesceRunChangeDetection:s=!1,scheduleInRootZone:i=eH}=e;if(typeof Zone>"u")throw new ne(908,ngDevMode&&"In this configuration Angular requires Zone.js");Zone.assertZonePatched();let o=this;o._nesting=0,o._outer=o._inner=Zone.current,ngDevMode&&(o._inner=o._inner.fork(new zk("Angular"))),Zone.TaskTrackingZoneSpec&&(o._inner=o._inner.fork(new Zone.TaskTrackingZoneSpec)),n&&Zone.longStackTraceZoneSpec&&(o._inner=o._inner.fork(Zone.longStackTraceZoneSpec)),o.shouldCoalesceEventChangeDetection=!s&&r,o.shouldCoalesceRunChangeDetection=s,o.callbackScheduled=!1,o.scheduleInRootZone=i,qie(o)}static isInAngularZone(){return typeof Zone<"u"&&Zone.current.get(rM)===!0}static assertInAngularZone(){if(!t.isInAngularZone())throw new ne(909,ngDevMode&&"Expected to be in Angular Zone, but it is not!")}static assertNotInAngularZone(){if(t.isInAngularZone())throw new ne(909,ngDevMode&&"Expected to not be in Angular Zone, but it is!")}run(e,n,r){return this._inner.run(e,n,r)}runTask(e,n,r,s){let i=this._inner,o=i.scheduleEventTask("NgZoneEvent: "+s,e,jie,u0,u0);try{return i.runTask(o,n,r)}finally{i.cancelTask(o)}}runGuarded(e,n,r){return this._inner.runGuarded(e,n,r)}runOutsideAngular(e){return this._outer.run(e)}},jie={};function sM(t){if(t._nesting==0&&!t.hasPendingMicrotasks&&!t.isStable)try{t._nesting++,t.onMicrotaskEmpty.emit(null)}finally{if(t._nesting--,!t.hasPendingMicrotasks)try{t.runOutsideAngular(()=>t.onStable.emit(null))}finally{t.isStable=!0}}}function Uie(t){if(t.isCheckStableRunning||t.callbackScheduled)return;t.callbackScheduled=!0;function e(){rH(()=>{t.callbackScheduled=!1,Gk(t),t.isCheckStableRunning=!0,sM(t),t.isCheckStableRunning=!1})}t.scheduleInRootZone?Zone.root.run(()=>{e()}):t._outer.run(()=>{e()}),Gk(t)}function qie(t){let e=()=>{Uie(t)},n=Hie++;t._inner=t._inner.fork({name:"angular",properties:{[rM]:!0,[LS]:n,[LS+n]:!0},onInvokeTask:(r,s,i,o,a,c)=>{if(Wie(c))return r.invokeTask(i,o,a,c);try{return u8(t),r.invokeTask(i,o,a,c)}finally{(t.shouldCoalesceEventChangeDetection&&o.type==="eventTask"||t.shouldCoalesceRunChangeDetection)&&e(),d8(t)}},onInvoke:(r,s,i,o,a,c,u)=>{try{return u8(t),r.invoke(i,o,a,c,u)}finally{t.shouldCoalesceRunChangeDetection&&!t.callbackScheduled&&!zie(c)&&e(),d8(t)}},onHasTask:(r,s,i,o)=>{r.hasTask(i,o),s===i&&(o.change=="microTask"?(t._hasPendingMicrotasks=o.microTask,Gk(t),sM(t)):o.change=="macroTask"&&(t.hasPendingMacrotasks=o.macroTask))},onHandleError:(r,s,i,o)=>(r.handleError(i,o),t.runOutsideAngular(()=>t.onError.emit(o)),!1)})}function Gk(t){t._hasPendingMicrotasks||(t.shouldCoalesceEventChangeDetection||t.shouldCoalesceRunChangeDetection)&&t.callbackScheduled===!0?t.hasPendingMicrotasks=!0:t.hasPendingMicrotasks=!1}function u8(t){t._nesting++,t.isStable&&(t.isStable=!1,t.onUnstable.emit(null))}function d8(t){t._nesting--,sM(t)}var xh=class{constructor(){l(this,"hasPendingMicrotasks",!1);l(this,"hasPendingMacrotasks",!1);l(this,"isStable",!0);l(this,"onUnstable",new cs);l(this,"onMicrotaskEmpty",new cs);l(this,"onStable",new cs);l(this,"onError",new cs)}run(e,n,r){return e.apply(n,r)}runGuarded(e,n,r){return e.apply(n,r)}runOutsideAngular(e){return e()}runTask(e,n,r,s){return e.apply(n,r)}};function Wie(t){return sH(t,"__ignore_ng_zone__")}function zie(t){return sH(t,"__scheduler_tick__")}function sH(t,e){return!Array.isArray(t)||t.length!==1?!1:t[0]?.data?.[e]===!0}function Gie(t="zone.js",e){return t==="noop"?new xh:t==="zone.js"?new qt(e):t}var $s=class{constructor(){l(this,"_console",console)}handleError(e){this._console.error("ERROR",e)}},iH=new $e(typeof ngDevMode>"u"||ngDevMode?"internal error handler":"",{providedIn:"root",factory:()=>{let t=fe(qt),e=fe($s);return n=>t.runOutsideAngular(()=>e.handleError(n))}}),d0=class{constructor(){l(this,"destroyed",!1);l(this,"listeners",null);l(this,"errorHandler",fe($s,{optional:!0}));l(this,"destroyRef",fe(Es));this.destroyRef.onDestroy(()=>{this.destroyed=!0,this.listeners=null})}subscribe(e){if(this.destroyed)throw new ne(953,ngDevMode&&"Unexpected subscription to destroyed `OutputRef`. The owning directive/component is destroyed.");return(this.listeners??(this.listeners=[])).push(e),{unsubscribe:()=>{let n=this.listeners?.indexOf(e);n!==void 0&&n!==-1&&this.listeners?.splice(n,1)}}}emit(e){if(this.destroyed){console.warn(gn(953,ngDevMode&&"Unexpected emit for destroyed `OutputRef`. The owning directive/component is destroyed."));return}if(this.listeners===null)return;let n=Et(null);try{for(let r of this.listeners)try{r(e)}catch(s){this.errorHandler?.handleError(s)}}finally{Et(n)}}};function Zie(t){return t.destroyRef}function oH(t){return ngDevMode&&us(oH),new d0}function p8(t,e){return ngDevMode&&us(iM),qV(t,e)}function Yie(t){return ngDevMode&&us(iM),qV(RC,t)}var iM=(p8.required=Yie,p8);function Xie(){return Hh(Bt(),re())}function Hh(t,e){return new pn(xs(t,e))}var pn=class{constructor(e){l(this,"nativeElement");this.nativeElement=e}};l(pn,"__NG_ELEMENT_ID__",Xie);function aH(t){return t instanceof pn?t.nativeElement:t}function oM(t){return typeof t=="function"&&t[rr]!==void 0}function Qie(t){return null}function ro(t,e){let n=SI(t,e?.equal),r=n[rr];return n.set=s=>Ou(r,s),n.update=s=>vx(r,s),n.asReadonly=KC.bind(n),ngDevMode&&(n.toString=()=>`[Signal: ${n()}]`,r.debugName=e?.debugName),n}function KC(){let t=this[rr];if(t.readonlyFn===void 0){let e=()=>this();e[rr]=t,t.readonlyFn=e}return t.readonlyFn}function lH(t){return oM(t)&&typeof t.set=="function"}function Kie(){return this._results[Symbol.iterator]()}var Nme,OS=class{constructor(e=!1){l(this,"_emitDistinctChangesOnly");l(this,"dirty",!0);l(this,"_onDirty");l(this,"_results",[]);l(this,"_changesDetected",!1);l(this,"_changes");l(this,"length",0);l(this,"first");l(this,"last");l(this,Nme,Kie);this._emitDistinctChangesOnly=e}get changes(){return this._changes??(this._changes=new si)}get(e){return this._results[e]}map(e){return this._results.map(e)}filter(e){return this._results.filter(e)}find(e){return this._results.find(e)}reduce(e,n){return this._results.reduce(e,n)}forEach(e){this._results.forEach(e)}some(e){return this._results.some(e)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(e,n){this.dirty=!1;let r=oi(e);(this._changesDetected=!Pse(this._results,r,n))&&(this._results=r,this.length=r.length,this.last=r[this.length-1],this.first=r[0])}notifyOnChanges(){this._changes!==void 0&&(this._changesDetected||!this._emitDistinctChangesOnly)&&this._changes.next(this)}onDirty(e){this._onDirty=e}setDirty(){this.dirty=!0,this._onDirty?.()}destroy(){this._changes!==void 0&&(this._changes.complete(),this._changes.unsubscribe())}};Nme=Symbol.iterator;var p0="ngSkipHydration",Jie="ngskiphydration";function aM(t){let e=t.mergedAttrs;if(e===null)return!1;for(let n=0;n=0){let a=dn(i[o]),c=Yk(i,o,a);ai(a,c),e=c;break}}}}return e||null}function Yk(t,e,n){return new BS(t[gd],e,n)}function pH(t){let e=Oy(t),n;if(fr(e)){let r=e,s=hH(r,t);n=Bs(s,r);let i=Yk(r,s,n[Mn]);i.component=t,ai(t,i),ai(i.native,i)}else{let r=e,s=r.lView;ngDevMode&&ui(s),n=Bs(r.nodeIndex,s)}return n}var Xk="__ngContext__";function ai(t,e){ngDevMode&&Fe(t,"Target expected"),fr(e)?(t[Xk]=e[gd],noe(e)):t[Xk]=e}function Oy(t){ngDevMode&&Fe(t,"Target expected");let e=t[Xk];return typeof e=="number"?dH(e):e||null}function lM(t){let e=Oy(t);return e?fr(e)?e:e.lView:null}function fH(t){return t&&t.constructor&&t.constructor.\u0275cmp}function soe(t){return t&&t.constructor&&t.constructor.\u0275dir}function f8(t,e){let n=t[de];for(let r=He;r=0?"dom":"output",g=typeof h=="boolean"?h:!1;t==p&&o.push({element:t,name:d,callback:f,useCapture:g,type:m})}}return o.sort(hoe),o}function hoe(t,e){return t.name==e.name?0:t.name"u"||ngDevMode)&&"The document object is not available in this context. Make sure the DOCUMENT injection token is provided.")}var Ii=new $e(ngDevMode?"AppId":"",{providedIn:"root",factory:()=>goe}),goe="ng",U0=new $e(ngDevMode?"Platform Initializer":""),Ta=new $e(ngDevMode?"Platform ID":"",{providedIn:"platform",factory:()=>"unknown"}),voe=new $e(ngDevMode?"Application Packages Root URL":""),yoe=new $e(ngDevMode?"AnimationModuleType":""),jh=new $e(ngDevMode?"CSP nonce":"",{providedIn:"root",factory:()=>No().body?.querySelector("[ngCspNonce]")?.getAttribute("ngCspNonce")||null}),eT={breakpoints:[16,32,48,64,96,128,256,384,640,750,828,1080,1200,1920,2048,3840],placeholderResolution:30,disableImageSizeWarning:!1,disableImageLazyLoadWarning:!1},tT=new $e(ngDevMode?"ImageConfig":"",{providedIn:"root",factory:()=>eT});function boe(t){return t}function woe(){let t=new ba;return(typeof ngServerMode>"u"||!ngServerMode)&&(t.store=Eoe(No(),fe(Ii))),t}var MC=class MC{constructor(){l(this,"store",{});l(this,"onSerializeCallbacks",{})}get(e,n){return this.store[e]!==void 0?this.store[e]:n}set(e,n){this.store[e]=n}remove(e){delete this.store[e]}hasKey(e){return this.store.hasOwnProperty(e)}get isEmpty(){return Object.keys(this.store).length===0}onSerialize(e,n){this.onSerializeCallbacks[e]=n}toJson(){for(let e in this.onSerializeCallbacks)if(this.onSerializeCallbacks.hasOwnProperty(e))try{this.store[e]=this.onSerializeCallbacks[e]()}catch(n){console.warn("Exception in onSerialize callback: ",n)}return JSON.stringify(this.store).replace(/"u"||ngDevMode?"IS_HYDRATION_DOM_REUSE_ENABLED":""),IH=!1,kH=new $e(typeof ngDevMode>"u"||ngDevMode?"PRESERVE_HOST_CONTENT":"",{providedIn:"root",factory:()=>IH}),AH=new $e(typeof ngDevMode>"u"||ngDevMode?"IS_I18N_HYDRATION_ENABLED":""),gM=new $e(typeof ngDevMode>"u"||ngDevMode?"IS_EVENT_REPLAY_ENABLED":""),MH=!1,vM=new $e(typeof ngDevMode>"u"||ngDevMode?"IS_INCREMENTAL_HYDRATION_ENABLED":""),m0=new $e(ngDevMode?"JSACTION_BLOCK_ELEMENT_MAP":"",{providedIn:"root",factory:()=>new Map}),g0;(function(t){t[t.CHANGE_DETECTION=0]="CHANGE_DETECTION",t[t.AFTER_NEXT_RENDER=1]="AFTER_NEXT_RENDER"})(g0||(g0={}));var Fo=new $e(ngDevMode?"TracingService":""),m8=new Set;function Ss(t){m8.has(t)||(m8.add(t),performance?.mark?.("mark_feature_usage",{detail:{feature:t}}))}function q0(t,e){if(xy()!==null)throw new ne(-602,ngDevMode&&`${t.name}() cannot be called from within a reactive context.${e?` ${e}`:""}`)}var ud=class{constructor(e,n){l(this,"view");l(this,"node");this.view=e,this.node=n}};l(ud,"__NG_ELEMENT_ID__",xoe);function xoe(){return new ud(re(),Bt())}var Ec;(function(t){t[t.EarlyRead=0]="EarlyRead",t[t.Write=1]="Write",t[t.MixedReadWrite=2]="MixedReadWrite",t[t.Read=3]="Read"})(Ec||(Ec={}));var Yy=class Yy{constructor(){l(this,"impl",null)}execute(){this.impl?.execute()}};l(Yy,"\u0275prov",hn({token:Yy,providedIn:"root",factory:()=>new Yy}));var Sh=Yy,PH=[Ec.EarlyRead,Ec.Write,Ec.MixedReadWrite,Ec.Read],Xy=class Xy{constructor(){l(this,"ngZone",fe(qt));l(this,"scheduler",fe(no));l(this,"errorHandler",fe($s,{optional:!0}));l(this,"sequences",new Set);l(this,"deferredRegistrations",new Set);l(this,"executing",!1);fe(Fo,{optional:!0})}execute(){let e=this.sequences.size>0;e&&kn(16),this.executing=!0;for(let n of PH)for(let r of this.sequences)if(!(r.erroredOrDestroyed||!r.hooks[n]))try{r.pipelinedValue=this.ngZone.runOutsideAngular(()=>this.maybeTrace(()=>{let s=r.hooks[n];return s(r.pipelinedValue)},r.snapshot))}catch(s){r.erroredOrDestroyed=!0,this.errorHandler?.handleError(s)}this.executing=!1;for(let n of this.sequences)n.afterRun(),n.once&&(this.sequences.delete(n),n.destroy());for(let n of this.deferredRegistrations)this.sequences.add(n);this.deferredRegistrations.size>0&&this.scheduler.notify(7),this.deferredRegistrations.clear(),e&&kn(17)}register(e){let{view:n}=e;n!==void 0?((n[Dc]??(n[Dc]=[])).push(e),Vh(n),n[dt]|=8192):this.executing?this.deferredRegistrations.add(e):this.addSequence(e)}addSequence(e){this.sequences.add(e),this.scheduler.notify(7)}unregister(e){this.executing&&this.sequences.has(e)?(e.erroredOrDestroyed=!0,e.pipelinedValue=void 0,e.once=!0):(this.sequences.delete(e),this.deferredRegistrations.delete(e))}maybeTrace(e,n){return n?n.run(g0.AFTER_NEXT_RENDER,e):e()}};l(Xy,"\u0275prov",hn({token:Xy,providedIn:"root",factory:()=>new Xy}));var HS=Xy,jS=class{constructor(e,n,r,s,i,o=null){l(this,"impl");l(this,"hooks");l(this,"view");l(this,"once");l(this,"snapshot");l(this,"erroredOrDestroyed",!1);l(this,"pipelinedValue");l(this,"unregisterOnDestroy");this.impl=e,this.hooks=n,this.view=r,this.once=s,this.snapshot=o,this.unregisterOnDestroy=i?.onDestroy(()=>this.destroy())}afterRun(){this.erroredOrDestroyed=!1,this.pipelinedValue=void 0,this.snapshot?.dispose(),this.snapshot=null}destroy(){this.impl.unregister(this),this.unregisterOnDestroy?.();let e=this.view?.[Dc];e&&(this.view[Dc]=e.filter(n=>n!==this))}};function US(t,e){ngDevMode&&q0(US,"Call `afterRender` outside of a reactive context. For example, schedule the render callback inside the component constructor`."),!e?.injector&&us(US);let n=e?.injector??fe(Ln);return typeof ngServerMode<"u"&&ngServerMode?bM:(Ss("NgAfterRender"),NH(t,n,e,!1))}function yM(t,e){!e?.injector&&us(yM);let n=e?.injector??fe(Ln);return typeof ngServerMode<"u"&&ngServerMode?bM:(Ss("NgAfterNextRender"),NH(t,n,e,!0))}function Soe(t,e){if(t instanceof Function){let n=[void 0,void 0,void 0,void 0];return n[e]=t,n}else return[t.earlyRead,t.write,t.mixedReadWrite,t.read]}function NH(t,e,n,r){let s=e.get(Sh);s.impl??(s.impl=e.get(HS));let i=e.get(Fo,null,{optional:!0}),o=n?.phase??Ec.MixedReadWrite,a=n?.manualCleanup!==!0?e.get(Es):null,c=e.get(ud,null,{optional:!0}),u=new jS(s.impl,Soe(t,o),c?.view,r,a,i?.snapshot(null));return s.impl.register(u),u}var bM={destroy(){}},pr;(function(t){t[t.NOT_STARTED=0]="NOT_STARTED",t[t.IN_PROGRESS=1]="IN_PROGRESS",t[t.COMPLETE=2]="COMPLETE",t[t.FAILED=3]="FAILED"})(pr||(pr={}));var qS=0,RH=1,bn;(function(t){t[t.Placeholder=0]="Placeholder",t[t.Loading=1]="Loading",t[t.Complete=2]="Complete",t[t.Error=3]="Error"})(bn||(bn={}));var bd;(function(t){t[t.Initial=-1]="Initial"})(bd||(bd={}));var mh=0,wa=1,Ry=2,Zx=3,Coe=4,Toe=5,Ch=6,Doe=7,gh=8,_oe=9,WS;(function(t){t[t.Manual=0]="Manual",t[t.Playthrough=1]="Playthrough"})(WS||(WS={}));function W0(t,e,n){let r=LH(t);e[r]===null&&(e[r]=[]),e[r].push(n)}function lS(t,e){let n=LH(t),r=e[n];if(r!==null){for(let s of r)s();e[n]=null}}function FH(t){lS(1,t),lS(0,t),lS(2,t)}function LH(t){let e=Coe;return t===1?e=Toe:t===2&&(e=_oe),e}function z0(t){return t+1}function Cs(t,e){let n=t[de],r=z0(e.index);return ngDevMode&&$0(n,r),t[r]}function Ioe(t,e,n){let r=t[de],s=z0(e);ngDevMode&&$0(r,s),t[s]=n}function Qr(t,e){let n=z0(e.index);return ngDevMode&&$0(t,n),t.data[n]}function koe(t,e,n){let r=z0(e);ngDevMode&&$0(t,r),t.data[r]=n}function Aoe(t,e,n){let r=e[de],s=Qr(r,n);switch(t){case bn.Complete:return s.primaryTmplIndex;case bn.Loading:return s.loadingTmplIndex;case bn.Error:return s.errorTmplIndex;case bn.Placeholder:return s.placeholderTmplIndex;default:return ngDevMode&&tt(`Unexpected defer block state: ${t}`),null}}function Jk(t,e){return e===bn.Placeholder?t.placeholderBlockConfig?.[qS]??null:e===bn.Loading?t.loadingBlockConfig?.[qS]??null:null}function OH(t){return t.loadingBlockConfig?.[RH]??null}function g8(t,e){if(!t||t.length===0)return e;let n=new Set(t);for(let r of e)n.add(r);return t.length===n.size?t:Array.from(n)}function Moe(t,e){let n=e.primaryTmplIndex+He;return Pd(t,n)}function BH(t){rt(t.loadingState,pr.COMPLETE,"Expecting all deferred dependencies to be loaded.")}function $H(t){return t!==null&&typeof t=="object"&&typeof t.primaryTmplIndex=="number"}function Poe(t,e){let n=null,r=z0(e.index);return He{for(let e of this.callbacks)e()})}};function VH(t,e){let n=ek.get(t);if(!n){n=new v0,ek.set(t,n);for(let r of GS)t.addEventListener(r,n.listener,zS)}return n.callbacks.add(e),()=>{let{callbacks:r,listener:s}=n;if(r.delete(e),r.size===0){ek.delete(t);for(let i of GS)t.removeEventListener(i,s,zS)}}}function HH(t,e){let n=JI.get(t);if(!n){n=new v0,JI.set(t,n);for(let r of ZS)t.addEventListener(r,n.listener,zS)}return n.callbacks.add(e),()=>{let{callbacks:r,listener:s}=n;if(r.delete(e),r.size===0){for(let i of ZS)t.removeEventListener(i,s,zS);JI.delete(t)}}}function wM(t,e,n){let r=n.get(qt),s=Kf.get(t);return Jf=Jf||r.runOutsideAngular(()=>new IntersectionObserver(i=>{for(let o of i)o.isIntersecting&&Kf.has(o.target)&&r.run(Kf.get(o.target).listener)})),s||(s=new v0,r.runOutsideAngular(()=>Jf.observe(t)),Kf.set(t,s),tk++),s.callbacks.add(e),()=>{Kf.has(t)&&(s.callbacks.delete(e),s.callbacks.size===0&&(Jf?.unobserve(t),Kf.delete(t),tk--),tk===0&&(Jf?.disconnect(),Jf=null))}}function Noe(t,e,n){if(n==null)return t;if(n>=0)return w5(n,t);let r=t[e.index];ngDevMode&&oo(r);let s=r[Wn]??null;if(ngDevMode&&s!==null){let o=Cs(t,e)[wa];rt(o,bn.Placeholder,"Expected a placeholder to be rendered in this defer block."),ui(s)}return s}function Roe(t,e){let n=$h(He+e,t);return ngDevMode&&fse(n),n}function Uh(t,e,n,r,s,i,o){let a=t[or],c=a.get(qt),u;function d(){if(ul(t)){u.destroy();return}let p=Cs(t,e),f=p[wa];if(f!==bd.Initial&&f!==bn.Placeholder){u.destroy();return}let h=Noe(t,e,r);if(!h||(u.destroy(),ul(h)))return;let m=Roe(h,n),g=s(m,()=>{c.run(()=>{t!==h&&VA(h,g),i()})},a);t!==h&&zC(h,g),W0(o,p,g)}u=US({read:d},{injector:a})}var G0="ngb";function jH(t,e,n=null){if(e.length===0||t.nodeType!==Node.ELEMENT_NODE)return;let r=t.getAttribute(_y.JSACTION),s=e.reduce((o,a)=>(r?.indexOf(a)??-1)===-1?o+a+":;":o,"");t.setAttribute(_y.JSACTION,`${r??""}${s}`);let i=n??"";i!==""&&s.length>0&&t.setAttribute(G0,i)}var Foe=(t,e,n)=>{let r=t,s=r.__jsaction_fns??new Map,i=s.get(e)??[];i.push(n),s.set(e,i),r.__jsaction_fns=s},UH=(t,e)=>{let n=t,r=n.getAttribute(G0)??"",s=e.get(r)??new Set;s.has(n)||s.add(n),e.set(r,s)};function Loe(t,e){if(t.length>0){let n=[];for(let s of t)e.has(s)&&(n=[...n,...e.get(s)]);new Set(n).forEach(qH)}}var qH=t=>{t.removeAttribute(_y.JSACTION),t.removeAttribute(G0),t.__jsaction_fns=void 0},EM=new $e(ngDevMode?"EVENT_CONTRACT_DETAILS":"",{providedIn:"root",factory:()=>({})});function WH(t,e){let n=e?.__jsaction_fns?.get(t.type);if(!(!n||!e?.isConnected))for(let r of n)r(t)}var e2=new Map;function Ooe(t,e){return e2.set(t,e),()=>e2.delete(t)}var v8=!1,zH=(t,e,n,r)=>{};function Boe(t,e,n,r){zH(t,e,n,r)}function $oe(){v8||(zH=(t,e,n,r)=>{let s=t[or].get(Ii);e2.get(s)?.(e,n,r)},v8=!0)}var Da=new $e(ngDevMode?"DEHYDRATED_BLOCK_REGISTRY":""),Qy=class Qy{constructor(){l(this,"registry",new Map);l(this,"cleanupFns",new Map);l(this,"jsActionMap",fe(m0));l(this,"contract",fe(EM));l(this,"hydrating",new Map);l(this,"awaitingCallbacks",new Map)}add(e,n){if(this.registry.set(e,n),this.awaitingCallbacks.has(e)){let r=this.awaitingCallbacks.get(e);for(let s of r)s()}}get(e){return this.registry.get(e)??null}has(e){return this.registry.has(e)}cleanup(e){Loe(e,this.jsActionMap);for(let n of e)this.registry.delete(n),this.jsActionMap.delete(n),this.invokeTriggerCleanupFns(n),this.hydrating.delete(n),this.awaitingCallbacks.delete(n);this.size===0&&this.contract.instance?.cleanUp()}get size(){return this.registry.size}addCleanupFn(e,n){let r=[];this.cleanupFns.has(e)&&(r=this.cleanupFns.get(e)),r.push(n),this.cleanupFns.set(e,r)}invokeTriggerCleanupFns(e){let n=this.cleanupFns.get(e)??[];for(let r of n)r();this.cleanupFns.delete(e)}awaitParentBlock(e,n){let r=this.awaitingCallbacks.get(e)??[];r.push(n),this.awaitingCallbacks.set(e,r)}};l(Qy,"\u0275prov",hn({token:Qy,providedIn:null,factory:()=>new Qy}));var t2=Qy,Voe="__nghData__",xM=Voe,Hoe="__nghDeferData__",nT=Hoe,By="ngh",GH="nghm",ZH=()=>null;function joe(t,e,n=!1){let r=t.getAttribute(By);if(r==null)return null;let[s,i]=r.split("|");if(r=n?i:s,!r)return null;let o=i?`|${i}`:"",a=n?s:o,c={};if(r!==""){let d=e.get(ba,null,{optional:!0});d!==null&&(c=d.get(xM,[])[Number(r)],ngDevMode&&Fe(c,"Unable to retrieve hydration info from the TransferState."))}let u={data:c,firstChild:t.firstChild??null};return n&&(u.firstChild=t,rT(u,0,t.nextSibling)),a?t.setAttribute(By,a):t.removeAttribute(By),ngDevMode&&Bd(t,!1),ngDevMode&&ngDevMode.hydratedComponents++,u}function Uoe(){ZH=joe}function YH(t,e,n=!1){return ZH(t,e,n)}function XH(t){let e=t._lView;return e[de].type===2?null:(cl(e)&&(e=e[He]),e)}function qoe(t){return t.textContent?.replace(/\s/gm,"")}function Woe(t){let e=No(),n=e.createNodeIterator(t,NodeFilter.SHOW_COMMENT,{acceptNode(i){let o=qoe(i);return o==="ngetn"||o==="ngtns"?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}),r,s=[];for(;r=n.nextNode();)s.push(r);for(let i of s)i.textContent==="ngetn"?i.replaceWith(e.createTextNode("")):i.remove()}var wd;(function(t){t.Hydrated="hydrated",t.Skipped="skipped",t.Mismatched="mismatched"})(wd||(wd={}));var QH="__ngDebugHydrationInfo__";function SM(t,e){t[QH]=e}function KH(t){return t[QH]??null}function Bd(t,e=!0){if(!ngDevMode)throw new Error("Calling `markRNodeAsClaimedByHydration` in prod mode is not supported and likely a mistake.");if(e&&Zoe(t))throw new Error("Trying to claim a node, which was claimed already.");SM(t,{status:wd.Hydrated}),ngDevMode.hydratedNodes++}function zoe(t){if(!ngDevMode)throw new Error("Calling `markRNodeAsSkippedByHydration` in prod mode is not supported and likely a mistake.");SM(t,{status:wd.Skipped}),ngDevMode.componentsSkippedHydration++}function Goe(t){let n=t.get(ba).get(nT,{});ngDevMode&&(ngDevMode.deferBlocksWithIncrementalHydration=Object.keys(n).length)}function y0(t,e=null,n=null){if(!ngDevMode)throw new Error("Calling `markRNodeAsMismatchedByHydration` in prod mode is not supported and likely a mistake.");for(;t&&!$S(t);)t=t?.parentNode;t&&SM(t,{status:wd.Mismatched,expectedNodeDetails:e,actualNodeDetails:n})}function Zoe(t){return KH(t)?.status===wd.Hydrated}function rT(t,e,n){t.segmentHeads??(t.segmentHeads={}),t.segmentHeads[e]=n}function n2(t,e){return t.segmentHeads?.[e]??null}function Z0(t){return t.get(vM,!1,{optional:!0})}function Yoe(t){if(!Z0(t))throw new ne(508,"Angular has detected that some `@defer` blocks use `hydrate` triggers, but incremental hydration was not enabled. Please ensure that the `withIncrementalHydration()` call is added as an argument for the `provideClientHydration()` function call in your application config.")}function CM(t){Fe(t,"Internal error: expecting an SSR id for a defer block that should be hydrated, but the id is not present")}function JH(t,e){let n=t.data,r=n[ah]?.[e]??null;return r===null&&n[od]?.[e]&&(r=TM(t,e)),r}function Xoe(t,e){return t.data[ah]?.[e]!==void 0}function e3(t,e){return t.data[od]?.[e]??null}function TM(t,e){let n=e3(t,e)??[],r=0;for(let s of n)r+=s[_c]*(s[lh]??1);return r}function t3(t){if(typeof t.disconnectedNodes>"u"){let e=t.data[qu];t.disconnectedNodes=e?new Set(e):null}return t.disconnectedNodes}function $d(t,e){if(typeof t.disconnectedNodes>"u"){let n=t.data[qu];t.disconnectedNodes=n?new Set(n):null}return!!t3(t)?.has(e)}function n3(t,e){let n=e,r=t.corruptedTextNodes;n.textContent===""?r.set(n,"ngetn"):n.nextSibling?.nodeType===Node.TEXT_NODE&&r.set(n,"ngtns")}function Qoe(t){let e=[];return t!==null&&(t.has(4)&&e.push(...ZS),t.has(3)&&e.push(...GS)),e}function Koe(t,e){let n=e.get(Da),s=e.get(ba).get(nT,{}),i=!1,o=t,a=null,c=[];for(;!i&&o;){ngDevMode&&rt(c.indexOf(o),-1,"Internal error: defer block hierarchy has a cycle."),i=n.has(o);let u=n.hydrating.get(o);if(a===null&&u!=null){a=u.promise;break}c.unshift(o),o=s[o][_H]}return{parentBlockPromise:a,hydrationQueue:c}}function Joe(t){let e=t.body.querySelectorAll("[jsaction]"),n=new Set,r=[ZS.join(":;"),GS.join(":;")].join("|");for(let s of e){let i=s.getAttribute("jsaction"),o=s.getAttribute("ngb");i?.match(r)&&o!==null&&n.add(s)}return n}function eae(t,e){let n=Joe(t),r=e.get(m0);for(let s of n)UH(s,r)}var r3=()=>({});function tae(t){let e=t.get(ba,null,{optional:!0});if(e!==null){let n=e.get(nT,{});return ngDevMode&&Fe(n,"Unable to retrieve defer block info from the TransferState."),n}return{}}function nae(){r3=tae}function rae(t){return r3(t)}function sae(t){return typeof t=="object"&&t.trigger===5}function iae(t){return t[mM]?.find(n=>sae(n))?.delay??null}function nk(t,e){return t[mM]?.includes(e)??!1}function oae(t){return{data:t,hydrate:{idle:nk(t,0),immediate:nk(t,1),timer:iae(t),viewport:nk(t,2)}}}function aae(t){let e=rae(t),n=new Map;for(let r in e)n.set(r,oae(e[r]));return n}function rk(t){return!!t&&t.nodeType===Node.COMMENT_NODE&&t.textContent?.trim()===GH}function y8(t){for(;t&&t.nodeType===Node.TEXT_NODE;)t=t.previousSibling;return t}function lae(t){for(let r of t.body.childNodes)if(rk(r))return;let e=y8(t.body.previousSibling);if(rk(e))return;let n=y8(t.head.lastChild);if(!rk(n))throw new ne(-507,typeof ngDevMode<"u"&&ngDevMode&&"Angular hydration logic detected that HTML content of this page was modified after it was produced during server side rendering. Make sure that there are no optimizations that remove comment nodes from HTML enabled on your CDN. Angular hydration relies on HTML produced by the server, including whitespaces and comment nodes.")}function s3(t,e){let n=t.contentQueries;if(n!==null){let r=Et(null);try{for(let s=0;s-1&&!customElements.get(n))&&!kM(r,n)){let o=iT(e),a=b0(e),c=`'${o?"@Component":"@NgModule"}.schemas'`,u=`'${n}' is not a known element${a}: +`;if(u+=`1. If '${n}' is an Angular component, then verify that it is ${o?"included in the '@Component.imports' of this component":"a part of an @NgModule where this component is declared"}. +`,n&&n.indexOf("-")>-1?u+=`2. If '${n}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the ${c} of this component to suppress this message.`:u+=`2. To allow any element add 'NO_ERRORS_SCHEMA' to the ${c} of this component.`,_M)throw new ne(304,u);console.error(gn(304,u))}}function hae(t,e,n,r){return r===null||kM(r,n)||e in t||H5(e)?!0:typeof Node>"u"||Node===null||!(t instanceof Node)}function b8(t,e,n,r){!e&&n===4&&(e="ng-template");let s=iT(r),i=b0(r),o=`Can't bind to '${t}' since it isn't a known property of '${e}'${i}.`,a=`'${s?"@Component":"@NgModule"}.schemas'`,c=s?"included in the '@Component.imports' of this component":"a part of an @NgModule where this component is declared";if(w8.has(t)){let u=w8.get(t);o+=` +If the '${t}' is an Angular control flow directive, please make sure that either the '${u}' directive or the 'CommonModule' is ${c}.`}else o+=` +1. If '${e}' is an Angular component and it has the '${t}' input, then verify that it is ${c}.`,e&&e.indexOf("-")>-1?(o+=` +2. If '${e}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the ${a} of this component to suppress this message.`,o+=` +3. To allow any property add 'NO_ERRORS_SCHEMA' to the ${a} of this component.`):o+=` +2. To allow any property add 'NO_ERRORS_SCHEMA' to the ${a} of this component.`;a3(o)}function a3(t){if(IM)throw new ne(303,t);console.error(gn(303,t))}function sT(t){!ngDevMode&&tt("Must never be called in production mode");let n=t[Kn][wn];return n&&n.constructor?Ut(n.constructor):null}function iT(t){return!ngDevMode&&tt("Must never be called in production mode"),!!sT(t)?.standalone}function b0(t){!ngDevMode&&tt("Must never be called in production mode");let n=sT(t)?.type?.name;return n?` (used in the '${n}' component template)`:""}var w8=new Map([["ngIf","NgIf"],["ngFor","NgFor"],["ngSwitchCase","NgSwitchCase"],["ngSwitchDefault","NgSwitchDefault"]]);function kM(t,e){if(t!==null)for(let n=0;n-1)return!0}return!1}var Yx;function l3(){if(Yx===void 0&&(Yx=null,Yn.trustedTypes))try{Yx=Yn.trustedTypes.createPolicy("angular",{createHTML:t=>t,createScript:t=>t,createScriptURL:t=>t})}catch{}return Yx}function qh(t){return l3()?.createHTML(t)||t}function mae(t){return l3()?.createScriptURL(t)||t}var Xx;function AM(){if(Xx===void 0&&(Xx=null,Yn.trustedTypes))try{Xx=Yn.trustedTypes.createPolicy("angular#unsafe-bypass",{createHTML:t=>t,createScript:t=>t,createScriptURL:t=>t})}catch{}return Xx}function E8(t){return AM()?.createHTML(t)||t}function x8(t){return AM()?.createScript(t)||t}function S8(t){return AM()?.createScriptURL(t)||t}var hl=class{constructor(e){l(this,"changingThisBreaksApplicationSecurity");this.changingThisBreaksApplicationSecurity=e}toString(){return`SafeValue must use [property]=binding: ${this.changingThisBreaksApplicationSecurity} (see ${Ji})`}},s2=class extends hl{getTypeName(){return"HTML"}},i2=class extends hl{getTypeName(){return"Style"}},o2=class extends hl{getTypeName(){return"Script"}},a2=class extends hl{getTypeName(){return"URL"}},l2=class extends hl{getTypeName(){return"ResourceURL"}};function ds(t){return t instanceof hl?t.changingThisBreaksApplicationSecurity:t}function lo(t,e){let n=c3(t);if(n!=null&&n!==e){if(n==="ResourceURL"&&e==="URL")return!0;throw new Error(`Required a safe ${e}, got a ${n} (see ${Ji})`)}return n===e}function c3(t){return t instanceof hl&&t.getTypeName()||null}function MM(t){return new s2(t)}function PM(t){return new i2(t)}function NM(t){return new o2(t)}function RM(t){return new a2(t)}function FM(t){return new l2(t)}function u3(t){let e=new u2(t);return gae()?new c2(e):e}var c2=class{constructor(e){l(this,"inertDocumentHelper");this.inertDocumentHelper=e}getInertBodyElement(e){e=""+e;try{let n=new window.DOMParser().parseFromString(qh(e),"text/html").body;return n===null?this.inertDocumentHelper.getInertBodyElement(e):(n.firstChild?.remove(),n)}catch{return null}}},u2=class{constructor(e){l(this,"defaultDoc");l(this,"inertDocument");this.defaultDoc=e,this.inertDocument=this.defaultDoc.implementation.createHTMLDocument("sanitization-inert")}getInertBodyElement(e){let n=this.inertDocument.createElement("template");return n.innerHTML=qh(e),n}};function gae(){try{return!!new window.DOMParser().parseFromString(qh(""),"text/html")}catch{return!1}}var vae=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:\/?#]*(?:[\/?#]|$))/i;function Wh(t){return t=String(t),t.match(vae)?t:((typeof ngDevMode>"u"||ngDevMode)&&console.warn(`WARNING: sanitizing unsafe URL value ${t} (see ${Ji})`),"unsafe:"+t)}function El(t){let e={};for(let n of t.split(","))e[n]=!0;return e}function Y0(...t){let e={};for(let n of t)for(let r in n)n.hasOwnProperty(r)&&(e[r]=!0);return e}var d3=El("area,br,col,hr,img,wbr"),p3=El("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),f3=El("rp,rt"),yae=Y0(f3,p3),bae=Y0(p3,El("address,article,aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul")),wae=Y0(f3,El("a,abbr,acronym,audio,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video")),d2=Y0(d3,bae,wae,yae),h3=El("background,cite,href,itemtype,longdesc,poster,src,xlink:href"),Eae=El("abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,scope,scrolling,shape,size,sizes,span,srclang,srcset,start,summary,tabindex,target,title,translate,type,usemap,valign,value,vspace,width"),xae=El("aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext"),p2=Y0(h3,Eae,xae),Sae=El("script,style,template"),f2=class{constructor(){l(this,"sanitizedSomething",!1);l(this,"buf",[])}sanitizeChildren(e){let n=e.firstChild,r=!0,s=[];for(;n;){if(n.nodeType===Node.ELEMENT_NODE?r=this.startElement(n):n.nodeType===Node.TEXT_NODE?this.chars(n.nodeValue):this.sanitizedSomething=!0,r&&n.firstChild){s.push(n),n=Dae(n);continue}for(;n;){n.nodeType===Node.ELEMENT_NODE&&this.endElement(n);let i=Tae(n);if(i){n=i;break}n=s.pop()}}return this.buf.join("")}startElement(e){let n=C8(e).toLowerCase();if(!d2.hasOwnProperty(n))return this.sanitizedSomething=!0,!Sae.hasOwnProperty(n);this.buf.push("<"),this.buf.push(n);let r=e.attributes;for(let s=0;s"),!0}endElement(e){let n=C8(e).toLowerCase();d2.hasOwnProperty(n)&&!d3.hasOwnProperty(n)&&(this.buf.push(""))}chars(e){this.buf.push(T8(e))}};function Cae(t,e){return(t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_CONTAINED_BY)!==Node.DOCUMENT_POSITION_CONTAINED_BY}function Tae(t){let e=t.nextSibling;if(e&&t!==e.previousSibling)throw m3(e);return e}function Dae(t){let e=t.firstChild;if(e&&Cae(t,e))throw m3(e);return e}function C8(t){let e=t.nodeName;return typeof e=="string"?e:"FORM"}function m3(t){return new Error(`Failed to sanitize html because the element is clobbered: ${t.outerHTML}`)}var _ae=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,Iae=/([^\#-~ |!])/g;function T8(t){return t.replace(/&/g,"&").replace(_ae,function(e){let n=e.charCodeAt(0),r=e.charCodeAt(1);return"&#"+((n-55296)*1024+(r-56320)+65536)+";"}).replace(Iae,function(e){return"&#"+e.charCodeAt(0)+";"}).replace(//g,">")}var Qx;function oT(t,e){let n=null;try{Qx=Qx||u3(t);let r=e?String(e):"";n=Qx.getInertBodyElement(r);let s=5,i=r;do{if(s===0)throw new Error("Failed to sanitize html because the input is unstable");s--,r=i,i=n.innerHTML,n=Qx.getInertBodyElement(r)}while(r!==i);let o=new f2,a=o.sanitizeChildren(h2(n)||n);return(typeof ngDevMode>"u"||ngDevMode)&&o.sanitizedSomething&&console.warn(`WARNING: sanitizing HTML stripped some content, see ${Ji}`),qh(a)}finally{if(n){let r=h2(n)||n;for(;r.firstChild;)r.firstChild.remove()}}}function h2(t){return"content"in t&&kae(t)?t.content:null}function kae(t){return t.nodeType===Node.ELEMENT_NODE&&t.nodeName==="TEMPLATE"}var Aae=/^>|^->||--!>|)/g,Pae="\u200B$1\u200B";function g3(t){return t.replace(Aae,e=>e.replace(Mae,Pae))}function LM(t,e){return ngDevMode&&ngDevMode.rendererCreateTextNode++,ngDevMode&&ngDevMode.rendererSetText++,t.createText(e)}function v3(t,e,n){ngDevMode&&ngDevMode.rendererSetText++,t.setValue(e,n)}function OM(t,e){return ngDevMode&&ngDevMode.rendererCreateComment++,t.createComment(g3(e))}function aT(t,e,n){return ngDevMode&&ngDevMode.rendererCreateElement++,t.createElement(e,n)}function Ed(t,e,n,r,s){ngDevMode&&ngDevMode.rendererInsertBefore++,t.insertBefore(e,n,r,s)}function y3(t,e,n){ngDevMode&&ngDevMode.rendererAppendChild++,ngDevMode&&Fe(e,"parent node must be defined"),t.appendChild(e,n)}function D8(t,e,n,r,s){r!==null?Ed(t,e,n,r,s):y3(t,e,n)}function X0(t,e,n){ngDevMode&&ngDevMode.rendererRemoveNode++,t.removeChild(null,e,n)}function b3(t){t.textContent=""}function Nae(t,e,n){ngDevMode&&Lh(n,"'newValue' should be a string"),t.setAttribute(e,"style",n),ngDevMode&&ngDevMode.rendererSetStyle++}function Rae(t,e,n){ngDevMode&&Lh(n,"'newValue' should be a string"),n===""?t.removeAttribute(e,"class"):t.setAttribute(e,"class",n),ngDevMode&&ngDevMode.rendererSetClassName++}function w3(t,e,n){let{mergedAttrs:r,classes:s,styles:i}=n;r!==null&&Sie(t,e,r),s!==null&&Rae(t,e,s),i!==null&&Nae(t,e,i)}function Fae(t){let e=re();t.src="",t.srcdoc=qh(""),X0(e[pt],t)}var In;(function(t){t[t.NONE=0]="NONE",t[t.HTML=1]="HTML",t[t.STYLE=2]="STYLE",t[t.SCRIPT=3]="SCRIPT",t[t.URL=4]="URL",t[t.RESOURCE_URL=5]="RESOURCE_URL",t[t.ATTRIBUTE_NO_BINDING=6]="ATTRIBUTE_NO_BINDING"})(In||(In={}));var cS,_8="svg",Lae="math";function Oae(){return cS||(cS={},vc(In.HTML,void 0,[["iframe",["srcdoc"]],["*",["innerHTML","outerHTML"]]]),vc(In.STYLE,void 0,[["*",["style"]]]),vc(In.URL,void 0,[["*",["formAction"]],["area",["href"]],["a",["href","xlink:href"]],["form",["action"]],["img",["src"]],["video",["src"]]]),vc(In.URL,Lae,[["annotation",["href","xlink:href"]],["annotation-xml",["href","xlink:href"]],["maction",["href","xlink:href"]],["malignmark",["href","xlink:href"]],["math",["href","xlink:href"]],["mroot",["href","xlink:href"]],["msqrt",["href","xlink:href"]],["merror",["href","xlink:href"]],["mfrac",["href","xlink:href"]],["mglyph",["href","xlink:href"]],["msub",["href","xlink:href"]],["msup",["href","xlink:href"]],["msubsup",["href","xlink:href"]],["mmultiscripts",["href","xlink:href"]],["mprescripts",["href","xlink:href"]],["mi",["href","xlink:href"]],["mn",["href","xlink:href"]],["mo",["href","xlink:href"]],["mpadded",["href","xlink:href"]],["mphantom",["href","xlink:href"]],["mrow",["href","xlink:href"]],["ms",["href","xlink:href"]],["mspace",["href","xlink:href"]],["mstyle",["href","xlink:href"]],["mtable",["href","xlink:href"]],["mtd",["href","xlink:href"]],["mtr",["href","xlink:href"]],["mtext",["href","xlink:href"]],["mover",["href","xlink:href"]],["munder",["href","xlink:href"]],["munderover",["href","xlink:href"]],["semantics",["href","xlink:href"]],["none",["href","xlink:href"]]]),vc(In.RESOURCE_URL,void 0,[["base",["href"]],["embed",["src"]],["frame",["src"]],["iframe",["src"]],["link",["href"]],["object",["codebase","data"]]]),vc(In.URL,_8,[["a",["href","xlink:href"]]]),vc(In.ATTRIBUTE_NO_BINDING,_8,[["animate",["attributeName","values","to","from"]],["set",["to","attributeName"]],["animateMotion",["attributeName"]],["animateTransform",["attributeName"]]]),vc(In.ATTRIBUTE_NO_BINDING,void 0,[["unknown",["attributeName","values","to","from","sandbox","allow","allowFullscreen","referrerPolicy","csp","fetchPriority"]],["iframe",["sandbox","allow","allowFullscreen","referrerPolicy","csp","fetchPriority"]]])),cS}function vc(t,e,n){for(let[r,s]of n){let i=e&&r!=="*"&&r!=="unknown"?`:${e}:${r}`:r;i=i.toLowerCase();for(let o of s)cS[`${i}|${o.toLowerCase()}`]=t}}function BM(t){let e=Q0();return e?E8(e.sanitize(In.HTML,t)||""):lo(t,"HTML")?E8(ds(t)):oT(No(),Mt(t))}function $M(t){let e=Q0();return e?e.sanitize(In.STYLE,t)||"":lo(t,"Style")?ds(t):Mt(t)}function VM(t){let e=Q0();return e?e.sanitize(In.URL,t)||"":lo(t,"URL")?ds(t):Wh(Mt(t))}function lT(t){let e=Q0();if(e)return S8(e.sanitize(In.RESOURCE_URL,t)||"");if(lo(t,"ResourceURL"))return S8(ds(t));throw new ne(904,ngDevMode&&`unsafe value used in a resource URL context (see ${Ji})`)}function HM(t){let e=Q0();if(e)return x8(e.sanitize(In.SCRIPT,t)||"");if(lo(t,"Script"))return x8(ds(t));throw new ne(905,ngDevMode&&"unsafe value used in a script context")}function E3(t){if(ngDevMode&&(!Array.isArray(t)||!Array.isArray(t.raw)||t.length!==1))throw new Error(`Unexpected interpolation in trusted HTML constant: ${t.join("?")}`);return qh(t[0])}function x3(t){if(ngDevMode&&(!Array.isArray(t)||!Array.isArray(t.raw)||t.length!==1))throw new Error(`Unexpected interpolation in trusted URL constant: ${t.join("?")}`);return mae(t[0])}var Bae={embed:{src:!0},frame:{src:!0},iframe:{src:!0},media:{src:!0},base:{href:!0},link:{href:!0},object:{data:!0,codebase:!0}};function $ae(t,e){return Bae[t.toLowerCase()]?.[e.toLowerCase()]===!0?lT:VM}function S3(t,e,n){return $ae(e,n)(t)}function Vae(t){if(t.toLowerCase().startsWith("on")){let e=`Binding to event property '${t}' is disallowed for security reasons, please use (${t.slice(2)})=... +If '${t}' is a directive input, make sure the directive is imported by the current module.`;throw new ne(306,e)}}function Hae(t){if(t.toLowerCase().startsWith("on"))throw new ne(306,ngDevMode&&`Binding to event attribute '${t}' is disallowed for security reasons, please use (${t.slice(2)})=...`)}function Q0(){let t=re();return t&&t[ko].sanitizer}var Kx=new Set(["href","xlink:href"]),jae={iframe:{sandbox:!0,allow:!0,allowfullscreen:!0,referrerpolicy:!0,csp:!0,fetchpriority:!0},":svg:animate":{attributename:!0,to:Kx,values:Kx,from:Kx},":svg:set":{attributename:!0,to:Kx},":svg:animatemotion":{attributename:!0},":svg:animatetransform":{attributename:!0}};function jM(t,e,n){let r=e.toLowerCase(),s=n.toLowerCase(),o=Vr()===-1?null:Hn();if(o&&o.type!==2)return t;let a=r[0]!==":"&&o?.namespace?`:${o.namespace}:${r}`:r,c=jae[a]?.[s];if(!c)return t;let u=re();if(o&&r==="iframe"){let f=xs(o,u);Fae(f)}let d=e[0]===":"?e.split(":").pop():e;if(typeof c!="boolean"){if(!o){let m=ngDevMode&&`Angular has detected that the \`${n}\` was applied as a binding to the <${e}> element. For security reasons, the \`${n}\` can be set on the <${e}> element as a static attribute only. +To fix this, switch the \`${n}\` binding to a static attribute in a template or in host bindings section.`;throw new ne(-910,m)}let h=xs(o,u).getAttribute("attributeName");if(h&&c.has(h.toLowerCase())){let m=ngDevMode&&`Angular has detected that the \`${n}\` was applied as a binding to the <${d}> element${b0(u)}. For security reasons, the \`${n}\` can be set on the <${d}> element as a static attribute only when the "attributeName" is set to '${h}'. +To fix this, switch the \`${h}\` binding to a static attribute in a template or in host bindings section.`;throw new ne(-910,m)}return t}let p=ngDevMode&&`Angular has detected that the \`${n}\` was applied as a binding to the <${d}> element${o?b0(u):""}. For security reasons, the \`${n}\` can be set on the <${d}> element as a static attribute only. +To fix this, switch the \`${n}\` binding to a static attribute in a template or in host bindings section.`;throw new ne(-910,p)}function Uae(t){return t=Wae(t.replace(/[$@]/g,"_")),`ng-reflect-${t}`}var qae=/([A-Z])/g;function Wae(t){return t.replace(qae,(...e)=>"-"+e[1].toLowerCase())}function zae(t){try{return t!=null?t.toString().slice(0,30):t}catch{return"[ERROR] Exception while trying to serialize the value"}}function C3(t){return t.ownerDocument.defaultView}function T3(t){return t.ownerDocument}function UM(t){return t.ownerDocument.body}var Th="\uFFFD";function ha(t){return t instanceof Function?t():t}var I8=200;function Gae(t){if(cT(t),!Ut(t).standalone)throw new ne(907,`The ${Xt(t)} component is not marked as standalone, but Angular expects to have a standalone component here. Please make sure the ${Xt(t)} component has the \`standalone: true\` flag in the decorator.`)}function cT(t){if(!Ut(t))throw new ne(906,`The ${Xt(t)} is not an Angular component, make sure it has the \`@Component\` decorator.`)}function Zae(t,e,n){throw new ne(-300,`Multiple components match node with tagname ${t.value}: ${Xt(e)} and ${Xt(n)}`)}function Yae(t,e,n,r,s){let o=sT(s)?.type?.name,c=`ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${r?` for '${r}'`:""}: '${k8(e)}'. Current value: '${k8(n)}'.${o?` Expression location: ${o} component`:""}`;throw t&&(c+=" It seems like the view has been created after its parent and its children have been dirty checked. Has it been created in a change detection hook?"),new ne(-100,c)}function k8(t){let e=String(t);try{(Array.isArray(t)||e==="[object Object]")&&(e=JSON.stringify(t))}catch{}return e.length>I8?e.substring(0,I8)+"\u2026":e}function A8(t,e,n,r,s){let[i,o,...a]=r.split(Th),c=o,u=o;for(let d=0;d-1?A8(t,e,e,i,r):{propName:i,oldValue:n,newValue:r};if(i===null){let o=e-1;for(;typeof s[o]!="string"&&s[o+1]===null;)o--;let a=s[o];if(typeof a=="string"){let c=a.match(new RegExp(Th,"g"));if(c&&c.length-1>e-o)return A8(t,o,e,a,r)}}return{propName:void 0,oldValue:n,newValue:r}}function Qae(t,e,n){ngDevMode&&di(e,"",'can not look for "" string.');let r=t.length;for(;;){let s=t.indexOf(e,n);if(s===-1)return s;if(s===0||t.charCodeAt(s-1)<=32){let i=e.length;if(s+i===r||t.charCodeAt(s+i)<=32)return s}n=s+1}}var D3="ng-template";function Kae(t,e,n,r){ngDevMode&&rt(n,n.toLowerCase(),"Class name expected to be lowercase.");let s=0;if(r){for(;s-1){let i;for(;++si?p="":(ngDevMode&&di(s[d],0,"We do not match directives on namespaced attributes"),p=s[d+1].toLowerCase()),r&2&&u!==p){if(Io(r))return!1;o=!0}}}}return Io(r)||o}function Io(t){return(t&1)===0}function tle(t,e,n,r){if(e===null)return-1;let s=0;if(r||!n){let i=!1;for(;s-1)for(n++;n0?'="'+a+'"':"")+"]"}else r&8?s+="."+o:r&4&&(s+=" "+o);else s!==""&&!Io(o)&&(e+=M8(i,s),s=""),r=o,i=i||!Io(r);n++}return s!==""&&(e+=M8(i,s)),e}function I3(t){return t.map(ole).join(",")}function ale(t){let e=[],n=[],r=1,s=2;for(;r"u"||ngDevMode?{__brand__:"NO_CHANGE"}:{};function WM(t,e,n,r,s,i,o,a,c,u,d){ngDevMode&&ngDevMode.tView++;let p=He+r,f=p+s,h=lle(p,f),m=typeof u=="function"?u():u,g=h[de]={type:t,blueprint:h,template:n,queries:null,viewQuery:a,declTNode:e,data:h.slice().fill(null,p),bindingStartIndex:p,expandoStartIndex:f,hostBindingOpCodes:null,firstCreatePass:!0,firstUpdatePass:!0,staticViewQueries:!1,staticContentQueries:!1,preOrderHooks:null,preOrderCheckHooks:null,contentHooks:null,contentCheckHooks:null,viewHooks:null,viewCheckHooks:null,destroyHooks:null,cleanup:null,contentQueries:null,components:null,directiveRegistry:typeof i=="function"?i():i,pipeRegistry:typeof o=="function"?o():o,firstChild:null,schemas:c,consts:m,incompleteFirstPass:!1,ssrId:d};return ngDevMode&&Object.seal(g),g}function lle(t,e){let n=[];for(let r=0;rHe&&M3(t,e,He,!!ngDevMode&&Fd()),kn(o?2:0,s),n(r,s)}finally{fl(i),kn(o?3:1,s)}}function dT(t,e,n){vle(t,e,n),(n.flags&64)===64&&yle(t,e,n)}function ZM(t,e,n=xs){let r=e.localNames;if(r!==null){let s=e.index+1;for(let i=0;i" tag is not allowed as a component host element.');return dle(o),o}function dle(t){N3(t)}var N3=()=>null;function ple(t){cH(t)?b3(t):Woe(t)}function fle(){N3=ple}function hle(t){return t==="class"?"className":t==="for"?"htmlFor":t==="formaction"?"formAction":t==="innerHtml"?"innerHTML":t==="readonly"?"readOnly":t==="tabindex"?"tabIndex":t}function fi(t,e,n,r,s,i,o,a){if(ngDevMode&&Oh(s,ct,"Incoming value should never be NO_CHANGE."),!a&&KM(e,t,n,r,s)){Ro(e)&&mle(n,e.index),ngDevMode&&gle(n,t,e,r,s);return}if(e.type&3){let c=xs(e,n);r=hle(r),ngDevMode&&(Vae(r),hae(c,r,e.value,t.schemas)||b8(r,e.value,e.type,n),ngDevMode.rendererSetProperty++),s=o!=null?o(s,e.value||"",r):s,i.setProperty(c,r,s)}else e.type&12&&ngDevMode&&!kM(t.schemas,e.value)&&b8(r,e.value,e.type,n)}function mle(t,e){ngDevMode&&ui(t);let n=Bs(e,t);n[dt]&16||(n[dt]|=64)}function g2(t,e,n,r){let s=xs(e,t),i=t[pt];n=Uae(n);let o=zae(r);if(e.type&3)r==null?i.removeAttribute(s,n):i.setAttribute(s,n,o);else{let a=g3(`bindings=${JSON.stringify({[n]:o},null,2)}`);i.setValue(s,a)}}function gle(t,e,n,r,s){if(!(n.type&7))return;let i=n.inputs?.[r],o=n.hostDirectiveInputs?.[r];if(o)for(let a=0;a0&&(o+=Th+s.join(Th)),t[r]=o}}function R3(t,e,n){return(t===null||Ns(t))&&(n=OA(n[e.index])),n[pt]}function QM(t,e){let n=t[or],r=n?n.get($s,null):null;r&&r.handleError(e)}function KM(t,e,n,r,s){let i=t.inputs?.[r],o=t.hostDirectiveInputs?.[r],a=!1;if(o)for(let c=0;c=0?r[a]():r[-a].unsubscribe(),o+=2}else{let a=r[n[o+1]];n[o].call(a)}r!==null&&(e[Cc]=null);let s=e[Tc];if(s!==null){e[Tc]=null;for(let o=0;o{Vh(t.lView)},consumerOnSignalRead(){this.lView[_i]=this}};function Rle(t){let e=t[_i]??Object.create(Fle);return e.lView=t,e}var Fle={...rl,consumerIsAlwaysLive:!0,kind:"template",consumerMarkedDirty:t=>{let e=pl(t.lView);for(;e&&!Z3(e[de]);)e=pl(e);e&&$A(e)},consumerOnSignalRead(){this.lView[_i]=this}};function Z3(t){return t.type!==2}function Y3(t){if(t[ol]===null)return;let e=!0;for(;e;){let n=!1;for(let r of t[ol])r.dirty&&(n=!0,r.zone===null||Zone.current===r.zone?r.run():r.zone.run(()=>r.run()));e=n&&!!(t[dt]&8192)}}var Lle=100;function hT(t,e=!0,n=0){let s=t[ko].rendererFactory,i=!!ngDevMode&&Fd();i||s.begin?.();try{Ole(t,n)}catch(o){throw e&&QM(t,o),o}finally{i||s.end?.()}}function Ole(t,e){let n=_5();try{if(PS(!0),w2(t,e),ngDevMode&&zA())return;let r=0;for(;H0(t);){if(r===Lle)throw new ne(103,ngDevMode&&"Infinite change detection while trying to refresh views. There may be components which each cause the other to require a refresh, causing an infinite loop.");r++,w2(t,1)}}finally{PS(n)}}function sP(t,e,n=!0){t8(e);try{hT(t,n)}finally{t8(Mc.Off)}}function X3(t,e,n,r){if(ngDevMode&&rt(V0(e),!1,"Should be run in update mode"),ul(e))return;let s=e[dt],i=ngDevMode&&Fd(),o=ngDevMode&&zA();YA(e);let a=!0,c=null,u=null;i||(Z3(t)?(u=Ale(e),c=sl(u)):xy()===null?(a=!1,u=Rle(e),c=sl(u)):e[_i]&&(Lu(e[_i]),e[_i]=null));try{b5(e),I5(t.bindingStartIndex),n!==null&&P3(t,e,n,2,r);let d=(s&3)===3;if(!i)if(d){let h=t.preOrderCheckHooks;h!==null&&iS(e,h,null)}else{let h=t.preOrderHooks;h!==null&&oS(e,h,0,null),QI(e,0)}if(o||Ble(e),Y3(e),Q3(e,0),t.contentQueries!==null&&s3(t,e),!i)if(d){let h=t.contentCheckHooks;h!==null&&iS(e,h)}else{let h=t.contentHooks;h!==null&&oS(e,h,1),QI(e,1)}Vle(t,e);let p=t.components;p!==null&&J3(e,p,0);let f=t.viewQuery;if(f!==null&&r2(2,f,r),!i)if(d){let h=t.viewCheckHooks;h!==null&&iS(e,h)}else{let h=t.viewHooks;h!==null&&oS(e,h,2),QI(e,2)}if(t.firstUpdatePass===!0&&(t.firstUpdatePass=!1),e[fh]){for(let h of e[fh])h();e[fh]=null}i||(z3(e),e[dt]&=-73)}catch(d){throw i||Vh(e),d}finally{u!==null&&(pc(u,c),a&&Ple(u)),XA()}}function Q3(t,e){for(let n=gH(t);n!==null;n=vH(n))for(let r=Wn;r0&&(t[n-1][ws]=r[ws]);let i=CS(t,Wn+e);F3(r[de],r);let o=i[Di];o!==null&&o.detachView(i[de]),r[ir]=null,r[ws]=null,r[dt]&=-129}return r}function Hle(t,e,n,r){ngDevMode&&ui(e),ngDevMode&&oo(n);let s=Wn+r,i=n.length;r>0&&(n[s-1][ws]=e),r-1&&(ngDevMode&&rt(r,e.indexOf(this._lView)-Wn,"An attached view should be in the same position within its container as its ViewRef in the VIEW_REFS array."),E0(e,r),CS(n,r))}this._attachedToViewContainer=!1}eb(this._lView[de],this._lView)}onDestroy(e){zC(this._lView,e)}markForCheck(){tb(this._cdRefInjectingView||this._lView,4)}detach(){this._lView[dt]&=-129}reattach(){Lk(this._lView),this._lView[dt]|=128}detectChanges(){this._lView[dt]|=1024,hT(this._lView,this.notifyErrorHandler)}checkNoChanges(){ngDevMode&&sP(this._lView,Mc.OnlyDirtyViews,this.notifyErrorHandler)}attachToViewContainerRef(){if(this._appRef)throw new ne(902,ngDevMode&&"This view is already attached directly to the ApplicationRef!");this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null;let e=cl(this._lView),n=this._lView[md];n!==null&&!e&&eP(n,this._lView),L3(this._lView[de],this._lView)}attachToAppRef(e){if(this._attachedToViewContainer)throw new ne(902,ngDevMode&&"This view is already attached to a ViewContainer!");this._appRef=e;let n=cl(this._lView),r=this._lView[md];r!==null&&!n&&n4(r,this._lView),Lk(this._lView)}};function jle(t){return H0(t._lView)||!!(t._lView[dt]&64)}function Ule(t){$A(t._cdRefInjectingView||t._lView)}var $r=class{};l($r,"__NG_ELEMENT_ID__",zle);var qle=$r,Wle=class extends qle{constructor(n,r,s){super();l(this,"_declarationLView");l(this,"_declarationTContainer");l(this,"elementRef");this._declarationLView=n,this._declarationTContainer=r,this.elementRef=s}get ssrId(){return this._declarationTContainer.tView?.ssrId||null}createEmbeddedView(n,r){return this.createEmbeddedViewImpl(n,r)}createEmbeddedViewImpl(n,r,s){let i=zh(this._declarationLView,this._declarationTContainer,n,{embeddedViewInjector:r,dehydratedView:s});return new _h(i)}};function zle(){return mT(Bt(),re())}function mT(t,e){return t.type&4?(ngDevMode&&Fe(t.tView,"TView must be allocated"),new Wle(e,t,Hh(t,e))):null}var E2="<-- AT THIS LOCATION";function Gle(t){switch(t){case 4:return"view container";case 2:return"element";case 8:return"ng-container";case 32:return"icu";case 64:return"i18n";case 16:return"projection";case 1:return"text";case 128:return"@let";default:return""}}function Zh(t,e,n,r,s,i=!1){if(!t||t.nodeType!==e||t.nodeType===Node.ELEMENT_NODE&&t.tagName.toLowerCase()!==n?.toLowerCase()){let a=`During hydration Angular expected ${N8(e,n,null)} but `,u=sT(r)?.type?.name,d=oP(r,s,i),p=`Angular expected this DOM: + +${d} + +`,f="",h=dn(r[Mn]);if(!t)a+=`the node was not found. + +`,y0(h,d);else{let v=N8(t.nodeType,t.tagName??null,t.textContent??null);a+=`found ${v}. + +`;let w=gT(t);f=`Actual DOM is: + +${w} + +`,y0(h,d,w)}let m=rb(u),g=a+p+f+s4()+m;throw new ne(-500,g)}}function r4(t){if(nb(t),!t.nextSibling){let e=`During hydration Angular expected more sibling nodes to be present. + +`,n=`Actual DOM is: + +${gT(t)} + +`,r=rb(),s=e+n+r;throw y0(t,"",n),new ne(-501,s)}}function nb(t,e=null,n=null){if(!t){let r=`During hydration, Angular expected an element to be present at this location. + +`,s="",i="";throw e!==null&&n!==null&&(s=oP(e,n,!1),i=rb(),y0(dn(e[Mn]),s,"")),new ne(-502,`${r}${s} + +${i}`)}}function Zle(t,e){let n=`During serialization, Angular was unable to find an element in the DOM: + +`,r=`${oP(t,e,!1)} + +`,s=rb();throw new ne(-502,n+r+s)}function P8(t,e){let n=`During hydration Angular was unable to locate a node using the "${e}" path, starting from the ${$y(t)} node. + +`,r=rb();throw y0(t),new ne(-502,n+r)}function Yle(t){let e="During serialization, Angular detected DOM nodes that were created outside of Angular context and provided as projectable nodes (likely via `ViewContainerRef.createComponent` or `createComponent` APIs). Hydration is not supported for such cases, consider refactoring the code to avoid this pattern or using `ngSkipHydration` on the host element of the component.\n\n",n=`${gT(t)} + +`,r=e+n+s4();return new ne(-503,r)}function Xle(t){let e="The `ngSkipHydration` flag is applied on a node that doesn't act as a component host. Hydration can be skipped only on per-component basis.\n\n",n=`${gT(t)} + +`,s=e+n+"Please move the `ngSkipHydration` attribute to the component host element.\n\n";return new ne(-504,s)}function Qle(t){let e=[];if(t.attrs)for(let n=0;n${e}`;case 8:return"";case 4:return"";default:return`#node(${Gle(t.type)})`}}function $y(t,e="\u2026"){let n=t;switch(n.nodeType){case Node.ELEMENT_NODE:let r=n.tagName.toLowerCase(),s=Jle(n);return`<${r}${s?" "+s:""}>${e}`;case Node.TEXT_NODE:let i=n.textContent?x0(n.textContent):"";return`#text${i?`(${i})`:""}`;case Node.COMMENT_NODE:return``;default:return`#node(${n.nodeType})`}}function oP(t,e,n){let r=" ",s="";e.prev?(s+=r+`\u2026 +`,s+=r+ik(e.prev)+` +`):e.type&&e.type&12&&(s+=r+`\u2026 +`),n?(s+=r+ik(e)+` +`,s+=r+` ${E2} +`):s+=r+ik(e)+` ${E2} +`,s+=r+`\u2026 +`;let i=e.type?tP(t[de],e,t):null;return i&&(s=$y(i,` +`+s)),s}function gT(t){let e=" ",n="",r=t;return r.previousSibling&&(n+=e+`\u2026 +`,n+=e+$y(r.previousSibling)+` +`),n+=e+$y(r)+` ${E2} +`,t.nextSibling&&(n+=e+`\u2026 +`),t.parentNode&&(n=$y(r.parentNode,` +`+n)),n}function N8(t,e,n){switch(t){case Node.ELEMENT_NODE:return`<${e.toLowerCase()}>`;case Node.TEXT_NODE:return`a text node${n?` (with the "${x0(n)}" content)`:""}`;case Node.COMMENT_NODE:return"a comment node";default:return`#node(nodeType=${t})`}}function rb(t){return`To fix this problem: + * check ${t?`the "${t}"`:"corresponding"} component for hydration-related issues + * check to see if your template has valid HTML structure + * or skip hydration by adding the \`ngSkipHydration\` attribute to its host node in a template + +`}function s4(){return`Note: attributes are only displayed to better represent the DOM but have no effect on hydration mismatches. + +`}function ece(t){return t.replace(/\s+/gm,"")}function x0(t,e=50){return t?(t=ece(t),t.length>e?`${t.substring(0,e-1)}\u2026`:t):""}function i4(t,e,n){let r=e.insertBeforeIndex,s=Array.isArray(r)?r[0]:r;return s===null?H3(t,e,n):(ngDevMode&&gr(n,s),dn(n[s]))}function o4(t,e,n,r,s){let i=e.insertBeforeIndex;if(Array.isArray(i)){ngDevMode&&xc(r);let o=r,a=null;if(e.type&3||(a=o,o=s),o!==null&&e.componentOffset===-1)for(let c=1;c1)for(let n=t.length-2;n>=0;n--){let r=t[n];l4(r)||rce(r,e)&&sce(r)===null&&ice(r,e.index)}}function l4(t){return!(t.type&64)}function rce(t,e){return l4(e)||t.index>e.index}function sce(t){let e=t.insertBeforeIndex;return Array.isArray(e)?e[0]:e}function ice(t,e){let n=t.insertBeforeIndex;Array.isArray(n)?n[0]=e:(U3(i4,o4),t.insertBeforeIndex=e)}function Vy(t,e){let n=t.data[e];if(n===null||typeof n=="string")return null;ngDevMode&&!(n.hasOwnProperty("tView")||n.hasOwnProperty("currentCaseLViewIndex"))&&tt("We expect to get 'null'|'TIcu'|'TIcuContainer', but got: "+n);let r=n.hasOwnProperty("currentCaseLViewIndex")?n:n.value;return ngDevMode&&qC(r),r}function oce(t,e,n){let r=t.data[e];ngDevMode&&rt(r===null||r.hasOwnProperty("tView"),!0,"We expect to get 'null'|'TIcuContainer'"),r===null?t.data[e]=n:(ngDevMode&&Yr(r,32),r.value=n)}function ace(t,e){ngDevMode&&dl(t);let n=t.insertBeforeIndex;n===null?(U3(i4,o4),n=t.insertBeforeIndex=[null,e]):(rt(Array.isArray(n),!0,"Expecting array here"),n.push(e))}function lce(t,e,n){let r=aP(t,n,64,null,null);return a4(e,r),r}function vT(t,e){let n=e[t.currentCaseLViewIndex];return n===null?n:n<0?~n:n}function c4(t){return t>>>17}function u4(t){return(t&131070)>>>1}function R8(t){return t&1}function cce(t,e,n){return ngDevMode&&yl(e,0,"Missing parent index"),ngDevMode&&Ad(n,0,"Missing ref index"),t|e<<17|n<<1}function d4(t){return t===-1}function lP(t,e,n){t.index=0;let r=vT(e,n);r!==null?(ngDevMode&&r0(r,0,e.cases.length-1),t.removes=e.remove[r]):t.removes=un}function YS(t){if(t.index0){let n=t.lView[e];return ngDevMode&&xc(n),n}else{t.stack.push(t.index,t.removes);let n=~e,r=t.lView[de].data[n];return ngDevMode&&qC(r),lP(t,r,t.lView),YS(t)}}else return t.stack.length===0?null:(t.removes=t.stack.pop(),t.index=t.stack.pop(),YS(t))}function uce(){let t={stack:[],index:-1};function e(n,r){for(t.lView=r;t.stack.length;)t.stack.pop();return ngDevMode&&Hs(n,r),lP(t,n.value,r),YS.bind(null,t)}return e}function dce(t,e){let n={stack:[],index:-1,lView:e};return ngDevMode&&qC(t),lP(n,t,e),YS.bind(null,n)}var pce=new RegExp(`^(\\d+)*(${pM}|${dM})*(.*)`);function fce(t,e){let n=[t];for(let r of e){let s=n.length-1;if(s>0&&n[s-1]===r){let i=n[s]||1;n[s]=i+1}else n.push(r,"")}return n.join("")}function hce(t){let e=t.match(pce),[n,r,s,i]=e,o=r?parseInt(r,10):s,a=[];for(let[c,u,d]of i.matchAll(/(f|n)(\d*)/g)){let p=parseInt(d,10)||1;a.push(u,p)}return[o,...a]}function mce(t){return!t.prev&&t.parent?.type===8}function ok(t){return t.index-He}function S0(t,e){return!(t.type&144)&&!!e[t.index]&&p4(dn(e[t.index]))}function p4(t){return!!t&&!t.isConnected}function f4(t,e){let n=t.i18nNodes;if(n)return n.get(e)}function gce(t,e,n){let s=t.data[ch]?.[n];return s?h4(s,e):null}function sb(t,e,n,r){let s=ok(r),i=f4(t,s);if(i===void 0){let o=t.data[ch];if(o?.[s])i=h4(o[s],n);else if(e.firstChild===r)i=t.firstChild;else{let a=r.prev===null,c=r.prev??r.parent;if(ngDevMode&&Fe(c,"Unexpected state: current TNode does not have a connection to the previous node or a parent node."),mce(r)){let u=ok(r.parent);i=n2(t,u)}else{let u=xs(c,n);if(a)i=u.firstChild;else{let d=ok(c),p=n2(t,d);if(c.type===2&&p){let h=TM(t,d)+1;i=yT(h,p)}else i=u.nextSibling}}}}return i}function yT(t,e){let n=e;for(let r=0;r-1){let c=o.substring(a+i.length).trim();ngDevMode&&rt(c.startsWith("d"),!0,"Invalid defer block id found in a comment node."),s.set(c,r)}}return s}function Ece(t){return t.textContent?.trimStart().startsWith("ngh=")?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}var m4=!1,g4=()=>{};function v4(t){m4=t}function cP(){return m4}function xce(t,e,n,r){g4(t,e,n,r)}function Sce(){g4=Mce}function Cce(t){return t=t??fe(Ln),t.get(AH,!1)}function Tce(t,e){let n=e.i18nChildren.get(t);return n===void 0&&(n=Dce(t),e.i18nChildren.set(t,n)),n}function Dce(t){let e=new Set;function n(r){switch(e.add(r.index),r.kind){case 1:case 2:{for(let s of r.children)n(s);break}case 3:{for(let s of r.cases)for(let i of s)n(i);break}}}for(let r=He;r{};function Pce(t,e,n){y4(t,e,n)}function Nce(){y4=Rce}function Rce(t,e,n){let r=t[Ls]?.dehydratedIcuData;r&&r.get(e)?.case===n&&r.delete(e)}function Fce(t){let e=t[Ls];if(e){let{i18nNodes:n,dehydratedIcuData:r}=e;if(n&&r){let s=t[pt];for(let i of r.values())Lce(s,n,i)}e.i18nNodes=void 0,e.dehydratedIcuData=void 0}}function Lce(t,e,n){for(let r of n.node.cases[n.case]){let s=e.get(r.index-He);s&&X0(t,s,!1)}}function b4(t){let e=t[Mo]??[],r=t[ir][pt],s=[];for(let i of e)i.data[hM]!==void 0?s.push(i):(w4(i,r),ngDevMode&&ngDevMode.dehydratedViewsRemoved++);t[Mo]=s}function Oce(t){let{lContainer:e}=t,n=e[Mo];if(n===null)return;let s=e[ir][pt];for(let i of n)w4(i,s),ngDevMode&&ngDevMode.dehydratedViewsRemoved++}function w4(t,e){let n=0,r=t.firstChild;if(r){let s=t.data[_c];for(;n0&&(i.firstChild=t,t=yT(r[_c],t)),n.push(i)}return[t,n]}var x4=()=>null;function Vce(t,e){let n=t[Mo];return!e||n===null||n.length===0?null:n[0].data[Kk]===e?n.shift():(b4(t),null)}function Hce(){x4=Vce}function Ih(t,e){return x4(t,e)}var S4=class{},uP=class{},C2=class{resolveComponentFactory(e){throw Error(`No component factory found for ${tn(e)}.`)}},Tk,ib=(Tk=class{},l(Tk,"NULL",new C2),Tk),Sd=class{},hr=class{constructor(){l(this,"destroyNode",null)}};l(hr,"__NG_ELEMENT_ID__",()=>jce());function jce(){let t=re(),e=Bt(),n=Bs(e.index,t);return(fr(n)?n:t)[pt]}var PC=class PC{};l(PC,"\u0275prov",hn({token:PC,providedIn:"root",factory:()=>null}));var QS=PC;function dP(t){return t.ngModule!==void 0}function Wu(t){return!!ki(t)}function Jx(t){return!!Ti(t)}function O8(t){return!!ls(t)}function Hy(t){return!!Ut(t)}function Uce(t){return Ut(t)?"component":ls(t)?"directive":Ti(t)?"pipe":"type"}function T2(t,e){if(FC(t)&&(t=xt(t),!t))throw new Error(`Expected forwardRef function, imported from "${Xt(e)}", to return a standalone entity or NgModule but got "${Xt(t)||t}".`);if(ki(t)==null){let n=Ut(t)||ls(t)||Ti(t);if(n!=null){if(!n.standalone)throw new Error(`The "${Xt(t)}" ${Uce(t)}, imported from "${Xt(e)}", is not standalone. Did you forget to add the standalone: true flag?`)}else throw dP(t)?new Error(`A module with providers was imported from "${Xt(e)}". Modules with providers are not supported in standalone components imports.`):new Error(`The "${Xt(t)}" type, imported from "${Xt(e)}", must be a standalone component / directive / pipe or an NgModule. Did you forget to add the required @Component / @Directive / @Pipe or @NgModule annotation?`)}}var qce=!0,D2=class{constructor(){l(this,"ownerNgModule",new Map);l(this,"ngModulesWithSomeUnresolvedDecls",new Set);l(this,"ngModulesScopeCache",new Map);l(this,"standaloneComponentsScopeCache",new Map)}resolveNgModulesDecls(){if(this.ngModulesWithSomeUnresolvedDecls.size!==0){for(let e of this.ngModulesWithSomeUnresolvedDecls){let n=ki(e);if(n?.declarations)for(let r of ha(n.declarations))Hy(r)&&this.ownerNgModule.set(r,e)}this.ngModulesWithSomeUnresolvedDecls.clear()}}getComponentDependencies(e,n){this.resolveNgModulesDecls();let r=Ut(e);if(r===null)throw new Error(`Attempting to get component dependencies for a type that is not a component: ${e}`);if(r.standalone){let s=this.getStandaloneComponentScope(e,n);return s.compilation.isPoisoned?{dependencies:[]}:{dependencies:[...s.compilation.directives,...s.compilation.pipes,...s.compilation.ngModules]}}else{if(!this.ownerNgModule.has(e))return{dependencies:[]};let s=this.getNgModuleScope(this.ownerNgModule.get(e));return s.compilation.isPoisoned?{dependencies:[]}:{dependencies:[...s.compilation.directives,...s.compilation.pipes]}}}registerNgModule(e,n){if(!Wu(e))throw new Error(`Attempting to register a Type which is not NgModule as NgModule: ${e}`);this.ngModulesWithSomeUnresolvedDecls.add(e)}clearScopeCacheFor(e){this.ngModulesScopeCache.delete(e),this.standaloneComponentsScopeCache.delete(e)}getNgModuleScope(e){if(this.ngModulesScopeCache.has(e))return this.ngModulesScopeCache.get(e);let n=this.computeNgModuleScope(e);return this.ngModulesScopeCache.set(e,n),n}computeNgModuleScope(e){let n=ki(e,!0),r={exported:{directives:new Set,pipes:new Set},compilation:{directives:new Set,pipes:new Set}};for(let s of ha(n.imports))if(Wu(s)){let i=this.getNgModuleScope(s);yc(i.exported.directives,r.compilation.directives),yc(i.exported.pipes,r.compilation.pipes)}else if(Sc(s))if(O8(s)||Hy(s))r.compilation.directives.add(s);else if(Jx(s))r.compilation.pipes.add(s);else throw new ne(980,"The standalone imported type is neither a component nor a directive nor a pipe");else{r.compilation.isPoisoned=!0;break}if(!r.compilation.isPoisoned)for(let s of ha(n.declarations)){if(Wu(s)||Sc(s)){r.compilation.isPoisoned=!0;break}Jx(s)?r.compilation.pipes.add(s):r.compilation.directives.add(s)}for(let s of ha(n.exports))if(Wu(s)){let i=this.getNgModuleScope(s);yc(i.exported.directives,r.exported.directives),yc(i.exported.pipes,r.exported.pipes),yc(i.exported.directives,r.compilation.directives),yc(i.exported.pipes,r.compilation.pipes)}else Jx(s)?r.exported.pipes.add(s):r.exported.directives.add(s);return r}getStandaloneComponentScope(e,n){if(this.standaloneComponentsScopeCache.has(e))return this.standaloneComponentsScopeCache.get(e);let r=this.computeStandaloneComponentScope(e,n);return this.standaloneComponentsScopeCache.set(e,r),r}computeStandaloneComponentScope(e,n){let r={compilation:{directives:new Set([e]),pipes:new Set,ngModules:new Set}};for(let s of oi(n??[])){let i=xt(s);try{T2(i,e)}catch{return r.compilation.isPoisoned=!0,r}if(Wu(i)){r.compilation.ngModules.add(i);let o=this.getNgModuleScope(i);if(o.exported.isPoisoned)return r.compilation.isPoisoned=!0,r;yc(o.exported.directives,r.compilation.directives),yc(o.exported.pipes,r.compilation.pipes)}else if(Jx(i))r.compilation.pipes.add(i);else if(O8(i)||Hy(i))r.compilation.directives.add(i);else return r.compilation.isPoisoned=!0,r}return r}isOrphanComponent(e){let n=Ut(e);return!n||n.standalone?!1:(this.resolveNgModulesDecls(),!this.ownerNgModule.has(e))}};function yc(t,e){for(let n of t)e.add(n)}var Cd=new D2,uS={},Ic=class{constructor(e,n){l(this,"injector");l(this,"parentInjector");this.injector=e,this.parentInjector=n}get(e,n,r){r=F0(r);let s=this.injector.get(e,uS,r);return s!==uS||n===uS?s:this.parentInjector.get(e,n,r)}};function _2(t,e,n){ngDevMode&&Os(nt(),"Expecting to be called in first template pass only");let r=n?t.styles:null,s=n?t.classes:null,i=0;if(e!==null)for(let o=0;o0&&(n.directiveToIndex=new Map);for(let f=0;f0;){let n=t[--e];if(typeof n=="number"&&n<0)return n}return 0}function eue(t,e,n){if(n){if(e.exportAs)for(let r=0;r{let[n,r,s]=t[e],i={propName:n,templateName:e,isSignal:(r&w0.SignalBased)!==0};return s&&(i.transform=s),i})}function sue(t){return Object.keys(t).map(e=>({propName:t[e],templateName:e}))}function iue(t){if((typeof ngJitMode>"u"||ngJitMode)&&t.debugInfo?.forbidOrphanRendering&&Cd.isOrphanComponent(t.type))throw new ne(981,`Orphan component found! Trying to render the component ${Ese(t.type)} without first loading the NgModule that declares it. It is recommended to make this component standalone in order to avoid this error. If this is not possible now, import the component's NgModule in the appropriate NgModule, or the standalone component in which you are trying to render this component. If this is a lazy import, load the NgModule lazily as well and use its module injector.`)}function oue(t,e,n){let r=e instanceof ci?e:e?.injector;return r&&t.getStandaloneInjector!==null&&(r=t.getStandaloneInjector(r)||r),r?new Ic(n,r):n}function aue(t){let e=t.get(Sd,null);if(e===null)throw new ne(407,ngDevMode&&"Angular was not able to inject a renderer (RendererFactory2). Likely this is due to a broken DI hierarchy. Make sure that any injector used to create this component has a correct parent.");let n=t.get(QS,null),r=t.get(no,null);return{rendererFactory:e,sanitizer:n,changeDetectionScheduler:r}}function lue(t,e){let n=(t.selectors[0][0]||"div").toLowerCase();return aT(e,n,n==="svg"?FA:n==="math"?LA:null)}var Nc=class extends uP{constructor(n,r){super();l(this,"componentDef");l(this,"ngModule");l(this,"selector");l(this,"componentType");l(this,"ngContentSelectors");l(this,"isBoundToModule");l(this,"cachedInputs",null);l(this,"cachedOutputs",null);this.componentDef=n,this.ngModule=r,this.componentType=n.type,this.selector=I3(n.selectors),this.ngContentSelectors=n.ngContentSelectors??[],this.isBoundToModule=!!r}get inputs(){return this.cachedInputs??(this.cachedInputs=rue(this.componentDef.inputs)),this.cachedInputs}get outputs(){return this.cachedOutputs??(this.cachedOutputs=sue(this.componentDef.outputs)),this.cachedOutputs}create(n,r,s,i){kn(22);let o=Et(null);try{let a=this.componentDef;ngDevMode&&iue(a);let c=s?["ng-version","19.2.25"]:ale(this.componentDef.selectors[0]),u=WM(0,null,null,1,0,null,null,null,null,[c],null),d=oue(a,i||this.ngModule,n),p=aue(d),f=p.rendererFactory.createRenderer(null,a),h=s?ule(f,s,a.encapsulation,d):lue(a,f),m=uT(null,u,null,512|zM(a),null,null,p,f,d,null,YH(h,d,!0));m[He]=h,YA(m);let g=null;try{let v=D4(He,u,m,"#host",()=>[this.componentDef],!0,0);h&&(w3(f,h,v),ai(h,m)),dT(u,m,v),DM(u,v,m),_4(u,v),r!==void 0&&cue(v,this.ngContentSelectors,r),g=Bs(v.index,m),m[wn]=g[wn],J0(u,m,null)}catch(v){throw g!==null&&Zk(g),Zk(m),v}finally{kn(23),XA()}return new JS(this.componentType,m)}finally{Et(o)}}},JS=class extends S4{constructor(n,r){super();l(this,"_rootLView");l(this,"instance");l(this,"hostView");l(this,"changeDetectorRef");l(this,"componentType");l(this,"location");l(this,"previousInputValues",null);l(this,"_tNode");this._rootLView=r,this._tNode=Pd(r[de],He),this.location=Hh(this._tNode,r),this.instance=Bs(this._tNode.index,r)[wn],this.hostView=this.changeDetectorRef=new _h(r,void 0,!1),this.componentType=n}setInput(n,r){let s=this._tNode;if(this.previousInputValues??(this.previousInputValues=new Map),this.previousInputValues.has(n)&&Object.is(this.previousInputValues.get(n),r))return;let i=this._rootLView,o=KM(s,i[de],i,n,r);this.previousInputValues.set(n,r);let a=Bs(s.index,i);if(tb(a,1),ngDevMode&&!o){let c=Xt(this.componentType),u=`Can't set value of the '${n}' input on the '${c}' component. `;u+=`Make sure that the '${n}' property is annotated with @Input() or a mapped @Input('${n}') exists.`,a3(u)}}get injector(){return new Vn(this._tNode,this._rootLView)}destroy(){this.hostView.destroy()}onDestroy(n){this.hostView.onDestroy(n)}};function cue(t,e,n){let r=t.projection=[];for(let s=0;s0;)this.remove(this.length-1)}get(n){let r=H8(this._lContainer);return r!==null&&r[n]||null}get length(){return this._lContainer.length-Wn}createEmbeddedView(n,r,s){let i,o;typeof s=="number"?i=s:s!=null&&(i=s.index,o=s.injector);let a=Ih(this._lContainer,n.ssrId),c=n.createEmbeddedViewImpl(r||{},o,a);return this.insertImpl(c,i,xd(this._hostTNode,a)),c}createComponent(n,r,s,i,o){let a=n&&!My(n),c;if(a)ngDevMode&&rt(typeof r!="object",!0,"It looks like Component factory was provided as the first argument and an options object as the second argument. This combination of arguments is incompatible. You can either change the first argument to provide Component type or change the second argument to be a number (representing an index at which to insert the new component's host view into this container)"),c=r;else{ngDevMode&&(Fe(Ut(n),"Provided Component class doesn't contain Component definition. Please check whether provided class has @Component decorator."),rt(typeof r!="number",!0,"It looks like Component type was provided as the first argument and a number (representing an index at which to insert the new component's host view into this container as the second argument. This combination of arguments is incompatible. Please use an object as the second argument instead."));let g=r||{};ngDevMode&&g.environmentInjector&&g.ngModuleRef&&tt("Cannot pass both environmentInjector and ngModuleRef options to createComponent()."),c=g.index,s=g.injector,i=g.projectableNodes,o=g.environmentInjector||g.ngModuleRef}let u=a?n:new Nc(Ut(n)),d=s||this.parentInjector;if(!o&&u.ngModule==null){let v=(a?d:this.parentInjector).get(ci,null);v&&(o=v)}let p=Ut(u.componentType??{}),f=Ih(this._lContainer,p?.id??null),h=f?.firstChild??null,m=u.create(d,i,h,o);return this.insertImpl(m.hostView,c,xd(this._hostTNode,f)),m}insert(n,r){return this.insertImpl(n,r,!0)}insertImpl(n,r,s){let i=n._lView;if(ngDevMode&&n.destroyed)throw new Error("Cannot insert a destroyed View in a ViewContainer!");if(rie(i)){let c=this.indexOf(n);if(c!==-1)this.detach(c);else{let u=i[ir];ngDevMode&&rt(Ir(u),!0,"An attached view should have its PARENT point to a container.");let d=new I4(u,u[Xr],u[ir]);d.detach(d.indexOf(n))}}let o=this._adjustIndex(r),a=this._lContainer;return Gh(a,i,o,s),n.attachToViewContainerRef(),KV(ck(a),o,n),n}move(n,r){if(ngDevMode&&n.destroyed)throw new Error("Cannot move a destroyed View in a ViewContainer!");return this.insert(n,r)}indexOf(n){let r=H8(this._lContainer);return r!==null?r.indexOf(n):-1}remove(n){let r=this._adjustIndex(n,-1),s=E0(this._lContainer,r);s&&(CS(ck(this._lContainer),r),eb(s[de],s))}detach(n){let r=this._adjustIndex(n,-1),s=E0(this._lContainer,r);return s&&CS(ck(this._lContainer),r)!=null?new _h(s):null}_adjustIndex(n,r=0){return n==null?this.length+r:(ngDevMode&&(Ad(n,-1,`ViewRef index must be positive, got ${n}`),kc(n,this.length+1+r,"index")),n)}};function H8(t){return t[IS]}function ck(t){return t[IS]||(t[IS]=[])}function k4(t,e){ngDevMode&&Yr(t,15);let n,r=e[t.index];return Ir(r)?n=r:(n=e4(r,e,null,t),e[t.index]=n,GM(e,n)),A4(n,e,t,r),new I4(n,t,e)}function pue(t,e){let n=t[pt];ngDevMode&&ngDevMode.rendererCreateComment++;let r=n.createComment(ngDevMode?"container":""),s=xs(e,t),i=n.parentNode(s);return Ed(n,i,r,n.nextSibling(s),!1),r}var A4=P4,fP=()=>!1;function M4(t,e,n){return fP(t,e,n)}function P4(t,e,n,r){if(t[va])return;let s;n.type&8?s=dn(r):s=pue(e,n),t[va]=s}function fue(t,e,n){if(t[va]&&t[Mo])return!0;let r=n[Ls],s=e.index-He;if(!r||h0(e)||$d(r,s))return!1;let o=n2(r,s),a=r.data[od]?.[s];ngDevMode&&Fe(a,"Unexpected state: no hydration info available for a given TNode, which represents a view container.");let[c,u]=$ce(o,a);return ngDevMode&&(Zh(c,Node.COMMENT_NODE,null,n,e,!0),Bd(c,!1)),t[va]=c,t[Mo]=u,!0}function hue(t,e,n,r){fP(t,n,e)||P4(t,e,n,r)}function mue(){A4=hue,fP=fue}var I2=class t{constructor(e){l(this,"queryList");l(this,"matches",null);this.queryList=e}clone(){return new t(this.queryList)}setDirty(){this.queryList.setDirty()}},k2=class t{constructor(e=[]){l(this,"queries");this.queries=e}createEmbeddedView(e){let n=e.queries;if(n!==null){let r=e.contentQueries!==null?e.contentQueries[0]:n.length,s=[];for(let i=0;i0)r.push(o[a/2]);else{let u=i[a+1],d=e[-c];ngDevMode&&oo(d);for(let p=Wn;pe.trim())}function O4(t,e,n){t.queries===null&&(t.queries=new A2),t.queries.track(new M2(e,n))}function Eue(t,e){let n=t.contentQueries||(t.contentQueries=[]),r=n.length?n[n.length-1]:-1;e!==r&&n.push(t.queries.length-1,e)}function mP(t,e){return ngDevMode&&Fe(t.queries,"TQueries must be defined to retrieve a TQuery"),t.queries.getByIndex(e)}function B4(t,e){let n=t[de],r=mP(n,e);return r.crossesNgTemplate?P2(n,t,e,[]):N4(n,t,r,e)}function gP(t,e,n){let r,s=gx(()=>{r._dirtyCounter();let i=xue(r,t);if(e&&i===void 0)throw new ne(-951,ngDevMode&&"Child query result is required but no value is available.");return i});return r=s[rr],r._dirtyCounter=ro(0),r._flatValue=void 0,ngDevMode&&(s.toString=()=>"[Query Signal]",r.debugName=n?.debugName),s}function $4(t){return gP(!0,!1,t)}function V4(t){return gP(!0,!0,t)}function H4(t){return gP(!1,!1,t)}function j4(t,e){let n=t[rr];n._lView=re(),n._queryIndex=e,n._queryList=hP(n._lView,e),n._queryList.onDirty(()=>n._dirtyCounter.update(r=>r+1))}function xue(t,e){let n=t._lView,r=t._queryIndex;if(n===void 0||r===void 0||n[dt]&4)return e?void 0:un;let s=hP(n,r),i=B4(n,r);return s.reset(i,aH),e?s.first:s._changesDetected||t._flatValue===void 0?t._flatValue=s.toArray():t._flatValue}function j8(t,e){return ngDevMode&&us(vP),$4(e)}function Sue(t,e){return ngDevMode&&us(vP),V4(e)}var vP=(j8.required=Sue,j8);function U4(t,e){return ngDevMode&&us(U4),H4(e)}function U8(t,e){return ngDevMode&&us(q4),$4(e)}function Cue(t,e){return ngDevMode&&us(W4),V4(e)}var q4=(U8.required=Cue,U8);function W4(t,e){return H4(e)}function z4(t,e){let n=Object.create(UV),r=new d0;n.value=t;function s(){return dc(n),q8(n.value),n.value}return s[rr]=n,s.asReadonly=KC.bind(s),s.set=i=>{n.equal(n.value,i)||(Ou(n,i),r.emit(i))},s.update=i=>{q8(n.value),s.set(i(n.value))},s.subscribe=r.subscribe.bind(r),s.destroyRef=r.destroyRef,ngDevMode&&(s.toString=()=>`[Model Signal: ${s()}]`,n.debugName=e?.debugName),s}function q8(t){if(t===RC)throw new ne(952,ngDevMode&&"Model is required but no value is available yet.")}function W8(t,e){return ngDevMode&&us(yP),z4(t,e)}function Tue(t){return ngDevMode&&us(yP),z4(RC,t)}var yP=(W8.required=Tue,W8),G4=!0,Td=class{},Due=Oc("ContentChildren",(t,e={})=>({selector:t,first:!1,isViewQuery:!1,descendants:!1,emitDistinctChangesOnly:G4,...e}),Td),_ue=Oc("ContentChild",(t,e={})=>({selector:t,first:!0,isViewQuery:!1,descendants:!0,...e}),Td),Iue=Oc("ViewChildren",(t,e={})=>({selector:t,first:!1,isViewQuery:!0,descendants:!0,emitDistinctChangesOnly:G4,...e}),Td),xl=Oc("ViewChild",(t,e)=>({selector:t,first:!0,isViewQuery:!0,descendants:!0,...e}),Td);function Z4(t){let e=[],n=new Map;function r(s){let i=n.get(s);if(!i){let o=t(s);n.set(s,i=o.then(Nue))}return i}return kh.forEach((s,i)=>{let o=[];s.templateUrl&&o.push(r(s.templateUrl).then(u=>{s.template=u}));let a=typeof s.styles=="string"?[s.styles]:s.styles||[];if(s.styles=a,s.styleUrl&&s.styleUrls?.length)throw new Error("@Component cannot define both `styleUrl` and `styleUrls`. Use `styleUrl` if the component has one stylesheet, or `styleUrls` if it has multiple");if(s.styleUrls?.length){let u=s.styles.length,d=s.styleUrls;s.styleUrls.forEach((p,f)=>{a.push(""),o.push(r(p).then(h=>{a[u+f]=h,d.splice(d.indexOf(p),1),d.length==0&&(s.styleUrls=void 0)}))})}else s.styleUrl&&o.push(r(s.styleUrl).then(u=>{a.push(u),s.styleUrl=void 0}));let c=Promise.all(o).then(()=>Rue(i));e.push(c)}),X4(),Promise.all(e).then(()=>{})}var kh=new Map,C0=new Set;function kue(t,e){Y4(e)&&(kh.set(t,e),C0.add(t))}function Aue(t){return C0.has(t)}function Y4(t){return!!(t.templateUrl&&!t.hasOwnProperty("template")||t.styleUrls&&t.styleUrls.length||t.styleUrl)}function X4(){let t=kh;return kh=new Map,t}function Mue(t){C0.clear(),t.forEach((e,n)=>C0.add(n)),kh=t}function Pue(){return kh.size===0}function Nue(t){return typeof t=="string"?t:t.text()}function Rue(t){C0.delete(t)}var N2=new Map,Q4=!0;function Fue(t,e,n){if(e&&e!==n&&Q4)throw new Error(`Duplicate module registered for ${t} - ${tn(e)} vs ${tn(e.name)}`)}function bP(t,e){let n=N2.get(e)||null;Fue(e,n,t),N2.set(e,t)}function K4(t){return N2.get(t)}function Lue(t){Q4=!t}var ml=class{},J4=class{};function wT(t,e){return new Ah(t,e??null,[])}var Oue=wT,Ah=class extends ml{constructor(n,r,s,i=!0){super();l(this,"ngModuleType");l(this,"_parent");l(this,"_bootstrapComponents",[]);l(this,"_r3Injector");l(this,"instance");l(this,"destroyCbs",[]);l(this,"componentFactoryResolver",new KS(this));this.ngModuleType=n,this._parent=r;let o=ki(n);ngDevMode&&Fe(o,`NgModule '${tn(n)}' is not a subtype of 'NgModuleType'.`),this._bootstrapComponents=ha(o.bootstrap),this._r3Injector=K5(n,r,[{provide:ml,useValue:this},{provide:ib,useValue:this.componentFactoryResolver},...s],tn(n),new Set(["environment"])),i&&this.resolveInjectorInitializers()}resolveInjectorInitializers(){this._r3Injector.resolveInjectorInitializers(),this.instance=this._r3Injector.get(this.ngModuleType)}get injector(){return this._r3Injector}destroy(){ngDevMode&&Fe(this.destroyCbs,"NgModule already destroyed");let n=this._r3Injector;!n.destroyed&&n.destroy(),this.destroyCbs.forEach(r=>r()),this.destroyCbs=null}onDestroy(n){ngDevMode&&Fe(this.destroyCbs,"NgModule already destroyed"),this.destroyCbs.push(n)}},Mh=class extends J4{constructor(n){super();l(this,"moduleType");this.moduleType=n}create(n){return new Ah(this.moduleType,n,[])}};function Bue(t,e,n){return new Ah(t,e,n,!1)}var tC=class extends ml{constructor(n){super();l(this,"injector");l(this,"componentFactoryResolver",new KS(this));l(this,"instance",null);let r=new ga([...n.providers,{provide:ml,useValue:this},{provide:ib,useValue:this.componentFactoryResolver}],n.parent||jC(),n.debugName,new Set(["environment"]));this.injector=r,n.runEnvironmentInitializers&&r.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(n){this.injector.onDestroy(n)}};function wP(t,e,n=null){return new tC({providers:t,parent:e,debugName:n,runEnvironmentInitializers:!0}).injector}var Ky=class Ky{constructor(e){l(this,"_injector");l(this,"cachedInjectors",new Map);this._injector=e}getOrCreateStandaloneInjector(e){if(!e.standalone)return null;if(!this.cachedInjectors.has(e)){let n=IA(!1,e.type),r=n.length>0?wP([n],this._injector,`Standalone[${e.type.name}]`):null;this.cachedInjectors.set(e,r)}return this.cachedInjectors.get(e)}ngOnDestroy(){try{for(let e of this.cachedInjectors.values())e!==null&&e.destroy()}finally{this.cachedInjectors.clear()}}};l(Ky,"\u0275prov",hn({token:Ky,providedIn:"environment",factory:()=>new Ky(Zr(ci))}));var R2=Ky;function ej(t){return Sa(()=>{(typeof ngDevMode>"u"||ngDevMode)&&wA();let e=rj(t),n={...e,decls:t.decls,vars:t.vars,template:t.template,consts:t.consts||null,ngContentSelectors:t.ngContentSelectors,onPush:t.changeDetection===yd.OnPush,directiveDefs:null,pipeDefs:null,dependencies:e.standalone&&t.dependencies||null,getStandaloneInjector:e.standalone?s=>s.get(R2).getOrCreateStandaloneInjector(n):null,getExternalStyles:null,signals:t.signals??!1,data:t.data||{},encapsulation:t.encapsulation||Vs.Emulated,styles:t.styles||un,_:null,schemas:t.schemas||null,tView:null,id:""};e.standalone&&Ss("NgStandalone"),sj(n);let r=t.dependencies;return n.directiveDefs=nC(r,!1),n.pipeDefs=nC(r,!0),n.id=Uue(n),n})}function $ue(t){return Ut(t)||ls(t)}function Vue(t){return t!==null}function EP(t){return Sa(()=>({type:t.type,bootstrap:t.bootstrap||un,declarations:t.declarations||un,imports:t.imports||un,exports:t.exports||un,transitiveCompileScopes:null,schemas:t.schemas||null,id:t.id||null}))}function Hue(t,e){if(t==null)return eo;let n={};for(let r in t)if(t.hasOwnProperty(r)){let s=t[r],i,o,a,c;Array.isArray(s)?(a=s[0],i=s[1],o=s[2]??i,c=s[3]||null):(i=s,o=s,a=w0.None,c=null),n[i]=[r,a,c],e[i]=o}return n}function jue(t){if(t==null)return eo;let e={};for(let n in t)t.hasOwnProperty(n)&&(e[t[n]]=n);return e}function tj(t){return Sa(()=>{let e=rj(t);return sj(e),e})}function nj(t){return{type:t.type,name:t.name,factory:null,pure:t.pure!==!1,standalone:t.standalone??!0,onDestroy:t.type.prototype.ngOnDestroy||null}}function rj(t){let e={};return{type:t.type,providersResolver:null,factory:null,hostBindings:t.hostBindings||null,hostVars:t.hostVars||0,hostAttrs:t.hostAttrs||null,contentQueries:t.contentQueries||null,declaredInputs:e,inputConfig:t.inputs||eo,exportAs:t.exportAs||null,standalone:t.standalone??!0,signals:t.signals===!0,selectors:t.selectors||un,viewQuery:t.viewQuery||null,features:t.features||null,setInput:null,findHostDirectiveDefs:null,hostDirectives:null,inputs:Hue(t.inputs,e),outputs:jue(t.outputs),debugInfo:null}}function sj(t){t.features?.forEach(e=>e(t))}function nC(t,e){if(!t)return null;let n=e?Ti:$ue;return()=>(typeof t=="function"?t():t).map(r=>n(r)).filter(Vue)}var dS=new Map;function Uue(t){let e=0,n=typeof t.consts=="function"?"":t.consts,r=[t.selectors,t.ngContentSelectors,t.hostVars,t.hostAttrs,n,t.vars,t.decls,t.encapsulation,t.standalone,t.signals,t.exportAs,JSON.stringify(t.inputs),JSON.stringify(t.outputs),Object.getOwnPropertyNames(t.type.prototype),!!t.contentQueries,!!t.viewQuery];if(typeof ngDevMode>"u"||ngDevMode)for(let i of r)di(typeof i,"function","Internal error: attempting to use a function in component id computation logic.");for(let i of r.join("|"))e=Math.imul(31,e)+i.charCodeAt(0)<<0;e+=2147483648;let s="c"+e;if((typeof ngDevMode>"u"||ngDevMode)&&(typeof ngServerMode>"u"||!ngServerMode))if(dS.has(s)){let i=dS.get(s);i!==t.type&&console.warn(gn(-912,`Component ID generation collision detected. Components '${i.name}' and '${t.type.name}' with selector '${I3(t.selectors)}' generated the same component ID. To fix this, you can change the selector of one of those components or add an extra host attribute to force a different ID.`))}else dS.set(s,t.type);return s}function ij(t){return Object.getPrototypeOf(t.prototype).constructor}function xP(t){let e=ij(t.type),n=!0,r=[t];for(;e;){let s;if(Ns(t))s=e.\u0275cmp||e.\u0275dir;else{if(e.\u0275cmp)throw new ne(903,ngDevMode&&`Directives cannot inherit Components. Directive ${Xt(t.type)} is attempting to extend component ${Xt(e)}`);s=e.\u0275dir}if(s){if(n){r.push(s);let o=t;o.inputs=uk(t.inputs),o.declaredInputs=uk(t.declaredInputs),o.outputs=uk(t.outputs);let a=s.hostBindings;a&&Zue(t,a);let c=s.viewQuery,u=s.contentQueries;if(c&&zue(t,c),u&&Gue(t,u),que(t,s),use(t.outputs,s.outputs),Ns(s)&&s.data.animation){let d=t.data;d.animation=(d.animation||[]).concat(s.data.animation)}}let i=s.features;if(i)for(let o=0;o=0;r--){let s=t[r];s.hostVars=e+=s.hostVars,s.hostAttrs=Eh(s.hostAttrs,n=Eh(n,s.hostAttrs))}}function uk(t){return t===eo?{}:t===un?[]:t}function zue(t,e){let n=t.viewQuery;n?t.viewQuery=(r,s)=>{e(r,s),n(r,s)}:t.viewQuery=e}function Gue(t,e){let n=t.contentQueries;n?t.contentQueries=(r,s,i)=>{e(r,s,i),n(r,s,i)}:t.contentQueries=e}function Zue(t,e){let n=t.hostBindings;n?t.hostBindings=(r,s)=>{e(r,s),n(r,s)}:t.hostBindings=e}var Yue=["providersResolver"],Xue=["template","decls","consts","vars","onPush","ngContentSelectors","styles","encapsulation","schemas"];function oj(t){let e=ij(t.type),n;Ns(t)?n=e.\u0275cmp:n=e.\u0275dir;let r=t;for(let s of Yue)r[s]=n[s];if(Ns(n))for(let s of Xue)r[s]=n[s]}function aj(t){let e=n=>{let r=Array.isArray(t);n.hostDirectives===null?(n.findHostDirectiveDefs=lj,n.hostDirectives=r?t.map(F2):[t]):r?n.hostDirectives.unshift(...t.map(F2)):n.hostDirectives.unshift(t)};return e.ngInherit=!0,e}function lj(t,e,n){if(t.hostDirectives!==null)for(let r of t.hostDirectives)if(typeof r=="function"){let s=r();for(let i of s)z8(F2(i),e,n)}else z8(r,e,n)}function z8(t,e,n){let r=ls(t.directive);(typeof ngDevMode>"u"||ngDevMode)&&Kue(t,r),Que(r.declaredInputs,t.inputs),lj(r,e,n),n.set(r,t),e.push(r)}function F2(t){return typeof t=="function"?{directive:xt(t),inputs:eo,outputs:eo}:{directive:xt(t.directive),inputs:G8(t.inputs),outputs:G8(t.outputs)}}function G8(t){if(t===void 0||t.length===0)return eo;let e={};for(let n=0;n"u"||ngDevMode)&&t.hasOwnProperty(r)&&rt(t[r],t[n],`Conflicting host directive input alias ${n}.`),t[r]=s}}function Kue(t,e){let n=t.directive;if(e===null)throw Ut(n)!==null?new ne(310,`Host directive ${n.name} cannot be a component.`):new ne(307,`Could not resolve metadata for host directive ${n.name}. Make sure that the ${n.name} class is annotated with an @Directive decorator.`);if(!e.standalone)throw new ne(308,`Host directive ${e.type.name} must be standalone.`);Z8("input",e,t.inputs),Z8("output",e,t.outputs)}function Z8(t,e,n){let r=e.type.name,s=t==="input"?e.inputs:e.outputs;for(let i in n)if(n.hasOwnProperty(i)){if(!s.hasOwnProperty(i))throw new ne(311,`Directive ${r} does not have an ${t} with a public name of ${i}.`);let o=n[i];if(s.hasOwnProperty(o)&&o!==i)throw new ne(312,`Cannot alias ${t} ${i} of host directive ${r} to ${o}, because it already has a different ${t} with the same public name.`)}}function rC(t){return SP(t)?Array.isArray(t)||!(t instanceof Map)&&Symbol.iterator in t:!1}function Jue(t,e,n){let r=t[Symbol.iterator](),s=e[Symbol.iterator]();for(;;){let i=r.next(),o=s.next();if(i.done&&o.done)return!0;if(i.done||o.done||!n(i.value,o.value))return!1}}function ede(t,e){if(Array.isArray(t))for(let n=0;nn.remove(t);return n.add(t),r}var sde=()=>typeof requestIdleCallback<"u"?requestIdleCallback:setTimeout,ide=()=>typeof requestIdleCallback<"u"?cancelIdleCallback:clearTimeout,Jy=class Jy{constructor(){l(this,"executingCallbacks",!1);l(this,"idleId",null);l(this,"current",new Set);l(this,"deferred",new Set);l(this,"ngZone",fe(qt));l(this,"requestIdleCallbackFn",sde().bind(globalThis));l(this,"cancelIdleCallbackFn",ide().bind(globalThis))}add(e){(this.executingCallbacks?this.deferred:this.current).add(e),this.idleId===null&&this.scheduleIdleCallback()}remove(e){let{current:n,deferred:r}=this;n.delete(e),r.delete(e),n.size===0&&r.size===0&&this.cancelIdleCallback()}scheduleIdleCallback(){let e=()=>{this.cancelIdleCallback(),this.executingCallbacks=!0;for(let n of this.current)n();if(this.current.clear(),this.executingCallbacks=!1,this.deferred.size>0){for(let n of this.deferred)this.current.add(n);this.deferred.clear(),this.scheduleIdleCallback()}};this.idleId=this.requestIdleCallbackFn(()=>this.ngZone.run(e))}cancelIdleCallback(){this.idleId!==null&&(this.cancelIdleCallbackFn(this.idleId),this.idleId=null)}ngOnDestroy(){this.cancelIdleCallback(),this.current.clear(),this.deferred.clear()}};l(Jy,"\u0275prov",hn({token:Jy,providedIn:"root",factory:()=>new Jy}));var L2=Jy;function ST(t){return(e,n)=>dj(t,e,n)}function dj(t,e,n){let r=n.get(sC),s=n.get(qt),i=()=>r.remove(e);return r.add(t,e,s),i}var e0=class e0{constructor(){l(this,"executingCallbacks",!1);l(this,"timeoutId",null);l(this,"invokeTimerAt",null);l(this,"current",[]);l(this,"deferred",[])}add(e,n,r){let s=this.executingCallbacks?this.deferred:this.current;this.addToQueue(s,Date.now()+e,n),this.scheduleTimer(r)}remove(e){let{current:n,deferred:r}=this;this.removeFromQueue(n,e)===-1&&this.removeFromQueue(r,e),n.length===0&&r.length===0&&this.clearTimeout()}addToQueue(e,n,r){let s=e.length;for(let i=0;in){s=i;break}JV(e,s,n,r)}removeFromQueue(e,n){let r=-1;for(let s=0;s-1&&X$(e,r,2),r}scheduleTimer(e){let n=()=>{this.clearTimeout(),this.executingCallbacks=!0;let s=[...this.current],i=Date.now();for(let a=0;a=0&&X$(this.current,0,o+1),this.executingCallbacks=!1,this.deferred.length>0){for(let a=0;a0){let s=Date.now(),i=this.current[0];if(this.timeoutId===null||this.invokeTimerAt&&this.invokeTimerAt-i>16){this.clearTimeout();let o=Math.max(i-s,16);this.invokeTimerAt=i,this.timeoutId=e.runOutsideAngular(()=>setTimeout(()=>e.run(n),o))}}}clearTimeout(){this.timeoutId!==null&&(clearTimeout(this.timeoutId),this.timeoutId=null)}ngOnDestroy(){this.clearTimeout(),this.current.length=0,this.deferred.length=0}};l(e0,"\u0275prov",hn({token:e0,providedIn:"root",factory:()=>new e0}));var sC=e0,t0=class t0{constructor(){l(this,"cachedInjectors",new Map)}getOrCreateInjector(e,n,r,s){if(!this.cachedInjectors.has(e)){let i=r.length>0?wP(r,n,s):null;this.cachedInjectors.set(e,i)}return this.cachedInjectors.get(e)}ngOnDestroy(){try{for(let e of this.cachedInjectors.values())e!==null&&e.destroy()}finally{this.cachedInjectors.clear()}}};l(t0,"\u0275prov",hn({token:t0,providedIn:"environment",factory:()=>new t0}));var O2=t0,pj=new $e("DEFER_BLOCK_DEPENDENCY_INTERCEPTOR"),fj=new $e(ngDevMode?"DEFER_BLOCK_CONFIG":"");function dk(t,e,n){return t.get(O2).getOrCreateInjector(e,t,n,ngDevMode?"DeferBlock Injector":"")}function ode(t,e,n){if(t instanceof Ic){let s=t.injector,i=t.parentInjector,o=dk(i,e,n);return new Ic(s,o)}let r=t.get(ci);if(r!==t){let s=dk(r,e,n);return new Ic(t,s)}return dk(t,e,n)}function al(t,e,n,r=!1){let s=n[ir],i=s[de];if(ul(s))return;ngDevMode&&Hs(e,s);let o=Cs(s,e);ngDevMode&&Fe(o,"Expected a defer block state defined");let a=o[wa],c=o[Doe];if(!(c!==null&&t"u"||!ngServerMode)&&(OH(u)!==null||Jk(u,bn.Loading)!==null||Jk(u,bn.Placeholder));ngDevMode&&d&&Fe(iC,"Expected scheduling function to be defined");let p=d?iC:hj;try{p(t,o,n,e,s)}catch(f){QM(s,f)}}}function ade(t,e){let n=t[Mo]?.findIndex(s=>s.data[VS]===e[wa])??-1;return{dehydratedView:n>-1?t[Mo][n]:null,dehydratedViewIx:n}}function hj(t,e,n,r,s){kn(20);let i=Aoe(t,s,r);if(i!==null){e[wa]=t;let o=s[de],a=i+He,c=Pd(o,a),u=0;iP(n,u);let d;if(t===bn.Complete){let m=Qr(o,r),g=m.providers;g&&g.length>0&&(d=ode(s[or],m,g))}let{dehydratedView:p,dehydratedViewIx:f}=ade(n,e),h=zh(s,c,null,{injector:d,dehydratedView:p});if(Gh(n,h,u,xd(c,p)),tb(h,2),f>-1&&n[Mo]?.splice(f,1),(t===bn.Complete||t===bn.Error)&&Array.isArray(e[gh])){for(let m of e[gh])m();e[gh]=null}}kn(21)}function lde(t,e,n,r,s){let i=Date.now(),o=s[de],a=Qr(o,r);if(e[Ry]===null||e[Ry]<=i){e[Ry]=null;let c=OH(a),u=e[Zx]!==null;if(t===bn.Loading&&c!==null&&!u){e[mh]=t;let d=Y8(c,e,r,n,s);e[Zx]=d}else{t>bn.Loading&&u&&(e[Zx](),e[Zx]=null,e[mh]=null),hj(t,e,n,r,s);let d=Jk(a,t);d!==null&&(e[Ry]=i+d,Y8(d,e,r,n,s))}}else e[mh]=t}function Y8(t,e,n,r,s){return dj(t,()=>{let o=e[mh];e[Ry]=null,e[mh]=null,o!==null&&al(o,n,r)},s[or])}function X8(t,e){return t{t.loadingState===pr.COMPLETE?(ngDevMode&&BH(t),al(bn.Complete,e,n)):t.loadingState===pr.FAILED&&al(bn.Error,e,n)})}var iC=null;function mj(t,e,n,r){let s=t.consts;n!=null&&(e.placeholderBlockConfig=to(s,n)),r!=null&&(e.loadingBlockConfig=to(s,r)),iC===null&&(iC=lde)}var pS="__ngAsyncComponentMetadataFn__";function cde(t){return t[pS]??null}function gj(t,e,n){let r=t;return r[pS]=()=>Promise.all(e()).then(s=>(n(...s),r[pS]=null,s)),r[pS]}function Us(t,e,n,r){return Sa(()=>{let s=t;e!==null&&(s.hasOwnProperty("decorators")&&s.decorators!==void 0?s.decorators.push(...e):s.decorators=e),n!==null&&(s.ctorParameters=n),r!==null&&(s.hasOwnProperty("propDecorators")&&s.propDecorators!==void 0?s.propDecorators={...s.propDecorators,...r}:s.propDecorators=r)})}var Zu=class Zu{log(e){console.log(e)}warn(e){console.warn(e)}};l(Zu,"\u0275fac",function(n){return new(n||Zu)}),l(Zu,"\u0275prov",hn({token:Zu,factory:Zu.\u0275fac,providedIn:"platform"}));var Ai=Zu;(typeof ngDevMode>"u"||ngDevMode)&&Us(Ai,[{type:St,args:[{providedIn:"platform"}]}],null,null);var B2=class{constructor(){l(this,"resolverToTokenToDependencies",new WeakMap);l(this,"resolverToProviders",new WeakMap);l(this,"resolverToEffects",new WeakMap);l(this,"standaloneInjectorToComponent",new WeakMap)}reset(){this.resolverToTokenToDependencies=new WeakMap,this.resolverToProviders=new WeakMap,this.standaloneInjectorToComponent=new WeakMap}},Qh=new B2;function ab(){return Qh}function ude(){Qh.reset(),bse(t=>dde(t))}function dde(t){let{context:e,type:n}=t;n===0?fde(e,t.service):n===1?mde(e,t.instance):n===2?vde(e,t.providerRecord):n===3&&pde(e,t.effect)}function pde(t,e){let n=DP(t.injector);n===null&&tt("An EffectCreated event must be run within an injection context.");let{resolverToEffects:r}=Qh;r.has(n)||r.set(n,[]),r.get(n).push(e)}function fde(t,e){let n=DP(t.injector);n===null&&tt("An Inject event must be run within an injection context.");let r=Qh.resolverToTokenToDependencies;if(r.has(n)||r.set(n,new WeakMap),!yde(t.token))return;let s=r.get(n);s.has(t.token)||s.set(t.token,[]);let{token:i,value:o,flags:a}=e;Fe(t.token,"Injector profiler context token is undefined.");let c=s.get(t.token);Fe(c,"Could not resolve dependencies for token."),t.injector instanceof Vn?c.push({token:i,value:o,flags:a,injectedIn:hde(t.injector)}):c.push({token:i,value:o,flags:a})}function hde(t){t instanceof Vn||tt("getNodeInjectorContext must be called with a NodeInjector");let e=Bc(t),n=Ld(t);if(n!==null)return Hs(n,e),{lView:e,tNode:n}}function mde(t,e){let{value:n}=e;DP(t.injector)===null&&tt("An InjectorCreatedInstance event must be run within an injection context.");let r;if(typeof n=="object"&&(r=n?.constructor),r==null||!gde(r))return;let s=t.injector.get(ci,null,{optional:!0});if(s===null)return;let{standaloneInjectorToComponent:i}=Qh;i.has(s)||i.set(s,r)}function gde(t){return!!Ut(t)?.standalone}function vde(t,e){let{resolverToProviders:n}=Qh,r;t?.injector instanceof Vn?r=Ld(t.injector):r=t.injector,r===null&&tt("A ProviderConfigured event must be run within an injection context."),n.has(r)||n.set(r,[]),n.get(r).push(e)}function DP(t){let e=null;return t===void 0||(t instanceof Vn?e=Bc(t):e=t),e}function yde(t){return t!==null&&(typeof t=="object"||typeof t=="function"||typeof t=="symbol")}function bde(t){ngDevMode&&Fe(t,"component"),tb(pH(t),3),EH(t).forEach(e=>wde(e))}function wde(t){let e=pH(t);e[dt]|=1024,hT(e)}function oC(t,e){let n=t[de];for(let r=He;r{let a={value:o.value},c=o.flags;a.flags={optional:(8&c)===8,host:(1&c)===1,self:(2&c)===2,skipSelf:(4&c)===4};for(let u=0;u{let a=o.injectedIn?.tNode;if(a===void 0)return!1;let c=Ld(e);return dl(a),dl(c),a===c})}function _de(t){let{standaloneInjectorToComponent:e}=ab();if(e.has(t))return e.get(t);let n=t.get(ml,null,{self:!0,optional:!0});return n===null||n.instance===null?null:n.instance.constructor}function Ide(t){let e=Ld(t),{resolverToProviders:n}=ab();return n.get(e)??[]}function kde(t){let e=new Map,r=Ade(e,new Set);return TS(t,r,[],new Set),e}function Ade(t,e){return(n,r)=>{if(t.has(n)||t.set(n,[r]),!e.has(r))for(let s of t.keys()){let i=t.get(s),o=yS(r);if(!o){let u=r.ngModule;o=yS(u)}if(!o)return;let a=i[0],c=!1;bh(o.imports,u=>{c||(c=u.ngModule===a||u===a,c&&t.get(s)?.unshift(r))})}e.add(r)}}function Mde(t){let e=ab().resolverToProviders.get(t)??[];if(Pde(t))return e;let n=_de(t);if(n===null)return e;let r=kde(n),s=[];for(let i of e){let o=i.provider,a=o.provide;if(a===li||a===_A)continue;let c=r.get(o)??[];!!Ut(n)?.standalone&&(c=[n,...c]),s.push({...i,importPath:c})}return s}function Pde(t){return t instanceof ga&&t.scopes.has("platform")}function Nde(t){if(t instanceof Vn)return Ide(t);if(t instanceof ci)return Mde(t);tt("getInjectorProviders only supports NodeInjector and EnvironmentInjector")}function Rde(t){if(t instanceof Vn){let e=Bc(t),n=Ld(t);return Hs(n,e),{type:"element",source:xs(n,e)}}return t instanceof ga?{type:"environment",source:t.source??null}:t instanceof wh?{type:"null",source:null}:null}function yj(t){let e=[t];return $2(t,e),e}function $2(t,e){let n=Fde(t);if(n===null){if(t instanceof Vn){let r=e[0];if(r instanceof Vn){let s=Lde(r);s===null&&tt("NodeInjector must have some connection to the module injector tree"),e.push(s),$2(s,e)}return e}}else e.push(n),$2(n,e);return e}function Fde(t){if(t instanceof ga)return t.parent;let e,n;if(t instanceof Vn)e=Ld(t),n=Bc(t);else{if(t instanceof wh)return null;if(t instanceof Ic)return t.parentInjector;tt("getInjectorParent only support injectors of type R3Injector, NodeInjector, NullInjector")}let r=ZC(e,n);if(eM(r)){let s=o0(r),i=a0(r,n),a=i[de].data[s+8];return new Vn(a,i)}else{let i=n[or].injector?.parent;if(i instanceof Vn)return i}return null}function Lde(t){let e;t instanceof Vn?e=Bc(t):tt("getModuleInjectorOfNodeInjector must be called with a NodeInjector");let n=e[or],r=n instanceof Ic?n.parentInjector:n.parent;return r||tt("NodeInjector must have some connection to the module injector tree"),r}function Ode(t){return t.kind==="computed"}function Bde(t){return t.kind==="template"}function $de(t){return t.kind==="effect"}function Vde(t){return t.kind==="signal"}function Hde(t){let e=Ld(t);dl(e);let n=Bc(t);ui(n);let r=n[e.index];return ui(r),r[_i]}function jde(t){let e=Array.from(t.keys()),n=[],r=[];for(let[s,i]of t.entries()){let o=e.indexOf(s);Ode(s)||Vde(s)?n.push({label:s.debugName,value:s.value,kind:s.kind}):Bde(s)?n.push({label:s.debugName??s.lView?.[Mn]?.tagName?.toLowerCase?.(),kind:s.kind}):$de(s)?n.push({label:s.debugName,kind:s.kind}):n.push({label:s.debugName,kind:s.kind});for(let a of i)r.push({consumer:o,producer:e.indexOf(a)})}return{nodes:n,edges:r}}function Ude(t){let e=t;return t instanceof Vn&&(e=Bc(t)),(ab().resolverToEffects.get(e)??[]).map(s=>s[rr])}function bj(t,e=new Map){for(let n of t){if(e.has(n))continue;let r=n.producerNode??[];e.set(n,r),bj(r,e)}return e}function qde(t){let e=null;if(!(t instanceof Vn)&&!(t instanceof ga))return tt("getSignalGraph must be called with a NodeInjector or R3Injector");t instanceof Vn&&(e=Hde(t));let n=Ude(t),r=e?[e,...n]:n,s=bj(r);return jde(s)}var eS="ng",Wde={\u0275getDependenciesFromInjectable:Tde,\u0275getInjectorProviders:Nde,\u0275getInjectorResolutionPath:yj,\u0275getInjectorMetadata:Rde,\u0275setProfiler:tie,\u0275getSignalGraph:qde,\u0275getDeferBlocks:Ede,getDirectiveMetadata:poe,getComponent:$S,getContext:bH,getListeners:TH,getOwningComponent:wH,getHostElement:CH,getInjector:xH,getRootComponents:EH,getDirectives:SH,applyChanges:bde,isSignal:oM},K8=!1;function zde(){if(!K8){K8=!0,typeof window<"u"&&ude();for(let[t,e]of Object.entries(Wde))Gde(t,e)}}function Gde(t,e){wj(t,e)}function Zde(t,e){wj(t,e)}function wj(t,e){if(typeof COMPILED>"u"||!COMPILED){let n=Yn;ngDevMode&&Fe(e,"function not defined"),n[eS]??(n[eS]={}),n[eS][t]=e}}var CT=new $e(""),Hd=new $e(""),Yu=class Yu{constructor(e,n,r){l(this,"_ngZone");l(this,"registry");l(this,"_isZoneStable",!0);l(this,"_callbacks",[]);l(this,"_taskTrackingZone",null);l(this,"_destroyRef");this._ngZone=e,this.registry=n,MA()&&(this._destroyRef=fe(Es,{optional:!0})??void 0),_P||(Ej(r),r.addToWindow(n)),this._watchAngularEvents(),e.run(()=>{this._taskTrackingZone=typeof Zone>"u"?null:Zone.current.get("TaskTrackingZone")})}_watchAngularEvents(){let e=this._ngZone.onUnstable.subscribe({next:()=>{this._isZoneStable=!1}}),n=this._ngZone.runOutsideAngular(()=>this._ngZone.onStable.subscribe({next:()=>{qt.assertNotInAngularZone(),queueMicrotask(()=>{this._isZoneStable=!0,this._runCallbacksIfReady()})}}));this._destroyRef?.onDestroy(()=>{e.unsubscribe(),n.unsubscribe()})}isStable(){return this._isZoneStable&&!this._ngZone.hasPendingMacrotasks}_runCallbacksIfReady(){if(this.isStable())queueMicrotask(()=>{for(;this._callbacks.length!==0;){let e=this._callbacks.pop();clearTimeout(e.timeoutId),e.doneCb()}});else{let e=this.getPendingTasks();this._callbacks=this._callbacks.filter(n=>n.updateCb&&n.updateCb(e)?(clearTimeout(n.timeoutId),!1):!0)}}getPendingTasks(){return this._taskTrackingZone?this._taskTrackingZone.macroTasks.map(e=>({source:e.source,creationLocation:e.creationLocation,data:e.data})):[]}addCallback(e,n,r){let s=-1;n&&n>0&&(s=setTimeout(()=>{this._callbacks=this._callbacks.filter(i=>i.timeoutId!==s),e()},n)),this._callbacks.push({doneCb:e,timeoutId:s,updateCb:r})}whenStable(e,n,r){if(r&&!this._taskTrackingZone)throw new Error('Task tracking zone is required when passing an update callback to whenStable(). Is "zone.js/plugins/task-tracking" loaded?');this.addCallback(e,n,r),this._runCallbacksIfReady()}registerApplication(e){this.registry.registerApplication(e,this)}unregisterApplication(e){this.registry.unregisterApplication(e)}findProviders(e,n,r){return[]}};l(Yu,"\u0275fac",function(n){return new(n||Yu)(Zr(qt),Zr(gl),Zr(Hd))}),l(Yu,"\u0275prov",hn({token:Yu,factory:Yu.\u0275fac}));var Rc=Yu;(typeof ngDevMode>"u"||ngDevMode)&&Us(Rc,[{type:St}],()=>[{type:qt},{type:gl},{type:void 0,decorators:[{type:Ke,args:[Hd]}]}],null);var Xu=class Xu{constructor(){l(this,"_applications",new Map)}registerApplication(e,n){this._applications.set(e,n)}unregisterApplication(e){this._applications.delete(e)}unregisterAllApplications(){this._applications.clear()}getTestability(e){return this._applications.get(e)||null}getAllTestabilities(){return Array.from(this._applications.values())}getAllRootElements(){return Array.from(this._applications.keys())}findTestabilityInTree(e,n=!0){return _P?.findTestabilityInTree(this,e,n)??null}};l(Xu,"\u0275fac",function(n){return new(n||Xu)}),l(Xu,"\u0275prov",hn({token:Xu,factory:Xu.\u0275fac,providedIn:"platform"}));var gl=Xu;(typeof ngDevMode>"u"||ngDevMode)&&Us(gl,[{type:St,args:[{providedIn:"platform"}]}],null,null);function Ej(t){_P=t}var _P,NC=class NC{};l(NC,"\u0275prov",hn({token:NC,providedIn:"root",factory:()=>new aC}));var D0=NC,aC=class{constructor(){l(this,"queuedEffectCount",0);l(this,"queues",new Map)}schedule(e){this.enqueue(e)}remove(e){let n=e.zone,r=this.queues.get(n);r.has(e)&&(r.delete(e),this.queuedEffectCount--)}enqueue(e){let n=e.zone;this.queues.has(n)||this.queues.set(n,new Set);let r=this.queues.get(n);r.has(e)||(this.queuedEffectCount++,r.add(e))}flush(){for(;this.queuedEffectCount>0;)for(let[e,n]of this.queues)e===null?this.flushQueue(n):e.run(()=>this.flushQueue(n))}flushQueue(e){for(let n of e)e.delete(n),this.queuedEffectCount--,n.run()}};function jd(t){return!!t&&typeof t.then=="function"}function Kh(t){return!!t&&typeof t.subscribe=="function"}var IP=new $e(ngDevMode?"Application Initializer":"");function Yde(t){return ma([{provide:IP,multi:!0,useValue:t}])}var Qu=class Qu{constructor(){l(this,"resolve");l(this,"reject");l(this,"initialized",!1);l(this,"done",!1);l(this,"donePromise",new Promise((e,n)=>{this.resolve=e,this.reject=n}));l(this,"appInits",fe(IP,{optional:!0})??[]);l(this,"injector",fe(Ln));if((typeof ngDevMode>"u"||ngDevMode)&&!Array.isArray(this.appInits))throw new ne(-209,`Unexpected type of the \`APP_INITIALIZER\` token value (expected an array, but got ${typeof this.appInits}). Please check that the \`APP_INITIALIZER\` token is configured as a \`multi: true\` provider.`)}runInitializers(){if(this.initialized)return;let e=[];for(let r of this.appInits){let s=AA(this.injector,r);if(jd(s))e.push(s);else if(Kh(s)){let i=new Promise((o,a)=>{s.subscribe({complete:o,error:a})});e.push(i)}}let n=()=>{this.done=!0,this.resolve()};Promise.all(e).then(()=>{n()}).catch(r=>{this.reject(r)}),e.length===0&&n(),this.initialized=!0}};l(Qu,"\u0275fac",function(n){return new(n||Qu)}),l(Qu,"\u0275prov",hn({token:Qu,factory:Qu.\u0275fac,providedIn:"root"}));var Ph=Qu;(typeof ngDevMode>"u"||ngDevMode)&&Us(Ph,[{type:St,args:[{providedIn:"root"}]}],()=>[],null);var lb=new $e(ngDevMode?"appBootstrapListener":"");function xj(){ngDevMode&&zde()}function Sj(){xI(()=>{throw new ne(600,ngDevMode&&"Writing to signals is not allowed in a `computed`.")})}function Cj(t){return t.isBoundToModule}var V2=class{constructor(e,n){l(this,"name");l(this,"token");this.name=e,this.token=n}},J8=10;function Tj(t,e){return Array.isArray(e)?e.reduce(Tj,t):{...t,...e}}var Ku=class Ku{constructor(){l(this,"_runningTick",!1);l(this,"_destroyed",!1);l(this,"_destroyListeners",[]);l(this,"_views",[]);l(this,"internalErrorHandler",fe(iH));l(this,"afterRenderManager",fe(Sh));l(this,"zonelessEnabled",fe(Od));l(this,"rootEffectScheduler",fe(D0));l(this,"dirtyFlags",0);l(this,"tracingSnapshot",null);l(this,"externalTestViews",new Set);l(this,"afterTick",new si);l(this,"componentTypes",[]);l(this,"components",[]);l(this,"isStable",fe(ya).hasPendingTasks.pipe(Vu(e=>!e)));l(this,"_injector",fe(ci));l(this,"_rendererFactory",null);l(this,"tickImpl",()=>{if((typeof ngDevMode>"u"||ngDevMode)&&ky(this._destroyed),this._runningTick)throw new ne(101,ngDevMode&&"ApplicationRef.tick is called recursively");let e=Et(null);try{if(this._runningTick=!0,this.synchronize(),typeof ngDevMode>"u"||ngDevMode)for(let n of this.allViews)n.checkNoChanges()}catch(n){this.internalErrorHandler(n)}finally{this._runningTick=!1,this.tracingSnapshot?.dispose(),this.tracingSnapshot=null,Et(e),this.afterTick.next(),kn(13)}});fe(Fo,{optional:!0})}get allViews(){return[...this.externalTestViews.keys(),...this._views]}get destroyed(){return this._destroyed}whenStable(){let e;return new Promise(n=>{e=this.isStable.subscribe({next:r=>{r&&n()}})}).finally(()=>{e.unsubscribe()})}get injector(){return this._injector}bootstrap(e,n){return this.bootstrapImpl(e,n)}bootstrapImpl(e,n,r=Ln.NULL){kn(10),(typeof ngDevMode>"u"||ngDevMode)&&ky(this._destroyed);let s=e instanceof uP;if(!this._injector.get(Ph).done){let f="";throw(typeof ngDevMode>"u"||ngDevMode)&&(f="Cannot bootstrap as there are still asynchronous initializers running."+(!s&&Sc(e)?"":" Bootstrap components in the `ngDoBootstrap` method of the root module.")),new ne(405,f)}let o;s?o=e:o=this._injector.get(ib).resolveComponentFactory(e),this.componentTypes.push(o.componentType);let a=Cj(o)?void 0:this._injector.get(ml),c=n||o.selector,u=o.create(r,[],c,a),d=u.location.nativeElement,p=u.injector.get(CT,null);return p?.registerApplication(d),u.onDestroy(()=>{this.detachView(u.hostView),fS(this.components,u),p?.unregisterApplication(d)}),this._loadComponent(u),(typeof ngDevMode>"u"||ngDevMode)&&this._injector.get(Ai).log("Angular is running in development mode."),kn(11,u),u}tick(){this.zonelessEnabled||(this.dirtyFlags|=1),this._tick()}_tick(){kn(12),this.tracingSnapshot!==null?this.tracingSnapshot.run(g0.CHANGE_DETECTION,this.tickImpl):this.tickImpl()}synchronize(){this._rendererFactory===null&&!this._injector.destroyed&&(this._rendererFactory=this._injector.get(Sd,null,{optional:!0}));let e=0;for(;this.dirtyFlags!==0&&e++"u"||ngDevMode)&&e>=J8)throw new ne(103,ngDevMode&&"Infinite change detection while refreshing application views. Ensure views are not calling `markForCheck` on every template execution or that afterRender hooks always mark views for check.")}synchronizeOnce(){if(this.dirtyFlags&16&&(this.dirtyFlags&=-17,this.rootEffectScheduler.flush()),this.dirtyFlags&7){let e=!!(this.dirtyFlags&1);this.dirtyFlags&=-8,this.dirtyFlags|=8;for(let{_lView:n,notifyErrorHandler:r}of this.allViews)Dj(n,r,e,this.zonelessEnabled);if(this.dirtyFlags&=-5,this.syncDirtyFlagsWithViews(),this.dirtyFlags&23)return}else this._rendererFactory?.begin?.(),this._rendererFactory?.end?.();this.dirtyFlags&8&&(this.dirtyFlags&=-9,this.afterRenderManager.execute()),this.syncDirtyFlagsWithViews()}syncDirtyFlagsWithViews(){if(this.allViews.some(({_lView:e})=>H0(e))){this.dirtyFlags|=2;return}else this.dirtyFlags&=-8}attachView(e){(typeof ngDevMode>"u"||ngDevMode)&&ky(this._destroyed);let n=e;this._views.push(n),n.attachToAppRef(this)}detachView(e){(typeof ngDevMode>"u"||ngDevMode)&&ky(this._destroyed);let n=e;fS(this._views,n),n.detachFromAppRef()}_loadComponent(e){this.attachView(e.hostView),this.tick(),this.components.push(e);let n=this._injector.get(lb,[]);if(ngDevMode&&!Array.isArray(n))throw new ne(-209,`Unexpected type of the \`APP_BOOTSTRAP_LISTENER\` token value (expected an array, but got ${typeof n}). Please check that the \`APP_BOOTSTRAP_LISTENER\` token is configured as a \`multi: true\` provider.`);n.forEach(r=>r(e))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(e=>e()),this._views.slice().forEach(e=>e.destroy())}finally{this._destroyed=!0,this._views=[],this._destroyListeners=[]}}onDestroy(e){return(typeof ngDevMode>"u"||ngDevMode)&&ky(this._destroyed),this._destroyListeners.push(e),()=>fS(this._destroyListeners,e)}destroy(){if(this._destroyed)throw new ne(406,ngDevMode&&"This instance of the `ApplicationRef` has already been destroyed.");let e=this._injector;e.destroy&&!e.destroyed&&e.destroy()}get viewCount(){return this._views.length}};l(Ku,"\u0275fac",function(n){return new(n||Ku)}),l(Ku,"\u0275prov",hn({token:Ku,factory:Ku.\u0275fac,providedIn:"root"}));var yr=Ku;(typeof ngDevMode>"u"||ngDevMode)&&Us(yr,[{type:St,args:[{providedIn:"root"}]}],()=>[],null);function ky(t){t&&console.warn(gn(406,"This instance of the `ApplicationRef` has already been destroyed."))}function fS(t,e){let n=t.indexOf(e);n>-1&&t.splice(n,1)}function Dj(t,e,n,r){if(!n&&!H0(t))return;hT(t,e,n&&!r?0:1)}function _j(t){let e=re(),n=Bt();if(Xh(e,n),!Aj(0,e))return;let r=e[or],s=Cs(e,n),i=t(()=>qs(0,e,n),r);W0(0,s,i)}function Ij(t,e){if(typeof ngServerMode<"u"&&ngServerMode)return;let n=re(),r=n[or],s=Bt(),i=n[de],o=Qr(i,s);if(o.loadingState===pr.NOT_STARTED){let a=Cs(n,s),u=t(()=>cb(o,n,s),r);W0(1,a,u)}}function kj(t,e,n){if(typeof ngServerMode<"u"&&ngServerMode)return;let r=e[or],s=Cs(e,n),i=s[Ch];ngDevMode&&CM(i);let o=t(()=>Vc(r,i),r);W0(2,s,o)}function cb(t,e,n){TT(t,e,n)}function TT(t,e,n){let r=e[or],s=e[de];if(t.loadingState!==pr.NOT_STARTED)return t.loadingPromise??Promise.resolve();let i=Cs(e,n),o=Moe(s,t);t.loadingState=pr.IN_PROGRESS,lS(1,i);let a=t.dependencyResolverFn;if(ngDevMode){let u=r.get(pj,null,{optional:!0});u&&(a=u.intercept(a))}let c=r.get(c0).add();return a?(t.loadingPromise=Promise.allSettled(a()).then(u=>{let d=!1,p=[],f=[];for(let h of u)if(h.status==="fulfilled"){let m=h.value,g=Ut(m)||ls(m);if(g)p.push(g);else{let v=Ti(m);v&&f.push(v)}}else{d=!0;break}if(d){if(t.loadingState=pr.FAILED,t.errorTmplIndex===null){let h=ngDevMode?b0(e):"",m=new ne(-750,ngDevMode&&`Loading dependencies for \`@defer\` block failed, but no \`@error\` block was configured${h}. Consider using the \`@error\` block to render an error state.`);QM(e,m)}}else{t.loadingState=pr.COMPLETE;let h=o.tView;if(p.length>0){h.directiveRegistry=g8(h.directiveRegistry,p);let m=p.map(v=>v.type),g=IA(!1,...m);t.providers=g}f.length>0&&(h.pipeRegistry=g8(h.pipeRegistry,f))}}),t.loadingPromise.finally(()=>{t.loadingPromise=null,c()})):(t.loadingPromise=Promise.resolve().then(()=>{t.loadingPromise=null,t.loadingState=pr.COMPLETE,c()}),t.loadingPromise)}function Aj(t,e){return!(t===0&&typeof ngServerMode<"u"&&ngServerMode||e[or].get(fj,null,{optional:!0})?.behavior===WS.Manual)}function qs(t,e,n){let r=e[de],s=e[n.index];if(ngDevMode&&oo(s),!Aj(t,e))return;let i=Cs(e,n),o=Qr(r,n);switch(FH(i),o.loadingState){case pr.NOT_STARTED:al(bn.Loading,n,s),TT(o,e,n),o.loadingState===pr.IN_PROGRESS&&Q8(o,n,s);break;case pr.IN_PROGRESS:al(bn.Loading,n,s),Q8(o,n,s);break;case pr.COMPLETE:ngDevMode&&BH(o),al(bn.Complete,n,s);break;case pr.FAILED:al(bn.Error,n,s);break;default:ngDevMode&&tt("Unknown defer block state")}}async function Vc(t,e,n){let r=t.get(Da);if(r.hydrating.has(e))return;let{parentBlockPromise:i,hydrationQueue:o}=Koe(e,t);if(o.length===0)return;i!==null&&o.shift(),Kde(r,o),i!==null&&await i;let a=o[0];r.has(a)?await eV(t,o,n):r.awaitParentBlock(a,async()=>await eV(t,o,n))}async function eV(t,e,n){let r=t.get(Da),s=r.hydrating,i=t.get(ya),o=i.add();for(let c=0;c-1?n.get(e[r]):null;s&&bT(s.lContainer)}function tV(t,e){let n=e.hydrating;for(let r in t)n.get(r)?.reject();e.cleanup(t)}function Kde(t,e){for(let n of e)t.hydrating.set(n,Promise.withResolvers())}function Jde(t){return new Promise(e=>yM(e,{injector:t}))}async function epe(t){let{tNode:e,lView:n}=t,r=Cs(n,e);return new Promise(s=>{tpe(r,s),qs(2,n,e)})}function tpe(t,e){Array.isArray(t[gh])||(t[gh]=[]),t[gh].push(e)}function wr(t,e,n){return t===0?nV(e,n):t===2?!nV(e,n):!(typeof ngServerMode<"u"&&ngServerMode)}function nV(t,e){let n=t[or],r=Qr(t[de],e),s=Z0(n),i=r.flags!==null&&(r.flags&1)===1;if(typeof ngServerMode<"u"&&ngServerMode)return!s||!i;let a=Cs(t,e)[Ch]!==null;return!(i&&a&&s)}function Hc(t,e){let n=Qr(t,e);return n.hydrateTriggers??(n.hydrateTriggers=new Map)}function npe(t,e,n){let r=[],s=[],i=[],o=[];for(let[a,c]of e){let u=n.get(a);if(u!==void 0){let d=c.data[_c],p=u;for(let f=0;fVc(t,n.blockName),t);r.addCleanupFn(n.blockName,i)}}function spe(t,e){if(e.length>0){let n=t.get(Da);for(let r of e){let s=wM(r.el,()=>Vc(t,r.blockName),t);n.addCleanupFn(r.blockName,s)}}}function ipe(t,e){for(let n of e){let r=t.get(Da),s=()=>Vc(t,n.blockName),o=ST(n.delay)(s,t);r.addCleanupFn(n.blockName,o)}}function ope(t,e){for(let n of e)Vc(t,n.blockName)}var rV=!1;function ape(t){rV||(rV=!0,t.get(Ai).log(gn(-751,"Angular has detected that this application contains `@defer` blocks and the hot module replacement (HMR) mode is enabled. All `@defer` block dependencies will be loaded eagerly.")))}function Mj(t,e,n,r,s,i,o,a,c,u){let d=re(),p=nt(),f=t+He,h=T0(d,p,t,null,0,0),m=d[or];if(p.firstCreatePass){Ss("NgDefer"),ngDevMode&&typeof ngHmrMode<"u"&&ngHmrMode&&ape(m);let M={primaryTmplIndex:e,loadingTmplIndex:r??null,placeholderTmplIndex:s??null,errorTmplIndex:i??null,placeholderBlockConfig:null,loadingBlockConfig:null,dependencyResolverFn:n??null,loadingState:pr.NOT_STARTED,loadingPromise:null,providers:null,hydrateTriggers:null,debug:null,flags:u??0};c?.(p,M,a,o),koe(p,f,M)}let g=d[f];M4(g,h,d);let v=null,w=null;if(g[Mo]?.length>0){let M=g[Mo][0].data;w=M[hM]??null,v=M[VS]}let b=[null,bd.Initial,null,null,null,null,w,v,null,null];Ioe(d,f,b);let D=null;w!==null&&(ngDevMode&&Yoe(m),D=m.get(Da),D.add(w,{lView:d,tNode:h,lContainer:g}));let B=()=>{FH(b),w!==null&&D?.cleanup([w])};W0(0,b,()=>VA(d,B)),zC(d,B)}function Pj(t){let e=re(),n=Hn();if(ngDevMode&&br(e[de],n,"when "),!wr(0,e,n))return;let r=ao();if(vr(e,r,t)){let s=Et(null);try{let i=!!t,a=Cs(e,n)[wa];i===!1&&a===bd.Initial?Xh(e,n):i===!0&&(a===bd.Initial||a===bn.Placeholder)&&qs(0,e,n)}finally{Et(s)}}}function Nj(t){let e=re(),n=Hn();if(ngDevMode&&br(e[de],n,"prefetch when "),!wr(1,e,n))return;let r=ao();if(vr(e,r,t)){let s=Et(null);try{let i=!!t,o=e[de],a=Hn(),c=Qr(o,a);i===!0&&c.loadingState===pr.NOT_STARTED&&cb(c,e,a)}finally{Et(s)}}}function Rj(t){let e=re(),n=Hn();if(ngDevMode&&br(e[de],n,"hydrate when "),!wr(2,e,n))return;let r=ao(),s=nt();if(Hc(s,n).set(6,null),vr(e,r,t))if(typeof ngServerMode<"u"&&ngServerMode)qs(2,e,n);else{let o=e[or],a=Et(null);try{if(!!t===!0){let d=Cs(e,n)[Ch];ngDevMode&&CM(d),Vc(o,d)}}finally{Et(a)}}}function Fj(){let t=re(),e=Bt();if(ngDevMode&&br(t[de],e,"hydrate never"),!wr(2,t,e))return;Hc(nt(),e).set(7,null),typeof ngServerMode<"u"&&ngServerMode&&qs(2,t,e)}function Lj(){let t=re(),e=Bt();ngDevMode&&br(t[de],e,"on idle"),wr(0,t,e)&&_j(xT)}function Oj(){let t=re(),e=Bt();ngDevMode&&br(t[de],e,"prefetch on idle"),wr(1,t,e)&&Ij(xT)}function Bj(){let t=re(),e=Bt();if(ngDevMode&&br(t[de],e,"hydrate on idle"),!wr(2,t,e))return;Hc(nt(),e).set(0,null),typeof ngServerMode<"u"&&ngServerMode?qs(2,t,e):kj(xT,t,e)}function $j(){let t=re(),e=Bt();if(ngDevMode&&br(t[de],e,"on immediate"),!wr(0,t,e))return;Qr(t[de],e).loadingTmplIndex===null&&Xh(t,e),qs(0,t,e)}function Vj(){let t=re(),e=Bt();if(ngDevMode&&br(t[de],e,"prefetch on immediate"),!wr(1,t,e))return;let n=t[de],r=Qr(n,e);r.loadingState===pr.NOT_STARTED&&TT(r,t,e)}function Hj(){let t=re(),e=Bt();if(ngDevMode&&br(t[de],e,"hydrate on immediate"),!wr(2,t,e))return;if(Hc(nt(),e).set(1,null),typeof ngServerMode<"u"&&ngServerMode)qs(2,t,e);else{let r=t[or],i=Cs(t,e)[Ch];ngDevMode&&CM(i),Vc(r,i)}}function jj(t){let e=re(),n=Bt();ngDevMode&&br(e[de],n,`on timer(${t}ms)`),wr(0,e,n)&&_j(ST(t))}function Uj(t){let e=re(),n=Bt();ngDevMode&&br(e[de],n,`prefetch on timer(${t}ms)`),wr(1,e,n)&&Ij(ST(t))}function qj(t){let e=re(),n=Bt();if(ngDevMode&&br(e[de],n,`hydrate on timer(${t}ms)`),!wr(2,e,n))return;Hc(nt(),n).set(5,{delay:t}),typeof ngServerMode<"u"&&ngServerMode?qs(2,e,n):kj(ST(t),e,n)}function Wj(t,e){let n=re(),r=Bt();ngDevMode&&br(n[de],r,`on hover${e===-1?"":"()"}`),wr(0,n,r)&&(Xh(n,r),typeof ngServerMode<"u"&&ngServerMode||Uh(n,r,t,e,HH,()=>qs(0,n,r),0))}function zj(t,e){let n=re(),r=Bt();if(ngDevMode&&br(n[de],r,`prefetch on hover${e===-1?"":"()"}`),!wr(1,n,r))return;let s=n[de],i=Qr(s,r);i.loadingState===pr.NOT_STARTED&&Uh(n,r,t,e,HH,()=>cb(i,n,r),1)}function Gj(){let t=re(),e=Bt();if(ngDevMode&&br(t[de],e,"hydrate on hover"),!wr(2,t,e))return;Hc(nt(),e).set(4,null),typeof ngServerMode<"u"&&ngServerMode&&qs(2,t,e)}function Zj(t,e){let n=re(),r=Bt();ngDevMode&&br(n[de],r,`on interaction${e===-1?"":"()"}`),wr(0,n,r)&&(Xh(n,r),typeof ngServerMode<"u"&&ngServerMode||Uh(n,r,t,e,VH,()=>qs(0,n,r),0))}function Yj(t,e){let n=re(),r=Bt();if(ngDevMode&&br(n[de],r,`prefetch on interaction${e===-1?"":"()"}`),!wr(1,n,r))return;let s=n[de],i=Qr(s,r);i.loadingState===pr.NOT_STARTED&&Uh(n,r,t,e,VH,()=>cb(i,n,r),1)}function Xj(){let t=re(),e=Bt();if(ngDevMode&&br(t[de],e,"hydrate on interaction"),!wr(2,t,e))return;Hc(nt(),e).set(3,null),typeof ngServerMode<"u"&&ngServerMode&&qs(2,t,e)}function Qj(t,e){let n=re(),r=Bt();ngDevMode&&br(n[de],r,`on viewport${e===-1?"":"()"}`),wr(0,n,r)&&(Xh(n,r),typeof ngServerMode<"u"&&ngServerMode||Uh(n,r,t,e,wM,()=>qs(0,n,r),0))}function Kj(t,e){let n=re(),r=Bt();if(ngDevMode&&br(n[de],r,`prefetch on viewport${e===-1?"":"()"}`),!wr(1,n,r))return;let s=n[de],i=Qr(s,r);i.loadingState===pr.NOT_STARTED&&Uh(n,r,t,e,wM,()=>cb(i,n,r),1)}function Jj(){let t=re(),e=Bt();if(ngDevMode&&br(t[de],e,"hydrate on viewport"),!wr(2,t,e))return;Hc(nt(),e).set(2,null),typeof ngServerMode<"u"&&ngServerMode&&qs(2,t,e)}function kP(t,e,n,r){let s=re(),i=ao();if(vr(s,i,e)){let o=nt(),a=Hn();_a(a,s,t,e,n,r),ngDevMode&&ar(o.data,a,"attr."+t,i)}return kP}function Jh(t,e){ngDevMode&&kc(2,e.length,"should have at least 3 values"),ngDevMode&&rt(e.length%2,1,"should have an odd number of values");let n=!1,r=Pn();for(let i=1;i>17&32767}function lpe(t){return ngDevMode&&_n(t,"expected number"),(t&2)==2}function cpe(t,e){return ngDevMode&&_n(t,"expected number"),ngDevMode&&r0(e,0,32767),t&131071|e<<17}function H2(t){return ngDevMode&&_n(t,"expected number"),t|2}function Id(t){return ngDevMode&&_n(t,"expected number"),(t&131068)>>2}function pk(t,e){return ngDevMode&&_n(t,"expected number"),ngDevMode&&r0(e,0,32767),t&-131069|e<<2}function upe(t){return ngDevMode&&_n(t,"expected number"),(t&1)===1}function j2(t){return ngDevMode&&_n(t,"expected number"),t|1}function dpe(t,e,n,r,s,i){ngDevMode&&RA(nt());let o=i?e.classBindings:e.styleBindings,a=_d(o),c=Id(o);t[r]=n;let u=!1,d;if(Array.isArray(n)){let p=n;d=p[1],(d===null||O0(p,d)>0)&&(u=!0)}else d=n;if(s)if(c!==0){let f=_d(t[a+1]);t[r+1]=tS(f,a),f!==0&&(t[f+1]=pk(t[f+1],r)),t[a+1]=cpe(t[a+1],r)}else t[r+1]=tS(a,0),a!==0&&(t[a+1]=pk(t[a+1],r)),a=r;else t[r+1]=tS(c,0),ngDevMode&&rt(a!==0&&c===0,!1,"Adding template bindings after hostBindings is not allowed."),a===0?a=r:t[c+1]=pk(t[c+1],r),c=r;u&&(t[r+1]=H2(t[r+1])),sV(t,d,r,!0),sV(t,d,r,!1),ppe(e,d,t,r,i),o=tS(a,c),i?e.classBindings=o:e.styleBindings=o}function ppe(t,e,n,r,s){let i=s?t.residualClasses:t.residualStyles;i!=null&&typeof e=="string"&&O0(i,e)>=0&&(n[r+1]=j2(n[r+1]))}function sV(t,e,n,r){let s=t[n+1],i=e===null,o=r?_d(s):Id(s),a=!1;for(;o!==0&&(a===!1||i);){ngDevMode&&gr(t,o);let c=t[o],u=t[o+1];fpe(c,e)&&(a=!0,t[o+1]=r?j2(u):H2(u)),o=r?_d(u):Id(u)}a&&(t[n+1]=r?H2(s):j2(s))}function fpe(t,e){return ngDevMode&&di(Array.isArray(e),!0,"Expected that 'tStylingKey' has been unwrapped"),t===null||e==null||(Array.isArray(t)?t[1]:t)===e?!0:Array.isArray(t)&&typeof e=="string"?O0(t,e)>=0:!1}var Or={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function eU(t){return t.substring(Or.key,Or.keyEnd)}function hpe(t){return t.substring(Or.value,Or.valueEnd)}function mpe(t){return rU(t),tU(t,Nh(t,0,Or.textEnd))}function tU(t,e){let n=Or.textEnd;return n===e?-1:(e=Or.keyEnd=vpe(t,Or.key=e,n),Nh(t,e,n))}function gpe(t){return rU(t),nU(t,Nh(t,0,Or.textEnd))}function nU(t,e){let n=Or.textEnd,r=Or.key=Nh(t,e,n);return n===r?-1:(r=Or.keyEnd=ype(t,r,n),r=iV(t,r,n,58),r=Or.value=Nh(t,r,n),r=Or.valueEnd=bpe(t,r,n),iV(t,r,n,59))}function rU(t){Or.key=0,Or.keyEnd=0,Or.value=0,Or.valueEnd=0,Or.textEnd=t.length}function Nh(t,e,n){for(;e32;)e++;return e}function ype(t,e,n){let r;for(;e=65&&(r&-33)<=90||r>=48&&r<=57);)e++;return e}function iV(t,e,n,r){return e=Nh(t,e,n),e32&&(a=o),i=s,s=r,r=c&-33}return a}function oV(t,e,n,r){let s=-1,i=n;for(;i>"+t.substring(n,n+1)+"<<]"+t.slice(n+1)+`'. Expecting '${e}'.`)}function $P(t,e,n){let r=re(),s=ao();if(vr(r,s,e)){let i=nt(),o=Hn();fi(i,o,r,t,e,r[pt],n,!1),ngDevMode&&ar(i.data,o,t,s)}return $P}function U2(t,e,n,r,s){KM(e,t,n,s?"class":"style",r)}function VP(t,e,n){return Oo(t,e,n,!1),VP}function HP(t,e){return Oo(t,e,null,!0),HP}function Lo(t){Bo(lU,wpe,t,!1)}function wpe(t,e){for(let n=gpe(e);n>=0;n=nU(e,n))lU(t,eU(e),hpe(e))}function iU(t){Bo(Dpe,ka,t,!0)}function ka(t,e){for(let n=mpe(e);n>=0;n=tU(e,n))Mi(t,eU(e),!0)}function Oo(t,e,n,r){let s=re(),i=nt(),o=wl(2);if(i.firstUpdatePass&&aU(i,t,o,r),e!==ct&&vr(s,o,e)){let a=i.data[Vr()];cU(i,a,s,s[pt],t,s[o+1]=Ipe(e,n),r,o)}}function Bo(t,e,n,r){let s=nt(),i=wl(2);s.firstUpdatePass&&aU(s,null,i,r);let o=re();if(n!==ct&&vr(o,i,n)){let a=s.data[Vr()];if(uU(a,r)&&!oU(s,i)){if(ngDevMode){let u=s.data[i];rt(Array.isArray(u)?u[1]:u,!1,"Styling linked list shadow input should be marked as 'false'")}let c=r?a.classesWithoutHost:a.stylesWithoutHost;ngDevMode&&r===!1&&c!==null&&rt(c.endsWith(";"),!0,"Expecting static portion to end with ';'"),c!==null&&(n=Dk(c,n||"")),U2(s,a,o,n,r)}else _pe(s,a,o,o[pt],o[i+1],o[i+1]=Tpe(t,e,n),r,i)}}function oU(t,e){return e>=t.expandoStartIndex}function aU(t,e,n,r){ngDevMode&&RA(t);let s=t.data;if(s[n+1]===null){let i=s[Vr()];ngDevMode&&Fe(i,"TNode expected");let o=oU(t,n);uU(i,r)&&e===null&&!o&&(e=!1),e=Epe(s,i,e,r),dpe(s,i,e,n,o,r)}}function Epe(t,e,n,r){let s=GA(t),i=r?e.residualClasses:e.residualStyles;if(s===null)(r?e.classBindings:e.styleBindings)===0&&(n=fk(null,t,e,n,r),n=_0(n,e.attrs,r),i=null);else{let o=e.directiveStylingLast;if(o===-1||t[o]!==s)if(n=fk(s,t,e,n,r),i===null){let c=xpe(t,e,r);c!==void 0&&Array.isArray(c)&&(c=fk(null,t,e,c[1],r),c=_0(c,e.attrs,r),Spe(t,e,r,c))}else i=Cpe(t,e,r)}return i!==void 0&&(r?e.residualClasses=i:e.residualStyles=i),n}function xpe(t,e,n){let r=n?e.classBindings:e.styleBindings;if(Id(r)!==0)return t[_d(r)]}function Spe(t,e,n,r){let s=n?e.classBindings:e.styleBindings;ngDevMode&&di(Id(s),0,"Expecting to have at least one template styling binding."),t[_d(s)]=r}function Cpe(t,e,n){let r,s=e.directiveEnd;ngDevMode&&di(e.directiveStylingLast,-1,"By the time this function gets called at least one hostBindings-node styling instruction must have executed.");for(let i=1+e.directiveStylingLast;i0;){let c=t[s],u=Array.isArray(c),d=u?c[1]:c,p=d===null,f=n[s+1];f===ct&&(f=p?un:void 0);let h=p?ZI(f,r):d===r?f:void 0;if(u&&!lC(h)&&(h=ZI(c,r)),lC(h)&&(a=h,o))return a;let m=t[s+1];s=o?_d(m):Id(m)}if(e!==null){let c=i?e.residualClasses:e.residualStyles;c!=null&&(a=ZI(c,r))}return a}function lC(t){return t!==void 0}function Ipe(t,e){return t==null||t===""||(typeof e=="string"?t=t+e:typeof t=="object"&&(t=tn(ds(t)))),t}function uU(t,e){return(t.flags&(e?8:16))!==0}function dU(t,e,n){let r=re(),s=em(r,t,e,n);Bo(Mi,ka,s,!0)}function pU(t,e,n,r,s){let i=re(),o=tm(i,t,e,n,r,s);Bo(Mi,ka,o,!0)}function fU(t,e,n,r,s,i,o){let a=re(),c=nm(a,t,e,n,r,s,i,o);Bo(Mi,ka,c,!0)}function hU(t,e,n,r,s,i,o,a,c){let u=re(),d=rm(u,t,e,n,r,s,i,o,a,c);Bo(Mi,ka,d,!0)}function mU(t,e,n,r,s,i,o,a,c,u,d){let p=re(),f=sm(p,t,e,n,r,s,i,o,a,c,u,d);Bo(Mi,ka,f,!0)}function gU(t,e,n,r,s,i,o,a,c,u,d,p,f){let h=re(),m=im(h,t,e,n,r,s,i,o,a,c,u,d,p,f);Bo(Mi,ka,m,!0)}function vU(t,e,n,r,s,i,o,a,c,u,d,p,f,h,m){let g=re(),v=om(g,t,e,n,r,s,i,o,a,c,u,d,p,f,h,m);Bo(Mi,ka,v,!0)}function yU(t,e,n,r,s,i,o,a,c,u,d,p,f,h,m,g,v){let w=re(),b=am(w,t,e,n,r,s,i,o,a,c,u,d,p,f,h,m,g,v);Bo(Mi,ka,b,!0)}function bU(t){let e=re(),n=Jh(e,t);Bo(Mi,ka,n,!0)}function wU(){let t=re()[Kn][wn];return ngDevMode&&Fe(t,"Expected component instance to be defined"),t}var q2=class{destroy(e){}updateValue(e,n){}swap(e,n){let r=Math.min(e,n),s=Math.max(e,n),i=this.detach(s);if(s-r>1){let o=this.detach(r);this.attach(r,i),this.attach(s,o)}else this.attach(r,i)}move(e,n){this.attach(n,this.detach(e))}};function hk(t,e,n,r,s){return t===n&&Object.is(e,r)?1:Object.is(s(t,e),s(n,r))?-1:0}function mk(t,e,n){let r=t.get(e);r!==void 0?r.add(n):t.set(e,new Set([n]))}function kpe(t,e,n){let r,s,i=0,o=t.length-1,a=ngDevMode?new Map:void 0;if(Array.isArray(e)){let c=e.length-1;for(;i<=o&&i<=c;){let u=t.at(i),d=e[i];ngDevMode&&mk(a,n(i,d),i);let p=hk(i,u,i,d,n);if(p!==0){p<0&&t.updateValue(i,d),i++;continue}let f=t.at(o),h=e[c];ngDevMode&&mk(a,n(c,h),c);let m=hk(o,f,c,h,n);if(m!==0){m<0&&t.updateValue(o,h),o--,c--;continue}let g=n(i,u),v=n(o,f),w=n(i,d);if(Object.is(w,v)){let b=n(c,h);Object.is(b,g)?(t.swap(i,o),t.updateValue(o,h),c--,o--):t.move(o,i),t.updateValue(i,d),i++;continue}if(r??(r=new cC),s??(s=cV(t,i,o,n)),W2(t,r,i,w))t.updateValue(i,d),i++,o++;else if(s.has(w))r.set(g,t.detach(i)),o--;else{let b=t.create(i,e[i]);t.attach(i,b),i++,o++}}for(;i<=c;)lV(t,r,n,i,e[i]),i++}else if(e!=null){let c=e[Symbol.iterator](),u=c.next();for(;!u.done&&i<=o;){let d=t.at(i),p=u.value;ngDevMode&&mk(a,n(i,p),i);let f=hk(i,d,i,p,n);if(f!==0)f<0&&t.updateValue(i,p),i++,u=c.next();else{r??(r=new cC),s??(s=cV(t,i,o,n));let h=n(i,p);if(W2(t,r,i,h))t.updateValue(i,p),i++,o++,u=c.next();else if(!s.has(h))t.attach(i,t.create(i,p)),i++,o++,u=c.next();else{let m=n(i,d);r.set(m,t.detach(i)),o--}}}for(;!u.done;)lV(t,r,n,t.length,u.value),u=c.next()}for(;i<=o;)t.destroy(t.detach(o--));if(r?.forEach(c=>{t.destroy(c)}),ngDevMode){let c=[];for(let[u,d]of a)if(d.size>1){let p=[...d].sort((f,h)=>f-h);for(let f=1;f0){let u=gn(-955,`The provided track expression resulted in duplicated keys for a given collection. Adjust the tracking expression such that it uniquely identifies all the items in the collection. Duplicated keys were: +`+c.join(`, +`)+".");console.warn(u)}}}function W2(t,e,n,r){return e!==void 0&&e.has(r)?(t.attach(n,e.get(r)),e.delete(r),!0):!1}function lV(t,e,n,r,s){if(W2(t,e,r,n(r,s)))t.updateValue(r,s);else{let i=t.create(r,s);t.attach(r,i)}}function cV(t,e,n,r){let s=new Set;for(let i=e;i<=n;i++)s.add(r(i,t.at(i)));return s}var cC=class{constructor(){l(this,"kvMap",new Map);l(this,"_vMap")}has(e){return this.kvMap.has(e)}delete(e){if(!this.has(e))return!1;let n=this.kvMap.get(e);return this._vMap!==void 0&&this._vMap.has(n)?(this.kvMap.set(e,this._vMap.get(n)),this._vMap.delete(n)):this.kvMap.delete(e),!0}get(e){return this.kvMap.get(e)}set(e,n){if(this.kvMap.has(e)){let r=this.kvMap.get(e);if(ngDevMode&&r===n)throw new Error(`Detected a duplicated value ${n} for the key ${e}`);this._vMap===void 0&&(this._vMap=new Map);let s=this._vMap;for(;s.has(r);)r=s.get(r);s.set(r,n)}else this.kvMap.set(e,n)}forEach(e){for(let[n,r]of this.kvMap)if(e(r,n),this._vMap!==void 0){let s=this._vMap;for(;s.has(r);)r=s.get(r),e(r,n)}}};function EU(t,e){Ss("NgControlFlow");let n=re(),r=ao(),s=n[r]!==ct?n[r]:-1,i=s!==-1?uC(n,He+s):void 0,o=0;if(vr(n,r,t)){let a=Et(null);try{if(i!==void 0&&iP(i,o),t!==-1){let c=He+t,u=uC(n,c),d=X2(n[de],c),p=Ih(u,d.tView.ssrId),f=zh(n,d,e,{dehydratedView:p});Gh(u,f,o,xd(d,p))}}finally{Et(a)}}else if(i!==void 0){let a=t4(i,o);a!==void 0&&(a[wn]=e)}}var z2=class{constructor(e,n,r){l(this,"lContainer");l(this,"$implicit");l(this,"$index");this.lContainer=e,this.$implicit=n,this.$index=r}get $count(){return this.lContainer.length-Wn}};function xU(t){return t}function jP(t,e){return e}var G2=class{constructor(e,n,r){l(this,"hasEmptyBlock");l(this,"trackByFn");l(this,"liveCollection");this.hasEmptyBlock=e,this.trackByFn=n,this.liveCollection=r}};function SU(t,e,n,r,s,i,o,a,c,u,d,p,f){Ss("NgControlFlow"),ngDevMode&&WV(o,`A track expression must be a function, was ${typeof o} instead.`);let h=re(),m=nt(),g=c!==void 0,v=re(),w=a?o.bind(v[Kn][wn]):o,b=new G2(g,w);v[He+t]=b,T0(h,m,t+1,e,n,r,s,to(m.consts,i)),g&&(ngDevMode&&Fe(u,"Missing number of declarations for the empty repeater block."),ngDevMode&&Fe(d,"Missing number of bindings for the empty repeater block."),T0(h,m,t+2,c,u,d,p,to(m.consts,f)))}function Ape(t){return t.length-He>2}var Z2=class{constructor(){l(this,"created",0);l(this,"destroyed",0)}reset(){this.created=0,this.destroyed=0}recordCreate(){this.created++}recordDestroy(){this.destroyed++}wasReCreated(e){return e>0&&this.created===this.destroyed&&this.created===e}},Y2=class extends q2{constructor(n,r,s){super();l(this,"lContainer");l(this,"hostLView");l(this,"templateTNode");l(this,"operationsCounter",ngDevMode?new Z2:void 0);l(this,"needsIndexUpdate",!1);this.lContainer=n,this.hostLView=r,this.templateTNode=s}get length(){return this.lContainer.length-Wn}at(n){return this.getLView(n)[wn].$implicit}attach(n,r){let s=r[Ls];this.needsIndexUpdate||(this.needsIndexUpdate=n!==this.length),Gh(this.lContainer,r,n,xd(this.templateTNode,s))}detach(n){return this.needsIndexUpdate||(this.needsIndexUpdate=n!==this.length-1),Mpe(this.lContainer,n)}create(n,r){let s=Ih(this.lContainer,this.templateTNode.tView.ssrId),i=zh(this.hostLView,this.templateTNode,new z2(this.lContainer,r,n),{dehydratedView:s});return this.operationsCounter?.recordCreate(),i}destroy(n){eb(n[de],n),this.operationsCounter?.recordDestroy()}updateValue(n,r){this.getLView(n)[wn].$implicit=r}reset(){this.needsIndexUpdate=!1,this.operationsCounter?.reset()}updateIndexes(){if(this.needsIndexUpdate)for(let n=0;n(Ca(!0),aT(r,s,QA()));function Ppe(t,e,n,r,s,i){let o=e[Ls],a=!o||Rd()||$c(n)||$d(o,i);if(Ca(a),a)return aT(r,s,QA());let c=sb(o,t,e,n);if(ngDevMode&&Zh(c,Node.ELEMENT_NODE,s,e,n),ngDevMode&&Bd(c),e3(o,i)&&(ngDevMode&&nb(c.nextSibling,e,n),rT(o,i,c.nextSibling)),o&&(aM(n)||cH(c))){if(Ro(n))cie(n),b3(c),ngDevMode&&zoe(c);else if(ngDevMode)throw Xle(c)}return c}function Npe(){DU=Ppe}function Rpe(t,e,n,r,s){ngDevMode&&ngDevMode.firstCreatePass++;let i=e.consts,o=to(i,r),a=Yh(e,t,8,"ng-container",o);o!==null&&_2(a,o,!0);let c=to(i,s);return UA()&&pP(e,n,a,c,YM),a.mergedAttrs=Eh(a.mergedAttrs,a.attrs),e.queries!==null&&e.queries.elementStart(e,a),a}function IT(t,e,n){let r=re(),s=nt(),i=t+He;ngDevMode&&gr(r,i),ngDevMode&&rt(Pn(),s.bindingStartIndex,"element containers should be created before any bindings");let o=s.firstCreatePass?Rpe(i,s,r,e,n):s.data[i];Po(o,!0);let a=_U(s,r,o,t);return r[i]=a,j0()&&pT(s,r,a,o),ai(a,r),UC(o)&&(dT(s,r,o),DM(s,o,r)),n!=null&&ZM(r,o),IT}function kT(){let t=Bt(),e=nt();return qA()?WA():(ngDevMode&&c5(t),t=t.parent,Po(t,!1)),ngDevMode&&Yr(t,8),e.firstCreatePass&&(KA(e,t),NA(t)&&e.queries.elementEnd(t)),kT}function qP(t,e,n){return IT(t,e,n),kT(),qP}var _U=(t,e,n,r)=>(Ca(!0),OM(e[pt],ngDevMode?"ng-container":""));function Fpe(t,e,n,r){let s,i=e[Ls],o=!i||Rd()||$d(i,r)||$c(n);if(Ca(o),o)return OM(e[pt],ngDevMode?"ng-container":"");let a=sb(i,t,e,n);ngDevMode&&nb(a,e,n);let c=JH(i,r);return ngDevMode&&_n(c,"Unexpected state: hydrating an , but no hydration info is available."),rT(i,r,a),s=yT(c,a),ngDevMode&&(Zh(s,Node.COMMENT_NODE,null,e,n),Bd(s)),s}function Lpe(){_U=Fpe}function IU(){return re()}function WP(t,e,n){let r=re(),s=ao();if(vr(r,s,e)){let i=nt(),o=Hn();fi(i,o,r,t,e,r[pt],n,!0),ngDevMode&&ar(i.data,o,t,s)}return WP}function zP(t,e,n){let r=re(),s=ao();if(vr(r,s,e)){let i=nt(),o=Hn(),a=GA(i.data),c=R3(a,o,r);fi(i,o,r,t,e,c,n,!0),ngDevMode&&ar(i.data,o,t,s)}return zP}var Uu=void 0;function Ope(t){let e=Math.floor(Math.abs(t)),n=t.toString().replace(/^[^.]*\.?/,"").length;return e===1&&n===0?1:5}var Bpe=["en",[["a","p"],["AM","PM"],Uu],[["AM","PM"],Uu,Uu],[["S","M","T","W","T","F","S"],["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],["Su","Mo","Tu","We","Th","Fr","Sa"]],Uu,[["J","F","M","A","M","J","J","A","S","O","N","D"],["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],["January","February","March","April","May","June","July","August","September","October","November","December"]],Uu,[["B","A"],["BC","AD"],["Before Christ","Anno Domini"]],0,[6,0],["M/d/yy","MMM d, y","MMMM d, y","EEEE, MMMM d, y"],["h:mm a","h:mm:ss a","h:mm:ss a z","h:mm:ss a zzzz"],["{1}, {0}",Uu,"{1} 'at' {0}",Uu],[".",",",";","%","+","-","E","\xD7","\u2030","\u221E","NaN",":"],["#,##0.###","#,##0%","\xA4#,##0.00","#E0"],"USD","$","US Dollar",{},"ltr",Ope],vh={};function kU(t,e,n){typeof e!="string"&&(n=e,e=t[On.LocaleId]),e=e.toLowerCase().replace(/_/g,"-"),vh[e]=t,n&&(vh[e][On.ExtraData]=n)}function ps(t){let e=Vpe(t),n=uV(e);if(n)return n;let r=e.split("-")[0];if(n=uV(r),n)return n;if(r==="en")return Bpe;throw new ne(701,ngDevMode&&`Missing locale data for the locale "${t}".`)}function AU(t){return ps(t)[On.CurrencyCode]||null}function AT(t){return ps(t)[On.PluralCase]}function uV(t){return t in vh||(vh[t]=Yn.ng&&Yn.ng.common&&Yn.ng.common.locales&&Yn.ng.common.locales[t]),vh[t]}function $pe(){vh={}}var On;(function(t){t[t.LocaleId=0]="LocaleId",t[t.DayPeriodsFormat=1]="DayPeriodsFormat",t[t.DayPeriodsStandalone=2]="DayPeriodsStandalone",t[t.DaysFormat=3]="DaysFormat",t[t.DaysStandalone=4]="DaysStandalone",t[t.MonthsFormat=5]="MonthsFormat",t[t.MonthsStandalone=6]="MonthsStandalone",t[t.Eras=7]="Eras",t[t.FirstDayOfWeek=8]="FirstDayOfWeek",t[t.WeekendRange=9]="WeekendRange",t[t.DateFormat=10]="DateFormat",t[t.TimeFormat=11]="TimeFormat",t[t.DateTimeFormat=12]="DateTimeFormat",t[t.NumberSymbols=13]="NumberSymbols",t[t.NumberFormats=14]="NumberFormats",t[t.CurrencyCode=15]="CurrencyCode",t[t.CurrencySymbol=16]="CurrencySymbol",t[t.CurrencyName=17]="CurrencyName",t[t.Currencies=18]="Currencies",t[t.Directionality=19]="Directionality",t[t.PluralCase=20]="PluralCase",t[t.ExtraData=21]="ExtraData"})(On||(On={}));function Vpe(t){return t.toLowerCase().replace(/_/g,"-")}var Hpe=["zero","one","two","few","many"];function jpe(t,e){let n=AT(e)(parseInt(t,10)),r=Hpe[n];return r!==void 0?r:"other"}var I0="en-US",Upe="USD",MT={marker:"element"},PT={marker:"ICU"},Ps;(function(t){t[t.SHIFT=2]="SHIFT",t[t.APPEND_EAGERLY=1]="APPEND_EAGERLY",t[t.COMMENT=2]="COMMENT"})(Ps||(Ps={}));var MU=I0;function PU(t){ngDevMode&&Fe(t,"Expected localeId to be defined"),typeof t=="string"&&(MU=t.toLowerCase().replace(/_/g,"-"))}function qpe(){return MU}var k0=0,jy=0;function Wpe(t){t&&(k0=k0|1<0){ngDevMode&&Fe(t,"tView should be defined");let r=t.data[n],s=Array.isArray(r)?r:r.update,i=Pn()-jy-1;FU(t,e,s,i,k0)}k0=0,jy=0}function NU(t,e,n){let r=t[pt];switch(n){case Node.COMMENT_NODE:return OM(r,e);case Node.TEXT_NODE:return LM(r,e);case Node.ELEMENT_NODE:return aT(r,e,null)}}var Uy=(t,e,n,r)=>(Ca(!0),NU(t,n,r));function Gpe(t,e,n,r){let s=t[Ls],i=e-He,o=!cP()||!s||Rd()||$d(s,i);if(Ca(o),o)return NU(t,n,r);let a=f4(s,i);return ngDevMode&&Fe(a,"expected native element"),ngDevMode&&rt(a.nodeType,r,"expected matching nodeType"),ngDevMode&&r===Node.ELEMENT_NODE&&rt(a.tagName.toLowerCase(),n.toLowerCase(),"expecting matching tagName"),ngDevMode&&Bd(a),a}function Zpe(){Uy=Gpe}function Ype(t,e,n,r){let s=t[pt];for(let i=0;i>>Ps.SHIFT,p=t[d],f=!1;p===null&&(p=t[d]=Uy(t,d,a,c?Node.COMMENT_NODE:Node.TEXT_NODE),f=j0()),u&&n!==null&&f&&Ed(s,n,p,r,!1)}}function RU(t,e,n,r){ngDevMode&&xc(r);let s=n[pt],i=null,o;for(let a=0;a>>1,h=e[++a],m=e[++a];XM(s,$h(f,n),null,null,h,m,null);break;default:if(ngDevMode)throw new ne(700,`Unable to determine the type of mutate operation for "${c}"`)}else switch(c){case PT:let u=e[++a],d=e[++a];if(n[d]===null){ngDevMode&&rt(typeof u,"string",`Expected "${u}" to be a comment node value`),ngDevMode&&ngDevMode.rendererCreateComment++,ngDevMode&&kS(n,d);let h=n[d]=Uy(n,d,u,Node.COMMENT_NODE);ai(h,n)}break;case MT:let p=e[++a],f=e[++a];if(n[f]===null){ngDevMode&&rt(typeof p,"string",`Expected "${p}" to be an element node tag name`),ngDevMode&&ngDevMode.rendererCreateElement++,ngDevMode&&kS(n,f);let h=n[f]=Uy(n,f,p,Node.ELEMENT_NODE);ai(h,n)}break;default:ngDevMode&&tt(`Unable to determine the type of mutate operation for "${c}"`)}}}function FU(t,e,n,r,s){for(let i=0;i>>2;switch(d&3){case 1:let f=n[++u],h=n[++u],m=t.data[p];if(ngDevMode&&Fe(m,"Experting TNode or string"),typeof m=="string")XM(e[pt],e[p],null,m,f,c,h);else{let v=Vr();fl(p);try{fi(t,m,e,f,c,e[pt],h,!1)}finally{fl(v)}}break;case 0:let g=e[p];g!==null&&v3(e[pt],g,c);break;case 2:Xpe(t,Vy(t,p),e,c);break;case 3:dV(t,Vy(t,p),r,e);break}}}}else{let c=n[i+1];if(c>0&&(c&3)===3){let u=c>>>2,d=Vy(t,u);e[d.currentCaseLViewIndex]<0&&dV(t,d,r,e)}}i+=a}}function dV(t,e,n,r){ngDevMode&&gr(r,e.currentCaseLViewIndex);let s=r[e.currentCaseLViewIndex];if(s!==null){let i=k0;s<0&&(s=r[e.currentCaseLViewIndex]=~s,i=-1),FU(t,r,e.update[s],n,i)}}function Xpe(t,e,n,r){let s=Qpe(e,r);if(vT(e,n)!==s&&(LU(t,e,n),n[e.currentCaseLViewIndex]=s===null?null:~s,s!==null)){let o=n[e.anchorIdx];o&&(ngDevMode&&xc(o),RU(t,e.create[s],n,o)),Pce(n,e.anchorIdx,s)}}function LU(t,e,n){let r=vT(e,n);if(r!==null){let s=e.remove[r];for(let i=0;i0){let a=$h(o,n);a!==null&&X0(n[pt],a)}else LU(t,Vy(t,~o),n)}}}function Qpe(t,e){let n=t.cases.indexOf(e);if(n===-1)switch(t.type){case 1:{let r=jpe(e,qpe());n=t.cases.indexOf(r),n===-1&&r!=="other"&&(n=t.cases.indexOf("other"));break}case 0:{n=t.cases.indexOf("other");break}}return n===-1?null:n}function Kpe(t){let e=t||(Array.isArray(this)?this:[]),n=[];for(let r=0;r>>Ps.SHIFT;n.push(`lView[${c}] = document.${o?"createComment":"createText"}(${JSON.stringify(i)});`),a&&n.push(`parent.appendChild(lView[${c}]);`)}return n}function NT(t){let e=new dC(t||(Array.isArray(this)?this:[])),n=[];function r(s){let i=s>>>2;switch(s&3){case 0:return`(lView[${i}] as Text).textContent = $$$`;case 1:let a=e.consumeString(),c=e.consumeFunction(),u=c?`(${c})($$$)`:"$$$";return`(lView[${i}] as Element).setAttribute('${a}', ${u})`;case 2:return`icuSwitchCase(${i}, $$$)`;case 3:return`icuUpdateCase(${i})`}throw new Error("unexpected OpCode")}for(;e.hasMore();){let s=e.consumeNumber(),i=e.consumeNumber(),o=e.i+i,a=[],c="";for(;e.i0?n.push(`remove(lView[${s}])`):n.push(`removeNestedICU(${~s})`)}return n}var dC=class{constructor(e){l(this,"i",0);l(this,"codes");this.codes=e}hasMore(){return this.i`}}let m=[];d.push(m),a=ffe(m,e,c,n,r,s,i.cases[p],f.join(""),h)|a}a&&gfe(r,a,o),t.push({kind:3,index:o,cases:d,currentCaseLViewIndex:c.currentCaseLViewIndex})}function pfe(t){let e=[],n=[],r=1,s=0;t=t.replace(OU,function(o,a,c){return c==="select"?r=0:r=1,s=parseInt(a.slice(1),10),""});let i=Q2(t);for(let o=0;on.length&&n.push(c)}return{type:r,mainBinding:s,cases:e,values:n}}function Q2(t){if(!t)return[];let e=0,n=[],r=[],s=/[{}]/g;s.lastIndex=0;let i;for(;i=s.exec(t);){let a=i.index;if(i[0]=="}"){if(n.pop(),n.length==0){let c=t.substring(e,a);OU.test(c)?r.push(pfe(c)):r.push(c),e=a+1}}else{if(n.length==0){let c=t.substring(e,a);r.push(c),e=a+1}n.push("{")}}let o=t.substring(e);return r.push(o),r}function ffe(t,e,n,r,s,i,o,a,c){let u=[],d=[],p=[];ngDevMode&&(dd(u,Jpe),dd(d,efe),dd(p,NT)),n.cases.push(o),n.create.push(u),n.remove.push(d),n.update.push(p);let h=u3(No()).getInertBodyElement(a);ngDevMode&&Fe(h,"Unable to generate inert body element");let m=h2(h)||h;return m?HU(t,e,n,r,s,u,d,p,m,i,c,0):0}function HU(t,e,n,r,s,i,o,a,c,u,d,p){let f=0,h=c.firstChild;for(;h;){let m=K0(e,r,1,null);switch(h.nodeType){case Node.ELEMENT_NODE:let g=h,v=g.tagName.toLowerCase();if(d2.hasOwnProperty(v)){gk(i,MT,v,u,m),e.data[m]=v;let B=g.attributes;for(let $=0;${let c=o||a,u=r[c]||[];if(u.length||(c.split("|").forEach(g=>{let v=g.match(Tfe),w=v?parseInt(v[1],10):mV,b=Cfe.test(g);u.push([w,b,g])}),r[c]=u),!u.length)throw new Error(`i18n postprocess: unmatched placeholder - ${c}`);let d=s[s.length-1],p=0;for(let g=0;ge.hasOwnProperty(i)?`${s}${e[i]}${c}`:r),n=n.replace(xfe,(r,s)=>e.hasOwnProperty(s)?e[s]:r),n=n.replace(Sfe,(r,s)=>{if(e.hasOwnProperty(s)){let i=e[s];if(!i.length)throw new Error(`i18n postprocess: unmatched ICU - ${r} with key: ${s}`);return i.shift()}return r})),n}function GP(t,e,n=-1){let r=nt(),s=re(),i=He+t;ngDevMode&&Fe(r,"tView should be defined");let o=to(r.consts,e),a=i0();if(r.firstCreatePass&&afe(r,a===null?0:a.index,s,i,o,n),r.type===2){let f=s[Kn];f[dt]|=32}else s[dt]|=32;let c=r.data[i],u=a===s[Xr]?null:a,d=$3(r,u,s),p=a&&a.type&8?s[a.index]:null;xce(s,i,a,n),Ype(s,c.create,d,p),k5(!0)}function ZP(){k5(!1)}function jU(t,e,n){GP(t,e,n),ZP()}function UU(t,e){let n=nt();ngDevMode&&Fe(n,"tView should be defined");let r=to(n.consts,e);cfe(n,t+He,r)}function YP(t){let e=re();return Wpe(vr(e,ao(),t)),YP}function qU(t){zpe(nt(),re(),t+He)}function WU(t,e={}){return Dfe(t,e)}function gV(t,e,n){return function r(s){if(s===Function)return n;let i=Ro(t)?Bs(t.index,e):e;tb(i,5);let o=e[wn],a=vV(e,o,n,s),c=r.__ngNextListenerFn__;for(;c;)a=vV(e,o,c,s)&&a,c=c.__ngNextListenerFn__;return a}}function vV(t,e,n,r){let s=Et(null);try{return kn(6,e,n),n(r)!==!1}catch(i){return _fe(t,i),!1}finally{kn(7,e,n),Et(s)}}function _fe(t,e){let n=t[or],r=n?n.get($s,null):null;r&&r.handleError(e)}function yV(t,e,n,r,s,i){ngDevMode&&gr(e,n);let o=e[n],a=e[de],u=a.data[n].outputs[r],d=o[u];if(ngDevMode&&!Ife(d))throw new Error(`@Output ${u} not initialized in '${o.constructor.name}'.`);let p=a.firstCreatePass?MS(a):null,f=HA(e),h=d.subscribe(i),m=f.length;f.push(i,h),p&&p.push(s,t.index,m,-(m+1))}function Ife(t){return t!=null&&typeof t.subscribe=="function"}function XP(t,e,n,r){let s=re(),i=nt(),o=Bt();return KP(i,s,s[pt],o,t,e,r),XP}function QP(t,e){let n=Bt(),r=re(),s=nt(),i=GA(s.data),o=R3(i,n,r);return KP(s,r,o,n,t,e),QP}function kfe(t,e,n,r){let s=t.cleanup;if(s!=null)for(let i=0;ic?a[c]:null}typeof o=="string"&&(i+=2)}return null}function KP(t,e,n,r,s,i,o){let a=UC(r),u=t.firstCreatePass?MS(t):null,d=HA(e);ngDevMode&&Yr(r,15);let p=!0;if(r.type&3||o){let f=xs(r,e),h=o?o(f):f,m=d.length,g=o?w=>o(dn(w[r.index])):r.index,v=null;if(!o&&a&&(v=kfe(t,e,s,r.index)),v!==null){let w=v.__ngLastListenerFn__||v;w.__ngNextListenerFn__=i,v.__ngLastListenerFn__=i,p=!1}else{i=gV(r,e,i),Boe(e,h,s,i);let w=n.listen(h,s,i);ngDevMode&&ngDevMode.rendererAddEventListener++,d.push(i,w),u&&u.push(s,g,m,m+1)}}else i=gV(r,e,i);if(p){let f=r.outputs?.[s],h=r.hostDirectiveOutputs?.[s];if(h&&h.length)for(let m=0;m(Ca(!0),LM(e[pt],r));function Pfe(t,e,n,r,s){let i=e[Ls],o=!i||Rd()||$c(n)||$d(i,s);if(Ca(o),o)return LM(e[pt],r);let a=sb(i,t,e,n);return ngDevMode&&Zh(a,Node.TEXT_NODE,null,e,n),ngDevMode&&Bd(a),a}function Nfe(){f6=Pfe}function vN(t){return FT("",t,""),vN}function FT(t,e,n){let r=re(),s=em(r,t,e,n);return s!==ct&&Sl(r,Vr(),s),FT}function yN(t,e,n,r,s){let i=re(),o=tm(i,t,e,n,r,s);return o!==ct&&Sl(i,Vr(),o),yN}function bN(t,e,n,r,s,i,o){let a=re(),c=nm(a,t,e,n,r,s,i,o);return c!==ct&&Sl(a,Vr(),c),bN}function wN(t,e,n,r,s,i,o,a,c){let u=re(),d=rm(u,t,e,n,r,s,i,o,a,c);return d!==ct&&Sl(u,Vr(),d),wN}function EN(t,e,n,r,s,i,o,a,c,u,d){let p=re(),f=sm(p,t,e,n,r,s,i,o,a,c,u,d);return f!==ct&&Sl(p,Vr(),f),EN}function xN(t,e,n,r,s,i,o,a,c,u,d,p,f){let h=re(),m=im(h,t,e,n,r,s,i,o,a,c,u,d,p,f);return m!==ct&&Sl(h,Vr(),m),xN}function SN(t,e,n,r,s,i,o,a,c,u,d,p,f,h,m){let g=re(),v=om(g,t,e,n,r,s,i,o,a,c,u,d,p,f,h,m);return v!==ct&&Sl(g,Vr(),v),SN}function CN(t,e,n,r,s,i,o,a,c,u,d,p,f,h,m,g,v){let w=re(),b=am(w,t,e,n,r,s,i,o,a,c,u,d,p,f,h,m,g,v);return b!==ct&&Sl(w,Vr(),b),CN}function TN(t){let e=re(),n=Jh(e,t);return n!==ct&&Sl(e,Vr(),n),TN}function Sl(t,e,n){ngDevMode&&Lh(n,"Value should be a string"),ngDevMode&&Oh(n,ct,"value should not be NO_CHANGE"),ngDevMode&&gr(t,e);let r=$h(e,t);ngDevMode&&Fe(r,"native element should exist"),v3(t[pt],r,n)}function DN(t,e,n){lH(e)&&(e=e());let r=re(),s=ao();if(vr(r,s,e)){let i=nt(),o=Hn();fi(i,o,r,t,e,r[pt],n,!1),ngDevMode&&ar(i.data,o,t,s)}return DN}function h6(t,e){let n=lH(t);return n&&t.set(e),n}function _N(t,e){let n=re(),r=nt(),s=Bt();return KP(r,n,n[pt],s,t,e),_N}var m6={};function IN(t){let e=nt(),n=re(),r=t+He,s=Yh(e,r,128,null,null);return Po(s,!1),WC(e,n,r,m6),IN}function g6(t){Ss("NgLet");let e=nt(),n=re(),r=Vr();return WC(e,n,r,t),t}function v6(t){let e=D5(),n=Nd(e,He+t);if(n===m6)throw new ne(314,ngDevMode&&"Attempting to access a @let declaration whose value is not available yet");return n}function y6(t,e){let n=nt(),r=re(),s=r[pt],i="data-ng-source-location";for(let[o,a,c,u]of e){let d=Pd(n,o+He);ngDevMode&&Yr(d,2);let p=$h(o+He,r);if(!p.hasAttribute(i)){let f=`${t}@o:${a},l:${c},c:${u}`;s.setAttribute(p,i,f)}}}function Rfe(t,e,n){let r=nt();if(r.firstCreatePass){let s=Ns(t);J2(n,r.data,r.blueprint,s,!0),J2(e,r.data,r.blueprint,s,!1)}}function J2(t,e,n,r,s){if(t=xt(t),Array.isArray(t))for(let i=0;i{kk(t,s)})}let d=a.providerIndexes&1048575,p=a.directiveStart,f=a.providerIndexes>>20;if(fd(t)||!t.multi){let h=new Pc(u,s,Vd),m=yk(c,e,s?d:d+f,p);m===-1?(Hk(RS(a,o),i,c),vk(i,t,e.length),e.push(c),a.directiveStart++,a.directiveEnd++,s&&(a.providerIndexes+=1048576),n.push(h),o.push(h)):(n[m]=h,o[m]=h)}else{let h=yk(c,e,d+f,p),m=yk(c,e,d,d+f),g=h>=0&&n[h],v=m>=0&&n[m];if(s&&!v||!s&&!g){Hk(RS(a,o),i,c);let w=Ofe(s?Lfe:Ffe,n.length,s,r,u);!s&&v&&(n[m].providerFactory=w),vk(i,t,e.length,0),e.push(c),a.directiveStart++,a.directiveEnd++,s&&(a.providerIndexes+=1048576),n.push(w),o.push(w)}else{let w=b6(n[s?m:h],u,!s&&r);vk(i,t,h>-1?h:m,w)}!s&&r&&v&&n[m].componentProviders++}}}function vk(t,e,n,r){let s=fd(e),i=Lse(e);if(s||i){let c=(i?xt(e.useClass):e).prototype.ngOnDestroy;if(c){let u=t.destroyHooks||(t.destroyHooks=[]);if(!s&&e.multi){ngDevMode&&Fe(r,"indexInFactory when registering multi factory destroy hook");let d=u.indexOf(n);d===-1?u.push(n,[r,c]):u[d+1].push(r,c)}else u.push(n,c)}}}function b6(t,e,n){return n&&t.componentProviders++,t.multi.push(e)-1}function yk(t,e,n,r){for(let s=n;s{n.providersResolver=(r,s)=>Rfe(r,s?s(t):t,e)}}function E6(t){return e=>{t.length<1||(e.getExternalStyles=n=>t.map(s=>s+"?ngcomp"+(n?"="+encodeURIComponent(n):"")+"&e="+e.encapsulation))}}function x6(t,e,n){let r=t.\u0275cmp;r.directiveDefs=nC(e,!1),r.pipeDefs=nC(n,!0)}function S6(t,e){return Sa(()=>{let n=ki(t,!0);n.declarations=nS(e.declarations||un),n.imports=nS(e.imports||un),n.exports=nS(e.exports||un),e.bootstrap&&(n.bootstrap=nS(e.bootstrap)),Cd.registerNgModule(t,e)})}function nS(t){if(typeof t=="function")return t;let e=oi(t);return e.some(FC)?()=>e.map(xt).map(bV):e.map(bV)}function bV(t){return dP(t)?t.ngModule:t}function C6(t,e,n){let r=js()+t,s=re();return s[r]===ct?Ia(s,r,n?e.call(n):e()):ob(s,r)}function T6(t,e,n,r){return R6(re(),js(),t,e,n,r)}function D6(t,e,n,r,s){return F6(re(),js(),t,e,n,r,s)}function _6(t,e,n,r,s,i){return L6(re(),js(),t,e,n,r,s,i)}function I6(t,e,n,r,s,i,o){return O6(re(),js(),t,e,n,r,s,i,o)}function k6(t,e,n,r,s,i,o,a){let c=js()+t,u=re(),d=io(u,c,n,r,s,i);return vr(u,c+4,o)||d?Ia(u,c+5,a?e.call(a,n,r,s,i,o):e(n,r,s,i,o)):ob(u,c+5)}function A6(t,e,n,r,s,i,o,a,c){let u=js()+t,d=re(),p=io(d,u,n,r,s,i);return Dd(d,u+4,o,a)||p?Ia(d,u+6,c?e.call(c,n,r,s,i,o,a):e(n,r,s,i,o,a)):ob(d,u+6)}function M6(t,e,n,r,s,i,o,a,c,u){let d=js()+t,p=re(),f=io(p,d,n,r,s,i);return ET(p,d+4,o,a,c)||f?Ia(p,d+7,u?e.call(u,n,r,s,i,o,a,c):e(n,r,s,i,o,a,c)):ob(p,d+7)}function P6(t,e,n,r,s,i,o,a,c,u,d){let p=js()+t,f=re(),h=io(f,p,n,r,s,i);return io(f,p+4,o,a,c,u)||h?Ia(f,p+8,d?e.call(d,n,r,s,i,o,a,c,u):e(n,r,s,i,o,a,c,u)):ob(f,p+8)}function N6(t,e,n,r){return B6(re(),js(),t,e,n,r)}function ub(t,e){ngDevMode&&gr(t,e);let n=t[e];return n===ct?void 0:n}function R6(t,e,n,r,s,i){let o=e+n;return vr(t,o,s)?Ia(t,o+1,i?r.call(i,s):r(s)):ub(t,o+1)}function F6(t,e,n,r,s,i,o){let a=e+n;return Dd(t,a,s,i)?Ia(t,a+2,o?r.call(o,s,i):r(s,i)):ub(t,a+2)}function L6(t,e,n,r,s,i,o,a){let c=e+n;return ET(t,c,s,i,o)?Ia(t,c+3,a?r.call(a,s,i,o):r(s,i,o)):ub(t,c+3)}function O6(t,e,n,r,s,i,o,a,c){let u=e+n;return io(t,u,s,i,o,a)?Ia(t,u+4,c?r.call(c,s,i,o,a):r(s,i,o,a)):ub(t,u+4)}function B6(t,e,n,r,s,i){let o=e+n,a=!1;for(let c=0;cr.name===t).length>1&&console.warn(gn(313,$fe(t)));for(let n=e.length-1;n>=0;n--){let r=e[n];if(t===r.name)return r}}if(ngDevMode)throw new ne(-302,Vfe(t))}function $fe(t){let e=re(),r=e[Kn][wn],s=iT(e),i=r?` in the '${r.constructor.name}' component`:"";return`Multiple pipes match the name \`${t}\`${i}. ${`check ${s?"'@Component.imports' of this component":"the imports of this module"}`}`}function Vfe(t){let e=re(),r=e[Kn][wn],s=iT(e),i=r?` in the '${r.constructor.name}' component`:"";return`The pipe '${t}' could not be found${i}. ${`Verify that it is ${s?"included in the '@Component.imports' of this component":"declared or imported in this module"}`}`}function V6(t,e,n){let r=t+He,s=re(),i=Nd(s,r);return db(s,r)?R6(s,js(),e,i.transform,n,i):i.transform(n)}function H6(t,e,n,r){let s=t+He,i=re(),o=Nd(i,s);return db(i,s)?F6(i,js(),e,o.transform,n,r,o):o.transform(n,r)}function j6(t,e,n,r,s){let i=t+He,o=re(),a=Nd(o,i);return db(o,i)?L6(o,js(),e,a.transform,n,r,s,a):a.transform(n,r,s)}function U6(t,e,n,r,s,i){let o=t+He,a=re(),c=Nd(a,o);return db(a,o)?O6(a,js(),e,c.transform,n,r,s,i,c):c.transform(n,r,s,i)}function q6(t,e,n){let r=t+He,s=re(),i=Nd(s,r);return db(s,r)?B6(s,js(),e,i.transform,n,i):i.transform.apply(i,n)}function db(t,e){return t[de].data[e].pure}function W6(t,e){return mT(t,e)}function z6(t,e){return()=>{try{return Cd.getComponentDependencies(t,e).dependencies}catch(n){throw console.error(`Computing dependencies in local compilation mode for the component "${t.name}" failed with the exception:`,n),n}}}function G6(t,e){let n=Ut(t);n!==null&&(n.debugInfo=e)}function Z6(t,e,n){let r=`./@ng/component?c=${t}&t=${encodeURIComponent(e)}`;return new URL(r,n).href}function Y6(t,e,n,r,s=null,i=null){ngDevMode&&cT(t);let o=Ut(t);e.apply(null,[t,n,...r]);let{newDef:a,oldDef:c}=Hfe(o,Ut(t));if(t[Md]=a,c.tView){let u=roe().values();for(let d of u)cl(d)&&d[ir]===null&&hS(s,i,a,c,d)}}function Hfe(t,e){let n={...t},r=Object.assign(t,e,{directiveDefs:n.directiveDefs,pipeDefs:n.pipeDefs,setInput:n.setInput,type:n.type});return ngDevMode&&rt(r,t,"Expected definition to be merged in place"),{newDef:r,oldDef:n}}function hS(t,e,n,r,s){ngDevMode&&Fe(r.tView,"Expected a component definition that has been instantiated at least once");let i=s[de];if(i===r.tView){ngDevMode&&cT(r.type),Ufe(t,e,n,r,s);return}for(let o=He;o{if(r.encapsulation===Vs.ShadowDom){let m=o.cloneNode(!1);o.replaceWith(m),o=m}let p=k3(n),f=uT(a,p,i,zM(n),o,c,null,null,null,null,null);qfe(a,s,f,c.index),eb(s[de],s);let h=s[ko].rendererFactory;jfe(h,r),f[pt]=h.createRenderer(o,n),F3(s[de],s),Wfe(c),J0(p,f,i),X3(p,f,p.template,i)};u===null?wV(t,e,d):u.run(()=>wV(t,e,d))}function wV(t,e,n){try{n()}catch(r){let s=r;if(e!==null&&s.message){let i=s.message+(s.stack?` +`+s.stack:"");t?.hot?.send?.("angular:invalidate",{id:e,message:i,error:!0})}throw r}}function qfe(t,e,n,r){for(let s=He;s=0;t--){let{moduleType:e,ngModule:n}=Wy[t];n.declarations&&n.declarations.every(Q6)&&(Wy.splice(t,1),Kfe(e,n))}}finally{bk=!1}}}function Q6(t){return Array.isArray(t)?t.every(Q6):!!xt(t)}function K6(t,e={}){J6(t,e),e.id!==void 0&&bP(t,e.id),Yfe(t,e)}function J6(t,e,n=!1){ngDevMode&&Fe(t,"Required value moduleType"),ngDevMode&&Fe(e,"Required value ngModule");let r=oi(e.declarations||un),s=null;Object.defineProperty(t,xA,{configurable:!0,get:()=>{if(s===null){if(ngDevMode&&e.imports&&e.imports.indexOf(t)>-1)throw new Error(`'${Xt(t)}' module can't import itself`);s=Br({usage:0,kind:"NgModule",type:t}).compileNgModule(Fs,`ng:///${t.name}/\u0275mod.js`,{type:t,bootstrap:oi(e.bootstrap||un).map(xt),declarations:r.map(xt),imports:oi(e.imports||un).map(xt).map(xV),exports:oi(e.exports||un).map(xt).map(xV),schemas:e.schemas?oi(e.schemas):null,id:e.id||null}),s.schemas||(s.schemas=[])}return s}});let i=null;Object.defineProperty(t,ll,{get:()=>{if(i===null){let a=Br({usage:0,kind:"NgModule",type:t});i=a.compileFactory(Fs,`ng:///${t.name}/\u0275fac.js`,{name:t.name,type:t,deps:QC(t),target:a.FactoryTarget.NgModule,typeArgumentCount:0})}return i},configurable:!!ngDevMode});let o=null;Object.defineProperty(t,bS,{get:()=>{if(o===null){ngDevMode&&hC(t,n);let a={name:t.name,type:t,providers:e.providers||un,imports:[(e.imports||un).map(xt),(e.exports||un).map(xt)]};o=Br({usage:0,kind:"NgModule",type:t}).compileInjector(Fs,`ng:///${t.name}/\u0275inj.js`,a)}return o},configurable:!!ngDevMode})}function e9(t,e){let n=`Unexpected "${Xt(t)}" found in the "declarations" array of the`,r=`"${Xt(t)}" is marked as standalone and can't be declared in any NgModule - did you intend to import it instead (by adding it to the "imports" array)?`;return`${n} ${e}, ${r}`}function hC(t,e,n){if(tA.get(t)||Sc(t))return;tA.set(t,!0),t=xt(t);let r;if(n){if(r=ki(t),!r)throw new Error(`Unexpected value '${t.name}' imported by the module '${n.name}'. Please add an @NgModule annotation.`)}else r=ki(t,!0);let s=[],i=ha(r.declarations),o=ha(r.imports);oi(o).map(EV).forEach(b=>{w(b,t),hC(b,!1,t)});let a=ha(r.exports);i.forEach(d),i.forEach(p),i.forEach(b=>f(b,t));let c=[...i.map(xt),...oi(o.map(t9)).map(xt)];a.forEach(h),i.forEach(b=>m(b,e));let u=Xfe(t,"NgModule");if(u&&(u.imports&&oi(u.imports).map(EV).forEach(b=>{w(b,t),hC(b,!1,t)}),u.bootstrap&&bh(u.bootstrap,v),u.bootstrap&&bh(u.bootstrap,g)),s.length)throw new Error(s.join(` +`));function d(b){b=xt(b),Ut(b)||ls(b)||Ti(b)||s.push(`Unexpected value '${Xt(b)}' declared by the module '${Xt(t)}'. Please add a @Pipe/@Directive/@Component annotation.`)}function p(b){b=xt(b);let D=ls(b);!Ut(b)&&D&&D.selectors.length==0&&s.push(`Directive ${Xt(b)} has no selector, please add it!`)}function f(b,D){if(b=xt(b),(Ut(b)||ls(b)||Ti(b))?.standalone){let M=`"${Xt(D)}" NgModule`;s.push(e9(b,M))}}function h(b){b=xt(b);let D=Ut(b)&&"component"||ls(b)&&"directive"||Ti(b)&&"pipe";D&&c.lastIndexOf(b)===-1&&s.push(`Can't export ${D} ${Xt(b)} from ${Xt(t)} as it was neither declared nor imported!`)}function m(b,D){b=xt(b);let B=mS.get(b);if(B&&B!==t){if(!D){let M=[B,t].map(Xt).sort();s.push(`Type ${Xt(b)} is part of the declarations of 2 modules: ${M[0]} and ${M[1]}! Please consider moving ${Xt(b)} to a higher module that imports ${M[0]} and ${M[1]}. You can also create a new NgModule that exports and includes ${Xt(b)} then import that NgModule in ${M[0]} and ${M[1]}.`)}}else mS.set(b,t)}function g(b){b=xt(b),!mS.get(b)&&!Sc(b)&&s.push(`Component ${Xt(b)} is not part of any NgModule or the module has not been imported into your module.`)}function v(b){b=xt(b),Ut(b)||s.push(`${Xt(b)} cannot be used as an entry component.`),Sc(b)&&s.push(`The \`${Xt(b)}\` class is a standalone component, which can not be used in the \`@NgModule.bootstrap\` array. Use the \`bootstrapApplication\` function for bootstrap instead.`)}function w(b,D){b=xt(b);let B=Ut(b)||ls(b);if(B!==null&&!B.standalone)throw new Error(`Unexpected directive '${b.name}' imported by the module '${D.name}'. Please add an @NgModule annotation.`);let M=Ti(b);if(M!==null&&!M.standalone)throw new Error(`Unexpected pipe '${b.name}' imported by the module '${D.name}'. Please add an @NgModule annotation.`)}}function EV(t){return t=xt(t),t.ngModule||t}function Xfe(t,e){let n=null;return r(t.__annotations__),r(t.decorators),n;function r(i){i&&i.forEach(s)}function s(i){n||(Object.getPrototypeOf(i).ngMetadataName==e?n=i:i.type&&Object.getPrototypeOf(i.type).ngMetadataName==e&&(n=i.args[0]))}}var mS=new WeakMap,tA=new WeakMap;function Qfe(){mS=new WeakMap,tA=new WeakMap,Wy.length=0,dS.clear()}function t9(t){t=xt(t);let e=ki(t);return e===null?[t]:oi(ha(e.exports).map(n=>ki(n)?(hC(n,!1),t9(n)):n))}function Kfe(t,e){let n=oi(e.declarations||un),r=AN(t);n.forEach(s=>{if(s=xt(s),s.hasOwnProperty(Md)){let o=Ut(s);kN(o,r)}else!s.hasOwnProperty($C)&&!s.hasOwnProperty(VC)&&(s.ngSelectorScope=t)})}function kN(t,e){t.directiveDefs=()=>Array.from(e.compilation.directives).map(n=>n.hasOwnProperty(Md)?Ut(n):ls(n)).filter(n=>!!n),t.pipeDefs=()=>Array.from(e.compilation.pipes).map(n=>Ti(n)),t.schemas=e.schemas,t.tView=null}function AN(t){if(Wu(t)){let e=Cd.getNgModuleScope(t);return{schemas:ki(t,!0).schemas||null,...e}}else if(Sc(t)){if((Ut(t)||ls(t))!==null)return{schemas:null,compilation:{directives:new Set,pipes:new Set},exported:{directives:new Set([t]),pipes:new Set}};if(Ti(t)!==null)return{schemas:null,compilation:{directives:new Set,pipes:new Set},exported:{directives:new Set,pipes:new Set([t])}}}throw new Error(`${t.name} does not have a module def (\u0275mod property)`)}function xV(t){return dP(t)?t.ngModule:t}var wk=0;function n9(t,e){(typeof ngDevMode>"u"||ngDevMode)&&wA();let n=null;kue(t,e),s9(t,e),Object.defineProperty(t,Md,{get:()=>{if(n===null){let r=Br({usage:0,kind:"component",type:t});if(Y4(e)){let u=[`Component '${t.name}' is not resolved:`];throw e.templateUrl&&u.push(` - templateUrl: ${e.templateUrl}`),e.styleUrls&&e.styleUrls.length&&u.push(` - styleUrls: ${JSON.stringify(e.styleUrls)}`),e.styleUrl&&u.push(` - styleUrl: ${e.styleUrl}`),u.push("Did you run and wait for 'resolveComponentResources()'?"),new Error(u.join(` +`))}let s=Gfe(),i=e.preserveWhitespaces;i===void 0&&(s!==null&&s.preserveWhitespaces!==void 0?i=s.preserveWhitespaces:i=!1);let o=e.encapsulation;o===void 0&&(s!==null&&s.defaultEncapsulation!==void 0?o=s.defaultEncapsulation:o=Vs.Emulated);let a=e.templateUrl||`ng:///${t.name}/template.html`,c={...i9(t,e),typeSourceSpan:r.createParseSourceSpan("Component",t.name,a),template:e.template||"",preserveWhitespaces:i,styles:typeof e.styles=="string"?[e.styles]:e.styles||un,animations:e.animations,declarations:[],changeDetection:e.changeDetection,encapsulation:o,interpolation:e.interpolation,viewProviders:e.viewProviders||null};wk++;try{if(c.usesInheritance&&o9(t),n=r.compileComponent(Fs,a,c),c.isStandalone){let u=oi(e.imports||un),{directiveDefs:d,pipeDefs:p}=Jfe(t,u);n.directiveDefs=d,n.pipeDefs=p,n.dependencies=()=>u.map(xt)}}finally{wk--}if(wk===0&&X6(),ehe(t)){let u=AN(t.ngSelectorScope);kN(n,u)}if(e.schemas)if(c.isStandalone)n.schemas=e.schemas;else throw new Error(`The 'schemas' was specified for the ${Xt(t)} but is only valid on a component that is standalone.`);else c.isStandalone&&(n.schemas=[])}return n},set:r=>{n=r},configurable:!!ngDevMode})}function Jfe(t,e){return{directiveDefs:()=>{{if(ngDevMode)for(let i of e)T2(i,t);return Hy(t)?[...Cd.getStandaloneComponentScope(t,e).compilation.directives].map(i=>Ut(i)||ls(i)).filter(i=>i!==null):[]}},pipeDefs:()=>{{if(ngDevMode)for(let i of e)T2(i,t);return Hy(t)?[...Cd.getStandaloneComponentScope(t,e).compilation.pipes].map(i=>Ti(i)).filter(i=>i!==null):[]}}}}function ehe(t){return t.ngSelectorScope!==void 0}function MN(t,e){let n=null;s9(t,e||{}),Object.defineProperty(t,$C,{get:()=>{if(n===null){let r=r9(t,e||{});n=Br({usage:0,kind:"directive",type:t}).compileDirective(Fs,r.sourceMapUrl,r.metadata)}return n},configurable:!!ngDevMode})}function r9(t,e){let n=t&&t.name,r=`ng:///${n}/\u0275dir.js`,s=Br({usage:0,kind:"directive",type:t}),i=i9(t,e);return i.typeSourceSpan=s.createParseSourceSpan("Directive",n,r),i.usesInheritance&&o9(t),{metadata:i,sourceMapUrl:r}}function s9(t,e){let n=null;Object.defineProperty(t,ll,{get:()=>{if(n===null){let r=r9(t,e),s=Br({usage:0,kind:"directive",type:t});n=s.compileFactory(Fs,`ng:///${t.name}/\u0275fac.js`,{name:r.metadata.name,type:r.metadata.type,typeArgumentCount:0,deps:QC(t),target:s.FactoryTarget.Directive})}return n},configurable:!!ngDevMode})}function the(t){return Object.getPrototypeOf(t.prototype)===Object.prototype}function i9(t,e){let n=tM(),r=n.ownPropMetadata(t);return{name:t.name,type:t,selector:e.selector!==void 0?e.selector:null,host:e.host||eo,propMetadata:r,inputs:e.inputs||un,outputs:e.outputs||un,queries:SV(t,r,a9),lifecycle:{usesOnChanges:n.hasLifecycleHook(t,"ngOnChanges")},typeSourceSpan:null,usesInheritance:!the(t),exportAs:she(e.exportAs),providers:e.providers||null,viewQueries:SV(t,r,l9),isStandalone:e.standalone===void 0?!0:!!e.standalone,isSignal:!!e.signals,hostDirectives:e.hostDirectives?.map(s=>typeof s=="function"?{directive:s}:s)||null}}function o9(t){let e=Object.prototype,n=Object.getPrototypeOf(t.prototype).constructor;for(;n&&n!==e;)!ls(n)&&!Ut(n)&&ohe(n)&&MN(n,null),n=Object.getPrototypeOf(n)}function nhe(t){return typeof t=="string"?u9(t):xt(t)}function rhe(t,e){return{propertyName:t,predicate:nhe(e.selector),descendants:e.descendants,first:e.first,read:e.read?e.read:null,static:!!e.static,emitDistinctChangesOnly:!!e.emitDistinctChangesOnly,isSignal:!!e.isSignal}}function SV(t,e,n){let r=[];for(let s in e)if(e.hasOwnProperty(s)){let i=e[s];i.forEach(o=>{if(n(o)){if(!o.selector)throw new Error(`Can't construct a query for the property "${s}" of "${Xt(t)}" since the query selector wasn't defined.`);if(i.some(c9))throw new Error("Cannot combine @Input decorators with query decorators");r.push(rhe(s,o))}})}return r}function she(t){return t===void 0?null:u9(t)}function a9(t){let e=t.ngMetadataName;return e==="ContentChild"||e==="ContentChildren"}function l9(t){let e=t.ngMetadataName;return e==="ViewChild"||e==="ViewChildren"}function c9(t){return t.ngMetadataName==="Input"}function u9(t){return t.split(",").map(e=>e.trim())}var ihe=["ngOnChanges","ngOnInit","ngOnDestroy","ngDoCheck","ngAfterViewInit","ngAfterViewChecked","ngAfterContentInit","ngAfterContentChecked"];function ohe(t){let e=tM();if(ihe.some(r=>e.hasLifecycleHook(t,r)))return!0;let n=e.propMetadata(t);for(let r in n){let s=n[r];for(let i=0;i{if(r===null){let s=CV(t,e),i=Br({usage:0,kind:"pipe",type:s.type});r=i.compileFactory(Fs,`ng:///${s.name}/\u0275fac.js`,{name:s.name,type:s.type,typeArgumentCount:0,deps:QC(t),target:i.FactoryTarget.Pipe})}return r},configurable:!!ngDevMode}),Object.defineProperty(t,VC,{get:()=>{if(n===null){let s=CV(t,e);n=Br({usage:0,kind:"pipe",type:s.type}).compilePipe(Fs,`ng:///${s.name}/\u0275pipe.js`,s)}return n},configurable:!!ngDevMode})}function CV(t,e){return{type:t,name:t.name,pipeName:e.name,pure:e.pure!==void 0?e.pure:!0,isStandalone:e.standalone===void 0?!0:!!e.standalone}}var bt=P0("Directive",(t={})=>t,void 0,void 0,(t,e)=>MN(t,e)),Ws=P0("Component",(t={})=>({changeDetection:yd.Default,...t}),bt,void 0,(t,e)=>n9(t,e)),zs=P0("Pipe",t=>({pure:!0,...t}),void 0,void 0,(t,e)=>d9(t,e)),Ge=Oc("Input",t=>t?typeof t=="string"?{alias:t}:t:{}),lm=Oc("Output",t=>({alias:t})),ahe=Oc("HostBinding",t=>({hostPropertyName:t})),lhe=Oc("HostListener",(t,e)=>({eventName:t,args:e})),co=P0("NgModule",t=>t,void 0,void 0,(t,e)=>K6(t,e)),Ea=class{constructor(e){l(this,"full");l(this,"major");l(this,"minor");l(this,"patch");this.full=e;let n=e.split(".");this.major=n[0],this.minor=n[1],this.patch=n.slice(2).join(".")}},che=new Ea("19.2.25"),mC=class{constructor(e,n){l(this,"ngModuleFactory");l(this,"componentFactories");this.ngModuleFactory=e,this.componentFactories=n}},Ju=class Ju{compileModuleSync(e){return new Mh(e)}compileModuleAsync(e){return Promise.resolve(this.compileModuleSync(e))}compileModuleAndAllComponentsSync(e){let n=this.compileModuleSync(e),r=ki(e),s=ha(r.declarations).reduce((i,o)=>{let a=Ut(o);return a&&i.push(new Nc(a)),i},[]);return new mC(n,s)}compileModuleAndAllComponentsAsync(e){return Promise.resolve(this.compileModuleAndAllComponentsSync(e))}clearCache(){}clearCacheFor(e){}getModuleId(e){}};l(Ju,"\u0275fac",function(n){return new(n||Ju)}),l(Ju,"\u0275prov",hn({token:Ju,factory:Ju.\u0275fac,providedIn:"root"}));var gC=Ju;(typeof ngDevMode>"u"||ngDevMode)&&Us(gC,[{type:St,args:[{providedIn:"root"}]}],null,null);var p9=new $e(ngDevMode?"compilerOptions":""),nA=class{};function f9(t,e,n){ngDevMode&&Yse(n);let r=new Mh(n);if(typeof ngJitMode<"u"&&!ngJitMode)return Promise.resolve(r);let s=t.get(p9,[]).concat(e);if(zfe({defaultEncapsulation:TV(s.map(u=>u.defaultEncapsulation)),preserveWhitespaces:TV(s.map(u=>u.preserveWhitespaces))}),Pue())return Promise.resolve(r);let i=s.flatMap(u=>u.providers??[]);if(i.length===0)return Promise.resolve(r);let o=Br({usage:0,kind:"NgModule",type:n}),c=Ln.create({providers:i}).get(o.ResourceLoader);return Z4(u=>Promise.resolve(c.get(u))).then(()=>r)}function TV(t){for(let e=t.length-1;e>=0;e--)if(t[e]!==void 0)return t[e]}var ed=class ed{constructor(){l(this,"zone",fe(qt));l(this,"changeDetectionScheduler",fe(no));l(this,"applicationRef",fe(yr));l(this,"_onMicrotaskEmptySubscription")}initialize(){this._onMicrotaskEmptySubscription||(this._onMicrotaskEmptySubscription=this.zone.onMicrotaskEmpty.subscribe({next:()=>{this.changeDetectionScheduler.runningTick||this.zone.run(()=>{this.applicationRef.tick()})}}))}ngOnDestroy(){this._onMicrotaskEmptySubscription?.unsubscribe()}};l(ed,"\u0275fac",function(n){return new(n||ed)}),l(ed,"\u0275prov",hn({token:ed,factory:ed.\u0275fac,providedIn:"root"}));var vC=ed;(typeof ngDevMode>"u"||ngDevMode)&&Us(vC,[{type:St,args:[{providedIn:"root"}]}],null,null);var PN=new $e(typeof ngDevMode>"u"||ngDevMode?"provideZoneChangeDetection token":"",{factory:()=>!1});function LT({ngZoneFactory:t,ignoreChangesOutsideZone:e,scheduleInRootZone:n}){return t??(t=()=>new qt({...NN(),scheduleInRootZone:n})),[{provide:qt,useFactory:t},{provide:li,multi:!0,useFactory:()=>{let r=fe(vC,{optional:!0});if((typeof ngDevMode>"u"||ngDevMode)&&r===null)throw new ne(402,"A required Injectable was not found in the dependency injection tree. If you are bootstrapping an NgModule, make sure that the `BrowserModule` is imported.");return()=>r.initialize()}},{provide:li,multi:!0,useFactory:()=>{let r=fe(yC);return()=>{r.initialize()}}},e===!0?{provide:nH,useValue:!0}:[],{provide:nM,useValue:n??eH}]}function uhe(t){let e=t?.ignoreChangesOutsideZone,n=t?.scheduleInRootZone,r=LT({ngZoneFactory:()=>{let s=NN(t);return s.scheduleInRootZone=n,s.shouldCoalesceEventChangeDetection&&Ss("NgZone_CoalesceEvent"),new qt(s)},ignoreChangesOutsideZone:e,scheduleInRootZone:n});return ma([{provide:PN,useValue:!0},{provide:Od,useValue:!1},r])}function NN(t){return{enableLongStackTrace:typeof ngDevMode>"u"?!1:!!ngDevMode,shouldCoalesceEventChangeDetection:t?.eventCoalescing??!1,shouldCoalesceRunChangeDetection:t?.runCoalescing??!1}}var td=class td{constructor(){l(this,"subscription",new Do);l(this,"initialized",!1);l(this,"zone",fe(qt));l(this,"pendingTasks",fe(ya))}initialize(){if(this.initialized)return;this.initialized=!0;let e=null;!this.zone.isStable&&!this.zone.hasPendingMacrotasks&&!this.zone.hasPendingMicrotasks&&(e=this.pendingTasks.add()),this.zone.runOutsideAngular(()=>{this.subscription.add(this.zone.onStable.subscribe(()=>{qt.assertNotInAngularZone(),queueMicrotask(()=>{e!==null&&!this.zone.hasPendingMacrotasks&&!this.zone.hasPendingMicrotasks&&(this.pendingTasks.remove(e),e=null)})}))}),this.subscription.add(this.zone.onUnstable.subscribe(()=>{qt.assertInAngularZone(),e??(e=this.pendingTasks.add())}))}ngOnDestroy(){this.subscription.unsubscribe()}};l(td,"\u0275fac",function(n){return new(n||td)}),l(td,"\u0275prov",hn({token:td,factory:td.\u0275fac,providedIn:"root"}));var yC=td;(typeof ngDevMode>"u"||ngDevMode)&&Us(yC,[{type:St,args:[{providedIn:"root"}]}],null,null);var DV=100,gS=0,rA=[];function dhe(){if(gS++,DV-gS<5){let t=new Error().stack;t&&rA.push(t)}if(gS===DV)throw new ne(103,`Angular could not stabilize because there were endless change notifications within the browser event loop. The stack from the last several notifications: +`+rA.join(` +`))}var nd=class nd{constructor(){l(this,"appRef",fe(yr));l(this,"taskService",fe(ya));l(this,"ngZone",fe(qt));l(this,"zonelessEnabled",fe(Od));l(this,"tracing",fe(Fo,{optional:!0}));l(this,"disableScheduling",fe(nH,{optional:!0})??!1);l(this,"zoneIsDefined",typeof Zone<"u"&&!!Zone.root.run);l(this,"schedulerTickApplyArgs",[{data:{__scheduler_tick__:!0}}]);l(this,"subscriptions",new Do);l(this,"angularZoneId",this.zoneIsDefined?this.ngZone._inner?.get(LS):null);l(this,"scheduleInRootZone",!this.zonelessEnabled&&this.zoneIsDefined&&(fe(nM,{optional:!0})??!1));l(this,"cancelScheduledCallback",null);l(this,"useMicrotaskScheduler",!1);l(this,"runningTick",!1);l(this,"pendingRenderTaskId",null);this.subscriptions.add(this.appRef.afterTick.subscribe(()=>{this.runningTick||this.cleanup()})),this.subscriptions.add(this.ngZone.onUnstable.subscribe(()=>{this.runningTick||this.cleanup()})),this.disableScheduling||(this.disableScheduling=!this.zonelessEnabled&&(this.ngZone instanceof xh||!this.zoneIsDefined))}notify(e){if(!this.zonelessEnabled&&e===5)return;let n=!1;switch(e){case 0:{this.appRef.dirtyFlags|=2;break}case 3:case 2:case 4:case 5:case 1:{this.appRef.dirtyFlags|=4;break}case 6:{this.appRef.dirtyFlags|=2,n=!0;break}case 12:{this.appRef.dirtyFlags|=16,n=!0;break}case 13:{this.appRef.dirtyFlags|=2,n=!0;break}case 11:{n=!0;break}case 9:case 8:case 7:case 10:default:this.appRef.dirtyFlags|=8}if(this.appRef.tracingSnapshot=this.tracing?.snapshot(this.appRef.tracingSnapshot)??null,!this.shouldScheduleTick(n))return;(typeof ngDevMode>"u"||ngDevMode)&&(this.useMicrotaskScheduler?dhe():(gS=0,rA.length=0));let r=this.useMicrotaskScheduler?c8:rH;this.pendingRenderTaskId=this.taskService.add(),this.scheduleInRootZone?this.cancelScheduledCallback=Zone.root.run(()=>r(()=>this.tick())):this.cancelScheduledCallback=this.ngZone.runOutsideAngular(()=>r(()=>this.tick()))}shouldScheduleTick(e){return!(this.disableScheduling&&!e||this.appRef.destroyed||this.pendingRenderTaskId!==null||this.runningTick||this.appRef._runningTick||!this.zonelessEnabled&&this.zoneIsDefined&&Zone.current.get(LS+this.angularZoneId))}tick(){if(this.runningTick||this.appRef.destroyed)return;if(this.appRef.dirtyFlags===0){this.cleanup();return}!this.zonelessEnabled&&this.appRef.dirtyFlags&7&&(this.appRef.dirtyFlags|=1);let e=this.taskService.add();try{this.ngZone.run(()=>{this.runningTick=!0,this.appRef._tick()},void 0,this.schedulerTickApplyArgs)}catch(n){throw this.taskService.remove(e),n}finally{this.cleanup()}this.useMicrotaskScheduler=!0,c8(()=>{this.useMicrotaskScheduler=!1,this.taskService.remove(e)})}ngOnDestroy(){this.subscriptions.unsubscribe(),this.cleanup()}cleanup(){if(this.runningTick=!1,this.cancelScheduledCallback?.(),this.cancelScheduledCallback=null,this.pendingRenderTaskId!==null){let e=this.pendingRenderTaskId;this.pendingRenderTaskId=null,this.taskService.remove(e)}}};l(nd,"\u0275fac",function(n){return new(n||nd)}),l(nd,"\u0275prov",hn({token:nd,factory:nd.\u0275fac,providedIn:"root"}));var vl=nd;(typeof ngDevMode>"u"||ngDevMode)&&Us(vl,[{type:St,args:[{providedIn:"root"}]}],()=>[],null);function phe(){if(Ss("NgZoneless"),(typeof ngDevMode>"u"||ngDevMode)&&typeof Zone<"u"&&Zone){let t=gn(914,'The application is using zoneless change detection, but is still loading Zone.js. Consider removing Zone.js to get the full benefits of zoneless. In applications using the Angular CLI, Zone.js is typically included in the "polyfills" section of the angular.json file.');console.warn(t)}return ma([{provide:no,useExisting:vl},{provide:qt,useClass:xh},{provide:Od,useValue:!0},{provide:nM,useValue:!1},typeof ngDevMode>"u"||ngDevMode?[{provide:tH,useValue:!0}]:[]])}function fhe(){return typeof ngI18nClosureMode<"u"&&ngI18nClosureMode&&typeof goog<"u"&&goog.LOCALE!=="en"?goog.LOCALE:typeof $localize<"u"&&$localize.locale||I0}var Ts=new $e(ngDevMode?"LocaleId":"",{providedIn:"root",factory:()=>fe(Ts,Wt.Optional|Wt.SkipSelf)||fhe()}),OT=new $e(ngDevMode?"DefaultCurrencyCode":"",{providedIn:"root",factory:()=>Upe}),hhe=new $e(ngDevMode?"Translations":""),mhe=new $e(ngDevMode?"TranslationsFormat":""),sA;(function(t){t[t.Error=0]="Error",t[t.Warning=1]="Warning",t[t.Ignore=2]="Ignore"})(sA||(sA={}));var ghe=200,_V=1200,rd=class rd{constructor(){l(this,"window",null);l(this,"observer",null);l(this,"options",fe(tT));l(this,"lcpImageUrl")}start(){if(typeof ngServerMode<"u"&&ngServerMode||typeof PerformanceObserver>"u"||this.options?.disableImageSizeWarning&&this.options?.disableImageLazyLoadWarning)return;this.observer=this.initPerformanceObserver();let e=No(),n=e.defaultView;if(n){this.window=n;let r=()=>{setTimeout(this.scanImages.bind(this),ghe)},s=()=>{e.readyState==="complete"?r():this.window?.addEventListener("load",r,{once:!0})};typeof Zone<"u"?Zone.root.run(()=>s()):s()}}ngOnDestroy(){this.observer?.disconnect()}initPerformanceObserver(){if(typeof PerformanceObserver>"u")return null;let e=new PerformanceObserver(n=>{let r=n.getEntries();if(r.length===0)return;let i=r[r.length-1].element?.src??"";i.startsWith("data:")||i.startsWith("blob:")||(this.lcpImageUrl=i)});return e.observe({type:"largest-contentful-paint",buffered:!0}),e}scanImages(){let e=No().querySelectorAll("img"),n,r=!1;e.forEach(s=>{this.options?.disableImageSizeWarning||!s.getAttribute("ng-img")&&this.isOversized(s)&&yhe(s.src),!this.options?.disableImageLazyLoadWarning&&this.lcpImageUrl&&s.src===this.lcpImageUrl&&(n=!0,(s.loading!=="lazy"||s.getAttribute("ng-img"))&&(r=!0))}),n&&!r&&this.lcpImageUrl&&!this.options?.disableImageLazyLoadWarning&&vhe(this.lcpImageUrl)}isOversized(e){if(!this.window)return!1;let n=[".svg"],r=(e.src||"").toLowerCase();if(n.some(g=>r.endsWith(g)))return!1;let s=this.window.getComputedStyle(e),i=parseFloat(s.getPropertyValue("width")),o=parseFloat(s.getPropertyValue("height")),a=s.getPropertyValue("box-sizing");if(s.getPropertyValue("object-fit")==="cover")return!1;if(a==="border-box"){let g=s.getPropertyValue("padding-top"),v=s.getPropertyValue("padding-right"),w=s.getPropertyValue("padding-bottom"),b=s.getPropertyValue("padding-left");i-=parseFloat(v)+parseFloat(b),o-=parseFloat(g)+parseFloat(w)}let u=e.naturalWidth,d=e.naturalHeight,p=this.window.devicePixelRatio*i,f=this.window.devicePixelRatio*o,h=u-p>=_V,m=d-f>=_V;return h||m}};l(rd,"\u0275fac",function(n){return new(n||rd)}),l(rd,"\u0275prov",hn({token:rd,factory:rd.\u0275fac,providedIn:"root"}));var bC=rd;(typeof ngDevMode>"u"||ngDevMode)&&Us(bC,[{type:St,args:[{providedIn:"root"}]}],null,null);function vhe(t){console.warn(gn(-913,`An image with src ${t} is the Largest Contentful Paint (LCP) element but was given a "loading" value of "lazy", which can negatively impact application loading performance. This warning can be addressed by changing the loading value of the LCP image to "eager", or by using the NgOptimizedImage directive's prioritization utilities. For more information about addressing or disabling this warning, see https://angular.dev/errors/NG0913`))}function yhe(t){console.warn(gn(-913,`An image with src ${t} has intrinsic file dimensions much larger than its rendered size. This can negatively impact application loading performance. For more information about addressing or disabling this warning, see https://angular.dev/errors/NG0913`))}var wC=new $e(ngDevMode?"PlatformDestroyListeners":""),h9=new $e(ngDevMode?"ENABLE_ROOT_COMPONENT_BOOTSTRAP":"");function eh(t){return!t.moduleRef}function m9(t){let e=eh(t)?t.r3Injector:t.moduleRef.injector,n=e.get(qt);return n.run(()=>{eh(t)?t.r3Injector.resolveInjectorInitializers():t.moduleRef.resolveInjectorInitializers();let r=e.get($s,null);if(typeof ngDevMode>"u"||ngDevMode){if(r===null){let i=eh(t)?"No `ErrorHandler` found in the Dependency Injection tree.":"No ErrorHandler. Is platform module (BrowserModule) included";throw new ne(402,i)}if(e.get(tH)&&e.get(PN))throw new ne(408,"Invalid change detection configuration: provideZoneChangeDetection and provideExperimentalZonelessChangeDetection cannot be used together.")}let s;if(n.runOutsideAngular(()=>{s=n.onError.subscribe({next:i=>{r.handleError(i)}})}),eh(t)){let i=()=>e.destroy(),o=t.platformInjector.get(wC);o.add(i),e.onDestroy(()=>{s.unsubscribe(),o.delete(i)})}else{let i=()=>t.moduleRef.destroy(),o=t.platformInjector.get(wC);o.add(i),t.moduleRef.onDestroy(()=>{fS(t.allPlatformModules,t.moduleRef),s.unsubscribe(),o.delete(i)})}return whe(r,n,()=>{let i=e.get(Ph);return i.runInitializers(),i.donePromise.then(()=>{let o=e.get(Ts,I0);if(PU(o||I0),!e.get(h9,!0))return eh(t)?e.get(yr):(t.allPlatformModules.push(t.moduleRef),t.moduleRef);if((typeof ngDevMode>"u"||ngDevMode)&&e.get(bC).start(),eh(t)){let c=e.get(yr);return t.rootComponent!==void 0&&c.bootstrap(t.rootComponent),c}else return bhe(t.moduleRef,t.allPlatformModules),t.moduleRef})})})}function bhe(t,e){let n=t.injector.get(yr);if(t._bootstrapComponents.length>0)t._bootstrapComponents.forEach(r=>n.bootstrap(r));else if(t.instance.ngDoBootstrap)t.instance.ngDoBootstrap(n);else throw new ne(-403,ngDevMode&&`The module ${tn(t.instance.constructor)} was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. Please define one of these.`);e.push(t)}function whe(t,e,n){try{let r=n();return jd(r)?r.catch(s=>{throw e.runOutsideAngular(()=>t.handleError(s)),s}):r}catch(r){throw e.runOutsideAngular(()=>t.handleError(r)),r}}var sd=class sd{constructor(e){l(this,"_injector");l(this,"_modules",[]);l(this,"_destroyListeners",[]);l(this,"_destroyed",!1);this._injector=e}bootstrapModuleFactory(e,n){let r=n?.scheduleInRootZone,s=()=>Gie(n?.ngZone,{...NN({eventCoalescing:n?.ngZoneEventCoalescing,runCoalescing:n?.ngZoneRunCoalescing}),scheduleInRootZone:r}),i=n?.ignoreChangesOutsideZone,o=[LT({ngZoneFactory:s,ignoreChangesOutsideZone:i}),{provide:no,useExisting:vl}],a=Bue(e.moduleType,this.injector,o);return m9({moduleRef:a,allPlatformModules:this._modules,platformInjector:this.injector})}bootstrapModule(e,n=[]){let r=Tj({},n);return f9(this.injector,r,e).then(s=>this.bootstrapModuleFactory(s,r))}onDestroy(e){this._destroyListeners.push(e)}get injector(){return this._injector}destroy(){if(this._destroyed)throw new ne(404,ngDevMode&&"The platform has already been destroyed!");this._modules.slice().forEach(n=>n.destroy()),this._destroyListeners.forEach(n=>n());let e=this._injector.get(wC,null);e&&(e.forEach(n=>n()),e.clear()),this._destroyed=!0}get destroyed(){return this._destroyed}};l(sd,"\u0275fac",function(n){return new(n||sd)(Zr(Ln))}),l(sd,"\u0275prov",hn({token:sd,factory:sd.\u0275fac,providedIn:"platform"}));var Rh=sd;(typeof ngDevMode>"u"||ngDevMode)&&Us(Rh,[{type:St,args:[{providedIn:"platform"}]}],()=>[{type:Ln}],null);var yh=null;function g9(t){if(pb())throw new ne(400,ngDevMode&&"There can be only one platform. Destroy the previous one to create a new one.");xj(),Sj(),yh=typeof ngServerMode>"u"||!ngServerMode?t:null;let e=t.get(Rh);return w9(t),e}function BT(t,e,n=[]){let r=`Platform: ${e}`,s=new $e(r);return(i=[])=>{let o=pb();if(!o){let a=[...n,...i,{provide:s,useValue:!0}];o=t?.(a)??g9(v9(a,r))}return typeof ngServerMode<"u"&&ngServerMode?o:y9(s)}}function v9(t=[],e){return Ln.create({name:e,providers:[{provide:B0,useValue:"platform"},{provide:wC,useValue:new Set([()=>yh=null])},...t]})}function y9(t){let e=pb();if(!e)throw new ne(401,ngDevMode&&"No platform exists!");if((typeof ngDevMode>"u"||ngDevMode)&&!e.injector.get(t,null))throw new ne(400,"A platform with a different configuration has been created. Please destroy it first.");return e}function pb(){return typeof ngServerMode<"u"&&ngServerMode?null:yh?.get(Rh)??null}function Ehe(){pb()?.destroy()}function b9(t=[]){if(yh)return yh;xj();let e=v9(t);return(typeof ngServerMode>"u"||!ngServerMode)&&(yh=e),Sj(),w9(e),e}function xhe(t){return ma([{provide:U0,useValue:t,multi:!0}])}function w9(t){let e=t.get(U0,null);AA(t,()=>{e?.forEach(n=>n())})}function She(t){if(typeof ngDevMode>"u"||ngDevMode){if(t.interval===void 0&&!t.useNgZoneOnStable)throw new Error("Must provide one of `useNgZoneOnStable` or `interval`");let e=t?.exhaustive===!1?Mc.OnlyDirtyViews:Mc.Exhaustive;return ma([t?.useNgZoneOnStable?{provide:qt,useFactory:()=>new EC(e)}:[],t?.interval!==void 0?Che(t.interval,e):[],{provide:li,multi:!0,useValue:()=>{if(t?.useNgZoneOnStable&&!(fe(qt)instanceof EC))throw new Error("`provideExperimentalCheckNoChangesForDebug` with `useNgZoneOnStable` must be after any other provider for `NgZone`.")}}])}else return ma([])}var EC=class extends qt{constructor(n){let r=fe(Od);super({shouldCoalesceEventChangeDetection:!0,shouldCoalesceRunChangeDetection:r});l(this,"checkNoChangesMode");l(this,"applicationRef");l(this,"scheduler");l(this,"errorHandler");l(this,"injector",fe(ci));this.checkNoChangesMode=n,r?(this.onMicrotaskEmpty.emit=()=>{},this.onStable.emit=()=>{this.scheduler||(this.scheduler=this.injector.get(vl)),!(this.scheduler.pendingRenderTaskId||this.scheduler.runningTick)&&this.checkApplicationViews()},this.onUnstable.emit=()=>{}):this.runOutsideAngular(()=>{this.onStable.subscribe(()=>{this.checkApplicationViews()})})}checkApplicationViews(){this.applicationRef||(this.applicationRef=this.injector.get(yr));for(let n of this.applicationRef.allViews)try{sP(n._lView,this.checkNoChangesMode,n.notifyErrorHandler)}catch(r){this.errorHandler||(this.errorHandler=this.injector.get($s)),this.errorHandler.handleError(r)}}};function Che(t,e){return{provide:li,multi:!0,useFactory:()=>{let n=fe(yr),r=fe($s),s=fe(vl),i=fe(qt);return()=>{function o(){i.runOutsideAngular(()=>{setTimeout(()=>{if(!n.destroyed){if(s.pendingRenderTaskId||s.runningTick){o();return}for(let a of n.allViews)try{sP(a._lView,e,a.notifyErrorHandler)}catch(c){r.handleError(c)}o()}},t)})}o()}}}}function The(){return typeof ngDevMode>"u"||!!ngDevMode}function Dhe(){(typeof ngDevMode>"u"||ngDevMode)&&(Yn.ngDevMode=!1)}function _he(t){let e=K4(t);if(!e)throw E9(t);return new Mh(e)}function Ihe(t){let e=K4(t);if(!e)throw E9(t);return e}function E9(t){return new Error(`No module with ID ${t} loaded`)}var An=class{};l(An,"__NG_ELEMENT_ID__",x9);function x9(t){return khe(Bt(),re(),(t&16)===16)}function khe(t,e,n){if(Ro(t)&&!n){let r=Bs(t.index,e);return new _h(r,r)}else if(t.type&175){let r=e[Kn];return new _h(r,e)}return null}var xC=class extends An{},iA=class extends xC{},oA=class{constructor(e,n){l(this,"name");l(this,"callback");this.name=e,this.callback=n}};function Ahe(t){return t.map(e=>e.nativeElement)}var A0=class{constructor(e){l(this,"nativeNode");this.nativeNode=e}get parent(){let e=this.nativeNode.parentNode;return e?new kd(e):null}get injector(){return xH(this.nativeNode)}get componentInstance(){let e=this.nativeNode;return e&&($S(e)||wH(e))}get context(){return $S(this.nativeNode)||bH(this.nativeNode)}get listeners(){return TH(this.nativeNode).filter(e=>e.type==="dom")}get references(){return foe(this.nativeNode)}get providerTokens(){return doe(this.nativeNode)}},kd=class extends A0{constructor(e){ngDevMode&&xc(e),super(e)}get nativeElement(){return this.nativeNode.nodeType==Node.ELEMENT_NODE?this.nativeNode:null}get name(){let e=Rs(this.nativeNode),n=e?e.lView:null;return n!==null?n[de].data[e.nodeIndex].value:this.nativeNode.nodeName}get properties(){let e=Rs(this.nativeNode),n=e?e.lView:null;if(n===null)return{};let r=n[de].data,s=r[e.nodeIndex],i={};return Mhe(this.nativeElement,i),Nhe(i,s,n,r),i}get attributes(){let e={},n=this.nativeElement;if(!n)return e;let r=Rs(n),s=r?r.lView:null;if(s===null)return{};let i=s[de].data[r.nodeIndex].attrs,o=[];if(i){let a=0;for(;ae[i]=!0),e}get childNodes(){let e=this.nativeNode.childNodes,n=[];for(let r=0;r{if(i.name===e){let o=i.callback;o.call(r,n),s.push(o)}}),typeof r.eventListeners=="function"&&r.eventListeners(e).forEach(i=>{if(i.toString().indexOf("__ngUnwrap__")!==-1){let o=i("__ngUnwrap__");return s.indexOf(o)===-1&&o.call(r,n)}})}};function Mhe(t,e){if(t){let n=Object.getPrototypeOf(t),r=Node.prototype;for(;n!==null&&n!==r;){let s=Object.getOwnPropertyDescriptors(n);for(let i in s)if(!i.startsWith("__")&&!i.startsWith("on")){let o=t[i];Phe(o)&&(e[i]=o)}n=Object.getPrototypeOf(n)}}}function Phe(t){return typeof t=="string"||typeof t=="boolean"||typeof t=="number"||t===null}function IV(t,e,n,r){let s=Rs(t.nativeNode),i=s?s.lView:null;if(i!==null){let o=i[de].data[s.nodeIndex];zu(o,i,e,n,r,t.nativeNode)}else RN(t.nativeNode,e,n,r)}function zu(t,e,n,r,s,i){ngDevMode&&Hs(t,e);let o=nie(t,e);if(t.type&11){if(Ek(o,n,r,s,i),Ro(t)){let c=Bs(t.index,e);c&&c[de].firstChild&&zu(c[de].firstChild,c,n,r,s,i)}else t.child&&zu(t.child,e,n,r,s,i),o&&RN(o,n,r,s);let a=e[t.index];Ir(a)&&kV(a,n,r,s,i)}else if(t.type&4){let a=e[t.index];Ek(a[va],n,r,s,i),kV(a,n,r,s,i)}else if(t.type&16){let a=e[Kn],u=a[Xr].projection[t.projection];if(Array.isArray(u))for(let d of u)Ek(d,n,r,s,i);else if(u){let d=a[ir],p=d[de].data[u.index];zu(p,d,n,r,s,i)}}else t.child&&zu(t.child,e,n,r,s,i);if(i!==o){let a=t.flags&2?t.projectionNext:t.next;a&&zu(a,e,n,r,s,i)}}function kV(t,e,n,r,s){for(let i=Wn;i1){let d=c[1];for(let p=1;pe,CC=class{constructor(e){l(this,"length",0);l(this,"collection");l(this,"_linkedRecords",null);l(this,"_unlinkedRecords",null);l(this,"_previousItHead",null);l(this,"_itHead",null);l(this,"_itTail",null);l(this,"_additionsHead",null);l(this,"_additionsTail",null);l(this,"_movesHead",null);l(this,"_movesTail",null);l(this,"_removalsHead",null);l(this,"_removalsTail",null);l(this,"_identityChangesHead",null);l(this,"_identityChangesTail",null);l(this,"_trackByFn");this._trackByFn=e||Rhe}forEachItem(e){let n;for(n=this._itHead;n!==null;n=n._next)e(n)}forEachOperation(e){let n=this._itHead,r=this._removalsHead,s=0,i=null;for(;n||r;){let o=!r||n&&n.currentIndex{o=this._trackByFn(s,a),n===null||!Object.is(n.trackById,o)?(n=this._mismatch(n,a,o,s),r=!0):(r&&(n=this._verifyReinsertion(n,a,o,s)),Object.is(n.item,a)||this._addIdentityChange(n,a)),n=n._next,s++}),this.length=s;return this._truncate(n),this.collection=e,this.isDirty}get isDirty(){return this._additionsHead!==null||this._movesHead!==null||this._removalsHead!==null||this._identityChangesHead!==null}_reset(){if(this.isDirty){let e;for(e=this._previousItHead=this._itHead;e!==null;e=e._next)e._nextPrevious=e._next;for(e=this._additionsHead;e!==null;e=e._nextAdded)e.previousIndex=e.currentIndex;for(this._additionsHead=this._additionsTail=null,e=this._movesHead;e!==null;e=e._nextMoved)e.previousIndex=e.currentIndex;this._movesHead=this._movesTail=null,this._removalsHead=this._removalsTail=null,this._identityChangesHead=this._identityChangesTail=null}}_mismatch(e,n,r,s){let i;return e===null?i=this._itTail:(i=e._prev,this._remove(e)),e=this._unlinkedRecords===null?null:this._unlinkedRecords.get(r,null),e!==null?(Object.is(e.item,n)||this._addIdentityChange(e,n),this._reinsertAfter(e,i,s)):(e=this._linkedRecords===null?null:this._linkedRecords.get(r,s),e!==null?(Object.is(e.item,n)||this._addIdentityChange(e,n),this._moveAfter(e,i,s)):e=this._addAfter(new aA(n,r),i,s)),e}_verifyReinsertion(e,n,r,s){let i=this._unlinkedRecords===null?null:this._unlinkedRecords.get(r,null);return i!==null?e=this._reinsertAfter(i,e._prev,s):e.currentIndex!=s&&(e.currentIndex=s,this._addToMoves(e,s)),e}_truncate(e){for(;e!==null;){let n=e._next;this._addToRemovals(this._unlink(e)),e=n}this._unlinkedRecords!==null&&this._unlinkedRecords.clear(),this._additionsTail!==null&&(this._additionsTail._nextAdded=null),this._movesTail!==null&&(this._movesTail._nextMoved=null),this._itTail!==null&&(this._itTail._next=null),this._removalsTail!==null&&(this._removalsTail._nextRemoved=null),this._identityChangesTail!==null&&(this._identityChangesTail._nextIdentityChange=null)}_reinsertAfter(e,n,r){this._unlinkedRecords!==null&&this._unlinkedRecords.remove(e);let s=e._prevRemoved,i=e._nextRemoved;return s===null?this._removalsHead=i:s._nextRemoved=i,i===null?this._removalsTail=s:i._prevRemoved=s,this._insertAfter(e,n,r),this._addToMoves(e,r),e}_moveAfter(e,n,r){return this._unlink(e),this._insertAfter(e,n,r),this._addToMoves(e,r),e}_addAfter(e,n,r){return this._insertAfter(e,n,r),this._additionsTail===null?this._additionsTail=this._additionsHead=e:this._additionsTail=this._additionsTail._nextAdded=e,e}_insertAfter(e,n,r){let s=n===null?this._itHead:n._next;return e._next=s,e._prev=n,s===null?this._itTail=e:s._prev=e,n===null?this._itHead=e:n._next=e,this._linkedRecords===null&&(this._linkedRecords=new TC),this._linkedRecords.put(e),e.currentIndex=r,e}_remove(e){return this._addToRemovals(this._unlink(e))}_unlink(e){this._linkedRecords!==null&&this._linkedRecords.remove(e);let n=e._prev,r=e._next;return n===null?this._itHead=r:n._next=r,r===null?this._itTail=n:r._prev=n,e}_addToMoves(e,n){return e.previousIndex===n||(this._movesTail===null?this._movesTail=this._movesHead=e:this._movesTail=this._movesTail._nextMoved=e),e}_addToRemovals(e){return this._unlinkedRecords===null&&(this._unlinkedRecords=new TC),this._unlinkedRecords.put(e),e.currentIndex=null,e._nextRemoved=null,this._removalsTail===null?(this._removalsTail=this._removalsHead=e,e._prevRemoved=null):(e._prevRemoved=this._removalsTail,this._removalsTail=this._removalsTail._nextRemoved=e),e}_addIdentityChange(e,n){return e.item=n,this._identityChangesTail===null?this._identityChangesTail=this._identityChangesHead=e:this._identityChangesTail=this._identityChangesTail._nextIdentityChange=e,e}},aA=class{constructor(e,n){l(this,"item");l(this,"trackById");l(this,"currentIndex",null);l(this,"previousIndex",null);l(this,"_nextPrevious",null);l(this,"_prev",null);l(this,"_next",null);l(this,"_prevDup",null);l(this,"_nextDup",null);l(this,"_prevRemoved",null);l(this,"_nextRemoved",null);l(this,"_nextAdded",null);l(this,"_nextMoved",null);l(this,"_nextIdentityChange",null);this.item=e,this.trackById=n}},lA=class{constructor(){l(this,"_head",null);l(this,"_tail",null)}add(e){this._head===null?(this._head=this._tail=e,e._nextDup=null,e._prevDup=null):(this._tail._nextDup=e,e._prevDup=this._tail,e._nextDup=null,this._tail=e)}get(e,n){let r;for(r=this._head;r!==null;r=r._nextDup)if((n===null||n<=r.currentIndex)&&Object.is(r.trackById,e))return r;return null}remove(e){let n=e._prevDup,r=e._nextDup;return n===null?this._head=r:n._nextDup=r,r===null?this._tail=n:r._prevDup=n,this._head===null}},TC=class{constructor(){l(this,"map",new Map)}put(e){let n=e.trackById,r=this.map.get(n);r||(r=new lA,this.map.set(n,r)),r.add(e)}get(e,n){let r=e,s=this.map.get(r);return s?s.get(e,n):null}remove(e){let n=e.trackById;return this.map.get(n).remove(e)&&this.map.delete(n),e}get isEmpty(){return this.map.size===0}clear(){this.map.clear()}};function AV(t,e,n){let r=t.previousIndex;if(r===null)return r;let s=0;return n&&r{if(n&&n.key===s)this._maybeAddToChanges(n,r),this._appendAfter=n,n=n._next;else{let i=this._getOrCreateRecordForKey(s,r);n=this._insertBeforeOrAppend(n,i)}}),n){n._prev&&(n._prev._next=null),this._removalsHead=n;for(let r=n;r!==null;r=r._nextRemoved)r===this._mapHead&&(this._mapHead=null),this._records.delete(r.key),r._nextRemoved=r._next,r.previousValue=r.currentValue,r.currentValue=null,r._prev=null,r._next=null}return this._changesTail&&(this._changesTail._nextChanged=null),this._additionsTail&&(this._additionsTail._nextAdded=null),this.isDirty}_insertBeforeOrAppend(e,n){if(e){let r=e._prev;return n._next=e,n._prev=r,e._prev=n,r&&(r._next=n),e===this._mapHead&&(this._mapHead=n),this._appendAfter=e,e}return this._appendAfter?(this._appendAfter._next=n,n._prev=this._appendAfter):this._mapHead=n,this._appendAfter=n,null}_getOrCreateRecordForKey(e,n){if(this._records.has(e)){let s=this._records.get(e);this._maybeAddToChanges(s,n);let i=s._prev,o=s._next;return i&&(i._next=o),o&&(o._prev=i),s._next=null,s._prev=null,s}let r=new uA(e);return this._records.set(e,r),r.currentValue=n,this._addToAdditions(r),r}_reset(){if(this.isDirty){let e;for(this._previousMapHead=this._mapHead,e=this._previousMapHead;e!==null;e=e._next)e._nextPrevious=e._next;for(e=this._changesHead;e!==null;e=e._nextChanged)e.previousValue=e.currentValue;for(e=this._additionsHead;e!=null;e=e._nextAdded)e.previousValue=e.currentValue;this._changesHead=this._changesTail=null,this._additionsHead=this._additionsTail=null,this._removalsHead=null}}_maybeAddToChanges(e,n){Object.is(n,e.currentValue)||(e.previousValue=e.currentValue,e.currentValue=n,this._addToChanges(e))}_addToAdditions(e){this._additionsHead===null?this._additionsHead=this._additionsTail=e:(this._additionsTail._nextAdded=e,this._additionsTail=e)}_addToChanges(e){this._changesHead===null?this._changesHead=this._changesTail=e:(this._changesTail._nextChanged=e,this._changesTail=e)}_forEach(e,n){e instanceof Map?e.forEach(n):Object.keys(e).forEach(r=>n(e[r],r))}},uA=class{constructor(e){l(this,"key");l(this,"previousValue",null);l(this,"currentValue",null);l(this,"_nextPrevious",null);l(this,"_next",null);l(this,"_prev",null);l(this,"_nextAdded",null);l(this,"_nextRemoved",null);l(this,"_nextChanged",null);this.key=e}};function MV(){return new Fc([new SC])}var bc=class bc{constructor(e){l(this,"factories");this.factories=e}static create(e,n){if(n!=null){let r=n.factories.slice();e=e.concat(r)}return new bc(e)}static extend(e){return{provide:bc,useFactory:n=>bc.create(e,n||MV()),deps:[[bc,new bl,new lt]]}}find(e){let n=this.factories.find(r=>r.supports(e));if(n!=null)return n;throw new ne(901,ngDevMode&&`Cannot find a differ supporting object '${e}' of type '${Fhe(e)}'`)}};l(bc,"\u0275prov",hn({token:bc,providedIn:"root",factory:MV}));var Fc=bc;function Fhe(t){return t.name||typeof t}function PV(){return new xa([new DC])}var wc=class wc{constructor(e){l(this,"factories");this.factories=e}static create(e,n){if(n){let r=n.factories.slice();e=e.concat(r)}return new wc(e)}static extend(e){return{provide:wc,useFactory:n=>wc.create(e,n||PV()),deps:[[wc,new bl,new lt]]}}find(e){let n=this.factories.find(r=>r.supports(e));if(n)return n;throw new ne(901,ngDevMode&&`Cannot find a differ supporting object '${e}'`)}};l(wc,"\u0275prov",hn({token:wc,providedIn:"root",factory:PV}));var xa=wc,Lhe=[new DC],Ohe=[new SC],Bhe=new Fc(Ohe),$he=new xa(Lhe),FN=BT(null,"core",[]),id=class id{constructor(e){}};l(id,"\u0275fac",function(n){return new(n||id)(Zr(yr))}),l(id,"\u0275mod",EP({type:id})),l(id,"\u0275inj",LC({}));var Lc=id;(typeof ngDevMode>"u"||ngDevMode)&&Us(Lc,[{type:co}],()=>[{type:yr}],null);function LN(t){let{rootComponent:e,appProviders:n,platformProviders:r,platformRef:s}=t;if(kn(8),typeof ngServerMode<"u"&&ngServerMode&&!s)throw new ne(401,ngDevMode&&"Missing Platform: This may be due to using `bootstrapApplication` on the server without passing a `BootstrapContext`. Please make sure that `bootstrapApplication` is called with a `context` argument.");try{let i=s?.injector??b9(r);(typeof ngDevMode>"u"||ngDevMode)&&e!==void 0&&Gae(e);let o=[LT({}),{provide:no,useExisting:vl},...n||[]],a=new tC({providers:o,parent:i,debugName:typeof ngDevMode>"u"||ngDevMode?"Environment Injector":"",runEnvironmentInitializers:!1});return m9({r3Injector:a.injector,platformInjector:i,rootComponent:e})}catch(i){return Promise.reject(i)}finally{kn(9)}}var rS=new WeakSet,NV="",vS=[];function RV(t){return t.get(gM,MH)}function ON(){let t=[{provide:gM,useFactory:()=>{let e=!0;if(typeof ngServerMode>"u"||!ngServerMode){let n=fe(Ii);e=!!window._ejsas?.[n]}return e&&Ss("NgEventReplay"),e}}];return(typeof ngServerMode>"u"||!ngServerMode)&&t.push({provide:li,useValue:()=>{let e=fe(yr),{injector:n}=e;if(!rS.has(e)){let r=fe(m0);if(RV(n)){$oe();let s=n.get(Ii),i=Ooe(s,(o,a,c)=>{o.nodeType===Node.ELEMENT_NODE&&(Foe(o,a,c),UH(o,r))});e.onDestroy(i)}}},multi:!0},{provide:lb,useFactory:()=>{let e=fe(yr),{injector:n}=e;return()=>{!RV(n)||rS.has(e)||(rS.add(e),e.onDestroy(()=>{if(rS.delete(e),typeof ngServerMode<"u"&&!ngServerMode){let r=n.get(Ii);GI(r)}}),e.whenStable().then(()=>{if(e.destroyed)return;let r=n.get(EM);Vhe(r,n);let s=n.get(m0);s.get(NV)?.forEach(qH),s.delete(NV);let i=r.instance;Z0(n)?e.onDestroy(()=>i.cleanUp()):i.cleanUp()}))}},multi:!0}),t}var Vhe=(t,e)=>{let n=e.get(Ii),r=window._ejsas[n],s=t.instance=new qx(new jx(r.c));for(let a of r.et)s.addEvent(a);for(let a of r.etc)s.addEvent(a);let i=W$(n);s.replayEarlyEventInfos(i),GI(n);let o=new Ux(a=>{jhe(e,a,a.currentTarget)});q$(s,o)};function Hhe(t,e,n){let r=new Map,s=e[Cc],i=t.cleanup;if(!i||!s)return r;for(let o=0;o=0)&&(r.has(d)?r.get(d).push(u):r.set(d,[u]))}return r}function jhe(t,e,n){let r=(n&&n.getAttribute(G0))??"";/d\d+/.test(r)?Uhe(r,t,e,n):e.eventPhase===zI.REPLAY&&WH(e,n)}function Uhe(t,e,n,r){vS.push({event:n,currentTarget:r}),Vc(e,t,qhe)}function qhe(t){let e=[...vS],n=new Set(t);vS=[];for(let{event:r,currentTarget:s}of e){let i=s.getAttribute(G0);n.has(i)?WH(r,s):vS.push({event:r,currentTarget:s})}}var dA=class{constructor(){l(this,"views",[]);l(this,"indexByContent",new Map)}add(e){let n=JSON.stringify(e);if(!this.indexByContent.has(n)){let r=this.views.length;return this.views.push(e),this.indexByContent.set(n,r),r}return this.indexByContent.get(n)}getAll(){return this.views}},Whe=0;function S9(t){return t.ssrId||(t.ssrId=`t${Whe++}`),t.ssrId}function C9(t,e,n){let r=[];return Dh(t,e,n,r),r.length}function zhe(t){let e=[];return rP(t,e),e.length}function T9(t,e,n){let r=t[Mn];return r&&!r.hasAttribute(p0)?_C(r,t,null,e):null}function D9(t,e,n){let r=OA(t[Mn]),s=T9(r,e);if(s===null)return;let i=dn(r[Mn]),o=t[ir],a=_C(i,o,null,e),c=r[pt],u=`${s}|${a}`;c.setAttribute(i,By,u)}function Ghe(t,e){let n=t.injector,r=Cce(n),s=Z0(n),i=new dA,o=new Map,a=t._views,c=n.get(gM,MH),u={regular:new Set,capture:new Set},d=new Map;t.injector.get(Ii);for(let h of a){let m=XH(h);if(m!==null){let g={serializedViewCollection:i,corruptedTextNodes:o,isI18nHydrationEnabled:r,isIncrementalHydrationEnabled:s,i18nChildren:new Map,eventTypesToReplay:u,shouldReplayEvents:c,deferBlocks:d};Ir(m)?D9(m,g):T9(m,g),Khe(o,e)}}let p=i.getAll(),f=n.get(ba);if(f.set(xM,p),d.size>0){let h={};for(let[m,g]of d.entries())h[m]=g;f.set(nT,h)}return u}function Zhe(t,e,n,r,s){let i=[],o="";for(let a=Wn;a0&&(D[mM]=B),r!==null&&(D[_H]=r),s.deferBlocks.set(w,D);let M=dn(t);M!==void 0?M.nodeType===Node.COMMENT_NODE&&FV(M,w):(ngDevMode&&nb(M,c,e),ngDevMode&&Zh(M,Node.COMMENT_NODE,null,c,e,!0),FV(M,w)),m||eme(v,b,w,s),r=w,p[hM]=w}p[VS]=g[wa]}m||Object.assign(p,_9(t[a],r,s))}let f=JSON.stringify(p);if(i.length>0&&f===o){let h=i[i.length-1];h[lh]??(h[lh]=1),h[lh]++}else o=f,i.push(p)}return i}function Yhe(t){let e=new Set([0,1,2,5]),n=[];for(let[r,s]of t)e.has(r)&&(s===null?n.push(r):n.push({trigger:r,delay:s.delay}));return n}function zy(t,e,n,r){var i;let s=e.index-He;t[ch]??(t[ch]={}),(i=t[ch])[s]??(i[s]=bce(e,n,r))}function Sk(t,e){let n=typeof e=="number"?e:e.index-He;t[qu]??(t[qu]=[]),t[qu].includes(n)||t[qu].push(n)}function _9(t,e=null,n){let r={},s=t[de],i=Tce(s,n),o=n.shouldReplayEvents?Hhe(s,t,n.eventTypesToReplay):null;for(let a=He;a0){let i=e.filter(o=>o.nodeType===Node.ELEMENT_NODE);for(let o of i)jH(o,s,n)}}var LV=!1,OV=!1,BV=!1,tme=1e4;function nme(){LV||(LV=!0,Uoe(),Npe(),Nfe(),Lpe(),rde(),mue(),Hce(),fle())}function rme(){OV||(OV=!0,Zpe(),Sce(),Nce())}function sme(){BV||(BV=!0,nae())}function ime(t){let e=t.get(Ai),n=`Angular hydrated ${ngDevMode.hydratedComponents} component(s) and ${ngDevMode.hydratedNodes} node(s), ${ngDevMode.componentsSkippedHydration} component(s) were skipped. `+(Z0(t)?`${ngDevMode.deferBlocksWithIncrementalHydration} defer block(s) were configured to use incremental hydration. `:"")+"Learn more at https://angular.dev/guide/hydration.";e.log(n)}function ome(t){let e=t.whenStable();if(typeof ngDevMode<"u"&&ngDevMode){let n=tme,r=t.injector.get(Ai),i=t.injector.get(qt).runOutsideAngular(()=>setTimeout(()=>lme(n,r),n));e.finally(()=>clearTimeout(i))}return e}var I9="ngcm";function ame(){let t=No();return(typeof ngServerMode>"u"||!ngServerMode)&&t.body.hasAttribute(I9)}function k9(){let t=[{provide:ad,useFactory:()=>{let e=!0;return(typeof ngServerMode>"u"||!ngServerMode)&&(e=!!fe(ba,{optional:!0})?.get(xM,null)),e&&Ss("NgHydration"),e}},{provide:li,useValue:()=>{if(v4(!1),!(typeof ngServerMode<"u"&&ngServerMode)){if(fe(ad))lae(No()),nme();else if(typeof ngDevMode<"u"&&ngDevMode&&!ame()){let e=fe(Ai),n=gn(-505,"Angular hydration was requested on the client, but there was no serialized information present in the server response, thus hydration was not enabled. Make sure the `provideClientHydration()` is included into the list of providers in the server part of the application configuration.");e.warn(n)}}},multi:!0}];return(typeof ngServerMode>"u"||!ngServerMode)&&t.push({provide:kH,useFactory:()=>fe(ad)},{provide:lb,useFactory:()=>{if(fe(ad)){let e=fe(yr);return()=>{ome(e).then(()=>{e.destroyed||(E4(e),typeof ngDevMode<"u"&&ngDevMode&&(Goe(e.injector),ime(e.injector)))})}}return()=>{}},multi:!0}),ma(t)}function A9(){return[{provide:AH,useFactory:()=>fe(ad)},{provide:li,useValue:()=>{fe(ad)&&(rme(),v4(!0),Ss("NgI18nHydration"))},multi:!0}]}function M9(){let t=[ON(),{provide:vM,useValue:!0},{provide:Da,useClass:t2},{provide:li,useValue:()=>{sme(),Ss("NgIncrementalHydration")},multi:!0}];return(typeof ngServerMode>"u"||!ngServerMode)&&t.push({provide:lb,useFactory:()=>{let e=fe(Ln),n=No();return()=>{let r=aae(e),s=wce(n,n.body);npe(e,r,s),eae(n,e)}},multi:!0}),t}function lme(t,e){let n=`Angular hydration expected the ApplicationRef.isStable() to emit \`true\`, but it didn't happen within ${t}ms. Angular hydration logic depends on the application becoming stable as a signal to complete hydration process.`;e.warn(gn(-506,n))}function Pi(t){return typeof t=="boolean"?t:t!=null&&t!=="false"}function cm(t,e=NaN){return!isNaN(parseFloat(t))&&!isNaN(Number(t))?Number(t):e}var P9="\u{1F170}\uFE0F",$T=!1;function cme(t){if(!$T)return;let{startLabel:e}=N9(t);performance.mark(e)}function ume(t){if(!$T)return;let{startLabel:e,labelName:n,endLabel:r}=N9(t);performance.mark(r),performance.measure(n,e,r),performance.clearMarks(e),performance.clearMarks(r)}function N9(t){let e=`${P9}:${t}`;return{labelName:e,startLabel:`start:${e}`,endLabel:`end:${e}`}}var $V=!1;function dme(){if(!$V&&(typeof performance>"u"||!performance.mark||!performance.measure)){$V=!0,console.warn("Performance API is not supported on this platform");return}$T=!0}function pme(){$T=!1}function sr(t){return _I(t)}function Ao(t,e){let n=gx(t,e?.equal);return ngDevMode&&(n.toString=()=>`[Computed: ${n()}]`,n[rr].debugName=e?.debugName),n}var n0=class n0 extends aC{constructor(){super(...arguments);l(this,"pendingTasks",fe(ya));l(this,"taskId",null)}schedule(n){super.schedule(n),this.taskId===null&&(this.taskId=this.pendingTasks.add(),queueMicrotask(()=>this.flush()))}flush(){try{super.flush()}finally{this.taskId!==null&&(this.pendingTasks.remove(this.taskId),this.taskId=null)}}};l(n0,"\u0275prov",hn({token:n0,providedIn:"root",factory:()=>new n0}));var IC=n0,pA=class{constructor(e,n,r,s,i,o){l(this,"scheduler");l(this,"effectFn");l(this,"zone");l(this,"injector");l(this,"unregisterOnDestroy");l(this,"watcher");this.scheduler=e,this.effectFn=n,this.zone=r,this.injector=i,this.watcher=r$(a=>this.runEffect(a),()=>this.schedule(),o),this.unregisterOnDestroy=s?.onDestroy(()=>this.destroy())}runEffect(e){try{this.effectFn(e)}catch(n){this.injector.get($s,null,{optional:!0})?.handleError(n)}}run(){this.watcher.run()}schedule(){this.scheduler.schedule(this)}destroy(){this.watcher.destroy(),this.unregisterOnDestroy?.()}};function VV(){}function fme(t,e){var o;ngDevMode&&q0(VV,"Call `effect` outside of a reactive context. For example, schedule the effect inside the component constructor."),!e?.injector&&us(VV);let n=e?.injector??fe(Ln),r=e?.manualCleanup!==!0?n.get(Es):null,s=new pA(n.get(IC),t,typeof Zone>"u"?null:Zone.current,r,n,e?.allowSignalWrites??!1),i=n.get(An,null,{optional:!0});return!i||!(i._lView[dt]&8)?s.watcher.notify():((o=i._lView)[fh]??(o[fh]=[])).push(s.watcher.notify),s}var Rme,fA=class{constructor(e){l(this,Rme);this[rr]=e}destroy(){this[rr].destroy()}};Rme=rr;function kC(t,e){ngDevMode&&q0(kC,"Call `effect` outside of a reactive context. For example, schedule the effect inside the component constructor."),!e?.injector&&us(kC),ngDevMode&&e?.allowSignalWrites!==void 0&&console.warn("The 'allowSignalWrites' flag is deprecated and no longer impacts effect() (writes are always allowed)");let n=e?.injector??fe(Ln),r=e?.manualCleanup!==!0?n.get(Es):null,s,i=n.get(ud,null,{optional:!0}),o=n.get(no);i!==null&&!e?.forceRoot?(s=gme(i.view,o,t),r instanceof FS&&r._lView===i.view&&(r=null)):s=vme(t,n.get(D0),o),s.injector=n,r!==null&&(s.onDestroyFn=r.onDestroy(()=>s.destroy()));let a=new fA(s);if(ngDevMode){s.debugName=e?.debugName??"";let c=as({injector:n,token:null});try{wse(a)}finally{as(c)}}return a}var R9={...rl,consumerIsAlwaysLive:!0,consumerAllowSignalWrites:!0,dirty:!0,hasRun:!1,cleanupFns:void 0,zone:null,kind:"effect",onDestroyFn:u0,run(){if(this.dirty=!1,ngDevMode&&fx())throw new Error("Schedulers cannot synchronously execute watches while scheduling.");if(this.hasRun&&!Fu(this))return;this.hasRun=!0;let t=r=>(this.cleanupFns??(this.cleanupFns=[])).push(r),e=sl(this),n=PS(!1);try{this.maybeCleanup(),this.fn(t)}finally{PS(n),pc(this,e)}},maybeCleanup(){if(this.cleanupFns?.length)try{for(;this.cleanupFns.length;)this.cleanupFns.pop()()}finally{this.cleanupFns=[]}}},hme={...R9,consumerMarkedDirty(){this.scheduler.schedule(this),this.notifier.notify(12)},destroy(){Lu(this),this.onDestroyFn(),this.maybeCleanup(),this.scheduler.remove(this)}},mme={...R9,consumerMarkedDirty(){this.view[dt]|=8192,Vh(this.view),this.notifier.notify(13)},destroy(){Lu(this),this.onDestroyFn(),this.maybeCleanup(),this.view[ol]?.delete(this)}};function gme(t,e,n){let r=Object.create(mme);return r.view=t,r.zone=typeof Zone<"u"?Zone.current:null,r.notifier=e,r.fn=n,t[ol]??(t[ol]=new Set),t[ol].add(r),r.consumerMarkedDirty(r),r}function vme(t,e,n){let r=Object.create(hme);return r.fn=t,r.scheduler=e,r.notifier=n,r.zone=typeof Zone<"u"?Zone.current:null,r.scheduler.schedule(r),r.notifier.notify(12),r}var Zn;(function(t){t[t.Idle=0]="Idle",t[t.Error=1]="Error",t[t.Loading=2]="Loading",t[t.Reloading=3]="Reloading",t[t.Resolved=4]="Resolved",t[t.Local=5]="Local"})(Zn||(Zn={}));var yme=t=>t;function hA(t,e){if(typeof t=="function"){let n=yx(t,yme,e?.equal);return HV(n)}else{let n=yx(t.source,t.computation,t.equal);return HV(n)}}function HV(t){ngDevMode&&(t.toString=()=>`[LinkedSignal: ${t()}]`);let e=t[rr],n=t;return n.set=r=>CI(e,r),n.update=r=>TI(e,r),n.asReadonly=KC.bind(t),n}function F9(t){t?.injector||us(F9);let e=t.request??(()=>null);return new AC(e,wme(t),t.defaultValue,t.equal?bme(t.equal):void 0,t.injector??fe(Ln))}var mA=class{constructor(e){l(this,"value");l(this,"isLoading",Ao(()=>this.status()===Zn.Loading||this.status()===Zn.Reloading));this.value=e,this.value.set=this.set.bind(this),this.value.update=this.update.bind(this),this.value.asReadonly=KC}update(e){this.set(e(sr(this.value)))}hasValue(){return this.value()!==void 0}asReadonly(){return this}},AC=class extends mA{constructor(n,r,s,i,o){super(Ao(()=>{let a=this.state().stream?.();return a&&gA(a)?a.value:this.defaultValue},{equal:i}));l(this,"loaderFn");l(this,"defaultValue");l(this,"equal");l(this,"pendingTasks");l(this,"state");l(this,"extRequest");l(this,"effectRef");l(this,"pendingController");l(this,"resolvePendingTask");l(this,"destroyed",!1);l(this,"status",Ao(()=>jV(this.state())));l(this,"error",Ao(()=>{let n=this.state().stream?.();return n&&!gA(n)?n.error:void 0}));this.loaderFn=r,this.defaultValue=s,this.equal=i,this.extRequest=hA({source:n,computation:a=>({request:a,reload:0})}),this.state=hA({source:this.extRequest,computation:(a,c)=>{let u=a.request===void 0?Zn.Idle:Zn.Loading;return c?{extRequest:a,status:u,previousStatus:jV(c.value),stream:c.value.extRequest.request===a.request?c.value.stream:void 0}:{extRequest:a,status:u,previousStatus:Zn.Idle,stream:void 0}}}),this.effectRef=kC(this.loadEffect.bind(this),{injector:o,manualCleanup:!0}),this.pendingTasks=o.get(c0),o.get(Es).onDestroy(()=>this.destroy())}set(n){if(this.destroyed)return;let r=sr(this.value),s=sr(this.state);s.status===Zn.Local&&(this.equal?this.equal(r,n):r===n)||(this.state.set({extRequest:s.extRequest,status:Zn.Local,previousStatus:Zn.Local,stream:ro({value:n})}),this.abortInProgressLoad())}reload(){let{status:n}=sr(this.state);return n===Zn.Idle||n===Zn.Loading?!1:(this.extRequest.update(({request:r,reload:s})=>({request:r,reload:s+1})),!0)}destroy(){this.destroyed=!0,this.effectRef.destroy(),this.abortInProgressLoad(),this.state.set({extRequest:{request:void 0,reload:0},status:Zn.Idle,previousStatus:Zn.Idle,stream:void 0})}async loadEffect(){let n=this.extRequest(),{status:r,previousStatus:s}=sr(this.state);if(n.request===void 0)return;if(r!==Zn.Loading)return;this.abortInProgressLoad();let i=this.resolvePendingTask=this.pendingTasks.add(),{signal:o}=this.pendingController=new AbortController;try{let a=await sr(()=>this.loaderFn({request:n.request,abortSignal:o,previous:{status:s}}));if(o.aborted||sr(this.extRequest)!==n)return;this.state.set({extRequest:n,status:Zn.Resolved,previousStatus:Zn.Resolved,stream:a})}catch(a){if(o.aborted||sr(this.extRequest)!==n)return;this.state.set({extRequest:n,status:Zn.Resolved,previousStatus:Zn.Error,stream:ro({error:a})})}finally{i?.(),i=void 0}}abortInProgressLoad(){sr(()=>this.pendingController?.abort()),this.pendingController=void 0,this.resolvePendingTask?.(),this.resolvePendingTask=void 0}};function bme(t){return(e,n)=>e===void 0||n===void 0?e===n:t(e,n)}function wme(t){return Eme(t)?t.stream:async e=>{try{return ro({value:await t.loader(e)})}catch(n){return ro({error:n})}}}function Eme(t){return!!t.stream}function jV(t){switch(t.status){case Zn.Loading:return t.extRequest.reload===0?Zn.Loading:Zn.Reloading;case Zn.Resolved:return gA(sr(t.stream))?Zn.Resolved:Zn.Error;default:return t.status}}function gA(t){return t.error===void 0}function xme(t){let e=t;for(;e;){let n=lM(e);if(n!==null)for(let r=He;r{let n=t.resolveMetadata(...e);Us(t.type,n.decorators,n.ctorParameters,n.propDecorators)})}function Cme(t){return Br({usage:1,kind:"component",type:t.type}).compileComponentDeclaration(Fs,`ng:///${t.type.name}/\u0275cmp.js`,t)}function ke(t){return Br({usage:1,kind:Tme(t.target),type:t.type}).compileFactoryDeclaration(Fs,`ng:///${t.type.name}/\u0275fac.js`,t)}function Tme(t){switch(t){case Te.Directive:return"directive";case Te.Component:return"component";case Te.Injectable:return"injectable";case Te.Pipe:return"pipe";case Te.NgModule:return"NgModule"}}function an(t){return Br({usage:1,kind:"injectable",type:t.type}).compileInjectableDeclaration(Fs,`ng:///${t.type.name}/\u0275prov.js`,t)}function $o(t){return Br({usage:1,kind:"NgModule",type:t.type}).compileInjectorDeclaration(Fs,`ng:///${t.type.name}/\u0275inj.js`,t)}function Vo(t){return Br({usage:1,kind:"NgModule",type:t.type}).compileNgModuleDeclaration(Fs,`ng:///${t.type.name}/\u0275mod.js`,t)}function Gs(t){return Br({usage:1,kind:"pipe",type:t.type}).compilePipeDeclaration(Fs,`ng:///${t.type.name}/\u0275pipe.js`,t)}var Ck=Symbol("NOT_SET"),L9=new Set,Dme={...Sy,consumerIsAlwaysLive:!0,consumerAllowSignalWrites:!0,value:Ck,cleanup:null,consumerMarkedDirty(){if(this.sequence.impl.executing){if(this.sequence.lastPhase===null||this.sequence.lastPhase(dc(d),d.value),d.signal[rr]=d,d.registerCleanupFn=p=>(d.cleanup??(d.cleanup=new Set)).add(p),this.nodes[c]=d,this.hooks[c]=p=>d.phaseFn(p)}}afterRun(){super.afterRun(),this.lastPhase=null}destroy(){super.destroy();for(let n of this.nodes)for(let r of n?.cleanup??L9)r()}};function yA(t,e){if(ngDevMode&&q0(yA,"Call `afterRenderEffect` outside of a reactive context. For example, create the render effect inside the component constructor`."),!e?.injector&&us(yA),typeof ngServerMode<"u"&&ngServerMode)return bM;let n=e?.injector??fe(Ln),r=n.get(no),s=n.get(Sh),i=n.get(Fo,null,{optional:!0});s.impl??(s.impl=n.get(HS));let o=t;typeof o=="function"&&(o={mixedReadWrite:t});let a=n.get(ud,null,{optional:!0}),c=new vA(s.impl,[o.earlyRead,o.write,o.mixedReadWrite,o.read],a?.view,r,n.get(Es),i?.snapshot(null));return s.impl.register(c),c}function _me(t,e){ngDevMode&&cT(t);let n=Ut(t),r=e.elementInjector||jC();return new Nc(n).create(r,e.projectableNodes,e.hostElement,e.environmentInjector)}function Ime(t){let e=Ut(t);if(!e)return null;let n=new Nc(e);return{get selector(){return n.selector},get type(){return n.componentType},get inputs(){return n.inputs},get outputs(){return n.outputs},get ngContentSelectors(){return n.ngContentSelectors},get isStandalone(){return e.standalone},get isSignal(){return e.signals}}}function kme(...t){return t.reduce((e,n)=>Object.assign(e,n,{providers:[...e.providers,...n.providers]}),{providers:[]})}var Ame=new $e(typeof ngDevMode>"u"||ngDevMode?"REQUEST":"",{providedIn:"platform",factory:()=>null}),Mme=new $e(typeof ngDevMode>"u"||ngDevMode?"RESPONSE_INIT":"",{providedIn:"platform",factory:()=>null}),Pme=new $e(typeof ngDevMode>"u"||ngDevMode?"REQUEST_CONTEXT":"",{providedIn:"platform",factory:()=>null});var En=new $e(ngDevMode?"DocumentToken":"");var $9=null;function Ds(){return $9}function BN(t){$9??($9=t)}var fb=class{},um=class um{historyGo(e){throw new Error(ngDevMode?"Not implemented":"")}};l(um,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:um,deps:[],target:Te.Injectable})),l(um,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:um,providedIn:"platform",useFactory:()=>fe(qd)}));var Ma=um;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ma,decorators:[{type:St,args:[{providedIn:"platform",useFactory:()=>fe(qd)}]}]});var Fme=new $e(ngDevMode?"Location Initialized":""),Ud=class Ud extends Ma{constructor(){super();l(this,"_location");l(this,"_history");l(this,"_doc",fe(En));this._location=window.location,this._history=window.history}getBaseHrefFromDOM(){return Ds().getBaseHref(this._doc)}onPopState(n){let r=Ds().getGlobalEventTarget(this._doc,"window");return r.addEventListener("popstate",n,!1),()=>r.removeEventListener("popstate",n)}onHashChange(n){let r=Ds().getGlobalEventTarget(this._doc,"window");return r.addEventListener("hashchange",n,!1),()=>r.removeEventListener("hashchange",n)}get href(){return this._location.href}get protocol(){return this._location.protocol}get hostname(){return this._location.hostname}get port(){return this._location.port}get pathname(){return this._location.pathname}get search(){return this._location.search}get hash(){return this._location.hash}set pathname(n){this._location.pathname=n}pushState(n,r,s){this._history.pushState(n,r,s)}replaceState(n,r,s){this._history.replaceState(n,r,s)}forward(){this._history.forward()}back(){this._history.back()}historyGo(n=0){this._history.go(n)}getState(){return this._history.state}};l(Ud,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ud,deps:[],target:Te.Injectable})),l(Ud,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ud,providedIn:"platform",useFactory:()=>new Ud}));var qd=Ud;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:qd,decorators:[{type:St,args:[{providedIn:"platform",useFactory:()=>new qd}]}],ctorParameters:()=>[]});function VT(t,e){return t?e?t.endsWith("/")?e.startsWith("/")?t+e.slice(1):t+e:e.startsWith("/")?t+e:`${t}/${e}`:t:e}function O9(t){let e=t.search(/#|\?|$/);return t[e-1]==="/"?t.slice(0,e-1)+t.slice(e):t}function Ho(t){return t&&t[0]!=="?"?`?${t}`:t}var dm=class dm{historyGo(e){throw new Error(ngDevMode?"Not implemented":"")}};l(dm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:dm,deps:[],target:Te.Injectable})),l(dm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:dm,providedIn:"root",useFactory:()=>fe(fm)}));var Pa=dm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Pa,decorators:[{type:St,args:[{providedIn:"root",useFactory:()=>fe(fm)}]}]});var hm=new $e(ngDevMode?"appBaseHref":""),pm=class pm extends Pa{constructor(n,r){super();l(this,"_platformLocation");l(this,"_baseHref");l(this,"_removeListenerFns",[]);this._platformLocation=n,this._baseHref=r??this._platformLocation.getBaseHrefFromDOM()??fe(En).location?.origin??""}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(n){this._removeListenerFns.push(this._platformLocation.onPopState(n),this._platformLocation.onHashChange(n))}getBaseHref(){return this._baseHref}prepareExternalUrl(n){return VT(this._baseHref,n)}path(n=!1){let r=this._platformLocation.pathname+Ho(this._platformLocation.search),s=this._platformLocation.hash;return s&&n?`${r}${s}`:r}pushState(n,r,s,i){let o=this.prepareExternalUrl(s+Ho(i));this._platformLocation.pushState(n,r,o)}replaceState(n,r,s,i){let o=this.prepareExternalUrl(s+Ho(i));this._platformLocation.replaceState(n,r,o)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(n=0){this._platformLocation.historyGo?.(n)}};l(pm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:pm,deps:[{token:Ma},{token:hm,optional:!0}],target:Te.Injectable})),l(pm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:pm,providedIn:"root"}));var fm=pm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:fm,decorators:[{type:St,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:Ma},{type:void 0,decorators:[{type:lt},{type:Ke,args:[hm]}]}]});var Aa=class Aa{constructor(e){l(this,"_subject",new si);l(this,"_basePath");l(this,"_locationStrategy");l(this,"_urlChangeListeners",[]);l(this,"_urlChangeSubscription",null);this._locationStrategy=e;let n=this._locationStrategy.getBaseHref();this._basePath=Ome(O9(B9(n))),this._locationStrategy.onPopState(r=>{this._subject.next({url:this.path(!0),pop:!0,state:r.state,type:r.type})})}ngOnDestroy(){this._urlChangeSubscription?.unsubscribe(),this._urlChangeListeners=[]}path(e=!1){return this.normalize(this._locationStrategy.path(e))}getState(){return this._locationStrategy.getState()}isCurrentPathEqualTo(e,n=""){return this.path()==this.normalize(e+Ho(n))}normalize(e){return Aa.stripTrailingSlash(Lme(this._basePath,B9(e)))}prepareExternalUrl(e){return e&&e[0]!=="/"&&(e="/"+e),this._locationStrategy.prepareExternalUrl(e)}go(e,n="",r=null){this._locationStrategy.pushState(r,"",e,n),this._notifyUrlChangeListeners(this.prepareExternalUrl(e+Ho(n)),r)}replaceState(e,n="",r=null){this._locationStrategy.replaceState(r,"",e,n),this._notifyUrlChangeListeners(this.prepareExternalUrl(e+Ho(n)),r)}forward(){this._locationStrategy.forward()}back(){this._locationStrategy.back()}historyGo(e=0){this._locationStrategy.historyGo?.(e)}onUrlChange(e){return this._urlChangeListeners.push(e),this._urlChangeSubscription??(this._urlChangeSubscription=this.subscribe(n=>{this._notifyUrlChangeListeners(n.url,n.state)})),()=>{let n=this._urlChangeListeners.indexOf(e);this._urlChangeListeners.splice(n,1),this._urlChangeListeners.length===0&&(this._urlChangeSubscription?.unsubscribe(),this._urlChangeSubscription=null)}}_notifyUrlChangeListeners(e="",n){this._urlChangeListeners.forEach(r=>r(e,n))}subscribe(e,n,r){return this._subject.subscribe({next:e,error:n??void 0,complete:r??void 0})}};l(Aa,"normalizeQueryParams",Ho),l(Aa,"joinWithSlash",VT),l(Aa,"stripTrailingSlash",O9),l(Aa,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Aa,deps:[{token:Pa}],target:Te.Injectable})),l(Aa,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Aa,providedIn:"root",useFactory:V9}));var hb=Aa;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:hb,decorators:[{type:St,args:[{providedIn:"root",useFactory:V9}]}],ctorParameters:()=>[{type:Pa}]});function V9(){return new hb(Zr(Pa))}function Lme(t,e){if(!t||!e.startsWith(t))return e;let n=e.substring(t.length);return n===""||["/",";","?","#"].includes(n[0])?n:e}function B9(t){return t.replace(/\/index.html$/,"")}function Ome(t){if(new RegExp("^(https?:)?//").test(t)){let[,n]=t.split(/\/\/[^\/]+/);return n}return t}var gm=class gm extends Pa{constructor(n,r){super();l(this,"_platformLocation");l(this,"_baseHref","");l(this,"_removeListenerFns",[]);this._platformLocation=n,r!=null&&(this._baseHref=r)}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(n){this._removeListenerFns.push(this._platformLocation.onPopState(n),this._platformLocation.onHashChange(n))}getBaseHref(){return this._baseHref}path(n=!1){let r=this._platformLocation.hash??"#";return r.length>0?r.substring(1):r}prepareExternalUrl(n){let r=VT(this._baseHref,n);return r.length>0?"#"+r:r}pushState(n,r,s,i){let o=this.prepareExternalUrl(s+Ho(i))||this._platformLocation.pathname;this._platformLocation.pushState(n,r,o)}replaceState(n,r,s,i){let o=this.prepareExternalUrl(s+Ho(i))||this._platformLocation.pathname;this._platformLocation.replaceState(n,r,o)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(n=0){this._platformLocation.historyGo?.(n)}};l(gm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:gm,deps:[{token:Ma},{token:hm,optional:!0}],target:Te.Injectable})),l(gm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:gm}));var WT=gm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:WT,decorators:[{type:St}],ctorParameters:()=>[{type:Ma},{type:void 0,decorators:[{type:lt},{type:Ke,args:[hm]}]}]});var Q9={ADP:[void 0,void 0,0],AFN:[void 0,"\u060B",0],ALL:[void 0,void 0,0],AMD:[void 0,"\u058F",2],AOA:[void 0,"Kz"],ARS:[void 0,"$"],AUD:["A$","$"],AZN:[void 0,"\u20BC"],BAM:[void 0,"KM"],BBD:[void 0,"$"],BDT:[void 0,"\u09F3"],BHD:[void 0,void 0,3],BIF:[void 0,void 0,0],BMD:[void 0,"$"],BND:[void 0,"$"],BOB:[void 0,"Bs"],BRL:["R$"],BSD:[void 0,"$"],BWP:[void 0,"P"],BYN:[void 0,void 0,2],BYR:[void 0,void 0,0],BZD:[void 0,"$"],CAD:["CA$","$",2],CHF:[void 0,void 0,2],CLF:[void 0,void 0,4],CLP:[void 0,"$",0],CNY:["CN\xA5","\xA5"],COP:[void 0,"$",2],CRC:[void 0,"\u20A1",2],CUC:[void 0,"$"],CUP:[void 0,"$"],CZK:[void 0,"K\u010D",2],DJF:[void 0,void 0,0],DKK:[void 0,"kr",2],DOP:[void 0,"$"],EGP:[void 0,"E\xA3"],ESP:[void 0,"\u20A7",0],EUR:["\u20AC"],FJD:[void 0,"$"],FKP:[void 0,"\xA3"],GBP:["\xA3"],GEL:[void 0,"\u20BE"],GHS:[void 0,"GH\u20B5"],GIP:[void 0,"\xA3"],GNF:[void 0,"FG",0],GTQ:[void 0,"Q"],GYD:[void 0,"$",2],HKD:["HK$","$"],HNL:[void 0,"L"],HRK:[void 0,"kn"],HUF:[void 0,"Ft",2],IDR:[void 0,"Rp",2],ILS:["\u20AA"],INR:["\u20B9"],IQD:[void 0,void 0,0],IRR:[void 0,void 0,0],ISK:[void 0,"kr",0],ITL:[void 0,void 0,0],JMD:[void 0,"$"],JOD:[void 0,void 0,3],JPY:["\xA5",void 0,0],KHR:[void 0,"\u17DB"],KMF:[void 0,"CF",0],KPW:[void 0,"\u20A9",0],KRW:["\u20A9",void 0,0],KWD:[void 0,void 0,3],KYD:[void 0,"$"],KZT:[void 0,"\u20B8"],LAK:[void 0,"\u20AD",0],LBP:[void 0,"L\xA3",0],LKR:[void 0,"Rs"],LRD:[void 0,"$"],LTL:[void 0,"Lt"],LUF:[void 0,void 0,0],LVL:[void 0,"Ls"],LYD:[void 0,void 0,3],MGA:[void 0,"Ar",0],MGF:[void 0,void 0,0],MMK:[void 0,"K",0],MNT:[void 0,"\u20AE",2],MRO:[void 0,void 0,0],MUR:[void 0,"Rs",2],MXN:["MX$","$"],MYR:[void 0,"RM"],NAD:[void 0,"$"],NGN:[void 0,"\u20A6"],NIO:[void 0,"C$"],NOK:[void 0,"kr",2],NPR:[void 0,"Rs"],NZD:["NZ$","$"],OMR:[void 0,void 0,3],PHP:["\u20B1"],PKR:[void 0,"Rs",2],PLN:[void 0,"z\u0142"],PYG:[void 0,"\u20B2",0],RON:[void 0,"lei"],RSD:[void 0,void 0,0],RUB:[void 0,"\u20BD"],RWF:[void 0,"RF",0],SBD:[void 0,"$"],SEK:[void 0,"kr",2],SGD:[void 0,"$"],SHP:[void 0,"\xA3"],SLE:[void 0,void 0,2],SLL:[void 0,void 0,0],SOS:[void 0,void 0,0],SRD:[void 0,"$"],SSP:[void 0,"\xA3"],STD:[void 0,void 0,0],STN:[void 0,"Db"],SYP:[void 0,"\xA3",0],THB:[void 0,"\u0E3F"],TMM:[void 0,void 0,0],TND:[void 0,void 0,3],TOP:[void 0,"T$"],TRL:[void 0,void 0,0],TRY:[void 0,"\u20BA"],TTD:[void 0,"$"],TWD:["NT$","$",2],TZS:[void 0,void 0,2],UAH:[void 0,"\u20B4"],UGX:[void 0,void 0,0],USD:["$"],UYI:[void 0,void 0,0],UYU:[void 0,"$"],UYW:[void 0,void 0,4],UZS:[void 0,void 0,2],VEF:[void 0,"Bs",2],VND:["\u20AB",void 0,0],VUV:[void 0,void 0,0],XAF:["FCFA",void 0,0],XCD:["EC$","$"],XOF:["F\u202FCFA",void 0,0],XPF:["CFPF",void 0,0],XXX:["\xA4"],YER:[void 0,void 0,0],ZAR:[void 0,"R"],ZMK:[void 0,void 0,0],ZMW:[void 0,"ZK"],ZWD:[void 0,void 0,0]},Mm;(function(t){t[t.Decimal=0]="Decimal",t[t.Percent=1]="Percent",t[t.Currency=2]="Currency",t[t.Scientific=3]="Scientific"})(Mm||(Mm={}));var qc;(function(t){t[t.Zero=0]="Zero",t[t.One=1]="One",t[t.Two=2]="Two",t[t.Few=3]="Few",t[t.Many=4]="Many",t[t.Other=5]="Other"})(qc||(qc={}));var fs;(function(t){t[t.Format=0]="Format",t[t.Standalone=1]="Standalone"})(fs||(fs={}));var Bn;(function(t){t[t.Narrow=0]="Narrow",t[t.Abbreviated=1]="Abbreviated",t[t.Wide=2]="Wide",t[t.Short=3]="Short"})(Bn||(Bn={}));var Zs;(function(t){t[t.Short=0]="Short",t[t.Medium=1]="Medium",t[t.Long=2]="Long",t[t.Full=3]="Full"})(Zs||(Zs={}));var Cr={Decimal:0,Group:1,List:2,PercentSign:3,PlusSign:4,MinusSign:5,Exponential:6,SuperscriptingExponent:7,PerMille:8,Infinity:9,NaN:10,TimeSeparator:11,CurrencyDecimal:12,CurrencyGroup:13},WN;(function(t){t[t.Sunday=0]="Sunday",t[t.Monday=1]="Monday",t[t.Tuesday=2]="Tuesday",t[t.Wednesday=3]="Wednesday",t[t.Thursday=4]="Thursday",t[t.Friday=5]="Friday",t[t.Saturday=6]="Saturday"})(WN||(WN={}));function K9(t){return ps(t)[On.LocaleId]}function J9(t,e,n){let r=ps(t),s=[r[On.DayPeriodsFormat],r[On.DayPeriodsStandalone]],i=uo(s,e);return uo(i,n)}function eq(t,e,n){let r=ps(t),s=[r[On.DaysFormat],r[On.DaysStandalone]],i=uo(s,e);return uo(i,n)}function tq(t,e,n){let r=ps(t),s=[r[On.MonthsFormat],r[On.MonthsStandalone]],i=uo(s,e);return uo(i,n)}function nq(t,e){let r=ps(t)[On.Eras];return uo(r,e)}function mb(t,e){let n=ps(t);return uo(n[On.DateFormat],e)}function gb(t,e){let n=ps(t);return uo(n[On.TimeFormat],e)}function vb(t,e){let r=ps(t)[On.DateTimeFormat];return uo(r,e)}function Ni(t,e){let n=ps(t),r=n[On.NumberSymbols][e];if(typeof r>"u"){if(e===Cr.CurrencyDecimal)return n[On.NumberSymbols][Cr.Decimal];if(e===Cr.CurrencyGroup)return n[On.NumberSymbols][Cr.Group]}return r}function XT(t,e){return ps(t)[On.NumberFormats][e]}function Bme(t){return ps(t)[On.Currencies]}var rq=AT;function sq(t){if(!t[On.ExtraData])throw new Error(`Missing extra locale data for the locale "${t[On.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`)}function iq(t){let e=ps(t);return sq(e),(e[On.ExtraData][2]||[]).map(r=>typeof r=="string"?$N(r):[$N(r[0]),$N(r[1])])}function oq(t,e,n){let r=ps(t);sq(r);let s=[r[On.ExtraData][0],r[On.ExtraData][1]],i=uo(s,e)||[];return uo(i,n)||[]}function uo(t,e){for(let n=e;n>-1;n--)if(typeof t[n]<"u")return t[n];throw new Error("Locale data API: locale data undefined")}function $N(t){let[e,n]=t.split(":");return{hours:+e,minutes:+n}}function aq(t,e,n="en"){let r=Bme(n)[t]||Q9[t]||[],s=r[1];return e==="narrow"&&typeof s=="string"?s:r[0]||t}var $me=2;function lq(t){let e,n=Q9[t];return n&&(e=n[2]),typeof e=="number"?e:$me}var Vme=/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,mm={},Hme=/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;function cq(t,e,n,r){let s=Xme(t);e=Cl(n,e)||e;let o=[],a;for(;e;)if(a=Hme.exec(e),a){o=o.concat(a.slice(1));let d=o.pop();if(!d)break;e=d}else{o.push(e);break}let c=s.getTimezoneOffset();r&&(c=dq(r,c),s=Yme(s,r));let u="";return o.forEach(d=>{let p=Gme(d);u+=p?p(s,n,c):d==="''"?"'":d.replace(/(^'|'$)/g,"").replace(/''/g,"'")}),u}function zT(t,e,n){let r=new Date(0);return r.setFullYear(t,e,n),r.setHours(0,0,0),r}function Cl(t,e){let n=K9(t);if(mm[n]??(mm[n]={}),mm[n][e])return mm[n][e];let r="";switch(e){case"shortDate":r=mb(t,Zs.Short);break;case"mediumDate":r=mb(t,Zs.Medium);break;case"longDate":r=mb(t,Zs.Long);break;case"fullDate":r=mb(t,Zs.Full);break;case"shortTime":r=gb(t,Zs.Short);break;case"mediumTime":r=gb(t,Zs.Medium);break;case"longTime":r=gb(t,Zs.Long);break;case"fullTime":r=gb(t,Zs.Full);break;case"short":let s=Cl(t,"shortTime"),i=Cl(t,"shortDate");r=HT(vb(t,Zs.Short),[s,i]);break;case"medium":let o=Cl(t,"mediumTime"),a=Cl(t,"mediumDate");r=HT(vb(t,Zs.Medium),[o,a]);break;case"long":let c=Cl(t,"longTime"),u=Cl(t,"longDate");r=HT(vb(t,Zs.Long),[c,u]);break;case"full":let d=Cl(t,"fullTime"),p=Cl(t,"fullDate");r=HT(vb(t,Zs.Full),[d,p]);break}return r&&(mm[n][e]=r),r}function HT(t,e){return e&&(t=t.replace(/\{([^}]+)}/g,function(n,r){return e!=null&&r in e?e[r]:n})),t}function jo(t,e,n="-",r,s){let i="";(t<0||s&&t<=0)&&(s?t=-t+1:(t=-t,i=n));let o=String(t);for(;o.length0||a>-n)&&(a+=n),t===3)a===0&&n===-12&&(a=12);else if(t===6)return jme(a,e);let c=Ni(o,Cr.MinusSign);return jo(a,e,c,r,s)}}function Ume(t,e){switch(t){case 0:return e.getFullYear();case 1:return e.getMonth();case 2:return e.getDate();case 3:return e.getHours();case 4:return e.getMinutes();case 5:return e.getSeconds();case 6:return e.getMilliseconds();case 7:return e.getDay();default:throw new Error(`Unknown DateType value "${t}".`)}}function Xn(t,e,n=fs.Format,r=!1){return function(s,i){return qme(s,i,t,e,n,r)}}function qme(t,e,n,r,s,i){switch(n){case 2:return tq(e,s,r)[t.getMonth()];case 1:return eq(e,s,r)[t.getDay()];case 0:let o=t.getHours(),a=t.getMinutes();if(i){let u=iq(e),d=oq(e,s,r),p=u.findIndex(f=>{if(Array.isArray(f)){let[h,m]=f,g=o>=h.hours&&a>=h.minutes,v=o0?Math.floor(s/60):Math.ceil(s/60);switch(t){case 0:return(s>=0?"+":"")+jo(o,2,i)+jo(Math.abs(s%60),2,i);case 1:return"GMT"+(s>=0?"+":"")+jo(o,1,i);case 2:return"GMT"+(s>=0?"+":"")+jo(o,2,i)+":"+jo(Math.abs(s%60),2,i);case 3:return r===0?"Z":(s>=0?"+":"")+jo(o,2,i)+":"+jo(Math.abs(s%60),2,i);default:throw new Error(`Unknown zone width "${t}"`)}}}var Wme=0,qT=4;function zme(t){let e=zT(t,Wme,1).getDay();return zT(t,0,1+(e<=qT?qT:qT+7)-e)}function uq(t){let e=t.getDay(),n=e===0?-3:qT-e;return zT(t.getFullYear(),t.getMonth(),t.getDate()+n)}function VN(t,e=!1){return function(n,r){let s;if(e){let i=new Date(n.getFullYear(),n.getMonth(),1).getDay()-1,o=n.getDate();s=1+Math.floor((o+i)/7)}else{let i=uq(n),o=zme(i.getFullYear()),a=i.getTime()-o.getTime();s=1+Math.round(a/6048e5)}return jo(s,t,Ni(r,Cr.MinusSign))}}function UT(t,e=!1){return function(n,r){let i=uq(n).getFullYear();return jo(i,t,Ni(r,Cr.MinusSign),e)}}var HN={};function Gme(t){if(HN[t])return HN[t];let e;switch(t){case"G":case"GG":case"GGG":e=Xn(3,Bn.Abbreviated);break;case"GGGG":e=Xn(3,Bn.Wide);break;case"GGGGG":e=Xn(3,Bn.Narrow);break;case"y":e=kr(0,1,0,!1,!0);break;case"yy":e=kr(0,2,0,!0,!0);break;case"yyy":e=kr(0,3,0,!1,!0);break;case"yyyy":e=kr(0,4,0,!1,!0);break;case"Y":e=UT(1);break;case"YY":e=UT(2,!0);break;case"YYY":e=UT(3);break;case"YYYY":e=UT(4);break;case"M":case"L":e=kr(1,1,1);break;case"MM":case"LL":e=kr(1,2,1);break;case"MMM":e=Xn(2,Bn.Abbreviated);break;case"MMMM":e=Xn(2,Bn.Wide);break;case"MMMMM":e=Xn(2,Bn.Narrow);break;case"LLL":e=Xn(2,Bn.Abbreviated,fs.Standalone);break;case"LLLL":e=Xn(2,Bn.Wide,fs.Standalone);break;case"LLLLL":e=Xn(2,Bn.Narrow,fs.Standalone);break;case"w":e=VN(1);break;case"ww":e=VN(2);break;case"W":e=VN(1,!0);break;case"d":e=kr(2,1);break;case"dd":e=kr(2,2);break;case"c":case"cc":e=kr(7,1);break;case"ccc":e=Xn(1,Bn.Abbreviated,fs.Standalone);break;case"cccc":e=Xn(1,Bn.Wide,fs.Standalone);break;case"ccccc":e=Xn(1,Bn.Narrow,fs.Standalone);break;case"cccccc":e=Xn(1,Bn.Short,fs.Standalone);break;case"E":case"EE":case"EEE":e=Xn(1,Bn.Abbreviated);break;case"EEEE":e=Xn(1,Bn.Wide);break;case"EEEEE":e=Xn(1,Bn.Narrow);break;case"EEEEEE":e=Xn(1,Bn.Short);break;case"a":case"aa":case"aaa":e=Xn(0,Bn.Abbreviated);break;case"aaaa":e=Xn(0,Bn.Wide);break;case"aaaaa":e=Xn(0,Bn.Narrow);break;case"b":case"bb":case"bbb":e=Xn(0,Bn.Abbreviated,fs.Standalone,!0);break;case"bbbb":e=Xn(0,Bn.Wide,fs.Standalone,!0);break;case"bbbbb":e=Xn(0,Bn.Narrow,fs.Standalone,!0);break;case"B":case"BB":case"BBB":e=Xn(0,Bn.Abbreviated,fs.Format,!0);break;case"BBBB":e=Xn(0,Bn.Wide,fs.Format,!0);break;case"BBBBB":e=Xn(0,Bn.Narrow,fs.Format,!0);break;case"h":e=kr(3,1,-12);break;case"hh":e=kr(3,2,-12);break;case"H":e=kr(3,1);break;case"HH":e=kr(3,2);break;case"m":e=kr(4,1);break;case"mm":e=kr(4,2);break;case"s":e=kr(5,1);break;case"ss":e=kr(5,2);break;case"S":e=kr(6,1);break;case"SS":e=kr(6,2);break;case"SSS":e=kr(6,3);break;case"Z":case"ZZ":case"ZZZ":e=jT(0);break;case"ZZZZZ":e=jT(3);break;case"O":case"OO":case"OOO":case"z":case"zz":case"zzz":e=jT(1);break;case"OOOO":case"ZZZZ":case"zzzz":e=jT(2);break;default:return null}return HN[t]=e,e}function dq(t,e){t=t.replace(/:/g,"");let n=Date.parse("Jan 01, 1970 00:00:00 "+t)/6e4;return isNaN(n)?e:n}function Zme(t,e){return t=new Date(t.getTime()),t.setMinutes(t.getMinutes()+e),t}function Yme(t,e,n){let s=t.getTimezoneOffset(),i=dq(e,s);return Zme(t,-1*(i-s))}function Xme(t){if(H9(t))return t;if(typeof t=="number"&&!isNaN(t))return new Date(t);if(typeof t=="string"){if(t=t.trim(),/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(t)){let[s,i=1,o=1]=t.split("-").map(a=>+a);return zT(s,i-1,o)}let n=parseFloat(t);if(!isNaN(t-n))return new Date(n);let r;if(r=t.match(Vme))return Qme(r)}let e=new Date(t);if(!H9(e))throw new Error(`Unable to convert "${t}" into a date`);return e}function Qme(t){let e=new Date(0),n=0,r=0,s=t[8]?e.setUTCFullYear:e.setFullYear,i=t[8]?e.setUTCHours:e.setHours;t[9]&&(n=Number(t[9]+t[10]),r=Number(t[9]+t[11])),s.call(e,Number(t[1]),Number(t[2])-1,Number(t[3]));let o=Number(t[4]||0)-n,a=Number(t[5]||0)-r,c=Number(t[6]||0),u=Math.floor(parseFloat("0."+(t[7]||0))*1e3);return i.call(e,o,a,c,u),e}function H9(t){return t instanceof Date&&!isNaN(t.valueOf())}var Kme=/^(\d+)?\.((\d+)(-(\d+))?)?$/,j9=22,GT=".",yb="0",Jme=";",ege=",",jN="#",U9="\xA4",tge="%";function ZN(t,e,n,r,s,i,o=!1){let a="",c=!1;if(!isFinite(t))a=Ni(n,Cr.Infinity);else{let u=rge(t);o&&(u=nge(u));let d=e.minInt,p=e.minFrac,f=e.maxFrac;if(i){let b=i.match(Kme);if(b===null)throw new Error(`${i} is not a valid digit info`);let D=b[1],B=b[3],M=b[5];D!=null&&(d=UN(D)),B!=null&&(p=UN(B)),M!=null?f=UN(M):B!=null&&p>f&&(f=p);let $=100;if(d>$||p>$||f>$)throw new ne(2306,ngDevMode&&`${i} is not a valid digit info. Exceeded maximum limits of ${$} digits.`)}sge(u,p,f);let h=u.digits,m=u.integerLen,g=u.exponent,v=[];for(c=h.every(b=>!b);m0?v=h.splice(m,h.length):(v=h,h=[0]);let w=[];for(h.length>=e.lgSize&&w.unshift(h.splice(-e.lgSize,h.length).join(""));h.length>e.gSize;)w.unshift(h.splice(-e.gSize,h.length).join(""));h.length&&w.unshift(h.join("")),a=w.join(Ni(n,r)),v.length&&(a+=Ni(n,s)+v.join("")),g&&(a+=Ni(n,Cr.Exponential)+"+"+g)}return t<0&&!c?a=e.negPre+a+e.negSuf:a=e.posPre+a+e.posSuf,a}function pq(t,e,n,r,s){let i=XT(e,Mm.Currency),o=YN(i,Ni(e,Cr.MinusSign));return o.minFrac=lq(r),o.maxFrac=o.minFrac,ZN(t,o,e,Cr.CurrencyGroup,Cr.CurrencyDecimal,s).replace(U9,n).replace(U9,"").trim()}function fq(t,e,n){let r=XT(e,Mm.Percent),s=YN(r,Ni(e,Cr.MinusSign));return ZN(t,s,e,Cr.Group,Cr.Decimal,n,!0).replace(new RegExp(tge,"g"),Ni(e,Cr.PercentSign))}function hq(t,e,n){let r=XT(e,Mm.Decimal),s=YN(r,Ni(e,Cr.MinusSign));return ZN(t,s,e,Cr.Group,Cr.Decimal,n)}function YN(t,e="-"){let n={minInt:1,minFrac:0,maxFrac:0,posPre:"",posSuf:"",negPre:"",negSuf:"",gSize:0,lgSize:0},r=t.split(Jme),s=r[0],i=r[1],o=s.indexOf(GT)!==-1?s.split(GT):[s.substring(0,s.lastIndexOf(yb)+1),s.substring(s.lastIndexOf(yb)+1)],a=o[0],c=o[1]||"";n.posPre=a.substring(0,a.indexOf(jN));for(let d=0;d-1&&(e=e.replace(GT,"")),(i=e.search(/e/i))>0?(s<0&&(s=i),s+=+e.slice(i+1),e=e.substring(0,i)):s<0&&(s=e.length),i=0;e.charAt(i)===yb;i++);if(i===(a=e.length))r=[0],s=1;else{for(a--;e.charAt(a)===yb;)a--;for(s-=i,r=[],o=0;i<=a;i++,o++)r[o]=Number(e.charAt(i))}return s>j9&&(r=r.splice(0,j9-1),n=s-1,s=1),{digits:r,exponent:n,integerLen:s}}function sge(t,e,n){if(e>n)throw new Error(`The minimum number of digits after fraction (${e}) is higher than the maximum (${n}).`);let r=t.digits,s=r.length-t.integerLen,i=Math.min(Math.max(e,s),n),o=i+t.integerLen,a=r[o];if(o>0){r.splice(Math.max(t.integerLen,o));for(let p=o;p=5)if(o-1<0){for(let p=0;p>o;p--)r.unshift(0),t.integerLen++;r.unshift(1),t.integerLen++}else r[o-1]++;for(;s=u?m.pop():c=!1),f>=10?1:0},0);d&&(r.unshift(d),t.integerLen++)}function UN(t){let e=parseInt(t);if(isNaN(e))throw new Error("Invalid integer literal when parsing "+t);return e}var vm=class vm{};l(vm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:vm,deps:[],target:Te.Injectable})),l(vm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:vm,providedIn:"root",useFactory:e=>new Pm(e),deps:[{token:Ts}]}));var Tl=vm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Tl,decorators:[{type:St,args:[{providedIn:"root",useFactory:t=>new Pm(t),deps:[Ts]}]}]});function mq(t,e,n,r){let s=`=${t}`;if(e.indexOf(s)>-1||(s=n.getPluralCategory(t,r),e.indexOf(s)>-1))return s;if(e.indexOf("other")>-1)return"other";throw new Error(`No plural message found for value "${t}"`)}var ym=class ym extends Tl{constructor(n){super();l(this,"locale");this.locale=n}getPluralCategory(n,r){switch(rq(r||this.locale)(n)){case qc.Zero:return"zero";case qc.One:return"one";case qc.Two:return"two";case qc.Few:return"few";case qc.Many:return"many";default:return"other"}}};l(ym,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:ym,deps:[{token:Ts}],target:Te.Injectable})),l(ym,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:ym}));var Pm=ym;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Pm,decorators:[{type:St}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[Ts]}]}]});var qN=/\s+/,q9=[],bm=class bm{constructor(e,n){l(this,"_ngEl");l(this,"_renderer");l(this,"initialClasses",q9);l(this,"rawClass");l(this,"stateMap",new Map);this._ngEl=e,this._renderer=n}set klass(e){this.initialClasses=e!=null?e.trim().split(qN):q9}set ngClass(e){this.rawClass=typeof e=="string"?e.trim().split(qN):e}ngDoCheck(){for(let n of this.initialClasses)this._updateState(n,!0);let e=this.rawClass;if(Array.isArray(e)||e instanceof Set)for(let n of e)this._updateState(n,!0);else if(e!=null)for(let n of Object.keys(e))this._updateState(n,!!e[n]);this._applyStateDiff()}_updateState(e,n){let r=this.stateMap.get(e);r!==void 0?(r.enabled!==n&&(r.changed=!0,r.enabled=n),r.touched=!0):this.stateMap.set(e,{enabled:n,changed:!0,touched:!0})}_applyStateDiff(){for(let e of this.stateMap){let n=e[0],r=e[1];r.changed?(this._toggleClass(n,r.enabled),r.changed=!1):r.touched||(r.enabled&&this._toggleClass(n,!1),this.stateMap.delete(n)),r.touched=!1}}_toggleClass(e,n){if(ngDevMode&&typeof e!="string")throw new Error(`NgClass can only toggle CSS classes expressed as strings, got ${tn(e)}`);e=e.trim(),e.length>0&&e.split(qN).forEach(r=>{n?this._renderer.addClass(this._ngEl.nativeElement,r):this._renderer.removeClass(this._ngEl.nativeElement,r)})}};l(bm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:bm,deps:[{token:pn},{token:hr}],target:Te.Directive})),l(bm,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:bm,isStandalone:!0,selector:"[ngClass]",inputs:{klass:["class","klass"],ngClass:"ngClass"},ngImport:k}));var np=bm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:np,decorators:[{type:bt,args:[{selector:"[ngClass]"}]}],ctorParameters:()=>[{type:pn},{type:hr}],propDecorators:{klass:[{type:Ge,args:["class"]}],ngClass:[{type:Ge,args:["ngClass"]}]}});var wm=class wm{constructor(e){l(this,"_viewContainerRef");l(this,"ngComponentOutlet",null);l(this,"ngComponentOutletInputs");l(this,"ngComponentOutletInjector");l(this,"ngComponentOutletContent");l(this,"ngComponentOutletNgModule");l(this,"ngComponentOutletNgModuleFactory");l(this,"_componentRef");l(this,"_moduleRef");l(this,"_inputsUsed",new Map);this._viewContainerRef=e}get componentInstance(){return this._componentRef?.instance??null}_needToReCreateNgModuleInstance(e){return e.ngComponentOutletNgModule!==void 0||e.ngComponentOutletNgModuleFactory!==void 0}_needToReCreateComponentInstance(e){return e.ngComponentOutlet!==void 0||e.ngComponentOutletContent!==void 0||e.ngComponentOutletInjector!==void 0||this._needToReCreateNgModuleInstance(e)}ngOnChanges(e){if(this._needToReCreateComponentInstance(e)&&(this._viewContainerRef.clear(),this._inputsUsed.clear(),this._componentRef=void 0,this.ngComponentOutlet)){let n=this.ngComponentOutletInjector||this._viewContainerRef.parentInjector;this._needToReCreateNgModuleInstance(e)&&(this._moduleRef?.destroy(),this.ngComponentOutletNgModule?this._moduleRef=wT(this.ngComponentOutletNgModule,W9(n)):this.ngComponentOutletNgModuleFactory?this._moduleRef=this.ngComponentOutletNgModuleFactory.create(W9(n)):this._moduleRef=void 0),this._componentRef=this._viewContainerRef.createComponent(this.ngComponentOutlet,{injector:n,ngModuleRef:this._moduleRef,projectableNodes:this.ngComponentOutletContent})}}ngDoCheck(){if(this._componentRef){if(this.ngComponentOutletInputs)for(let e of Object.keys(this.ngComponentOutletInputs))this._inputsUsed.set(e,!0);this._applyInputStateDiff(this._componentRef)}}ngOnDestroy(){this._moduleRef?.destroy()}_applyInputStateDiff(e){for(let[n,r]of this._inputsUsed)r?(e.setInput(n,this.ngComponentOutletInputs[n]),this._inputsUsed.set(n,!1)):(e.setInput(n,void 0),this._inputsUsed.delete(n))}};l(wm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:wm,deps:[{token:mr}],target:Te.Directive})),l(wm,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:wm,isStandalone:!0,selector:"[ngComponentOutlet]",inputs:{ngComponentOutlet:"ngComponentOutlet",ngComponentOutletInputs:"ngComponentOutletInputs",ngComponentOutletInjector:"ngComponentOutletInjector",ngComponentOutletContent:"ngComponentOutletContent",ngComponentOutletNgModule:"ngComponentOutletNgModule",ngComponentOutletNgModuleFactory:"ngComponentOutletNgModuleFactory"},exportAs:["ngComponentOutlet"],usesOnChanges:!0,ngImport:k}));var rp=wm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:rp,decorators:[{type:bt,args:[{selector:"[ngComponentOutlet]",exportAs:"ngComponentOutlet"}]}],ctorParameters:()=>[{type:mr}],propDecorators:{ngComponentOutlet:[{type:Ge}],ngComponentOutletInputs:[{type:Ge}],ngComponentOutletInjector:[{type:Ge}],ngComponentOutletContent:[{type:Ge}],ngComponentOutletNgModule:[{type:Ge}],ngComponentOutletNgModuleFactory:[{type:Ge}]}});function W9(t){return t.get(ml).injector}var ZT=class{constructor(e,n,r,s){l(this,"$implicit");l(this,"ngForOf");l(this,"index");l(this,"count");this.$implicit=e,this.ngForOf=n,this.index=r,this.count=s}get first(){return this.index===0}get last(){return this.index===this.count-1}get even(){return this.index%2===0}get odd(){return!this.even}},Em=class Em{constructor(e,n,r){l(this,"_viewContainer");l(this,"_template");l(this,"_differs");l(this,"_ngForOf",null);l(this,"_ngForOfDirty",!0);l(this,"_differ",null);l(this,"_trackByFn");this._viewContainer=e,this._template=n,this._differs=r}set ngForOf(e){this._ngForOf=e,this._ngForOfDirty=!0}set ngForTrackBy(e){(typeof ngDevMode>"u"||ngDevMode)&&e!=null&&typeof e!="function"&&console.warn(`trackBy must be a function, but received ${JSON.stringify(e)}. See https://angular.io/api/common/NgForOf#change-propagation for more information.`),this._trackByFn=e}get ngForTrackBy(){return this._trackByFn}set ngForTemplate(e){e&&(this._template=e)}ngDoCheck(){if(this._ngForOfDirty){this._ngForOfDirty=!1;let e=this._ngForOf;if(!this._differ&&e)if(typeof ngDevMode>"u"||ngDevMode)try{this._differ=this._differs.find(e).create(this.ngForTrackBy)}catch{let n=`Cannot find a differ supporting object '${e}' of type '${ige(e)}'. NgFor only supports binding to Iterables, such as Arrays.`;throw typeof e=="object"&&(n+=" Did you mean to use the keyvalue pipe?"),new ne(-2200,n)}else this._differ=this._differs.find(e).create(this.ngForTrackBy)}if(this._differ){let e=this._differ.diff(this._ngForOf);e&&this._applyChanges(e)}}_applyChanges(e){let n=this._viewContainer;e.forEachOperation((r,s,i)=>{if(r.previousIndex==null)n.createEmbeddedView(this._template,new ZT(r.item,this._ngForOf,-1,-1),i===null?void 0:i);else if(i==null)n.remove(s===null?void 0:s);else if(s!==null){let o=n.get(s);n.move(o,i),z9(o,r)}});for(let r=0,s=n.length;r{let s=n.get(r.currentIndex);z9(s,r)})}static ngTemplateContextGuard(e,n){return!0}};l(Em,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Em,deps:[{token:mr},{token:$r},{token:Fc}],target:Te.Directive})),l(Em,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Em,isStandalone:!0,selector:"[ngFor][ngForOf]",inputs:{ngForOf:"ngForOf",ngForTrackBy:"ngForTrackBy",ngForTemplate:"ngForTemplate"},ngImport:k}));var Wc=Em;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Wc,decorators:[{type:bt,args:[{selector:"[ngFor][ngForOf]"}]}],ctorParameters:()=>[{type:mr},{type:$r},{type:Fc}],propDecorators:{ngForOf:[{type:Ge}],ngForTrackBy:[{type:Ge}],ngForTemplate:[{type:Ge}]}});function z9(t,e){t.context.$implicit=e.item}function ige(t){return t.name||typeof t}var jc=class jc{constructor(e,n){l(this,"_viewContainer");l(this,"_context",new YT);l(this,"_thenTemplateRef",null);l(this,"_elseTemplateRef",null);l(this,"_thenViewRef",null);l(this,"_elseViewRef",null);this._viewContainer=e,this._thenTemplateRef=n}set ngIf(e){this._context.$implicit=this._context.ngIf=e,this._updateView()}set ngIfThen(e){G9(e,(typeof ngDevMode>"u"||ngDevMode)&&"ngIfThen"),this._thenTemplateRef=e,this._thenViewRef=null,this._updateView()}set ngIfElse(e){G9(e,(typeof ngDevMode>"u"||ngDevMode)&&"ngIfElse"),this._elseTemplateRef=e,this._elseViewRef=null,this._updateView()}_updateView(){this._context.$implicit?this._thenViewRef||(this._viewContainer.clear(),this._elseViewRef=null,this._thenTemplateRef&&(this._thenViewRef=this._viewContainer.createEmbeddedView(this._thenTemplateRef,this._context))):this._elseViewRef||(this._viewContainer.clear(),this._thenViewRef=null,this._elseTemplateRef&&(this._elseViewRef=this._viewContainer.createEmbeddedView(this._elseTemplateRef,this._context)))}static ngTemplateContextGuard(e,n){return!0}};l(jc,"ngIfUseIfTypeGuard"),l(jc,"ngTemplateGuard_ngIf"),l(jc,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:jc,deps:[{token:mr},{token:$r}],target:Te.Directive})),l(jc,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:jc,isStandalone:!0,selector:"[ngIf]",inputs:{ngIf:"ngIf",ngIfThen:"ngIfThen",ngIfElse:"ngIfElse"},ngImport:k}));var sp=jc;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:sp,decorators:[{type:bt,args:[{selector:"[ngIf]"}]}],ctorParameters:()=>[{type:mr},{type:$r}],propDecorators:{ngIf:[{type:Ge}],ngIfThen:[{type:Ge}],ngIfElse:[{type:Ge}]}});var YT=class{constructor(){l(this,"$implicit",null);l(this,"ngIf",null)}};function G9(t,e){if(t&&!t.createEmbeddedView)throw new ne(2020,(typeof ngDevMode>"u"||ngDevMode)&&`${e} must be a TemplateRef, but received '${tn(t)}'.`)}var bb=class{constructor(e,n){l(this,"_viewContainerRef");l(this,"_templateRef");l(this,"_created",!1);this._viewContainerRef=e,this._templateRef=n}create(){this._created=!0,this._viewContainerRef.createEmbeddedView(this._templateRef)}destroy(){this._created=!1,this._viewContainerRef.clear()}enforceState(e){e&&!this._created?this.create():!e&&this._created&&this.destroy()}},xm=class xm{constructor(){l(this,"_defaultViews",[]);l(this,"_defaultUsed",!1);l(this,"_caseCount",0);l(this,"_lastCaseCheckIndex",0);l(this,"_lastCasesMatched",!1);l(this,"_ngSwitch")}set ngSwitch(e){this._ngSwitch=e,this._caseCount===0&&this._updateDefaultCases(!0)}_addCase(){return this._caseCount++}_addDefault(e){this._defaultViews.push(e)}_matchCase(e){let n=e===this._ngSwitch;return this._lastCasesMatched||(this._lastCasesMatched=n),this._lastCaseCheckIndex++,this._lastCaseCheckIndex===this._caseCount&&(this._updateDefaultCases(!this._lastCasesMatched),this._lastCaseCheckIndex=0,this._lastCasesMatched=!1),n}_updateDefaultCases(e){if(this._defaultViews.length>0&&e!==this._defaultUsed){this._defaultUsed=e;for(let n of this._defaultViews)n.enforceState(e)}}};l(xm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:xm,deps:[],target:Te.Directive})),l(xm,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:xm,isStandalone:!0,selector:"[ngSwitch]",inputs:{ngSwitch:"ngSwitch"},ngImport:k}));var Uo=xm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Uo,decorators:[{type:bt,args:[{selector:"[ngSwitch]"}]}],propDecorators:{ngSwitch:[{type:Ge}]}});var Sm=class Sm{constructor(e,n,r){l(this,"ngSwitch");l(this,"_view");l(this,"ngSwitchCase");this.ngSwitch=r,(typeof ngDevMode>"u"||ngDevMode)&&!r&&gq("ngSwitchCase","NgSwitchCase"),r._addCase(),this._view=new bb(e,n)}ngDoCheck(){this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase))}};l(Sm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Sm,deps:[{token:mr},{token:$r},{token:Uo,host:!0,optional:!0}],target:Te.Directive})),l(Sm,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Sm,isStandalone:!0,selector:"[ngSwitchCase]",inputs:{ngSwitchCase:"ngSwitchCase"},ngImport:k}));var ip=Sm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:ip,decorators:[{type:bt,args:[{selector:"[ngSwitchCase]"}]}],ctorParameters:()=>[{type:mr},{type:$r},{type:Uo,decorators:[{type:lt},{type:pi}]}],propDecorators:{ngSwitchCase:[{type:Ge}]}});var Cm=class Cm{constructor(e,n,r){(typeof ngDevMode>"u"||ngDevMode)&&!r&&gq("ngSwitchDefault","NgSwitchDefault"),r._addDefault(new bb(e,n))}};l(Cm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Cm,deps:[{token:mr},{token:$r},{token:Uo,host:!0,optional:!0}],target:Te.Directive})),l(Cm,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Cm,isStandalone:!0,selector:"[ngSwitchDefault]",ngImport:k}));var op=Cm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:op,decorators:[{type:bt,args:[{selector:"[ngSwitchDefault]"}]}],ctorParameters:()=>[{type:mr},{type:$r},{type:Uo,decorators:[{type:lt},{type:pi}]}]});function gq(t,e){throw new ne(2e3,`An element with the "${t}" attribute (matching the "${e}" directive) must be located inside an element with the "ngSwitch" attribute (matching "NgSwitch" directive)`)}var Tm=class Tm{constructor(e){l(this,"_localization");l(this,"_activeView");l(this,"_caseViews",{});this._localization=e}set ngPlural(e){this._updateView(e)}addCase(e,n){this._caseViews[e]=n}_updateView(e){this._clearViews();let n=Object.keys(this._caseViews),r=mq(e,n,this._localization);this._activateView(this._caseViews[r])}_clearViews(){this._activeView&&this._activeView.destroy()}_activateView(e){e&&(this._activeView=e,this._activeView.create())}};l(Tm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Tm,deps:[{token:Tl}],target:Te.Directive})),l(Tm,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Tm,isStandalone:!0,selector:"[ngPlural]",inputs:{ngPlural:"ngPlural"},ngImport:k}));var Dl=Tm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Dl,decorators:[{type:bt,args:[{selector:"[ngPlural]"}]}],ctorParameters:()=>[{type:Tl}],propDecorators:{ngPlural:[{type:Ge}]}});var Dm=class Dm{constructor(e,n,r,s){l(this,"value");this.value=e;let i=!isNaN(Number(e));s.addCase(i?`=${e}`:e,new bb(r,n))}};l(Dm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Dm,deps:[{token:"ngPluralCase",attribute:!0},{token:$r},{token:mr},{token:Dl,host:!0}],target:Te.Directive})),l(Dm,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Dm,isStandalone:!0,selector:"[ngPluralCase]",ngImport:k}));var ap=Dm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:ap,decorators:[{type:bt,args:[{selector:"[ngPluralCase]"}]}],ctorParameters:()=>[{type:void 0,decorators:[{type:XC,args:["ngPluralCase"]}]},{type:$r},{type:mr},{type:Dl,decorators:[{type:pi}]}]});var _m=class _m{constructor(e,n,r){l(this,"_ngEl");l(this,"_differs");l(this,"_renderer");l(this,"_ngStyle",null);l(this,"_differ",null);this._ngEl=e,this._differs=n,this._renderer=r}set ngStyle(e){this._ngStyle=e,!this._differ&&e&&(this._differ=this._differs.find(e).create())}ngDoCheck(){if(this._differ){let e=this._differ.diff(this._ngStyle);e&&this._applyChanges(e)}}_setStyle(e,n){let[r,s]=e.split("."),i=r.indexOf("-")===-1?void 0:so.DashCase;n!=null?this._renderer.setStyle(this._ngEl.nativeElement,r,s?`${n}${s}`:n,i):this._renderer.removeStyle(this._ngEl.nativeElement,r,i)}_applyChanges(e){e.forEachRemovedItem(n=>this._setStyle(n.key,null)),e.forEachAddedItem(n=>this._setStyle(n.key,n.currentValue)),e.forEachChangedItem(n=>this._setStyle(n.key,n.currentValue))}};l(_m,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:_m,deps:[{token:pn},{token:xa},{token:hr}],target:Te.Directive})),l(_m,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:_m,isStandalone:!0,selector:"[ngStyle]",inputs:{ngStyle:"ngStyle"},ngImport:k}));var lp=_m;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:lp,decorators:[{type:bt,args:[{selector:"[ngStyle]"}]}],ctorParameters:()=>[{type:pn},{type:xa},{type:hr}],propDecorators:{ngStyle:[{type:Ge,args:["ngStyle"]}]}});var Im=class Im{constructor(e){l(this,"_viewContainerRef");l(this,"_viewRef",null);l(this,"ngTemplateOutletContext",null);l(this,"ngTemplateOutlet",null);l(this,"ngTemplateOutletInjector",null);this._viewContainerRef=e}ngOnChanges(e){if(this._shouldRecreateView(e)){let n=this._viewContainerRef;if(this._viewRef&&n.remove(n.indexOf(this._viewRef)),!this.ngTemplateOutlet){this._viewRef=null;return}let r=this._createContextForwardProxy();this._viewRef=n.createEmbeddedView(this.ngTemplateOutlet,r,{injector:this.ngTemplateOutletInjector??void 0})}}_shouldRecreateView(e){return!!e.ngTemplateOutlet||!!e.ngTemplateOutletInjector}_createContextForwardProxy(){return new Proxy({},{set:(e,n,r)=>this.ngTemplateOutletContext?Reflect.set(this.ngTemplateOutletContext,n,r):!1,get:(e,n,r)=>{if(this.ngTemplateOutletContext)return Reflect.get(this.ngTemplateOutletContext,n,r)}})}};l(Im,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Im,deps:[{token:mr}],target:Te.Directive})),l(Im,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Im,isStandalone:!0,selector:"[ngTemplateOutlet]",inputs:{ngTemplateOutletContext:"ngTemplateOutletContext",ngTemplateOutlet:"ngTemplateOutlet",ngTemplateOutletInjector:"ngTemplateOutletInjector"},usesOnChanges:!0,ngImport:k}));var cp=Im;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:cp,decorators:[{type:bt,args:[{selector:"[ngTemplateOutlet]"}]}],ctorParameters:()=>[{type:mr}],propDecorators:{ngTemplateOutletContext:[{type:Ge}],ngTemplateOutlet:[{type:Ge}],ngTemplateOutletInjector:[{type:Ge}]}});var Z9=[np,rp,Wc,sp,cp,lp,Uo,ip,op,Dl,ap];function qo(t,e){return new ne(2100,ngDevMode&&`InvalidPipeArgument: '${e}' for pipe '${tn(t)}'`)}var zN=class{createSubscription(e,n){return sr(()=>e.subscribe({next:n,error:r=>{throw r}}))}dispose(e){sr(()=>e.unsubscribe())}},GN=class{createSubscription(e,n){return e.then(r=>n?.(r),r=>{throw r}),{unsubscribe:()=>{n=null}}}dispose(e){e.unsubscribe()}},oge=new GN,age=new zN,Wd=class Wd{constructor(e){l(this,"_ref");l(this,"_latestValue",null);l(this,"markForCheckOnValueUpdate",!0);l(this,"_subscription",null);l(this,"_obj",null);l(this,"_strategy",null);this._ref=e}ngOnDestroy(){this._subscription&&this._dispose(),this._ref=null}transform(e){if(!this._obj){if(e)try{this.markForCheckOnValueUpdate=!1,this._subscribe(e)}finally{this.markForCheckOnValueUpdate=!0}return this._latestValue}return e!==this._obj?(this._dispose(),this.transform(e)):this._latestValue}_subscribe(e){this._obj=e,this._strategy=this._selectStrategy(e),this._subscription=this._strategy.createSubscription(e,n=>this._updateLatestValue(e,n))}_selectStrategy(e){if(jd(e))return oge;if(Kh(e))return age;throw qo(Wd,e)}_dispose(){this._strategy.dispose(this._subscription),this._latestValue=null,this._subscription=null,this._obj=null}_updateLatestValue(e,n){e===this._obj&&(this._latestValue=n,this.markForCheckOnValueUpdate&&this._ref?.markForCheck())}};l(Wd,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Wd,deps:[{token:An}],target:Te.Pipe})),l(Wd,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Wd,isStandalone:!0,name:"async",pure:!1}));var up=Wd;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:up,decorators:[{type:zs,args:[{name:"async",pure:!1}]}],ctorParameters:()=>[{type:An}]});var zd=class zd{transform(e){if(e==null)return null;if(typeof e!="string")throw qo(zd,e);return e.toLowerCase()}};l(zd,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:zd,deps:[],target:Te.Pipe})),l(zd,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:zd,isStandalone:!0,name:"lowercase"}));var dp=zd;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:dp,decorators:[{type:zs,args:[{name:"lowercase"}]}]});var lge=/(?:[0-9A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u0870-\u0887\u0889-\u088E\u08A0-\u08C9\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C5D\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u1711\u171F-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4C\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7CA\uA7D0\uA7D1\uA7D3\uA7D5-\uA7D9\uA7F2-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDD70-\uDD7A\uDD7C-\uDD8A\uDD8C-\uDD92\uDD94\uDD95\uDD97-\uDDA1\uDDA3-\uDDB1\uDDB3-\uDDB9\uDDBB\uDDBC\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD23\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF1C\uDF27\uDF30-\uDF45\uDF70-\uDF81\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC71\uDC72\uDC75\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDEB8\uDF00-\uDF1A\uDF40-\uDF46]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCDF\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEB0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|\uD80B[\uDF90-\uDFF0]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE70-\uDEBE\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD82C[\uDC00-\uDD22\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD837[\uDF00-\uDF1E]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDE90-\uDEAD\uDEC0-\uDEEB]|\uD839[\uDFE0-\uDFE6\uDFE8-\uDFEB\uDFED\uDFEE\uDFF0-\uDFFE]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43\uDD4B]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDEDF\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF38\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])\S*/g,Gd=class Gd{transform(e){if(e==null)return null;if(typeof e!="string")throw qo(Gd,e);return e.replace(lge,n=>n[0].toUpperCase()+n.slice(1).toLowerCase())}};l(Gd,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Gd,deps:[],target:Te.Pipe})),l(Gd,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Gd,isStandalone:!0,name:"titlecase"}));var pp=Gd;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:pp,decorators:[{type:zs,args:[{name:"titlecase"}]}]});var Zd=class Zd{transform(e){if(e==null)return null;if(typeof e!="string")throw qo(Zd,e);return e.toUpperCase()}};l(Zd,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Zd,deps:[],target:Te.Pipe})),l(Zd,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Zd,isStandalone:!0,name:"uppercase"}));var fp=Zd;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:fp,decorators:[{type:zs,args:[{name:"uppercase"}]}]});var cge="mediumDate",XN=new $e(ngDevMode?"DATE_PIPE_DEFAULT_TIMEZONE":""),QN=new $e(ngDevMode?"DATE_PIPE_DEFAULT_OPTIONS":""),Yd=class Yd{constructor(e,n,r){l(this,"locale");l(this,"defaultTimezone");l(this,"defaultOptions");this.locale=e,this.defaultTimezone=n,this.defaultOptions=r}transform(e,n,r,s){if(e==null||e===""||e!==e)return null;try{let i=n??this.defaultOptions?.dateFormat??cge,o=r??this.defaultOptions?.timezone??this.defaultTimezone??void 0;return cq(e,i,s||this.locale,o)}catch(i){throw qo(Yd,i.message)}}};l(Yd,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Yd,deps:[{token:Ts},{token:XN,optional:!0},{token:QN,optional:!0}],target:Te.Pipe})),l(Yd,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Yd,isStandalone:!0,name:"date"}));var hp=Yd;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:hp,decorators:[{type:zs,args:[{name:"date"}]}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[Ts]}]},{type:void 0,decorators:[{type:Ke,args:[XN]},{type:lt}]},{type:void 0,decorators:[{type:Ke,args:[QN]},{type:lt}]}]});var uge=/#/g,Xd=class Xd{constructor(e){l(this,"_localization");this._localization=e}transform(e,n,r){if(e==null)return"";if(typeof n!="object"||n===null)throw qo(Xd,n);let s=mq(e,Object.keys(n),this._localization,r);return n[s].replace(uge,e.toString())}};l(Xd,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Xd,deps:[{token:Tl}],target:Te.Pipe})),l(Xd,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Xd,isStandalone:!0,name:"i18nPlural"}));var mp=Xd;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:mp,decorators:[{type:zs,args:[{name:"i18nPlural"}]}],ctorParameters:()=>[{type:Tl}]});var Qd=class Qd{transform(e,n){if(e==null)return"";if(typeof n!="object"||typeof e!="string")throw qo(Qd,n);return n.hasOwnProperty(e)?n[e]:n.hasOwnProperty("other")?n.other:""}};l(Qd,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Qd,deps:[],target:Te.Pipe})),l(Qd,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Qd,isStandalone:!0,name:"i18nSelect"}));var gp=Qd;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:gp,decorators:[{type:zs,args:[{name:"i18nSelect"}]}]});var km=class km{transform(e){return JSON.stringify(e,null,2)}};l(km,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:km,deps:[],target:Te.Pipe})),l(km,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:km,isStandalone:!0,name:"json",pure:!1}));var vp=km;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:vp,decorators:[{type:zs,args:[{name:"json",pure:!1}]}]});function dge(t,e){return{key:t,value:e}}var Am=class Am{constructor(e){l(this,"differs");l(this,"differ");l(this,"keyValues",[]);l(this,"compareFn",Y9);this.differs=e}transform(e,n=Y9){if(!e||!(e instanceof Map)&&typeof e!="object")return null;this.differ??(this.differ=this.differs.find(e).create());let r=this.differ.diff(e),s=n!==this.compareFn;return r&&(this.keyValues=[],r.forEachItem(i=>{this.keyValues.push(dge(i.key,i.currentValue))})),(r||s)&&(n&&this.keyValues.sort(n),this.compareFn=n),this.keyValues}};l(Am,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Am,deps:[{token:xa}],target:Te.Pipe})),l(Am,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Am,isStandalone:!0,name:"keyvalue",pure:!1}));var yp=Am;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:yp,decorators:[{type:zs,args:[{name:"keyvalue",pure:!1}]}],ctorParameters:()=>[{type:xa}]});function Y9(t,e){let n=t.key,r=e.key;if(n===r)return 0;if(n==null)return 1;if(r==null)return-1;if(typeof n=="string"&&typeof r=="string")return n[{type:void 0,decorators:[{type:Ke,args:[Ts]}]}]});var Jd=class Jd{constructor(e){l(this,"_locale");this._locale=e}transform(e,n,r){if(!KN(e))return null;r||(r=this._locale);try{let s=JN(e);return fq(s,r,n)}catch(s){throw qo(Jd,s.message)}}};l(Jd,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Jd,deps:[{token:Ts}],target:Te.Pipe})),l(Jd,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Jd,isStandalone:!0,name:"percent"}));var wp=Jd;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:wp,decorators:[{type:zs,args:[{name:"percent"}]}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[Ts]}]}]});var ep=class ep{constructor(e,n="USD"){l(this,"_locale");l(this,"_defaultCurrencyCode");this._locale=e,this._defaultCurrencyCode=n}transform(e,n=this._defaultCurrencyCode,r="symbol",s,i){if(!KN(e))return null;i||(i=this._locale),typeof r=="boolean"&&((typeof ngDevMode>"u"||ngDevMode)&&console&&console.warn&&console.warn('Warning: the currency pipe has been changed in Angular v5. The symbolDisplay option (third parameter) is now a string instead of a boolean. The accepted values are "code", "symbol" or "symbol-narrow".'),r=r?"symbol":"code");let o=n||this._defaultCurrencyCode;r!=="code"&&(r==="symbol"||r==="symbol-narrow"?o=aq(o,r==="symbol"?"wide":"narrow",i):o=r);try{let a=JN(e);return pq(a,i,o,n,s)}catch(a){throw qo(ep,a.message)}}};l(ep,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:ep,deps:[{token:Ts},{token:OT}],target:Te.Pipe})),l(ep,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:ep,isStandalone:!0,name:"currency"}));var Ep=ep;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ep,decorators:[{type:zs,args:[{name:"currency"}]}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[Ts]}]},{type:void 0,decorators:[{type:Ke,args:[OT]}]}]});function KN(t){return!(t==null||t===""||t!==t)}function JN(t){if(typeof t=="string"&&!isNaN(Number(t)-parseFloat(t)))return Number(t);if(typeof t!="number")throw new Error(`${t} is not a number`);return t}var tp=class tp{transform(e,n,r){if(e==null)return null;if(!(typeof e=="string"||Array.isArray(e)))throw qo(tp,e);return e.slice(n,r)}};l(tp,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:tp,deps:[],target:Te.Pipe})),l(tp,"\u0275pipe",Gs({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:tp,isStandalone:!0,name:"slice",pure:!1}));var xp=tp;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:xp,decorators:[{type:zs,args:[{name:"slice",pure:!1}]}]});var X9=[up,fp,dp,vp,xp,bp,wp,pp,Ep,hp,mp,gp,yp],Uc=class Uc{};l(Uc,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Uc,deps:[],target:Te.NgModule})),l(Uc,"\u0275mod",Vo({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Uc,imports:[np,rp,Wc,sp,cp,lp,Uo,ip,op,Dl,ap,up,fp,dp,vp,xp,bp,wp,pp,Ep,hp,mp,gp,yp],exports:[np,rp,Wc,sp,cp,lp,Uo,ip,op,Dl,ap,up,fp,dp,vp,xp,bp,wp,pp,Ep,hp,mp,gp,yp]})),l(Uc,"\u0275inj",$o({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Uc}));var Er=Uc;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Er,decorators:[{type:co,args:[{imports:[Z9,X9],exports:[Z9,X9]}]}]});function eR(t,e){e=encodeURIComponent(e);for(let n of t.split(";")){let r=n.indexOf("="),[s,i]=r==-1?[n,""]:[n.slice(0,r),n.slice(r+1)];if(s.trim()===e)return decodeURIComponent(i)}return null}var QT="browser",vq="server";function yq(t){return t===QT}function KT(t){return t===vq}var wb=class{};var xxe=new Ea("19.2.25");var iR="20";function Nm(t,e){return oR(t)?new URL(t):new URL(t,e.location.href)}function oR(t){return/^https?:\/\//.test(t)}function bq(t){return oR(t)?new URL(t).hostname:t}function pge(t){if(!(typeof t=="string")||t.trim()==="")return!1;try{let n=new URL(t);return!0}catch{return!1}}function fge(t){return t.endsWith("/")?t.slice(0,-1):t}function hge(t){return t.startsWith("/")?t.slice(1):t}var Bm=t=>t.src,kq=new $e(ngDevMode?"ImageLoader":"",{providedIn:"root",factory:()=>Bm});function rD(t,e){return function(r){return pge(r)||mge(r,e||[]),r=fge(r),[{provide:kq,useValue:o=>(oR(o.src)&&gge(r,o.src),t(r,{...o,src:hge(o.src)}))}]}}function mge(t,e){throw new ne(2959,ngDevMode&&`Image loader has detected an invalid path (\`${t}\`). To fix this, supply a path using one of the following formats: ${e.join(" or ")}`)}function gge(t,e){throw new ne(2959,ngDevMode&&`Image loader has detected a \`\` tag with an invalid \`ngSrc\` attribute: ${e}. This image loader expects \`ngSrc\` to be a relative URL - however the provided value is an absolute URL. To fix this, provide \`ngSrc\` as a path relative to the base URL configured for this loader (\`${t}\`).`)}var Sxe=rD(vge,ngDevMode?["https:///cdn-cgi/image//"]:void 0);function vge(t,e){let n="format=auto";return e.width&&(n+=`,width=${e.width}`),e.isPlaceholder&&(n+=`,quality=${iR}`),`${t}/cdn-cgi/image/${n}/${e.src}`}var yge={name:"Cloudinary",testUrl:wge},bge=/https?\:\/\/[^\/]+\.cloudinary\.com\/.+/;function wge(t){return bge.test(t)}var Cxe=rD(Ege,ngDevMode?["https://res.cloudinary.com/mysite","https://mysite.cloudinary.com","https://subdomain.mysite.com"]:void 0);function Ege(t,e){let r=`f_auto,${e.isPlaceholder?"q_auto:low":"q_auto"}`;return e.width&&(r+=`,w_${e.width}`),e.loaderParams?.rounded&&(r+=",r_max"),`${t}/image/upload/${r}/${e.src}`}var xge={name:"ImageKit",testUrl:Cge},Sge=/https?\:\/\/[^\/]+\.imagekit\.io\/.+/;function Cge(t){return Sge.test(t)}var Txe=rD(Tge,ngDevMode?["https://ik.imagekit.io/mysite","https://subdomain.mysite.com"]:void 0);function Tge(t,e){let{src:n,width:r}=e,s=[];r&&s.push(`w-${r}`),e.isPlaceholder&&s.push(`q-${iR}`);let i=s.length?[t,`tr:${s.join(",")}`,n]:[t,n];return new URL(i.join("/")).href}var Dge={name:"Imgix",testUrl:Ige},_ge=/https?\:\/\/[^\/]+\.imgix\.net\/.+/;function Ige(t){return _ge.test(t)}var Dxe=rD(kge,ngDevMode?["https://somepath.imgix.net/"]:void 0);function kge(t,e){let n=new URL(`${t}/${e.src}`);return n.searchParams.set("auto","format"),e.width&&n.searchParams.set("w",e.width.toString()),e.isPlaceholder&&n.searchParams.set("q",iR),n.href}var Age={name:"Netlify",testUrl:Pge},Mge=/https?\:\/\/[^\/]+\.netlify\.app\/.+/;function Pge(t){return Mge.test(t)}function jn(t,e=!0){return`The NgOptimizedImage directive ${e?`(activated on an element with the \`ngSrc="${t}"\`) `:""}has detected that`}function Aq(t){if(!ngDevMode)throw new ne(2958,`Unexpected invocation of the ${t} in the prod mode. Please make sure that the prod mode is enabled for production builds.`)}var Rm=class Rm{constructor(){l(this,"images",new Map);l(this,"window",null);l(this,"observer",null);let e=yq(fe(Ta));Aq("LCP checker");let n=fe(En).defaultView;e&&typeof PerformanceObserver<"u"&&(this.window=n,this.observer=this.initPerformanceObserver())}initPerformanceObserver(){let e=new PerformanceObserver(n=>{let r=n.getEntries();if(r.length===0)return;let i=r[r.length-1].element?.src??"";if(i.startsWith("data:")||i.startsWith("blob:"))return;let o=this.images.get(i);o&&(!o.priority&&!o.alreadyWarnedPriority&&(o.alreadyWarnedPriority=!0,Nge(i)),o.modified&&!o.alreadyWarnedModified&&(o.alreadyWarnedModified=!0,Rge(i)))});return e.observe({type:"largest-contentful-paint",buffered:!0}),e}registerImage(e,n,r){if(!this.observer)return;let s={priority:r,modified:!1,alreadyWarnedModified:!1,alreadyWarnedPriority:!1};this.images.set(Nm(e,this.window).href,s)}unregisterImage(e){this.observer&&this.images.delete(Nm(e,this.window).href)}updateImage(e,n){if(!this.observer)return;let r=Nm(e,this.window).href,s=this.images.get(r);s&&(s.modified=!0,this.images.set(Nm(n,this.window).href,s),this.images.delete(r))}ngOnDestroy(){this.observer&&(this.observer.disconnect(),this.images.clear())}};l(Rm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Rm,deps:[],target:Te.Injectable})),l(Rm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Rm,providedIn:"root"}));var eD=Rm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:eD,decorators:[{type:St,args:[{providedIn:"root"}]}],ctorParameters:()=>[]});function Nge(t){let e=jn(t);console.error(gn(2955,`${e} this image is the Largest Contentful Paint (LCP) element but was not marked "priority". This image should be marked "priority" in order to prioritize its loading. To fix this, add the "priority" attribute.`))}function Rge(t){let e=jn(t);console.warn(gn(2964,`${e} this image is the Largest Contentful Paint (LCP) element and has had its "ngSrc" attribute modified. This can cause slower loading performance. It is recommended not to modify the "ngSrc" property on any image which could be the LCP element.`))}var Fge=new Set(["localhost","127.0.0.1","0.0.0.0"]),Lge=new $e(ngDevMode?"PRECONNECT_CHECK_BLOCKLIST":""),Fm=class Fm{constructor(){l(this,"document",fe(En));l(this,"preconnectLinks",null);l(this,"alreadySeen",new Set);l(this,"window",this.document.defaultView);l(this,"blocklist",new Set(Fge));Aq("preconnect link checker");let e=fe(Lge,{optional:!0});e&&this.populateBlocklist(e)}populateBlocklist(e){Array.isArray(e)?Mq(e,n=>{this.blocklist.add(bq(n))}):this.blocklist.add(bq(e))}assertPreconnect(e,n){if(typeof ngServerMode<"u"&&ngServerMode)return;let r=Nm(e,this.window);this.blocklist.has(r.hostname)||this.alreadySeen.has(r.origin)||(this.alreadySeen.add(r.origin),this.preconnectLinks??(this.preconnectLinks=this.queryPreconnectLinks()),this.preconnectLinks.has(r.origin)||console.warn(gn(2956,`${jn(n)} there is no preconnect tag present for this image. Preconnecting to the origin(s) that serve priority images ensures that these images are delivered as soon as possible. To fix this, please add the following element into the of the document: + `)))}queryPreconnectLinks(){let e=new Set,n=this.document.querySelectorAll("link[rel=preconnect]");for(let r of n){let s=Nm(r.href,this.window);e.add(s.origin)}return e}ngOnDestroy(){this.preconnectLinks?.clear(),this.alreadySeen.clear()}};l(Fm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Fm,deps:[],target:Te.Injectable})),l(Fm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Fm,providedIn:"root"}));var tD=Fm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:tD,decorators:[{type:St,args:[{providedIn:"root"}]}],ctorParameters:()=>[]});function Mq(t,e){for(let n of t)Array.isArray(n)?Mq(n,e):e(n)}var wq=5,Oge=new $e(typeof ngDevMode>"u"||ngDevMode?"NG_OPTIMIZED_PRELOADED_IMAGES":"",{providedIn:"root",factory:()=>new Set}),Lm=class Lm{constructor(){l(this,"preloadedImages",fe(Oge));l(this,"document",fe(En));l(this,"errorShown",!1)}createPreloadLinkTag(e,n,r,s){if(ngDevMode&&!this.errorShown&&this.preloadedImages.size>=wq&&(this.errorShown=!0,console.warn(gn(2961,`The \`NgOptimizedImage\` directive has detected that more than ${wq} images were marked as priority. This might negatively affect an overall performance of the page. To fix this, remove the "priority" attribute from images with less priority.`))),this.preloadedImages.has(n))return;this.preloadedImages.add(n);let i=e.createElement("link");e.setAttribute(i,"as","image"),e.setAttribute(i,"href",n),e.setAttribute(i,"rel","preload"),e.setAttribute(i,"fetchpriority","high"),s&&e.setAttribute(i,"imageSizes",s),r&&e.setAttribute(i,"imageSrcset",r),e.appendChild(this.document.head,i)}};l(Lm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Lm,deps:[],target:Te.Injectable})),l(Lm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Lm,providedIn:"root"}));var nD=Lm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:nD,decorators:[{type:St,args:[{providedIn:"root"}]}]});var Eq=50,rR=/^((\s*\d+w\s*(,|$)){1,})$/,Bge=/^((\s*\d+(\.\d+)?x\s*(,|$)){1,})$/,tR=3,xb=2,$ge=[1,2],Vge=640,xq=.1,Sq=1e3,Hge=1920,jge=1080,Uge=15,nR=1e3,Cq=4e3,Tq=1e4,qge=[Dge,xge,yge,Age],Dq=10,Eb=0,Om=class Om{constructor(){l(this,"imageLoader",fe(kq));l(this,"config",Wge(fe(tT)));l(this,"renderer",fe(hr));l(this,"imgElement",fe(pn).nativeElement);l(this,"injector",fe(Ln));l(this,"lcpObserver");l(this,"_renderedSrc",null);l(this,"ngSrc");l(this,"ngSrcset");l(this,"sizes");l(this,"width");l(this,"height");l(this,"loading");l(this,"priority",!1);l(this,"loaderParams");l(this,"disableOptimizedSrcset",!1);l(this,"fill",!1);l(this,"placeholder");l(this,"placeholderConfig");l(this,"src");l(this,"srcset");ngDevMode&&(this.lcpObserver=this.injector.get(eD),fe(Es).onDestroy(()=>{!this.priority&&this._renderedSrc!==null&&this.lcpObserver.unregisterImage(this._renderedSrc)}))}ngOnInit(){if(Ss("NgOptimizedImage"),ngDevMode){let e=this.injector.get(qt);if(Pq(this,"ngSrc",this.ngSrc),tve(this,this.ngSrcset),zge(this),this.ngSrcset&&Gge(this),Zge(this),eve(this),this.fill?(ave(this),e.runOutsideAngular(()=>lve(this,this.imgElement,this.renderer))):(ove(this),this.height!==void 0&&_q(this,this.height,"height"),this.width!==void 0&&_q(this,this.width,"width"),e.runOutsideAngular(()=>ive(this,this.imgElement,this.renderer))),cve(this),this.ngSrcset||Yge(this),Xge(this,this.imageLoader),uve(this.ngSrc,this.imageLoader),dve(this,this.imageLoader),pve(this,this.imageLoader),e.runOutsideAngular(()=>{this.lcpObserver.registerImage(this.getRewrittenSrc(),this.ngSrc,this.priority)}),this.priority&&(this.injector.get(tD).assertPreconnect(this.getRewrittenSrc(),this.ngSrc),typeof ngServerMode<"u"&&!ngServerMode)){let r=this.injector.get(yr);fve(r)}}this.placeholder&&this.removePlaceholderOnLoad(this.imgElement),this.setHostAttributes()}setHostAttributes(){this.fill?this.sizes||(this.sizes="100vw"):(this.setHostAttribute("width",this.width.toString()),this.setHostAttribute("height",this.height.toString())),this.setHostAttribute("loading",this.getLoadingBehavior()),this.setHostAttribute("fetchpriority",this.getFetchPriority()),this.setHostAttribute("ng-img","true");let e=this.updateSrcAndSrcset();this.sizes?this.getLoadingBehavior()==="lazy"?this.setHostAttribute("sizes","auto, "+this.sizes):this.setHostAttribute("sizes",this.sizes):this.ngSrcset&&rR.test(this.ngSrcset)&&this.getLoadingBehavior()==="lazy"&&this.setHostAttribute("sizes","auto, 100vw"),typeof ngServerMode<"u"&&ngServerMode&&this.priority&&this.injector.get(nD).createPreloadLinkTag(this.renderer,this.getRewrittenSrc(),e,this.sizes)}ngOnChanges(e){if(ngDevMode&&sve(this,e,["ngSrcset","width","height","priority","fill","loading","sizes","loaderParams","disableOptimizedSrcset"]),e.ngSrc&&!e.ngSrc.isFirstChange()){let n=this._renderedSrc;if(this.updateSrcAndSrcset(!0),ngDevMode){let r=this._renderedSrc;n&&r&&n!==r&&this.injector.get(qt).runOutsideAngular(()=>{this.lcpObserver.updateImage(n,r)})}}ngDevMode&&e.placeholder?.currentValue&&typeof ngServerMode<"u"&&!ngServerMode&&hve(this,this.imgElement)}callImageLoader(e){let n=e;return this.loaderParams&&(n.loaderParams=this.loaderParams),this.imageLoader(n)}getLoadingBehavior(){return!this.priority&&this.loading!==void 0?this.loading:this.priority?"eager":"lazy"}getFetchPriority(){return this.priority?"high":"auto"}getRewrittenSrc(){if(!this._renderedSrc){let e={src:this.ngSrc};this._renderedSrc=this.callImageLoader(e)}return this._renderedSrc}getRewrittenSrcset(){let e=rR.test(this.ngSrcset);return this.ngSrcset.split(",").filter(r=>r!=="").map(r=>{r=r.trim();let s=e?parseFloat(r):parseFloat(r)*this.width;return`${this.callImageLoader({src:this.ngSrc,width:s})} ${r}`}).join(", ")}getAutomaticSrcset(){return this.sizes?this.getResponsiveSrcset():this.getFixedSrcset()}getResponsiveSrcset(){let{breakpoints:e}=this.config,n=e;return this.sizes?.trim()==="100vw"&&(n=e.filter(s=>s>=Vge)),n.map(s=>`${this.callImageLoader({src:this.ngSrc,width:s})} ${s}w`).join(", ")}updateSrcAndSrcset(e=!1){e&&(this._renderedSrc=null);let n=this.getRewrittenSrc();this.setHostAttribute("src",n);let r;return this.ngSrcset?r=this.getRewrittenSrcset():this.shouldGenerateAutomaticSrcset()&&(r=this.getAutomaticSrcset()),r&&this.setHostAttribute("srcset",r),r}getFixedSrcset(){return $ge.map(n=>`${this.callImageLoader({src:this.ngSrc,width:this.width*n})} ${n}x`).join(", ")}shouldGenerateAutomaticSrcset(){let e=!1;return this.sizes||(e=this.width>Hge||this.height>jge),!this.disableOptimizedSrcset&&!this.srcset&&this.imageLoader!==Bm&&!e}generatePlaceholder(e){let{placeholderResolution:n}=this.config;return e===!0?`url("${Iq(this.callImageLoader({src:this.ngSrc,width:n,isPlaceholder:!0}))}")`:typeof e=="string"?`url("${Iq(e)}")`:null}shouldBlurPlaceholder(e){return!e||!e.hasOwnProperty("blur")?!0:!!e.blur}removePlaceholderOnLoad(e){let n=()=>{let i=this.injector.get(An);r(),s(),this.placeholder=!1,i.markForCheck()},r=this.renderer.listen(e,"load",n),s=this.renderer.listen(e,"error",n);aR(e,n)}setHostAttribute(e,n){this.renderer.setAttribute(this.imgElement,e,n)}};l(Om,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Om,deps:[],target:Te.Directive})),l(Om,"\u0275dir",Ct({minVersion:"16.1.0",version:"19.2.25",type:Om,isStandalone:!0,selector:"img[ngSrc]",inputs:{ngSrc:["ngSrc","ngSrc",Nq],ngSrcset:"ngSrcset",sizes:"sizes",width:["width","width",cm],height:["height","height",cm],loading:"loading",priority:["priority","priority",Pi],loaderParams:"loaderParams",disableOptimizedSrcset:["disableOptimizedSrcset","disableOptimizedSrcset",Pi],fill:["fill","fill",Pi],placeholder:["placeholder","placeholder",Rq],placeholderConfig:"placeholderConfig",src:"src",srcset:"srcset"},host:{properties:{"style.position":'fill ? "absolute" : null',"style.width":'fill ? "100%" : null',"style.height":'fill ? "100%" : null',"style.inset":'fill ? "0" : null',"style.background-size":'placeholder ? "cover" : null',"style.background-position":'placeholder ? "50% 50%" : null',"style.background-repeat":'placeholder ? "no-repeat" : null',"style.background-image":"placeholder ? generatePlaceholder(placeholder) : null","style.filter":'placeholder && shouldBlurPlaceholder(placeholderConfig) ? "blur(15px)" : null'}},usesOnChanges:!0,ngImport:k}));var sR=Om;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:sR,decorators:[{type:bt,args:[{selector:"img[ngSrc]",host:{"[style.position]":'fill ? "absolute" : null',"[style.width]":'fill ? "100%" : null',"[style.height]":'fill ? "100%" : null',"[style.inset]":'fill ? "0" : null',"[style.background-size]":'placeholder ? "cover" : null',"[style.background-position]":'placeholder ? "50% 50%" : null',"[style.background-repeat]":'placeholder ? "no-repeat" : null',"[style.background-image]":"placeholder ? generatePlaceholder(placeholder) : null","[style.filter]":`placeholder && shouldBlurPlaceholder(placeholderConfig) ? "blur(${Uge}px)" : null`}}]}],ctorParameters:()=>[],propDecorators:{ngSrc:[{type:Ge,args:[{required:!0,transform:Nq}]}],ngSrcset:[{type:Ge}],sizes:[{type:Ge}],width:[{type:Ge,args:[{transform:cm}]}],height:[{type:Ge,args:[{transform:cm}]}],loading:[{type:Ge}],priority:[{type:Ge,args:[{transform:Pi}]}],loaderParams:[{type:Ge}],disableOptimizedSrcset:[{type:Ge,args:[{transform:Pi}]}],fill:[{type:Ge,args:[{transform:Pi}]}],placeholder:[{type:Ge,args:[{transform:Rq}]}],placeholderConfig:[{type:Ge}],src:[{type:Ge}],srcset:[{type:Ge}]}});function Wge(t){let e={};return t.breakpoints&&(e.breakpoints=t.breakpoints.sort((n,r)=>n-r)),Object.assign({},eT,t,e)}function zge(t){if(t.src)throw new ne(2950,`${jn(t.ngSrc)} both \`src\` and \`ngSrc\` have been set. Supplying both of these attributes breaks lazy loading. The NgOptimizedImage directive sets \`src\` itself based on the value of \`ngSrc\`. To fix this, please remove the \`src\` attribute.`)}function Gge(t){if(t.srcset)throw new ne(2951,`${jn(t.ngSrc)} both \`srcset\` and \`ngSrcset\` have been set. Supplying both of these attributes breaks lazy loading. The NgOptimizedImage directive sets \`srcset\` itself based on the value of \`ngSrcset\`. To fix this, please remove the \`srcset\` attribute.`)}function Zge(t){let e=t.ngSrc.trim();if(e.startsWith("data:"))throw e.length>Eq&&(e=e.substring(0,Eq)+"..."),new ne(2952,`${jn(t.ngSrc,!1)} \`ngSrc\` is a Base64-encoded string (${e}). NgOptimizedImage does not support Base64-encoded strings. To fix this, disable the NgOptimizedImage directive for this element by removing \`ngSrc\` and using a standard \`src\` attribute instead.`)}function Yge(t){if(t.sizes?.match(/((\)|,)\s|^)\d+px/))throw new ne(2952,`${jn(t.ngSrc,!1)} \`sizes\` was set to a string including pixel values. For automatic \`srcset\` generation, \`sizes\` must only include responsive values, such as \`sizes="50vw"\` or \`sizes="(min-width: 768px) 50vw, 100vw"\`. To fix this, modify the \`sizes\` attribute, or provide your own \`ngSrcset\` value directly.`)}function Xge(t,e){Qge(t),Kge(t,e),Jge(t)}function Qge(t){if(t.placeholderConfig&&!t.placeholder)throw new ne(2952,`${jn(t.ngSrc,!1)} \`placeholderConfig\` options were provided for an image that does not use the \`placeholder\` attribute, and will have no effect.`)}function Kge(t,e){if(t.placeholder===!0&&e===Bm)throw new ne(2963,`${jn(t.ngSrc)} the \`placeholder\` attribute is set to true but no image loader is configured (i.e. the default one is being used), which would result in the same image being used for the primary image and its placeholder. To fix this, provide a loader or remove the \`placeholder\` attribute from the image.`)}function Jge(t){if(t.placeholder&&typeof t.placeholder=="string"&&t.placeholder.startsWith("data:")){if(t.placeholder.length>Tq)throw new ne(2965,`${jn(t.ngSrc)} the \`placeholder\` attribute is set to a data URL which is longer than ${Tq} characters. This is strongly discouraged, as large inline placeholders directly increase the bundle size of Angular and hurt page load performance. To fix this, generate a smaller data URL placeholder.`);t.placeholder.length>Cq&&console.warn(gn(2965,`${jn(t.ngSrc)} the \`placeholder\` attribute is set to a data URL which is longer than ${Cq} characters. This is discouraged, as large inline placeholders directly increase the bundle size of Angular and hurt page load performance. For better loading performance, generate a smaller data URL placeholder.`))}}function eve(t){let e=t.ngSrc.trim();if(e.startsWith("blob:"))throw new ne(2952,`${jn(t.ngSrc)} \`ngSrc\` was set to a blob URL (${e}). Blob URLs are not supported by the NgOptimizedImage directive. To fix this, disable the NgOptimizedImage directive for this element by removing \`ngSrc\` and using a regular \`src\` attribute instead.`)}function Pq(t,e,n){let r=typeof n=="string",s=r&&n.trim()==="";if(!r||s)throw new ne(2952,`${jn(t.ngSrc)} \`${e}\` has an invalid value (\`${n}\`). To fix this, change the value to a non-empty string.`)}function tve(t,e){if(e==null)return;Pq(t,"ngSrcset",e);let n=e,r=rR.test(n),s=Bge.test(n);if(s&&nve(t,n),!(r||s))throw new ne(2952,`${jn(t.ngSrc)} \`ngSrcset\` has an invalid value (\`${e}\`). To fix this, supply \`ngSrcset\` using a comma-separated list of one or more width descriptors (e.g. "100w, 200w") or density descriptors (e.g. "1x, 2x").`)}function nve(t,e){if(!e.split(",").every(r=>r===""||parseFloat(r)<=tR))throw new ne(2952,`${jn(t.ngSrc)} the \`ngSrcset\` contains an unsupported image density:\`${e}\`. NgOptimizedImage generally recommends a max image density of ${xb}x but supports image densities up to ${tR}x. The human eye cannot distinguish between image densities greater than ${xb}x - which makes them unnecessary for most use cases. Images that will be pinch-zoomed are typically the primary use case for ${tR}x images. Please remove the high density descriptor and try again.`)}function rve(t,e){let n;return e==="width"||e==="height"?n=`Changing \`${e}\` may result in different attribute value applied to the underlying image element and cause layout shifts on a page.`:n=`Changing the \`${e}\` would have no effect on the underlying image element, because the resource loading has already occurred.`,new ne(2953,`${jn(t.ngSrc)} \`${e}\` was updated after initialization. The NgOptimizedImage directive will not react to this input change. ${n} To fix this, either switch \`${e}\` to a static value or wrap the image element in an @if that is gated on the necessary value.`)}function sve(t,e,n){n.forEach(r=>{if(e.hasOwnProperty(r)&&!e[r].isFirstChange())throw r==="ngSrc"&&(t={ngSrc:e[r].previousValue}),rve(t,r)})}function _q(t,e,n){let r=typeof e=="number"&&e>0,s=typeof e=="string"&&/^\d+$/.test(e.trim())&&parseInt(e)>0;if(!r&&!s)throw new ne(2952,`${jn(t.ngSrc)} \`${n}\` has an invalid value. To fix this, provide \`${n}\` as a number greater than 0.`)}function ive(t,e,n){let r=()=>{s(),i();let o=window.getComputedStyle(e),a=parseFloat(o.getPropertyValue("width")),c=parseFloat(o.getPropertyValue("height"));if(o.getPropertyValue("box-sizing")==="border-box"){let B=o.getPropertyValue("padding-top"),M=o.getPropertyValue("padding-right"),$=o.getPropertyValue("padding-bottom"),j=o.getPropertyValue("padding-left");a-=parseFloat(M)+parseFloat(j),c-=parseFloat(B)+parseFloat($)}let d=a/c,p=a!==0&&c!==0,f=e.naturalWidth,h=e.naturalHeight,m=f/h,g=t.width,v=t.height,w=g/v,b=Math.abs(w-m)>xq,D=p&&Math.abs(m-d)>xq;if(b)console.warn(gn(2952,`${jn(t.ngSrc)} the aspect ratio of the image does not match the aspect ratio indicated by the width and height attributes. +Intrinsic image size: ${f}w x ${h}h (aspect-ratio: ${JT(m)}). +Supplied width and height attributes: ${g}w x ${v}h (aspect-ratio: ${JT(w)}). +To fix this, update the width and height attributes.`));else if(D)console.warn(gn(2952,`${jn(t.ngSrc)} the aspect ratio of the rendered image does not match the image's intrinsic aspect ratio. +Intrinsic image size: ${f}w x ${h}h (aspect-ratio: ${JT(m)}). +Rendered image size: ${a}w x ${c}h (aspect-ratio: ${JT(d)}). +This issue can occur if "width" and "height" attributes are added to an image without updating the corresponding image styling. To fix this, adjust image styling. In most cases, adding "height: auto" or "width: auto" to the image styling will fix this issue.`));else if(!t.ngSrcset&&p){let B=xb*a,M=xb*c,$=f-B>=Sq,j=h-M>=Sq;($||j)&&console.warn(gn(2960,`${jn(t.ngSrc)} the intrinsic image is significantly larger than necessary. +Rendered image size: ${a}w x ${c}h. +Intrinsic image size: ${f}w x ${h}h. +Recommended intrinsic image size: ${B}w x ${M}h. +Note: Recommended intrinsic image size is calculated assuming a maximum DPR of ${xb}. To improve loading time, resize the image or consider using the "ngSrcset" and "sizes" attributes.`))}},s=n.listen(e,"load",r),i=n.listen(e,"error",()=>{s(),i()});aR(e,r)}function ove(t){let e=[];if(t.width===void 0&&e.push("width"),t.height===void 0&&e.push("height"),e.length>0)throw new ne(2954,`${jn(t.ngSrc)} these required attributes are missing: ${e.map(n=>`"${n}"`).join(", ")}. Including "width" and "height" attributes will prevent image-related layout shifts. To fix this, include "width" and "height" attributes on the image tag or turn on "fill" mode with the \`fill\` attribute.`)}function ave(t){if(t.width||t.height)throw new ne(2952,`${jn(t.ngSrc)} the attributes \`height\` and/or \`width\` are present along with the \`fill\` attribute. Because \`fill\` mode causes an image to fill its containing element, the size attributes have no effect and should be removed.`)}function lve(t,e,n){let r=()=>{s(),i();let o=e.clientHeight;t.fill&&o===0&&console.warn(gn(2952,`${jn(t.ngSrc)} the height of the fill-mode image is zero. This is likely because the containing element does not have the CSS 'position' property set to one of the following: "relative", "fixed", or "absolute". To fix this problem, make sure the container element has the CSS 'position' property defined and the height of the element is not zero.`))},s=n.listen(e,"load",r),i=n.listen(e,"error",()=>{s(),i()});aR(e,r)}function cve(t){if(t.loading&&t.priority)throw new ne(2952,`${jn(t.ngSrc)} the \`loading\` attribute was used on an image that was marked "priority". Setting \`loading\` on priority images is not allowed because these images will always be eagerly loaded. To fix this, remove the \u201Cloading\u201D attribute from the priority image.`);let e=["auto","eager","lazy"];if(typeof t.loading=="string"&&!e.includes(t.loading))throw new ne(2952,`${jn(t.ngSrc)} the \`loading\` attribute has an invalid value (\`${t.loading}\`). To fix this, provide a valid value ("lazy", "eager", or "auto").`)}function uve(t,e){if(e===Bm){let n="";for(let r of qge)if(r.testUrl(t)){n=r.name;break}n&&console.warn(gn(2962,`NgOptimizedImage: It looks like your images may be hosted on the ${n} CDN, but your app is not using Angular's built-in loader for that CDN. We recommend switching to use the built-in by calling \`provide${n}Loader()\` in your \`providers\` and passing it your instance's base URL. If you don't want to use the built-in loader, define a custom loader function using IMAGE_LOADER to silence this warning.`))}}function dve(t,e){t.ngSrcset&&e===Bm&&console.warn(gn(2963,`${jn(t.ngSrc)} the \`ngSrcset\` attribute is present but no image loader is configured (i.e. the default one is being used), which would result in the same image being used for all configured sizes. To fix this, provide a loader or remove the \`ngSrcset\` attribute from the image.`))}function pve(t,e){t.loaderParams&&e===Bm&&console.warn(gn(2963,`${jn(t.ngSrc)} the \`loaderParams\` attribute is present but no image loader is configured (i.e. the default one is being used), which means that the loaderParams data will not be consumed and will not affect the URL. To fix this, provide a custom loader or remove the \`loaderParams\` attribute from the image.`))}async function fve(t){Eb===0?(Eb++,await t.whenStable(),Eb>Dq&&console.warn(gn(2966,`NgOptimizedImage: The "priority" attribute is set to true more than ${Dq} times (${Eb} times). Marking too many images as "high" priority can hurt your application's LCP (https://web.dev/lcp). "Priority" should only be set on the image expected to be the page's LCP element.`))):Eb++}function hve(t,e){let n=window.getComputedStyle(e),r=parseFloat(n.getPropertyValue("width")),s=parseFloat(n.getPropertyValue("height"));(r>nR||s>nR)&&console.warn(gn(2967,`${jn(t.ngSrc)} it uses a placeholder image, but at least one of the dimensions attribute (height or width) exceeds the limit of ${nR}px. To fix this, use a smaller image as a placeholder.`))}function aR(t,e){t.complete&&t.naturalWidth&&e()}function JT(t){return Number.isInteger(t)?t:t.toFixed(2)}function Nq(t){return typeof t=="string"?t:ds(t)}function Iq(t){return t.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Rq(t){return typeof t=="string"&&t!=="true"&&t!=="false"&&t!==""?t:Pi(t)}var zc=new $e(ngDevMode?"EventManagerPlugins":""),$m=class $m{constructor(e,n){l(this,"_zone");l(this,"_plugins");l(this,"_eventNameToPlugin",new Map);this._zone=n,e.forEach(r=>{r.manager=this}),this._plugins=e.slice().reverse()}addEventListener(e,n,r,s){return this._findPluginFor(n).addEventListener(e,n,r,s)}getZone(){return this._zone}_findPluginFor(e){let n=this._eventNameToPlugin.get(e);if(n)return n;if(n=this._plugins.find(s=>s.supports(e)),!n)throw new ne(5101,(typeof ngDevMode>"u"||ngDevMode)&&`No event manager plugin found for event ${e}`);return this._eventNameToPlugin.set(e,n),n}};l($m,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:$m,deps:[{token:zc},{token:qt}],target:Te.Injectable})),l($m,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:$m}));var Sp=$m;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Sp,decorators:[{type:St}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[zc]}]},{type:qt}]});var Cp=class{constructor(e){l(this,"_doc");l(this,"manager");this._doc=e}},sD="ng-app-id";function Fq(t){for(let e of t)e.remove()}function Lq(t,e){let n=e.createElement("style");return n.textContent=t,n}function mve(t,e,n,r){let s=t.head?.querySelectorAll(`style[${sD}="${e}"],link[${sD}="${e}"]`);if(s)for(let i of s)i.removeAttribute(sD),i instanceof HTMLLinkElement?r.set(i.href.slice(i.href.lastIndexOf("/")+1),{usage:0,elements:[i]}):i.textContent&&n.set(i.textContent,{usage:0,elements:[i]})}function cR(t,e){let n=e.createElement("link");return n.setAttribute("rel","stylesheet"),n.setAttribute("href",t),n}var Vm=class Vm{constructor(e,n,r,s={}){l(this,"doc");l(this,"appId");l(this,"nonce");l(this,"inline",new Map);l(this,"external",new Map);l(this,"hosts",new Set);l(this,"isServer");this.doc=e,this.appId=n,this.nonce=r,this.isServer=KT(s),mve(e,n,this.inline,this.external),this.hosts.add(e.head)}addStyles(e,n){for(let r of e)this.addUsage(r,this.inline,Lq);n?.forEach(r=>this.addUsage(r,this.external,cR))}removeStyles(e,n){for(let r of e)this.removeUsage(r,this.inline);n?.forEach(r=>this.removeUsage(r,this.external))}addUsage(e,n,r){let s=n.get(e);s?((typeof ngDevMode>"u"||ngDevMode)&&s.usage===0&&s.elements.forEach(i=>i.setAttribute("ng-style-reused","")),s.usage++):n.set(e,{usage:1,elements:[...this.hosts].map(i=>this.addElement(i,r(e,this.doc)))})}removeUsage(e,n){let r=n.get(e);r&&(r.usage--,r.usage<=0&&(Fq(r.elements),n.delete(e)))}ngOnDestroy(){for(let[,{elements:e}]of[...this.inline,...this.external])Fq(e);this.hosts.clear()}addHost(e){this.hosts.add(e);for(let[n,{elements:r}]of this.inline)r.push(this.addElement(e,Lq(n,this.doc)));for(let[n,{elements:r}]of this.external)r.push(this.addElement(e,cR(n,this.doc)))}removeHost(e){this.hosts.delete(e)}addElement(e,n){return this.nonce&&n.setAttribute("nonce",this.nonce),this.isServer&&n.setAttribute(sD,this.appId),e.appendChild(n)}};l(Vm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Vm,deps:[{token:En},{token:Ii},{token:jh,optional:!0},{token:Ta}],target:Te.Injectable})),l(Vm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Vm}));var Tp=Vm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Tp,decorators:[{type:St}],ctorParameters:()=>[{type:Document,decorators:[{type:Ke,args:[En]}]},{type:void 0,decorators:[{type:Ke,args:[Ii]}]},{type:void 0,decorators:[{type:Ke,args:[jh]},{type:lt}]},{type:void 0,decorators:[{type:Ke,args:[Ta]}]}]});var lR={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/",math:"http://www.w3.org/1998/Math/MathML"},dR=/%COMP%/g,gve=/\/\*#\s*sourceMappingURL=(.+?)\s*\*\//,vve=/^https?:/,$q="%COMP%",yve=`_nghost-${$q}`,bve=`_ngcontent-${$q}`,wve=!0,Vq=new $e(ngDevMode?"RemoveStylesOnCompDestroy":"",{providedIn:"root",factory:()=>wve});function Eve(t){return bve.replace(dR,t)}function xve(t){return yve.replace(dR,t)}function Hq(t,e){return e.map(n=>n.replace(dR,t))}function jq(t,e){if(!t)return e;let n=new URL(t,"http://localhost");return e.map(r=>r.includes("sourceMappingURL=")?r.replace(gve,(s,i)=>{if(i[0]==="/"||i.startsWith("data:")||vve.test(i))return`/*# sourceMappingURL=${i} */`;let{pathname:o}=new URL(i,n);return`/*# sourceMappingURL=${o} */`}):r)}var Hm=class Hm{constructor(e,n,r,s,i,o,a,c=null,u=null){l(this,"eventManager");l(this,"sharedStylesHost");l(this,"appId");l(this,"removeStylesOnCompDestroy");l(this,"doc");l(this,"platformId");l(this,"ngZone");l(this,"nonce");l(this,"tracingService");l(this,"rendererByCompId",new Map);l(this,"defaultRenderer");l(this,"platformIsServer");this.eventManager=e,this.sharedStylesHost=n,this.appId=r,this.removeStylesOnCompDestroy=s,this.doc=i,this.platformId=o,this.ngZone=a,this.nonce=c,this.tracingService=u,this.platformIsServer=KT(o),this.defaultRenderer=new Sb(e,i,a,this.platformIsServer,this.tracingService)}createRenderer(e,n){if(!e||!n)return this.defaultRenderer;this.platformIsServer&&n.encapsulation===Vs.ShadowDom&&(n={...n,encapsulation:Vs.Emulated});let r=this.getOrCreateRenderer(e,n);return r instanceof iD?r.applyToHost(e):r instanceof Cb&&r.applyStyles(),r}getOrCreateRenderer(e,n){let r=this.rendererByCompId,s=r.get(n.id);if(!s){let i=this.doc,o=this.ngZone,a=this.eventManager,c=this.sharedStylesHost,u=this.removeStylesOnCompDestroy,d=this.platformIsServer,p=this.tracingService;switch(n.encapsulation){case Vs.Emulated:s=new iD(a,c,n,this.appId,u,i,o,d,p);break;case Vs.ShadowDom:return new uR(a,c,e,n,i,o,this.nonce,d,p);default:s=new Cb(a,c,n,u,i,o,d,p);break}r.set(n.id,s)}return s}ngOnDestroy(){this.rendererByCompId.clear()}componentReplaced(e){this.rendererByCompId.delete(e)}};l(Hm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Hm,deps:[{token:Sp},{token:Tp},{token:Ii},{token:Vq},{token:En},{token:Ta},{token:qt},{token:jh},{token:Fo,optional:!0}],target:Te.Injectable})),l(Hm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Hm}));var jm=Hm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:jm,decorators:[{type:St}],ctorParameters:()=>[{type:Sp},{type:Tp},{type:void 0,decorators:[{type:Ke,args:[Ii]}]},{type:void 0,decorators:[{type:Ke,args:[Vq]}]},{type:Document,decorators:[{type:Ke,args:[En]}]},{type:Object,decorators:[{type:Ke,args:[Ta]}]},{type:qt},{type:void 0,decorators:[{type:Ke,args:[jh]}]},{type:Fo,decorators:[{type:Ke,args:[Fo]},{type:lt}]}]});var Sb=class{constructor(e,n,r,s,i){l(this,"eventManager");l(this,"doc");l(this,"ngZone");l(this,"platformIsServer");l(this,"tracingService");l(this,"data",Object.create(null));l(this,"throwOnSyntheticProps",!0);l(this,"destroyNode",null);this.eventManager=e,this.doc=n,this.ngZone=r,this.platformIsServer=s,this.tracingService=i}destroy(){}createElement(e,n){return n?this.doc.createElementNS(lR[n]||n,e):this.doc.createElement(e)}createComment(e){return this.doc.createComment(e)}createText(e){return this.doc.createTextNode(e)}appendChild(e,n){(Bq(e)?e.content:e).appendChild(n)}insertBefore(e,n,r){e&&(Bq(e)?e.content:e).insertBefore(n,r)}removeChild(e,n){n.remove()}selectRootElement(e,n){let r=typeof e=="string"?this.doc.querySelector(e):e;if(!r)throw new ne(-5104,(typeof ngDevMode>"u"||ngDevMode)&&`The selector "${e}" did not match any elements`);return n||(r.textContent=""),r}parentNode(e){return e.parentNode}nextSibling(e){return e.nextSibling}setAttribute(e,n,r,s){if(s){n=s+":"+n;let i=lR[s];i?e.setAttributeNS(i,n,r):e.setAttribute(n,r)}else e.setAttribute(n,r)}removeAttribute(e,n,r){if(r){let s=lR[r];s?e.removeAttributeNS(s,n):e.removeAttribute(`${r}:${n}`)}else e.removeAttribute(n)}addClass(e,n){e.classList.add(n)}removeClass(e,n){e.classList.remove(n)}setStyle(e,n,r,s){s&(so.DashCase|so.Important)?e.style.setProperty(n,r,s&so.Important?"important":""):e.style[n]=r}removeStyle(e,n,r){r&so.DashCase?e.style.removeProperty(n):e.style[n]=""}setProperty(e,n,r){e!=null&&((typeof ngDevMode>"u"||ngDevMode)&&this.throwOnSyntheticProps&&Oq(n,"property"),e[n]=r)}setValue(e,n){e.nodeValue=n}listen(e,n,r,s){if((typeof ngDevMode>"u"||ngDevMode)&&this.throwOnSyntheticProps&&Oq(n,"listener"),typeof e=="string"&&(e=Ds().getGlobalEventTarget(this.doc,e),!e))throw new ne(5102,(typeof ngDevMode>"u"||ngDevMode)&&`Unsupported event target ${e} for event ${n}`);let i=this.decoratePreventDefault(r);return this.tracingService?.wrapEventListener&&(i=this.tracingService.wrapEventListener(e,n,i)),this.eventManager.addEventListener(e,n,i,s)}decoratePreventDefault(e){return n=>{if(n==="__ngUnwrap__")return e;(this.platformIsServer?this.ngZone.runGuarded(()=>e(n)):e(n))===!1&&n.preventDefault()}}},Sve=64;function Oq(t,e){if(t.charCodeAt(0)===Sve)throw new ne(5105,`Unexpected synthetic ${e} ${t} found. Please make sure that: + - Make sure \`provideAnimationsAsync()\`, \`provideAnimations()\` or \`provideNoopAnimations()\` call was added to a list of providers used to bootstrap an application. + - There is a corresponding animation configuration named \`${t}\` defined in the \`animations\` field of the \`@Component\` decorator (see https://angular.dev/api/core/Component#animations).`)}function Bq(t){return t.tagName==="TEMPLATE"&&t.content!==void 0}var uR=class extends Sb{constructor(n,r,s,i,o,a,c,u,d){super(n,o,a,u,d);l(this,"sharedStylesHost");l(this,"hostEl");l(this,"shadowRoot");this.sharedStylesHost=r,this.hostEl=s,this.shadowRoot=s.attachShadow({mode:"open"}),this.sharedStylesHost.addHost(this.shadowRoot);let p=i.styles;if(ngDevMode){let h=Ds().getBaseHref(o)??"";p=jq(h,p)}p=Hq(i.id,p);for(let h of p){let m=document.createElement("style");c&&m.setAttribute("nonce",c),m.textContent=h,this.shadowRoot.appendChild(m)}let f=i.getExternalStyles?.();if(f)for(let h of f){let m=cR(h,o);c&&m.setAttribute("nonce",c),this.shadowRoot.appendChild(m)}}nodeOrShadowRoot(n){return n===this.hostEl?this.shadowRoot:n}appendChild(n,r){return super.appendChild(this.nodeOrShadowRoot(n),r)}insertBefore(n,r,s){return super.insertBefore(this.nodeOrShadowRoot(n),r,s)}removeChild(n,r){return super.removeChild(null,r)}parentNode(n){return this.nodeOrShadowRoot(super.parentNode(this.nodeOrShadowRoot(n)))}destroy(){this.sharedStylesHost.removeHost(this.shadowRoot)}},Cb=class extends Sb{constructor(n,r,s,i,o,a,c,u,d){super(n,o,a,c,u);l(this,"sharedStylesHost");l(this,"removeStylesOnCompDestroy");l(this,"styles");l(this,"styleUrls");this.sharedStylesHost=r,this.removeStylesOnCompDestroy=i;let p=s.styles;if(ngDevMode){let f=Ds().getBaseHref(o)??"";p=jq(f,p)}this.styles=d?Hq(d,p):p,this.styleUrls=s.getExternalStyles?.(d)}applyStyles(){this.sharedStylesHost.addStyles(this.styles,this.styleUrls)}destroy(){this.removeStylesOnCompDestroy&&this.sharedStylesHost.removeStyles(this.styles,this.styleUrls)}},iD=class extends Cb{constructor(n,r,s,i,o,a,c,u,d){let p=i+"-"+s.id;super(n,r,s,o,a,c,u,d,p);l(this,"contentAttr");l(this,"hostAttr");this.contentAttr=Eve(p),this.hostAttr=xve(p)}applyToHost(n){this.applyStyles(),this.setAttribute(n,this.hostAttr,"")}createElement(n,r){let s=super.createElement(n,r);return super.setAttribute(s,this.contentAttr,""),s}};var oD=class t extends fb{constructor(){super(...arguments);l(this,"supportsDOMEvents",!0)}static makeCurrent(){BN(new t)}onAndCancel(n,r,s,i){return n.addEventListener(r,s,i),()=>{n.removeEventListener(r,s,i)}}dispatchEvent(n,r){n.dispatchEvent(r)}remove(n){n.remove()}createElement(n,r){return r=r||this.getDefaultDocument(),r.createElement(n)}createHtmlDocument(){return document.implementation.createHTMLDocument("fakeTitle")}getDefaultDocument(){return document}isElementNode(n){return n.nodeType===Node.ELEMENT_NODE}isShadowRoot(n){return n instanceof DocumentFragment}getGlobalEventTarget(n,r){return r==="window"?window:r==="document"?n:r==="body"?n.body:null}getBaseHref(n){let r=Cve();return r==null?null:Tve(r)}resetBaseElement(){Tb=null}getUserAgent(){return window.navigator.userAgent}getCookie(n){return eR(document.cookie,n)}},Tb=null;function Cve(){return Tb=Tb||document.head.querySelector("base"),Tb?Tb.getAttribute("href"):null}function Tve(t){return new URL(t,document.baseURI).pathname}var aD=class{addToWindow(e){Yn.getAngularTestability=(r,s=!0)=>{let i=e.findTestabilityInTree(r,s);if(i==null)throw new ne(5103,(typeof ngDevMode>"u"||ngDevMode)&&"Could not find testability for element.");return i},Yn.getAllAngularTestabilities=()=>e.getAllTestabilities(),Yn.getAllAngularRootElements=()=>e.getAllRootElements();let n=r=>{let s=Yn.getAllAngularTestabilities(),i=s.length,o=function(){i--,i==0&&r()};s.forEach(a=>{a.whenStable(o)})};Yn.frameworkStabilizers||(Yn.frameworkStabilizers=[]),Yn.frameworkStabilizers.push(n)}findTestabilityInTree(e,n,r){if(n==null)return null;let s=e.getTestability(n);return s??(r?Ds().isShadowRoot(n)?this.findTestabilityInTree(e,n.host,!0):this.findTestabilityInTree(e,n.parentElement,!0):null)}},Um=class Um{build(){return new XMLHttpRequest}};l(Um,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Um,deps:[],target:Te.Injectable})),l(Um,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Um}));var lD=Um;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:lD,decorators:[{type:St}]});var qm=class qm extends Cp{constructor(e){super(e)}supports(e){return!0}addEventListener(e,n,r,s){return e.addEventListener(n,r,s),()=>this.removeEventListener(e,n,r,s)}removeEventListener(e,n,r,s){return e.removeEventListener(n,r,s)}};l(qm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:qm,deps:[{token:En}],target:Te.Injectable})),l(qm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:qm}));var Db=qm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Db,decorators:[{type:St}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[En]}]}]});var Uq=["alt","control","meta","shift"],Dve={"\b":"Backspace"," ":"Tab","\x7F":"Delete","\x1B":"Escape",Del:"Delete",Esc:"Escape",Left:"ArrowLeft",Right:"ArrowRight",Up:"ArrowUp",Down:"ArrowDown",Menu:"ContextMenu",Scroll:"ScrollLock",Win:"OS"},_ve={alt:t=>t.altKey,control:t=>t.ctrlKey,meta:t=>t.metaKey,shift:t=>t.shiftKey},Wo=class Wo extends Cp{constructor(e){super(e)}supports(e){return Wo.parseEventName(e)!=null}addEventListener(e,n,r,s){let i=Wo.parseEventName(n),o=Wo.eventCallback(i.fullKey,r,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>Ds().onAndCancel(e,i.domEventName,o,s))}static parseEventName(e){let n=e.toLowerCase().split("."),r=n.shift();if(n.length===0||!(r==="keydown"||r==="keyup"))return null;let s=Wo._normalizeKey(n.pop()),i="",o=n.indexOf("code");if(o>-1&&(n.splice(o,1),i="code."),Uq.forEach(c=>{let u=n.indexOf(c);u>-1&&(n.splice(u,1),i+=c+".")}),i+=s,n.length!=0||s.length===0)return null;let a={};return a.domEventName=r,a.fullKey=i,a}static matchEventFullKeyCode(e,n){let r=Dve[e.key]||e.key,s="";return n.indexOf("code.")>-1&&(r=e.code,s="code."),r==null||!r?!1:(r=r.toLowerCase(),r===" "?r="space":r==="."&&(r="dot"),Uq.forEach(i=>{if(i!==r){let o=_ve[i];o(e)&&(s+=i+".")}}),s+=r,s===n)}static eventCallback(e,n,r){return s=>{Wo.matchEventFullKeyCode(s,e)&&r.runGuarded(()=>n(s))}}static _normalizeKey(e){return e==="esc"?"escape":e}};l(Wo,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Wo,deps:[{token:En}],target:Te.Injectable})),l(Wo,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Wo}));var _b=Wo;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:_b,decorators:[{type:St}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[En]}]}]});function pR(t,e,n){return LN({rootComponent:t,platformRef:n?.platformRef,...Ive(e)})}function Ive(t){return{appProviders:[...fR,...t?.providers??[]],platformProviders:qq}}function kve(){oD.makeCurrent()}function Ave(){return new $s}function Mve(){return uM(document),document}var qq=[{provide:Ta,useValue:QT},{provide:U0,useValue:kve,multi:!0},{provide:En,useFactory:Mve}],Pve=BT(FN,"browser",qq),Wq=new $e(typeof ngDevMode>"u"||ngDevMode?"BrowserModule Providers Marker":""),zq=[{provide:Hd,useClass:aD},{provide:CT,useClass:Rc,deps:[qt,gl,Hd]},{provide:Rc,useClass:Rc,deps:[qt,gl,Hd]}],fR=[{provide:B0,useValue:"root"},{provide:$s,useFactory:Ave},{provide:zc,useClass:Db,multi:!0,deps:[En]},{provide:zc,useClass:_b,multi:!0,deps:[En]},jm,Tp,Sp,{provide:Sd,useExisting:jm},{provide:wb,useClass:lD},typeof ngDevMode>"u"||ngDevMode?{provide:Wq,useValue:!0}:[]],Gc=class Gc{constructor(){if((typeof ngDevMode>"u"||ngDevMode)&&fe(Wq,{optional:!0,skipSelf:!0}))throw new ne(5100,"Providers from the `BrowserModule` have already been loaded. If you need access to common directives such as NgIf and NgFor, import the `CommonModule` instead.")}};l(Gc,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Gc,deps:[],target:Te.NgModule})),l(Gc,"\u0275mod",Vo({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Gc,exports:[Er,Lc]})),l(Gc,"\u0275inj",$o({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Gc,providers:[...fR,...zq],imports:[Er,Lc]}));var cD=Gc;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:cD,decorators:[{type:co,args:[{providers:[...fR,...zq],exports:[Er,Lc]}]}],ctorParameters:()=>[]});var Wm=class Wm{constructor(e){l(this,"_doc");l(this,"_dom");this._doc=e,this._dom=Ds()}addTag(e,n=!1){return e?this._getOrCreateElement(e,n):null}addTags(e,n=!1){return e?e.reduce((r,s)=>(s&&r.push(this._getOrCreateElement(s,n)),r),[]):[]}getTag(e){if(!e)return null;let n=this._doc.querySelector(`meta[${e}]`);return n?.nodeName.toLowerCase()==="meta"?n:null}getTags(e){if(!e)return[];let n=this._doc.querySelectorAll(`meta[${e}]`);return n?[].slice.call(n).filter(r=>r.nodeName.toLowerCase()==="meta"):[]}updateTag(e,n){if(!e)return null;n=n||this._parseSelector(e);let r=this.getTag(n);return r?this._setMetaElementAttributes(e,r):this._getOrCreateElement(e,!0)}removeTag(e){this.removeTagElement(this.getTag(e))}removeTagElement(e){e&&this._dom.remove(e)}_getOrCreateElement(e,n=!1){if(!n){let i=this._parseSelector(e),o=this.getTags(i).filter(a=>this._containsAttributes(e,a))[0];if(o!==void 0)return o}let r=this._dom.createElement("meta");return this._setMetaElementAttributes(e,r),this._doc.getElementsByTagName("head")[0].appendChild(r),r}_setMetaElementAttributes(e,n){return Object.keys(e).forEach(r=>n.setAttribute(this._getMetaKeyMap(r),e[r])),n}_parseSelector(e){let n=e.name?"name":"property";return`${n}=${this._escapeSelectorValue(String(e[n]))}`}_escapeSelectorValue(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}_containsAttributes(e,n){return Object.keys(e).every(r=>n.getAttribute(this._getMetaKeyMap(r))===e[r])}_getMetaKeyMap(e){return Nve[e]||e}};l(Wm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Wm,deps:[{token:En}],target:Te.Injectable})),l(Wm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Wm,providedIn:"root"}));var hR=Wm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:hR,decorators:[{type:St,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[En]}]}]});var Nve={httpEquiv:"http-equiv"},zm=class zm{constructor(e){l(this,"_doc");this._doc=e}getTitle(){return this._doc.title}setTitle(e){this._doc.title=e||""}};l(zm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:zm,deps:[{token:En}],target:Te.Injectable})),l(zm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:zm,providedIn:"root"}));var mR=zm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:mR,decorators:[{type:St,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[En]}]}]});var Rve={pan:!0,panstart:!0,panmove:!0,panend:!0,pancancel:!0,panleft:!0,panright:!0,panup:!0,pandown:!0,pinch:!0,pinchstart:!0,pinchmove:!0,pinchend:!0,pinchcancel:!0,pinchin:!0,pinchout:!0,press:!0,pressup:!0,rotate:!0,rotatestart:!0,rotatemove:!0,rotateend:!0,rotatecancel:!0,swipe:!0,swipeleft:!0,swiperight:!0,swipeup:!0,swipedown:!0,tap:!0,doubletap:!0},Qm=new $e(typeof ngDevMode>"u"||ngDevMode?"HammerGestureConfig":""),dD=new $e(typeof ngDevMode>"u"||ngDevMode?"HammerLoader":""),Gm=class Gm{constructor(){l(this,"events",[]);l(this,"overrides",{});l(this,"options")}buildHammer(e){let n=new Hammer(e,this.options);n.get("pinch").set({enable:!0}),n.get("rotate").set({enable:!0});for(let r in this.overrides)n.get(r).set(this.overrides[r]);return n}};l(Gm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Gm,deps:[],target:Te.Injectable})),l(Gm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Gm}));var Km=Gm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Km,decorators:[{type:St}]});var Zm=class Zm extends Cp{constructor(n,r,s,i){super(n);l(this,"_config");l(this,"_injector");l(this,"loader");l(this,"_loaderPromise",null);this._config=r,this._injector=s,this.loader=i}supports(n){return!Rve.hasOwnProperty(n.toLowerCase())&&!this.isCustomEvent(n)?!1:!window.Hammer&&!this.loader?((typeof ngDevMode>"u"||ngDevMode)&&this._injector.get(Ai).warn(`The "${n}" event cannot be bound because Hammer.JS is not loaded and no custom loader has been specified.`),!1):!0}addEventListener(n,r,s){let i=this.manager.getZone();if(r=r.toLowerCase(),!window.Hammer&&this.loader){this._loaderPromise=this._loaderPromise||i.runOutsideAngular(()=>this.loader());let o=!1,a=()=>{o=!0};return i.runOutsideAngular(()=>this._loaderPromise.then(()=>{if(!window.Hammer){(typeof ngDevMode>"u"||ngDevMode)&&this._injector.get(Ai).warn("The custom HAMMER_LOADER completed, but Hammer.JS is not present."),a=()=>{};return}o||(a=this.addEventListener(n,r,s))}).catch(()=>{(typeof ngDevMode>"u"||ngDevMode)&&this._injector.get(Ai).warn(`The "${r}" event cannot be bound because the custom Hammer.JS loader failed.`),a=()=>{}})),()=>{a()}}return i.runOutsideAngular(()=>{let o=this._config.buildHammer(n),a=function(c){i.runGuarded(function(){s(c)})};return o.on(r,a),()=>{o.off(r,a),typeof o.destroy=="function"&&o.destroy()}})}isCustomEvent(n){return this._config.events.indexOf(n)>-1}};l(Zm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Zm,deps:[{token:En},{token:Qm},{token:Ln},{token:dD,optional:!0}],target:Te.Injectable})),l(Zm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Zm}));var Ib=Zm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ib,decorators:[{type:St}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[En]}]},{type:Km,decorators:[{type:Ke,args:[Qm]}]},{type:Ln},{type:void 0,decorators:[{type:lt},{type:Ke,args:[dD]}]}]});var Zc=class Zc{};l(Zc,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Zc,deps:[],target:Te.NgModule})),l(Zc,"\u0275mod",Vo({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Zc})),l(Zc,"\u0275inj",$o({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Zc,providers:[{provide:zc,useClass:Ib,multi:!0,deps:[En,Qm,Ln,[new lt,dD]]},{provide:Qm,useClass:Km}]}));var gR=Zc;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:gR,decorators:[{type:co,args:[{providers:[{provide:zc,useClass:Ib,multi:!0,deps:[En,Qm,Ln,[new lt,dD]]},{provide:Qm,useClass:Km}]}]}]});var Ym=class Ym{};l(Ym,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ym,deps:[],target:Te.Injectable})),l(Ym,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ym,providedIn:"root",useExisting:vn(()=>kb)}));var uD=Ym;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:uD,decorators:[{type:St,args:[{providedIn:"root",useExisting:vn(()=>kb)}]}]});var Xm=class Xm extends uD{constructor(n){super();l(this,"_doc");this._doc=n}sanitize(n,r){if(r==null)return null;switch(n){case In.NONE:return r;case In.HTML:return lo(r,"HTML")?ds(r):oT(this._doc,String(r)).toString();case In.STYLE:return lo(r,"Style")?ds(r):r;case In.SCRIPT:if(lo(r,"Script"))return ds(r);throw new ne(5200,(typeof ngDevMode>"u"||ngDevMode)&&"unsafe value used in a script context");case In.URL:return lo(r,"URL")?ds(r):Wh(String(r));case In.RESOURCE_URL:if(lo(r,"ResourceURL"))return ds(r);throw new ne(5201,(typeof ngDevMode>"u"||ngDevMode)&&`unsafe value used in a resource URL context (see ${Ji})`);default:throw new ne(5202,(typeof ngDevMode>"u"||ngDevMode)&&`Unexpected SecurityContext ${n} (see ${Ji})`)}}bypassSecurityTrustHtml(n){return MM(n)}bypassSecurityTrustStyle(n){return PM(n)}bypassSecurityTrustScript(n){return NM(n)}bypassSecurityTrustUrl(n){return RM(n)}bypassSecurityTrustResourceUrl(n){return FM(n)}};l(Xm,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Xm,deps:[{token:En}],target:Te.Injectable})),l(Xm,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Xm,providedIn:"root"}));var kb=Xm;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:kb,decorators:[{type:St,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:void 0,decorators:[{type:Ke,args:[En]}]}]});var Gq;(function(t){t[t.NoHttpTransferCache=0]="NoHttpTransferCache",t[t.HttpTransferCacheOptions=1]="HttpTransferCacheOptions",t[t.I18nSupport=2]="I18nSupport",t[t.EventReplay=3]="EventReplay",t[t.IncrementalHydration=4]="IncrementalHydration"})(Gq||(Gq={}));var zxe=new Ea("19.2.25");var tg=class tg{constructor(e,n){l(this,"_renderer");l(this,"_elementRef");l(this,"onChange",e=>{});l(this,"onTouched",()=>{});this._renderer=e,this._elementRef=n}setProperty(e,n){this._renderer.setProperty(this._elementRef.nativeElement,e,n)}registerOnTouched(e){this.onTouched=e}registerOnChange(e){this.onChange=e}setDisabledState(e){this.setProperty("disabled",e)}};l(tg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:tg,deps:[{token:hr},{token:pn}],target:Te.Directive})),l(tg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:tg,isStandalone:!0,ngImport:k}));var Lb=tg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Lb,decorators:[{type:bt}],ctorParameters:()=>[{type:hr},{type:pn}]});var ng=class ng extends Lb{};l(ng,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:ng,deps:null,target:Te.Directive})),l(ng,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:ng,isStandalone:!0,usesInheritance:!0,ngImport:k}));var Na=ng;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Na,decorators:[{type:bt}]});var Ri=new $e(ngDevMode?"NgValueAccessor":""),iW={provide:Ri,useExisting:vn(()=>kp),multi:!0},rg=class rg extends Na{writeValue(e){this.setProperty("checked",e)}};l(rg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:rg,deps:null,target:Te.Directive})),l(rg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:rg,isStandalone:!1,selector:"input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]",host:{listeners:{change:"onChange($event.target.checked)",blur:"onTouched()"}},providers:[iW],usesInheritance:!0,ngImport:k}));var kp=rg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:kp,decorators:[{type:bt,args:[{selector:"input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]",host:{"(change)":"onChange($event.target.checked)","(blur)":"onTouched()"},providers:[iW],standalone:!1}]}]});var oW={provide:Ri,useExisting:vn(()=>Kc),multi:!0};function Fve(){let t=Ds()?Ds().getUserAgent():"";return/android (\d+)/.test(t.toLowerCase())}var aW=new $e(ngDevMode?"CompositionEventMode":""),sg=class sg extends Lb{constructor(n,r,s){super(n,r);l(this,"_compositionMode");l(this,"_composing",!1);this._compositionMode=s,this._compositionMode==null&&(this._compositionMode=!Fve())}writeValue(n){let r=n??"";this.setProperty("value",r)}_handleInput(n){(!this._compositionMode||this._compositionMode&&!this._composing)&&this.onChange(n)}_compositionStart(){this._composing=!0}_compositionEnd(n){this._composing=!1,this._compositionMode&&this.onChange(n)}};l(sg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:sg,deps:[{token:hr},{token:pn},{token:aW,optional:!0}],target:Te.Directive})),l(sg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:sg,isStandalone:!1,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]",host:{listeners:{input:"$any(this)._handleInput($event.target.value)",blur:"onTouched()",compositionstart:"$any(this)._compositionStart()",compositionend:"$any(this)._compositionEnd($event.target.value)"}},providers:[oW],usesInheritance:!0,ngImport:k}));var Kc=sg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Kc,decorators:[{type:bt,args:[{selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]",host:{"(input)":"$any(this)._handleInput($event.target.value)","(blur)":"onTouched()","(compositionstart)":"$any(this)._compositionStart()","(compositionend)":"$any(this)._compositionEnd($event.target.value)"},providers:[oW],standalone:!1}]}],ctorParameters:()=>[{type:hr},{type:pn},{type:void 0,decorators:[{type:lt},{type:Ke,args:[aW]}]}]});function CR(t){return t==null||TR(t)===0}function TR(t){return t==null?null:Array.isArray(t)||typeof t=="string"?t.length:t instanceof Set?t.size:null}var er=new $e(ngDevMode?"NgValidators":""),_s=new $e(ngDevMode?"NgAsyncValidators":""),Lve=/^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;function Ove(t){return e=>{if(e.value==null||t==null)return null;let n=parseFloat(e.value);return!isNaN(n)&&n{if(e.value==null||t==null)return null;let n=parseFloat(e.value);return!isNaN(n)&&n>t?{max:{max:t,actual:e.value}}:null}}function $ve(t){return CR(t.value)?{required:!0}:null}function Vve(t){return t.value===!0?null:{required:!0}}function Hve(t){return CR(t.value)||Lve.test(t.value)?null:{email:!0}}function jve(t){return e=>{let n=e.value?.length??TR(e.value);return n===null||n===0?null:n{let n=e.value?.length??TR(e.value);return n!==null&&n>t?{maxlength:{requiredLength:t,actualLength:n}}:null}}function qve(t){if(!t)return vR;let e,n;return typeof t=="string"?(n="",t.charAt(0)!=="^"&&(n+="^"),n+=t,t.charAt(t.length-1)!=="$"&&(n+="$"),e=new RegExp(n)):(n=t.toString(),e=t),r=>{if(CR(r.value))return null;let s=r.value;return e.test(s)?null:{pattern:{requiredPattern:n,actualValue:s}}}}function vR(t){return null}function lW(t){return t!=null}function cW(t){let e=jd(t)?OI(t):t;if((typeof ngDevMode>"u"||ngDevMode)&&!Kh(e)){let n="Expected async validator to return Promise or Observable.";throw typeof t=="object"&&(n+=" Are you using a synchronous validator where an async validator is expected?"),new ne(-1101,n)}return e}function uW(t){let e={};return t.forEach(n=>{e=n!=null?{...e,...n}:e}),Object.keys(e).length===0?null:e}function dW(t,e){return e.map(n=>n(t))}function Wve(t){return!t.validate}function pW(t){return t.map(e=>Wve(e)?e:n=>e.validate(n))}function zve(t){if(!t)return null;let e=t.filter(lW);return e.length==0?null:function(n){return uW(dW(n,e))}}function DR(t){return t!=null?zve(pW(t)):null}function Gve(t){if(!t)return null;let e=t.filter(lW);return e.length==0?null:function(n){let r=dW(n,e).map(cW);return BI(r).pipe(Vu(uW))}}function _R(t){return t!=null?Gve(pW(t)):null}function Zq(t,e){return t===null?[e]:Array.isArray(t)?[...t,e]:[t,e]}function fW(t){return t._rawValidators}function hW(t){return t._rawAsyncValidators}function yR(t){return t?Array.isArray(t)?t:[t]:[]}function fD(t,e){return Array.isArray(t)?t.includes(e):t===e}function Yq(t,e){let n=yR(e);return yR(t).forEach(s=>{fD(n,s)||n.push(s)}),n}function Xq(t,e){return yR(e).filter(n=>!fD(t,n))}var hD=class{constructor(){l(this,"_composedValidatorFn");l(this,"_composedAsyncValidatorFn");l(this,"_rawValidators",[]);l(this,"_rawAsyncValidators",[]);l(this,"_onDestroyCallbacks",[])}get value(){return this.control?this.control.value:null}get valid(){return this.control?this.control.valid:null}get invalid(){return this.control?this.control.invalid:null}get pending(){return this.control?this.control.pending:null}get disabled(){return this.control?this.control.disabled:null}get enabled(){return this.control?this.control.enabled:null}get errors(){return this.control?this.control.errors:null}get pristine(){return this.control?this.control.pristine:null}get dirty(){return this.control?this.control.dirty:null}get touched(){return this.control?this.control.touched:null}get status(){return this.control?this.control.status:null}get untouched(){return this.control?this.control.untouched:null}get statusChanges(){return this.control?this.control.statusChanges:null}get valueChanges(){return this.control?this.control.valueChanges:null}get path(){return null}_setValidators(e){this._rawValidators=e||[],this._composedValidatorFn=DR(this._rawValidators)}_setAsyncValidators(e){this._rawAsyncValidators=e||[],this._composedAsyncValidatorFn=_R(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn||null}get asyncValidator(){return this._composedAsyncValidatorFn||null}_registerOnDestroy(e){this._onDestroyCallbacks.push(e)}_invokeOnDestroyCallbacks(){this._onDestroyCallbacks.forEach(e=>e()),this._onDestroyCallbacks=[]}reset(e=void 0){this.control&&this.control.reset(e)}hasError(e,n){return this.control?this.control.hasError(e,n):!1}getError(e,n){return this.control?this.control.getError(e,n):null}},lr=class extends hD{constructor(){super(...arguments);l(this,"name")}get formDirective(){return null}get path(){return null}},zo=class extends hD{constructor(){super(...arguments);l(this,"_parent",null);l(this,"name",null);l(this,"valueAccessor",null)}},mD=class{constructor(e){l(this,"_cd");this._cd=e}get isTouched(){return this._cd?.control?._touched?.(),!!this._cd?.control?.touched}get isUntouched(){return!!this._cd?.control?.untouched}get isPristine(){return this._cd?.control?._pristine?.(),!!this._cd?.control?.pristine}get isDirty(){return!!this._cd?.control?.dirty}get isValid(){return this._cd?.control?._status?.(),!!this._cd?.control?.valid}get isInvalid(){return!!this._cd?.control?.invalid}get isPending(){return!!this._cd?.control?.pending}get isSubmitted(){return this._cd?._submitted?.(),!!this._cd?.submitted}},mW={"[class.ng-untouched]":"isUntouched","[class.ng-touched]":"isTouched","[class.ng-pristine]":"isPristine","[class.ng-dirty]":"isDirty","[class.ng-valid]":"isValid","[class.ng-invalid]":"isInvalid","[class.ng-pending]":"isPending"},Zve={...mW,"[class.ng-submitted]":"isSubmitted"},ig=class ig extends mD{constructor(e){super(e)}};l(ig,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:ig,deps:[{token:zo,self:!0}],target:Te.Directive})),l(ig,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:ig,isStandalone:!1,selector:"[formControlName],[ngModel],[formControl]",host:{properties:{"class.ng-untouched":"isUntouched","class.ng-touched":"isTouched","class.ng-pristine":"isPristine","class.ng-dirty":"isDirty","class.ng-valid":"isValid","class.ng-invalid":"isInvalid","class.ng-pending":"isPending"}},usesInheritance:!0,ngImport:k}));var Ng=ig;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ng,decorators:[{type:bt,args:[{selector:"[formControlName],[ngModel],[formControl]",host:mW,standalone:!1}]}],ctorParameters:()=>[{type:zo,decorators:[{type:Jn}]}]});var og=class og extends mD{constructor(e){super(e)}};l(og,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:og,deps:[{token:lr,optional:!0,self:!0}],target:Te.Directive})),l(og,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:og,isStandalone:!1,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]",host:{properties:{"class.ng-untouched":"isUntouched","class.ng-touched":"isTouched","class.ng-pristine":"isPristine","class.ng-dirty":"isDirty","class.ng-valid":"isValid","class.ng-invalid":"isInvalid","class.ng-pending":"isPending","class.ng-submitted":"isSubmitted"}},usesInheritance:!0,ngImport:k}));var Rg=og;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Rg,decorators:[{type:bt,args:[{selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]",host:Zve,standalone:!1}]}],ctorParameters:()=>[{type:lr,decorators:[{type:lt},{type:Jn}]}]});var IR=` +
+ +
+ + In your class: + + this.myGroup = new FormGroup({ + firstName: new FormControl() + });`,xD=` +
+
+ +
+
+ + In your class: + + this.myGroup = new FormGroup({ + person: new FormGroup({ firstName: new FormControl() }) + });`,Yve=` +
+
+
+ +
+
+
+ + In your class: + + this.cityArray = new FormArray([new FormControl('SF')]); + this.myGroup = new FormGroup({ + cities: this.cityArray + });`,kR=` +
+
+ +
+
`,Xve=` +
+ + +
+`;function Qve(t){return new ne(1050,`formControlName must be used with a parent formGroup directive. You'll want to add a formGroup + directive and pass it an existing FormGroup instance (you can create one in your class). + + ${Kve(t)} + + Example: + + ${IR}`)}function Kve(t){return t==null||t===""?"":`Affected Form Control ${typeof t=="string"?"name":"index"}: "${t}"`}function Jve(){return new ne(1051,`formControlName cannot be used with an ngModelGroup parent. It is only compatible with parents + that also have a "form" prefix: formGroupName, formArrayName, or formGroup. + + Option 1: Update the parent to be formGroupName (reactive form strategy) + + ${xD} + + Option 2: Use ngModel instead of formControlName (template-driven strategy) + + ${kR}`)}function eye(){return new ne(1052,`formGroup expects a FormGroup instance. Please pass one in. + + Example: + + ${IR}`)}function tye(){return new ne(1053,`formGroupName must be used with a parent formGroup directive. You'll want to add a formGroup + directive and pass it an existing FormGroup instance (you can create one in your class). + + Example: + + ${xD}`)}function nye(){return new ne(1054,`formArrayName must be used with a parent formGroup directive. You'll want to add a formGroup + directive and pass it an existing FormGroup instance (you can create one in your class). + + Example: + + ${Yve}`)}var gW=` + It looks like you're using the disabled attribute with a reactive form directive. If you set disabled to true + when you set up this control in your component class, the disabled attribute will actually be set in the DOM for + you. We recommend using this approach to avoid 'changed after checked' errors. + + Example: + // Specify the \`disabled\` property at control creation time: + form = new FormGroup({ + first: new FormControl({value: 'Nancy', disabled: true}, Validators.required), + last: new FormControl('Drew', Validators.required) + }); + + // Controls can also be enabled/disabled after creation: + form.get('first')?.enable(); + form.get('last')?.disable(); +`,rye=` + It looks like you're constructing using a FormControl with both an options argument and an + async validators argument. Mixing these arguments will cause your async validators to be dropped. + You should either put all your validators in the options object, or in separate validators + arguments. For example: + + // Using validators arguments + fc = new FormControl(42, Validators.required, myAsyncValidator); + + // Using AbstractControlOptions + fc = new FormControl(42, {validators: Validators.required, asyncValidators: myAV}); + + // Do NOT mix them: async validators will be dropped! + fc = new FormControl(42, {validators: Validators.required}, /* Oops! */ myAsyncValidator); +`;function sye(t){return` + It looks like you're using ngModel on the same form field as ${t}. + Support for using the ngModel input property and ngModelChange event with + reactive form directives has been deprecated in Angular v6 and will be removed + in a future version of Angular. + + For more information on this, see our API docs here: + https://angular.io/api/forms/${t==="formControl"?"FormControlDirective":"FormControlName"}#use-with-ngmodel + `}function vW(t,e){return t?`with name: '${e}'`:`at index: ${e}`}function iye(t){return` + There are no form controls registered with this ${t?"group":"array"} yet. If you're using ngModel, + you may want to check next tick (e.g. use setTimeout). + `}function oye(t,e){return`Cannot find form control ${vW(t,e)}`}function aye(t,e){return`Must supply a value for form control ${vW(t,e)}`}var Ab="VALID",pD="INVALID",Jm="PENDING",Mb="DISABLED",Jc=class{},gD=class extends Jc{constructor(n,r){super();l(this,"value");l(this,"source");this.value=n,this.source=r}},Nb=class extends Jc{constructor(n,r){super();l(this,"pristine");l(this,"source");this.pristine=n,this.source=r}},Rb=class extends Jc{constructor(n,r){super();l(this,"touched");l(this,"source");this.touched=n,this.source=r}},eg=class extends Jc{constructor(n,r){super();l(this,"status");l(this,"source");this.status=n,this.source=r}},vD=class extends Jc{constructor(n){super();l(this,"source");this.source=n}},yD=class extends Jc{constructor(n){super();l(this,"source");this.source=n}};function AR(t){return(Ob(t)?t.validators:t)||null}function lye(t){return Array.isArray(t)?DR(t):t||null}function MR(t,e){return(typeof ngDevMode>"u"||ngDevMode)&&Ob(e)&&t&&console.warn(rye),(Ob(e)?e.asyncValidators:t)||null}function cye(t){return Array.isArray(t)?_R(t):t||null}function Ob(t){return t!=null&&!Array.isArray(t)&&typeof t=="object"}function yW(t,e,n){let r=t.controls;if(!(e?Object.keys(r):r).length)throw new ne(1e3,typeof ngDevMode>"u"||ngDevMode?iye(e):"");if(!r[n])throw new ne(1001,typeof ngDevMode>"u"||ngDevMode?oye(e,n):"")}function bW(t,e,n){t._forEachChild((r,s)=>{if(n[s]===void 0)throw new ne(1002,typeof ngDevMode>"u"||ngDevMode?aye(e,s):"")})}var Fg=class{constructor(e,n){l(this,"_pendingDirty",!1);l(this,"_hasOwnPendingAsyncValidator",null);l(this,"_pendingTouched",!1);l(this,"_onCollectionChange",()=>{});l(this,"_updateOn");l(this,"_parent",null);l(this,"_asyncValidationSubscription");l(this,"_composedValidatorFn");l(this,"_composedAsyncValidatorFn");l(this,"_rawValidators");l(this,"_rawAsyncValidators");l(this,"value");l(this,"_status",Ao(()=>this.statusReactive()));l(this,"statusReactive",ro(void 0));l(this,"errors");l(this,"_pristine",Ao(()=>this.pristineReactive()));l(this,"pristineReactive",ro(!0));l(this,"_touched",Ao(()=>this.touchedReactive()));l(this,"touchedReactive",ro(!1));l(this,"_events",new si);l(this,"events",this._events.asObservable());l(this,"valueChanges");l(this,"statusChanges");l(this,"_onDisabledChange",[]);this._assignValidators(e),this._assignAsyncValidators(n)}get validator(){return this._composedValidatorFn}set validator(e){this._rawValidators=this._composedValidatorFn=e}get asyncValidator(){return this._composedAsyncValidatorFn}set asyncValidator(e){this._rawAsyncValidators=this._composedAsyncValidatorFn=e}get parent(){return this._parent}get status(){return sr(this.statusReactive)}set status(e){sr(()=>this.statusReactive.set(e))}get valid(){return this.status===Ab}get invalid(){return this.status===pD}get pending(){return this.status==Jm}get disabled(){return this.status===Mb}get enabled(){return this.status!==Mb}get pristine(){return sr(this.pristineReactive)}set pristine(e){sr(()=>this.pristineReactive.set(e))}get dirty(){return!this.pristine}get touched(){return sr(this.touchedReactive)}set touched(e){sr(()=>this.touchedReactive.set(e))}get untouched(){return!this.touched}get updateOn(){return this._updateOn?this._updateOn:this.parent?this.parent.updateOn:"change"}setValidators(e){this._assignValidators(e)}setAsyncValidators(e){this._assignAsyncValidators(e)}addValidators(e){this.setValidators(Yq(e,this._rawValidators))}addAsyncValidators(e){this.setAsyncValidators(Yq(e,this._rawAsyncValidators))}removeValidators(e){this.setValidators(Xq(e,this._rawValidators))}removeAsyncValidators(e){this.setAsyncValidators(Xq(e,this._rawAsyncValidators))}hasValidator(e){return fD(this._rawValidators,e)}hasAsyncValidator(e){return fD(this._rawAsyncValidators,e)}clearValidators(){this.validator=null}clearAsyncValidators(){this.asyncValidator=null}markAsTouched(e={}){let n=this.touched===!1;this.touched=!0;let r=e.sourceControl??this;this._parent&&!e.onlySelf&&this._parent.markAsTouched({...e,sourceControl:r}),n&&e.emitEvent!==!1&&this._events.next(new Rb(!0,r))}markAllAsTouched(e={}){this.markAsTouched({onlySelf:!0,emitEvent:e.emitEvent,sourceControl:this}),this._forEachChild(n=>n.markAllAsTouched(e))}markAsUntouched(e={}){let n=this.touched===!0;this.touched=!1,this._pendingTouched=!1;let r=e.sourceControl??this;this._forEachChild(s=>{s.markAsUntouched({onlySelf:!0,emitEvent:e.emitEvent,sourceControl:r})}),this._parent&&!e.onlySelf&&this._parent._updateTouched(e,r),n&&e.emitEvent!==!1&&this._events.next(new Rb(!1,r))}markAsDirty(e={}){let n=this.pristine===!0;this.pristine=!1;let r=e.sourceControl??this;this._parent&&!e.onlySelf&&this._parent.markAsDirty({...e,sourceControl:r}),n&&e.emitEvent!==!1&&this._events.next(new Nb(!1,r))}markAsPristine(e={}){let n=this.pristine===!1;this.pristine=!0,this._pendingDirty=!1;let r=e.sourceControl??this;this._forEachChild(s=>{s.markAsPristine({onlySelf:!0,emitEvent:e.emitEvent})}),this._parent&&!e.onlySelf&&this._parent._updatePristine(e,r),n&&e.emitEvent!==!1&&this._events.next(new Nb(!0,r))}markAsPending(e={}){this.status=Jm;let n=e.sourceControl??this;e.emitEvent!==!1&&(this._events.next(new eg(this.status,n)),this.statusChanges.emit(this.status)),this._parent&&!e.onlySelf&&this._parent.markAsPending({...e,sourceControl:n})}disable(e={}){let n=this._parentMarkedDirty(e.onlySelf);this.status=Mb,this.errors=null,this._forEachChild(s=>{s.disable({...e,onlySelf:!0})}),this._updateValue();let r=e.sourceControl??this;e.emitEvent!==!1&&(this._events.next(new gD(this.value,r)),this._events.next(new eg(this.status,r)),this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._updateAncestors({...e,skipPristineCheck:n},this),this._onDisabledChange.forEach(s=>s(!0))}enable(e={}){let n=this._parentMarkedDirty(e.onlySelf);this.status=Ab,this._forEachChild(r=>{r.enable({...e,onlySelf:!0})}),this.updateValueAndValidity({onlySelf:!0,emitEvent:e.emitEvent}),this._updateAncestors({...e,skipPristineCheck:n},this),this._onDisabledChange.forEach(r=>r(!1))}_updateAncestors(e,n){this._parent&&!e.onlySelf&&(this._parent.updateValueAndValidity(e),e.skipPristineCheck||this._parent._updatePristine({},n),this._parent._updateTouched({},n))}setParent(e){this._parent=e}getRawValue(){return this.value}updateValueAndValidity(e={}){if(this._setInitialStatus(),this._updateValue(),this.enabled){let r=this._cancelExistingSubscription();this.errors=this._runValidator(),this.status=this._calculateStatus(),(this.status===Ab||this.status===Jm)&&this._runAsyncValidator(r,e.emitEvent)}let n=e.sourceControl??this;e.emitEvent!==!1&&(this._events.next(new gD(this.value,n)),this._events.next(new eg(this.status,n)),this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._parent&&!e.onlySelf&&this._parent.updateValueAndValidity({...e,sourceControl:n})}_updateTreeValidity(e={emitEvent:!0}){this._forEachChild(n=>n._updateTreeValidity(e)),this.updateValueAndValidity({onlySelf:!0,emitEvent:e.emitEvent})}_setInitialStatus(){this.status=this._allControlsDisabled()?Mb:Ab}_runValidator(){return this.validator?this.validator(this):null}_runAsyncValidator(e,n){if(this.asyncValidator){this.status=Jm,this._hasOwnPendingAsyncValidator={emitEvent:n!==!1};let r=cW(this.asyncValidator(this));this._asyncValidationSubscription=r.subscribe(s=>{this._hasOwnPendingAsyncValidator=null,this.setErrors(s,{emitEvent:n,shouldHaveEmitted:e})})}}_cancelExistingSubscription(){if(this._asyncValidationSubscription){this._asyncValidationSubscription.unsubscribe();let e=this._hasOwnPendingAsyncValidator?.emitEvent??!1;return this._hasOwnPendingAsyncValidator=null,e}return!1}setErrors(e,n={}){this.errors=e,this._updateControlsErrors(n.emitEvent!==!1,this,n.shouldHaveEmitted)}get(e){let n=e;return n==null||(Array.isArray(n)||(n=n.split(".")),n.length===0)?null:n.reduce((r,s)=>r&&r._find(s),this)}getError(e,n){let r=n?this.get(n):this;return r&&r.errors?r.errors[e]:null}hasError(e,n){return!!this.getError(e,n)}get root(){let e=this;for(;e._parent;)e=e._parent;return e}_updateControlsErrors(e,n,r){this.status=this._calculateStatus(),e&&this.statusChanges.emit(this.status),(e||r)&&this._events.next(new eg(this.status,n)),this._parent&&this._parent._updateControlsErrors(e,n,r)}_initObservables(){this.valueChanges=new cs,this.statusChanges=new cs}_calculateStatus(){return this._allControlsDisabled()?Mb:this.errors?pD:this._hasOwnPendingAsyncValidator||this._anyControlsHaveStatus(Jm)?Jm:this._anyControlsHaveStatus(pD)?pD:Ab}_anyControlsHaveStatus(e){return this._anyControls(n=>n.status===e)}_anyControlsDirty(){return this._anyControls(e=>e.dirty)}_anyControlsTouched(){return this._anyControls(e=>e.touched)}_updatePristine(e,n){let r=!this._anyControlsDirty(),s=this.pristine!==r;this.pristine=r,this._parent&&!e.onlySelf&&this._parent._updatePristine(e,n),s&&this._events.next(new Nb(this.pristine,n))}_updateTouched(e={},n){this.touched=this._anyControlsTouched(),this._events.next(new Rb(this.touched,n)),this._parent&&!e.onlySelf&&this._parent._updateTouched(e,n)}_registerOnCollectionChange(e){this._onCollectionChange=e}_setUpdateStrategy(e){Ob(e)&&e.updateOn!=null&&(this._updateOn=e.updateOn)}_parentMarkedDirty(e){let n=this._parent&&this._parent.dirty;return!e&&!!n&&!this._parent._anyControlsDirty()}_find(e){return null}_assignValidators(e){this._rawValidators=Array.isArray(e)?e.slice():e,this._composedValidatorFn=lye(this._rawValidators)}_assignAsyncValidators(e){this._rawAsyncValidators=Array.isArray(e)?e.slice():e,this._composedAsyncValidatorFn=cye(this._rawAsyncValidators)}},Lg=class extends Fg{constructor(n,r,s){super(AR(r),MR(s,r));l(this,"controls");(typeof ngDevMode>"u"||ngDevMode)&&uye(n),this.controls=n,this._initObservables(),this._setUpdateStrategy(r),this._setUpControls(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator})}registerControl(n,r){return this.controls[n]?this.controls[n]:(this.controls[n]=r,r.setParent(this),r._registerOnCollectionChange(this._onCollectionChange),r)}addControl(n,r,s={}){this.registerControl(n,r),this.updateValueAndValidity({emitEvent:s.emitEvent}),this._onCollectionChange()}removeControl(n,r={}){this.controls[n]&&this.controls[n]._registerOnCollectionChange(()=>{}),delete this.controls[n],this.updateValueAndValidity({emitEvent:r.emitEvent}),this._onCollectionChange()}setControl(n,r,s={}){this.controls[n]&&this.controls[n]._registerOnCollectionChange(()=>{}),delete this.controls[n],r&&this.registerControl(n,r),this.updateValueAndValidity({emitEvent:s.emitEvent}),this._onCollectionChange()}contains(n){return this.controls.hasOwnProperty(n)&&this.controls[n].enabled}setValue(n,r={}){bW(this,!0,n),Object.keys(n).forEach(s=>{yW(this,!0,s),this.controls[s].setValue(n[s],{onlySelf:!0,emitEvent:r.emitEvent})}),this.updateValueAndValidity(r)}patchValue(n,r={}){n!=null&&(Object.keys(n).forEach(s=>{let i=this.controls[s];i&&i.patchValue(n[s],{onlySelf:!0,emitEvent:r.emitEvent})}),this.updateValueAndValidity(r))}reset(n={},r={}){this._forEachChild((s,i)=>{s.reset(n?n[i]:null,{onlySelf:!0,emitEvent:r.emitEvent})}),this._updatePristine(r,this),this._updateTouched(r,this),this.updateValueAndValidity(r)}getRawValue(){return this._reduceChildren({},(n,r,s)=>(n[s]=r.getRawValue(),n))}_syncPendingControls(){let n=this._reduceChildren(!1,(r,s)=>s._syncPendingControls()?!0:r);return n&&this.updateValueAndValidity({onlySelf:!0}),n}_forEachChild(n){Object.keys(this.controls).forEach(r=>{let s=this.controls[r];s&&n(s,r)})}_setUpControls(){this._forEachChild(n=>{n.setParent(this),n._registerOnCollectionChange(this._onCollectionChange)})}_updateValue(){this.value=this._reduceValue()}_anyControls(n){for(let[r,s]of Object.entries(this.controls))if(this.contains(r)&&n(s))return!0;return!1}_reduceValue(){let n={};return this._reduceChildren(n,(r,s,i)=>((s.enabled||this.disabled)&&(r[i]=s.value),r))}_reduceChildren(n,r){let s=n;return this._forEachChild((i,o)=>{s=r(s,i,o)}),s}_allControlsDisabled(){for(let n of Object.keys(this.controls))if(this.controls[n].enabled)return!1;return Object.keys(this.controls).length>0||this.disabled}_find(n){return this.controls.hasOwnProperty(n)?this.controls[n]:null}};function uye(t){let e=Object.keys(t).filter(n=>n.includes("."));e.length>0&&console.warn(`FormGroup keys cannot include \`.\`, please replace the keys for: ${e.join(",")}.`)}var bR=class extends Lg{};var Go=new $e(typeof ngDevMode>"u"||ngDevMode?"CallSetDisabledState":"",{providedIn:"root",factory:()=>Vb}),Vb="always";function SD(t,e){return[...e.path,t]}function Bb(t,e,n=Vb){(typeof ngDevMode>"u"||ngDevMode)&&(t||Pg(e,"Cannot find control with"),e.valueAccessor||vye(e)),PR(t,e),e.valueAccessor.writeValue(t.value),(t.disabled||n==="always")&&e.valueAccessor.setDisabledState?.(t.disabled),pye(t,e),hye(t,e),fye(t,e),dye(t,e)}function bD(t,e,n=!0){let r=()=>{n&&(typeof ngDevMode>"u"||ngDevMode)&&gye(e)};e.valueAccessor&&(e.valueAccessor.registerOnChange(r),e.valueAccessor.registerOnTouched(r)),ED(t,e),t&&(e._invokeOnDestroyCallbacks(),t._registerOnCollectionChange(()=>{}))}function wD(t,e){t.forEach(n=>{n.registerOnValidatorChange&&n.registerOnValidatorChange(e)})}function dye(t,e){if(e.valueAccessor.setDisabledState){let n=r=>{e.valueAccessor.setDisabledState(r)};t.registerOnDisabledChange(n),e._registerOnDestroy(()=>{t._unregisterOnDisabledChange(n)})}}function PR(t,e){let n=fW(t);e.validator!==null?t.setValidators(Zq(n,e.validator)):typeof n=="function"&&t.setValidators([n]);let r=hW(t);e.asyncValidator!==null?t.setAsyncValidators(Zq(r,e.asyncValidator)):typeof r=="function"&&t.setAsyncValidators([r]);let s=()=>t.updateValueAndValidity();wD(e._rawValidators,s),wD(e._rawAsyncValidators,s)}function ED(t,e){let n=!1;if(t!==null){if(e.validator!==null){let s=fW(t);if(Array.isArray(s)&&s.length>0){let i=s.filter(o=>o!==e.validator);i.length!==s.length&&(n=!0,t.setValidators(i))}}if(e.asyncValidator!==null){let s=hW(t);if(Array.isArray(s)&&s.length>0){let i=s.filter(o=>o!==e.asyncValidator);i.length!==s.length&&(n=!0,t.setAsyncValidators(i))}}}let r=()=>{};return wD(e._rawValidators,r),wD(e._rawAsyncValidators,r),n}function pye(t,e){e.valueAccessor.registerOnChange(n=>{t._pendingValue=n,t._pendingChange=!0,t._pendingDirty=!0,t.updateOn==="change"&&wW(t,e)})}function fye(t,e){e.valueAccessor.registerOnTouched(()=>{t._pendingTouched=!0,t.updateOn==="blur"&&t._pendingChange&&wW(t,e),t.updateOn!=="submit"&&t.markAsTouched()})}function wW(t,e){t._pendingDirty&&t.markAsDirty(),t.setValue(t._pendingValue,{emitModelToViewChange:!1}),e.viewToModelUpdate(t._pendingValue),t._pendingChange=!1}function hye(t,e){let n=(r,s)=>{e.valueAccessor.writeValue(r),s&&e.viewToModelUpdate(r)};t.registerOnChange(n),e._registerOnDestroy(()=>{t._unregisterOnChange(n)})}function EW(t,e){t==null&&(typeof ngDevMode>"u"||ngDevMode)&&Pg(e,"Cannot find control with"),PR(t,e)}function mye(t,e){return ED(t,e)}function gye(t){return Pg(t,"There is no FormControl instance attached to form control element with")}function Pg(t,e){let n=NR(t);throw new Error(`${e} ${n}`)}function NR(t){let e=t.path;return e&&e.length>1?`path: '${e.join(" -> ")}'`:e?.[0]?`name: '${e}'`:"unspecified name attribute"}function vye(t){let e=NR(t);throw new ne(-1203,`No value accessor for form control ${e}.`)}function yye(t){let e=NR(t);throw new ne(1200,`Value accessor was not provided as an array for form control with ${e}. Check that the \`NG_VALUE_ACCESSOR\` token is configured as a \`multi: true\` provider.`)}function RR(t,e){if(!t.hasOwnProperty("model"))return!1;let n=t.model;return n.isFirstChange()?!0:!Object.is(e,n.currentValue)}function bye(t){return Object.getPrototypeOf(t.constructor)===Na}function xW(t,e){t._syncPendingControls(),e.forEach(n=>{let r=n.control;r.updateOn==="submit"&&r._pendingChange&&(n.viewToModelUpdate(r._pendingValue),r._pendingChange=!1)})}function FR(t,e){if(!e)return null;!Array.isArray(e)&&(typeof ngDevMode>"u"||ngDevMode)&&yye(t);let n,r,s;return e.forEach(i=>{i.constructor===Kc?n=i:bye(i)?(r&&(typeof ngDevMode>"u"||ngDevMode)&&Pg(t,"More than one built-in value accessor matches form control with"),r=i):(s&&(typeof ngDevMode>"u"||ngDevMode)&&Pg(t,"More than one custom value accessor matches form control with"),s=i)}),s||r||n||((typeof ngDevMode>"u"||ngDevMode)&&Pg(t,"No valid value accessor for form control with"),null)}function wye(t,e){let n=t.indexOf(e);n>-1&&t.splice(n,1)}function SW(t,e,n,r){r!=="never"&&((r===null||r==="once")&&!e._ngModelWarningSentOnce||r==="always"&&!n._ngModelWarningSent)&&(console.warn(sye(t)),e._ngModelWarningSentOnce=!0,n._ngModelWarningSent=!0)}var CW={provide:lr,useExisting:vn(()=>kl)},Pb=Promise.resolve(),ag=class ag extends lr{constructor(n,r,s){super();l(this,"callSetDisabledState");l(this,"_submitted",Ao(()=>this.submittedReactive()));l(this,"submittedReactive",ro(!1));l(this,"_directives",new Set);l(this,"form");l(this,"ngSubmit",new cs);l(this,"options");this.callSetDisabledState=s,this.form=new Lg({},DR(n),_R(r))}get submitted(){return sr(this.submittedReactive)}ngAfterViewInit(){this._setUpdateStrategy()}get formDirective(){return this}get control(){return this.form}get path(){return[]}get controls(){return this.form.controls}addControl(n){Pb.then(()=>{let r=this._findContainer(n.path);n.control=r.registerControl(n.name,n.control),Bb(n.control,n,this.callSetDisabledState),n.control.updateValueAndValidity({emitEvent:!1}),this._directives.add(n)})}getControl(n){return this.form.get(n.path)}removeControl(n){Pb.then(()=>{let r=this._findContainer(n.path);r&&r.removeControl(n.name),this._directives.delete(n)})}addFormGroup(n){Pb.then(()=>{let r=this._findContainer(n.path),s=new Lg({});EW(s,n),r.registerControl(n.name,s),s.updateValueAndValidity({emitEvent:!1})})}removeFormGroup(n){Pb.then(()=>{let r=this._findContainer(n.path);r&&r.removeControl(n.name)})}getFormGroup(n){return this.form.get(n.path)}updateModel(n,r){Pb.then(()=>{this.form.get(n.path).setValue(r)})}setValue(n){this.control.setValue(n)}onSubmit(n){return this.submittedReactive.set(!0),xW(this.form,this._directives),this.ngSubmit.emit(n),this.form._events.next(new vD(this.control)),n?.target?.method==="dialog"}onReset(){this.resetForm()}resetForm(n=void 0){this.form.reset(n),this.submittedReactive.set(!1),this.form._events.next(new yD(this.form))}_setUpdateStrategy(){this.options&&this.options.updateOn!=null&&(this.form._updateOn=this.options.updateOn)}_findContainer(n){return n.pop(),n.length?this.form.get(n):this.form}};l(ag,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:ag,deps:[{token:er,optional:!0,self:!0},{token:_s,optional:!0,self:!0},{token:Go,optional:!0}],target:Te.Directive})),l(ag,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:ag,isStandalone:!1,selector:"form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]",inputs:{options:["ngFormOptions","options"]},outputs:{ngSubmit:"ngSubmit"},host:{listeners:{submit:"onSubmit($event)",reset:"onReset()"}},providers:[CW],exportAs:["ngForm"],usesInheritance:!0,ngImport:k}));var kl=ag;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:kl,decorators:[{type:bt,args:[{selector:"form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]",providers:[CW],host:{"(submit)":"onSubmit($event)","(reset)":"onReset()"},outputs:["ngSubmit"],exportAs:"ngForm",standalone:!1}]}],ctorParameters:()=>[{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[er]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[_s]}]},{type:void 0,decorators:[{type:lt},{type:Ke,args:[Go]}]}],propDecorators:{options:[{type:Ge,args:["ngFormOptions"]}]}});function Qq(t,e){let n=t.indexOf(e);n>-1&&t.splice(n,1)}function Kq(t){return typeof t=="object"&&t!==null&&Object.keys(t).length===2&&"value"in t&&"disabled"in t}var Fb=class extends Fg{constructor(n=null,r,s){super(AR(r),MR(s,r));l(this,"defaultValue",null);l(this,"_onChange",[]);l(this,"_pendingValue");l(this,"_pendingChange",!1);this._applyFormState(n),this._setUpdateStrategy(r),this._initObservables(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator}),Ob(r)&&(r.nonNullable||r.initialValueIsDefault)&&(Kq(n)?this.defaultValue=n.value:this.defaultValue=n)}setValue(n,r={}){this.value=this._pendingValue=n,this._onChange.length&&r.emitModelToViewChange!==!1&&this._onChange.forEach(s=>s(this.value,r.emitViewToModelChange!==!1)),this.updateValueAndValidity(r)}patchValue(n,r={}){this.setValue(n,r)}reset(n=this.defaultValue,r={}){this._applyFormState(n),this.markAsPristine(r),this.markAsUntouched(r),this.setValue(this.value,r),this._pendingChange=!1}_updateValue(){}_anyControls(n){return!1}_allControlsDisabled(){return this.disabled}registerOnChange(n){this._onChange.push(n)}_unregisterOnChange(n){Qq(this._onChange,n)}registerOnDisabledChange(n){this._onDisabledChange.push(n)}_unregisterOnDisabledChange(n){Qq(this._onDisabledChange,n)}_forEachChild(n){}_syncPendingControls(){return this.updateOn==="submit"&&(this._pendingDirty&&this.markAsDirty(),this._pendingTouched&&this.markAsTouched(),this._pendingChange)?(this.setValue(this._pendingValue,{onlySelf:!0,emitModelToViewChange:!1}),!0):!1}_applyFormState(n){Kq(n)?(this.value=this._pendingValue=n.value,n.disabled?this.disable({onlySelf:!0,emitEvent:!1}):this.enable({onlySelf:!0,emitEvent:!1})):this.value=this._pendingValue=n}};var Eye=t=>t instanceof Fb,lg=class lg extends lr{constructor(){super(...arguments);l(this,"_parent")}ngOnInit(){this._checkParentType(),this.formDirective.addFormGroup(this)}ngOnDestroy(){this.formDirective&&this.formDirective.removeFormGroup(this)}get control(){return this.formDirective.getFormGroup(this)}get path(){return SD(this.name==null?this.name:this.name.toString(),this._parent)}get formDirective(){return this._parent?this._parent.formDirective:null}_checkParentType(){}};l(lg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:lg,deps:null,target:Te.Directive})),l(lg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:lg,isStandalone:!1,usesInheritance:!0,ngImport:k}));var Ap=lg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ap,decorators:[{type:bt,args:[{standalone:!1}]}]});function xye(){return new ne(1350,` + ngModel cannot be used to register form controls with a parent formGroup directive. Try using + formGroup's partner directive "formControlName" instead. Example: + + ${IR} + + Or, if you'd like to avoid registering this form control, indicate that it's standalone in ngModelOptions: + + Example: + + ${Xve}`)}function Sye(){return new ne(1351,` + ngModel cannot be used to register form controls with a parent formGroupName or formArrayName directive. + + Option 1: Use formControlName instead of ngModel (reactive strategy): + + ${xD} + + Option 2: Update ngModel's parent be ngModelGroup (template-driven strategy): + + ${kR}`)}function Cye(){return new ne(1352,`If ngModel is used within a form tag, either the name attribute must be set or the form + control must be defined as 'standalone' in ngModelOptions. + + Example 1: + Example 2: `)}function Tye(){return new ne(1353,` + ngModelGroup cannot be used with a parent formGroup directive. + + Option 1: Use formGroupName instead of ngModelGroup (reactive strategy): + + ${xD} + + Option 2: Use a regular form tag instead of the formGroup directive (template-driven strategy): + + ${kR}`)}var TW={provide:lr,useExisting:vn(()=>Al)},Dp=class Dp extends Ap{constructor(n,r,s){super();l(this,"name","");this._parent=n,this._setValidators(r),this._setAsyncValidators(s)}_checkParentType(){if(!(this._parent instanceof Dp)&&!(this._parent instanceof kl)&&(typeof ngDevMode>"u"||ngDevMode))throw Tye()}};l(Dp,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Dp,deps:[{token:lr,host:!0,skipSelf:!0},{token:er,optional:!0,self:!0},{token:_s,optional:!0,self:!0}],target:Te.Directive})),l(Dp,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Dp,isStandalone:!1,selector:"[ngModelGroup]",inputs:{name:["ngModelGroup","name"]},providers:[TW],exportAs:["ngModelGroup"],usesInheritance:!0,ngImport:k}));var Al=Dp;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Al,decorators:[{type:bt,args:[{selector:"[ngModelGroup]",providers:[TW],exportAs:"ngModelGroup",standalone:!1}]}],ctorParameters:()=>[{type:lr,decorators:[{type:pi},{type:bl}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[er]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[_s]}]}],propDecorators:{name:[{type:Ge,args:["ngModelGroup"]}]}});var DW={provide:zo,useExisting:vn(()=>Mp)},Jq=Promise.resolve(),_p=class _p extends zo{constructor(n,r,s,i,o,a){super();l(this,"_changeDetectorRef");l(this,"callSetDisabledState");l(this,"control",new Fb);l(this,"_registered",!1);l(this,"viewModel");l(this,"name","");l(this,"isDisabled");l(this,"model");l(this,"options");l(this,"update",new cs);this._changeDetectorRef=o,this.callSetDisabledState=a,this._parent=n,this._setValidators(r),this._setAsyncValidators(s),this.valueAccessor=FR(this,i)}ngOnChanges(n){if(this._checkForErrors(),!this._registered||"name"in n){if(this._registered&&(this._checkName(),this.formDirective)){let r=n.name.previousValue;this.formDirective.removeControl({name:r,path:this._getPath(r)})}this._setUpControl()}"isDisabled"in n&&this._updateDisabled(n),RR(n,this.viewModel)&&(this._updateValue(this.model),this.viewModel=this.model)}ngOnDestroy(){this.formDirective&&this.formDirective.removeControl(this)}get path(){return this._getPath(this.name)}get formDirective(){return this._parent?this._parent.formDirective:null}viewToModelUpdate(n){this.viewModel=n,this.update.emit(n)}_setUpControl(){this._setUpdateStrategy(),this._isStandalone()?this._setUpStandalone():this.formDirective.addControl(this),this._registered=!0}_setUpdateStrategy(){this.options&&this.options.updateOn!=null&&(this.control._updateOn=this.options.updateOn)}_isStandalone(){return!this._parent||!!(this.options&&this.options.standalone)}_setUpStandalone(){Bb(this.control,this,this.callSetDisabledState),this.control.updateValueAndValidity({emitEvent:!1})}_checkForErrors(){(typeof ngDevMode>"u"||ngDevMode)&&!this._isStandalone()&&Dye(this._parent),this._checkName()}_checkName(){if(this.options&&this.options.name&&(this.name=this.options.name),!this._isStandalone()&&!this.name&&(typeof ngDevMode>"u"||ngDevMode))throw Cye()}_updateValue(n){Jq.then(()=>{this.control.setValue(n,{emitViewToModelChange:!1}),this._changeDetectorRef?.markForCheck()})}_updateDisabled(n){let r=n.isDisabled.currentValue,s=r!==0&&Pi(r);Jq.then(()=>{s&&!this.control.disabled?this.control.disable():!s&&this.control.disabled&&this.control.enable(),this._changeDetectorRef?.markForCheck()})}_getPath(n){return this._parent?SD(n,this._parent):[n]}};l(_p,"ngAcceptInputType_isDisabled"),l(_p,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:_p,deps:[{token:lr,host:!0,optional:!0},{token:er,optional:!0,self:!0},{token:_s,optional:!0,self:!0},{token:Ri,optional:!0,self:!0},{token:An,optional:!0},{token:Go,optional:!0}],target:Te.Directive})),l(_p,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:_p,isStandalone:!1,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:{name:"name",isDisabled:["disabled","isDisabled"],model:["ngModel","model"],options:["ngModelOptions","options"]},outputs:{update:"ngModelChange"},providers:[DW],exportAs:["ngModel"],usesInheritance:!0,usesOnChanges:!0,ngImport:k}));var Mp=_p;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Mp,decorators:[{type:bt,args:[{selector:"[ngModel]:not([formControlName]):not([formControl])",providers:[DW],exportAs:"ngModel",standalone:!1}]}],ctorParameters:()=>[{type:lr,decorators:[{type:lt},{type:pi}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[er]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[_s]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[Ri]}]},{type:An,decorators:[{type:lt},{type:Ke,args:[An]}]},{type:void 0,decorators:[{type:lt},{type:Ke,args:[Go]}]}],propDecorators:{name:[{type:Ge}],isDisabled:[{type:Ge,args:["disabled"]}],model:[{type:Ge,args:["ngModel"]}],options:[{type:Ge,args:["ngModelOptions"]}],update:[{type:lm,args:["ngModelChange"]}]}});function Dye(t){if(!(t instanceof Al)&&t instanceof Ap)throw Sye();if(!(t instanceof Al)&&!(t instanceof kl))throw xye()}var cg=class cg{};l(cg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:cg,deps:[],target:Te.Directive})),l(cg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:cg,isStandalone:!1,selector:"form:not([ngNoForm]):not([ngNativeValidate])",host:{attributes:{novalidate:""}},ngImport:k}));var Og=cg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Og,decorators:[{type:bt,args:[{selector:"form:not([ngNoForm]):not([ngNativeValidate])",host:{novalidate:""},standalone:!1}]}]});var _W={provide:Ri,useExisting:vn(()=>Pp),multi:!0},ug=class ug extends Na{writeValue(e){let n=e??"";this.setProperty("value",n)}registerOnChange(e){this.onChange=n=>{e(n==""?null:parseFloat(n))}}};l(ug,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:ug,deps:null,target:Te.Directive})),l(ug,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:ug,isStandalone:!1,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]",host:{listeners:{input:"onChange($event.target.value)",blur:"onTouched()"}},providers:[_W],usesInheritance:!0,ngImport:k}));var Pp=ug;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Pp,decorators:[{type:bt,args:[{selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]",host:{"(input)":"onChange($event.target.value)","(blur)":"onTouched()"},providers:[_W],standalone:!1}]}]});var IW={provide:Ri,useExisting:vn(()=>Np),multi:!0};function _ye(){throw new ne(1202,` + If you define both a name and a formControlName attribute on your radio button, their values + must match. Ex: + `)}var dg=class dg{constructor(){l(this,"_accessors",[])}add(e,n){this._accessors.push([e,n])}remove(e){for(let n=this._accessors.length-1;n>=0;--n)if(this._accessors[n][1]===e){this._accessors.splice(n,1);return}}select(e){this._accessors.forEach(n=>{this._isSameGroup(n,e)&&n[1]!==e&&n[1].fireUncheck(e.value)})}_isSameGroup(e,n){return e[0].control?e[0]._parent===n._control._parent&&e[1].name===n.name:!1}};l(dg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:dg,deps:[],target:Te.Injectable})),l(dg,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:dg,providedIn:"root"}));var $b=dg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:$b,decorators:[{type:St,args:[{providedIn:"root"}]}]});var pg=class pg extends Na{constructor(n,r,s,i){super(n,r);l(this,"_registry");l(this,"_injector");l(this,"_state");l(this,"_control");l(this,"_fn");l(this,"setDisabledStateFired",!1);l(this,"onChange",()=>{});l(this,"name");l(this,"formControlName");l(this,"value");l(this,"callSetDisabledState",fe(Go,{optional:!0})??Vb);this._registry=s,this._injector=i}ngOnInit(){this._control=this._injector.get(zo),this._checkName(),this._registry.add(this._control,this)}ngOnDestroy(){this._registry.remove(this)}writeValue(n){this._state=n===this.value,this.setProperty("checked",this._state)}registerOnChange(n){this._fn=n,this.onChange=()=>{n(this.value),this._registry.select(this)}}setDisabledState(n){(this.setDisabledStateFired||n||this.callSetDisabledState==="whenDisabledForLegacyCode")&&this.setProperty("disabled",n),this.setDisabledStateFired=!0}fireUncheck(n){this.writeValue(n)}_checkName(){this.name&&this.formControlName&&this.name!==this.formControlName&&(typeof ngDevMode>"u"||ngDevMode)&&_ye(),!this.name&&this.formControlName&&(this.name=this.formControlName)}};l(pg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:pg,deps:[{token:hr},{token:pn},{token:$b},{token:Ln}],target:Te.Directive})),l(pg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:pg,isStandalone:!1,selector:"input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]",inputs:{name:"name",formControlName:"formControlName",value:"value"},host:{listeners:{change:"onChange()",blur:"onTouched()"}},providers:[IW],usesInheritance:!0,ngImport:k}));var Np=pg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Np,decorators:[{type:bt,args:[{selector:"input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]",host:{"(change)":"onChange()","(blur)":"onTouched()"},providers:[IW],standalone:!1}]}],ctorParameters:()=>[{type:hr},{type:pn},{type:$b},{type:Ln}],propDecorators:{name:[{type:Ge}],formControlName:[{type:Ge}],value:[{type:Ge}]}});var kW={provide:Ri,useExisting:vn(()=>Rp),multi:!0},fg=class fg extends Na{writeValue(e){this.setProperty("value",parseFloat(e))}registerOnChange(e){this.onChange=n=>{e(n==""?null:parseFloat(n))}}};l(fg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:fg,deps:null,target:Te.Directive})),l(fg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:fg,isStandalone:!1,selector:"input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]",host:{listeners:{change:"onChange($event.target.value)",input:"onChange($event.target.value)",blur:"onTouched()"}},providers:[kW],usesInheritance:!0,ngImport:k}));var Rp=fg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Rp,decorators:[{type:bt,args:[{selector:"input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]",host:{"(change)":"onChange($event.target.value)","(input)":"onChange($event.target.value)","(blur)":"onTouched()"},providers:[kW],standalone:!1}]}]});var Hb=new $e(ngDevMode?"NgModelWithFormControlWarning":""),AW={provide:zo,useExisting:vn(()=>Fp)},Yc=class Yc extends zo{constructor(n,r,s,i,o){super();l(this,"_ngModelWarningConfig");l(this,"callSetDisabledState");l(this,"viewModel");l(this,"form");l(this,"model");l(this,"update",new cs);l(this,"_ngModelWarningSent",!1);this._ngModelWarningConfig=i,this.callSetDisabledState=o,this._setValidators(n),this._setAsyncValidators(r),this.valueAccessor=FR(this,s)}set isDisabled(n){(typeof ngDevMode>"u"||ngDevMode)&&console.warn(gW)}ngOnChanges(n){if(this._isControlChanged(n)){let r=n.form.previousValue;r&&bD(r,this,!1),Bb(this.form,this,this.callSetDisabledState),this.form.updateValueAndValidity({emitEvent:!1})}RR(n,this.viewModel)&&((typeof ngDevMode>"u"||ngDevMode)&&SW("formControl",Yc,this,this._ngModelWarningConfig),this.form.setValue(this.model),this.viewModel=this.model)}ngOnDestroy(){this.form&&bD(this.form,this,!1)}get path(){return[]}get control(){return this.form}viewToModelUpdate(n){this.viewModel=n,this.update.emit(n)}_isControlChanged(n){return n.hasOwnProperty("form")}};l(Yc,"_ngModelWarningSentOnce",!1),l(Yc,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Yc,deps:[{token:er,optional:!0,self:!0},{token:_s,optional:!0,self:!0},{token:Ri,optional:!0,self:!0},{token:Hb,optional:!0},{token:Go,optional:!0}],target:Te.Directive})),l(Yc,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Yc,isStandalone:!1,selector:"[formControl]",inputs:{form:["formControl","form"],isDisabled:["disabled","isDisabled"],model:["ngModel","model"]},outputs:{update:"ngModelChange"},providers:[AW],exportAs:["ngForm"],usesInheritance:!0,usesOnChanges:!0,ngImport:k}));var Fp=Yc;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Fp,decorators:[{type:bt,args:[{selector:"[formControl]",providers:[AW],exportAs:"ngForm",standalone:!1}]}],ctorParameters:()=>[{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[er]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[_s]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[Ri]}]},{type:void 0,decorators:[{type:lt},{type:Ke,args:[Hb]}]},{type:void 0,decorators:[{type:lt},{type:Ke,args:[Go]}]}],propDecorators:{form:[{type:Ge,args:["formControl"]}],isDisabled:[{type:Ge,args:["disabled"]}],model:[{type:Ge,args:["ngModel"]}],update:[{type:lm,args:["ngModelChange"]}]}});var MW={provide:lr,useExisting:vn(()=>Ml)},hg=class hg extends lr{constructor(n,r,s){super();l(this,"callSetDisabledState");l(this,"_submitted",Ao(()=>this._submittedReactive()));l(this,"_submittedReactive",ro(!1));l(this,"_oldForm");l(this,"_onCollectionChange",()=>this._updateDomValue());l(this,"directives",[]);l(this,"form",null);l(this,"ngSubmit",new cs);this.callSetDisabledState=s,this._setValidators(n),this._setAsyncValidators(r)}get submitted(){return sr(this._submittedReactive)}set submitted(n){this._submittedReactive.set(n)}ngOnChanges(n){if((typeof ngDevMode>"u"||ngDevMode)&&!this.form)throw eye();n.hasOwnProperty("form")&&(this._updateValidators(),this._updateDomValue(),this._updateRegistrations(),this._oldForm=this.form)}ngOnDestroy(){this.form&&(ED(this.form,this),this.form._onCollectionChange===this._onCollectionChange&&this.form._registerOnCollectionChange(()=>{}))}get formDirective(){return this}get control(){return this.form}get path(){return[]}addControl(n){let r=this.form.get(n.path);return Bb(r,n,this.callSetDisabledState),r.updateValueAndValidity({emitEvent:!1}),this.directives.push(n),r}getControl(n){return this.form.get(n.path)}removeControl(n){bD(n.control||null,n,!1),wye(this.directives,n)}addFormGroup(n){this._setUpFormContainer(n)}removeFormGroup(n){this._cleanUpFormContainer(n)}getFormGroup(n){return this.form.get(n.path)}addFormArray(n){this._setUpFormContainer(n)}removeFormArray(n){this._cleanUpFormContainer(n)}getFormArray(n){return this.form.get(n.path)}updateModel(n,r){this.form.get(n.path).setValue(r)}onSubmit(n){return this._submittedReactive.set(!0),xW(this.form,this.directives),this.ngSubmit.emit(n),this.form._events.next(new vD(this.control)),n?.target?.method==="dialog"}onReset(){this.resetForm()}resetForm(n=void 0){this.form.reset(n),this._submittedReactive.set(!1),this.form._events.next(new yD(this.form))}_updateDomValue(){this.directives.forEach(n=>{let r=n.control,s=this.form.get(n.path);r!==s&&(bD(r||null,n),Eye(s)&&(Bb(s,n,this.callSetDisabledState),n.control=s))}),this.form._updateTreeValidity({emitEvent:!1})}_setUpFormContainer(n){let r=this.form.get(n.path);EW(r,n),r.updateValueAndValidity({emitEvent:!1})}_cleanUpFormContainer(n){if(this.form){let r=this.form.get(n.path);r&&mye(r,n)&&r.updateValueAndValidity({emitEvent:!1})}}_updateRegistrations(){this.form._registerOnCollectionChange(this._onCollectionChange),this._oldForm&&this._oldForm._registerOnCollectionChange(()=>{})}_updateValidators(){PR(this.form,this),this._oldForm&&ED(this._oldForm,this)}};l(hg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:hg,deps:[{token:er,optional:!0,self:!0},{token:_s,optional:!0,self:!0},{token:Go,optional:!0}],target:Te.Directive})),l(hg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:hg,isStandalone:!1,selector:"[formGroup]",inputs:{form:["formGroup","form"]},outputs:{ngSubmit:"ngSubmit"},host:{listeners:{submit:"onSubmit($event)",reset:"onReset()"}},providers:[MW],exportAs:["ngForm"],usesInheritance:!0,usesOnChanges:!0,ngImport:k}));var Ml=hg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ml,decorators:[{type:bt,args:[{selector:"[formGroup]",providers:[MW],host:{"(submit)":"onSubmit($event)","(reset)":"onReset()"},exportAs:"ngForm",standalone:!1}]}],ctorParameters:()=>[{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[er]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[_s]}]},{type:void 0,decorators:[{type:lt},{type:Ke,args:[Go]}]}],propDecorators:{form:[{type:Ge,args:["formGroup"]}],ngSubmit:[{type:lm}]}});var PW={provide:lr,useExisting:vn(()=>Ra)},mg=class mg extends Ap{constructor(n,r,s){super();l(this,"name",null);this._parent=n,this._setValidators(r),this._setAsyncValidators(s)}_checkParentType(){if(RW(this._parent)&&(typeof ngDevMode>"u"||ngDevMode))throw tye()}};l(mg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:mg,deps:[{token:lr,host:!0,optional:!0,skipSelf:!0},{token:er,optional:!0,self:!0},{token:_s,optional:!0,self:!0}],target:Te.Directive})),l(mg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:mg,isStandalone:!1,selector:"[formGroupName]",inputs:{name:["formGroupName","name"]},providers:[PW],usesInheritance:!0,ngImport:k}));var Ra=mg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ra,decorators:[{type:bt,args:[{selector:"[formGroupName]",providers:[PW],standalone:!1}]}],ctorParameters:()=>[{type:lr,decorators:[{type:lt},{type:pi},{type:bl}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[er]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[_s]}]}],propDecorators:{name:[{type:Ge,args:["formGroupName"]}]}});var NW={provide:lr,useExisting:vn(()=>Pl)},gg=class gg extends lr{constructor(n,r,s){super();l(this,"_parent");l(this,"name",null);this._parent=n,this._setValidators(r),this._setAsyncValidators(s)}ngOnInit(){if(RW(this._parent)&&(typeof ngDevMode>"u"||ngDevMode))throw nye();this.formDirective.addFormArray(this)}ngOnDestroy(){this.formDirective?.removeFormArray(this)}get control(){return this.formDirective.getFormArray(this)}get formDirective(){return this._parent?this._parent.formDirective:null}get path(){return SD(this.name==null?this.name:this.name.toString(),this._parent)}};l(gg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:gg,deps:[{token:lr,host:!0,optional:!0,skipSelf:!0},{token:er,optional:!0,self:!0},{token:_s,optional:!0,self:!0}],target:Te.Directive})),l(gg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:gg,isStandalone:!1,selector:"[formArrayName]",inputs:{name:["formArrayName","name"]},providers:[NW],usesInheritance:!0,ngImport:k}));var Pl=gg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Pl,decorators:[{type:bt,args:[{selector:"[formArrayName]",providers:[NW],standalone:!1}]}],ctorParameters:()=>[{type:lr,decorators:[{type:lt},{type:pi},{type:bl}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[er]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[_s]}]}],propDecorators:{name:[{type:Ge,args:["formArrayName"]}]}});function RW(t){return!(t instanceof Ra)&&!(t instanceof Ml)&&!(t instanceof Pl)}var FW={provide:zo,useExisting:vn(()=>Lp)},Xc=class Xc extends zo{constructor(n,r,s,i,o){super();l(this,"_ngModelWarningConfig");l(this,"_added",!1);l(this,"viewModel");l(this,"control");l(this,"name",null);l(this,"model");l(this,"update",new cs);l(this,"_ngModelWarningSent",!1);this._ngModelWarningConfig=o,this._parent=n,this._setValidators(r),this._setAsyncValidators(s),this.valueAccessor=FR(this,i)}set isDisabled(n){(typeof ngDevMode>"u"||ngDevMode)&&console.warn(gW)}ngOnChanges(n){this._added||this._setUpControl(),RR(n,this.viewModel)&&((typeof ngDevMode>"u"||ngDevMode)&&SW("formControlName",Xc,this,this._ngModelWarningConfig),this.viewModel=this.model,this.formDirective.updateModel(this,this.model))}ngOnDestroy(){this.formDirective&&this.formDirective.removeControl(this)}viewToModelUpdate(n){this.viewModel=n,this.update.emit(n)}get path(){return SD(this.name==null?this.name:this.name.toString(),this._parent)}get formDirective(){return this._parent?this._parent.formDirective:null}_setUpControl(){(typeof ngDevMode>"u"||ngDevMode)&&Iye(this._parent,this.name),this.control=this.formDirective.addControl(this),this._added=!0}};l(Xc,"_ngModelWarningSentOnce",!1),l(Xc,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Xc,deps:[{token:lr,host:!0,optional:!0,skipSelf:!0},{token:er,optional:!0,self:!0},{token:_s,optional:!0,self:!0},{token:Ri,optional:!0,self:!0},{token:Hb,optional:!0}],target:Te.Directive})),l(Xc,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Xc,isStandalone:!1,selector:"[formControlName]",inputs:{name:["formControlName","name"],isDisabled:["disabled","isDisabled"],model:["ngModel","model"]},outputs:{update:"ngModelChange"},providers:[FW],usesInheritance:!0,usesOnChanges:!0,ngImport:k}));var Lp=Xc;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Lp,decorators:[{type:bt,args:[{selector:"[formControlName]",providers:[FW],standalone:!1}]}],ctorParameters:()=>[{type:lr,decorators:[{type:lt},{type:pi},{type:bl}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[er]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[_s]}]},{type:void 0,decorators:[{type:lt},{type:Jn},{type:Ke,args:[Ri]}]},{type:void 0,decorators:[{type:lt},{type:Ke,args:[Hb]}]}],propDecorators:{name:[{type:Ge,args:["formControlName"]}],isDisabled:[{type:Ge,args:["disabled"]}],model:[{type:Ge,args:["ngModel"]}],update:[{type:lm,args:["ngModelChange"]}]}});function Iye(t,e){if(!(t instanceof Ra)&&t instanceof Ap)throw Jve();if(!(t instanceof Ra)&&!(t instanceof Ml)&&!(t instanceof Pl))throw Qve(e)}var LW={provide:Ri,useExisting:vn(()=>Nl),multi:!0};function OW(t,e){return t==null?`${e}`:(e&&typeof e=="object"&&(e="Object"),`${t}: ${e}`.slice(0,50))}function kye(t){return t.split(":")[0]}var vg=class vg extends Na{constructor(){super(...arguments);l(this,"value");l(this,"_optionMap",new Map);l(this,"_idCounter",0);l(this,"_compareWith",Object.is)}set compareWith(n){if(typeof n!="function"&&(typeof ngDevMode>"u"||ngDevMode))throw new ne(1201,`compareWith must be a function, but received ${JSON.stringify(n)}`);this._compareWith=n}writeValue(n){this.value=n;let r=this._getOptionId(n),s=OW(r,n);this.setProperty("value",s)}registerOnChange(n){this.onChange=r=>{this.value=this._getOptionValue(r),n(this.value)}}_registerOption(){return(this._idCounter++).toString()}_getOptionId(n){for(let r of this._optionMap.keys())if(this._compareWith(this._optionMap.get(r),n))return r;return null}_getOptionValue(n){let r=kye(n);return this._optionMap.has(r)?this._optionMap.get(r):n}};l(vg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:vg,deps:null,target:Te.Directive})),l(vg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:vg,isStandalone:!1,selector:"select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]",inputs:{compareWith:"compareWith"},host:{listeners:{change:"onChange($event.target.value)",blur:"onTouched()"}},providers:[LW],usesInheritance:!0,ngImport:k}));var Nl=vg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Nl,decorators:[{type:bt,args:[{selector:"select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]",host:{"(change)":"onChange($event.target.value)","(blur)":"onTouched()"},providers:[LW],standalone:!1}]}],propDecorators:{compareWith:[{type:Ge}]}});var yg=class yg{constructor(e,n,r){l(this,"_element");l(this,"_renderer");l(this,"_select");l(this,"id");this._element=e,this._renderer=n,this._select=r,this._select&&(this.id=this._select._registerOption())}set ngValue(e){this._select!=null&&(this._select._optionMap.set(this.id,e),this._setElementValue(OW(this.id,e)),this._select.writeValue(this._select.value))}set value(e){this._setElementValue(e),this._select&&this._select.writeValue(this._select.value)}_setElementValue(e){this._renderer.setProperty(this._element.nativeElement,"value",e)}ngOnDestroy(){this._select&&(this._select._optionMap.delete(this.id),this._select.writeValue(this._select.value))}};l(yg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:yg,deps:[{token:pn},{token:hr},{token:Nl,host:!0,optional:!0}],target:Te.Directive})),l(yg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:yg,isStandalone:!1,selector:"option",inputs:{ngValue:"ngValue",value:"value"},ngImport:k}));var Bg=yg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Bg,decorators:[{type:bt,args:[{selector:"option",standalone:!1}]}],ctorParameters:()=>[{type:pn},{type:hr},{type:Nl,decorators:[{type:lt},{type:pi}]}],propDecorators:{ngValue:[{type:Ge,args:["ngValue"]}],value:[{type:Ge,args:["value"]}]}});var BW={provide:Ri,useExisting:vn(()=>Rl),multi:!0};function eW(t,e){return t==null?`${e}`:(typeof e=="string"&&(e=`'${e}'`),e&&typeof e=="object"&&(e="Object"),`${t}: ${e}`.slice(0,50))}function Aye(t){return t.split(":")[0]}var bg=class bg extends Na{constructor(){super(...arguments);l(this,"value");l(this,"_optionMap",new Map);l(this,"_idCounter",0);l(this,"_compareWith",Object.is)}set compareWith(n){if(typeof n!="function"&&(typeof ngDevMode>"u"||ngDevMode))throw new ne(1201,`compareWith must be a function, but received ${JSON.stringify(n)}`);this._compareWith=n}writeValue(n){this.value=n;let r;if(Array.isArray(n)){let s=n.map(i=>this._getOptionId(i));r=(i,o)=>{i._setSelected(s.indexOf(o.toString())>-1)}}else r=(s,i)=>{s._setSelected(!1)};this._optionMap.forEach(r)}registerOnChange(n){this.onChange=r=>{let s=[],i=r.selectedOptions;if(i!==void 0){let o=i;for(let a=0;a[{type:pn},{type:hr},{type:Rl,decorators:[{type:lt},{type:pi}]}],propDecorators:{ngValue:[{type:Ge,args:["ngValue"]}],value:[{type:Ge,args:["value"]}]}});function $W(t){return typeof t=="number"?t:parseInt(t,10)}function VW(t){return typeof t=="number"?t:parseFloat(t)}var Eg=class Eg{constructor(){l(this,"_validator",vR);l(this,"_onChange");l(this,"_enabled")}ngOnChanges(e){if(this.inputName in e){let n=this.normalizeInput(e[this.inputName].currentValue);this._enabled=this.enabled(n),this._validator=this._enabled?this.createValidator(n):vR,this._onChange&&this._onChange()}}validate(e){return this._validator(e)}registerOnValidatorChange(e){this._onChange=e}enabled(e){return e!=null}};l(Eg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Eg,deps:[],target:Te.Directive})),l(Eg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Eg,isStandalone:!0,usesOnChanges:!0,ngImport:k}));var Fa=Eg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Fa,decorators:[{type:bt}]});var HW={provide:er,useExisting:vn(()=>Op),multi:!0},xg=class xg extends Fa{constructor(){super(...arguments);l(this,"max");l(this,"inputName","max");l(this,"normalizeInput",n=>VW(n));l(this,"createValidator",n=>Bve(n))}};l(xg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:xg,deps:null,target:Te.Directive})),l(xg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:xg,isStandalone:!1,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:{max:"max"},host:{properties:{"attr.max":"_enabled ? max : null"}},providers:[HW],usesInheritance:!0,ngImport:k}));var Op=xg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Op,decorators:[{type:bt,args:[{selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",providers:[HW],host:{"[attr.max]":"_enabled ? max : null"},standalone:!1}]}],propDecorators:{max:[{type:Ge}]}});var jW={provide:er,useExisting:vn(()=>Bp),multi:!0},Sg=class Sg extends Fa{constructor(){super(...arguments);l(this,"min");l(this,"inputName","min");l(this,"normalizeInput",n=>VW(n));l(this,"createValidator",n=>Ove(n))}};l(Sg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Sg,deps:null,target:Te.Directive})),l(Sg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Sg,isStandalone:!1,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:{min:"min"},host:{properties:{"attr.min":"_enabled ? min : null"}},providers:[jW],usesInheritance:!0,ngImport:k}));var Bp=Sg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Bp,decorators:[{type:bt,args:[{selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",providers:[jW],host:{"[attr.min]":"_enabled ? min : null"},standalone:!1}]}],propDecorators:{min:[{type:Ge}]}});var UW={provide:er,useExisting:vn(()=>eu),multi:!0},qW={provide:er,useExisting:vn(()=>$p),multi:!0},Cg=class Cg extends Fa{constructor(){super(...arguments);l(this,"required");l(this,"inputName","required");l(this,"normalizeInput",Pi);l(this,"createValidator",n=>$ve)}enabled(n){return n}};l(Cg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Cg,deps:null,target:Te.Directive})),l(Cg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Cg,isStandalone:!1,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:{required:"required"},host:{properties:{"attr.required":'_enabled ? "" : null'}},providers:[UW],usesInheritance:!0,ngImport:k}));var eu=Cg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:eu,decorators:[{type:bt,args:[{selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",providers:[UW],host:{"[attr.required]":'_enabled ? "" : null'},standalone:!1}]}],propDecorators:{required:[{type:Ge}]}});var Tg=class Tg extends eu{constructor(){super(...arguments);l(this,"createValidator",n=>Vve)}};l(Tg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Tg,deps:null,target:Te.Directive})),l(Tg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Tg,isStandalone:!1,selector:"input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]",host:{properties:{"attr.required":'_enabled ? "" : null'}},providers:[qW],usesInheritance:!0,ngImport:k}));var $p=Tg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:$p,decorators:[{type:bt,args:[{selector:"input[type=checkbox][required][formControlName],input[type=checkbox][required][formControl],input[type=checkbox][required][ngModel]",providers:[qW],host:{"[attr.required]":'_enabled ? "" : null'},standalone:!1}]}]});var WW={provide:er,useExisting:vn(()=>Vp),multi:!0},Dg=class Dg extends Fa{constructor(){super(...arguments);l(this,"email");l(this,"inputName","email");l(this,"normalizeInput",Pi);l(this,"createValidator",n=>Hve)}enabled(n){return n}};l(Dg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Dg,deps:null,target:Te.Directive})),l(Dg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Dg,isStandalone:!1,selector:"[email][formControlName],[email][formControl],[email][ngModel]",inputs:{email:"email"},providers:[WW],usesInheritance:!0,ngImport:k}));var Vp=Dg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Vp,decorators:[{type:bt,args:[{selector:"[email][formControlName],[email][formControl],[email][ngModel]",providers:[WW],standalone:!1}]}],propDecorators:{email:[{type:Ge}]}});var zW={provide:er,useExisting:vn(()=>Hp),multi:!0},_g=class _g extends Fa{constructor(){super(...arguments);l(this,"minlength");l(this,"inputName","minlength");l(this,"normalizeInput",n=>$W(n));l(this,"createValidator",n=>jve(n))}};l(_g,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:_g,deps:null,target:Te.Directive})),l(_g,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:_g,isStandalone:!1,selector:"[minlength][formControlName],[minlength][formControl],[minlength][ngModel]",inputs:{minlength:"minlength"},host:{properties:{"attr.minlength":"_enabled ? minlength : null"}},providers:[zW],usesInheritance:!0,ngImport:k}));var Hp=_g;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Hp,decorators:[{type:bt,args:[{selector:"[minlength][formControlName],[minlength][formControl],[minlength][ngModel]",providers:[zW],host:{"[attr.minlength]":"_enabled ? minlength : null"},standalone:!1}]}],propDecorators:{minlength:[{type:Ge}]}});var GW={provide:er,useExisting:vn(()=>jp),multi:!0},Ig=class Ig extends Fa{constructor(){super(...arguments);l(this,"maxlength");l(this,"inputName","maxlength");l(this,"normalizeInput",n=>$W(n));l(this,"createValidator",n=>Uve(n))}};l(Ig,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ig,deps:null,target:Te.Directive})),l(Ig,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:Ig,isStandalone:!1,selector:"[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]",inputs:{maxlength:"maxlength"},host:{properties:{"attr.maxlength":"_enabled ? maxlength : null"}},providers:[GW],usesInheritance:!0,ngImport:k}));var jp=Ig;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:jp,decorators:[{type:bt,args:[{selector:"[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]",providers:[GW],host:{"[attr.maxlength]":"_enabled ? maxlength : null"},standalone:!1}]}],propDecorators:{maxlength:[{type:Ge}]}});var ZW={provide:er,useExisting:vn(()=>Up),multi:!0},kg=class kg extends Fa{constructor(){super(...arguments);l(this,"pattern");l(this,"inputName","pattern");l(this,"normalizeInput",n=>n);l(this,"createValidator",n=>qve(n))}};l(kg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:kg,deps:null,target:Te.Directive})),l(kg,"\u0275dir",Ct({minVersion:"14.0.0",version:"19.2.25",type:kg,isStandalone:!1,selector:"[pattern][formControlName],[pattern][formControl],[pattern][ngModel]",inputs:{pattern:"pattern"},host:{properties:{"attr.pattern":"_enabled ? pattern : null"}},providers:[ZW],usesInheritance:!0,ngImport:k}));var Up=kg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Up,decorators:[{type:bt,args:[{selector:"[pattern][formControlName],[pattern][formControl],[pattern][ngModel]",providers:[ZW],host:{"[attr.pattern]":"_enabled ? pattern : null"},standalone:!1}]}],propDecorators:{pattern:[{type:Ge}]}});var tW=[Og,Bg,$g,Kc,Pp,Rp,kp,Nl,Rl,Np,Ng,Rg,eu,Hp,jp,Up,$p,Vp,Bp,Op],nW=[Mp,Al,kl],rW=[Fp,Ml,Lp,Ra,Pl],Qc=class Qc{};l(Qc,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Qc,deps:[],target:Te.NgModule})),l(Qc,"\u0275mod",Vo({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Qc,declarations:[Og,Bg,$g,Kc,Pp,Rp,kp,Nl,Rl,Np,Ng,Rg,eu,Hp,jp,Up,$p,Vp,Bp,Op],exports:[Og,Bg,$g,Kc,Pp,Rp,kp,Nl,Rl,Np,Ng,Rg,eu,Hp,jp,Up,$p,Vp,Bp,Op]})),l(Qc,"\u0275inj",$o({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Qc}));var Fl=Qc;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Fl,decorators:[{type:co,args:[{declarations:tW,exports:tW}]}]});var wR=class extends Fg{constructor(n,r,s){super(AR(r),MR(s,r));l(this,"controls");this.controls=n,this._initObservables(),this._setUpdateStrategy(r),this._setUpControls(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator})}at(n){return this.controls[this._adjustIndex(n)]}push(n,r={}){this.controls.push(n),this._registerControl(n),this.updateValueAndValidity({emitEvent:r.emitEvent}),this._onCollectionChange()}insert(n,r,s={}){this.controls.splice(n,0,r),this._registerControl(r),this.updateValueAndValidity({emitEvent:s.emitEvent})}removeAt(n,r={}){let s=this._adjustIndex(n);s<0&&(s=0),this.controls[s]&&this.controls[s]._registerOnCollectionChange(()=>{}),this.controls.splice(s,1),this.updateValueAndValidity({emitEvent:r.emitEvent})}setControl(n,r,s={}){let i=this._adjustIndex(n);i<0&&(i=0),this.controls[i]&&this.controls[i]._registerOnCollectionChange(()=>{}),this.controls.splice(i,1),r&&(this.controls.splice(i,0,r),this._registerControl(r)),this.updateValueAndValidity({emitEvent:s.emitEvent}),this._onCollectionChange()}get length(){return this.controls.length}setValue(n,r={}){bW(this,!1,n),n.forEach((s,i)=>{yW(this,!1,i),this.at(i).setValue(s,{onlySelf:!0,emitEvent:r.emitEvent})}),this.updateValueAndValidity(r)}patchValue(n,r={}){n!=null&&(n.forEach((s,i)=>{this.at(i)&&this.at(i).patchValue(s,{onlySelf:!0,emitEvent:r.emitEvent})}),this.updateValueAndValidity(r))}reset(n=[],r={}){this._forEachChild((s,i)=>{s.reset(n[i],{onlySelf:!0,emitEvent:r.emitEvent})}),this._updatePristine(r,this),this._updateTouched(r,this),this.updateValueAndValidity(r)}getRawValue(){return this.controls.map(n=>n.getRawValue())}clear(n={}){this.controls.length<1||(this._forEachChild(r=>r._registerOnCollectionChange(()=>{})),this.controls.splice(0),this.updateValueAndValidity({emitEvent:n.emitEvent}))}_adjustIndex(n){return n<0?n+this.length:n}_syncPendingControls(){let n=this.controls.reduce((r,s)=>s._syncPendingControls()?!0:r,!1);return n&&this.updateValueAndValidity({onlySelf:!0}),n}_forEachChild(n){this.controls.forEach((r,s)=>{n(r,s)})}_updateValue(){this.value=this.controls.filter(n=>n.enabled||this.disabled).map(n=>n.value)}_anyControls(n){return this.controls.some(r=>r.enabled&&n(r))}_setUpControls(){this._forEachChild(n=>this._registerControl(n))}_allControlsDisabled(){for(let n of this.controls)if(n.enabled)return!1;return this.controls.length>0||this.disabled}_registerControl(n){n.setParent(this),n._registerOnCollectionChange(this._onCollectionChange)}_find(n){return this.at(n)??null}};function sW(t){return!!t&&(t.asyncValidators!==void 0||t.validators!==void 0||t.updateOn!==void 0)}var Ip=class Ip{constructor(){l(this,"useNonNullable",!1)}get nonNullable(){let e=new Ip;return e.useNonNullable=!0,e}group(e,n=null){let r=this._reduceControls(e),s={};return sW(n)?s=n:n!==null&&(s.validators=n.validator,s.asyncValidators=n.asyncValidator),new Lg(r,s)}record(e,n=null){let r=this._reduceControls(e);return new bR(r,n)}control(e,n,r){let s={};return this.useNonNullable?(sW(n)?s=n:(s.validators=n,s.asyncValidators=r),new Fb(e,{...s,nonNullable:!0})):new Fb(e,n,r)}array(e,n,r){let s=e.map(i=>this._createControl(i));return new wR(s,n,r)}_reduceControls(e){let n={};return Object.keys(e).forEach(r=>{n[r]=this._createControl(e[r])}),n}_createControl(e){if(e instanceof Fb)return e;if(e instanceof Fg)return e;if(Array.isArray(e)){let n=e[0],r=e.length>1?e[1]:null,s=e.length>2?e[2]:null;return this.control(n,r,s)}else return this.control(e)}};l(Ip,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ip,deps:[],target:Te.Injectable})),l(Ip,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ip,providedIn:"root"}));var Vg=Ip;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Vg,decorators:[{type:St,args:[{providedIn:"root"}]}]});var Ag=class Ag{};l(Ag,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ag,deps:[],target:Te.Injectable})),l(Ag,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Ag,providedIn:"root",useFactory:()=>fe(Vg).nonNullable}));var ER=Ag;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:ER,decorators:[{type:St,args:[{providedIn:"root",useFactory:()=>fe(Vg).nonNullable}]}]});var Mg=class Mg extends Vg{group(e,n=null){return super.group(e,n)}control(e,n,r){return super.control(e,n,r)}array(e,n,r){return super.array(e,n,r)}};l(Mg,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Mg,deps:null,target:Te.Injectable})),l(Mg,"\u0275prov",an({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Mg,providedIn:"root"}));var xR=Mg;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:xR,decorators:[{type:St,args:[{providedIn:"root"}]}]});var tSe=new Ea("19.2.25"),_l=class _l{static withConfig(e){return{ngModule:_l,providers:[{provide:Go,useValue:e.callSetDisabledState??Vb}]}}};l(_l,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:_l,deps:[],target:Te.NgModule})),l(_l,"\u0275mod",Vo({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:_l,declarations:[Mp,Al,kl],exports:[Fl,Mp,Al,kl]})),l(_l,"\u0275inj",$o({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:_l,imports:[Fl]}));var hs=_l;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:hs,decorators:[{type:co,args:[{declarations:nW,exports:[Fl,nW]}]}]});var Il=class Il{static withConfig(e){return{ngModule:Il,providers:[{provide:Hb,useValue:e.warnOnNgModelWithFormControl??"always"},{provide:Go,useValue:e.callSetDisabledState??Vb}]}}};l(Il,"\u0275fac",ke({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Il,deps:[],target:Te.NgModule})),l(Il,"\u0275mod",Vo({minVersion:"14.0.0",version:"19.2.25",ngImport:k,type:Il,declarations:[Fp,Ml,Lp,Ra,Pl],exports:[Fl,Fp,Ml,Lp,Ra,Pl]})),l(Il,"\u0275inj",$o({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:Il,imports:[Fl]}));var SR=Il;Ie({minVersion:"12.0.0",version:"19.2.25",ngImport:k,type:SR,decorators:[{type:co,args:[{declarations:[rW],exports:[Fl,rW]}]}]});var It=(()=>{let t=typeof location<"u"?location.pathname:"/",e=typeof location<"u"?location.search.replace(/^\?/,""):"",n={},r=e,s=null,i=null,o=!1,a=[{state:null,url:t+(e?`?${e}`:"")}];function c(){let m=new URLSearchParams(r),g={};m.has("track")&&(g.track=m.get("track")),m.has("map")&&(g.map=m.get("map")),m.has("xaxis")&&(g.xaxis=m.get("xaxis")),m.has("tab")&&(g.tab=m.get("tab")),m.has("sel_point")&&(g.sel_point=Number(m.get("sel_point"))),m.has("speed_mode")&&(g.speed_mode=m.get("speed_mode")),m.has("progress")&&(g.progress=m.get("progress"));let v=m.get("metrics");if(v&&(g.metrics=v.split(",").filter(Boolean)),m.has("f_date")&&(g.f_date=m.get("f_date").split(",").map(w=>w||null)),m.has("f_dist")&&(g.f_dist=m.get("f_dist").split(",").map(w=>w?Number(w):null)),m.has("f_dur")&&(g.f_dur=m.get("f_dur").split(",").map(w=>w?Number(w):null)),m.has("f_mets")&&(g.f_mets=m.get("f_mets").split(",")),m.has("f_tags")&&(g.f_tags=m.get("f_tags").split(",")),m.has("q")&&(g.q=m.get("q")),m.has("re")&&(g.re=m.get("re")==="1"),m.has("sort")){let w=m.get("sort"),b=w.startsWith("-"),D=b?w.substring(1):w;g.sort=`${D}-${b?"desc":"asc"}`}if(m.has("map_pos")){let w=m.get("map_pos").split(",").map(Number);w.length===3&&w.every(isFinite)&&(g.map_pos=w)}if(m.has("storage")&&(g.storage=m.get("storage")),m.has("sel")){let w=m.get("sel").split(",").map(Number);w.length===2&&w.every(b=>!isNaN(b)&&isFinite(b))&&(g.sel=w)}return g}function u(){i&&(clearTimeout(i),i=null);let m=new URLSearchParams;if(n.track&&m.set("track",n.track),n.map&&m.set("map",n.map),n.xaxis&&n.xaxis!=="time"&&m.set("xaxis",n.xaxis),n.tab&&n.tab!=="graphs"&&m.set("tab",n.tab),n.storage&&n.storage!=="memory"&&m.set("storage",n.storage),n.sel_point!==void 0&&m.set("sel_point",String(n.sel_point)),n.speed_mode&&m.set("speed_mode",n.speed_mode),n.q&&m.set("q",n.q),n.progress&&m.set("progress",n.progress),n.re&&m.set("re","1"),n.sort){let v=n.sort.split("-"),w=v[0],b=v[1];m.set("sort",(b==="desc"?"-":"")+w)}let g=m.toString();if(n.metrics&&(g+=`${g?"&":""}metrics=${n.metrics.join(",")}`),n.f_date&&(g+=`${g?"&":""}f_date=${n.f_date.map(v=>v||"").join(",")}`),n.f_dist&&(g+=`${g?"&":""}f_dist=${n.f_dist.map(v=>v??"").join(",")}`),n.f_dur&&(g+=`${g?"&":""}f_dur=${n.f_dur.map(v=>v??"").join(",")}`),n.f_mets&&(g+=`${g?"&":""}f_mets=${n.f_mets.join(",")}`),n.f_tags&&(g+=`${g?"&":""}f_tags=${n.f_tags.join(",")}`),n.map_pos){let v=`${(+n.map_pos[0]).toFixed(5)},${(+n.map_pos[1]).toFixed(5)},${n.map_pos[2]}`;g+=`${g?"&":""}map_pos=${v}`}if(n.sel){let v=`${+n.sel[0].toFixed(4)},${+n.sel[1].toFixed(4)}`;g+=`${g?"&":""}sel=${v}`}if(r=g,g!==s){let w=(typeof location<"u"?location.pathname:"/")+(g?`?${g}`:""),b=c();o?(a.push({state:b,url:w}),a.length>100&&a.shift(),o=!1):a.length>0?a[a.length-1]={state:b,url:w}:a.push({state:b,url:w}),s=g}}n=c();function d(){return{...n}}function p(m,g=!1){g&&(o=!0);for(let[v,w]of Object.entries(m)){let b=v;w==null?delete n[b]:n[b]=w}u()}function f(){n=c()}function h(){i&&(clearTimeout(i),i=null),n={},o=!1,r="",s="",a=[{state:null,url:typeof location<"u"?location.pathname:"/"}]}return{read:c,get:d,patch:p,refresh:f,reset:h}})();var CD=class{constructor(){this.trackStore=new Map;this.settingStore=new Map}async openDB(){return Promise.resolve()}async save(e){return this.trackStore.set(e.id,e),Promise.resolve()}async getAll(){return Promise.resolve(Array.from(this.trackStore.values()))}async remove(e){return this.trackStore.delete(e),Promise.resolve()}async clear(){return this.trackStore.clear(),this.settingStore.clear(),Promise.resolve()}async set(e,n){return this.settingStore.set(e,n),Promise.resolve()}async get(e){return Promise.resolve(this.settingStore.get(e)??null)}},LR=class{constructor(){this.db=null;this.DB_NAME="weg-gps-db";this.DB_VERSION=2}async openDB(){return new Promise((e,n)=>{let r=indexedDB.open(this.DB_NAME,this.DB_VERSION);r.onupgradeneeded=()=>{let s=r.result;s.objectStoreNames.contains("tracks")||s.createObjectStore("tracks",{keyPath:"id"}),s.objectStoreNames.contains("settings")||s.createObjectStore("settings")},r.onsuccess=()=>{this.db=r.result,e()},r.onerror=()=>n(r.error)})}getStore(e,n){if(!this.db)throw new Error("IndexedDB not opened");return this.db.transaction(e,n).objectStore(e)}async save(e){return new Promise((n,r)=>{let s=this.getStore("tracks","readwrite").put(e);s.onsuccess=()=>n(),s.onerror=()=>r(s.error)})}async getAll(){return new Promise((e,n)=>{let r=this.getStore("tracks","readonly").getAll();r.onsuccess=()=>e(r.result||[]),r.onerror=()=>n(r.error)})}async remove(e){return new Promise((n,r)=>{let s=this.getStore("tracks","readwrite").delete(e);s.onsuccess=()=>n(),s.onerror=()=>r(s.error)})}async clear(){return this.db?new Promise((e,n)=>{let r=this.db.transaction(["tracks","settings"],"readwrite");r.objectStore("tracks").clear(),r.objectStore("settings").clear(),r.oncomplete=()=>e(),r.onerror=()=>n(r.error)}):Promise.resolve()}async set(e,n){return new Promise((r,s)=>{let i=this.getStore("settings","readwrite").put(n,e);i.onsuccess=()=>r(),i.onerror=()=>s(i.error)})}async get(e){return new Promise((n,r)=>{let s=this.getStore("settings","readonly").get(e);s.onsuccess=()=>n(s.result??null),s.onerror=()=>r(s.error)})}},tu=new CD,tr={openDB:async()=>{tu=It.get().storage==="indexeddb"?new LR:new CD,await tu.openDB()},save:t=>tu.save(t),getAll:()=>tu.getAll(),remove:t=>tu.remove(t),clear:()=>tu.clear(),set:(t,e)=>tu.set(t,e),get:t=>tu.get(t)};var st=(()=>{let t={},e=null;function n(U,ee,xe,Ze,N){}function r(U){}function s(U){t[U.id]=U}function i(U){U.forEach(ee=>{t[ee.id]=ee})}function o(U){delete t[U]}function a(){t={}}function c(){t={}}function u(U,ee){}function d(U,ee){}function p(){}function f(U){}function h(U,ee){}function m(){}function g(U,ee,xe,Ze,N,A){}function v(){}function w(U,ee){}function b(U){}function D(U,ee,xe,Ze){}function B(){}function M(){}function $(){return[0,0,0]}function j(U,ee,xe){}function G(U,ee,xe){}function Se(U){}function pe(U,ee){return Object.keys(t)}return{init:n,getMap:()=>null,setCustomClickHandler:U=>{e=U},switchBasemap:r,addTrack:s,addTracks:i,removeTrack:o,clearTracks:a,removeAllTracks:c,setTrackVisible:u,setSelectedTrack:d,fitAll:p,fitTrack:f,showCursorAt:h,hideCursor:m,highlightSegment:g,clearHighlight:v,setTrackHover:w,ensureVisible:b,centerOn:D,closePopup:B,invalidateSize:M,getPosition:$,setPosition:j,colorTrackByMetric:G,clearMetricColor:Se,findTracksPassingThroughPoints:pe,getTrackData:U=>t[U]}})();import ez from"uplot";function Ll(t,e,n,r){let i=t*Math.PI/180,o=n*Math.PI/180,a=(n-t)*Math.PI/180,c=(r-e)*Math.PI/180,u=Math.sin(a/2)*Math.sin(a/2)+Math.cos(i)*Math.cos(o)*Math.sin(c/2)*Math.sin(c/2);return 6371e3*(2*Math.atan2(Math.sqrt(u),Math.sqrt(1-u)))}function YW(t){let e=new Uint32Array([Math.floor(t/1e3)]);return btoa(String.fromCharCode(...new Uint8Array(e.buffer))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function XW(){return Math.random().toString(36).slice(2,6)}function Hr(t){return t<60?`${Math.round(t)}s`:t<3600?`${Math.round(t/60)}m`:`${Math.round(t/3600)}h`}function Nn(t){let e=Math.floor(t/3600),n=Math.floor(t%3600/60);return e>0?`${e}h ${n}m`:`${n}m ${Math.floor(t%60)}s`}function qp(t){if(t==null||!isFinite(t))return"--";let e=Math.floor(t/60),n=Math.round(t%60);return`${e}:${n.toString().padStart(2,"0")}`}function Zo(t){let e=new Date(t);return isNaN(e.getTime())?"Unknown date":e.toISOString().split("T")[0]}function QW(t){let e=new Date(t);if(isNaN(e.getTime()))return"Unknown";let n=e.toISOString();return`${n.split("T")[0]} ${n.split("T")[1].slice(0,5)}`}function KW(t){if(t===0)return"0 B";let e=1024,n=["B","KB","MB","GB"],r=Math.floor(Math.log(t)/Math.log(e));return`${parseFloat((t/Math.pow(e,r)).toFixed(2))} ${n[r]}`}function TD(t){let e=0;for(let r=0;r=0&&p0?c/u:t[a]}return o}function en(t,e=1){let n=parseInt(t.slice(1,3),16),r=parseInt(t.slice(3,5),16),s=parseInt(t.slice(5,7),16);return`rgba(${n}, ${r}, ${s}, ${e})`}import Mye from"fit-file-parser";function OR(t){if(!t.length)return null;let e=t[0].lat,n=t[0].lat,r=t[0].lon,s=t[0].lon;for(let i of t)i.latn&&(n=i.lat),i.lons&&(s=i.lon);return{minLat:e,maxLat:n,minLon:r,maxLon:s}}var hi=16384,Pye=new Float64Array(hi),Nye=new Float64Array(hi),Rye=new Float64Array(hi),Fye=new Float64Array(hi),Lye=new Float64Array(hi),Oye=new Float64Array(hi),Bye=new Float64Array(hi);function BR(t,e){let n=t.length;if(n<=2)return t;let r=n<=hi?Pye:new Float64Array(n),s=n<=hi?Nye:new Float64Array(n),i=n<=hi?Rye:new Float64Array(n),o=n<=hi?Fye:new Float64Array(n);for(let h=0;h=m){let $=g+v>>1,j=(s[$]-(s[g]+s[v])*.5)*w,G=r[$]-(r[g]+r[v])*.5;c+=Math.sqrt(j*j+G*G)+(o[v]-o[g])*1e-6,g=v}}}let d=[t[0]],p=t[0],f=c<-1e9?1e-9:0;for(let h=1;h=e&&(d.push(m),p=m)}return d.push(t[n-1]),d}var ln=(()=>{function t(N){let A=N.length,S=0;for(let x=0;x0){let I=N[x-1],F=Ll(I.lat,I.lon,C.lat,C.lon);if(S+=F,C.speed==null&&C.time!=null&&I.time!=null){let J=(C.time-I.time)/1e3;J>0&&J<10&&(C.speed=F/J)}if(C.gradient===void 0&&C.ele!=null&&I.ele!=null){let J=C.ele-I.ele;F>.5?C.gradient=J/F*100:C.gradient=I.gradient||0}}C.dist=S}if(A>2){let x=A<=hi?Lye:new Float64Array(A),C=A<=hi?Oye:new Float64Array(A),I=A<=hi?Bye:new Float64Array(A);for(let ae=0;ae=Ae){V-=C[L-Ae],z-=I[L-Ae];let q=V*ie,H=x[L]-x[L-Ae],le=1.225*Math.exp(-x[L]*oe),K=Math.atan2(H,(z+1)*.5);J+=q*q*le*1e-4+K*(z*ie)*.01}}let we=J<-1e12?1e-9:0;for(let ae=1;ae0){let De=N[Ce-1];if(he.ele!=null&&De.ele!=null){let Ne=he.ele-De.ele;Ne>0?S.elevGain+=Ne:S.elevLoss-=Ne}(he.gearFront!=null&&he.gearFront!==De.gearFront||he.gearRear!=null&&he.gearRear!==De.gearRear)&&q++}he.power!=null&&(x+=he.power,C++,he.power>S.maxPower&&(S.maxPower=he.power)),he.hr!=null&&(I+=he.hr,F++,he.hr>S.maxHR&&(S.maxHR=he.hr)),he.cad!=null&&(J+=he.cad,oe++),he.speed!=null&&(we+=he.speed,ae++,he.speed>S.maxSpeed&&(S.maxSpeed=he.speed)),he.battery!=null&&(Ae+=he.battery,ie++),he.temp!=null&&(L=!0,V+=he.temp,z++,(S.minTemp==null||he.tempS.maxTemp)&&(S.maxTemp=he.temp)),(he.gearFront!=null||he.gearRear!=null)&&(H=!0)}S.totalDist=N[N.length-1].dist||0,S.avgPower=C?Math.round(x/C):null,S.avgHR=F?Math.round(I/F):null,S.avgCadence=oe?Math.round(J/oe):null,S.avgSpeed=ae?we/ae:null,S.avgBattery=ie?Math.round(Ae/ie):null,S.avgTemp=z?Number((V/z).toFixed(1)):null,S.shifts=H?q:null;let le=N[0].time,K=N[N.length-1].time;return le!=null&&K!=null&&(S.duration=K-le),F&&(S.sensors.push("Heart Rate"),A&&(S.hrZones=m(N),S.hrCurve=d(N))),oe&&S.sensors.push("Cadence"),C&&(S.sensors.push("Power"),A&&(S.powerCurve=u(N),S.powerZones=p(N))),L&&S.sensors.push("Temperature"),H&&S.sensors.push("Shifting"),ie&&S.sensors.push("Battery"),S}function s(N){if(!N||!N.points||!N.stats)return;let A=N.points,S=N.stats;S.avgHR!=null&&!S.hrCurve&&(S.hrZones=m(A),S.hrCurve=d(A)),S.avgPower!=null&&!S.powerCurve&&(S.powerCurve=u(A),S.powerZones=p(A))}function i(N){let A=N.length;if(A<8)return[];let S=[],x=["Q1 Opening Sector","Q2 Mid-Climb Sector","Q3 Valley Tempo","Q4 Finale Sector"];for(let q=0;q<4;q++){let H=Math.floor(q*A/4),le=Math.min(A-1,Math.floor((q+1)*A/4)-1);if(le>H){let K=N.slice(H,le+1);S.push({id:`q${q+1}`,label:x[q],kind:"quarter",startIdx:H,endIdx:le,stats:r(K,!0)})}}let C=["Opening Third","Middle Third","Final Third"];for(let q=0;q<3;q++){let H=Math.floor(q*A/3),le=Math.min(A-1,Math.floor((q+1)*A/3)-1);if(le>H){let K=N.slice(H,le+1);S.push({id:`t${q+1}`,label:C[q],kind:"third",startIdx:H,endIdx:le,stats:r(K,!1)})}}let I=0,F=1e3,J=1;for(let q=1;q=F||q===A-1){if(q>I+2){let le=N.slice(I,q+1);S.push({id:`km-${J}`,label:`Km ${J}`,kind:"km",startIdx:I,endIdx:q,stats:r(le,!1)}),J++}I=q,F+=1e3}let oe=30,we=!1,ae=0,Ae=1,ie=!1,V=0,z=1,L=n*1.15;for(let q=oe;q=1.8&&!we)we=!0,ae=q-oe;else if((K<.8||q===A-1)&&we&&(we=!1,q-ae>=45&&Ae<=6)){let he=N.slice(ae,q+1);S.push({id:`climb-${Ae}`,label:`Climb Segment ${Ae}`,kind:"climb",startIdx:ae,endIdx:q,stats:r(he,!0)}),Ae++}let Ce=N[q].power??0;if(Ce>=L&&!ie)ie=!0,V=q;else if((Ce=15&&z<=6)){let he=N.slice(V,q+1);S.push({id:`sprint-${z}`,label:`Sprint Interval ${z}`,kind:"sprint",startIdx:V,endIdx:q,stats:r(he,!0)}),z++}}return S}function o(N){let A=[];for(let S=0;SS)continue;let oe=0,we=0,ae=S-J;for(let Ae=0;Ae<=ae;Ae++){let ie=x[Ae+J]-x[Ae];ie>oe&&(oe=ie,we=Ae)}C[J]={val:Math.round(oe/J),idx:we},I=!0}return I?C:null}function u(N){let A=N.length,S=new Array(A),x=!1;for(let F=0;Fx*n);for(let x=1;x10)continue;let J=C.power;Jx===0)?null:A}function f(N){n=N}function h(){return n}function m(N){let A=[0,0,0,0,0];for(let S=1;S10)continue;let F=x.hr;FS===0)?null:A}function g(N){e=N}function v(){return[...e]}function w(N,A,S){let x=N.indexOf(A);if(x===-1)return null;let C=x+A.length,I=N.indexOf(S,C);if(I===-1)return null;let F=N.slice(C,I).trim();return F!==""?F:null}function b(N,A){let S=N.indexOf(A);if(S===-1)return null;let x=S+A.length,C=N.indexOf('"',x);return C===-1?null:N.slice(x,C)}let D=-1,B=0;function M(N,A,S){for(;AA&&N.charCodeAt(S-1)<=32;)S--;if(A>=S)return null;let x=!1,C=N.charCodeAt(A);C===45?(x=!0,A++):C===43&&A++;let I=0,F=0;for(let J=A;J=48&&oe<=57)I=I*10+(oe-48),F++;else break}return F===0?null:x?-I:I}function $(N,A,S){for(;AA&&N.charCodeAt(S-1)<=32;)S--;if(A>=S)return null;let x=!1,C=N.charCodeAt(A);C===45?(x=!0,A++):C===43&&A++;let I=0,F=0,J=1,oe=!1,we=0;for(let Ae=A;Ae=48&&ie<=57)we++,oe?(F=F*10+(ie-48),J*=10):I=I*10+(ie-48);else if(ie===46&&!oe)oe=!0;else{let V=parseFloat(N.slice(A-(x?1:0),S));return Number.isFinite(V)?V:null}}if(we===0)return null;let ae=I+F/J;return x?-ae:ae}function j(N,A,S){for(;AA&&N.charCodeAt(S-1)<=32;)S--;let x=S-A;if(x>=20&&N.charCodeAt(A+10)===84&&N.charCodeAt(S-1)===90){let I=(N.charCodeAt(A)-48)*1e3+(N.charCodeAt(A+1)-48)*100+(N.charCodeAt(A+2)-48)*10+(N.charCodeAt(A+3)-48),F=(N.charCodeAt(A+5)-48)*10+(N.charCodeAt(A+6)-48),J=(N.charCodeAt(A+8)-48)*10+(N.charCodeAt(A+9)-48),oe=I<<9|F<<5|J;oe!==D&&(D=oe,B=Date.UTC(I,F-1,J));let we=(N.charCodeAt(A+11)-48)*10+(N.charCodeAt(A+12)-48),ae=(N.charCodeAt(A+14)-48)*10+(N.charCodeAt(A+15)-48),Ae=(N.charCodeAt(A+17)-48)*10+(N.charCodeAt(A+18)-48),ie=0;return N.charCodeAt(A+19)===46&&x>=24&&(ie=(N.charCodeAt(A+20)-48)*100+(N.charCodeAt(A+21)-48)*10+(N.charCodeAt(A+22)-48)),B+we*36e5+ae*6e4+Ae*1e3+ie}let C=new Date(N.slice(A,S)).getTime();return Number.isFinite(C)?C:null}function G(N,A,S,x){let C=N.indexOf(x,A);if(C===-1||C>=S)return 0;let I=C+x.length,F=N.indexOf('"',I);return F===-1||F>=S?0:$(N,I,F)??0}function Se(N,A){let S=A??new TextDecoder().decode(N),x=S.indexOf(""),F=(I!==-1?w(C.slice(I),"",""):null)||w(C,"","")||"Unnamed Track",J=C.indexOf(">",C.indexOf("",V+6);if(z===-1)break;let L=S.indexOf("",z+1);if(L===-1)break;ae=L+8;let q=G(S,V+6,z+1,'lat="'),H=G(S,V+6,z+1,'lon="'),le=null,K=null,Ce=null,he=null,De=null,Ne=null,et=null,Pt=null,$t=null,me=null,Ue=null,nn=null,kt=z+1;for(;kt=L)break;let ot=S.indexOf(">",ft+1);if(ot===-1||ot>=L)break;let ht=S.charCodeAt(ft+1);if(ht===47){kt=ot+1;continue}let at=ot-ft-1;if(ht===103&&at===26&&Ce!==null&&he!==null&&Ne!==null)break;let Tt=S.indexOf("<",ot+1);if(Tt===-1||Tt>L)break;if(S.charCodeAt(Tt+1)===47){let Ft=ot+1,Zt=Tt;at===3?ht===101?le=$(S,Ft,Zt):ht===99&&he===null&&(he=M(S,Ft,Zt)):at===2?ht===104&&Ce===null&&(Ce=M(S,Ft,Zt)):at===4?ht===116?S.charCodeAt(ft+2)===105?K=j(S,Ft,Zt):Ne===null&&(Ne=$(S,Ft,Zt)):ht===84&&Ne===null&&(Ne=$(S,Ft,Zt)):at===5?(ht===112||ht===80||ht===87)&&De===null?De=$(S,Ft,Zt):(ht===115||ht===83)&&et===null?et=$(S,Ft,Zt):ht===97&&Ne===null&&(Ne=$(S,Ft,Zt)):at===7?(ht===98||ht===66)&&nn===null?nn=M(S,Ft,Zt):ht===67&&he===null&&(he=M(S,Ft,Zt)):at===8?(ht===103||ht===71)&&$t===null&&($t=M(S,Ft,Zt)):at===9?ht===103?S.charCodeAt(ft+8)===104&&Ce===null?Ce=M(S,Ft,Zt):Pt===null&&(Pt=M(S,Ft,Zt)):ht===71&&Pt===null&&(Pt=M(S,Ft,Zt)):at===10?(ht===103&&he===null||ht===82&&he===null)&&(he=M(S,Ft,Zt)):at===12?ht===103&&S.charCodeAt(ft+8)===97&&Ne===null?Ne=$(S,Ft,Zt):ht===80&&De===null?De=$(S,Ft,Zt):ht===72&&Ce===null&&(Ce=M(S,Ft,Zt)):at===13?(ht===103||ht===71)&&Ue===null&&(Ue=M(S,Ft,Zt)):at===14?(ht===103||ht===71)&&me===null?me=M(S,Ft,Zt):ht===65&&Ne===null&&(Ne=$(S,Ft,Zt)):at===11&&ht===84&&Ne===null&&(Ne=$(S,Ft,Zt));let Un=Tt+2+at;if(S.charCodeAt(Un)===62)kt=Un+1;else{let Ar=S.indexOf(">",Tt+2);kt=Ar!==-1?Ar+1:Tt+2}if(nn!==null&&Ce!==null&&he!==null&&Ne!==null)break}else kt=Tt}let cn=null;me!=null&&Ue!=null&&Ue!==0?cn=me/Ue:Pt!=null&&$t!=null&&$t!==0&&(cn=Pt/$t),we.push({lat:q,lon:H,ele:le,time:K,hr:Ce,cad:he,power:De,speed:et,temp:Ne,gearFront:Pt,gearRear:$t,gearFrontTooth:me,gearRearTooth:Ue,battery:nn,gears:cn})}if(!we.length)throw new Error("No track points found in GPX");let Ae=t(we),ie=r(Ae);return{name:F,device:oe,format:"gpx",points:Ae,stats:ie}}function pe(N,A){let S=A??new TextDecoder().decode(N),x=S.indexOf(""),C=x!==-1?S.slice(0,x):S,I=w(C,"","")||"Unnamed TCX",F=w(C,"",""),J=F?w(F,"",""):null,oe=[],we=x!==-1?x:0;for(;we",we);if(ie===-1)break;let V=S.indexOf("",ie+12);if(V===-1)break;we=V+13;let z=null,L=null,q=null,H=null,le=null,K=null,Ce=null,he=null,De=null,Ne=null,et=null,Pt=null,$t=null,me=null,Ue=ie+12;for(;Ue=V)break;let cn=S.indexOf(">",kt+1);if(cn===-1||cn>=V)break;let ft=S.charCodeAt(kt+1);if(ft===47){Ue=cn+1;continue}let ot=cn-kt-1,ht=S.indexOf("<",cn+1);if(ht===-1||ht>V)break;if(S.charCodeAt(ht+1)===47){let at=cn+1,Tt=ht;ot===4?ft===84?S.charCodeAt(kt+2)===105?H=j(S,at,Tt):De===null&&(De=$(S,at,Tt)):ft===116&&De===null&&(De=$(S,at,Tt)):ot===5?ft===86&&le===null?le=M(S,at,Tt):(ft===87||ft===80||ft===112)&&Ce===null?Ce=$(S,at,Tt):(ft===83||ft===115)&&he===null?he=$(S,at,Tt):ft===97&&De===null&&(De=$(S,at,Tt)):ot===7?ft===67&&K===null?K=M(S,at,Tt):(ft===66||ft===98)&&me===null&&(me=M(S,at,Tt)):ot===8?(ft===71||ft===103)&&et===null&&(et=M(S,at,Tt)):ot===9?(ft===71||ft===103)&&Ne===null&&(Ne=M(S,at,Tt)):ot===10?ft===82&&K===null&&(K=M(S,at,Tt)):ot===11?ft===84&&De===null&&(De=$(S,at,Tt)):ot===13?(ft===71||ft===103)&&$t===null&&($t=M(S,at,Tt)):ot===14?ft===65?S.charCodeAt(kt+2)===108?q=$(S,at,Tt):De===null&&(De=$(S,at,Tt)):(ft===71||ft===103)&&Pt===null&&(Pt=M(S,at,Tt)):ot===15?ft===76&&(z=$(S,at,Tt)):ot===16?ft===76&&(L=$(S,at,Tt)):ot===2&&ft===104&&le===null?le=M(S,at,Tt):ot===3&&ft===99&&K===null?K=M(S,at,Tt):ot===12&&(ft===72&&le===null?le=M(S,at,Tt):ft===80&&Ce===null&&(Ce=$(S,at,Tt)));let Ft=ht+2+ot;if(S.charCodeAt(Ft)===62)Ue=Ft+1;else{let Zt=S.indexOf(">",ht+2);Ue=Zt!==-1?Zt+1:ht+2}if(me!==null&&le!==null&&K!==null&&De!==null)break}else Ue=ht}if(z==null||L==null)continue;let nn=null;Pt!=null&&$t!=null&&$t!==0?nn=Pt/$t:Ne!=null&&et!=null&&et!==0&&(nn=Ne/et),oe.push({lat:z,lon:L,ele:q,time:H,hr:le,cad:K,power:Ce,speed:he,temp:De,gearFront:Ne,gearRear:et,gearFrontTooth:Pt,gearRearTooth:$t,battery:me,gears:nn})}let ae=t(oe),Ae=r(ae);return{name:I,device:J,format:"tcx",points:ae,stats:Ae}}function U(N){if(N.byteLength<14)return null;let A=new DataView(N),S=A.getUint8(0);if(S<12||S+2>N.byteLength||A.getUint8(8)!==46||A.getUint8(9)!==70||A.getUint8(10)!==73||A.getUint8(11)!==84)return null;let x=A.getUint32(4,!0),C=Math.min(N.byteLength,S+x),I=631065600,F=180/Math.pow(2,31),J=new Array(16),oe=[],we=[],ae=[],Ae=[],ie=[],V=S;for(;VC)return null;V++;let H=A.getUint8(V++)===0,le=A.getUint16(V,H);V+=2;let K=A.getUint8(V++);if(V+K*3>C)return null;let Ce=new Array(K),he=0;for(let De=0;DeC)return null;let H=q.littleEndian,le=q.globalMsgNum;if(le===20&&q.fields.length===10&&q.recordSize===25&&q.fields[0].num===253&&q.fields[1].num===0){let he=A.getUint32(V,H),De=A.getInt32(V+4,H),Ne=A.getInt32(V+8,H),et=A.getUint16(V+12,H),Pt=A.getUint8(V+14),$t=A.getUint8(V+15),me=A.getUint32(V+16,H),Ue=A.getUint16(V+20,H),nn=A.getUint16(V+22,H),kt=A.getInt8(V+24);ae.push({timestamp:(he+I)*1e3,position_lat:De*F,position_long:Ne*F,altitude:et/5-500,heart_rate:Pt,cadence:$t,distance:me/100,speed:Ue/1e3*3.6,power:nn,temperature:kt}),V+=25;continue}let K={},Ce=V;for(let he=0;he{let x=(F,J)=>{if(F){S(F);return}try{let oe=J.sessions?.[0]?.start_time?`Fit Activity ${new Date(J.sessions[0].start_time).toISOString().split("T")[0]}`:"Unnamed Fit",we=null,ae=[],Ae=null,ie=null;J.sports?.[0]?(Ae=J.sports[0].sport,ie=J.sports[0].sub_sport):J.sessions?.[0]&&(Ae=J.sessions[0].sport,ie=J.sessions[0].sub_sport);let V=me=>me.product_name||me.garmin_product||me.product||me.device_type||me.manufacturer||null;if(J.file_ids?.[0]){let me=J.file_ids[0];we=V(me),ae.push({name:me.product_name||me.garmin_product||me.product,manufacturer:me.manufacturer,serial:me.serial_number?String(me.serial_number):void 0,version:me.software_version?String(me.software_version):void 0,type:"main"})}J.device_infos&&J.device_infos.forEach(me=>{if(me.device_index==="creator"||me.device_index===0){let nn=V(me);(me.product_name||me.garmin_product||!we)&&(we=nn),ae.length>0&&ae[0].type==="main"&&((me.product_name||me.garmin_product||!ae[0].name)&&(ae[0].name=me.product_name||me.garmin_product||me.product),ae[0].manufacturer||(ae[0].manufacturer=me.manufacturer),!ae[0].serial&&me.serial_number&&(ae[0].serial=String(me.serial_number)),!ae[0].version&&me.software_version&&(ae[0].version=String(me.software_version)),!ae[0].hardwareVersion&&me.hardware_version&&(ae[0].hardwareVersion=String(me.hardware_version)));return}ae.push({name:me.product_name||me.garmin_product||me.product||me.device_type||"Sensor",manufacturer:me.manufacturer,serial:me.serial_number?String(me.serial_number):void 0,version:me.software_version?String(me.software_version):void 0,hardwareVersion:me.hardware_version?String(me.hardware_version):void 0,type:me.device_type||"sensor",batteryStatus:me.battery_status,batteryVoltage:me.battery_voltage,batteryLevel:me.battery_level,sourceType:me.source_type!=null?String(me.source_type):void 0})}),J.sensor_settings&&J.sensor_settings.forEach(me=>{let Ue=me.name||me.product||me.sensor_type;if(!Ue)return;let nn=me.ant_id?String(me.ant_id):void 0,kt=ae.find(cn=>nn&&cn.serial===nn||cn.name===Ue&&cn.manufacturer===me.manufacturer);kt?(kt.name||(kt.name=Ue),kt.manufacturer||(kt.manufacturer=me.manufacturer),kt.type||(kt.type=me.sensor_type),kt.sourceType||(kt.sourceType=me.connection_type!=null?String(me.connection_type):void 0)):ae.push({name:Ue,manufacturer:me.manufacturer,serial:nn,type:me.sensor_type||"sensor",sourceType:me.connection_type!=null?String(me.connection_type):void 0})});let z=[];J.device_statuses&&(J.device_statuses.forEach((me,Ue)=>{me.timestamp&&me.battery_level!=null&&z.push({time:typeof me.timestamp=="number"?me.timestamp:new Date(me.timestamp).getTime(),level:me.battery_level,idx:Ue})}),z.sort((me,Ue)=>me.time-Ue.time||me.idx-Ue.idx));let L=[];J.events&&(J.events.forEach((me,Ue)=>{let nn=me.front_gear_num??me.front_gear??null,kt=me.rear_gear_num??me.rear_gear??null,cn=me.front_gear_num_tooth??null,ft=me.rear_gear_num_tooth??null;if(me.event==="rear_gear_change"||me.event==="front_gear_change"){let ot=me.data;if(ot!=null){let ht=ot>>24&255,at=ot>>16&255,Tt=ot>>8&255,Ft=ot&255;at!==0&&(nn=at),ht!==0&&(cn=ht),Ft!==0&&(kt=Ft),Tt!==0&&(ft=Tt)}}me.timestamp&&(nn!=null||kt!=null||cn!=null||ft!=null)&&L.push({time:typeof me.timestamp=="number"?me.timestamp:new Date(me.timestamp).getTime(),front:nn,rear:kt,frontTooth:cn,rearTooth:ft,idx:Ue})}),L.sort((me,Ue)=>me.time-Ue.time||me.idx-Ue.idx));let q=J.records||[],H=null,le=0,K=null,Ce=null,he=null,De=null,Ne=0,et=[];for(let me=0;me name, Placemark > name");C&&(x=C.textContent?.trim()||x);let I=S.querySelectorAll("coordinates");if(!I.length)throw new Error("No coordinates found in KML");let F=[];if(I.forEach(we=>{(we.textContent?.trim().split(/\s+/)||[]).forEach(Ae=>{let ie=Ae.split(",");if(ie.length<2)return;let V=parseFloat(ie[0]),z=parseFloat(ie[1]),L=ie.length>2?parseFloat(ie[2]):null;isNaN(z)||isNaN(V)||F.push({lat:z,lon:V,ele:L!=null&&isNaN(L)?null:L,time:null,hr:null,cad:null,power:null,speed:null,temp:null,gearFront:null,gearRear:null,gearFrontTooth:null,gearRearTooth:null,battery:null,gears:null})})}),!F.length)throw new Error("No valid coordinates in KML");let J=t(F),oe=r(J);return{name:x,format:"kml",points:J,stats:oe}}async function Ze(N){let A=N.name.split(".").pop()?.toLowerCase(),S=N._buf??await N.arrayBuffer(),x=N._text,C;switch(A){case"gpx":C=Se(S,x);break;case"tcx":C=pe(S,x);break;case"fit":C=await ee(S);break;case"kml":C=xe(S);break;default:throw new Error(`Unsupported format: .${A}`)}return C&&(C.fileName=N.name,C.fileSize=N.size,C.points&&C.stats&&(s(C),C.stats.sections=i(C.points))),C}return{parseFile:Ze,computeStats:r,ensureCurvesAndZones:s,analyzeTrackSections:i,findOverlaps:o,calculatePowerCurve:u,calculateHRCurve:d,calculatePowerZones:p,calculateHRZones:m,enrichPoints:t,setHRZones:g,getHRZones:v,setFTP:f,getFTP:h}})();var Ol=(()=>{function t(){let n=ln.getFTP(),r=[.55,.75,.9,1.05,1.2,1.5].map(c=>c*n),s=["Active Recovery","Endurance","Tempo","Threshold","VO2 Max","Anaerobic","Neuromuscular"],i=["#82E0AA","#A8C8A0","#F7DC6F","#F8C471","#F39C12","#E67E22","#C0392B"],o=[],a=0;for(let c=0;ce?t.toFixed(1):Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},speed:{label:"Speed",field:"speed",unit:"km/h",color:it.speed.color,abbr:"spd",icon:it.speed.icon,fmt:t=>(t*3.6).toFixed(1),fmtAxis:t=>(t*3.6).toFixed(0),transform:t=>t,smoothSigma:2},gradient:{label:"Gradient",field:"gradient",unit:"%",color:it.gradient.color,abbr:"grad",icon:it.gradient.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>t.toFixed(0),smoothSigma:2},power:{label:"Power",field:"power",unit:"W",color:it.power.color,abbr:"pwr",icon:it.power.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},hr:{label:"Heart Rate",field:"hr",unit:"bpm",color:it.hr.color,abbr:"hr",icon:it.hr.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},cadence:{label:"Cadence",field:"cad",unit:"rpm",color:it.cadence.color,abbr:"cad",icon:it.cadence.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},temperature:{label:"Temp",field:"temp",unit:"\xB0C",color:it.temperature.color,abbr:"temp",icon:it.temperature.icon,fmt:t=>t.toFixed(1),fmtAxis:t=>Math.round(t).toString(),smoothSigma:6},gearRear:{label:"Rear Gear",field:"gearRearTooth",unit:"T",color:it.gearRear.color,abbr:"rgr",icon:it.gearRear.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gearFront:{label:"Front Gear",field:"gearFrontTooth",unit:"T",color:it.gearFront.color,abbr:"fgr",icon:it.gearFront.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},gears:{label:"Gears",field:"gears",unit:"",color:it.gears.color,abbr:"gr",icon:it.gears.icon,fmt:t=>t.toFixed(2),fmtAxis:t=>t.toFixed(1)},battery:{label:"Battery",field:"battery",unit:"%",color:it.battery.color,abbr:"bat",icon:it.battery.icon,fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString()},vam:{label:"VAM",field:"ele",unit:"m/h",color:"#FFA07A",abbr:"vam",icon:"trending_up",fmt:t=>Math.round(t).toString(),fmtAxis:t=>Math.round(t).toString(),smoothSigma:5,compute:(t,e)=>{let n=new Array(t.length).fill(null);for(let r=1;r0&&(n[r]=o/a*3600)}}return e(n)}}};var Fi={cycling:{name:"Cycling",icon:"directions_bike",defaultPreset:"speed"},skiing:{name:"Skiing",icon:"downhill_skiing",defaultPreset:"speed"},running:{name:"Running",icon:"directions_run",defaultPreset:"pace",paceUnit:"km"},swimming:{name:"Swimming",icon:"pool",defaultPreset:"pace",paceUnit:"100m"}};function JW(t){if(!t)return"question_mark";let e=t.toLowerCase();return Fi[e]?.icon||"exercise"}var Pe=(()=>{let t=[],e=null,n="time",r="speed",s=null,i=null,o=!1,a=!1,c=new Set(["elevation"]),u=new Set,d=new Set(["speed","gradient","vam","temperature"]),p=new Set(["power"]),f="time",h=null,m=[],g=null,v=null,w=!1,b=!1,D=null,B=null,M=null,$=null,j=null,G=null,Se=null,pe=null,U=null,ee=null,xe=null,Ze=null,N=130,A=28,S=20,x=!0,C=null,I=null,F=null,J=null,oe=null,we=null,ae=null;function Ae(T,_,R,O){U=T,ee=_,xe=R,Ze=O,I=document.getElementById("charts-container"),I?.addEventListener("scroll",()=>{M&&j&&$&&sF(M,j,$)}),F=document.getElementById("chart-empty"),J=document.getElementById("chart-stats-sel"),oe=document.getElementById("btn-reset-selection"),C=document.getElementById("hist-tooltip"),i=ez.sync("strasse-sync"),document.getElementById("sel-cancel-btn")?.addEventListener("click",Ue),oe?.classList.add("hidden");let Q=new Set(["w","a","s","d"]),W=new Set;document.addEventListener("keydown",te=>{if(!t.length||!h||["INPUT","TEXTAREA","SELECT"].includes(document.activeElement?.tagName||""))return;let X=te.key.toLowerCase();if(!Q.has(X))return;te.preventDefault(),W.add(X);let se=t[0].uplot;Se||(Se=[se.scales.x.min,se.scales.x.max]);let[ge,ce]=Se,ye=(ce-ge)*.1,ve=.15,Z=ge,Be=ce;if(X==="a")Z=ge-ye,Be=ce-ye;else if(X==="d")Z=ge+ye,Be=ce+ye;else if(X==="w"||X==="s"){let _e=B!==null?B:(ge+ce)/2,ze=X==="w"?1-ve:1+ve*1.2;Z=_e-(_e-ge)*ze,Be=_e+(ce-_e)*ze}let je=[t[0].xData[0],t[0].xData[t[0].xData.length-1]];if(Zje[1]){let _e=Be-je[1];Z-=_e,Be-=_e}Z=Math.max(je[0],Z),Be=Math.min(je[1],Be),Be-Z>.001&&(Se=[Z,Be],ie(Z,Be,!0))}),document.addEventListener("keyup",te=>{let X=te.key.toLowerCase();Q.has(X)&&W.delete(X)})}function ie(T,_,R=!1){if(!t.length)return;if(!R){t.forEach(({uplot:se})=>se.setScale("x",{min:T,max:_}));return}let O=G?G[0]:t[0].uplot.scales.x.min,Q=G?G[1]:t[0].uplot.scales.x.max;pe&&cancelAnimationFrame(pe);let W=(se,ge,ce)=>se+(ge-se)*ce,te=.25,X=()=>{if(!Se)return;let[se,ge]=Se,ce=W(G[0],se,te),ue=W(G[1],ge,te);t.forEach(({uplot:ye})=>{ye.setScale("x",{min:ce,max:ue})}),Math.abs(ce-se)>1e-4||Math.abs(ue-ge)>1e-4?pe=requestAnimationFrame(X):pe=null};pe=requestAnimationFrame(X)}function V(T,_=[],R=!1){D=null,g=null,v=null,m=_,u=new Set(Object.entries(mi).filter(([,O])=>T.points.some(Q=>Q[O.field]!=null)).map(([O])=>O)),c.size===0&&(c=new Set(["elevation"].filter(O=>u.has(O)))),document.querySelectorAll(".metric-pill").forEach(O=>{let Q=O,W=Q.dataset.metric,te=u.has(W);Q.classList.toggle("active",te&&c.has(W)),Q.classList.toggle("disabled",!te)}),h=T,R?fF(T):ot(),window.__trackStateService?.graphsTab?.syncFromChartView()}function z(){D=null,g=null,v=null,h=null,Yg(),F||(F=document.getElementById("chart-empty")),F&&(F.style.display="flex",F.innerHTML=` no_sim
Select a track to view analysis
- `);let l=document.getElementById("chart-stats");l&&l.classList.add("hidden"),It(),at=null,nt&&nt(null)}function it(){Y!==null&&(cancelAnimationFrame(Y),Y=null),d=new Set(["elevation"]),T=new Set,$=new Set(["speed","gradient","vam","temperature"]),M=new Set(["power"]),F="time",b=[],W=null,O=null,h=null,p=null,E=null,_=null,N=!0,D(),document.querySelectorAll("#metric-pills .metric-pill").forEach(x=>{let S=x;S.classList.toggle("active",d.has(S.dataset.metric)),S.classList.remove("disabled","overflow-hidden")});let l=document.getElementById("pill-overflow");l&&l.classList.add("hidden");let c=document.getElementById("chart-toolbar");c&&c.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(x=>{x.classList.toggle("active",x.dataset.axis==="time")})}function K(l){d.has(l)?d.delete(l):d.add(l),I&&vt(!0)}function bt(l,c,x=!1){let S=$.has(l);c&&!S?($.add(l),I&&!x&&vt(!0)):!c&&S&&($.delete(l),I&&!x&&vt(!0))}function Pt(l,c){let x=M.has(l);c&&!x?(M.add(l),I&&vt(!0)):!c&&x&&(M.delete(l),I&&vt(!0))}function ut(l){d=new Set(l),I&&vt(!0),document.querySelectorAll(".metric-pill").forEach(c=>{let x=c;x.classList.toggle("active",d.has(x.dataset.metric))})}function Ht(l){if(F===l||!I){F=l;return}let c=I.points,x=c.find(P=>P.time!=null)?.time||0,S=P=>{if(P===null)return null;let B=0;if(F==="distance"){let A=P*1e3;B=c.findIndex(q=>(q.dist||0)>=A)}else{let A=x+P*1e3;B=c.findIndex(q=>(q.time||0)>=A)}return B===-1&&(B=c.length-1),l==="distance"?(c[B].dist||0)/1e3:((c[B].time||x)-x)/1e3};g!==null&&(g=S(g)),u!==null&&(u=S(u));let H=null;if(t.length){let P=t[0].uplot,B=S(P.scales.x.min),A=S(P.scales.x.max);B!==null&&A!==null&&(H=[B,A])}F=l,vt(!0),H&&(a=!0,t.forEach(({uplot:P})=>{P.batch(()=>P.setScale("x",{min:H[0],max:H[1]}))}),a=!1)}function dt(){N=!N,t.forEach(({histCol:l})=>l.classList.toggle("visible",N)),Et()}function Lt(l){nt=l}function st(l,c=!1){at===l||l===null?(at=null,gt(),nt&&nt(null)):(at=l,gt(),At()),I&&!c&&vt(!0)}function gt(){document.querySelectorAll(".map-color-btn").forEach(l=>{let c=l;c.classList.toggle("active",c.dataset.metric===at)})}function At(){if(!nt||!at||!I)return;let l=t.find(x=>x.metricKey===at);if(!l)return;let c=zt(at,l.yData);nt({pts:I.points,colors:c})}function zt(l,c){let x=c.filter(Q=>Q!=null&&isFinite(Q));if(!x.length)return c.map(()=>"#888896");let S=Math.min(...x),H=Math.max(...x),P=I?.sport,B=P?Ye[P.toLowerCase()]:null,A=B?.defaultPreset||"speed",J=Gt.get().speed_mode||A,X=B?.paceUnit||"km";return c.map(Q=>{if(Q==null||!isFinite(Q))return"#888896";if(l==="gradient")return is(Q);if(l==="speed"){if(J==="pace"){let tt=(X==="km"?1e3:100)/Q;return uo(tt)}return uo(Q)}let et=H===S?.5:Math.max(0,Math.min(1,(Q-S)/(H-S)));return et<=.25?Ve("#4575b4","#91bfdb",et/.25):et<=.5?Ve("#91bfdb","#fee090",(et-.25)/.25):et<=.75?Ve("#fee090","#fc8d59",(et-.5)/.25):Ve("#fc8d59","#d73027",(et-.75)/.25)})}function V(){R()}function R(){g=null,u=null,f=null,rt&&rt(null),t.forEach(l=>{l.pinnedHistY=null}),_t(),De(),a=!0,t.forEach(({uplot:l,xData:c})=>{l.batch(()=>l.setScale("x",{min:c[0],max:c[c.length-1]})),l._strasse?.updateHeaderStats(c[0],c[c.length-1])}),a=!1,lt&<(null,null,F)}function Dt(l){if(!j)return;let c=(x,S)=>{let H=document.querySelector(`#${x} .stat-value`);H&&(H.textContent=S)};c("sel-distance",l.totalDist!=null?`${(l.totalDist/1e3).toFixed(1)} km`:"\u2014"),c("sel-duration",l.duration!=null?he(Math.floor(l.duration/1e3)):"\u2014"),c("sel-elevation",l.elevGain!=null?`${Math.round(l.elevGain)} m`:"\u2014"),c("sel-avg-speed",l.avgSpeed!=null?`${(l.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),c("sel-avg-power",l.avgPower!=null?`${l.avgPower} W`:"\u2014"),c("sel-avg-hr",l.avgHR!=null?`${l.avgHR} bpm`:"\u2014"),c("sel-avg-temp",l.avgTemp!=null?`${l.avgTemp.toFixed(1)} \xB0C`:"\u2014"),j.classList.remove("hidden"),Rt&&Rt.classList.remove("hidden")}function It(){j&&j.classList.add("hidden"),Rt&&Rt.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(l=>{let c=document.querySelector(`#${l} .stat-value`);c&&(c.textContent="--")})}function Wt(l,c,x=!1){if(!I)return;let S=I.points,H=S.find(J=>J.time!=null)?.time||0,P=((S[S.length-1]?.time||0)-H)/1e3;l>1e12&&(l=(l-H)/1e3),c>1e12&&(c=(c-H)/1e3),l=Math.max(0,Math.min(l,P)),c=Math.max(0,Math.min(c,P));let B=J=>{if(F==="time")return J;let X=H+J*1e3,Q=S.findIndex(et=>(et.time||0)>=X);return Q===-1&&(Q=S.length-1),(S[Q].dist||0)/1e3},A=B(l),q=B(c);g=A,u=q,W=[A,q],!x&&(a=!0,t.forEach(({uplot:J})=>{J.batch(()=>J.setScale("x",{min:A,max:q}))}),a=!1,qt(),De())}function Et(){if(!t.length||!G)return;let l=Math.round(Math.max(100,G.getBoundingClientRect().width-y-(N?w+m:0))),c=!1;t.forEach(({uplot:x,histCanvas:S,histData:H})=>{l!==x.width&&(x.setSize({width:l,height:x.height}),c=!0,N&&S&&H&&Le(S,H,x.height))}),c&&_t()}function vt(l=!1){let c=null,x=0;if(l&&G&&(x=G.scrollTop),l&&W)c=[W[0],W[1]];else if(l&&t.length){let St=t[0].uplot;c=[St.scales.x.min,St.scales.x.max]}if(!I){Rn(l);return}let S=I.points;if(!S.length){Rn(l);return}let H=I?.sport,P=H?Ye[H.toLowerCase()]:null,B=P?.defaultPreset||"speed",q=Gt.get().speed_mode||B,J=P?.paceUnit||"km",X=[...d].filter(St=>S.some(ct=>ct[qe[St].field]!=null));if(!X.length){Rn(l),U&&(U.style.display="flex",U.innerHTML=` + `);let T=document.getElementById("chart-stats");T&&T.classList.add("hidden"),kt(),we=null,ae&&ae(null),window.__trackStateService?.graphsTab?.syncFromChartView()}function L(){pe!==null&&(cancelAnimationFrame(pe),pe=null),c=new Set(["elevation"]),u=new Set,d=new Set(["speed","gradient","vam","temperature"]),p=new Set(["power"]),f="time",m=[],G=null,Se=null,B=null,M=null,$=null,j=null,x=!0,z(),document.querySelectorAll("#metric-pills .metric-pill").forEach(R=>{let O=R;O.classList.toggle("active",c.has(O.dataset.metric)),O.classList.remove("disabled","overflow-hidden")});let T=document.getElementById("pill-overflow");T&&T.classList.add("hidden");let _=document.getElementById("chart-toolbar");_&&_.classList.remove("collapsed"),document.querySelectorAll("#x-axis-ctrl .seg-btn").forEach(R=>{R.classList.toggle("active",R.dataset.axis==="time")}),window.__trackStateService?.graphsTab?.syncFromChartView()}function q(T){c.has(T)?c.delete(T):c.add(T),h&&ot(!0),window.__trackStateService?.graphsTab?.syncFromChartView()}function H(T,_,R=!1){let O=d.has(T);_&&!O?(d.add(T),h&&!R&&ot(!0)):!_&&O&&(d.delete(T),h&&!R&&ot(!0))}function le(T,_){let R=p.has(T);_&&!R?(p.add(T),h&&ot(!0)):!_&&R&&(p.delete(T),h&&ot(!0))}function K(T){c=new Set(T),h&&ot(!0),document.querySelectorAll(".metric-pill").forEach(_=>{let R=_;R.classList.toggle("active",c.has(R.dataset.metric))}),window.__trackStateService?.graphsTab?.syncFromChartView()}function Ce(T){if(f===T||!h){f=T,window.__trackStateService?.graphsTab?.syncFromChartView();return}let _=h.points,R=_.find(W=>W.time!=null)?.time||0,O=W=>{if(W===null)return null;let te=0;if(f==="distance"){let X=W*1e3;te=_.findIndex(se=>(se.dist||0)>=X)}else{let X=R+W*1e3;te=_.findIndex(se=>(se.time||0)>=X)}return te===-1&&(te=_.length-1),T==="distance"?(_[te].dist||0)/1e3:((_[te].time||R)-R)/1e3};g!==null&&(g=O(g)),v!==null&&(v=O(v));let Q=null;if(t.length){let W=t[0].uplot,te=O(W.scales.x.min),X=O(W.scales.x.max);te!==null&&X!==null&&(Q=[te,X])}f=T,ot(!0),Q&&(o=!0,t.forEach(({uplot:W})=>{W.batch(()=>W.setScale("x",{min:Q[0],max:Q[1]}))}),o=!1)}function he(){x=!x,t.forEach(({histCol:T})=>T.classList.toggle("visible",x)),ft()}function De(T){ae=T}function Ne(T,_=!1){we===T||T===null?(we=null,et(),ae&&ae(null)):(we=T,et(),Pt()),h&&!_&&ot(!0)}function et(){document.querySelectorAll(".map-color-btn").forEach(T=>{let _=T;_.classList.toggle("active",_.dataset.metric===we)})}function Pt(){if(!ae||!we||!h)return;let T=t.find(R=>R.metricKey===we);if(!T)return;let _=$t(we,T.yData);ae({pts:h.points,colors:_})}function $t(T,_){let R=_.filter(ue=>ue!=null&&isFinite(ue));if(!R.length)return _.map(()=>"#888896");let O=Math.min(...R),Q=Math.max(...R),W=h?.sport,te=W?Fi[W.toLowerCase()]:null,X=te?.defaultPreset||"speed",ge=It.get().speed_mode||X,ce=te?.paceUnit||"km";return _.map(ue=>{if(ue==null||!isFinite(ue))return"#888896";if(T==="gradient")return nw(ue);if(T==="speed"){if(ge==="pace"){let ve=(ce==="km"?1e3:100)/ue;return dF(ve)}return dF(ue)}let ye=Q===O?.5:Math.max(0,Math.min(1,(ue-O)/(Q-O)));return ye<=.25?ho("#4575b4","#91bfdb",ye/.25):ye<=.5?ho("#91bfdb","#fee090",(ye-.25)/.25):ye<=.75?ho("#fee090","#fc8d59",(ye-.5)/.25):ho("#fc8d59","#d73027",(ye-.75)/.25)})}function me(){Ue()}function Ue(){g=null,v=null,D=null,Ze&&Ze(null),t.forEach(T=>{T.pinnedHistY=null}),at(),Ar(),o=!0,t.forEach(({uplot:T,xData:_})=>{T.batch(()=>T.setScale("x",{min:_[0],max:_[_.length-1]})),T._strasse?.updateHeaderStats(_[0],_[_.length-1])}),o=!1,ee&&ee(null,null,f)}function nn(T){if(window.__trackStateService?.graphsTab?.setSelectionStats(T),J||(J=document.getElementById("chart-stats-sel")),!J)return;let _=(R,O)=>{let Q=document.querySelector(`#${R} .stat-value`);Q&&(Q.textContent=O)};_("sel-distance",T.totalDist!=null?`${(T.totalDist/1e3).toFixed(1)} km`:"\u2014"),_("sel-duration",T.duration!=null?Nn(Math.floor(T.duration/1e3)):"\u2014"),_("sel-elevation",T.elevGain!=null?`${Math.round(T.elevGain)} m`:"\u2014"),_("sel-avg-speed",T.avgSpeed!=null?`${(T.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014"),_("sel-avg-power",T.avgPower!=null?`${T.avgPower} W`:"\u2014"),_("sel-avg-hr",T.avgHR!=null?`${T.avgHR} bpm`:"\u2014"),_("sel-avg-temp",T.avgTemp!=null?`${T.avgTemp.toFixed(1)} \xB0C`:"\u2014"),J.classList.remove("hidden"),oe&&oe.classList.remove("hidden")}function kt(){window.__trackStateService?.graphsTab?.setSelectionStats(null),J||(J=document.getElementById("chart-stats-sel")),J&&J.classList.add("hidden"),oe&&oe.classList.add("hidden"),["sel-distance","sel-duration","sel-elevation","sel-avg-speed","sel-avg-power","sel-avg-hr","sel-avg-temp"].forEach(T=>{let _=document.querySelector(`#${T} .stat-value`);_&&(_.textContent="--")})}function cn(T,_,R=!1){if(!h)return;let O=h.points,Q=O.find(ge=>ge.time!=null)?.time||0,W=((O[O.length-1]?.time||0)-Q)/1e3;T>1e12&&(T=(T-Q)/1e3),_>1e12&&(_=(_-Q)/1e3),T=Math.max(0,Math.min(T,W)),_=Math.max(0,Math.min(_,W));let te=ge=>{if(f==="time")return ge;let ce=Q+ge*1e3,ue=O.findIndex(ye=>(ye.time||0)>=ce);return ue===-1&&(ue=O.length-1),(O[ue].dist||0)/1e3},X=te(T),se=te(_);g=X,v=se,G=[X,se],!R&&(o=!0,t.forEach(({uplot:ge})=>{ge.batch(()=>ge.setScale("x",{min:X,max:se}))}),o=!1,Tt(),Ar())}function ft(){if((!I||!I.isConnected)&&(I=document.getElementById("charts-container")),!t.length||!I)return;let T=Math.round(Math.max(100,I.getBoundingClientRect().width-A-(x?N+S:0))),_=!1;t.forEach(({uplot:R,histCanvas:O,histData:Q})=>{T!==R.width&&(R.setSize({width:T,height:R.height}),_=!0,x&&O&&Q&&La(O,Q,R.height))}),_&&at()}function ot(T=!1){(!I||!I.isConnected)&&(I=document.getElementById("charts-container")),(!F||!F.isConnected)&&(F=document.getElementById("chart-empty"));let _=null,R=0;if(T&&I&&(R=I.scrollTop),T&&G)_=[G[0],G[1]];else if(T&&t.length){let je=t[0].uplot;_=[je.scales.x.min,je.scales.x.max]}if(!h){Yg(T);return}let O=h.points;if(!O.length){Yg(T);return}let Q=h?.sport,W=Q?Fi[Q.toLowerCase()]:null,te=W?.defaultPreset||"speed",se=It.get().speed_mode||te,ge=W?.paceUnit||"km",ce=[...c].filter(je=>O.some(_e=>_e[mi[je].field]!=null));if(!ce.length){Yg(T),F&&(F.style.display="flex",F.innerHTML=` no_sim
No data for selected metrics
- `);return}U&&(U.style.display="none");let Q=G?G.getBoundingClientRect().width:800,et=Math.round(Math.max(100,Q-y-(N?w+m:0))),tt=l&&s===I&&e===F&&n===q&&o===at&&t.length>0,L;if(tt)L=t[0].xData;else if(F==="distance")L=S.map(St=>(St.dist||0)/1e3);else{let St=S.find(Ct=>Ct.time!=null)?.time||0,ct=0;L=S.map(Ct=>(Ct.time!=null&&(ct=(Ct.time-St)/1e3),ct))}let wt=new Map;if(tt){C&&(C.style.display="none");let St=new Set(X);for(let ct of t){let Ct=$.has(ct.metricKey),pt=M.has(ct.metricKey);St.has(ct.metricKey)&&ct.smoothed===Ct&&ct.incZero===pt&&ct.w===et?wt.set(ct.metricKey,ct):(i.unsub(ct.uplot),ct.uplot.destroy(),ct.row.remove())}t=[]}else Rn(l);if(G){let St=new Array(X.length).fill(null),ct=null;for(let Ct=X.length-1;Ct>=0;Ct--){St[Ct]=ct;let pt=wt.get(X[Ct]);pt&&(ct=pt.row)}X.forEach((Ct,pt)=>{let xt=wt.get(Ct);if(xt){t.push(xt);let mt=xt.uplot,Kt=mt._strasse,Xt=a;a=!0,mt.batch(()=>{c&&(mt.scales.x.min!==c[0]||mt.scales.x.max!==c[1])?mt.setScale("x",{min:c[0],max:c[1]}):(Kt?.updateHeaderStats(mt.scales.x.min,mt.scales.x.max,mt),mt.redraw(!1))}),a=Xt;let te=null;if(f!=null&&xt.xData[f]!=null&&xt.yData[f]!=null&&(xe(xt.histData),xt.histData.min!=null&&xt.histData.max!=null)){let de=xt.histData.max-xt.histData.min||1;te=Math.min(xt.histData.BINS-1,Math.floor((xt.yData[f]-xt.histData.min)/de*xt.histData.BINS)),xt.hoveredHistY=xt.yData[f]}Le(xt.histCanvas,xt.histData,130,te);return}let kt=qe[Ct],Ot=kt.transform,Vt=kt.fmt,ne=kt.fmtAxis,ie=kt.unit,re=kt.label;Ct==="speed"&&q==="pace"&&(re="Pace",ie=`min/${J}`,Vt=mt=>On(mt),ne=mt=>On(mt),Ot=mt=>mt==null||mt<.1?null:(J==="km"?1e3:100)/mt,kt={...kt,label:re,unit:ie,fmt:Vt,fmtAxis:ne,transform:Ot});let ae=kt.compute?kt.compute(S,mo):mo(S.map(mt=>{let Kt=mt[kt.field];return Kt!=null&&Ot?Ot(Kt):Kt}));$.has(Ct)&&(ae=Cn(ae,kt.smoothSigma||2)),yt(Ct,kt,L,ae,et,S,c,St[pt])})}s=I,e=F,n=q,o=at,po(I),g!=null&&u!=null&&qt(),gt(),at&&At(),l&&G&&x>0&&(G.scrollTop=x)}function yt(l,c,x,S,H,P,B=null,A=null){let q=I?.sport,X=(q?Ye[q.toLowerCase()]:null)?.defaultPreset||"speed",et=Gt.get().speed_mode||X,tt=l==="elevation"?Tl(P,20):null,L=document.createElement("div");L.className="chart-row",L.dataset.metric=l,L.style.setProperty("--chart-color",c.color);let wt=document.createElement("div");wt.className=`chart-row-header${N?" with-histogram":""}`;let St=document.createElement("div");St.className="chart-row-label-group",St.innerHTML=` - ${c.icon} - ${c.label} - `;let ct=document.createElement("button");ct.className=`icon-btn mini smooth-btn${$.has(l)?" active":""}`,ct.title="Toggle data smoothing",ct.innerHTML=`${$.has(l)?"blur_on":"blur_off"}`,ct.addEventListener("click",ot=>{ot.stopPropagation(),$.has(l)?$.delete(l):$.add(l),vt(!0)});let Ct=document.createElement("button");Ct.className=`map-color-btn icon-btn${at===l?" active":""}`,Ct.dataset.metric=l,Ct.title="Color map track by this metric",Ct.innerHTML='colorize',Ct.addEventListener("click",()=>st(l));let pt=null;if(l==="cadence"||l==="power"||l==="speed"){pt=document.createElement("button");let ot=M.has(l);pt.className=`icon-btn mini${ot?" active":""}`,pt.title=ot?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",pt.innerHTML=`${ot?"exposure_zero":"mobile_off"}`,pt.addEventListener("click",Mt=>{Mt.stopPropagation(),M.has(l)?M.delete(l):M.add(l),vt(!0)})}let xt=document.createElement("div");xt.className="chart-stats-total";let kt=document.createElement("div");kt.className="chart-stats-selection";let Ot=document.createElement("div");Ot.className="chart-row-stats-container",Ot.append(xt,kt);let Vt=document.createElement("div");Vt.className="chart-row-actions",Vt.append(ct,Ct);let ne=document.createElement("div");if(ne.className="chart-row-right-actions",l==="speed"){let ot=document.createElement("div");ot.className="seg-ctrl",ot.innerHTML=` - - - `,ot.addEventListener("click",Mt=>{let se=Mt.target.closest(".seg-btn");if(!se)return;let oe=se.dataset.mode;if(oe==="speed"||oe==="pace"){let jt=oe===X;Gt.patch({speed_mode:jt?null:oe}),vt(!0)}}),ne.append(ot)}pt&&ne.append(pt),wt.append(St,Vt,Ot,ne);let ie=document.createElement("div");ie.className="chart-row-body";let re=document.createElement("div");re.style.position="relative",ie.appendChild(re);let ae=document.createElement("div");ae.className="fixed-x-label fixed-x-min";let mt=document.createElement("div");mt.className="fixed-x-label fixed-x-max",re.append(ae,mt);let Kt=document.createElement("div");Kt.className=`hist-col${N?" visible":""}`;let Xt=document.createElement("canvas");Xt.className="hist-canvas",Kt.appendChild(Xt),ie.appendChild(Kt),L.append(wt,ie);let te=F==="distance";function de(ot,Mt){if(ot==null)return"";if(te){let se=Mt<1?3:Mt<5?2:Mt<20?1:0;return`${ot.toFixed(se)} km`}else{let se=Math.abs(ot),oe=Math.floor(se/3600),jt=Math.floor(se%3600/60),Ce=Math.round(se%60),ye=oe>0?`${oe}:`:"",Oe=oe>0?String(jt).padStart(2,"0"):String(jt),Re=String(Ce).padStart(2,"0");return`${ot<0?"-":""}${ye}${Oe}:${Re}`}}let fe=M.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",ge=1/0,Qt=-1/0,ue=0,Me=0,Be=1/0,Je=-1/0,Ae=0,on=0;for(let ot=0;otQt&&(Qt=Mt),ue+=Mt,Me++,(Mt!==0||fe)&&(MtJe&&(Je=Mt),Ae+=Mt,on++))}Me===0&&(ge=0,Qt=100);let _s=Me?{min:ge,max:Qt,avg:ue/Me}:null,cs=on?{min:Be,max:Je,avg:Ae/on}:null,ho=Math.abs(Qt-ge)*.1||1,El=[ge-ho,Qt+ho],bo=!1;function Rs(ot,Mt,se){let oe=M.has(l)||l!=="power"&&l!=="cadence"&&l!=="speed",jt=Mt-ot;ae.textContent=de(ot,jt),mt.textContent=de(Mt,jt);let Ce=(ye,Oe,Re=!1)=>{let We=Re&&oe===fe?cs:oo(x,S,ye,Oe,oe);if(!We)return"";let an=` - align_flex_end${c.fmt(We.min,!0)} ${c.unit} - align_center${c.fmt(We.avg,!0)} ${c.unit} - align_flex_start${c.fmt(We.max,!0)} ${c.unit} - `;if(l==="elevation"){let Ge=hl(P,ye,Oe);an+=` - trending_up+${Math.round(Ge.gain)} m - trending_down-${Math.round(Ge.loss)} m - `}return an};bo||(bo=!0,xt.innerHTML=`all_inclusive${Ce(x[0],x[x.length-1],!0)}`,xt.querySelector(".all-chip")?.addEventListener("click",ye=>{ye.stopPropagation(),R()})),g!==null&&u!==null?(kt.innerHTML=Ce(g,u,!1),kt.style.display="flex",kt.style.setProperty("--sel-color",c.color)):kt.style.display="none"}let kl=!1,Cl={width:H,height:130,padding:[4,0,0,0],cursor:{sync:{key:i.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:l==="elevation"?(ot,Mt)=>is(tt?tt[ot.cursor.idx]:null):c.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(ot,Mt,se)=>[Mt,se],min:B?B[0]:void 0,max:B?B[1]:void 0},y:{range:()=>El,dir:l==="speed"&&et==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(ot,Mt,se,oe)=>{let jt=oe-se,ye=(ot.bbox.width>0?ot.bbox.width:ot.width)/80,Oe=jt/ye,Re;te?Re=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:Re=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let We=Re[Re.length-1];for(let Ze=0;Ze=Oe){We=Re[Ze];break}let an=[],Ge=Math.ceil(se/We)*We,vs=We<1?2:0;for(;Ge<=oe;){let Ze=ot.valToPos(Ge,"x",!0);Ze>=ot.bbox.left+80&&Ze<=ot.bbox.left+ot.bbox.width-80&&an.push(Number(Ge.toFixed(vs))),Ge+=We}return an},values:(ot,Mt)=>{let se=(ot.scales.x?.max??1)-(ot.scales.x?.min??0);return Mt.map(oe=>{if(oe==null)return"";let jt=ot.valToPos(oe,"x",!0);return jtot.bbox.left+ot.bbox.width-80?null:de(oe,se)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(ot,Mt)=>Mt.map(se=>se!=null?c.fmtAxis(se):"")}],series:[{},{label:c.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[ot=>{let Mt=ot.bbox.top+ot.bbox.height+5;ae.style.top=`${Mt}px`,ae.style.left=`${ot.bbox.left}px`,mt.style.top=`${Mt}px`,mt.style.left=`${ot.bbox.left+ot.bbox.width}px`,mt.style.transform="translateX(-100%)"},ot=>{l==="gears"?go(ot,x,S,c.color,1.5,l,null,P):l==="elevation"?bl(ot,x,S,tt):l==="gradient"?vl(ot,x,S):at===l?Ml(ot,x,S,P,l):go(ot,x,S,c.color,1.5,l,null,P)},ot=>{let Mt=t.find(oe=>oe.uplot===ot);if(!Mt)return;let se=ot._strasse;f!=null?yl(ot,x,S,c.color,c,P,l):(se&&se.pinYVal&&(se.pinYVal.style.display="none"),Mt.pinnedHistY!=null&&xl(ot,x,S,Mt.pinnedHistY,c.color,c))},ot=>{let Mt=ot.cursor.idx,se=f!=null,oe=Mt!=null&&ot.cursor.left>=0;if(oe&&f==null){let jt=ot.valToPos(S[Mt],"y",!0);Math.abs(ot.cursor.top-jt)>100&&(oe=!1)}if(oe&&Mt!==f&&ro(ot,P,Mt,le(c.color,.4),1),g!=null&&u!=null){let jt=ot.ctx,Ce=window.devicePixelRatio||1,ye=ot.bbox,Oe=ot.valToPos(g,"x",!0),Re=ot.valToPos(u,"x",!0);jt.save(),jt.beginPath(),jt.lineWidth=3*Ce,jt.strokeStyle=c.color,jt.moveTo(Oe,ye.top+ye.height),jt.lineTo(Re,ye.top+ye.height),jt.stroke();let We=Math.abs(u-g),an=F==="distance"?`${We.toFixed(2)} km`:he(We),Ge=9*Ce,vs=`bold ${Ge}px system-ui, sans-serif`;jt.font!==vs&&(jt.font=vs);let Ze=jt.measureText(an).width,yo=Math.max(ye.left,Oe),xo=Math.min(ye.left+ye.width,Re);if(xo-yo>Ze+14*Ce){let Pl=5*Ce,Ll=2*Ce,ys=Ze+Pl*2,xs=Ge+Ll*2,Ws=(yo+xo)/2-ys/2,qs=ye.top+ye.height-xs/2;jt.beginPath(),jt.roundRect?jt.roundRect(Ws,qs,ys,xs,3*Ce):jt.rect(Ws,qs,ys,xs),jt.fillStyle=c.color,jt.fill(),jt.fillStyle="#000",jt.textAlign="center",jt.textBaseline="middle",jt.fillText(an,Ws+ys/2,qs+xs/2)}jt.restore()}se&&co(ot,P,f,c.color,!0,.7),oe&&Mt!==f&&co(ot,P,Mt,c.color,!0,1)}],setCursor:[ot=>{if(a)return;let Mt=ot.cursor.idx;ot.redraw(!1),ot.cursor.left>=0?h=ot.posToVal(ot.cursor.left,"x"):h=null;let se=ot._strasse,oe=Mt!=null&&S[Mt]!=null;if(oe&&f==null){let jt=ot.valToPos(S[Mt],"y",!0);Math.abs(ot.cursor.top-jt)>100&&(oe=!1)}if(se&&(oe?lo(ot,se.curYVal,Mt,x,S,P,c,l):se.curYVal.style.display="none"),r||(Mt!=null&&P[Mt]?Z&&(f!=null||oe)?Z(P[Mt]):Z&&!oe&&Z(null):Mt===null&&Z&&Z(null)),Mt!=null&&S[Mt]!=null){let{min:jt,max:Ce}=ke;if(jt!=null&&Ce!=null){let ye=Ce-jt||1,Oe=Math.min(ke.BINS-1,Math.floor((S[Mt]-jt)/ye*ke.BINS));ln.hoveredHistY!==S[Mt]&&(ln.hoveredHistY=S[Mt],Le(Xt,ke,130,Oe))}}else ln.hoveredHistY!==null&&(ln.hoveredHistY=null,Le(Xt,ke,130))}],setScale:[(ot,Mt)=>{if(Mt!=="x"||kl)return;let{min:se,max:oe}=ot.scales.x;W=[se,oe],Rs(se,oe,ot),!a&&(k||(O=null),a=!0,t.forEach(({uplot:jt})=>{jt!==ot&&jt.batch(()=>jt.setScale("x",{min:se,max:oe}))}),a=!1,_t(),De(),lt&&g!==null&<(g,u,F))}],setSelect:[ot=>{if(k)return;O=null;let{left:Mt,width:se}=ot.select;if(se>0){let oe=ot.posToVal(Mt,"x"),jt=ot.posToVal(Mt+se,"x");g=oe,u=jt,Rs(ot.scales.x.min,ot.scales.x.max,ot),_t(),De(),lt&<(g,u,F),ot.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},Ns=document.createElement("div");Ns.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let ds=document.createElement("div");ds.className="sel-fill",ds.style.display="none";let us=document.createElement("div");us.className="sel-line sel-line-anchor",us.style.display="none";let ms=document.createElement("div");ms.className="sel-line-label sel-line-label-anchor",ms.style.display="none";let qn=document.createElement("div");qn.className="sel-handle sel-handle-anchor",qn.style.display="none";let zn=document.createElement("div");zn.className="sel-graph-marker",zn.innerHTML=`play_circle`,zn.style.display="none";let ps=document.createElement("div");ps.className="sel-line sel-line-end",ps.style.display="none";let fs=document.createElement("div");fs.className="sel-line-label sel-line-label-end",fs.style.display="none";let Un=document.createElement("div");Un.className="sel-handle sel-handle-end",Un.style.display="none";let Vn=document.createElement("div");Vn.className="sel-graph-marker",Vn.innerHTML=`stop_circle`,Vn.style.display="none";let gs=document.createElement("div");gs.className="cur-y-val",gs.style.cssText=`color:${c.color};display:none`;let hs=document.createElement("div");hs.className="cur-y-val pin",hs.style.cssText=`color:${c.color};display:none`,Ns.append(ds,us,ms,qn,zn,ps,fs,Un,Vn,gs,hs);let ke={yData:S,xData:x,def:c,BINS:24,min:Me?ge:void 0,max:Me?Qt:void 0,fullStats:cs,fullStatsAll:_s},ln={uplot:null,row:L,xData:x,yData:S,def:c,metricKey:l,statsTotalEl:xt,statsSelEl:kt,histCol:Kt,histCanvas:Xt,histData:ke,hoveredHistY:null,pinnedHistY:null,smoothed:$.has(l),incZero:M.has(l),w:H};ke.plot=ln;let $l=a;a=!0;let tn=new ko(Cl,[x,S],(ot,Mt)=>{ln.uplot=ot,t.push(ln),re.appendChild(ot.root),ot.over.appendChild(Ns),ot._strasse={selFill:ds,anchorLine:us,anchorLabel:ms,anchorHandle:qn,anchorMarker:zn,endLine:ps,endLabel:fs,endHandle:Un,endMarker:Vn,curYVal:gs,pinYVal:hs,updateHeaderStats:Rs},ot.batch(()=>{Mt()})});a=$l,ee(qn,tn,x,!0),ee(Un,tn,x,!1);let bs=null;tn.over.addEventListener("mousedown",ot=>{if(ot.button!==0)return;v=!1;let Mt=tn.over.getBoundingClientRect();bs=ot.clientX-Mt.left}),tn.over.addEventListener("mousemove",ot=>{if(bs!==null){let Mt=tn.over.getBoundingClientRect();Math.abs(ot.clientX-Mt.left-bs)>5&&(v=!0)}}),tn.over.addEventListener("mouseup",()=>{bs=null}),tn.over.addEventListener("click",()=>{if(v)return;let ot=tn.cursor.idx;ot!=null&&P[ot]&&(f=ot,t.forEach(({uplot:Mt})=>Mt.redraw(!1)),Ft&&Ft(P[ot],ot),rt&&rt(ot))}),L.addEventListener("dblclick",R);let vo=null;if(f!=null&&x[f]!=null&&S[f]!=null&&(xe(ke),ke.min!=null&&ke.max!=null)){let ot=ke.max-ke.min||1;vo=Math.min(ke.BINS-1,Math.floor((S[f]-ke.min)/ot*ke.BINS)),ln.hoveredHistY=S[f]}Le(Xt,ke,130,vo),_n(Xt,ke),G&&(A?G.insertBefore(L,A):G.appendChild(L))}function _t(){qt(),t.forEach(({uplot:l})=>l.batch(()=>l.redraw(!1)))}function qt(){t.forEach(({uplot:l,def:c})=>{let x=l._strasse;if(!x)return;let{selFill:S,anchorLine:H,anchorLabel:P,anchorHandle:B,anchorMarker:A,endLine:q,endLabel:J,endHandle:X,endMarker:Q}=x;if(g==null||u==null){[S,H,P,B,A,q,J,X,Q].forEach(Vt=>{Vt.style.display="none"});return}let et=l.valToPos(g,"x"),tt=l.valToPos(u,"x"),L=window.devicePixelRatio||1,wt=l.bbox,St=wt.width/L,ct=wt.height/L,Ct=(wt.top+wt.height)/L,pt=et>=0&&et<=St,xt=tt>=0&&tt<=St,kt=Math.max(0,et),Ot=Math.min(St,tt);if(Ot>kt?(S.style.left=`${kt}px`,S.style.width=`${Ot-kt}px`,S.style.top="0",S.style.height=`${ct}px`,S.style.backgroundColor=le(c.color,.07),S.style.display=""):S.style.display="none",pt){H.style.left=`${et}px`,H.style.height=`${ct}px`,H.style.borderLeftColor=c.color,H.style.display="";let Vt=Yt(g);P.textContent=Vt;let ne=Vt.length*7+10;P.style.left=et+ne+4Vt.style.display="none");if(xt){q.style.left=`${tt}px`,q.style.height=`${ct}px`,q.style.borderLeftColor=c.color,q.style.display="";let Vt=Yt(u);J.textContent=Vt;let ne=Vt.length*7+10;J.style.left=tt-ne-3>0?`${tt-ne-3}px`:`${tt+3}px`,J.style.display="",X.style.left=`${tt}px`,X.style.backgroundColor=c.color,X.style.display="",Q.style.left=`${tt}px`,Q.style.top=`${Ct}px`;let ie=Q.querySelector(".material-symbols-rounded");ie&&(ie.style.color=c.color),Q.style.display=""}else[q,J,X,Q].forEach(Vt=>Vt.style.display="none")})}function Yt(l){return F==="distance"?`${l.toFixed(2)} km`:he(l)}function ee(l,c,x,S){l.style.pointerEvents="auto",l.addEventListener("mousedown",H=>{H.stopPropagation(),H.preventDefault();let P=H.clientX,B=S?g:u,A=c.over.offsetWidth,q=c.scales.x.min,J=c.scales.x.max,X=A/(J-q),Q=[x[0],x[x.length-1]];document.body.style.cursor="ew-resize",v=!0;function et(L){let wt=L.clientX-P,St=(B||0)+wt/X;St=Math.max(Q[0],Math.min(Q[1],St)),S?g=Math.min(St,(u||Q[1])-.001):u=Math.max(St,(g||Q[0])+.001),t.forEach(ct=>ct.uplot._strasse?.updateHeaderStats(ct.uplot.scales.x.min,ct.uplot.scales.x.max)),_t(),De(),lt&<(g,u,F)}function tt(){document.body.style.cursor="",v=!1,document.removeEventListener("mousemove",et),document.removeEventListener("mouseup",tt)}document.addEventListener("mousemove",et),document.addEventListener("mouseup",tt)})}function xe(l){let{yData:c,xData:x,BINS:S}=l;if(l._lastYData===c&&l.bins)return;l._lastYData=c;let H=l.min,P=l.max;if(H==null||P==null){let Q=1/0,et=-1/0,tt=0;for(let L=0;Let&&(et=wt),tt++)}if(!tt)return;H=Q,P=et,l.min=H,l.max=P}let B=new Array(S).fill(0),A=new Array(S).fill(0),q=P-H||1,J=l.plot?.metricKey??Object.keys(qe).find(Q=>qe[Q]===l.def),X=!J||M.has(J)||J!=="power"&&J!=="cadence"&&J!=="speed";for(let Q=0;Q0&&x[Q-1]!=null?x[Q-1]:x[Q],wt=Q{Le(l,c,x.height)})}function Le(l,c,x,S=null){let{def:H,BINS:P}=c;xe(c);let{bins:B,min:A,max:q}=c;if(!B||A==null||q==null)return;let J=g!=null&&u!=null;if(J&&(c._lastSelRange?.[0]!==g||c._lastSelRange?.[1]!==u)){c._lastSelRange=[g,u];let mt=new Array(P).fill(0),Kt=new Array(P).fill(0),{yData:Xt,xData:te}=c,de=q-A||1,fe=c.plot?.metricKey??Object.keys(qe).find(Qt=>qe[Qt]===c.def),ge=!fe||M.has(fe)||fe!=="power"&&fe!=="cadence"&&fe!=="speed";for(let Qt=0;Qtu)continue;let Be=Math.min(P-1,Math.floor((ue-A)/de*P));mt[Be]++;let Je=Qt>0&&te[Qt-1]!=null?te[Qt-1]:te[Qt],Ae=QtH.fmtAxis(mt),ct="9px system-ui, sans-serif";L.font!==ct&&(L.font=ct);let pt={t:4,r:0,b:30,l:Math.ceil(Math.max(L.measureText(`${St(q)} ${H.unit}`).width,L.measureText(`${St(A)} ${H.unit}`).width))+6};c.padL=pt.l;let xt=et-pt.l-pt.r,kt=tt-pt.t-pt.b,Ot=mt=>pt.t+(P-1-mt)*(kt/P),Vt=kt/P-1,ne=J?.15:.6;L.fillStyle=le(H.color,ne);for(let mt=0;mtmt+Kt,0);if(ie>0){let mt=[{x:pt.l,y:pt.t+kt}],Kt=0;for(let Xt=0;XtXt+te+2&&mt0){let mt=0;for(let ue=0;ue{let H=no(l,c,S);if(H!=null&&x){let{min:P,max:B,BINS:A}=c,q=B-P||1;x.pinnedHistY=P+(H+.5)*(q/A),t.forEach(({uplot:J})=>J.redraw(!1))}}),l.addEventListener("mousemove",S=>{p=S,so(S,l,c)}),l.addEventListener("mouseenter",()=>{_=l,E=c}),l.addEventListener("mouseleave",()=>{_===l&&(_=null,E=null),C&&(C.style.display="none");let S=document.getElementById("hist-line");S&&(S.style.display="none"),x&&(x.hoveredHistY=null,Le(l,c,l.height/(window.devicePixelRatio||1)))})}function no(l,c,x){let{bins:S,BINS:H}=c;if(!S)return null;let P=l.getBoundingClientRect(),B=x.clientY-P.top,A={t:4,b:30},q=P.height-A.t-A.b,J=Math.floor((B-A.t)/q*H),X=H-1-J;return J<0||J>=H?null:X}function so(l,c,x){if(!C)return;let{bins:S,binAccum:H,min:P,max:B,BINS:A,def:q,plot:J}=x;if(!S||!H||P==null||B==null)return;let X=document.getElementById("hist-line"),Q=no(c,x,l);if(Q==null||!S[Q]){C.style.display="none",X&&(X.style.display="none"),J&&(J.hoveredHistY=null,Le(c,x,c.height/(window.devicePixelRatio||1)));return}if(J){let te=B-P||1;J.hoveredHistY=P+(Q+.5)*(te/A),Le(c,x,c.height/(window.devicePixelRatio||1),Q)}let et=S[Q],tt=S.reduce((te,de)=>te+de,0),L=et/tt*100,wt=B-P||1,St=P+Q*(wt/A),ct=P+(Q+1)*(wt/A),Ct=`${q.fmt(St,!0)} \u2013 ${q.fmt(ct,!0)} ${q.unit}`,pt="",xt=(St+ct)/2,kt=Object.keys(qe).find(te=>qe[te]===q),Ot=[];if(kt==="power"?Ot=$n.getPowerZones():kt==="hr"&&(Ot=$n.getHRZones()),Ot.length>0){let te=Ot.findIndex(fe=>xt>=fe.min&&xt=Ot[Ot.length-1].min?Ot[Ot.length-1]:null;if(de){let fe=te!==-1?te:Ot.length-1;pt=` -
- Z${fe+1} + `);return}F&&(F.style.display="none");let ue=I?I.getBoundingClientRect().width:800,ye=Math.round(Math.max(100,ue-A-(x?N+S:0))),ve=T&&e===h&&n===f&&r===se&&s===we&&t.length>0,Z;if(ve)Z=t[0].xData;else if(f==="distance")Z=O.map(je=>(je.dist||0)/1e3);else{let je=O.find(ze=>ze.time!=null)?.time||0,_e=0;Z=O.map(ze=>(ze.time!=null&&(_e=(ze.time-je)/1e3),_e))}let Be=new Map;if(ve){C&&(C.style.display="none");let je=new Set(ce);for(let _e of t){let ze=d.has(_e.metricKey),Re=p.has(_e.metricKey);je.has(_e.metricKey)&&_e.smoothed===ze&&_e.incZero===Re&&_e.w===ye?Be.set(_e.metricKey,_e):(i.unsub(_e.uplot),_e.uplot.destroy(),_e.row.remove())}t=[]}else Yg(T);if(I){let je=new Array(ce.length).fill(null),_e=null;for(let ze=ce.length-1;ze>=0;ze--){je[ze]=_e;let Re=Be.get(ce[ze]);Re&&(_e=Re.row)}ce.forEach((ze,Re)=>{let Le=Be.get(ze);if(Le){t.push(Le);let Me=Le.uplot,zt=Me._strasse,Lt=o;o=!0,Me.batch(()=>{_&&(Me.scales.x.min!==_[0]||Me.scales.x.max!==_[1])?Me.setScale("x",{min:_[0],max:_[1]}):(zt?.updateHeaderStats(Me.scales.x.min,Me.scales.x.max,Me),Me.redraw(!1))}),o=Lt;let Yt=null;if(D!=null&&Le.xData[D]!=null&&Le.yData[D]!=null&&(Un(Le.histData),Le.histData.min!=null&&Le.histData.max!=null)){let zn=Le.histData.max-Le.histData.min||1;Yt=Math.min(Le.histData.BINS-1,Math.floor((Le.yData[D]-Le.histData.min)/zn*Le.histData.BINS)),Le.hoveredHistY=Le.yData[D]}La(Le.histCanvas,Le.histData,130,Yt);return}let We=mi[ze],gt=We.transform,mt=We.fmt,Qt=We.fmtAxis,rn=We.unit,$n=We.label;ze==="speed"&&se==="pace"&&($n="Pace",rn=`min/${ge}`,mt=Me=>qp(Me),Qt=Me=>qp(Me),gt=Me=>Me==null||Me<.1?null:(ge==="km"?1e3:100)/Me,We={...We,label:$n,unit:rn,fmt:mt,fmtAxis:Qt,transform:gt});let xn=We.compute?We.compute(O,pF):pF(O.map(Me=>{let zt=Me[We.field];return zt!=null&>?gt(zt):zt}));d.has(ze)&&(xn=Hg(xn,We.smoothSigma||2)),ht(ze,We,Z,xn,ye,O,_,je[Re])})}e=h,n=f,r=se,s=we,fF(h),g!=null&&v!=null&&Tt(),et(),we&&Pt(),T&&I&&R>0&&(I.scrollTop=R)}function ht(T,_,R,O,Q,W,te=null,X=null){let se=h?.sport,ce=(se?Fi[se.toLowerCase()]:null)?.defaultPreset||"speed",ye=It.get().speed_mode||ce,ve=T==="elevation"?rG(W,20):null,Z=document.createElement("div");Z.className="chart-row",Z.dataset.metric=T,Z.style.setProperty("--chart-color",_.color);let Be=document.createElement("div");Be.className=`chart-row-header${x?" with-histogram":""}`;let je=document.createElement("div");je.className="chart-row-label-group",je.innerHTML=` + ${_.icon} + ${_.label} + `;let _e=document.createElement("button");_e.className=`icon-btn mini smooth-btn${d.has(T)?" active":""}`,_e.title="Toggle data smoothing",_e.innerHTML=`${d.has(T)?"blur_on":"blur_off"}`,_e.addEventListener("click",Ee=>{Ee.stopPropagation(),d.has(T)?d.delete(T):d.add(T),ot(!0)});let ze=document.createElement("button");ze.className=`map-color-btn icon-btn${we===T?" active":""}`,ze.dataset.metric=T,ze.title="Color map track by this metric",ze.innerHTML='colorize',ze.addEventListener("click",()=>Ne(T));let Re=null;if(T==="cadence"||T==="power"||T==="speed"){Re=document.createElement("button");let Ee=p.has(T);Re.className=`icon-btn mini${Ee?" active":""}`,Re.title=Ee?"Currently INCLUDING 0 values":"Currently EXCLUDING 0 values",Re.innerHTML=`${Ee?"exposure_zero":"mobile_off"}`,Re.addEventListener("click",qe=>{qe.stopPropagation(),p.has(T)?p.delete(T):p.add(T),ot(!0)})}let Le=document.createElement("div");Le.className="chart-stats-total";let We=document.createElement("div");We.className="chart-stats-selection";let gt=document.createElement("div");gt.className="chart-row-stats-container",gt.append(Le,We);let mt=document.createElement("div");mt.className="chart-row-actions",mt.append(_e,ze);let Qt=document.createElement("div");if(Qt.className="chart-row-right-actions",T==="speed"){let Ee=document.createElement("div");Ee.className="seg-ctrl",Ee.innerHTML=` + + + `,Ee.addEventListener("click",qe=>{let Kt=qe.target.closest(".seg-btn");if(!Kt)return;let Jt=Kt.dataset.mode;if(Jt==="speed"||Jt==="pace"){let wt=Jt===ce;It.patch({speed_mode:wt?null:Jt}),ot(!0)}}),Qt.append(Ee)}Re&&Qt.append(Re),Be.append(je,mt,gt,Qt);let rn=document.createElement("div");rn.className="chart-row-body";let $n=document.createElement("div");$n.style.position="relative",rn.appendChild($n);let xn=document.createElement("div");xn.className="fixed-x-label fixed-x-min";let Me=document.createElement("div");Me.className="fixed-x-label fixed-x-max",$n.append(xn,Me);let zt=document.createElement("div");zt.className=`hist-col${x?" visible":""}`;let Lt=document.createElement("canvas");Lt.className="hist-canvas",zt.appendChild(Lt),rn.appendChild(zt),Z.append(Be,rn);let Yt=f==="distance";function zn(Ee,qe){if(Ee==null)return"";if(Yt){let Kt=qe<1?3:qe<5?2:qe<20?1:0;return`${Ee.toFixed(Kt)} km`}else{let Kt=Math.abs(Ee),Jt=Math.floor(Kt/3600),wt=Math.floor(Kt%3600/60),ts=Math.round(Kt%60),Tr=Jt>0?`${Jt}:`:"",mo=Jt>0?String(wt).padStart(2,"0"):String(wt),Ys=String(ts).padStart(2,"0");return`${Ee<0?"-":""}${Tr}${mo}:${Ys}`}}let cr=p.has(T)||T!=="power"&&T!=="cadence"&&T!=="speed",ur=1/0,Vt=-1/0,Gn=0,qr=0,Is=1/0,Oa=-1/0,ms=0,jl=0;for(let Ee=0;EeVt&&(Vt=qe),Gn+=qe,qr++,(qe!==0||cr)&&(qeOa&&(Oa=qe),ms+=qe,jl++))}qr===0&&(ur=0,Vt=100);let FD=qr?{min:ur,max:Vt,avg:Gn/qr}:null,iw=jl?{min:Is,max:Oa,avg:ms/jl}:null,gF=Math.abs(Vt-ur)*.1||1,oG=[ur-gF,Vt+gF],vF=!1;function LD(Ee,qe,Kt){let Jt=p.has(T)||T!=="power"&&T!=="cadence"&&T!=="speed",wt=qe-Ee;xn.textContent=zn(Ee,wt),Me.textContent=zn(qe,wt);let ts=(Tr,mo,Ys=!1)=>{let gi=Ys&&Jt===cr?iw:iF(R,O,Tr,mo,Jt);if(!gi)return"";let ql=` + align_flex_end${_.fmt(gi.min,!0)} ${_.unit} + align_center${_.fmt(gi.avg,!0)} ${_.unit} + align_flex_start${_.fmt(gi.max,!0)} ${_.unit} + `;if(T==="elevation"){let Yo=Qz(W,Tr,mo);ql+=` + trending_up+${Math.round(Yo.gain)} m + trending_down-${Math.round(Yo.loss)} m + `}return ql};vF||(vF=!0,Le.innerHTML=`all_inclusive${ts(R[0],R[R.length-1],!0)}`,Le.querySelector(".all-chip")?.addEventListener("click",Tr=>{Tr.stopPropagation(),Ue()})),g!==null&&v!==null?(We.innerHTML=ts(g,v,!1),We.style.display="flex",We.style.setProperty("--sel-color",_.color)):We.style.display="none"}let aG=!1,lG={width:Q,height:130,padding:[4,0,0,0],cursor:{sync:{key:i.key},drag:{x:!0,y:!1,uni:16},focus:{prox:16},points:{size:7,stroke:"#0e0e10",width:2,fill:T==="elevation"?(Ee,qe)=>nw(ve?ve[Ee.cursor.idx]:null):_.color},x:!1,y:!1},select:{show:!0,left:0,top:0,width:0,height:0},legend:{show:!1},scales:{x:{time:!1,range:(Ee,qe,Kt)=>[qe,Kt],min:te?te[0]:void 0,max:te?te[1]:void 0},y:{range:()=>oG,dir:T==="speed"&&ye==="pace"?-1:1}},axes:[{side:2,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{show:!0,stroke:"#2e2e34"},size:30,space:80,font:"10px system-ui, sans-serif",splits:(Ee,qe,Kt,Jt)=>{let wt=Jt-Kt,Tr=(Ee.bbox.width>0?Ee.bbox.width:Ee.width)/80,mo=wt/Tr,Ys;Yt?Ys=[.01,.02,.05,.1,.2,.25,.5,1,2,5,10,20,50,100,200,500,1e3,2e3,5e3,1e4,2e4,5e4,1e5,2e5,5e5,1e6]:Ys=[1,2,5,10,15,30,60,120,300,600,900,1800,3600,7200,14400,28800,43200,86400,604800,2592e3,31536e3];let gi=Ys[Ys.length-1];for(let Xo=0;Xo=mo){gi=Ys[Xo];break}let ql=[],Yo=Math.ceil(Kt/gi)*gi,hw=gi<1?2:0;for(;Yo<=Jt;){let Xo=Ee.valToPos(Yo,"x",!0);Xo>=Ee.bbox.left+80&&Xo<=Ee.bbox.left+Ee.bbox.width-80&&ql.push(Number(Yo.toFixed(hw))),Yo+=gi}return ql},values:(Ee,qe)=>{let Kt=(Ee.scales.x?.max??1)-(Ee.scales.x?.min??0);return qe.map(Jt=>{if(Jt==null)return"";let wt=Ee.valToPos(Jt,"x",!0);return wtEe.bbox.left+Ee.bbox.width-80?null:zn(Jt,Kt)})}},{side:3,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},ticks:{stroke:"#2e2e34"},size:55,font:"10px system-ui, sans-serif",values:(Ee,qe)=>qe.map(Kt=>Kt!=null?_.fmtAxis(Kt):"")}],series:[{},{label:_.label,stroke:"rgba(0,0,0,0)",width:0,points:{show:!1},paths:()=>null}],hooks:{draw:[Ee=>{let qe=Ee.bbox.top+Ee.bbox.height+5;xn.style.top=`${qe}px`,xn.style.left=`${Ee.bbox.left}px`,Me.style.top=`${qe}px`,Me.style.left=`${Ee.bbox.left+Ee.bbox.width}px`,Me.style.transform="translateX(-100%)"},Ee=>{T==="gears"?mF(Ee,R,O,_.color,1.5,T,null,W):T==="elevation"?Kz(Ee,R,O,ve):T==="gradient"?Jz(Ee,R,O):we===T?iG(Ee,R,O,W,T):mF(Ee,R,O,_.color,1.5,T,null,W)},Ee=>{let qe=t.find(Jt=>Jt.uplot===Ee);if(!qe)return;let Kt=Ee._strasse;D!=null?eG(Ee,R,O,_.color,_,W,T):(Kt&&Kt.pinYVal&&(Kt.pinYVal.style.display="none"),qe.pinnedHistY!=null&&tG(Ee,R,O,qe.pinnedHistY,_.color,_))},Ee=>{let qe=Ee.cursor.idx,Kt=D!=null,Jt=qe!=null&&Ee.cursor.left>=0;if(Jt&&D==null){let wt=Ee.valToPos(O[qe],"y",!0);Math.abs(Ee.cursor.top-wt)>100&&(Jt=!1)}if(Jt&&qe!==D&&cF(Ee,W,qe,en(_.color,.4),1),g!=null&&v!=null){let wt=Ee.ctx,ts=window.devicePixelRatio||1,Tr=Ee.bbox,mo=Ee.valToPos(g,"x",!0),Ys=Ee.valToPos(v,"x",!0);wt.save(),wt.beginPath(),wt.lineWidth=3*ts,wt.strokeStyle=_.color,wt.moveTo(mo,Tr.top+Tr.height),wt.lineTo(Ys,Tr.top+Tr.height),wt.stroke();let gi=Math.abs(v-g),ql=f==="distance"?`${gi.toFixed(2)} km`:Nn(gi),Yo=9*ts,hw=`bold ${Yo}px system-ui, sans-serif`;wt.font!==hw&&(wt.font=hw);let Xo=wt.measureText(ql).width,bF=Math.max(Tr.left,mo),wF=Math.min(Tr.left+Tr.width,Ys);if(wF-bF>Xo+14*ts){let uG=5*ts,dG=2*ts,mw=Xo+uG*2,gw=Yo+dG*2,BD=(bF+wF)/2-mw/2,$D=Tr.top+Tr.height-gw/2;wt.beginPath(),wt.roundRect?wt.roundRect(BD,$D,mw,gw,3*ts):wt.rect(BD,$D,mw,gw),wt.fillStyle=_.color,wt.fill(),wt.fillStyle="#000",wt.textAlign="center",wt.textBaseline="middle",wt.fillText(ql,BD+mw/2,$D+gw/2)}wt.restore()}Kt&&uF(Ee,W,D,_.color,!0,.7),Jt&&qe!==D&&uF(Ee,W,qe,_.color,!0,1)}],setCursor:[Ee=>{if(o)return;let qe=Ee.cursor.idx;Ee.redraw(!1),Ee.cursor.left>=0?B=Ee.posToVal(Ee.cursor.left,"x"):B=null;let Kt=Ee._strasse,Jt=qe!=null&&O[qe]!=null;if(Jt&&D==null){let wt=Ee.valToPos(O[qe],"y",!0);Math.abs(Ee.cursor.top-wt)>100&&(Jt=!1)}if(Kt&&(Jt?oF(Ee,Kt.curYVal,qe,R,O,W,_,T):Kt.curYVal.style.display="none"),a||(qe!=null&&W[qe]?U&&(D!=null||Jt)?U(W[qe]):U&&!Jt&&U(null):qe===null&&U&&U(null)),qe!=null&&O[qe]!=null){let{min:wt,max:ts}=es;if(wt!=null&&ts!=null){let Tr=ts-wt||1,mo=Math.min(es.BINS-1,Math.floor((O[qe]-wt)/Tr*es.BINS));Ul.hoveredHistY!==O[qe]&&(Ul.hoveredHistY=O[qe],La(Lt,es,130,mo))}}else Ul.hoveredHistY!==null&&(Ul.hoveredHistY=null,La(Lt,es,130))}],setScale:[(Ee,qe)=>{if(qe!=="x"||aG)return;let{min:Kt,max:Jt}=Ee.scales.x;G=[Kt,Jt],LD(Kt,Jt,Ee),!o&&(b||(Se=null),o=!0,t.forEach(({uplot:wt})=>{wt!==Ee&&wt.batch(()=>wt.setScale("x",{min:Kt,max:Jt}))}),o=!1,at(),Ar(),ee&&g!==null&&ee(g,v,f))}],setSelect:[Ee=>{if(b)return;Se=null;let{left:qe,width:Kt}=Ee.select;if(Kt>0){let Jt=Ee.posToVal(qe,"x"),wt=Ee.posToVal(qe+Kt,"x");g=Jt,v=wt,LD(Ee.scales.x.min,Ee.scales.x.max,Ee),at(),Ar(),ee&&ee(g,v,f),Ee.setSelect({left:0,top:0,width:0,height:0},!1)}}]}},OD=document.createElement("div");OD.style.cssText="position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:5";let ow=document.createElement("div");ow.className="sel-fill",ow.style.display="none";let aw=document.createElement("div");aw.className="sel-line sel-line-anchor",aw.style.display="none";let lw=document.createElement("div");lw.className="sel-line-label sel-line-label-anchor",lw.style.display="none";let Kg=document.createElement("div");Kg.className="sel-handle sel-handle-anchor",Kg.style.display="none";let Jg=document.createElement("div");Jg.className="sel-graph-marker",Jg.innerHTML=`play_circle`,Jg.style.display="none";let cw=document.createElement("div");cw.className="sel-line sel-line-end",cw.style.display="none";let uw=document.createElement("div");uw.className="sel-line-label sel-line-label-end",uw.style.display="none";let ev=document.createElement("div");ev.className="sel-handle sel-handle-end",ev.style.display="none";let tv=document.createElement("div");tv.className="sel-graph-marker",tv.innerHTML=`stop_circle`,tv.style.display="none";let dw=document.createElement("div");dw.className="cur-y-val",dw.style.cssText=`color:${_.color};display:none`;let pw=document.createElement("div");pw.className="cur-y-val pin",pw.style.cssText=`color:${_.color};display:none`,OD.append(ow,aw,lw,Kg,Jg,cw,uw,ev,tv,dw,pw);let es={yData:O,xData:R,def:_,BINS:24,min:qr?ur:void 0,max:qr?Vt:void 0,fullStats:iw,fullStatsAll:FD},Ul={uplot:null,row:Z,xData:R,yData:O,def:_,metricKey:T,statsTotalEl:Le,statsSelEl:We,histCol:zt,histCanvas:Lt,histData:es,hoveredHistY:null,pinnedHistY:null,smoothed:d.has(T),incZero:p.has(T),w:Q};es.plot=Ul;let cG=o;o=!0;let Ba=new ez(lG,[R,O],(Ee,qe)=>{Ul.uplot=Ee,t.push(Ul),$n.appendChild(Ee.root),Ee.over.appendChild(OD),Ee._strasse={selFill:ow,anchorLine:aw,anchorLabel:lw,anchorHandle:Kg,anchorMarker:Jg,endLine:cw,endLabel:uw,endHandle:ev,endMarker:tv,curYVal:dw,pinYVal:pw,updateHeaderStats:LD},Ee.batch(()=>{qe()})});o=cG,Zt(Kg,Ba,R,!0),Zt(ev,Ba,R,!1);let fw=null;Ba.over.addEventListener("mousedown",Ee=>{if(Ee.button!==0)return;w=!1;let qe=Ba.over.getBoundingClientRect();fw=Ee.clientX-qe.left}),Ba.over.addEventListener("mousemove",Ee=>{if(fw!==null){let qe=Ba.over.getBoundingClientRect();Math.abs(Ee.clientX-qe.left-fw)>5&&(w=!0)}}),Ba.over.addEventListener("mouseup",()=>{fw=null}),Ba.over.addEventListener("click",()=>{if(w)return;let Ee=Ba.cursor.idx;Ee!=null&&W[Ee]&&(D=Ee,t.forEach(({uplot:qe})=>qe.redraw(!1)),xe&&xe(W[Ee],Ee),Ze&&Ze(Ee))}),Z.addEventListener("dblclick",Ue);let yF=null;if(D!=null&&R[D]!=null&&O[D]!=null&&(Un(es),es.min!=null&&es.max!=null)){let Ee=es.max-es.min||1;yF=Math.min(es.BINS-1,Math.floor((O[D]-es.min)/Ee*es.BINS)),Ul.hoveredHistY=O[D]}La(Lt,es,130,yF),Xz(Lt,es),I&&(X?I.insertBefore(Z,X):I.appendChild(Z))}function at(){Tt(),t.forEach(({uplot:T})=>T.batch(()=>T.redraw(!1)))}function Tt(){t.forEach(({uplot:T,def:_})=>{let R=T._strasse;if(!R)return;let{selFill:O,anchorLine:Q,anchorLabel:W,anchorHandle:te,anchorMarker:X,endLine:se,endLabel:ge,endHandle:ce,endMarker:ue}=R;if(g==null||v==null){[O,Q,W,te,X,se,ge,ce,ue].forEach(mt=>{mt.style.display="none"});return}let ye=T.valToPos(g,"x"),ve=T.valToPos(v,"x"),Z=window.devicePixelRatio||1,Be=T.bbox,je=Be.width/Z,_e=Be.height/Z,ze=(Be.top+Be.height)/Z,Re=ye>=0&&ye<=je,Le=ve>=0&&ve<=je,We=Math.max(0,ye),gt=Math.min(je,ve);if(gt>We?(O.style.left=`${We}px`,O.style.width=`${gt-We}px`,O.style.top="0",O.style.height=`${_e}px`,O.style.backgroundColor=en(_.color,.07),O.style.display=""):O.style.display="none",Re){Q.style.left=`${ye}px`,Q.style.height=`${_e}px`,Q.style.borderLeftColor=_.color,Q.style.display="";let mt=Ft(g);W.textContent=mt;let Qt=mt.length*7+10;W.style.left=ye+Qt+4mt.style.display="none");if(Le){se.style.left=`${ve}px`,se.style.height=`${_e}px`,se.style.borderLeftColor=_.color,se.style.display="";let mt=Ft(v);ge.textContent=mt;let Qt=mt.length*7+10;ge.style.left=ve-Qt-3>0?`${ve-Qt-3}px`:`${ve+3}px`,ge.style.display="",ce.style.left=`${ve}px`,ce.style.backgroundColor=_.color,ce.style.display="",ue.style.left=`${ve}px`,ue.style.top=`${ze}px`;let rn=ue.querySelector(".material-symbols-rounded");rn&&(rn.style.color=_.color),ue.style.display=""}else[se,ge,ce,ue].forEach(mt=>mt.style.display="none")})}function Ft(T){return f==="distance"?`${T.toFixed(2)} km`:Nn(T)}function Zt(T,_,R,O){T.style.pointerEvents="auto",T.addEventListener("mousedown",Q=>{Q.stopPropagation(),Q.preventDefault();let W=Q.clientX,te=O?g:v,X=_.over.offsetWidth,se=_.scales.x.min,ge=_.scales.x.max,ce=X/(ge-se),ue=[R[0],R[R.length-1]];document.body.style.cursor="ew-resize",w=!0;function ye(Z){let Be=Z.clientX-W,je=(te||0)+Be/ce;je=Math.max(ue[0],Math.min(ue[1],je)),O?g=Math.min(je,(v||ue[1])-.001):v=Math.max(je,(g||ue[0])+.001),t.forEach(_e=>_e.uplot._strasse?.updateHeaderStats(_e.uplot.scales.x.min,_e.uplot.scales.x.max)),at(),Ar(),ee&&ee(g,v,f)}function ve(){document.body.style.cursor="",w=!1,document.removeEventListener("mousemove",ye),document.removeEventListener("mouseup",ve)}document.addEventListener("mousemove",ye),document.addEventListener("mouseup",ve)})}function Un(T){let{yData:_,xData:R,BINS:O}=T;if(T._lastYData===_&&T.bins)return;T._lastYData=_;let Q=T.min,W=T.max;if(Q==null||W==null){let ue=1/0,ye=-1/0,ve=0;for(let Z=0;Z<_.length;Z++){let Be=_[Z];Be==null||!isFinite(Be)||(Beye&&(ye=Be),ve++)}if(!ve)return;Q=ue,W=ye,T.min=Q,T.max=W}let te=new Array(O).fill(0),X=new Array(O).fill(0),se=W-Q||1,ge=T.plot?.metricKey??Object.keys(mi).find(ue=>mi[ue]===T.def),ce=!ge||p.has(ge)||ge!=="power"&&ge!=="cadence"&&ge!=="speed";for(let ue=0;ue<_.length;ue++){let ye=_[ue];if(ye==null||!isFinite(ye)||ye===0&&!ce)continue;let ve=Math.min(O-1,Math.floor((ye-Q)/se*O));te[ve]++;let Z=ue>0&&R[ue-1]!=null?R[ue-1]:R[ue],Be=ue{La(T,_,R.height)})}function La(T,_,R,O=null){let{def:Q,BINS:W}=_;Un(_);let{bins:te,min:X,max:se}=_;if(!te||X==null||se==null)return;let ge=g!=null&&v!=null;if(ge&&(_._lastSelRange?.[0]!==g||_._lastSelRange?.[1]!==v)){_._lastSelRange=[g,v];let Me=new Array(W).fill(0),zt=new Array(W).fill(0),{yData:Lt,xData:Yt}=_,zn=se-X||1,cr=_.plot?.metricKey??Object.keys(mi).find(Vt=>mi[Vt]===_.def),ur=!cr||p.has(cr)||cr!=="power"&&cr!=="cadence"&&cr!=="speed";for(let Vt=0;Vtv)continue;let Is=Math.min(W-1,Math.floor((Gn-X)/zn*W));Me[Is]++;let Oa=Vt>0&&Yt[Vt-1]!=null?Yt[Vt-1]:Yt[Vt],ms=VtQ.fmtAxis(Me),_e="9px system-ui, sans-serif";Z.font!==_e&&(Z.font=_e);let Re={t:4,r:0,b:30,l:Math.ceil(Math.max(Z.measureText(`${je(se)} ${Q.unit}`).width,Z.measureText(`${je(X)} ${Q.unit}`).width))+6};_.padL=Re.l;let Le=ye-Re.l-Re.r,We=ve-Re.t-Re.b,gt=Me=>Re.t+(W-1-Me)*(We/W),mt=We/W-1,Qt=ge?.15:.6;Z.fillStyle=en(Q.color,Qt);for(let Me=0;MeMe+zt,0);if(rn>0){let Me=[{x:Re.l,y:Re.t+We}],zt=0;for(let Lt=0;LtLt+Yt+2&&Me0){let Me=0;for(let Gn=0;Gn{let Q=rF(T,_,O);if(Q!=null&&R){let{min:W,max:te,BINS:X}=_,se=te-W||1;R.pinnedHistY=W+(Q+.5)*(se/X),t.forEach(({uplot:ge})=>ge.redraw(!1))}}),T.addEventListener("mousemove",O=>{M=O,sF(O,T,_)}),T.addEventListener("mouseenter",()=>{j=T,$=_}),T.addEventListener("mouseleave",()=>{j===T&&(j=null,$=null),C&&(C.style.display="none");let O=document.getElementById("hist-line");O&&(O.style.display="none"),R&&(R.hoveredHistY=null,La(T,_,T.height/(window.devicePixelRatio||1)))})}function rF(T,_,R){let{bins:O,BINS:Q}=_;if(!O)return null;let W=T.getBoundingClientRect(),te=R.clientY-W.top,X={t:4,b:30},se=W.height-X.t-X.b,ge=Math.floor((te-X.t)/se*Q),ce=Q-1-ge;return ge<0||ge>=Q?null:ce}function sF(T,_,R){if(!C)return;let{bins:O,binAccum:Q,min:W,max:te,BINS:X,def:se,plot:ge}=R;if(!O||!Q||W==null||te==null)return;let ce=document.getElementById("hist-line"),ue=rF(_,R,T);if(ue==null||!O[ue]){C.style.display="none",ce&&(ce.style.display="none"),ge&&(ge.hoveredHistY=null,La(_,R,_.height/(window.devicePixelRatio||1)));return}if(ge){let Yt=te-W||1;ge.hoveredHistY=W+(ue+.5)*(Yt/X),La(_,R,_.height/(window.devicePixelRatio||1),ue)}let ye=O[ue],ve=O.reduce((Yt,zn)=>Yt+zn,0),Z=ye/ve*100,Be=te-W||1,je=W+ue*(Be/X),_e=W+(ue+1)*(Be/X),ze=`${se.fmt(je,!0)} \u2013 ${se.fmt(_e,!0)} ${se.unit}`,Re="",Le=(je+_e)/2,We=Object.keys(mi).find(Yt=>mi[Yt]===se),gt=[];if(We==="power"?gt=Ol.getPowerZones():We==="hr"&&(gt=Ol.getHRZones()),gt.length>0){let Yt=gt.findIndex(cr=>Le>=cr.min&&Le=gt[gt.length-1].min?gt[gt.length-1]:null;if(zn){let cr=Yt!==-1?Yt:gt.length-1;Re=` +
+ Z${cr+1} \xB7 - ${de.name} -
- `}}let Vt=F==="distance"?`${H[Q].toFixed(2)} km`:he(H[Q]),ne=H[Q]/H.reduce((te,de)=>te+de,0)*100,ie=` -
${Ct}
- ${pt} - `;if(Vt&&(ie+=`
- ${F==="distance"?"Dist":"Time"} - ${Vt} - ${ne.toFixed(1)}% -
`),x.selBins&&x.selBinAccum){let te=F==="distance"?`${x.selBinAccum[Q].toFixed(2)} km`:he(x.selBinAccum[Q]),de=x.selBinAccum[Q]/x.selBinAccum.reduce((fe,ge)=>fe+ge,0)*100;ie+=` + ${zn.name} +
+ `}}let mt=f==="distance"?`${Q[ue].toFixed(2)} km`:Nn(Q[ue]),Qt=Q[ue]/Q.reduce((Yt,zn)=>Yt+zn,0)*100,rn=` +
${ze}
+ ${Re} + `;if(mt&&(rn+=`
+ ${f==="distance"?"Dist":"Time"} + ${mt} + ${Qt.toFixed(1)}% +
`),R.selBins&&R.selBinAccum){let Yt=f==="distance"?`${R.selBinAccum[ue].toFixed(2)} km`:Nn(R.selBinAccum[ue]),zn=R.selBinAccum[ue]/R.selBinAccum.reduce((cr,ur)=>cr+ur,0)*100;rn+=`
- Sel ${F==="distance"?"Dist":"Time"} - ${te} - ${de.toFixed(1)}% + Sel ${f==="distance"?"Dist":"Time"} + ${Yt} + ${zn.toFixed(1)}%
- `}C.innerHTML=ie,C.style.display="block";let re=C.offsetHeight,ae=C.offsetWidth,mt=c.getBoundingClientRect(),Kt=mt.height-4-30,Xt=mt.top+4+(A-1-Q+.5)*(Kt/A);C.style.left=`${mt.left-ae-12}px`,C.style.top=`${Xt-re/2}px`,X&&(X.style.display="block",X.style.top=`${Xt}px`,X.style.left="0px",X.style.width=`${mt.left}px`)}function Rn(l=!1){C&&(C.style.display="none"),t.forEach(({uplot:c,row:x})=>{i.unsub(c),c.destroy(),x.remove()}),t=[],s=null,l||(g=null,u=null),v=!1}function oo(l,c,x,S,H=!0){let P=1/0,B=-1/0,A=0,q=0;for(let J=0;JS)continue;let X=c[J];X==null||!isFinite(X)||X===0&&!H||(XB&&(B=X),A+=X,q++)}return q?{min:P,max:B,avg:A/q}:null}function hl(l,c,x){let S=0,H=0,P=null,B=F==="distance",A=l[0].time||0;for(let q=0;qx)&&J.ele!=null){if(P!=null){let Q=J.ele-P;Q>0?S+=Q:Q<0&&(H+=Math.abs(Q))}P=J.ele}}return{gain:S,loss:H}}function lo(l,c,x,S,H,P,B,A){if(x==null||H[x]==null){c.style.display="none";return}let q=l.valToPos(S[x],"x",!1),J=l.valToPos(H[x],"y",!1),X="#888896",Q=0;if(x>0&&P[x]&&P[x-1]){let ct=P[x-1],Ct=P[x],pt=(Ct.dist||0)-(ct.dist||0);pt>.1&&Ct.ele!=null&&ct.ele!=null&&(Q=(Ct.ele-ct.ele)/pt*100,X=is(Q))}let et=A!=="elevation"?`${B.fmt(H[x],!1)} ${B.unit}`:`${B.fmt(H[x],!1)} ${B.unit} \u2220 ${Math.abs(Q).toFixed(1)}%`;if(A==="gearRear"&&P[x].gearRearTooth!=null)et=`${P[x].gearRearTooth}T (pos ${H[x]})`;else if(A==="gearFront"&&P[x].gearFrontTooth!=null)et=`${P[x].gearFrontTooth}T (pos ${H[x]})`;else if(A==="gears"){let ct=P[x],Ct=ct.gearFrontTooth!=null?`${ct.gearFrontTooth}T`:ct.gearFront!=null?`pos ${ct.gearFront}`:"",pt=ct.gearRearTooth!=null?`${ct.gearRearTooth}T`:ct.gearRear!=null?`pos ${ct.gearRear}`:"";(Ct||pt)&&(et+=` (${Ct} / ${pt})`)}c.innerHTML!==et&&(c.innerHTML=et);let tt=`${B.color}44`;c.style.color!==B.color&&(c.style.color=B.color),c.style.borderColor!==tt&&(c.style.borderColor=tt);let L=`${q}px`,wt=`${J}px`,St="translate(6px, -50%)";c.style.left!==L&&(c.style.left=L),c.style.top!==wt&&(c.style.top=wt),c.style.transform!==St&&(c.style.transform=St),c.style.display!==""&&(c.style.display="")}let io=new Map;function ao(l){let c=io.get(l);return c||(c=le(is(l),.8),io.set(l,c)),c}function bl(l,c,x,S){let H=l.ctx,P=l.bbox,B=window.devicePixelRatio||1,A=l.scales.x?.min??-1/0,q=l.scales.x?.max??1/0,J=l.scales.y?.min??0,X=l.scales.y?.max??100,Q=P.width/(q-A||1),et=P.height/(X-J||1),tt=P.top+P.height,L=l.series[0]?.idxs,wt=L?Math.max(1,L[0]):1,St=L?Math.min(c.length-1,L[1]+1):c.length-1,ct=Math.max(1,Math.floor((St-wt)/250));H.save(),H.lineWidth=1.5*B;let Ct=new Map,pt=wt-1;for(let xt=wt;xt<=St;xt+=ct){let kt=c[xt],Ot=c[pt];if(pt=xt,kt==null||x[xt]==null||Ot==null||x[xt-ct]==null||ktq)continue;let Vt=P.left+(Ot-A)*Q,ne=tt-(x[xt-ct]-J)*et,ie=P.left+(kt-A)*Q,re=tt-(x[xt]-J)*et,ae=S&&S[xt]!=null?Math.round(S[xt]/2)*2:null,mt=ao(ae),Kt=Ct.get(mt);Kt||(Kt=[],Ct.set(mt,Kt)),Kt.push(Vt,ne,ie,re)}for(let[xt,kt]of Ct){H.beginPath(),H.strokeStyle=xt;for(let Ot=0;OtA)continue;let Ot=H.left+(kt-B)*X,Vt=et-(x[pt-St]-q)*Q,ne=H.left+(xt-B)*X,ie=et-(x[pt]-q)*Q,re=Math.round(x[pt]/2)*2,ae=ao(re),mt=ct.get(ae);mt||(mt=[],ct.set(ae,mt)),mt.push(Ot,Vt,ne,ie)}for(let[pt,xt]of ct){S.beginPath(),S.strokeStyle=pt;for(let kt=0;kt{let kt=`bold ${10*B}px system-ui, sans-serif`;q.font!==kt&&(q.font=kt);let Vt=q.measureText(ct).width+10*B,ne=16*B,ie=Ct-Vt/2,re=Math.max(A.left,Math.min(A.left+A.width-Vt,ie)),ae=pt-ne/2;q.save(),q.globalAlpha=P,q.setLineDash([]),q.beginPath(),q.roundRect?q.roundRect(re,ae,Vt,ne,3*B):q.rect(re,ae,Vt,ne),q.fillStyle="rgba(14,14,16,0.92)",q.fill(),q.strokeStyle=le(S,.27),q.lineWidth=1*B,q.stroke(),q.fillStyle=S,q.textAlign="center",q.textBaseline="middle",q.fillText(ct,re+Vt/2,ae+ne/2+.5*B),q.restore()};H||ro(l,c,x,S,P);let St=16*B;wt(L,et,A.top+St/2,!0),wt(tt,et,A.top+A.height+15*B,!1)}function yl(l,c,x,S,H,P,B){if(f==null)return;let A=c[f],q=x[f];if(A==null||q==null)return;let J=l.valToPos(A,"x",!0),X=l.valToPos(q,"y",!0),Q=l.bbox,et=l.ctx,tt=window.devicePixelRatio||1;et.save(),et.beginPath(),et.strokeStyle=S,et.lineWidth=1.5*tt,et.moveTo(J,Q.top),et.lineTo(J,Q.top+Q.height),et.stroke(),et.beginPath(),et.setLineDash([3*tt,3*tt]),et.strokeStyle=le(S,.5),et.lineWidth=1*tt,et.moveTo(Q.left,X),et.lineTo(J,X),et.stroke(),et.beginPath(),et.setLineDash([]),et.arc(J,X,5*tt,0,Math.PI*2),et.fillStyle="#0e0e10",et.fill(),et.strokeStyle=S,et.lineWidth=2.5*tt,et.stroke(),et.restore();let L=l._strasse;L&&L.pinYVal&&lo(l,L.pinYVal,f,c,x,P,H,B)}function xl(l,c,x,S,H,P){let B=l.bbox,A=l.ctx,q=window.devicePixelRatio||1,J=l.valToPos(S,"y",!0),X=Math.max(B.top,Math.min(B.top+B.height,J));A.save(),A.beginPath(),A.setLineDash([4*q,4*q]),A.strokeStyle=le(H,.4),A.lineWidth=1*q,A.moveTo(B.left,X),A.lineTo(B.left+B.width,X),A.stroke(),wl(l,c,x,X,H);let Q=P.fmt(S,!0),et=`bold ${10*q}px system-ui, sans-serif`;A.font!==et&&(A.font=et);let L=A.measureText(Q).width+8*q,wt=16*q,St=B.left-L-2*q,ct=X-wt/2;A.beginPath(),A.setLineDash([]),A.roundRect?A.roundRect(St,ct,L,wt,3*q):A.rect(St,ct,L,wt),A.fillStyle="rgba(14,14,16,0.95)",A.fill(),A.strokeStyle=H,A.lineWidth=1*q,A.stroke(),A.fillStyle="#fff",A.textAlign="center",A.textBaseline="middle",A.fillText(Q,St+L/2,ct+wt/2+.5*q),A.restore()}function wl(l,c,x,S,H){let P=l.ctx,B=l.bbox,A=l.scales.x?.min??-1/0,q=l.scales.x?.max??1/0,J=l.scales.y?.min??0,X=l.scales.y?.max??100,Q=B.width/(q-A||1),et=B.height/(X-J||1),tt=l.scales.y?.dir??1,L=tt===-1?B.top:B.top+B.height,wt=tt===-1?et:-et,St=l.series[0]?.idxs,ct=St?Math.max(0,St[0]-1):0,Ct=St?Math.min(c.length-1,St[1]+1):c.length-1,pt=Math.max(1,Math.floor((Ct-ct)/250));P.save(),P.beginPath(),P.rect(B.left,B.top,B.width,B.height),P.clip(),P.fillStyle=le(H,.2),P.beginPath();let xt=!1,kt=!1,Ot=0;for(let Vt=ct;Vt<=Ct;Vt+=pt){let ne=c[Vt],ie=x[Vt];if(ne==null||ie==null||neq){xt&&(P.lineTo(Ot,S),P.closePath(),xt=!1);continue}let re=B.left+(ne-A)*Q,ae=L+(ie-J)*wt;Ot=re,ae>16,B=S>>8&255,A=S&255,q=H>>16,J=H>>8&255,X=H&255,Q=P+(q-P)*x,et=B+(J-B)*x,tt=A+(X-A)*x;return`#${((1<<24)+(Math.round(Q)<<16)+(Math.round(et)<<8)+Math.round(tt)).toString(16).slice(1)}`}function is(l){if(l==null)return"#888896";let c=Math.abs(l),x=Math.min(1,c/8);return l>0?Ve("#A8C8A0","#d73027",x):Ve("#A8C8A0","#4575b4",x)}function uo(l){if(l==null)return"#888896";let c=l*3.6;if(c<=5)return"#4575b4";if(c>=60)return"#d73027";if(c<=45){let x=(c-5)/40;return x<=.25?Ve("#4575b4","#91bfdb",x/.25):x<=.5?Ve("#91bfdb","#abdda4",(x-.25)/.25):x<=.75?Ve("#abdda4","#fee08b",(x-.5)/.25):Ve("#fee08b","#fc8d59",(x-.75)/.25)}else{let x=(c-45)/15;return Ve("#fc8d59","#d73027",x)}}function Tl(l,c){let x=new Array(l.length).fill(null);for(let S=0;S0&&(H.dist||0)-(l[P].dist||0)1&&l[B].ele!=null&&l[P].ele!=null&&(x[S]=(l[B].ele-l[P].ele)/A*100)}return x}function mo(l){let c=[...l];for(let x=0;x=0&&c[S]===null;)S--;let H=x+1;for(;H=0&&H=0?c[x]=c[S]:H{let J=document.querySelector(`#${A} .stat-value`);J&&(J.textContent=q)};x("stat-distance",c.totalDist!=null?`${(c.totalDist/1e3).toFixed(1)} km`:"\u2014"),x("stat-duration",c.duration!=null?he(Math.floor(c.duration/1e3)):"\u2014"),x("stat-elevation",c.elevGain!=null?`${Math.round(c.elevGain)} m`:"\u2014");let S=A=>{let q=t.find(Q=>Q.metricKey===A);if(!q)return A==="speed"?c.avgSpeed??null:A==="power"?c.avgPower??null:A==="cadence"?c.avgCadence??null:null;if(q.histData.fullStats!==void 0)return q.histData.fullStats?q.histData.fullStats.avg:null;let J=M.has(A)||A!=="power"&&A!=="cadence"&&A!=="speed",X=q.yData.filter(Q=>Q!=null&&(J||Q!==0));return X.length?X.reduce((Q,et)=>Q+et,0)/X.length:null},H=S("speed");x("stat-avg-speed",H!=null?`${(H*3.6).toFixed(1)} km/h`:"\u2014");let P=S("power");x("stat-avg-power",P!=null?`${Math.round(P)} W`:"\u2014");let B=S("cadence");x("stat-avg-cad",B!=null?`${Math.round(B)} rpm`:"\u2014"),x("stat-avg-hr",c.avgHR!=null?`${c.avgHR} bpm`:"\u2014"),x("stat-avg-temp",c.avgTemp!=null?`${c.avgTemp.toFixed(1)} \xB0C`:"\u2014")}let yn=16384,xn=new Float64Array(yn),kn=new Float64Array(yn),as=new Float64Array(yn),Nn=new Float64Array(yn),Bs=new Float64Array(yn),rs=new Float64Array(yn),Wn=new Float64Array(64),fo=[3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300,360];function Sl(l,c,x){if(!l.length)return 0;Wn.fill(0);let S=0;for(let H=0;H=St)continue;let pt=1/Ct,xt=0,kt=0,Ot=0;for(let Vt=L;Vt=Ct){xt-=rs[Vt-Ct],kt-=Nn[Vt-Ct];let ne=(xt+kt*.05)*pt;ne>Ot&&(Ot=ne)}S+=Ot*1e-4}for(let ct=L;ct0&&(Wn[Ct-1]+=.5),Ct<63&&(Wn[Ct+1]+=.5)}}}}for(let H=0;H<64;H++)S+=Wn[H]*1e-5;return G&&(G.dataset.intervalScore=S.toFixed(2)),S}return{init:$t,loadTrack:z,clear:D,resetState:it,toggleMetric:K,setXAxis:Ht,toggleStats:dt,setSelectionStats:Dt,clearSelectionStats:It,restoreSelection:Wt,resetZoom:V,cancelSelection:R,analyzeTelemetryIntervals:Sl,setCursorAt:(l,c=!1)=>{if(f=l,rt&&rt(l),c){Z&&I?.points?.[l]&&Z(I.points[l]);return}r=!0,t.forEach(({uplot:x,yData:S,xData:H})=>{H[l]!=null&&S[l]!=null&&x.batch(()=>{x.setCursor({left:x.valToPos(H[l],"x"),top:x.valToPos(S[l],"y")},!0,!1)})}),r=!1,Z&&I?.points?.[l]&&Z(I.points[l])},setHoverAt:l=>{r=!0,t.forEach(({uplot:c,yData:x,xData:S})=>{l===null?c.batch(()=>{c.setCursor({left:-10,top:-10},!0,!1)}):S[l]!=null&&x[l]!=null&&c.batch(()=>{c.setCursor({left:c.valToPos(S[l],"x"),top:c.valToPos(x[l],"y")},!0,!1)})}),r=!1,Z&&Z(l!=null&&I?.points?.[l]?I.points[l]:null)},clearPinnedDot:()=>{f=null,rt&&rt(null),t.forEach(({uplot:l})=>l.redraw(!1))},resize:Et,METRICS:qe,isDragging:()=>v,setMapColorChangeCb:Lt,toggleMapColor:st,getMapColorMetric:()=>at,getActiveMetrics:()=>d,getAvailableMetrics:()=>T,setActiveMetrics:ut,setSmooth:bt,setZeroInclusion:Pt,updateMetricOrder:l=>{let c=new Set;l.forEach(x=>{d.has(x)&&c.add(x)}),d.forEach(x=>{c.has(x)||c.add(x)}),d=c,I&&vt(!0)},getXAxis:()=>F};function Ml(l,c,x,S,H){let P=l.ctx,B=l.bbox,A=window.devicePixelRatio||1,q=zt(H,x);P.save(),P.beginPath(),P.rect(B.left,B.top,B.width,B.height),P.clip();let J=H==="gearRear"||H==="gearFront";for(let X=1;Xtt.time!=null)?.time||0,Q=x.field;S.beginPath(),S.strokeStyle="rgba(255, 255, 255, 0.04)",S.lineWidth=1*P;let et=!0;for(let tt=0;tt0){let xt=J[tt-1];(L.time&&xt.time?L.time-xt.time:0)>B&&(et=!0)}let St=x.transform?x.transform(wt):wt;if(St==null){et=!0;continue}let ct=F==="distance"?(L.dist||0)/1e3:(L.time-X)/1e3;if(ctl.scales.x.max+10){et=!0;continue}let Ct=l.valToPos(ct,"x",!0),pt=l.valToPos(St,"y",!0);if(et)S.moveTo(Ct,pt),et=!1;else{if(A){let xt=J[tt-1],kt=F==="distance"?(xt.dist||0)/1e3:(xt.time-X)/1e3;S.lineTo(l.valToPos(kt,"x",!0),pt)}S.lineTo(Ct,pt)}}S.stroke()}S.restore()}function go(l,c,x,S,H,P,B=null,A=[]){let q=l.ctx,J=l.bbox,X=window.devicePixelRatio||1,Q=6e4;q.save(),q.beginPath(),q.strokeStyle=le(S,.8),q.lineWidth=H*X;let et=P==="gearRear"||P==="gearFront",tt=!0,L=null,wt=1,St=1;if(P==="gears"&&A.length>0){let Qt=1/0,ue=-1/0;for(let Me=0;Meue&&(ue=Be))}Qt<=ue&&(wt=Qt,St=ue)}let ct=B?B[0]:l.scales.x?.min??-1/0,Ct=B?B[1]:l.scales.x?.max??1/0,pt=l.scales.x?.min??-1/0,xt=l.scales.x?.max??1/0,kt=l.scales.y?.min??0,Ot=l.scales.y?.max??100,Vt=J.width/(xt-pt||1),ne=J.height/(Ot-kt||1),ie=l.scales.y?.dir??1,re=ie===-1?J.top:J.top+J.height,ae=ie===-1?ne:-ne,mt=B?null:l.series[0]?.idxs,Kt=mt?Math.max(0,mt[0]-1):0,Xt=mt?Math.min(c.length-1,mt[1]+1):c.length-1,te=et||P==="gears"?1:Math.max(1,Math.floor((Xt-Kt)/250)),de=F==="time",fe=Q/1e3,ge=Kt;for(let Qt=Kt;Qt<=Xt;Qt+=te){let ue=c[Qt],Me=x[Qt];if(ue==null||Me==null){tt=!0;continue}if(P==="gears"&&A[Qt]){let Ae=A[Qt].gearFrontTooth??A[Qt].gearFront;if(Ae!=null&&Ae!==L){if(!tt&&Qt>0){q.stroke(),q.beginPath();let _s=J.left+(c[ge]-pt)*Vt,cs=re+(x[ge]-kt)*ae;q.moveTo(_s,cs)}let on=S;St!==wt&&Ae!=null&&(Ae===wt?on="#FFC400":Ae===St?on="#FF8C00":on="#FFA500"),q.strokeStyle=le(on,.8),L=Ae}}if(Qt>Kt&&de){let Ae=c[ge];Ae!=null&&ue-Ae>fe&&(tt=!0)}if(ueCt){tt=!0;continue}let Be=J.left+(ue-pt)*Vt,Je=re+(Me-kt)*ae;if(tt)q.moveTo(Be,Je),tt=!1;else{if(et){let Ae=c[ge];q.lineTo(J.left+(Ae-pt)*Vt,Je)}q.lineTo(Be,Je)}ge=Qt}q.stroke(),q.restore()}})();var Nl={"Heart Rate":Nt.hr.icon,Cadence:Nt.cadence.icon,Power:Nt.power.icon,Temperature:Nt.temperature.icon,Shifting:Nt.gears.icon,Battery:Nt.battery.icon},Pn=()=>{},$o=()=>{};function Po(t,s){Pn=t,$o=s}function Lo(){let t=document.getElementById("details-view");t&&(t.innerHTML=` -
+ `}C.innerHTML=rn,C.style.display="block";let $n=C.offsetHeight,xn=C.offsetWidth,Me=_.getBoundingClientRect(),zt=Me.height-4-30,Lt=Me.top+4+(X-1-ue+.5)*(zt/X);C.style.left=`${Me.left-xn-12}px`,C.style.top=`${Lt-$n/2}px`,ce&&(ce.style.display="block",ce.style.top=`${Lt}px`,ce.style.left="0px",ce.style.width=`${Me.left}px`)}function Yg(T=!1){C&&(C.style.display="none"),t.forEach(({uplot:_,row:R})=>{i.unsub(_),_.destroy(),R.remove()}),t=[],e=null,T||(g=null,v=null),w=!1}function iF(T,_,R,O,Q=!0){let W=1/0,te=-1/0,X=0,se=0;for(let ge=0;geO)continue;let ce=_[ge];ce==null||!isFinite(ce)||ce===0&&!Q||(cete&&(te=ce),X+=ce,se++)}return se?{min:W,max:te,avg:X/se}:null}function Qz(T,_,R){let O=0,Q=0,W=null,te=f==="distance",X=T[0].time||0;for(let se=0;seR)&&ge.ele!=null){if(W!=null){let ue=ge.ele-W;ue>0?O+=ue:ue<0&&(Q+=Math.abs(ue))}W=ge.ele}}return{gain:O,loss:Q}}function oF(T,_,R,O,Q,W,te,X){if(R==null||Q[R]==null){_.style.display="none";return}let se=T.valToPos(O[R],"x",!1),ge=T.valToPos(Q[R],"y",!1),ce="#888896",ue=0;if(R>0&&W[R]&&W[R-1]){let _e=W[R-1],ze=W[R],Re=(ze.dist||0)-(_e.dist||0);Re>.1&&ze.ele!=null&&_e.ele!=null&&(ue=(ze.ele-_e.ele)/Re*100,ce=nw(ue))}let ye=X!=="elevation"?`${te.fmt(Q[R],!1)} ${te.unit}`:`${te.fmt(Q[R],!1)} ${te.unit} \u2220 ${Math.abs(ue).toFixed(1)}%`;if(X==="gearRear"&&W[R].gearRearTooth!=null)ye=`${W[R].gearRearTooth}T (pos ${Q[R]})`;else if(X==="gearFront"&&W[R].gearFrontTooth!=null)ye=`${W[R].gearFrontTooth}T (pos ${Q[R]})`;else if(X==="gears"){let _e=W[R],ze=_e.gearFrontTooth!=null?`${_e.gearFrontTooth}T`:_e.gearFront!=null?`pos ${_e.gearFront}`:"",Re=_e.gearRearTooth!=null?`${_e.gearRearTooth}T`:_e.gearRear!=null?`pos ${_e.gearRear}`:"";(ze||Re)&&(ye+=` (${ze} / ${Re})`)}_.innerHTML!==ye&&(_.innerHTML=ye);let ve=`${te.color}44`;_.style.color!==te.color&&(_.style.color=te.color),_.style.borderColor!==ve&&(_.style.borderColor=ve);let Z=`${se}px`,Be=`${ge}px`,je="translate(6px, -50%)";_.style.left!==Z&&(_.style.left=Z),_.style.top!==Be&&(_.style.top=Be),_.style.transform!==je&&(_.style.transform=je),_.style.display!==""&&(_.style.display="")}let aF=new Map;function lF(T){let _=aF.get(T);return _||(_=en(nw(T),.8),aF.set(T,_)),_}function Kz(T,_,R,O){let Q=T.ctx,W=T.bbox,te=window.devicePixelRatio||1,X=T.scales.x?.min??-1/0,se=T.scales.x?.max??1/0,ge=T.scales.y?.min??0,ce=T.scales.y?.max??100,ue=W.width/(se-X||1),ye=W.height/(ce-ge||1),ve=W.top+W.height,Z=T.series[0]?.idxs,Be=Z?Math.max(1,Z[0]):1,je=Z?Math.min(_.length-1,Z[1]+1):_.length-1,_e=Math.max(1,Math.floor((je-Be)/250));Q.save(),Q.lineWidth=1.5*te;let ze=new Map,Re=Be-1;for(let Le=Be;Le<=je;Le+=_e){let We=_[Le],gt=_[Re];if(Re=Le,We==null||R[Le]==null||gt==null||R[Le-_e]==null||Wese)continue;let mt=W.left+(gt-X)*ue,Qt=ve-(R[Le-_e]-ge)*ye,rn=W.left+(We-X)*ue,$n=ve-(R[Le]-ge)*ye,xn=O&&O[Le]!=null?Math.round(O[Le]/2)*2:null,Me=lF(xn),zt=ze.get(Me);zt||(zt=[],ze.set(Me,zt)),zt.push(mt,Qt,rn,$n)}for(let[Le,We]of ze){Q.beginPath(),Q.strokeStyle=Le;for(let gt=0;gtX)continue;let gt=Q.left+(We-te)*ce,mt=ye-(R[Re-je]-se)*ue,Qt=Q.left+(Le-te)*ce,rn=ye-(R[Re]-se)*ue,$n=Math.round(R[Re]/2)*2,xn=lF($n),Me=_e.get(xn);Me||(Me=[],_e.set(xn,Me)),Me.push(gt,mt,Qt,rn)}for(let[Re,Le]of _e){O.beginPath(),O.strokeStyle=Re;for(let We=0;We{let We=`bold ${10*te}px system-ui, sans-serif`;se.font!==We&&(se.font=We);let mt=se.measureText(_e).width+10*te,Qt=16*te,rn=ze-mt/2,$n=Math.max(X.left,Math.min(X.left+X.width-mt,rn)),xn=Re-Qt/2;se.save(),se.globalAlpha=W,se.setLineDash([]),se.beginPath(),se.roundRect?se.roundRect($n,xn,mt,Qt,3*te):se.rect($n,xn,mt,Qt),se.fillStyle="rgba(14,14,16,0.92)",se.fill(),se.strokeStyle=en(O,.27),se.lineWidth=1*te,se.stroke(),se.fillStyle=O,se.textAlign="center",se.textBaseline="middle",se.fillText(_e,$n+mt/2,xn+Qt/2+.5*te),se.restore()};Q||cF(T,_,R,O,W);let je=16*te;Be(Z,ye,X.top+je/2,!0),Be(ve,ye,X.top+X.height+15*te,!1)}function eG(T,_,R,O,Q,W,te){if(D==null)return;let X=_[D],se=R[D];if(X==null||se==null)return;let ge=T.valToPos(X,"x",!0),ce=T.valToPos(se,"y",!0),ue=T.bbox,ye=T.ctx,ve=window.devicePixelRatio||1;ye.save(),ye.beginPath(),ye.strokeStyle=O,ye.lineWidth=1.5*ve,ye.moveTo(ge,ue.top),ye.lineTo(ge,ue.top+ue.height),ye.stroke(),ye.beginPath(),ye.setLineDash([3*ve,3*ve]),ye.strokeStyle=en(O,.5),ye.lineWidth=1*ve,ye.moveTo(ue.left,ce),ye.lineTo(ge,ce),ye.stroke(),ye.beginPath(),ye.setLineDash([]),ye.arc(ge,ce,5*ve,0,Math.PI*2),ye.fillStyle="#0e0e10",ye.fill(),ye.strokeStyle=O,ye.lineWidth=2.5*ve,ye.stroke(),ye.restore();let Z=T._strasse;Z&&Z.pinYVal&&oF(T,Z.pinYVal,D,_,R,W,Q,te)}function tG(T,_,R,O,Q,W){let te=T.bbox,X=T.ctx,se=window.devicePixelRatio||1,ge=T.valToPos(O,"y",!0),ce=Math.max(te.top,Math.min(te.top+te.height,ge));X.save(),X.beginPath(),X.setLineDash([4*se,4*se]),X.strokeStyle=en(Q,.4),X.lineWidth=1*se,X.moveTo(te.left,ce),X.lineTo(te.left+te.width,ce),X.stroke(),nG(T,_,R,ce,Q);let ue=W.fmt(O,!0),ye=`bold ${10*se}px system-ui, sans-serif`;X.font!==ye&&(X.font=ye);let Z=X.measureText(ue).width+8*se,Be=16*se,je=te.left-Z-2*se,_e=ce-Be/2;X.beginPath(),X.setLineDash([]),X.roundRect?X.roundRect(je,_e,Z,Be,3*se):X.rect(je,_e,Z,Be),X.fillStyle="rgba(14,14,16,0.95)",X.fill(),X.strokeStyle=Q,X.lineWidth=1*se,X.stroke(),X.fillStyle="#fff",X.textAlign="center",X.textBaseline="middle",X.fillText(ue,je+Z/2,_e+Be/2+.5*se),X.restore()}function nG(T,_,R,O,Q){let W=T.ctx,te=T.bbox,X=T.scales.x?.min??-1/0,se=T.scales.x?.max??1/0,ge=T.scales.y?.min??0,ce=T.scales.y?.max??100,ue=te.width/(se-X||1),ye=te.height/(ce-ge||1),ve=T.scales.y?.dir??1,Z=ve===-1?te.top:te.top+te.height,Be=ve===-1?ye:-ye,je=T.series[0]?.idxs,_e=je?Math.max(0,je[0]-1):0,ze=je?Math.min(_.length-1,je[1]+1):_.length-1,Re=Math.max(1,Math.floor((ze-_e)/250));W.save(),W.beginPath(),W.rect(te.left,te.top,te.width,te.height),W.clip(),W.fillStyle=en(Q,.2),W.beginPath();let Le=!1,We=!1,gt=0;for(let mt=_e;mt<=ze;mt+=Re){let Qt=_[mt],rn=R[mt];if(Qt==null||rn==null||Qtse){Le&&(W.lineTo(gt,O),W.closePath(),Le=!1);continue}let $n=te.left+(Qt-X)*ue,xn=Z+(rn-ge)*Be;gt=$n,xn>16,te=O>>8&255,X=O&255,se=Q>>16,ge=Q>>8&255,ce=Q&255,ue=W+(se-W)*R,ye=te+(ge-te)*R,ve=X+(ce-X)*R;return`#${((1<<24)+(Math.round(ue)<<16)+(Math.round(ye)<<8)+Math.round(ve)).toString(16).slice(1)}`}function nw(T){if(T==null)return"#888896";let _=Math.abs(T),R=Math.min(1,_/8);return T>0?ho("#A8C8A0","#d73027",R):ho("#A8C8A0","#4575b4",R)}function dF(T){if(T==null)return"#888896";let _=T*3.6;if(_<=5)return"#4575b4";if(_>=60)return"#d73027";if(_<=45){let R=(_-5)/40;return R<=.25?ho("#4575b4","#91bfdb",R/.25):R<=.5?ho("#91bfdb","#abdda4",(R-.25)/.25):R<=.75?ho("#abdda4","#fee08b",(R-.5)/.25):ho("#fee08b","#fc8d59",(R-.75)/.25)}else{let R=(_-45)/15;return ho("#fc8d59","#d73027",R)}}function rG(T,_){let R=new Array(T.length).fill(null);for(let O=0;O0&&(Q.dist||0)-(T[W].dist||0)<_/2;)W--;for(;te1&&T[te].ele!=null&&T[W].ele!=null&&(R[O]=(T[te].ele-T[W].ele)/X*100)}return R}function pF(T){let _=[...T];for(let R=0;R<_.length;R++)if(_[R]===null){let O=R-1;for(;O>=0&&_[O]===null;)O--;let Q=R+1;for(;Q<_.length&&_[Q]===null;)Q++;O>=0&&Q<_.length?_[R]=_[O]+(_[Q]-_[O])*(R-O)/(Q-O):O>=0?_[R]=_[O]:Q<_.length&&(_[R]=_[Q])}return _}function fF(T){let _=T.stats,R=(X,se)=>{let ge=document.querySelector(`#${X} .stat-value`);ge&&(ge.textContent=se)};R("stat-distance",_.totalDist!=null?`${(_.totalDist/1e3).toFixed(1)} km`:"\u2014"),R("stat-duration",_.duration!=null?Nn(Math.floor(_.duration/1e3)):"\u2014"),R("stat-elevation",_.elevGain!=null?`${Math.round(_.elevGain)} m`:"\u2014");let O=X=>{let se=t.find(ue=>ue.metricKey===X);if(!se)return X==="speed"?_.avgSpeed??null:X==="power"?_.avgPower??null:X==="cadence"?_.avgCadence??null:null;if(se.histData.fullStats!==void 0)return se.histData.fullStats?se.histData.fullStats.avg:null;let ge=p.has(X)||X!=="power"&&X!=="cadence"&&X!=="speed",ce=se.yData.filter(ue=>ue!=null&&(ge||ue!==0));return ce.length?ce.reduce((ue,ye)=>ue+ye,0)/ce.length:null},Q=O("speed");R("stat-avg-speed",Q!=null?`${(Q*3.6).toFixed(1)} km/h`:"\u2014");let W=O("power");R("stat-avg-power",W!=null?`${Math.round(W)} W`:"\u2014");let te=O("cadence");R("stat-avg-cad",te!=null?`${Math.round(te)} rpm`:"\u2014"),R("stat-avg-hr",_.avgHR!=null?`${_.avgHR} bpm`:"\u2014"),R("stat-avg-temp",_.avgTemp!=null?`${_.avgTemp.toFixed(1)} \xB0C`:"\u2014"),window.__trackStateService?.graphsTab?.updateTotalStats({dist:_.totalDist!=null?`${(_.totalDist/1e3).toFixed(1)} km`:"\u2014",duration:_.duration!=null?Nn(Math.floor(_.duration/1e3)):"\u2014",elevation:_.elevGain!=null?`${Math.round(_.elevGain)} m`:"\u2014",avgSpeed:Q!=null?`${(Q*3.6).toFixed(1)} km/h`:"\u2014",avgPower:W!=null?`${Math.round(W)} W`:"\u2014",avgHr:_.avgHR!=null?`${_.avgHR} bpm`:"\u2014",avgTemp:_.avgTemp!=null?`${_.avgTemp.toFixed(1)} \xB0C`:"\u2014"})}let ou=16384,au=new Float64Array(ou),Xp=new Float64Array(ou),rw=new Float64Array(ou),Xg=new Float64Array(ou),RD=new Float64Array(ou),sw=new Float64Array(ou),Qg=new Float64Array(64),hF=[3,5,8,10,12,15,20,25,30,40,45,60,75,90,120,150,180,240,300,360];function sG(T,_,R){if(!T.length)return 0;Qg.fill(0);let O=0;for(let Q=0;Q=je)continue;let Re=1/ze,Le=0,We=0,gt=0;for(let mt=Z;mt=ze){Le-=sw[mt-ze],We-=Xg[mt-ze];let Qt=(Le+We*.05)*Re;Qt>gt&&(gt=Qt)}O+=gt*1e-4}for(let _e=Z;_e0&&(Qg[ze-1]+=.5),ze<63&&(Qg[ze+1]+=.5)}}}}for(let Q=0;Q<64;Q++)O+=Qg[Q]*1e-5;return I&&(I.dataset.intervalScore=O.toFixed(2)),O}return{init:Ae,loadTrack:V,clear:z,resetState:L,toggleMetric:q,setXAxis:Ce,toggleStats:he,setSelectionStats:nn,clearSelectionStats:kt,restoreSelection:cn,resetZoom:me,cancelSelection:Ue,analyzeTelemetryIntervals:sG,setCursorAt:(T,_=!1)=>{if(D=T,Ze&&Ze(T),_){U&&h?.points?.[T]&&U(h.points[T]);return}a=!0,t.forEach(({uplot:R,yData:O,xData:Q})=>{Q[T]!=null&&O[T]!=null&&R.batch(()=>{R.setCursor({left:R.valToPos(Q[T],"x"),top:R.valToPos(O[T],"y")},!0,!1)})}),a=!1,U&&h?.points?.[T]&&U(h.points[T])},setHoverAt:T=>{a=!0,t.forEach(({uplot:_,yData:R,xData:O})=>{T===null?_.batch(()=>{_.setCursor({left:-10,top:-10},!0,!1)}):O[T]!=null&&R[T]!=null&&_.batch(()=>{_.setCursor({left:_.valToPos(O[T],"x"),top:_.valToPos(R[T],"y")},!0,!1)})}),a=!1,U&&U(T!=null&&h?.points?.[T]?h.points[T]:null)},clearPinnedDot:()=>{D=null,Ze&&Ze(null),t.forEach(({uplot:T})=>T.redraw(!1))},resize:ft,METRICS:mi,isDragging:()=>w,setMapColorChangeCb:De,toggleMapColor:Ne,getMapColorMetric:()=>we,getActiveMetrics:()=>c,getAvailableMetrics:()=>u,setActiveMetrics:K,setSmooth:H,setZeroInclusion:le,updateMetricOrder:T=>{let _=new Set;T.forEach(R=>{c.has(R)&&_.add(R)}),c.forEach(R=>{_.has(R)||_.add(R)}),c=_,h&&ot(!0)},getXAxis:()=>f};function iG(T,_,R,O,Q){let W=T.ctx,te=T.bbox,X=window.devicePixelRatio||1,se=$t(Q,R);W.save(),W.beginPath(),W.rect(te.left,te.top,te.width,te.height),W.clip();let ge=Q==="gearRear"||Q==="gearFront";for(let ce=1;ce<_.length;ce++){if(_[ce]==null||R[ce]==null||_[ce-1]==null||R[ce-1]==null)continue;let ue=T.valToPos(_[ce-1],"x",!0),ye=T.valToPos(R[ce-1],"y",!0),ve=T.valToPos(_[ce],"x",!0),Z=T.valToPos(R[ce],"y",!0),Be=se[ce];W.beginPath(),W.moveTo(ue,ye),ge&&W.lineTo(ve,ye),W.lineTo(ve,Z),W.strokeStyle=Be,W.lineWidth=2*X,W.stroke()}W.restore()}function o0e(T,_,R){if(!m.length)return;let O=T.ctx,Q=T.bbox,W=window.devicePixelRatio||1,te=6e4;O.save(),O.beginPath(),O.rect(Q.left,Q.top,Q.width,Q.height),O.clip();let X=_==="gearRear"||_==="gearFront";for(let se of m){if(h&&se.id===h.id)continue;let ge=se.points,ce=ge.find(ve=>ve.time!=null)?.time||0,ue=R.field;O.beginPath(),O.strokeStyle="rgba(255, 255, 255, 0.04)",O.lineWidth=1*W;let ye=!0;for(let ve=0;ve0){let Le=ge[ve-1];(Z.time&&Le.time?Z.time-Le.time:0)>te&&(ye=!0)}let je=R.transform?R.transform(Be):Be;if(je==null){ye=!0;continue}let _e=f==="distance"?(Z.dist||0)/1e3:(Z.time-ce)/1e3;if(_eT.scales.x.max+10){ye=!0;continue}let ze=T.valToPos(_e,"x",!0),Re=T.valToPos(je,"y",!0);if(ye)O.moveTo(ze,Re),ye=!1;else{if(X){let Le=ge[ve-1],We=f==="distance"?(Le.dist||0)/1e3:(Le.time-ce)/1e3;O.lineTo(T.valToPos(We,"x",!0),Re)}O.lineTo(ze,Re)}}O.stroke()}O.restore()}function mF(T,_,R,O,Q,W,te=null,X=[]){let se=T.ctx,ge=T.bbox,ce=window.devicePixelRatio||1,ue=6e4;se.save(),se.beginPath(),se.strokeStyle=en(O,.8),se.lineWidth=Q*ce;let ye=W==="gearRear"||W==="gearFront",ve=!0,Z=null,Be=1,je=1;if(W==="gears"&&X.length>0){let Vt=1/0,Gn=-1/0;for(let qr=0;qrGn&&(Gn=Is))}Vt<=Gn&&(Be=Vt,je=Gn)}let _e=te?te[0]:T.scales.x?.min??-1/0,ze=te?te[1]:T.scales.x?.max??1/0,Re=T.scales.x?.min??-1/0,Le=T.scales.x?.max??1/0,We=T.scales.y?.min??0,gt=T.scales.y?.max??100,mt=ge.width/(Le-Re||1),Qt=ge.height/(gt-We||1),rn=T.scales.y?.dir??1,$n=rn===-1?ge.top:ge.top+ge.height,xn=rn===-1?Qt:-Qt,Me=te?null:T.series[0]?.idxs,zt=Me?Math.max(0,Me[0]-1):0,Lt=Me?Math.min(_.length-1,Me[1]+1):_.length-1,Yt=ye||W==="gears"?1:Math.max(1,Math.floor((Lt-zt)/250)),zn=f==="time",cr=ue/1e3,ur=zt;for(let Vt=zt;Vt<=Lt;Vt+=Yt){let Gn=_[Vt],qr=R[Vt];if(Gn==null||qr==null){ve=!0;continue}if(W==="gears"&&X[Vt]){let ms=X[Vt].gearFrontTooth??X[Vt].gearFront;if(ms!=null&&ms!==Z){if(!ve&&Vt>0){se.stroke(),se.beginPath();let FD=ge.left+(_[ur]-Re)*mt,iw=$n+(R[ur]-We)*xn;se.moveTo(FD,iw)}let jl=O;je!==Be&&ms!=null&&(ms===Be?jl="#FFC400":ms===je?jl="#FF8C00":jl="#FFA500"),se.strokeStyle=en(jl,.8),Z=ms}}if(Vt>zt&&zn){let ms=_[ur];ms!=null&&Gn-ms>cr&&(ve=!0)}if(Gn<_e||Gn>ze){ve=!0;continue}let Is=ge.left+(Gn-Re)*mt,Oa=$n+(qr-We)*xn;if(ve)se.moveTo(Is,Oa),ve=!1;else{if(ye){let ms=_[ur];se.lineTo(ge.left+(ms-Re)*mt,Oa)}se.lineTo(Is,Oa)}ur=Vt}se.stroke(),se.restore()}})();var jb=["#FF6B35","#4ECDC4","#45B7D1","#F7DC6F","#FF6B6B","#BB8FCE","#82E0AA","#F8C471","#3b82f6"],Kr=class{constructor(){this.tracks={};this.skippedImports=[];this.selectedId=null;this.activeTab="graphs";this.colorIdx=0;this.followDot=!1;this.currentMapColors=null;this.cancelProcessing=!1;this.searchQuery="";this.searchRegex=!1;this.currentSort="date-desc";this.selectionRange=null;this.filters={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null};this.toastMessage=null;this.stateChanges$=new si;this.appRef=null;this.graphsTab=null;this.insightsTab=null;this.detailsTab=null;this.combinedTab=null;this.evolutionTab=null;this.coursesTab=null;this.onSelectTrackCallback=null;this.onDeleteTrackCallback=null;this.onApplyFiltersCallback=null;this.onChartRangeChangeCallback=null;window.__trackStateService=this}get allTracks(){return Object.values(this.tracks)}get selectedTrack(){return this.selectedId&&this.tracks[this.selectedId]?this.tracks[this.selectedId]:null}get filteredTrackIds(){return Object.keys(this.tracks).filter(n=>!this.tracks[n]._filtered).sort((n,r)=>{if(n===this.selectedId)return-1;if(r===this.selectedId)return 1;let s=this.tracks[n],i=this.tracks[r],o=s.stats,a=i.stats,c=0;switch(this.currentSort){case"date-asc":c=(o.startTime||0)-(a.startTime||0);break;case"date-desc":c=(a.startTime||0)-(o.startTime||0);break;case"dist-asc":c=(o.totalDist||0)-(a.totalDist||0);break;case"dist-desc":c=(a.totalDist||0)-(o.totalDist||0);break;case"dur-asc":c=(o.duration||0)-(a.duration||0);break;case"dur-desc":c=(a.duration||0)-(o.duration||0);break;default:c=0}return c||n.localeCompare(r)})}get filteredTracks(){return this.filteredTrackIds.map(e=>this.tracks[e])}getGlobalTags(){let e=new Set;return Object.values(this.tracks).forEach(n=>{(n.tags||[]).forEach(r=>e.add(r))}),Array.from(e).sort()}showToast(e,n="info"){this.toastMessage={msg:e,type:n};let r=document.getElementById("toast-container");if(r){r.innerHTML="";let s=document.createElement("div");s.className=`toast ${n}`,s.textContent=e,r.appendChild(s)}this.notify()}selectTrack(e,n=!0,r=!1){this.onSelectTrackCallback&&this.onSelectTrackCallback(e,n,r)}selectTrackAndRange(e,n){this.selectTrack(e,!0),n&&(Pe.restoreSelection(n[0],n[1]),this.onChartRangeChangeCallback&&this.onChartRangeChangeCallback(n[0],n[1],"time",!0))}async deleteTrack(e){this.onDeleteTrackCallback?await this.onDeleteTrackCallback(e):(await tr.remove(e),st.removeTrack(e),delete this.tracks[e],this.selectedId===e&&(this.selectedId=null,Pe.clear(),It.patch({track:null,sel:null,sel_point:null})),this.applyFilters())}applyFilters(e=!1){if(this.onApplyFiltersCallback){this.onApplyFiltersCallback(e);return}Object.keys(this.tracks).forEach(r=>{let s=this.tracks[r],i=s.stats,o=!0;if(this.searchQuery)if(this.searchRegex)try{new RegExp(this.searchQuery,"i").test(s.name)||(o=!1)}catch{o=!1}else s.name.toLowerCase().includes(this.searchQuery.toLowerCase())||(o=!1);if(o&&(this.filters.date[0]||this.filters.date[1])){let a=this.filters.date[0]?new Date(this.filters.date[0]).getTime():0,c=this.filters.date[1]?new Date(this.filters.date[1]).getTime():1/0,u=i.startTime||0;(uc)&&(o=!1)}if(o&&(this.filters.dist[0]!==null||this.filters.dist[1]!==null)){let a=(this.filters.dist[0]||0)*1e3,c=(this.filters.dist[1]||1/0)*1e3;(i.totalDistc)&&(o=!1)}if(o&&(this.filters.dur[0]!==null||this.filters.dur[1]!==null)){let a=(this.filters.dur[0]||0)*6e4,c=(this.filters.dur[1]||1/0)*6e4,u=i.duration||0;(uc)&&(o=!1)}if(o&&this.filters.metrics.size>0)for(let a of this.filters.metrics){let c=Pe.METRICS[a]?.field;if(c&&!s.points.some(u=>u[c]!=null)){o=!1;break}}if(o&&this.filters.sport&&s.sport!==this.filters.sport&&(o=!1),o&&this.filters.tags.length>0){let a=s.tags||[];this.filters.tags.every(c=>a.includes(c))||(o=!1)}s._filtered=!o,st.setTrackVisible(s.id,s.visible&&o)}),e||this.notify()}syncFiltersToUrl(e=!1){It.patch({f_date:this.filters.date.every(n=>n===null)?null:this.filters.date,f_dist:this.filters.dist.every(n=>n===null)?null:this.filters.dist,f_dur:this.filters.dur.every(n=>n===null)?null:this.filters.dur,f_mets:this.filters.metrics.size===0?null:Array.from(this.filters.metrics),f_tags:this.filters.tags.length===0?null:this.filters.tags},e)}onTagsChanged(){this.applyFilters(),this.syncFiltersToUrl(),this.notify()}onDateRangeSelected(e,n){this.filters.date=[e,n],this.applyFilters(),this.syncFiltersToUrl(!0),this.notify()}activateTab(e,n=!1){this.activeTab=e,document.querySelectorAll(".tab-btn").forEach(r=>{r.classList.toggle("active",r.dataset.tab===e)}),document.querySelectorAll(".tab-content").forEach(r=>{r.classList.toggle("active",r.id===`tab-${e}`)}),It.patch({tab:e},n),this.notify()}notify(){this.stateChanges$.next();try{this.appRef?.tick()}catch{}}};Kr=dr([St({providedIn:"root"})],Kr);var $ye=[{key:"elevation",label:"Elevation",icon:"height",color:"#4ecdc4",title:"Toggle Elevation graph"},{key:"vam",label:"VAM",icon:"trending_up",color:"#ffa07a",title:"Toggle VAM graph"},{key:"speed",label:"Speed",icon:"speed",color:"#45b7d1",title:"Toggle Speed graph"},{key:"gradient",label:"Gradient",icon:"trending_up",color:"#a8c8a0",title:"Toggle Gradient graph"},{key:"power",label:"Power",icon:"bolt",color:"#f7dc6f",title:"Toggle Power graph"},{key:"hr",label:"Heart Rate",icon:"favorite",color:"#ff6b6b",title:"Toggle Heart Rate graph"},{key:"cadence",label:"Cadence",icon:"directions_run",color:"#bb8fce",title:"Toggle Cadence graph"},{key:"temperature",label:"Temp",icon:"thermostat",color:"#f8c471",title:"Toggle Temperature graph"},{key:"battery",label:"Battery",icon:"battery_full",color:"#45b7d1",title:"Toggle Battery graph"},{key:"gearRear",label:"Rear Gear",icon:"settings",color:"#82e0aa",title:"Toggle Rear Gear graph"},{key:"gearFront",label:"Front Gear",icon:"settings_input_component",color:"#a8c8a0",title:"Toggle Front Gear graph"},{key:"gears",label:"Gears",icon:"settings",color:"#ff8c00",title:"Toggle Gears graph"}],jg=class{constructor(){this.state=fe(Kr);this.cdr=fe(An);this.metricPills=[...$ye];this.activeMetrics=new Set(["elevation","speed","power","hr","temperature"]);this.availableMetrics=new Set;this.overflowHiddenPills=new Set;this.toolbarCollapsed=!1;this.xAxis="time";this.hasTrack=!1;this.hasSelection=!1;this.totalStats={dist:"--",duration:"--",elevation:"--",avgSpeed:"--",avgPower:"--",avgHr:"--",avgTemp:"--"};this.selectionStats={dist:"--",duration:"--",elevation:"--",avgSpeed:"--",avgPower:"--",avgHr:"--",avgTemp:"--"};this.draggedEl=null;this.state.graphsTab=this}ngOnInit(){this.cdr.detectChanges()}trackByPillKey(e,n){return n.key}isPillActive(e){return this.hasTrack?this.availableMetrics.has(e)&&this.activeMetrics.has(e):this.activeMetrics.has(e)}isPillAvailable(e){return this.availableMetrics.has(e)}syncFromChartView(){if(this.activeMetrics=new Set(Pe.getActiveMetrics()),this.availableMetrics=new Set(Pe.getAvailableMetrics()),this.xAxis=Pe.getXAxis(),this.hasTrack=this.state.selectedTrack!==null,this.state.selectedTrack){let e=this.state.selectedTrack.stats;this.totalStats={dist:e.totalDist!=null?`${(e.totalDist/1e3).toFixed(1)} km`:"\u2014",duration:e.duration!=null?Nn(Math.floor(e.duration/1e3)):"\u2014",elevation:e.elevGain!=null?`${Math.round(e.elevGain)} m`:"\u2014",avgSpeed:e.avgSpeed!=null?`${(e.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014",avgPower:e.avgPower!=null?`${Math.round(e.avgPower)} W`:"\u2014",avgHr:e.avgHR!=null?`${e.avgHR} bpm`:"\u2014",avgTemp:e.avgTemp!=null?`${e.avgTemp.toFixed(1)} \xB0C`:"\u2014"}}else this.totalStats={dist:"--",duration:"--",elevation:"--",avgSpeed:"--",avgPower:"--",avgHr:"--",avgTemp:"--"},this.hasSelection=!1;this.updateToolbarLayout(),this.cdr.detectChanges()}updateTotalStats(e){this.hasTrack=!0,this.totalStats={...this.totalStats,...e},this.cdr.detectChanges()}setSelectionStats(e){e?(this.hasSelection=!0,this.selectionStats={dist:e.totalDist!=null?`${(e.totalDist/1e3).toFixed(1)} km`:"\u2014",duration:e.duration!=null?Nn(Math.floor(e.duration/1e3)):"\u2014",elevation:e.elevGain!=null?`${Math.round(e.elevGain)} m`:"\u2014",avgSpeed:e.avgSpeed!=null?`${(e.avgSpeed*3.6).toFixed(1)} km/h`:"\u2014",avgPower:e.avgPower!=null?`${e.avgPower} W`:"\u2014",avgHr:e.avgHR!=null?`${e.avgHR} bpm`:"\u2014",avgTemp:e.avgTemp!=null?`${e.avgTemp.toFixed(1)} \xB0C`:"\u2014"}):(this.hasSelection=!1,this.selectionStats={dist:"--",duration:"--",elevation:"--",avgSpeed:"--",avgPower:"--",avgHr:"--",avgTemp:"--"}),this.cdr.detectChanges()}updateToolbarLayout(){let e=document.getElementById("chart-toolbar"),n=e?Math.max(0,e.clientWidth-280):600,r=0,s=!1,i=new Set;for(let o of this.metricPills){if(!this.isPillActive(o.key))continue;let a=36+o.key.length*6;r+=a+6,r>n&&(s=!0,i.add(o.key))}this.overflowHiddenPills=i,this.toolbarCollapsed=s,this.cdr.detectChanges()}onPillClick(e){Pe.toggleMetric(e),this.syncMetricsToUrl(),this.syncFromChartView(),Pe.getActiveMetrics().has(e)&&document.querySelector(`.chart-row[data-metric="${e}"]`)?.scrollIntoView({behavior:"smooth"})}onSelectXAxis(e){this.xAxis=e,Pe.setXAxis(e),It.patch({xaxis:e}),this.cdr.detectChanges()}onToggleFollowDot(){this.state.followDot=!this.state.followDot,this.cdr.detectChanges()}onResetZoom(){Pe.resetZoom(),st.clearHighlight(),this.hasSelection=!1,this.cdr.detectChanges()}onCancelSelection(){Pe.cancelSelection(),this.hasSelection=!1,this.cdr.detectChanges()}onOpenMetricMenu(e){e.stopPropagation();let n=e.currentTarget;document.querySelectorAll(".metric-menu-popup").forEach(u=>u.remove());let r=document.createElement("div");r.className="metric-menu-popup";let s=Pe.METRICS,i=Pe.getAvailableMetrics(),o=Pe.getActiveMetrics();Object.entries(s).forEach(([u,d])=>{if(!i.has(u))return;let p=document.createElement("div");p.className=`menu-item ${o.has(u)?"active":""}`,p.innerHTML=` + ${d.icon} + ${d.label} + ${o.has(u)?"check":""} + `,p.addEventListener("click",()=>{Pe.toggleMetric(u);let f=Pe.getActiveMetrics().has(u);p.classList.toggle("active",f),p.querySelector(".check").textContent=f?"check":"",this.syncMetricsToUrl(),this.syncFromChartView()}),r.appendChild(p)});let a=n.getBoundingClientRect();r.style.top=`${a.bottom+5}px`,r.style.right=`${window.innerWidth-a.right}px`,document.body.appendChild(r);let c=u=>{!r.contains(u.target)&&!n.contains(u.target)&&(r.remove(),document.removeEventListener("click",c))};setTimeout(()=>document.addEventListener("click",c),0)}onDragStart(e){let n=e.target.closest(".metric-pill");n&&(this.draggedEl=n,e.dataTransfer&&(e.dataTransfer.effectAllowed="move"),n.classList.add("dragging-pill"),setTimeout(()=>n.style.opacity="0.4",0))}onDragOver(e){e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect="move");let n=document.getElementById("metric-pills"),r=e.target.closest(".metric-pill");if(n&&r&&this.draggedEl&&r!==this.draggedEl){let s=r.getBoundingClientRect(),i=e.clientX-s.left>s.width/2;n.insertBefore(this.draggedEl,i?r.nextSibling:r)}}onDragEnd(){if(!this.draggedEl)return;this.draggedEl.classList.remove("dragging-pill"),this.draggedEl.style.opacity="",this.draggedEl=null;let e=document.getElementById("metric-pills");if(!e)return;let n=Array.from(e.querySelectorAll(".metric-pill")).map(r=>r.dataset.metric);Pe.updateMetricOrder(n),this.syncMetricsToUrl(),this.cdr.detectChanges()}syncMetricsToUrl(){let e=Pe.getActiveMetrics(),n=Pe.METRICS,r=Array.from(e).map(s=>n[s].abbr);It.patch({metrics:r.length?r:null})}};jg=dr([Ws({selector:"app-graphs-tab",standalone:!0,imports:[Er,hs],template:` +
+
+ + ... +
+ +
+
+ + +
+ + +
+
+ +
+
+
+
Total
+
+ Dist{{ totalStats.dist }} +
+
+ Time{{ totalStats.duration }} +
+
+ Elev{{ totalStats.elevation }} +
+
+ Avg Spd{{ totalStats.avgSpeed }} +
+
+ Avg Pwr{{ totalStats.avgPower }} +
+
+ Avg HR{{ totalStats.avgHr }} +
+
+ Avg Temp{{ totalStats.avgTemp }} +
+
+
+
+ Sel + +
+
+ Dist{{ selectionStats.dist }} +
+
+ Time{{ selectionStats.duration }} +
+
+ Elev{{ selectionStats.elevation }} +
+
+ Avg Spd{{ selectionStats.avgSpeed }} +
+
+ Avg Pwr{{ selectionStats.avgPower }} +
+
+ Avg HR{{ selectionStats.avgHr }} +
+
+ Avg Temp{{ selectionStats.avgTemp }} +
+
+
+
+ +
+
no_sim -
Select a track for details
+
Select a track to view analysis
- `)}var cn=16384,Ue=[new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn),new Float64Array(cn)],Co=[3,5,10,15,20,30,45,60,90];function Wl(t,s){let e=t.points,n=Math.min(e.length,cn),o=0;for(let v=0;v=n)continue;let f=1/k,h=Math.max(1,k>>1);for(let p=0;p<7;p++){let E=Ue[p],_=0,W=0,O=0,Y=0,Z=1/(10+p*15+v*2);for(let lt=0;lt=k){let rt=E[lt-k];_-=rt,W-=rt*rt;let w=_*f,y=Math.max(0,W*f-w*w),m=E[lt-h],N=Ft-E[lt-1],C=N*N*Z,G=v<4?Math.exp(-C):1/(1+C);Y+=N*N*G;let U=1/(1+y*1e-4);O+=(Ft-w)*(m-w)*U}}o+=(O+Y*.001)/Math.max(1,n)}}let i=t.stats.sections||Jt.analyzeTrackSections(e),a=[];for(let v=0;vk[1].secs-v[1].secs).slice(0,8).map(([v,k])=>({combo:v,ratio:(k.front/Math.max(1,k.rear)).toFixed(2),seconds:k.secs,pct:Number((k.secs/Math.max(1,n)*100).toFixed(1)),avgPower:Math.round(k.pwrSum/Math.max(1,k.secs)),avgCadence:Math.round(k.cadSum/Math.max(1,k.secs))})),T=s.length>0?s:[t],$=1,M=1,F=1,I=0,b=0;for(let v=0;vt.stats.totalDist&&$++,(k.avgPower||0)>(t.stats.avgPower||0)&&M++,k.elevGain>t.stats.elevGain&&F++}let g=Math.round(I/Math.max(1,T.length)),u=(b/Math.max(1,T.length)/1e3).toFixed(1);return{stabilityAccum:o,splitRows:a.slice(0,12),gearMatrix:d,peerSummary:{cohortSize:T.length,distRank:$,pwrRank:M,elevRank:F,cohortAvgPower:g,cohortAvgDistKm:u}}}function Ee(t,s=[],e=[],n){let o=document.getElementById("details-view");if(!o)return;if(!t){o.innerHTML="";return}let i=t;if(n&&n.length===2){let f=t.points[0]?.time||0,h=f+n[0]*1e3,p=f+n[1]*1e3,E=Math.max(0,t.points.findIndex(W=>(W.time||0)>=h)),_=t.points.findIndex(W=>(W.time||0)>=p);if(_===-1&&(_=t.points.length-1),_>E+2){let W=t.points.slice(E,_+1),O=Jt.computeStats(W,!0);i={...t,points:W,stats:O}}}let a=i.stats,r=i.points[0].time;Jt.ensureCurvesAndZones(i);let d=Wl(i,e),T=Math.min(99.9,Math.max(80,95+Math.tanh(d.stabilityAccum*.002)*4.5)).toFixed(1);o.innerHTML=` -
-
+ `})],jg);import jye from"uplot";var jr=[],Li=null,zp=!1,Oi=null,uz=()=>{},dz=null;function pz(t){dz=t}function fz(){return dz||window.__trackStateService?.coursesTab||null}function hz(t){zp=t,t||(st.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"))}function $R(t){return jr.filter(e=>{if(e.points.length===0)return!1;for(let n of e.points){let r=!1;for(let s of t.points)if(Ll(n.lat,n.lon,s.lat,s.lon)<=n.radius){r=!0;break}if(!r)return!1}return!0})}function mz(t){uz=t,Vye()}function gz(){jr=[],Li=null,Oi=null,zp=!1;let t=fz();if(t&&typeof t.reset=="function"){t.reset();return}let e=document.getElementById("courses-view");e&&(e.innerHTML=` +
+ route +
No courses created yet
+
+ `)}function Ub(t){jr=[];let e=[{trackIdx:0,suffix:"Full Loop",fracs:[.1,.5,.85],radius:450},{trackIdx:1,suffix:"Opening Climb Sector",fracs:[.08,.25,.45],radius:450},{trackIdx:2,suffix:"Lakeside Corridor",fracs:[.1,.45,.8],radius:850},{trackIdx:3,suffix:"Sprint Interval Sector",fracs:[.2,.5,.75],radius:850},{trackIdx:4,suffix:"Alpine Grand Tour Stage",fracs:[.1,.5,.85],radius:900},{trackIdx:5,suffix:"Summit Finish Climb",fracs:[.5,.72,.92],radius:900}];for(let n=0;n0&&(Li=jr[0].id,Oi=jr[0].id)}function vz(){return jr.map(t=>t.id)}async function Vye(){try{let t=await tr.get("courses");t&&(jr=t)}catch(t){console.error("Courses: Failed to load courses",t)}}async function VR(){try{await tr.set("courses",jr)}catch(t){console.error("Courses: Failed to save courses",t),uz("Failed to save courses","error")}}function Hye(t){let e=0;for(let n=0;nn)return{duration:0,dist:0,avgWatts:null,avgHR:null,avgSpeed:null,avgCadence:null,avgVam:null};let i=Math.max(0,Math.min(e,s-1)),o=Math.max(i,Math.min(n,s-1)),a=r[i]?.time||0,u=((r[o]?.time||0)-a)/1e3,d=0,p=0,f=0,h=0,m=0,g=0,v=0,w=0,b=0;for(let B=i;B<=o;B++){let M=r[B];if(M.power!=null&&(d+=M.power,p++),M.hr!=null&&(f+=M.hr,h++),M.speed!=null&&(m+=M.speed,g++),M.cadence!=null&&(v+=M.cadence,w++),B>i){let $=r[B-1];if(M.ele!=null&&$.ele!=null){let j=M.ele-$.ele;j>0&&(b+=j)}}}let D=o>i?(r[o].dist||0)-(r[i].dist||0):0;return{duration:u,dist:D,avgWatts:p>0?Math.round(d/p):null,avgHR:h>0?Math.round(f/h):null,avgSpeed:g>0?m/g:null,avgCadence:w>0?Math.round(v/w):null,avgVam:u>0?Math.round(b/(u/3600)):null}}function tz(t){let e=Math.floor(t/3600),n=Math.floor(t%3600/60),r=Math.floor(t%60);return e>0?`${e}:${n.toString().padStart(2,"0")}:${r.toString().padStart(2,"0")}`:`${n}:${r.toString().padStart(2,"0")}`}var ID=16384,nz=new Float64Array(ID),rz=new Float64Array(ID),sz=new Float64Array(ID),iz=new Float64Array(32),oz=new Float64Array(32),Bl=180,az=28,lz=new Float64Array(Bl),cz=new Float64Array(Bl),Ug=new Float64Array(Bl+1),DD=new Float64Array(Bl+1);function yz(){let t=0,e={},n=Oi||Li?jr.filter(a=>a.id===Oi||a.id===Li):jr;for(let a of n){if(a.points.length<2)continue;let c=st.findTracksPassingThroughPoints(a.points.map(d=>({lat:d.lat,lng:d.lon})),a.points[0]?.radius||20),u=4;for(let d=0;d{let c=a.points.map(h=>({lat:h.lat,lng:h.lon})),u=st.findTracksPassingThroughPoints(c,a.points[0]?.radius||20);s+=u.length;let d=a.id===Oi,p=a.id===Li,f=[];if(d){let h=u.map(g=>{let v=st.getTrackData(g);if(!v)return null;let w=_D(v,a.points);if(!w)return null;let b=Wp(v,w.startIdx,w.endIdx),D=Math.max(1,w.endIdx-w.startIdx),B=w.startIdx+Math.floor(D*.25),M=w.startIdx+Math.floor(D*.5),$=w.startIdx+Math.floor(D*.75),j=Wp(v,w.startIdx,B),G=Wp(v,B,M),Se=Wp(v,M,$),pe=Wp(v,$,w.endIdx),U=v.stats?.startTime||v.points?.[0]?.time,ee=U?Zo(U):"-",Ze=(v.sport?Fi[v.sport.toLowerCase()]:null)?.paceUnit||"km",N="--";if(b.avgSpeed!=null&&b.avgSpeed>.1){let A=(Ze==="km"?1e3:100)/b.avgSpeed;N=`${qp(A)}\xA0min/${Ze}`}return{id:g,displayName:v.displayName||v.name||g,date:ee,sport:v.sport||null,color:v.color||"#FF6B35",...b,splitsSummary:`${j.avgWatts||0}/${G.avgWatts||0}/${Se.avgWatts||0}/${pe.avgWatts||0}W`,gapLabel:"CR",dtwDistance:e[g]||0,distStr:b.dist!=null?`${(b.dist/1e3).toFixed(2)}\xA0km`:"-",durationStr:tz(b.duration),speedStr:b.avgSpeed!=null?`${(b.avgSpeed*3.6).toFixed(1)}\xA0km/h`:"-",paceStr:N,vamStr:b.avgVam!=null?`${b.avgVam}\xA0m/h`:"-",wattsStr:b.avgWatts!=null?`${b.avgWatts}\xA0W`:"-",hrStr:b.avgHR!=null?`${b.avgHR}\xA0bpm`:"-",startIdx:w.startIdx,endIdx:w.endIdx,isSelected:g===r}}).filter(g=>g!==null);h.sort((g,v)=>g.duration-v.duration||g.id.localeCompare(v.id));let m=h[0]?.duration||0;h.forEach((g,v)=>{if(v===0)g.gapLabel="KOM / CR";else{let w=Math.max(0,g.duration-m);g.gapLabel=`+${tz(w)}`}}),f=h}return{id:a.id,name:a.name,points:a.points,pointsCount:a.points.length,distanceKm:Hye(a).toFixed(2),matchingCount:u.length,isOpen:d,isActive:p,matchedTracks:f}}),o=i.find(a=>a.id===Oi||a.id===Li)||i[0]||null;return{courseViews:i,selectedCourseSummary:o,totalMatchesCount:s,corridorDeviationStr:t.toFixed(2),isEditMode:zp,activeCourseId:Li,openCourseId:Oi}}function $l(){let t=fz();if(t&&typeof t.render=="function"){t.render();return}}function HR(t,e=450){let n=t?.trim()||`Course ${jr.length+1}`,r=window.__trackStateService,s=r?.selectedTrack||r?.allTracks?.[0],i=[];if(s?.points&&s.points.length>=10){let a=s.points.length,c=s.points[Math.floor(a*.1)],u=s.points[Math.floor(a*.5)],d=s.points[Math.floor(a*.85)];i.push({lat:c.lat,lon:c.lon,radius:e,name:"Start Gate"},{lat:u.lat,lon:u.lon,radius:e,name:"Mid Sector"},{lat:d.lat,lon:d.lon,radius:e,name:"Finish Gate"})}let o={id:`course-${jr.length+1}-${Math.random().toString(36).substring(2,6)}`,name:n,points:i};return jr.push(o),Li=o.id,Oi=o.id,zp=!0,VR(),$l(),o}function bz(t,e){let n=jr.find(s=>s.id===t);if(!n)return;let r=e.trim();r!==""&&(n.name=r,VR()),$l()}function wz(t){Li=t,zp=!0,$l()}function Ez(t){Li=t,Oi=Oi===t?null:t,zp=!1,st.setCustomClickHandler(null),$l()}function nu(t,e=!1){Li=t,e&&(Oi=t),zp=!1,st.setCustomClickHandler(null),$l()}function xz(t){confirm("Are you sure you want to delete this course?")&&(jr=jr.filter(e=>e.id!==t),Li===t&&(Li=null),Oi===t&&(Oi=null),VR(),$l())}function Sz(t,e,n){let r=st.getTrackData(t);if(!r)return;let s=window.__trackStateService;s?s.selectTrack(t,!1):document.dispatchEvent(new CustomEvent("select-track",{detail:{id:t}})),setTimeout(()=>{let i=r.points,o=i.find(m=>m.time!=null)?.time||0,a=Math.max(0,Math.min(e,i.length-1)),c=Math.max(0,Math.min(n,i.length-1)),u=Math.max(0,((i[a]?.time||0)-o)/1e3),d=Math.max(0,((i[c]?.time||0)-o)/1e3),p=Pe.getXAxis(),f=u,h=d;p==="distance"&&(f=Math.max(0,(i[a]?.dist||0)/1e3),h=Math.max(0,(i[c]?.dist||0)/1e3)),It.patch({sel:[f,h],tab:"graphs"},!0),s&&s.activateTab("graphs",!1),Pe.restoreSelection(u,d),st.highlightSegment(t,r.points,e,n,!0)},50)}var ru=16384,Cz=new Float64Array(ru),Tz=new Float64Array(ru),Dz=new Float64Array(ru),Uye=new Float64Array(ru),qye=new Float64Array(ru),kD=new Float64Array(ru+1),AD=new Float64Array(ru+1),_z=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,420,600,900,1200];function Wye(t,e,n){let r=Math.min(t.length,ru);if(r===0)return{minWPrimeBal:2e4,matchesBurned:0,decouplingPct:0,quadrantPct:[25,25,25,25],sectionPeaks:[]};for(let M=0;M0?pe*U*36:0;Cz[M]=j,Tz[M]=1/G,Dz[M]=Se,Uye[M]=pe,qye[M]=ee,kD[M+1]=kD[M]+j,AD[M+1]=AD[M]+ee}let s=0;for(let M=0;M<_z.length;M++){let $=_z[M];if($>r)continue;let j=r-$,G=0,Se=0;for(let pe=0;pe<=j;pe++){let U=kD[pe+$]-kD[pe],ee=AD[pe+$]-AD[pe];U>G&&(G=U),ee>Se&&(Se=ee)}s+=(G+Se)/$}let i=2e4,o=2e4,a=0,c=!1,u=r>>1,d=0,p=0,f=[0,0,0,0],h=88,m=e/h;for(let M=0;M0?Se:0,xe=546*Math.exp(-.008*(pe+U*.625))+316;o=Math.min(2e4,o-U+(2e4-o)*(1/xe)),o17500&&c&&(c=!1);let Ze=$/j;Ze>=m&&j>=h?f[0]++:Ze>=m&&j0?d/u:1,v=r-u>0?p/(r-u):1,w=g>0?(g-v)/g*100:0,b=[Number((f[0]/r*100).toFixed(1)),Number((f[1]/r*100).toFixed(1)),Number((f[2]/r*100).toFixed(1)),Number((f[3]/r*100).toFixed(1))],B=(n&&n.length>0?n.filter(M=>M.kind==="quarter"||M.kind==="climb"||M.kind==="sprint"):[]).slice(0,8).map(M=>{let $=M.stats,j=$.duration&&$.duration>0?$.duration/36e5:0;return{label:M.label,distKm:Number(($.totalDist/1e3).toFixed(2)),avgPower:$.avgPower||0,peak60sPower:$.powerCurve?.[60]?.power||$.avgPower||0,avgHR:$.avgHR||0,vam:j>0?Math.round($.elevGain/j):0}});return s<-1e12&&(i=0),{minWPrimeBal:i,matchesBurned:a,decouplingPct:w,quadrantPct:b,sectionPeaks:B}}var qb=null,jR=null;function UR(){return qb||window.__trackStateService?.insightsTab||null}function Iz(t){jR=t}var po=class{constructor(){this.state=fe(Kr);this.cdr=fe(An);this.elRef=fe(pn);this.isResetState=!0;this.hasTrack=!1;this.hasInsights=!1;this.currentTrack=null;this.allTracks=[];this.powerColor=it.power.color;this.hrColor=it.hr.color;this.elevColor=it.elevation.color;this.mapColorMetric=null;this.powerTableExpanded=!1;this.hrTableExpanded=!1;this.wPrimeMinAttr="20000";this.matchesBurned=0;this.sectionRangeBadge="Full Track";this.powerCurveRows=[];this.hrCurveRows=[];this.powerZoneRows=[];this.hrZoneRows=[];this.climbingStats={elevGain:0,elevLoss:0,grade:"0.0",vam:0};this.hasEfficiency=!1;this.efficiencyStats={ef:"0.00",decoupling:"0.0",wPrimeKj:"20.0",quadrantsText:"25% / 25% / 25% / 25%",np:0,ifVal:"0.00",vi:"1.00",tss:0,workKj:0};this.sectionPeaks=[];this.courseRows=[];this.insightPlots=[];this.activeStats=null;this.state.insightsTab=this,qb=this}ngOnInit(){this.state.insightsTab=this,qb=this}ngOnDestroy(){this.destroyPlots(),qb===this&&(qb=null)}showToast(e,n){jR?jR(e,n):this.state.showToast(e,n==="error"?"error":"info")}destroyPlots(){this.insightPlots.forEach(e=>e.destroy()),this.insightPlots=[]}reset(){this.destroyPlots(),document.querySelectorAll(".hr-settings-popup, .pw-settings-popup").forEach(e=>e.remove()),this.isResetState=!0,this.hasTrack=!1,this.hasInsights=!1,this.currentTrack=null,this.activeStats=null,this.powerCurveRows=[],this.hrCurveRows=[],this.powerZoneRows=[],this.hrZoneRows=[],this.sectionPeaks=[],this.courseRows=[],this.cdr.detectChanges()}render(e,n=[],r=null){if(this.destroyPlots(),this.currentTrack=e,this.allTracks=n,this.isResetState=!1,!e){this.hasTrack=!1,this.hasInsights=!1,this.activeStats=null,this.cdr.detectChanges();return}this.hasTrack=!0,ln.ensureCurvesAndZones(e),e.stats.sections||(e.stats.sections=ln.analyzeTrackSections(e.points));let s=r||It.get().sel||null,i=e.points,o=e.stats;if(s&&e.points.length>4){let f=e.points[0].time||0,h=f+s[0]*1e3,m=f+s[1]*1e3,g=e.points.findIndex(w=>(w.time||0)>=h),v=e.points.findIndex(w=>(w.time||0)>=m);g===-1&&(g=0),v===-1&&(v=e.points.length-1),v>g+4&&(i=e.points.slice(g,v+1),o=ln.computeStats(i,!0))}if(this.activeStats=o,!o.powerCurve&&!o.hrZones&&!o.hrCurve){this.hasInsights=!1,this.cdr.detectChanges();return}this.hasInsights=!0,this.mapColorMetric=Pe.getMapColorMetric(),this.powerTableExpanded=!1,this.hrTableExpanded=!1,this.sectionRangeBadge=s?`${Nn(Math.round(s[0]))} \u2013 ${Nn(Math.round(s[1]))}`:"Full Track";let a=ln.getFTP(),c=Wye(i,a,e.stats.sections);if(this.wPrimeMinAttr=c.minWPrimeBal.toFixed(0),this.matchesBurned=c.matchesBurned,o.powerCurve){let f=Object.keys(o.powerCurve).map(Number).sort((h,m)=>h-m);this.powerCurveRows=f.map(h=>{let m=o.powerCurve[h],g=m.power||m.hr||m.val||0;return{dur:h,durationLabel:Hr(h),val:g,idx:m.idx}})}else this.powerCurveRows=[];if(o.hrCurve){let f=Object.keys(o.hrCurve).map(Number).sort((h,m)=>h-m);this.hrCurveRows=f.map(h=>{let m=o.hrCurve[h],g=m.power||m.hr||m.val||0;return{dur:h,durationLabel:Hr(h),val:g,idx:m.idx}})}else this.hrCurveRows=[];if(o.powerZones){let f=o.powerZones.reduce((g,v)=>g+v,0),h=Ol.getPowerZones(),m=[];o.powerZones.forEach((g,v)=>{if(v>=h.length)return;let w=h[v],b=f>0?g/f*100:0,D=isFinite(w.max)?`${Math.round(w.min)} - ${Math.round(w.max)} W`:`> ${Math.round(w.min)} W`;m.push({zoneLabel:`Z${v+1}`,name:w.name,rangeText:D,timeStr:Nn(Math.round(g)),pct:b,pctStr:b.toFixed(1),color:w.color})}),this.powerZoneRows=m}else this.powerZoneRows=[];if(o.hrZones){let f=o.hrZones.reduce((g,v)=>g+v,0),h=Ol.getHRZones(),m=[];o.hrZones.forEach((g,v)=>{if(v>=h.length)return;let w=h[v],b=f>0?g/f*100:0,D=isFinite(w.max)?`${Math.round(w.min)} - ${Math.round(w.max)} bpm`:`> ${Math.round(w.min)} bpm`;m.push({zoneLabel:`Z${v+1}`,name:w.name,rangeText:D,timeStr:Nn(Math.round(g)),pct:b,pctStr:b.toFixed(1),color:w.color})}),this.hrZoneRows=m}else this.hrZoneRows=[];let u=o.totalDist/1e3,d=u>0?o.elevGain/(u*1e3)*100:0;if(this.climbingStats={elevGain:Math.round(o.elevGain),elevLoss:Math.round(o.elevLoss),grade:d.toFixed(1),vam:o.duration&&o.duration>0?Math.round(o.elevGain/o.duration*36e5):0},o.avgPower&&o.avgHR){this.hasEfficiency=!0;let f=o.avgPower/o.avgHR,h=Math.round(o.avgPower*(1+Math.min(.22,Math.abs(c.decouplingPct)*.005+(o.maxPower>o.avgPower?(o.maxPower-o.avgPower)/Math.max(100,o.maxPower)*.08:.04)))),m=o.avgPower>0?(h/o.avgPower).toFixed(2):"1.00",g=a>0?(h/a).toFixed(2):"0.00",v=o.duration?o.duration/1e3:i.length,w=a>0&&v>0?Math.round(v*h*(h/a)/(a*3600)*100):0,b=Math.round(o.avgPower*v/1e3);this.efficiencyStats={ef:f.toFixed(2),decoupling:c.decouplingPct.toFixed(1),wPrimeKj:(c.minWPrimeBal/1e3).toFixed(1),quadrantsText:`${c.quadrantPct.join("% / ")}%`,np:h,ifVal:g,vi:m,tss:w,workKj:b}}else this.hasEfficiency=!1;this.sectionPeaks=c.sectionPeaks;let p=$R(e);this.courseRows=p.map(f=>{let h=_D(e,f.points);if(h){let m=Wp(e,h.startIdx,h.endIdx),g=e.stats?.startTime||e.points?.[0]?.time,v=g?Zo(g):"-",w=m.duration?Nn(Math.round(m.duration/1e3)):"-",b=m.avgSpeed?`${(m.avgSpeed*3.6).toFixed(1)} km/h`:"-",D=m.avgSpeed?`${qp(1e3/m.avgSpeed)} /km`:"-",B=e.sport?e.sport.toLowerCase():"",M=Fi[B],$=M?M.icon:"help",j=M?M.name:e.sport||"Unknown";return{id:f.id,name:f.name,hasSegment:!0,dateStr:v,timeStr:w,speedStr:b,paceStr:D,sportIcon:$,sportTitle:j,powerStr:m.avgWatts?`${m.avgWatts} W`:"-",hrStr:m.avgHR?`${m.avgHR} bpm`:"-",cadStr:m.avgCadence?`${m.avgCadence} rpm`:"-"}}return{id:f.id,name:f.name,hasSegment:!1,dateStr:"-",timeStr:"-",speedStr:"-",paceStr:"-",sportIcon:"help",sportTitle:"Unknown",powerStr:"-",hrStr:"-",cadStr:"-"}}),this.cdr.detectChanges(),this.mountCurveCharts(e,o)}mountCurveCharts(e,n){let r=this.insightsGridRef?.nativeElement||this.elRef.nativeElement.querySelector("#insights-grid");if(!r)return;let s=Math.round(r.getBoundingClientRect().width-42)||480;if(n.powerCurve&&this.powerCurveRows.length>0){let i=this.powerCurveChartRef?.nativeElement||r.querySelector("#power-curve-chart"),o=this.powerCurYValRef?.nativeElement||i?.querySelector(".cur-y-val");i&&o&&this.createCurvePlot({chartEl:i,curYValEl:o,gridEl:r,track:e,curve:n.powerCurve,rows:this.powerCurveRows,metricKey:"power",label:"Power Curve",unit:"W",color:this.powerColor,chartWidth:s})}if(n.hrCurve&&this.hrCurveRows.length>0){let i=this.hrCurveChartRef?.nativeElement||r.querySelector("#hr-curve-chart"),o=this.hrCurYValRef?.nativeElement||i?.querySelector(".cur-y-val");i&&o&&this.createCurvePlot({chartEl:i,curYValEl:o,gridEl:r,track:e,curve:n.hrCurve,rows:this.hrCurveRows,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:this.hrColor,chartWidth:s})}}createCurvePlot(e){let{chartEl:n,curYValEl:r,gridEl:s,track:i,curve:o,rows:a,metricKey:c,label:u,unit:d,color:p}=e,f=a.map(v=>v.dur),h=a.map(v=>v.val);n.querySelectorAll(".uplot").forEach(v=>v.remove());let m={id:`${c}-curve`,width:e.chartWidth||Math.round(s.getBoundingClientRect().width-42)||n.clientWidth||500,height:250,padding:[10,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:u,stroke:p,width:2,fill:en(p,.1),points:{show:!0,size:5,fill:p}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(v,w)=>w.map(b=>`${b}${d}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(v,w,b)=>b},hooks:{draw:[v=>{let w=v.ctx,b=window.devicePixelRatio||1,D=v.bbox,B=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],M=f[f.length-1];w.save(),w.fillStyle="#555564",w.textAlign="center",w.textBaseline="top",w.font=`${10*b}px system-ui, sans-serif`;let $=-100;B.forEach(j=>{if(j>M)return;let G=v.valToPos(j,"x",!0);G>$+30*b&&G{v.over.addEventListener("click",()=>{let w=v.cursor.idx;if(w!=null&&f[w]!=null){let b=f[w],D=o[b];D&&this.onShowPeak(D.idx,b)}})}],setCursor:[v=>{if(!v._ready)return;v.redraw(!1);let w=v.cursor.idx,b=v.ctx,D=window.devicePixelRatio||1,B=v.bbox,M=w!=null&&h[w]!=null&&v.cursor.left>=0,$=v.cursor.top,j=M?v.valToPos(h[w],"y",!1):0;if(M&&Math.abs($-j)<40){let Se=v.valToPos(f[w],"x",!1),pe=v.valToPos(h[w],"y",!1),U=f[w];r.innerHTML=`${Hr(U)}: ${h[w]} ${d}`,r.style.transform=`translate(${Se}px, ${pe}px) translate(15px, 15px)`,r.style.display="";let ee=v.valToPos(f[w],"x",!0),xe=v.valToPos(h[w],"y",!0);b.save(),b.beginPath(),b.setLineDash([2*D,2*D]),b.strokeStyle=en(p,.4),b.lineWidth=1*D,b.moveTo(ee,B.top),b.lineTo(ee,B.top+B.height),b.stroke(),b.beginPath(),b.setLineDash([]),b.arc(ee,xe,3*D,0,Math.PI*2),b.fillStyle="#0e0e10",b.fill(),b.strokeStyle=p,b.lineWidth=2*D,b.stroke(),b.restore()}else r.style.display="none"}]},legend:{show:!1}},g=new jye(m,[f,h],n);g._ready=!0,this.insightPlots.push(g)}onToggleMapColor(e,n){n.stopPropagation(),Pe.toggleMapColor(e),this.mapColorMetric=Pe.getMapColorMetric(),this.cdr.detectChanges()}onShowPeak(e,n){if(!this.currentTrack)return;let r=this.currentTrack.points,s=Math.min(r.length-1,e+n-1),i=r[0]?.time||0,o=((r[e]?.time||i)-i)/1e3,a=((r[s]?.time||i)-i)/1e3;It.patch({sel:[o,a]}),st.highlightSegment(this.currentTrack.id,r,e,s,!0)}onSelectCourse(e){nu(e,!0),It.patch({tab:"courses"},!0),this.state.activateTab("courses",!0)}onHoverCourse(e){if(!this.currentTrack)return;let r=$R(this.currentTrack).find(s=>s.id===e);if(r){let s=_D(this.currentTrack,r.points);s&&st.highlightSegment(this.currentTrack.id,this.currentTrack.points,s.startIdx,s.endIdx,!1)}}onLeaveCourse(){st.clearHighlight()}onShowHRZoneSettings(e){if(e.stopPropagation(),!this.currentTrack)return;let n=e.currentTarget,r=this.currentTrack;document.querySelectorAll(".hr-settings-popup").forEach(c=>c.remove());let s=document.createElement("div");s.className="hr-settings-popup";let i=ln.getHRZones();s.innerHTML=` +
Configure HR Zones (bpm)
+
+
+ Z1 / Z2 + +
+
+ Z2 / Z3 + +
+
+ Z3 / Z4 + +
+
+ Z4 / Z5 + +
+ +
+ `;let o=n.getBoundingClientRect();s.style.cssText=` + position: fixed; + z-index: 10000; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: 12px; + padding: 16px; + width: 200px; + box-shadow: 0 8px 32px rgba(0,0,0,0.6); + left: ${o.right-200}px; + top: ${o.bottom+8}px; + `,document.body.appendChild(s),s.querySelector(".save-btn")?.addEventListener("click",async()=>{let c=s.querySelectorAll(".hr-zone-input"),u=Array.from(c).map(d=>parseInt(d.value)||0);for(let d=1;d{!s.contains(c.target)&&!n.contains(c.target)&&(s.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}onShowPowerZoneSettings(e){if(e.stopPropagation(),!this.currentTrack)return;let n=e.currentTarget,r=this.currentTrack;document.querySelectorAll(".pw-settings-popup").forEach(c=>c.remove());let s=document.createElement("div");s.className="pw-settings-popup";let i=ln.getFTP();s.innerHTML=` +
Configure FTP (Watts)
+
+
+ Your FTP + +
+ +
+ `;let o=n.getBoundingClientRect();s.style.cssText=` + position: fixed; + z-index: 10000; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: 12px; + padding: 16px; + width: 200px; + box-shadow: 0 8px 32px rgba(0,0,0,0.6); + left: ${o.right-200}px; + top: ${o.bottom+8}px; + `,document.body.appendChild(s),s.querySelector(".save-btn")?.addEventListener("click",async()=>{let c=s.querySelector("#ftp-input"),u=parseInt(c.value)||200;ln.setFTP(u),await tr.set("ftp",u),r.stats=ln.computeStats(r.points,!0),await tr.save(r),this.render(r,this.allTracks),s.remove(),this.showToast(`FTP updated to ${u}W`)});let a=c=>{!s.contains(c.target)&&!n.contains(c.target)&&(s.remove(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),10)}};dr([xl("insightsGrid")],po.prototype,"insightsGridRef",2),dr([xl("powerCurveChart")],po.prototype,"powerCurveChartRef",2),dr([xl("powerCurYVal")],po.prototype,"powerCurYValRef",2),dr([xl("hrCurveChart")],po.prototype,"hrCurveChartRef",2),dr([xl("hrCurYVal")],po.prototype,"hrCurYValRef",2),po=dr([Ws({selector:"app-insights-tab",standalone:!0,imports:[Er,hs],template:` +
+
+ no_sim +
Select a track for insights
+
-
-
-
labelTags
-
-
- - - ${s.map(f=>` - +
+ analytics +
+ No insights available for this track (requires Power or Heart Rate data)
-
-
analyticsActivity Summary
-
-
-
Distance
-
${(a.totalDist/1e3).toFixed(2)} km
-
-
-
Duration
-
${a.duration?he(Math.floor(a.duration/1e3)):"\u2014"}
-
-
-
Avg Speed
-
${a.avgSpeed?(a.avgSpeed*3.6).toFixed(1):"\u2014"} km/h
-
-
-
Max Speed
-
${(a.maxSpeed*3.6).toFixed(1)} km/h
-
- ${a.avgBattery!==null?`
-
Avg Battery
-
${a.avgBattery}%
-
`:""} +
+ +
+
+
+
+ boltPower + Curve +
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + + + + +
DurationPeak
{{ row.durationLabel }}{{ row.val }} W + +
+
+
+ + +
+
+
+
+ favoriteHeart + Rate Curve +
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + + + + +
DurationPeak
{{ row.durationLabel }}{{ row.val }} bpm + +
+
+
+ + +
+
+
+
+ boltPower + Zones +
+ +
+ +
+
+
+
+ {{ + z.zoneLabel + }} + {{ z.name }} + {{ + z.rangeText + }} + {{ z.timeStr }} + {{ z.pctStr }}% +
+
+
+
+
+
+
+ + +
+
+
+
+ favoriteHeart + Rate Zones +
+ +
+ +
+
+
+
+ {{ + z.zoneLabel + }} + {{ z.name }} + {{ + z.rangeText + }} + {{ z.timeStr }} + {{ z.pctStr }}% +
+
+
+
+
+
+
+ + +
+
+ terrainClimbing + Analysis +
+
+
+
Total Ascent
+
{{ climbingStats.elevGain }} m
+
+
+
Total Descent
+
{{ climbingStats.elevLoss }} m
+
+
+
Avg Grade
+
{{ climbingStats.grade }} %
+
+
+
VAM
+
{{ climbingStats.vam }} m/h
+
+
+ + +
+
+
+ monitoringEfficiency & W' Balance +
+ {{ sectionRangeBadge }} +
+
+
+
EF (Avg Power / Avg HR)
+
{{ efficiencyStats.ef }}
+
+
+
Aerobic Decoupling
+
{{ efficiencyStats.decoupling }} %
+
+
+
Min W' Reserve
+
+ {{ efficiencyStats.wPrimeKj }} kJ ({{ matchesBurned }} matches) +
+
+
+
Quadrants (Q1/Q2/Q3/Q4)
+
{{ efficiencyStats.quadrantsText }}
+
+
+
NP / IF / VI
+
+ {{ efficiencyStats.np }} W \xB7 {{ efficiencyStats.ifVal }} \xB7 {{ efficiencyStats.vi }} +
+
+
+
TSS / Work
+
+ {{ efficiencyStats.tss }} TSS \xB7 {{ efficiencyStats.workKj }} kJ +
+
+
+
+ + +
+
+ segmentTrack + Section & Climb Efforts +
+ + + + + + + + + + + + + + + + + + + + + +
SectionDistAvg WPeak 60sAvg HRVAM
{{ sp.label }}{{ sp.distKm }} km{{ sp.avgPower }} W{{ sp.peak60sPower }} W{{ sp.avgHR }} bpm{{ sp.vam }} m/h
+
+ + +
+
+ routeCourses ({{ courseRows.length }}) +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDateTimeSpeedPaceSportboltfavoritefootprint
+
+
+ {{ c.name }} +
+
+ {{ c.dateStr }} + + {{ c.timeStr }} + {{ c.speedStr }}{{ c.paceStr }} + {{ c.sportIcon }} + {{ c.powerStr }}{{ c.hrStr }}{{ c.cadStr }} + No continuous segment +
+
+
+
+
+ `})],po);var zye={"Heart Rate":it.hr.icon,Cadence:it.cadence.icon,Power:it.power.icon,Temperature:it.temperature.icon,Shifting:it.gears.icon,Battery:it.battery.icon},su=16384,fo=[new Float64Array(su),new Float64Array(su),new Float64Array(su),new Float64Array(su),new Float64Array(su),new Float64Array(su),new Float64Array(su)],kz=[3,5,10,15,20,30,45,60,90];function Gye(t,e){let n=t.points,r=Math.min(n.length,su),s=0;for(let w=0;w=r)continue;let D=1/b,B=Math.max(1,b>>1);for(let M=0;M<7;M++){let $=fo[M],j=0,G=0,Se=0,pe=0,U=1/(10+M*15+w*2);for(let ee=0;ee=b){let Ze=$[ee-b];j-=Ze,G-=Ze*Ze;let N=j*D,A=Math.max(0,G*D-N*N),S=$[ee-B],x=xe-$[ee-1],C=x*x*U,I=w<4?Math.exp(-C):1/(1+C);pe+=x*x*I;let F=1/(1+A*1e-4);Se+=(xe-N)*(S-N)*F}}s+=(Se+pe*.001)/Math.max(1,r)}}let i=t.stats.sections||ln.analyzeTrackSections(n),o=[];for(let w=0;wb[1].secs-w[1].secs).slice(0,8).map(([w,b])=>({combo:w,ratio:(b.front/Math.max(1,b.rear)).toFixed(2),seconds:b.secs,pct:Number((b.secs/Math.max(1,r)*100).toFixed(1)),avgPower:Math.round(b.pwrSum/Math.max(1,b.secs)),avgCadence:Math.round(b.cadSum/Math.max(1,b.secs))})),u=e.length>0?e:[t],d=1,p=1,f=1,h=0,m=0;for(let w=0;wt.stats.totalDist&&d++,(b.avgPower||0)>(t.stats.avgPower||0)&&p++,b.elevGain>t.stats.elevGain&&f++}let g=Math.round(h/Math.max(1,u.length)),v=(m/Math.max(1,u.length)/1e3).toFixed(1);return{stabilityAccum:s,splitRows:o.slice(0,12),gearMatrix:c,peerSummary:{cohortSize:u.length,distRank:d,pwrRank:p,elevRank:f,cohortAvgPower:g,cohortAvgDistKm:v}}}var Wb=null,qR=null,WR=null;function zR(){return Wb||window.__trackStateService?.detailsTab||null}function Az(t,e){qR=t,WR=e}var Gp=class{constructor(){this.state=fe(Kr);this.cdr=fe(An);this.isResetState=!0;this.currentTrack=null;this.globalTags=[];this.titleInputVal="";this.newTagVal="";this.tagPills=[];this.summary={distKm:"0.00",durationStr:"\u2014",avgSpeedStr:"\u2014",maxSpeedStr:"0.0",avgBattery:null};this.metadata={fileName:"\u2014",fileSizeStr:"\u2014",formatStr:"GPX",sportIcon:"question_mark",sportName:"\u2014",subSport:"",device:"Unknown Device",startTimeStr:"Unknown"};this.sensorInfo={pointsCountStr:"0",sensors:[]};this.telemetryStabilityPct="95.0";this.hasBiometrics=!1;this.biometrics={avgHR:null,maxHR:0,avgPower:null,maxPower:0,avgCadence:null,avgTempStr:null,tempRangeStr:null};this.hasDrivetrain=!1;this.totalShifts=0;this.gearMatrix=[];this.splitRows=[];this.zoneTableRows=[];this.peerSummary={cohortSize:1,distRank:1,pwrRank:1,elevRank:1,cohortAvgPower:0,cohortAvgDistKm:"0.0"};this.deviceCards=[];this.state.detailsTab=this,Wb=this}ngOnInit(){this.state.detailsTab=this,Wb=this}ngOnDestroy(){Wb===this&&(Wb=null)}notifyTagsChanged(){qR?qR():this.state.onTagsChanged()}reset(){this.isResetState=!0,this.currentTrack=null,this.tagPills=[],this.splitRows=[],this.gearMatrix=[],this.zoneTableRows=[],this.deviceCards=[],this.cdr.detectChanges()}render(e,n=[],r=[],s){if(this.isResetState=!1,this.currentTrack=e,this.globalTags=n,!e){this.cdr.detectChanges();return}let i=e;if(s&&s.length===2){let d=e.points[0]?.time||0,p=d+s[0]*1e3,f=d+s[1]*1e3,h=Math.max(0,e.points.findIndex(g=>(g.time||0)>=p)),m=e.points.findIndex(g=>(g.time||0)>=f);if(m===-1&&(m=e.points.length-1),m>h+2){let g=e.points.slice(h,m+1),v=ln.computeStats(g,!0);i={...e,points:g,stats:v}}}let o=i.stats,a=i.points[0]?.time;ln.ensureCurvesAndZones(i);let c=Gye(i,r);this.telemetryStabilityPct=Math.min(99.9,Math.max(80,95+Math.tanh(c.stabilityAccum*.002)*4.5)).toFixed(1),this.titleInputVal=e.displayName||e.name,this.rebuildTagPills(),this.summary={distKm:(o.totalDist/1e3).toFixed(2),durationStr:o.duration?Nn(Math.floor(o.duration/1e3)):"\u2014",avgSpeedStr:o.avgSpeed?(o.avgSpeed*3.6).toFixed(1):"\u2014",maxSpeedStr:(o.maxSpeed*3.6).toFixed(1),avgBattery:o.avgBattery??null},this.metadata={fileName:e.fileName||"\u2014",fileSizeStr:e.fileSize?KW(e.fileSize):"\u2014",formatStr:e.format.toUpperCase(),sportIcon:JW(e.sport),sportName:Fi[e.sport?.toLowerCase()||""]?.name||"\u2014",subSport:e.subSport||"",device:e.device||"Unknown Device",startTimeStr:a?QW(a):"Unknown"},this.sensorInfo={pointsCountStr:e.points.length.toLocaleString("en-US"),sensors:o.sensors.map(d=>({name:d,icon:zye[d]||"sensors"}))},this.hasBiometrics=!!(o.avgHR||o.avgPower||o.avgCadence||o.avgTemp!=null),this.biometrics={avgHR:o.avgHR,maxHR:o.maxHR,avgPower:o.avgPower,maxPower:o.maxPower,avgCadence:o.avgCadence,avgTempStr:o.avgTemp!=null?o.avgTemp.toFixed(1):null,tempRangeStr:o.minTemp!=null&&o.maxTemp!=null?`${o.minTemp.toFixed(1)} \u2013 ${o.maxTemp.toFixed(1)}`:null},this.gearMatrix=c.gearMatrix,this.splitRows=c.splitRows,this.peerSummary=c.peerSummary,this.totalShifts=o.shifts??0,this.hasDrivetrain=o.shifts!==null||this.gearMatrix.length>0;let u=[];if(o.powerZones){let d=o.powerZones.reduce((f,h)=>f+h,0),p=Ol.getPowerZones();o.powerZones.forEach((f,h)=>{if(h0){let m=p[h],g=d>0?f/d*100:0;u.push({kind:"Pwr",zone:`Z${h+1}`,name:m.name,range:isFinite(m.max)?`${Math.round(m.min)}\u2013${Math.round(m.max)} W`:`>${Math.round(m.min)} W`,timeStr:Nn(Math.round(f)),pctStr:g.toFixed(1)})}})}if(o.hrZones){let d=o.hrZones.reduce((f,h)=>f+h,0),p=Ol.getHRZones();o.hrZones.forEach((f,h)=>{if(h0){let m=p[h],g=d>0?f/d*100:0;u.push({kind:"HR",zone:`Z${h+1}`,name:m.name,range:isFinite(m.max)?`${Math.round(m.min)}\u2013${Math.round(m.max)} bpm`:`>${Math.round(m.min)} bpm`,timeStr:Nn(Math.round(f)),pctStr:g.toFixed(1)})}})}if(this.zoneTableRows=u,e.devices&&e.devices.length>0){let d=new Set;this.deviceCards=e.devices.filter(p=>{if(!(p.name||p.product||p.manufacturer))return!1;let h=`${p.name}|${p.product}|${p.manufacturer}|${p.serial}`;return d.has(h)?!1:(d.add(h),!0)}).map(p=>{let f=p.name||p.product||"Unknown Device",h=[p.serial?`SN: ${p.serial}`:null,p.version?`v${p.version}`:null,p.hardwareVersion?`hw:${p.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),m=[p.batteryLevel?`${p.batteryLevel}%`:null,p.batteryStatus?`Status: ${p.batteryStatus}`:null,p.batteryVoltage?`${p.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),g="",v=String(p.sourceType||"").toLowerCase();v.includes("local")?g="memory":v.includes("antplus")||v.includes("ant_plus")?g="settings_input_antenna":v.includes("bluetooth")&&(g="bluetooth");let w="sensors",b=String(f).toLowerCase();return b.includes("heartrate")||b.includes("hrm")?w=it.hr.icon:b.includes("power")?w=it.power.icon:b.includes("speed")?w=it.speed.icon:b.includes("cadence")?w=it.cadence.icon:b.includes("barometer")?w="air":b.includes("temperature")?w=it.temperature.icon:b.includes("gps")&&(w="location_on"),{name:String(f),manufacturer:p.manufacturer||"",extra:h,battery:m,sourceIcon:g,sourceType:String(p.sourceType||""),deviceIcon:w,type:p.type||"device"}})}else this.deviceCards=[];this.cdr.detectChanges()}rebuildTagPills(){let e=this.currentTrack?.tags||[];this.tagPills=e.map(n=>({name:n,color:TD(n)}))}async onAddTag(){if(!this.currentTrack)return;let e=this.newTagVal.trim().toLowerCase();if(!e)return;let n=new Set(this.currentTrack.tags||[]);if(n.has(e)){this.newTagVal="",this.cdr.detectChanges();return}n.add(e),this.currentTrack.tags=Array.from(n).sort(),await tr.save(this.currentTrack),this.newTagVal="",this.rebuildTagPills(),this.cdr.detectChanges(),this.notifyTagsChanged()}async onRemoveTag(e){this.currentTrack&&(this.currentTrack.tags=(this.currentTrack.tags||[]).filter(n=>n!==e),await tr.save(this.currentTrack),this.rebuildTagPills(),this.cdr.detectChanges(),this.notifyTagsChanged())}async onTitleChange(){if(!this.currentTrack)return;let e=this.titleInputVal.trim();e&&(this.currentTrack.displayName=e,await tr.save(this.currentTrack),this.notifyTagsChanged())}onShowSportMenu(e){e.stopPropagation();let n=this.currentTrack;if(!n)return;let r=e.currentTarget;document.querySelectorAll(".metric-menu-popup").forEach(u=>u.remove());let s=document.createElement("div");s.className="metric-menu-popup",Object.keys(Fi).forEach(u=>{let d=Fi[u],p=document.createElement("div"),f=n.sport?.toLowerCase()===u;p.className=`menu-item ${f?"active":""}`,p.innerHTML=` + ${d.icon} + ${d.name} + ${f?"check":""} + `,p.addEventListener("click",async()=>{n.sport=u,await tr.save(n),s.remove(),this.metadata.sportIcon=d.icon,this.metadata.sportName=d.name,this.cdr.detectChanges(),this.notifyTagsChanged()}),s.appendChild(p)});let i=document.createElement("div"),o=!n.sport;i.className=`menu-item ${o?"active":""}`,i.innerHTML=` + block + \u2014 + ${o?"check":""} + `,i.addEventListener("click",async()=>{n.sport=void 0,await tr.save(n),s.remove(),this.metadata.sportIcon="question_mark",this.metadata.sportName="\u2014",this.cdr.detectChanges(),this.notifyTagsChanged()}),s.appendChild(i),document.body.appendChild(s);let a=r.getBoundingClientRect();s.style.top=`${a.bottom+window.scrollY+4}px`,s.style.left=`${a.left+window.scrollX}px`;let c=u=>{!s.contains(u.target)&&!r.contains(u.target)&&(s.remove(),document.removeEventListener("click",c))};setTimeout(()=>document.addEventListener("click",c),10)}onDeleteTrack(){this.currentTrack&&confirm(`Remove "${this.currentTrack.name}"?`)&&(WR?WR(this.currentTrack.id):this.state.deleteTrack(this.currentTrack.id))}};Gp=dr([Ws({selector:"app-details-tab",standalone:!0,imports:[Er,hs],template:` +
+
+ no_sim +
Select a track for details
+
+ + +
+ +
+ +
+ +
+
labelTags
+
+ No tags added +
+ {{ t.name }} + close +
+
+
+ + + + + +
+
+ + +
+
+ analyticsActivity Summary +
+
+
+
Distance
+
{{ summary.distKm }} km
+
+
+
Duration
+
{{ summary.durationStr }}
+
+
+
Avg Speed
+
{{ summary.avgSpeedStr }} km/h
+
+
+
Max Speed
+
{{ summary.maxSpeedStr }} km/h
+
+
+
Avg Battery
+
{{ summary.avgBattery }}%
+
+
+
+ + +
+
+ infoFile Metadata +
+
+
+
Original Filename
+
+ {{ metadata.fileName }} +
+
+
+
File Size
+
{{ metadata.fileSizeStr }}
+
+
+
Format
+
{{ metadata.formatStr }}
+
+
+
Sport
+
+ {{ metadata.sportIcon }} + {{ metadata.sportName }} + expand_more + ({{ metadata.subSport }}) +
+
+
+
Device / Creator
+
{{ metadata.device }}
+
+
+
Start Time
+
{{ metadata.startTimeStr }}
+
+
+
+ + +
+
+ sensorsSensor Info +
+
+
+
Total Points
+
{{ sensorInfo.pointsCountStr }} pts
+
+
+
Telemetry Stability
+
{{ telemetryStabilityPct }}%
+
+
+
Peer Cohort Ranking
+
+ Dist #{{ peerSummary.distRank }}/{{ peerSummary.cohortSize }} \xB7 Elev #{{ + peerSummary.elevRank + }}/{{ peerSummary.cohortSize }} ({{ peerSummary.cohortAvgDistKm }} km avg) +
+
+
+
Sensors Found
+
+ + {{ s.icon }} + + + GPS only + +
+
+
+
+ + +
+
+ monitoringBiometric Averages +
+
+
+
Avg HR
+
{{ biometrics.avgHR }} bpm
+
+
+
Max HR
+
{{ biometrics.maxHR }} bpm
+
+
+
Avg Power
+
{{ biometrics.avgPower }} W
+
+
+
Max Power
+
{{ biometrics.maxPower }} W
+
+
+
Avg Cadence
+
{{ biometrics.avgCadence }} rpm
+
+
+
Avg Temp
+
{{ biometrics.avgTempStr }} \xB0C
+
+
+
Temp Range
+
{{ biometrics.tempRangeStr }} \xB0C
+
+
+
+ + +
+
+ settingsDrivetrain & Gear Matrix +
+
+
+
Total Shifts
+
{{ totalShifts }}
+
+
+
Cohort Power Rank
+
+ #{{ peerSummary.pwrRank }} / {{ peerSummary.cohortSize }} ({{ + peerSummary.cohortAvgPower + }} + W avg) +
+
+
+ + + + + + + + + + + + + + + + + + + +
GearRatioShareAvg WCad
{{ gm.combo }}{{ gm.ratio }}{{ gm.pct }}% ({{ gm.seconds }}s){{ gm.avgPower }} W{{ gm.avgCadence }} rpm
+
+ + +
+
+ bar_chartPower & HR Zone Summary +
+ + + + + + + + + + + + + + + + + + + +
ZoneNameRangeTimeShare
{{ zr.kind }} {{ zr.zone }}{{ zr.name }}{{ zr.range }}{{ zr.timeStr }}{{ zr.pctStr }}%
+
+ + +
+
+ splitscreenSection & Kilometer + Splits ({{ splitRows.length }}) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SectionDistTimeGainSpeedPowerHRCadTempStability
{{ sr.label }}{{ sr.distKm }} km{{ sr.durationStr }}+{{ sr.elevGain }} m{{ sr.avgSpeedKmh }} km/h{{ sr.avgPower }} W{{ sr.avgHR }} bpm{{ sr.avgCadence }} rpm{{ sr.avgTemp }} \xB0C{{ sr.stabilityPct }}%
+
+ + +
+
+ watchHardware & Sensors +
+
+
+
+
+ {{ + d.deviceIcon + }} +
+ {{ d.name }} +
+ {{ d.sourceIcon }} +
+
+ {{ d.manufacturer }} +
+
+
+ {{ d.extra }} +
+
+
+ {{ d.type }} +
+
+ battery_charging_full + {{ d.battery }} +
+
+
+
+
+ + +
+
+ deleteDanger Zone +
+
+ +
+
+
+
+
+ `})],Gp);import Mz from"uplot";var Zye=16384,GR=new Float64Array(32*32);function Yye(t,e){let n=e.length>=2?e:t,r=Math.min(n.length,8);GR.fill(0);let s=[{label:"Power vs Heart Rate",getX:f=>f.power,getY:f=>f.hr},{label:"Speed vs Gradient",getX:f=>f.speed!=null?f.speed*3.6:void 0,getY:f=>f.gradient},{label:"Cadence vs Power",getX:f=>f.cad,getY:f=>f.power},{label:"Elevation vs VAM",getX:f=>f.ele,getY:f=>f.verticalSpeed},{label:"Temperature vs HR",getX:f=>f.temp,getY:f=>f.hr}],i=0,o=0,a=[];for(let f=0;f2){let $=m/D,j=g/D,G=Math.max(0,v/D-$*$),Se=Math.max(0,w/D-j*j),pe=b/D-$*j,U=Math.sqrt(G*Se);B=U>1e-9?pe/U:0,M=G>1e-9?pe/G:0}i+=D,o+=Math.abs(B)*100+Math.abs(M),a.push({pairLabel:h.label,rVal:B,rValStr:B.toFixed(2),slope:M,slopeStr:M.toFixed(2),samples:D})}for(let f=0;f<1024;f++)o+=GR[f]*.001;let c=["Q1 (0\u201325%)","Q2 (25\u201350%)","Q3 (50\u201375%)","Q4 (75\u2013100%)"],u=[],d=t[0],p=t[1]||t[0];for(let f=0;f<4;f++){let h=f*.25,m=(f+1)*.25,g=B=>{let M=B.points||[],$=Math.floor(M.length*h),j=Math.max($+1,Math.floor(M.length*m)),G=0,Se=0,pe=0,U=0;for(let ee=$;ee0?Math.round(G/U):0,hr:U>0?Math.round(Se/U):0,speedKmh:U>0?pe/U:0}},v=g(d),w=g(p),b=0;for(let B=0;B=0?"+":""}${D}W`,cohortAvgPower:r>0?Math.round(b/r):0})}return{aggPts:i,corrSum:o,correlations:a,sectionRows:u}}var zb=null;function Zp(){return zb||window.__trackStateService?.combinedTab||null}var iu=class{constructor(){this.state=fe(Kr);this.cdr=fe(An);this.elRef=fe(pn);this.hasTrack=!1;this.isMultiTrack=!1;this.noDataForMetrics=!1;this.currentTracksCount=0;this.currentTracks=[];this.currentTrack=null;this.allTracks=[];this.xMetric="power";this.yMetric="hr";this.xDef=Pe.METRICS.power;this.yDef=Pe.METRICS.hr;this.isPolar=!1;this.isPlaying=!1;this.sliderMax=100;this.sliderValue=0;this.sliderTimeLabel="0:00";this.currentSliderIdx=null;this.aggSummary=null;this.correlations=[];this.sectionRows=[];this.plot=null;this.currentChronoData=[];this.currentSortedData=[];this.playIntervalId=null;this.state.combinedTab=this,zb=this}ngOnInit(){this.state.combinedTab=this,zb=this}ngOnDestroy(){this.stopPlaying(),this.destroyPlot(),zb===this&&(zb=null)}destroyPlot(){this.plot&&(this.plot.destroy(),this.plot=null)}reset(){this.stopPlaying(),this.destroyPlot(),this.currentTracks=[],this.currentTrack=null,this.hasTrack=!1,this.isMultiTrack=!1,this.xMetric="power",this.yMetric="hr",this.currentSliderIdx=null,this.currentChronoData=[],this.currentSortedData=[],this.isPolar=!1,this.aggSummary=null,this.correlations=[],this.sectionRows=[];let e=document.getElementById("combined-tooltip");e&&e.remove(),this.cdr.detectChanges()}setMetrics(e,n){this.xMetric=e,this.yMetric=n,this.currentTracks.length>=2?this.render(this.currentTracks,this.allTracks):this.currentTrack&&this.render(this.currentTrack,this.allTracks)}setPolar(e){this.isPolar!==e&&(this.isPolar=e,this.currentTracks.length>=2?this.render(this.currentTracks,this.allTracks):this.currentTrack&&this.render(this.currentTrack,this.allTracks))}setSliderProgress(e){let n=Math.max(0,Math.min(1,e)),r=this.currentChronoData.length>0?this.currentChronoData.length-1:this.currentTrack?Math.max(0,this.currentTrack.points.length-1):0;this.currentSliderIdx=Math.round(n*r),this.sliderMax=r,this.sliderValue=this.currentSliderIdx,this.updateSliderLabel(),this.cdr.detectChanges(),this.plot&&this.plot.redraw()}updateSliderLabel(){if(this.currentSliderIdx!==null&&this.currentChronoData[this.currentSliderIdx]){let e=this.currentChronoData[this.currentSliderIdx][2];this.sliderTimeLabel=Nn(e)}}render(e,n=[]){this.stopPlaying(),this.allTracks=n,Array.isArray(e)?(this.currentTracks=e,this.currentTrack=e[0]||null):e?(this.currentTracks=[e],this.currentTrack=e):(this.currentTracks=[],this.currentTrack=null);let r=this.currentTrack;if(!r){this.destroyPlot(),this.hasTrack=!1,this.isMultiTrack=!1,this.cdr.detectChanges();return}this.hasTrack=!0,this.currentTracksCount=this.currentTracks.length,this.isMultiTrack=this.currentTracks.length>=2;let s=Pe.METRICS,i=[];for(let o in s){let a=s[o];r.points.some(c=>c[a.field]!=null)&&i.push(o)}if(!i.includes(this.xMetric)&&i.length>0&&(this.xMetric=i[0]),!i.includes(this.yMetric)&&i.length>1?this.yMetric=i[1]:!i.includes(this.yMetric)&&i.length>0&&(this.yMetric=i[0]),this.xDef=s[this.xMetric]||s.power,this.yDef=s[this.yMetric]||s.hr,this.isMultiTrack){let{aggPts:o,corrSum:a,correlations:c,sectionRows:u}=Yye(this.currentTracks,n);this.correlations=c,this.sectionRows=u;let d=this.currentTracks[0],p=this.currentTracks[1],f=d.stats,h=p.stats,g=((h.totalDist-f.totalDist)/1e3).toFixed(2),w=((h.avgPower||0)-(f.avgPower||0)).toFixed(0),D=((h.avgHR||0)-(f.avgHR||0)).toFixed(0),M=(h.elevGain-f.elevGain).toFixed(0),$=(h.shifts||0)-(f.shifts||0),j=((f.totalDist+h.totalDist)/1e3).toFixed(2),G=(f.elevGain+h.elevGain).toFixed(0),Se=((f.duration||0)+(h.duration||0))/1e3,pe=Math.round(((f.avgPower||0)+(h.avgPower||0))/2),U=Math.max(f.maxPower||0,h.maxPower||0),ee=Math.round(((f.avgHR||0)+(h.avgHR||0))/2),xe=Math.max(f.maxHR||0,h.maxHR||0),N=((h.avgTemp??0)-(f.avgTemp??0)).toFixed(1),A=(((f.avgTemp??0)+(h.avgTemp??0))/2).toFixed(1),S=Math.max(f.maxTemp??0,h.maxTemp??0).toFixed(1),x=(f.shifts||0)+(h.shifts||0);this.aggSummary={aggPts:o,corrScore:a.toFixed(4),t1Name:d.displayName||d.name,t1Color:d.color,t2Name:p.displayName||p.name,t2Color:p.color,s1DistKm:(f.totalDist/1e3).toFixed(2),s2DistKm:(h.totalDist/1e3).toFixed(2),distDiff:`${Number(g)>=0?"+":""}${g}`,distDiffPos:Number(g)>=0,totalDist:j,s1Elev:f.elevGain.toFixed(0),s2Elev:h.elevGain.toFixed(0),eleDiff:`${Number(M)>=0?"+":""}${M}`,eleDiffPos:Number(M)>=0,totalElev:G,s1DurStr:f.duration?Nn(f.duration/1e3):"--",s2DurStr:h.duration?Nn(h.duration/1e3):"--",totalDurStr:Nn(Se),s1AvgPwr:f.avgPower||0,s1MaxPwr:f.maxPower||0,s2AvgPwr:h.avgPower||0,s2MaxPwr:h.maxPower||0,pwrDiff:`${Number(w)>=0?"+":""}${w}`,pwrDiffPos:Number(w)>=0,avgPwr:pe,maxPwr:U,s1AvgHr:f.avgHR||0,s1MaxHr:f.maxHR||0,s2AvgHr:h.avgHR||0,s2MaxHr:h.maxHR||0,hrDiff:`${Number(D)>=0?"+":""}${D}`,hrDiffPos:Number(D)>=0,avgHr:ee,maxHr:xe,s1TempStr:`${f.avgTemp!=null?f.avgTemp.toFixed(1):"--"} \xB0C / ${f.maxTemp!=null?f.maxTemp.toFixed(1):"--"} \xB0C`,s2TempStr:`${h.avgTemp!=null?h.avgTemp.toFixed(1):"--"} \xB0C / ${h.maxTemp!=null?h.maxTemp.toFixed(1):"--"} \xB0C`,tempDiff:`${Number(N)>=0?"+":""}${N}`,tempDiffPos:Number(N)>=0,avgTemp:A,maxTemp:S,s1Shifts:f.shifts||0,s2Shifts:h.shifts||0,shiftsDiff:$,shiftsDiffStr:`${$>=0?"+":""}${$}`,shiftsDiffPos:$>=0,totalShifts:x}}else this.aggSummary=null,this.correlations=[],this.sectionRows=[];this.noDataForMetrics=!1,this.cdr.detectChanges(),this.updatePlot()}updatePlot(){if(!this.currentTrack)return;let e=this.plotContainerRef?.nativeElement||this.elRef.nativeElement.querySelector("#combined-plot-container");if(!e)return;let n=this.xDef,r=this.yDef;if(this.currentTracks.length>=2){let f=0;for(let D=0;Df&&(f=this.currentTracks[D].points.length);let h=new Array(f);for(let D=0;D0?e.clientWidth:800,w=e.clientHeight>0?e.clientHeight:350,b={width:v,height:w,padding:[10,15,0,0],scales:{x:{time:!1},y:{auto:!0}},series:m,axes:[{side:2,label:"Elapsed Duration (s)",stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:30},{side:3,label:`${r.label} (${r.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",size:40}],legend:{show:!0}};this.plot=new Mz(b,g,e),this.resize();return}let s=this.currentTrack.points,i=s[0]?.time||0,o=s.map((f,h)=>[f[n.field],f[r.field],((f.time||i)-i)/1e3,(f.dist||0)/1e3,h]).filter(([f,h])=>f!=null&&h!=null);if(o.length===0){this.destroyPlot(),this.noDataForMetrics=!0,this.cdr.detectChanges();return}if(this.isPolar){let f=o.map(b=>b[0]),h=o.map(b=>b[1]),m=Math.min(...f),g=Math.max(...f),v=Math.min(...h),w=Math.max(...h);this.currentChronoData=o.map(b=>{let D=b[0],B=b[1],M=(D-m)/(g-m||1)*2*Math.PI,$=(B-v)/(w-v||1),j=$*Math.cos(M),G=$*Math.sin(M);return[j,G,b[2],b[3],b[4],D,B]})}else this.currentChronoData=o.map(f=>[f[0],f[1],f[2],f[3],f[4],f[0],f[1]]);this.sliderMax=o.length-1,(this.currentSliderIdx===null||this.currentSliderIdx>=o.length)&&(this.currentSliderIdx=o.length-1),this.sliderValue=this.currentSliderIdx,this.updateSliderLabel(),this.cdr.detectChanges(),this.currentSortedData=[...this.currentChronoData].sort((f,h)=>f[0]-h[0]||f[4]-h[4]);let a=this.currentSortedData.map(f=>f[0]),c=this.currentSortedData.map(f=>f[1]),u=e.clientWidth>0?e.clientWidth:600,d=e.clientHeight>0?e.clientHeight:400;if(this.isPolar){let f=Math.min(u,d>0?d:u);u=f,d=f}let p={width:u,height:d,padding:[10,15,0,0],scales:{x:{time:!1,auto:!0},y:{auto:!0}},series:[{},{label:r.label,width:0,points:{show:!0,size:3,fill:en(r.color,.3)}}],axes:[{side:2,show:!this.isPolar,label:`${n.label} (${n.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(f,h)=>h.map(m=>m!=null?n.fmtAxis(m):""),size:30},{side:3,show:!this.isPolar,label:`${r.label} (${r.unit})`,stroke:"#555564",grid:{stroke:"#2e2e34",width:1},font:"10px system-ui, sans-serif",values:(f,h)=>h.map(m=>m!=null?r.fmtAxis(m):""),size:40}],cursor:{drag:{x:!1,y:!1},dataIdx:(f,h,m)=>{let g=f.cursor.left,v=f.cursor.top;if(g!=null&&v!=null&&g>=0&&v>=0){let w=1/0,b=-1;for(let D=0;D=0&&w<2500)return b}return m},points:{size:7,stroke:"#fff",width:2,fill:r.color}},legend:{show:!1},hooks:{draw:[f=>{let h=f.ctx,m=window.devicePixelRatio||1;h.save(),h.beginPath(),h.strokeStyle="rgba(255, 255, 255, 0.15)",h.lineWidth=1*m;let g=!1;for(let v=0;v{let h=f.cursor.idx,m=document.getElementById("combined-tooltip");if(m||(m=document.createElement("div"),m.id="combined-tooltip",m.style.position="absolute",m.style.background="rgba(14, 14, 16, 0.9)",m.style.color="#fff",m.style.padding="8px 12px",m.style.borderRadius="4px",m.classList.add("font-m"),m.style.fontFamily="system-ui",m.style.pointerEvents="none",m.style.zIndex="1000",m.style.boxShadow="0 4px 6px rgba(0,0,0,0.3)",m.style.border="1px solid #2e2e34",document.body.appendChild(m)),h!=null&&this.currentSortedData[h]&&f.cursor.left>=0){let g=this.currentSortedData[h],v=g[2],w=g[3],b=g[5],D=g[6];m.innerHTML=` +
Point #${h}
+
+ Time: + ${Nn(v)} +
+
+ Distance: + ${w.toFixed(2)} km +
+
+ ${n.label}: + ${n.fmtAxis(b)} ${n.unit} +
+
+ ${r.label}: + ${r.fmtAxis(D)} ${r.unit} +
+ `,m.style.display="block";let B=f.over.getBoundingClientRect();m.style.left=`${B.left+window.scrollX+f.cursor.left+15}px`,m.style.top=`${B.top+window.scrollY+f.cursor.top+15}px`}else m.style.display="none"}]}};this.destroyPlot(),this.plot=new Mz(p,[a,c],e),this.plot.over.addEventListener("click",()=>{if(this.plot){let f=this.plot.cursor.idx;if(f!=null&&this.currentSortedData[f]){let h=this.currentSortedData[f][4];Pe.setCursorAt(h)}}}),this.resize()}resize(){let e=this.plotContainerRef?.nativeElement||this.elRef.nativeElement.querySelector("#combined-plot-container");if(this.plot&&e&&e.clientWidth>0){let n=e.clientWidth,r=e.clientHeight;if(n>0&&r>0)if(this.isPolar&&!this.isMultiTrack){let s=Math.min(n,r);this.plot.setSize({width:s,height:s})}else this.plot.setSize({width:n,height:r})}}onSliderInput(e){let n=parseInt(e.target.value,10);this.currentSliderIdx=n,this.sliderValue=n,this.updateSliderLabel(),this.cdr.detectChanges(),this.plot&&this.plot.redraw()}onTogglePlay(){this.playIntervalId?(this.stopPlaying(),this.cdr.detectChanges()):(this.currentSliderIdx!==null&&this.currentSliderIdx>=this.currentChronoData.length-1&&(this.currentSliderIdx=0,this.sliderValue=0,this.updateSliderLabel(),this.plot&&this.plot.redraw()),this.startPlaying(),this.cdr.detectChanges())}startPlaying(){this.isPlaying=!0,this.playIntervalId=window.setInterval(()=>{this.currentSliderIdx!==null&&this.currentSliderIdxd.remove());let s=document.createElement("div");s.className="metric-menu-popup";let i=Pe.METRICS,o=this.currentTrack;if(!o)return;let a=[];for(let d in i){let p=i[d];o.points.some(f=>f[p.field]!=null)&&a.push(d)}a.forEach(d=>{let p=i[d],f=document.createElement("div"),h=e==="x"?this.xMetric:this.yMetric;f.className=`menu-item ${h===d?"active":""}`,f.innerHTML=` + ${p.icon} + ${p.label} + ${h===d?"check":""} + `,f.addEventListener("click",()=>{e==="x"?this.xMetric=d:this.yMetric=d,s.remove(),this.currentTracks.length>=2?this.render(this.currentTracks,this.allTracks):this.render(this.currentTrack,this.allTracks)}),s.appendChild(f)});let c=r.getBoundingClientRect();s.style.top=`${c.bottom+5}px`,s.style.left=`${c.left}px`,document.body.appendChild(s);let u=d=>{!s.contains(d.target)&&!r.contains(d.target)&&(s.remove(),document.removeEventListener("click",u))};setTimeout(()=>document.addEventListener("click",u),0)}};dr([xl("plotContainer")],iu.prototype,"plotContainerRef",2),iu=dr([Ws({selector:"app-combined-tab",standalone:!0,imports:[Er,hs],template:` +
+
+ no_sim +
Select a track for combined analysis
+
+ + + +
+
+ Aggregate Track Comparison & Section Analysis ({{ currentTracksCount }} Tracks) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Metric + {{ aggSummary.t1Name }} (T1) + + {{ aggSummary.t2Name }} (T2) + Delta (T2 - T1)Aggregate Summary
Distance{{ aggSummary.s1DistKm }} km{{ aggSummary.s2DistKm }} km + {{ aggSummary.distDiff }} km + + {{ aggSummary.totalDist }} km (Total) +
Elevation Gain{{ aggSummary.s1Elev }} m{{ aggSummary.s2Elev }} m + {{ aggSummary.eleDiff }} m + + {{ aggSummary.totalElev }} m (Total) +
Duration{{ aggSummary.s1DurStr }}{{ aggSummary.s2DurStr }}-- + {{ aggSummary.totalDurStr }} (Total) +
Avg / Max Power + {{ aggSummary.s1AvgPwr }} W / {{ aggSummary.s1MaxPwr }} W + + {{ aggSummary.s2AvgPwr }} W / {{ aggSummary.s2MaxPwr }} W + + {{ aggSummary.pwrDiff }} W (Avg) + + {{ aggSummary.avgPwr }} W (Avg) / {{ aggSummary.maxPwr }} W (Max) +
Avg / Max HR + {{ aggSummary.s1AvgHr }} bpm / {{ aggSummary.s1MaxHr }} bpm + + {{ aggSummary.s2AvgHr }} bpm / {{ aggSummary.s2MaxHr }} bpm + + {{ aggSummary.hrDiff }} bpm (Avg) + + {{ aggSummary.avgHr }} bpm (Avg) / {{ aggSummary.maxHr }} bpm (Max) +
Avg / Max Temp{{ aggSummary.s1TempStr }}{{ aggSummary.s2TempStr }} + {{ aggSummary.tempDiff }} \xB0C (Avg) + + {{ aggSummary.avgTemp }} \xB0C (Avg) / {{ aggSummary.maxTemp }} \xB0C (Max) +
Gear Shifts{{ aggSummary.s1Shifts }}{{ aggSummary.s2Shifts }} + {{ aggSummary.shiftsDiffStr }} + + {{ aggSummary.totalShifts }} (Total) +
{{ sr.sectionLabel }} Split + {{ sr.t1Power }}W \xB7 {{ sr.t1Hr }}bpm \xB7 {{ sr.t1SpeedStr }}km/h + + {{ sr.t2Power }}W \xB7 {{ sr.t2Hr }}bpm \xB7 {{ sr.t2SpeedStr }}km/h + {{ sr.pwrDeltaStr }}Cohort Avg: {{ sr.cohortAvgPower }}W
+
+ + {{ c.pairLabel }}: r={{ c.rValStr }}, \u03B2={{ c.slopeStr }} ({{ + c.samples + }}) + +
+
+ + +
+
+ arrow_forward + X Axis: + +
+
+ arrow_upward + Y Axis: + +
+
+ schedule + Time: + + {{ sliderTimeLabel }} + +
+
+ + +
+
+ +
+
+ No data for selected metrics +
+
+
+
+ `})],iu);import qg from"uplot";function Vl(t,e){let n=0;for(let M=0;Mn&&(n=$)}n||(n=Date.UTC(2026,7,1));let r=new Date(n),s=r.getUTCFullYear(),i=Date.UTC(s-1,r.getUTCMonth(),r.getUTCDate(),r.getUTCHours(),r.getUTCMinutes(),r.getUTCSeconds()),o=Date.UTC(s,r.getUTCMonth()-6,r.getUTCDate(),r.getUTCHours(),r.getUTCMinutes(),r.getUTCSeconds()),a=Date.UTC(s,r.getUTCMonth()-1,r.getUTCDate(),r.getUTCHours(),r.getUTCMinutes(),r.getUTCSeconds()),c=0,u=0,d=0,p=0,f=0,h=n;t.forEach(M=>{if(!M.stats.startTime)return;let $=e(M);if($===void 0)return;f+=$;let j=M.stats.startTime;j=i&&(u+=$),j>=o&&(d+=$),j>=a&&(p+=$)});let m=7*24*60*60*1e3,g=Date.UTC(s,0,1),v=Math.max(.1,(n-g)/m),w=Math.max(.1,(n-i)/m),b=Math.max(.1,(n-o)/m),D=Math.max(.1,(n-a)/m),B=Math.max(.1,(n-h)/m);return{currentYear:c,pastYear:u,past6m:d,past1m:p,total:f,currentYearAvg:c/v,pastYearAvg:u/w,past6mAvg:d/b,past1mAvg:p/D,totalAvg:f/B}}function ZR(t,e,n){let r=e?1e3:1,s=i=>(e?i/r:i).toLocaleString("en-US",{minimumFractionDigits:e?1:0,maximumFractionDigits:e?1:0});return[{period:"Current Year",valueFormatted:s(t.currentYear),weeklyAvgFormatted:s(t.currentYearAvg),unit:n},{period:"Past Year",valueFormatted:s(t.pastYear),weeklyAvgFormatted:s(t.pastYearAvg),unit:n},{period:"Past 6 Months",valueFormatted:s(t.past6m),weeklyAvgFormatted:s(t.past6mAvg),unit:n},{period:"Past 1 Month",valueFormatted:s(t.past1m),weeklyAvgFormatted:s(t.past1mAvg),unit:n},{period:"Total",valueFormatted:s(t.total),weeklyAvgFormatted:s(t.totalAvg),unit:n}]}function Xye(t){let e=Vl(t,a=>a.stats.totalDist),n=Vl(t,a=>a.stats.elevGain),r=Vl(t,a=>a.stats.duration?a.stats.duration/36e5:0),s=Vl(t,a=>{let c=(a.stats.duration||0)/1e3,u=a.stats.avgPower||150,d=200,p=u/d;return c*u*p/(d*3600)*100}),i=Vl(t,a=>{let c=(a.stats.duration||0)/1e3,u=a.stats.avgPower||0;return c*u/1e3}),o=Vl(t,a=>(a.stats.sections||[]).filter(u=>u.kind==="climb").length);return{distance:e,elevation:n,durationHours:r,tss:s,workKj:i,climbCount:o}}function Pz(t){let e=Xye(t),n=(s,i=1)=>s.toLocaleString("en-US",{minimumFractionDigits:i,maximumFractionDigits:i});return[{label:"Distance",unit:"km",data:e.distance,scale:.001,digits:1},{label:"Elevation Gain",unit:"m",data:e.elevation,scale:1,digits:0},{label:"Moving Duration",unit:"h",data:e.durationHours,scale:1,digits:1},{label:"Training Stress (TSS)",unit:"TSS",data:e.tss,scale:1,digits:0},{label:"Mechanical Work",unit:"kJ",data:e.workKj,scale:1,digits:0},{label:"Categorized Climbs",unit:"climbs",data:e.climbCount,scale:1,digits:0}].map(s=>({label:s.label,unit:s.unit,past1m:n(s.data.past1m*s.scale,s.digits),past6m:n(s.data.past6m*s.scale,s.digits),pastYear:n(s.data.pastYear*s.scale,s.digits),currentYear:n(s.data.currentYear*s.scale,s.digits),total:n(s.data.total*s.scale,s.digits),weeklyAvg:n(s.data.totalAvg*s.scale,s.digits)}))}var Wg=[],Zb=[],MD="week",Bz=null;function $z(t){Bz=t}function Yb(){return Bz||window.__trackStateService?.evolutionTab||null}function Xb(){Wg.forEach(t=>t.destroy()),Wg=[],Zb=[]}function Vz(){Xb(),MD="week";let t=Yb();if(t&&typeof t.reset=="function"){t.reset();return}let e=document.getElementById("evolution-view");e&&(e.innerHTML=` +
+ no_sim +
Select a track for progress analysis
+ `)}function QR(t){MD=t,Zb.forEach(e=>{e&&e.updateGrouping&&e.updateGrouping(t)})}function Qb(t){let e=Yb();if(e&&typeof e.setGrouping=="function"){e.setGrouping(t);return}QR(t)}function KR(t){It.patch({progress:t==="all"?null:t}),Zb.forEach(e=>{e&&e.updateRange&&e.updateRange(t)})}function PD(t){let e=Yb();if(e&&typeof e.setRange=="function"){e.setRange(t);return}KR(t)}function JR(t){Zb.forEach(e=>{e&&e.updatePin&&e.updatePin(t)})}function ND(t){let e=Yb();if(e&&typeof e.setPinnedDuration=="function"){e.setPinnedDuration(t);return}JR(t)}var Kb=16384,Gb=new Float64Array(Kb+1),Yp=new Float64Array(Kb+1),YR=new Float64Array(Kb+1),Nz=new Float64Array(Kb),XR=new Float64Array(365),Rz=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,360,450,600,750,900,1200];function Fz(t,e,n,r){let s={};e.forEach(u=>{let d=n==="power"?u.stats.powerCurve:u.stats.hrCurve;if(!d)return;let p=u.name||"Unnamed Track",f=u.stats.startTime||u.addedAt?Zo(u.stats.startTime||u.addedAt):"Unknown Date",h=`${p} (${f})`;Object.entries(d).forEach(([m,g])=>{let v=Number(m),w=g.power||g.hr;(!s[v]||w>s[v].val)&&(s[v]={val:w,trackInfo:h,trackId:u.id,idx:g.idx})})});let i=t&&(n==="power"?t.stats.powerCurve:t.stats.hrCurve)||{},o=new Set;Object.keys(s).forEach(u=>o.add(Number(u))),Object.keys(i).forEach(u=>o.add(Number(u)));let a=Array.from(o).sort((u,d)=>u-d);return{rows:a.map(u=>{let d=i[u]?i[u].power||i[u].hr:"-",p=s[u]?.val||"-";return{dur:u,durLabel:Hr(u),curValStr:`${d} ${r}`,maxValStr:`${p} ${r}`,mxId:s[u]?.trackId,mxIdx:s[u]?.idx}}),initialDur:a[0]||5}}function Hz(t,e){e.forEach(j=>{ln.ensureCurvesAndZones(j)});let n=0,r=0;XR.fill(0);for(let j=0;jSe)continue;let F=Se-I,J=0,oe=0;for(let we=0;we<=F;we++){let ae=Yp[we+I]-Yp[we],Ae=Gb[we+I]-Gb[we];Ae>J&&(J=Ae),ae>oe&&(oe=ae)}r+=(J+oe+YR[F])/I*.001}let pe=2/8,U=1-pe,ee=2/43,xe=1-ee,Ze=52,N=1/(195-Ze),A=0,S=0;for(let C=0;C5?"Fresh / Peak":o>=-10?"Optimal Load":"High Fatigue",p=Pz(e),f=Vl(e,j=>j.stats.totalDist),h=Vl(e,j=>j.stats.elevGain),m=ZR(f,!0,"km"),g=ZR(h,!1,"m"),v=e.some(j=>!!j.stats.powerCurve),w=e.some(j=>!!j.stats.hrCurve),b=v?Fz(t,e,"power","W"):{rows:[],initialDur:5},D=w?Fz(t,e,"hr","bpm"):{rows:[],initialDur:5},B=new Set;e.forEach(j=>{j.sport&&B.add(j.sport)});let $=[...e].sort((j,G)=>(G.stats.startTime||G.addedAt||0)-(j.stats.startTime||j.addedAt||0)||j.id.localeCompare(G.id)).map(j=>{let G=(j.stats.duration||0)/1e3,Se=j.stats.avgPower||150,pe=200,U=Se/pe,ee=G*Se*U/(pe*3600)*100;return{id:j.id,dateStr:j.stats.startTime?Zo(j.stats.startTime):"-",name:j.displayName||j.name||j.id,sport:j.sport||"cycling",color:j.color||"#FF6B35",distKm:((j.stats.totalDist||0)/1e3).toFixed(1),elevGainM:Math.round(j.stats.elevGain||0).toString(),durationStr:Hr(Math.round(G)),avgPowerStr:j.stats.avgPower!=null?`${Math.round(j.stats.avgPower)} W`:"-",avgHrStr:j.stats.avgHR!=null?`${Math.round(j.stats.avgHR)} bpm`:"-",tssStr:Math.round(ee).toString()}});return{atlStr:c,ctlStr:u,tsbStr:a,tsbStatus:d,trackName:t&&t.name||"Current Track",hasPowerCurve:v,hasHrCurve:w,powerInitialDur:b.initialDur,hrInitialDur:D.initialDur,accumulatedSummaryRows:p,distanceAccumulatedRows:m,elevationAccumulatedRows:g,powerCurveRows:b.rows,hrCurveRows:D.rows,historyRows:$,availableSports:Array.from(B).sort()}}function jz(t,e,n,r,s,i,o,a,c){MD=s;let u=t.querySelector("#evolution-container")||document.getElementById("evolution-container");if(!u)return;let d=u.clientWidth||570,p=[];Zb=p;let f=qg.sync("progress-sync"),h=u.querySelector("#distance-evolution-card")||document.getElementById("distance-evolution-card"),m=u.querySelector("#elevation-evolution-card")||document.getElementById("elevation-evolution-card");if(h&&p.push(Oz(h,n,"distance",f,c,d)),m&&p.push(Oz(m,n,"elevation",f,c,d)),n.some(g=>g.stats.powerCurve)){let g=u.querySelector("#power-evolution-card")||document.getElementById("power-evolution-card");g&&p.push(Lz({cardContainer:g,currentTrack:e,allTracks:n,metricKey:"power",unit:"W",color:it.power.color,onPinChange:i,onRangeChange:o,onTrackSelect:a,gridWidth:d}))}if(n.some(g=>g.stats.hrCurve)){let g=u.querySelector("#hr-evolution-card")||document.getElementById("hr-evolution-card");g&&p.push(Lz({cardContainer:g,currentTrack:e,allTracks:n,metricKey:"hr",unit:"bpm",color:it.hr.color,onPinChange:i,onRangeChange:o,onTrackSelect:a,gridWidth:d}))}r!=="all"&&p.forEach(g=>{g&&g.updateRange&&g.updateRange(r)}),Wg.forEach(g=>{g._ready=!0})}function Jb(t,e,n,r){let s=Yb();if(s&&typeof s.render=="function"){s.render(t,e,n,r);return}}function Lz(t){let{cardContainer:e,currentTrack:n,allTracks:r,metricKey:s,unit:i,color:o,onPinChange:a,onTrackSelect:c,gridWidth:u}=t,d=null,f=It.get().progress||"all",h=e.querySelector(`#${s}-evolution-chart`);if(!h)return;h.innerHTML="";let m={};r.forEach(S=>{let x=s==="power"?S.stats.powerCurve:S.stats.hrCurve;if(!x)return;let C=S.name||"Unnamed Track",I=S.stats.startTime||S.addedAt?Zo(S.stats.startTime||S.addedAt):"Unknown Date",F=`${C} (${I})`;Object.entries(x).forEach(([J,oe])=>{let we=Number(J),ae=oe.power||oe.hr;(!m[we]||ae>m[we].val)&&(m[we]={val:ae,trackInfo:F,trackId:S.id,idx:oe.idx})})});let g=n&&(s==="power"?n.stats.powerCurve:n.stats.hrCurve)||{},v=new Set;Object.keys(m).forEach(S=>v.add(Number(S))),Object.keys(g).forEach(S=>v.add(Number(S)));let w=Array.from(v).sort((S,x)=>S-x),b=w,D=w.map(S=>{let x=g[S];return x?x.power||x.hr:null}),B=w.map(S=>m[S]?.val||null),M=r.filter(S=>(S.stats.startTime||S.addedAt)!=null);M.sort((S,x)=>(S.stats.startTime||S.addedAt||0)-(x.stats.startTime||x.addedAt||0)||S.id.localeCompare(x.id));let $=[],j={};w.forEach(S=>j[S]=[]),M.forEach(S=>{let x=s==="power"?S.stats.powerCurve:S.stats.hrCurve;x&&($.push((S.stats.startTime||S.addedAt)/1e3),w.forEach(C=>{let I=x[C],F=I?s==="power"?I.power:I.hr:null;j[C].push(F)}))});let G=w[0]||5,Se=M,pe=null;function U(S,x){let C=$[$.length-1]||1785542400,I=0;x==="1m"?I=C-30*24*3600:x==="2m"?I=C-60*24*3600:x==="6m"?I=C-180*24*3600:x==="1y"?I=C-365*24*3600:x==="2y"&&(I=C-2*365*24*3600);let F=[];$.forEach((Ae,ie)=>{Ae>=I&&F.push(ie)});let J=F.map(Ae=>$[Ae]),oe=j[S]||[],we=F.map(Ae=>oe[Ae]),ae=Hg(we,5);return Se=F.map(Ae=>M[Ae]),{xFiltered:J,rawYFiltered:we,smoothedYFiltered:ae}}let ee=null,xe=document.createElement("div");xe.className="cur-y-val font-m",xe.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",h.style.position="relative",h.appendChild(xe);let Ze={id:`${s}-evolution`,width:400,height:250,padding:[0,10,0,10],scales:{x:{time:!1,distr:3,auto:!0},y:{auto:!0}},series:[{},{label:"Current Track",stroke:o,width:2,fill:en(o,.1),points:{show:!0,size:5,fill:o}},{label:"All-Time Max",stroke:"#888888",width:1,fill:"transparent",points:{show:!0,size:6,fill:"#888888"}}],axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:()=>[],ticks:{show:!1},font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},values:(S,x)=>x.map(C=>`${C}${i}`),font:"10px system-ui, sans-serif",size:50}],cursor:{drag:{x:!1,y:!1},dataIdx:(S,x,C)=>C,x:!1,y:!1},hooks:{draw:[S=>{let x=S.ctx,C=window.devicePixelRatio||1,I=S.bbox,F=[1,2,5,10,20,30,60,120,300,600,1200,1800,3600,7200,10800],J=b[b.length-1];x.save(),x.fillStyle="#555564",x.textAlign="center",x.textBaseline="top",x.font=`${10*C}px system-ui, sans-serif`;let oe=-100;if(F.forEach(we=>{if(we>J)return;let ae=S.valToPos(we,"x",!0);ae>oe+30*C&&ae=0){let ae=S.valToPos(pe,"x",!0),Ae=S.valToPos(D[we]||B[we],"y",!0);x.save(),x.beginPath(),x.setLineDash([]);let ie=D[we],V=ie!==null?5*C:3*C,z=ie!==null?o:"#888888";x.arc(ae,Ae,V,0,2*Math.PI),x.fillStyle=z,x.fill(),x.strokeStyle="#fff",x.lineWidth=2*C,x.stroke(),x.restore()}}x.restore()},S=>{let x=S.ctx,C=window.devicePixelRatio||1,I=S.bbox,F=S.cursor.idx,J=1,oe=S.cursor.left,we=S.cursor.top;if(oe!=null&&we!=null&&oe>=0&&we>=0){let ae=1/0,Ae=-1,ie=30,V=ie*ie;for(let z=0;z{if(!S._ready)return;S.redraw(!1);let x=S.cursor.idx,C=S.cursor.left,I=S.cursor.top;if(C!=null&&I!=null&&C>=0&&I>=0){let oe=1/0,we=-1,ae=30,Ae=ae*ae;for(let ie=0;ie${Hr(oe)}
`;if(we!==null&&(Ae+=` +
+ Current: + ${we} ${i} +
+ `),ae!==null&&(Ae+=` +
+ Max: + ${ae} ${i} +
+ `),xe.innerHTML=Ae,ee&&pe===null){G=oe;let{xFiltered:ie,rawYFiltered:V,smoothedYFiltered:z}=U(G,f),L=z.map(le=>le!==null?le*.9:null),q=z.map(le=>le!==null?le*1.1:null);ee.setData([ie,V,z,L,q]);let H=e.querySelector(`#${s}-timeline-label`);H&&(H.textContent=`Progress ${Hr(oe)} ${s==="power"?"Power":"HR"}`)}xe.style.display="",xe.style.left=`${C+F.left}px`,xe.style.top=`${I+F.top}px`,xe.style.transform="translate(5px, -50%)"}else xe.style.display="none"}]}};d=new qg(Ze,[b,D,B],h),Wg.push(d),h.addEventListener("click",()=>{if(!d)return;let S=d.cursor.idx;if(S!=null){let x=b[S],C=null;if(pe!==null?C=null:C=x,a(C),n){let I=n.stats,F=s==="power"?I.powerCurve:I.hrCurve;if(F){let J=F[x];if(J){let oe=J.idx,we=x,ae=n.points[oe],Ae=n.points[oe+we-1];if(ae&&Ae&&ae.time!=null&&Ae.time!=null){let ie=n.points[0].time||0,V=(ae.time-ie)/1e3,z=(Ae.time-ie)/1e3;c?.(n.id,[V,z])}}}}}}),h.addEventListener("mouseleave",()=>{d&&d.redraw()});let N=null,A=e.querySelector(`#${s}-timeline-chart`);if(A){A.innerHTML="",A.style.position="relative";let S=document.createElement("div");if(S.className="timeline-tooltip font-m",S.style.cssText="position:absolute;background:rgba(14, 14, 16, 0.9);color:#fff;padding:8px 12px;border-radius:4px;font-family:system-ui;pointer-events:none;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,0.3);border:1px solid #2e2e34;display:none;",A.appendChild(S),$.length>0){let{xFiltered:x,rawYFiltered:C,smoothedYFiltered:I}=U(G,f),F=I.map(ie=>ie!==null?ie*.9:null),J=I.map(ie=>ie!==null?ie*1.1:null),oe=[x,C,I,F,J],we=[{value:(ie,V)=>V!=null?Zo(V*1e3):"-"},{label:"Value",stroke:o,width:0,points:{show:!0,size:6,fill:en(o,.5)}},{label:"Trend",stroke:o,width:2,points:{show:!1},spanGaps:!0,fill:"transparent",dash:[5,5]},{label:"Lower Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0},{label:"Upper Bound",stroke:"transparent",width:0,points:{show:!1},spanGaps:!0}],ae=e.querySelector(`#${s}-timeline-label`);ae&&(ae.textContent=`Progress ${Hr(G)} ${s==="power"?"Power":"HR"}`);let Ae={width:Math.max(100,(u||570)-400),height:250,padding:[0,10,0,10],tzDate:ie=>qg.tzDate(new Date(ie*1e3),"Etc/UTC"),cursor:{points:{show:!1},drag:{setScale:!1},x:!1,y:!1},scales:{x:{time:!0,range:ie=>{let V=ie.data[0][0],z=ie.data[0][ie.data[0].length-1];return V===void 0||z===void 0?[0,100]:V===z?[V-3600,z+3600]:[V,z]}},y:{range:(ie,V,z)=>[V*.9,z*1.1]}},series:we,bands:[{series:[4,3],fill:en(o,.2)}],hooks:{init:[ie=>{ie.over.addEventListener("click",()=>{if(N!=null){let V=Se[N];if(V){let z=V.stats,L=s==="power"?z.powerCurve:z.hrCurve;if(L){let q=L[G];if(q){let H=q.idx,le=G,K=V.points[H],Ce=V.points[H+le-1];if(K&&Ce&&K.time!=null&&Ce.time!=null){let he=V.points[0].time||0,De=(K.time-he)/1e3,Ne=(Ce.time-he)/1e3;t.onTrackSelect?.(V.id,[De,Ne])}else t.onTrackSelect?.(V.id,null)}else t.onTrackSelect?.(V.id,null)}else t.onTrackSelect?.(V.id,null)}}})}],draw:[ie=>{let V=ie.cursor.idx;if(V!=null&&ie.data[0][V]!=null){let z=ie.data[1][V];if(z!=null){let L=ie.valToPos(ie.data[0][V],"x",!0),q=ie.valToPos(z,"y",!0),H=ie.ctx,le=window.devicePixelRatio||1;H.save(),H.beginPath(),H.setLineDash([2*le,2*le]),H.strokeStyle=en(o,.4),H.lineWidth=1*le,H.moveTo(L,ie.bbox.top),H.lineTo(L,ie.bbox.top+ie.bbox.height),H.moveTo(ie.bbox.left,q),H.lineTo(ie.bbox.left+ie.bbox.width,q),H.stroke(),H.restore(),H.save(),H.beginPath(),H.setLineDash([]),H.arc(L,q,12*le,0,2*Math.PI),H.fillStyle=en(o,.2),H.fill(),H.restore(),H.save(),H.beginPath(),H.arc(L,q,6*le,0,2*Math.PI),H.fillStyle=o,H.fill(),H.strokeStyle="#fff",H.lineWidth=2*le,H.stroke(),H.restore(),H.save(),H.setLineDash([]);let K=new Date(ie.data[0][V]*1e3),Ce=`${K.getUTCFullYear()}-${String(K.getUTCMonth()+1).padStart(2,"0")}-${String(K.getUTCDate()).padStart(2,"0")}`;H.font=`bold ${10*le}px system-ui, sans-serif`;let De=H.measureText(Ce).width+10*le,Ne=16*le,et=L-De/2,Pt=Math.max(ie.bbox.left,Math.min(ie.bbox.left+ie.bbox.width-De,et)),$t=ie.bbox.top+ie.bbox.height+2*le;H.fillStyle="rgba(14, 14, 16, 0.92)",H.beginPath(),H.roundRect?H.roundRect(Pt,$t,De,Ne,3*le):H.rect(Pt,$t,De,Ne),H.fill(),H.strokeStyle=en(o,.27),H.lineWidth=1*le,H.stroke(),H.fillStyle=o,H.textAlign="center",H.textBaseline="middle",H.fillText(Ce,Pt+De/2,$t+Ne/2);let me=`${z.toFixed(0)} ${i}`,nn=H.measureText(me).width+10*le,kt=ie.bbox.left-nn-2*le,cn=q-Ne/2;H.fillStyle="rgba(14, 14, 16, 0.92)",H.beginPath(),H.roundRect?H.roundRect(kt,cn,nn,Ne,3*le):H.rect(kt,cn,nn,Ne),H.fill(),H.strokeStyle=en(o,.27),H.lineWidth=1*le,H.stroke(),H.fillStyle=o,H.textAlign="left",H.textBaseline="middle",H.fillText(me,kt+5*le,cn+Ne/2),H.restore()}}}],setCursor:[ie=>{if(!ie._ready)return;ie.redraw(!1);let V=ie.cursor.idx,z=ie.cursor.left,L=ie.cursor.top,q=ie.bbox;if(z!=null&&L!=null&&z>=0&&L>=0){let H=1/0,le=-1,K=30,Ce=K*K,he=ie.data[0],De=ie.data[1];for(let Ne=0;Ne + Date: + ${le} +
+
+ Value: + ${Ce} +
+ `,S.style.display="block",S.style.left=`${z+q.left}px`,S.style.top=`${L+q.top}px`,S.style.transform="translate(5px, -50%)"}else S.style.display="none"}]},axes:[{space:50,stroke:"#555564",grid:{stroke:"#2e2e34"},show:!0,font:"10px system-ui, sans-serif",size:30,values:(ie,V)=>V.map(z=>{let L=new Date(z*1e3);return`${L.getUTCFullYear()}-${String(L.getUTCMonth()+1).padStart(2,"0")}`})},{stroke:"#555564",grid:{stroke:"#2e2e34"},font:"10px system-ui, sans-serif",values:(ie,V)=>V.map(z=>`${z} ${i}`),show:!0,space:15,size:50}]};ee=new qg(Ae,oe,A),Wg.push(ee),A.addEventListener("mouseleave",()=>{ee.redraw()})}else A.innerHTML='
No data for the past year
'}return{updatePin:S=>{pe=S,S!==null&&(G=S);let x=e.querySelector(`#${s}-timeline-label`);if(x&&(x.textContent=`Progress ${Hr(G)} ${s==="power"?"Power":"HR"}${pe!==null?" (Pinned)":""}`),ee){let{xFiltered:C,rawYFiltered:I,smoothedYFiltered:F}=U(G,f),J=F.map(we=>we!==null?we*.9:null),oe=F.map(we=>we!==null?we*1.1:null);ee.setData([C,I,F,J,oe])}d&&d.redraw()},updateRange:S=>{if(f=S,ee){let{xFiltered:x,rawYFiltered:C,smoothedYFiltered:I}=U(G,f),F=I.map(oe=>oe!==null?oe*.9:null),J=I.map(oe=>oe!==null?oe*1.1:null);ee.setData([x,C,I,F,J])}}}}function Uz(t){let e=new Date(t),n=e.getUTCDay(),r=e.getUTCDate()-n+(n===0?-6:1);return e.setUTCDate(r),e.setUTCHours(0,0,0,0),e}function Qye(t){let e={};return t.forEach(n=>{if(!n.stats.startTime||!n.stats.totalDist)return;let r=new Date(n.stats.startTime),s=Uz(r),i=s.toISOString().split("T")[0];e[i]||(e[i]={timestamp:s.getTime(),distance:0}),e[i].distance+=n.stats.totalDist}),Object.entries(e).map(([n,r])=>({week:n,timestamp:r.timestamp,distance:r.distance})).sort((n,r)=>n.timestamp-r.timestamp)}function Kye(t){let e={};return t.forEach(n=>{if(!n.stats.startTime||n.stats.elevGain===void 0)return;let r=new Date(n.stats.startTime),s=Uz(r),i=s.toISOString().split("T")[0];e[i]||(e[i]={timestamp:s.getTime(),elevation:0}),e[i].elevation+=n.stats.elevGain}),Object.entries(e).map(([n,r])=>({week:n,timestamp:r.timestamp,elevation:r.elevation})).sort((n,r)=>n.timestamp-r.timestamp)}function Jye(t){let e={};return t.forEach(n=>{if(!n.stats.startTime||!n.stats.totalDist)return;let r=new Date(n.stats.startTime),s=new Date(Date.UTC(r.getUTCFullYear(),r.getUTCMonth(),1)),i=s.toISOString().slice(0,7);e[i]||(e[i]={timestamp:s.getTime(),distance:0}),e[i].distance+=n.stats.totalDist}),Object.entries(e).map(([n,r])=>({week:n,timestamp:r.timestamp,distance:r.distance})).sort((n,r)=>n.timestamp-r.timestamp)}function e0e(t){let e={};return t.forEach(n=>{if(!n.stats.startTime||n.stats.elevGain===void 0)return;let r=new Date(n.stats.startTime),s=new Date(Date.UTC(r.getUTCFullYear(),r.getUTCMonth(),1)),i=s.toISOString().slice(0,7);e[i]||(e[i]={timestamp:s.getTime(),elevation:0}),e[i].elevation+=n.stats.elevGain}),Object.entries(e).map(([n,r])=>({week:n,timestamp:r.timestamp,elevation:r.elevation})).sort((n,r)=>n.timestamp-r.timestamp)}function Oz(t,e,n,r,s,i){let o=n==="distance",a=MD,c=It.get().progress||"all",u=o?Qye(e):Kye(e),d=o?Jye(e):e0e(e),p=a==="month"?d:u,f=o?it.distance.color:it.elevation.color,h=o?"km":"m",m=t.querySelector(`#${n}-weekly-chart`),g=t.querySelector(`#${n}-y-axis-chart`);if(!m||!g)return;m.innerHTML="",m.style.position="relative";let v=document.createElement("div");v.className="cur-y-val",v.style.cssText=`color:${f};display:none`,m.appendChild(v);let w=p.map(U=>U.timestamp/1e3),b=o?p.map(U=>U.distance/1e3):p.map(U=>U.elevation);if(w.length===0)return;let D=Hg(b,2),B=Math.max(0,(i||570)-20-320-20),M=Math.max(B,w.length*40),$=Math.max(...b)*1.1,j={width:M,height:150,padding:[10,10,0,10],tzDate:U=>qg.tzDate(new Date(U*1e3),"Etc/UTC"),scales:{x:{time:!0},y:{range:[0,$]}},series:[{},{label:o?"Distance":"Elevation",stroke:f,fill:en(f,.1),width:2,points:{show:!0,size:4}},{label:"Trend",stroke:f,width:2,dash:[5,5],points:{show:!1}}],cursor:{sync:r?{key:r.key}:void 0,drag:{x:!1,y:!1},points:{show:!1},x:!1,y:!1},hooks:{init:[U=>{U.over.addEventListener("click",()=>{let ee=U.cursor.idx;if(ee!=null){let xe=p[ee];if(xe){let Ze=new Date(xe.timestamp),N=new Date(xe.timestamp+7*24*60*60*1e3),A=Ze.toISOString().split("T")[0],S=N.toISOString().split("T")[0];s?.(A,S)}}})}],setCursor:[U=>{if(!U._ready)return;let ee=U.cursor.idx,xe=U.cursor.left,Ze=U.cursor.top;if(ee!=null&&xe!=null&&Ze!=null&&xe>=0&&Ze>=0){let N=U.data[1][ee],A=N!=null?o?`${N.toFixed(1)} km`:`${N.toFixed(0)} m`:"\u2014";v.innerHTML=A,v.style.display="block",v.style.left=`${U.valToPos(U.data[0][ee],"x",!1)}px`,v.style.top=`${U.valToPos(U.data[1][ee],"y",!1)}px`,v.style.transform="translate(6px, -50%)"}else v.style.display="none";U.redraw(!1)}],draw:[U=>{let ee=U.cursor.idx;if(ee!=null&&U.data[0][ee]!=null){let xe=U.valToPos(U.data[0][ee],"x",!0),Ze=U.valToPos(U.data[1][ee],"y",!0),N=window.devicePixelRatio||1,A=U.ctx,S=U.bbox;A.save(),A.beginPath(),A.setLineDash([2*N,2*N]),A.strokeStyle=en(f,.4),A.lineWidth=1*N,A.moveTo(xe,S.top),A.lineTo(xe,S.top+S.height),A.moveTo(S.left,Ze),A.lineTo(S.left+S.width,Ze),A.stroke(),A.restore(),A.save(),A.beginPath(),A.setLineDash([]),A.arc(xe,Ze,12*N,0,2*Math.PI),A.fillStyle=en(f,.2),A.fill(),A.restore(),A.save(),A.beginPath(),A.arc(xe,Ze,6*N,0,2*Math.PI),A.fillStyle=f,A.fill(),A.strokeStyle="#fff",A.lineWidth=2*N,A.stroke(),A.restore(),A.save(),A.setLineDash([]);let x=new Date(U.data[0][ee]*1e3),C=`${x.getUTCFullYear()}-${String(x.getUTCMonth()+1).padStart(2,"0")}-${String(x.getUTCDate()).padStart(2,"0")}`;A.font=`bold ${10*N}px system-ui, sans-serif`;let F=A.measureText(C).width+10*N,J=16*N,oe=xe-F/2,we=Math.max(S.left,Math.min(S.left+S.width-F,oe)),ae=S.top+S.height+2*N;A.fillStyle="rgba(14, 14, 16, 0.92)",A.beginPath(),A.roundRect?A.roundRect(we,ae,F,J,3*N):A.rect(we,ae,F,J),A.fill(),A.strokeStyle=en(f,.27),A.lineWidth=1*N,A.stroke(),A.fillStyle=f,A.textAlign="center",A.textBaseline="middle",A.fillText(C,we+F/2,ae+J/2),A.restore()}}]},axes:[{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,space:40,values:(U,ee)=>ee.map(xe=>{let Ze=new Date(xe*1e3);return`${Ze.getUTCMonth()+1}/${Ze.getUTCDate()}`}),font:"10px system-ui, sans-serif",size:30},{stroke:"#555564",grid:{stroke:"#2e2e34",width:1},show:!0,values:(U,ee)=>ee.map(xe=>`${xe.toFixed(0)} ${h}`),font:"10px system-ui, sans-serif",size:40}]},G=new qg(j,[w,b,D],m);Wg.push(G);let Se=t.querySelector(".chart-scroll-container");Se&&w.length*40>M&&(Se.scrollLeft=Se.scrollWidth-Se.clientWidth);function pe(){p=a==="month"?d:u;let U=p[p.length-1]?.timestamp||17855424e5,ee=0;c==="1m"?ee=U-30*24*3600*1e3:c==="2m"?ee=U-60*24*3600*1e3:c==="6m"?ee=U-180*24*3600*1e3:c==="1y"?ee=U-365*24*3600*1e3:c==="2y"&&(ee=U-2*365*24*3600*1e3);let xe=p.filter(C=>C.timestamp>=ee),Ze=xe.map(C=>C.timestamp/1e3),N=o?xe.map(C=>C.distance/1e3):xe.map(C=>C.elevation),A=Hg(N,2),S=Math.max(m.clientWidth,Ze.length*40),x=Math.max(1,...N)*1.1;G.setSize({width:S,height:150}),G.setScale("y",{min:0,max:x}),G.setData([Ze,N,A]),Se&&(Se.scrollLeft=Se.scrollWidth-Se.clientWidth)}return{updateRange:U=>{c=U,pe()},updateGrouping:U=>{a=U,pe()}}}var zg=class{constructor(){this.state=fe(Kr);this.cdr=fe(An);this.elRef=fe(pn);this.isEmpty=!0;this.currentGrouping="week";this.currentRange="all";this.pinnedDuration=null;this.selectedSportFilter="all";this.availableSports=[];this.atlStr="0.0";this.ctlStr="0.0";this.tsbStr="0.0";this.tsbStatus="Optimal Load";this.trackName="Current Track";this.hasPowerCurve=!1;this.hasHrCurve=!1;this.powerInitialDur=5;this.hrInitialDur=5;this.powerTimelineLabel="Progress 5s Power";this.hrTimelineLabel="Progress 5s HR";this.accumulatedSummaryRows=[];this.distanceAccumulatedRows=[];this.elevationAccumulatedRows=[];this.powerCurveRows=[];this.hrCurveRows=[];this.historyRows=[];this.distanceColor=it.distance.color;this.distanceIcon=it.distance.icon;this.elevationColor=it.elevation.color;this.elevationIcon=it.elevation.icon;this.powerColor=it.power.color;this.hrColor=it.hr.color;this.metricPills=[{target:"distance",label:"Distance",color:it.distance.color,icon:it.distance.icon},{target:"elevation",label:"Elevation",color:it.elevation.color,icon:it.elevation.icon},{target:"power",label:"Power",color:it.power.color,icon:it.power.icon},{target:"hr",label:"Heart Rate",color:it.hr.color,icon:it.hr.icon}];this.rangeOptions=[{key:"1m",label:"1M"},{key:"2m",label:"2M"},{key:"6m",label:"6M"},{key:"1y",label:"1Y"},{key:"2y",label:"2Y"},{key:"all",label:"\u221E"}];this.pinDurationOptions=[{sec:5,label:"5s"},{sec:30,label:"30s"},{sec:60,label:"1m"},{sec:300,label:"5m"},{sec:1200,label:"20m"},{sec:null,label:"Free"}];this.lastCurrentTrack=null;this.lastAllTracks=[];this.state.evolutionTab=this,$z(this)}ngOnInit(){let e=this.elRef.nativeElement;document.getElementById("evolution-view")||(e.id="evolution-view")}ngOnDestroy(){Xb(),this.state.evolutionTab===this&&(this.state.evolutionTab=null)}trackByLabel(e,n){return n.label}trackByPeriod(e,n){return n.period}trackByDur(e,n){return n.dur}trackByHistoryId(e,n){return n.id}reset(){Xb(),this.isEmpty=!0,this.currentGrouping="week",this.currentRange="all",this.pinnedDuration=null,this.selectedSportFilter="all",this.accumulatedSummaryRows=[],this.distanceAccumulatedRows=[],this.elevationAccumulatedRows=[],this.powerCurveRows=[],this.hrCurveRows=[],this.historyRows=[],this.cdr.detectChanges()}render(e,n,r,s){Xb(),this.lastCurrentTrack=e,this.lastAllTracks=n,this.lastOnTrackSelect=r,this.lastOnDateRangeSelect=s,this.isEmpty=!1,this.currentRange=It.get().progress||"all",this.pinnedDuration=null;let i=this.selectedSportFilter==="all"?n:n.filter(u=>u.sport===this.selectedSportFilter),o=i.length>0?i:n,a=Hz(e,o);this.atlStr=a.atlStr,this.ctlStr=a.ctlStr,this.tsbStr=a.tsbStr,this.tsbStatus=a.tsbStatus,this.trackName=a.trackName,this.hasPowerCurve=a.hasPowerCurve,this.hasHrCurve=a.hasHrCurve,this.powerInitialDur=a.powerInitialDur,this.hrInitialDur=a.hrInitialDur,this.powerTimelineLabel=`Progress ${Hr(this.powerInitialDur)} Power`,this.hrTimelineLabel=`Progress ${Hr(this.hrInitialDur)} HR`,this.accumulatedSummaryRows=a.accumulatedSummaryRows,this.distanceAccumulatedRows=a.distanceAccumulatedRows,this.elevationAccumulatedRows=a.elevationAccumulatedRows,this.powerCurveRows=a.powerCurveRows,this.hrCurveRows=a.hrCurveRows,this.historyRows=a.historyRows,this.availableSports=a.availableSports;let c=document.getElementById("evolution-view")||this.elRef.nativeElement;c&&(c.dataset.tsb=this.tsbStr),this.cdr.detectChanges(),jz(this.elRef.nativeElement,e,o,this.currentRange,this.currentGrouping,u=>this.setPinnedDuration(u),u=>this.setRange(u),r,s)}setGrouping(e){this.currentGrouping=e,this.cdr.detectChanges(),QR(e)}setRange(e){this.currentRange=e,this.cdr.detectChanges(),KR(e)}setPinnedDuration(e){this.pinnedDuration=e;let n=e!==null?e:this.powerInitialDur,r=e!==null?e:this.hrInitialDur;this.powerTimelineLabel=`Progress ${Hr(n)} Power${e!==null?" (Pinned)":""}`,this.hrTimelineLabel=`Progress ${Hr(r)} HR${e!==null?" (Pinned)":""}`,this.cdr.detectChanges(),JR(e)}onSportFilterChange(){this.render(this.lastCurrentTrack,this.lastAllTracks,this.lastOnTrackSelect,this.lastOnDateRangeSelect)}onMetricPillClick(e){document.getElementById(`${e}-evolution-card`)?.scrollIntoView({behavior:"smooth"})}onDistanceScroll(e){let n=e.target,r=this.elRef.nativeElement.querySelector(".elevation-progress-card .chart-scroll-container");n&&r&&r.scrollLeft!==n.scrollLeft&&(r.scrollLeft=n.scrollLeft)}onElevationScroll(e){let n=e.target,r=this.elRef.nativeElement.querySelector(".distance-progress-card .chart-scroll-container");r&&n&&r.scrollLeft!==n.scrollLeft&&(r.scrollLeft=n.scrollLeft)}onSelectCurveMax(e,n){n.preventDefault(),n.stopPropagation(),e.mxId&&document.dispatchEvent(new CustomEvent("select-track",{detail:{id:e.mxId,idx:e.mxIdx!=null?Number(e.mxIdx):null,dur:e.dur!=null?Number(e.dur):null}}))}onHistoryRowClick(e){this.lastOnTrackSelect?this.lastOnTrackSelect(e,null):this.state.selectTrack(e,!0)}};zg=dr([Ws({selector:"app-evolution-tab",standalone:!0,imports:[Er,hs],template:` +
+
+ no_sim +
Select a track for progress analysis
+
+ + +
+
+
+ +
+ +
+ + +
+ +
+ +
+ + +
+ +
+
+ +
+
+
+ +
+ +
+
+
+ monitoring + Accumulated Longitudinal Progress Summary +
+
+ CTL: {{ ctlStr }} + ATL: {{ atlStr }} + TSB: {{ tsbStr }} ({{ tsbStatus }}) +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
MetricPast 1MPast 6MPast YearCurrent YearTotalWeekly Avg
{{ r.label }}{{ r.past1m }} {{ r.unit }}{{ r.past6m }} {{ r.unit }}{{ r.pastYear }} {{ r.unit }}{{ r.currentYear }} {{ r.unit }}{{ r.total }} {{ r.unit }}{{ r.weeklyAvg }} {{ r.unit }}/wk
+
-
-
infoFile Metadata
-
-
-
Original Filename
-
${me(t.fileName||"\u2014")}
-
-
-
File Size
-
${t.fileSize?Mo(t.fileSize):"\u2014"}
-
-
-
Format
-
${t.format.toUpperCase()}
-
-
-
Sport
-
- ${Eo(t.sport)} - ${me(Ye[t.sport?.toLowerCase()||""]?.name||"\u2014")} - expand_more - ${t.subSport?`(${me(t.subSport)})`:""} + +
+
+
+ {{ distanceIcon }} + Distance Progress +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + +
PeriodDistanceDistance/Week
{{ r.period }}{{ r.valueFormatted }} {{ r.unit }}{{ r.weeklyAvgFormatted }} {{ r.unit }}
+
-
-
Device / Creator
-
${t.device||"Unknown Device"}
-
-
-
Start Time
-
${r?So(r):"Unknown"}
-
-
-
-
-
sensorsSensor Info
-
-
-
Total Points
-
${t.points.length.toLocaleString("en-US")} pts
-
-
-
Telemetry Stability
-
${T}%
-
-
-
Sensors Found
-
- ${a.sensors.length?a.sensors.map(f=>`${Nl[f]||"sensors"}`).join(""):'GPS only'} + +
+
+
+ {{ elevationIcon }} + Elevation Progress +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + +
PeriodElevationElevation/Week
{{ r.period }}{{ r.valueFormatted }} {{ r.unit }}{{ r.weeklyAvgFormatted }} {{ r.unit }}
+
-
-
- ${a.avgHR||a.avgPower||a.avgCadence||a.avgTemp!=null?` -
-
monitoringBiometric Averages
-
- ${a.avgHR?`
-
Avg HR
-
${a.avgHR} bpm
-
`:""} - ${a.maxHR?`
-
Max HR
-
${a.maxHR} bpm
-
`:""} - ${a.avgPower?`
-
Avg Power
-
${a.avgPower} W
-
`:""} - ${a.maxPower?`
-
Max Power
-
${a.maxPower} W
-
`:""} - ${a.avgCadence?`
-
Avg Cadence
-
${a.avgCadence} rpm
-
`:""} - ${a.avgTemp!=null?`
-
Avg Temp
-
${a.avgTemp.toFixed(1)} \xB0C
-
`:""} - ${a.minTemp!=null&&a.maxTemp!=null?`
-
Temp Range
-
${a.minTemp.toFixed(1)} \u2013 ${a.maxTemp.toFixed(1)} \xB0C
-
`:""} -
-
`:""} - - ${a.shifts!==null||d.gearMatrix.length>0?` -
-
settingsDrivetrain & Gear Matrix
-
-
-
Total Shifts
-
${a.shifts??0}
-
-
-
Cohort Power Rank
-
#${d.peerSummary.pwrRank} / ${d.peerSummary.cohortSize} (${d.peerSummary.cohortAvgPower} W avg)
+ +
+
+
+
+
+ bolt + Power Curve Progress +
+
+
+
+
+
+
+
+
+ bolt + {{ + powerTimelineLabel + }} +
+
+
+
+
+
+
+
+
+ + {{ trackName }} +
+
+ + All-Time Max +
+
+
+ + chevron_right + table_chart + Data Table + + + + + + + + + + + + + + + + +
DurationCurrentAll-Time Max
{{ row.durLabel }}{{ row.curValStr }} + {{ row.maxValStr }} + +
+
-
- - - - - - - - - - - - ${d.gearMatrix.map(f=>` - - - - - - - - `).join("")} - -
GearRatioShareAvg WCad
${me(f.combo)}${f.ratio}${f.pct}% (${f.seconds}s)${f.avgPower} W${f.avgCadence} rpm
-
`:""} - - ${d.splitRows.length>0?` -
-
splitscreenSection & Kilometer Splits (${d.splitRows.length})
- - - - - - - - - - - - - - - - - ${d.splitRows.map(f=>` - - - - - - - - - - - - - `).join("")} - -
SectionDistTimeGainSpeedPowerHRCadTempStability
${me(f.label)}${f.distKm} km${f.durationStr}+${f.elevGain} m${f.avgSpeedKmh} km/h${f.avgPower} W${f.avgHR} bpm${f.avgCadence} rpm${f.avgTemp} \xB0C${f.stabilityPct}%
-
`:""} - - ${t.devices&&t.devices.length>0?` -
-
watchHardware & Sensors
-
- ${(()=>{let f=new Set;return t.devices.filter(h=>{if(!(h.name||h.product||h.manufacturer))return!1;let E=`${h.name}|${h.product}|${h.manufacturer}|${h.serial}`;return f.has(E)?!1:(f.add(E),!0)}).map(h=>{let p=h.name||h.product||"Unknown Device",E=h.manufacturer?`${h.manufacturer}`:"",_=[h.serial?`SN: ${h.serial}`:null,h.version?`v${h.version}`:null,h.hardwareVersion?`hw:${h.hardwareVersion}`:null].filter(Boolean).join(" \u2022 "),W=[h.batteryLevel?`${h.batteryLevel}%`:null,h.batteryStatus?`Status: ${h.batteryStatus}`:null,h.batteryVoltage?`${h.batteryVoltage.toFixed(2)}V`:null].filter(Boolean).join(" \u2022 "),O="",Y=String(h.sourceType||"").toLowerCase();Y.includes("local")?O="memory":Y.includes("antplus")||Y.includes("ant_plus")?O="settings_input_antenna":Y.includes("bluetooth")&&(O="bluetooth");let Z="sensors",lt=String(p).toLowerCase();return lt.includes("heartrate")||lt.includes("hrm")?Z=Nt.hr.icon:lt.includes("power")?Z=Nt.power.icon:lt.includes("speed")?Z=Nt.speed.icon:lt.includes("cadence")?Z=Nt.cadence.icon:lt.includes("barometer")?Z="air":lt.includes("temperature")?Z=Nt.temperature.icon:lt.includes("gps")&&(Z="location_on"),` -
-
-
- ${Z} -
${me(p)}
- ${O?`${O}`:""} -
-
${E}
+ + +
+
+
+
+
+ favorite + Heart Rate Curve Progress
- ${_?`
${me(_)}
`:""} -
-
${me(h.type||"device")}
- ${W?`
- battery_charging_full - ${me(W)} -
`:""} +
+
+
+
+
+
+
+
+ favorite + {{ + hrTimelineLabel + }}
- `}).join("")})()} -
-
`:""} -
-
deleteDanger Zone
-
- +
+
+
+
+
+
+
+ + {{ trackName }} +
+
+ + All-Time Max +
+
+
+ + chevron_right + table_chart + Data Table + + + + + + + + + + + + + + + + +
DurationCurrentAll-Time Max
{{ row.durLabel }}{{ row.curValStr }} + {{ row.maxValStr }} + +
+
+
+ + +
+
+
+ history + Longitudinal Activity History ({{ historyRows.length }}) +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateActivitySportDistanceElevationDurationAvg PowerAvg HREst. TSS
{{ h.dateStr }} + {{ h.name }} + {{ h.sport }}{{ h.distKm }} km{{ h.elevGainM }} m{{ h.durationStr }}{{ h.avgPowerStr }}{{ h.avgHrStr }}{{ h.tssStr }}
+
-
+
- `;let $=document.getElementById("tag-container"),M=document.getElementById("new-tag-input"),F=document.getElementById("btn-add-tag"),I=()=>{$.innerHTML="";let f=t.tags||[];if(f.length===0){$.innerHTML='No tags added';return}f.forEach(h=>{let p=Ts(h),E=document.createElement("div");E.className="tag-pill font-s",E.style.cssText=` - background: ${p}15; - border: 1px solid ${p}44; - color: ${p}; - padding: 2px 8px; - border-radius: 4px; - font-weight: 600; - display: flex; - align-items: center; - gap: 6px; - `,E.innerHTML=` - ${me(h)} - close - `,$.appendChild(E)}),$.querySelectorAll(".btn-remove-tag").forEach(h=>{h.addEventListener("click",async p=>{let E=p.currentTarget.dataset.tag;t.tags=(t.tags||[]).filter(_=>_!==E),await ce.save(t),I(),Pn()})})},b=async()=>{let f=M.value.trim().toLowerCase();if(!f)return;let h=new Set(t.tags||[]);if(h.has(f)){M.value="";return}h.add(f),t.tags=Array.from(h).sort(),await ce.save(t),M.value="",I(),Pn()};F.addEventListener("click",b),M.addEventListener("keydown",f=>{f.key==="Enter"&&b()});let g=o.querySelector("#details-title-input");g?.addEventListener("change",async()=>{let f=g.value.trim();f&&(t.displayName=f,await ce.save(t),Pn())});let u=document.getElementById("sport-dropdown-trigger");u?.addEventListener("click",f=>{f.stopPropagation(),v(u)});function v(f){if(!t)return;document.querySelectorAll(".metric-menu-popup").forEach(O=>O.remove());let h=document.createElement("div");h.className="metric-menu-popup",Object.keys(Ye).forEach(O=>{let Y=Ye[O],Z=document.createElement("div"),lt=t.sport?.toLowerCase()===O;Z.className=`menu-item ${lt?"active":""}`,Z.innerHTML=` - ${Y.icon} - ${Y.name} - ${lt?"check":""} - `,Z.addEventListener("click",async()=>{t.sport=O,await ce.save(t),h.remove();let Ft=document.getElementById("sport-icon");Ft&&(Ft.textContent=Y.icon);let rt=document.getElementById("sport-name");rt&&(rt.textContent=Y.name),Pn()}),h.appendChild(Z)});let p=document.createElement("div"),E=!t.sport;p.className=`menu-item ${E?"active":""}`,p.innerHTML=` - block - \u2014 - ${E?"check":""} - `,p.addEventListener("click",async()=>{t.sport=void 0,await ce.save(t),h.remove();let O=document.getElementById("sport-icon");O&&(O.textContent="question_mark");let Y=document.getElementById("sport-name");Y&&(Y.textContent="\u2014"),Pn()}),h.appendChild(p),document.body.appendChild(h);let _=f.getBoundingClientRect();h.style.top=`${_.bottom+window.scrollY+4}px`,h.style.left=`${_.left+window.scrollX}px`;let W=O=>{!h.contains(O.target)&&!f.contains(O.target)&&(h.remove(),document.removeEventListener("click",W))};setTimeout(()=>document.addEventListener("click",W),10)}I(),document.getElementById("btn-delete-track")?.addEventListener("click",()=>{confirm(`Remove "${t.name}"?`)&&$o(t.id)})}import Gl from"uplot";var we=[];function No(t){return we.filter(s=>{if(s.points.length===0)return!1;for(let e of s.points){let n=!1;for(let o of t.points)if(en(e.lat,e.lon,o.lat,o.lon)<=e.radius){n=!0;break}if(!n)return!1}return!0})}var un=null,Yn=!1,dn=null,Wo=()=>{},ql=null;function qo(t){Wo=t,zl()}function zo(){we=[],un=null,dn=null,Yn=!1;let t=document.getElementById("courses-view");t&&(t.innerHTML=` -
- route -
No courses created yet
-
- `)}function Us(t){we=[];let s=[{trackIdx:0,suffix:"Full Loop",fracs:[.1,.5,.85],radius:450},{trackIdx:1,suffix:"Opening Climb Sector",fracs:[.08,.25,.45],radius:450},{trackIdx:2,suffix:"Lakeside Corridor",fracs:[.1,.45,.8],radius:850},{trackIdx:3,suffix:"Sprint Interval Sector",fracs:[.2,.5,.75],radius:850},{trackIdx:4,suffix:"Alpine Grand Tour Stage",fracs:[.1,.5,.85],radius:900},{trackIdx:5,suffix:"Summit Finish Climb",fracs:[.5,.72,.92],radius:900}];for(let e=0;e0&&(un=we[0].id,dn=we[0].id)}function Uo(){return we.map(t=>t.id)}async function zl(){try{let t=await ce.get("courses");t&&(we=t)}catch(t){console.error("Courses: Failed to load courses",t)}}async function Vs(){try{await ce.set("courses",we)}catch(t){console.error("Courses: Failed to save courses",t),Wo("Failed to save courses","error")}}function Ul(t){let s=0;for(let e=0;ee)return{duration:0,dist:0,avgWatts:null,avgHR:null,avgSpeed:null,avgCadence:null,avgVam:null};let i=Math.max(0,Math.min(s,o-1)),a=Math.max(i,Math.min(e,o-1)),r=n[i]?.time||0,T=((n[a]?.time||0)-r)/1e3,$=0,M=0,F=0,I=0,b=0,g=0,u=0,v=0,k=0;for(let h=i;h<=a;h++){let p=n[h];if(p.power!=null&&($+=p.power,M++),p.hr!=null&&(F+=p.hr,I++),p.speed!=null&&(b+=p.speed,g++),p.cadence!=null&&(u+=p.cadence,v++),h>i){let E=n[h-1];if(p.ele!=null&&E.ele!=null){let _=p.ele-E.ele;_>0&&(k+=_)}}}let f=a>i?(n[a].dist||0)-(n[i].dist||0):0;return{duration:T,dist:f,avgWatts:M>0?Math.round($/M):null,avgHR:I>0?Math.round(F/I):null,avgSpeed:g>0?b/g:null,avgCadence:v>0?Math.round(u/v):null,avgVam:T>0?Math.round(k/(T/3600)):null}}function Vl(t){let s=Math.floor(t/3600),e=Math.floor(t%3600/60),n=Math.floor(t%60);return s>0?`${s}:${e.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`:`${e}:${n.toString().padStart(2,"0")}`}function Os(){return` - calendar_today Date - straighten Distance - timer Duration - speed Speed - speed Pace - trending_up VAM - bolt Power - favorite HR - `}function Ys(t,s,e){let o=(s?Ye[s.toLowerCase()]:null)?.paceUnit||"km",i="--";if(t.avgSpeed!=null&&t.avgSpeed>.1){let a=(o==="km"?1e3:100)/t.avgSpeed;i=`${On(a)} min/${o}`}return` - ${e} - ${t.dist!=null?`${(t.dist/1e3).toFixed(2)} km`:"-"} - ${Vl(t.duration)} - ${t.avgSpeed!=null?`${(t.avgSpeed*3.6).toFixed(1)} km/h`:"-"} - ${i} - ${t.avgVam!=null?`${t.avgVam} m/h`:"-"} - ${t.avgWatts!=null?`${t.avgWatts} W`:"-"} - ${t.avgHR!=null?`${t.avgHR} bpm`:"-"} - `}var Cs=16384,Ao=new Float64Array(Cs),Io=new Float64Array(Cs),Ho=new Float64Array(Cs),Fo=new Float64Array(32),Do=new Float64Array(32),sn=180,Bo=28,_o=new Float64Array(sn),Ro=new Float64Array(sn),Ln=new Float64Array(sn+1),Es=new Float64Array(sn+1);function je(){let t=document.getElementById("courses-view");if(!t)return;let s=0,e=dn||un?we.filter(n=>n.id===dn||n.id===un):we;for(let n of e){if(n.points.length<2)continue;let o=Bt.findTracksPassingThroughPoints(n.points.map(a=>({lat:a.lat,lng:a.lon})),n.points[0]?.radius||20),i=4;for(let a=0;a -
-
-
- ${Yn?` - + +
+ {{ selectedCourseSummary.name }} + {{ selectedCourseSummary.pointsCount }} gates + {{ totalMatchesCount }} matched efforts + DTW Dev: {{ corridorDeviationStr }}m +
+
+
+ - `:` - - `} +
-
-
-
- ${we.length===0?` -
+ +
+
+
route
No courses created yet
- `:we.map(n=>{let o=n.points.map(d=>({lat:d.lat,lng:d.lon})),i=Bt.findTracksPassingThroughPoints(o,n.points[0]?.radius||20),a=n.id===dn,r="";if(a){let d=i.map(T=>{let $=Bt.getTrackData(T);if(!$)return null;let M=ks($,n.points);if(!M)return null;let F=wn($,M.startIdx,M.endIdx),I=Math.max(1,M.endIdx-M.startIdx),b=M.startIdx+Math.floor(I*.25),g=M.startIdx+Math.floor(I*.5),u=M.startIdx+Math.floor(I*.75),v=wn($,M.startIdx,b),k=wn($,b,g),f=wn($,g,u),h=wn($,u,M.endIdx),p=$.stats?.startTime||$.points?.[0]?.time,E=p?nn(p):"-";return{id:T,displayName:$.displayName||$.name||T,date:E,sport:$.sport,color:$.color,...F,splitsSummary:`${v.avgWatts||0}/${k.avgWatts||0}/${f.avgWatts||0}/${h.avgWatts||0}W`,startIdx:M.startIdx,endIdx:M.endIdx}}).filter(T=>T!==null);d.sort((T,$)=>T.duration-$.duration||T.id.localeCompare($.id)),r=` -
- ${d.length===0?` -
No matching tracks
- `:` - - - - - ${Os()} - - - - ${d.map(T=>` - - - ${Ys(T,T.sport,T.date)} - - `).join("")} - -
Track (${d.length})
-
-
- ${me(T.displayName)} -
-
- `} + +
+
+ {{ + c.isOpen ? 'expand_more' : 'chevron_right' + }} + +
+ {{ c.name }} + edit
- `}return` -
-
- ${a?"expand_more":"chevron_right"} -
${me(n.name)} edit
-
straighten ${Ul(n).toFixed(2)} km | ${n.points.length} points | ${i.length} matching tracks
-
- - -
+ +
+ +
+ +
+ straighten + {{ c.distanceKm }} km | {{ c.pointsCount }} points | {{ c.matchingCount }} matching + tracks +
+ +
+ +
- ${r}
- `}).join("")} + +
+
No matching tracks
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Track ({{ c.matchedTracks.length }}) + calendar_today + Date + + straighten + Distance + + timer + Duration + + speed + Speed + + speed + Pace + + trending_up + VAM + + bolt + Power + + favorite + HR + + view_column + Q1\u2013Q4 Splits + + emoji_events + Gap +
+
+
+ {{ t.displayName }} + #{{ idx + 1 }} +
+
{{ t.date }}{{ t.distStr }}{{ t.durationStr }}{{ t.speedStr }}{{ t.paceStr }}{{ t.vamStr }}{{ t.wattsStr }}{{ t.hrStr }} + {{ t.splitsSummary }} + + {{ t.gapLabel }} +
+
+
+
- `,document.getElementById("btn-new-course")?.addEventListener("click",()=>{Ol()}),document.getElementById("btn-done-edit")?.addEventListener("click",()=>{Yn=!1,Bt.setCustomClickHandler(null),document.getElementById("map-container")?.classList.remove("editing-mode"),je()}),t.querySelectorAll(".course-item").forEach(n=>{let o=n.dataset.id;n.querySelector(".btn-edit-course")?.addEventListener("click",i=>{i.stopPropagation(),Vo(o)}),n.querySelector(".btn-rename-course")?.addEventListener("click",i=>{i.stopPropagation(),Yl(o)}),n.querySelector(".btn-delete-course")?.addEventListener("click",i=>{i.stopPropagation(),jl(o)}),n.querySelector(".course-item-header")?.addEventListener("click",i=>{i.target.closest(".course-actions")||i.target.closest(".btn-rename-course")||(Tn(o),dn=dn===o?null:o,je())}),n.querySelectorAll(".course-track-row").forEach(i=>{let a=i.dataset.trackId,r=parseInt(i.dataset.start,10),d=parseInt(i.dataset.end,10);i.querySelector(".track-name-cell")?.addEventListener("click",T=>{T.stopPropagation();let $=Bt.getTrackData(a);$&&(_e(a,!1),setTimeout(()=>{let M=$.points,F=M.find(h=>h.time!=null)?.time||0,I=Math.max(0,Math.min(r,M.length-1)),b=Math.max(0,Math.min(d,M.length-1)),g=Math.max(0,((M[I]?.time||0)-F)/1e3),u=Math.max(0,((M[b]?.time||0)-F)/1e3),v=ft.getXAxis(),k=g,f=u;v==="distance"&&(k=Math.max(0,(M[I]?.dist||0)/1e3),f=Math.max(0,(M[b]?.dist||0)/1e3)),Gt.patch({sel:[k,f],tab:"graphs"},!0),ft.restoreSelection(g,u),Bt.highlightSegment(a,$.points,r,d,!0)},50))}),i.addEventListener("mouseenter",()=>{Bt.setTrackHover(a,!0)}),i.addEventListener("mouseleave",()=>{Bt.setTrackHover(a,!1)})})})}function Ol(){let t=`Course ${we.length+1}`,s={id:Math.random().toString(36).substring(2,9),name:t,points:[]};we.push(s),Vs(),je(),Vo(s.id)}function Yl(t){let s=we.find(r=>r.id===t);if(!s)return;let e=document.querySelector(`.course-item[data-id="${t}"]`);if(!e)return;let n=e.querySelector(".course-name");if(!n)return;let o=s.name;n.innerHTML=``;let i=n.querySelector(".course-name-input");i.focus(),i.select();let a=()=>{let r=i.value.trim();r!==""&&(s.name=r,Vs()),je()};i.addEventListener("blur",a),i.addEventListener("keydown",r=>{r.key==="Enter"?a():r.key==="Escape"&&je()})}function Vo(t){un=t,Yn=!0,je()}function Oo(){ql=null}function Tn(t,s=!1){un=t,s&&(dn=t),Yn=!1,Bt.setCustomClickHandler(null),Oo(),je()}function jl(t){confirm("Are you sure you want to delete this course?")&&(we=we.filter(s=>s.id!==t),un===t&&(un=null,Oo()),Vs(),je())}var Ls=()=>{},js=[];function Qo(){js.forEach(t=>t.destroy()),js=[]}function Ko(t){Ls=t}function Jo(){Qo(),document.querySelectorAll(".hr-settings-popup").forEach(s=>s.remove());let t=document.getElementById("insights-view");t&&(t.innerHTML=` + `})],Gg);function qz(t,e){Az(t,e)}function Wz(){let t=zR();if(t){t.reset();return}let e=document.getElementById("details-view");e&&(e.innerHTML=` +
+ no_sim +
Select a track for details
+
+ `)}function Jr(t,e=[],n=[],r){let s=zR();s&&s.render(t,e,n,r)}function zz(t){Iz(t)}function Gz(){let t=UR();if(t){t.reset();return}document.querySelectorAll(".hr-settings-popup").forEach(n=>n.remove());let e=document.getElementById("insights-view");e&&(e.innerHTML=`
no_sim
Select a track for insights
- `)}var mn=16384,Yo=new Float64Array(mn),jo=new Float64Array(mn),Go=new Float64Array(mn),Zl=new Float64Array(mn),Xl=new Float64Array(mn),$s=new Float64Array(mn+1),Ps=new Float64Array(mn+1),Zo=[1,2,3,5,8,10,15,20,30,45,60,90,120,180,240,300,420,600,900,1200];function Ql(t,s,e){let n=Math.min(t.length,mn);if(n===0)return{minWPrimeBal:2e4,matchesBurned:0,decouplingPct:0,quadrantPct:[25,25,25,25],sectionPeaks:[]};for(let p=0;p0?Y*Z*36:0;Yo[p]=_,jo[p]=1/W,Go[p]=O,Zl[p]=Y,Xl[p]=lt,$s[p+1]=$s[p]+_,Ps[p+1]=Ps[p]+lt}let o=0;for(let p=0;pn)continue;let _=n-E,W=0,O=0;for(let Y=0;Y<=_;Y++){let Z=$s[Y+E]-$s[Y],lt=Ps[Y+E]-Ps[Y];Z>W&&(W=Z),lt>O&&(O=lt)}o+=(W+O)/E}let i=2e4,a=2e4,r=0,d=!1,T=n>>1,$=0,M=0,F=[0,0,0,0],I=88,b=s/I;for(let p=0;p0?O:0,Ft=546*Math.exp(-.008*(Y+Z*.625))+316;a=Math.min(2e4,a-Z+(2e4-a)*(1/Ft)),a17500&&d&&(d=!1);let rt=E/_;rt>=b&&_>=I?F[0]++:rt>=b&&_0?$/T:1,u=n-T>0?M/(n-T):1,v=g>0?(g-u)/g*100:0,k=[Number((F[0]/n*100).toFixed(1)),Number((F[1]/n*100).toFixed(1)),Number((F[2]/n*100).toFixed(1)),Number((F[3]/n*100).toFixed(1))],h=(e&&e.length>0?e.filter(p=>p.kind==="quarter"||p.kind==="climb"||p.kind==="sprint"):[]).slice(0,8).map(p=>{let E=p.stats,_=E.duration&&E.duration>0?E.duration/36e5:0;return{label:p.label,distKm:Number((E.totalDist/1e3).toFixed(2)),avgPower:E.avgPower||0,peak60sPower:E.powerCurve?.[60]?.power||E.avgPower||0,avgHR:E.avgHR||0,vam:_>0?Math.round(E.elevGain/_):0}});return o<-1e12&&(i=0),{minWPrimeBal:i,matchesBurned:r,decouplingPct:v,quadrantPct:k,sectionPeaks:h}}function be(t,s=[],e=null){Qo();let n=document.getElementById("insights-view");if(!n)return;if(!t){n.innerHTML="";return}Jt.ensureCurvesAndZones(t),t.stats.sections||(t.stats.sections=Jt.analyzeTrackSections(t.points));let o=e||Gt.get().sel||null,i=t.points,a=t.stats;if(o&&t.points.length>4){let g=t.points[0].time||0,u=g+o[0]*1e3,v=g+o[1]*1e3,k=t.points.findIndex(h=>(h.time||0)>=u),f=t.points.findIndex(h=>(h.time||0)>=v);k===-1&&(k=0),f===-1&&(f=t.points.length-1),f>k+4&&(i=t.points.slice(k,f+1),a=Jt.computeStats(i,!0))}if(!a.powerCurve&&!a.hrZones&&!a.hrCurve){n.innerHTML=` -
- analytics -
No insights available for this track (requires Power or Heart Rate data)
-
- `;return}let r=Ql(i,Jt.getFTP(),t.stats.sections),d=r.minWPrimeBal;n.innerHTML=` -
- `;let T=document.getElementById("insights-grid");if(!T)return;let $=Math.round(T.getBoundingClientRect().width-42)||480;if(a.powerCurve&&Xo({grid:T,track:t,curve:a.powerCurve,metricKey:"power",label:"Power Curve",unit:"W",color:Nt.power.color,icon:"bolt",chartWidth:$}),a.hrCurve&&Xo({grid:T,track:t,curve:a.hrCurve,metricKey:"hr",label:"Heart Rate Curve",unit:"bpm",color:Nt.hr.color,icon:"favorite",chartWidth:$}),a.powerZones){let g=document.createElement("div");g.className="insight-card";let u="power",v=Nt.power.color;g.style.setProperty("--chart-color",v);let k=ft.getMapColorMetric()===u,f=a.powerZones.reduce((E,_)=>E+_,0),h=$n.getPowerZones(),p="";a.powerZones.forEach((E,_)=>{if(_>=h.length)return;let W=h[_],O=f>0?E/f*100:0,Y=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} W`:`> ${Math.round(W.min)} W`;p+=` -
-
- Z${_+1} - ${W.name} - ${Y} - ${he(Math.round(E))} - ${O.toFixed(1)}% -
-
-
-
-
- `}),g.innerHTML=` -
-
-
- boltPower Zones -
- -
- + `)}function Ur(t,e=[],n=null){let r=UR();r&&r.render(t,e,n)}function Zz(){let t=Zp();if(t){t.reset();return}let e=document.getElementById("combined-tooltip");e&&e.remove();let n=document.getElementById("combined-view");n&&(n.innerHTML=` +
+ no_sim +
Select a track for combined analysis
-
${p}
- `,T.appendChild(g),g.querySelector(".map-color-btn")?.addEventListener("click",E=>{E.stopPropagation(),ft.toggleMapColor(u);let _=ft.getMapColorMetric();T.querySelectorAll(".map-color-btn").forEach(W=>{let O=W;O.classList.toggle("active",O.dataset.metric===_)})}),g.querySelector(".btn-pw-settings")?.addEventListener("click",E=>{E.stopPropagation(),Jl(E.currentTarget,t)})}if(a.hrZones){let g=document.createElement("div");g.className="insight-card";let u="hr",v=Nt.hr.color;g.style.setProperty("--chart-color",v);let k=ft.getMapColorMetric()===u,f=a.hrZones.reduce((E,_)=>E+_,0),h=$n.getHRZones(),p="";a.hrZones.forEach((E,_)=>{if(_>=h.length)return;let W=h[_],O=f>0?E/f*100:0,Y=isFinite(W.max)?`${Math.round(W.min)} - ${Math.round(W.max)} bpm`:`> ${Math.round(W.min)} bpm`;p+=` -
-
- Z${_+1} - ${W.name} - ${Y} - ${he(Math.round(E))} - ${O.toFixed(1)}% -
-
-
-
+ `)}function eF(t,e){let n=Zp();n&&n.setMetrics(t,e)}function ew(t){let e=Zp();e&&e.setPolar(t)}function tw(t){let e=Zp();e&&e.setSliderProgress(t)}function Hl(t,e=[]){let n=Zp();n&&n.render(t,e)}function tF(){let t=Zp();t&&t.resize()}var t0e=16,nF=[{label:"Newest first",val:"date-desc",icon:"calendar_today"},{label:"Oldest first",val:"date-asc",icon:"history"},{label:"Longest distance",val:"dist-desc",icon:"straighten"},{label:"Shortest distance",val:"dist-asc",icon:"horizontal_rule"},{label:"Longest duration",val:"dur-desc",icon:"timer"},{label:"Shortest duration",val:"dur-asc",icon:"timer_off"}],n0e=[{key:"power",title:"Power",icon:"bolt"},{key:"hr",title:"Heart Rate",icon:"favorite"},{key:"cadence",title:"Cadence",icon:"directions_run"},{key:"temperature",title:"Temperature",icon:"thermostat"},{key:"battery",title:"Battery",icon:"battery_full"},{key:"gearRear",title:"Rear Gear",icon:"settings"},{key:"gearFront",title:"Front Gear",icon:"settings_input_component"}],r0e=[{id:"graphs",label:"Analysis",icon:"monitoring",marginLeft:""},{id:"insights",label:"Insights",icon:"analytics",marginLeft:""},{id:"details",label:"Details",icon:"list_alt",marginLeft:""},{id:"combined",label:"Combined",icon:"layers",marginLeft:""},{id:"evolution",label:"Progress",icon:"timeline",marginLeft:"auto"},{id:"courses",label:"Courses",icon:"route",marginLeft:""}];function s0e(t,e){let n=new Date(t),r=new Date(e);return n.getUTCFullYear()===r.getUTCFullYear()&&n.getUTCMonth()===r.getUTCMonth()&&n.getUTCDate()===r.getUTCDate()}var Zg=class{constructor(){this.state=fe(Kr);this.cdr=fe(An);this.appRef=fe(yr);this.tabs=r0e;this.filterMetricOptions=n0e;this.displayedTracks=[];this.allSportOptions=[];this.commonSportOptions=[];this.filterPanelOpen=!1;this.sportDropdownOpen=!1;this.dropActive=!1;this.loaderVisible=!1;this.loaderText="Importing tracks";this.loaderFilename="";this.loaderProgressPct=0;this.loaderProgressIndex="";this.loaderProgressTotal="";this.loaderIcon="download";this.loaderIconColor="var(--accent)";this.loaderWarningCount=0;this.preloadedBenchmarkPayloads=null;this.state.appRef=this.appRef,this.state.onSelectTrackCallback=(e,n=!0,r=!1)=>this.selectTrack(e,n,r),this.state.onDeleteTrackCallback=e=>this.deleteTrack(e),this.state.onApplyFiltersCallback=(e=!1)=>this.applyFilters(e),this.state.onChartRangeChangeCallback=(e,n,r,s=!1)=>this.onChartRangeChange(e,n,r,s)}get trackListHeaderLabel(){return this.displayedTracks.length>0||Object.keys(this.state.tracks).length>0?`Tracks (${this.displayedTracks.length})`:"Tracks"}get importWarningTitle(){return this.state.skippedImports.length>0?`Skipped ${this.state.skippedImports.length} imports. Click to view details.`:"Show skipped imports"}get currentSortIcon(){let e=nF.find(n=>n.val===this.state.currentSort);return e?e.icon:"calendar_today"}get currentSortLabel(){let e=nF.find(n=>n.val===this.state.currentSort);return e?e.label.replace(" first","").replace(" distance","").replace(" duration",""):"Date"}ngOnInit(){this.cdr.detectChanges()}ngAfterViewInit(){this.initApp()}trackById(e,n){return n.id}capitalize(e){return e?e.charAt(0).toUpperCase()+e.slice(1):""}formatTrackDate(e){return e.points.length&&e.points[0].time?Zo(e.points[0].time):"Unknown date"}formatTrackKm(e){return Math.round((e.stats.totalDist||0)/1e3)}getSportIcon(e){if(!e)return"category";let n=e.toLowerCase();return n.includes("run")?"directions_run":n.includes("cycl")||n.includes("bike")?"directions_bike":n.includes("walk")?"directions_walk":n.includes("swim")?"pool":n.includes("hik")?"hiking":"sports"}getTagColor(e){return TD(e)}onCancelLoader(){this.state.cancelProcessing=!0,this.loaderVisible=!1,this.cdr.detectChanges()}onToggleFilterPanel(){this.filterPanelOpen=!this.filterPanelOpen,this.cdr.detectChanges()}onFitAll(){st.fitAll()}onClearAll(){this.clearAll()}onSearchInput(e){this.state.searchQuery=e.target.value,this.applyFilters(),It.patch({q:this.state.searchQuery||null})}onToggleRegex(){this.state.searchRegex=!this.state.searchRegex,this.applyFilters(),It.patch({re:this.state.searchRegex?!0:null})}onFilterInput(e,n,r){let s=r.target.value;e==="date"?this.state.filters.date[n]=s===""?null:s:e==="dist"?this.state.filters.dist[n]=s===""?null:Number(s):this.state.filters.dur[n]=s===""?null:Number(s),this.applyFilters(),this.state.syncFiltersToUrl()}onToggleSportDropdown(e){e.stopPropagation(),this.sportDropdownOpen=!this.sportDropdownOpen,this.cdr.detectChanges()}onSelectSportFilter(e,n=!1){this.state.filters.sport=this.state.filters.sport===e?null:e,n&&(this.sportDropdownOpen=!1),this.applyFilters(),this.state.syncFiltersToUrl(),this.cdr.detectChanges()}onFilterTagsInput(e){let n=e.target.value;this.state.filters.tags=n.split(",").map(r=>r.trim().toLowerCase()).filter(r=>!!r),this.applyFilters(),this.state.syncFiltersToUrl()}onToggleMetricFilter(e){this.state.filters.metrics.has(e)?this.state.filters.metrics.delete(e):this.state.filters.metrics.add(e),this.applyFilters(),this.state.syncFiltersToUrl()}onResetFilters(){this.state.filters={date:[null,null],dist:[null,null],dur:[null,null],metrics:new Set,tags:[],sport:null},this.applyFilters(),this.state.syncFiltersToUrl()}onOpenSortMenu(e){e.stopPropagation();let n=e.currentTarget;document.querySelectorAll(".sort-menu-popup").forEach(o=>o.remove());let r=document.createElement("div");r.className="sort-menu-popup",nF.forEach(o=>{let a=document.createElement("div");a.className=`menu-item ${this.state.currentSort===o.val?"active":""}`,a.innerHTML=` + ${o.icon} + ${o.label} + ${this.state.currentSort===o.val?"check":""} + `,a.addEventListener("click",()=>{this.state.currentSort=o.val,It.patch({sort:o.val}),this.renderTrackList(),r.remove()}),r.appendChild(a)});let s=n.getBoundingClientRect();r.style.top=`${s.bottom+5}px`,r.style.left=`${s.left}px`,document.body.appendChild(r);let i=o=>{!r.contains(o.target)&&!n.contains(o.target)&&(r.remove(),document.removeEventListener("click",i))};setTimeout(()=>document.addEventListener("click",i),0)}onTrackItemClick(e,n){e.target.closest(".icon-btn")||this.selectTrack(n.id)}onToggleTrackVis(e,n){e.stopPropagation(),n.visible=!n.visible,st.setTrackVisible(n.id,n.visible),tr.save(n),this.cdr.detectChanges()}onFileInputChange(e){let n=e.target,r=Array.from(n.files||[]);this.handleFiles(r),n.value=""}onTabClick(e){this.activateTab(e,!0);let n=this.state.selectedTrack;if(e==="details"&&n&&Jr(n,this.state.getGlobalTags()),e==="insights"&&n&&Ur(n),e==="evolution"&&Jb(n,this.state.allTracks,(r,s)=>{this.selectTrack(r,!0),s&&(Pe.restoreSelection(s[0],s[1]),this.onChartRangeChange(s[0],s[1],"time",!0))},(r,s)=>{this.state.filters.date=[r,s],this.applyFilters(),this.state.syncFiltersToUrl(!0)}),e==="combined"&&n&&Hl(n),e==="courses"&&$l(),e==="graphs"){Pe.resize(),this.state.graphsTab?.updateToolbarLayout();let r=It.get().sel;r&&Pe.restoreSelection(r[0],r[1])}}activateTab(e,n=!1){this.state.activeTab=e,It.patch({tab:e},n),this.cdr.detectChanges()}updateSportFilterOptions(){let e=new Set;Object.values(this.state.tracks).forEach(r=>{r.sport&&e.add(r.sport)});let n=Array.from(e).sort();if(this.allSportOptions=n,n.length<=4)this.commonSportOptions=n;else{let r=["running","cycling","walking"];this.commonSportOptions=r.filter(s=>e.has(s))}}renderTrackList(){this.updateSportFilterOptions(),this.displayedTracks=this.state.filteredTracks,this.cdr.detectChanges()}applyFilters(e=!1){Object.keys(this.state.tracks).forEach(r=>{let s=this.state.tracks[r],i=s.stats,o=!0;if(this.state.searchQuery)if(this.state.searchRegex)try{new RegExp(this.state.searchQuery,"i").test(s.name)||(o=!1)}catch{o=!1}else s.name.toLowerCase().includes(this.state.searchQuery.toLowerCase())||(o=!1);if(o&&(this.state.filters.date[0]||this.state.filters.date[1])){let a=this.state.filters.date[0]?new Date(this.state.filters.date[0]).getTime():0,c=this.state.filters.date[1]?new Date(this.state.filters.date[1]).getTime():1/0,u=i.startTime||0;(uc)&&(o=!1)}if(o&&(this.state.filters.dist[0]!==null||this.state.filters.dist[1]!==null)){let a=(this.state.filters.dist[0]||0)*1e3,c=(this.state.filters.dist[1]||1/0)*1e3;(i.totalDistc)&&(o=!1)}if(o&&(this.state.filters.dur[0]!==null||this.state.filters.dur[1]!==null)){let a=(this.state.filters.dur[0]||0)*6e4,c=(this.state.filters.dur[1]||1/0)*6e4,u=i.duration||0;(uc)&&(o=!1)}if(o&&this.state.filters.metrics.size>0)for(let a of this.state.filters.metrics){let c=Pe.METRICS[a]?.field;if(c&&!s.points.some(u=>u[c]!=null)){o=!1;break}}if(o&&this.state.filters.sport&&s.sport!==this.state.filters.sport&&(o=!1),o&&this.state.filters.tags.length>0){let a=s.tags||[];this.state.filters.tags.every(c=>a.includes(c))||(o=!1)}s._filtered=!o,st.setTrackVisible(s.id,s.visible&&o)}),e||this.renderTrackList()}selectTrack(e,n=!0,r=!1){if(!this.state.tracks[e])return;if(e===this.state.selectedId){n&&st.fitTrack(e);return}let s=this.state.selectedId!==null;s&&(Pe.clear(),Jr(null,[]),Ur(null)),this.state.selectedId=e,this.state.currentMapColors=null,st.clearMetricColor(e),s&&Pe.toggleMapColor(null),It.patch({track:e,sel:null},!0),s&&Pe.cancelSelection(),this.renderTrackList();let i=It.get().tab||"graphs",o=this.state.tracks[e],a=this.state.allTracks;i==="details"&&Jr(o,this.state.getGlobalTags()),i==="insights"&&Ur(o),i==="combined"&&Hl(o),i==="courses"&&$l(),i==="evolution"&&Jb(o,a,(c,u)=>{this.selectTrack(c,!0),u&&(Pe.restoreSelection(u[0],u[1]),this.onChartRangeChange(u[0],u[1],"time",!0))}),st.setSelectedTrack(e,n),n&&st.fitTrack(e),Pe.loadTrack(o,a,r),this.cdr.detectChanges()}async deleteTrack(e){await tr.remove(e),st.removeTrack(e),delete this.state.tracks[e],this.state.selectedId===e&&(this.state.selectedId=null,Pe.clear(),Jr(null,[]),Ur(null),It.patch({track:null,sel:null,sel_point:null})),this.applyFilters()}onChartCursorMove(e){e&&e.lat!=null&&e.lon!=null?(st.showCursorAt(e.lat,e.lon),this.state.followDot&&st.centerOn(e.lat,e.lon,null,!0)):st.hideCursor()}onChartRangeChange(e,n,r,s=!1){let i=this.state.selectedTrack;if(!i)return;if(e===null||n===null){st.clearHighlight(),(It.get().tab||"graphs")==="insights"&&Ur(i),It.patch({sel:null});return}let o=i.points,a=0,c=o.length-1;if(r==="distance"){let p=e*1e3,f=n*1e3;a=o.findIndex(h=>(h.dist||0)>=p),c=o.findIndex(h=>(h.dist||0)>=f)}else{let p=o.find(m=>m.time!=null)?.time||0,f=p+e*1e3,h=p+n*1e3;a=o.findIndex(m=>(m.time||0)>=f),c=o.findIndex(m=>(m.time||0)>=h)}a===-1&&(a=0),c===-1&&(c=o.length-1);let u=o.slice(a,c+1),d=ln.computeStats(u);Pe.setSelectionStats(d),(It.get().tab||"graphs")==="insights"&&Ur(i),st.highlightSegment(i.id,o,a,c,s,this.state.currentMapColors),st.ensureVisible(u.map(p=>[p.lat,p.lon])),It.patch({sel:[e,n]})}onChartClick(e,n){e&&e.lat!=null&&e.lon!=null&&st.centerOn(e.lat,e.lon,t0e)}async resetBenchmarkState(){typeof window.__resetBenchmarkSeed=="function"&&window.__resetBenchmarkSeed(),await tr.clear(),this.state.tracks={},this.state.skippedImports=[],this.state.selectedId=null,this.state.colorIdx=0,this.state.currentMapColors=null,this.state.cancelProcessing=!1,this.state.followDot=!1,this.state.searchQuery="",this.state.searchRegex=!1,this.state.currentSort="date-desc",this.state.filters.date=[null,null],this.state.filters.dist=[null,null],this.state.filters.dur=[null,null],this.state.filters.metrics.clear(),this.state.filters.tags=[],this.state.filters.sport=null,this.state.activeTab="graphs",ln.setHRZones([120,140,160,180]),ln.setFTP(200),gz(),Gz(),Wz(),Zz(),Vz(),st.removeAllTracks&&st.removeAllTracks(),st.clearTracks&&st.clearTracks(),st.clearHighlight(),Pe.resetState?Pe.resetState():Pe.clear&&Pe.clear(),It.reset();let e=document.getElementById("toast-container");e&&(e.innerHTML=""),document.querySelectorAll(".modal-backdrop").forEach(n=>n.remove()),this.renderTrackList()}async initApp(){let e=null,n=new Promise(o=>{e=window.setTimeout(o,1e3)});try{let o=document.fonts?Promise.all([document.fonts.load('24px "Material Symbols Rounded"').catch(()=>{}),document.fonts.ready]):Promise.resolve();await Promise.race([o,n])}finally{e!==null&&window.clearTimeout(e)}document.body.classList.remove("loading-fonts");let r=It.get();zz((o,a)=>this.state.showToast(o,a==="error"?"error":"info")),qz(()=>{this.applyFilters(),this.state.syncFiltersToUrl()},o=>{this.deleteTrack(o)}),mz((o,a)=>this.state.showToast(o,a==="error"?"error":"info")),st.init(o=>this.selectTrack(o),(o,a,c)=>It.patch({map_pos:[o,a,c]}),(o,a)=>{this.selectTrack(o,!1),Pe.setCursorAt(a)},(o,a)=>{o===this.state.selectedId?Pe.setHoverAt(a):Pe.setHoverAt(null)},()=>{}),Pe.init(o=>this.onChartCursorMove(o),(o,a,c)=>this.onChartRangeChange(o,a,c),(o,a)=>this.onChartClick(o,a),o=>It.patch({sel_point:o})),Pe.setMapColorChangeCb(o=>{o?(this.state.currentMapColors=o.colors,this.state.selectedId&&st.colorTrackByMetric(this.state.selectedId,o.pts,o.colors)):(this.state.currentMapColors=null,this.state.selectedId&&st.clearMetricColor(this.state.selectedId));let a=It.get();a.sel&&this.onChartRangeChange(a.sel[0],a.sel[1],Pe.getXAxis())}),this.applyState(r),await tr.openDB(),await this.resetBenchmarkState(),this.initResizeHandle(),this.initSidebarResizer(),this.initDropZone(),this.initGlobalListeners(),this.state.graphsTab?.updateToolbarLayout(),this.bindBenchmarkSteps(),await this.preloadBenchmarkFiles();let s=document.createElement("div");s.id="app-is-ready",s.setAttribute("data-ready","true"),s.style.display="none",document.body.appendChild(s);let i=document.createElement("div");i.id="appIsReady",i.setAttribute("data-ready","true"),i.style.display="none",document.body.appendChild(i)}applyState(e){let n=e.track;if(n!==this.state.selectedId&&(n&&this.state.tracks[n]?this.selectTrack(n,!0):!n&&this.state.selectedId&&(this.state.selectedId=null,Pe.clear(),Jr(null,[]),Ur(null),this.renderTrackList(),st.fitAll())),e.map&&typeof e.map=="string"&&st.switchBasemap(e.map),e.map_pos){let[r,s,i]=e.map_pos;st.setPosition(r,s,i)}if(e.tab&&this.activateTab(e.tab,!1),e.xaxis&&Pe.setXAxis(e.xaxis),e.metrics){let r=Pe.METRICS,s=e.metrics.map(i=>Object.keys(r).find(o=>r[o].abbr===i)).filter(i=>i!==void 0);s.length&&Pe.setActiveMetrics(s)}e.f_date&&(this.state.filters.date=e.f_date.map(r=>r||null)),e.f_dist&&(this.state.filters.dist=e.f_dist.map(r=>r===0?0:r||null)),e.f_dur&&(this.state.filters.dur=e.f_dur.map(r=>r===0?0:r||null)),e.f_mets&&(this.state.filters.metrics=new Set(e.f_mets)),e.f_tags&&(this.state.filters.tags=e.f_tags),e.q&&(this.state.searchQuery=e.q),e.re&&(this.state.searchRegex=e.re),e.sort&&(this.state.currentSort=e.sort),this.applyFilters()}initGlobalListeners(){document.addEventListener("select-track",e=>{let n=e.detail.id,r=e.detail.idx,s=e.detail.dur;if(n&&this.state.tracks[n]&&(this.selectTrack(n),r!=null&&s!=null)){let i=this.state.tracks[n],o=i.points;if(r>=0&&rm.time!=null)?.time||0,u=(a.time-c)/1e3,d=u+s;Pe.restoreSelection(u,d);let p=o.findIndex(m=>(m.time||0)>=a.time+s*1e3);p===-1&&(p=o.length-1);let f=o.slice(r,p+1),h=ln.computeStats(f);Pe.setSelectionStats(h),Ur(i),st.highlightSegment(n,o,r,p,!1,this.state.currentMapColors),st.ensureVisible(f.map(m=>[m.lat,m.lon])),It.patch({sel:[u,d]})}}}}),document.addEventListener("click",e=>{if(this.sportDropdownOpen){let n=document.getElementById("sport-dropdown-content"),r=document.getElementById("sport-burger-btn");n&&!n.contains(e.target)&&e.target!==r&&(this.sportDropdownOpen=!1,this.cdr.detectChanges())}}),document.addEventListener("keydown",e=>{e.key==="Escape"&&(st.hideCursor(),st.closePopup?.(),document.querySelectorAll(".color-picker-popup, .metric-menu-popup, .sort-menu-popup, .modal-backdrop").forEach(n=>n.remove()))}),window.addEventListener("resize",()=>{Pe.resize(),tF(),st.invalidateSize?.(),this.state.graphsTab?.updateToolbarLayout()})}initResizeHandle(){let e=document.getElementById("resize-handle"),n=document.getElementById("chart-panel");if(!e||!n)return;let r=!1;e.addEventListener("mousedown",()=>{r=!0,document.body.style.cursor="ns-resize"}),document.addEventListener("mousemove",s=>{if(!r)return;let i=window.innerHeight-s.clientY,o=Math.max(100,Math.min(window.innerHeight-100,i));n.style.height=`${o}px`,Pe.resize(),tF(),st.invalidateSize?.()}),document.addEventListener("mouseup",()=>{r&&(r=!1,document.body.style.cursor="")})}initSidebarResizer(){let e=document.getElementById("sidebar-resizer"),n=document.getElementById("sidebar");if(!e||!n)return;let r=!1;e.addEventListener("mousedown",()=>{r=!0,e.classList.add("dragging"),document.body.classList.add("dragging-sidebar")}),document.addEventListener("mousemove",s=>{if(!r)return;let i=s.clientX,o=Math.max(200,Math.min(600,i));n.style.width=`${o}px`,n.style.setProperty("--sidebar-w",`${o}px`),Pe.resize(),st.invalidateSize?.()}),document.addEventListener("mouseup",()=>{r&&(r=!1,e.classList.remove("dragging"),document.body.classList.remove("dragging-sidebar"))})}initDropZone(){window.addEventListener("dragover",e=>{e.preventDefault(),this.dropActive=!0,this.cdr.detectChanges()}),window.addEventListener("dragleave",e=>{e.relatedTarget===null&&(this.dropActive=!1,this.cdr.detectChanges())}),window.addEventListener("drop",async e=>{e.preventDefault(),this.dropActive=!1,this.cdr.detectChanges();let n=e.dataTransfer?.items;if(!n)return;let r=[],s=[];for(let o=0;oo.file(c));r.push(a)}else if(o.isDirectory){let a=o.createReader(),c=[],u;do u=await new Promise(d=>a.readEntries(d)),c.push(...u);while(u.length>0);for(let d of c)await i(d)}}for(let o of s)await i(o);r.length&&await this.handleFiles(r)})}onShowSkippedImportsModal(e){e.stopPropagation();let n=document.createElement("div");n.className="modal-backdrop";let r="";this.state.skippedImports.forEach(a=>{r+=`
${a.name}: ${a.reason}
`}),n.innerHTML=` +